627 lines
34 KiB
HTML
627 lines
34 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>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>
|