@chenchaolong/plugin-trade-compliance-workbench 1.0.51 → 1.0.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/lib/analytics-export.d.ts.map +1 -1
- package/dist/lib/analytics-export.js +1 -3
- package/dist/lib/analytics-export.js.map +1 -1
- package/dist/lib/analytics-query.d.ts.map +1 -1
- package/dist/lib/analytics-query.js +13 -20
- package/dist/lib/analytics-query.js.map +1 -1
- package/dist/lib/catalog-import/confidence.d.ts +1 -0
- package/dist/lib/catalog-import/confidence.d.ts.map +1 -1
- package/dist/lib/catalog-import/confidence.js +12 -0
- package/dist/lib/catalog-import/confidence.js.map +1 -1
- package/dist/lib/catalog-import/docx.parser.d.ts.map +1 -1
- package/dist/lib/catalog-import/docx.parser.js +7 -6
- package/dist/lib/catalog-import/docx.parser.js.map +1 -1
- package/dist/lib/catalog-import/pdf-layout.parser.d.ts.map +1 -1
- package/dist/lib/catalog-import/pdf-layout.parser.js +8 -7
- package/dist/lib/catalog-import/pdf-layout.parser.js.map +1 -1
- package/dist/lib/catalog-import/spreadsheet.parser.d.ts.map +1 -1
- package/dist/lib/catalog-import/spreadsheet.parser.js +12 -13
- package/dist/lib/catalog-import/spreadsheet.parser.js.map +1 -1
- package/dist/lib/constants.d.ts +1 -0
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +1 -0
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/demo-data.definitions.js +1 -1
- package/dist/lib/demo-data.definitions.js.map +1 -1
- package/dist/lib/entities/catalog.entity.d.ts +7 -1
- package/dist/lib/entities/catalog.entity.d.ts.map +1 -1
- package/dist/lib/entities/catalog.entity.js +26 -2
- package/dist/lib/entities/catalog.entity.js.map +1 -1
- package/dist/lib/entities/customer.entity.js.map +1 -1
- package/dist/lib/entities/procurement.entity.js.map +1 -1
- package/dist/lib/import-jobs/import-command.builder.js +2 -2
- package/dist/lib/import-jobs/import-command.builder.js.map +1 -1
- package/dist/lib/import-jobs/import-job-callback.processor.d.ts.map +1 -1
- package/dist/lib/import-jobs/import-job-callback.processor.js +2 -0
- package/dist/lib/import-jobs/import-job-callback.processor.js.map +1 -1
- package/dist/lib/remote-components/trade-compliance-workbench/app.css +1 -1
- package/dist/lib/remote-components/trade-compliance-workbench/app.js +8 -8
- package/dist/lib/remote-components/trade-compliance-workbench/editor-source.mjs +17 -1
- package/dist/lib/remote-components/trade-compliance-workbench/editor.js +100 -100
- package/dist/lib/remote-ui/action-execution.d.ts +3 -0
- package/dist/lib/remote-ui/action-execution.d.ts.map +1 -1
- package/dist/lib/remote-ui/action-execution.js +21 -1
- package/dist/lib/remote-ui/action-execution.js.map +1 -1
- package/dist/lib/remote-ui/app-source.js +178 -153
- package/dist/lib/remote-ui/app-source.js.map +1 -1
- package/dist/lib/remote-ui/bridge.d.ts.map +1 -1
- package/dist/lib/remote-ui/components/forms.d.ts +5 -2
- package/dist/lib/remote-ui/components/forms.d.ts.map +1 -1
- package/dist/lib/remote-ui/components/forms.js +4 -4
- package/dist/lib/remote-ui/components/forms.js.map +1 -1
- package/dist/lib/remote-ui/components/layout.d.ts.map +1 -1
- package/dist/lib/remote-ui/components/layout.js +31 -4
- package/dist/lib/remote-ui/components/layout.js.map +1 -1
- package/dist/lib/remote-ui/components/task-status.js +2 -2
- package/dist/lib/remote-ui/components/task-status.js.map +1 -1
- package/dist/lib/remote-ui/contract-import.d.ts +1 -0
- package/dist/lib/remote-ui/contract-import.d.ts.map +1 -1
- package/dist/lib/remote-ui/contract-import.js +3 -1
- package/dist/lib/remote-ui/contract-import.js.map +1 -1
- package/dist/lib/remote-ui/contracts.d.ts +21 -0
- package/dist/lib/remote-ui/contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/import-task-status.d.ts +5 -2
- package/dist/lib/remote-ui/import-task-status.d.ts.map +1 -1
- package/dist/lib/remote-ui/import-task-status.js +13 -8
- package/dist/lib/remote-ui/import-task-status.js.map +1 -1
- package/dist/lib/remote-ui/pages/analytics-detail-list.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/analytics-detail-list.js.map +1 -1
- package/dist/lib/remote-ui/pages/catalog-import-history.d.ts +63 -0
- package/dist/lib/remote-ui/pages/catalog-import-history.d.ts.map +1 -0
- package/dist/lib/remote-ui/pages/catalog-import-history.js +158 -0
- package/dist/lib/remote-ui/pages/catalog-import-history.js.map +1 -0
- package/dist/lib/remote-ui/pages/catalogs.css +164 -0
- package/dist/lib/remote-ui/pages/catalogs.d.ts +12 -6
- package/dist/lib/remote-ui/pages/catalogs.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/catalogs.js +79 -23
- package/dist/lib/remote-ui/pages/catalogs.js.map +1 -1
- package/dist/lib/remote-ui/pages/contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/contracts.js +0 -16
- package/dist/lib/remote-ui/pages/contracts.js.map +1 -1
- package/dist/lib/remote-ui/pages/files-prototype.css +2 -2
- package/dist/lib/remote-ui/pages/files.d.ts +1 -1
- package/dist/lib/remote-ui/pages/files.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/files.js +6 -6
- package/dist/lib/remote-ui/pages/files.js.map +1 -1
- package/dist/lib/remote-ui/pages/home.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/home.js +2 -2
- package/dist/lib/remote-ui/pages/home.js.map +1 -1
- package/dist/lib/remote-ui/pages/procurement.d.ts +6 -1
- package/dist/lib/remote-ui/pages/procurement.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/procurement.js +77 -16
- package/dist/lib/remote-ui/pages/procurement.js.map +1 -1
- package/dist/lib/remote-ui/pages/sales.d.ts +4 -1
- package/dist/lib/remote-ui/pages/sales.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/sales.js +9 -4
- package/dist/lib/remote-ui/pages/sales.js.map +1 -1
- package/dist/lib/remote-ui/procurement-contracts.d.ts +7 -1
- package/dist/lib/remote-ui/procurement-contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/procurement-contracts.js.map +1 -1
- package/dist/lib/remote-ui/sidebar-state.d.ts +1 -0
- package/dist/lib/remote-ui/sidebar-state.d.ts.map +1 -1
- package/dist/lib/remote-ui/sidebar-state.js +3 -0
- package/dist/lib/remote-ui/sidebar-state.js.map +1 -1
- package/dist/lib/remote-ui/styles.css +1 -1
- package/dist/lib/sales-file.service.d.ts.map +1 -1
- package/dist/lib/sales-file.service.js +33 -1
- package/dist/lib/sales-file.service.js.map +1 -1
- package/dist/lib/schema-maintenance.d.ts.map +1 -1
- package/dist/lib/schema-maintenance.js +125 -0
- package/dist/lib/schema-maintenance.js.map +1 -1
- package/dist/lib/types.d.ts +3 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +1 -0
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/workbench-action-contract.d.ts +1 -1
- package/dist/lib/workbench-action-contract.d.ts.map +1 -1
- package/dist/lib/workbench-action-contract.js +3 -1
- package/dist/lib/workbench-action-contract.js.map +1 -1
- package/dist/lib/workbench-view.provider.d.ts +19 -9
- package/dist/lib/workbench-view.provider.d.ts.map +1 -1
- package/dist/lib/workbench-view.provider.js +43 -7
- package/dist/lib/workbench-view.provider.js.map +1 -1
- package/dist/lib/workbench.middleware.js +8 -8
- package/dist/lib/workbench.middleware.js.map +1 -1
- package/dist/lib/workbench.service.d.ts +44 -3
- package/dist/lib/workbench.service.d.ts.map +1 -1
- package/dist/lib/workbench.service.js +788 -152
- package/dist/lib/workbench.service.js.map +1 -1
- package/package.json +2 -1
|
@@ -16,6 +16,9 @@ type ActionNotificationPolicy = 'silent' | {
|
|
|
16
16
|
export type ActionExecutionOptions = {
|
|
17
17
|
suppressRefresh?: boolean;
|
|
18
18
|
};
|
|
19
|
+
export declare function createMutationCoordinator(): {
|
|
20
|
+
run<T>(operation: () => Promise<T>, onBusyChange?: (busy: boolean) => void): Promise<T>;
|
|
21
|
+
};
|
|
19
22
|
export declare const ACTION_NOTIFICATION_POLICIES: Record<WorkbenchActionKey, ActionNotificationPolicy>;
|
|
20
23
|
export declare function executeWorkbenchAction<T>({ actionKey, mutate, refresh, notify, onResult, resolveMessage, suppressRefresh }: {
|
|
21
24
|
actionKey: WorkbenchActionKey;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-execution.d.ts","sourceRoot":"","sources":["../../../src/lib/remote-ui/action-execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAC/F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAE9C,MAAM,MAAM,YAAY,CAAC,CAAC,GAAG,OAAO,IAAI;IACtC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,CAAC,EAAE,CAAC,CAAA;IACR,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,KAAK,wBAAwB,GAAG,QAAQ,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAA;AAChF,MAAM,MAAM,sBAAsB,GAAG;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAElE,eAAO,MAAM,4BAA4B,EAAE,MAAM,CAAC,kBAAkB,EAAE,wBAAwB,
|
|
1
|
+
{"version":3,"file":"action-execution.d.ts","sourceRoot":"","sources":["../../../src/lib/remote-ui/action-execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAC/F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAE9C,MAAM,MAAM,YAAY,CAAC,CAAC,GAAG,OAAO,IAAI;IACtC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,CAAC,EAAE,CAAC,CAAA;IACR,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,KAAK,wBAAwB,GAAG,QAAQ,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAA;AAChF,MAAM,MAAM,sBAAsB,GAAG;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAElE,wBAAgB,yBAAyB;QAG3B,CAAC,aAAa,MAAM,OAAO,CAAC,CAAC,CAAC,iBAAgB,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAqB,OAAO,CAAC,CAAC,CAAC;EAOjH;AAED,eAAO,MAAM,4BAA4B,EAAE,MAAM,CAAC,kBAAkB,EAAE,wBAAwB,CAwC7F,CAAA;AAiBD,wBAAsB,sBAAsB,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAqC,EAAE,eAAe,EAAE,EAAE;IACxJ,SAAS,EAAE,kBAAkB,CAAA;IAC7B,MAAM,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IACtC,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IAC5C,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,MAAM,CAAA;CACrD,GAAG,sBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAiBpD"}
|
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
import { isWorkbenchActionKey } from '../workbench-action-contract.js';
|
|
2
|
+
export function createMutationCoordinator() {
|
|
3
|
+
let running = false;
|
|
4
|
+
return {
|
|
5
|
+
async run(operation, onBusyChange = () => undefined) {
|
|
6
|
+
if (running)
|
|
7
|
+
throw new Error('操作正在执行,请稍候');
|
|
8
|
+
running = true;
|
|
9
|
+
onBusyChange(true);
|
|
10
|
+
try {
|
|
11
|
+
return await operation();
|
|
12
|
+
}
|
|
13
|
+
finally {
|
|
14
|
+
running = false;
|
|
15
|
+
onBusyChange(false);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
2
20
|
export const ACTION_NOTIFICATION_POLICIES = {
|
|
3
21
|
refresh: 'silent',
|
|
4
22
|
load_excel_editor_runtime: 'silent',
|
|
@@ -31,12 +49,14 @@ export const ACTION_NOTIFICATION_POLICIES = {
|
|
|
31
49
|
download_sales_file: { tone: 'success', fallback: '销售文件下载成功' },
|
|
32
50
|
download_import_issues: { tone: 'success', fallback: '导入问题 Excel 下载成功' },
|
|
33
51
|
retry_import_task: 'silent',
|
|
52
|
+
resolve_stalled_catalog_import: 'silent',
|
|
34
53
|
delete_import_task: 'silent',
|
|
35
54
|
download_source_file: 'silent',
|
|
36
55
|
preview_source_file: 'silent',
|
|
37
56
|
save_edited_sales_file: 'silent',
|
|
38
57
|
search_hs_code: 'silent',
|
|
39
|
-
get_hs_code_detail: 'silent'
|
|
58
|
+
get_hs_code_detail: 'silent',
|
|
59
|
+
translate_purchase_product_name: 'silent'
|
|
40
60
|
};
|
|
41
61
|
const refreshActions = new Set([
|
|
42
62
|
'save_controlled_goods',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-execution.js","sourceRoot":"","sources":["../../../src/lib/remote-ui/action-execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAA2B,MAAM,iCAAiC,CAAA;AAc/F,MAAM,CAAC,MAAM,4BAA4B,GAAyD;IAChG,OAAO,EAAE,QAAQ;IACjB,yBAAyB,EAAE,QAAQ;IACnC,cAAc,EAAE,QAAQ;IACxB,qBAAqB,EAAE,QAAQ;IAC/B,uBAAuB,EAAE,QAAQ;IACjC,uBAAuB,EAAE,QAAQ;IACjC,yBAAyB,EAAE,QAAQ;IACnC,oBAAoB,EAAE,QAAQ;IAC9B,6BAA6B,EAAE,QAAQ;IACvC,eAAe,EAAE,QAAQ;IACzB,qBAAqB,EAAE,QAAQ;IAC/B,iBAAiB,EAAE,QAAQ;IAC3B,oBAAoB,EAAE,QAAQ;IAC9B,eAAe,EAAE,QAAQ;IACzB,yBAAyB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE;IACrE,wBAAwB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE;IACrE,4BAA4B,EAAE,QAAQ;IACtC,+BAA+B,EAAE,QAAQ;IACzC,2BAA2B,EAAE,QAAQ;IACrC,2CAA2C,EAAE,QAAQ;IACrD,aAAa,EAAE,QAAQ;IACvB,aAAa,EAAE,QAAQ;IACvB,wBAAwB,EAAE,QAAQ;IAClC,oBAAoB,EAAE,QAAQ;IAC9B,oBAAoB,EAAE,QAAQ;IAC9B,gBAAgB,EAAE,QAAQ;IAC1B,oBAAoB,EAAE,QAAQ;IAC9B,mBAAmB,EAAE,QAAQ;IAC7B,mBAAmB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE;IAC9D,sBAAsB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,EAAE;IACxE,iBAAiB,EAAE,QAAQ;IAC3B,kBAAkB,EAAE,QAAQ;IAC5B,oBAAoB,EAAE,QAAQ;IAC9B,mBAAmB,EAAE,QAAQ;IAC7B,sBAAsB,EAAE,QAAQ;IAChC,cAAc,EAAE,QAAQ;IACxB,kBAAkB,EAAE,QAAQ;
|
|
1
|
+
{"version":3,"file":"action-execution.js","sourceRoot":"","sources":["../../../src/lib/remote-ui/action-execution.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,7 +24,7 @@ import { AnalyticsComplianceCategoryKeys } from './analytics-contracts.js';
|
|
|
24
24
|
import { ContractImportError, findRecoverableContractImport, findResumableContractImports, runContractImportOrchestration, runCustomerContractReanalysis, taskTransition } from './contract-import.js';
|
|
25
25
|
import { createTaskChatSynchronizer, importTaskFromStart, importTaskProgressPercent, isLocalUploadPlaceholder, mergeImportTaskItems, removeImportTaskItem, taskBusinessRefreshRevision, taskRouteRefreshTarget } from './import-task-status.js';
|
|
26
26
|
import { compareTaskBusinessOrder, createPendingResultQueue, createPollingTaskTracker, isAbortError, isPollingObservationTimeout, submitAndRefreshTaskState } from './polling.js';
|
|
27
|
-
import {
|
|
27
|
+
import { createMutationCoordinator, executeWorkbenchAction } from './action-execution.js';
|
|
28
28
|
import { createDeferredBulkReconcileCoordinator, runBulkDelete } from './bulk-delete.js';
|
|
29
29
|
import './styles.css';
|
|
30
30
|
const pageMeta = {
|
|
@@ -93,6 +93,7 @@ function App() {
|
|
|
93
93
|
const deletedImportTaskIdsRef = React.useRef(new Set());
|
|
94
94
|
const [busy, setBusy] = React.useState(false);
|
|
95
95
|
const [actionBusy, setActionBusy] = React.useState(false);
|
|
96
|
+
const mutationCoordinatorRef = React.useRef(createMutationCoordinator());
|
|
96
97
|
const [customerContractBulkBusy, setCustomerContractBulkBusy] = React.useState(false);
|
|
97
98
|
const [salesFileBulkBusy, setSalesFileBulkBusy] = React.useState(false);
|
|
98
99
|
const [settingsRateBulkBusy, setSettingsRateBulkBusy] = React.useState(false);
|
|
@@ -122,8 +123,13 @@ function App() {
|
|
|
122
123
|
key: 'tradeComplianceTask', context: { task, relatedRecords }
|
|
123
124
|
});
|
|
124
125
|
},
|
|
125
|
-
|
|
126
|
-
await bridge.invokeClientCommand('assistant.
|
|
126
|
+
openConversation: async (conversationId, task) => {
|
|
127
|
+
await bridge.invokeClientCommand('assistant.conversation.open', {
|
|
128
|
+
target: 'assistant.conversation',
|
|
129
|
+
conversationId,
|
|
130
|
+
contextKey: 'tradeComplianceTask',
|
|
131
|
+
context: { task }
|
|
132
|
+
});
|
|
127
133
|
}
|
|
128
134
|
});
|
|
129
135
|
const changeRouteRef = React.useRef(() => undefined);
|
|
@@ -420,27 +426,19 @@ function App() {
|
|
|
420
426
|
React.useEffect(() => {
|
|
421
427
|
toastTimers.sync(toasts);
|
|
422
428
|
}, [toastTimers, toasts]);
|
|
429
|
+
const runMutation = React.useCallback((operation) => mutationCoordinatorRef.current.run(operation, setActionBusy), []);
|
|
423
430
|
const executeAction = React.useCallback(async (actionKey, input, options = {}) => {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
downloadActionFile(result.data); },
|
|
436
|
-
...options
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
finally {
|
|
440
|
-
if (blocksPage)
|
|
441
|
-
setActionBusy(false);
|
|
442
|
-
}
|
|
443
|
-
}, [load]);
|
|
431
|
+
return runMutation(() => executeWorkbenchAction({
|
|
432
|
+
actionKey,
|
|
433
|
+
mutate: async () => asActionResult(unwrapResponse(await bridge.executeAction(actionKey, input))),
|
|
434
|
+
refresh: load,
|
|
435
|
+
notify: setToast,
|
|
436
|
+
resolveMessage: resolveActionMessage,
|
|
437
|
+
onResult: result => { if (actionKey === 'download_import_issues' || actionKey === 'download_sales_file')
|
|
438
|
+
downloadActionFile(result.data); },
|
|
439
|
+
...options
|
|
440
|
+
}));
|
|
441
|
+
}, [load, runMutation]);
|
|
444
442
|
const executeSalesFileAction = React.useCallback((actionKey, input, options = {}) => executeAction(actionKey, input, options), [executeAction]);
|
|
445
443
|
const schedulePendingReviewPresentation = React.useCallback(() => {
|
|
446
444
|
if (reviewPresentationTimerRef.current != null)
|
|
@@ -470,12 +468,14 @@ function App() {
|
|
|
470
468
|
refresh: loadTaskState,
|
|
471
469
|
signal,
|
|
472
470
|
onTransition: (previous, next) => {
|
|
471
|
+
upsertLocalImportTask(next);
|
|
473
472
|
const notice = taskTransition(previous, next);
|
|
474
473
|
if (notice)
|
|
475
474
|
setToast(notice);
|
|
476
475
|
},
|
|
477
476
|
onPollError: error => setToast({ message: `任务状态查询失败:${error.message}`, tone: 'error' })
|
|
478
477
|
});
|
|
478
|
+
upsertLocalImportTask(completion.task);
|
|
479
479
|
setImportCompletions(current => ({ ...current, [completion.task.documentType]: completion }));
|
|
480
480
|
await refreshTaskRouteRef.current(completion.task);
|
|
481
481
|
return completion;
|
|
@@ -496,7 +496,7 @@ function App() {
|
|
|
496
496
|
setToast({ message: error instanceof Error ? error.message : '目录解析失败', tone: 'error' });
|
|
497
497
|
throw error;
|
|
498
498
|
}
|
|
499
|
-
}, [loadTaskState, scheduleTaskStateRecovery]);
|
|
499
|
+
}, [loadTaskState, scheduleTaskStateRecovery, upsertLocalImportTask]);
|
|
500
500
|
const orchestrateContractImport = React.useCallback(async (start, signal) => {
|
|
501
501
|
const task = start.data?.task;
|
|
502
502
|
if (!task)
|
|
@@ -600,35 +600,37 @@ function App() {
|
|
|
600
600
|
return false;
|
|
601
601
|
}, [upsertLocalImportTask]);
|
|
602
602
|
const executeFileAction = React.useCallback(async (actionKey, file, input, notifyError = true) => {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
603
|
+
return runMutation(async () => {
|
|
604
|
+
try {
|
|
605
|
+
const raw = await bridge.executeFileAction(actionKey, file, input);
|
|
606
|
+
const start = asActionResult(unwrapResponse(raw));
|
|
607
|
+
const task = importTaskFromStart(start, actionKey, input, file);
|
|
608
|
+
if (task) {
|
|
609
|
+
upsertLocalImportTask(task);
|
|
610
|
+
if (isLocalUploadPlaceholder(task))
|
|
611
|
+
scheduleTaskStateRecovery();
|
|
612
|
+
else
|
|
613
|
+
startTrackingUploadedImportTask(task);
|
|
614
|
+
}
|
|
615
|
+
if (start.success === false)
|
|
616
|
+
throw actionResponseError(start, '上传失败');
|
|
617
|
+
await loadTaskState().catch((refreshError) => {
|
|
618
|
+
notifyTaskRecoveryRefreshError(refreshError instanceof Error ? refreshError : new Error(String(refreshError)));
|
|
619
|
+
});
|
|
620
|
+
await presentImmediateContractUploadReview(actionKey, start);
|
|
621
|
+
setToast({ message: resolveActionMessage(start) || '解析任务已提交', tone: 'info' });
|
|
622
|
+
return start;
|
|
613
623
|
}
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
await loadTaskState().catch((refreshError) => {
|
|
625
|
-
notifyTaskRecoveryRefreshError(refreshError instanceof Error ? refreshError : new Error(String(refreshError)));
|
|
626
|
-
});
|
|
627
|
-
if (notifyError && !(error instanceof CatalogImportError))
|
|
628
|
-
setToast({ message: error instanceof Error ? error.message : '上传失败', tone: 'error' });
|
|
629
|
-
throw error;
|
|
630
|
-
}
|
|
631
|
-
}, [loadTaskState, notifyTaskRecoveryRefreshError, presentImmediateContractUploadReview, scheduleTaskStateRecovery, startTrackingUploadedImportTask, upsertLocalImportTask]);
|
|
624
|
+
catch (error) {
|
|
625
|
+
await loadTaskState().catch((refreshError) => {
|
|
626
|
+
notifyTaskRecoveryRefreshError(refreshError instanceof Error ? refreshError : new Error(String(refreshError)));
|
|
627
|
+
});
|
|
628
|
+
if (notifyError && !(error instanceof CatalogImportError))
|
|
629
|
+
setToast({ message: error instanceof Error ? error.message : '上传失败', tone: 'error' });
|
|
630
|
+
throw error;
|
|
631
|
+
}
|
|
632
|
+
});
|
|
633
|
+
}, [loadTaskState, notifyTaskRecoveryRefreshError, presentImmediateContractUploadReview, runMutation, scheduleTaskStateRecovery, startTrackingUploadedImportTask, upsertLocalImportTask]);
|
|
632
634
|
const executeCatalogFileAction = React.useCallback((actionKey, file, input) => executeFileAction(actionKey, file, input, false), [executeFileAction]);
|
|
633
635
|
React.useEffect(() => {
|
|
634
636
|
const tasks = data.importTasks.items;
|
|
@@ -671,52 +673,58 @@ function App() {
|
|
|
671
673
|
}
|
|
672
674
|
}, [data.importTasks.items, handleBackgroundImportTrackingError, orchestrateContractImport]);
|
|
673
675
|
const retryImport = React.useCallback(async (taskId) => {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
676
|
+
return runMutation(async () => {
|
|
677
|
+
try {
|
|
678
|
+
const raw = await submitAndRefreshTaskState(() => bridge.executeAction('retry_import_task', { taskId }), loadTaskState, notifyTaskRecoveryRefreshError);
|
|
679
|
+
const start = asActionResult(unwrapResponse(raw));
|
|
680
|
+
if (start.success === false)
|
|
681
|
+
throw actionResponseError(start, '重新解析失败');
|
|
682
|
+
setToast({ message: resolveActionMessage(start) || '重新解析任务已提交', tone: 'info' });
|
|
683
|
+
}
|
|
684
|
+
catch (error) {
|
|
685
|
+
if (!(error instanceof CatalogImportError))
|
|
686
|
+
setToast({ message: error instanceof Error ? error.message : '重新解析失败', tone: 'error' });
|
|
687
|
+
throw error;
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
}, [loadTaskState, notifyTaskRecoveryRefreshError, runMutation]);
|
|
687
691
|
const retryContractImport = React.useCallback(async (taskId) => {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
692
|
+
return runMutation(async () => {
|
|
693
|
+
try {
|
|
694
|
+
const raw = await submitAndRefreshTaskState(() => bridge.executeAction('retry_import_task', { taskId }), loadTaskState, notifyTaskRecoveryRefreshError);
|
|
695
|
+
const start = asActionResult(unwrapResponse(raw));
|
|
696
|
+
if (start.success === false)
|
|
697
|
+
throw actionResponseError(start, '重新解析失败');
|
|
698
|
+
setToast({ message: resolveActionMessage(start) || '重新解析任务已提交', tone: 'info' });
|
|
699
|
+
}
|
|
700
|
+
catch (error) {
|
|
701
|
+
setToast({ message: error instanceof Error ? error.message : '重新解析失败', tone: 'error' });
|
|
702
|
+
throw error;
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
}, [loadTaskState, notifyTaskRecoveryRefreshError, runMutation]);
|
|
700
706
|
const deleteImportTaskRecord = React.useCallback(async (task, options) => {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
taskChatSynchronizerRef.current.
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
707
|
+
return runMutation(async () => {
|
|
708
|
+
const result = asActionResult(unwrapResponse(await bridge.executeAction('delete_import_task', { taskId: task.id })));
|
|
709
|
+
if (result.success === false)
|
|
710
|
+
throw actionResponseError(result, '任务删除失败');
|
|
711
|
+
catalogTaskTrackerRef.current.abort(task.id);
|
|
712
|
+
contractTaskTrackerRef.current.abort(task.id);
|
|
713
|
+
removeLocalImportTask(task.id);
|
|
714
|
+
if (taskChatSynchronizerRef.current?.isSelected(task.id)) {
|
|
715
|
+
taskChatSynchronizerRef.current.clear();
|
|
716
|
+
await bridge.invokeClientCommand('assistant.context.set', {
|
|
717
|
+
key: 'tradeComplianceTask', clear: true
|
|
718
|
+
}).catch(() => undefined);
|
|
719
|
+
await bridge.invokeClientCommand('assistant.chat.send_message', {
|
|
720
|
+
text: `任务“${task.sourceFileName || documentTypeLabel(task.documentType)}”已取消并删除。`,
|
|
721
|
+
clientMessageId: `trade-task:${task.id}:deleted`
|
|
722
|
+
}).catch(() => undefined);
|
|
723
|
+
}
|
|
724
|
+
if (options.refresh)
|
|
725
|
+
await loadTaskState();
|
|
726
|
+
});
|
|
727
|
+
}, [loadTaskState, removeLocalImportTask, runMutation]);
|
|
720
728
|
const deleteImportTask = React.useCallback(async (task) => {
|
|
721
729
|
await deleteImportTaskRecord(task, { refresh: true });
|
|
722
730
|
}, [deleteImportTaskRecord]);
|
|
@@ -779,14 +787,16 @@ function App() {
|
|
|
779
787
|
return attached;
|
|
780
788
|
}, []);
|
|
781
789
|
const consumeCustomerContractReanalysisResult = React.useCallback(async (runId) => {
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
790
|
+
return runMutation(async () => {
|
|
791
|
+
const consumed = asActionResult(unwrapResponse(await bridge.executeAction('consume_customer_contract_reanalysis_result', { runId })));
|
|
792
|
+
if (consumed.success === false)
|
|
793
|
+
throw new Error(resolveActionMessage(consumed) || '确认重新分析结果失败');
|
|
794
|
+
});
|
|
795
|
+
}, [runMutation]);
|
|
786
796
|
const reanalyzeCustomerContract = React.useCallback(async (input) => {
|
|
787
797
|
setCustomerReanalysisState({ status: 'RUNNING', message: 'AI 重新分析中' });
|
|
788
798
|
try {
|
|
789
|
-
const raw = await submitAndRefreshTaskState(() => bridge.executeAction('reanalyze_customer_contract', { reviewSource: input.reviewSource, ...(input.customerContractId ? { id: input.customerContractId } : {}), ...(input.importTaskId ? { importTaskId: input.importTaskId } : {}) }), loadTaskState, notifyTaskRecoveryRefreshError);
|
|
799
|
+
const raw = await runMutation(() => submitAndRefreshTaskState(() => bridge.executeAction('reanalyze_customer_contract', { reviewSource: input.reviewSource, ...(input.customerContractId ? { id: input.customerContractId } : {}), ...(input.importTaskId ? { importTaskId: input.importTaskId } : {}) }), loadTaskState, notifyTaskRecoveryRefreshError));
|
|
790
800
|
const response = asActionResult(unwrapResponse(raw));
|
|
791
801
|
if (response.success === false || !response.data)
|
|
792
802
|
throw actionResponseError(response, 'AI 重新分析启动失败');
|
|
@@ -827,7 +837,7 @@ function App() {
|
|
|
827
837
|
setToast({ message: error instanceof Error ? error.message : 'AI 重新分析失败', tone: 'error' });
|
|
828
838
|
throw error;
|
|
829
839
|
}
|
|
830
|
-
}, [applyCustomerContractReanalysisResult, consumeCustomerContractReanalysisResult, loadTaskState, scheduleTaskStateRecovery]);
|
|
840
|
+
}, [applyCustomerContractReanalysisResult, consumeCustomerContractReanalysisResult, loadTaskState, runMutation, scheduleTaskStateRecovery]);
|
|
831
841
|
React.useEffect(() => {
|
|
832
842
|
for (const recovery of data.customerContractAnalyses.items) {
|
|
833
843
|
const recoverable = recovery.recoveryType === 'ACTIVE_POLL' || recovery.recoveryType === 'SUCCEEDED_RESULT';
|
|
@@ -942,6 +952,12 @@ function App() {
|
|
|
942
952
|
const payload = asRecord(unwrapResponse(await bridge.requestData({ page: query.page, pageSize: requestedPageSize, parameters: { collection: 'importIssues', documentType: query.documentType, batchId: query.batchId, issueType: query.issueType } })));
|
|
943
953
|
return { items: Array.isArray(payload.items) ? payload.items : [], total: numberValue(payload.total, 0), page: numberValue(payload.page, query.page), pageSize: requestedPageSize };
|
|
944
954
|
}, []);
|
|
955
|
+
const queryCatalogHistory = React.useCallback(async (query) => {
|
|
956
|
+
const requestedPageSize = resolvePaginationPageSize(query.pageSize);
|
|
957
|
+
const collection = query.documentType === 'CONTROLLED_CATALOG' ? 'controlledBatchHistory' : 'sanctionBatchHistory';
|
|
958
|
+
const payload = asRecord(unwrapResponse(await bridge.requestData({ page: query.page, pageSize: requestedPageSize, parameters: { collection } })));
|
|
959
|
+
return { items: Array.isArray(payload.items) ? payload.items : [], total: numberValue(payload.total, 0), page: numberValue(payload.page, query.page), pageSize: requestedPageSize };
|
|
960
|
+
}, []);
|
|
945
961
|
const queryCatalog = React.useCallback(async (collection, query) => {
|
|
946
962
|
if (collection === 'controlledGoods')
|
|
947
963
|
latestControlledCatalogQueryRef.current = query;
|
|
@@ -955,7 +971,7 @@ function App() {
|
|
|
955
971
|
const requestCatalogPage = async (page) => asRecord(unwrapResponse(await bridge.requestData({
|
|
956
972
|
page,
|
|
957
973
|
pageSize: requestedPageSize,
|
|
958
|
-
parameters: { collection, filters: encodeViewFilters(query.filters), refreshNonce: nextSummaryRequestNonce() }
|
|
974
|
+
parameters: { collection, filters: encodeViewFilters(query.filters), batchId: query.batchId, refreshNonce: nextSummaryRequestNonce() }
|
|
959
975
|
})));
|
|
960
976
|
let committedPage = query.page;
|
|
961
977
|
let payload = await requestCatalogPage(committedPage);
|
|
@@ -992,6 +1008,9 @@ function App() {
|
|
|
992
1008
|
setBusy(gate.activeCount() > 0);
|
|
993
1009
|
}
|
|
994
1010
|
}, []);
|
|
1011
|
+
const resolveStalledCatalogImport = React.useCallback(async (taskId, decision) => {
|
|
1012
|
+
return runMutation(async () => asActionResult(unwrapResponse(await bridge.executeAction('resolve_stalled_catalog_import', { taskId, decision }))));
|
|
1013
|
+
}, [runMutation]);
|
|
995
1014
|
const queryMonthlyRates = React.useCallback(async (query) => {
|
|
996
1015
|
latestSettingsRatesQueryRef.current = query;
|
|
997
1016
|
const requestedPageSize = resolvePaginationPageSize(query.pageSize);
|
|
@@ -1156,24 +1175,21 @@ function App() {
|
|
|
1156
1175
|
return analyticsDetailPage(payload, query.page, pageSize);
|
|
1157
1176
|
}, []);
|
|
1158
1177
|
const exportAnalytics = React.useCallback(async (_request) => {
|
|
1159
|
-
setActionBusy(true);
|
|
1160
1178
|
try {
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1179
|
+
await runMutation(async () => {
|
|
1180
|
+
const committed = analyticsRequestsRef.current.committed();
|
|
1181
|
+
const request = { filters: committed.filters, format: 'XLSX' };
|
|
1182
|
+
const result = asActionResult(unwrapResponse(await bridge.executeAction('export_analytics', request)));
|
|
1183
|
+
if (result.success === false)
|
|
1184
|
+
throw new Error(resolveActionMessage(result) || '分析导出失败');
|
|
1185
|
+
downloadActionFile(result.data);
|
|
1186
|
+
setToast({ message: '分析数据导出成功', tone: 'success' });
|
|
1187
|
+
});
|
|
1168
1188
|
}
|
|
1169
1189
|
catch (error) {
|
|
1170
1190
|
setToast({ message: error instanceof Error ? error.message : '分析导出失败', tone: 'error' });
|
|
1171
|
-
throw error;
|
|
1172
|
-
}
|
|
1173
|
-
finally {
|
|
1174
|
-
setActionBusy(false);
|
|
1175
1191
|
}
|
|
1176
|
-
}, []);
|
|
1192
|
+
}, [runMutation]);
|
|
1177
1193
|
const openAnalyticsDetailAction = React.useCallback((row) => {
|
|
1178
1194
|
const action = row.action;
|
|
1179
1195
|
if (action.kind === 'CUSTOMER_CONTRACT_REVIEW') {
|
|
@@ -1221,38 +1237,48 @@ function App() {
|
|
|
1221
1237
|
setToast({ message: '当前明细缺少可跳转的业务标识', tone: 'error' });
|
|
1222
1238
|
}, [openImportTaskFromStatus, setToast]);
|
|
1223
1239
|
const saveSettings = React.useCallback(async (request) => {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1240
|
+
return runMutation(async () => {
|
|
1241
|
+
const result = asActionResult(unwrapResponse(await bridge.executeAction('save_settings', request)));
|
|
1242
|
+
if (result.success === false)
|
|
1243
|
+
throw new Error(resolveActionMessage(result) || '设置保存失败');
|
|
1244
|
+
await loadRoute({ type: 'page', page: 'settings' }, settingsRatesQueryRef.current.page, settingsRatesQueryRef.current.pageSize);
|
|
1245
|
+
});
|
|
1246
|
+
}, [loadRoute, runMutation]);
|
|
1229
1247
|
const restoreSettings = React.useCallback(async (request) => {
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1248
|
+
return runMutation(async () => {
|
|
1249
|
+
const result = asActionResult(unwrapResponse(await bridge.executeAction('restore_settings_default', request)));
|
|
1250
|
+
if (result.success === false)
|
|
1251
|
+
throw new Error(resolveActionMessage(result) || '恢复系统默认失败');
|
|
1252
|
+
await loadRoute({ type: 'page', page: 'settings' }, settingsRatesQueryRef.current.page, settingsRatesQueryRef.current.pageSize);
|
|
1253
|
+
});
|
|
1254
|
+
}, [loadRoute, runMutation]);
|
|
1235
1255
|
const deleteSettingsRate = React.useCallback(async (request, options = {}) => {
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1256
|
+
return runMutation(async () => {
|
|
1257
|
+
const result = asActionResult(unwrapResponse(await bridge.executeAction('delete_settings_rate', request)));
|
|
1258
|
+
if (result.success === false)
|
|
1259
|
+
throw new Error(resolveActionMessage(result) || '月度汇率删除失败');
|
|
1260
|
+
if (options.suppressRefresh)
|
|
1261
|
+
return;
|
|
1262
|
+
const { page, pageSize } = settingsRatesQueryRef.current;
|
|
1263
|
+
const clampedPage = clampPageAfterSingleDeletion(page, pageSize, data.settings.rates.total);
|
|
1264
|
+
await loadRoute({ type: 'page', page: 'settings' }, clampedPage, pageSize);
|
|
1265
|
+
});
|
|
1266
|
+
}, [data.settings.rates.total, loadRoute, runMutation]);
|
|
1245
1267
|
const uploadCompanyLogo = React.useCallback(async (file) => {
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1268
|
+
return runMutation(async () => {
|
|
1269
|
+
const result = asActionResult(unwrapResponse(await bridge.executeFileAction('upload_company_logo', file, {})));
|
|
1270
|
+
if (result.success === false || !result.data?.logoFileId)
|
|
1271
|
+
throw new Error(resolveActionMessage(result) || '公司 Logo 上传失败');
|
|
1272
|
+
return result.data.logoFileId;
|
|
1273
|
+
});
|
|
1274
|
+
}, [runMutation]);
|
|
1251
1275
|
const discardCompanyLogo = React.useCallback(async (logoFileId) => {
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1276
|
+
return runMutation(async () => {
|
|
1277
|
+
const result = asActionResult(unwrapResponse(await bridge.executeAction('discard_company_logo', { logoFileId })));
|
|
1278
|
+
if (result.success === false)
|
|
1279
|
+
throw new Error(resolveActionMessage(result) || '公司 Logo 草稿清理失败');
|
|
1280
|
+
});
|
|
1281
|
+
}, [runMutation]);
|
|
1256
1282
|
const openSalesFiles = React.useCallback((order) => {
|
|
1257
1283
|
setActiveSalesFileOrder(order);
|
|
1258
1284
|
if (!order)
|
|
@@ -1293,7 +1319,7 @@ function App() {
|
|
|
1293
1319
|
: page === 'customer-contract-review'
|
|
1294
1320
|
? _jsx(ContractUploadCommand, { label: "\u4E0A\u4F20\u5BA2\u6237\u5408\u540C", busy: busy || actionBusy || customerContractBulkBusy, onFile: file => executeFileAction('upload_customer_contract', file, { documentType: 'CUSTOMER_CONTRACT' }), onError: message => setToast({ message, tone: 'error' }) })
|
|
1295
1321
|
: undefined;
|
|
1296
|
-
return (_jsxs(_Fragment, { children: [_jsxs(WorkbenchShell, { route: route, breadcrumbs: buildBreadcrumbs(route), title: meta.title, subtitle: page === 'home' ? undefined : meta.subtitle, topbarActions: _jsx(TaskStatusMenu, { items: taskStatusItems, busy: busy || actionBusy, onBulkDelete: bulkDeleteImportTasks, onActionError: notifyTaskStatusActionError }), commands: (page === 'controlled-goods' || page === 'sanctioned-companies') ? _jsx(CatalogCommands, { busy: busy || actionBusy, onUpload: () => setCatalogCommand('upload'), onCreate: () => setCatalogCommand('create') }) : contractCommands, busy: busy || actionBusy, onRouteChange: changeRoute, onRefresh: () => void load(), children: [page === 'home' && _jsx(HomePage, {}), page === 'controlled-goods' && _jsx(ControlledGoodsPage, { collection: data.controlledGoods, batches: data.controlledBatches.items, busy: busy || actionBusy, onAction: executeAction, onFileAction: executeCatalogFileAction, onRefresh: load, onQuery: (query) => queryCatalog('controlledGoods', query), onIssueQuery: queryImportIssues, importCompletion: importCompletions.CONTROLLED_CATALOG, importFailure: importFailures.CONTROLLED_CATALOG, onRetryImport: retryImport, command: catalogCommand, onCommandHandled: () => setCatalogCommand(null), onNotify: setToast }), page === 'sanctioned-companies' && _jsx(SanctionedCompaniesPage, { collection: data.sanctionedCompanies, batches: data.sanctionBatches.items, busy: busy || actionBusy, onAction: executeAction, onFileAction: executeCatalogFileAction, onRefresh: load, onQuery: (query) => queryCatalog('sanctionedCompanies', query), onIssueQuery: queryImportIssues, importCompletion: importCompletions.SANCTION_CATALOG, importFailure: importFailures.SANCTION_CATALOG, onRetryImport: retryImport, command: catalogCommand, onCommandHandled: () => setCatalogCommand(null), onNotify: setToast }), page === 'procurement' && route.type === 'procurement' && _jsx(ProcurementPage, { route: route, suppliers: data.suppliers, purchaseOrders: data.purchaseOrders, purchaseLines: data.purchaseLines, supplier: procurementContext.supplier, order: procurementContext.order, metrics: procurementContext.metrics, importTask: purchaseImportTask, reviewDraft: purchaseReviewDraft, busy: busy || actionBusy, onQuery: queryProcurement, onAction: executeAction, onFileAction: executeFileAction, onRouteChange: changeRoute, onRetryImport: retryContractImport, onReviewClose: closePurchaseReview, onNotify: setToast }), page === 'customer-contract-review' && _jsx(CustomerContractsPage, { collection: data.customerContracts, busy: busy || actionBusy || customerContractBulkBusy, importReviewState: customerImportState, onQuery: queryCustomerContracts, onAction: executeAction, onFileAction: executeFileAction, onReanalyze: reanalyzeCustomerContract, onLoadReview: loadCustomerContractReview, onReviewClose: closeCustomerReview, reanalysisState: customerReanalysisState, onRetryImport: retryContractImport, onQueryRequested: rememberCustomerContractQuery, onQueryCancelRegistration: registerCustomerContractQueryCancel, onBulkReconcile: reconcileCustomerContractsAfterBulk, onBulkBusyChange: setCustomerContractBulkBusy, onNotify: setToast }), page === 'sales' && route.type === 'sales' && _jsx(SalesPage, { route: route, customers: data.salesCustomers, orders: data.salesOrders, lines: data.salesLines, busy: busy || actionBusy, onQuery: querySales, onAction: executeAction, onRouteChange: changeRoute, onOpenFiles: openSalesFiles, onNotify: setToast }), page === 'sales-files' && _jsx(SalesFilesPage, { orders: data.salesFileOrders, history: data.generatedFiles, activeOrder: activeSalesFileOrder, visualPrototypeState: salesFilesPrototypeState, onPrototypeStateClose: () => setSalesFilesPrototypeState(undefined), banks: data.settings.banks, busy: busy || actionBusy, externalBulkBusy: salesFileBulkBusy || salesFileBulkReconcileBusy, onQuery: querySalesFiles, onBulkReconcile: reconcileGeneratedFilesAfterBulk, onBulkBusyChange: setSalesFileBulkBusy, onBulkViewActiveChange: setGeneratedFilesBulkViewActive, onAction: executeSalesFileAction, onOpenSalesOrder: selectSalesFileOrder, onDownload: file => executeAction('download_sales_file', { id: file.id }).then(() => undefined), onEdit: async (file) => setEditingSalesFile(file), onNotify: setToast }), page === 'analytics' && _jsx(AnalyticsPage, { data: data.analytics, committedQuery: analyticsCommittedQuery, detailRefreshKey: analyticsDetailRefreshKey, busy: busy || actionBusy, error: analyticsError, onQuery: queryAnalytics, onDetailQuery: queryAnalyticsDetails, onDetailAction: openAnalyticsDetailAction, onExportXlsx: exportAnalytics }), page === 'settings' && _jsx(SettingsPage, { data: data.settings, busy: busy || actionBusy, externalBulkBusy: settingsRateBulkBusy || settingsRateBulkReconcileBusy, onSave: saveSettings, onRestoreDefault: restoreSettings, onDeleteRate: deleteSettingsRate, onRateQuery: queryMonthlyRates, onBulkReconcile: reconcileSettingsRatesAfterBulk, onBulkBusyChange: setSettingsRateBulkBusy, onBulkViewActiveChange: setSettingsRatesBulkViewActive, onUploadLogo: uploadCompanyLogo, onDiscardLogo: discardCompanyLogo, onNotify: setToast }), !['home', 'controlled-goods', 'sanctioned-companies', 'procurement', 'customer-contract-review', 'sales', 'sales-files', 'analytics', 'settings'].includes(page) && _jsxs("section", { className: "tcw-page-placeholder", "data-page": page, children: [_jsx(InfoNotice, { children: "\u9875\u9762\u57FA\u7840\u7ED3\u6784\u5DF2\u5C31\u7EEA\uFF0C\u4E1A\u52A1\u5185\u5BB9\u5C06\u5728\u5BF9\u5E94\u9875\u9762\u6A21\u5757\u4E2D\u52A0\u8F7D\u3002" }), _jsx("div", { className: "tcw-placeholder-body", "aria-label": `${meta.title}页面内容` })] })] }), _jsx(LoadingBlocker, { visible: busy || actionBusy || customerContractBulkBusy, label: actionBusy || customerContractBulkBusy ? '操作处理中' : '数据加载中' }), _jsx(ToastStack, { items: toasts, onClose: closeToast }), editingSalesFile && _jsx(SalesFileEditor, { file: editingSalesFile, onNotify: setToast, onClose: () => setEditingSalesFile(null), onSaved: () => {
|
|
1322
|
+
return (_jsxs(_Fragment, { children: [_jsxs(WorkbenchShell, { route: route, breadcrumbs: buildBreadcrumbs(route), title: meta.title, subtitle: page === 'home' ? undefined : meta.subtitle, topbarActions: _jsx(TaskStatusMenu, { items: taskStatusItems, busy: busy || actionBusy, onBulkDelete: bulkDeleteImportTasks, onActionError: notifyTaskStatusActionError }), commands: (page === 'controlled-goods' || page === 'sanctioned-companies') ? _jsx(CatalogCommands, { busy: busy || actionBusy, onUpload: () => setCatalogCommand('upload'), onCreate: () => setCatalogCommand('create'), onHistory: () => setCatalogCommand('history') }) : contractCommands, busy: busy || actionBusy, onRouteChange: changeRoute, onRefresh: () => void load(), children: [page === 'home' && _jsx(HomePage, {}), page === 'controlled-goods' && _jsx(ControlledGoodsPage, { collection: data.controlledGoods, batches: data.controlledBatches.items, busy: busy || actionBusy, onAction: executeAction, onFileAction: executeCatalogFileAction, onRefresh: load, onQuery: (query) => queryCatalog('controlledGoods', query), onIssueQuery: queryImportIssues, onHistoryQuery: queryCatalogHistory, tasks: data.importTasks.items, onResolveStalledImport: resolveStalledCatalogImport, onRefreshTasks: loadTaskState, importCompletion: importCompletions.CONTROLLED_CATALOG, importFailure: importFailures.CONTROLLED_CATALOG, onRetryImport: retryImport, command: catalogCommand, onCommandHandled: () => setCatalogCommand(null), onNotify: setToast }), page === 'sanctioned-companies' && _jsx(SanctionedCompaniesPage, { collection: data.sanctionedCompanies, batches: data.sanctionBatches.items, busy: busy || actionBusy, onAction: executeAction, onFileAction: executeCatalogFileAction, onRefresh: load, onQuery: (query) => queryCatalog('sanctionedCompanies', query), onIssueQuery: queryImportIssues, onHistoryQuery: queryCatalogHistory, tasks: data.importTasks.items, onResolveStalledImport: resolveStalledCatalogImport, onRefreshTasks: loadTaskState, importCompletion: importCompletions.SANCTION_CATALOG, importFailure: importFailures.SANCTION_CATALOG, onRetryImport: retryImport, command: catalogCommand, onCommandHandled: () => setCatalogCommand(null), onNotify: setToast }), page === 'procurement' && route.type === 'procurement' && _jsx(ProcurementPage, { route: route, suppliers: data.suppliers, purchaseOrders: data.purchaseOrders, purchaseLines: data.purchaseLines, supplier: procurementContext.supplier, order: procurementContext.order, metrics: procurementContext.metrics, importTask: purchaseImportTask, reviewDraft: purchaseReviewDraft, busy: busy || actionBusy, onQuery: queryProcurement, onAction: executeAction, onFileAction: executeFileAction, onRouteChange: changeRoute, onRetryImport: retryContractImport, onReviewClose: closePurchaseReview, onNotify: setToast }), page === 'customer-contract-review' && _jsx(CustomerContractsPage, { collection: data.customerContracts, busy: busy || actionBusy || customerContractBulkBusy, importReviewState: customerImportState, onQuery: queryCustomerContracts, onAction: executeAction, onFileAction: executeFileAction, onReanalyze: reanalyzeCustomerContract, onLoadReview: loadCustomerContractReview, onReviewClose: closeCustomerReview, reanalysisState: customerReanalysisState, onRetryImport: retryContractImport, onQueryRequested: rememberCustomerContractQuery, onQueryCancelRegistration: registerCustomerContractQueryCancel, onBulkReconcile: reconcileCustomerContractsAfterBulk, onBulkBusyChange: setCustomerContractBulkBusy, onNotify: setToast }), page === 'sales' && route.type === 'sales' && _jsx(SalesPage, { route: route, customers: data.salesCustomers, orders: data.salesOrders, lines: data.salesLines, busy: busy || actionBusy, onQuery: querySales, onAction: executeAction, onRouteChange: changeRoute, onOpenFiles: openSalesFiles, onNotify: setToast }), page === 'sales-files' && _jsx(SalesFilesPage, { orders: data.salesFileOrders, history: data.generatedFiles, activeOrder: activeSalesFileOrder, visualPrototypeState: salesFilesPrototypeState, onPrototypeStateClose: () => setSalesFilesPrototypeState(undefined), banks: data.settings.banks, busy: busy || actionBusy, externalBulkBusy: salesFileBulkBusy || salesFileBulkReconcileBusy, onQuery: querySalesFiles, onBulkReconcile: reconcileGeneratedFilesAfterBulk, onBulkBusyChange: setSalesFileBulkBusy, onBulkViewActiveChange: setGeneratedFilesBulkViewActive, onAction: executeSalesFileAction, onOpenSalesOrder: selectSalesFileOrder, onDownload: file => executeAction('download_sales_file', { id: file.id }).then(() => undefined), onEdit: async (file) => setEditingSalesFile(file), onNotify: setToast }), page === 'analytics' && _jsx(AnalyticsPage, { data: data.analytics, committedQuery: analyticsCommittedQuery, detailRefreshKey: analyticsDetailRefreshKey, busy: busy || actionBusy, error: analyticsError, onQuery: queryAnalytics, onDetailQuery: queryAnalyticsDetails, onDetailAction: openAnalyticsDetailAction, onExportXlsx: exportAnalytics }), page === 'settings' && _jsx(SettingsPage, { data: data.settings, busy: busy || actionBusy, externalBulkBusy: settingsRateBulkBusy || settingsRateBulkReconcileBusy, onSave: saveSettings, onRestoreDefault: restoreSettings, onDeleteRate: deleteSettingsRate, onRateQuery: queryMonthlyRates, onBulkReconcile: reconcileSettingsRatesAfterBulk, onBulkBusyChange: setSettingsRateBulkBusy, onBulkViewActiveChange: setSettingsRatesBulkViewActive, onUploadLogo: uploadCompanyLogo, onDiscardLogo: discardCompanyLogo, onNotify: setToast }), !['home', 'controlled-goods', 'sanctioned-companies', 'procurement', 'customer-contract-review', 'sales', 'sales-files', 'analytics', 'settings'].includes(page) && _jsxs("section", { className: "tcw-page-placeholder", "data-page": page, children: [_jsx(InfoNotice, { children: "\u9875\u9762\u57FA\u7840\u7ED3\u6784\u5DF2\u5C31\u7EEA\uFF0C\u4E1A\u52A1\u5185\u5BB9\u5C06\u5728\u5BF9\u5E94\u9875\u9762\u6A21\u5757\u4E2D\u52A0\u8F7D\u3002" }), _jsx("div", { className: "tcw-placeholder-body", "aria-label": `${meta.title}页面内容` })] })] }), _jsx(LoadingBlocker, { visible: busy || actionBusy || customerContractBulkBusy, label: actionBusy || customerContractBulkBusy ? '操作处理中' : '数据加载中' }), _jsx(ToastStack, { items: toasts, onClose: closeToast }), editingSalesFile && _jsx(SalesFileEditor, { file: editingSalesFile, runMutation: runMutation, onNotify: setToast, onClose: () => setEditingSalesFile(null), onSaved: () => {
|
|
1297
1323
|
setEditingSalesFile(null);
|
|
1298
1324
|
if (page === 'analytics') {
|
|
1299
1325
|
setAnalyticsDetailRefreshKey(current => current + 1);
|
|
@@ -1484,9 +1510,6 @@ function actionResponseError(result, fallback) {
|
|
|
1484
1510
|
function asRecord(value) {
|
|
1485
1511
|
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
1486
1512
|
}
|
|
1487
|
-
function stringArray(value) {
|
|
1488
|
-
return Array.isArray(value) ? value.filter((item) => typeof item === 'string' && Boolean(item.trim())) : [];
|
|
1489
|
-
}
|
|
1490
1513
|
function summaryRequestParameters(value) {
|
|
1491
1514
|
const parameters = { ...asRecord(value) };
|
|
1492
1515
|
delete parameters.collection;
|
|
@@ -1627,7 +1650,7 @@ async function ensureExcelEditorRuntime() {
|
|
|
1627
1650
|
});
|
|
1628
1651
|
return excelEditorRuntimePromise;
|
|
1629
1652
|
}
|
|
1630
|
-
function SalesFileEditor({ file, onClose, onSaved, onNotify }) {
|
|
1653
|
+
function SalesFileEditor({ file, runMutation, onClose, onSaved, onNotify }) {
|
|
1631
1654
|
const containerRef = React.useRef(null);
|
|
1632
1655
|
const editorRef = React.useRef(null);
|
|
1633
1656
|
const [error, setError] = React.useState('');
|
|
@@ -1649,9 +1672,11 @@ function SalesFileEditor({ file, onClose, onSaved, onNotify }) {
|
|
|
1649
1672
|
if (cancelled || !container)
|
|
1650
1673
|
return;
|
|
1651
1674
|
const editor = await runtime.open({ container, base64: payload.base64, onSave: async (base64) => {
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1675
|
+
await runMutation(async () => {
|
|
1676
|
+
const saved = asActionResult(unwrapResponse(await bridge.executeAction('save_edited_sales_file', { id: file.id, base64, editVersion: payload.editVersion, expectedStorageFileId: payload.storageFileId })));
|
|
1677
|
+
if (saved.success === false)
|
|
1678
|
+
throw new Error(resolveActionMessage(saved) || '工作簿保存失败');
|
|
1679
|
+
});
|
|
1655
1680
|
} });
|
|
1656
1681
|
if (cancelled)
|
|
1657
1682
|
editor.dispose();
|
|
@@ -1666,7 +1691,7 @@ function SalesFileEditor({ file, onClose, onSaved, onNotify }) {
|
|
|
1666
1691
|
}
|
|
1667
1692
|
})();
|
|
1668
1693
|
return () => { cancelled = true; editorRef.current?.dispose(); editorRef.current = null; };
|
|
1669
|
-
}, [file.id]);
|
|
1694
|
+
}, [file.id, runMutation]);
|
|
1670
1695
|
const save = async () => { if (!editorRef.current)
|
|
1671
1696
|
return; setSaving(true); try {
|
|
1672
1697
|
await editorRef.current.save();
|