@chenchaolong/plugin-trade-compliance-workbench 0.1.6 → 0.1.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.
@@ -311,12 +311,13 @@
311
311
  }
312
312
 
313
313
  function renderProductsPage() {
314
- const groups = groupBy(filteredProducts, (item) => value(item.supplierName, '未识别供应商'))
315
314
  return h('div', { className: 'tcw-page products-page' },
316
- pageToolbar('供应商商品', '供应商合同识别结果先进入待审核,确认后按供应商归类入库。', [
315
+ businessPanel('供应商商品', '上传供应商合同后,识别结果在列表内完成审核、驳回和入库。', [
317
316
  uploadButton('upload_supplier_contract', '上传供应商合同')
318
- ]),
319
- renderListPanel('供应商商品列表', 'pending-supplier-products', supplierReviews, ['供应商', '商品', '型号', '海关编码', '退税率', '英文品名', '管控状态'], (item) => {
317
+ ], [
318
+ renderListToolbar('供应商商品列表', supplierReviews.length),
319
+ h('div', { className: 'pending-supplier-products tcw-table-section' },
320
+ reviewTable(['供应商', '商品', '型号', '海关编码', '退税率', '英文品名', '管控状态'], supplierReviews, (item) => {
320
321
  const row = readMerged(item)
321
322
  return [
322
323
  value(row.supplierName),
@@ -327,17 +328,21 @@
327
328
  value(row.englishName),
328
329
  status(controlStatusText(row.controlledStatus), controlStatusLevel(row.controlledStatus))
329
330
  ]
330
- }, '暂无供应商商品识别结果。上传供应商合同并等待智能体识别后会显示在这里。')
331
+ }, '暂无供应商商品识别结果。上传供应商合同并等待智能体识别后会显示在这里。')
332
+ )
333
+ ])
331
334
  )
332
335
  }
333
336
 
334
337
  function renderWorkbooksPage() {
335
338
  return h('div', { className: 'tcw-page workbooks-page' },
336
- pageToolbar('销售发票', '上传购销合同后审核发票字段,审核通过后生成固定模板 Excel。', [
339
+ businessPanel('销售发票', '上传购销合同后,先审核发票字段,再生成固定模板 Excel。', [
337
340
  uploadButton('upload_sales_contract', '上传购销合同'),
338
341
  h('button', { className: 'tcw-btn tcw-btn-primary', disabled: busy, onClick: generateWorkbook }, '生成销售发票')
339
- ]),
340
- renderListPanel('购销合同识别列表', 'pending-sales-contracts', salesReviews, ['文件/标题', '发票号', '合同号', '买方', '卖方'], (item) => {
342
+ ], [
343
+ renderListToolbar('购销合同识别列表', salesReviews.length),
344
+ h('div', { className: 'pending-sales-contracts tcw-table-section' },
345
+ reviewTable(['文件/标题', '发票号', '合同号', '买方', '卖方'], salesReviews, (item) => {
341
346
  const row = readMerged(item)
342
347
  return [
343
348
  value(item.title),
@@ -346,14 +351,21 @@
346
351
  value(row.buyerName),
347
352
  value(row.sellerName)
348
353
  ]
349
- }, '暂无购销合同识别结果。'),
350
- panel('已生成销售发票', table(['文件名', '发票号', '合同号', '模板工作表', '状态'], filteredWorkbooks, (item) => [
351
- value(item.fileName),
352
- value(item.invoiceNo),
353
- value(item.contractNo),
354
- Array.isArray(item.sheetNames) ? item.sheetNames.join('、') : '-',
355
- status(value(item.status, 'generated'), 'ok')
356
- ], '暂无销售发票生成历史。'))
354
+ }, '暂无购销合同识别结果。')
355
+ ),
356
+ h('section', { className: 'tcw-history-section' },
357
+ h('div', { className: 'tcw-subsection-head' },
358
+ h('div', null, h('h3', null, '已生成销售发票'), h('p', null, `${filteredWorkbooks.length} 条生成历史`))
359
+ ),
360
+ table(['文件名', '发票号', '合同号', '模板工作表', '状态'], filteredWorkbooks, (item) => [
361
+ value(item.fileName),
362
+ value(item.invoiceNo),
363
+ value(item.contractNo),
364
+ Array.isArray(item.sheetNames) ? item.sheetNames.join('、') : '-',
365
+ status(value(item.status, 'generated'), 'ok')
366
+ ], '暂无销售发票生成历史。')
367
+ )
368
+ ])
357
369
  )
358
370
  }
359
371
 
@@ -380,7 +392,28 @@
380
392
 
