feat(client): add offline digital employee overview
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@qiming-ai/qimingclaw",
|
||||
"version": "0.9.7",
|
||||
"description": "启明数字员工",
|
||||
"description": "飞天数字员工",
|
||||
"main": "dist/main/main.js",
|
||||
"author": "Qiming Team",
|
||||
"license": "MIT",
|
||||
@@ -128,7 +128,7 @@
|
||||
},
|
||||
"build": {
|
||||
"appId": "com.qiming.qimingclaw",
|
||||
"productName": "启明数字员工",
|
||||
"productName": "飞天数字员工",
|
||||
"afterSign": "scripts/build/after-sign.js",
|
||||
"electronLanguages": [
|
||||
"en",
|
||||
@@ -297,8 +297,8 @@
|
||||
"hardenedRuntime": true,
|
||||
"extendInfo": {
|
||||
"CFBundleIdentifier": "com.qiming.agent",
|
||||
"CFBundleName": "启明数字员工",
|
||||
"CFBundleDisplayName": "启明数字员工",
|
||||
"CFBundleName": "飞天数字员工",
|
||||
"CFBundleDisplayName": "飞天数字员工",
|
||||
"NSDesktopFolderUsageDescription": "需要访问桌面文件夹以支持文件操作",
|
||||
"NSDocumentsFolderUsageDescription": "需要访问文档文件夹以支持文件操作",
|
||||
"NSDownloadsFolderUsageDescription": "需要访问下载文件夹以支持文件操作"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
function t(n,e,i,s){if(typeof e=="function"?n!==e||!s:!e.has(n))throw new TypeError("Cannot read private member from an object whose class did not declare it");return i==="m"?s:i==="a"?s.call(n):s?s.value:e.get(n)}function c(n,e,i,s,_){if(typeof e=="function"?n!==e||!0:!e.has(n))throw new TypeError("Cannot write private member to an object whose class did not declare it");return e.set(n,i),i}var a,r,o,l,u;const d="__TAURI_TO_IPC_KEY__";function w(n,e=!1){return window.__TAURI_INTERNALS__.transformCallback(n,e)}class g{constructor(e){a.set(this,void 0),r.set(this,0),o.set(this,[]),l.set(this,void 0),c(this,a,e||(()=>{})),this.id=w(i=>{const s=i.index;if("end"in i){s==t(this,r,"f")?this.cleanupCallback():c(this,l,s);return}const _=i.message;if(s==t(this,r,"f")){for(t(this,a,"f").call(this,_),c(this,r,t(this,r,"f")+1);t(this,r,"f")in t(this,o,"f");){const p=t(this,o,"f")[t(this,r,"f")];t(this,a,"f").call(this,p),delete t(this,o,"f")[t(this,r,"f")],c(this,r,t(this,r,"f")+1)}t(this,r,"f")===t(this,l,"f")&&this.cleanupCallback()}else t(this,o,"f")[s]=_})}cleanupCallback(){window.__TAURI_INTERNALS__.unregisterCallback(this.id)}set onmessage(e){c(this,a,e)}get onmessage(){return t(this,a,"f")}[(a=new WeakMap,r=new WeakMap,o=new WeakMap,l=new WeakMap,d)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[d]()}}class f{constructor(e,i,s){this.plugin=e,this.event=i,this.channelId=s}async unregister(){return h(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}}async function m(n,e,i){const s=new g(i);try{return await h(`plugin:${n}|register_listener`,{event:e,handler:s}),new f(n,e,s.id)}catch{return await h(`plugin:${n}|registerListener`,{event:e,handler:s}),new f(n,e,s.id)}}async function I(n){return h(`plugin:${n}|check_permissions`)}async function C(n){return h(`plugin:${n}|request_permissions`)}async function h(n,e={},i){return window.__TAURI_INTERNALS__.invoke(n,e,i)}function T(n,e="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(n,e)}class k{get rid(){return t(this,u,"f")}constructor(e){u.set(this,void 0),c(this,u,e)}async close(){return h("plugin:resources|close",{rid:this.rid})}}u=new WeakMap;function E(){return!!(globalThis||window).isTauri}export{g as Channel,f as PluginListener,k as Resource,d as SERIALIZE_TO_IPC_FN,m as addPluginListener,I as checkPermissions,T as convertFileSrc,h as invoke,E as isTauri,C as requestPermissions,w as transformCallback};
|
||||
@@ -0,0 +1,7 @@
|
||||
# Digital Employee Static Assets
|
||||
|
||||
This directory is owned by the React digital employee frontend.
|
||||
|
||||
- `avatars/` keeps the original digital employee character images used by the home page `Avatar3D` stage.
|
||||
- Do not place the legacy Vue standalone application bundle here.
|
||||
- If an avatar file is renamed, update `src/pages/digital/CommandDeck.tsx` in the same change.
|
||||
|
After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 483 KiB |
|
After Width: | Height: | Size: 507 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 552 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="color-scheme" content="dark" />
|
||||
<link rel="icon" type="image/png" href="/sgrobot-digital/logo.png" />
|
||||
<title>sgRobot</title>
|
||||
<script>
|
||||
window.__TAURI__ = window.__TAURI__ || {};
|
||||
</script>
|
||||
<script type="module" crossorigin src="/sgrobot-digital/assets/index-DwDxQhF4.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/sgrobot-digital/assets/index-BTJFqpbJ.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 2.1 MiB |
@@ -0,0 +1,660 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>sgRobot 业务流程与架构模块映射</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
.theme-dark-blue { background-color: #0d2758; }
|
||||
.theme-text-dark-blue { color: #0d2758; }
|
||||
.theme-light-blue-bg { background-color: #f0f6fc; }
|
||||
.theme-border-blue { border-color: #aec3db; }
|
||||
.theme-red { color: #d92d20; }
|
||||
|
||||
body {
|
||||
font-family: "PingFang SC", "Microsoft YaHei", "Noto Sans SC", "Source Han Sans SC", Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.text-xs { font-size: 0.92rem !important; }
|
||||
.text-sm { font-size: 1.08rem !important; }
|
||||
.text-base { font-size: 1.24rem !important; }
|
||||
.text-lg { font-size: 1.4rem !important; }
|
||||
.text-xl { font-size: 1.62rem !important; }
|
||||
.text-3xl { font-size: 2.75rem !important; }
|
||||
.text-\[13px\] { font-size: 1.14rem !important; }
|
||||
|
||||
[data-tip] {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.module-map {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.module-card {
|
||||
border: 1px solid #aec3db;
|
||||
border-radius: 8px;
|
||||
background: white;
|
||||
box-shadow: 0 6px 16px rgba(13, 39, 88, 0.07);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.module-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 12px;
|
||||
color: white;
|
||||
background: #0d2758;
|
||||
font-weight: 800;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.module-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
padding: 10px;
|
||||
background: #f0f6fc;
|
||||
}
|
||||
|
||||
.module-pill {
|
||||
border: 1px solid #c8d7e8;
|
||||
border-radius: 999px;
|
||||
padding: 3px 9px;
|
||||
background: white;
|
||||
color: #0d2758;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.flow-card {
|
||||
border: 1px solid #aec3db;
|
||||
border-radius: 8px;
|
||||
background: white;
|
||||
box-shadow: 0 8px 20px rgba(13, 39, 88, 0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.flow-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 14px 16px 10px 16px;
|
||||
border-bottom: 1px solid #d8e4f2;
|
||||
}
|
||||
|
||||
.flow-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: #0d2758;
|
||||
font-weight: 800;
|
||||
font-size: 1.22rem;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.flow-tag {
|
||||
border: 1px solid #c8d7e8;
|
||||
border-radius: 999px;
|
||||
padding: 3px 10px;
|
||||
color: #5f7082;
|
||||
background: #f8fbff;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.flow-note {
|
||||
padding: 9px 16px;
|
||||
background: #f8fbff;
|
||||
color: #5f7082;
|
||||
border-bottom: 1px solid #d8e4f2;
|
||||
font-weight: 700;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.swimlane-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.lane {
|
||||
min-width: 1080px;
|
||||
display: grid;
|
||||
grid-template-columns: 220px minmax(0, 1fr);
|
||||
border-bottom: 1px solid #d8e4f2;
|
||||
background: #f0f6fc;
|
||||
}
|
||||
|
||||
.lane:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.lane-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
min-height: 54px;
|
||||
padding: 10px 12px;
|
||||
background: #0d2758;
|
||||
color: white;
|
||||
font-weight: 800;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.lane-body {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
gap: 10px;
|
||||
min-height: 118px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.module-node {
|
||||
min-width: 180px;
|
||||
flex: 1 1 0;
|
||||
border: 1px solid #c8d7e8;
|
||||
border-left: 5px solid #0d2758;
|
||||
border-radius: 7px;
|
||||
background: white;
|
||||
color: #0d2758;
|
||||
padding: 9px 10px 10px 10px;
|
||||
box-shadow: 0 2px 8px rgba(13, 39, 88, 0.06);
|
||||
}
|
||||
|
||||
.module-node.risk {
|
||||
border-left-color: #d92d20;
|
||||
}
|
||||
|
||||
.module-node.memory {
|
||||
border-left-color: #7a5af8;
|
||||
}
|
||||
|
||||
.module-node.service {
|
||||
border-left-color: #00856f;
|
||||
}
|
||||
|
||||
.node-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.node-number {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 999px;
|
||||
color: white;
|
||||
background: #0d2758;
|
||||
font-weight: 800;
|
||||
font-size: 0.8rem;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.module-node.risk .node-number {
|
||||
background: #d92d20;
|
||||
}
|
||||
|
||||
.module-node.memory .node-number {
|
||||
background: #7a5af8;
|
||||
}
|
||||
|
||||
.module-node.service .node-number {
|
||||
background: #00856f;
|
||||
}
|
||||
|
||||
.node-module {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
max-width: 100%;
|
||||
border: 1px solid #c8d7e8;
|
||||
border-radius: 999px;
|
||||
background: #f8fbff;
|
||||
padding: 2px 8px;
|
||||
color: #5f7082;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 800;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.node-title {
|
||||
display: block;
|
||||
font-weight: 900;
|
||||
line-height: 1.25;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.node-desc {
|
||||
display: block;
|
||||
color: #5f7082;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.legend {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
border: 1px solid #c8d7e8;
|
||||
border-radius: 999px;
|
||||
background: white;
|
||||
color: #0d2758;
|
||||
padding: 5px 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.legend-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 999px;
|
||||
background: #0d2758;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.legend-dot.risk {
|
||||
background: #d92d20;
|
||||
}
|
||||
|
||||
.legend-dot.memory {
|
||||
background: #7a5af8;
|
||||
}
|
||||
|
||||
.legend-dot.service {
|
||||
background: #00856f;
|
||||
}
|
||||
|
||||
#sg-tooltip {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
max-width: 440px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 6px;
|
||||
background: #0d2758;
|
||||
color: white;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.45;
|
||||
box-shadow: 0 12px 32px rgba(13, 39, 88, 0.22);
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transform: translateY(4px);
|
||||
transition: opacity 0.12s ease, transform 0.12s ease;
|
||||
}
|
||||
|
||||
#sg-tooltip.is-visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.module-map {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.module-map {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.flow-head {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.lane {
|
||||
min-width: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.lane-body {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.module-node {
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-white p-4 md:p-8 min-h-screen text-sm select-none">
|
||||
|
||||
<nav class="max-w-[1780px] mx-auto mb-5 flex flex-wrap items-center justify-between gap-3 border border-blue-200 rounded-lg px-4 py-3 shadow-sm bg-white">
|
||||
<div class="flex items-center gap-2 theme-text-dark-blue font-bold text-base" data-tip="汇报专用静态网站,可直接双击 index.html 打开,不需要启动本地服务。">
|
||||
<i class="fa-solid fa-display"></i>
|
||||
<span>sgRobot 汇报静态网站</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="index.html" class="border theme-border-blue theme-text-dark-blue rounded px-4 py-2 font-bold bg-white hover:bg-blue-50" data-tip="返回 sgRobot 的目标态业务架构总览。">业务架构总览</a>
|
||||
<a href="flows.html" class="theme-dark-blue text-white rounded px-4 py-2 font-bold shadow-sm" data-tip="当前页面展示业务流程如何落到架构模块。">业务流程图</a>
|
||||
<a href="roadmap.html" class="border theme-border-blue theme-text-dark-blue rounded px-4 py-2 font-bold bg-white hover:bg-blue-50" data-tip="查看五月底上线倒排的里程碑、分工边界和验收口径。">里程碑与分工</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<header class="max-w-[1780px] mx-auto mb-6">
|
||||
<div class="flex items-center mb-2" data-tip="本页展示业务流程与架构模块的对应关系,不再只画孤立步骤。">
|
||||
<div class="w-10 h-10 theme-dark-blue text-white flex items-center justify-center rounded shadow-sm mr-3">
|
||||
<i class="fa-solid fa-route text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold theme-text-dark-blue tracking-wide">sgRobot <span class="font-bold">业务流程与架构模块映射</span></h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-14 text-[13px] font-medium text-gray-700 leading-relaxed" data-tip="每条流程按架构图的上下分层来摆放,节点上的小标签标明它落到哪个具体模块。">
|
||||
读图方式:每张流程图按<span class="font-bold">四个架构分区</span>自上而下展开,节点编号表示业务先后顺序,节点标签表示承接该动作的<span class="theme-red font-bold">具体架构模块</span>。
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="max-w-[1780px] mx-auto flex flex-col gap-5">
|
||||
<section class="border-2 theme-border-blue rounded-lg p-4 bg-white shadow-sm" data-tip="这里先把架构图中的四个分区和模块列出来,后续每个流程节点都会引用这些模块。">
|
||||
<div class="flex flex-wrap items-center justify-between gap-3 mb-4">
|
||||
<div class="font-bold theme-text-dark-blue text-lg flex items-center gap-2">
|
||||
<i class="fa-solid fa-layer-group"></i>
|
||||
<span>架构模块对照</span>
|
||||
</div>
|
||||
<div class="legend">
|
||||
<span class="legend-item" data-tip="蓝色节点表示常规业务动作。"><span class="legend-dot"></span>常规动作</span>
|
||||
<span class="legend-item" data-tip="红色节点表示需要人工判断、风险确认或异常处置。"><span class="legend-dot risk"></span>风险决策</span>
|
||||
<span class="legend-item" data-tip="绿色节点表示按需后台服务、设备连接或外部系统协作。"><span class="legend-dot service"></span>服务协作</span>
|
||||
<span class="legend-item" data-tip="紫色节点表示结果、经验、规则或过程记录沉淀。"><span class="legend-dot memory"></span>记录沉淀</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="module-map">
|
||||
<div class="module-card" data-tip="业务入口与协同负责把人的需求、系统事件和审批动作接进系统。">
|
||||
<div class="module-title"><i class="fa-solid fa-right-to-bracket"></i><span>业务入口与协同</span></div>
|
||||
<div class="module-list">
|
||||
<span class="module-pill" data-tip="接收人工提交、系统接口、计划任务和事件触发。">业务需求入口</span>
|
||||
<span class="module-pill" data-tip="让用户、运维和审批人查看、操作、审批、回放和验收成果。">协同工作台</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="module-card" data-tip="任务治理与风控负责计划拆解、任务执行管理、人工治理和风险规则。">
|
||||
<div class="module-title"><i class="fa-solid fa-shield-halved"></i><span>任务治理与风控</span></div>
|
||||
<div class="module-list">
|
||||
<span class="module-pill" data-tip="把业务目标拆成执行计划和计划步骤。">目标计划管理</span>
|
||||
<span class="module-pill" data-tip="管理工作任务、执行记录、重试、恢复点和超时。">任务执行管理</span>
|
||||
<span class="module-pill" data-tip="承接审批、暂停、恢复、取消、人工接管和重新规划。">人工治理</span>
|
||||
<span class="module-pill" data-tip="管理记忆规则、服务占用、风险等级和健康状态。">风险与规则</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="module-card" data-tip="自动执行与能力负责真正完成业务动作,并管理外部系统、设备和后台服务。">
|
||||
<div class="module-title"><i class="fa-solid fa-gears"></i><span>自动执行与能力</span></div>
|
||||
<div class="module-list">
|
||||
<span class="module-pill" data-tip="登记可被调度使用的自动化能力。">能力目录</span>
|
||||
<span class="module-pill" data-tip="检查前置条件、匹配能力、安排顺序和失败恢复。">调度中枢</span>
|
||||
<span class="module-pill" data-tip="执行规则清楚、结果稳定、可重复的任务。">自动脚本</span>
|
||||
<span class="module-pill" data-tip="把多步骤工作组织成可治理流程。">流程编排</span>
|
||||
<span class="module-pill" data-tip="辅助规划、解释、诊断和修复建议。">智能辅助</span>
|
||||
<span class="module-pill" data-tip="对接网页、业务系统、设备和机器人。">外部系统适配</span>
|
||||
<span class="module-pill" data-tip="按需启动和回收邮件读取、监听器、浏览器环境等后台服务。">按需后台服务</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="module-card" data-tip="运营记录与看板沉淀过程、成果、经验和指标,让管理者看到进度、风险和结果。">
|
||||
<div class="module-title"><i class="fa-solid fa-chart-column"></i><span>运营记录与看板</span></div>
|
||||
<div class="module-list">
|
||||
<span class="module-pill" data-tip="保存计划、任务、执行和审批的当前状态。">业务状态台账</span>
|
||||
<span class="module-pill" data-tip="记录关键过程变化,用于回放、审计和问题追踪。">过程日志</span>
|
||||
<span class="module-pill" data-tip="保存文件、报告、截图和数据结果。">成果资料库</span>
|
||||
<span class="module-pill" data-tip="沉淀项目事实、偏好、关键决策、处理经验和观察摘要。">经验与记忆库</span>
|
||||
<span class="module-pill" data-tip="展示任务看板、审批队列、记忆索引和服务健康。">运营看板</span>
|
||||
<span class="module-pill" data-tip="按时间顺序展示过程回放、诊断和追责。">全程追踪</span>
|
||||
<span class="module-pill" data-tip="统计服务时效、成功率、响应耗时和人工介入率。">运营指标</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="flow-root" class="flex flex-col gap-5"></div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const lanes = [
|
||||
{ key: "entry", icon: "fa-right-to-bracket", name: "业务入口与协同", tip: "对应架构图第一分区:业务需求入口和协同工作台。" },
|
||||
{ key: "governance", icon: "fa-shield-halved", name: "任务治理与风控", tip: "对应架构图第二分区:目标计划管理、任务执行管理、人工治理、风险与规则。" },
|
||||
{ key: "execution", icon: "fa-gears", name: "自动执行与能力", tip: "对应架构图第三分区:能力目录、调度中枢、自动脚本、流程编排、智能辅助、外部系统适配、按需后台服务。" },
|
||||
{ key: "records", icon: "fa-chart-column", name: "运营记录与看板", tip: "对应架构图第四分区:业务状态台账、过程日志、成果资料库、经验与记忆库、运营看板、全程追踪、运营指标。" },
|
||||
];
|
||||
|
||||
const flows = [
|
||||
{
|
||||
title: "人工交办任务处理",
|
||||
icon: "fa-user-pen",
|
||||
tag: "用户主动发起",
|
||||
tip: "用户主动提交目标后,流程依次经过需求入口、计划治理、自动执行、成果验收和经验沉淀。",
|
||||
nodes: [
|
||||
{ lane: "entry", step: 1, module: "协同工作台", title: "接收交办", desc: "目标、材料、期望结果", tip: "用户在协同工作台提交业务目标、背景材料和验收要求。" },
|
||||
{ lane: "entry", step: 2, module: "业务需求入口", title: "登记目标", desc: "形成可追踪入口", tip: "业务需求入口把原始需求登记成可追踪的业务目标。" },
|
||||
{ lane: "governance", step: 3, module: "目标计划管理", title: "拆解计划", desc: "步骤、依赖、验收标准", tip: "目标计划管理把业务目标拆成执行计划、计划步骤、依赖和验收标准。" },
|
||||
{ lane: "governance", step: 4, module: "任务执行管理", title: "生成任务", desc: "排队、优先级、恢复点", tip: "任务执行管理把计划步骤转成工作任务,并设置优先级、重试和恢复点。" },
|
||||
{ lane: "execution", step: 5, module: "调度中枢", title: "匹配能力", desc: "脚本、流程、智能辅助", tip: "调度中枢为工作任务选择合适能力,并检查前置条件。" },
|
||||
{ lane: "execution", step: 6, module: "自动脚本 / 流程编排", title: "执行任务", desc: "自动处理并持续回写", tip: "自动执行模块完成实际业务动作,并持续回写过程状态和中间成果。" },
|
||||
{ lane: "governance", step: 7, module: "人工治理", title: "成果验收", desc: "确认、退回、接管", type: "risk", tip: "人工治理负责成果确认、退回重做、暂停或人工接管。" },
|
||||
{ lane: "records", step: 8, module: "成果资料库 / 运营看板", title: "成果呈现", desc: "报告、截图、任务看板", type: "memory", tip: "成果资料库保存交付物,运营看板展示任务状态和验收结果。" },
|
||||
{ lane: "records", step: 9, module: "经验与记忆库", title: "经验沉淀", desc: "偏好、决策、处理经验", type: "memory", tip: "经验与记忆库沉淀用户偏好、关键决策和处理经验,供后续任务复用。" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "邮件与消息触发处理",
|
||||
icon: "fa-envelope-open-text",
|
||||
tag: "事件自动触发",
|
||||
tip: "邮件、消息或业务通知到达后,按需服务先把事件读入,再由治理模块判断是否生成任务。",
|
||||
nodes: [
|
||||
{ lane: "execution", step: 1, module: "按需后台服务", title: "启动读取服务", desc: "邮件、监听器、消息", type: "service", tip: "按需后台服务在需要时启动邮件读取或消息监听,不要求所有服务随主程序常驻。" },
|
||||
{ lane: "entry", step: 2, module: "业务需求入口", title: "接收事件", desc: "通知、邮件、业务提醒", tip: "业务需求入口把读取到的消息统一登记为事件或待判断请求。" },
|
||||
{ lane: "governance", step: 3, module: "风险与规则", title: "分类判断", desc: "优先级、风险、是否自动处理", type: "risk", tip: "风险与规则判断消息类别、优先级、影响范围,以及是否需要人工确认。" },
|
||||
{ lane: "governance", step: 4, module: "目标计划管理", title: "生成目标或任务", desc: "纳入统一治理", tip: "符合条件的消息会被转成业务目标、执行计划或工作任务。" },
|
||||
{ lane: "execution", step: 5, module: "调度中枢 / 自动脚本", title: "自动处理", desc: "回复、归档、提取、触发后续流程", tip: "调度中枢选择处理能力,自动完成回复、归档、数据提取或后续流程触发。" },
|
||||
{ lane: "governance", step: 6, module: "人工治理", title: "异常转人工", desc: "审批、补充、接管", type: "risk", tip: "遇到权限、金额、外部影响或识别不确定时,进入人工审批或人工接管。" },
|
||||
{ lane: "records", step: 7, module: "过程日志 / 运营看板", title: "记录处理结果", desc: "结果、风险、处理人", type: "memory", tip: "过程日志记录处理过程,运营看板展示处理结果、风险状态和责任人。" },
|
||||
{ lane: "records", step: 8, module: "经验与记忆库", title: "更新规则经验", desc: "分类经验、处理偏好", type: "memory", tip: "消息分类、人工判断和处理偏好沉淀为后续自动判断依据。" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "定时巡检与报告",
|
||||
icon: "fa-calendar-check",
|
||||
tag: "周期运营任务",
|
||||
tip: "周期巡检从计划任务入口进入,经过巡检计划、外部采集、报告生成和运营指标沉淀。",
|
||||
nodes: [
|
||||
{ lane: "entry", step: 1, module: "业务需求入口", title: "排程触发", desc: "日常、周报、月报", tip: "业务需求入口接收计划任务触发,启动周期巡检流程。" },
|
||||
{ lane: "governance", step: 2, module: "目标计划管理", title: "生成巡检计划", desc: "对象、范围、标准", tip: "目标计划管理根据巡检对象、范围、责任人和验收标准生成计划。" },
|
||||
{ lane: "governance", step: 3, module: "任务执行管理", title: "安排巡检任务", desc: "批次、优先级、超时", tip: "任务执行管理把巡检计划拆成工作任务,并配置批次、优先级和超时管控。" },
|
||||
{ lane: "execution", step: 4, module: "外部系统适配", title: "连接巡检对象", desc: "系统、网页、设备", type: "service", tip: "外部系统适配连接业务系统、网页、设备或机器人,准备采集信息。" },
|
||||
{ lane: "execution", step: 5, module: "自动脚本 / 智能辅助", title: "采集并生成报告", desc: "指标、截图、结论", tip: "自动脚本采集数据,智能辅助整理结论、异常和建议。" },
|
||||
{ lane: "records", step: 6, module: "成果资料库", title: "归档报告证据", desc: "报告、截图、数据结果", type: "memory", tip: "成果资料库保存巡检报告、截图和数据结果,支撑验收和复盘。" },
|
||||
{ lane: "records", step: 7, module: "运营指标", title: "更新运营指标", desc: "趋势、成功率、耗时", type: "memory", tip: "运营指标沉淀巡检趋势、执行成功率、响应耗时和服务时效。" },
|
||||
{ lane: "governance", step: 8, module: "人工治理", title: "异常升级", desc: "告警、确认、复盘", type: "risk", tip: "发现异常、超时或失败率升高时,转人工确认、升级和复盘。" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "高风险动作审批",
|
||||
icon: "fa-shield-halved",
|
||||
tag: "人控关键节点",
|
||||
tip: "高风险动作通过风险规则识别,在执行前转入人工治理,并在全程追踪中留痕。",
|
||||
nodes: [
|
||||
{ lane: "governance", step: 1, module: "风险与规则", title: "识别风险动作", desc: "权限、影响、不可逆", type: "risk", tip: "风险与规则识别删除、发布、付款、发信、改配置、控制设备等高风险动作。" },
|
||||
{ lane: "governance", step: 2, module: "任务执行管理", title: "暂停在风险点", desc: "停止继续执行", type: "risk", tip: "任务执行管理把流程暂停在风险节点,避免未经确认继续执行。" },
|
||||
{ lane: "entry", step: 3, module: "协同工作台", title: "呈现审批材料", desc: "原因、影响、建议", type: "risk", tip: "协同工作台向审批人展示目标、原因、影响范围、可选方案和建议动作。" },
|
||||
{ lane: "governance", step: 4, module: "人工治理", title: "审批决策", desc: "通过、拒绝、接管、重规划", type: "risk", tip: "人工治理承接审批通过、拒绝、补充材料、人工接管或重新规划。" },
|
||||
{ lane: "execution", step: 5, module: "调度中枢", title: "执行分支", desc: "继续、取消、转人工", tip: "调度中枢根据审批结论继续执行、取消任务或转人工处理。" },
|
||||
{ lane: "records", step: 6, module: "全程追踪", title: "审批留痕", desc: "谁、何时、为何", type: "memory", tip: "全程追踪记录审批人、审批时间、审批理由和最终结果。" },
|
||||
{ lane: "records", step: 7, module: "经验与记忆库", title: "沉淀审批边界", desc: "规则、案例、判断依据", type: "memory", tip: "审批案例会沉淀为后续风险判断、审批边界和培训材料。" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "外部系统与设备协作",
|
||||
icon: "fa-plug-circle-bolt",
|
||||
tag: "跨系统协作",
|
||||
tip: "跨系统任务通过服务准备、外部适配、状态回写和成果归档,把网页、设备和机器人纳入统一治理。",
|
||||
nodes: [
|
||||
{ lane: "entry", step: 1, module: "业务需求入口", title: "协作请求进入", desc: "业务系统、人、计划任务", tip: "业务需求入口接收需要外部系统、设备或机器人参与的协作请求。" },
|
||||
{ lane: "governance", step: 2, module: "风险与规则", title: "检查权限与服务占用", desc: "账号、设备、占用关系", type: "risk", tip: "风险与规则检查权限、账号、设备状态和后台服务占用关系。" },
|
||||
{ lane: "execution", step: 3, module: "按需后台服务", title: "准备运行环境", desc: "浏览器环境、连接、服务实例", type: "service", tip: "按需后台服务准备浏览器环境、设备连接或外部服务实例。" },
|
||||
{ lane: "execution", step: 4, module: "外部系统适配", title: "执行外部动作", desc: "网页、设备、机器人", type: "service", tip: "外部系统适配执行网页操作、设备控制或机器人动作。" },
|
||||
{ lane: "records", step: 5, module: "业务状态台账", title: "状态回写", desc: "进度、异常、服务健康", type: "memory", tip: "业务状态台账记录进度、异常和服务健康,供治理流程继续判断。" },
|
||||
{ lane: "governance", step: 6, module: "任务执行管理", title: "异常恢复", desc: "重试、替代、接管", type: "risk", tip: "外部系统不可用、设备异常或页面变化时,任务执行管理负责重试、替代路径或人工接管。" },
|
||||
{ lane: "records", step: 7, module: "成果资料库 / 全程追踪", title: "成果归档", desc: "证据、状态、经验", type: "memory", tip: "最终成果、截图证据、设备状态和处理过程统一归档。" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "失败恢复与复盘改进",
|
||||
icon: "fa-screwdriver-wrench",
|
||||
tag: "持续改进闭环",
|
||||
tip: "失败不是只停在报错,而是由记录层提供证据,治理层决策恢复路径,执行层重试,最后沉淀规则。",
|
||||
nodes: [
|
||||
{ lane: "records", step: 1, module: "过程日志", title: "发现失败事实", desc: "失败、超时、不达标", type: "risk", tip: "过程日志记录任务失败、超时、外部异常或成果不达标。" },
|
||||
{ lane: "records", step: 2, module: "全程追踪", title: "汇总证据", desc: "过程、截图、状态", type: "memory", tip: "全程追踪汇总过程记录、截图、服务状态和最近变更。" },
|
||||
{ lane: "execution", step: 3, module: "智能辅助", title: "自动诊断", desc: "原因、影响、建议", tip: "智能辅助根据证据给出可能原因、影响范围和修复建议。" },
|
||||
{ lane: "governance", step: 4, module: "任务执行管理", title: "选择恢复路径", desc: "重试、替代、回退", type: "risk", tip: "任务执行管理根据风险和预算选择自动重试、替代能力或回退路径。" },
|
||||
{ lane: "execution", step: 5, module: "调度中枢", title: "执行恢复方案", desc: "重新调度、替代执行", tip: "调度中枢安排重试、替代能力或补偿步骤。" },
|
||||
{ lane: "governance", step: 6, module: "人工治理", title: "人工介入", desc: "补充、确认、接管", type: "risk", tip: "自动恢复仍不可靠或风险较高时,人工治理负责补充信息、确认方案或接管执行。" },
|
||||
{ lane: "records", step: 7, module: "经验与记忆库", title: "复盘沉淀", desc: "原因、方法、预防", type: "memory", tip: "处理完成后沉淀失败原因、修复方法、适用条件和预防建议。" },
|
||||
{ lane: "governance", step: 8, module: "风险与规则", title: "优化规则", desc: "减少重复失败", type: "memory", tip: "复盘结果转化为规则、能力说明、巡检项或审批边界优化。" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
function escapeHtml(value) {
|
||||
return String(value)
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """);
|
||||
}
|
||||
|
||||
function renderNode(node) {
|
||||
const type = node.type ? ` ${escapeHtml(node.type)}` : "";
|
||||
return `
|
||||
<div class="module-node${type}" data-tip="${escapeHtml(node.tip)}">
|
||||
<div class="node-top">
|
||||
<span class="node-number">${escapeHtml(node.step)}</span>
|
||||
<span class="node-module">${escapeHtml(node.module)}</span>
|
||||
</div>
|
||||
<span class="node-title">${escapeHtml(node.title)}</span>
|
||||
<span class="node-desc">${escapeHtml(node.desc)}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderFlow(flow) {
|
||||
const lanesHtml = lanes.map((lane) => {
|
||||
const nodes = flow.nodes
|
||||
.filter((node) => node.lane === lane.key)
|
||||
.sort((a, b) => a.step - b.step)
|
||||
.map(renderNode)
|
||||
.join("");
|
||||
return `
|
||||
<div class="lane" data-tip="${escapeHtml(lane.tip)}">
|
||||
<div class="lane-head">
|
||||
<span><i class="fa-solid ${escapeHtml(lane.icon)} mr-1"></i>${escapeHtml(lane.name)}</span>
|
||||
</div>
|
||||
<div class="lane-body">${nodes}</div>
|
||||
</div>
|
||||
`;
|
||||
}).join("");
|
||||
return `
|
||||
<section class="flow-card" data-tip="${escapeHtml(flow.tip)}">
|
||||
<div class="flow-head">
|
||||
<div class="flow-title">
|
||||
<i class="fa-solid ${escapeHtml(flow.icon)}"></i>
|
||||
<span>${escapeHtml(flow.title)}</span>
|
||||
</div>
|
||||
<span class="flow-tag" data-tip="${escapeHtml(flow.tip)}">${escapeHtml(flow.tag)}</span>
|
||||
</div>
|
||||
<div class="flow-note" data-tip="节点按数字读,四层顺序与架构图一致;有些流程会在治理、执行和记录之间回流。">
|
||||
节点按数字读;每一层就是架构图中的一个分区,节点标签就是承接该步骤的具体模块。
|
||||
</div>
|
||||
<div class="swimlane-grid">${lanesHtml}</div>
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
|
||||
document.getElementById("flow-root").innerHTML = flows.map(renderFlow).join("");
|
||||
|
||||
const tooltip = document.createElement("div");
|
||||
tooltip.id = "sg-tooltip";
|
||||
document.body.appendChild(tooltip);
|
||||
|
||||
let activeTipTarget = null;
|
||||
|
||||
function positionTooltip(event) {
|
||||
const margin = 14;
|
||||
const offset = 16;
|
||||
const rect = tooltip.getBoundingClientRect();
|
||||
let left = event.clientX + offset;
|
||||
let top = event.clientY + offset;
|
||||
|
||||
if (left + rect.width + margin > window.innerWidth) {
|
||||
left = Math.max(margin, event.clientX - rect.width - offset);
|
||||
}
|
||||
if (top + rect.height + margin > window.innerHeight) {
|
||||
top = Math.max(margin, event.clientY - rect.height - offset);
|
||||
}
|
||||
|
||||
tooltip.style.left = `${left}px`;
|
||||
tooltip.style.top = `${top}px`;
|
||||
}
|
||||
|
||||
function showTooltip(target, event) {
|
||||
const text = target.dataset.tip;
|
||||
if (!text) return;
|
||||
activeTipTarget = target;
|
||||
tooltip.textContent = text;
|
||||
tooltip.classList.add("is-visible");
|
||||
positionTooltip(event);
|
||||
}
|
||||
|
||||
function hideTooltip() {
|
||||
activeTipTarget = null;
|
||||
tooltip.classList.remove("is-visible");
|
||||
}
|
||||
|
||||
document.addEventListener("pointerover", (event) => {
|
||||
const target = event.target.closest("[data-tip]");
|
||||
if (target) showTooltip(target, event);
|
||||
});
|
||||
|
||||
document.addEventListener("pointermove", (event) => {
|
||||
if (activeTipTarget) positionTooltip(event);
|
||||
});
|
||||
|
||||
document.addEventListener("pointerout", (event) => {
|
||||
if (!activeTipTarget) return;
|
||||
const next = event.relatedTarget;
|
||||
if (!next || !activeTipTarget.contains(next)) hideTooltip();
|
||||
});
|
||||
|
||||
document.querySelectorAll("[data-tip]").forEach((element) => {
|
||||
element.setAttribute("tabindex", "0");
|
||||
element.setAttribute("aria-label", element.dataset.tip);
|
||||
element.addEventListener("focus", (event) => {
|
||||
const rect = event.currentTarget.getBoundingClientRect();
|
||||
showTooltip(event.currentTarget, {
|
||||
clientX: rect.left + rect.width / 2,
|
||||
clientY: rect.top + rect.height / 2,
|
||||
});
|
||||
});
|
||||
element.addEventListener("blur", hideTooltip);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,650 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>sgRobot 目标态业务架构</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
/* 自定义一些特定颜色以更贴近原图 */
|
||||
.theme-dark-blue { background-color: #0d2758; }
|
||||
.theme-text-dark-blue { color: #0d2758; }
|
||||
.theme-light-blue-bg { background-color: #f0f6fc; }
|
||||
.theme-border-blue { border-color: #aec3db; }
|
||||
.theme-text-gray { color: #5f7082; }
|
||||
.theme-red { color: #d92d20; }
|
||||
|
||||
/* 连接线箭头样式辅助 */
|
||||
.arrow-right-solid {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 5px solid transparent;
|
||||
border-bottom: 5px solid transparent;
|
||||
border-left: 8px solid #0d2758;
|
||||
}
|
||||
.arrow-down-solid {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-top: 8px solid #0d2758;
|
||||
}
|
||||
|
||||
/* 用于核心闭环的虚线箭头 */
|
||||
.dashed-arrow-line {
|
||||
background-image: linear-gradient(to right, #d92d20 50%, transparent 50%);
|
||||
background-size: 10px 2px;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.arrow-right-red {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 4px solid transparent;
|
||||
border-bottom: 4px solid transparent;
|
||||
border-left: 6px solid #d92d20;
|
||||
}
|
||||
.arrow-left-red {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 4px solid transparent;
|
||||
border-bottom: 4px solid transparent;
|
||||
border-right: 6px solid #d92d20;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "PingFang SC", "Microsoft YaHei", "Noto Sans SC", "Source Han Sans SC", Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* 汇报场景下整体字号再上调一档,兼顾投屏可读性 */
|
||||
.text-xs { font-size: 0.92rem !important; }
|
||||
.text-sm { font-size: 1.08rem !important; }
|
||||
.text-base { font-size: 1.24rem !important; }
|
||||
.text-lg { font-size: 1.4rem !important; }
|
||||
.text-xl { font-size: 1.62rem !important; }
|
||||
.text-3xl { font-size: 2.75rem !important; }
|
||||
.text-\[9px\] { font-size: 0.82rem !important; }
|
||||
.text-\[10px\] { font-size: 0.92rem !important; }
|
||||
.text-\[11px\] { font-size: 1.02rem !important; }
|
||||
.text-\[13px\] { font-size: 1.14rem !important; }
|
||||
|
||||
/* 放大后给各层卡片更多高度,避免文字贴边 */
|
||||
.min-h-\[60px\] { min-height: 86px !important; }
|
||||
.min-h-\[65px\] { min-height: 92px !important; }
|
||||
.min-h-\[70px\] { min-height: 104px !important; }
|
||||
|
||||
[data-tip] {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.term-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px 6px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.term {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border: 1px solid #c8d7e8;
|
||||
border-radius: 999px;
|
||||
background: #f8fbff;
|
||||
padding: 2px 8px;
|
||||
color: #5f7082;
|
||||
font-size: 0.86rem;
|
||||
line-height: 1.35;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#sg-tooltip {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
max-width: 520px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 6px;
|
||||
background: #0d2758;
|
||||
color: white;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.45;
|
||||
white-space: pre-line;
|
||||
box-shadow: 0 12px 32px rgba(13, 39, 88, 0.22);
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transform: translateY(4px);
|
||||
transition: opacity 0.12s ease, transform 0.12s ease;
|
||||
}
|
||||
|
||||
#sg-tooltip.is-visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-white p-4 md:p-8 min-h-screen text-sm select-none">
|
||||
|
||||
<nav class="max-w-[1780px] mx-auto mb-5 flex flex-wrap items-center justify-between gap-3 border border-blue-200 rounded-lg px-4 py-3 shadow-sm bg-white">
|
||||
<div class="flex items-center gap-2 theme-text-dark-blue font-bold text-base" data-tip="汇报专用静态网站,可直接双击 index.html 打开,不需要启动本地服务。">
|
||||
<i class="fa-solid fa-display"></i>
|
||||
<span>sgRobot 汇报静态网站</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="index.html" class="theme-dark-blue text-white rounded px-4 py-2 font-bold shadow-sm" data-tip="查看 sgRobot 的目标态业务架构总览。">业务架构总览</a>
|
||||
<a href="flows.html" class="border theme-border-blue theme-text-dark-blue rounded px-4 py-2 font-bold bg-white hover:bg-blue-50" data-tip="查看几类典型业务如何进入、执行、沉淀和被人工治理。">业务流程图</a>
|
||||
<a href="roadmap.html" class="border theme-border-blue theme-text-dark-blue rounded px-4 py-2 font-bold bg-white hover:bg-blue-50" data-tip="查看五月底上线倒排的里程碑、分工边界和验收口径。">里程碑与分工</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="max-w-[1780px] mx-auto mb-6">
|
||||
<div class="flex items-center mb-2">
|
||||
<div class="w-10 h-10 theme-dark-blue text-white flex items-center justify-center rounded shadow-sm mr-3">
|
||||
<i class="fa-solid fa-cube text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold theme-text-dark-blue tracking-wide">sgRobot <span class="font-bold">目标态业务架构</span></h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-14 text-[13px] font-medium text-gray-700 leading-relaxed">
|
||||
围绕<span class="font-bold">业务入口</span>、<span class="font-bold">任务治理</span>、<span class="font-bold">自动执行</span>、<span class="theme-red font-bold">运营看板</span>四条主线,把目标接收、计划拆解、执行过程、人工决策、经验沉淀和后台服务统一纳入可管理的业务闭环。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="max-w-[1780px] mx-auto relative">
|
||||
|
||||
<!-- 顶层用户 -->
|
||||
<div class="flex justify-center mb-[-12px] relative z-10">
|
||||
<div class="bg-white border-2 theme-border-blue rounded-full px-10 py-2 flex items-center gap-3 shadow-sm" data-tip="系统的外部参与者。用户提交目标,运维关注健康与风险,审批人处理治理节点,外部业务系统可通过系统接口或业务事件触发任务。">
|
||||
<i class="fa-solid fa-user-group text-blue-600 text-lg"></i>
|
||||
<span class="font-bold theme-text-dark-blue text-base">
|
||||
<span data-tip="用户是目标和需求的主要提出者,可以发起任务、补充输入和接受结果。">用户</span> /
|
||||
<span data-tip="运维关注系统健康、服务状态、告警、失败恢复和上线风险。">运维</span> /
|
||||
<span data-tip="审批人负责处理高风险动作、外部副作用、权限边界和人工治理节点。">审批人</span> /
|
||||
<span data-tip="外部业务系统通过系统接口、消息或业务事件触发 sgRobot 工作流。">外部业务系统</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center mb-2 text-blue-600 text-lg">
|
||||
<i class="fa-solid fa-arrow-down"></i>
|
||||
</div>
|
||||
|
||||
<!-- 主结构外框 -->
|
||||
<div class="border-2 theme-border-blue rounded-lg p-3 pt-6 flex flex-col gap-2 relative bg-white">
|
||||
<div class="absolute right-[-10px] top-[15%] bottom-[15%] w-[20px] border-r-2 border-t-2 border-b-2 theme-border-blue rounded-r-lg z-0 opacity-50 hidden lg:block"></div>
|
||||
|
||||
<!-- Plane 1: 业务入口与协同 -->
|
||||
<div class="flex items-stretch border theme-border-blue rounded bg-white relative z-10">
|
||||
<div class="w-12 md:w-40 theme-dark-blue text-white flex flex-col items-center justify-center p-2 rounded-l flex-shrink-0" data-tip="业务入口与协同负责把人的需求、系统事件和业务审批统一接入,并把任务进展反馈给相关人员。">
|
||||
<div class="bg-white/20 px-2 py-1 rounded text-xs mb-1 font-mono">1</div>
|
||||
<span class="font-bold hidden md:block text-center leading-tight">业务入口与协同</span>
|
||||
<span class="font-bold md:hidden text-center writing-vertical-lr text-xs">入口协同</span>
|
||||
</div>
|
||||
<div class="flex-1 theme-light-blue-bg p-3 grid grid-cols-1 md:grid-cols-2 gap-4 rounded-r">
|
||||
<div class="bg-white border theme-border-blue rounded p-2 flex items-center gap-3 shadow-sm min-h-[60px] w-full" data-tip="业务需求入口把人工提交、接口调用、计划任务和事件触发统一登记为可跟踪的业务目标或处理请求。">
|
||||
<i class="fa-solid fa-arrow-right-to-bracket text-2xl theme-text-dark-blue ml-2"></i>
|
||||
<div>
|
||||
<div class="font-bold theme-text-dark-blue text-sm">业务需求入口</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="人工提交是用户在控制台或对话入口主动发起的目标。">人工提交</span>
|
||||
<span class="term" data-tip="系统接口让外部业务系统以结构化请求提交目标、状态或审批动作。">系统接口</span>
|
||||
<span class="term" data-tip="计划任务是按时间、周期或排程触发的目标入口。">计划任务</span>
|
||||
<span class="term" data-tip="事件触发来自邮件、系统通知、消息、文件变化或内部业务事件。">事件触发</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 flex items-center gap-3 shadow-sm min-h-[60px] w-full" data-tip="协同工作台让用户、运维和审批人查看进度、处理审批、回放过程和验收成果。">
|
||||
<i class="fa-solid fa-desktop text-2xl theme-text-dark-blue ml-2"></i>
|
||||
<div>
|
||||
<div class="font-bold theme-text-dark-blue text-sm">协同工作台</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="查看用于读取目标、计划、任务、执行记录、服务状态和经验记忆。">查看</span>
|
||||
<span class="term" data-tip="操作是用户对任务、服务、参数和视图发起的显式动作。">操作</span>
|
||||
<span class="term" data-tip="审批用于确认高风险动作、外部副作用或权限敏感步骤。">审批</span>
|
||||
<span class="term" data-tip="回放按事件时间线复原过程,用于诊断、复盘和追责。">回放</span>
|
||||
<span class="term" data-tip="成果浏览用于查看报告、截图、文件、日志快照和结构化结果。">成果浏览</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Plane 2: 任务治理与风控 -->
|
||||
<div class="flex items-stretch border theme-border-blue rounded bg-white relative z-10">
|
||||
<div class="w-12 md:w-40 theme-dark-blue text-white flex flex-col items-center justify-center p-2 rounded-l flex-shrink-0" data-tip="任务治理与风控负责把业务目标拆成计划和任务,并统一管理审批、风险、暂停、恢复、重试和服务占用规则。">
|
||||
<i class="fa-solid fa-sliders text-xl mb-1"></i>
|
||||
<span class="font-bold hidden md:block text-center leading-tight">任务治理与风控</span>
|
||||
<span class="font-bold md:hidden text-center writing-vertical-lr text-xs mt-2">任务风控</span>
|
||||
</div>
|
||||
<div class="flex-1 theme-light-blue-bg p-3 grid grid-cols-1 md:grid-cols-4 gap-3 rounded-r">
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[70px]" data-tip="目标与计划管理把原始目标转成可审查、可冻结、可重规划的计划结构。">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<i class="fa-solid fa-bullseye theme-text-dark-blue text-lg"></i>
|
||||
<span class="font-bold theme-text-dark-blue text-[13px]">目标计划管理</span>
|
||||
</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="业务目标是用户或外部系统想达成的结果,也是后续计划拆解的源头。">业务目标</span>
|
||||
<span class="term" data-tip="执行计划描述成功标准、风险、依赖和执行步骤。">执行计划</span>
|
||||
<span class="term" data-tip="计划步骤是计划中的单个动作,用于生成可调度的工作任务。">计划步骤</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[70px]" data-tip="任务执行管理负责从步骤生成任务,并管理执行尝试、失败恢复、服务占用和最终状态。">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<i class="fa-solid fa-list-ul theme-text-dark-blue text-lg"></i>
|
||||
<span class="font-bold theme-text-dark-blue text-[13px]">任务执行管理</span>
|
||||
</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="工作任务是可调度的工作单元,绑定能力、输入、依赖和优先级。">工作任务</span>
|
||||
<span class="term" data-tip="执行记录代表一次任务执行尝试,重试会产生新的执行记录。">执行记录</span>
|
||||
<span class="term" data-tip="自动重试是失败或中断后的再执行策略,受预算和风险约束。">自动重试</span>
|
||||
<span class="term" data-tip="恢复点是长任务的过程锚点,用于失败后恢复和问题诊断。">恢复点</span>
|
||||
<span class="term" data-tip="超时管控防止任务无限运行,超时后进入恢复或人工介入路径。">超时管控</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[70px]" data-tip="人工治理把人的介入变成可记录、可回放、可追责的业务操作,而不是后台直接改结果。">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<i class="fa-solid fa-user-check theme-text-dark-blue text-lg"></i>
|
||||
<span class="font-bold theme-text-dark-blue text-[13px]">人工治理</span>
|
||||
</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="审批通过允许高风险步骤、外部副作用或权限敏感动作继续执行。">审批通过</span>
|
||||
<span class="term" data-tip="暂停让人检查任务状态、参数、风险或依赖。">暂停</span>
|
||||
<span class="term" data-tip="恢复从暂停点继续执行,通常需要保留上下文和服务占用状态。">恢复</span>
|
||||
<span class="term" data-tip="取消终止任务或计划,并释放相关服务占用。">取消</span>
|
||||
<span class="term" data-tip="人工接管把自动执行转交给人工或指定操作者处理。">人工接管</span>
|
||||
<span class="term" data-tip="重新规划在现有目标下重新生成或修改执行路径。">重新规划</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[70px]" data-tip="风险与规则规定经验记忆怎么用、后台服务怎么占用、哪些动作必须审批、哪些状态必须进入看板。">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<i class="fa-solid fa-shield-halved theme-text-dark-blue text-lg"></i>
|
||||
<span class="font-bold theme-text-dark-blue text-[13px]">风险与规则</span>
|
||||
</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="记忆规则规定经验何时召回、写入、遗忘、替代或标记冲突。">记忆规则</span>
|
||||
<span class="term" data-tip="服务占用记录任务对后台服务的使用关系,防止误停和资源泄漏。">服务占用</span>
|
||||
<span class="term" data-tip="风险等级表示动作、任务、服务或记忆使用的风险级别和审批要求。">风险等级</span>
|
||||
<span class="term" data-tip="健康状态汇总任务、服务、通道和看板等关键组件是否正常。">健康状态</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Plane 3: 自动执行与能力 -->
|
||||
<div class="flex items-stretch border theme-border-blue rounded bg-white relative z-10">
|
||||
<div class="w-12 md:w-40 theme-dark-blue text-white flex flex-col items-center justify-center p-2 rounded-l flex-shrink-0" data-tip="自动执行与能力负责真正完成业务动作,包括脚本、流程、智能辅助、外部系统适配和按需后台服务。">
|
||||
<i class="fa-solid fa-gears text-xl mb-1"></i>
|
||||
<span class="font-bold hidden md:block text-center leading-tight">自动执行与能力</span>
|
||||
<span class="font-bold md:hidden text-center writing-vertical-lr text-xs mt-2">自动执行</span>
|
||||
</div>
|
||||
<div class="flex-1 theme-light-blue-bg p-3 grid grid-cols-1 md:grid-cols-7 gap-3 rounded-r">
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[60px]" data-tip="能力目录管理可治理自动化能力的登记、版本、使用约定、策略和健康。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-solid fa-box mr-1"></i>能力目录</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="能力登记把脚本、流程、智能辅助或外部适配纳入统一目录。">能力登记</span>
|
||||
<span class="term" data-tip="版本管理用于区分能力说明、实现和兼容边界。">版本管理</span>
|
||||
<span class="term" data-tip="使用约定说明输入、输出、成果和过程记录要求。">使用约定</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[60px]" data-tip="调度中枢负责检查前置条件、匹配自动化能力、安排执行顺序并处理失败恢复。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-solid fa-sitemap mr-1"></i>调度中枢</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="前置检查判断任务、服务、记忆、成果和审批之间的依赖是否满足。">前置检查</span>
|
||||
<span class="term" data-tip="能力匹配根据使用约定、风险、可用性和上下文选择合适能力。">能力匹配</span>
|
||||
<span class="term" data-tip="失败恢复处理回滚、替代路径、重试和人工兜底。">失败恢复</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[60px]" data-tip="自动脚本适合规则清楚、结果稳定、可重试、可审计的任务。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-solid fa-code mr-1"></i>自动脚本</div>
|
||||
<div class="term-list"><span class="term" data-tip="确定性任务适合明确输入输出,结果更容易测试和审计。">确定性任务</span></div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[60px]" data-tip="流程编排承载组合能力和子流程,把多步骤操作纳入统一治理。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-solid fa-diagram-project mr-1"></i>流程编排</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="组合能力把多个原子能力组合为一个可治理流程。">组合能力</span>
|
||||
<span class="term" data-tip="子流程是在一个任务内部继续拆分的执行片段。">子流程</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[60px]" data-tip="智能辅助用于规划、选择、解释和修复建议,但任务状态仍由治理流程统一管理。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-solid fa-brain mr-1"></i>智能辅助</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="规划用于把目标拆成可审查的计划和步骤。">规划</span>
|
||||
<span class="term" data-tip="修复建议用于失败诊断、替代能力和补偿路径建议。">修复建议</span>
|
||||
<span class="term" data-tip="解释用于说明计划、风险、失败原因和人工介入建议。">解释</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[60px]" data-tip="外部系统适配把网页、设备和机器人能力接入统一业务流程,避免各自独立运行、难以管理。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-solid fa-robot mr-1"></i>外部系统适配</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="网页操作用于网页、控制台和浏览器自动化能力。">网页操作</span>
|
||||
<span class="term" data-tip="设备接入用于连接硬件、串口、设备接口或外设能力。">设备接入</span>
|
||||
<span class="term" data-tip="机器人控制用于机器人本体能力,如感知、运动和语音。">机器人控制</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[60px]" data-tip="按需后台服务负责邮件读取、监听器、浏览器环境、配套后台程序和外部服务进程的启动、占用、健康、日志和空闲回收。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-solid fa-server mr-1"></i>按需后台服务</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="服务定义描述后台服务如何启动、停止、授权、检查健康和对外提供能力。">服务定义</span>
|
||||
<span class="term" data-tip="运行实例是服务的一次实际运行,记录访问地址、进程和状态。">运行实例</span>
|
||||
<span class="term" data-tip="占用关系表示某个任务正在依赖服务实例,决定服务是否能回收。">占用关系</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Plane 4: 运营记录与看板 -->
|
||||
<div class="flex items-stretch border theme-border-blue rounded bg-white relative z-10">
|
||||
<div class="w-12 md:w-40 theme-dark-blue text-white flex flex-col items-center justify-center p-2 rounded-l flex-shrink-0" data-tip="运营记录与看板沉淀业务过程、成果、经验和服务状态,让管理者能看进度、看风险、看结果、看责任。">
|
||||
<i class="fa-solid fa-database text-xl mb-1"></i>
|
||||
<span class="font-bold hidden md:block text-center leading-tight">运营记录与看板</span>
|
||||
<span class="font-bold md:hidden text-center writing-vertical-lr text-xs mt-2">运营看板</span>
|
||||
</div>
|
||||
<div class="flex-1 theme-light-blue-bg p-3 grid grid-cols-1 md:grid-cols-7 gap-3 rounded-r">
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[65px]" data-tip="业务状态台账保存计划、任务、执行记录和审批记录的当前状态,是进度和责任判断的依据。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-solid fa-lock mr-1"></i>业务状态台账</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="执行计划状态表示计划处于草稿、审核、激活、阻塞、完成或取消等阶段。">执行计划</span>
|
||||
<span class="term" data-tip="工作任务状态表示任务是否待处理、排队、执行中、暂停、失败或完成。">工作任务</span>
|
||||
<span class="term" data-tip="执行记录状态表示一次执行尝试的生命周期和健康信息。">执行记录</span>
|
||||
<span class="term" data-tip="审批记录状态表示审批请求是否待处理、已通过、已拒绝、已过期或已取消。">审批记录</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[65px]" data-tip="过程日志记录所有关键变化,是审计、回放、看板生成和问题追踪的基础。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-regular fa-file-lines mr-1"></i>过程日志</div>
|
||||
<div class="term-list"><span class="term" data-tip="关键过程记录是已经发生的业务变化,如任务开始、执行失败、服务启动或经验更新。">关键过程记录</span></div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[65px]" data-tip="成果资料库存放执行生成的文件、报告、截图和结构化数据结果。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-solid fa-folder-open mr-1"></i>成果资料库</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="文件是执行生成或引用的本地或远端文件产物。">文件</span>
|
||||
<span class="term" data-tip="报告是面向人或验收的总结性产物。">报告</span>
|
||||
<span class="term" data-tip="截图用于证明界面、网页、浏览器或视觉状态。">截图</span>
|
||||
<span class="term" data-tip="数据结果是可被系统继续读取的结构化数据、表格、记录或索引。">数据结果</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[65px]" data-tip="经验与记忆库存放可复用知识,不代表当前任务状态,必须受来源、置信度、保留和遗忘规则约束。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-solid fa-brain mr-1"></i>经验与记忆库</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="项目事实是相对稳定、可引用的信息,但仍应有来源和置信度。">项目事实</span>
|
||||
<span class="term" data-tip="使用偏好记录用户、项目或团队的长期选择倾向。">使用偏好</span>
|
||||
<span class="term" data-tip="关键决策记录已经确定的架构、流程、策略或边界选择。">关键决策</span>
|
||||
<span class="term" data-tip="处理经验记录过去执行中的成功路径、失败模式和修复方法。">处理经验</span>
|
||||
<span class="term" data-tip="观察摘要从邮件、消息、工单、服务日志或运行结果中提炼可复用结论。">观察摘要</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[65px]" data-tip="运营看板面向管理、查询和协同,由状态、过程日志、成果、经验记忆和服务健康汇总生成。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-solid fa-chart-column mr-1"></i>运营看板</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="任务看板展示任务状态、阻塞、风险和下一步动作。">任务看板</span>
|
||||
<span class="term" data-tip="审批队列集中展示等待人工处理的治理节点。">审批队列</span>
|
||||
<span class="term" data-tip="记忆索引让用户查看、修正、替代或遗忘长期记忆。">记忆索引</span>
|
||||
<span class="term" data-tip="服务健康展示服务实例、占用关系、重启和最近错误。">服务健康</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[65px]" data-tip="全程追踪按时间顺序展示计划、任务、执行、审批、服务和经验记忆变化。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-solid fa-clock-rotate-left mr-1"></i>全程追踪</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="过程回放按时间顺序复原业务过程和人工操作。">过程回放</span>
|
||||
<span class="term" data-tip="诊断用于定位失败原因、依赖问题、服务退化或策略阻塞。">诊断</span>
|
||||
<span class="term" data-tip="追责用于确认谁在什么时候通过什么操作改变了什么状态。">追责</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white border theme-border-blue rounded p-2 shadow-sm min-h-[65px]" data-tip="运营指标用于验收、运营和持续改进,衡量服务时效、成功率、响应耗时和人工介入率。">
|
||||
<div class="font-bold theme-text-dark-blue text-[13px]"><i class="fa-solid fa-chart-simple mr-1"></i>运营指标</div>
|
||||
<div class="term-list">
|
||||
<span class="term" data-tip="服务时效衡量任务、服务或工作流的服务水平和完成时限。">服务时效</span>
|
||||
<span class="term" data-tip="成功率衡量任务、能力、服务或计划执行成功的比例。">成功率</span>
|
||||
<span class="term" data-tip="响应耗时衡量目标接入、任务排队、执行、看板生成和审批等待时间。">响应耗时</span>
|
||||
<span class="term" data-tip="人工介入率衡量有多少任务需要审批、暂停、接管或人工修复。">人工介入率</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- End of Main Architecture Container -->
|
||||
|
||||
<!-- 核心闭环 -->
|
||||
<div class="mt-4 border border-blue-200 rounded flex overflow-hidden shadow-sm">
|
||||
<div class="w-16 md:w-24 theme-dark-blue text-white flex flex-col items-center justify-center p-2 flex-shrink-0" data-tip="核心闭环展示一次业务目标从接入、计划、执行、沉淀、看板到人工决策的完整路径。">
|
||||
<i class="fa-solid fa-rotate text-xl mb-1"></i>
|
||||
<span class="font-bold text-center text-xs md:text-sm">核心闭环</span>
|
||||
</div>
|
||||
<div class="flex-1 bg-white p-4 relative overflow-x-auto">
|
||||
<div class="flex items-center justify-between min-w-[1260px] mb-4 mt-2 px-4">
|
||||
<div class="flex items-center gap-1 font-bold theme-text-dark-blue" data-tip="业务目标是用户或外部系统想达成的结果,进入系统后会先转成可治理的执行计划。"><i class="fa-solid fa-bullseye mr-1"></i>业务目标</div>
|
||||
<i class="fa-solid fa-arrow-right text-blue-300 text-sm"></i>
|
||||
<div class="flex items-center gap-1 border border-blue-200 px-2 py-1 rounded theme-text-dark-blue" data-tip="执行计划描述为什么做、做成什么、如何拆,并支持人工审查、冻结和重新规划。"><i class="fa-regular fa-file-lines mr-1"></i>执行计划</div>
|
||||
<i class="fa-solid fa-arrow-right text-blue-300 text-sm"></i>
|
||||
<div class="flex items-center gap-1 border border-blue-200 px-2 py-1 rounded theme-text-dark-blue" data-tip="工作任务是由计划步骤拆出来的可调度工作单元,负责绑定能力、输入、优先级和依赖。"><i class="fa-solid fa-list-ul mr-1"></i>工作任务</div>
|
||||
<i class="fa-solid fa-arrow-right text-blue-300 text-sm"></i>
|
||||
<div class="flex items-center gap-1 border border-blue-200 px-2 py-1 rounded theme-text-dark-blue" data-tip="能力匹配为当前任务选择正式自动化能力或业务流程,必须满足版本、策略、权限和输入输出约定。"><i class="fa-solid fa-link mr-1"></i>能力匹配</div>
|
||||
<i class="fa-solid fa-arrow-right text-blue-300 text-sm"></i>
|
||||
<div class="flex items-center gap-1 border border-blue-200 px-2 py-1 rounded theme-text-dark-blue" data-tip="执行前准备需要召回的经验记忆、需要启动或占用的后台服务,例如邮件读取、浏览器环境或外部服务进程。"><i class="fa-solid fa-server mr-1"></i>经验与服务准备</div>
|
||||
<i class="fa-solid fa-arrow-right text-blue-300 text-sm"></i>
|
||||
<div class="flex items-center gap-1 border border-blue-200 px-2 py-1 rounded theme-text-dark-blue" data-tip="执行记录代表任务的一次执行尝试,记录执行人、服务占用、运行状态、恢复点和最终状态。"><i class="fa-regular fa-circle-play mr-1"></i>执行记录</div>
|
||||
<i class="fa-solid fa-arrow-right text-blue-300 text-sm"></i>
|
||||
<div class="flex items-center gap-1 font-bold theme-text-dark-blue" data-tip="自动执行阶段由脚本、流程、智能辅助或外部系统适配真正调用资源,并持续回写过程记录和状态。"><i class="fa-solid fa-gear mr-1"></i>自动执行</div>
|
||||
<i class="fa-solid fa-arrow-right text-blue-300 text-sm"></i>
|
||||
<div class="flex items-center gap-1 border border-blue-200 px-2 py-1 rounded theme-text-dark-blue bg-gray-50" data-tip="执行结果沉淀为业务状态、过程日志、成果资料和可复用经验,后续看板和审计都从这里生成。"><i class="fa-solid fa-database mr-1"></i>过程记录与成果沉淀</div>
|
||||
<i class="fa-solid fa-arrow-right text-blue-300 text-sm"></i>
|
||||
<div class="flex items-center gap-1 font-bold theme-text-dark-blue" data-tip="运营看板面向管理和查询,包括任务看板、全程追踪、审批队列、记忆索引和服务健康。"><i class="fa-solid fa-chart-column mr-1"></i>运营看板</div>
|
||||
<i class="fa-solid fa-arrow-right text-blue-300 text-sm"></i>
|
||||
<div class="flex items-center gap-1 font-bold theme-red border border-red-200 px-2 py-1 rounded" data-tip="人工决策允许审批、暂停、恢复、取消、接管和重新规划,并把每次干预记录下来。"><i class="fa-regular fa-user mr-1"></i>人工决策</div>
|
||||
</div>
|
||||
<!-- 底部虚线回环 -->
|
||||
<div class="relative mt-6 min-w-[1260px] h-4">
|
||||
<div class="absolute w-[80%] left-[10%] border-t border-dashed border-red-500 top-1/2"></div>
|
||||
<div class="absolute left-[10%] top-1/2 -mt-1"><div class="arrow-left-red"></div></div>
|
||||
<div class="absolute w-full flex justify-center -top-3">
|
||||
<span class="bg-white px-2 text-xs font-bold theme-red" data-tip="人工决策会回到计划或任务层,改变后续执行路径,而不是直接绕过业务流程。">审批 / 暂停 / 恢复 / 取消 / 人工接管 / 重新规划</span>
|
||||
</div>
|
||||
<!-- 垂直连接线 -->
|
||||
<div class="absolute left-[10%] bottom-1/2 h-4 border-l border-dashed border-red-500"></div>
|
||||
<div class="absolute right-[10%] bottom-1/2 h-6 border-r border-dashed border-red-500"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
const tooltip = document.createElement("div");
|
||||
tooltip.id = "sg-tooltip";
|
||||
document.body.appendChild(tooltip);
|
||||
|
||||
let activeTipTarget = null;
|
||||
|
||||
const exampleRules = [
|
||||
{ keys: ["汇报专用静态网站"], example: "双击 report-site/index.html 打开后,可在业务架构总览和业务流程图之间切换。" },
|
||||
{ keys: ["业务架构总览"], example: "汇报开场先用这一页讲清楚 sgRobot 的四个业务分区。" },
|
||||
{ keys: ["业务流程图"], example: "讲邮件触发流程时,可以切到流程页看它经过哪些架构模块。" },
|
||||
{ keys: ["外部参与者"], example: "业务人员提交目标,运维看服务状态,审批人处理高风险动作。" },
|
||||
{ keys: ["用户是目标"], example: "用户提出“把今天收到的客户邮件整理成日报”。" },
|
||||
{ keys: ["运维关注"], example: "运维发现邮件读取服务连续失败后,查看健康状态并重启服务。" },
|
||||
{ keys: ["审批人负责"], example: "系统要自动发送外部邮件前,审批人确认内容和收件人。" },
|
||||
{ keys: ["外部业务系统"], example: "工单系统产生新工单后,通过系统接口触发 sgRobot 处理。" },
|
||||
|
||||
{ keys: ["业务入口与协同"], example: "用户提交巡检需求,外部系统推送消息,审批人在工作台确认风险动作。" },
|
||||
{ keys: ["业务需求入口"], example: "每天 9 点的巡检计划、人工提交的日报需求、邮件到达事件都先进入这里。" },
|
||||
{ keys: ["人工提交"], example: "负责人在工作台提交“生成本周设备巡检报告”。" },
|
||||
{ keys: ["系统接口"], example: "CRM 系统把新客户资料同步过来,请求自动补全客户画像。" },
|
||||
{ keys: ["计划任务"], example: "每个工作日 18 点自动汇总当天处理结果。" },
|
||||
{ keys: ["事件触发"], example: "指定邮箱收到带附件的邮件后,自动触发读取和归档流程。" },
|
||||
{ keys: ["协同工作台"], example: "审批人打开工作台查看待审批队列,运维查看失败任务。" },
|
||||
{ keys: ["查看"], example: "查看某个任务当前是排队中、执行中还是等待审批。" },
|
||||
{ keys: ["操作"], example: "用户手动暂停一个执行中的网页采集任务。" },
|
||||
{ keys: ["审批"], example: "自动发送客户邮件前,需要审批人确认内容。" },
|
||||
{ keys: ["回放"], example: "复盘昨天失败的巡检任务,查看它在哪一步超时。" },
|
||||
{ keys: ["成果浏览"], example: "打开自动生成的报告、截图和数据表进行验收。" },
|
||||
|
||||
{ keys: ["任务治理与风控"], example: "把“处理客户邮件”拆成读取、分类、回复、归档,并在发信前要求审批。" },
|
||||
{ keys: ["目标计划管理"], example: "把“生成月度巡检报告”拆成采集数据、生成报告、提交验收。" },
|
||||
{ keys: ["业务目标"], example: "目标可以是“完成今日邮件分类并输出异常清单”。" },
|
||||
{ keys: ["执行计划"], example: "计划中写明先读取邮件,再分类,再生成日报,最后等待验收。" },
|
||||
{ keys: ["计划步骤"], example: "“登录系统下载报表”就是计划里的一个步骤。" },
|
||||
{ keys: ["任务执行管理"], example: "同一计划下的多个采集任务可以排队、重试、暂停或取消。" },
|
||||
{ keys: ["工作任务"], example: "“读取 inbox 中未处理邮件”是一项可调度工作任务。" },
|
||||
{ keys: ["执行记录"], example: "第一次读取邮件失败后,第二次重试会形成新的执行记录。" },
|
||||
{ keys: ["自动重试"], example: "网页临时超时后,系统在 3 分钟后自动再试一次。" },
|
||||
{ keys: ["恢复点"], example: "长流程已经完成数据下载,失败后从报告生成环节继续。" },
|
||||
{ keys: ["超时管控"], example: "浏览器操作超过 10 分钟未完成,就转入失败恢复或人工介入。" },
|
||||
{ keys: ["人工治理"], example: "任务可以被审批、暂停、恢复、取消、接管或重新规划。" },
|
||||
{ keys: ["审批通过"], example: "审批人确认发信内容无误后,允许流程继续发送。" },
|
||||
{ keys: ["暂停"], example: "发现输入资料不完整时,先暂停任务等待补充。" },
|
||||
{ keys: ["恢复"], example: "资料补齐后,从暂停点继续执行,不必从头开始。" },
|
||||
{ keys: ["取消"], example: "业务目标已经撤销,取消计划并释放后台服务。" },
|
||||
{ keys: ["人工接管"], example: "网页验证码无法自动处理时,转给人工完成后再继续。" },
|
||||
{ keys: ["重新规划"], example: "原接口不可用,改走网页下载报表的替代路径。" },
|
||||
{ keys: ["风险与规则"], example: "涉及外部发信、删除文件、控制设备的动作必须进入审批。" },
|
||||
{ keys: ["记忆规则"], example: "用户偏好可以长期保留,但临时验证码不允许写入记忆。" },
|
||||
{ keys: ["服务占用"], example: "某个任务正在使用邮件读取服务时,系统不会把该服务提前回收。" },
|
||||
{ keys: ["风险等级"], example: "读取邮件是低风险,批量发信是高风险,需要审批。" },
|
||||
{ keys: ["健康状态"], example: "邮件服务正常、浏览器环境异常、任务队列积压都能被展示出来。" },
|
||||
|
||||
{ keys: ["自动执行与能力"], example: "系统调用脚本、流程、智能辅助和外部系统适配来完成真实业务动作。" },
|
||||
{ keys: ["能力目录"], example: "“读取邮件”“生成报告”“网页下载报表”都登记成可复用能力。" },
|
||||
{ keys: ["能力登记"], example: "新增一个“登录后台下载销售报表”的自动化能力。" },
|
||||
{ keys: ["版本管理"], example: "报表下载流程改版后,保留 v1 和 v2,避免影响旧任务。" },
|
||||
{ keys: ["使用约定"], example: "规定输入必须包含日期范围,输出必须包含报告文件和数据结果。" },
|
||||
{ keys: ["调度中枢"], example: "先检查账号和服务是否可用,再安排读取邮件、分类和生成报告。" },
|
||||
{ keys: ["前置检查"], example: "执行前确认邮箱权限、浏览器环境、审批状态都满足条件。" },
|
||||
{ keys: ["能力匹配"], example: "同样是取报表,优先走接口,接口失败再走网页自动化。" },
|
||||
{ keys: ["失败恢复"], example: "下载失败后先重试,仍失败则换备用路径或转人工处理。" },
|
||||
{ keys: ["自动脚本"], example: "每天固定导出报表、清洗数据、生成 CSV 文件。" },
|
||||
{ keys: ["确定性任务"], example: "把固定格式表格转换成统一字段就是确定性任务。" },
|
||||
{ keys: ["流程编排"], example: "把邮件读取、附件解析、报告生成、审批发送组合成一条流程。" },
|
||||
{ keys: ["组合能力"], example: "“客户邮件处理”由读取、分类、回复草稿、归档四个能力组合。" },
|
||||
{ keys: ["子流程"], example: "报告生成任务内部再拆成取数、制图、写摘要三个子流程。" },
|
||||
{ keys: ["智能辅助"], example: "根据失败日志判断可能原因,并给出下一步处理建议。" },
|
||||
{ keys: ["规划用于"], example: "把“做一份巡检报告”拆成采集、分析、生成、验收。" },
|
||||
{ keys: ["修复建议"], example: "系统提示“登录页结构变化,建议改用备用选择器或人工接管”。" },
|
||||
{ keys: ["解释用于"], example: "向审批人说明为什么这一步被判定为高风险。" },
|
||||
{ keys: ["外部系统适配"], example: "同一业务流程可以同时操作网页后台、设备接口和机器人。" },
|
||||
{ keys: ["网页操作"], example: "自动登录后台,下载当天订单报表。" },
|
||||
{ keys: ["设备接入"], example: "读取设备状态或通过设备接口下发巡检命令。" },
|
||||
{ keys: ["机器人控制"], example: "让机器人执行移动、拍照、语音播报等动作。" },
|
||||
{ keys: ["按需后台服务"], example: "只有处理邮件任务时才启动邮件读取服务,空闲后自动回收。" },
|
||||
{ keys: ["服务定义"], example: "定义邮件读取服务如何启动、检查健康、停止和授权。" },
|
||||
{ keys: ["运行实例"], example: "当前启动了一个邮件读取实例,状态为运行中。" },
|
||||
{ keys: ["占用关系"], example: "任务 A 正在使用浏览器环境,因此该环境不能被其他任务关闭。" },
|
||||
|
||||
{ keys: ["运营记录与看板"], example: "领导可以看到任务进度、风险节点、成果报告和人工介入情况。" },
|
||||
{ keys: ["业务状态台账"], example: "某计划已激活,三个任务成功,一个任务等待审批。" },
|
||||
{ keys: ["执行计划状态"], example: "计划当前处于“等待审批”或“执行中”。" },
|
||||
{ keys: ["工作任务状态"], example: "任务当前是排队中、执行中、暂停、失败或完成。" },
|
||||
{ keys: ["执行记录状态"], example: "第 2 次执行成功,第 1 次执行因网页超时失败。" },
|
||||
{ keys: ["审批记录状态"], example: "发信审批已通过,删除文件审批被拒绝。" },
|
||||
{ keys: ["过程日志"], example: "记录任务开始、服务启动、审批通过、执行失败等关键变化。" },
|
||||
{ keys: ["关键过程记录"], example: "“09:03 邮件读取服务启动”“09:05 附件解析失败”。" },
|
||||
{ keys: ["成果资料库"], example: "保存巡检报告、页面截图、附件解析结果和导出的表格。" },
|
||||
{ keys: ["文件是"], example: "保存下载的 Excel、PDF 报告或邮件附件。" },
|
||||
{ keys: ["报告是"], example: "自动生成日报、巡检报告或异常汇总。" },
|
||||
{ keys: ["截图用于"], example: "保留网页提交成功页面,作为验收证据。" },
|
||||
{ keys: ["数据结果"], example: "把邮件分类结果保存成结构化表格,供后续统计。" },
|
||||
{ keys: ["经验与记忆库"], example: "记录某项目常用账号、报告格式偏好、失败处理经验。" },
|
||||
{ keys: ["项目事实"], example: "某系统的报表入口固定在“运营中心 / 日报”菜单下。" },
|
||||
{ keys: ["使用偏好"], example: "用户偏好报告用中文摘要,并保留原始数据表。" },
|
||||
{ keys: ["关键决策"], example: "决定所有外部发信必须先进入人工审批。" },
|
||||
{ keys: ["处理经验"], example: "某网页下载失败时,先刷新登录态再重试。" },
|
||||
{ keys: ["观察摘要"], example: "最近三次失败都集中在同一个外部系统登录环节。" },
|
||||
{ keys: ["运营看板"], example: "展示今日任务成功率、待审批数量、失败任务和服务健康。" },
|
||||
{ keys: ["任务看板"], example: "看到哪些任务已完成、哪些阻塞、哪些需要人工介入。" },
|
||||
{ keys: ["审批队列"], example: "所有等待确认的发信、删除、设备控制动作集中展示。" },
|
||||
{ keys: ["记忆索引"], example: "查看并修正“用户偏好报告格式”的长期记忆。" },
|
||||
{ keys: ["服务健康"], example: "邮件读取服务正常,浏览器环境重启 1 次,设备连接异常。" },
|
||||
{ keys: ["全程追踪"], example: "按时间线查看一次任务从提交到验收的完整过程。" },
|
||||
{ keys: ["过程回放"], example: "复盘某次失败,看到它在附件解析步骤出错。" },
|
||||
{ keys: ["诊断"], example: "定位失败原因是账号过期、网页变化还是服务不可用。" },
|
||||
{ keys: ["追责"], example: "确认是谁在什么时间批准了批量发信动作。" },
|
||||
{ keys: ["运营指标"], example: "每周统计成功率、平均耗时和人工介入率。" },
|
||||
{ keys: ["服务时效"], example: "巡检报告要求 30 分钟内完成并提交。" },
|
||||
{ keys: ["成功率"], example: "本周邮件处理任务 100 次,成功 96 次。" },
|
||||
{ keys: ["响应耗时"], example: "从邮件到达到生成处理结果平均耗时 2 分钟。" },
|
||||
{ keys: ["人工介入率"], example: "本月 12% 的任务因审批或异常需要人工介入。" },
|
||||
|
||||
{ keys: ["核心闭环"], example: "一封客户邮件进入系统后,生成任务、自动处理、沉淀成果,再进入看板和复盘。" },
|
||||
{ keys: ["经验与服务准备"], example: "执行前先读取用户偏好,并启动邮件读取或浏览器服务。" },
|
||||
{ keys: ["过程记录与成果沉淀"], example: "任务完成后保存报告、截图、日志和可复用处理经验。" },
|
||||
{ keys: ["人工决策"], example: "审批人确认批量发信、暂停异常任务或要求重新规划。" },
|
||||
{ keys: ["审批 / 暂停"], example: "审批不通过时,流程回到计划层重新规划。" },
|
||||
];
|
||||
|
||||
function normalizeText(value) {
|
||||
return (value || "").replace(/\s+/g, " ").trim();
|
||||
}
|
||||
|
||||
function tooltipExample(target) {
|
||||
const label = normalizeText(target.textContent);
|
||||
const base = normalizeText(target.dataset.tip);
|
||||
const haystack = `${label} ${base}`;
|
||||
const rule = exampleRules.find((item) => item.keys.every((key) => haystack.includes(key)));
|
||||
if (rule) return rule.example;
|
||||
return "领导查看该节点时,可以把它对应到一次人工交办、邮件触发、定时巡检或高风险审批中的具体动作。";
|
||||
}
|
||||
|
||||
function tooltipText(target) {
|
||||
const text = normalizeText(target.dataset.tip);
|
||||
if (!text) return "";
|
||||
if (text.includes("例:")) return text;
|
||||
return `${text}\n例:${tooltipExample(target)}`;
|
||||
}
|
||||
|
||||
function positionTooltip(event) {
|
||||
const margin = 14;
|
||||
const offset = 16;
|
||||
const rect = tooltip.getBoundingClientRect();
|
||||
let left = event.clientX + offset;
|
||||
let top = event.clientY + offset;
|
||||
|
||||
if (left + rect.width + margin > window.innerWidth) {
|
||||
left = Math.max(margin, event.clientX - rect.width - offset);
|
||||
}
|
||||
if (top + rect.height + margin > window.innerHeight) {
|
||||
top = Math.max(margin, event.clientY - rect.height - offset);
|
||||
}
|
||||
|
||||
tooltip.style.left = `${left}px`;
|
||||
tooltip.style.top = `${top}px`;
|
||||
}
|
||||
|
||||
function showTooltip(target, event) {
|
||||
const text = tooltipText(target);
|
||||
if (!text) return;
|
||||
activeTipTarget = target;
|
||||
tooltip.textContent = text;
|
||||
tooltip.classList.add("is-visible");
|
||||
positionTooltip(event);
|
||||
}
|
||||
|
||||
function hideTooltip() {
|
||||
activeTipTarget = null;
|
||||
tooltip.classList.remove("is-visible");
|
||||
}
|
||||
|
||||
document.addEventListener("pointerover", (event) => {
|
||||
const target = event.target.closest("[data-tip]");
|
||||
if (target) showTooltip(target, event);
|
||||
});
|
||||
|
||||
document.addEventListener("pointermove", (event) => {
|
||||
if (activeTipTarget) positionTooltip(event);
|
||||
});
|
||||
|
||||
document.addEventListener("pointerout", (event) => {
|
||||
if (!activeTipTarget) return;
|
||||
const next = event.relatedTarget;
|
||||
if (!next || !activeTipTarget.contains(next)) hideTooltip();
|
||||
});
|
||||
|
||||
document.querySelectorAll("[data-tip]").forEach((element) => {
|
||||
element.setAttribute("tabindex", "0");
|
||||
element.setAttribute("aria-label", tooltipText(element));
|
||||
element.addEventListener("focus", (event) => {
|
||||
const rect = event.currentTarget.getBoundingClientRect();
|
||||
showTooltip(event.currentTarget, {
|
||||
clientX: rect.left + rect.width / 2,
|
||||
clientY: rect.top + rect.height / 2,
|
||||
});
|
||||
});
|
||||
element.addEventListener("blur", hideTooltip);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,626 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>sgRobot 五月底上线任务分工表</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
.theme-dark-blue { background-color: #0d2758; }
|
||||
.theme-text-dark-blue { color: #0d2758; }
|
||||
.theme-light-blue-bg { background-color: #f0f6fc; }
|
||||
.theme-border-blue { border-color: #aec3db; }
|
||||
.theme-red { color: #d92d20; }
|
||||
|
||||
body {
|
||||
font-family: "PingFang SC", "Microsoft YaHei", "Noto Sans SC", "Source Han Sans SC", Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.text-sm { font-size: 1.08rem !important; }
|
||||
.text-base { font-size: 1.24rem !important; }
|
||||
.text-lg { font-size: 1.4rem !important; }
|
||||
.text-xl { font-size: 1.62rem !important; }
|
||||
.text-3xl { font-size: 2.75rem !important; }
|
||||
.text-\[13px\] { font-size: 1.14rem !important; }
|
||||
|
||||
[data-tip] { cursor: help; }
|
||||
|
||||
.panel {
|
||||
border: 1px solid #aec3db;
|
||||
border-radius: 8px;
|
||||
background: white;
|
||||
box-shadow: 0 8px 20px rgba(13, 39, 88, 0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.panel-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 14px 16px 10px 16px;
|
||||
border-bottom: 1px solid #d8e4f2;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: #0d2758;
|
||||
font-weight: 900;
|
||||
font-size: 1.3rem;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.panel-tag {
|
||||
border: 1px solid #c8d7e8;
|
||||
border-radius: 999px;
|
||||
padding: 3px 10px;
|
||||
color: #5f7082;
|
||||
background: #f8fbff;
|
||||
font-weight: 800;
|
||||
white-space: nowrap;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
padding: 14px;
|
||||
background: #f0f6fc;
|
||||
}
|
||||
|
||||
.summary-card {
|
||||
border: 1px solid #aec3db;
|
||||
border-radius: 8px;
|
||||
background: white;
|
||||
padding: 12px;
|
||||
color: #0d2758;
|
||||
}
|
||||
|
||||
.summary-card strong {
|
||||
display: block;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.summary-card span {
|
||||
display: block;
|
||||
color: #5f7082;
|
||||
font-weight: 800;
|
||||
line-height: 1.32;
|
||||
}
|
||||
|
||||
.task-table-wrap {
|
||||
overflow-x: auto;
|
||||
background: #f0f6fc;
|
||||
}
|
||||
|
||||
.task-table {
|
||||
width: 100%;
|
||||
min-width: 1320px;
|
||||
border-collapse: collapse;
|
||||
color: #0d2758;
|
||||
}
|
||||
|
||||
.task-table th {
|
||||
background: #0d2758;
|
||||
color: white;
|
||||
text-align: left;
|
||||
padding: 11px 12px;
|
||||
font-weight: 900;
|
||||
border-right: 1px solid #375078;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.task-table td {
|
||||
background: white;
|
||||
padding: 11px 12px;
|
||||
border-right: 1px solid #d8e4f2;
|
||||
border-bottom: 1px solid #d8e4f2;
|
||||
vertical-align: top;
|
||||
font-weight: 760;
|
||||
line-height: 1.38;
|
||||
}
|
||||
|
||||
.task-table tr:nth-child(even) td {
|
||||
background: #f8fbff;
|
||||
}
|
||||
|
||||
.task-name {
|
||||
font-weight: 900;
|
||||
color: #0d2758;
|
||||
}
|
||||
|
||||
.date-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border-radius: 999px;
|
||||
background: #0d2758;
|
||||
color: white;
|
||||
padding: 4px 10px;
|
||||
font-weight: 900;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.owner-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border-radius: 999px;
|
||||
border: 1px solid #c8d7e8;
|
||||
background: white;
|
||||
color: #0d2758;
|
||||
padding: 4px 10px;
|
||||
font-weight: 900;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.boundary-ok {
|
||||
color: #0d2758;
|
||||
}
|
||||
|
||||
.boundary-no {
|
||||
color: #9f1239;
|
||||
}
|
||||
|
||||
.interface-map-wrap {
|
||||
overflow-x: auto;
|
||||
background: #f0f6fc;
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.interface-map {
|
||||
min-width: 1320px;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
border: 1px solid #d8e4f2;
|
||||
border-radius: 8px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.map-note {
|
||||
padding: 10px 14px 14px 14px;
|
||||
background: #f0f6fc;
|
||||
color: #5f7082;
|
||||
font-weight: 800;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.timeline {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, minmax(160px, 1fr));
|
||||
gap: 10px;
|
||||
padding: 14px;
|
||||
background: #f0f6fc;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.time-card {
|
||||
min-width: 170px;
|
||||
border: 1px solid #aec3db;
|
||||
border-radius: 8px;
|
||||
background: white;
|
||||
padding: 12px;
|
||||
color: #0d2758;
|
||||
}
|
||||
|
||||
.time-date {
|
||||
display: inline-flex;
|
||||
background: #0d2758;
|
||||
color: white;
|
||||
border-radius: 999px;
|
||||
padding: 4px 10px;
|
||||
font-weight: 900;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.time-title {
|
||||
font-weight: 900;
|
||||
line-height: 1.25;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.time-text {
|
||||
color: #5f7082;
|
||||
font-weight: 760;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
#sg-tooltip {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
max-width: 460px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 6px;
|
||||
background: #0d2758;
|
||||
color: white;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.45;
|
||||
box-shadow: 0 12px 32px rgba(13, 39, 88, 0.22);
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transform: translateY(4px);
|
||||
transition: opacity 0.12s ease, transform 0.12s ease;
|
||||
}
|
||||
|
||||
#sg-tooltip.is-visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.summary-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
.timeline { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.summary-grid { grid-template-columns: 1fr; }
|
||||
.timeline { grid-template-columns: 1fr; }
|
||||
.panel-head { align-items: flex-start; flex-direction: column; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-white p-4 md:p-8 min-h-screen text-sm select-none">
|
||||
|
||||
<div class="max-w-[1780px] mx-auto mb-4 border border-amber-300 bg-amber-50 text-amber-900 rounded-lg px-4 py-3 shadow-sm">
|
||||
<div class="font-black text-base">历史汇报版</div>
|
||||
<div class="text-sm leading-relaxed mt-1">
|
||||
本页面保留为早期 10 任务包汇报视图,不再作为团队分工和接口冻结源头。当前分工、接口 owner、状态、Mock 和验收证据以
|
||||
<code>plan/2026-04-26-architecture-team-handoff/</code>
|
||||
及其中的 <code>interfaces/interface-freeze-register.md</code> 为准。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="max-w-[1780px] mx-auto mb-5 flex flex-wrap items-center justify-between gap-3 border border-blue-200 rounded-lg px-4 py-3 shadow-sm bg-white">
|
||||
<div class="flex items-center gap-2 theme-text-dark-blue font-bold text-base" data-tip="汇报专用静态网站,可直接双击 index.html 打开,不需要启动本地服务。">
|
||||
<i class="fa-solid fa-display"></i>
|
||||
<span>sgRobot 汇报静态网站</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="index.html" class="border theme-border-blue theme-text-dark-blue rounded px-4 py-2 font-bold bg-white hover:bg-blue-50" data-tip="返回业务架构总览。">业务架构总览</a>
|
||||
<a href="flows.html" class="border theme-border-blue theme-text-dark-blue rounded px-4 py-2 font-bold bg-white hover:bg-blue-50" data-tip="查看业务流程如何落到架构模块。">业务流程图</a>
|
||||
<a href="roadmap.html" class="theme-dark-blue text-white rounded px-4 py-2 font-bold shadow-sm" data-tip="当前页面只看任务、负责人、日期和边界。">里程碑与分工</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<header class="max-w-[1780px] mx-auto mb-6">
|
||||
<div class="flex items-center mb-2" data-tip="这一页只保留领导最需要看的信息:哪个任务、谁负责、什么时候完成、边界是什么。">
|
||||
<div class="w-10 h-10 theme-dark-blue text-white flex items-center justify-center rounded shadow-sm mr-3">
|
||||
<i class="fa-solid fa-list-check text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold theme-text-dark-blue tracking-wide">sgRobot <span class="font-bold">五月底上线任务分工表</span></h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-14 text-[13px] font-medium text-gray-700 leading-relaxed" data-tip="负责人先按角色写,后续可以替换成具体姓名。">
|
||||
原则:<span class="font-bold">一个任务,一个负责人,一个完成日期,一个边界</span>。各模块只按公共接口交付,不互相改代码;5 月 31 日统一验收。
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="max-w-[1780px] mx-auto flex flex-col gap-5">
|
||||
<section class="panel" data-tip="这四个数字是领导快速判断范围用的。">
|
||||
<div class="panel-head">
|
||||
<div class="panel-title"><i class="fa-solid fa-circle-info"></i><span>一页结论</span></div>
|
||||
<span class="panel-tag" data-tip="如需具体人名,直接把负责人角色替换为姓名即可。">负责人先按角色占位</span>
|
||||
</div>
|
||||
<div class="summary-grid">
|
||||
<div class="summary-card" data-tip="共 10 个任务包;公共接口只做口径冻结,核心控制另行实现,避免一个负责人背所有责任。"><strong>10 个</strong><span>任务包</span></div>
|
||||
<div class="summary-card" data-tip="只设一个最终日期:2026 年 5 月 31 日完成上线验收。"><strong>5/31</strong><span>上线验收收口</span></div>
|
||||
<div class="summary-card" data-tip="模块之间只通过公共接口、测试样例和交付物对接。"><strong>互不改代码</strong><span>只按接口交付</span></div>
|
||||
<div class="summary-card" data-tip="测试和发布有否决权,没证据就不能算完成。"><strong>有证据</strong><span>才算完成</span></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-tip="这是核心表。领导看这一张表就能知道谁负责什么、哪天完成、边界在哪里。">
|
||||
<div class="panel-head">
|
||||
<div class="panel-title"><i class="fa-solid fa-table"></i><span>任务分工总表</span></div>
|
||||
<span class="panel-tag" data-tip="完成日期是建议倒排,可根据真实人员情况微调。">按完成日期倒排</span>
|
||||
</div>
|
||||
<div class="task-table-wrap">
|
||||
<table class="task-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>任务</th>
|
||||
<th>负责人</th>
|
||||
<th>完成日期</th>
|
||||
<th>交付物</th>
|
||||
<th>边界:只负责</th>
|
||||
<th>边界:不负责</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-tip="公共接口不要求 4 月 30 日全部实现,只要求各负责人把字段、调用方向、Mock 数据和验收口径确认下来。">
|
||||
<td><span class="task-name">公共接口口径冻结</span></td>
|
||||
<td><span class="owner-pill">总负责人 + 各模块负责人</span></td>
|
||||
<td><span class="date-pill">4/30</span></td>
|
||||
<td>接口目录、字段草案、Mock 数据、对接方向、验收口径</td>
|
||||
<td class="boundary-ok">只冻结模块之间怎么对接,以及每个模块交付什么数据</td>
|
||||
<td class="boundary-no">不要求一次性完成所有后端实现;不替各模块写内部代码</td>
|
||||
</tr>
|
||||
<tr data-tip="核心后端只负责把主链路跑起来,不再同时承担所有适配模块的接口设计责任。">
|
||||
<td><span class="task-name">核心控制主链路</span></td>
|
||||
<td><span class="owner-pill">核心后端负责人</span></td>
|
||||
<td><span class="date-pill">5/08</span></td>
|
||||
<td>计划、任务、执行记录、审批、服务占用、能力目录最小实现</td>
|
||||
<td class="boundary-ok">核心状态推进、公共接口实现、主链路冒烟</td>
|
||||
<td class="boundary-no">不写 UI;不写浏览器、硬件、本地服务实现</td>
|
||||
</tr>
|
||||
<tr data-tip="解决新增 Skill 时自动写控制脚本的问题。">
|
||||
<td><span class="task-name">Skill 编写助手</span></td>
|
||||
<td><span class="owner-pill">Skill 工具负责人</span></td>
|
||||
<td><span class="date-pill">5/08</span></td>
|
||||
<td>控制脚本生成器、模板、校验器、3 个示例 Skill</td>
|
||||
<td class="boundary-ok">自动生成新 Skill 的控制脚本和校验规则</td>
|
||||
<td class="boundary-no">不做浏览器、硬件、本地服务底层适配</td>
|
||||
</tr>
|
||||
<tr data-tip="把已有自动化脚本批量纳入 Skill 体系。">
|
||||
<td><span class="task-name">自动化脚本批量转 Skill</span></td>
|
||||
<td><span class="owner-pill">脚本迁移负责人</span></td>
|
||||
<td><span class="date-pill">5/12</span></td>
|
||||
<td>转换工具、迁移清单、已转换 Skill 包、回归报告</td>
|
||||
<td class="boundary-ok">旧脚本包装、补输入输出、补日志、登记能力目录</td>
|
||||
<td class="boundary-no">不重写业务逻辑;不改适配器底层能力</td>
|
||||
</tr>
|
||||
<tr data-tip="浏览器适配独立成包,不和 UI 混在一起。">
|
||||
<td><span class="task-name">浏览器适配</span></td>
|
||||
<td><span class="owner-pill">浏览器适配负责人</span></td>
|
||||
<td><span class="date-pill">5/12</span></td>
|
||||
<td>浏览器适配器、示例 Skill、截图证据、失败说明</td>
|
||||
<td class="boundary-ok">打开页面、点击、输入、下载、截图、会话和错误回写</td>
|
||||
<td class="boundary-no">不决定业务审批;不做 UI 页面;不写硬件接口</td>
|
||||
</tr>
|
||||
<tr data-tip="子程序和本地服务单独管理,避免主程序和后台服务绑死。">
|
||||
<td><span class="task-name">本地服务与子程序管理</span></td>
|
||||
<td><span class="owner-pill">本地服务负责人</span></td>
|
||||
<td><span class="date-pill">5/14</span></td>
|
||||
<td>服务管理器、服务清单、健康数据、运维命令</td>
|
||||
<td class="boundary-ok">邮件读取、监听器、后台进程启动停止、健康、日志、回收</td>
|
||||
<td class="boundary-no">不定义业务流程;不直接修改任务结果</td>
|
||||
</tr>
|
||||
<tr data-tip="硬件适配要有安全边界,不能绕过人工治理。">
|
||||
<td><span class="task-name">硬件与机器人适配</span></td>
|
||||
<td><span class="owner-pill">硬件适配负责人</span></td>
|
||||
<td><span class="date-pill">5/14</span></td>
|
||||
<td>硬件适配器、模拟测试、状态回写、安全风险清单</td>
|
||||
<td class="boundary-ok">设备连接、状态读取、基础动作、机器人控制、异常停止</td>
|
||||
<td class="boundary-no">不绕过审批执行高风险动作;不负责浏览器自动化</td>
|
||||
</tr>
|
||||
<tr data-tip="UI 只做操作台,不能自己发明另一套后端状态。">
|
||||
<td><span class="task-name">UI 操作台</span></td>
|
||||
<td><span class="owner-pill">前端负责人</span></td>
|
||||
<td><span class="date-pill">5/18</span></td>
|
||||
<td>任务看板、审批队列、服务健康、成果浏览、过程回放</td>
|
||||
<td class="boundary-ok">用户操作入口和可视化验收页面</td>
|
||||
<td class="boundary-no">不绕过后端改状态;不自建任务模型</td>
|
||||
</tr>
|
||||
<tr data-tip="编译打包独立负责 Windows、信创、ARM,不和业务开发绑在一起。">
|
||||
<td><span class="task-name">浏览器编译与平台打包</span></td>
|
||||
<td><span class="owner-pill">构建发布负责人</span></td>
|
||||
<td><span class="date-pill">5/22</span></td>
|
||||
<td>Windows / 信创 / ARM 构建产物、依赖清单、安装说明</td>
|
||||
<td class="boundary-ok">平台构建、依赖整理、打包、失败归因</td>
|
||||
<td class="boundary-no">不改业务逻辑;不写 Skill;不做 UI 功能</td>
|
||||
</tr>
|
||||
<tr data-tip="测试发布负责最终收口和上线判断。">
|
||||
<td><span class="task-name">测试验收与发布收口</span></td>
|
||||
<td><span class="owner-pill">测试发布负责人</span></td>
|
||||
<td><span class="date-pill">5/31</span></td>
|
||||
<td>测试报告、上线风险、已知问题、发布包、回滚方案</td>
|
||||
<td class="boundary-ok">模块测试、端到端测试、兼容验证、发布门禁</td>
|
||||
<td class="boundary-no">不替功能模块补实现,但可判定是否阻断上线</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-tip="这张图只表达接口关系:每个负责人都通过中间的公共接口对接,模块之间不互相改代码。">
|
||||
<div class="panel-head">
|
||||
<div class="panel-title"><i class="fa-solid fa-diagram-project"></i><span>分工接口关系图</span></div>
|
||||
<span class="panel-tag" data-tip="线上的文字就是这个负责人和核心接口之间的交付接口。">看线上的接口名</span>
|
||||
</div>
|
||||
<div class="interface-map-wrap">
|
||||
<svg class="interface-map" viewBox="0 0 1500 720" role="img" aria-label="sgRobot 五月底上线分工接口关系图">
|
||||
<defs>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth">
|
||||
<path d="M0,0 L0,6 L9,3 z" fill="#6f8faf"></path>
|
||||
</marker>
|
||||
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
|
||||
<feDropShadow dx="0" dy="4" stdDeviation="4" flood-color="#0d2758" flood-opacity="0.12"></feDropShadow>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<rect x="40" y="30" width="1420" height="660" rx="10" fill="#f8fbff" stroke="#d8e4f2"></rect>
|
||||
|
||||
<rect x="555" y="64" width="390" height="92" rx="10" fill="#0d2758" filter="url(#shadow)"></rect>
|
||||
<text x="750" y="102" text-anchor="middle" fill="#ffffff" font-size="25" font-weight="900">核心控制主链路</text>
|
||||
<text x="750" y="132" text-anchor="middle" fill="#dbeafe" font-size="18" font-weight="800">核心后端负责人:5/08 实现</text>
|
||||
|
||||
<rect x="565" y="285" width="370" height="118" rx="10" fill="#ffffff" stroke="#aec3db" stroke-width="2" filter="url(#shadow)"></rect>
|
||||
<text x="750" y="325" text-anchor="middle" fill="#0d2758" font-size="24" font-weight="900">公共接口合同</text>
|
||||
<text x="750" y="356" text-anchor="middle" fill="#5f7082" font-size="17" font-weight="800">总负责人 + 各模块负责人共同确认:4/30</text>
|
||||
<text x="750" y="383" text-anchor="middle" fill="#d92d20" font-size="17" font-weight="900">核心后端只实现主链路,不替各模块兜底</text>
|
||||
|
||||
<line x1="750" y1="156" x2="750" y2="285" stroke="#6f8faf" stroke-width="3" marker-end="url(#arrow)"></line>
|
||||
<text x="766" y="226" fill="#5f7082" font-size="16" font-weight="800">核心接口实现</text>
|
||||
|
||||
<rect x="75" y="75" width="290" height="72" rx="8" fill="#ffffff" stroke="#aec3db" stroke-width="2" filter="url(#shadow)"></rect>
|
||||
<text x="220" y="106" text-anchor="middle" fill="#0d2758" font-size="20" font-weight="900">Skill 编写助手</text>
|
||||
<text x="220" y="131" text-anchor="middle" fill="#5f7082" font-size="16" font-weight="800">Skill 工具负责人</text>
|
||||
<line x1="365" y1="111" x2="565" y2="302" stroke="#6f8faf" stroke-width="3" marker-end="url(#arrow)"></line>
|
||||
<rect x="376" y="178" width="172" height="32" rx="16" fill="#ffffff" stroke="#c8d7e8"></rect>
|
||||
<text x="462" y="200" text-anchor="middle" fill="#0d2758" font-size="15" font-weight="900">Skill 生成合同</text>
|
||||
|
||||
<rect x="75" y="185" width="290" height="72" rx="8" fill="#ffffff" stroke="#aec3db" stroke-width="2" filter="url(#shadow)"></rect>
|
||||
<text x="220" y="216" text-anchor="middle" fill="#0d2758" font-size="20" font-weight="900">脚本批量转 Skill</text>
|
||||
<text x="220" y="241" text-anchor="middle" fill="#5f7082" font-size="16" font-weight="800">脚本迁移负责人</text>
|
||||
<line x1="365" y1="221" x2="565" y2="327" stroke="#6f8faf" stroke-width="3" marker-end="url(#arrow)"></line>
|
||||
<rect x="386" y="253" width="160" height="32" rx="16" fill="#ffffff" stroke="#c8d7e8"></rect>
|
||||
<text x="466" y="275" text-anchor="middle" fill="#0d2758" font-size="15" font-weight="900">Skill 包接口</text>
|
||||
|
||||
<rect x="75" y="295" width="290" height="72" rx="8" fill="#ffffff" stroke="#aec3db" stroke-width="2" filter="url(#shadow)"></rect>
|
||||
<text x="220" y="326" text-anchor="middle" fill="#0d2758" font-size="20" font-weight="900">浏览器适配</text>
|
||||
<text x="220" y="351" text-anchor="middle" fill="#5f7082" font-size="16" font-weight="800">浏览器适配负责人</text>
|
||||
<line x1="365" y1="331" x2="565" y2="344" stroke="#6f8faf" stroke-width="3" marker-end="url(#arrow)"></line>
|
||||
<rect x="384" y="333" width="158" height="32" rx="16" fill="#ffffff" stroke="#c8d7e8"></rect>
|
||||
<text x="463" y="355" text-anchor="middle" fill="#0d2758" font-size="15" font-weight="900">浏览器接口</text>
|
||||
|
||||
<rect x="75" y="405" width="290" height="72" rx="8" fill="#ffffff" stroke="#aec3db" stroke-width="2" filter="url(#shadow)"></rect>
|
||||
<text x="220" y="436" text-anchor="middle" fill="#0d2758" font-size="20" font-weight="900">本地服务管理</text>
|
||||
<text x="220" y="461" text-anchor="middle" fill="#5f7082" font-size="16" font-weight="800">本地服务负责人</text>
|
||||
<line x1="365" y1="441" x2="565" y2="366" stroke="#6f8faf" stroke-width="3" marker-end="url(#arrow)"></line>
|
||||
<rect x="392" y="397" width="146" height="32" rx="16" fill="#ffffff" stroke="#c8d7e8"></rect>
|
||||
<text x="465" y="419" text-anchor="middle" fill="#0d2758" font-size="15" font-weight="900">服务合同</text>
|
||||
|
||||
<rect x="75" y="515" width="290" height="72" rx="8" fill="#ffffff" stroke="#aec3db" stroke-width="2" filter="url(#shadow)"></rect>
|
||||
<text x="220" y="546" text-anchor="middle" fill="#0d2758" font-size="20" font-weight="900">硬件与机器人适配</text>
|
||||
<text x="220" y="571" text-anchor="middle" fill="#5f7082" font-size="16" font-weight="800">硬件适配负责人</text>
|
||||
<line x1="365" y1="551" x2="565" y2="388" stroke="#6f8faf" stroke-width="3" marker-end="url(#arrow)"></line>
|
||||
<rect x="382" y="474" width="168" height="32" rx="16" fill="#ffffff" stroke="#c8d7e8"></rect>
|
||||
<text x="466" y="496" text-anchor="middle" fill="#0d2758" font-size="15" font-weight="900">硬件适配接口</text>
|
||||
|
||||
<rect x="1135" y="120" width="290" height="72" rx="8" fill="#ffffff" stroke="#aec3db" stroke-width="2" filter="url(#shadow)"></rect>
|
||||
<text x="1280" y="151" text-anchor="middle" fill="#0d2758" font-size="20" font-weight="900">UI 操作台</text>
|
||||
<text x="1280" y="176" text-anchor="middle" fill="#5f7082" font-size="16" font-weight="800">前端负责人</text>
|
||||
<line x1="1135" y1="156" x2="935" y2="310" stroke="#6f8faf" stroke-width="3" marker-end="url(#arrow)"></line>
|
||||
<rect x="960" y="220" width="152" height="32" rx="16" fill="#ffffff" stroke="#c8d7e8"></rect>
|
||||
<text x="1036" y="242" text-anchor="middle" fill="#0d2758" font-size="15" font-weight="900">UI 数据接口</text>
|
||||
|
||||
<rect x="1135" y="285" width="290" height="72" rx="8" fill="#ffffff" stroke="#aec3db" stroke-width="2" filter="url(#shadow)"></rect>
|
||||
<text x="1280" y="316" text-anchor="middle" fill="#0d2758" font-size="20" font-weight="900">浏览器编译与打包</text>
|
||||
<text x="1280" y="341" text-anchor="middle" fill="#5f7082" font-size="16" font-weight="800">构建发布负责人</text>
|
||||
<line x1="1135" y1="321" x2="935" y2="344" stroke="#6f8faf" stroke-width="3" marker-end="url(#arrow)"></line>
|
||||
<rect x="954" y="311" width="170" height="32" rx="16" fill="#ffffff" stroke="#c8d7e8"></rect>
|
||||
<text x="1039" y="333" text-anchor="middle" fill="#0d2758" font-size="15" font-weight="900">构建产物接口</text>
|
||||
|
||||
<rect x="1135" y="450" width="290" height="72" rx="8" fill="#ffffff" stroke="#aec3db" stroke-width="2" filter="url(#shadow)"></rect>
|
||||
<text x="1280" y="481" text-anchor="middle" fill="#0d2758" font-size="20" font-weight="900">测试验收与发布</text>
|
||||
<text x="1280" y="506" text-anchor="middle" fill="#5f7082" font-size="16" font-weight="800">测试发布负责人</text>
|
||||
<line x1="1135" y1="486" x2="935" y2="378" stroke="#6f8faf" stroke-width="3" marker-end="url(#arrow)"></line>
|
||||
<rect x="958" y="412" width="158" height="32" rx="16" fill="#ffffff" stroke="#c8d7e8"></rect>
|
||||
<text x="1037" y="434" text-anchor="middle" fill="#0d2758" font-size="15" font-weight="900">验收门禁</text>
|
||||
|
||||
<rect x="520" y="560" width="460" height="76" rx="10" fill="#fff7f7" stroke="#fecaca" stroke-width="2"></rect>
|
||||
<text x="750" y="592" text-anchor="middle" fill="#9f1239" font-size="21" font-weight="900">规则:负责人之间不直接改对方模块</text>
|
||||
<text x="750" y="620" text-anchor="middle" fill="#9f1239" font-size="17" font-weight="800">所有协作都落到接口合同、交付包、测试报告</text>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="map-note" data-tip="这句话是给领导看的解释口径。">
|
||||
读图方式:每个白框是一个负责人,线上的文字是他交给核心控制或从核心控制读取的接口。除测试发布外,其他负责人不直接验收别人内部实现,只按接口和交付物对接。
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-tip="把里程碑压缩到几个关键日期,领导只需要知道每个日期要看到什么。">
|
||||
<div class="panel-head">
|
||||
<div class="panel-title"><i class="fa-solid fa-calendar-days"></i><span>简版里程碑</span></div>
|
||||
<span class="panel-tag" data-tip="不再画复杂甘特图,只保留关键日期。">哪个任务哪天完成</span>
|
||||
</div>
|
||||
<div class="timeline">
|
||||
<div class="time-card" data-tip="这里只冻结口径,不要求完成全部实现。目标是让各模块能并行开工。">
|
||||
<span class="time-date">4/30</span>
|
||||
<div class="time-title">公共接口口径冻结</div>
|
||||
<div class="time-text">接口目录、字段草案、Mock 数据、对接方向确认。</div>
|
||||
</div>
|
||||
<div class="time-card" data-tip="核心后端在这个日期前交付主链路最小实现,不再背所有适配模块的实现。">
|
||||
<span class="time-date">5/08</span>
|
||||
<div class="time-title">核心主链路完成</div>
|
||||
<div class="time-text">计划、任务、执行记录、审批、服务占用可冒烟。</div>
|
||||
</div>
|
||||
<div class="time-card" data-tip="这一阶段拿到 Skill 生产、脚本迁移和浏览器适配首批能力。">
|
||||
<span class="time-date">5/12</span>
|
||||
<div class="time-title">Skill 与浏览器首批完成</div>
|
||||
<div class="time-text">Skill 编写助手、脚本转 Skill、浏览器适配可用。</div>
|
||||
</div>
|
||||
<div class="time-card" data-tip="本地服务和硬件适配要给出可调用版本。">
|
||||
<span class="time-date">5/14</span>
|
||||
<div class="time-title">服务与硬件完成</div>
|
||||
<div class="time-text">本地服务管理、硬件与机器人适配完成首版验收。</div>
|
||||
</div>
|
||||
<div class="time-card" data-tip="UI 在 5 月 18 日前必须从粗略页面变成可操作台。">
|
||||
<span class="time-date">5/18</span>
|
||||
<div class="time-title">UI 操作台完成</div>
|
||||
<div class="time-text">任务、审批、服务、成果、回放都能操作或查看。</div>
|
||||
</div>
|
||||
<div class="time-card" data-tip="五月底只做验收和发布,不再扩功能。">
|
||||
<span class="time-date">5/31</span>
|
||||
<div class="time-title">上线验收完成</div>
|
||||
<div class="time-text">发布包、测试报告、回滚方案、演示材料齐备。</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const tooltip = document.createElement("div");
|
||||
tooltip.id = "sg-tooltip";
|
||||
document.body.appendChild(tooltip);
|
||||
|
||||
let activeTipTarget = null;
|
||||
|
||||
function positionTooltip(event) {
|
||||
const margin = 14;
|
||||
const offset = 16;
|
||||
const rect = tooltip.getBoundingClientRect();
|
||||
let left = event.clientX + offset;
|
||||
let top = event.clientY + offset;
|
||||
|
||||
if (left + rect.width + margin > window.innerWidth) {
|
||||
left = Math.max(margin, event.clientX - rect.width - offset);
|
||||
}
|
||||
if (top + rect.height + margin > window.innerHeight) {
|
||||
top = Math.max(margin, event.clientY - rect.height - offset);
|
||||
}
|
||||
|
||||
tooltip.style.left = `${left}px`;
|
||||
tooltip.style.top = `${top}px`;
|
||||
}
|
||||
|
||||
function showTooltip(target, event) {
|
||||
const text = target.dataset.tip;
|
||||
if (!text) return;
|
||||
activeTipTarget = target;
|
||||
tooltip.textContent = text;
|
||||
tooltip.classList.add("is-visible");
|
||||
positionTooltip(event);
|
||||
}
|
||||
|
||||
function hideTooltip() {
|
||||
activeTipTarget = null;
|
||||
tooltip.classList.remove("is-visible");
|
||||
}
|
||||
|
||||
document.addEventListener("pointerover", (event) => {
|
||||
const target = event.target.closest("[data-tip]");
|
||||
if (target) showTooltip(target, event);
|
||||
});
|
||||
|
||||
document.addEventListener("pointermove", (event) => {
|
||||
if (activeTipTarget) positionTooltip(event);
|
||||
});
|
||||
|
||||
document.addEventListener("pointerout", (event) => {
|
||||
if (!activeTipTarget) return;
|
||||
const next = event.relatedTarget;
|
||||
if (!next || !activeTipTarget.contains(next)) hideTooltip();
|
||||
});
|
||||
|
||||
document.querySelectorAll("[data-tip]").forEach((element) => {
|
||||
element.setAttribute("tabindex", "0");
|
||||
element.setAttribute("aria-label", element.dataset.tip);
|
||||
element.addEventListener("focus", (event) => {
|
||||
const rect = event.currentTarget.getBoundingClientRect();
|
||||
showTooltip(event.currentTarget, {
|
||||
clientX: rect.left + rect.width / 2,
|
||||
clientY: rect.top + rect.height / 2,
|
||||
});
|
||||
});
|
||||
element.addEventListener("blur", hideTooltip);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,176 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>白领一天业务测试页</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
color: #1f2937;
|
||||
background: #f6f8fb;
|
||||
}
|
||||
header {
|
||||
padding: 20px 28px;
|
||||
background: #0f766e;
|
||||
color: white;
|
||||
}
|
||||
main {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 16px;
|
||||
padding: 20px;
|
||||
}
|
||||
section {
|
||||
min-height: 180px;
|
||||
padding: 16px;
|
||||
border: 1px solid #d8dee8;
|
||||
border-radius: 8px;
|
||||
background: white;
|
||||
}
|
||||
h1,
|
||||
h2 {
|
||||
margin: 0 0 12px;
|
||||
}
|
||||
label,
|
||||
input,
|
||||
select,
|
||||
textarea,
|
||||
button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin: 8px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
padding: 8px;
|
||||
border: 1px solid #cbd5e1;
|
||||
border-radius: 6px;
|
||||
}
|
||||
button {
|
||||
padding: 9px 12px;
|
||||
border: 0;
|
||||
border-radius: 6px;
|
||||
color: white;
|
||||
background: #2563eb;
|
||||
cursor: pointer;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
text-align: left;
|
||||
}
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
background: #e0f2fe;
|
||||
color: #0369a1;
|
||||
}
|
||||
.result {
|
||||
min-height: 22px;
|
||||
color: #166534;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>白领一天业务测试页</h1>
|
||||
<p>用于验证数字员工通过 sgBrowser 完成网页采集、填写、比对和下载确认。</p>
|
||||
</header>
|
||||
<main>
|
||||
<section id="company-contact">
|
||||
<h2>供应商联系人</h2>
|
||||
<p data-field="company">白银智维科技有限公司</p>
|
||||
<p data-field="contact">联系人:李敏</p>
|
||||
<p data-field="phone">电话:0931-6201888</p>
|
||||
<p data-field="email">邮箱:limin@example.local</p>
|
||||
</section>
|
||||
|
||||
<section id="industry-news">
|
||||
<h2>行业动态</h2>
|
||||
<ol>
|
||||
<li data-score="96">内网终端安全巡检纳入月度闭环</li>
|
||||
<li data-score="88">营销系统工单响应时限压缩至 2 小时</li>
|
||||
<li data-score="81">国产化办公终端批量适配完成</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section id="customer-form">
|
||||
<h2>客户回访登记</h2>
|
||||
<label>客户名称<input id="customer-name" /></label>
|
||||
<label>联系电话<input id="customer-phone" /></label>
|
||||
<label>回访结论<select id="visit-result"><option>请选择</option><option>已解决</option><option>需跟进</option></select></label>
|
||||
<textarea id="visit-note" rows="3" placeholder="回访备注"></textarea>
|
||||
<button id="prepare-form" type="button">检查表单</button>
|
||||
<p id="form-status" class="result"></p>
|
||||
</section>
|
||||
|
||||
<section id="product-compare">
|
||||
<h2>设备方案比对</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>方案</th><th>价格</th><th>交付天数</th><th>风险</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>基础巡检包</td><td>68000</td><td>12</td><td>低</td></tr>
|
||||
<tr><td>增强巡检包</td><td>82000</td><td>9</td><td>中</td></tr>
|
||||
<tr><td>全量管控包</td><td>98000</td><td>7</td><td>中</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section id="todo-login">
|
||||
<h2>待办系统</h2>
|
||||
<label>用户名<input id="login-user" /></label>
|
||||
<label>口令<input id="login-pass" type="password" /></label>
|
||||
<button id="login-button" type="button">登录</button>
|
||||
<ul id="todo-list">
|
||||
<li><span class="badge">紧急</span> 完成安全巡检日报</li>
|
||||
<li><span class="badge">普通</span> 核对客户回访清单</li>
|
||||
<li><span class="badge">普通</span> 整理明日会议材料</li>
|
||||
</ul>
|
||||
<p id="login-status" class="result"></p>
|
||||
</section>
|
||||
|
||||
<section id="customer-list">
|
||||
<h2>客户清单</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><td>兰州新区供电服务站</td><td>待回访</td><td>王磊</td></tr>
|
||||
<tr><td>白银银光营业厅</td><td>已完成</td><td>张琴</td></tr>
|
||||
<tr><td>景泰调度中心</td><td>需协同</td><td>马宁</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section id="download-center">
|
||||
<h2>资料下载</h2>
|
||||
<p>最新资料:2026 年 5 月内网终端巡检模板</p>
|
||||
<a id="latest-download" href="daily-template-202605.xlsx" download>下载巡检模板</a>
|
||||
</section>
|
||||
</main>
|
||||
<script>
|
||||
document.getElementById("prepare-form").addEventListener("click", function () {
|
||||
const name = document.getElementById("customer-name").value.trim();
|
||||
const result = document.getElementById("visit-result").value;
|
||||
document.getElementById("form-status").textContent =
|
||||
name && result !== "请选择" ? "表单已检查,等待人工确认提交" : "表单信息不完整";
|
||||
});
|
||||
document.getElementById("login-button").addEventListener("click", function () {
|
||||
document.getElementById("login-status").textContent = "已读取待办,不执行真实登录";
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
ArrowLeftOutlined,
|
||||
ReloadOutlined,
|
||||
ApiOutlined,
|
||||
AppstoreOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import {
|
||||
setupService,
|
||||
@@ -57,6 +58,7 @@ import AboutPage from "./components/pages/AboutPage";
|
||||
import LogViewer from "./components/pages/LogViewer";
|
||||
import PermissionsPage from "./components/pages/PermissionsPage";
|
||||
import SessionsPage from "./components/pages/SessionsPage";
|
||||
import OverviewPage from "./components/pages/OverviewPage";
|
||||
import MCPSettings from "./components/settings/MCPSettings";
|
||||
import type { WebviewHeaderActions } from "./components/pages/SessionsPage";
|
||||
import { createLogger } from "./services/utils/rendererLog";
|
||||
@@ -104,6 +106,7 @@ export function useI18nLang(): I18nContextValue {
|
||||
// Tab 类型定义(对齐 Tauri 客户端)
|
||||
type TabKey =
|
||||
| "client"
|
||||
| "overview"
|
||||
| "sessions"
|
||||
| "mcp"
|
||||
| "settings"
|
||||
@@ -1054,6 +1057,11 @@ function App() {
|
||||
icon: <DashboardOutlined />,
|
||||
label: t("Claw.Menu.client"),
|
||||
},
|
||||
{
|
||||
key: "overview",
|
||||
icon: <AppstoreOutlined />,
|
||||
label: t("Claw.Menu.overview"),
|
||||
},
|
||||
{
|
||||
key: "sessions",
|
||||
icon: <TeamOutlined />,
|
||||
@@ -1353,6 +1361,7 @@ function App() {
|
||||
onLoginStarted={handleLoginStarted}
|
||||
/>
|
||||
)}
|
||||
{activeTab === "overview" && <OverviewPage />}
|
||||
{activeTab === "sessions" && (
|
||||
<SessionsPage
|
||||
autoOpen={sessionsAutoOpen}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { Alert, Button, Input, message } from "antd";
|
||||
import { ReloadOutlined, SaveOutlined } from "@ant-design/icons";
|
||||
import { APP_DISPLAY_NAME } from "@shared/constants";
|
||||
import { t } from "../../services/core/i18n";
|
||||
import styles from "../../styles/components/OverviewPage.module.css";
|
||||
|
||||
const OVERVIEW_URL_SETTING_KEY = "overview.digital_employee_url";
|
||||
const DEFAULT_OVERVIEW_URL = "sgrobot-digital/index.html#/digital";
|
||||
|
||||
function normalizeOverviewUrl(value: string): string {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return DEFAULT_OVERVIEW_URL;
|
||||
const url = new URL(trimmed, window.location.href);
|
||||
const legacySgRobotEndpoint =
|
||||
(url.hostname === "localhost" && url.port === "5173") ||
|
||||
(url.hostname === "127.0.0.1" && url.port === "42617");
|
||||
if (legacySgRobotEndpoint && url.pathname === "/_app/digital") {
|
||||
return DEFAULT_OVERVIEW_URL;
|
||||
}
|
||||
if (!["http:", "https:", "file:"].includes(url.protocol)) {
|
||||
throw new Error("Unsupported protocol");
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
function OverviewPage() {
|
||||
const webviewRef = useRef<HTMLElement | null>(null);
|
||||
const [url, setUrl] = useState(DEFAULT_OVERVIEW_URL);
|
||||
const [draftUrl, setDraftUrl] = useState(DEFAULT_OVERVIEW_URL);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [userAgent, setUserAgent] = useState<string | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
window.electronAPI?.app
|
||||
.getVersion()
|
||||
.then((version) => {
|
||||
setUserAgent(navigator.userAgent + ` ${APP_DISPLAY_NAME}/${version}`);
|
||||
})
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
let mounted = true;
|
||||
window.electronAPI?.settings
|
||||
.get(OVERVIEW_URL_SETTING_KEY)
|
||||
.then((saved) => {
|
||||
if (!mounted || typeof saved !== "string" || !saved.trim()) return;
|
||||
const normalized = normalizeOverviewUrl(saved);
|
||||
setUrl(normalized);
|
||||
setDraftUrl(normalized);
|
||||
})
|
||||
.catch(() => {});
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const el = webviewRef.current as any;
|
||||
if (!el) return;
|
||||
|
||||
const handleStartLoading = () => setError(null);
|
||||
const handleFailLoad = (e: any) => {
|
||||
if (e.errorCode && e.errorCode !== -3) {
|
||||
setError(
|
||||
t(
|
||||
"Claw.Overview.loadFailed",
|
||||
e.errorDescription || t("Claw.EmbeddedWebview.unknownError"),
|
||||
String(e.errorCode),
|
||||
),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
el.addEventListener("did-start-loading", handleStartLoading);
|
||||
el.addEventListener("did-fail-load", handleFailLoad);
|
||||
return () => {
|
||||
el.removeEventListener("did-start-loading", handleStartLoading);
|
||||
el.removeEventListener("did-fail-load", handleFailLoad);
|
||||
};
|
||||
}, [url]);
|
||||
|
||||
const canSave = useMemo(() => draftUrl.trim() !== url, [draftUrl, url]);
|
||||
const webviewUrl = useMemo(
|
||||
() => new URL(url, window.location.href).toString(),
|
||||
[url],
|
||||
);
|
||||
|
||||
const handleReload = useCallback(() => {
|
||||
setError(null);
|
||||
(webviewRef.current as any)?.reload?.();
|
||||
}, []);
|
||||
|
||||
const handleSave = useCallback(async () => {
|
||||
try {
|
||||
const normalized = normalizeOverviewUrl(draftUrl);
|
||||
await window.electronAPI?.settings.set(
|
||||
OVERVIEW_URL_SETTING_KEY,
|
||||
normalized,
|
||||
);
|
||||
setUrl(normalized);
|
||||
setDraftUrl(normalized);
|
||||
setError(null);
|
||||
message.success(t("Claw.Overview.urlSaved"));
|
||||
} catch {
|
||||
message.error(t("Claw.Overview.invalidUrl"));
|
||||
}
|
||||
}, [draftUrl]);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.toolbar}>
|
||||
<span className={styles.title}>{t("Claw.Overview.title")}</span>
|
||||
<Input
|
||||
size="small"
|
||||
className={styles.urlInput}
|
||||
value={draftUrl}
|
||||
onChange={(e) => setDraftUrl(e.target.value)}
|
||||
onPressEnter={handleSave}
|
||||
/>
|
||||
<Button
|
||||
size="small"
|
||||
icon={<SaveOutlined />}
|
||||
onClick={handleSave}
|
||||
disabled={!canSave}
|
||||
>
|
||||
{t("Claw.Common.save")}
|
||||
</Button>
|
||||
<Button size="small" icon={<ReloadOutlined />} onClick={handleReload}>
|
||||
{t("Claw.Common.refresh")}
|
||||
</Button>
|
||||
</div>
|
||||
{error && (
|
||||
<Alert
|
||||
message={error}
|
||||
type="error"
|
||||
showIcon
|
||||
closable
|
||||
onClose={() => setError(null)}
|
||||
className={styles.error}
|
||||
/>
|
||||
)}
|
||||
<webview
|
||||
ref={webviewRef as any}
|
||||
src={webviewUrl}
|
||||
useragent={userAgent}
|
||||
className={styles.webview}
|
||||
allowpopups={"true" as any}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default OverviewPage;
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<link rel="icon" type="image/png" href="/icon.png" />
|
||||
<!-- 与 @shared/constants APP_DISPLAY_NAME 保持一致 -->
|
||||
<title>启明</title>
|
||||
<title>飞天</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
.container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
background: var(--color-bg-layout);
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
background: var(--color-bg-container);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
flex: 0 0 auto;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.urlInput {
|
||||
flex: 1;
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.error {
|
||||
margin: 8px 12px 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.webview {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
min-height: 0;
|
||||
border: none;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ import {
|
||||
describe("Constants", () => {
|
||||
describe("App Identity", () => {
|
||||
it("should have consistent app name", () => {
|
||||
expect(APP_DISPLAY_NAME).toBe("启明数字员工");
|
||||
expect(APP_DISPLAY_NAME).toBe("飞天数字员工");
|
||||
expect(APP_NAME_IDENTIFIER).toBe("qimingclaw");
|
||||
});
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import type { AgentEngineType } from "@shared/types/electron";
|
||||
// ==================== 应用名称 ====================
|
||||
|
||||
/** 应用对外显示名称(窗口标题、关于、安装包名称等),与 package.json build.productName 保持一致 */
|
||||
export const APP_DISPLAY_NAME = "启明数字员工";
|
||||
export const APP_DISPLAY_NAME = "飞天数字员工";
|
||||
|
||||
/** 应用技术标识(进程名、目录名等,小写字母),与 appId 等保持一致 */
|
||||
export const APP_NAME_IDENTIFIER = "qimingclaw";
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"Claw.Agent.Status.stopped": "Stopped",
|
||||
"Claw.Agent.Status.error": "Error",
|
||||
"Claw.Menu.client": "Client",
|
||||
"Claw.Menu.overview": "Overview",
|
||||
"Claw.Menu.session": "Session",
|
||||
"Claw.Menu.mcp": "MCP",
|
||||
"Claw.Menu.settings": "Settings",
|
||||
@@ -254,6 +255,10 @@
|
||||
"Claw.EmbeddedWebview.back": "Back",
|
||||
"Claw.EmbeddedWebview.refresh": "Refresh",
|
||||
"Claw.EmbeddedWebview.unknownError": "Unknown error",
|
||||
"Claw.Overview.title": "Digital Employee Overview",
|
||||
"Claw.Overview.loadFailed": "Digital employee page failed to load: {0} ({1})",
|
||||
"Claw.Overview.urlSaved": "Overview URL saved",
|
||||
"Claw.Overview.invalidUrl": "Enter a valid http/https URL",
|
||||
"Claw.AgentRunner.configSaved": "Config saved",
|
||||
"Claw.AgentRunner.stopped": "Agent Runner stopped",
|
||||
"Claw.AgentRunner.started": "Agent Runner started",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"Claw.Agent.Status.stopped": "已停止",
|
||||
"Claw.Agent.Status.error": "错误",
|
||||
"Claw.Menu.client": "客户端",
|
||||
"Claw.Menu.overview": "概览",
|
||||
"Claw.Menu.session": "会话",
|
||||
"Claw.Menu.mcp": "MCP",
|
||||
"Claw.Menu.settings": "设置",
|
||||
@@ -254,6 +255,10 @@
|
||||
"Claw.EmbeddedWebview.back": "返回",
|
||||
"Claw.EmbeddedWebview.refresh": "刷新",
|
||||
"Claw.EmbeddedWebview.unknownError": "未知错误",
|
||||
"Claw.Overview.title": "数字员工概览",
|
||||
"Claw.Overview.loadFailed": "数字员工页面加载失败: {0} ({1})",
|
||||
"Claw.Overview.urlSaved": "概览地址已保存",
|
||||
"Claw.Overview.invalidUrl": "请输入有效的 http/https 地址",
|
||||
"Claw.AgentRunner.configSaved": "配置已保存",
|
||||
"Claw.AgentRunner.stopped": "Agent Runner 已停止",
|
||||
"Claw.AgentRunner.started": "Agent Runner 已启动",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"Claw.Agent.Status.stopped": "已停止",
|
||||
"Claw.Agent.Status.error": "錯誤",
|
||||
"Claw.Menu.client": "客戶端",
|
||||
"Claw.Menu.overview": "概覽",
|
||||
"Claw.Menu.session": "工作階段",
|
||||
"Claw.Menu.mcp": "MCP",
|
||||
"Claw.Menu.settings": "設定",
|
||||
@@ -254,6 +255,10 @@
|
||||
"Claw.EmbeddedWebview.back": "返回",
|
||||
"Claw.EmbeddedWebview.refresh": "重新整理",
|
||||
"Claw.EmbeddedWebview.unknownError": "未知錯誤",
|
||||
"Claw.Overview.title": "數字員工概覽",
|
||||
"Claw.Overview.loadFailed": "數字員工頁面載入失敗: {0} ({1})",
|
||||
"Claw.Overview.urlSaved": "概覽位址已儲存",
|
||||
"Claw.Overview.invalidUrl": "請輸入有效的 http/https 位址",
|
||||
"Claw.AgentRunner.configSaved": "配置已儲存",
|
||||
"Claw.AgentRunner.stopped": "Agent Runner 已停止",
|
||||
"Claw.AgentRunner.started": "Agent Runner 已啟動",
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"Claw.Agent.Status.stopped": "已停止",
|
||||
"Claw.Agent.Status.error": "錯誤",
|
||||
"Claw.Menu.client": "客戶端",
|
||||
"Claw.Menu.overview": "概覽",
|
||||
"Claw.Menu.session": "工作階段",
|
||||
"Claw.Menu.mcp": "MCP",
|
||||
"Claw.Menu.settings": "設定",
|
||||
@@ -254,6 +255,10 @@
|
||||
"Claw.EmbeddedWebview.back": "返回",
|
||||
"Claw.EmbeddedWebview.refresh": "重新整理",
|
||||
"Claw.EmbeddedWebview.unknownError": "未知錯誤",
|
||||
"Claw.Overview.title": "數字員工概覽",
|
||||
"Claw.Overview.loadFailed": "數字員工頁面載入失敗: {0} ({1})",
|
||||
"Claw.Overview.urlSaved": "概覽位址已儲存",
|
||||
"Claw.Overview.invalidUrl": "請輸入有效的 http/https 位址",
|
||||
"Claw.AgentRunner.configSaved": "配置已儲存",
|
||||
"Claw.AgentRunner.stopped": "Agent Runner 已停止",
|
||||
"Claw.AgentRunner.started": "Agent Runner 已啟動",
|
||||
|
||||