@chenchaolong/plugin-trade-compliance-workbench 0.1.47 → 0.1.49
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.
|
@@ -74,6 +74,8 @@
|
|
|
74
74
|
const [busy, setBusy] = React.useState(false)
|
|
75
75
|
const [query, setQuery] = React.useState('')
|
|
76
76
|
const [pageByList, setPageByList] = React.useState({})
|
|
77
|
+
const [pageSizeByList, setPageSizeByList] = React.useState({})
|
|
78
|
+
const [pageJumpByList, setPageJumpByList] = React.useState({})
|
|
77
79
|
const [detailItem, setDetailItem] = React.useState(null)
|
|
78
80
|
const [formDialog, setFormDialog] = React.useState(null)
|
|
79
81
|
const [deleteDialog, setDeleteDialog] = React.useState(null)
|
|
@@ -84,6 +86,7 @@
|
|
|
84
86
|
loading: false,
|
|
85
87
|
searched: false,
|
|
86
88
|
error: '',
|
|
89
|
+
jumpPage: '',
|
|
87
90
|
result: null
|
|
88
91
|
})
|
|
89
92
|
const pollingRef = React.useRef(null)
|
|
@@ -104,10 +107,11 @@
|
|
|
104
107
|
}
|
|
105
108
|
}, [])
|
|
106
109
|
|
|
107
|
-
React.useEffect(reportResize, [data, activePage, selectedIds, statusFilter, overviewTab, busy, formDialog, deleteDialog, hsCodeSearch, hsCodeDetailDialog])
|
|
110
|
+
React.useEffect(reportResize, [data, activePage, selectedIds, statusFilter, overviewTab, pageByList, pageSizeByList, busy, formDialog, deleteDialog, hsCodeSearch, hsCodeDetailDialog])
|
|
108
111
|
|
|
109
112
|
const reviewItems = data.reviewItems.filter((item) => !isPlaceholderReviewItem(item))
|
|
110
113
|
const pendingItems = reviewItems.filter((item) => (item.reviewStatus || 'pending') === 'pending')
|
|
114
|
+
const filteredPendingItems = filterItems(pendingItems, query, overviewSearchKeys)
|
|
111
115
|
const controlledReviewRows = reviewItems.filter((item) => item.type === 'controlled_goods' && item.reviewStatus !== 'confirmed')
|
|
112
116
|
const controlledRows = controlledReviewRows.concat(data.controlledGoods.map(toControlledGoodsReviewRow))
|
|
113
117
|
const controlledReviews = applyStatusFilter(filterItems(controlledRows, query, reviewSearchKeys), statusFilter)
|
|
@@ -194,15 +198,17 @@
|
|
|
194
198
|
}
|
|
195
199
|
}
|
|
196
200
|
|
|
197
|
-
async function searchSupplierHsCandidatesForForm() {
|
|
201
|
+
async function searchSupplierHsCandidatesForForm(page) {
|
|
198
202
|
if (!formDialog || formDialog.type !== 'supplier_product' || busy) return
|
|
199
203
|
const keyword = String(formDialog.hsCandidateKeyword || buildSupplierHsCandidateKeyword(formDialog.values) || '').trim()
|
|
200
204
|
if (!keyword) {
|
|
201
205
|
setFormDialog(Object.assign({}, formDialog, { hsCandidateError: '请输入商品名称、型号或海关编码后再查询。' }))
|
|
202
206
|
return
|
|
203
207
|
}
|
|
208
|
+
const nextPage = Math.max(1, Number(page) || 1)
|
|
204
209
|
setFormDialog(Object.assign({}, formDialog, {
|
|
205
210
|
hsCandidateKeyword: keyword,
|
|
211
|
+
hsCandidatePage: nextPage,
|
|
206
212
|
hsCandidateLoading: true,
|
|
207
213
|
hsCandidateError: '',
|
|
208
214
|
hsCandidateStatus: ''
|
|
@@ -210,20 +216,22 @@
|
|
|
210
216
|
try {
|
|
211
217
|
const response = await executeAction('search_hs_code', null, {
|
|
212
218
|
keywords: keyword,
|
|
213
|
-
page:
|
|
219
|
+
page: nextPage,
|
|
214
220
|
filterFailureCode: true,
|
|
215
221
|
displayChapter: false,
|
|
216
222
|
displayEnName: true
|
|
217
223
|
}, {})
|
|
218
224
|
assertActionSuccess(response)
|
|
219
225
|
const result = getActionDataPayload(response)
|
|
220
|
-
const candidates = Array.isArray(result && result.results) ? result.results
|
|
226
|
+
const candidates = Array.isArray(result && result.results) ? result.results : []
|
|
221
227
|
setFormDialog((current) => current ? Object.assign({}, current, {
|
|
222
228
|
hsCandidateKeyword: keyword,
|
|
229
|
+
hsCandidatePage: nextPage,
|
|
223
230
|
hsCandidateLoading: false,
|
|
224
231
|
hsCandidateError: '',
|
|
225
232
|
hsCandidateStatus: candidates.length ? 'pending_confirmation' : 'not_found',
|
|
226
|
-
hsCandidates: candidates
|
|
233
|
+
hsCandidates: candidates,
|
|
234
|
+
hsCandidatePagination: result && result.pagination ? result.pagination : null
|
|
227
235
|
}) : current)
|
|
228
236
|
} catch (error) {
|
|
229
237
|
setFormDialog((current) => current ? Object.assign({}, current, {
|
|
@@ -466,6 +474,9 @@
|
|
|
466
474
|
values: valuesFromItem(item.type, item),
|
|
467
475
|
hsCandidates: Array.isArray(merged.hsCodeCandidates) ? merged.hsCodeCandidates : [],
|
|
468
476
|
hsCandidateKeyword: merged.hsCodeLookupKeyword || buildSupplierHsCandidateKeyword(merged),
|
|
477
|
+
hsCandidatePage: 1,
|
|
478
|
+
hsCandidateJumpPage: '',
|
|
479
|
+
hsCandidatePagination: null,
|
|
469
480
|
hsCandidateStatus: merged.hsCodeLookupStatus || '',
|
|
470
481
|
hsCandidateError: merged.hsCodeLookupError || '',
|
|
471
482
|
hsCandidateLoading: false
|
|
@@ -480,6 +491,9 @@
|
|
|
480
491
|
values: emptyFormValues(type),
|
|
481
492
|
hsCandidates: [],
|
|
482
493
|
hsCandidateKeyword: '',
|
|
494
|
+
hsCandidatePage: 1,
|
|
495
|
+
hsCandidateJumpPage: '',
|
|
496
|
+
hsCandidatePagination: null,
|
|
483
497
|
hsCandidateStatus: '',
|
|
484
498
|
hsCandidateError: '',
|
|
485
499
|
hsCandidateLoading: false
|
|
@@ -664,15 +678,20 @@
|
|
|
664
678
|
}
|
|
665
679
|
|
|
666
680
|
function renderOverviewPage() {
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
|
|
681
|
+
const filteredPendingControlledItems = filteredPendingItems.filter((item) => item.type === 'controlled_goods')
|
|
682
|
+
const filteredPendingSupplierItems = filteredPendingItems.filter((item) => item.type === 'supplier_product')
|
|
683
|
+
const filteredPendingSalesItems = filteredPendingItems.filter((item) => item.type === 'customs_workbook')
|
|
684
|
+
const overviewRows = overviewTab === 'all'
|
|
685
|
+
? filteredPendingItems
|
|
686
|
+
: filteredPendingItems.filter((item) => item.type === overviewTab)
|
|
687
|
+
const overviewListKey = `overview-${overviewTab}`
|
|
688
|
+
const overviewPage = paginateRows(overviewListKey, overviewRows)
|
|
670
689
|
return h('div', { className: 'tcw-page overview-page' },
|
|
671
690
|
h('section', { className: 'tcw-metrics' },
|
|
672
|
-
metric('待审核',
|
|
673
|
-
metric('管控识别待审',
|
|
674
|
-
metric('供应商商品待审',
|
|
675
|
-
metric('销售合同待审',
|
|
691
|
+
metric('待审核', filteredPendingItems.length, 'dashboard', 'blue'),
|
|
692
|
+
metric('管控识别待审', filteredPendingControlledItems.length, 'shield', 'green'),
|
|
693
|
+
metric('供应商商品待审', filteredPendingSupplierItems.length, 'box', 'orange'),
|
|
694
|
+
metric('销售合同待审', filteredPendingSalesItems.length, 'invoice', 'violet'),
|
|
676
695
|
metric('已入库管控商品', data.controlledGoods.length, 'archive', 'slate'),
|
|
677
696
|
metric('已入库供应商商品', data.products.length, 'supplier', 'green'),
|
|
678
697
|
metric('销售发票历史', data.workbookGenerations.length, 'document', 'violet'),
|
|
@@ -681,14 +700,15 @@
|
|
|
681
700
|
panel('待办事项明细',
|
|
682
701
|
h('div', { className: 'tcw-overview-panel' },
|
|
683
702
|
h('div', { className: 'tcw-overview-tabs' }, [
|
|
684
|
-
overviewTabButton('all', '全部',
|
|
685
|
-
overviewTabButton('controlled_goods', '管控商品',
|
|
686
|
-
overviewTabButton('supplier_product', '供应商商品',
|
|
687
|
-
overviewTabButton('customs_workbook', '销售发票',
|
|
703
|
+
overviewTabButton('all', '全部', filteredPendingItems.length),
|
|
704
|
+
overviewTabButton('controlled_goods', '管控商品', filteredPendingControlledItems.length),
|
|
705
|
+
overviewTabButton('supplier_product', '供应商商品', filteredPendingSupplierItems.length),
|
|
706
|
+
overviewTabButton('customs_workbook', '销售发票', filteredPendingSalesItems.length)
|
|
688
707
|
]),
|
|
689
|
-
|
|
690
|
-
? compactReviewList(
|
|
691
|
-
: empty('暂无待审核记录。智能体识别结果会先出现在这里。')
|
|
708
|
+
overviewPage.rows.length
|
|
709
|
+
? compactReviewList(overviewPage.rows)
|
|
710
|
+
: empty('暂无待审核记录。智能体识别结果会先出现在这里。'),
|
|
711
|
+
pagination(overviewListKey, overviewRows.length)
|
|
692
712
|
)
|
|
693
713
|
)
|
|
694
714
|
)
|
|
@@ -884,20 +904,26 @@
|
|
|
884
904
|
function renderHsCodePagination(pagination) {
|
|
885
905
|
if (!pagination || (!pagination.hasPrevious && !pagination.hasNext && (!pagination.pages || pagination.pages.length <= 1))) return null
|
|
886
906
|
const pages = Array.isArray(pagination.pages) ? pagination.pages.filter((item) => item.page) : []
|
|
887
|
-
const
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
)
|
|
900
|
-
|
|
907
|
+
const maxPage = Number(pagination.maxVisiblePage) || Math.max(...pages.map((item) => Number(item.page) || 0), pagination.currentPage || hsCodeSearch.page || 1)
|
|
908
|
+
const currentPage = pagination.currentPage || hsCodeSearch.page || 1
|
|
909
|
+
return renderUnifiedPagination({
|
|
910
|
+
page: currentPage,
|
|
911
|
+
totalPages: Math.max(1, maxPage),
|
|
912
|
+
pageSize: 10,
|
|
913
|
+
fixedPageSize: true,
|
|
914
|
+
loading: hsCodeSearch.loading,
|
|
915
|
+
hasPrevious: pagination.hasPrevious,
|
|
916
|
+
hasNext: pagination.hasNext,
|
|
917
|
+
jumpValue: hsCodeSearch.jumpPage || '',
|
|
918
|
+
onPageChange: searchHsCodePage,
|
|
919
|
+
onJumpInput: (nextValue) => setHsCodeSearch(Object.assign({}, hsCodeSearch, { jumpPage: nextValue })),
|
|
920
|
+
onJump: () => {
|
|
921
|
+
const nextPage = Number(hsCodeSearch.jumpPage)
|
|
922
|
+
if (!Number.isFinite(nextPage) || nextPage <= 0) return
|
|
923
|
+
searchHsCodePage(nextPage)
|
|
924
|
+
setHsCodeSearch((current) => Object.assign({}, current, { jumpPage: '' }))
|
|
925
|
+
}
|
|
926
|
+
})
|
|
901
927
|
}
|
|
902
928
|
|
|
903
929
|
function compactReviewList(items) {
|
|
@@ -1042,7 +1068,7 @@
|
|
|
1042
1068
|
}
|
|
1043
1069
|
|
|
1044
1070
|
function paginateRows(listKey, rows) {
|
|
1045
|
-
const pageSize =
|
|
1071
|
+
const pageSize = getPageSize(listKey)
|
|
1046
1072
|
const total = rows.length
|
|
1047
1073
|
const totalPages = Math.max(1, Math.ceil(total / pageSize))
|
|
1048
1074
|
const current = Math.min(Math.max(pageByList[listKey] || 1, 1), totalPages)
|
|
@@ -1050,15 +1076,44 @@
|
|
|
1050
1076
|
}
|
|
1051
1077
|
|
|
1052
1078
|
function pagination(listKey, total) {
|
|
1053
|
-
if (total <=
|
|
1079
|
+
if (total <= 0) return null
|
|
1054
1080
|
const page = paginateRows(listKey, Array.from({ length: total }))
|
|
1055
|
-
return
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1081
|
+
return renderUnifiedPagination({
|
|
1082
|
+
total,
|
|
1083
|
+
page: page.page,
|
|
1084
|
+
totalPages: page.totalPages,
|
|
1085
|
+
pageSize: page.pageSize,
|
|
1086
|
+
pageSizeOptions: [10, 20, 50],
|
|
1087
|
+
jumpValue: pageJumpByList[listKey] || '',
|
|
1088
|
+
onPageChange: (nextPage) => setLocalPage(listKey, nextPage, page.totalPages),
|
|
1089
|
+
onPageSizeChange: (nextSize) => setLocalPageSize(listKey, nextSize),
|
|
1090
|
+
onJumpInput: (nextValue) => setPageJumpByList(Object.assign({}, pageJumpByList, { [listKey]: nextValue })),
|
|
1091
|
+
onJump: () => jumpLocalPage(listKey, page.totalPages)
|
|
1092
|
+
})
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
function getPageSize(listKey) {
|
|
1096
|
+
const value = Number(pageSizeByList[listKey])
|
|
1097
|
+
return Number.isFinite(value) && value > 0 ? value : 10
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
function setLocalPage(listKey, nextPage, totalPages) {
|
|
1101
|
+
const page = Math.min(Math.max(Number(nextPage) || 1, 1), totalPages || 1)
|
|
1102
|
+
setPageByList(Object.assign({}, pageByList, { [listKey]: page }))
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
function setLocalPageSize(listKey, nextSize) {
|
|
1106
|
+
const pageSize = Number(nextSize) || 10
|
|
1107
|
+
setPageSizeByList(Object.assign({}, pageSizeByList, { [listKey]: pageSize }))
|
|
1108
|
+
setPageByList(Object.assign({}, pageByList, { [listKey]: 1 }))
|
|
1109
|
+
setPageJumpByList(Object.assign({}, pageJumpByList, { [listKey]: '' }))
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
function jumpLocalPage(listKey, totalPages) {
|
|
1113
|
+
const value = Number(pageJumpByList[listKey])
|
|
1114
|
+
if (!Number.isFinite(value) || value <= 0) return
|
|
1115
|
+
setLocalPage(listKey, value, totalPages)
|
|
1116
|
+
setPageJumpByList(Object.assign({}, pageJumpByList, { [listKey]: '' }))
|
|
1062
1117
|
}
|
|
1063
1118
|
|
|
1064
1119
|
function renderDetailModal() {
|
|
@@ -1100,7 +1155,7 @@
|
|
|
1100
1155
|
const fields = formDialog.type === 'controlled_goods' ? controlledGoodsFormFields : supplierProductFormFields
|
|
1101
1156
|
const title = `${formDialog.mode === 'create' ? '新增' : '编辑'}${formDialog.type === 'controlled_goods' ? '管控商品' : '供应商商品'}`
|
|
1102
1157
|
return h('div', { className: 'tcw-modal-backdrop' },
|
|
1103
|
-
h('form', { className: 'tcw-modal tcw-form-modal', onSubmit: saveProductForm },
|
|
1158
|
+
h('form', { className: formDialog.type === 'supplier_product' ? 'tcw-modal tcw-form-modal tcw-form-modal-supplier' : 'tcw-modal tcw-form-modal', onSubmit: saveProductForm },
|
|
1104
1159
|
h('div', { className: 'tcw-modal-head' },
|
|
1105
1160
|
h('h2', null, title),
|
|
1106
1161
|
h('button', { type: 'button', className: 'tcw-icon-btn', onClick: () => setFormDialog(null) }, '×')
|
|
@@ -1119,6 +1174,7 @@
|
|
|
1119
1174
|
|
|
1120
1175
|
function renderSupplierHsCandidatePanel() {
|
|
1121
1176
|
const candidates = Array.isArray(formDialog.hsCandidates) ? formDialog.hsCandidates : []
|
|
1177
|
+
const pagination = formDialog.hsCandidatePagination || null
|
|
1122
1178
|
return h('section', { className: 'tcw-hs-candidate-panel' },
|
|
1123
1179
|
h('div', { className: 'tcw-subsection-head' },
|
|
1124
1180
|
h('div', null,
|
|
@@ -1132,23 +1188,93 @@
|
|
|
1132
1188
|
placeholder: '商品名称、型号或海关编码',
|
|
1133
1189
|
onChange: (event) => setFormDialog(Object.assign({}, formDialog, { hsCandidateKeyword: event.target.value }))
|
|
1134
1190
|
}),
|
|
1135
|
-
h('button', { type: 'button', className: 'tcw-mini-btn', disabled: busy || formDialog.hsCandidateLoading, onClick: searchSupplierHsCandidatesForForm }, formDialog.hsCandidateLoading ? '查询中' : '查询')
|
|
1191
|
+
h('button', { type: 'button', className: 'tcw-mini-btn', disabled: busy || formDialog.hsCandidateLoading, onClick: () => searchSupplierHsCandidatesForForm(1) }, formDialog.hsCandidateLoading ? '查询中' : '查询')
|
|
1136
1192
|
)
|
|
1137
1193
|
),
|
|
1138
1194
|
formDialog.hsCandidateError ? h('div', { className: 'tcw-error' }, formDialog.hsCandidateError) : null,
|
|
1139
|
-
candidates.length ?
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
h('
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1195
|
+
candidates.length ? h('div', { className: 'tcw-hs-candidate-result' },
|
|
1196
|
+
table(['编码', '商品名称', '英文名称', '单位', '退税率', '监管', '检验检疫', '操作'], candidates, (candidate) => [
|
|
1197
|
+
h('strong', { className: 'tcw-hs-code-text' }, value(candidate.code)),
|
|
1198
|
+
value(candidate.name),
|
|
1199
|
+
value(candidate.englishName),
|
|
1200
|
+
value(candidate.unit),
|
|
1201
|
+
value(candidate.taxRefundRate),
|
|
1202
|
+
value(candidate.regulatoryConditions),
|
|
1203
|
+
value(candidate.inspectionQuarantine),
|
|
1204
|
+
h('div', { className: 'tcw-row-actions' },
|
|
1205
|
+
h('button', { type: 'button', className: 'tcw-mini-btn', onClick: () => selectHsCandidate(candidate) }, '选用'),
|
|
1206
|
+
h('button', { type: 'button', className: 'tcw-mini-btn', disabled: !candidate.code && !candidate.detailUrl, onClick: () => loadHsCodeDetail(candidate) }, '详情')
|
|
1207
|
+
)
|
|
1208
|
+
], '暂无候选编码。'),
|
|
1209
|
+
renderSupplierHsCandidatePagination(pagination)
|
|
1210
|
+
) : empty('暂无候选编码,可调整关键词后查询。')
|
|
1211
|
+
)
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
function renderSupplierHsCandidatePagination(pagination) {
|
|
1215
|
+
if (!pagination || (!pagination.hasPrevious && !pagination.hasNext && (!pagination.pages || pagination.pages.length <= 1))) return null
|
|
1216
|
+
const pages = Array.isArray(pagination.pages) ? pagination.pages.filter((item) => item.page) : []
|
|
1217
|
+
const currentPage = pagination.currentPage || formDialog.hsCandidatePage || 1
|
|
1218
|
+
const maxPage = Number(pagination.maxVisiblePage) || Math.max(...pages.map((item) => Number(item.page) || 0), currentPage)
|
|
1219
|
+
return renderUnifiedPagination({
|
|
1220
|
+
page: currentPage,
|
|
1221
|
+
totalPages: Math.max(1, maxPage),
|
|
1222
|
+
pageSize: 10,
|
|
1223
|
+
fixedPageSize: true,
|
|
1224
|
+
loading: formDialog.hsCandidateLoading,
|
|
1225
|
+
hasPrevious: pagination.hasPrevious,
|
|
1226
|
+
hasNext: pagination.hasNext,
|
|
1227
|
+
jumpValue: formDialog.hsCandidateJumpPage || '',
|
|
1228
|
+
onPageChange: searchSupplierHsCandidatesForForm,
|
|
1229
|
+
onJumpInput: (nextValue) => setFormDialog(Object.assign({}, formDialog, { hsCandidateJumpPage: nextValue })),
|
|
1230
|
+
onJump: () => {
|
|
1231
|
+
const nextPage = Number(formDialog.hsCandidateJumpPage)
|
|
1232
|
+
if (!Number.isFinite(nextPage) || nextPage <= 0) return
|
|
1233
|
+
searchSupplierHsCandidatesForForm(nextPage)
|
|
1234
|
+
setFormDialog((current) => current ? Object.assign({}, current, { hsCandidateJumpPage: '' }) : current)
|
|
1235
|
+
}
|
|
1236
|
+
})
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
function renderUnifiedPagination(config) {
|
|
1240
|
+
const totalPages = Math.max(1, Number(config.totalPages) || 1)
|
|
1241
|
+
const page = Math.min(Math.max(Number(config.page) || 1, 1), totalPages)
|
|
1242
|
+
const canPrevious = config.hasPrevious === undefined ? page > 1 : Boolean(config.hasPrevious)
|
|
1243
|
+
const canNext = config.hasNext === undefined ? page < totalPages : Boolean(config.hasNext)
|
|
1244
|
+
const loading = Boolean(config.loading)
|
|
1245
|
+
const jumpValue = config.jumpValue || ''
|
|
1246
|
+
const pageSize = Number(config.pageSize) || 10
|
|
1247
|
+
return h('div', { className: 'tcw-pagination tcw-pagination-unified' },
|
|
1248
|
+
config.total == null ? null : h('span', { className: 'tcw-pagination-total' }, `共 ${config.total} 条`),
|
|
1249
|
+
h('button', { className: 'tcw-page-btn', disabled: loading || !canPrevious, onClick: () => config.onPageChange(1) }, '首页'),
|
|
1250
|
+
h('button', { className: 'tcw-page-btn', disabled: loading || !canPrevious, onClick: () => config.onPageChange(page - 1) }, '上一页'),
|
|
1251
|
+
h('span', { className: 'tcw-page-current' }, `第 ${page} / ${totalPages} 页`),
|
|
1252
|
+
h('button', { className: 'tcw-page-btn', disabled: loading || !canNext, onClick: () => config.onPageChange(page + 1) }, '下一页'),
|
|
1253
|
+
h('button', { className: 'tcw-page-btn', disabled: loading || !canNext, onClick: () => config.onPageChange(totalPages) }, '末页'),
|
|
1254
|
+
h('span', { className: 'tcw-page-size-label' }, '每页'),
|
|
1255
|
+
config.fixedPageSize
|
|
1256
|
+
? h('span', { className: 'tcw-page-size-fixed' }, `${pageSize} 条/页`)
|
|
1257
|
+
: h('select', {
|
|
1258
|
+
className: 'tcw-page-size-select',
|
|
1259
|
+
value: pageSize,
|
|
1260
|
+
onChange: (event) => config.onPageSizeChange(Number(event.target.value))
|
|
1261
|
+
}, (config.pageSizeOptions || [10, 20, 50]).map((size) => h('option', { key: size, value: size }, `${size} 条/页`))),
|
|
1262
|
+
h('input', {
|
|
1263
|
+
className: 'tcw-page-jump-input',
|
|
1264
|
+
type: 'number',
|
|
1265
|
+
min: 1,
|
|
1266
|
+
max: totalPages,
|
|
1267
|
+
value: jumpValue,
|
|
1268
|
+
placeholder: String(page),
|
|
1269
|
+
onChange: (event) => config.onJumpInput(event.target.value),
|
|
1270
|
+
onKeyDown: (event) => {
|
|
1271
|
+
if (event.key === 'Enter') {
|
|
1272
|
+
event.preventDefault()
|
|
1273
|
+
config.onJump()
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
}),
|
|
1277
|
+
h('button', { className: 'tcw-page-btn', disabled: loading, onClick: config.onJump }, '跳转')
|
|
1152
1278
|
)
|
|
1153
1279
|
}
|
|
1154
1280
|
|
|
@@ -1340,6 +1466,27 @@
|
|
|
1340
1466
|
}
|
|
1341
1467
|
|
|
1342
1468
|
const reviewSearchKeys = ['title', 'sourceLocation']
|
|
1469
|
+
const overviewSearchKeys = [
|
|
1470
|
+
'title',
|
|
1471
|
+
'sourceLocation',
|
|
1472
|
+
'sourceFileName',
|
|
1473
|
+
'fileName',
|
|
1474
|
+
'supplierName',
|
|
1475
|
+
'supplierCreditCode',
|
|
1476
|
+
'productName',
|
|
1477
|
+
'model',
|
|
1478
|
+
'description',
|
|
1479
|
+
'hsCode',
|
|
1480
|
+
'contractHsCode',
|
|
1481
|
+
'enrichedHsCode',
|
|
1482
|
+
'englishName',
|
|
1483
|
+
'invoiceNo',
|
|
1484
|
+
'contractNo',
|
|
1485
|
+
'buyerName',
|
|
1486
|
+
'sellerName',
|
|
1487
|
+
'controlNote',
|
|
1488
|
+
'keywords'
|
|
1489
|
+
]
|
|
1343
1490
|
const controlledGoodsFormFields = [
|
|
1344
1491
|
{ key: 'productName', label: '商品名称', placeholder: '例如:高性能服务器' },
|
|
1345
1492
|
{ key: 'hsCode', label: '海关编码', placeholder: '例如:8471501010' },
|
|
@@ -1945,11 +2092,83 @@ button, input, textarea, select { font: inherit; letter-spacing: 0; }
|
|
|
1945
2092
|
.tcw-error { border: 1px solid color-mix(in srgb, var(--tcw-danger) 35%, var(--tcw-border)); border-radius: 8px; background: color-mix(in srgb, var(--tcw-danger) 6%, var(--tcw-card)); color: var(--tcw-danger); padding: 10px 12px; font-size: 13px; font-weight: 800; }
|
|
1946
2093
|
.row-selection-checkbox { width: 16px; height: 16px; }
|
|
1947
2094
|
.tcw-empty { display: grid; place-items: center; min-height: 86px; border: 1px dashed var(--tcw-border); border-radius: 8px; background: var(--tcw-soft); color: var(--tcw-muted); padding: 16px; text-align: center; }
|
|
1948
|
-
.tcw-pagination {
|
|
2095
|
+
.tcw-pagination {
|
|
2096
|
+
display: flex;
|
|
2097
|
+
flex-wrap: wrap;
|
|
2098
|
+
align-items: center;
|
|
2099
|
+
gap: 6px;
|
|
2100
|
+
border: 1px solid var(--tcw-border);
|
|
2101
|
+
border-radius: 8px;
|
|
2102
|
+
background: var(--tcw-card);
|
|
2103
|
+
padding: 8px 10px;
|
|
2104
|
+
color: var(--tcw-muted);
|
|
2105
|
+
font-size: 12px;
|
|
2106
|
+
}
|
|
2107
|
+
.tcw-pagination-unified { justify-content: flex-start; }
|
|
1949
2108
|
.tcw-page-buttons { display: flex; gap: 8px; }
|
|
2109
|
+
.tcw-pagination-total {
|
|
2110
|
+
display: inline-flex;
|
|
2111
|
+
align-items: center;
|
|
2112
|
+
min-height: 28px;
|
|
2113
|
+
color: var(--tcw-primary);
|
|
2114
|
+
}
|
|
2115
|
+
.tcw-page-btn {
|
|
2116
|
+
display: inline-flex;
|
|
2117
|
+
align-items: center;
|
|
2118
|
+
justify-content: center;
|
|
2119
|
+
min-width: 48px;
|
|
2120
|
+
min-height: 28px;
|
|
2121
|
+
border: 1px solid var(--tcw-border);
|
|
2122
|
+
border-radius: 6px;
|
|
2123
|
+
background: #fff;
|
|
2124
|
+
color: var(--tcw-primary);
|
|
2125
|
+
padding: 4px 9px;
|
|
2126
|
+
cursor: pointer;
|
|
2127
|
+
font-size: 12px;
|
|
2128
|
+
font-weight: 700;
|
|
2129
|
+
}
|
|
2130
|
+
.tcw-page-btn:disabled {
|
|
2131
|
+
cursor: not-allowed;
|
|
2132
|
+
background: var(--tcw-soft);
|
|
2133
|
+
color: #9aa7b8;
|
|
2134
|
+
}
|
|
2135
|
+
.tcw-page-current {
|
|
2136
|
+
display: inline-flex;
|
|
2137
|
+
align-items: center;
|
|
2138
|
+
min-height: 28px;
|
|
2139
|
+
border-radius: 6px;
|
|
2140
|
+
background: var(--tcw-primary);
|
|
2141
|
+
color: #fff;
|
|
2142
|
+
padding: 4px 12px;
|
|
2143
|
+
font-weight: 800;
|
|
2144
|
+
}
|
|
2145
|
+
.tcw-page-size-label {
|
|
2146
|
+
color: var(--tcw-primary);
|
|
2147
|
+
font-weight: 800;
|
|
2148
|
+
}
|
|
2149
|
+
.tcw-page-size-select,
|
|
2150
|
+
.tcw-page-jump-input,
|
|
2151
|
+
.tcw-page-size-fixed {
|
|
2152
|
+
min-height: 28px;
|
|
2153
|
+
border: 1px solid var(--tcw-border);
|
|
2154
|
+
border-radius: 6px;
|
|
2155
|
+
background: #fff;
|
|
2156
|
+
color: var(--tcw-text);
|
|
2157
|
+
padding: 4px 8px;
|
|
2158
|
+
font-size: 12px;
|
|
2159
|
+
}
|
|
2160
|
+
.tcw-page-size-select { min-width: 92px; }
|
|
2161
|
+
.tcw-page-size-fixed { display: inline-flex; align-items: center; }
|
|
2162
|
+
.tcw-page-jump-input { width: 56px; }
|
|
1950
2163
|
.tcw-modal-backdrop { position: fixed; inset: 0; z-index: 10; display: grid; place-items: center; background: rgba(15, 23, 42, .32); padding: 20px; }
|
|
1951
2164
|
.tcw-modal { display: grid; gap: 12px; width: min(900px, 100%); max-height: calc(100vh - 48px); overflow: auto; border: 1px solid var(--tcw-border); border-radius: 8px; background: var(--tcw-card); padding: 16px; box-shadow: 0 18px 48px rgba(15, 23, 42, .18); }
|
|
1952
2165
|
.tcw-form-modal { width: min(960px, 100%); }
|
|
2166
|
+
.tcw-form-modal-supplier {
|
|
2167
|
+
width: min(1180px, calc(100vw - 96px));
|
|
2168
|
+
max-height: min(760px, calc(100vh - 56px));
|
|
2169
|
+
gap: 10px;
|
|
2170
|
+
padding: 14px;
|
|
2171
|
+
}
|
|
1953
2172
|
.tcw-confirm-modal { width: min(480px, 100%); }
|
|
1954
2173
|
.tcw-hs-detail-modal { width: min(980px, 100%); }
|
|
1955
2174
|
.tcw-modal-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
|
@@ -1959,6 +2178,61 @@ button, input, textarea, select { font: inherit; letter-spacing: 0; }
|
|
|
1959
2178
|
.tcw-edit-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
|
|
1960
2179
|
.tcw-edit-grid-two { grid-template-columns: repeat(2, minmax(260px, 1fr)); }
|
|
1961
2180
|
.tcw-field-wide { grid-column: 1 / -1; }
|
|
2181
|
+
.tcw-form-modal-supplier .tcw-modal-head h2 { font-size: 17px; }
|
|
2182
|
+
.tcw-form-modal-supplier .tcw-edit-grid-two {
|
|
2183
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
2184
|
+
gap: 8px 12px;
|
|
2185
|
+
}
|
|
2186
|
+
.tcw-form-modal-supplier .tcw-field { gap: 4px; }
|
|
2187
|
+
.tcw-form-modal-supplier .tcw-field span { font-size: 11px; }
|
|
2188
|
+
.tcw-form-modal-supplier .tcw-field input,
|
|
2189
|
+
.tcw-form-modal-supplier .tcw-field select {
|
|
2190
|
+
min-height: 32px;
|
|
2191
|
+
padding: 6px 9px;
|
|
2192
|
+
}
|
|
2193
|
+
.tcw-form-modal-supplier .tcw-field textarea {
|
|
2194
|
+
min-height: 58px;
|
|
2195
|
+
padding: 7px 9px;
|
|
2196
|
+
}
|
|
2197
|
+
.tcw-form-modal-supplier .tcw-field-wide {
|
|
2198
|
+
grid-column: span 3;
|
|
2199
|
+
}
|
|
2200
|
+
.tcw-form-modal-supplier .tcw-hs-candidate-panel {
|
|
2201
|
+
display: grid;
|
|
2202
|
+
grid-template-columns: minmax(0, 1fr) minmax(320px, .55fr);
|
|
2203
|
+
gap: 10px;
|
|
2204
|
+
align-items: start;
|
|
2205
|
+
border-top: 1px solid var(--tcw-border);
|
|
2206
|
+
padding-top: 10px;
|
|
2207
|
+
}
|
|
2208
|
+
.tcw-form-modal-supplier .tcw-hs-candidate-panel > .tcw-subsection-head {
|
|
2209
|
+
align-items: center;
|
|
2210
|
+
}
|
|
2211
|
+
.tcw-form-modal-supplier .tcw-hs-candidate-panel > .tcw-table-wrap,
|
|
2212
|
+
.tcw-form-modal-supplier .tcw-hs-candidate-panel > .tcw-empty,
|
|
2213
|
+
.tcw-form-modal-supplier .tcw-hs-candidate-panel > .tcw-error {
|
|
2214
|
+
grid-column: 1 / -1;
|
|
2215
|
+
max-height: 210px;
|
|
2216
|
+
overflow: auto;
|
|
2217
|
+
}
|
|
2218
|
+
.tcw-form-modal-supplier .tcw-hs-candidate-result {
|
|
2219
|
+
display: grid;
|
|
2220
|
+
gap: 8px;
|
|
2221
|
+
grid-column: 1 / -1;
|
|
2222
|
+
}
|
|
2223
|
+
.tcw-form-modal-supplier .tcw-hs-candidate-result .tcw-table-wrap {
|
|
2224
|
+
max-height: 210px;
|
|
2225
|
+
}
|
|
2226
|
+
.tcw-form-modal-supplier .tcw-hs-candidate-search {
|
|
2227
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
2228
|
+
}
|
|
2229
|
+
.tcw-form-modal-supplier .tcw-modal-actions {
|
|
2230
|
+
position: sticky;
|
|
2231
|
+
bottom: -14px;
|
|
2232
|
+
border-top: 1px solid var(--tcw-border);
|
|
2233
|
+
background: var(--tcw-card);
|
|
2234
|
+
padding-top: 10px;
|
|
2235
|
+
}
|
|
1962
2236
|
.tcw-confirm-text { margin: 0; color: var(--tcw-text); font-size: 14px; line-height: 1.7; }
|
|
1963
2237
|
.tcw-detail-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
|
|
1964
2238
|
.tcw-detail-field { display: grid; grid-template-columns: 108px minmax(0, 1fr); gap: 8px; align-items: start; border: 1px solid var(--tcw-border); border-radius: 6px; background: var(--tcw-soft); padding: 8px 10px; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chenchaolong/plugin-trade-compliance-workbench",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.49",
|
|
4
4
|
"description": "Trade Compliance Workbench app plugin for controlled goods review, supplier product management, and customs workbook generation.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "XpertAI",
|