合并 origin/mvp-foundation:活动模块接真接口 + 员工模块界面改版 + 启动抽屉「责任人」+ 身份菜单直链运营中心(shanqin 三条)
CI / ci (push) Failing after 11s

主支这边:W05 1.4.1–1.4.7 七条 + 刚合进来的 feat/activity-ops-w05(运营中心活动模块接口 L1/L2/L3、
W05 在途修订、同日 harness/工作台修);远端三条是队友的前端:活动模块 L1/L2/L3 接真接口(顺手按接口文档
补了 api/activity-ops.ts 契约)、员工模块界面改版、启动抽屉固定参数「责任人」、工作台身份菜单直链 /ops。

冲突三处,全是两边各写了一版同一样东西:
① `packages/contracts/src/activity-ops.ts` / `api/activity-ops.ts`(add/add):取后端那版 —— 队友是照
   《API文档-活动模块》补的,43 个导出同名、路由 12 条全同,只差 launchOptionSchema / INSTANCE_REASON_KINDS /
   STEP_RESULTS 三个名字;队友前端对着后端契约原样编译通过。
② `docs/API文档-活动模块.md`:取后端按契约回写的那份(已含 §5 责任人 ownerId、combo 语义、关键台账看板一节、
   候选料号改单选);队友那侧是回写前的旧稿。
设计端活动库两条路由改名 `/api/gov/activity-packages` 让位随 feat 分支进来,队友契约与治理台同名路由撞车那 7 条
路由注册表测试(远端主支自己红)就此消解;api-report 按合并树重刷。

