From bb6760d7a47e4ddd16f3088f5835a173dc88fe3d Mon Sep 17 00:00:00 2001 From: 18628386721 <18628386721@163.com> Date: Mon, 27 Jul 2026 21:00:25 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=89=E9=9D=A2=E6=8B=86=E5=88=86=E2=91=A2:?= =?UTF-8?q?=E5=A3=B3=E5=8F=82=E6=95=B0=E5=8C=96=E4=B8=A4=E5=8F=B0,?= =?UTF-8?q?=E5=8F=B0=E8=B4=A6=E9=9A=8F=E5=9F=9F=E5=8A=A8=E6=80=81=E7=94=9F?= =?UTF-8?q?=E6=88=90,=E9=A1=B6=E6=A0=8F=E4=BA=92=E8=B7=B3=E6=8C=89?= =?UTF-8?q?=E6=9D=83=E4=BA=AE=E7=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m --- apps/web/src/app/app-shell.tsx | 29 +++++ apps/web/src/app/gov-shell.tsx | 189 ++++++++++++++++++++++------- apps/web/src/app/main.tsx | 2 +- apps/web/src/shared/gov/gov-api.ts | 17 ++- 4 files changed, 186 insertions(+), 51 deletions(-) diff --git a/apps/web/src/app/app-shell.tsx b/apps/web/src/app/app-shell.tsx index e61f204..af1a7ad 100644 --- a/apps/web/src/app/app-shell.tsx +++ b/apps/web/src/app/app-shell.tsx @@ -25,6 +25,7 @@ import { ReportDesk } from '@features/desk-report'; import { Ico } from '@web-shared/Ico.tsx'; import { call } from '@web-shared/typed-fetch.ts'; import { useChatWidth } from '@web-shared/useChatWidth.ts'; +import { SURFACE_META, canSeeSurface } from '@web-shared/gov/surfaces.ts'; import { queryKeys } from './query.ts'; type ModuleKey = 'tasks' | 'approvals' | 'messages' | 'minutes' | 'report'; @@ -123,6 +124,34 @@ export function AppShell() { ); })}
+ {/* + 另两面的入口 —— 按授权亮灯:没有治理授权的人根本看不见,不给点了才说没权。 + 两枚并排、只留章不留名:轨底还得放身份钮,竖排三件会把左轨撑出滚动条(实测)。 + */} + {(canSeeSurface(session.data, 'design') || canSeeSurface(session.data, 'ops')) && ( +
+ {canSeeSurface(session.data, 'design') && ( + + 设 + + )} + {canSeeSurface(session.data, 'ops') && ( + + 运 + + )} +
+ )} {/* 轨底身份即登出入口 —— 会话在服务端,点它是真作废,不只是清本地 */} - ))} +
{SURFACE_META[surface].brand}
+ {ZONES.filter((z) => SURFACE_ZONES[surface].includes(z.key)).map((z) => + // 台账不是一个固定位,是一段**随数据域生长**的动态位 —— 每域一枚 + z.key === 'ledgers' ? ( + go({ zone: 'ledgers', tab: domain, stack: [] })} + /> + ) : ( + + ), + )}
{(me?.name ?? '—').slice(0, 1)} {me?.name ?? '未登录'} @@ -149,14 +186,23 @@ export function GovShell() {
- + {surface === 'ops' && ( + + )} + {/* 三面互跳:另一面按授权亮灯,工作台人人可回 */} + {canSeeSurface(session.data, other) && ( + + + {SURFACE_META[other].brand} + + )} 工作台 @@ -220,6 +266,57 @@ export function GovShell() { ); } +/** + * 台账段 —— 左轨里唯一的**动态位**:一域一枚,随数据域发布而生长。 + * + * 这是「设计产生运营的形状」最直观的一处:导航本身就是被设计出来的。 + */ +function LedgerRail({ + domains, + active, + onPick, +}: { + domains: readonly string[]; + active: string | undefined; + onPick: (domain: string) => void; +}) { + return ( + <> +
+ 台账 +
+ {domains.length === 0 ? ( +
+ 随数据域 +
+ 发布生长 +
+ ) : ( + domains.map((d) => ( + + )) + )} + + ); +} + /** 企业蓝图 —— Task 6 接真;在那之前先给设计者一句「这里将有什么」 */ function BlueprintPlaceholder() { return ( diff --git a/apps/web/src/app/main.tsx b/apps/web/src/app/main.tsx index c0ce80e..e0b9796 100644 --- a/apps/web/src/app/main.tsx +++ b/apps/web/src/app/main.tsx @@ -97,7 +97,7 @@ function Gate() { } return govSurface !== undefined ? ( - + ) : ( // .proto-root 是工作台补充样式的作用域(原型 app.css 通篇以它起头); // 治理台不裹它 —— 裹了工作台的补充样式就会漏进治理台的树里 diff --git a/apps/web/src/shared/gov/gov-api.ts b/apps/web/src/shared/gov/gov-api.ts index ad9f7a5..6692cfd 100644 --- a/apps/web/src/shared/gov/gov-api.ts +++ b/apps/web/src/shared/gov/gov-api.ts @@ -57,8 +57,13 @@ export type GovWorkflow = GovWorkflowOutput; export type GovTaskLog = GovTaskLogOutput; export type GovGrants = GovGrantsOutput; -export const useGovTasks = (): UseQueryResult => - useQuery({ queryKey: ['gov', 'tasks'], queryFn: () => call(listGovTasksRoute) }); +/** `enabled: false` 供设计中心用 —— 那一面不看运行态,别去要一份自己无权也无用的数据 */ +export const useGovTasks = (opts?: { enabled?: boolean }): UseQueryResult => + useQuery({ + queryKey: ['gov', 'tasks'], + queryFn: () => call(listGovTasksRoute), + enabled: opts?.enabled ?? true, + }); export const useGovApprovals = (): UseQueryResult => useQuery({ queryKey: ['gov', 'approvals'], queryFn: () => call(listApprovalsRoute) }); @@ -85,8 +90,12 @@ export const useGovActivities = (): UseQueryResult => export const useGovTools = (): UseQueryResult => useQuery({ queryKey: ['gov', 'tools'], queryFn: () => call(listToolsRoute) }); -export const useGovObjects = (): UseQueryResult => - useQuery({ queryKey: ['gov', 'objects'], queryFn: () => call(listLedgerObjectsRoute) }); +export const useGovObjects = (opts?: { enabled?: boolean }): UseQueryResult => + useQuery({ + queryKey: ['gov', 'objects'], + queryFn: () => call(listLedgerObjectsRoute), + enabled: opts?.enabled ?? true, + }); export const useGovLedger = (domain: string | undefined, object: string | undefined): UseQueryResult => useQuery({