381
393
  function renderListPanel(title, className, rows, headers, mapRow, emptyText) {
382
394
  return panel(title, h('div', { className },
383
- h('div', { className: 'tcw-list-toolbar' },
395
+ renderListToolbar(null, rows.length),
396
+ reviewTable(headers, rows, mapRow, emptyText)
397
+ ))
398
+ }
399
+
400
+ function businessPanel(title, subtitle, actions, content) {
401
+ return h('section', { className: 'tcw-business-panel' },
402
+ h('div', { className: 'tcw-business-head' },
403
+ h('div', null, h('h2', null, title), h('p', null, subtitle)),
404
+ h('div', { className: 'tcw-button-row' }, actions)
405
+ ),
406
+ h('div', { className: 'tcw-business-body' }, content)
407
+ )
408
+ }
409
+
410
+ function renderListToolbar(title, total) {
411
+ return h('div', { className: 'tcw-list-toolbar' },
412
+ h('div', { className: 'tcw-list-title' },
413
+ title ? h('h3', null, title) : null,
414
+ h('span', null, `${total || 0} 条记录`)
415
+ ),
416
+ h('div', { className: 'tcw-list-actions' },
384
417
  h('label', { className: 'tcw-filter' },
385
418
  h('span', null, '状态'),
386
419
  h('select', { className: 'status-filter', value: statusFilter, onChange: (event) => { setStatusFilter(event.target.value); setSelectedIds([]) } },
@@ -391,9 +424,8 @@
391
424
  )
392
425
  ),
393
426
  h('button', { className: 'tcw-btn tcw-btn-primary', disabled: busy || selectedIds.length === 0, onClick: batchApproveSelected }, `批量审核${selectedIds.length ? ` (${selectedIds.length})` : ''}`)
394
- ),
395
- reviewTable(headers, rows, mapRow, emptyText)
396
- ))
427
+ )
428
+ )
397
429
  }
398
430
 
