@chenchaolong/plugin-trade-compliance-workbench 1.0.5 → 1.0.7
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/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/adapters/hsbianma.provider.d.ts +6 -8
- package/dist/lib/adapters/hsbianma.provider.d.ts.map +1 -1
- package/dist/lib/adapters/hsbianma.provider.js +159 -53
- package/dist/lib/adapters/hsbianma.provider.js.map +1 -1
- package/dist/lib/adapters/translation.provider.d.ts +7 -1
- package/dist/lib/adapters/translation.provider.d.ts.map +1 -1
- package/dist/lib/adapters/translation.provider.js +15 -5
- package/dist/lib/adapters/translation.provider.js.map +1 -1
- package/dist/lib/domain/catalog-localization.d.ts +14 -0
- package/dist/lib/domain/catalog-localization.d.ts.map +1 -0
- package/dist/lib/domain/catalog-localization.js +19 -0
- package/dist/lib/domain/catalog-localization.js.map +1 -0
- package/dist/lib/domain/file-name.d.ts +8 -0
- package/dist/lib/domain/file-name.d.ts.map +1 -0
- package/dist/lib/domain/file-name.js +111 -0
- package/dist/lib/domain/file-name.js.map +1 -0
- package/dist/lib/domain/import-issues.d.ts +4 -0
- package/dist/lib/domain/import-issues.d.ts.map +1 -1
- package/dist/lib/domain/import-issues.js +14 -3
- package/dist/lib/domain/import-issues.js.map +1 -1
- package/dist/lib/entities/catalog.entity.d.ts +5 -1
- package/dist/lib/entities/catalog.entity.d.ts.map +1 -1
- package/dist/lib/entities/catalog.entity.js +16 -0
- package/dist/lib/entities/catalog.entity.js.map +1 -1
- package/dist/lib/entities/customer.entity.d.ts +3 -0
- package/dist/lib/entities/customer.entity.d.ts.map +1 -1
- package/dist/lib/entities/customer.entity.js +12 -0
- package/dist/lib/entities/customer.entity.js.map +1 -1
- package/dist/lib/entities/shared.entity.d.ts +9 -0
- package/dist/lib/entities/shared.entity.d.ts.map +1 -1
- package/dist/lib/entities/shared.entity.js +33 -0
- package/dist/lib/entities/shared.entity.js.map +1 -1
- package/dist/lib/import-jobs/agent-handoff.dispatcher.d.ts +15 -0
- package/dist/lib/import-jobs/agent-handoff.dispatcher.d.ts.map +1 -0
- package/dist/lib/import-jobs/agent-handoff.dispatcher.js +114 -0
- package/dist/lib/import-jobs/agent-handoff.dispatcher.js.map +1 -0
- package/dist/lib/import-jobs/contracts.d.ts +76 -0
- package/dist/lib/import-jobs/contracts.d.ts.map +1 -0
- package/dist/lib/import-jobs/contracts.js +31 -0
- package/dist/lib/import-jobs/contracts.js.map +1 -0
- package/dist/lib/import-jobs/import-command.builder.d.ts +30 -0
- package/dist/lib/import-jobs/import-command.builder.d.ts.map +1 -0
- package/dist/lib/import-jobs/import-command.builder.js +97 -0
- package/dist/lib/import-jobs/import-command.builder.js.map +1 -0
- package/dist/lib/import-jobs/import-job-callback.processor.d.ts +15 -0
- package/dist/lib/import-jobs/import-job-callback.processor.d.ts.map +1 -0
- package/dist/lib/import-jobs/import-job-callback.processor.js +107 -0
- package/dist/lib/import-jobs/import-job-callback.processor.js.map +1 -0
- package/dist/lib/import-jobs/import-job.coordinator.d.ts +17 -0
- package/dist/lib/import-jobs/import-job.coordinator.d.ts.map +1 -0
- package/dist/lib/import-jobs/import-job.coordinator.js +256 -0
- package/dist/lib/import-jobs/import-job.coordinator.js.map +1 -0
- package/dist/lib/import-jobs/import-job.processor.d.ts +24 -0
- package/dist/lib/import-jobs/import-job.processor.d.ts.map +1 -0
- package/dist/lib/import-jobs/import-job.processor.js +213 -0
- package/dist/lib/import-jobs/import-job.processor.js.map +1 -0
- package/dist/lib/import-jobs/import-timeout.processor.d.ts +12 -0
- package/dist/lib/import-jobs/import-timeout.processor.d.ts.map +1 -0
- package/dist/lib/import-jobs/import-timeout.processor.js +37 -0
- package/dist/lib/import-jobs/import-timeout.processor.js.map +1 -0
- package/dist/lib/import-jobs/organization-lease.d.ts +39 -0
- package/dist/lib/import-jobs/organization-lease.d.ts.map +1 -0
- package/dist/lib/import-jobs/organization-lease.js +136 -0
- package/dist/lib/import-jobs/organization-lease.js.map +1 -0
- package/dist/lib/plugin-context.token.d.ts +4 -0
- package/dist/lib/plugin-context.token.d.ts.map +1 -0
- package/dist/lib/plugin-context.token.js +2 -0
- package/dist/lib/plugin-context.token.js.map +1 -0
- package/dist/lib/public-dto.d.ts +6 -0
- package/dist/lib/public-dto.d.ts.map +1 -0
- package/dist/lib/public-dto.js +33 -0
- package/dist/lib/public-dto.js.map +1 -0
- 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 +26 -0
- package/dist/lib/remote-ui/action-execution.d.ts.map +1 -0
- package/dist/lib/remote-ui/action-execution.js +85 -0
- package/dist/lib/remote-ui/action-execution.js.map +1 -0
- package/dist/lib/remote-ui/analytics-contracts.d.ts +3 -2
- package/dist/lib/remote-ui/analytics-contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/analytics-contracts.js.map +1 -1
- package/dist/lib/remote-ui/app-source.d.ts.map +1 -1
- package/dist/lib/remote-ui/app-source.js +426 -169
- package/dist/lib/remote-ui/app-source.js.map +1 -1
- package/dist/lib/remote-ui/company-logo-lifecycle.d.ts +14 -0
- package/dist/lib/remote-ui/company-logo-lifecycle.d.ts.map +1 -0
- package/dist/lib/remote-ui/company-logo-lifecycle.js +52 -0
- package/dist/lib/remote-ui/company-logo-lifecycle.js.map +1 -0
- package/dist/lib/remote-ui/components/data-grid.d.ts +9 -4
- package/dist/lib/remote-ui/components/data-grid.d.ts.map +1 -1
- package/dist/lib/remote-ui/components/data-grid.js +41 -9
- package/dist/lib/remote-ui/components/data-grid.js.map +1 -1
- package/dist/lib/remote-ui/components/forms.d.ts +6 -1
- package/dist/lib/remote-ui/components/forms.d.ts.map +1 -1
- package/dist/lib/remote-ui/components/forms.js +6 -1
- 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 +3 -3
- package/dist/lib/remote-ui/components/layout.js.map +1 -1
- package/dist/lib/remote-ui/contract-import.d.ts +37 -32
- package/dist/lib/remote-ui/contract-import.d.ts.map +1 -1
- package/dist/lib/remote-ui/contract-import.js +51 -59
- package/dist/lib/remote-ui/contract-import.js.map +1 -1
- package/dist/lib/remote-ui/contracts.d.ts +20 -27
- package/dist/lib/remote-ui/contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/contracts.js +8 -0
- package/dist/lib/remote-ui/contracts.js.map +1 -1
- package/dist/lib/remote-ui/customer-contract-contracts.d.ts +5 -11
- 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/date-time.d.ts +3 -0
- package/dist/lib/remote-ui/date-time.d.ts.map +1 -0
- package/dist/lib/remote-ui/date-time.js +58 -0
- package/dist/lib/remote-ui/date-time.js.map +1 -0
- package/dist/lib/remote-ui/model.d.ts +26 -1
- package/dist/lib/remote-ui/model.d.ts.map +1 -1
- package/dist/lib/remote-ui/model.js +151 -15
- package/dist/lib/remote-ui/model.js.map +1 -1
- package/dist/lib/remote-ui/pages/analytics.d.ts +2 -0
- package/dist/lib/remote-ui/pages/analytics.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/analytics.js +11 -6
- package/dist/lib/remote-ui/pages/analytics.js.map +1 -1
- package/dist/lib/remote-ui/pages/catalogs.d.ts +37 -14
- package/dist/lib/remote-ui/pages/catalogs.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/catalogs.js +149 -91
- package/dist/lib/remote-ui/pages/catalogs.js.map +1 -1
- package/dist/lib/remote-ui/pages/contracts.d.ts +11 -6
- package/dist/lib/remote-ui/pages/contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/contracts.js +45 -33
- package/dist/lib/remote-ui/pages/contracts.js.map +1 -1
- package/dist/lib/remote-ui/pages/files.d.ts +29 -3
- package/dist/lib/remote-ui/pages/files.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/files.js +60 -16
- 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 +18 -18
- package/dist/lib/remote-ui/pages/home.js.map +1 -1
- package/dist/lib/remote-ui/pages/procurement.d.ts +29 -4
- package/dist/lib/remote-ui/pages/procurement.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/procurement.js +58 -63
- package/dist/lib/remote-ui/pages/procurement.js.map +1 -1
- package/dist/lib/remote-ui/pages/sales.d.ts +47 -1
- package/dist/lib/remote-ui/pages/sales.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/sales.js +60 -20
- package/dist/lib/remote-ui/pages/sales.js.map +1 -1
- package/dist/lib/remote-ui/pages/settings.d.ts +34 -1
- package/dist/lib/remote-ui/pages/settings.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/settings.js +120 -94
- package/dist/lib/remote-ui/pages/settings.js.map +1 -1
- package/dist/lib/remote-ui/polling.d.ts +41 -0
- package/dist/lib/remote-ui/polling.d.ts.map +1 -0
- package/dist/lib/remote-ui/polling.js +148 -0
- package/dist/lib/remote-ui/polling.js.map +1 -0
- package/dist/lib/remote-ui/procurement-contracts.d.ts +4 -9
- package/dist/lib/remote-ui/procurement-contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/sales-contracts.d.ts +2 -2
- package/dist/lib/remote-ui/sales-contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/settings-contracts.d.ts +9 -1
- package/dist/lib/remote-ui/settings-contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/settings-contracts.js.map +1 -1
- package/dist/lib/remote-ui/toast-queue.d.ts +29 -0
- package/dist/lib/remote-ui/toast-queue.d.ts.map +1 -0
- package/dist/lib/remote-ui/toast-queue.js +71 -0
- package/dist/lib/remote-ui/toast-queue.js.map +1 -0
- package/dist/lib/sales-file.service.d.ts.map +1 -1
- package/dist/lib/sales-file.service.js +5 -5
- package/dist/lib/sales-file.service.js.map +1 -1
- package/dist/lib/types.d.ts +5 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +3 -0
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/workbench-action-contract.d.ts +4 -0
- package/dist/lib/workbench-action-contract.d.ts.map +1 -0
- package/dist/lib/workbench-action-contract.js +43 -0
- package/dist/lib/workbench-action-contract.js.map +1 -0
- package/dist/lib/workbench-view.provider.d.ts +57 -78
- package/dist/lib/workbench-view.provider.d.ts.map +1 -1
- package/dist/lib/workbench-view.provider.js +89 -91
- package/dist/lib/workbench-view.provider.js.map +1 -1
- package/dist/lib/workbench.middleware.d.ts +129 -72
- package/dist/lib/workbench.middleware.d.ts.map +1 -1
- package/dist/lib/workbench.middleware.js +16 -3
- package/dist/lib/workbench.middleware.js.map +1 -1
- package/dist/lib/workbench.plugin.d.ts +3 -1
- package/dist/lib/workbench.plugin.d.ts.map +1 -1
- package/dist/lib/workbench.plugin.js +13 -4
- package/dist/lib/workbench.plugin.js.map +1 -1
- package/dist/lib/workbench.service.d.ts +136 -40
- package/dist/lib/workbench.service.d.ts.map +1 -1
- package/dist/lib/workbench.service.js +985 -71
- package/dist/lib/workbench.service.js.map +1 -1
- package/package.json +6 -5
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import type { FilterDefinition, FilterMapping, FilterState, WorkbenchRoute } from '../contracts.js';
|
|
1
|
+
import type { FilterDefinition, FilterMapping, FilterState, PaginationPageSize, WorkbenchRoute } from '../contracts.js';
|
|
2
2
|
import type { ProcurementActionResult, ProcurementDeleteEntityType, ProcurementMetrics, ProcurementPageProps, PurchaseContractReviewDraft, PurchaseOrderLineDraft, PurchaseOrderLineRow, PurchaseOrderRow, SupplierRow } from '../procurement-contracts.js';
|
|
3
|
+
import './procurement-contracts.css';
|
|
3
4
|
export type { ProcurementPageProps } from '../procurement-contracts.js';
|
|
4
5
|
export declare const procurementFilterMappings: {
|
|
5
6
|
suppliers: Record<string, FilterMapping<SupplierRow>>;
|
|
6
7
|
purchaseOrders: Record<string, FilterMapping<PurchaseOrderRow>>;
|
|
7
8
|
purchaseLines: Record<string, FilterMapping<PurchaseOrderLineRow>>;
|
|
8
9
|
};
|
|
9
|
-
export declare function createProcurementQueryScheduler(query: (filters: FilterState) => void, debounceMs?: number): {
|
|
10
|
-
schedule(type: FilterDefinition["type"], filters: FilterState): void;
|
|
11
|
-
flush(filters: FilterState): void;
|
|
10
|
+
export declare function createProcurementQueryScheduler(query: (page: number, filters: FilterState, pageSize: PaginationPageSize) => void, debounceMs?: number): {
|
|
11
|
+
schedule(type: FilterDefinition["type"], filters: FilterState, pageSize?: PaginationPageSize): void;
|
|
12
|
+
flush(filters: FilterState, pageSize?: PaginationPageSize): void;
|
|
13
|
+
page(page: number, filters: FilterState, pageSize?: PaginationPageSize): void;
|
|
14
|
+
pageSize(pageSize: PaginationPageSize, filters: FilterState): void;
|
|
12
15
|
cancel: () => void;
|
|
13
16
|
};
|
|
14
17
|
export declare function createProcurementActionApi({ onAction, onFileAction }: Pick<ProcurementPageProps, 'onAction' | 'onFileAction'>): {
|
|
@@ -33,4 +36,26 @@ export declare function ProcurementContextBar(props: {
|
|
|
33
36
|
order: PurchaseOrderRow;
|
|
34
37
|
onRouteChange: (route: WorkbenchRoute) => void;
|
|
35
38
|
}): import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
export declare function LineDialog({ state, order, busy, onAction, onClose, onSave }: {
|
|
40
|
+
state: {
|
|
41
|
+
mode: 'create' | 'review';
|
|
42
|
+
item: PurchaseOrderLineDraft;
|
|
43
|
+
} | null;
|
|
44
|
+
order: PurchaseOrderRow | null;
|
|
45
|
+
busy: boolean;
|
|
46
|
+
onAction: ProcurementPageProps['onAction'];
|
|
47
|
+
onClose: () => void;
|
|
48
|
+
onSave: (item: PurchaseOrderLineDraft) => Promise<void> | void;
|
|
49
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
50
|
+
type DeleteTarget = {
|
|
51
|
+
entityType: ProcurementDeleteEntityType;
|
|
52
|
+
item: SupplierRow | PurchaseOrderRow | PurchaseOrderLineRow;
|
|
53
|
+
};
|
|
54
|
+
export declare function DeleteDialog({ target, supplier, busy, onCancel, onConfirm }: {
|
|
55
|
+
target: DeleteTarget | null;
|
|
56
|
+
supplier: SupplierRow | null;
|
|
57
|
+
busy: boolean;
|
|
58
|
+
onCancel: () => void;
|
|
59
|
+
onConfirm: () => void;
|
|
60
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
36
61
|
//# sourceMappingURL=procurement.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"procurement.d.ts","sourceRoot":"","sources":["../../../../src/lib/remote-ui/pages/procurement.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoB,gBAAgB,EAAE,aAAa,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"procurement.d.ts","sourceRoot":"","sources":["../../../../src/lib/remote-ui/pages/procurement.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoB,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAe,kBAAkB,EAAmB,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACvK,OAAO,KAAK,EAGV,uBAAuB,EAEvB,2BAA2B,EAC3B,kBAAkB,EAClB,oBAAoB,EACpB,2BAA2B,EAC3B,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EAGhB,WAAW,EACZ,MAAM,6BAA6B,CAAA;AAMpC,OAAO,6BAA6B,CAAA;AAEpC,YAAY,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAkCvE,eAAO,MAAM,yBAAyB,EAAE;IACtC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC,CAAA;IACrD,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAA;IAC/D,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAA;CAwBnE,CAAA;AAED,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,kBAAkB,KAAK,IAAI,EAAE,UAAU,SAAM;mBAIhI,gBAAgB,CAAC,MAAM,CAAC,WAAW,WAAW,aAAY,kBAAkB;mBAK5E,WAAW,aAAY,kBAAkB;eAC7C,MAAM,WAAW,WAAW,aAAY,kBAAkB;uBAClD,kBAAkB,WAAW,WAAW;;EAG9D;AAED,wBAAgB,0BAA0B,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,IAAI,CAAC,oBAAoB,EAAE,UAAU,GAAG,cAAc,CAAC;mCAOrF,IAAI;iCAKZ,MAAM,SAAS,2BAA2B;4BAC/C,WAAW;iCACN,gBAAgB;uCACV,MAAM,SAAS,sBAAsB;gCAC5C,oBAAoB;+BACrB,2BAA2B,MAAM,MAAM;EAErE;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,WAAW,SAAwD,GAAG,kBAAkB,CAqB1L;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,2BAA2B,GAAG,MAAM,EAAE,CA2B3F;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,2CAsD1D;AA2FD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,WAAW,CAAC;IAAC,aAAa,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,gBAAgB,CAAC;IAAC,aAAa,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAA;CAAE,2CAO7P;AAwDD,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;IAAE,KAAK,EAAE;QAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;QAAC,IAAI,EAAE,sBAAsB,CAAA;KAAE,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,oBAAoB,CAAC,UAAU,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAAC,MAAM,EAAE,CAAC,IAAI,EAAE,sBAAsB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CAAE,kDAqC1U;AAiDD,KAAK,YAAY,GAAG;IAAE,UAAU,EAAE,2BAA2B,CAAC;IAAC,IAAI,EAAE,WAAW,GAAG,gBAAgB,GAAG,oBAAoB,CAAA;CAAE,CAAA;AAE5H,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE;IAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,IAAI,CAAA;CAAE,2CAKtM"}
|
|
@@ -3,6 +3,9 @@ import React from 'react';
|
|
|
3
3
|
import { DataGrid, FilterPanel, InfoNotice, RiskNotice } from '../components/data-grid.js';
|
|
4
4
|
import { ConfirmDialog, FieldGrid, FormField, Modal, ReviewSplit } from '../components/forms.js';
|
|
5
5
|
import { HsCodeLookupDialog } from './catalogs.js';
|
|
6
|
+
import { formatBeijingDateTime, formatBusinessDate } from '../date-time.js';
|
|
7
|
+
import { runNotifiedOperation } from '../toast-queue.js';
|
|
8
|
+
import './procurement-contracts.css';
|
|
6
9
|
const PAGE_SIZE = 20;
|
|
7
10
|
const sanctionLabels = { UNCHECKED: '未检查', CLEAR: '无命中', HIT: '命中提醒' };
|
|
8
11
|
const hsStatusLabels = { UNCONFIRMED: '待审核', AI_CONFIRMED: 'AI确认', MANUALLY_CONFIRMED: '人工确认' };
|
|
@@ -21,7 +24,7 @@ const orderFilters = [
|
|
|
21
24
|
{ type: 'amount-range', key: 'contractAmountCny', label: '采购金额', currency: 'CNY' },
|
|
22
25
|
{ type: 'select', key: 'hasUnpaid', label: '未付款', options: booleanOptions() },
|
|
23
26
|
{ type: 'select', key: 'hasUnrefunded', label: '未退税', options: booleanOptions() },
|
|
24
|
-
{ type: 'select', key: 'linkStatus', label: '
|
|
27
|
+
{ type: 'select', key: 'linkStatus', label: '已匹配客户合同', options: [{ value: 'LINKED', label: '已关联' }, { value: 'UNLINKED', label: '未关联' }] }
|
|
25
28
|
];
|
|
26
29
|
const lineFilters = [
|
|
27
30
|
{ type: 'text', key: 'productName', label: '商品名称' },
|
|
@@ -59,15 +62,17 @@ export function createProcurementQueryScheduler(query, debounceMs = 300) {
|
|
|
59
62
|
const cancel = () => { if (timer)
|
|
60
63
|
clearTimeout(timer); timer = null; };
|
|
61
64
|
return {
|
|
62
|
-
schedule(type, filters) {
|
|
65
|
+
schedule(type, filters, pageSize = PAGE_SIZE) {
|
|
63
66
|
cancel();
|
|
64
67
|
if (type !== 'text') {
|
|
65
|
-
query(filters);
|
|
68
|
+
query(1, filters, pageSize);
|
|
66
69
|
return;
|
|
67
70
|
}
|
|
68
|
-
timer = setTimeout(() => { timer = null; query(filters); }, debounceMs);
|
|
71
|
+
timer = setTimeout(() => { timer = null; query(1, filters, pageSize); }, debounceMs);
|
|
69
72
|
},
|
|
70
|
-
flush(filters) { cancel(); query(filters); },
|
|
73
|
+
flush(filters, pageSize = PAGE_SIZE) { cancel(); query(1, filters, pageSize); },
|
|
74
|
+
page(page, filters, pageSize = PAGE_SIZE) { cancel(); query(page, filters, pageSize); },
|
|
75
|
+
pageSize(pageSize, filters) { cancel(); query(1, filters, pageSize); },
|
|
71
76
|
cancel
|
|
72
77
|
};
|
|
73
78
|
}
|
|
@@ -91,7 +96,7 @@ export function createProcurementActionApi({ onAction, onFileAction }) {
|
|
|
91
96
|
deleteEntity: (entityType, id) => mutate('delete_entity', { entityType, id })
|
|
92
97
|
};
|
|
93
98
|
}
|
|
94
|
-
export function buildProcurementMetrics(orders, lines, currentYear = new Date().
|
|
99
|
+
export function buildProcurementMetrics(orders, lines, currentYear = Number(formatBeijingDateTime(new Date()).slice(0, 4))) {
|
|
95
100
|
const currentYearPrefix = `${currentYear}-`;
|
|
96
101
|
const productAmounts = new Map();
|
|
97
102
|
const orderBalances = {};
|
|
@@ -170,37 +175,28 @@ export function ProcurementPage(props) {
|
|
|
170
175
|
const [lineDialog, setLineDialog] = React.useState(null);
|
|
171
176
|
const [deleteTarget, setDeleteTarget] = React.useState(null);
|
|
172
177
|
const [draft, setDraft] = React.useState(props.reviewDraft);
|
|
173
|
-
const [message, setMessage] = React.useState('');
|
|
174
178
|
const closeDraft = React.useCallback(() => { setDraft(null); props.onReviewClose?.(); }, [props.onReviewClose]);
|
|
175
179
|
const api = React.useMemo(() => createProcurementActionApi(props), [props.onAction, props.onFileAction]);
|
|
176
180
|
const collectionKey = routeCollection(props.route);
|
|
177
181
|
const definitions = collectionKey === 'suppliers' ? supplierFilters : collectionKey === 'purchaseOrders' ? orderFilters : lineFilters;
|
|
178
|
-
const
|
|
182
|
+
const currentPageSize = collectionKey === 'suppliers' ? pagination(props.suppliers).pageSize : collectionKey === 'purchaseOrders' ? pagination(props.purchaseOrders).pageSize : pagination(props.purchaseLines).pageSize;
|
|
183
|
+
const query = React.useCallback((page, nextFilters, pageSize) => props.onQuery(collectionKey, {
|
|
179
184
|
page,
|
|
180
|
-
pageSize
|
|
185
|
+
pageSize,
|
|
181
186
|
filters: nextFilters,
|
|
182
187
|
parameters: props.route.level === 'orders' ? { supplierId: props.route.supplierId } : props.route.level === 'lines' ? { supplierId: props.route.supplierId, purchaseOrderId: props.route.orderId } : undefined
|
|
183
188
|
}), [collectionKey, props.onQuery, props.route]);
|
|
184
|
-
const scheduler = React.useMemo(() => createProcurementQueryScheduler((nextFilters) => void query(
|
|
189
|
+
const scheduler = React.useMemo(() => createProcurementQueryScheduler((page, nextFilters, pageSize) => void query(page, nextFilters, pageSize)), [query]);
|
|
185
190
|
React.useEffect(() => () => scheduler.cancel(), [scheduler]);
|
|
186
191
|
React.useEffect(() => { setDraft(props.reviewDraft); }, [props.reviewDraft]);
|
|
187
192
|
const changeFilter = (key, value) => {
|
|
188
193
|
const next = { ...filters, [key]: value };
|
|
189
194
|
setFilters(next);
|
|
190
|
-
scheduler.schedule(definitions.find((item) => item.key === key)?.type ?? 'text', next);
|
|
195
|
+
scheduler.schedule(definitions.find((item) => item.key === key)?.type ?? 'text', next, currentPageSize);
|
|
191
196
|
};
|
|
192
|
-
const reset = () => { setFilters({}); scheduler.flush({}); };
|
|
197
|
+
const reset = () => { setFilters({}); scheduler.flush({}, currentPageSize); };
|
|
193
198
|
const execute = async (operation, success) => {
|
|
194
|
-
|
|
195
|
-
try {
|
|
196
|
-
await operation();
|
|
197
|
-
setMessage(success);
|
|
198
|
-
return true;
|
|
199
|
-
}
|
|
200
|
-
catch (cause) {
|
|
201
|
-
setMessage(errorMessage(cause));
|
|
202
|
-
return false;
|
|
203
|
-
}
|
|
199
|
+
return runNotifiedOperation(async () => { await operation(); }, props.onNotify, { success, error: '采购操作失败' });
|
|
204
200
|
};
|
|
205
201
|
const saveLine = (item) => {
|
|
206
202
|
if (stateIsCreate(lineDialog))
|
|
@@ -210,7 +206,7 @@ export function ProcurementPage(props) {
|
|
|
210
206
|
return api.updatePurchaseLine({ ...item, id: item.id });
|
|
211
207
|
};
|
|
212
208
|
const reviewVisible = Boolean(props.importTask && (draft || props.importTask.duplicateContractError));
|
|
213
|
-
return (_jsxs("section", { className: "tcw-procurement-page", "data-procurement-level": props.route.level, children: [
|
|
209
|
+
return (_jsxs("section", { className: "tcw-procurement-page tcw-procurement-prototype-surface", "data-procurement-level": props.route.level, children: [props.importTask && (props.importTask.status === 'FAILED' || props.importTask.status === 'TIMED_OUT') && _jsxs("div", { className: "tcw-procurement-import-failure", role: "alert", children: [props.importTask.errorMessage || '采购合同解析失败', props.onRetryImport && _jsxs("button", { type: "button", className: "tcw-button tcw-button--secondary", onClick: () => void Promise.resolve(props.onRetryImport?.(props.importTask.id)).catch(() => undefined), children: [_jsx("i", { className: "ri-restart-line", "aria-hidden": "true" }), "\u91CD\u65B0\u89E3\u6790"] })] }), props.route.level === 'suppliers' && _jsx(SupplierLevel, { props: props, filters: filters, definitions: definitions, onFilter: changeFilter, onSubmit: () => scheduler.flush(filters, currentPageSize), onReset: reset, onPage: (page) => scheduler.page(page, filters, currentPageSize), onPageSize: (pageSize) => scheduler.pageSize(pageSize, filters), onSupplierDialog: setSupplierDialog, onDelete: (item) => setDeleteTarget({ entityType: 'supplier', item }) }), props.route.level === 'orders' && _jsx(OrderLevel, { props: props, filters: filters, definitions: definitions, onFilter: changeFilter, onSubmit: () => scheduler.flush(filters, currentPageSize), onReset: reset, onPage: (page) => scheduler.page(page, filters, currentPageSize), onPageSize: (pageSize) => scheduler.pageSize(pageSize, filters), onOrderDialog: setOrderDialog, onDelete: (item) => setDeleteTarget({ entityType: 'purchaseOrder', item }) }), props.route.level === 'lines' && _jsx(LineLevel, { props: props, filters: filters, definitions: definitions, onFilter: changeFilter, onSubmit: () => scheduler.flush(filters, currentPageSize), onReset: reset, onPage: (page) => scheduler.page(page, filters, currentPageSize), onPageSize: (pageSize) => scheduler.pageSize(pageSize, filters), onLineDialog: setLineDialog, onDelete: (item) => setDeleteTarget({ entityType: 'purchaseLine', item }) }), _jsx(SupplierDialog, { state: supplierDialog, busy: props.busy, onClose: () => setSupplierDialog(null), onSave: (item) => execute(() => api.updateSupplier(item), '供应商主档已保存').then((saved) => { if (saved)
|
|
214
210
|
setSupplierDialog(null); }) }), _jsx(OrderDialog, { state: orderDialog, lines: props.purchaseLines.items, busy: props.busy, onClose: () => setOrderDialog(null), onSave: (item) => execute(() => api.updatePurchaseOrder(item), '采购订单已保存').then((saved) => { if (saved)
|
|
215
211
|
setOrderDialog(null); }) }), _jsx(LineDialog, { state: lineDialog, order: props.order ?? null, busy: props.busy, onAction: props.onAction, onClose: () => setLineDialog(null), onSave: (item) => execute(() => saveLine(item), '采购商品已保存').then((saved) => { if (saved)
|
|
216
212
|
setLineDialog(null); }) }), _jsx(PurchaseContractReviewDialog, { open: reviewVisible, task: props.importTask, draft: draft, busy: props.busy, onChange: setDraft, onClose: closeDraft, onSave: (nextDraft) => execute(() => api.savePurchaseReview(props.importTask.id, nextDraft), '采购合同审核已保存').then((saved) => { if (saved)
|
|
@@ -221,66 +217,66 @@ export function ProcurementPage(props) {
|
|
|
221
217
|
setDeleteTarget(null); });
|
|
222
218
|
} })] }));
|
|
223
219
|
}
|
|
224
|
-
function SupplierLevel({ props, filters, definitions, onFilter, onSubmit, onReset, onPage, onSupplierDialog, onDelete }) {
|
|
220
|
+
function SupplierLevel({ props, filters, definitions, onFilter, onSubmit, onReset, onPage, onPageSize, onSupplierDialog, onDelete }) {
|
|
225
221
|
const columns = [
|
|
226
|
-
{ type: 'custom', key: 'code', header: '供应商代码', width: 130, render: (_, row) => _jsx(LinkButton, { icon: "ri-file-list-3-line", onClick: () => row.id && props.onRouteChange({ type: 'procurement', level: 'orders', supplierId: row.id }), children: row.code || '—' }) },
|
|
222
|
+
{ type: 'custom', key: 'code', header: '供应商代码', width: 130, title: (_, row) => row.code || undefined, render: (_, row) => _jsx(LinkButton, { icon: "ri-file-list-3-line", title: row.code || undefined, onClick: () => row.id && props.onRouteChange({ type: 'procurement', level: 'orders', supplierId: row.id }), children: row.code || '—' }) },
|
|
227
223
|
{ type: 'ellipsis', key: 'name', header: '供应商名称', width: 240, maxWidth: 240 },
|
|
228
224
|
{ type: 'text', key: 'shortName', header: '简称', width: 140 },
|
|
229
225
|
{ type: 'text', key: 'contactName', header: '联系人', width: 130 },
|
|
230
226
|
{ type: 'text', key: 'phone', header: '联系电话', width: 160 },
|
|
231
|
-
{ type: '
|
|
232
|
-
{ type: '
|
|
227
|
+
{ type: 'text', key: 'countryOrRegion', header: '国别/地区', width: 120, format: (value) => String(value || '—') },
|
|
228
|
+
{ type: 'custom', key: 'sanctionStatus', header: '制裁风险', width: 110, truncate: false, render: (_, row) => _jsx(StatusTag, { tone: row.sanctionStatus === 'HIT' ? 'danger' : row.sanctionStatus === 'CLEAR' ? 'success' : 'muted', children: sanctionLabels[row.sanctionStatus ?? 'UNCHECKED'] }) },
|
|
229
|
+
{ type: 'text', key: 'createdAt', header: '创建时间', width: 170, truncate: false, format: formatBeijingDateTime }
|
|
233
230
|
];
|
|
234
|
-
return _jsxs(_Fragment, { children: [_jsx(ProcurementLevelHeading, { title: "\u4F9B\u5E94\u5546\u5217\u8868", description: "\u4E00\u7EA7\u9875\u9762\uFF1A\u7BA1\u7406\u4F9B\u5E94\u5546\u4E3B\u6863\uFF0C\u5E76\u901A\u8FC7\u4F9B\u5E94\u5546\u4EE3\u7801\u8FDB\u5165\u8BE5\u4F9B\u5E94\u5546\u7684\u91C7\u8D2D\u8BA2\u5355\u5217\u8868\u3002" }), _jsx(FilterPanel, { definitions: definitions, values: filters, onChange: onFilter, onQuery: onSubmit, onReset: onReset }), _jsx(InfoNotice, { children: "\u91C7\u8D2D\u5408\u540C\u4E0A\u4F20\u540E\u81EA\u52A8\u5F52\u5165\u4F9B\u5E94\u5546\uFF1B\u540C\u540D\u4F9B\u5E94\u5546\u5F52\u5E76\u5230\u540C\u4E00\u4E3B\u6863\u3002\u70B9\u51FB\u4F9B\u5E94\u5546\u4EE3\u7801\u8FDB\u5165\u91C7\u8D2D\u8BA2\u5355\u5217\u8868\u3002" }), _jsx(DataGrid, { columns: columns, rows: props.suppliers.items, rowKey: (row, index) => row.id ?? index, pagination: pagination(props.suppliers), onPageChange: onPage, emptyText: "\u6682\u65E0\u4F9B\u5E94\u5546\u6570\u636E", actionWidth:
|
|
231
|
+
return _jsxs(_Fragment, { children: [_jsx(ProcurementLevelHeading, { title: "\u4F9B\u5E94\u5546\u5217\u8868", description: "\u4E00\u7EA7\u9875\u9762\uFF1A\u7BA1\u7406\u4F9B\u5E94\u5546\u4E3B\u6863\uFF0C\u5E76\u901A\u8FC7\u4F9B\u5E94\u5546\u4EE3\u7801\u8FDB\u5165\u8BE5\u4F9B\u5E94\u5546\u7684\u91C7\u8D2D\u8BA2\u5355\u5217\u8868\u3002" }), _jsx(FilterPanel, { definitions: definitions, values: filters, onChange: onFilter, onQuery: onSubmit, onReset: onReset }), _jsx(InfoNotice, { children: "\u91C7\u8D2D\u5408\u540C\u4E0A\u4F20\u540E\u81EA\u52A8\u5F52\u5165\u4F9B\u5E94\u5546\uFF1B\u540C\u540D\u4F9B\u5E94\u5546\u5F52\u5E76\u5230\u540C\u4E00\u4E3B\u6863\u3002\u70B9\u51FB\u4F9B\u5E94\u5546\u4EE3\u7801\u8FDB\u5165\u91C7\u8D2D\u8BA2\u5355\u5217\u8868\u3002" }), _jsx(DataGrid, { columns: columns, rows: props.suppliers.items, rowKey: (row, index) => row.id ?? index, pagination: pagination(props.suppliers), onPageChange: onPage, onPageSizeChange: onPageSize, emptyText: "\u6682\u65E0\u4F9B\u5E94\u5546\u6570\u636E", actionWidth: 190, actions: (row) => _jsxs(_Fragment, { children: [_jsxs("button", { type: "button", onClick: () => onSupplierDialog({ mode: 'detail', item: row }), children: [_jsx("i", { className: "ri-eye-line", "aria-hidden": "true" }), "\u8BE6\u60C5"] }), _jsxs("button", { type: "button", onClick: () => onSupplierDialog({ mode: 'review', item: row }), children: [_jsx("i", { className: "ri-edit-line", "aria-hidden": "true" }), "\u5BA1\u6838"] }), _jsxs("button", { type: "button", className: "is-danger", onClick: () => onDelete(row), children: [_jsx("i", { className: "ri-delete-bin-line", "aria-hidden": "true" }), "\u5220\u9664"] })] }) })] });
|
|
235
232
|
}
|
|
236
|
-
function OrderLevel({ props, filters, definitions, onFilter, onSubmit, onReset, onPage, onOrderDialog, onDelete }) {
|
|
233
|
+
function OrderLevel({ props, filters, definitions, onFilter, onSubmit, onReset, onPage, onPageSize, onOrderDialog, onDelete }) {
|
|
237
234
|
const metrics = props.metrics ?? buildProcurementMetrics(props.purchaseOrders.items, props.purchaseLines.items);
|
|
238
235
|
const columns = [
|
|
239
|
-
{ type: 'custom', key: 'contractNo', header: '采购合同编号', width: 160, render: (_, row) => _jsx(LinkButton, { icon: "ri-file-list-2-line", onClick: () => row.id && props.onRouteChange({ type: 'procurement', level: 'lines', supplierId: props.route.level === 'orders' ? props.route.supplierId : row.supplierId, orderId: row.id }), children: row.contractNo }) },
|
|
240
|
-
{ type: 'text', key: 'orderDate', header: '下单日期', width: 120 },
|
|
241
|
-
{ type: 'text', key: 'contractAmountCny', header: '采购金额(人民币)', width: 160, align: 'right', format: currency },
|
|
242
|
-
{ type: 'text', key: 'paidAmountCny', header: '已付款', width: 130, align: 'right', format: currency },
|
|
243
|
-
{ type: 'text', key: 'unpaidAmount', header: '未付款', width: 130, align: 'right', accessor: (row) => balance(metrics, row).unpaidAmountCny, format: currency },
|
|
244
|
-
{ type: 'text', key: 'refundedAmountCny', header: '已退税', width: 130, align: 'right', format: currency },
|
|
245
|
-
{ type: 'text', key: 'estimatedRefundAmountCny', header: '预计退税总额', width: 150, align: 'right', format: currency },
|
|
246
|
-
{ type: 'text', key: 'unrefundedAmount', header: '未退税', width: 130, align: 'right', accessor: (row) => balance(metrics, row).unrefundedAmountCny, format: currency },
|
|
236
|
+
{ type: 'custom', key: 'contractNo', header: '采购合同编号', width: 160, title: (_, row) => row.contractNo, render: (_, row) => _jsx(LinkButton, { icon: "ri-file-list-2-line", title: row.contractNo, onClick: () => row.id && props.onRouteChange({ type: 'procurement', level: 'lines', supplierId: props.route.level === 'orders' ? props.route.supplierId : row.supplierId, orderId: row.id }), children: row.contractNo }) },
|
|
237
|
+
{ type: 'text', key: 'orderDate', header: '下单日期', width: 120, truncate: false, format: formatBusinessDate },
|
|
238
|
+
{ type: 'text', key: 'contractAmountCny', header: '采购金额(人民币)', width: 160, align: 'right', truncate: false, format: currency },
|
|
239
|
+
{ type: 'text', key: 'paidAmountCny', header: '已付款', width: 130, align: 'right', truncate: false, format: currency },
|
|
240
|
+
{ type: 'text', key: 'unpaidAmount', header: '未付款', width: 130, align: 'right', truncate: false, accessor: (row) => balance(metrics, row).unpaidAmountCny, format: currency },
|
|
241
|
+
{ type: 'text', key: 'refundedAmountCny', header: '已退税', width: 130, align: 'right', truncate: false, format: currency },
|
|
242
|
+
{ type: 'text', key: 'estimatedRefundAmountCny', header: '预计退税总额', width: 150, align: 'right', truncate: false, format: currency },
|
|
243
|
+
{ type: 'text', key: 'unrefundedAmount', header: '未退税', width: 130, align: 'right', truncate: false, accessor: (row) => balance(metrics, row).unrefundedAmountCny, format: currency },
|
|
247
244
|
{ type: 'text', key: 'customerContractNo', header: '匹配客户合同', width: 150, format: (value) => String(value || '未关联') }
|
|
248
245
|
];
|
|
249
|
-
return _jsxs(_Fragment, { children: [props.supplier && _jsx(ProcurementContextBar, { level: "supplier", supplier: props.supplier, onRouteChange: props.onRouteChange }), _jsx(ProcurementLevelHeading, { title: "\u91C7\u8D2D\u8BA2\u5355\u5217\u8868", description: "\u4E8C\u7EA7\u9875\u9762\uFF1A\u67E5\u770B\u5F53\u524D\u4F9B\u5E94\u5546\u7684\u91C7\u8D2D\u8BA2\u5355\uFF0C\u5E76\u901A\u8FC7\u91C7\u8D2D\u5408\u540C\u7F16\u53F7\u8FDB\u5165\u8BA2\u5355\u5546\u54C1\u5217\u8868\u3002" }), _jsx(MetricStrip, { metrics: metrics }), _jsx(FilterPanel, { definitions: definitions, values: filters, onChange: onFilter, onQuery: onSubmit, onReset: onReset }), _jsx(DataGrid, { columns: columns, rows: props.purchaseOrders.items, rowKey: (row, index) => row.id ?? index, pagination: pagination(props.purchaseOrders), onPageChange: onPage, emptyText: "\u6682\u65E0\u91C7\u8D2D\u8BA2\u5355\u6570\u636E", actionWidth:
|
|
246
|
+
return _jsxs(_Fragment, { children: [props.supplier && _jsx(ProcurementContextBar, { level: "supplier", supplier: props.supplier, onRouteChange: props.onRouteChange }), _jsx(ProcurementLevelHeading, { title: "\u91C7\u8D2D\u8BA2\u5355\u5217\u8868", description: "\u4E8C\u7EA7\u9875\u9762\uFF1A\u67E5\u770B\u5F53\u524D\u4F9B\u5E94\u5546\u7684\u91C7\u8D2D\u8BA2\u5355\uFF0C\u5E76\u901A\u8FC7\u91C7\u8D2D\u5408\u540C\u7F16\u53F7\u8FDB\u5165\u8BA2\u5355\u5546\u54C1\u5217\u8868\u3002" }), _jsx(MetricStrip, { metrics: metrics }), _jsx(FilterPanel, { definitions: definitions, values: filters, onChange: onFilter, onQuery: onSubmit, onReset: onReset }), _jsx(DataGrid, { columns: columns, rows: props.purchaseOrders.items, rowKey: (row, index) => row.id ?? index, pagination: pagination(props.purchaseOrders), onPageChange: onPage, onPageSizeChange: onPageSize, emptyText: "\u6682\u65E0\u91C7\u8D2D\u8BA2\u5355\u6570\u636E", actionWidth: 190, actions: (row) => _jsxs(_Fragment, { children: [_jsxs("button", { type: "button", onClick: () => onOrderDialog({ mode: 'detail', item: row }), children: [_jsx("i", { className: "ri-eye-line", "aria-hidden": "true" }), "\u8BE6\u60C5"] }), _jsxs("button", { type: "button", onClick: () => onOrderDialog({ mode: 'review', item: row }), children: [_jsx("i", { className: "ri-edit-line", "aria-hidden": "true" }), "\u5BA1\u6838"] }), _jsxs("button", { type: "button", className: "is-danger", onClick: () => onDelete(row), children: [_jsx("i", { className: "ri-delete-bin-line", "aria-hidden": "true" }), "\u5220\u9664"] })] }) })] });
|
|
250
247
|
}
|
|
251
|
-
function LineLevel({ props, filters, definitions, onFilter, onSubmit, onReset, onPage, onLineDialog, onDelete }) {
|
|
248
|
+
function LineLevel({ props, filters, definitions, onFilter, onSubmit, onReset, onPage, onPageSize, onLineDialog, onDelete }) {
|
|
252
249
|
const columns = [
|
|
253
250
|
{ type: 'ellipsis', key: 'productName', header: '商品名称', width: 170, maxWidth: 170 },
|
|
254
251
|
{ type: 'ellipsis', key: 'productDescription', header: '商品描述', width: 190, maxWidth: 190 },
|
|
255
252
|
{ type: 'text', key: 'modelSpecification', header: '规格型号', width: 150 },
|
|
256
|
-
{ type: 'text', key: 'unit', header: '单位', width: 80 },
|
|
257
|
-
{ type: 'text', key: 'quantity', header: '数量', width: 110, align: 'right', format: number },
|
|
258
|
-
{ type: 'text', key: 'unitPriceTaxIncluded', header: '含税单价', width: 120, align: 'right', format: currency },
|
|
259
|
-
{ type: 'text', key: 'lineAmountTaxIncluded', header: '含税金额', width: 130, align: 'right', format: currency },
|
|
260
|
-
{ type: 'text', key: 'vatRate', header: '增值税率', width: 100, align: 'right', format: percent },
|
|
253
|
+
{ type: 'text', key: 'unit', header: '单位', width: 80, truncate: false },
|
|
254
|
+
{ type: 'text', key: 'quantity', header: '数量', width: 110, align: 'right', truncate: false, format: number },
|
|
255
|
+
{ type: 'text', key: 'unitPriceTaxIncluded', header: '含税单价', width: 120, align: 'right', truncate: false, format: currency },
|
|
256
|
+
{ type: 'text', key: 'lineAmountTaxIncluded', header: '含税金额', width: 130, align: 'right', truncate: false, format: currency },
|
|
257
|
+
{ type: 'text', key: 'vatRate', header: '增值税率', width: 100, align: 'right', truncate: false, format: percent },
|
|
261
258
|
{ type: 'text', key: 'hsCode', header: '海关编码', width: 130 },
|
|
262
|
-
{ type: 'text', key: 'refundRate', header: '退税率', width: 90, align: 'right', format: percent },
|
|
263
|
-
{ type: 'custom', key: 'hsCodeStatus', header: '编码确认状态', width: 120, render: (_, row) => _jsx(StatusTag, { tone: row.hsCodeStatus === 'UNCONFIRMED' || !row.hsCodeStatus ? 'warning' : 'success', children: hsStatusLabels[row.hsCodeStatus ?? 'UNCONFIRMED'] }) },
|
|
264
|
-
{ type: 'text', key: 'complianceCategories', header: '命中合规分类', width: 150, format: (value) => Array.isArray(value) && value.length ? value.map((item) => complianceLabels[item]).join('、') : '无命中' }
|
|
265
|
-
{ type: 'text', key: 'sourceType', header: '来源类型', width: 110, format: (value) => sourceTypeLabels[value] }
|
|
259
|
+
{ type: 'text', key: 'refundRate', header: '退税率', width: 90, align: 'right', truncate: false, format: percent },
|
|
260
|
+
{ type: 'custom', key: 'hsCodeStatus', header: '编码确认状态', width: 120, truncate: false, render: (_, row) => _jsx(StatusTag, { tone: row.hsCodeStatus === 'UNCONFIRMED' || !row.hsCodeStatus ? 'warning' : 'success', children: hsStatusLabels[row.hsCodeStatus ?? 'UNCONFIRMED'] }) },
|
|
261
|
+
{ type: 'text', key: 'complianceCategories', header: '命中合规分类', width: 150, format: (value) => Array.isArray(value) && value.length ? value.map((item) => complianceLabels[item]).join('、') : '无命中' }
|
|
266
262
|
];
|
|
267
263
|
const newLine = { purchaseOrderId: props.order?.id ?? '', sourceType: 'MANUAL_ENTRY', productName: '', quantity: '', unitPriceTaxIncluded: '', lineAmountTaxIncluded: '', hsCodeStatus: 'UNCONFIRMED' };
|
|
268
|
-
return _jsxs(_Fragment, { children: [_jsx(ProcurementLevelHeading, { title: "\u91C7\u8D2D\u5546\u54C1\u5217\u8868", description: "\u4E09\u7EA7\u9875\u9762\uFF1A\u67E5\u770B\u5F53\u524D\u91C7\u8D2D\u8BA2\u5355\u7684\u5546\u54C1\u660E\u7EC6\uFF0C\u53EF\u65B0\u589E\u3001\u5BA1\u6838\u548C\u903B\u8F91\u5220\u9664\u5546\u54C1\u3002", commands: _jsxs("button", { type: "button", className: "tcw-button tcw-button--primary", disabled: props.busy || !props.order?.id, onClick: () => onLineDialog({ mode: 'create', item: newLine }), children: [_jsx("i", { className: "ri-add-line", "aria-hidden": "true" }), "\u65B0\u589E\u5546\u54C1"] }) }), props.supplier && props.order && _jsx(ProcurementContextBar, { level: "order", supplier: props.supplier, order: props.order, onRouteChange: props.onRouteChange }), _jsx(FilterPanel, { definitions: definitions, values: filters, onChange: onFilter, onQuery: onSubmit, onReset: onReset }), _jsx(InfoNotice, { children: "\u53EF\u901A\u8FC7\u5BA1\u6838\u5B8C\u5584\u82F1\u6587\u540D\u79F0\u3001\u6D77\u5173\u7F16\u7801\u3001\u9000\u7A0E\u7387\u548C\u98CE\u9669\u5339\u914D\u4FE1\u606F\u3002" }), _jsx(DataGrid, { columns: columns, rows: props.purchaseLines.items, rowKey: (row, index) => row.id ?? index, pagination: pagination(props.purchaseLines), onPageChange: onPage, emptyText: "\u6682\u65E0\u91C7\u8D2D\u5546\u54C1\u6570\u636E", actionWidth: 120, actions: (row) => _jsxs(_Fragment, { children: [_jsxs("button", { type: "button", onClick: () => onLineDialog({ mode: 'review', item: row }), children: [_jsx("i", { className: "ri-edit-line", "aria-hidden": "true" }), "\u5BA1\u6838"] }), _jsxs("button", { type: "button", className: "is-danger", onClick: () => onDelete(row), children: [_jsx("i", { className: "ri-delete-bin-line", "aria-hidden": "true" }), "\u5220\u9664"] })] }) })] });
|
|
264
|
+
return _jsxs(_Fragment, { children: [_jsx(ProcurementLevelHeading, { title: "\u91C7\u8D2D\u5546\u54C1\u5217\u8868", description: "\u4E09\u7EA7\u9875\u9762\uFF1A\u67E5\u770B\u5F53\u524D\u91C7\u8D2D\u8BA2\u5355\u7684\u5546\u54C1\u660E\u7EC6\uFF0C\u53EF\u65B0\u589E\u3001\u5BA1\u6838\u548C\u903B\u8F91\u5220\u9664\u5546\u54C1\u3002", commands: _jsxs("button", { type: "button", className: "tcw-button tcw-button--primary", disabled: props.busy || !props.order?.id, onClick: () => onLineDialog({ mode: 'create', item: newLine }), children: [_jsx("i", { className: "ri-add-line", "aria-hidden": "true" }), "\u65B0\u589E\u5546\u54C1"] }) }), props.supplier && props.order && _jsx(ProcurementContextBar, { level: "order", supplier: props.supplier, order: props.order, onRouteChange: props.onRouteChange }), _jsx(FilterPanel, { definitions: definitions, values: filters, onChange: onFilter, onQuery: onSubmit, onReset: onReset }), _jsx(InfoNotice, { children: "\u53EF\u901A\u8FC7\u5BA1\u6838\u5B8C\u5584\u82F1\u6587\u540D\u79F0\u3001\u6D77\u5173\u7F16\u7801\u3001\u9000\u7A0E\u7387\u548C\u98CE\u9669\u5339\u914D\u4FE1\u606F\u3002" }), _jsx(DataGrid, { columns: columns, rows: props.purchaseLines.items, rowKey: (row, index) => row.id ?? index, pagination: pagination(props.purchaseLines), onPageChange: onPage, onPageSizeChange: onPageSize, emptyText: "\u6682\u65E0\u91C7\u8D2D\u5546\u54C1\u6570\u636E", actionWidth: 120, actions: (row) => _jsxs(_Fragment, { children: [_jsxs("button", { type: "button", onClick: () => onLineDialog({ mode: 'review', item: row }), children: [_jsx("i", { className: "ri-edit-line", "aria-hidden": "true" }), "\u5BA1\u6838"] }), _jsxs("button", { type: "button", className: "is-danger", onClick: () => onDelete(row), children: [_jsx("i", { className: "ri-delete-bin-line", "aria-hidden": "true" }), "\u5220\u9664"] })] }) })] });
|
|
269
265
|
}
|
|
270
266
|
function ProcurementLevelHeading({ title, description, commands }) {
|
|
271
267
|
return _jsxs("header", { className: "tcw-procurement-level-heading", children: [_jsxs("div", { children: [_jsx("h2", { children: title }), _jsx("p", { children: description })] }), commands && _jsx("div", { className: "tcw-procurement-toolbar", children: commands })] });
|
|
272
268
|
}
|
|
273
269
|
export function ProcurementContextBar(props) {
|
|
274
|
-
return _jsxs("section", { className:
|
|
270
|
+
return _jsxs("section", { className: `tcw-procurement-context tcw-procurement-context--${props.level}`, "aria-label": props.level === 'supplier' ? '供应商上下文' : '采购订单上下文', children: [props.level === 'supplier' ? _jsxs(_Fragment, { children: [_jsx(ContextValue, { label: "\u4F9B\u5E94\u5546\u4EE3\u7801", value: props.supplier.code }), _jsx(ContextValue, { label: "\u4F9B\u5E94\u5546\u540D\u79F0", value: props.supplier.name }), _jsx(ContextValue, { label: "\u8054\u7CFB\u4EBA", value: props.supplier.contactName }), _jsx(ContextValue, { label: "\u8054\u7CFB\u7535\u8BDD", value: props.supplier.phone })] }) : _jsxs(_Fragment, { children: [_jsx(ContextValue, { label: "\u4F9B\u5E94\u5546", value: props.supplier.name }), _jsx(ContextValue, { label: "\u91C7\u8D2D\u5408\u540C\u7F16\u53F7", value: props.order.contractNo }), _jsx(ContextValue, { label: "\u4E0B\u5355\u65E5\u671F", value: formatBusinessDate(props.order.orderDate) }), _jsx(ContextValue, { label: "\u91C7\u8D2D\u91D1\u989D", value: currency(props.order.contractAmountCny) })] }), _jsx("div", { className: "tcw-procurement-context-actions", children: props.level === 'supplier' ? _jsxs("button", { type: "button", className: "tcw-button tcw-button--secondary", onClick: () => props.onRouteChange({ type: 'procurement', level: 'suppliers' }), children: [_jsx("i", { className: "ri-arrow-left-line", "aria-hidden": "true" }), "\u8FD4\u56DE\u4F9B\u5E94\u5546\u5217\u8868"] }) : _jsxs("button", { type: "button", className: "tcw-button tcw-button--secondary", onClick: () => props.onRouteChange({ type: 'procurement', level: 'orders', supplierId: props.supplier.id ?? props.order.supplierId }), children: [_jsx("i", { className: "ri-arrow-left-line", "aria-hidden": "true" }), "\u8FD4\u56DE\u8BA2\u5355\u5217\u8868"] }) })] });
|
|
275
271
|
}
|
|
276
272
|
function MetricStrip({ metrics }) {
|
|
277
273
|
const items = [
|
|
278
|
-
['订单总数', number(metrics.totalOrderCount)],
|
|
279
|
-
['
|
|
280
|
-
['本年订单数', number(metrics.currentYearOrderCount)],
|
|
281
|
-
['本年采购金额', currency(metrics.currentYearPurchaseAmountCny)]
|
|
274
|
+
['订单总数', number(metrics.totalOrderCount), 'ri-clipboard-line', 'blue'],
|
|
275
|
+
['采购总金额', currency(metrics.totalPurchaseAmountCny), 'ri-wallet-3-line', 'green'],
|
|
276
|
+
['本年订单数', number(metrics.currentYearOrderCount), 'ri-calendar-check-line', 'orange'],
|
|
277
|
+
['本年采购金额', currency(metrics.currentYearPurchaseAmountCny), 'ri-bar-chart-grouped-line', 'violet']
|
|
282
278
|
];
|
|
283
|
-
return _jsxs("section", { className: "tcw-procurement-metrics", "aria-label": "\u91C7\u8D2D\u7EDF\u8BA1", children: [items.map(([label, value]) => _jsxs("div", { children: [_jsx("span", { children: label }), _jsx("strong", { children: value })] }, label)), _jsxs("div", { className: "tcw-procurement-top", children: [_jsx("span", { children: "\u91C7\u8D2D\u5546\u54C1TOP5" }), metrics.topProducts.length ? _jsx("ol", { children: metrics.topProducts.map((item) => _jsxs("li", { children: [_jsx("span", { children: item.productName }), _jsx("strong", { children: currency(item.amountCny) })] }, item.productName)) }) : _jsx("small", { children: "\u6682\u65E0\u5546\u54C1\u6570\u636E" })] })] });
|
|
279
|
+
return _jsxs("section", { className: "tcw-procurement-metrics", "aria-label": "\u91C7\u8D2D\u7EDF\u8BA1", children: [items.map(([label, value, icon, tone]) => _jsxs("div", { className: `tcw-procurement-metric tcw-procurement-metric--${tone}`, children: [_jsx("i", { className: `${icon} tcw-procurement-metric-icon`, "aria-hidden": "true" }), _jsx("span", { children: label }), _jsx("strong", { children: value })] }, label)), _jsxs("div", { className: "tcw-procurement-top", children: [_jsx("span", { children: "\u91C7\u8D2D\u5546\u54C1TOP5" }), metrics.topProducts.length ? _jsx("ol", { children: metrics.topProducts.map((item) => _jsxs("li", { children: [_jsx("span", { children: item.productName }), _jsx("strong", { children: currency(item.amountCny) })] }, item.productName)) }) : _jsx("small", { children: "\u6682\u65E0\u5546\u54C1\u6570\u636E" })] })] });
|
|
284
280
|
}
|
|
285
281
|
function SupplierDialog({ state, busy, onClose, onSave }) {
|
|
286
282
|
const [value, setValue] = React.useState(state?.item ?? null);
|
|
@@ -291,7 +287,7 @@ function SupplierDialog({ state, busy, onClose, onSave }) {
|
|
|
291
287
|
const fields = [
|
|
292
288
|
['code', '供应商代码'], ['name', '供应商名称', true], ['shortName', '简称'], ['countryOrRegion', '国别/地区'], ['contactName', '联系人'], ['phone', '联系电话'], ['wechat', '微信'], ['email', '邮箱'], ['address', '地址'], ['taxNumber', '税号'], ['paymentAccount', '收款账号'], ['bankName', '开户行'], ['taxpayerRating', '纳税等级'], ['website', '公司网站'], ['businessProducts', '经营产品']
|
|
293
289
|
];
|
|
294
|
-
return _jsxs(Modal, { open: true, title: state.mode === 'detail' ? '供应商详情' : '供应商详情审核', size: "wide", onClose: onClose, footer: disabled ? _jsxs("button", { type: "button", className: "tcw-button tcw-button--secondary", onClick: onClose, children: [_jsx("i", { className: "ri-close-line", "aria-hidden": "true" }), "\u5173\u95ED"] }) : _jsxs(_Fragment, { children: [_jsxs("button", { type: "button", className: "tcw-button tcw-button--secondary", onClick: onClose, children: [_jsx("i", { className: "ri-close-line", "aria-hidden": "true" }), "\u53D6\u6D88"] }), _jsxs("button", { type: "button", className: "tcw-button tcw-button--primary", disabled: busy || !value.name.trim(), onClick: () => void onSave(value), children: [_jsx("i", { className: "ri-save-line", "aria-hidden": "true" }), "\u4FDD\u5B58"] })] }), children: [_jsx(FieldGrid, { columns:
|
|
290
|
+
return _jsxs(Modal, { open: true, title: state.mode === 'detail' ? '供应商详情' : '供应商详情审核', size: "wide", onClose: onClose, footer: disabled ? _jsxs("button", { type: "button", className: "tcw-button tcw-button--secondary", onClick: onClose, children: [_jsx("i", { className: "ri-close-line", "aria-hidden": "true" }), "\u5173\u95ED"] }) : _jsxs(_Fragment, { children: [_jsxs("button", { type: "button", className: "tcw-button tcw-button--secondary", onClick: onClose, children: [_jsx("i", { className: "ri-close-line", "aria-hidden": "true" }), "\u53D6\u6D88"] }), _jsxs("button", { type: "button", className: "tcw-button tcw-button--primary", disabled: busy || !value.name.trim(), onClick: () => void onSave(value), children: [_jsx("i", { className: "ri-save-line", "aria-hidden": "true" }), "\u4FDD\u5B58"] })] }), children: [_jsxs("p", { className: "tcw-procurement-dialog-kicker", children: ["\u6765\u6E90\uFF1A\u91C7\u8D2D\u5408\u540C\u5F52\u5E76 ", _jsxs("span", { children: ["\u6700\u8FD1\u5236\u88C1\u68C0\u67E5\uFF1A", value.complianceCheckedAt ? formatBeijingDateTime(value.complianceCheckedAt) : '尚未检查'] })] }), _jsxs("div", { className: "tcw-procurement-supplier-review", children: [_jsx(FieldGrid, { columns: 1, children: fields.map(([key, label, required]) => _jsx(FormField, { label: label, required: required, children: _jsx("input", { disabled: disabled || key === 'code', value: String(value[key] ?? ''), onChange: (event) => setValue({ ...value, [key]: event.target.value }) }) }, key)) }), _jsxs("aside", { children: [_jsx(FormField, { label: "\u5907\u6CE8", children: _jsx("textarea", { rows: 6, disabled: disabled, value: value.remarks ?? '', onChange: (event) => setValue({ ...value, remarks: event.target.value }) }) }), _jsxs("dl", { children: [_jsxs("div", { children: [_jsx("dt", { children: "\u5236\u88C1\u98CE\u9669" }), _jsx("dd", { children: _jsx(StatusTag, { tone: value.sanctionStatus === 'HIT' ? 'danger' : 'success', children: sanctionLabels[value.sanctionStatus ?? 'UNCHECKED'] }) })] }), _jsxs("div", { children: [_jsx("dt", { children: "\u521B\u5EFA\u4EBA" }), _jsx("dd", { children: value.createdByName || '—' })] }), _jsxs("div", { children: [_jsx("dt", { children: "\u521B\u5EFA\u65F6\u95F4" }), _jsx("dd", { children: formatBeijingDateTime(value.createdAt) })] }), _jsxs("div", { children: [_jsx("dt", { children: "\u6700\u540E\u7F16\u8F91\u4EBA" }), _jsx("dd", { children: value.updatedByName || '—' })] }), _jsxs("div", { children: [_jsx("dt", { children: "\u6700\u540E\u7F16\u8F91\u65F6\u95F4" }), _jsx("dd", { children: formatBeijingDateTime(value.updatedAt) })] })] }), _jsx(InfoNotice, { children: "\u5236\u88C1\u98CE\u9669\u4E3A\u7CFB\u7EDF\u6700\u8FD1\u4E00\u6B21\u68C0\u67E5\u7ED3\u679C\uFF0C\u4FDD\u5B58\u540E\u5C06\u89E6\u53D1\u65B0\u7684\u5236\u88C1\u68C0\u67E5\u3002" })] })] })] });
|
|
295
291
|
}
|
|
296
292
|
function OrderDialog({ state, lines, busy, onClose, onSave }) {
|
|
297
293
|
const [value, setValue] = React.useState(state?.item ?? null);
|
|
@@ -303,7 +299,7 @@ function OrderDialog({ state, lines, busy, onClose, onSave }) {
|
|
|
303
299
|
const error = amount(value.paidAmountCny) > amount(value.contractAmountCny) ? '已付款不能超过采购订单总额' : amount(value.refundedAmountCny) > amount(estimated) ? '已退税不能超过预计退税总额' : '';
|
|
304
300
|
return _jsxs(Modal, { open: true, title: disabled ? '采购订单详情' : '采购订单审核', size: "wide", onClose: onClose, footer: disabled ? _jsxs("button", { type: "button", className: "tcw-button tcw-button--secondary", onClick: onClose, children: [_jsx("i", { className: "ri-close-line", "aria-hidden": "true" }), "\u5173\u95ED"] }) : _jsxs(_Fragment, { children: [_jsxs("button", { type: "button", className: "tcw-button tcw-button--secondary", onClick: onClose, children: [_jsx("i", { className: "ri-close-line", "aria-hidden": "true" }), "\u53D6\u6D88"] }), _jsxs("button", { type: "button", className: "tcw-button tcw-button--primary", disabled: busy || Boolean(error) || !value.orderDate, onClick: () => void onSave(value), children: [_jsx("i", { className: "ri-save-line", "aria-hidden": "true" }), "\u4FDD\u5B58"] })] }), children: [error && _jsx(RiskNotice, { children: error }), _jsxs(FieldGrid, { columns: 2, children: [_jsx(FormField, { label: "\u91C7\u8D2D\u5408\u540C\u7F16\u53F7", required: true, children: _jsx("input", { disabled: true, value: value.contractNo }) }), _jsx(FormField, { label: "\u4E0B\u5355\u65E5\u671F", required: true, children: _jsx("input", { type: "date", disabled: disabled, value: value.orderDate, onChange: (event) => setValue({ ...value, orderDate: event.target.value }) }) }), _jsx(MoneyField, { label: "\u91C7\u8D2D\u8BA2\u5355\u603B\u989D", disabled: disabled, value: value.contractAmountCny, onChange: (next) => setValue({ ...value, contractAmountCny: next }) }), _jsx(MoneyField, { label: "\u5DF2\u4ED8\u6B3E", disabled: disabled, value: value.paidAmountCny, onChange: (next) => setValue({ ...value, paidAmountCny: next }) }), _jsx(MoneyField, { label: "\u672A\u4ED8\u6B3E", disabled: true, value: String(Math.max(amount(value.contractAmountCny) - amount(value.paidAmountCny), 0)) }), _jsx(MoneyField, { label: "\u5DF2\u9000\u7A0E", disabled: disabled, value: value.refundedAmountCny, onChange: (next) => setValue({ ...value, refundedAmountCny: next }) }), _jsx(MoneyField, { label: "\u9884\u8BA1\u9000\u7A0E\u603B\u989D", disabled: true, value: estimated }), _jsx(MoneyField, { label: "\u672A\u9000\u7A0E", disabled: true, value: String(Math.max(amount(estimated) - amount(value.refundedAmountCny), 0)) }), _jsx(FormField, { label: "\u5339\u914D\u5BA2\u6237\u5408\u540C", children: _jsx("input", { disabled: true, value: value.customerContractNo || '未关联' }) }), _jsx(FormField, { label: "\u6765\u6E90\u6587\u4EF6", children: _jsx("input", { disabled: true, value: value.sourceFileName || '—' }) })] })] });
|
|
305
301
|
}
|
|
306
|
-
function LineDialog({ state, order, busy, onAction, onClose, onSave }) {
|
|
302
|
+
export function LineDialog({ state, order, busy, onAction, onClose, onSave }) {
|
|
307
303
|
const [value, setValue] = React.useState(state?.item ?? null);
|
|
308
304
|
const [hsOpen, setHsOpen] = React.useState(false);
|
|
309
305
|
React.useEffect(() => setValue(state?.item ?? null), [state]);
|
|
@@ -317,7 +313,7 @@ function LineDialog({ state, order, busy, onAction, onClose, onSave }) {
|
|
|
317
313
|
return Promise.resolve({ success: false, message: '采购商品仅支持海关编码查询' });
|
|
318
314
|
return onAction(actionKey, input);
|
|
319
315
|
};
|
|
320
|
-
return _jsxs(_Fragment, { children: [
|
|
316
|
+
return _jsxs(_Fragment, { children: [_jsx(Modal, { open: true, title: state.mode === 'create' ? '新增商品' : '采购商品审核', size: "wide", onClose: onClose, footer: _jsxs(_Fragment, { children: [_jsxs("button", { type: "button", className: "tcw-button tcw-button--secondary", onClick: onClose, children: [_jsx("i", { className: "ri-close-line", "aria-hidden": "true" }), "\u53D6\u6D88"] }), _jsxs("button", { type: "button", className: "tcw-button tcw-button--primary", disabled: busy || errors.length > 0, onClick: () => void onSave(value), children: [_jsx("i", { className: "ri-save-line", "aria-hidden": "true" }), "\u4FDD\u5B58"] })] }), children: _jsxs("div", { className: "tcw-procurement-line-form", children: [_jsxs("div", { className: "tcw-procurement-source-label", children: ["\u6765\u6E90\u7C7B\u578B\uFF1A", sourceTypeLabels[value.sourceType]] }), state.mode === 'review' && errors.length > 0 && _jsx(RiskNotice, { children: errors.join(';') }), _jsxs(FieldGrid, { columns: 2, children: [_jsx(TextField, { label: "\u5546\u54C1\u540D\u79F0", required: true, value: value.productName, onChange: (next) => setValue({ ...value, productName: next }) }), _jsx(TextField, { label: "\u5546\u54C1\u63CF\u8FF0", value: value.productDescription, onChange: (next) => setValue({ ...value, productDescription: next }) }), _jsx(TextField, { label: "\u89C4\u683C\u578B\u53F7", value: value.modelSpecification, onChange: (next) => setValue({ ...value, modelSpecification: next }) }), _jsx(TextField, { label: "\u5355\u4F4D", required: true, value: value.unit, onChange: (next) => setValue({ ...value, unit: next }) }), _jsx(TextField, { label: "\u6570\u91CF", required: true, type: "number", value: value.quantity, onChange: (next) => setValue({ ...value, quantity: next, lineAmountTaxIncluded: String(amount(next) * amount(value.unitPriceTaxIncluded)) }) }), _jsx(TextField, { label: "\u542B\u7A0E\u5355\u4EF7\uFF08\u4EBA\u6C11\u5E01\uFF09", required: true, type: "number", value: value.unitPriceTaxIncluded, onChange: (next) => setValue({ ...value, unitPriceTaxIncluded: next, lineAmountTaxIncluded: String(amount(value.quantity) * amount(next)) }) }), _jsx(TextField, { label: "\u542B\u7A0E\u91D1\u989D\uFF08\u4EBA\u6C11\u5E01\uFF09", required: true, type: "number", value: value.lineAmountTaxIncluded || String(computedAmount), onChange: (next) => setValue({ ...value, lineAmountTaxIncluded: next }) }), _jsx(TextField, { label: "\u589E\u503C\u7A0E\u7387", required: true, type: "number", value: value.vatRate, onChange: (next) => setValue({ ...value, vatRate: next }) }), _jsx(FormField, { label: "\u6D77\u5173\u7F16\u7801", children: _jsxs("div", { className: "tcw-procurement-inline-field", children: [_jsx("input", { value: value.hsCode ?? '', onChange: (event) => setValue({ ...value, hsCode: event.target.value }) }), _jsxs("button", { type: "button", className: "tcw-button tcw-button--secondary", onClick: () => setHsOpen(true), children: [_jsx("i", { className: "ri-search-line", "aria-hidden": "true" }), "HS\u7F16\u7801\u67E5\u8BE2"] })] }) }), _jsx(FormField, { label: "\u7F16\u7801\u786E\u8BA4\u72B6\u6001", children: _jsx("div", { className: "tcw-procurement-line-status", children: enumOptions(hsStatusLabels).map((item) => _jsxs("label", { children: [_jsx("input", { type: "radio", name: "line-hs-code-status", value: item.value, checked: (value.hsCodeStatus ?? 'UNCONFIRMED') === item.value, onChange: () => setValue({ ...value, hsCodeStatus: item.value }) }), item.label] }, item.value)) }) }), _jsx(TextField, { label: "\u9000\u7A0E\u7387", required: true, type: "number", value: value.refundRate, onChange: (next) => setValue({ ...value, refundRate: next }) }), _jsx(TextField, { label: "\u9000\u7A0E\u653F\u7B56\u4F9D\u636E", required: true, value: value.refundPolicyReference, onChange: (next) => setValue({ ...value, refundPolicyReference: next }) }), _jsx(TextField, { label: "\u653F\u7B56\u65E5\u671F", required: true, type: "date", value: value.refundPolicyDate, onChange: (next) => setValue({ ...value, refundPolicyDate: next, refundValidationMethod: 'REVIEW_CONFIRMED' }) }), _jsx(TextField, { label: "\u82F1\u6587\u540D\u79F0", value: value.englishName, onChange: (next) => setValue({ ...value, englishName: next }) })] })] }) }), _jsx(HsCodeLookupDialog, { open: hsOpen, initialQuery: value.hsCode || value.englishName || value.productName, onAction: hsAction, onClose: () => setHsOpen(false) })] });
|
|
321
317
|
}
|
|
322
318
|
function PurchaseContractReviewDialog({ open, task, draft, busy, onChange, onClose, onSave }) {
|
|
323
319
|
const errors = draft ? validatePurchaseContractReview(draft) : [];
|
|
@@ -338,15 +334,15 @@ function SourcePreview({ draft, task }) {
|
|
|
338
334
|
const location = draft.lines.find(line => line.sourceContent)?.sourceLocation;
|
|
339
335
|
return _jsxs("div", { className: "tcw-procurement-source", children: [_jsx("strong", { children: draft.sourceFileName || task?.sourceFileName || '采购合同源文件' }), draft.sourceFileUrl ? _jsx("iframe", { src: draft.sourceFileUrl, title: "\u91C7\u8D2D\u5408\u540C\u6E90\u6587\u4EF6" }) : explicit ? _jsxs(_Fragment, { children: [_jsx("small", { children: location || '来源位置未标注' }), _jsx("pre", { children: explicit })] }) : _jsx("pre", { children: "\u6E90\u6587\u4EF6\u6682\u65E0\u6CD5\u5728\u7EBF\u9884\u89C8" })] });
|
|
340
336
|
}
|
|
341
|
-
function DeleteDialog({ target, supplier, busy, onCancel, onConfirm }) {
|
|
337
|
+
export function DeleteDialog({ target, supplier, busy, onCancel, onConfirm }) {
|
|
342
338
|
const isOrder = target?.entityType === 'purchaseOrder';
|
|
343
339
|
const order = isOrder ? target.item : null;
|
|
344
340
|
const name = target?.entityType === 'supplier' ? target.item.name : target?.entityType === 'purchaseOrder' ? target.item.contractNo : target?.item?.productName;
|
|
345
|
-
return _jsx(ConfirmDialog, { open: Boolean(target), title: isOrder ? '确认删除采购订单?' : `确认删除${target?.entityType === 'supplier' ? '供应商' : '采购商品'}?`, danger: true, confirmText: "\u786E\u8BA4\u5220\u9664", confirmDisabled: busy, onCancel: onCancel, onConfirm: onConfirm, message: _jsxs("div", { className: "tcw-procurement-delete-summary", children: [
|
|
341
|
+
return _jsx(ConfirmDialog, { open: Boolean(target), title: isOrder ? '确认删除采购订单?' : `确认删除${target?.entityType === 'supplier' ? '供应商' : '采购商品'}?`, danger: true, confirmText: "\u786E\u8BA4\u5220\u9664", confirmDisabled: busy, onCancel: onCancel, onConfirm: onConfirm, message: isOrder ? _jsxs("div", { className: "tcw-procurement-delete-summary is-order", children: [_jsxs("strong", { className: "tcw-procurement-delete-warning", children: [_jsx("i", { className: "ri-error-warning-fill", "aria-hidden": "true" }), "\u5220\u9664\u540E\u5C06\u903B\u8F91\u5220\u9664\u8BE5\u91C7\u8D2D\u8BA2\u5355\u53CA\u5176\u5168\u90E8\u5546\u54C1\u660E\u7EC6\uFF0C\u8BF7\u8C28\u614E\u64CD\u4F5C\u3002"] }), _jsxs("dl", { className: "tcw-procurement-delete-details", children: [_jsxs("div", { children: [_jsx("dt", { children: "\u91C7\u8D2D\u5408\u540C\u7F16\u53F7" }), _jsx("dd", { children: name || '—' })] }), _jsxs("div", { children: [_jsx("dt", { children: "\u4F9B\u5E94\u5546" }), _jsx("dd", { children: supplier?.name || '—' })] }), _jsxs("div", { children: [_jsx("dt", { children: "\u5546\u54C1\u6761\u6570" }), _jsx("dd", { children: order?.lineCount ?? 0 })] }), _jsxs("div", { children: [_jsx("dt", { children: "\u91C7\u8D2D\u91D1\u989D" }), _jsx("dd", { children: currency(order?.contractAmountCny) })] }), _jsxs("div", { children: [_jsx("dt", { children: "\u5DF2\u4ED8\u6B3E / \u5DF2\u9000\u7A0E" }), _jsxs("dd", { children: [currency(order?.paidAmountCny), " / ", currency(order?.refundedAmountCny)] })] })] }), _jsxs("p", { className: "tcw-procurement-delete-info", children: [_jsx("i", { className: "ri-information-line", "aria-hidden": "true" }), "\u91CD\u65B0\u4E0A\u4F20\u540C\u7F16\u53F7\u5408\u540C\u4F1A\u4F5C\u4E3A\u5168\u65B0\u8BB0\u5F55\uFF0C\u4E0D\u8FC1\u79FB\u65E7\u8BA2\u5355\u4EBA\u5DE5\u6570\u636E\u3002"] })] }) : _jsx("div", { className: "tcw-procurement-delete-summary", children: _jsx("strong", { children: name || '当前记录' }) }) });
|
|
346
342
|
}
|
|
347
343
|
function ReviewSection({ title, children }) { return _jsxs("section", { className: "tcw-procurement-review-section", children: [_jsx("h3", { children: title }), children] }); }
|
|
348
344
|
function ContextValue({ label, value }) { return _jsxs("div", { children: [_jsx("span", { children: label }), _jsx("strong", { children: String(value || '—') })] }); }
|
|
349
|
-
function LinkButton({ children, icon, onClick }) { return _jsxs("button", { type: "button", className: "tcw-procurement-link", onClick: onClick, children: [_jsx("i", { className: icon, "aria-hidden": "true" }), children] }); }
|
|
345
|
+
function LinkButton({ children, icon, title, onClick }) { return _jsxs("button", { type: "button", className: "tcw-procurement-link", title: title, onClick: onClick, children: [_jsx("i", { className: icon, "aria-hidden": "true" }), children] }); }
|
|
350
346
|
function StatusTag({ children, tone }) { return _jsx("span", { className: `tcw-procurement-status tcw-procurement-status--${tone}`, children: children }); }
|
|
351
347
|
function TextField({ label, value, required, type = 'text', onChange }) { return _jsx(FormField, { label: label, required: required, children: _jsx("input", { type: type, value: String(value ?? ''), onChange: (event) => onChange(event.target.value) }) }); }
|
|
352
348
|
function MoneyField({ label, value, disabled, onChange }) { return _jsx(FormField, { label: label, children: _jsx("input", { type: "number", disabled: disabled, value: String(value ?? ''), onChange: (event) => onChange?.(event.target.value) }) }); }
|
|
@@ -362,9 +358,8 @@ function currency(value) { return `¥${amount(value).toLocaleString('zh-CN', { m
|
|
|
362
358
|
function number(value) { return amount(value).toLocaleString('zh-CN'); }
|
|
363
359
|
function percent(value) { return `${(rate(value) * 100).toLocaleString('zh-CN', { maximumFractionDigits: 4 })}%`; }
|
|
364
360
|
function booleanOptions() { return [{ value: 'true', label: '是' }, { value: 'false', label: '否' }]; }
|
|
365
|
-
function enumOptions(labels) { return Object.entries(labels).map(([value, label]) => ({ value, label
|
|
361
|
+
function enumOptions(labels) { return Object.entries(labels).map(([value, label]) => ({ value, label })); }
|
|
366
362
|
function pagination(collection) { const total = collection.total ?? collection.items.length; const pageSize = collection.pageSize ?? PAGE_SIZE; return { page: collection.page ?? 1, pageSize, total, pageCount: Math.max(1, Math.ceil(total / pageSize)) }; }
|
|
367
363
|
function assertSucceeded(result) { if (result.success === false)
|
|
368
364
|
throw new Error(result.message || '采购操作失败'); }
|
|
369
|
-
function errorMessage(cause) { return cause instanceof Error ? cause.message : '采购操作失败'; }
|
|
370
365
|
//# sourceMappingURL=procurement.js.map
|