@chenchaolong/plugin-trade-compliance-workbench 1.0.25 → 1.0.27
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/dist/lib/remote-components/trade-compliance-workbench/app.css +1 -1
- package/dist/lib/remote-components/trade-compliance-workbench/app.js +5 -5
- package/dist/lib/remote-ui/action-execution.d.ts +5 -2
- package/dist/lib/remote-ui/action-execution.d.ts.map +1 -1
- package/dist/lib/remote-ui/action-execution.js +2 -2
- package/dist/lib/remote-ui/action-execution.js.map +1 -1
- package/dist/lib/remote-ui/app-source.d.ts.map +1 -1
- package/dist/lib/remote-ui/app-source.js +122 -28
- package/dist/lib/remote-ui/app-source.js.map +1 -1
- package/dist/lib/remote-ui/bulk-delete.d.ts +56 -0
- package/dist/lib/remote-ui/bulk-delete.d.ts.map +1 -0
- package/dist/lib/remote-ui/bulk-delete.js +138 -0
- package/dist/lib/remote-ui/bulk-delete.js.map +1 -0
- package/dist/lib/remote-ui/components/bulk-delete.d.ts +21 -0
- package/dist/lib/remote-ui/components/bulk-delete.d.ts.map +1 -0
- package/dist/lib/remote-ui/components/bulk-delete.js +9 -0
- package/dist/lib/remote-ui/components/bulk-delete.js.map +1 -0
- package/dist/lib/remote-ui/components/data-grid.d.ts +12 -1
- package/dist/lib/remote-ui/components/data-grid.d.ts.map +1 -1
- package/dist/lib/remote-ui/components/data-grid.js +24 -5
- package/dist/lib/remote-ui/components/data-grid.js.map +1 -1
- package/dist/lib/remote-ui/components/task-status.d.ts +10 -1
- package/dist/lib/remote-ui/components/task-status.d.ts.map +1 -1
- package/dist/lib/remote-ui/components/task-status.js +79 -10
- package/dist/lib/remote-ui/components/task-status.js.map +1 -1
- package/dist/lib/remote-ui/customer-contract-contracts.d.ts +7 -2
- package/dist/lib/remote-ui/customer-contract-contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/customer-contract-contracts.js.map +1 -1
- package/dist/lib/remote-ui/import-task-status.d.ts.map +1 -1
- package/dist/lib/remote-ui/import-task-status.js +2 -0
- package/dist/lib/remote-ui/import-task-status.js.map +1 -1
- package/dist/lib/remote-ui/model.d.ts +1 -0
- package/dist/lib/remote-ui/model.d.ts.map +1 -1
- package/dist/lib/remote-ui/model.js +3 -0
- package/dist/lib/remote-ui/model.js.map +1 -1
- package/dist/lib/remote-ui/pages/catalogs.d.ts +31 -3
- package/dist/lib/remote-ui/pages/catalogs.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/catalogs.js +119 -9
- package/dist/lib/remote-ui/pages/catalogs.js.map +1 -1
- package/dist/lib/remote-ui/pages/contracts.d.ts +61 -3
- package/dist/lib/remote-ui/pages/contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/contracts.js +203 -9
- package/dist/lib/remote-ui/pages/contracts.js.map +1 -1
- package/dist/lib/remote-ui/pages/files.d.ts +52 -10
- package/dist/lib/remote-ui/pages/files.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/files.js +122 -12
- package/dist/lib/remote-ui/pages/files.js.map +1 -1
- package/dist/lib/remote-ui/pages/home.js +4 -4
- package/dist/lib/remote-ui/pages/home.js.map +1 -1
- package/dist/lib/remote-ui/pages/procurement.d.ts +87 -2
- package/dist/lib/remote-ui/pages/procurement.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/procurement.js +225 -21
- package/dist/lib/remote-ui/pages/procurement.js.map +1 -1
- package/dist/lib/remote-ui/pages/settings.css +3 -0
- package/dist/lib/remote-ui/pages/settings.d.ts +39 -6
- package/dist/lib/remote-ui/pages/settings.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/settings.js +98 -5
- package/dist/lib/remote-ui/pages/settings.js.map +1 -1
- package/dist/lib/remote-ui/procurement-contracts.d.ts +6 -2
- package/dist/lib/remote-ui/procurement-contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/procurement-contracts.js +11 -1
- package/dist/lib/remote-ui/procurement-contracts.js.map +1 -1
- package/dist/lib/remote-ui/styles.css +30 -11
- package/package.json +2 -1
|
@@ -13,14 +13,17 @@ type ActionNotificationPolicy = 'silent' | {
|
|
|
13
13
|
tone: 'success';
|
|
14
14
|
fallback: string;
|
|
15
15
|
};
|
|
16
|
+
export type ActionExecutionOptions = {
|
|
17
|
+
suppressRefresh?: boolean;
|
|
18
|
+
};
|
|
16
19
|
export declare const ACTION_NOTIFICATION_POLICIES: Record<WorkbenchActionKey, ActionNotificationPolicy>;
|
|
17
|
-
export declare function executeWorkbenchAction<T>({ actionKey, mutate, refresh, notify, onResult, resolveMessage }: {
|
|
20
|
+
export declare function executeWorkbenchAction<T>({ actionKey, mutate, refresh, notify, onResult, resolveMessage, suppressRefresh }: {
|
|
18
21
|
actionKey: WorkbenchActionKey;
|
|
19
22
|
mutate: () => Promise<ActionResult<T>>;
|
|
20
23
|
refresh: () => void | Promise<void>;
|
|
21
24
|
notify?: Notify;
|
|
22
25
|
onResult?: (result: ActionResult<T>) => void;
|
|
23
26
|
resolveMessage?: (result: ActionResult<T>) => string;
|
|
24
|
-
}): Promise<ActionResult<T>>;
|
|
27
|
+
} & ActionExecutionOptions): Promise<ActionResult<T>>;
|
|
25
28
|
export {};
|
|
26
29
|
//# sourceMappingURL=action-execution.d.ts.map
|
|
@@ -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;
|
|
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,CAsC7F,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"}
|
|
@@ -52,7 +52,7 @@ const refreshActions = new Set([
|
|
|
52
52
|
'update_customer_contract_review',
|
|
53
53
|
'delete_entity'
|
|
54
54
|
]);
|
|
55
|
-
export async function executeWorkbenchAction({ actionKey, mutate, refresh, notify, onResult, resolveMessage = defaultActionMessage }) {
|
|
55
|
+
export async function executeWorkbenchAction({ actionKey, mutate, refresh, notify, onResult, resolveMessage = defaultActionMessage, suppressRefresh }) {
|
|
56
56
|
try {
|
|
57
57
|
if (!isWorkbenchActionKey(actionKey))
|
|
58
58
|
throw new Error(`未配置操作通知策略:${String(actionKey)}`);
|
|
@@ -61,7 +61,7 @@ export async function executeWorkbenchAction({ actionKey, mutate, refresh, notif
|
|
|
61
61
|
if (result.success === false)
|
|
62
62
|
throw new Error(resolveMessage(result) || '操作失败');
|
|
63
63
|
onResult?.(result);
|
|
64
|
-
if (result.refresh && refreshActions.has(actionKey)) {
|
|
64
|
+
if (result.refresh && refreshActions.has(actionKey) && !suppressRefresh) {
|
|
65
65
|
try {
|
|
66
66
|
await refresh();
|
|
67
67
|
}
|
|
@@ -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;
|
|
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;CAC7B,CAAA;AAED,MAAM,cAAc,GAAG,IAAI,GAAG,CAAqB;IACjD,uBAAuB;IACvB,yBAAyB;IACzB,yBAAyB;IACzB,2BAA2B;IAC3B,sBAAsB;IACtB,+BAA+B;IAC/B,iBAAiB;IACjB,uBAAuB;IACvB,mBAAmB;IACnB,sBAAsB;IACtB,iCAAiC;IACjC,eAAe;CAChB,CAAC,CAAA;AAEF,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,oBAAoB,EAAE,eAAe,EAO5H;IACxB,IAAI,CAAC;QACH,IAAI,CAAC,oBAAoB,CAAC,SAAS,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,aAAa,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;QACvF,MAAM,MAAM,GAAG,4BAA4B,CAAC,SAAS,CAAC,CAAA;QACtD,MAAM,MAAM,GAAG,MAAM,MAAM,EAAE,CAAA;QAC7B,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,CAAA;QAC/E,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAA;QAClB,IAAI,MAAM,CAAC,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YACxE,IAAI,CAAC;gBAAC,MAAM,OAAO,EAAE,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;YAAC,CAAC;QAClF,CAAC;QACD,IAAI,MAAM,KAAK,QAAQ;YAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,cAAc,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;QAC5G,OAAO,MAAM,CAAA;IACf,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,4BAA4B,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QACpG,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,QAAQ;YAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;QACtI,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,MAAoB;IAChD,OAAO,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,EAAE,CAAA;AACtD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-source.d.ts","sourceRoot":"","sources":["../../../src/lib/remote-ui/app-source.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app-source.d.ts","sourceRoot":"","sources":["../../../src/lib/remote-ui/app-source.tsx"],"names":[],"mappings":"AA+BA,OAAO,cAAc,CAAA"}
|
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
|
3
3
|
import { createRoot } from 'react-dom/client';
|
|
4
4
|
import { createRemoteBridge } from './bridge.js';
|
|
5
5
|
import { resolvePaginationPageSize } from './contracts.js';
|
|
6
|
-
import { clampPageAfterSingleDeletion, createBlobUrlOwner, createKeyedLatestRequestGate, createLatestCommittedRequest, createLatestRequestGate, generatedFileHistoryKey, normalizeWorkbenchData, routeDataRequest, runKeyedLatestRequest, unwrapResponse } from './model.js';
|
|
6
|
+
import { clampPageAfterSingleDeletion, createBlobUrlOwner, createKeyedLatestRequestGate, createLatestCommittedRequest, createLatestRequestGate, generatedFileHistoryKey, isCurrentSettingsRouteRevision, normalizeWorkbenchData, routeDataRequest, runKeyedLatestRequest, unwrapResponse } from './model.js';
|
|
7
7
|
import { encodeViewFilters } from '../view-parameters.js';
|
|
8
8
|
import { InfoNotice } from './components/data-grid.js';
|
|
9
9
|
import { LoadingBlocker, ToastStack } from './components/forms.js';
|
|
@@ -13,8 +13,9 @@ import { buildBreadcrumbs, WorkbenchShell } from './components/layout.js';
|
|
|
13
13
|
import { CatalogCommands, CatalogImportError, ControlledGoodsPage, findActiveCatalogImportTasks, findLatestFailedCatalogImportTask, runCatalogImportOrchestration, SanctionedCompaniesPage } from './pages/catalogs.js';
|
|
14
14
|
import { HomePage } from './pages/home.js';
|
|
15
15
|
import { ProcurementPage } from './pages/procurement.js';
|
|
16
|
+
import { procurementRouteForQuery } from './procurement-contracts.js';
|
|
16
17
|
import { adaptPurchaseReview } from './purchase-review-adapter.js';
|
|
17
|
-
import { CustomerContractsPage, adaptCustomerContractReview } from './pages/contracts.js';
|
|
18
|
+
import { CustomerContractsPage, adaptCustomerContractReview, createCustomerContractQueryCancelCoordinator, customerContractRouteEntryQuery, reconcileLatestCustomerContractQuery } from './pages/contracts.js';
|
|
18
19
|
import { SalesPage } from './pages/sales.js';
|
|
19
20
|
import { SalesFilesPage } from './pages/files.js';
|
|
20
21
|
import { AnalyticsPage, AnalyticsPrototypeBoard } from './pages/analytics.js';
|
|
@@ -23,6 +24,7 @@ import { ContractImportError, findRecoverableContractImport, findResumableContra
|
|
|
23
24
|
import { createTaskChatSynchronizer, importTaskFromStart, importTaskProgressPercent, isLocalUploadPlaceholder, mergeImportTaskItems, removeImportTaskItem } from './import-task-status.js';
|
|
24
25
|
import { compareTaskBusinessOrder, createPendingResultQueue, createPollingTaskTracker, isAbortError, isPollingObservationTimeout, submitAndRefreshTaskState } from './polling.js';
|
|
25
26
|
import { ACTION_NOTIFICATION_POLICIES, executeWorkbenchAction } from './action-execution.js';
|
|
27
|
+
import { createDeferredBulkReconcileCoordinator, runBulkDelete } from './bulk-delete.js';
|
|
26
28
|
import './styles.css';
|
|
27
29
|
const pageMeta = {
|
|
28
30
|
home: { title: '首页', subtitle: '查看系统风险操作提示与外贸合规业务流程。' },
|
|
@@ -60,6 +62,7 @@ let excelEditorRuntimePromise = null;
|
|
|
60
62
|
function App() {
|
|
61
63
|
const [route, setRoute] = React.useState({ type: 'page', page: 'home' });
|
|
62
64
|
const routeRef = React.useRef(route);
|
|
65
|
+
const routeRevisionRef = React.useRef(0);
|
|
63
66
|
const contextRef = React.useRef(null);
|
|
64
67
|
const requestGateRef = React.useRef(createLatestRequestGate());
|
|
65
68
|
const taskStateRequestGateRef = React.useRef(createLatestRequestGate());
|
|
@@ -68,7 +71,15 @@ function App() {
|
|
|
68
71
|
const settingsRatesRequestGateRef = React.useRef(createLatestRequestGate());
|
|
69
72
|
const generatedFilesRequestGateRef = React.useRef(createKeyedLatestRequestGate());
|
|
70
73
|
const activeGeneratedFilesKeyRef = React.useRef(null);
|
|
74
|
+
const latestGeneratedFilesQueryRef = React.useRef({ page: 1, pageSize: 20, filters: {} });
|
|
75
|
+
const generatedFilesBulkViewActiveRef = React.useRef(false);
|
|
76
|
+
const generatedFilesBulkReconcileRef = React.useRef(createDeferredBulkReconcileCoordinator());
|
|
77
|
+
const latestCustomerContractQueryRef = React.useRef({ page: 1, pageSize: 20, filters: {} });
|
|
78
|
+
const customerContractQueryCancelCoordinatorRef = React.useRef(createCustomerContractQueryCancelCoordinator());
|
|
71
79
|
const settingsRatesQueryRef = React.useRef({ page: 1, pageSize: 20 });
|
|
80
|
+
const latestSettingsRatesQueryRef = React.useRef({ page: 1, pageSize: 20 });
|
|
81
|
+
const settingsRatesBulkViewActiveRef = React.useRef(false);
|
|
82
|
+
const settingsRatesBulkReconcileRef = React.useRef(createDeferredBulkReconcileCoordinator());
|
|
72
83
|
const analyticsRequestsRef = React.useRef(createLatestCommittedRequest(initialAnalyticsQuery));
|
|
73
84
|
const [analyticsCommittedQuery, setAnalyticsCommittedQuery] = React.useState(initialAnalyticsQuery);
|
|
74
85
|
const analyticsPrototypeListenerCleanupRef = React.useRef(null);
|
|
@@ -80,6 +91,11 @@ function App() {
|
|
|
80
91
|
const deletedImportTaskIdsRef = React.useRef(new Set());
|
|
81
92
|
const [busy, setBusy] = React.useState(false);
|
|
82
93
|
const [actionBusy, setActionBusy] = React.useState(false);
|
|
94
|
+
const [customerContractBulkBusy, setCustomerContractBulkBusy] = React.useState(false);
|
|
95
|
+
const [salesFileBulkBusy, setSalesFileBulkBusy] = React.useState(false);
|
|
96
|
+
const [settingsRateBulkBusy, setSettingsRateBulkBusy] = React.useState(false);
|
|
97
|
+
const [salesFileBulkReconcileBusy, setSalesFileBulkReconcileBusy] = React.useState(false);
|
|
98
|
+
const [settingsRateBulkReconcileBusy, setSettingsRateBulkReconcileBusy] = React.useState(false);
|
|
83
99
|
const [catalogCommand, setCatalogCommand] = React.useState(null);
|
|
84
100
|
const [importCompletions, setImportCompletions] = React.useState({ CONTROLLED_CATALOG: null, SANCTION_CATALOG: null });
|
|
85
101
|
const [importFailures, setImportFailures] = React.useState({ CONTROLLED_CATALOG: null, SANCTION_CATALOG: null });
|
|
@@ -208,7 +224,7 @@ function App() {
|
|
|
208
224
|
const requestedPageSize = resolvePaginationPageSize(pageSize);
|
|
209
225
|
const request = routeDataRequest(targetRoute, page, requestedPageSize, filters);
|
|
210
226
|
if (!request)
|
|
211
|
-
return;
|
|
227
|
+
return false;
|
|
212
228
|
const collection = String(asRecord(request.parameters).collection);
|
|
213
229
|
const requests = collection === 'analytics' ? analyticsRequestsRef.current : routeRequestGateRef.current;
|
|
214
230
|
const analyticsCandidate = collection === 'analytics' ? analyticsQueryFromRoute(page, requestedPageSize, filters) : null;
|
|
@@ -217,16 +233,18 @@ function App() {
|
|
|
217
233
|
try {
|
|
218
234
|
const payload = asRecord(unwrapResponse(await bridge.requestData(request)));
|
|
219
235
|
if (!requests.commit(requestId))
|
|
220
|
-
return;
|
|
236
|
+
return false;
|
|
221
237
|
if (routeRef.current !== targetRoute && JSON.stringify(routeRef.current) !== JSON.stringify(targetRoute))
|
|
222
|
-
return;
|
|
238
|
+
return false;
|
|
223
239
|
if (collection === 'analytics') {
|
|
224
240
|
setAnalyticsCommittedQuery(analyticsRequestsRef.current.committed());
|
|
225
241
|
setData(current => ({ ...current, analytics: normalizeWorkbenchData({ summary: { analytics: payload } }).analytics }));
|
|
226
242
|
}
|
|
227
243
|
else if (collection === 'settings') {
|
|
228
244
|
const settings = normalizeWorkbenchData({ summary: { settings: payload } }).settings;
|
|
229
|
-
|
|
245
|
+
const committedRatesQuery = { page: settings.rates.page, pageSize: settings.rates.pageSize };
|
|
246
|
+
settingsRatesQueryRef.current = committedRatesQuery;
|
|
247
|
+
latestSettingsRatesQueryRef.current = committedRatesQuery;
|
|
230
248
|
setData(current => ({ ...current, settings }));
|
|
231
249
|
}
|
|
232
250
|
else
|
|
@@ -244,6 +262,7 @@ function App() {
|
|
|
244
262
|
order: payload.order && typeof payload.order === 'object' ? payload.order : null,
|
|
245
263
|
metrics: payload.metrics && typeof payload.metrics === 'object' ? payload.metrics : targetRoute.level === 'orders' ? null : current.metrics
|
|
246
264
|
}));
|
|
265
|
+
return true;
|
|
247
266
|
}
|
|
248
267
|
catch (error) {
|
|
249
268
|
if (requests.isLatest(requestId)) {
|
|
@@ -251,6 +270,7 @@ function App() {
|
|
|
251
270
|
setAnalyticsCommittedQuery({ ...analyticsRequestsRef.current.committed() });
|
|
252
271
|
setToast({ message: error instanceof Error ? `页面加载失败:${error.message}` : '页面加载失败', tone: 'error' });
|
|
253
272
|
}
|
|
273
|
+
return false;
|
|
254
274
|
}
|
|
255
275
|
finally {
|
|
256
276
|
requests.finish(requestId);
|
|
@@ -387,7 +407,7 @@ function App() {
|
|
|
387
407
|
React.useEffect(() => {
|
|
388
408
|
toastTimers.sync(toasts);
|
|
389
409
|
}, [toastTimers, toasts]);
|
|
390
|
-
const executeAction = React.useCallback(async (actionKey, input) => {
|
|
410
|
+
const executeAction = React.useCallback(async (actionKey, input, options = {}) => {
|
|
391
411
|
const blocksPage = ACTION_NOTIFICATION_POLICIES[actionKey] !== 'silent';
|
|
392
412
|
if (blocksPage)
|
|
393
413
|
setActionBusy(true);
|
|
@@ -399,7 +419,8 @@ function App() {
|
|
|
399
419
|
notify: setToast,
|
|
400
420
|
resolveMessage: resolveActionMessage,
|
|
401
421
|
onResult: result => { if (actionKey === 'download_import_issues' || actionKey === 'download_sales_file')
|
|
402
|
-
downloadActionFile(result.data); }
|
|
422
|
+
downloadActionFile(result.data); },
|
|
423
|
+
...options
|
|
403
424
|
});
|
|
404
425
|
}
|
|
405
426
|
finally {
|
|
@@ -407,7 +428,7 @@ function App() {
|
|
|
407
428
|
setActionBusy(false);
|
|
408
429
|
}
|
|
409
430
|
}, [load]);
|
|
410
|
-
const executeSalesFileAction = React.useCallback((actionKey, input) => executeAction(actionKey, input), [executeAction]);
|
|
431
|
+
const executeSalesFileAction = React.useCallback((actionKey, input, options = {}) => executeAction(actionKey, input, options), [executeAction]);
|
|
411
432
|
const schedulePendingReviewPresentation = React.useCallback(() => {
|
|
412
433
|
if (reviewPresentationTimerRef.current != null)
|
|
413
434
|
return;
|
|
@@ -659,7 +680,7 @@ function App() {
|
|
|
659
680
|
throw error;
|
|
660
681
|
}
|
|
661
682
|
}, [loadTaskState, notifyTaskRecoveryRefreshError]);
|
|
662
|
-
const
|
|
683
|
+
const deleteImportTaskRecord = React.useCallback(async (task, options) => {
|
|
663
684
|
const result = asActionResult(unwrapResponse(await bridge.executeAction('delete_import_task', { taskId: task.id })));
|
|
664
685
|
if (result.success === false)
|
|
665
686
|
throw actionResponseError(result, '任务删除失败');
|
|
@@ -676,8 +697,23 @@ function App() {
|
|
|
676
697
|
clientMessageId: `trade-task:${task.id}:deleted`
|
|
677
698
|
}).catch(() => undefined);
|
|
678
699
|
}
|
|
679
|
-
|
|
700
|
+
if (options.refresh)
|
|
701
|
+
await loadTaskState();
|
|
680
702
|
}, [loadTaskState, removeLocalImportTask]);
|
|
703
|
+
const deleteImportTask = React.useCallback(async (task) => {
|
|
704
|
+
await deleteImportTaskRecord(task, { refresh: true });
|
|
705
|
+
}, [deleteImportTaskRecord]);
|
|
706
|
+
const bulkDeleteImportTasks = React.useCallback(async (items) => {
|
|
707
|
+
const tasksById = new Map(data.importTasks.items.map(task => [task.id, task]));
|
|
708
|
+
const result = await runBulkDelete(items.map(item => item.id), async (id) => {
|
|
709
|
+
const task = tasksById.get(id);
|
|
710
|
+
if (!task)
|
|
711
|
+
throw new Error('任务已不存在');
|
|
712
|
+
await deleteImportTaskRecord(task, { refresh: false });
|
|
713
|
+
});
|
|
714
|
+
await loadTaskState();
|
|
715
|
+
return result.failed.map(failure => ({ id: failure.key, message: failure.message }));
|
|
716
|
+
}, [data.importTasks.items, deleteImportTaskRecord, loadTaskState]);
|
|
681
717
|
const openImportTaskFromStatus = React.useCallback(async (task) => {
|
|
682
718
|
if (task.status === 'FAILED' || task.status === 'TIMED_OUT') {
|
|
683
719
|
if (task.documentType === 'PURCHASE_CONTRACT' || task.documentType === 'CUSTOMER_CONTRACT')
|
|
@@ -906,13 +942,13 @@ function App() {
|
|
|
906
942
|
const maxPage = Math.max(1, Math.ceil(total / requestedPageSize));
|
|
907
943
|
if (query.page > maxPage) {
|
|
908
944
|
if (!gate.isLatest(requestId))
|
|
909
|
-
return;
|
|
945
|
+
return false;
|
|
910
946
|
committedPage = maxPage;
|
|
911
947
|
payload = await requestCatalogPage(maxPage);
|
|
912
948
|
total = numberValue(payload.total, 0);
|
|
913
949
|
}
|
|
914
950
|
if (!gate.isLatest(requestId))
|
|
915
|
-
return;
|
|
951
|
+
return false;
|
|
916
952
|
setData((current) => ({
|
|
917
953
|
...current,
|
|
918
954
|
[collection]: {
|
|
@@ -923,10 +959,12 @@ function App() {
|
|
|
923
959
|
pageSize: requestedPageSize
|
|
924
960
|
}
|
|
925
961
|
}));
|
|
962
|
+
return true;
|
|
926
963
|
}
|
|
927
964
|
catch (error) {
|
|
928
965
|
if (gate.isLatest(requestId))
|
|
929
966
|
setToast({ message: error instanceof Error ? `查询失败:${error.message}` : '查询失败', tone: 'error' });
|
|
967
|
+
return false;
|
|
930
968
|
}
|
|
931
969
|
finally {
|
|
932
970
|
gate.finish(requestId);
|
|
@@ -934,44 +972,69 @@ function App() {
|
|
|
934
972
|
}
|
|
935
973
|
}, []);
|
|
936
974
|
const queryMonthlyRates = React.useCallback(async (query) => {
|
|
975
|
+
latestSettingsRatesQueryRef.current = query;
|
|
937
976
|
const requestedPageSize = resolvePaginationPageSize(query.pageSize);
|
|
938
977
|
const gate = settingsRatesRequestGateRef.current;
|
|
978
|
+
const requestRouteRevision = routeRevisionRef.current;
|
|
939
979
|
const requestId = gate.begin();
|
|
940
980
|
setBusy(true);
|
|
941
981
|
try {
|
|
942
982
|
const payload = asRecord(unwrapResponse(await bridge.requestData({ page: query.page, pageSize: requestedPageSize, parameters: { collection: 'monthlyRates' } })));
|
|
943
983
|
if (!gate.commit(requestId))
|
|
944
|
-
return;
|
|
945
|
-
|
|
984
|
+
return false;
|
|
985
|
+
if (!isCurrentSettingsRouteRevision(requestRouteRevision, routeRevisionRef.current, routeRef.current))
|
|
986
|
+
return false;
|
|
987
|
+
const committedRatesQuery = { page: numberValue(payload.page, query.page), pageSize: requestedPageSize };
|
|
988
|
+
settingsRatesQueryRef.current = committedRatesQuery;
|
|
989
|
+
latestSettingsRatesQueryRef.current = committedRatesQuery;
|
|
946
990
|
setData(current => ({ ...current, settings: normalizeWorkbenchData({ summary: { settings: { ...current.settings, rates: { ...payload, pageSize: requestedPageSize } } } }).settings }));
|
|
991
|
+
return true;
|
|
947
992
|
}
|
|
948
993
|
catch (error) {
|
|
949
994
|
if (gate.isLatest(requestId))
|
|
950
995
|
setToast({ message: error instanceof Error ? `月度汇率加载失败:${error.message}` : '月度汇率加载失败', tone: 'error' });
|
|
996
|
+
return false;
|
|
951
997
|
}
|
|
952
998
|
finally {
|
|
953
999
|
gate.finish(requestId);
|
|
954
1000
|
setBusy(gate.activeCount() + requestGateRef.current.activeCount() + routeRequestGateRef.current.activeCount() > 0);
|
|
955
1001
|
}
|
|
956
1002
|
}, []);
|
|
957
|
-
const queryProcurement = React.useCallback(async (
|
|
958
|
-
|
|
959
|
-
|
|
1003
|
+
const queryProcurement = React.useCallback(async (collection, query) => {
|
|
1004
|
+
const targetRoute = procurementRouteForQuery(collection, query);
|
|
1005
|
+
if (!targetRoute)
|
|
1006
|
+
return false;
|
|
1007
|
+
return await loadRoute(targetRoute, query.page, query.pageSize, query.filters);
|
|
1008
|
+
}, [loadRoute]);
|
|
960
1009
|
const queryCustomerContracts = React.useCallback(async (query) => {
|
|
961
|
-
|
|
1010
|
+
latestCustomerContractQueryRef.current = query;
|
|
1011
|
+
return await loadRoute({ type: 'page', page: 'customer-contract-review' }, query.page, query.pageSize, query.filters);
|
|
962
1012
|
}, [loadRoute]);
|
|
1013
|
+
const rememberCustomerContractQuery = React.useCallback((query) => {
|
|
1014
|
+
latestCustomerContractQueryRef.current = query;
|
|
1015
|
+
}, []);
|
|
1016
|
+
const registerCustomerContractQueryCancel = React.useCallback((cancel) => customerContractQueryCancelCoordinatorRef.current.register(cancel), []);
|
|
1017
|
+
const reconcileCustomerContractsAfterBulk = React.useCallback(() => {
|
|
1018
|
+
const isActive = routeRef.current.type === 'page' && routeRef.current.page === 'customer-contract-review';
|
|
1019
|
+
if (isActive)
|
|
1020
|
+
customerContractQueryCancelCoordinatorRef.current.cancelCurrent();
|
|
1021
|
+
return reconcileLatestCustomerContractQuery({
|
|
1022
|
+
isActive: () => isActive,
|
|
1023
|
+
latestQuery: () => latestCustomerContractQueryRef.current,
|
|
1024
|
+
query: queryCustomerContracts
|
|
1025
|
+
});
|
|
1026
|
+
}, [queryCustomerContracts]);
|
|
963
1027
|
const querySales = React.useCallback(async (_collection, query) => {
|
|
964
1028
|
await loadRoute(routeRef.current, query.page, query.pageSize, query.filters);
|
|
965
1029
|
}, [loadRoute]);
|
|
966
1030
|
const querySalesFiles = React.useCallback(async (collection, query) => {
|
|
967
1031
|
const requestedPageSize = resolvePaginationPageSize(query.pageSize);
|
|
968
|
-
if (collection === 'salesFileOrders')
|
|
969
|
-
await loadRoute({ type: 'page', page: 'sales-files' }, query.page, requestedPageSize, query.filters);
|
|
970
|
-
|
|
971
|
-
}
|
|
1032
|
+
if (collection === 'salesFileOrders')
|
|
1033
|
+
return await loadRoute({ type: 'page', page: 'sales-files' }, query.page, requestedPageSize, query.filters);
|
|
1034
|
+
latestGeneratedFilesQueryRef.current = { ...query, pageSize: requestedPageSize };
|
|
972
1035
|
const key = generatedFileHistoryKey(query.parameters);
|
|
973
1036
|
activeGeneratedFilesKeyRef.current = key;
|
|
974
|
-
await runKeyedLatestRequest({
|
|
1037
|
+
return await runKeyedLatestRequest({
|
|
975
1038
|
gate: generatedFilesRequestGateRef.current,
|
|
976
1039
|
key,
|
|
977
1040
|
request: async () => asRecord(unwrapResponse(await bridge.requestData({ page: query.page, pageSize: requestedPageSize, parameters: { collection, ...query.parameters, filters: encodeViewFilters(query.filters) } }))),
|
|
@@ -982,6 +1045,30 @@ function App() {
|
|
|
982
1045
|
onFinish: () => setBusy(generatedFilesRequestGateRef.current.activeCount() + requestGateRef.current.activeCount() + routeRequestGateRef.current.activeCount() + analyticsRequestsRef.current.activeCount() > 0)
|
|
983
1046
|
});
|
|
984
1047
|
}, [loadRoute]);
|
|
1048
|
+
const generatedFilesBulkReconcileOptions = React.useCallback(() => ({
|
|
1049
|
+
isActive: () => routeRef.current.type === 'page' && routeRef.current.page === 'sales-files' && generatedFilesBulkViewActiveRef.current,
|
|
1050
|
+
latestQuery: () => latestGeneratedFilesQueryRef.current,
|
|
1051
|
+
query: (query) => querySalesFiles('generatedFiles', query),
|
|
1052
|
+
onBusyChange: setSalesFileBulkReconcileBusy
|
|
1053
|
+
}), [querySalesFiles]);
|
|
1054
|
+
const settingsRatesBulkReconcileOptions = React.useCallback(() => ({
|
|
1055
|
+
isActive: () => routeRef.current.type === 'page' && routeRef.current.page === 'settings' && settingsRatesBulkViewActiveRef.current,
|
|
1056
|
+
latestQuery: () => latestSettingsRatesQueryRef.current,
|
|
1057
|
+
query: queryMonthlyRates,
|
|
1058
|
+
onBusyChange: setSettingsRateBulkReconcileBusy
|
|
1059
|
+
}), [queryMonthlyRates]);
|
|
1060
|
+
const setGeneratedFilesBulkViewActive = React.useCallback((active) => {
|
|
1061
|
+
generatedFilesBulkViewActiveRef.current = active;
|
|
1062
|
+
if (active)
|
|
1063
|
+
void generatedFilesBulkReconcileRef.current.activate(generatedFilesBulkReconcileOptions());
|
|
1064
|
+
}, [generatedFilesBulkReconcileOptions]);
|
|
1065
|
+
const setSettingsRatesBulkViewActive = React.useCallback((active) => {
|
|
1066
|
+
settingsRatesBulkViewActiveRef.current = active;
|
|
1067
|
+
if (active)
|
|
1068
|
+
void settingsRatesBulkReconcileRef.current.activate(settingsRatesBulkReconcileOptions());
|
|
1069
|
+
}, [settingsRatesBulkReconcileOptions]);
|
|
1070
|
+
const reconcileGeneratedFilesAfterBulk = React.useCallback(() => generatedFilesBulkReconcileRef.current.reconcile(generatedFilesBulkReconcileOptions()), [generatedFilesBulkReconcileOptions]);
|
|
1071
|
+
const reconcileSettingsRatesAfterBulk = React.useCallback(() => settingsRatesBulkReconcileRef.current.reconcile(settingsRatesBulkReconcileOptions()), [settingsRatesBulkReconcileOptions]);
|
|
985
1072
|
const queryAnalytics = React.useCallback(async (query) => {
|
|
986
1073
|
const requestedQuery = { ...query, pageSize: resolvePaginationPageSize(query.pageSize) };
|
|
987
1074
|
const requests = analyticsRequestsRef.current;
|
|
@@ -1041,10 +1128,12 @@ function App() {
|
|
|
1041
1128
|
throw new Error(resolveActionMessage(result) || '恢复系统默认失败');
|
|
1042
1129
|
await loadRoute({ type: 'page', page: 'settings' }, settingsRatesQueryRef.current.page, settingsRatesQueryRef.current.pageSize);
|
|
1043
1130
|
}, [loadRoute]);
|
|
1044
|
-
const deleteSettingsRate = React.useCallback(async (request) => {
|
|
1131
|
+
const deleteSettingsRate = React.useCallback(async (request, options = {}) => {
|
|
1045
1132
|
const result = asActionResult(unwrapResponse(await bridge.executeAction('delete_settings_rate', request)));
|
|
1046
1133
|
if (result.success === false)
|
|
1047
1134
|
throw new Error(resolveActionMessage(result) || '月度汇率删除失败');
|
|
1135
|
+
if (options.suppressRefresh)
|
|
1136
|
+
return;
|
|
1048
1137
|
const { page, pageSize } = settingsRatesQueryRef.current;
|
|
1049
1138
|
const clampedPage = clampPageAfterSingleDeletion(page, pageSize, data.settings.rates.total);
|
|
1050
1139
|
await loadRoute({ type: 'page', page: 'settings' }, clampedPage, pageSize);
|
|
@@ -1080,6 +1169,11 @@ function App() {
|
|
|
1080
1169
|
setActiveSalesFileOrder(order);
|
|
1081
1170
|
}, []);
|
|
1082
1171
|
const changeRoute = React.useCallback((nextRoute) => {
|
|
1172
|
+
routeRevisionRef.current += 1;
|
|
1173
|
+
settingsRatesRequestGateRef.current.invalidate();
|
|
1174
|
+
latestCustomerContractQueryRef.current = customerContractRouteEntryQuery(nextRoute) ?? latestCustomerContractQueryRef.current;
|
|
1175
|
+
if (nextRoute.type === 'page' && nextRoute.page === 'settings')
|
|
1176
|
+
latestSettingsRatesQueryRef.current = { page: 1, pageSize: 20 };
|
|
1083
1177
|
routeRef.current = nextRoute;
|
|
1084
1178
|
setRoute(nextRoute);
|
|
1085
1179
|
void loadRoute(nextRoute);
|
|
@@ -1093,11 +1187,11 @@ function App() {
|
|
|
1093
1187
|
? _jsx(ContractUploadCommand, { label: "\u4E0A\u4F20\u91C7\u8D2D\u5408\u540C", busy: busy || actionBusy, onFile: file => executeFileAction('upload_purchase_contract', file, { documentType: 'PURCHASE_CONTRACT' }), onError: message => setToast({ message, tone: 'error' }) })
|
|
1094
1188
|
: undefined
|
|
1095
1189
|
: page === 'customer-contract-review'
|
|
1096
|
-
? _jsx(ContractUploadCommand, { label: "\u4E0A\u4F20\u5BA2\u6237\u5408\u540C", busy: busy || actionBusy, onFile: file => executeFileAction('upload_customer_contract', file, { documentType: 'CUSTOMER_CONTRACT' }), onError: message => setToast({ message, tone: 'error' }) })
|
|
1190
|
+
? _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' }) })
|
|
1097
1191
|
: undefined;
|
|
1098
1192
|
if (analyticsPrototypeVisible)
|
|
1099
|
-
return (_jsxs(_Fragment, { children: [_jsx(WorkbenchShell, { route: route, breadcrumbs: buildBreadcrumbs(route), title: meta.title, topbarActions: _jsx(TaskStatusMenu, { items: taskStatusItems, busy: busy || actionBusy, onActionError: notifyTaskStatusActionError }), onRouteChange: changeRoute, onRefresh: () => void load(), children: _jsx(AnalyticsPrototypeBoard, { onClose: () => setAnalyticsPrototypeVisible(false) }) }), _jsx(LoadingBlocker, { visible: busy || actionBusy, label: actionBusy ? '操作处理中' : '数据加载中' }), _jsx(ToastStack, { items: toasts, onClose: closeToast })] }));
|
|
1100
|
-
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, 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, importReviewState: customerImportState, onQuery: queryCustomerContracts, onAction: executeAction, onFileAction: executeFileAction, onReanalyze: reanalyzeCustomerContract, onLoadReview: loadCustomerContractReview, onReviewClose: closeCustomerReview, reanalysisState: customerReanalysisState, onRetryImport: retryContractImport, 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, onQuery: querySalesFiles, 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, busy: busy || actionBusy, error: analyticsError, onQuery: queryAnalytics, onExportXlsx: exportAnalytics }), page === 'settings' && _jsx(SettingsPage, { data: data.settings, busy: busy || actionBusy, onSave: saveSettings, onRestoreDefault: restoreSettings, onDeleteRate: deleteSettingsRate, onRateQuery: queryMonthlyRates, 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, label: actionBusy ? '操作处理中' : '数据加载中' }), _jsx(ToastStack, { items: toasts, onClose: closeToast }), editingSalesFile && _jsx(SalesFileEditor, { file: editingSalesFile, onNotify: setToast, onClose: () => setEditingSalesFile(null), onSaved: () => { setEditingSalesFile(null); if (activeSalesFileOrder)
|
|
1193
|
+
return (_jsxs(_Fragment, { children: [_jsx(WorkbenchShell, { route: route, breadcrumbs: buildBreadcrumbs(route), title: meta.title, topbarActions: _jsx(TaskStatusMenu, { items: taskStatusItems, busy: busy || actionBusy, onBulkDelete: bulkDeleteImportTasks, onActionError: notifyTaskStatusActionError }), onRouteChange: changeRoute, onRefresh: () => void load(), children: _jsx(AnalyticsPrototypeBoard, { onClose: () => setAnalyticsPrototypeVisible(false) }) }), _jsx(LoadingBlocker, { visible: busy || actionBusy || customerContractBulkBusy, label: actionBusy || customerContractBulkBusy ? '操作处理中' : '数据加载中' }), _jsx(ToastStack, { items: toasts, onClose: closeToast })] }));
|
|
1194
|
+
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, busy: busy || actionBusy, error: analyticsError, onQuery: queryAnalytics, 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: () => { setEditingSalesFile(null); if (activeSalesFileOrder)
|
|
1101
1195
|
void querySalesFiles('generatedFiles', { page: 1, pageSize: 20, filters: {}, parameters: { customerContractId: activeSalesFileOrder.customerContractId, purchaseOrderId: activeSalesFileOrder.purchaseOrderId } }); } })] }));
|
|
1102
1196
|
}
|
|
1103
1197
|
function routePage(route) {
|