399
431
  function reviewTable(headers, rows, mapRow, emptyText) {
@@ -680,11 +712,11 @@
680
712
  * { box-sizing: border-box; }
681
713
  body { margin: 0; background: var(--tcw-bg); color: var(--tcw-text); font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
682
714
  button, input { font: inherit; letter-spacing: 0; }
683
- .tcw-shell { display: grid; gap: 12px; min-height: 100vh; padding: 14px 16px 18px; }
684
- .tcw-header { display: grid; grid-template-columns: minmax(0, 1fr) minmax(340px, 520px); gap: 12px; align-items: end; }
715
+ .tcw-shell { display: grid; gap: 10px; min-height: 100vh; padding: 12px 14px 18px; }
716
+ .tcw-header { display: grid; grid-template-columns: minmax(260px, .72fr) minmax(340px, 520px); gap: 12px; align-items: center; border: 1px solid var(--tcw-border); border-radius: 8px; background: var(--tcw-card); padding: 12px 14px; }
685
717
  .tcw-title-block { display: grid; gap: 3px; }
686
718
  .tcw-kicker { color: var(--tcw-primary); font-size: 12px; font-weight: 900; }
687
- .tcw-title-block h1 { margin: 0; font-size: 22px; line-height: 1.22; }
719
+ .tcw-title-block h1 { margin: 0; font-size: 20px; line-height: 1.22; }
688
720
  .tcw-title-block p, .tcw-page-head p, .tcw-drawer-head p { margin: 0; color: var(--tcw-muted); font-size: 13px; }
689
721
  .tcw-header-actions { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; }
690
722
  .tcw-search, .tcw-field input { width: 100%; min-height: 36px; border: 1px solid var(--tcw-border); border-radius: 6px; background: var(--tcw-card); color: var(--tcw-text); padding: 8px 10px; }
@@ -697,18 +729,28 @@ button, input { font: inherit; letter-spacing: 0; }
697
729
  .tcw-upload { border-style: dashed; border-color: color-mix(in srgb, var(--tcw-primary) 42%, var(--tcw-border)); color: var(--tcw-primary); font-weight: 800; }
698
730
  .tcw-upload input { display: none; }
699
731
  .tcw-notice { border: 1px solid color-mix(in srgb, var(--tcw-primary) 24%, var(--tcw-border)); border-radius: 6px; background: color-mix(in srgb, var(--tcw-primary) 7%, var(--tcw-card)); padding: 10px 12px; color: var(--tcw-primary-dark); font-size: 13px; }
700
- .tcw-tabs { display: flex; gap: 6px; overflow-x: auto; border-bottom: 1px solid var(--tcw-border); }
701
- .tcw-tab { min-height: 38px; border: 0; border-bottom: 3px solid transparent; background: transparent; color: var(--tcw-muted); padding: 8px 12px; cursor: pointer; font-weight: 900; }
732
+ .tcw-tabs { display: flex; gap: 6px; overflow-x: auto; border-bottom: 1px solid var(--tcw-border); padding: 0 2px; }
733
+ .tcw-tab { min-height: 34px; border: 0; border-bottom: 3px solid transparent; background: transparent; color: var(--tcw-muted); padding: 7px 12px; cursor: pointer; font-weight: 900; }
702
734
  .tcw-tab.active { border-color: var(--tcw-primary); color: var(--tcw-primary); }
703
735
  .tcw-main { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; align-items: start; }
704
736
  .tcw-main.with-drawer { grid-template-columns: minmax(0, 1fr) minmax(340px, 410px); }
705
737
  .tcw-content, .tcw-drawer, .tcw-panel, .tcw-supplier-block { border: 1px solid var(--tcw-border); border-radius: 8px; background: var(--tcw-card); }
706
- .tcw-content { min-width: 0; padding: 12px; }
738
+ .tcw-content { min-width: 0; border: 0; background: transparent; padding: 0; }
707
739
  .tcw-page { display: grid; gap: 12px; }
708
740
  .tcw-page-head, .tcw-drawer-head, .tcw-supplier-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
709
741
  .tcw-page-head h2, .tcw-drawer-head h2, .tcw-panel h3 { margin: 0 0 4px; font-size: 16px; line-height: 1.35; }
710
742
  .tcw-button-row { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; }
711
743
  .tcw-panel { display: grid; gap: 10px; padding: 12px; }
744
+ .tcw-business-panel { display: grid; gap: 0; border: 1px solid var(--tcw-border); border-radius: 8px; background: var(--tcw-card); overflow: hidden; }
745
+ .tcw-business-head { display: flex; align-items: center; justify-content: space-between; gap: 14px; border-bottom: 1px solid var(--tcw-border); background: var(--tcw-card); padding: 14px 16px; }
746
+ .tcw-business-head h2 { margin: 0 0 4px; font-size: 18px; line-height: 1.25; }
747
+ .tcw-business-head p { margin: 0; color: var(--tcw-muted); font-size: 13px; }
748
+ .tcw-business-body { display: grid; gap: 12px; padding: 14px 16px 16px; }
749
+ .tcw-table-section { display: grid; gap: 0; }
750
+ .tcw-history-section { display: grid; gap: 10px; border-top: 1px solid var(--tcw-border); padding-top: 14px; }
751
+ .tcw-subsection-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
752
+ .tcw-subsection-head h3, .tcw-list-title h3 { margin: 0; font-size: 15px; line-height: 1.3; }
753
+ .tcw-subsection-head p, .tcw-list-title span { margin: 0; color: var(--tcw-muted); font-size: 12px; }
712
754
  .tcw-metrics { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
713
755
  .tcw-metric { display: grid; gap: 4px; border: 1px solid var(--tcw-border); border-radius: 8px; background: var(--tcw-card); padding: 12px; }
714
756
  .tcw-metric span { color: var(--tcw-muted); font-size: 12px; }
@@ -724,7 +766,9 @@ button, input { font: inherit; letter-spacing: 0; }
724
766
  .tcw-table tr:last-child td { border-bottom: 0; }
725
767
  .tcw-table tr.clickable { cursor: pointer; }
726
768
  .tcw-table tr.clickable:hover td { background: color-mix(in srgb, var(--tcw-primary) 5%, transparent); }
727
- .tcw-list-toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; }
769
+ .tcw-list-toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
770
+ .tcw-list-title { display: grid; gap: 2px; min-width: 160px; }
771
+ .tcw-list-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 8px; }
728
772
  .tcw-filter { display: inline-flex; align-items: center; gap: 8px; color: var(--tcw-muted); font-size: 13px; font-weight: 800; }
729
773
  .tcw-filter select { min-height: 34px; border: 1px solid var(--tcw-border); border-radius: 6px; background: var(--tcw-card); color: var(--tcw-text); padding: 6px 28px 6px 9px; }
730
774
  .tcw-row-actions { display: flex; flex-wrap: wrap; gap: 6px; }
@@ -732,7 +776,7 @@ button, input { font: inherit; letter-spacing: 0; }
732
776
  .tcw-mini-btn.danger { border-color: color-mix(in srgb, var(--tcw-danger) 35%, var(--tcw-border)); background: color-mix(in srgb, var(--tcw-danger) 6%, var(--tcw-card)); color: var(--tcw-danger); }
733
777
  .tcw-mini-btn:disabled { cursor: not-allowed; opacity: .5; }
734
778
  .row-selection-checkbox { width: 16px; height: 16px; }
735
- .tcw-empty { display: grid; place-items: center; min-height: 96px; border: 1px dashed var(--tcw-border); border-radius: 8px; background: var(--tcw-soft); color: var(--tcw-muted); padding: 18px; text-align: center; }
779
+ .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; }
736
780
  .tcw-supplier-block { display: grid; gap: 10px; padding: 12px; }
737
781
  .tcw-supplier-head strong { font-size: 15px; }
738
782
  .tcw-supplier-head span { color: var(--tcw-muted); font-size: 12px; }
@@ -758,6 +802,8 @@ button, input { font: inherit; letter-spacing: 0; }
758
802
  .tcw-status.muted { background: #eef2f6; color: var(--tcw-muted); }
759
803
  @media (max-width: 1040px) {
760
804
  .tcw-header, .tcw-main.with-drawer, .tcw-form { grid-template-columns: 1fr; }
805
+ .tcw-business-head { align-items: stretch; flex-direction: column; }
806
+ .tcw-button-row, .tcw-list-actions { justify-content: flex-start; }
761
807
  .tcw-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
762
808
  .tcw-drawer { position: static; max-height: none; }
763
809
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chenchaolong/plugin-trade-compliance-workbench",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
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",