diff --git a/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx b/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx new file mode 100644 index 00000000..02a98e22 --- /dev/null +++ b/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx @@ -0,0 +1,386 @@ +import { XProTable } from '@/components/ProComponents'; +import WorkspaceLayout from '@/components/WorkspaceLayout'; +import { SUCCESS_CODE } from '@/constants/codes.constants'; +import { apiDigitalEmployeeAdminWorkbenchList } from '@/services/systemManage'; +import type { + DigitalEmployeeAdminWorkbenchRow, + DigitalEmployeeAdminWorkbenchView, +} from '@/types/interfaces/systemManage'; +import type { + ActionType, + FormInstance, + ProColumns, +} from '@ant-design/pro-components'; +import { Button, Drawer, message, Space, Tabs, Tag, Typography } from 'antd'; +import { useMemo, useRef, useState } from 'react'; +import { history, useModel } from 'umi'; + +const WORKBENCH_TABS: Array<{ + key: DigitalEmployeeAdminWorkbenchView; + label: string; +}> = [ + { key: 'business', label: '业务视图' }, + { key: 'interventions', label: '介入台' }, + { key: 'artifact_lifecycle', label: '产物治理' }, + { key: 'notifications', label: '通知运营' }, + { key: 'audits', label: '审计诊断' }, + { key: 'daily_reports', label: '日报运营' }, + { key: 'route_governance', label: '路由治理' }, +]; + +const ENTITY_TYPE_OPTIONS = { + plan: { text: 'Plan' }, + task: { text: 'Task' }, + run: { text: 'Run' }, + event: { text: 'Event' }, + artifact: { text: 'Artifact' }, + approval: { text: 'Approval' }, +}; + +const STATUS_TONE: Record = { + active: 'processing', + allowed: 'success', + approved: 'success', + blocked: 'error', + completed: 'success', + deleted: 'default', + failed: 'error', + pending: 'warning', + rejected: 'error', + running: 'processing', + synced: 'success', + warn: 'warning', +}; + +function compactText(value?: string, maxLength = 96): string { + const text = (value || '').replace(/\s+/g, ' ').trim(); + if (!text) return '--'; + return text.length > maxLength ? `${text.slice(0, maxLength)}...` : text; +} + +function jsonText(value?: Record): string { + if (!value) return '{}'; + return JSON.stringify(value, null, 2); +} + +function tone(value?: string): string { + return value ? STATUS_TONE[value.toLowerCase()] || 'default' : 'default'; +} + +function renderSummary(record: DigitalEmployeeAdminWorkbenchRow) { + const title = compactText(record.title || record.entity_id, 72); + const summary = compactText(record.summary || record.kind || record.category); + const meta = [ + record.plan_id && `Plan ${record.plan_id}`, + record.task_id && `Task ${record.task_id}`, + record.run_id && `Run ${record.run_id}`, + record.approval_id && `Approval ${record.approval_id}`, + record.artifact_id && `Artifact ${record.artifact_id}`, + record.route_decision_id && `Route ${record.route_decision_id}`, + ].filter((item): item is string => Boolean(item)); + + return ( +
+ + + {title} + + {record.status && {record.status}} + + + {summary} + + {meta.length > 0 && ( + + {meta.slice(0, 3).map((item) => ( + + {item} + + ))} + + )} +
+ ); +} + +const DigitalEmployeeOps: React.FC = () => { + const { hasPermission } = useModel('menuModel'); + const actionRef = useRef(); + const formRef = useRef(); + const [activeView, setActiveView] = + useState('business'); + const [detailRecord, setDetailRecord] = + useState(null); + const businessViewJson = useMemo( + () => jsonText(detailRecord?.business_view), + [detailRecord], + ); + const payloadJson = useMemo( + () => jsonText(detailRecord?.payload), + [detailRecord], + ); + + const columns: ProColumns[] = useMemo( + () => [ + { + title: '客户端 Key', + dataIndex: 'client_key', + hideInTable: true, + fieldProps: { placeholder: '输入完整客户端 Key', allowClear: true }, + }, + { + title: '设备 ID', + dataIndex: 'device_id', + width: 150, + ellipsis: true, + fieldProps: { placeholder: '输入设备 ID', allowClear: true }, + renderText: (value) => value || '--', + }, + { + title: '实体类型', + dataIndex: 'entity_type', + width: 120, + valueType: 'select', + valueEnum: ENTITY_TYPE_OPTIONS, + fieldProps: { placeholder: '选择实体类型', allowClear: true }, + render: (_, record) => {record.entity_type || '--'}, + }, + { + title: '实体 ID', + dataIndex: 'entity_id', + width: 180, + ellipsis: true, + fieldProps: { placeholder: '输入实体 ID', allowClear: true }, + }, + { + title: '状态', + dataIndex: 'status', + width: 110, + fieldProps: { placeholder: '输入状态', allowClear: true }, + render: (_, record) => ( + {record.status || '--'} + ), + }, + { + title: '类型/分类', + dataIndex: 'kind', + width: 190, + ellipsis: true, + fieldProps: { placeholder: '输入 kind', allowClear: true }, + render: (_, record) => ( + + {record.kind && {record.kind}} + {record.category && {record.category}} + + ), + }, + { + title: '分类', + dataIndex: 'category', + hideInTable: true, + fieldProps: { placeholder: '输入 category', allowClear: true }, + }, + { + title: '等级', + dataIndex: 'level', + width: 90, + fieldProps: { placeholder: '等级', allowClear: true }, + renderText: (value) => value || '--', + }, + { + title: '优先级', + dataIndex: 'priority', + width: 90, + fieldProps: { placeholder: '优先级', allowClear: true }, + renderText: (value) => value || '--', + }, + { + title: '业务摘要', + dataIndex: 'summary', + width: 400, + hideInSearch: true, + render: (_, record) => renderSummary(record), + }, + { + title: '更新时间', + dataIndex: 'updated_range', + valueType: 'dateTimeRange', + hideInTable: true, + }, + { + title: '发生时间', + dataIndex: 'occurred_at', + width: 170, + hideInSearch: true, + renderText: (value) => value || '--', + }, + { + title: '同步时间', + dataIndex: 'synced_at', + width: 170, + hideInSearch: true, + valueType: 'dateTime', + }, + { + title: '详情', + valueType: 'option', + fixed: 'right', + width: 120, + render: (_, record) => ( + + + {record.sync_record_url && ( + + )} + + ), + }, + ], + [], + ); + + const request = async (params: Record) => { + const updatedRange = params.updated_range || []; + const response = await apiDigitalEmployeeAdminWorkbenchList({ + view: activeView, + pageNo: params.current || 1, + pageSize: params.pageSize || 15, + clientKey: params.client_key, + deviceId: params.device_id, + entityType: params.entity_type, + entityId: params.entity_id, + status: params.status, + kind: params.kind, + category: params.category, + level: params.level, + priority: params.priority, + updatedFrom: updatedRange[0], + updatedTo: updatedRange[1], + }); + + if (response.code !== SUCCESS_CODE) { + message.error(response.message || '查询数字员工运营台失败'); + } + + return { + data: response.data?.records || [], + total: response.data?.total || 0, + success: response.code === SUCCESS_CODE, + }; + }; + + return ( + + { + setActiveView(key as DigitalEmployeeAdminWorkbenchView); + formRef.current?.resetFields(); + actionRef.current?.setPageInfo?.({ current: 1, pageSize: 15 }); + actionRef.current?.reload(); + }} + /> + + key={activeView} + actionRef={actionRef} + formRef={formRef} + rowKey={(record) => + `${activeView}:${record.sync_record_id || record.entity_id}` + } + columns={columns} + request={request} + showQueryButtons={hasPermission( + 'content_digital_employee_ops_query_list', + )} + /> + setDetailRecord(null)} + > + {detailRecord && ( + <> +
{renderSummary(detailRecord)}
+ + 客户端: + {detailRecord.client_key_masked || '--'} /{' '} + {detailRecord.device_id || '--'} + + + 实体: + {detailRecord.entity_type || '--'} / {detailRecord.entity_id || '--'} + + + 关联: + {[ + detailRecord.plan_id && `Plan ${detailRecord.plan_id}`, + detailRecord.task_id && `Task ${detailRecord.task_id}`, + detailRecord.run_id && `Run ${detailRecord.run_id}`, + detailRecord.approval_id && `Approval ${detailRecord.approval_id}`, + detailRecord.artifact_id && `Artifact ${detailRecord.artifact_id}`, + detailRecord.notification_id && + `Notification ${detailRecord.notification_id}`, + detailRecord.report_id && `Report ${detailRecord.report_id}`, + detailRecord.route_decision_id && + `Route ${detailRecord.route_decision_id}`, + ] + .filter(Boolean) + .join(' / ') || '--'} + + Business View + +
+                {businessViewJson}
+              
+
+ Payload + +
+                {payloadJson}
+              
+
+ + )} +
+
+ ); +}; + +export default DigitalEmployeeOps; diff --git a/qiming/src/routes/index.ts b/qiming/src/routes/index.ts index 40c68007..754509ac 100644 --- a/qiming/src/routes/index.ts +++ b/qiming/src/routes/index.ts @@ -357,6 +357,12 @@ const routes = [ component: '@/pages/SystemManagement/Content/DigitalEmployeeSync', }, + { + path: 'content-digital-employee-ops', + name: '数字员工运营台', + component: + '@/pages/SystemManagement/Content/DigitalEmployeeOps', + }, ], }, { diff --git a/qiming/src/services/menuService.ts b/qiming/src/services/menuService.ts index 7aec27d5..54b425e3 100644 --- a/qiming/src/services/menuService.ts +++ b/qiming/src/services/menuService.ts @@ -55,6 +55,8 @@ const MENU_ICON_MAP: Record = { content_manage: 'icons-nav-cube', // 数字员工同步记录 content_digital_employee_sync: 'icons-nav-robot', + // 数字员工运营台 + content_digital_employee_ops: 'icons-nav-robot', // 支付与收益(开发者) dev_payment_earnings: 'icons-nav-my-earnings', // 订阅与积分(管理员) diff --git a/qiming/src/services/systemManage.ts b/qiming/src/services/systemManage.ts index 7dc4709d..7f53395f 100644 --- a/qiming/src/services/systemManage.ts +++ b/qiming/src/services/systemManage.ts @@ -8,6 +8,8 @@ import type { AccessStatsResult, AddSystemUserParams, ConversationStatsResult, + DigitalEmployeeAdminWorkbenchListParams, + DigitalEmployeeAdminWorkbenchPage, DigitalEmployeeSyncRecordListParams, DigitalEmployeeSyncRecordPage, ModelConfigDto, @@ -284,6 +286,30 @@ export async function apiDigitalEmployeeSyncRecordList( }); } +// 查询数字员工正式运营台 +export async function apiDigitalEmployeeAdminWorkbenchList( + data: DigitalEmployeeAdminWorkbenchListParams, +): Promise> { + return request(`/api/digital-employee/admin/workbench/${data.view}`, { + method: 'GET', + params: { + client_key: data.clientKey, + device_id: data.deviceId, + entity_type: data.entityType, + entity_id: data.entityId, + status: data.status, + kind: data.kind, + category: data.category, + level: data.level, + priority: data.priority, + updated_from: data.updatedFrom, + updated_to: data.updatedTo, + page_no: data.pageNo, + page_size: data.pageSize, + }, + }); +} + // 查询网页应用列表 export async function apiSystemResourceWebappList( data: SystemWebappListParams, diff --git a/qiming/src/types/interfaces/systemManage.ts b/qiming/src/types/interfaces/systemManage.ts index 6c02ff8b..39d3248b 100644 --- a/qiming/src/types/interfaces/systemManage.ts +++ b/qiming/src/types/interfaces/systemManage.ts @@ -556,6 +556,68 @@ export interface DigitalEmployeeSyncRecordPage { records: DigitalEmployeeSyncRecordInfo[]; } +export type DigitalEmployeeAdminWorkbenchView = + | 'business' + | 'interventions' + | 'artifact_lifecycle' + | 'notifications' + | 'audits' + | 'daily_reports' + | 'route_governance'; + +export interface DigitalEmployeeAdminWorkbenchRow { + view: DigitalEmployeeAdminWorkbenchView | string; + sync_record_id: number; + sync_record_url?: string; + entity_type?: string; + entity_id?: string; + operation?: string; + title?: string; + status?: string; + kind?: string; + category?: string; + level?: string; + priority?: string; + summary?: string; + plan_id?: string; + task_id?: string; + run_id?: string; + approval_id?: string; + artifact_id?: string; + notification_id?: string; + report_id?: string; + route_decision_id?: string; + occurred_at?: string; + synced_at?: string; + client_key_masked?: string; + device_id?: string; + business_view?: Record; + payload?: Record; +} + +export interface DigitalEmployeeAdminWorkbenchListParams + extends SystemPaginationParams { + view: DigitalEmployeeAdminWorkbenchView; + clientKey?: string; + deviceId?: string; + entityType?: string; + entityId?: string; + status?: string; + kind?: string; + category?: string; + level?: string; + priority?: string; + updatedFrom?: string; + updatedTo?: string; +} + +export interface DigitalEmployeeAdminWorkbenchPage { + total: number; + page_no: number; + page_size: number; + records: DigitalEmployeeAdminWorkbenchRow[]; +} + // 网页应用信息 export type SystemWebappInfo = SystemResourceInfo; diff --git a/qimingclaw/docs/digital-employee-frontend-integration-plan.md b/qimingclaw/docs/digital-employee-frontend-integration-plan.md index 45e5586d..950f49c1 100644 --- a/qimingclaw/docs/digital-employee-frontend-integration-plan.md +++ b/qimingclaw/docs/digital-employee-frontend-integration-plan.md @@ -609,8 +609,8 @@ GET /api/digital-employee/approvals - 建议:下一轮围绕管理端正式审计视图和诊断修复动作,把本地可追溯审计继续推进到可运营处置。 12. **管理端业务查询模型** - - 已吸收:管理端已有通用 sync record 接收、查询、payload 摘要和深链;后端 sync record 已开始保存客户端顶层 `contract_version`、`entity_summary` 和 `business_view`,并基于现有 `digital_employee_sync_record` 拆出 `/api/digital-employee/plans`、`/plans/{plan_id}`、`/tasks`、`/runs`、`/events`、`/artifacts`、`/approvals` 管理端业务查询模型;列表支持客户端 Key、设备、实体 ID、状态、同步状态和同步时间范围过滤,业务 row 会提炼 title/status/summary、Plan/Task/Run 关联、发生/开始/结束时间、sync record 深链和脱敏客户端 Key;Plan 视图会聚合 task/run 计数与最近事件,Plan 详情会返回关联 tasks/runs/events/artifacts/approvals 摘要。embedded adapter 已拆出同名只读业务查询接口,从 qimingclaw runtime、artifact、approval 和 canonical event 投影生成统一分页视图;embedded 数字员工页已新增“业务视图”入口,支持计划/任务/运行/事件/产物/审批分段、实体/状态/同步状态/时间筛选、分页和详情 JSON 查看;客户端 outbox 的 event `business_view` 已开始按 route decision、governance command、approval action、artifact lifecycle/access、skill call audit 和 ready PlanStep dispatch 细分常用字段,本地与管理端业务视图投影已开始闭环。 - - 缺口:复杂组合检索、跨设备聚合图、正式外部管理端菜单整合和物化业务表仍待吸收。 + - 已吸收:管理端已有通用 sync record 接收、查询、payload 摘要和深链;后端 sync record 已开始保存客户端顶层 `contract_version`、`entity_summary` 和 `business_view`,并基于现有 `digital_employee_sync_record` 拆出 `/api/digital-employee/plans`、`/plans/{plan_id}`、`/tasks`、`/runs`、`/events`、`/artifacts`、`/approvals` 管理端业务查询模型;列表支持客户端 Key、设备、实体 ID、状态、同步状态和同步时间范围过滤,业务 row 会提炼 title/status/summary、Plan/Task/Run 关联、发生/开始/结束时间、sync record 深链和脱敏客户端 Key;Plan 视图会聚合 task/run 计数与最近事件,Plan 详情会返回关联 tasks/runs/events/artifacts/approvals 摘要。embedded adapter 已拆出同名只读业务查询接口,从 qimingclaw runtime、artifact、approval 和 canonical event 投影生成统一分页视图;embedded 数字员工页已新增“业务视图”入口,支持计划/任务/运行/事件/产物/审批分段、实体/状态/同步状态/时间筛选、分页和详情 JSON 查看;客户端 outbox 的 event `business_view` 已开始按 route decision、governance command、approval action、artifact lifecycle/access、skill call audit 和 ready PlanStep dispatch 细分常用字段,本地与管理端业务视图投影已开始闭环。正式外部管理端台面已开始吸收:qiming-backend 新增 `/api/digital-employee/admin/workbench/{view}`,qiming 管理端新增“数字员工运营台”,统一展示业务视图、介入台、产物治理、通知运营、审计诊断、日报运营和路由治理,只读消费 sync record `business_view` 并提供同步记录深链。 + - 缺口:复杂组合检索、跨设备聚合图、远程裁决/策略编辑动作和物化业务表仍待吸收。 - 建议:先使用 sync record 派生业务查询模型和 embedded 业务视图预览承接联调,再按容量和查询压力决定是否拆 Plan / Task / Run / Event 物理业务表。 13. **日报实体与导出交付**