Archived
运营中心收口:四区(驾驶舱/工作流/台账/系统)摆建设中占位;L2「启动活动」改「创建活动」、沙箱区块隐藏、行内终止撤掉收口 L3、负责人小签隐藏;文案定名活动列表/活动号
CI / ci (push) Failing after 12s
CI / ci (push) Failing after 12s
This commit is contained in:
@@ -38,6 +38,7 @@ import { TestbedHome } from '@features/gov-testbed';
|
||||
import { CockpitHome } from '@features/gov-memory';
|
||||
import { ChanPage, LlmPage, ModelsHome, SystemHome } from '@features/gov-system';
|
||||
import { Btn } from '@web-shared/Btn.tsx';
|
||||
import { Card, Note } from '@web-shared/gov/primitives.tsx';
|
||||
|
||||
/* ── URL 编解码:`#/<surface>/<zone>/<tab>[/<k>:<id>…]` ────────────────── */
|
||||
|
||||
@@ -292,7 +293,23 @@ export function GovShell({ surface }: { surface: Surface }) {
|
||||
);
|
||||
}
|
||||
|
||||
/** 运营中心四区先摆建设中(2026-08-28 用户定:驾驶舱 / 工作流 / 台账 / 系统)——
|
||||
真面板组件与其下钻路由原样留着,只换区首页;要做回来,把区从这个集合摘掉即可 */
|
||||
const WIP_ZONES: ReadonlySet<GovZone> = new Set(['cockpit', 'runs', 'ledgers', 'system']);
|
||||
|
||||
/** 建设中占位:如实说还没有 —— 不摆假数据、不摆点不动的钮(与知识库「待建」页同一条规矩) */
|
||||
function WipHome({ zone }: { zone: GovZone }) {
|
||||
const zm = ZM[zone];
|
||||
return (
|
||||
<Card ico={zm.icon} title={zm.title} extra="建设中">
|
||||
<Note>这一区正在建设中 —— 运营中心目前开放「活动」与「员工」两区,其余区建好后开放。</Note>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function ZoneHome({ zone, tab, nav }: { zone: GovZone; tab: string; nav: Nav }) {
|
||||
/* 建设中的区先拦在这里(2026-08-28 用户定):真面板组件仍在下方映射里,摘掉集合即恢复 */
|
||||
if (WIP_ZONES.has(zone)) return <WipHome zone={zone} />;
|
||||
const P = {
|
||||
// 设计中心
|
||||
blueprint: BlueprintHome,
|
||||
|
||||
@@ -227,7 +227,7 @@ const INSTANCE_PAGE_SIZE = 8;
|
||||
type InstanceFilterKey = 'id' | 'owner' | 'state' | 'time';
|
||||
|
||||
const INSTANCE_FILTER_LABEL: Readonly<Record<InstanceFilterKey, string>> = {
|
||||
id: '实例',
|
||||
id: '活动号',
|
||||
owner: '负责人',
|
||||
state: '状态',
|
||||
time: '启动时间',
|
||||
@@ -240,7 +240,7 @@ type PopAskSpec = { title: string; okLabel: string; danger?: boolean; onOk: () =
|
||||
const errText = (e: unknown): string => (e as { message?: string } | null)?.message ?? '网络错误,请稍后重试';
|
||||
|
||||
/** 气泡式二次确认 —— 锚在页头右下的小泡泡:一句话问清,确认/取消两钮;点气泡外的透明罩即取消;
|
||||
`inrow` = 锚在行内操作格(终止实例用,接口文档 §10),定位由 CSS 的 .inrow 变体给。
|
||||
`inrow` = 锚在行内操作格的变体(行内终止撤掉后暂无处用,2026-08-28;变体与 CSS 保留,要用直接传);
|
||||
2026-08-28 反馈闭环(用户报:终止点了不知道成没成):确认后气泡**不再立即消失** ——
|
||||
在途时留场转忙碌(两钮禁用、罩不可点),成功由调用方 onSuccess 关掉,失败把原因留在气泡里可重试 */
|
||||
function PopAsk({ spec, onCancel, inrow, busy, error }: { spec: PopAskSpec; onCancel: () => void; inrow?: boolean; busy?: boolean; error?: string | null }) {
|
||||
@@ -470,7 +470,7 @@ function LaunchDrawer({ activityId, name, onCancel, onLaunch }: { activityId: st
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<small>这次启动的实例归他 —— 负责人验收、数据工单都落到责任人身上;默认是你自己。</small>
|
||||
<small>这次创建的活动归他 —— 负责人验收、数据工单都落到责任人身上;默认是你自己。</small>
|
||||
{fieldErr['ownerId'] !== undefined && <small className="warn">{fieldErr['ownerId']}</small>}
|
||||
</label>
|
||||
</section>
|
||||
@@ -577,8 +577,12 @@ function LaunchDrawer({ activityId, name, onCancel, onLaunch }: { activityId: st
|
||||
* · 启动活动(即创建实例)—— 弹参数抽屉(LaunchDrawer),参数表按活动下发;已禁用不能启动。
|
||||
*
|
||||
* 2026-08-27 接真接口(docs/API文档-活动模块.md):定义 §2.2 / 清单 §3 / 启动 §4、§5 / 禁用激活终止 §8;
|
||||
* 沙箱区:view.url + 票据装载,高度听 `jcai:view-height`;view 为 null 藏起整个区块。
|
||||
* 沙箱区:view.url + 票据装载,高度听 `jcai:view-height`;2026-08-28 用户定:沙箱区块先隐藏(SHOW_SANDBOX 开关)。
|
||||
*/
|
||||
|
||||
/** 沙箱区块开关(2026-08-28 用户定:先隐藏)—— 置回 true 即恢复;显式标注 boolean 免得被字面量收窄 */
|
||||
const SHOW_SANDBOX: boolean = false;
|
||||
|
||||
export function ActvPage({ id, nav }: { id: string; nav: Nav }) {
|
||||
/* 接口对接(2026-08-27,docs/API文档-活动模块.md):定义 §2.2 / 实例清单 §3(检索分页全在服务端)/ 写动作 §5、§8 */
|
||||
const actQ = useOpsActivity(id);
|
||||
@@ -590,9 +594,9 @@ export function ActvPage({ id, nav }: { id: string; nav: Nav }) {
|
||||
const [fFrom, setFFrom] = useState('');
|
||||
const [fTo, setFTo] = useState('');
|
||||
const [page, setPage] = useState(0);
|
||||
/* 轻量二次确认(2026-08-26 用户定):头部动作(禁用/激活)走页头气泡;行内「终止活动」走行内气泡(接口文档 §10) */
|
||||
/* 轻量二次确认(2026-08-26 用户定):头部动作(禁用/激活)走页头气泡;
|
||||
行内「终止活动」与它的气泡已撤(2026-08-28 用户定:终止只留在 L3) */
|
||||
const [ask, setAsk] = useState<PopAskSpec | null>(null);
|
||||
const [rowAsk, setRowAsk] = useState<{ rid: string; no: string } | null>(null);
|
||||
/* 启动抽屉(2026-08-27 用户定) */
|
||||
const [launch, setLaunch] = useState(false);
|
||||
|
||||
@@ -632,7 +636,6 @@ export function ActvPage({ id, nav }: { id: string; nav: Nav }) {
|
||||
const qc = useQueryClient();
|
||||
const disable = useGovAction(() => call(disableOpsActivityRoute, { params: { activityId: id } }), ['activities']);
|
||||
const activate = useGovAction(() => call(activateOpsActivityRoute, { params: { activityId: id } }), ['activities']);
|
||||
const terminate = useGovAction((iid: string) => call(terminateOpsInstanceRoute, { params: { activityId: id, instanceId: iid } }), ['activities']);
|
||||
/* 页头写动作的在途/失败态 —— 摆进气泡(2026-08-28 用户报:点了没反馈);同一时刻只有一枚气泡,二选一即可 */
|
||||
const headBusy = disable.isPending || activate.isPending;
|
||||
const headErr = disable.isError ? errText(disable.error) : activate.isError ? errText(activate.error) : null;
|
||||
@@ -666,7 +669,7 @@ export function ActvPage({ id, nav }: { id: string; nav: Nav }) {
|
||||
<Chip ico="tag">v{a.version}</Chip>
|
||||
{/* 绑定的 LLM 上头版(2026-08-25 用户定):每个活动一个专属 agent */}
|
||||
<Chip ico="cpu">{a.llm}</Chip>
|
||||
<Chip ico="user">{a.owner?.name ?? '—'}</Chip>
|
||||
{/* 负责人小签隐藏(2026-08-28 用户定:活动本身没有负责人;责任人是每次创建的固定参数,在 L3 看) */}
|
||||
<Chip ico="calendar-days">创建于 {atMinute(a.createdAt).slice(0, 5)}</Chip>
|
||||
</>
|
||||
}
|
||||
@@ -703,8 +706,8 @@ export function ActvPage({ id, nav }: { id: string; nav: Nav }) {
|
||||
});
|
||||
},
|
||||
},
|
||||
/* 启动活动(2026-08-27 接):弹参数抽屉填参启动;已禁用不能启动 —— 先激活,再启动 */
|
||||
{ label: '启动活动', ico: 'play', primary: st === 'active', disabled: st !== 'active', onClick: () => setLaunch(true) },
|
||||
/* 创建活动(2026-08-28 用户改文案,原「启动活动」):弹参数抽屉填参创建实例;已禁用不能创建 —— 先激活 */
|
||||
{ label: '创建活动', ico: 'play', primary: st === 'active', disabled: st !== 'active', onClick: () => setLaunch(true) },
|
||||
/* 版本迭代入口先隐藏(2026-08-25 用户定):功能设计回头讨论,要做时把这行加回 acts
|
||||
{ label: '版本迭代', ico: 'git-branch', disabled: true },
|
||||
*/
|
||||
@@ -714,7 +717,8 @@ export function ActvPage({ id, nav }: { id: string; nav: Nav }) {
|
||||
{launch && <LaunchDrawer activityId={a.id} name={a.name} onCancel={() => setLaunch(false)} onLaunch={onLaunched} />}
|
||||
</div>
|
||||
|
||||
<Sec ico="repeat" title="历史活动" extra={`共 ${list?.stats.total ?? '…'} 个 · 查看详情进 L3`}>
|
||||
{/* 「历史活动」改「活动列表」(2026-08-28 用户定) */}
|
||||
<Sec ico="repeat" title="活动列表" extra={`共 ${list?.stats.total ?? '…'} 个 · 查看详情进 L3`}>
|
||||
{/* 统计带 + 检索条同一行(2026-08-26 用户定:检索放右侧)——
|
||||
左:总数 + 五态灰字合计(状态色只进 6px 小圆点);右:条件下拉 + 随条件换控件;
|
||||
统计数是服务端给的全局 stats,不随检索条件动(2026-08-27 接接口) */}
|
||||
@@ -751,7 +755,7 @@ export function ActvPage({ id, nav }: { id: string; nav: Nav }) {
|
||||
<input
|
||||
className="g-iselect-input"
|
||||
value={fText}
|
||||
placeholder="按实例号模糊搜,如 INS-2417"
|
||||
placeholder="按活动号模糊搜,如 INS-2417"
|
||||
onChange={(e) => {
|
||||
setFText(e.target.value);
|
||||
setPage(0);
|
||||
@@ -835,9 +839,10 @@ export function ActvPage({ id, nav }: { id: string; nav: Nav }) {
|
||||
2026-08-27 接接口:摆的是 no(人读实例号),寻址(L3/终止)用 id(任务 uuid) */}
|
||||
<QueryGate query={instQ}>
|
||||
<div className="g-itab">
|
||||
{/* 列序(2026-08-26 用户定):实例 / 负责人 / 输入 / 输出 / 启动时间 / 状态 / 操作(操作栏也有标题) */}
|
||||
{/* 列序(2026-08-26 用户定):实例 / 负责人 / 输入 / 输出 / 启动时间 / 状态 / 操作(操作栏也有标题);
|
||||
表头第一列定名「活动号」(2026-08-28 用户定) */}
|
||||
<div className="g-itab-h">
|
||||
<span>实例</span>
|
||||
<span>活动号</span>
|
||||
<span>负责人</span>
|
||||
<span>输入</span>
|
||||
<span>输出</span>
|
||||
@@ -862,38 +867,10 @@ export function ActvPage({ id, nav }: { id: string; nav: Nav }) {
|
||||
{INSTANCE_STATE_LABEL[r.state]}
|
||||
</span>
|
||||
<span className="a">
|
||||
{r.state === 'running' && (
|
||||
<button
|
||||
type="button"
|
||||
className="g-rowbtn danger"
|
||||
onClick={() => {
|
||||
terminate.reset();
|
||||
setRowAsk({ rid: r.id, no: r.no });
|
||||
}}
|
||||
>
|
||||
终止活动
|
||||
</button>
|
||||
)}
|
||||
{/* L3 实例详情(2026-08-26 接):路由 id 带活动与实例两段,详情页按活动找回上下文 */}
|
||||
{/* 行内「终止活动」撤掉(2026-08-28 用户定):终止只留在 L3 详情页头部,清单行只剩查看 */}
|
||||
<button type="button" className="g-rowbtn" onClick={() => nav.push({ k: 'acti', id: `${a.id}:${r.id}` })}>
|
||||
查看详情
|
||||
</button>
|
||||
{/* 行内终止的二次确认(接口文档 §10):轻气泡锚在操作格里,触发钮左边;
|
||||
确认后留场等结果 —— 成功自动关 + 行状态翻亮,失败原因摆进气泡(2026-08-28 用户报) */}
|
||||
{rowAsk?.rid === r.id && (
|
||||
<PopAsk
|
||||
inrow
|
||||
spec={{
|
||||
title: `确认终止实例 ${rowAsk.no}?`,
|
||||
okLabel: '确认终止',
|
||||
danger: true,
|
||||
onOk: () => terminate.mutate(r.id, { onSuccess: () => setRowAsk(null) }),
|
||||
}}
|
||||
busy={terminate.isPending}
|
||||
error={terminate.isError ? errText(terminate.error) : null}
|
||||
onCancel={() => setRowAsk(null)}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -901,7 +878,7 @@ export function ActvPage({ id, nav }: { id: string; nav: Nav }) {
|
||||
{pageRows.length === 0 && (
|
||||
<div className="g-irow-empty">
|
||||
<Ico name="search" s={14} />
|
||||
没有匹配的实例 —— 换个条件,或清空重看全部。
|
||||
没有匹配的活动 —— 换个条件,或清空重看全部。
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -923,9 +900,10 @@ export function ActvPage({ id, nav }: { id: string; nav: Nav }) {
|
||||
{/*
|
||||
* 沙箱(2026-08-25 用户定;2026-08-27 接接口,文档 §2.3):加载服务器返回的活动视图 HTML。
|
||||
* 隔离:iframe + sandbox="allow-scripts" —— 不透明源,禁同源/表单/弹窗,视图只能渲染与跑自己的脚本;
|
||||
* src = 活动详情里的 view.url + 装载那一刻现取的票据;view 为 null 时整个区块藏起来。
|
||||
* src = 活动详情里的 view.url + 装载那一刻现取的票据。
|
||||
* 2026-08-28 用户定:沙箱区块**先隐藏**(SandboxFrame 组件与 view 取数保留,SHOW_SANDBOX 置回 true 即恢复)。
|
||||
*/}
|
||||
{a.view !== null && (
|
||||
{SHOW_SANDBOX && a.view !== null && (
|
||||
<Sec ico="dashboard" title="活动视图 · 沙箱" extra="服务器返回的 HTML · 隔离渲染">
|
||||
<SandboxFrame activityId={a.id} viewUrl={a.view.url} name={a.name} />
|
||||
</Sec>
|
||||
@@ -1104,7 +1082,7 @@ export function ActiPage({ id }: { id: string }) {
|
||||
<Chip ico="cpu">{d.llm}</Chip>
|
||||
</>
|
||||
}
|
||||
desc="一次运行的完整视图:输入 / 过程 / 输出 / 状态 —— 实例不可编辑、不可删除,进行中的运行可终止。"
|
||||
desc="一次运行的完整视图:输入 / 过程 / 输出 / 状态 —— 活动不可编辑、不可删除,进行中的运行可终止。"
|
||||
acts={[
|
||||
/* 唯一动作(2026-08-26 用户定:实例不许删、不许编):进行中可终止,轻气泡二次确认 */
|
||||
...(state === 'running'
|
||||
@@ -1117,7 +1095,7 @@ export function ActiPage({ id }: { id: string }) {
|
||||
onClick: () => {
|
||||
terminate.reset();
|
||||
setAsk({
|
||||
title: `确认终止实例 ${d.no}?`,
|
||||
title: `确认终止活动 ${d.no}?`,
|
||||
okLabel: '确认终止',
|
||||
danger: true,
|
||||
onOk: () => terminate.mutate(undefined, { onSuccess: () => setAsk(null) }),
|
||||
|
||||
@@ -98,6 +98,10 @@ L1(模块首页 · 活动清单)需要一个**标签页**切换,因为活
|
||||
- 2026-08-27 · **启动固定参数「责任人」(用户定)**:每次启动必须指定这次实例的责任人(负责人验收、数据工单都落到他身上)—— 它是**启动契约的固定字段 `ownerId`**,不进按活动下发的参数表。抽屉里已加「固定参数」段:人员下拉来自员工名册真接口(`GET /api/gov/staff`,只列在职),默认当前登录人(标注「我自己」);接口口径见 `docs/API文档-活动模块.md` §5。
|
||||
- 2026-08-28 · **轻气泡确认的反馈闭环(用户报修)**:禁用/激活/终止实例确认后气泡**不再立即消失** —— 请求在途留场转忙碌(两钮禁用、罩不可点),成功自动关(列表/详情由失效重取刷新,状态翻转有弹出高亮),失败把接口原因留在气泡里可重试。此前确认即关 + mutation 无 onError,失败时全哑,点了不知道成没成。
|
||||
- 2026-08-28 · **L3 实例详情 7 秒轮询(用户定)**:`useOpsInstance` 加 `refetchInterval` —— 待执行/进行中每 7 秒重取一次;进终态(完成/驳回/失败)自动停,不白打接口。
|
||||
- 2026-08-28 · **运营中心四区先摆建设中(用户定)**:驾驶舱 / 工作流 / 台账 / 系统的区首页换建设中占位(gov-shell `WIP_ZONES`),真面板与下钻深链保留,摘掉集合即恢复;目前运营中心只开放「活动」与「员工」。
|
||||
- 2026-08-28 · **L2 头部「启动活动」改文案为「创建活动」(用户定)**;同页「活动视图 · 沙箱」区块先隐藏(`SHOW_SANDBOX=false`,SandboxFrame 与 view 取数保留)。
|
||||
- 2026-08-28 · **终止收口到 L3(用户定)**:L2 实例清单行内的「终止活动」按钮连同行内气泡一并撤掉(PopAsk 的 inrow 变体与 CSS 保留),终止只在 L3 详情页头部;**界面文案收口(同日两轮定)**:L1 卡底栏仍叫「实例」;L2 区块「历史活动」改「**活动列表**」,表头第一列与检索条件定名「**活动号**」,L3 描述与终止确认气泡里的「实例」改「活动」。工作流区的「节点实例」是另一概念,未动。
|
||||
- 2026-08-28 · **L2 头版负责人小签隐藏(用户定)**:活动本身没有负责人——责任人是每次创建的固定参数(`ownerId`),归 L3 实例头版;定义上的 owner 字段保留不渲染。
|
||||
|
||||
## 三、功能表(整理稿)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user