@chenchaolong/plugin-trade-compliance-workbench 1.0.149 → 1.0.151
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.js +7 -7
- package/dist/lib/remote-ui/app-source.js +43 -23
- package/dist/lib/remote-ui/app-source.js.map +1 -1
- package/dist/lib/remote-ui/pages/files.d.ts +2 -7
- package/dist/lib/remote-ui/pages/files.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/files.js +14 -38
- package/dist/lib/remote-ui/pages/files.js.map +1 -1
- package/package.json +23 -24
|
@@ -104,8 +104,6 @@ function App() {
|
|
|
104
104
|
const settingsRatesBulkReconcileRef = React.useRef(createDeferredBulkReconcileCoordinator());
|
|
105
105
|
const analyticsRequestsRef = React.useRef(createLatestCommittedRequest(initialAnalyticsQuery));
|
|
106
106
|
const [analyticsCommittedQuery, setAnalyticsCommittedQuery] = React.useState(initialAnalyticsQuery);
|
|
107
|
-
const salesFilesPrototypeListenerCleanupRef = React.useRef(null);
|
|
108
|
-
const [salesFilesPrototypeState, setSalesFilesPrototypeState] = React.useState(undefined);
|
|
109
107
|
const [data, setData] = React.useState(() => normalizeWorkbenchData(null));
|
|
110
108
|
const importTaskItemsRef = React.useRef([]);
|
|
111
109
|
const deletedImportTaskIdsRef = React.useRef(new Set());
|
|
@@ -153,6 +151,8 @@ function App() {
|
|
|
153
151
|
}
|
|
154
152
|
});
|
|
155
153
|
const changeRouteRef = React.useRef(() => undefined);
|
|
154
|
+
const taskStateRefreshInFlightRef = React.useRef(null);
|
|
155
|
+
const taskStateRefreshQueuedRef = React.useRef(false);
|
|
156
156
|
const [procurementContext, setProcurementContext] = React.useState({ supplier: null, order: null, metrics: null });
|
|
157
157
|
const [purchaseImportTask, setPurchaseImportTask] = React.useState(null);
|
|
158
158
|
const [purchaseReviewDraft, setPurchaseReviewDraft] = React.useState(null);
|
|
@@ -280,20 +280,22 @@ function App() {
|
|
|
280
280
|
return normalized.importTasks;
|
|
281
281
|
}
|
|
282
282
|
}, []);
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
const
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
283
|
+
const pruneTaskTrackingState = React.useCallback((tasks) => {
|
|
284
|
+
const currentTaskIds = new Set(tasks.map(task => task.id));
|
|
285
|
+
for (const taskId of handledContractTasksRef.current) {
|
|
286
|
+
if (!currentTaskIds.has(taskId))
|
|
287
|
+
handledContractTasksRef.current.delete(taskId);
|
|
288
|
+
}
|
|
289
|
+
const currentRevisions = new Set();
|
|
290
|
+
for (const task of tasks) {
|
|
291
|
+
const revision = taskBusinessRefreshRevision(task);
|
|
292
|
+
if (revision)
|
|
293
|
+
currentRevisions.add(revision);
|
|
294
|
+
}
|
|
295
|
+
for (const revision of refreshedTaskBusinessRevisionsRef.current) {
|
|
296
|
+
if (!currentRevisions.has(revision))
|
|
297
|
+
refreshedTaskBusinessRevisionsRef.current.delete(revision);
|
|
298
|
+
}
|
|
297
299
|
}, []);
|
|
298
300
|
const loadRoute = React.useCallback(async (targetRoute, page = 1, pageSize = 20, filters = {}) => {
|
|
299
301
|
const requestedPageSize = resolvePaginationPageSize(pageSize);
|
|
@@ -378,7 +380,7 @@ function App() {
|
|
|
378
380
|
setBusy(gate.activeCount() + routeRequestGateRef.current.activeCount() + analyticsRequestsRef.current.activeCount() > 0);
|
|
379
381
|
}
|
|
380
382
|
}, [loadImportTasksFallback, loadRoute]);
|
|
381
|
-
const
|
|
383
|
+
const loadTaskStateCore = React.useCallback(async () => {
|
|
382
384
|
const active = contextRef.current;
|
|
383
385
|
if (!active)
|
|
384
386
|
return false;
|
|
@@ -414,6 +416,21 @@ function App() {
|
|
|
414
416
|
gate.finish(requestId);
|
|
415
417
|
}
|
|
416
418
|
}, [loadImportTasksFallback]);
|
|
419
|
+
const loadTaskState = React.useCallback(async () => {
|
|
420
|
+
if (taskStateRefreshInFlightRef.current) {
|
|
421
|
+
taskStateRefreshQueuedRef.current = true;
|
|
422
|
+
return taskStateRefreshInFlightRef.current;
|
|
423
|
+
}
|
|
424
|
+
const run = loadTaskStateCore();
|
|
425
|
+
taskStateRefreshInFlightRef.current = run;
|
|
426
|
+
return run.finally(() => {
|
|
427
|
+
taskStateRefreshInFlightRef.current = null;
|
|
428
|
+
if (!taskStateRefreshQueuedRef.current)
|
|
429
|
+
return;
|
|
430
|
+
taskStateRefreshQueuedRef.current = false;
|
|
431
|
+
void loadTaskState();
|
|
432
|
+
});
|
|
433
|
+
}, [loadTaskStateCore]);
|
|
417
434
|
const scheduleTaskStateRecovery = React.useCallback(() => {
|
|
418
435
|
if (taskRecoveryTimerRef.current != null)
|
|
419
436
|
return;
|
|
@@ -430,7 +447,8 @@ function App() {
|
|
|
430
447
|
}, [loadTaskState]);
|
|
431
448
|
React.useEffect(() => {
|
|
432
449
|
importTaskItemsRef.current = data.importTasks.items;
|
|
433
|
-
|
|
450
|
+
pruneTaskTrackingState(data.importTasks.items);
|
|
451
|
+
}, [data.importTasks.items, pruneTaskTrackingState]);
|
|
434
452
|
React.useEffect(() => {
|
|
435
453
|
void syncSelectedTaskForChat(taskChatSynchronizerRef.current, data.importTasks.items).catch(notifyTaskStatusActionError);
|
|
436
454
|
}, [data.importTasks.items, notifyTaskStatusActionError]);
|
|
@@ -467,7 +485,6 @@ function App() {
|
|
|
467
485
|
React.useEffect(() => {
|
|
468
486
|
bridge.start({
|
|
469
487
|
onInit(nextContext) {
|
|
470
|
-
configureSalesFilesPrototypeCapability(asRecord(nextContext.initialQuery?.parameters));
|
|
471
488
|
contextRef.current = nextContext;
|
|
472
489
|
const normalized = normalizeWorkbenchData(nextContext.payload);
|
|
473
490
|
bridge.configure({ uploadPolicy: normalized.uploadPolicy });
|
|
@@ -477,8 +494,6 @@ function App() {
|
|
|
477
494
|
}
|
|
478
495
|
});
|
|
479
496
|
return () => {
|
|
480
|
-
salesFilesPrototypeListenerCleanupRef.current?.();
|
|
481
|
-
salesFilesPrototypeListenerCleanupRef.current = null;
|
|
482
497
|
blobUrlOwnerRef.current.dispose();
|
|
483
498
|
const previewRuntime = sourcePreviewRuntimePromise;
|
|
484
499
|
sourcePreviewRuntimePromise = null;
|
|
@@ -488,7 +503,7 @@ function App() {
|
|
|
488
503
|
void editorRuntime?.then(runtime => runtime.dispose?.(), () => undefined);
|
|
489
504
|
bridge.destroy();
|
|
490
505
|
};
|
|
491
|
-
}, [
|
|
506
|
+
}, [load]);
|
|
492
507
|
React.useEffect(() => () => toastTimers.dispose(), [toastTimers]);
|
|
493
508
|
React.useEffect(() => {
|
|
494
509
|
const timer = window.setTimeout(() => bridge.reportResize(), 0);
|
|
@@ -938,6 +953,11 @@ function App() {
|
|
|
938
953
|
}
|
|
939
954
|
}, [applyCustomerContractReanalysisResult, consumeCustomerContractReanalysisResult, loadTaskState, runMutation, scheduleTaskStateRecovery]);
|
|
940
955
|
React.useEffect(() => {
|
|
956
|
+
const currentRunIds = new Set(data.customerContractAnalyses.items.map(recovery => recovery.run.id));
|
|
957
|
+
for (const runId of handledReanalysisResultsRef.current) {
|
|
958
|
+
if (!currentRunIds.has(runId))
|
|
959
|
+
handledReanalysisResultsRef.current.delete(runId);
|
|
960
|
+
}
|
|
941
961
|
for (const recovery of data.customerContractAnalyses.items) {
|
|
942
962
|
const recoverable = recovery.recoveryType === 'ACTIVE_POLL' || recovery.recoveryType === 'SUCCEEDED_RESULT';
|
|
943
963
|
if (!recoverable)
|
|
@@ -1478,7 +1498,7 @@ function App() {
|
|
|
1478
1498
|
: page === 'customer-contract-review'
|
|
1479
1499
|
? _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' }) })
|
|
1480
1500
|
: undefined;
|
|
1481
|
-
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'), onClear: page === 'controlled-goods' ? () => setClearControlledCatalogOpen(true) : () => setClearSanctionCatalogOpen(true) }) : 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,
|
|
1501
|
+
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'), onClear: page === 'controlled-goods' ? () => setClearControlledCatalogOpen(true) : () => setClearSanctionCatalogOpen(true) }) : 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, 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, customerOptions: uniqueNames([...data.customers.items, ...data.analytics.dashboard.customerValueTop5, ...data.analytics.dashboard.receivableRiskTop5]), supplierOptions: uniqueNames([...data.suppliers.items, ...data.analytics.dashboard.supplierRiskTop5]), 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, onClearBusinessData: clearBusinessData, 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: () => {
|
|
1482
1502
|
setEditingSalesFile(null);
|
|
1483
1503
|
if (page === 'analytics') {
|
|
1484
1504
|
setAnalyticsDetailRefreshKey(current => current + 1);
|