@chenchaolong/plugin-trade-compliance-workbench 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/lib/demo-data.definitions.js +1 -1
- package/dist/lib/demo-data.definitions.js.map +1 -1
- package/dist/lib/demo-data.service.d.ts.map +1 -1
- package/dist/lib/demo-data.service.js +1 -3
- package/dist/lib/demo-data.service.js.map +1 -1
- package/dist/lib/entities/index.d.ts +2 -2
- package/dist/lib/entities/index.d.ts.map +1 -1
- package/dist/lib/entities/index.js +2 -2
- package/dist/lib/entities/index.js.map +1 -1
- package/dist/lib/entities/shared.entity.d.ts +2 -5
- package/dist/lib/entities/shared.entity.d.ts.map +1 -1
- package/dist/lib/entities/shared.entity.js +5 -16
- package/dist/lib/entities/shared.entity.js.map +1 -1
- package/dist/lib/legacy-schema-cleanup.d.ts +9 -0
- package/dist/lib/legacy-schema-cleanup.d.ts.map +1 -0
- package/dist/lib/legacy-schema-cleanup.js +28 -0
- package/dist/lib/legacy-schema-cleanup.js.map +1 -0
- package/dist/lib/remote-components/trade-compliance-workbench/app.css +3268 -1
- package/dist/lib/remote-components/trade-compliance-workbench/app.js +5 -5
- package/dist/lib/remote-ui/app-source.d.ts.map +1 -1
- package/dist/lib/remote-ui/app-source.js +7 -6
- package/dist/lib/remote-ui/app-source.js.map +1 -1
- package/dist/lib/remote-ui/bridge.d.ts +0 -4
- package/dist/lib/remote-ui/bridge.d.ts.map +1 -1
- package/dist/lib/remote-ui/bridge.js +23 -20
- package/dist/lib/remote-ui/bridge.js.map +1 -1
- package/dist/lib/remote-ui/components/data-grid.js +1 -1
- package/dist/lib/remote-ui/components/data-grid.js.map +1 -1
- package/dist/lib/remote-ui/components/forms.js +2 -2
- package/dist/lib/remote-ui/components/forms.js.map +1 -1
- package/dist/lib/remote-ui/components/layout.d.ts +5 -1
- package/dist/lib/remote-ui/components/layout.d.ts.map +1 -1
- package/dist/lib/remote-ui/components/layout.js +23 -3
- package/dist/lib/remote-ui/components/layout.js.map +1 -1
- package/dist/lib/remote-ui/contracts.d.ts +1 -0
- package/dist/lib/remote-ui/contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/model.d.ts.map +1 -1
- package/dist/lib/remote-ui/model.js +11 -11
- package/dist/lib/remote-ui/model.js.map +1 -1
- package/dist/lib/remote-ui/pages/analytics.js +1 -1
- package/dist/lib/remote-ui/pages/analytics.js.map +1 -1
- package/dist/lib/remote-ui/pages/catalogs.js +14 -14
- package/dist/lib/remote-ui/pages/catalogs.js.map +1 -1
- package/dist/lib/remote-ui/pages/contracts.js +3 -3
- package/dist/lib/remote-ui/pages/contracts.js.map +1 -1
- package/dist/lib/remote-ui/pages/files.js +5 -5
- package/dist/lib/remote-ui/pages/files.js.map +1 -1
- package/dist/lib/remote-ui/pages/home.d.ts +18 -62
- package/dist/lib/remote-ui/pages/home.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/home.js +25 -131
- package/dist/lib/remote-ui/pages/home.js.map +1 -1
- package/dist/lib/remote-ui/pages/procurement.js +11 -11
- package/dist/lib/remote-ui/pages/procurement.js.map +1 -1
- package/dist/lib/remote-ui/pages/sales.js +8 -8
- package/dist/lib/remote-ui/pages/sales.js.map +1 -1
- package/dist/lib/remote-ui/pages/settings.d.ts +0 -3
- package/dist/lib/remote-ui/pages/settings.d.ts.map +1 -1
- package/dist/lib/remote-ui/pages/settings.js +7 -56
- package/dist/lib/remote-ui/pages/settings.js.map +1 -1
- package/dist/lib/remote-ui/settings-contracts.d.ts +2 -16
- package/dist/lib/remote-ui/settings-contracts.d.ts.map +1 -1
- package/dist/lib/remote-ui/settings-contracts.js +2 -2
- package/dist/lib/remote-ui/settings-contracts.js.map +1 -1
- package/dist/lib/remote-ui/sidebar-state.d.ts +5 -0
- package/dist/lib/remote-ui/sidebar-state.d.ts.map +1 -0
- package/dist/lib/remote-ui/sidebar-state.js +18 -0
- package/dist/lib/remote-ui/sidebar-state.js.map +1 -0
- package/dist/lib/runtime-validation.d.ts +0 -1
- package/dist/lib/runtime-validation.d.ts.map +1 -1
- package/dist/lib/runtime-validation.js +0 -17
- package/dist/lib/runtime-validation.js.map +1 -1
- package/dist/lib/types.d.ts +11 -10
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +8 -2
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/view-parameters.d.ts +3 -0
- package/dist/lib/view-parameters.d.ts.map +1 -0
- package/dist/lib/view-parameters.js +23 -0
- package/dist/lib/view-parameters.js.map +1 -0
- package/dist/lib/workbench-view.provider.d.ts +14 -9
- package/dist/lib/workbench-view.provider.d.ts.map +1 -1
- package/dist/lib/workbench-view.provider.js +55 -20
- package/dist/lib/workbench-view.provider.js.map +1 -1
- package/dist/lib/workbench.plugin.d.ts +4 -1
- package/dist/lib/workbench.plugin.d.ts.map +1 -1
- package/dist/lib/workbench.plugin.js +12 -4
- package/dist/lib/workbench.plugin.js.map +1 -1
- package/dist/lib/workbench.service.d.ts +4 -8
- package/dist/lib/workbench.service.d.ts.map +1 -1
- package/dist/lib/workbench.service.js +10 -25
- package/dist/lib/workbench.service.js.map +1 -1
- package/package.json +3 -1
- package/dist/lib/domain/risk-notice.d.ts +0 -59
- package/dist/lib/domain/risk-notice.d.ts.map +0 -1
- package/dist/lib/domain/risk-notice.js +0 -30
- package/dist/lib/domain/risk-notice.js.map +0 -1
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export type RiskOperationItem = {
|
|
2
|
+
key: string;
|
|
3
|
+
title: string;
|
|
4
|
+
description: string;
|
|
5
|
+
icon: string;
|
|
6
|
+
};
|
|
7
|
+
export type WorkflowDirection = 'right' | 'down' | 'left' | null;
|
|
8
|
+
export type WorkflowArea = `step-${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8}`;
|
|
9
|
+
export type WorkflowLayout = {
|
|
10
|
+
area: WorkflowArea;
|
|
11
|
+
desktop: WorkflowDirection;
|
|
12
|
+
tablet: WorkflowDirection;
|
|
13
|
+
mobile: WorkflowDirection;
|
|
14
|
+
};
|
|
3
15
|
export type WorkflowStep = {
|
|
4
16
|
key: string;
|
|
5
17
|
title: string;
|
|
@@ -7,65 +19,9 @@ export type WorkflowStep = {
|
|
|
7
19
|
description: string;
|
|
8
20
|
icon: string;
|
|
9
21
|
tone: 'blue' | 'green' | 'violet' | 'orange';
|
|
22
|
+
layout: WorkflowLayout;
|
|
10
23
|
};
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export type HomePageProps = {
|
|
15
|
-
dashboard?: Record<string, unknown> | null;
|
|
16
|
-
riskNotice?: RiskNoticePayload | string | null;
|
|
17
|
-
};
|
|
18
|
-
export declare const RISK_OPERATION_ITEMS: readonly [{
|
|
19
|
-
readonly key: "replace-controlled";
|
|
20
|
-
readonly title: "覆盖管控目录";
|
|
21
|
-
readonly description: "确认目录类型和被覆盖的历史文件。覆盖后新目录立即生效,原目录数据只在后台留痕,前端暂不支持恢复。";
|
|
22
|
-
readonly icon: "ri-folder-warning-line";
|
|
23
|
-
}, {
|
|
24
|
-
readonly key: "duplicate-contract";
|
|
25
|
-
readonly title: "重复上传合同";
|
|
26
|
-
readonly description: "采购合同和客户合同均不允许覆盖;发现相同合同编码时系统会阻止上传。确需重传时必须先逻辑删除旧合同,旧合同人工金额不迁移到新记录。";
|
|
27
|
-
readonly icon: "ri-upload-cloud-2-line";
|
|
28
|
-
}, {
|
|
29
|
-
readonly key: "replace-catalog";
|
|
30
|
-
readonly title: "覆盖目录";
|
|
31
|
-
readonly description: "管控商品目录和公司制裁目录覆盖都会立即影响风险结果,请确认被覆盖文件和记录数量。";
|
|
32
|
-
readonly icon: "ri-book-open-line";
|
|
33
|
-
}, {
|
|
34
|
-
readonly key: "delete-business";
|
|
35
|
-
readonly title: "删除业务数据";
|
|
36
|
-
readonly description: "删除供应商、客户、订单、商品、目录记录或历史文件前,请确认其下游影响。业务删除和目录覆盖均为逻辑删除。";
|
|
37
|
-
readonly icon: "ri-delete-bin-line";
|
|
38
|
-
}, {
|
|
39
|
-
readonly key: "payments";
|
|
40
|
-
readonly title: "维护付款、收款和退税";
|
|
41
|
-
readonly description: "采购和销售金额统一使用人民币;金额超过订单总额或预计退税额时系统将禁止保存。";
|
|
42
|
-
readonly icon: "ri-money-cny-circle-line";
|
|
43
|
-
}, {
|
|
44
|
-
readonly key: "profit-rate";
|
|
45
|
-
readonly title: "维护利润率";
|
|
46
|
-
readonly description: "客户默认利润率会实时影响其全部未单独设置利润率的派生销售订单,历史生成文件不会自动更新。";
|
|
47
|
-
readonly icon: "ri-line-chart-line";
|
|
48
|
-
}, {
|
|
49
|
-
readonly key: "risk-review";
|
|
50
|
-
readonly title: "核对风险";
|
|
51
|
-
readonly description: "系统会匹配管控商品目录和公司制裁目录;命中制裁公司只提示、不阻止保存,但必须人工核对风险明细。";
|
|
52
|
-
readonly icon: "ri-shield-check-line";
|
|
53
|
-
}, {
|
|
54
|
-
readonly key: "sales-file";
|
|
55
|
-
readonly title: "生成销售文件";
|
|
56
|
-
readonly description: "生成前请确认公司信息、银行信息和利润率规则。模板辅助字段由用户在生成后的 Excel 中审核修改。";
|
|
57
|
-
readonly icon: "ri-file-excel-2-line";
|
|
58
|
-
}, {
|
|
59
|
-
readonly key: "edit-excel";
|
|
60
|
-
readonly title: "在线编辑 Excel";
|
|
61
|
-
readonly description: "历史文件在线保存会直接覆盖当前文件,不保留旧版本,也不会反向更新采购合同、客户合同或数据分析数据。";
|
|
62
|
-
readonly icon: "ri-edit-box-line";
|
|
63
|
-
}, {
|
|
64
|
-
readonly key: "confirm-operation";
|
|
65
|
-
readonly title: "操作前请确认";
|
|
66
|
-
readonly description: "外贸合规数据会直接影响合同关联、利润校验、销售文件和经营报表。执行目录覆盖、合同删除、金额修改或文件生成前,请核对业务对象和数据内容。";
|
|
67
|
-
readonly icon: "ri-error-warning-line";
|
|
68
|
-
}];
|
|
69
|
-
export declare const WORKFLOW_STEPS: WorkflowStep[];
|
|
70
|
-
export declare function HomePage({ dashboard, riskNotice }?: HomePageProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
export declare const RISK_OPERATION_ITEMS: readonly RiskOperationItem[];
|
|
25
|
+
export declare const WORKFLOW_STEPS: readonly WorkflowStep[];
|
|
26
|
+
export declare function HomePage(): import("react/jsx-runtime").JSX.Element;
|
|
71
27
|
//# sourceMappingURL=home.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"home.d.ts","sourceRoot":"","sources":["../../../../src/lib/remote-ui/pages/home.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"home.d.ts","sourceRoot":"","sources":["../../../../src/lib/remote-ui/pages/home.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,iBAAiB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AACjG,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;AAChE,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAA;AAClE,MAAM,MAAM,cAAc,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAAA;AACrI,MAAM,MAAM,YAAY,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,CAAA;AAEjM,eAAO,MAAM,oBAAoB,EAAE,SAAS,iBAAiB,EAWnD,CAAA;AAEV,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EASxC,CAAA;AAEV,wBAAgB,QAAQ,4CAcvB"}
|
|
@@ -1,136 +1,30 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
export const RISK_OPERATION_ITEMS = [
|
|
3
|
+
{ key: 'catalog-replace', title: '覆盖管控目录', description: '确认目录类型和被覆盖的历史文件。', icon: 'ri-file-warning-line' },
|
|
4
|
+
{ key: 'duplicate-contract', title: '重复上传合同', description: '采购合同和客户合同不允许覆盖已有记录。', icon: 'ri-file-copy-2-line' },
|
|
5
|
+
{ key: 'catalog-impact', title: '覆盖目录', description: '目录覆盖会立即影响商品和公司风险结果。', icon: 'ri-refresh-line' },
|
|
6
|
+
{ key: 'delete-data', title: '删除业务数据', description: '删除前请核对其下游影响,前端不提供恢复。', icon: 'ri-delete-bin-line' },
|
|
7
|
+
{ key: 'payments', title: '维护付款、收款和退税', description: '金额使用人民币,超过订单总额时禁止保存。', icon: 'ri-money-cny-circle-line' },
|
|
8
|
+
{ key: 'profit', title: '维护利润率', description: '客户默认利润率会影响派生销售订单。', icon: 'ri-percent-line' },
|
|
9
|
+
{ key: 'risk-review', title: '核对风险', description: '命中管控或制裁目录时必须人工复核。', icon: 'ri-shield-check-line' },
|
|
10
|
+
{ key: 'generate-file', title: '生成销售文件', description: '生成前确认公司、银行和利润率规则。', icon: 'ri-file-excel-2-line' },
|
|
11
|
+
{ key: 'edit-excel', title: '在线编辑 Excel', description: '保存会直接覆盖当前历史文件。', icon: 'ri-edit-box-line' },
|
|
12
|
+
{ key: 'confirm', title: '操作前请确认', description: '目录、合同、金额和文件操作会影响下游业务。', icon: 'ri-error-warning-line' }
|
|
13
|
+
];
|
|
5
14
|
export const WORKFLOW_STEPS = [
|
|
6
|
-
{ key: 'catalogs', title: '维护管控商品与公司制裁目录', titleLines: ['维护管控商品与', '公司制裁目录'], description: '上传并维护管控商品目录和公司制裁目录', icon: 'ri-book-open-line', tone: 'blue' },
|
|
7
|
-
{ key: 'contracts', title: '上传并审核采购合同和客户合同', titleLines: ['上传并审核采购', '合同和客户合同'], description: '上传采购合同和客户合同并进行审核入库', icon: 'ri-file-upload-line', tone: 'green' },
|
|
8
|
-
{ key: 'risk-match', title: '商品及公司风险匹配', titleLines: ['商品及公司', '风险匹配'], description: '系统匹配目录进行商品和公司风险识别', icon: 'ri-shield-check-line', tone: 'violet' },
|
|
9
|
-
{ key: 'derive-sales', title: '自动派生销售订单', titleLines: ['自动派生', '销售订单'], description: '根据客户合同自动关联采购合同并派生订单', icon: 'ri-shopping-cart-line', tone: 'orange' },
|
|
10
|
-
{ key: 'profit-check', title: '利润率校验', titleLines: ['利润率校验'], description: '校验利润率是否符合企业规则和要求', icon: 'ri-percent-line', tone: 'blue' },
|
|
11
|
-
{ key: 'bank', title: '选择银行信息(报关单跳过)', titleLines: ['选择银行信息', '(报关单跳过)'], description: '选择或确认银行信息用于相关单据', icon: 'ri-bank-line', tone: 'green' },
|
|
12
|
-
{ key: 'review-files', title: '生成并在线审核销售文件', titleLines: ['生成并在线审核', '销售文件'], description: '生成销售文件并在 Excel 中审核修改', icon: 'ri-file-check-line', tone: 'violet' },
|
|
13
|
-
{ key: 'analytics', title: '数据分析', titleLines: ['数据分析'], description: '查看业务数据和经营分析报表', icon: 'ri-bar-chart-line', tone: 'blue' }
|
|
15
|
+
{ key: 'catalogs', title: '维护管控商品与公司制裁目录', titleLines: ['维护管控商品与', '公司制裁目录'], description: '上传并维护管控商品目录和公司制裁目录', icon: 'ri-book-open-line', tone: 'blue', layout: { area: 'step-1', desktop: 'right', tablet: 'right', mobile: 'down' } },
|
|
16
|
+
{ key: 'contracts', title: '上传并审核采购合同和客户合同', titleLines: ['上传并审核采购', '合同和客户合同'], description: '上传采购合同和客户合同并进行审核入库', icon: 'ri-file-upload-line', tone: 'green', layout: { area: 'step-2', desktop: 'right', tablet: 'down', mobile: 'down' } },
|
|
17
|
+
{ key: 'risk-match', title: '商品及公司风险匹配', titleLines: ['商品及公司', '风险匹配'], description: '系统匹配目录进行商品和公司风险识别', icon: 'ri-shield-check-line', tone: 'violet', layout: { area: 'step-3', desktop: 'right', tablet: 'left', mobile: 'down' } },
|
|
18
|
+
{ key: 'derive-sales', title: '自动派生销售订单', titleLines: ['自动派生', '销售订单'], description: '根据客户合同自动关联采购合同并派生订单', icon: 'ri-shopping-cart-line', tone: 'orange', layout: { area: 'step-4', desktop: 'down', tablet: 'down', mobile: 'down' } },
|
|
19
|
+
{ key: 'profit-check', title: '利润率校验', titleLines: ['利润率校验'], description: '校验利润率是否符合企业规则和要求', icon: 'ri-percent-line', tone: 'blue', layout: { area: 'step-5', desktop: 'left', tablet: 'right', mobile: 'down' } },
|
|
20
|
+
{ key: 'bank', title: '选择银行信息(报关单跳过)', titleLines: ['选择银行信息', '(报关单跳过)'], description: '选择或确认银行信息用于相关单据', icon: 'ri-bank-line', tone: 'green', layout: { area: 'step-6', desktop: 'left', tablet: 'down', mobile: 'down' } },
|
|
21
|
+
{ key: 'review-files', title: '生成并在线审核销售文件', titleLines: ['生成并在线审核', '销售文件'], description: '生成销售文件并在 Excel 中审核修改', icon: 'ri-file-check-line', tone: 'violet', layout: { area: 'step-7', desktop: 'left', tablet: 'left', mobile: 'down' } },
|
|
22
|
+
{ key: 'analytics', title: '数据分析', titleLines: ['数据分析'], description: '查看业务数据和经营分析报表', icon: 'ri-bar-chart-line', tone: 'blue', layout: { area: 'step-8', desktop: null, tablet: null, mobile: null } }
|
|
14
23
|
];
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const configuredItems = extractRiskItems(configuredNodes);
|
|
21
|
-
const riskItems = configuredContent ? configuredItems : RISK_OPERATION_ITEMS;
|
|
22
|
-
return (_jsxs("div", { className: "tcw-home-page", children: [_jsxs("section", { className: "tcw-home-section", "aria-labelledby": "risk-operation-title", children: [_jsxs("h2", { id: "risk-operation-title", className: "tcw-home-section-title", children: [_jsx("i", { className: "ri-shield-flash-line", "aria-hidden": "true" }), "\u98CE\u9669\u64CD\u4F5C\u63D0\u793A"] }), riskItems.length > 0 ? (_jsx("div", { className: "tcw-home-risk-matrix", children: riskItems.map((item) => (_jsxs("article", { className: "tcw-home-risk-item", "data-risk-operation": item.key, children: [_jsxs("div", { className: "tcw-home-risk-heading", children: [_jsx("i", { className: item.icon, "aria-hidden": "true" }), _jsx("h3", { children: item.title })] }), _jsx("p", { children: item.description })] }, item.key))) })) : (_jsx("div", { className: "tcw-home-maintained-notice", "data-maintained-risk-notice": true, children: renderSafeRichTextNodes(configuredNodes, 'risk') }))] }), _jsxs("section", { className: "tcw-home-section", "aria-labelledby": "workflow-title", children: [_jsxs("div", { className: "tcw-home-workflow-heading", children: [_jsx("h2", { id: "workflow-title", className: "tcw-home-section-title", children: "\u4E1A\u52A1\u6D41\u7A0B\u56FE" }), _jsx("p", { children: "\u8BF7\u6309\u7167\u4EE5\u4E0B\u4E1A\u52A1\u6D41\u7A0B\u8FDB\u884C\u64CD\u4F5C" })] }), _jsx("div", { className: "tcw-home-workflow-scroll", children: _jsx("div", { className: "tcw-home-workflow", children: WORKFLOW_STEPS.map((step, index) => (_jsxs(React.Fragment, { children: [_jsxs("article", { className: `tcw-home-workflow-step tcw-home-workflow-step--${step.tone}`, "data-workflow-step": step.key, children: [_jsx("span", { className: "tcw-home-step-number", children: index + 1 }), _jsx("i", { className: step.icon, "aria-hidden": "true" }), _jsx("h3", { "aria-label": step.title, children: step.titleLines.map((line) => _jsx("span", { className: "tcw-home-step-title-line", children: line }, line)) }), _jsx("p", { children: step.description })] }), index < WORKFLOW_STEPS.length - 1 && (_jsx("i", { className: "ri-arrow-right-line tcw-home-workflow-connector", "data-workflow-connector": true, "aria-hidden": "true" }))] }, step.key))) }) })] })] }));
|
|
23
|
-
}
|
|
24
|
-
function resolveRiskNoticeContent(dashboard, riskNotice) {
|
|
25
|
-
const source = riskNotice === undefined ? dashboard?.riskNotice : riskNotice;
|
|
26
|
-
if (typeof source === 'string')
|
|
27
|
-
return source.trim();
|
|
28
|
-
if (!source || typeof source !== 'object')
|
|
29
|
-
return '';
|
|
30
|
-
const content = source.content;
|
|
31
|
-
return typeof content === 'string' ? content.trim() : '';
|
|
32
|
-
}
|
|
33
|
-
function parseSafeRichText(content) {
|
|
34
|
-
const root = { tag: 'root', children: [] };
|
|
35
|
-
const stack = [root];
|
|
36
|
-
const blockedTags = [];
|
|
37
|
-
for (const token of content.match(/<[^>]*>|[^<]+|</g) ?? []) {
|
|
38
|
-
if (!token.startsWith('<')) {
|
|
39
|
-
if (blockedTags.length === 0)
|
|
40
|
-
stack.at(-1)?.children.push(decodeHtmlEntities(token));
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
const match = token.match(/^<\s*(\/?)\s*([a-z][a-z0-9]*)[^>]*>$/i);
|
|
44
|
-
if (!match)
|
|
45
|
-
continue;
|
|
46
|
-
const closing = match[1] === '/';
|
|
47
|
-
const rawTag = match[2].toLowerCase();
|
|
48
|
-
const selfClosing = token.endsWith('/>');
|
|
49
|
-
if (blockedTags.length > 0) {
|
|
50
|
-
if (closing && rawTag === blockedTags.at(-1))
|
|
51
|
-
blockedTags.pop();
|
|
52
|
-
else if (!closing && !selfClosing && BLOCKED_RICH_TEXT_TAGS.has(rawTag))
|
|
53
|
-
blockedTags.push(rawTag);
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
if (BLOCKED_RICH_TEXT_TAGS.has(rawTag)) {
|
|
57
|
-
if (!closing && !selfClosing)
|
|
58
|
-
blockedTags.push(rawTag);
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
if (!SAFE_RICH_TEXT_TAGS.has(rawTag))
|
|
62
|
-
continue;
|
|
63
|
-
const tag = rawTag === 'b' ? 'strong' : rawTag;
|
|
64
|
-
if (closing) {
|
|
65
|
-
let openIndex = -1;
|
|
66
|
-
for (let index = stack.length - 1; index > 0; index -= 1) {
|
|
67
|
-
if (stack[index].tag === tag) {
|
|
68
|
-
openIndex = index;
|
|
69
|
-
break;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
if (openIndex > 0)
|
|
73
|
-
stack.splice(openIndex);
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
const node = { tag, children: [] };
|
|
77
|
-
stack.at(-1)?.children.push(node);
|
|
78
|
-
if (tag !== 'br' && !selfClosing)
|
|
79
|
-
stack.push(node);
|
|
80
|
-
}
|
|
81
|
-
return root.children;
|
|
82
|
-
}
|
|
83
|
-
function extractRiskItems(nodes) {
|
|
84
|
-
const listItems = nodes.flatMap((node) => {
|
|
85
|
-
if (typeof node === 'string' || (node.tag !== 'ul' && node.tag !== 'ol'))
|
|
86
|
-
return [];
|
|
87
|
-
return node.children.filter((child) => typeof child !== 'string' && child.tag === 'li');
|
|
88
|
-
});
|
|
89
|
-
return listItems.map((item, index) => {
|
|
90
|
-
const titleNode = findFirstNode(item, 'strong');
|
|
91
|
-
const title = titleNode ? nodeText(titleNode).trim() : `风险提示 ${index + 1}`;
|
|
92
|
-
const description = nodeText(item, titleNode).replace(/^[\s::,,。-]+/, '').trim();
|
|
93
|
-
return {
|
|
94
|
-
key: `configured-${index + 1}`,
|
|
95
|
-
title,
|
|
96
|
-
description,
|
|
97
|
-
icon: 'ri-error-warning-line'
|
|
98
|
-
};
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
function findFirstNode(node, tag) {
|
|
102
|
-
for (const child of node.children) {
|
|
103
|
-
if (typeof child === 'string')
|
|
104
|
-
continue;
|
|
105
|
-
if (child.tag === tag)
|
|
106
|
-
return child;
|
|
107
|
-
const nested = findFirstNode(child, tag);
|
|
108
|
-
if (nested)
|
|
109
|
-
return nested;
|
|
110
|
-
}
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
function nodeText(node, excluded = null) {
|
|
114
|
-
return node.children.map((child) => {
|
|
115
|
-
if (typeof child === 'string')
|
|
116
|
-
return child;
|
|
117
|
-
return child === excluded ? '' : nodeText(child, excluded);
|
|
118
|
-
}).join('');
|
|
119
|
-
}
|
|
120
|
-
function renderSafeRichTextNodes(nodes, keyPrefix) {
|
|
121
|
-
return nodes.map((node, index) => {
|
|
122
|
-
if (typeof node === 'string')
|
|
123
|
-
return node;
|
|
124
|
-
return React.createElement(node.tag, { key: `${keyPrefix}-${index}` }, ...renderSafeRichTextNodes(node.children, `${keyPrefix}-${index}`));
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
function decodeHtmlEntities(value) {
|
|
128
|
-
const entities = { amp: '&', apos: "'", gt: '>', lt: '<', nbsp: '\u00a0', quot: '"' };
|
|
129
|
-
return value.replace(/&(#x[\da-f]+|#\d+|[a-z]+);/gi, (entity, code) => {
|
|
130
|
-
if (code[0] !== '#')
|
|
131
|
-
return entities[code.toLowerCase()] ?? entity;
|
|
132
|
-
const point = code[1].toLowerCase() === 'x' ? Number.parseInt(code.slice(2), 16) : Number.parseInt(code.slice(1), 10);
|
|
133
|
-
return Number.isSafeInteger(point) && point >= 0 && point <= 0x10ffff ? String.fromCodePoint(point) : entity;
|
|
134
|
-
});
|
|
24
|
+
export function HomePage() {
|
|
25
|
+
return _jsxs("div", { className: "tcw-home-page", children: [_jsxs("section", { className: "tcw-home-section", "aria-labelledby": "risk-operation-title", children: [_jsxs("h2", { id: "risk-operation-title", className: "tcw-home-section-title", children: [_jsx("i", { className: "ri-shield-flash-line", "aria-hidden": "true" }), "\u98CE\u9669\u64CD\u4F5C\u63D0\u793A"] }), _jsx("div", { className: "tcw-home-risk-matrix", children: RISK_OPERATION_ITEMS.map(item => _jsxs("article", { className: "tcw-home-risk-item", "data-risk-operation": item.key, children: [_jsxs("div", { className: "tcw-home-risk-heading", children: [_jsx("i", { className: item.icon, "aria-hidden": "true" }), _jsx("h3", { children: item.title })] }), _jsx("p", { children: item.description })] }, item.key)) })] }), _jsxs("section", { className: "tcw-home-section", "aria-labelledby": "workflow-title", children: [_jsxs("div", { className: "tcw-home-workflow-heading", children: [_jsx("h2", { id: "workflow-title", className: "tcw-home-section-title", children: "\u4E1A\u52A1\u6D41\u7A0B\u56FE" }), _jsx("p", { children: "\u8BF7\u6309\u7167\u4EE5\u4E0B\u4E1A\u52A1\u6D41\u7A0B\u8FDB\u884C\u64CD\u4F5C" })] }), _jsx("div", { className: "tcw-home-workflow", children: WORKFLOW_STEPS.map((step, index) => {
|
|
26
|
+
const { layout } = step;
|
|
27
|
+
return _jsxs("article", { className: `tcw-home-workflow-step tcw-home-workflow-step--${step.tone}`, style: { gridArea: layout.area }, "data-workflow-step": step.key, children: [_jsx("span", { className: "tcw-home-step-number", children: index + 1 }), _jsx("i", { className: step.icon, "aria-hidden": "true" }), _jsx("h3", { "aria-label": step.title, children: step.titleLines.map(line => _jsx("span", { className: "tcw-home-step-title-line", children: line }, line)) }), _jsx("p", { children: step.description }), layout.desktop && _jsx("i", { className: "ri-arrow-right-line tcw-home-workflow-connector", "data-workflow-connector": true, "data-desktop-direction": layout.desktop, "data-tablet-direction": layout.tablet ?? undefined, "data-mobile-direction": layout.mobile ?? undefined, "aria-hidden": "true" })] }, step.key);
|
|
28
|
+
}) })] })] });
|
|
135
29
|
}
|
|
136
30
|
//# sourceMappingURL=home.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"home.js","sourceRoot":"","sources":["../../../../src/lib/remote-ui/pages/home.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"home.js","sourceRoot":"","sources":["../../../../src/lib/remote-ui/pages/home.tsx"],"names":[],"mappings":"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"}
|
|
@@ -210,7 +210,7 @@ export function ProcurementPage(props) {
|
|
|
210
210
|
return api.updatePurchaseLine({ ...item, id: item.id });
|
|
211
211
|
};
|
|
212
212
|
const reviewVisible = Boolean(props.importTask && (draft || props.importTask.duplicateContractError));
|
|
213
|
-
return (_jsxs("section", { className: "tcw-procurement-page", "data-procurement-level": props.route.level, children: [message && _jsx("div", { className: "tcw-procurement-feedback", role: "status", children: message }), props.importTask && (props.importTask.status === 'FAILED' || props.importTask.status === 'TIMED_OUT') && _jsxs("div", { className: "tcw-procurement-feedback", role: "alert", children: [props.importTask.errorMessage || '采购合同解析失败', props.onRetryImport &&
|
|
213
|
+
return (_jsxs("section", { className: "tcw-procurement-page", "data-procurement-level": props.route.level, children: [message && _jsx("div", { className: "tcw-procurement-feedback", role: "status", children: message }), props.importTask && (props.importTask.status === 'FAILED' || props.importTask.status === 'TIMED_OUT') && _jsxs("div", { className: "tcw-procurement-feedback", role: "alert", children: [props.importTask.errorMessage || '采购合同解析失败', props.onRetryImport && _jsxs("button", { type: "button", className: "tcw-button tcw-button--secondary", onClick: () => void props.onRetryImport?.(props.importTask.id), 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), onReset: reset, onPage: (page) => void query(page, 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), onReset: reset, onPage: (page) => void query(page, 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), onReset: reset, onPage: (page) => void query(page, 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
214
|
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
215
|
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
216
|
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)
|
|
@@ -223,7 +223,7 @@ export function ProcurementPage(props) {
|
|
|
223
223
|
}
|
|
224
224
|
function SupplierLevel({ props, filters, definitions, onFilter, onSubmit, onReset, onPage, onSupplierDialog, onDelete }) {
|
|
225
225
|
const columns = [
|
|
226
|
-
{ type: 'custom', key: 'code', header: '供应商代码', width: 130, render: (_, row) => _jsx(LinkButton, { onClick: () => row.id && props.onRouteChange({ type: 'procurement', level: 'orders', supplierId: row.id }), children: row.code || '—' }) },
|
|
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 || '—' }) },
|
|
227
227
|
{ type: 'ellipsis', key: 'name', header: '供应商名称', width: 240, maxWidth: 240 },
|
|
228
228
|
{ type: 'text', key: 'shortName', header: '简称', width: 140 },
|
|
229
229
|
{ type: 'text', key: 'contactName', header: '联系人', width: 130 },
|
|
@@ -231,12 +231,12 @@ function SupplierLevel({ props, filters, definitions, onFilter, onSubmit, onRese
|
|
|
231
231
|
{ type: 'custom', key: 'sanctionStatus', header: '制裁风险', width: 110, render: (_, row) => _jsx(StatusTag, { tone: row.sanctionStatus === 'HIT' ? 'danger' : row.sanctionStatus === 'CLEAR' ? 'success' : 'muted', children: sanctionLabels[row.sanctionStatus ?? 'UNCHECKED'] }) },
|
|
232
232
|
{ type: 'text', key: 'createdAt', header: '创建时间', width: 170 }
|
|
233
233
|
];
|
|
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: 160, actions: (row) => _jsxs(_Fragment, { children: [
|
|
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: 160, 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
235
|
}
|
|
236
236
|
function OrderLevel({ props, filters, definitions, onFilter, onSubmit, onReset, onPage, onOrderDialog, onDelete }) {
|
|
237
237
|
const metrics = props.metrics ?? buildProcurementMetrics(props.purchaseOrders.items, props.purchaseLines.items);
|
|
238
238
|
const columns = [
|
|
239
|
-
{ type: 'custom', key: 'contractNo', header: '采购合同编号', width: 160, render: (_, row) => _jsx(LinkButton, { 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 }) },
|
|
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
240
|
{ type: 'text', key: 'orderDate', header: '下单日期', width: 120 },
|
|
241
241
|
{ type: 'text', key: 'contractAmountCny', header: '采购金额(人民币)', width: 160, align: 'right', format: currency },
|
|
242
242
|
{ type: 'text', key: 'paidAmountCny', header: '已付款', width: 130, align: 'right', format: currency },
|
|
@@ -246,7 +246,7 @@ function OrderLevel({ props, filters, definitions, onFilter, onSubmit, onReset,
|
|
|
246
246
|
{ type: 'text', key: 'unrefundedAmount', header: '未退税', width: 130, align: 'right', accessor: (row) => balance(metrics, row).unrefundedAmountCny, format: currency },
|
|
247
247
|
{ type: 'text', key: 'customerContractNo', header: '匹配客户合同', width: 150, format: (value) => String(value || '未关联') }
|
|
248
248
|
];
|
|
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: 160, actions: (row) => _jsxs(_Fragment, { children: [
|
|
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: 160, 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
250
|
}
|
|
251
251
|
function LineLevel({ props, filters, definitions, onFilter, onSubmit, onReset, onPage, onLineDialog, onDelete }) {
|
|
252
252
|
const columns = [
|
|
@@ -265,7 +265,7 @@ function LineLevel({ props, filters, definitions, onFilter, onSubmit, onReset, o
|
|
|
265
265
|
{ type: 'text', key: 'sourceType', header: '来源类型', width: 110, format: (value) => sourceTypeLabels[value] }
|
|
266
266
|
];
|
|
267
267
|
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: [
|
|
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"] })] }) })] });
|
|
269
269
|
}
|
|
270
270
|
function ProcurementLevelHeading({ title, description, commands }) {
|
|
271
271
|
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 })] });
|
|
@@ -291,7 +291,7 @@ function SupplierDialog({ state, busy, onClose, onSave }) {
|
|
|
291
291
|
const fields = [
|
|
292
292
|
['code', '供应商代码'], ['name', '供应商名称', true], ['shortName', '简称'], ['countryOrRegion', '国别/地区'], ['contactName', '联系人'], ['phone', '联系电话'], ['wechat', '微信'], ['email', '邮箱'], ['address', '地址'], ['taxNumber', '税号'], ['paymentAccount', '收款账号'], ['bankName', '开户行'], ['taxpayerRating', '纳税等级'], ['website', '公司网站'], ['businessProducts', '经营产品']
|
|
293
293
|
];
|
|
294
|
-
return _jsxs(Modal, { open: true, title: state.mode === 'detail' ? '供应商详情' : '供应商详情审核', size: "wide", onClose: onClose, footer: disabled ?
|
|
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: 2, children: fields.map(([key, label, required]) => _jsx(FormField, { label: label, required: required, full: key === 'address' || key === 'businessProducts', children: _jsx("input", { disabled: disabled, value: String(value[key] ?? ''), onChange: (event) => setValue({ ...value, [key]: event.target.value }) }) }, key)) }), _jsxs("div", { className: "tcw-procurement-audit-meta", children: [_jsx(StatusTag, { tone: value.sanctionStatus === 'HIT' ? 'danger' : 'success', children: sanctionLabels[value.sanctionStatus ?? 'UNCHECKED'] }), _jsxs("span", { children: ["\u6700\u8FD1\u5236\u88C1\u68C0\u67E5\uFF1A", value.complianceCheckedAt || '尚未检查'] }), _jsxs("span", { children: ["\u6700\u540E\u7F16\u8F91\uFF1A", value.updatedByName || '—', " ", value.updatedAt || ''] })] })] });
|
|
295
295
|
}
|
|
296
296
|
function OrderDialog({ state, lines, busy, onClose, onSave }) {
|
|
297
297
|
const [value, setValue] = React.useState(state?.item ?? null);
|
|
@@ -301,7 +301,7 @@ function OrderDialog({ state, lines, busy, onClose, onSave }) {
|
|
|
301
301
|
const disabled = state.mode === 'detail';
|
|
302
302
|
const estimated = value.estimatedRefundAmountCny ?? lines.filter((item) => item.purchaseOrderId === value.id).reduce((total, item) => total + estimatedLineRefund(item), 0).toFixed(2);
|
|
303
303
|
const error = amount(value.paidAmountCny) > amount(value.contractAmountCny) ? '已付款不能超过采购订单总额' : amount(value.refundedAmountCny) > amount(estimated) ? '已退税不能超过预计退税总额' : '';
|
|
304
|
-
return _jsxs(Modal, { open: true, title: disabled ? '采购订单详情' : '采购订单审核', size: "wide", onClose: onClose, footer: disabled ?
|
|
304
|
+
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
305
|
}
|
|
306
306
|
function LineDialog({ state, order, busy, onAction, onClose, onSave }) {
|
|
307
307
|
const [value, setValue] = React.useState(state?.item ?? null);
|
|
@@ -317,12 +317,12 @@ function LineDialog({ state, order, busy, onAction, onClose, onSave }) {
|
|
|
317
317
|
return Promise.resolve({ success: false, message: '采购商品仅支持海关编码查询' });
|
|
318
318
|
return onAction(actionKey, input);
|
|
319
319
|
};
|
|
320
|
-
return _jsxs(_Fragment, { children: [_jsxs(Modal, { open: true, title: state.mode === 'create' ? '新增商品' : '采购商品审核', size: "wide", onClose: onClose, footer: _jsxs(_Fragment, { children: [
|
|
320
|
+
return _jsxs(_Fragment, { children: [_jsxs(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-source-label", children: ["\u6765\u6E90\u7C7B\u578B\uFF1A", sourceTypeLabels[value.sourceType]] }), 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("select", { value: value.hsCodeStatus ?? 'UNCONFIRMED', onChange: (event) => setValue({ ...value, hsCodeStatus: event.target.value }), children: enumOptions(hsStatusLabels).map((item) => _jsx("option", { value: item.value, children: 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
321
|
}
|
|
322
322
|
function PurchaseContractReviewDialog({ open, task, draft, busy, onChange, onClose, onSave }) {
|
|
323
323
|
const errors = draft ? validatePurchaseContractReview(draft) : [];
|
|
324
324
|
const duplicate = task?.duplicateContractError;
|
|
325
|
-
return _jsxs(Modal, { open: open, title: "\u91C7\u8D2D\u5408\u540C\u5BA1\u6838", size: "full", onClose: onClose, footer: _jsxs(_Fragment, { children: [
|
|
325
|
+
return _jsxs(Modal, { open: open, title: "\u91C7\u8D2D\u5408\u540C\u5BA1\u6838", size: "full", 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 || !draft || Boolean(duplicate) || errors.length > 0, onClick: () => draft && void onSave(draft), children: [_jsx("i", { className: "ri-check-double-line", "aria-hidden": "true" }), "\u5BA1\u6838\u5E76\u5165\u5E93"] })] }), children: [duplicate && _jsx(RiskNotice, { children: duplicate }), !draft ? _jsx(RiskNotice, { children: task?.errorMessage || '采购合同解析结果不可用' }) : _jsx(ReviewSplit, { editor: _jsxs("div", { className: "tcw-procurement-review-editor", children: [errors.length > 0 && _jsx(RiskNotice, { children: errors.join(';') }), _jsx(ReviewSection, { title: "\u4F9B\u5E94\u5546\u4FE1\u606F", children: _jsx(SupplierDraftEditor, { supplier: draft.supplier, onChange: (supplier) => onChange({ ...draft, supplier }) }) }), _jsx(ReviewSection, { title: "\u8BA2\u5355\u4FE1\u606F", children: _jsxs(FieldGrid, { columns: 2, children: [_jsx(TextField, { label: "\u91C7\u8D2D\u5408\u540C\u7F16\u53F7", required: true, value: draft.order.contractNo, onChange: (value) => onChange({ ...draft, order: { ...draft.order, contractNo: value } }) }), _jsx(TextField, { label: "\u4E0B\u5355\u65E5\u671F", required: true, type: "date", value: draft.order.orderDate, onChange: (value) => onChange({ ...draft, order: { ...draft.order, orderDate: value } }) }), _jsx(TextField, { label: "\u91C7\u8D2D\u603B\u989D\uFF08\u4EBA\u6C11\u5E01\uFF09", required: true, type: "number", value: draft.order.contractAmountCny, onChange: (value) => onChange({ ...draft, order: { ...draft.order, contractAmountCny: value } }) }), _jsx(TextField, { label: "\u5DF2\u4ED8\u6B3E", type: "number", value: draft.order.paidAmountCny, onChange: (value) => onChange({ ...draft, order: { ...draft.order, paidAmountCny: value } }) }), _jsx(TextField, { label: "\u5DF2\u9000\u7A0E", type: "number", value: draft.order.refundedAmountCny, onChange: (value) => onChange({ ...draft, order: { ...draft.order, refundedAmountCny: value } }) })] }) }), _jsx(ReviewSection, { title: `全部商品(${draft.lines.length})`, children: _jsx("div", { className: "tcw-procurement-review-lines", children: draft.lines.map((line, index) => _jsx(ContractLineEditor, { index: index, line: line, onChange: (next) => onChange({ ...draft, lines: draft.lines.map((item, lineIndex) => lineIndex === index ? next : item) }) }, line.id ?? index)) }) })] }), source: _jsx(SourcePreview, { draft: draft, task: task }) })] });
|
|
326
326
|
}
|
|
327
327
|
function ContractLineEditor({ line, index, onChange }) {
|
|
328
328
|
return _jsxs("section", { className: "tcw-procurement-review-line", children: [_jsxs("h4", { children: ["\u5546\u54C1 ", index + 1, " ", _jsx(StatusTag, { tone: "muted", children: sourceTypeLabels[line.sourceType] })] }), _jsxs(FieldGrid, { columns: 2, children: [_jsx(TextField, { label: "\u5546\u54C1\u540D\u79F0", required: true, value: line.productName, onChange: (value) => onChange({ ...line, productName: value }) }), _jsx(TextField, { label: "\u5546\u54C1\u63CF\u8FF0", value: line.productDescription, onChange: (value) => onChange({ ...line, productDescription: value }) }), _jsx(TextField, { label: "\u82F1\u6587\u540D\u79F0", value: line.englishName, onChange: (value) => onChange({ ...line, englishName: value }) }), _jsx(TextField, { label: "\u89C4\u683C\u578B\u53F7", value: line.modelSpecification, onChange: (value) => onChange({ ...line, modelSpecification: value }) }), _jsx(TextField, { label: "\u5355\u4F4D", required: true, value: line.unit, onChange: (value) => onChange({ ...line, unit: value }) }), _jsx(TextField, { label: "\u6570\u91CF", required: true, type: "number", value: line.quantity, onChange: (value) => onChange({ ...line, quantity: value }) }), _jsx(TextField, { label: "\u542B\u7A0E\u5355\u4EF7", required: true, type: "number", value: line.unitPriceTaxIncluded, onChange: (value) => onChange({ ...line, unitPriceTaxIncluded: value }) }), _jsx(TextField, { label: "\u542B\u7A0E\u91D1\u989D", required: true, type: "number", value: line.lineAmountTaxIncluded, onChange: (value) => onChange({ ...line, lineAmountTaxIncluded: value }) }), _jsx(TextField, { label: "\u589E\u503C\u7A0E\u7387", required: true, type: "number", value: line.vatRate, onChange: (value) => onChange({ ...line, vatRate: value }) }), _jsx(TextField, { label: "\u6D77\u5173\u7F16\u7801", value: line.hsCode, onChange: (value) => onChange({ ...line, hsCode: value }) }), _jsx(FormField, { label: "\u7F16\u7801\u786E\u8BA4\u72B6\u6001", children: _jsx("select", { value: line.hsCodeStatus ?? 'UNCONFIRMED', onChange: (event) => onChange({ ...line, hsCodeStatus: event.target.value }), children: enumOptions(hsStatusLabels).map((item) => _jsx("option", { value: item.value, children: item.label }, item.value)) }) }), _jsx(TextField, { label: "\u9000\u7A0E\u7387", required: true, type: "number", value: line.refundRate, onChange: (value) => onChange({ ...line, refundRate: value }) }), _jsx(TextField, { label: "\u9000\u7A0E\u653F\u7B56\u4F9D\u636E", required: true, value: line.refundPolicyReference, onChange: (value) => onChange({ ...line, refundPolicyReference: value }) }), _jsx(TextField, { label: "\u9000\u7A0E\u653F\u7B56\u65E5\u671F", required: true, type: "date", value: line.refundPolicyDate, onChange: (value) => onChange({ ...line, refundPolicyDate: value, refundValidationMethod: 'REVIEW_CONFIRMED' }) }), line.amountMismatch && _jsx(FormField, { label: "\u91D1\u989D\u5DEE\u5F02\u786E\u8BA4", required: true, children: _jsxs("label", { className: "tcw-procurement-checkbox", children: [_jsx("input", { type: "checkbox", checked: Boolean(line.amountMismatchConfirmed), onChange: (event) => onChange({ ...line, amountMismatchConfirmed: event.target.checked }) }), "\u786E\u8BA4\u4FDD\u7559\u5408\u540C\u539F\u59CB\u91D1\u989D"] }) })] })] });
|
|
@@ -346,7 +346,7 @@ function DeleteDialog({ target, supplier, busy, onCancel, onConfirm }) {
|
|
|
346
346
|
}
|
|
347
347
|
function ReviewSection({ title, children }) { return _jsxs("section", { className: "tcw-procurement-review-section", children: [_jsx("h3", { children: title }), children] }); }
|
|
348
348
|
function ContextValue({ label, value }) { return _jsxs("div", { children: [_jsx("span", { children: label }), _jsx("strong", { children: String(value || '—') })] }); }
|
|
349
|
-
function LinkButton({ children, onClick }) { return
|
|
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] }); }
|
|
350
350
|
function StatusTag({ children, tone }) { return _jsx("span", { className: `tcw-procurement-status tcw-procurement-status--${tone}`, children: children }); }
|
|
351
351
|
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
352
|
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) }) }); }
|