- 后端: FastAPI + SQLAlchemy 2.0 + Pydantic v2 + Celery (19个API模块) - 前端: React 18 + TypeScript + Ant Design 5 + Zustand (19个页面组件) - 权限: RBAC四维权限体系 (RB-01~RB-13) - 任务: 四步向导创建 + 双执行器(龙虾/脚本) + 定时调度 - 部署: Docker Compose 6服务 + Nginx反代 + Alembic迁移 统计: 88个文件 | 8779行代码 | 默认账号: admin/admin123
3455 lines
87 KiB
HTML
3455 lines
87 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||
<title>Agent 任务系统 v2.1 产品需求文档(PRD)</title>
|
||
<style>
|
||
*{box-sizing:border-box}
|
||
:root{
|
||
--pri:#6366f1;
|
||
--pri-l:#eef2ff;
|
||
--txt:#0f172a;
|
||
--sub:#64748b;
|
||
--muted:#94a3b8;
|
||
--bdr:#e2e8f0;
|
||
--bg:#f8fafc;
|
||
--code-bg:#f1f5f9;
|
||
--tbl-head:#f8fafc;
|
||
--ok:#16a34a;--ok-bg:#dcfce7;
|
||
--warn:#b45309;--warn-bg:#fef3c7;
|
||
--err:#dc2626;--err-bg:#fee2e2;
|
||
}
|
||
html,body{margin:0;padding:0}
|
||
body{
|
||
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
|
||
color:var(--txt);
|
||
background:var(--bg);
|
||
line-height:1.7;
|
||
-webkit-font-smoothing:antialiased;
|
||
}
|
||
.layout{display:flex;max-width:1400px;margin:0 auto;min-height:100vh}
|
||
/* Sidebar TOC */
|
||
.sidebar{
|
||
position:sticky;top:0;
|
||
width:280px;height:100vh;overflow-y:auto;
|
||
background:#fff;border-right:1px solid var(--bdr);
|
||
padding:24px 18px;flex-shrink:0;
|
||
}
|
||
.sidebar h2{font-size:13px;color:var(--sub);text-transform:uppercase;letter-spacing:1px;margin:0 0 12px;font-weight:600}
|
||
.sidebar .toc{font-size:13px}
|
||
.sidebar .toc ul{list-style:none;padding:0;margin:0}
|
||
.sidebar .toc li{margin:2px 0}
|
||
.sidebar .toc a{
|
||
color:var(--sub);text-decoration:none;
|
||
display:block;padding:5px 10px;border-radius:6px;
|
||
border-left:2px solid transparent;transition:all .12s;
|
||
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
|
||
}
|
||
.sidebar .toc a:hover{background:var(--pri-l);color:var(--pri)}
|
||
.sidebar .toc > ul > li > a{font-weight:600;color:var(--txt);margin-top:8px}
|
||
.sidebar .toc > ul > li > ul a{padding-left:20px;font-size:12px}
|
||
.sidebar .toc > ul > li > ul > li > ul a{padding-left:32px;font-size:11.5px;color:var(--muted)}
|
||
.sidebar .toc a.active{background:var(--pri-l);color:var(--pri);border-left-color:var(--pri);font-weight:600}
|
||
/* Content */
|
||
.content{
|
||
flex:1;padding:40px 48px 120px;
|
||
max-width:100%;overflow-x:hidden;
|
||
}
|
||
.content > :first-child{margin-top:0}
|
||
/* Headings */
|
||
h1,h2,h3,h4,h5{
|
||
font-weight:700;line-height:1.35;
|
||
margin:32px 0 14px;scroll-margin-top:24px;
|
||
}
|
||
h1{
|
||
font-size:30px;padding-bottom:14px;
|
||
border-bottom:3px solid var(--pri);margin-top:0;
|
||
}
|
||
h2{
|
||
font-size:22px;padding-bottom:8px;
|
||
border-bottom:1px solid var(--bdr);
|
||
margin-top:42px;
|
||
}
|
||
h2::before{
|
||
content:"";display:inline-block;
|
||
width:4px;height:20px;background:var(--pri);
|
||
margin-right:10px;vertical-align:-3px;border-radius:2px;
|
||
}
|
||
h3{font-size:17px;margin-top:28px;color:#1e293b}
|
||
h4{font-size:15px;margin-top:20px;color:#334155}
|
||
h5{font-size:14px;color:var(--sub)}
|
||
/* Meta info table (first table) */
|
||
p{margin:10px 0}
|
||
hr{border:none;border-top:1px dashed var(--bdr);margin:36px 0}
|
||
/* Inline code */
|
||
code{
|
||
background:var(--code-bg);color:#be185d;
|
||
padding:2px 6px;border-radius:4px;
|
||
font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
|
||
font-size:.88em;
|
||
}
|
||
pre{
|
||
background:#0f172a;color:#e2e8f0;
|
||
padding:16px 20px;border-radius:10px;overflow-x:auto;
|
||
font-size:13px;line-height:1.6;margin:14px 0;
|
||
}
|
||
pre code{background:transparent;color:inherit;padding:0;font-size:inherit}
|
||
/* Tables */
|
||
table{
|
||
width:100%;border-collapse:collapse;
|
||
margin:14px 0;font-size:13px;
|
||
background:#fff;border-radius:8px;overflow:hidden;
|
||
box-shadow:0 1px 2px rgba(0,0,0,.04);
|
||
border:1px solid var(--bdr);
|
||
}
|
||
th,td{
|
||
padding:10px 14px;text-align:left;
|
||
border-bottom:1px solid var(--bdr);
|
||
vertical-align:top;
|
||
}
|
||
th{
|
||
background:var(--tbl-head);color:var(--sub);
|
||
font-weight:600;font-size:12px;
|
||
text-transform:uppercase;letter-spacing:.5px;
|
||
border-bottom:2px solid var(--bdr);
|
||
}
|
||
tr:last-child td{border-bottom:none}
|
||
tr:hover td{background:#fafbfc}
|
||
/* Lists */
|
||
ul,ol{padding-left:24px;margin:10px 0}
|
||
li{margin:4px 0}
|
||
li > ul,li > ol{margin:4px 0}
|
||
/* Emphasis */
|
||
strong{color:var(--pri);font-weight:600}
|
||
em{color:var(--sub)}
|
||
/* Blockquote */
|
||
blockquote{
|
||
border-left:4px solid var(--pri);
|
||
background:var(--pri-l);
|
||
margin:14px 0;padding:10px 18px;
|
||
color:#3730a3;border-radius:0 8px 8px 0;
|
||
}
|
||
/* Back to top */
|
||
.back-top{
|
||
position:fixed;right:24px;bottom:24px;
|
||
width:44px;height:44px;border-radius:50%;
|
||
background:var(--pri);color:#fff;
|
||
display:flex;align-items:center;justify-content:center;
|
||
font-size:20px;cursor:pointer;border:none;
|
||
box-shadow:0 4px 14px rgba(99,102,241,.4);
|
||
opacity:0;pointer-events:none;transition:opacity .2s;z-index:100;
|
||
}
|
||
.back-top.show{opacity:1;pointer-events:auto}
|
||
/* Print */
|
||
@media print{
|
||
.sidebar,.back-top{display:none}
|
||
.content{padding:0}
|
||
body{background:#fff}
|
||
table{box-shadow:none}
|
||
h1,h2,h3{page-break-after:avoid}
|
||
tr,table{page-break-inside:avoid}
|
||
}
|
||
/* Responsive */
|
||
@media(max-width:960px){
|
||
.layout{flex-direction:column}
|
||
.sidebar{position:static;width:100%;height:auto;max-height:none;border-right:none;border-bottom:1px solid var(--bdr)}
|
||
.content{padding:24px}
|
||
h1{font-size:24px}
|
||
h2{font-size:18px}
|
||
table{font-size:12px}
|
||
th,td{padding:8px 10px}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="layout">
|
||
<aside class="sidebar">
|
||
<h2>📋 文档目录</h2>
|
||
<nav class="toc"><div class="toc">
|
||
<ul>
|
||
<li><a href="#_1">一、产品概述</a><ul>
|
||
<li><a href="#11">1.1 产品定位</a></li>
|
||
<li><a href="#12">1.2 核心能力</a></li>
|
||
<li><a href="#13">1.3 默认账号</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#_2">二、系统模块总览</a></li>
|
||
<li><a href="#rb">三、全局业务规则(RB)</a></li>
|
||
<li><a href="#_3">四、全局交互规范</a><ul>
|
||
<li><a href="#41-toast">4.1 Toast 反馈</a></li>
|
||
<li><a href="#42-modal">4.2 Modal 弹窗</a></li>
|
||
<li><a href="#43">4.3 表格通用</a></li>
|
||
<li><a href="#44">4.4 权限与可见性</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#01">01. 登录页</a><ul>
|
||
<li><a href="#11_1">1.1 页面目标</a></li>
|
||
<li><a href="#12_1">1.2 页面结构</a></li>
|
||
<li><a href="#13_1">1.3 表单字段</a></li>
|
||
<li><a href="#14">1.4 操作细节</a></li>
|
||
<li><a href="#15">1.5 交互规则</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#02">02. 仪表盘(首页)</a><ul>
|
||
<li><a href="#21">2.1 页面目标</a></li>
|
||
<li><a href="#22">2.2 页面结构</a></li>
|
||
<li><a href="#23">2.3 操作细节</a></li>
|
||
<li><a href="#24">2.4 交互规则</a></li>
|
||
<li><a href="#25">2.5 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#03">03. 组织架构</a><ul>
|
||
<li><a href="#31">3.1 页面目标</a></li>
|
||
<li><a href="#32">3.2 页面结构</a></li>
|
||
<li><a href="#33">3.3 数据字段</a></li>
|
||
<li><a href="#34">3.4 操作细节</a></li>
|
||
<li><a href="#35">3.5 表单字段(新增/编辑组织弹窗)</a></li>
|
||
<li><a href="#36">3.6 交互规则</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#04">04. 角色管理</a><ul>
|
||
<li><a href="#41">4.1 页面目标</a></li>
|
||
<li><a href="#42">4.2 页面结构</a></li>
|
||
<li><a href="#43_1">4.3 列表字段</a></li>
|
||
<li><a href="#44_1">4.4 操作细节</a></li>
|
||
<li><a href="#45">4.5 表单字段(弹窗)</a></li>
|
||
<li><a href="#46">4.6 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#05">05. 用户管理</a><ul>
|
||
<li><a href="#51">5.1 页面目标</a></li>
|
||
<li><a href="#52">5.2 页面结构</a></li>
|
||
<li><a href="#53">5.3 操作细节</a></li>
|
||
<li><a href="#54">5.4 表单字段(新增/编辑)</a></li>
|
||
<li><a href="#55">5.5 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#06">06. 产品管理</a><ul>
|
||
<li><a href="#61">6.1 页面目标</a></li>
|
||
<li><a href="#62">6.2 页面结构</a></li>
|
||
<li><a href="#63">6.3 列表字段</a></li>
|
||
<li><a href="#64">6.4 操作细节</a></li>
|
||
<li><a href="#65">6.5 表单字段</a></li>
|
||
<li><a href="#66">6.6 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#07">07. 渠道码管理</a><ul>
|
||
<li><a href="#71">7.1 页面目标</a></li>
|
||
<li><a href="#72">7.2 页面结构</a></li>
|
||
<li><a href="#73">7.3 列表字段</a></li>
|
||
<li><a href="#74">7.4 操作细节</a></li>
|
||
<li><a href="#75">7.5 表单字段(新增/编辑)</a></li>
|
||
<li><a href="#76">7.6 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#08">08. 平台产品账号</a><ul>
|
||
<li><a href="#81">8.1 页面目标</a></li>
|
||
<li><a href="#82">8.2 页面结构</a></li>
|
||
<li><a href="#83">8.3 列表字段</a></li>
|
||
<li><a href="#84">8.4 操作细节</a></li>
|
||
<li><a href="#85">8.5 表单字段</a></li>
|
||
<li><a href="#86">8.6 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#09-skill">09. Skill 管理</a><ul>
|
||
<li><a href="#91">9.1 页面目标</a></li>
|
||
<li><a href="#92">9.2 页面结构</a></li>
|
||
<li><a href="#93">9.3 列表字段</a></li>
|
||
<li><a href="#94">9.4 操作细节</a></li>
|
||
<li><a href="#95">9.5 表单字段</a></li>
|
||
<li><a href="#96">9.6 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#10">10. 任务创建(四步向导)</a><ul>
|
||
<li><a href="#101">10.1 页面目标</a></li>
|
||
<li><a href="#102">10.2 页面结构</a></li>
|
||
<li><a href="#103">10.3 关键字段</a></li>
|
||
<li><a href="#104">10.4 操作细节</a></li>
|
||
<li><a href="#105">10.5 交互规则 / 校验</a></li>
|
||
<li><a href="#106">10.6 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#11_2">11. 任务列表</a><ul>
|
||
<li><a href="#111">11.1 页面目标</a></li>
|
||
<li><a href="#112">11.2 页面结构</a></li>
|
||
<li><a href="#113">11.3 状态枚举</a></li>
|
||
<li><a href="#114">11.4 操作细节</a></li>
|
||
<li><a href="#115">11.5 详情弹窗内容</a></li>
|
||
<li><a href="#116">11.6 按钮显示规则</a></li>
|
||
<li><a href="#117">11.7 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#12_2">12. 菜单管理</a><ul>
|
||
<li><a href="#121">12.1 页面目标</a></li>
|
||
<li><a href="#122">12.2 页面结构</a></li>
|
||
<li><a href="#123">12.3 数据字段</a></li>
|
||
<li><a href="#124">12.4 操作细节</a></li>
|
||
<li><a href="#125">12.5 表单字段</a></li>
|
||
<li><a href="#126">12.6 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#13_2">13. 平台套件</a><ul>
|
||
<li><a href="#131">13.1 页面目标</a></li>
|
||
<li><a href="#132">13.2 页面结构</a></li>
|
||
<li><a href="#133">13.3 数据字段</a></li>
|
||
<li><a href="#134">13.4 操作细节</a></li>
|
||
<li><a href="#135">13.5 表单字段</a></li>
|
||
<li><a href="#136">13.6 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#14-skill">14. Skill 调用日志</a><ul>
|
||
<li><a href="#141">14.1 页面目标</a></li>
|
||
<li><a href="#142">14.2 页面结构</a></li>
|
||
<li><a href="#143">14.3 操作细节</a></li>
|
||
<li><a href="#144">14.4 详情弹窗</a></li>
|
||
<li><a href="#145">14.5 状态枚举</a></li>
|
||
<li><a href="#146">14.6 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#15_1">15. 操作日志(审计)</a><ul>
|
||
<li><a href="#151">15.1 页面目标</a></li>
|
||
<li><a href="#152">15.2 页面结构</a></li>
|
||
<li><a href="#153">15.3 模块与操作枚举</a></li>
|
||
<li><a href="#154">15.4 操作细节</a></li>
|
||
<li><a href="#155">15.5 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#16">16. 统计报表</a><ul>
|
||
<li><a href="#161">16.1 页面目标</a></li>
|
||
<li><a href="#162">16.2 页面结构</a></li>
|
||
<li><a href="#163">16.3 操作细节</a></li>
|
||
<li><a href="#164">16.4 指标示例</a></li>
|
||
<li><a href="#165">16.5 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#17">17. 执行器配置</a><ul>
|
||
<li><a href="#171">17.1 页面目标</a></li>
|
||
<li><a href="#172">17.2 页面结构</a></li>
|
||
<li><a href="#173">17.3 卡片字段</a></li>
|
||
<li><a href="#174">17.4 操作细节</a></li>
|
||
<li><a href="#175">17.5 表单字段</a></li>
|
||
<li><a href="#176">17.6 交互规则</a></li>
|
||
<li><a href="#177">17.7 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#18">18. 脚本模板管理</a><ul>
|
||
<li><a href="#181">18.1 页面目标</a></li>
|
||
<li><a href="#182">18.2 页面结构</a></li>
|
||
<li><a href="#183">18.3 操作细节</a></li>
|
||
<li><a href="#184">18.4 表单字段</a></li>
|
||
<li><a href="#185">18.5 交互规则</a></li>
|
||
<li><a href="#186">18.6 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#19">19. 定时任务</a><ul>
|
||
<li><a href="#191">19.1 页面目标</a></li>
|
||
<li><a href="#192">19.2 页面结构</a></li>
|
||
<li><a href="#193">19.3 操作细节</a></li>
|
||
<li><a href="#194">19.4 表单字段</a></li>
|
||
<li><a href="#195">19.5 执行记录弹窗</a></li>
|
||
<li><a href="#196">19.6 交互规则</a></li>
|
||
<li><a href="#197">19.7 提示反馈</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</nav>
|
||
</aside>
|
||
<main class="content">
|
||
<h1 id="agent-v21-prd">Agent 任务系统 v2.1 产品需求文档(PRD)</h1>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>项</th>
|
||
<th>内容</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>文档版本</td>
|
||
<td>v2.1</td>
|
||
</tr>
|
||
<tr>
|
||
<td>产出时间</td>
|
||
<td>2026-04-24</td>
|
||
</tr>
|
||
<tr>
|
||
<td>产品形态</td>
|
||
<td>Web 管理后台(Next.js 14 + NestJS + PostgreSQL)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>文档来源</td>
|
||
<td>基于高保真原型 <code>agent_task_system_merged.html</code> 反向拆解</td>
|
||
</tr>
|
||
<tr>
|
||
<td>说明</td>
|
||
<td>本文档按模块编写 PRD,每个模块包含:页面目标、页面结构、数据字段、<strong>按钮级操作细节</strong>、表单字段、交互规则、提示反馈</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<hr />
|
||
<h2 id="_1">一、产品概述</h2>
|
||
<h3 id="11">1.1 产品定位</h3>
|
||
<p>企业级 <strong>Agent 任务自动化平台</strong>,提供基于角色权限的 Skill 调度与管理能力,支持龙虾 Agent + 脚本引擎双执行器架构。</p>
|
||
<h3 id="12">1.2 核心能力</h3>
|
||
<ul>
|
||
<li><strong>权限体系</strong>:组织(公司 → 部门 → 小组)→ 角色(部门级)→ 菜单/产品/Skill/账号四维权限</li>
|
||
<li><strong>产品链路</strong>:产品 → 渠道码(内导 + 自然)→ 平台产品账号 → 归属用户</li>
|
||
<li><strong>Skill 中心</strong>:龙虾 Agent + 脚本模板双执行器,支持参数映射与测试台</li>
|
||
<li><strong>任务调度</strong>:四步向导创建任务、交集校验、实时执行、定时调度</li>
|
||
<li><strong>观测能力</strong>:任务列表、Skill 调用日志、操作日志、统计报表</li>
|
||
<li><strong>系统设置</strong>:执行器节点管理、脚本模板库、定时任务</li>
|
||
</ul>
|
||
<h3 id="13">1.3 默认账号</h3>
|
||
<ul>
|
||
<li>用户名:<code>admin</code> / 密码:<code>admin123</code></li>
|
||
<li>登录成功后进入仪表盘</li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="_2">二、系统模块总览</h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>编号</th>
|
||
<th>模块名</th>
|
||
<th>分组</th>
|
||
<th>核心职责</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>01</td>
|
||
<td>登录页</td>
|
||
<td>入口</td>
|
||
<td>账号密码 + 验证码登录</td>
|
||
</tr>
|
||
<tr>
|
||
<td>02</td>
|
||
<td>仪表盘</td>
|
||
<td>首页</td>
|
||
<td>系统运行概览、快捷入口、实时数据</td>
|
||
</tr>
|
||
<tr>
|
||
<td>03</td>
|
||
<td>组织架构</td>
|
||
<td>权限管理</td>
|
||
<td>公司/部门/小组三级树</td>
|
||
</tr>
|
||
<tr>
|
||
<td>04</td>
|
||
<td>角色管理</td>
|
||
<td>权限管理</td>
|
||
<td>部门级角色 + 四维权限配置</td>
|
||
</tr>
|
||
<tr>
|
||
<td>05</td>
|
||
<td>用户管理</td>
|
||
<td>权限管理</td>
|
||
<td>用户 CRUD、多角色绑定、跨部门授权</td>
|
||
</tr>
|
||
<tr>
|
||
<td>12</td>
|
||
<td>菜单管理</td>
|
||
<td>权限管理</td>
|
||
<td>菜单树 + 按钮权限维护</td>
|
||
</tr>
|
||
<tr>
|
||
<td>06</td>
|
||
<td>产品管理</td>
|
||
<td>产品管理</td>
|
||
<td>产品 CRUD、渠道码绑定、批量导入</td>
|
||
</tr>
|
||
<tr>
|
||
<td>07</td>
|
||
<td>渠道码管理</td>
|
||
<td>产品管理</td>
|
||
<td>内导/自然渠道码独立管理、产品绑定</td>
|
||
</tr>
|
||
<tr>
|
||
<td>13</td>
|
||
<td>平台套件</td>
|
||
<td>产品管理</td>
|
||
<td>平台 + 产品代号两级关系维护</td>
|
||
</tr>
|
||
<tr>
|
||
<td>08</td>
|
||
<td>平台产品账号</td>
|
||
<td>平台账号</td>
|
||
<td>用户自管平台登录凭据、连通测试</td>
|
||
</tr>
|
||
<tr>
|
||
<td>09</td>
|
||
<td>Skill 管理</td>
|
||
<td>Skill 中心</td>
|
||
<td>双执行器 Skill 注册、参数映射、测试</td>
|
||
</tr>
|
||
<tr>
|
||
<td>14</td>
|
||
<td>Skill 调用日志</td>
|
||
<td>Skill 中心</td>
|
||
<td>历史调用审计、详情与日志回放</td>
|
||
</tr>
|
||
<tr>
|
||
<td>10</td>
|
||
<td>任务创建</td>
|
||
<td>任务中心</td>
|
||
<td>四步向导:Skill → 产品 → 参数 → 确认</td>
|
||
</tr>
|
||
<tr>
|
||
<td>11</td>
|
||
<td>任务列表</td>
|
||
<td>任务中心</td>
|
||
<td>任务检索、取消、重试、详情查看</td>
|
||
</tr>
|
||
<tr>
|
||
<td>15</td>
|
||
<td>操作日志</td>
|
||
<td>日志</td>
|
||
<td>系统增删改 + 登录审计</td>
|
||
</tr>
|
||
<tr>
|
||
<td>16</td>
|
||
<td>统计报表</td>
|
||
<td>日志</td>
|
||
<td>多维度可视化统计</td>
|
||
</tr>
|
||
<tr>
|
||
<td>17</td>
|
||
<td>执行器配置</td>
|
||
<td>系统设置</td>
|
||
<td>龙虾/脚本执行器节点配置</td>
|
||
</tr>
|
||
<tr>
|
||
<td>18</td>
|
||
<td>脚本模板管理</td>
|
||
<td>系统设置</td>
|
||
<td>Python/Node/Shell 模板库</td>
|
||
</tr>
|
||
<tr>
|
||
<td>19</td>
|
||
<td>定时任务</td>
|
||
<td>系统设置</td>
|
||
<td>Cron 调度、执行记录、手动触发</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<hr />
|
||
<h2 id="rb">三、全局业务规则(RB)</h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>编号</th>
|
||
<th>规则</th>
|
||
<th>说明</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>RB-01</td>
|
||
<td>角色归属部门</td>
|
||
<td>角色分"全局角色"与"部门级角色",部门级角色仅在所属部门内可选</td>
|
||
</tr>
|
||
<tr>
|
||
<td>RB-02</td>
|
||
<td>用户多角色取并集</td>
|
||
<td>用户可绑定多个角色,有效权限 = ∪ 所有角色的权限</td>
|
||
</tr>
|
||
<tr>
|
||
<td>RB-03</td>
|
||
<td>密码规则</td>
|
||
<td>至少 6 位;重置后原 Token 失效</td>
|
||
</tr>
|
||
<tr>
|
||
<td>RB-04</td>
|
||
<td>删除用户级联</td>
|
||
<td>用户删除后,角色绑定与平台产品账号一并清除</td>
|
||
</tr>
|
||
<tr>
|
||
<td>RB-06</td>
|
||
<td>菜单权限</td>
|
||
<td>角色的菜单权限决定左侧导航可见项</td>
|
||
</tr>
|
||
<tr>
|
||
<td>RB-07</td>
|
||
<td>Skill 权限并集</td>
|
||
<td>任务创建仅展示当前用户所有角色 <code>skill_scope</code> 的并集</td>
|
||
</tr>
|
||
<tr>
|
||
<td>RB-08</td>
|
||
<td>部门切换清空角色</td>
|
||
<td>用户切换部门时自动清空已选角色(避免权限跨部门带入)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>RB-09</td>
|
||
<td>渠道码必填</td>
|
||
<td>新建产品时 <code>内导渠道码</code> 与 <code>自然渠道码</code> 均必填</td>
|
||
</tr>
|
||
<tr>
|
||
<td>RB-12</td>
|
||
<td>产品范围交集校验</td>
|
||
<td>任务可选产品 = <code>Skill.product_scope</code> ∩ <code>用户角色.data_scope</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>RB-13</td>
|
||
<td>执行器类型二选一</td>
|
||
<td>Skill 的执行器 = 龙虾 Agent 或 脚本模板(互斥);执行器配置仅超级管理员可改</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<hr />
|
||
<h2 id="_3">四、全局交互规范</h2>
|
||
<h3 id="41-toast">4.1 Toast 反馈</h3>
|
||
<ul>
|
||
<li>成功:绿底绿字(<code>#dcfce7</code> / <code>#166534</code>),文案格式 <code>✅ xxx 成功</code></li>
|
||
<li>错误:红底红字(<code>#fee2e2</code> / <code>#991b1b</code>),文案格式 <code>❌ xxx</code> 或 <code>请输入 xxx</code></li>
|
||
<li>显示时长:2.5 秒自动隐藏,从顶部透明下滑渐现</li>
|
||
</ul>
|
||
<h3 id="42-modal">4.2 Modal 弹窗</h3>
|
||
<ul>
|
||
<li>所有模态框右上角提供 <code>✕</code> 关闭</li>
|
||
<li>点击半透明遮罩关闭弹窗</li>
|
||
<li>保存按钮通常位于页脚右侧(主按钮紫色 <code>#6366f1</code>),取消按钮左侧(灰色边框)</li>
|
||
<li>删除确认弹窗独立样式:红色主按钮、🗑️ 图标、说明"此操作不可恢复"</li>
|
||
</ul>
|
||
<h3 id="43">4.3 表格通用</h3>
|
||
<ul>
|
||
<li>表头支持批量选择(复选框)</li>
|
||
<li>行内操作列放在最右:常见为 <code>编辑 / 删除 / 其他</code></li>
|
||
<li>搜索 + 下拉筛选均实时触发(<code>oninput</code> / <code>onchange</code> → <code>filterT()</code>)</li>
|
||
<li>分页栏位于底部:<code>共 X 条</code> + 页码</li>
|
||
</ul>
|
||
<h3 id="44">4.4 权限与可见性</h3>
|
||
<ul>
|
||
<li>左侧菜单由当前角色的 <code>menu_scope</code> 决定(RB-06)</li>
|
||
<li>按钮级权限由 <code>button_code</code> 决定(如 <code>product:create</code>)</li>
|
||
<li>超级管理员 (<code>super_admin</code>) 可见全部模块</li>
|
||
</ul>
|
||
<hr />
|
||
<h1 id="prd">五、模块 PRD 详情</h1>
|
||
<hr />
|
||
<h2 id="01">01. 登录页</h2>
|
||
<h3 id="11_1">1.1 页面目标</h3>
|
||
<p>通过账号密码(+ 验证码)验证用户身份,登录成功后签发 JWT Token 并跳转仪表盘。</p>
|
||
<h3 id="12_1">1.2 页面结构</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>区块</th>
|
||
<th>内容</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>左侧品牌区</td>
|
||
<td>产品名 <code>🤖 Agent任务系统</code>、Slogan、4 条核心特性</td>
|
||
</tr>
|
||
<tr>
|
||
<td>右侧登录表单</td>
|
||
<td>标题、欢迎语、用户名 / 密码 / 验证码输入、选项栏、登录按钮、页脚</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Toast 反馈区</td>
|
||
<td>右上角,登录结果提示</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="13_1">1.3 表单字段</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>默认</th>
|
||
<th>校验</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>用户名 / 邮箱</td>
|
||
<td>text</td>
|
||
<td>是</td>
|
||
<td><code>admin</code></td>
|
||
<td>非空,否则显示"请输入用户名"</td>
|
||
</tr>
|
||
<tr>
|
||
<td>密码</td>
|
||
<td>password</td>
|
||
<td>是</td>
|
||
<td><code>admin123</code></td>
|
||
<td>非空,否则显示"请输入密码"</td>
|
||
</tr>
|
||
<tr>
|
||
<td>验证码</td>
|
||
<td>text(4 位)</td>
|
||
<td>否(前端未强制)</td>
|
||
<td>空</td>
|
||
<td>最多 4 位</td>
|
||
</tr>
|
||
<tr>
|
||
<td>记住登录</td>
|
||
<td>checkbox</td>
|
||
<td>否</td>
|
||
<td>已勾选</td>
|
||
<td>—</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="14">1.4 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>验证码图片</td>
|
||
<td><code>A7X2</code> 验证码图</td>
|
||
<td>点击刷新验证码(随机生成 4 位大写字母数字,排除易混字符)</td>
|
||
<td>始终可用</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>选项栏</td>
|
||
<td>忘记密码?</td>
|
||
<td>Toast:<code>请联系管理员重置密码</code></td>
|
||
<td>始终可用</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>表单页脚</td>
|
||
<td><code>登 录</code></td>
|
||
<td>1. 前端校验用户名/密码非空;2. 置 disabled + loading;3. 1.5s 后:若 <code>admin/admin123</code> → Toast <code>✅ 登录成功!正在跳转...</code> + 1s 后 <code>postMessage('login-success')</code> 通知父容器;否则 → Toast <code>❌ 用户名或密码错误</code> + 刷新验证码</td>
|
||
<td>校验通过后</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="15">1.5 交互规则</h3>
|
||
<ul>
|
||
<li>登录接口失败时,清空验证码并刷新</li>
|
||
<li>嵌入 iframe 中时通过 <code>window.parent.postMessage('login-success','*')</code> 通知宿主应用展开侧边栏并跳转仪表盘</li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="02">02. 仪表盘(首页)</h2>
|
||
<h3 id="21">2.1 页面目标</h3>
|
||
<p>系统运行概览 + 实时数据统计 + 快捷入口,提供用户日常首屏视图。</p>
|
||
<h3 id="22">2.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>面包屑 + 用户信息</strong> 顶栏</li>
|
||
<li><strong>快捷入口区</strong>:4 个方块(创建任务 / 管理 Skill / 平台账号 / 任务列表)</li>
|
||
<li><strong>今日指标卡</strong>:6 张卡(今日任务总数 / 成功 / 失败 / 运行中 / 活跃用户 / 已注册 Skill)</li>
|
||
<li><strong>图表行 1</strong>:最近 7 天任务趋势(柱状图)+ 执行器分布(环形 Legend)</li>
|
||
<li><strong>图表行 2</strong>:热门 Skill Top 5 + 部门任务统计(进度条)</li>
|
||
<li><strong>最新任务动态</strong>:任务列表(8 行,ID / Skill / 执行器 / 产品 / 创建人 / 状态 / 耗时 / 时间)</li>
|
||
<li><strong>系统状态</strong>:4 组(龙虾 / 脚本引擎 / 数据库 / 消息队列)</li>
|
||
</ol>
|
||
<h3 id="23">2.3 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>快捷入口</td>
|
||
<td>⚡ 创建任务</td>
|
||
<td>跳转"10. 任务创建"</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>快捷入口</td>
|
||
<td>🧩 管理 Skill</td>
|
||
<td>跳转"09. Skill 管理"</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>快捷入口</td>
|
||
<td>🔗 平台账号</td>
|
||
<td>跳转"08. 平台产品账号"</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>快捷入口</td>
|
||
<td>📋 任务列表</td>
|
||
<td>跳转"11. 任务列表"</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>最新任务动态</td>
|
||
<td>查看全部 →</td>
|
||
<td>跳转"11. 任务列表"</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>图表柱子</td>
|
||
<td>柱子 hover</td>
|
||
<td>高亮对应柱子并展示数值</td>
|
||
<td>鼠标悬停</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="24">2.4 交互规则</h3>
|
||
<ul>
|
||
<li>柱状图进入视图后自带高度缓动动画(100ms 起)</li>
|
||
<li>每 3 秒模拟一次实时刷新:有 30% 概率 <code>今日任务总数 +1</code>,其中 80% 加到"成功",20% 加到"失败"</li>
|
||
<li>指标卡 hover 显示轻微阴影提升</li>
|
||
</ul>
|
||
<h3 id="25">2.5 提示反馈</h3>
|
||
<ul>
|
||
<li>无负面反馈(只读页面)</li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="03">03. 组织架构</h2>
|
||
<h3 id="31">3.1 页面目标</h3>
|
||
<p>维护 <code>公司 → 部门 → 小组</code> 三级树形结构,部门节点挂载角色与成员。</p>
|
||
<h3 id="32">3.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>左栏 · 组织树</strong>:搜索框 + 树(含展开/收起、当前选中高亮、新增按钮)</li>
|
||
<li><strong>右栏 · 详情面板</strong>:组织信息(类型 / 成员数 / 下辖组数 / 负责人 / 状态 / 创建时间)+ 编辑/删除按钮</li>
|
||
<li><strong>部门角色列表</strong>:角色名称 / 角色编码 / 成员数 / Skill 数 / 状态</li>
|
||
<li><strong>部门成员列表</strong>:姓名 / 工号 / 所属小组 / 角色 / 入职日期 / 状态 + 导出按钮</li>
|
||
<li><strong>弹窗</strong>:新增/编辑组织、确认删除</li>
|
||
</ol>
|
||
<h3 id="33">3.3 数据字段</h3>
|
||
<ul>
|
||
<li>组织树节点:组织名、图标(🏢 公司 / 🏬 部门 / 👥 小组)、成员数徽章</li>
|
||
<li>详情:类型(公司/部门/小组)、成员数、下辖组数、负责人、状态、创建时间</li>
|
||
<li>角色列表列:角色名称、角色编码、成员数、Skill 数、状态</li>
|
||
<li>成员列表列:姓名、工号、所属小组、角色(多标签)、入职日期、状态</li>
|
||
</ul>
|
||
<h3 id="34">3.4 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>组织树卡头</td>
|
||
<td>+ 新增</td>
|
||
<td>打开 <code>新增组织</code> 弹窗</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>树节点</td>
|
||
<td>▼/▶ 折叠符</td>
|
||
<td><code>toggleTree()</code> 切换子节点展开/折叠</td>
|
||
<td>节点有子项</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>树节点</td>
|
||
<td>节点行</td>
|
||
<td><code>selectOrg()</code> 选中该节点、更新右侧详情面板(类型/成员/下辖组/徽章)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>详情面板</td>
|
||
<td>编辑</td>
|
||
<td>打开 <code>编辑组织</code> 弹窗(标题动态)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>详情面板</td>
|
||
<td>删除</td>
|
||
<td>打开 <code>⚠️ 确认删除</code> 弹窗</td>
|
||
<td>始终</td>
|
||
<td>有</td>
|
||
</tr>
|
||
<tr>
|
||
<td>成员列表</td>
|
||
<td>导出</td>
|
||
<td>导出当前部门成员(CSV)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>删除弹窗</td>
|
||
<td>确认删除</td>
|
||
<td>Toast <code>已删除</code>,关闭弹窗;子部门/人员自动移至上级</td>
|
||
<td>始终</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>新增/编辑弹窗</td>
|
||
<td>保存</td>
|
||
<td>Toast <code>保存成功</code>,关闭</td>
|
||
<td>校验通过</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>新增/编辑弹窗</td>
|
||
<td>取消 / ✕</td>
|
||
<td>关闭不保存</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="35">3.5 表单字段(新增/编辑组织弹窗)</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>默认</th>
|
||
<th>选项</th>
|
||
<th>备注</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>上级组织</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>星辰科技有限公司</td>
|
||
<td>公司/部门下拉</td>
|
||
<td>根节点无上级</td>
|
||
</tr>
|
||
<tr>
|
||
<td>组织名称</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
<td>—</td>
|
||
<td>非空</td>
|
||
</tr>
|
||
<tr>
|
||
<td>组织类型</td>
|
||
<td>select</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
<td>公司 / 部门 / 小组</td>
|
||
<td>必选</td>
|
||
</tr>
|
||
<tr>
|
||
<td>负责人</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>—</td>
|
||
<td>用户列表</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>排序号</td>
|
||
<td>number</td>
|
||
<td>否</td>
|
||
<td>0</td>
|
||
<td>—</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>状态</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>启用</td>
|
||
<td>启用 / 禁用</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>备注</td>
|
||
<td>textarea(2 行)</td>
|
||
<td>否</td>
|
||
<td>—</td>
|
||
<td>—</td>
|
||
<td>—</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="36">3.6 交互规则</h3>
|
||
<ul>
|
||
<li>删除节点时提示"删除后该组织下的子部门和人员将移至上级组织"</li>
|
||
<li>树节点高亮通过 <code>.sel</code> 类控制</li>
|
||
<li>搜索框实时过滤树节点(前端)</li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="04">04. 角色管理</h2>
|
||
<h3 id="41">4.1 页面目标</h3>
|
||
<p>部门级角色管理,通过 4 个维度配置权限(菜单 + 产品范围 + Skill + 平台账号),支持多角色并集。</p>
|
||
<h3 id="42">4.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>筛选栏</strong>:搜索框(角色名/编码)+ 部门下拉 + 状态下拉 + <code>+ 新增角色</code> 按钮</li>
|
||
<li><strong>角色列表</strong>:表格 10 列(含批量 checkbox)</li>
|
||
<li><strong>新增/编辑弹窗</strong>:4 个 Tab</li>
|
||
<li><strong>业务规则说明卡</strong>:RB-01 ~ RB-06</li>
|
||
</ol>
|
||
<h3 id="43_1">4.3 列表字段</h3>
|
||
<p>复选框、角色名称、角色编码、所属部门、菜单权限(X 项/全部)、产品范围(X 个/全部)、Skill 数、平台账号(X 个/全部)、成员数、状态、操作</p>
|
||
<h3 id="44_1">4.4 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>+ 新增角色</td>
|
||
<td>打开弹窗,标题 <code>新增角色</code>、表单清空</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>编辑</td>
|
||
<td>打开弹窗,标题 <code>编辑角色 — {名}</code>,回填</td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>删除</td>
|
||
<td>删除(超级管理员行隐藏此按钮)</td>
|
||
<td>每行(非 super_admin)</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗 Tab</td>
|
||
<td>📋 菜单权限 / 📦 产品范围 / 🧩 Skill 权限 / 🔗 平台账号</td>
|
||
<td><code>switchRoleTab(i)</code> 切换</td>
|
||
<td>弹窗打开时</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>菜单权限 Tab</td>
|
||
<td>全选 checkbox</td>
|
||
<td>级联选中所有子菜单</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗</td>
|
||
<td>取消 / ✕</td>
|
||
<td>关闭</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗</td>
|
||
<td>保存</td>
|
||
<td>Toast <code>保存成功</code>、关闭</td>
|
||
<td>必填校验通过</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>表头</td>
|
||
<td>全选 checkbox</td>
|
||
<td>批量勾选所有行</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="45">4.5 表单字段(弹窗)</h3>
|
||
<p><strong>基本信息(表单顶部,非 Tab 内)</strong></p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>选项</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>角色名称</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>角色编码</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td>唯一</td>
|
||
</tr>
|
||
<tr>
|
||
<td>所属部门</td>
|
||
<td>select</td>
|
||
<td>是</td>
|
||
<td>投放部 / 运营部 / 技术部 / 产品部</td>
|
||
</tr>
|
||
<tr>
|
||
<td>状态</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>启用 / 禁用</td>
|
||
</tr>
|
||
<tr>
|
||
<td>描述</td>
|
||
<td>textarea</td>
|
||
<td>否</td>
|
||
<td>—</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Tab 0 菜单权限</strong>:菜单树 + 全选 checkbox,一级包含:首页、权限管理、产品管理、Skill 中心、任务中心。</p>
|
||
<p><strong>Tab 1 产品范围</strong>:多选 checkbox,选项 <code>ProductA ~ ProductD</code>。</p>
|
||
<p><strong>Tab 2 Skill 权限</strong>:多选 checkbox,选项:竞品分析 Agent、数据采集脚本、素材生成 Agent、评论监控脚本、投放优化 Agent、价格监控 Agent。</p>
|
||
<p><strong>Tab 3 平台账号</strong>:表格(平台 / 账号 / 状态 / 绑定 checkbox)。</p>
|
||
<h3 id="46">4.6 提示反馈</h3>
|
||
<ul>
|
||
<li>成功:<code>保存成功</code></li>
|
||
<li>失败:输入非空校验不通过时显示 <code>请输入角色名称</code> 等</li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="05">05. 用户管理</h2>
|
||
<h3 id="51">5.1 页面目标</h3>
|
||
<p>用户 CRUD、部门-角色联动、跨组协作的额外产品授权、多角色绑定。</p>
|
||
<h3 id="52">5.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>筛选栏</strong>:搜索框 + 部门/角色/状态下拉 + 导出 + <code>+ 新增用户</code></li>
|
||
<li><strong>用户列表</strong>:表格(复选框、用户名、工号、所属部门/分组、角色、平台产品账号数、额外授权数、状态、创建时间、操作)</li>
|
||
<li><strong>新增/编辑用户弹窗</strong></li>
|
||
<li><strong>重置密码弹窗</strong> / <strong>删除确认弹窗</strong></li>
|
||
<li><strong>业务规则说明</strong>:RB-02、RB-03、RB-04、RB-08</li>
|
||
</ol>
|
||
<h3 id="53">5.3 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>导出</td>
|
||
<td>导出用户列表(CSV)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>+ 新增用户</td>
|
||
<td>打开新增弹窗(清空)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>编辑</td>
|
||
<td>打开编辑弹窗(回填)</td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>重置密码</td>
|
||
<td>打开重置密码弹窗</td>
|
||
<td>每行</td>
|
||
<td>是(弹窗内)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>删除</td>
|
||
<td>打开删除确认弹窗</td>
|
||
<td>每行</td>
|
||
<td>是(弹窗内)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>表头</td>
|
||
<td>全选 checkbox</td>
|
||
<td>批量选中所有行</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>编辑弹窗·部门</td>
|
||
<td>select change</td>
|
||
<td><code>onDeptChange()</code>:清空已选角色、刷新角色列表、Toast <code>⚠️ 已切换部门,角色已清空(RB-08)</code></td>
|
||
<td>切换部门</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>编辑弹窗·角色</td>
|
||
<td>多选框</td>
|
||
<td>展开下拉,勾选/取消角色</td>
|
||
<td>已选部门</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>编辑弹窗</td>
|
||
<td>+ 添加授权</td>
|
||
<td><code>addGrant()</code> 追加一行(产品 select + 有效期 date + 删除按钮)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>编辑弹窗·授权行</td>
|
||
<td>删除</td>
|
||
<td>移除该授权行</td>
|
||
<td>行存在</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>编辑弹窗</td>
|
||
<td>取消</td>
|
||
<td>关闭</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>编辑弹窗</td>
|
||
<td>保存</td>
|
||
<td>校验后 Toast <code>✅ 保存成功</code></td>
|
||
<td>必填通过</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>重置密码弹窗</td>
|
||
<td>确认重置</td>
|
||
<td>Toast <code>✅ 密码已重置</code>;原 Token 失效</td>
|
||
<td>两次密码一致</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>删除确认弹窗</td>
|
||
<td>确认删除</td>
|
||
<td>Toast <code>✅ 已删除</code>;级联清除角色绑定与账号</td>
|
||
<td>始终</td>
|
||
<td>—</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="54">5.4 表单字段(新增/编辑)</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>默认</th>
|
||
<th>说明</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>用户名</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
<td>唯一</td>
|
||
</tr>
|
||
<tr>
|
||
<td>密码</td>
|
||
<td>password</td>
|
||
<td>是(新增时)</td>
|
||
<td>—</td>
|
||
<td>至少 6 位(RB-03)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>邮箱</td>
|
||
<td>email</td>
|
||
<td>否</td>
|
||
<td>—</td>
|
||
<td>格式校验</td>
|
||
</tr>
|
||
<tr>
|
||
<td>手机号</td>
|
||
<td>tel</td>
|
||
<td>否</td>
|
||
<td>—</td>
|
||
<td>格式校验</td>
|
||
</tr>
|
||
<tr>
|
||
<td>所属部门</td>
|
||
<td>select</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
<td>tf/yy/tech/pm</td>
|
||
</tr>
|
||
<tr>
|
||
<td>状态</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>启用</td>
|
||
<td>启用 / 禁用</td>
|
||
</tr>
|
||
<tr>
|
||
<td>绑定角色</td>
|
||
<td>multi-select</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
<td>根据部门动态加载,至少选 1 个</td>
|
||
</tr>
|
||
<tr>
|
||
<td>额外产品授权</td>
|
||
<td>动态行(产品 select + 有效期 date)</td>
|
||
<td>否</td>
|
||
<td>空</td>
|
||
<td>跨部门/小组协作用(RB-02 并集)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>部门-角色联动字典</strong>:
|
||
- tf(投放部)→ 投放主管、投放专员、数据分析师
|
||
- yy(运营部)→ 运营主管、运营专员
|
||
- tech(技术部)→ 开发工程师、运维工程师、测试工程师
|
||
- pm(产品部)→ 产品经理、UI 设计师</p>
|
||
<h3 id="55">5.5 提示反馈</h3>
|
||
<ul>
|
||
<li>保存成功 / 已删除 / 密码已重置(绿色)</li>
|
||
<li><code>请输入用户名</code> / <code>请至少选择一个角色</code> / <code>⚠️ 已切换部门,角色已清空(RB-08)</code>(红色)</li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="06">06. 产品管理</h2>
|
||
<h3 id="61">6.1 页面目标</h3>
|
||
<p>产品 CRUD、渠道码(内导/自然)必填绑定、CSV 批量导入、多维筛选。</p>
|
||
<h3 id="62">6.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>统计卡</strong>:产品总数 / 启用中 / 已禁用 / 平台数</li>
|
||
<li><strong>筛选栏</strong>:搜索 + 平台/部门/状态下拉 + 导出 + 📤 导入 + <code>+ 新增产品</code></li>
|
||
<li><strong>产品列表</strong>:8 列 + 操作</li>
|
||
<li><strong>新增/编辑弹窗</strong> / <strong>批量导入弹窗</strong> / <strong>删除确认弹窗</strong></li>
|
||
</ol>
|
||
<h3 id="63">6.3 列表字段</h3>
|
||
<p>复选框、产品名称、产品代号(唯一)、平台、部门/小组、内导渠道码(如 <code>IC001</code>)、自然渠道码(如 <code>NC001</code>)、负责人、状态</p>
|
||
<h3 id="64">6.4 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>导出</td>
|
||
<td>Toast <code>📥 导出成功</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>📤 导入</td>
|
||
<td>打开 <code>批量导入产品</code> 弹窗</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>+ 新增产品</td>
|
||
<td>打开新增弹窗</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>编辑 / 删除</td>
|
||
<td>同模式</td>
|
||
<td>每行</td>
|
||
<td>删除是</td>
|
||
</tr>
|
||
<tr>
|
||
<td>导入弹窗</td>
|
||
<td>上传区</td>
|
||
<td><code>fileInput.click()</code> 触发文件选择</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>导入弹窗</td>
|
||
<td>清除文件</td>
|
||
<td>清空已选文件,禁用 <code>开始导入</code></td>
|
||
<td>文件已选</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>导入弹窗</td>
|
||
<td>📥 下载导入模板</td>
|
||
<td>Toast <code>📥 模板已下载</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>导入弹窗</td>
|
||
<td>开始导入</td>
|
||
<td>Toast <code>✅ 成功导入 21 条,覆盖 2 条</code></td>
|
||
<td>文件已选</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>导入弹窗</td>
|
||
<td>取消</td>
|
||
<td>关闭</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>新增/编辑弹窗</td>
|
||
<td>保存</td>
|
||
<td>校验渠道码必填(RB-09),Toast <code>✅ 保存成功</code></td>
|
||
<td>校验通过</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="65">6.5 表单字段</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>选项</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>产品名称</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>产品代号</td>
|
||
<td>input</td>
|
||
<td>是(唯一)</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>所属平台</td>
|
||
<td>select</td>
|
||
<td>是</td>
|
||
<td>小红书 / 抖音 / 微信公众号 / 微博 / Facebook / TikTok</td>
|
||
</tr>
|
||
<tr>
|
||
<td>所属部门</td>
|
||
<td>select</td>
|
||
<td>是</td>
|
||
<td>投放部 / 运营部 / 技术部</td>
|
||
</tr>
|
||
<tr>
|
||
<td>所属小组</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>投放一/二组、内容运营组 等</td>
|
||
</tr>
|
||
<tr>
|
||
<td>负责人</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>用户列表</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>内导渠道码</strong></td>
|
||
<td>input</td>
|
||
<td><strong>是(RB-09)</strong></td>
|
||
<td>唯一</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>自然渠道码</strong></td>
|
||
<td>input</td>
|
||
<td><strong>是(RB-09)</strong></td>
|
||
<td>唯一</td>
|
||
</tr>
|
||
<tr>
|
||
<td>状态</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>启用 / 禁用</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="66">6.6 提示反馈</h3>
|
||
<ul>
|
||
<li>成功:<code>✅ 保存成功</code> / <code>✅ 成功导入 X 条,覆盖 Y 条</code></li>
|
||
<li>失败:<code>内导渠道码必填(RB-09)</code> / <code>自然渠道码必填(RB-09)</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="07">07. 渠道码管理</h2>
|
||
<h3 id="71">7.1 页面目标</h3>
|
||
<p>按 Tab 分别管理 <strong>内导渠道码</strong> 与 <strong>自然渠道码</strong>,支持与产品的双向绑定。</p>
|
||
<h3 id="72">7.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>统计卡</strong>:渠道码总数 / 内导数 / 自然数 / 关联产品数</li>
|
||
<li><strong>Tab</strong>:内导渠道码 | 自然渠道码(互斥显示)</li>
|
||
<li>每个 Tab 内:搜索 + 状态下拉 + <code>+ 新增 {类型} 渠道码</code> + 列表</li>
|
||
<li><strong>新增/编辑渠道码弹窗</strong> / <strong>绑定产品弹窗</strong> / <strong>删除确认弹窗</strong></li>
|
||
</ol>
|
||
<h3 id="73">7.3 列表字段</h3>
|
||
<p>渠道码(<code>IC001</code> 代码样式)、渠道名称、类型(内导/自然)、关联产品数、状态、创建时间、操作(编辑 / 绑定 / 删除)</p>
|
||
<h3 id="74">7.4 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Tab</td>
|
||
<td>内导 / 自然</td>
|
||
<td><code>switchTab(i)</code> 切换列表</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Tab 头</td>
|
||
<td>+ 新增内导/自然渠道码</td>
|
||
<td>打开新增弹窗(type 预设)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>编辑 / 绑定 / 删除</td>
|
||
<td>分别打开对应弹窗</td>
|
||
<td>每行</td>
|
||
<td>删除是</td>
|
||
</tr>
|
||
<tr>
|
||
<td>绑定弹窗</td>
|
||
<td>解绑(每行)</td>
|
||
<td>移除该产品绑定,Toast <code>已解绑</code></td>
|
||
<td>存在绑定</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>绑定弹窗</td>
|
||
<td>绑定</td>
|
||
<td>将下拉选中产品加入已绑定列表,Toast <code>✅ 绑定成功</code></td>
|
||
<td>选中产品</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>绑定弹窗</td>
|
||
<td>关闭</td>
|
||
<td>关闭</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="75">7.5 表单字段(新增/编辑)</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>选项</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>渠道码</td>
|
||
<td>input</td>
|
||
<td>是(唯一)</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>渠道名称</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>渠道类型</td>
|
||
<td>select</td>
|
||
<td>是</td>
|
||
<td>内导(internal)/ 自然(natural)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>状态</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>启用 / 禁用</td>
|
||
</tr>
|
||
<tr>
|
||
<td>备注</td>
|
||
<td>input</td>
|
||
<td>否</td>
|
||
<td>—</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="76">7.6 提示反馈</h3>
|
||
<ul>
|
||
<li><code>✅ 保存成功</code> / <code>✅ 绑定成功</code> / <code>已解绑</code></li>
|
||
<li><code>请输入渠道码</code> / <code>请输入渠道名称</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="08">08. 平台产品账号</h2>
|
||
<h3 id="81">8.1 页面目标</h3>
|
||
<p><strong>v2.1 变更</strong>:平台产品账号归属 <strong>用户</strong>(非角色),由用户自行维护各平台登录凭据,支持连通测试。</p>
|
||
<h3 id="82">8.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>变更说明条</strong>(顶部 note)</li>
|
||
<li><strong>统计卡</strong>:我的账号总数 / 启用中 / 已禁用 / 覆盖平台</li>
|
||
<li><strong>筛选栏</strong>:搜索 + 平台/状态下拉 + <code>+ 添加平台产品账号</code></li>
|
||
<li><strong>账号列表</strong>:6 行、8 列</li>
|
||
<li><strong>新增/编辑弹窗</strong>(含密码加密显示 + 连通测试)</li>
|
||
<li><strong>连通测试结果弹窗</strong> / <strong>删除确认弹窗</strong></li>
|
||
</ol>
|
||
<h3 id="83">8.3 列表字段</h3>
|
||
<p>平台(图标+文字)、平台地址(URL)、产品代号(<code>PROD001</code>)、产品名称、登录账号、登录密码(<code>●●●●●●</code>)、谷歌密钥(<code>●●●●5A2F</code> 部分显示)、状态</p>
|
||
<h3 id="84">8.4 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>+ 添加平台产品账号</td>
|
||
<td>打开新增弹窗</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>编辑</td>
|
||
<td>打开编辑弹窗,<code>openEdit(plat, code, login)</code> 回填</td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>测试</td>
|
||
<td>执行连通测试,打开测试结果弹窗(随机成功/失败)</td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>删除</td>
|
||
<td>打开删除弹窗(有任务引用的账号禁止删除)</td>
|
||
<td>每行</td>
|
||
<td>是</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗</td>
|
||
<td>选择平台(select)</td>
|
||
<td><code>onPlatChange()</code> 自动填充平台名/地址、按平台过滤产品列表</td>
|
||
<td>始终</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗</td>
|
||
<td>👁️ 显示/隐藏密码</td>
|
||
<td><code>togglePwd()</code> 切换密码字段 <code>type=password↔text</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗</td>
|
||
<td>🔌 连通测试</td>
|
||
<td>1.5s 后随机 Toast <code>✅ 连通成功!</code> 或 <code>连通失败</code></td>
|
||
<td>平台/账号已填</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗</td>
|
||
<td>保存 / 取消</td>
|
||
<td>保存后 <code>✅ 保存成功</code></td>
|
||
<td>校验通过</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="85">8.5 表单字段</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>说明</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>选择平台</td>
|
||
<td>select</td>
|
||
<td>是</td>
|
||
<td>小红书(xhs) / 抖音(dy) / 微信公众号(wx) / 微博(wb) / Facebook(fb) / TikTok(tt)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>平台名称</td>
|
||
<td>input readonly</td>
|
||
<td>—</td>
|
||
<td>随平台联动</td>
|
||
</tr>
|
||
<tr>
|
||
<td>平台地址</td>
|
||
<td>input readonly</td>
|
||
<td>—</td>
|
||
<td>随平台联动(如 <code>pro.xiaohongshu.com</code>)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>产品代号</td>
|
||
<td>select</td>
|
||
<td>是</td>
|
||
<td>按所选平台 + 用户 <code>data_scope</code> 动态加载</td>
|
||
</tr>
|
||
<tr>
|
||
<td>登录账号</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>登录密码</td>
|
||
<td>password</td>
|
||
<td>是</td>
|
||
<td>👁️ 可切换显隐</td>
|
||
</tr>
|
||
<tr>
|
||
<td>谷歌密钥(2FA)</td>
|
||
<td>password</td>
|
||
<td>否</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>状态</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>启用 / 禁用</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>平台信息字典(PLAT_INFO)</strong>:
|
||
- <code>xhs</code> → 小红书 / <code>pro.xiaohongshu.com</code> / 产品 <code>[PROD001, PROD002]</code>
|
||
- <code>dy</code> → 抖音 / <code>business.douyin.com</code> / <code>[PROD003, PROD004]</code>
|
||
- <code>wx</code> → 微信公众号 / <code>mp.weixin.qq.com</code> / <code>[PROD005]</code>
|
||
- <code>wb</code> → 微博 / <code>weibo.com</code> / <code>[PROD008]</code>
|
||
- <code>fb</code> → Facebook / <code>business.facebook.com</code> / <code>[PROD006]</code>
|
||
- <code>tt</code> → TikTok / <code>ads.tiktok.com</code> / <code>[PROD007]</code></p>
|
||
<h3 id="86">8.6 提示反馈</h3>
|
||
<ul>
|
||
<li><code>✅ 已加载 {平台}平台信息</code> / <code>✅ 保存成功</code> / <code>✅ 已删除</code></li>
|
||
<li><code>✅ 连通成功!</code> / <code>连通失败</code></li>
|
||
<li><code>请选择平台</code> / <code>请选择产品代号</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="09-skill">09. Skill 管理</h2>
|
||
<h3 id="91">9.1 页面目标</h3>
|
||
<p>Skill 注册与管理,支持 <strong>双执行器</strong>(龙虾 Agent / 脚本模板)、产品范围绑定、JSON Schema 参数映射、内置测试台。</p>
|
||
<h3 id="92">9.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>统计卡</strong>:Skill 总数 / 龙虾数 / 脚本数 / 启用中</li>
|
||
<li><strong>筛选栏</strong>:搜索 + 分类/执行器/状态下拉 + <code>+ 注册 Skill</code></li>
|
||
<li><strong>Skill 列表</strong>:6 行、7 列</li>
|
||
<li><strong>注册/编辑 Skill 弹窗</strong>:5 Tab(基本信息 / 执行器配置 / 产品范围 / 参数映射 / 测试台)</li>
|
||
<li><strong>删除确认弹窗</strong></li>
|
||
</ol>
|
||
<h3 id="93">9.3 列表字段</h3>
|
||
<p>Skill 名称、分类、执行器(🦞 龙虾 / 📜 脚本)、产品范围(X 个或全部)、调用次数、成功率(带颜色)、状态</p>
|
||
<h3 id="94">9.4 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>+ 注册 Skill</td>
|
||
<td>打开弹窗,标题 <code>注册 Skill</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>编辑 / 删除</td>
|
||
<td>弹窗回填 / 删除弹窗</td>
|
||
<td>每行</td>
|
||
<td>删除是;<strong>已被角色引用需先解除</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗 Tab</td>
|
||
<td>5 Tab 切换</td>
|
||
<td><code>switchST(i)</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Tab 0</td>
|
||
<td>执行器类型 radio(龙虾/脚本)</td>
|
||
<td><code>selExec()</code> 显隐对应配置区(RB-13)</td>
|
||
<td>必选</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Tab 1 龙虾</td>
|
||
<td>🔌 测试连通性</td>
|
||
<td>Toast <code>✅ 龙虾平台连通成功</code></td>
|
||
<td>配置完整</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Tab 1 脚本</td>
|
||
<td>脚本模板 select</td>
|
||
<td><code>onScriptTpl()</code> 联动脚本类型</td>
|
||
<td>选中模板</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Tab 1 脚本</td>
|
||
<td>+ 添加环境变量</td>
|
||
<td><code>addEnv()</code> 追加 KV 行</td>
|
||
<td>脚本模式</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Tab 1 脚本</td>
|
||
<td>环境变量行·删除</td>
|
||
<td>移除该行</td>
|
||
<td>行存在</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Tab 2</td>
|
||
<td>产品多选框</td>
|
||
<td>展开下拉,勾选/取消</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Tab 3</td>
|
||
<td>inputSchema textarea</td>
|
||
<td>可编辑 JSON Schema</td>
|
||
<td>始终</td>
|
||
<td>合法 JSON</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Tab 3</td>
|
||
<td>参数映射行</td>
|
||
<td>为每个字段选择「表达式/常量」</td>
|
||
<td>始终</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Tab 4</td>
|
||
<td>测试参数 JSON textarea</td>
|
||
<td>可编辑</td>
|
||
<td>始终</td>
|
||
<td>合法 JSON</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Tab 4</td>
|
||
<td>▶️ 执行测试</td>
|
||
<td><code>runTest()</code>:每 500ms 追加日志,2.5s 完成</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗</td>
|
||
<td>保存</td>
|
||
<td>Toast <code>✅ Skill 已保存</code></td>
|
||
<td>校验通过</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="95">9.5 表单字段</h3>
|
||
<p><strong>Tab 0 基本信息</strong></p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Skill 名称</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
</tr>
|
||
<tr>
|
||
<td>分类</td>
|
||
<td>select</td>
|
||
<td>否(内容发布 / 数据采集 / 账号运营 / 广告投放 / 数据分析)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>描述</td>
|
||
<td>textarea</td>
|
||
<td>否</td>
|
||
</tr>
|
||
<tr>
|
||
<td>执行器类型</td>
|
||
<td>radio</td>
|
||
<td>是(RB-13,二选一)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Tab 1 执行器配置 · 龙虾模式</strong></p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>默认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>API 地址</td>
|
||
<td>url</td>
|
||
<td>是</td>
|
||
<td><code>https://api.lobster-agent.com/v1</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>API Key</td>
|
||
<td>password</td>
|
||
<td>是</td>
|
||
<td><code>sk-lobster-xxxx</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Agent ID</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td><code>agent_xhs_publish_01</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Tab 1 执行器配置 · 脚本模式</strong></p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>默认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>脚本模板</td>
|
||
<td>select</td>
|
||
<td>是</td>
|
||
<td>Python-通用HTTP / Python-数据清洗 / Shell-文件处理 / Node.js-API 调用</td>
|
||
</tr>
|
||
<tr>
|
||
<td>环境变量(KV 动态行)</td>
|
||
<td>动态组</td>
|
||
<td>否</td>
|
||
<td>预填 1 行 <code>API_KEY</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>超时时间(秒)</td>
|
||
<td>number</td>
|
||
<td>否</td>
|
||
<td>30</td>
|
||
</tr>
|
||
<tr>
|
||
<td>脚本类型</td>
|
||
<td>input readonly</td>
|
||
<td>否</td>
|
||
<td>联动自填 python/shell/node</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Tab 2 产品范围</strong>:多选 <code>PROD001 ~ PROD006</code></p>
|
||
<p><strong>Tab 3 参数映射</strong>:JSON Schema + 逐字段映射(表达式/常量)</p>
|
||
<p><strong>Tab 4 测试台</strong>:测试参数 JSON + 日志输出区</p>
|
||
<h3 id="96">9.6 提示反馈</h3>
|
||
<ul>
|
||
<li><code>✅ 龙虾平台连通成功</code> / <code>✅ Skill 已保存</code> / <code>✅ 已删除</code></li>
|
||
<li>点击弹窗外关闭所有多选下拉 <code>.ms-drop</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="10">10. 任务创建(四步向导)</h2>
|
||
<h3 id="101">10.1 页面目标</h3>
|
||
<p>通过 <strong>4 步向导</strong> 创建任务:选择 Skill → 选择产品 → 填写参数 → 确认提交,过程包含 RB-07/RB-12 权限与交集校验。</p>
|
||
<h3 id="102">10.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>步骤条</strong>(4 个节点 + 连线)</li>
|
||
<li><strong>Step 1</strong>:Skill 卡片列表(搜索 + 选择)+ 规则提示条</li>
|
||
<li><strong>Step 2</strong>:产品卡片列表(搜索 + 选择)+ 交集提示条 + 渠道码自动填充提示</li>
|
||
<li><strong>Step 3</strong>:参数表单(自动回填 Skill + 产品 + 渠道码)</li>
|
||
<li><strong>Step 4</strong>:确认信息预览 + 校验通过条</li>
|
||
<li><strong>成功弹窗</strong>:任务 ID + 基本信息 + "继续创建/查看任务列表"</li>
|
||
</ol>
|
||
<h3 id="103">10.3 关键字段</h3>
|
||
<ul>
|
||
<li>Skill 卡:名称、执行器、分类、描述</li>
|
||
<li>产品卡:名称、代号、平台、投放组</li>
|
||
<li>参数表单:产品(只读)、发布内容、标签、发布时间、内导渠道码(只读,自动填充)</li>
|
||
<li>渠道码映射(PROD_CH):<code>PROD001→IC001/NC001</code> 等</li>
|
||
</ul>
|
||
<h3 id="104">10.4 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Step 1 搜索框</td>
|
||
<td>输入</td>
|
||
<td><code>filterSkills()</code> 实时过滤卡片</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Step 1</td>
|
||
<td>Skill 卡</td>
|
||
<td><code>selSkill()</code> 记录选中,解锁下一步</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Step 1 右下</td>
|
||
<td>下一步 →</td>
|
||
<td><code>goStep(2)</code>:当前步骤 done、下一步 active</td>
|
||
<td><strong>已选 Skill</strong></td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Step 2 搜索框</td>
|
||
<td>输入</td>
|
||
<td><code>filterProds()</code> 实时过滤</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Step 2</td>
|
||
<td>产品卡</td>
|
||
<td><code>selProd()</code> 记录选中 + 显示渠道码填充提示</td>
|
||
<td>交集内产品</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Step 2 右下</td>
|
||
<td>上一步 / 下一步 →</td>
|
||
<td>前后切换</td>
|
||
<td>下一步需已选产品</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Step 3</td>
|
||
<td>标签输入</td>
|
||
<td><code>Enter</code> 键 <code>addTag()</code> 追加标签</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Step 3</td>
|
||
<td>标签 ×</td>
|
||
<td>删除该标签</td>
|
||
<td>标签存在</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Step 3 右下</td>
|
||
<td>上一步 / 下一步 →</td>
|
||
<td>切换</td>
|
||
<td>下一步需内容非空</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Step 4 右下</td>
|
||
<td>🚀 提交任务</td>
|
||
<td>打开成功弹窗(任务 ID <code>TASK-20260423-001</code>)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>成功弹窗</td>
|
||
<td>继续创建</td>
|
||
<td><code>resetWizard()</code> 回到 Step 1、清空所有状态</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>成功弹窗</td>
|
||
<td>查看任务列表</td>
|
||
<td>跳转"11. 任务列表"</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>成功弹窗</td>
|
||
<td>✕</td>
|
||
<td>关闭弹窗</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="105">10.5 交互规则 / 校验</h3>
|
||
<ul>
|
||
<li><strong>Step 1 提示</strong>:<code>📋 仅展示您角色 skill_scope 中的 Skill(RB-07),合并所有角色取并集</code></li>
|
||
<li><strong>Step 2 提示</strong>:<code>⚠️ 产品范围 = Skill.product_scope ∩ 用户角色.data_scope(RB-12 交集校验)</code></li>
|
||
<li><strong>渠道码提示</strong>:选中产品后出现 <code>✅ 渠道码已自动填充 — 内导: IC001 · 自然: NC001</code></li>
|
||
<li><strong>Step 4 校验条</strong>:<code>✅ Skill 权限校验通过 · 产品范围交集校验通过 · 参数校验通过</code></li>
|
||
<li>步骤切换使用 <code>.step-ct.show</code> 类控制显示;步骤节点三态:active / done / pending</li>
|
||
</ul>
|
||
<h3 id="106">10.6 提示反馈</h3>
|
||
<ul>
|
||
<li>成功弹窗文案:<code>🎉 任务已提交</code> + <code>任务创建成功!</code> + 任务 ID</li>
|
||
<li>搜索占位:<code>🔍 搜索 Skill 名称...</code> / <code>🔍 搜索产品...</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="11_2">11. 任务列表</h2>
|
||
<h3 id="111">11.1 页面目标</h3>
|
||
<p>展示所有任务,支持状态/执行器/时间范围筛选,提供详情、取消、重试行内操作。</p>
|
||
<h3 id="112">11.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>统计卡 × 5</strong>:任务总数(1,234)/ 成功(1,089)/ 失败(45)/ 运行中(8)/ 超时(92)</li>
|
||
<li><strong>筛选栏</strong>:搜索(任务 ID/Skill 名)+ 状态/执行器/时间范围下拉 + 导出</li>
|
||
<li><strong>列表</strong>:任务 ID / Skill / 执行器 / 产品 / 创建人 / 状态 / 耗时 / 创建时间 / 操作</li>
|
||
<li><strong>详情弹窗</strong>(4 Tab:基本信息 / 输入参数 / 执行结果 / 执行日志)</li>
|
||
<li><strong>取消确认弹窗</strong></li>
|
||
<li><strong>分页</strong></li>
|
||
</ol>
|
||
<h3 id="113">11.3 状态枚举</h3>
|
||
<p><code>SUCCEEDED</code>(绿)/ <code>FAILED</code>(红)/ <code>RUNNING</code>(黄,带 <code>...</code>)/ <code>PENDING</code>(灰)/ <code>TIMEOUT</code>(橙)</p>
|
||
<h3 id="114">11.4 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>搜索 / 状态 / 执行器 / 时间范围</td>
|
||
<td><code>filterT()</code> 按 <code>data-q / data-st / data-exec</code> 过滤</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>导出</td>
|
||
<td>Toast <code>📥 导出成功</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>详情</td>
|
||
<td>打开 <code>📋 任务详情</code> 弹窗</td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>取消</td>
|
||
<td>打开取消确认弹窗 → Toast <code>✅ 任务已取消</code></td>
|
||
<td><strong>仅 RUNNING / PENDING</strong></td>
|
||
<td>是</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>重试</td>
|
||
<td>Toast <code>🔄 已重新提交</code></td>
|
||
<td><strong>仅 FAILED / TIMEOUT</strong></td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>详情弹窗 Tab</td>
|
||
<td>基本信息 / 输入参数 / 执行结果 / 执行日志</td>
|
||
<td><code>switchDT(i)</code></td>
|
||
<td>弹窗打开时</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>分页</td>
|
||
<td>页码</td>
|
||
<td>切换当前页</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>取消弹窗</td>
|
||
<td>取消 / 确认取消</td>
|
||
<td>关闭 / 向执行器发停止信号</td>
|
||
<td>始终</td>
|
||
<td>—</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="115">11.5 详情弹窗内容</h3>
|
||
<ul>
|
||
<li><strong>Tab 0 基本信息</strong>:任务 ID、Skill、执行器、产品、创建人、状态(带色标签)、创建时间、耗时</li>
|
||
<li><strong>Tab 1 输入参数</strong>:JSON 展示(product_id / content / tags / channel_code)</li>
|
||
<li><strong>Tab 2 执行结果</strong>:JSON 展示(status / post_id / post_url / published_at)</li>
|
||
<li><strong>Tab 3 执行日志</strong>:深色日志盒,带时间戳 + 彩色级别(状态变更用黄色/绿色)</li>
|
||
</ul>
|
||
<h3 id="116">11.6 按钮显示规则</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>状态</th>
|
||
<th>显示按钮</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>SUCCEEDED</td>
|
||
<td>详情</td>
|
||
</tr>
|
||
<tr>
|
||
<td>FAILED</td>
|
||
<td>详情 + 重试</td>
|
||
</tr>
|
||
<tr>
|
||
<td>RUNNING</td>
|
||
<td>详情 + 取消</td>
|
||
</tr>
|
||
<tr>
|
||
<td>PENDING</td>
|
||
<td>详情 + 取消</td>
|
||
</tr>
|
||
<tr>
|
||
<td>TIMEOUT</td>
|
||
<td>详情 + 重试</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="117">11.7 提示反馈</h3>
|
||
<ul>
|
||
<li><code>📥 导出成功</code> / <code>✅ 任务已取消</code> / <code>🔄 已重新提交</code></li>
|
||
<li>取消弹窗文案:<code>⚠️ 取消任务</code> / <code>确定取消运行中的任务?</code> / <code>将向执行器发送停止信号</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="12_2">12. 菜单管理</h2>
|
||
<h3 id="121">12.1 页面目标</h3>
|
||
<p>维护系统菜单树(目录/菜单/外链)+ 每个菜单下的按钮权限码。</p>
|
||
<h3 id="122">12.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>操作栏</strong>:+ 新增菜单 / 全部展开 / 全部收起</li>
|
||
<li><strong>左侧 菜单树</strong>:可展开/收起、行内编辑按钮、点击行切换右侧按钮视图</li>
|
||
<li><strong>右侧 按钮管理</strong>:标题显示当前菜单名、按钮列表表格、+ 新增按钮</li>
|
||
<li><strong>菜单编辑弹窗</strong> / <strong>按钮编辑弹窗</strong> / <strong>删除确认弹窗</strong></li>
|
||
</ol>
|
||
<h3 id="123">12.3 数据字段</h3>
|
||
<ul>
|
||
<li>菜单树:图标(📁 目录 / 📄 菜单 / 🔗 外链)、菜单名、行内"编辑"链接</li>
|
||
<li>按钮权限表:按钮名称、权限标识(<code>product:create</code>)、类型(primary/default/danger/warning)、状态</li>
|
||
</ul>
|
||
<p><strong>按钮权限库(BTN_DATA)示例</strong>:
|
||
- <code>product</code>:新增 / 编辑 / 删除 / 导入 / 导出
|
||
- <code>role</code>:新增 / 编辑 / 删除 / 复制
|
||
- <code>user</code>:新增 / 编辑 / 删除 / 重置密码
|
||
- <code>skill</code>:注册 / 编辑 / 删除 / 测试
|
||
- <code>channel</code>:新增 / 编辑 / 绑定
|
||
- <code>menu-mgmt</code>:新增菜单 / 编辑菜单 / 新增按钮</p>
|
||
<h3 id="124">12.4 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>操作栏</td>
|
||
<td>+ 新增菜单</td>
|
||
<td>打开菜单弹窗(清空)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>操作栏</td>
|
||
<td>全部展开 / 全部收起</td>
|
||
<td><code>expandAll()</code> / <code>collapseAll()</code> 更新树</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>菜单树</td>
|
||
<td>▼/▶</td>
|
||
<td><code>toggleTree()</code> 局部折叠</td>
|
||
<td>节点有子项</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>菜单树</td>
|
||
<td>行点击</td>
|
||
<td><code>showBtns(key)</code> 更新右侧按钮表</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>菜单树</td>
|
||
<td>编辑(每行)</td>
|
||
<td>打开菜单弹窗(回填)</td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>按钮表</td>
|
||
<td>+ 新增按钮</td>
|
||
<td>打开按钮弹窗(自动填充所属菜单)</td>
|
||
<td>当前已选菜单</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>按钮表</td>
|
||
<td>编辑(每行)</td>
|
||
<td>打开按钮弹窗(回填)</td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>按钮表</td>
|
||
<td>删除(每行)</td>
|
||
<td>删除确认弹窗 → Toast <code>✅ 已删除</code></td>
|
||
<td>每行</td>
|
||
<td>是</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗</td>
|
||
<td>保存</td>
|
||
<td>Toast <code>✅ 菜单已保存</code> / <code>✅ 按钮已保存</code></td>
|
||
<td>校验通过</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="125">12.5 表单字段</h3>
|
||
<p><strong>菜单编辑弹窗</strong></p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>默认</th>
|
||
<th>说明</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>菜单类型</td>
|
||
<td>select</td>
|
||
<td>是</td>
|
||
<td>directory</td>
|
||
<td>directory / menu / link;<strong>link 时隐藏组件路径与排序</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>菜单名称</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>父级菜单</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>顶级</td>
|
||
<td>顶级 / 权限管理 / 产品管理 / …</td>
|
||
</tr>
|
||
<tr>
|
||
<td>路由路径</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
<td>形如 <code>/product</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>图标</td>
|
||
<td>input</td>
|
||
<td>否</td>
|
||
<td>—</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>前端组件路径</td>
|
||
<td>input</td>
|
||
<td>否</td>
|
||
<td>—</td>
|
||
<td><code>link</code> 类型时隐藏</td>
|
||
</tr>
|
||
<tr>
|
||
<td>排序号</td>
|
||
<td>number</td>
|
||
<td>是</td>
|
||
<td>1</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>是否可见</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>显示</td>
|
||
<td>显示/隐藏</td>
|
||
</tr>
|
||
<tr>
|
||
<td>状态</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>启用</td>
|
||
<td>启用/禁用</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>按钮编辑弹窗</strong></p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>说明</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>所属菜单</td>
|
||
<td>input readonly</td>
|
||
<td>—</td>
|
||
<td>自动填充</td>
|
||
</tr>
|
||
<tr>
|
||
<td>按钮名称</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>权限标识</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td>唯一,形如 <code>product:create</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>按钮类型</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>primary / default / danger / warning</td>
|
||
</tr>
|
||
<tr>
|
||
<td>状态</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>启用 / 禁用</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="126">12.6 提示反馈</h3>
|
||
<ul>
|
||
<li><code>✅ 菜单已保存</code> / <code>✅ 按钮已保存</code> / <code>✅ 已删除</code></li>
|
||
<li>删除确认说明:<code>删除需确保无子菜单、无角色引用</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="13_2">13. 平台套件</h2>
|
||
<h3 id="131">13.1 页面目标</h3>
|
||
<p>维护 <strong>平台 + 产品代号</strong> 两级关系,为"08 平台产品账号"提供选择源。</p>
|
||
<h3 id="132">13.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>搜索栏</strong>:搜索平台名 + <code>+ 新增平台</code></li>
|
||
<li><strong>平台卡片网格</strong>(主视图):5 个平台卡(小红书/抖音/Facebook/TikTok/微信公众号)</li>
|
||
<li><strong>平台详情</strong>(点卡片后进入):← 返回 + 平台名 + 编辑/删除 + 信息块 + 产品代号表</li>
|
||
<li><strong>平台编辑弹窗</strong> / <strong>产品代号编辑弹窗</strong> / <strong>删除确认弹窗</strong></li>
|
||
</ol>
|
||
<h3 id="133">13.3 数据字段</h3>
|
||
<ul>
|
||
<li>平台卡:图标+名称、平台地址、产品数、账号数、状态</li>
|
||
<li>详情块:平台地址、状态、关联账号数</li>
|
||
<li>产品代号表:产品代号(<code>PROD001</code>)、产品名称、关联账号数、状态</li>
|
||
</ul>
|
||
<h3 id="134">13.4 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>搜索栏</td>
|
||
<td>搜索</td>
|
||
<td><code>filterCards()</code> 按 <code>data-q</code> 过滤</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>搜索栏</td>
|
||
<td>+ 新增平台</td>
|
||
<td>打开平台弹窗(清空)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>平台卡</td>
|
||
<td>卡片点击</td>
|
||
<td><code>showPlatDetail(key)</code> 进入详情视图</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>详情</td>
|
||
<td>← 返回</td>
|
||
<td><code>hidePlatDetail()</code> 回到列表</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>详情</td>
|
||
<td>编辑平台</td>
|
||
<td>打开平台弹窗(回填名称/地址)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>详情</td>
|
||
<td>删除平台</td>
|
||
<td>删除确认弹窗 → Toast <code>✅ 已删除</code></td>
|
||
<td><strong>无关联账号</strong></td>
|
||
<td>是</td>
|
||
</tr>
|
||
<tr>
|
||
<td>产品代号表</td>
|
||
<td>+ 新增产品代号</td>
|
||
<td>打开产品代号弹窗(自动填充平台)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>产品代号表</td>
|
||
<td>编辑 / 删除(每行)</td>
|
||
<td>弹窗</td>
|
||
<td>每行</td>
|
||
<td>删除是</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗</td>
|
||
<td>保存</td>
|
||
<td>Toast <code>✅ 平台已保存</code> / <code>✅ 产品代号已保存</code></td>
|
||
<td>校验通过</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="135">13.5 表单字段</h3>
|
||
<p><strong>平台编辑弹窗</strong></p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>平台名称</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
</tr>
|
||
<tr>
|
||
<td>平台地址</td>
|
||
<td>input</td>
|
||
<td>是(<code>https://...</code>)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>平台图标</td>
|
||
<td>input</td>
|
||
<td>否(emoji 或 URL)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>备注</td>
|
||
<td>textarea</td>
|
||
<td>否</td>
|
||
</tr>
|
||
<tr>
|
||
<td>状态</td>
|
||
<td>select</td>
|
||
<td>否(启用/禁用)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>产品代号编辑弹窗</strong></p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>所属平台</td>
|
||
<td>input readonly</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>产品代号</td>
|
||
<td>input</td>
|
||
<td>是(<code>PROD001</code> 格式)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>产品名称</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
</tr>
|
||
<tr>
|
||
<td>状态</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="136">13.6 提示反馈</h3>
|
||
<ul>
|
||
<li><code>✅ 平台已保存</code> / <code>✅ 产品代号已保存</code> / <code>✅ 已删除</code></li>
|
||
<li>删除说明:<code>已关联账号的平台/产品需先解除</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="14-skill">14. Skill 调用日志</h2>
|
||
<h3 id="141">14.1 页面目标</h3>
|
||
<p>展示全部 Skill 调用历史,支持多维筛选、查看详情与日志回放、CSV 导出。</p>
|
||
<h3 id="142">14.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>统计卡 × 4</strong>:总调用(12,456)/ 成功(12,102)/ 失败(354)/ 平均耗时(2.4s)</li>
|
||
<li><strong>筛选栏</strong>:搜索(Skill/调用者)+ 状态/执行器/时间范围下拉 + 导出 CSV</li>
|
||
<li><strong>列表</strong>:调用 ID / Skill / 执行器 / 产品 / 调用者 / 状态 / 耗时 / 时间 / 操作</li>
|
||
<li><strong>详情弹窗</strong>:4 Tab(基本信息 / 请求参数 / 响应结果 / 执行日志)</li>
|
||
<li><strong>分页</strong></li>
|
||
</ol>
|
||
<h3 id="143">14.3 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>搜索 / 状态 / 执行器 / 时间范围</td>
|
||
<td><code>filterT()</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>导出 CSV</td>
|
||
<td>Toast <code>📥 导出成功</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>详情</td>
|
||
<td>打开详情弹窗</td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>详情弹窗 Tab</td>
|
||
<td>切换</td>
|
||
<td><code>switchLT(i)</code></td>
|
||
<td>弹窗打开</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="144">14.4 详情弹窗</h3>
|
||
<ul>
|
||
<li>基本信息:调用 ID(<code>LOG-20260423-001</code>)、Skill、执行器、调用者(含分组)、状态、耗时、时间</li>
|
||
<li>请求参数:JSON</li>
|
||
<li>响应结果:JSON(post_id / post_url 等)</li>
|
||
<li>执行日志:带时间戳、彩色级别的日志盒</li>
|
||
</ul>
|
||
<h3 id="145">14.5 状态枚举</h3>
|
||
<p><code>SUCCESS</code> / <code>FAILED</code> / <code>TIMEOUT</code></p>
|
||
<h3 id="146">14.6 提示反馈</h3>
|
||
<ul>
|
||
<li><code>📥 导出成功</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="15_1">15. 操作日志(审计)</h2>
|
||
<h3 id="151">15.1 页面目标</h3>
|
||
<p>记录全局的新增/编辑/删除/登录/导出行为,支持审计追踪与变更对比。</p>
|
||
<h3 id="152">15.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>筛选栏</strong>:搜索(操作人/模块)+ 模块/操作/时间下拉 + 导出</li>
|
||
<li><strong>列表</strong>:日志 ID(<code>OPLOG-xxx</code>)/ 操作人 / 模块 / 操作 / 描述 / IP / 时间</li>
|
||
<li><strong>详情弹窗</strong>:基本信息 + 请求参数 JSON + 变更 before/after JSON 对比</li>
|
||
<li><strong>分页</strong></li>
|
||
</ol>
|
||
<h3 id="153">15.3 模块与操作枚举</h3>
|
||
<ul>
|
||
<li>模块:用户管理 / 角色管理 / 产品管理 / Skill 管理 / 任务管理 / 平台产品账号 / 登录</li>
|
||
<li>操作:新增 / 编辑 / 删除 / 登录 / 导出</li>
|
||
</ul>
|
||
<h3 id="154">15.4 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>搜索 / 模块 / 操作</td>
|
||
<td><code>filterT()</code> 过滤</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>导出</td>
|
||
<td>Toast <code>📥 导出成功</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>详情</td>
|
||
<td>打开详情弹窗</td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>详情弹窗</td>
|
||
<td>关闭</td>
|
||
<td>关闭弹窗</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="155">15.5 提示反馈</h3>
|
||
<ul>
|
||
<li><code>📥 导出成功</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="16">16. 统计报表</h2>
|
||
<h3 id="161">16.1 页面目标</h3>
|
||
<p>多维度可视化展板:任务趋势、执行器分布、状态分布、Skill/产品/用户排行。</p>
|
||
<h3 id="162">16.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>KPI 卡 × 4</strong>:任务总数 / 成功率 / 平均耗时 / 活跃 Skill(含环比)</li>
|
||
<li><strong>图表行 1</strong>:任务执行趋势(7 日柱状)+ 执行器分布(饼图 SVG)</li>
|
||
<li><strong>图表行 2</strong>:任务状态分布(柱状)+ Skill 调用 Top 5(排名列表)</li>
|
||
<li><strong>图表行 3</strong>:产品任务量 Top X + 用户活跃 Top X</li>
|
||
<li><strong>控制栏</strong>:时间范围下拉 + 刷新 + 导出 PDF</li>
|
||
</ol>
|
||
<h3 id="163">16.3 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>控制栏</td>
|
||
<td>时间范围 select</td>
|
||
<td><code>onchange → refreshCharts()</code> 重绘</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>控制栏</td>
|
||
<td>刷新</td>
|
||
<td><code>refreshCharts()</code> 所有柱子归零 → 50ms 后恢复(动画)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>控制栏</td>
|
||
<td>导出 PDF</td>
|
||
<td>Toast <code>📥 报表已导出</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="164">16.4 指标示例</h3>
|
||
<ul>
|
||
<li>任务总数:1,234</li>
|
||
<li>成功率:96.3%</li>
|
||
<li>平均耗时:2.4s</li>
|
||
<li>活跃 Skill:18</li>
|
||
<li>7 日趋势:<code>[156, 189, 145, 201, 178, 210, 155]</code></li>
|
||
<li>执行器分布:龙虾 67% / 脚本 33%</li>
|
||
<li>状态分布:成功 1089 / 失败 45 / 运行中 8 / 超时 92</li>
|
||
<li>Top 5 Skill:数据清洗脚本 5123、竞品数据采集 3401、小红书笔记发布 1256 …</li>
|
||
<li>时间范围选项:最近 7 天 / 最近 30 天 / 本月 / 上月</li>
|
||
</ul>
|
||
<h3 id="165">16.5 提示反馈</h3>
|
||
<ul>
|
||
<li><code>📥 报表已导出</code> / <code>📊 数据已刷新</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="17">17. 执行器配置</h2>
|
||
<h3 id="171">17.1 页面目标</h3>
|
||
<p>管理 <strong>龙虾 Agent</strong> 与 <strong>脚本引擎</strong> 两个执行器的节点配置、健康监控、并发/超时/重试策略。</p>
|
||
<h3 id="172">17.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>权限提示条</strong>:<code>仅超级管理员可修改(RB-13)</code></li>
|
||
<li><strong>执行器卡片 × 2</strong>:龙虾执行器 / 脚本执行器</li>
|
||
<li>每卡片包含:状态标签、描述、参数块、当前任务占用(n/N)、最近 24 小时健康度(24 个圆点 timeline)、3 个操作按钮</li>
|
||
<li><strong>龙虾配置弹窗</strong> / <strong>脚本配置弹窗</strong></li>
|
||
</ol>
|
||
<h3 id="173">17.3 卡片字段</h3>
|
||
<p><strong>龙虾执行器</strong>:API 地址 / 超时(30s)/ 重试(3 次)/ 并发上限(10)/ 当前 3/10</p>
|
||
<p><strong>脚本执行器</strong>:工作目录 / 超时(60s)/ 并发上限(5)/ 沙箱模式 / 当前 1/5</p>
|
||
<h3 id="174">17.4 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>龙虾卡片</td>
|
||
<td>⚙️ 配置</td>
|
||
<td>打开龙虾配置弹窗</td>
|
||
<td>超级管理员</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>龙虾卡片</td>
|
||
<td>🔌 测试</td>
|
||
<td>Toast <code>✅ 龙虾平台连通正常</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>龙虾卡片</td>
|
||
<td>🔄 重启</td>
|
||
<td>Toast <code>🔄 已重启</code></td>
|
||
<td>超级管理员</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>脚本卡片</td>
|
||
<td>⚙️ 配置 / 🔌 测试 / 🔄 重启</td>
|
||
<td>同上(脚本版)</td>
|
||
<td>同上</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>龙虾弹窗</td>
|
||
<td>🔌 测试连通性</td>
|
||
<td>Toast <code>✅ 龙虾平台连通正常</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>配置弹窗</td>
|
||
<td>取消</td>
|
||
<td>关闭</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>配置弹窗</td>
|
||
<td>保存</td>
|
||
<td>Toast <code>✅ 配置已保存</code></td>
|
||
<td>校验通过</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="175">17.5 表单字段</h3>
|
||
<p><strong>龙虾配置弹窗</strong></p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>默认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>API 地址</td>
|
||
<td>text</td>
|
||
<td>是</td>
|
||
<td>示例值</td>
|
||
</tr>
|
||
<tr>
|
||
<td>API Key</td>
|
||
<td>password</td>
|
||
<td>是</td>
|
||
<td>示例值</td>
|
||
</tr>
|
||
<tr>
|
||
<td>超时时间(秒)</td>
|
||
<td>number</td>
|
||
<td>否</td>
|
||
<td>30</td>
|
||
</tr>
|
||
<tr>
|
||
<td>重试次数</td>
|
||
<td>number</td>
|
||
<td>否</td>
|
||
<td>3</td>
|
||
</tr>
|
||
<tr>
|
||
<td>并发上限</td>
|
||
<td>number</td>
|
||
<td>否</td>
|
||
<td>10</td>
|
||
</tr>
|
||
<tr>
|
||
<td>轮询间隔(ms)</td>
|
||
<td>number</td>
|
||
<td>否</td>
|
||
<td>2000</td>
|
||
</tr>
|
||
<tr>
|
||
<td>回调 URL</td>
|
||
<td>text</td>
|
||
<td>否</td>
|
||
<td>示例值</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>脚本配置弹窗</strong></p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>默认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>工作目录</td>
|
||
<td>text</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Python 路径</td>
|
||
<td>text</td>
|
||
<td>否</td>
|
||
<td><code>/usr/bin/python3</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Node 路径</td>
|
||
<td>text</td>
|
||
<td>否</td>
|
||
<td><code>/usr/bin/node</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>全局超时(秒)</td>
|
||
<td>number</td>
|
||
<td>否</td>
|
||
<td>60</td>
|
||
</tr>
|
||
<tr>
|
||
<td>并发上限</td>
|
||
<td>number</td>
|
||
<td>否</td>
|
||
<td>5</td>
|
||
</tr>
|
||
<tr>
|
||
<td>沙箱模式</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>Docker 容器 / 本地进程 / 虚拟环境</td>
|
||
</tr>
|
||
<tr>
|
||
<td>日志目录</td>
|
||
<td>text</td>
|
||
<td>否</td>
|
||
<td>—</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="176">17.6 交互规则</h3>
|
||
<ul>
|
||
<li><code>initHealth(id)</code> 生成 24 个小圆点,随机展示成功/异常状态,悬停显示 tooltip</li>
|
||
</ul>
|
||
<h3 id="177">17.7 提示反馈</h3>
|
||
<ul>
|
||
<li><code>✅ 龙虾平台连通正常</code> / <code>✅ 脚本引擎正常</code> / <code>🔄 已重启</code> / <code>✅ 配置已保存</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="18">18. 脚本模板管理</h2>
|
||
<h3 id="181">18.1 页面目标</h3>
|
||
<p>维护脚本执行器使用的预置模板,支持 Python/Node.js/Shell 代码编辑 + 环境变量声明 + Skill 引用追踪。</p>
|
||
<h3 id="182">18.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>筛选栏</strong>:搜索(模板名)+ 脚本类型下拉 + <code>+ 新增模板</code></li>
|
||
<li><strong>模板列表</strong>:模板名 / 脚本类型 / 环境变量(逗号列表)/ 引用 Skill 数 / 状态 / 更新时间</li>
|
||
<li><strong>新增/编辑弹窗</strong>:表单 + 代码编辑器(<code>code-area</code>)+ 环境变量动态行</li>
|
||
<li><strong>删除确认弹窗</strong></li>
|
||
</ol>
|
||
<h3 id="183">18.3 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>搜索 / 脚本类型</td>
|
||
<td><code>filterT()</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>+ 新增模板</td>
|
||
<td>打开弹窗(清空)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>编辑</td>
|
||
<td>打开弹窗(回填)</td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>删除</td>
|
||
<td>删除确认弹窗</td>
|
||
<td>每行</td>
|
||
<td>是(需先解除 Skill 引用)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗·代码区</td>
|
||
<td>格式化</td>
|
||
<td>Toast <code>✅ 代码已格式化</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗·环境变量</td>
|
||
<td>+ 添加变量</td>
|
||
<td>追加变量行</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗</td>
|
||
<td>取消 / 保存</td>
|
||
<td>关闭 / Toast <code>✅ 模板已保存</code></td>
|
||
<td>校验通过</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="184">18.4 表单字段</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>说明</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>模板名称</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td>placeholder <code>如 通用 HTTP 请求</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>脚本类型</td>
|
||
<td>select</td>
|
||
<td>是</td>
|
||
<td>Python / Node.js / Shell(切换时联动示例代码)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>描述</td>
|
||
<td>textarea(2 行)</td>
|
||
<td>否</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>脚本代码</td>
|
||
<td>textarea(大)</td>
|
||
<td>是</td>
|
||
<td>类型切换时预填示例模板(<code>CODE</code> 字典)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>环境变量声明</td>
|
||
<td>动态表</td>
|
||
<td>否</td>
|
||
<td>每行:变量名(只读)/ 描述 / 必填(select 必填/可选)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>状态</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>启用 / 禁用</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="185">18.5 交互规则</h3>
|
||
<ul>
|
||
<li>切换脚本类型 → <code>onTplType()</code> 自动填充示例代码(Python/Node/Shell)</li>
|
||
<li>动态添加环境变量行:<code>appendChild</code> 到 <code>envList</code></li>
|
||
</ul>
|
||
<h3 id="186">18.6 提示反馈</h3>
|
||
<ul>
|
||
<li><code>✅ 代码已格式化</code> / <code>✅ 模板已保存</code> / <code>✅ 已删除</code></li>
|
||
<li>删除前警告:<code>已被 Skill 引用的模板需先解除关联</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="19">19. 定时任务</h2>
|
||
<h3 id="191">19.1 页面目标</h3>
|
||
<p>管理 Cron 定时调度任务,关联 Skill + 产品 + 参数,支持执行记录查看、启停、手动触发。</p>
|
||
<h3 id="192">19.2 页面结构</h3>
|
||
<ol>
|
||
<li><strong>统计卡 × 4</strong>:定时任务(8)/ 运行中(6)/ 已暂停(2)/ 7 日成功率(94.2%)</li>
|
||
<li><strong>筛选栏</strong>:搜索 + 状态下拉 + <code>+ 新增定时任务</code></li>
|
||
<li><strong>列表</strong>:任务名 / Skill / Cron 表达式 / 产品 / 下次执行 / 最近 7 次(timeline)/ 状态 / 开关</li>
|
||
<li><strong>新增/编辑弹窗</strong>(含 Cron 解析)</li>
|
||
<li><strong>执行记录弹窗</strong> / <strong>删除确认弹窗</strong></li>
|
||
</ol>
|
||
<h3 id="193">19.3 操作细节</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>位置</th>
|
||
<th>按钮</th>
|
||
<th>行为</th>
|
||
<th>条件</th>
|
||
<th>二次确认</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>搜索 / 状态</td>
|
||
<td><code>filterT()</code></td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>筛选栏</td>
|
||
<td>+ 新增定时任务</td>
|
||
<td>打开弹窗(清空)</td>
|
||
<td>始终</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>编辑</td>
|
||
<td>打开弹窗(回填)</td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>记录</td>
|
||
<td>打开执行记录弹窗(展示最近 5 次)</td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>触发</td>
|
||
<td>Toast <code>▶️ 手动触发成功</code></td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>删除</td>
|
||
<td>删除确认弹窗 → Toast <code>✅ 已删除</code></td>
|
||
<td>每行</td>
|
||
<td>是</td>
|
||
</tr>
|
||
<tr>
|
||
<td>列表行</td>
|
||
<td>开关 toggle</td>
|
||
<td>启用/暂停切换,同步状态标签;Toast <code>✅ 已启用</code> / <code>⏸️ 已暂停</code></td>
|
||
<td>每行</td>
|
||
<td>无</td>
|
||
</tr>
|
||
<tr>
|
||
<td>弹窗</td>
|
||
<td>保存</td>
|
||
<td>Toast <code>✅ 定时任务已保存</code></td>
|
||
<td>校验通过</td>
|
||
<td>无</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="194">19.4 表单字段</h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>字段</th>
|
||
<th>类型</th>
|
||
<th>必填</th>
|
||
<th>默认</th>
|
||
<th>选项/说明</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>任务名称</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
<td>如 <code>每日竞品数据采集</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>关联 Skill</td>
|
||
<td>select</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
<td>竞品数据采集 / 小红书笔记发布 / 数据清洗脚本 / 抖音视频上传 / Facebook广告投放</td>
|
||
</tr>
|
||
<tr>
|
||
<td>关联产品</td>
|
||
<td>select</td>
|
||
<td>是</td>
|
||
<td>—</td>
|
||
<td>PROD001 / PROD002 / PROD003 / 全部产品</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Cron 表达式</td>
|
||
<td>input</td>
|
||
<td>是</td>
|
||
<td><code>0 8 * * *</code></td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>帮助文本</td>
|
||
<td>动态文本</td>
|
||
<td>—</td>
|
||
<td>实时解析</td>
|
||
<td>下述对照表</td>
|
||
</tr>
|
||
<tr>
|
||
<td>执行参数(JSON)</td>
|
||
<td>textarea(3 行)</td>
|
||
<td>否</td>
|
||
<td>示例 JSON</td>
|
||
<td>必须为合法 JSON</td>
|
||
</tr>
|
||
<tr>
|
||
<td>失败重试</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>—</td>
|
||
<td>重试 3 次 / 重试 1 次 / 不重试</td>
|
||
</tr>
|
||
<tr>
|
||
<td>超时(秒)</td>
|
||
<td>number</td>
|
||
<td>否</td>
|
||
<td>120</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr>
|
||
<td>状态</td>
|
||
<td>select</td>
|
||
<td>否</td>
|
||
<td>启用</td>
|
||
<td>启用 / 暂停</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Cron 解析对照</strong>:
|
||
- <code>0 8 * * *</code> → <code>📅 每天 08:00 执行</code>
|
||
- <code>0 */2 * * *</code> → <code>📅 每 2 小时执行</code>
|
||
- <code>0 9 * * 1</code> → <code>📅 每周一 09:00 执行</code>
|
||
- <code>0 0 1 * *</code> → <code>📅 每月 1 号 00:00 执行</code>
|
||
- <code>30 10 * * *</code> → <code>📅 每天 10:30 执行</code>
|
||
- <code>0 18 * * 5</code> → <code>📅 每周五 18:00 执行</code>
|
||
- <code>0 */4 * * *</code> → <code>📅 每 4 小时执行</code>
|
||
- 其他 → <code>📅 自定义表达式: {输入值}</code></p>
|
||
<h3 id="195">19.5 执行记录弹窗</h3>
|
||
<p>表格:执行时间(YYYY-MM-DD HH:MM:SS)/ 状态(成功/失败 标签)/ 耗时(s)/ 结果文本</p>
|
||
<h3 id="196">19.6 交互规则</h3>
|
||
<ul>
|
||
<li>Cron 表达式输入实时解析 → <code>parseCron(value)</code> 更新帮助文本</li>
|
||
<li>开关 toggle:启用 → <code>tg tg-ok</code> <code>运行中</code>;暂停 → <code>tg tg-w</code> <code>已暂停</code>;同步更新 <code>data-st</code></li>
|
||
<li><code>initTimelines()</code> 为每行生成 7 个圆点(近 7 日执行成功/失败)</li>
|
||
</ul>
|
||
<h3 id="197">19.7 提示反馈</h3>
|
||
<ul>
|
||
<li><code>✅ 定时任务已保存</code> / <code>▶️ 手动触发成功</code> / <code>✅ 已删除</code> / <code>✅ 已启用</code> / <code>⏸️ 已暂停</code></li>
|
||
</ul>
|
||
<hr />
|
||
<h1 id="_4">六、待完善 / 开发注意事项</h1>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>项</th>
|
||
<th>说明</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>数据权限隔离</td>
|
||
<td>后端需严格按 RB-07/RB-12 做 Skill 权限并集 + 产品范围交集校验,前端仅展示性过滤</td>
|
||
</tr>
|
||
<tr>
|
||
<td>密码与密钥加密</td>
|
||
<td>平台账号密码、API Key、谷歌 2FA 密钥需服务端加密存储(AES),仅返回掩码</td>
|
||
</tr>
|
||
<tr>
|
||
<td>删除前置校验</td>
|
||
<td>用户/Skill/平台/产品/模板/菜单删除前都需检查引用关系,前端原型已提示</td>
|
||
</tr>
|
||
<tr>
|
||
<td>导入文件格式</td>
|
||
<td>产品批量导入需约定 CSV/Excel 模板字段与校验规则</td>
|
||
</tr>
|
||
<tr>
|
||
<td>日志规模</td>
|
||
<td>操作日志、Skill 调用日志量级大,需分库或冷热分层存储</td>
|
||
</tr>
|
||
<tr>
|
||
<td>权限按钮码</td>
|
||
<td><code>button_code</code> 需跟前端按钮统一字典,前后端共享枚举</td>
|
||
</tr>
|
||
<tr>
|
||
<td>执行器选择</td>
|
||
<td>RB-13 执行器类型互斥,后端需校验保存时 <code>executor_type</code> 只能设置一份配置</td>
|
||
</tr>
|
||
<tr>
|
||
<td>时区</td>
|
||
<td>Cron 执行、日志时间建议统一使用服务器本地时区 + UTC 存储,前端按当前用户时区展示</td>
|
||
</tr>
|
||
<tr>
|
||
<td>二次确认统一</td>
|
||
<td>所有删除/取消类操作都需弹窗确认(本原型已遵循)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>响应式支持</td>
|
||
<td>登录页已做移动端隐藏左栏,其他后台页默认 PC 端 1280+,移动端不在当前版本范围</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<hr />
|
||
<p><strong>文档结束。</strong> 本 PRD 覆盖 19 个原型页面、按钮级操作细节、字段清单与业务规则,可直接用于开发排期、测试用例编写与原型评审。</p>
|
||
</main>
|
||
</div>
|
||
<button class="back-top" id="backTop" title="回到顶部">↑</button>
|
||
<script>
|
||
// Back to top
|
||
const bt=document.getElementById('backTop');
|
||
window.addEventListener('scroll',()=>{
|
||
if(window.scrollY>400)bt.classList.add('show');else bt.classList.remove('show');
|
||
});
|
||
bt.addEventListener('click',()=>window.scrollTo({top:0,behavior:'smooth'}));
|
||
|
||
// TOC active highlight on scroll
|
||
const links=document.querySelectorAll('.toc a');
|
||
const headings=[...document.querySelectorAll('.content h2, .content h3')];
|
||
function onScroll(){
|
||
const y=window.scrollY+120;
|
||
let current=headings[0];
|
||
for(const h of headings){if(h.offsetTop<=y)current=h;else break;}
|
||
if(!current)return;
|
||
links.forEach(a=>{
|
||
a.classList.toggle('active',a.getAttribute('href')==='#'+current.id);
|
||
});
|
||
}
|
||
window.addEventListener('scroll',onScroll);onScroll();
|
||
</script>
|
||
</body>
|
||
</html>
|