五道门禁绿:2240 测试通过、23 跳过(无模型密钥 / 无真信箱的惯常项)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0167qWjeyBwvfdGovd7FWbCu
This commit is contained in:
xcs
2026-08-27 23:22:57 +08:00
co-authored by Claude Fable 5
10 changed files with 1318 additions and 875 deletions
+4 -4
View File
@@ -178,10 +178,10 @@ export function AppShell() {
<Ico name="user" s={14} />
个人中心
</a>
{/* 设计中心直链数据域页,整页导航过去(2026-08-25 用户定) */}
<a href="/design#/design/data/domains">
<Ico name="pen-line" s={14} />
设计中心
{/* 运营中心直链活动板块(2026-08-28 用户定,原设计中心入口改此),整页导航过去 */}
<a href="/ops#/ops/tasks/active">
<Ico name="list-checks" s={14} />
运营中心
</a>
<button type="button" className="danger" onClick={logout}>
<Ico name="log-out" s={14} />
+1 -1
View File
@@ -499,7 +499,7 @@
/* 但右上角装饰光晕定位 right:-60px,裁切一放开它就探出视口右缘 60px,整页出现横向滚动
(2026-08-25 用户报:页面能左右滑)—— 把它收回盒内,光晕照留 */
.proto-root .jc-topbar.jc-topbar-app::after { right: 0; }
/* 身份菜单:头像 + 姓名,悬停出下拉(个人中心 / 设计中心 / 退出登录)—— 纯 CSS 悬停无 JS;
/* 身份菜单:头像 + 姓名,悬停出下拉(个人中心 / 运营中心 / 退出登录)—— 纯 CSS 悬停无 JS;
登出入口收进下拉,是全站唯一入口(2026-08-25 用户定);2026-08-26 从顶栏挪进左轨底部(见下方 rail 变体) */
.proto-root .jc-usermenu { position: relative; display: flex; align-items: center; gap: 8px; padding: 4px 8px 4px 4px; border-radius: 10px; cursor: default; color: var(--ink-4); transition: background var(--t-fast); }
.proto-root .jc-usermenu:hover { background: var(--soft); }
+164
View File
@@ -736,9 +736,17 @@
border-top: 1px solid var(--tone-line, var(--cline)); border-right: 1px solid var(--tone-line, var(--cline)); }
.g-actvd .g-popask p, .g-actid .g-popask p { margin: 0; font-size: 13px; font-weight: 600; line-height: 1.55; color: var(--ink); }
.g-actvd .g-popask-a, .g-actid .g-popask-a { display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px; }
/* 失败原因留在气泡里(2026-08-28 用户报:终止点了不知道成没成)—— 选择器多带一层 .g-popask,压过上面的 p 基则 */
.g-actvd .g-popask .g-popask-err, .g-actid .g-popask .g-popask-err { margin: 8px 0 0; font-size: 12px; font-weight: 500; line-height: 1.5; color: var(--danger-accent, #d83931); }
@media (prefers-reduced-motion: reduce) {
.g-actvd .g-popask, .g-actid .g-popask { animation: none; }
}
/* 行内终止的轻气泡(2026-08-27 接接口,文档 §10:L2 行内终止也要二次确认)——
锚在操作格里(触发钮左边,垂直对行中线);不进退场动画:行是表格流,气泡从格子里长出来就够 */
.g-actvd .g-irow .a { position: relative; }
.g-actvd .g-popask.inrow { top: 50%; right: calc(100% + 8px); transform: translateY(-50%); animation: none; }
/* 实例详情:文件列表与键值区之间补一道距 */
.g-actid .g-files { display: grid; gap: 8px; margin-top: 10px; }
/* ══ 启动活动 · 参数抽屉(2026-08-27 用户定)══
骨架复用全局 g-drawer;portal 挂在 body 上,作用域类 .g-launch 得自己带着走。
@@ -759,6 +767,162 @@
.g-launch .g-combo .g-input { flex: 1; min-width: 0; }
.g-launch .g-combo-back { flex: none; padding: 4px 6px; border: 0; border-radius: 6px; background: transparent; color: var(--brand); font: inherit; font-size: 12px; font-weight: 600; cursor: pointer; }
.g-launch .g-combo-back:hover { text-decoration: underline; }
/* ══ 员工模块(成员与组织)改版(2026-08-27 用户定:只改布局与样式,数据/接口/功能不动)══
作用域 .g-people:共享件(g-* 基类)本体不动,这里全是本模块的件;
目录行 = 表头与数据同一条栅格;首字圆块色板轮换(t-brand/collab/warn/decision)是本页唯一记忆点 */
/* —— 卡内容区补距(2026-08-27 用户:卡片内容贴边、太挤)——
.g-card-b(padding 14px 16px / gap 12px)定义了但从没接线,内容直落 .g-card 贴边(见 236 行注释);
共享件不动,本模块作用域内补同一组数值:左右 16、上 12、末尾 14。
整幅列表(目录行 .g-mtab / 角色开关 .g-rtab)不进这条 —— 它们边到边,用自己的行分隔线 */
.g-people .g-card > :not(.g-card-h) { margin: 12px 16px 0; }
.g-people .g-card > :not(.g-card-h):last-child { margin-bottom: 14px; }
.g-people .g-card > .g-mtab, .g-people .g-card > .g-rtab { margin: 0; border: 0; border-top: 1px solid var(--line-soft); border-radius: 0; }
/* —— 成员 · 工具条:从卡头抽出,卡内第一行;左检索,右筛选 + 主操作 —— */
.g-people-bar { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.g-people-search { position: relative; flex: none; width: 280px; display: flex; align-items: center; }
.g-people-search > svg { position: absolute; left: 10px; color: var(--ink-4); pointer-events: none; }
.g-people-search .g-input { padding-left: 30px; }
.g-people-bar .g-tick { margin-left: auto; }
/* —— 成员目录行(用户选定:目录行而非卡片网格)—— */
.g-people .g-mtab { background: var(--card); border: 1px solid var(--cline); border-radius: 12px; overflow: hidden; }
.g-people .g-mrow-h, .g-people .g-mrow { display: grid; grid-template-columns: 40px minmax(160px, 1.3fr) minmax(190px, 1.1fr) minmax(130px, .9fr) minmax(170px, 1.1fr) 76px 16px; align-items: center; gap: 12px; padding: 0 14px; }
.g-people .g-mrow-h { height: 34px; font-size: 11px; font-weight: 600; letter-spacing: .04em; color: var(--ink-4); background: #fbfcfe; border-bottom: 1px solid var(--line-soft); }
.g-people .g-mrow { width: 100%; min-height: 56px; padding-top: 8px; padding-bottom: 8px; border: 0; border-bottom: 1px solid var(--line-soft); background: transparent; font: inherit; text-align: left; cursor: pointer; transition: background var(--t-fast); }
/* 斑马:第 1 个 child 是表头,数据行从 2 起 —— odd 命中的正是第 2、4… 条数据 */
.g-people .g-mrow:nth-child(odd) { background: #fafbfd; }
.g-people .g-mrow:hover { background: #f3f6fb; }
.g-people .g-mrow:last-child { border-bottom: 0; }
.g-people .g-mrow:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
/* 停用行整行降饱和 —— 一眼分出在职/停用,不必等读到状态丸 */
.g-people .g-mrow.off { opacity: .62; }
.g-people .g-mava { width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center; font-size: 14px; font-weight: 700; color: var(--tone-ink); background: var(--tone-soft); border: 1px solid var(--tone-line); }
.g-people .who { min-width: 0; line-height: 1.45; }
.g-people .who b { display: block; font-size: 13px; font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.g-people .who em { display: block; font-style: normal; font-family: var(--mono); font-size: 10.5px; color: var(--ink-4); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.g-people .g-mrow .mail { font-size: 12px; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.g-people .g-mrow .role { font-family: var(--mono); font-size: 11.5px; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.g-people .g-mrow .ends { display: flex; flex-wrap: wrap; gap: 4px; min-width: 0; }
.g-people .g-mrow .st { display: flex; justify-content: flex-end; }
.g-people .g-mrow .x { color: var(--ink-4); display: grid; place-items: center; transition: color var(--t-fast), transform var(--t-fast); }
.g-people .g-mrow:hover .x { color: var(--brand); transform: translateX(2px); }
/* —— 权限 · 一行一角色:身份 | 可进端 | 操作;描述收成灰字,确认带与编辑区走全宽 —— */
.g-people .g-ptab { display: flex; flex-direction: column; gap: 8px; }
.g-people .g-prole { background: var(--card); border: 1px solid var(--cline); border-radius: 12px; padding: 12px 14px; }
.g-people .g-prole-row { display: grid; grid-template-columns: minmax(200px, 1fr) minmax(0, 2fr) auto; align-items: center; gap: 14px; }
.g-people .g-prole .id { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.g-people .g-prole .id b { font-size: 13px; font-weight: 700; color: var(--ink); }
.g-people .g-prole .id em { font-style: normal; font-size: 11px; color: var(--ink-4); white-space: nowrap; }
.g-people .g-prole .body { min-width: 0; }
.g-people .g-prole .ends { display: flex; flex-wrap: wrap; gap: 4px; }
.g-people .g-prole .desc { display: block; margin-top: 5px; font-size: 12px; line-height: 1.6; color: var(--ink-4); }
.g-people .g-prole .a { display: flex; gap: 8px; justify-content: flex-end; }
.g-people .g-prole > .g-note { margin-top: 10px; }
.g-people .g-prole .g-ask { margin-top: 10px; }
.g-people .g-prole-edit { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--line-soft); animation: g-fade .18s ease-out; }
/* —— 组织 · 树行 / 建组条 / 空态 / 组成员行 —— */
.g-people .g-tree-r { min-height: 34px; font-size: 12.5px; }
.g-people .g-tree-r.on { background: var(--brand-wash); box-shadow: inset 3px 0 0 var(--brand); }
.g-people .g-tree-r em { font-family: var(--mono); }
.g-people-tadd { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line-soft); }
.g-people-tadd .g-input { flex: 1; min-width: 0; }
.g-people-tadd .g-note { flex-basis: 100%; }
.g-people-empty { min-height: 320px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 24px; background: var(--card); border: 1px dashed var(--cline); border-radius: 12px; color: var(--ink-4); text-align: center; }
.g-people-empty p { margin: 0; max-width: 340px; font-size: 12.5px; line-height: 1.7; }
.g-people-empty .g-people-tadd { width: min(360px, 100%); margin-top: 4px; padding-top: 0; border-top: 0; }
.g-people .g-gmtab { background: var(--card); border: 1px solid var(--cline); border-radius: 12px; overflow: hidden; }
.g-people .g-gmrow { display: flex; align-items: center; gap: 12px; padding: 9px 14px; border-bottom: 1px solid var(--line-soft); transition: background var(--t-fast); }
.g-people .g-gmrow:hover { background: #f7f9fc; }
.g-people .g-gmrow:last-child { border-bottom: 0; }
.g-people .g-gmrow .who { flex: 1; }
.g-people .g-gmrow.off { opacity: .62; }
/* —— 成员详情 · 主从 2:1(DESIGN-SPEC §9)+ 危险区通栏 —— */
.g-people-dgrid { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 14px; align-items: start; }
.g-people-dgrid .main, .g-people-dgrid .rail { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
@media (max-width: 1024px) { .g-people-dgrid { grid-template-columns: 1fr; } }
/* 危险区:白卡 + 红描边标题行;钮非实心(danger 类自带),确认带三必答不变 */
.g-people-danger { margin-top: 14px; background: var(--card); border: 1px solid #f6c6c3; border-radius: 12px; padding: 13px 16px; }
.g-people-danger .hd { display: flex; align-items: center; gap: 8px; color: var(--danger); }
.g-people-danger .hd b { font-size: 13px; font-weight: 700; }
.g-people-danger .hd span { margin-left: 4px; font-size: 11.5px; line-height: 1.6; color: var(--ink-4); }
/* ── 第二轮深化(2026-08-27 用户:还要更好看)───────────────────────── */
/* 成员行:首字圆块 hover 轻放大(transform-only,不推别人);角色列 = 迷你 mono 小丸 */
.g-people .g-mava { transition: transform var(--t-fast); }
.g-people .g-mrow:hover .g-mava { transform: scale(1.08); }
.g-people .g-mrow .role { display: flex; flex-wrap: wrap; gap: 4px; font-family: var(--mono); font-size: 11.5px; color: var(--ink-2); }
.g-people .g-mrow .role .rp { font-style: normal; font-family: var(--mono); font-size: 10.5px; font-weight: 600; padding: 1px 7px; border-radius: 6px; border: 1px solid var(--line-soft); background: #f6f8fb; color: var(--ink-2); white-space: nowrap; }
/* 权限行:可进端三槽点位 —— 三个端固定位,授了 brand 实底、没授虚灰;列向下扫即成矩阵 */
.g-people .g-prole .ends3 { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; }
.g-people .g-prole .ends3 .ep { font-style: normal; font-size: 10.5px; font-weight: 600; padding: 2px 9px; border-radius: 999px; border: 1px dashed var(--cline); color: var(--ink-4); background: transparent; white-space: nowrap; }
.g-people .g-prole .ends3 .ep.on { border: 1px solid var(--tone-line, #c5d8ff); background: #f0f4ff; color: #245bdb; }
.g-people .g-prole { transition: border-color var(--t-fast); }
.g-people .g-prole:hover { border-color: #c9d4e2; }
/* 成员详情 hero:这个人是主角 —— 60px 首字圆块 + 名/状态 + 可进端;右侧两条动态事实 */
.g-people-d .g-mhero { display: flex; align-items: flex-start; gap: 16px; padding: 18px 20px; margin-bottom: 14px; background: var(--card); border: 1px solid var(--cline); border-radius: 14px; }
.g-people-d .g-mhero-ava { flex: none; width: 60px; height: 60px; border-radius: 50%; display: grid; place-items: center; font-size: 24px; font-weight: 700; color: var(--tone-ink); background: var(--tone-soft); border: 1px solid var(--tone-line); }
.g-people-d .g-mhero-t { flex: 1; min-width: 0; }
.g-people-d .g-mhero-t > em { font-style: normal; font-size: 11px; font-weight: 600; letter-spacing: .06em; color: var(--ink-4); }
.g-people-d .g-mhero-t h2 { display: flex; align-items: center; gap: 10px; margin: 3px 0 0; font-size: 19px; font-weight: 700; color: var(--ink); }
.g-people-d .g-mhero-t p { margin: 6px 0 0; font-size: 12px; line-height: 1.6; color: var(--ink-3); }
.g-people-d .g-mhero-t p i { margin: 0 7px; font-style: normal; color: var(--ink-4); }
.g-people-d .g-mhero-ends { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 9px; }
.g-people-d .g-mhero-meta { flex: none; display: flex; flex-direction: column; gap: 8px; text-align: right; }
.g-people-d .g-mhero-meta em { display: block; font-style: normal; font-size: 10.5px; color: var(--ink-4); }
.g-people-d .g-mhero-meta b { display: block; margin-top: 2px; font-family: var(--mono); font-size: 12px; font-weight: 600; color: var(--ink-2); }
/* 身份卡键值改 2×2 栅格(事实只有 4 条,别再竖排长条) */
.g-people-d .g-rows { display: grid; grid-template-columns: 1fr 1fr; box-shadow: none; }
.g-people-d .g-rows > div { grid-template-columns: 96px minmax(0, 1fr); padding: 10px 14px; }
/* 角色 = 开关清单:行 = 名字+描述 | 可进端 | 开关 */
.g-people-d .g-rtab { display: flex; flex-direction: column; }
.g-people-d .g-rrow { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) auto; align-items: center; gap: 12px; padding: 10px 14px; border-bottom: 1px solid var(--line-soft); transition: background var(--t-fast); }
.g-people-d .g-rrow:last-child { border-bottom: 0; }
.g-people-d .g-rrow:hover { background: #f7f9fc; }
.g-people-d .g-rrow .id { min-width: 0; }
.g-people-d .g-rrow .id b { display: block; font-size: 12.5px; font-weight: 700; color: var(--ink); }
.g-people-d .g-rrow .id em { display: block; margin-top: 2px; font-style: normal; font-size: 11px; line-height: 1.5; color: var(--ink-4); }
.g-people-d .g-rrow .ends { font-size: 11px; color: var(--ink-3); }
.g-people-d .g-role-sw { position: relative; flex: none; width: 36px; height: 20px; padding: 0; border: 1px solid var(--cline); border-radius: 999px; background: #e8edf3; cursor: pointer; transition: background var(--t-fast), border-color var(--t-fast); }
.g-people-d .g-role-sw i { position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(19, 28, 38, .25); transition: transform .15s ease-out; }
.g-people-d .g-role-sw.on { background: var(--brand); border-color: var(--brand); }
.g-people-d .g-role-sw.on i { transform: translateX(16px); }
.g-people-d .g-role-sw:disabled { opacity: .45; cursor: default; }
.g-people-d .g-role-sw:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
/* 危险区:两条动作行 —— 每行说清动作与后果,钮在行右 */
.g-people-danger .g-drow { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-top: 1px solid var(--line-soft); }
.g-people-danger .hd + .g-drow { margin-top: 6px; }
.g-people-danger .g-drow .t { flex: 1; min-width: 0; }
.g-people-danger .g-drow .t b { display: block; font-size: 12.5px; font-weight: 600; color: var(--ink); }
.g-people-danger .g-drow .t em { display: block; margin-top: 2px; font-style: normal; font-size: 11px; line-height: 1.6; color: var(--ink-4); }
.g-people-danger .g-ask { margin-top: 10px; }
/* 详情页进场:一处克制的错落上浮(≤300ms,reduced-motion 全关) */
@keyframes people-rise { from { opacity: 0; transform: translateY(5px); } }
.g-people-d .g-mhero, .g-people-d .g-people-dgrid .main > *, .g-people-d .g-people-dgrid .rail > *, .g-people-d .g-people-danger { animation: people-rise .28s ease-out both; }
.g-people-d .g-people-dgrid .main > :nth-child(2) { animation-delay: .05s; }
.g-people-d .g-people-dgrid .rail > :nth-child(1) { animation-delay: .04s; }
.g-people-d .g-people-dgrid .rail > :nth-child(2) { animation-delay: .08s; }
.g-people-d .g-people-dgrid .rail > :nth-child(3) { animation-delay: .12s; }
.g-people-d .g-people-danger { animation-delay: .14s; }
@media (prefers-reduced-motion: reduce) {
.g-people .g-prole-edit { animation: none; }
.g-people .g-mrow, .g-people .g-mrow .x, .g-people .g-mava, .g-people .g-prole { transition: none; }
.g-people-d .g-mhero, .g-people-d .g-people-dgrid .main > *, .g-people-d .g-people-dgrid .rail > *, .g-people-d .g-people-danger { animation: none; }
.g-people-d .g-role-sw, .g-people-d .g-role-sw i { transition: none; }
}
.g-fcard .mbtn { flex: none; width: 26px; height: 26px; display: grid; place-items: center; border: 1px solid transparent; border-radius: 7px; background: transparent; color: var(--ink-4); cursor: pointer; }
.g-fcard .mbtn:hover, .g-fcard .mbtn.on { border-color: var(--cline); background: #f3f6fa; color: var(--ink); }
.g-fcard .mbtn.bad:hover { border-color: #e6c4c4; background: #fdf2f2; color: var(--danger); }