@chenchaolong/plugin-trade-compliance-workbench 0.1.45 → 0.1.47

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.
@@ -630,7 +630,6 @@
630
630
  )
631
631
  )
632
632
  ),
633
- renderAssistantPanel(),
634
633
  detailItem ? renderDetailModal() : null,
635
634
  formDialog ? renderFormModal() : null,
636
635
  deleteDialog ? renderDeleteConfirmModal() : null,
@@ -647,61 +646,18 @@
647
646
  )
648
647
  ),
649
648
  h('nav', { className: 'tcw-nav', 'aria-label': '主导航' }, [
650
- tab('overview-page', '总览', '1', pendingItems.length, 'blue'),
651
- tab('controlled-goods-page', '管控规则库', '2', controlledReviews.length, 'green'),
652
- tab('products-page', '供应商商品', '3', supplierReviews.length, 'orange'),
653
- tab('workbooks-page', '销售发票', '4', salesReviews.length + filteredWorkbooks.length, 'violet'),
654
- tab('hs-code-search-page', '工具', '5', null, 'slate')
655
- ]),
656
- h('section', { className: 'tcw-sidebar-section' },
657
- h('h2', null, '主流程'),
658
- h('ol', { className: 'tcw-flow-list' }, [
659
- '维护管控规则',
660
- '上传供应商合同',
661
- '确认 HS 编码候选',
662
- '审核供应商商品',
663
- '上传购销合同',
664
- '生成销售发票'
665
- ].map((item) => h('li', { key: item }, h('span', null), item)))
666
- ),
667
- h('section', { className: 'tcw-sidebar-section compact' },
668
- h('h2', null, '数据关系'),
669
- h('p', null, '管控规则用于匹配供应商商品,已确认商品进入销售发票生成流程。')
670
- )
671
- )
672
- }
673
-
674
- function renderAssistantPanel() {
675
- return h('aside', { className: 'tcw-assistant' },
676
- h('div', { className: 'tcw-assistant-head' },
677
- h('span', { className: 'tcw-assistant-mark' }, 'AI'),
678
- h('div', null,
679
- h('strong', null, '外贸合规助手'),
680
- h('p', null, '按流程处理识别结果,减少来回切换。')
681
- )
682
- ),
683
- h('section', { className: 'tcw-assistant-card' },
684
- h('h3', null, '当前建议'),
685
- h('p', null, assistantTip(activePage))
686
- ),
687
- h('section', { className: 'tcw-assistant-card' },
688
- h('h3', null, '快捷入口'),
689
- h('div', { className: 'tcw-assistant-actions' }, [
690
- h('button', { className: 'tcw-mini-btn', onClick: () => setActivePage('controlled-goods-page') }, '管控规则'),
691
- h('button', { className: 'tcw-mini-btn', onClick: () => setActivePage('products-page') }, '商品审核'),
692
- h('button', { className: 'tcw-mini-btn', onClick: () => setActivePage('hs-code-search-page') }, '查 HS 编码')
693
- ])
694
- ),
695
- h('section', { className: 'tcw-assistant-card' },
696
- h('h3', null, '处理顺序'),
697
- h('p', null, '先把管控规则和供应商商品确认入库,再审核购销合同并生成销售发票。')
698
- )
649
+ tab('overview-page', '总览', 'dashboard', pendingItems.length, 'blue'),
650
+ tab('controlled-goods-page', '管控商品', 'shield', controlledReviews.length, 'green'),
651
+ tab('products-page', '供应商商品', 'box', supplierReviews.length, 'orange'),
652
+ tab('workbooks-page', '销售发票', 'invoice', salesReviews.length + filteredWorkbooks.length, 'violet'),
653
+ tab('hs-code-search-page', '工具', 'search', null, 'slate')
654
+ ])
699
655
  )
700
656
  }
701
657
 
702
658
  function tab(key, label, icon, count, tone) {
703
659
  return h('button', { key, className: key === activePage ? 'tcw-tab active' : 'tcw-tab', onClick: () => setActivePage(key) },
704
- h('span', { className: 'tcw-nav-icon ' + (tone || 'blue') }, icon),
660
+ h('span', { className: 'tcw-nav-icon ' + (tone || 'blue') }, iconImage(icon, label, tone)),
705
661
  h('span', null, label),
706
662
  count == null ? null : h('em', null, count)
707
663
  )
@@ -713,22 +669,22 @@
713
669
  : pendingItems.filter((item) => item.type === overviewTab).slice(0, 12)
714
670
  return h('div', { className: 'tcw-page overview-page' },
715
671
  h('section', { className: 'tcw-metrics' },
716
- metric('待审核', pendingItems.length, '', 'blue'),
717
- metric('管控识别待审', pendingControlledReviews.length, '', 'green'),
718
- metric('供应商商品待审', pendingSupplierReviews.length, '', 'orange'),
719
- metric('销售合同待审', pendingSalesReviews.length, '', 'violet'),
720
- metric('已入库管控商品', data.controlledGoods.length, '', 'slate'),
721
- metric('已入库供应商商品', data.products.length, '', 'green'),
722
- metric('销售发票历史', data.workbookGenerations.length, '', 'violet'),
723
- metric('全部审核记录', reviewItems.length, '', 'blue')
672
+ metric('待审核', pendingItems.length, 'dashboard', 'blue'),
673
+ metric('管控识别待审', pendingControlledReviews.length, 'shield', 'green'),
674
+ metric('供应商商品待审', pendingSupplierReviews.length, 'box', 'orange'),
675
+ metric('销售合同待审', pendingSalesReviews.length, 'invoice', 'violet'),
676
+ metric('已入库管控商品', data.controlledGoods.length, 'archive', 'slate'),
677
+ metric('已入库供应商商品', data.products.length, 'supplier', 'green'),
678
+ metric('销售发票历史', data.workbookGenerations.length, 'document', 'violet'),
679
+ metric('全部审核记录', reviewItems.length, 'records', 'blue')
724
680
  ),
725
681
  panel('待办事项明细',
726
682
  h('div', { className: 'tcw-overview-panel' },
727
683
  h('div', { className: 'tcw-overview-tabs' }, [
728
684
  overviewTabButton('all', '全部', pendingItems.length),
729
- overviewTabButton('controlled_goods', '规则', pendingItems.filter((item) => item.type === 'controlled_goods').length),
730
- overviewTabButton('supplier_product', '商品', pendingItems.filter((item) => item.type === 'supplier_product').length),
731
- overviewTabButton('customs_workbook', '发票', pendingItems.filter((item) => item.type === 'customs_workbook').length)
685
+ overviewTabButton('controlled_goods', '管控商品', pendingItems.filter((item) => item.type === 'controlled_goods').length),
686
+ overviewTabButton('supplier_product', '供应商商品', pendingItems.filter((item) => item.type === 'supplier_product').length),
687
+ overviewTabButton('customs_workbook', '销售发票', pendingItems.filter((item) => item.type === 'customs_workbook').length)
732
688
  ]),
733
689
  pendingOverviewItems.length
734
690
  ? compactReviewList(pendingOverviewItems)
@@ -1307,7 +1263,7 @@
1307
1263
 
1308
1264
  function metric(label, valueText, icon, tone) {
1309
1265
  return h('div', { className: 'tcw-metric' },
1310
- h('span', { className: 'tcw-metric-icon ' + (tone || 'blue') }, icon || '·'),
1266
+ h('span', { className: 'tcw-metric-icon ' + (tone || 'blue') }, iconImage(icon, label, tone)),
1311
1267
  h('div', { className: 'tcw-metric-body' },
1312
1268
  h('span', null, label),
1313
1269
  h('strong', null, valueText)
@@ -1315,6 +1271,34 @@
1315
1271
  )
1316
1272
  }
1317
1273
 
1274
+ function iconImage(name, label, tone) {
1275
+ return h('img', { src: iconDataUri(name, tone), alt: label || '', 'aria-hidden': label ? undefined : true })
1276
+ }
1277
+
1278
+ function iconDataUri(name, tone) {
1279
+ const colors = {
1280
+ blue: '#2563eb',
1281
+ green: '#139160',
1282
+ orange: '#e07818',
1283
+ violet: '#7c3aed',
1284
+ slate: '#526174'
1285
+ }
1286
+ const color = colors[tone] || colors.blue
1287
+ const paths = {
1288
+ dashboard: '<rect x="4" y="4" width="7" height="7" rx="1.5"/><rect x="13" y="4" width="7" height="7" rx="1.5"/><rect x="4" y="13" width="7" height="7" rx="1.5"/><rect x="13" y="13" width="7" height="7" rx="1.5"/>',
1289
+ shield: '<path d="M12 3l7 3v5c0 4.8-2.9 8.2-7 10-4.1-1.8-7-5.2-7-10V6l7-3z"/><path d="M9 12l2 2 4-5"/>',
1290
+ box: '<path d="M4 8l8-4 8 4-8 4-8-4z"/><path d="M4 8v8l8 4 8-4V8"/><path d="M12 12v8"/>',
1291
+ invoice: '<path d="M7 3h8l4 4v14l-3-1.5L13 21l-3-1.5L7 21V3z"/><path d="M15 3v5h4"/><path d="M9 11h6"/><path d="M9 15h6"/>',
1292
+ search: '<circle cx="11" cy="11" r="6"/><path d="M16 16l4 4"/>',
1293
+ archive: '<path d="M4 7h16v13H4V7z"/><path d="M3 4h18v3H3z"/><path d="M9 11h6"/>',
1294
+ supplier: '<path d="M4 20V8l8-4 8 4v12"/><path d="M8 20v-7h8v7"/><path d="M10 9h4"/>',
1295
+ document: '<path d="M7 3h7l5 5v13H7V3z"/><path d="M14 3v6h5"/><path d="M9 13h6"/><path d="M9 17h6"/>',
1296
+ records: '<path d="M6 5h12v16H6V5z"/><path d="M9 3h6v4H9z"/><path d="M9 11h6"/><path d="M9 15h6"/>'
1297
+ }
1298
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="${color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${paths[name] || paths.dashboard}</svg>`
1299
+ return 'data:image/svg+xml;utf8,' + encodeURIComponent(svg)
1300
+ }
1301
+
1318
1302
  function panel(title, content) {
1319
1303
  return h('section', { className: 'tcw-panel' }, h('h3', null, title), content)
1320
1304
  }
@@ -1824,7 +1808,7 @@
1824
1808
 
1825
1809
  function pageTitle(key) {
1826
1810
  if (key === 'overview-page') return '总览'
1827
- if (key === 'controlled-goods-page') return '管控规则库'
1811
+ if (key === 'controlled-goods-page') return '管控商品'
1828
1812
  if (key === 'products-page') return '供应商商品'
1829
1813
  if (key === 'hs-code-search-page') return '工具'
1830
1814
  return '销售发票'
@@ -1840,20 +1824,12 @@
1840
1824
 
1841
1825
  function pageBreadcrumb(key) {
1842
1826
  if (key === 'overview-page') return 'Workspace / 总览'
1843
- if (key === 'controlled-goods-page') return 'Workspace / 管控规则库'
1827
+ if (key === 'controlled-goods-page') return 'Workspace / 管控商品'
1844
1828
  if (key === 'products-page') return 'Workspace / 供应商商品'
1845
1829
  if (key === 'workbooks-page') return 'Workspace / 销售发票'
1846
1830
  return 'Workspace / 工具'
1847
1831
  }
1848
1832
 
1849
- function assistantTip(key) {
1850
- if (key === 'overview-page') return '从总览开始,优先确认管控规则和供应商商品,再推进发票生成。'
1851
- if (key === 'controlled-goods-page') return '维护管控商品时,建议先核对 HS 编码和关键词,再保存入库。'
1852
- if (key === 'products-page') return '供应商商品可先选用候选 HS 编码,再检查英文品名和管控状态。'
1853
- if (key === 'workbooks-page') return '购销合同审核完毕后,再生成销售发票,避免后面重改。'
1854
- return '海关编码查询页用于人工确认候选结果,必要时可回到商品页继续处理。'
1855
- }
1856
-
1857
1833
  function isObject(value) {
1858
1834
  return value && typeof value === 'object' && !Array.isArray(value)
1859
1835
  }
@@ -1926,6 +1902,11 @@ button, input, textarea, select { font: inherit; letter-spacing: 0; }
1926
1902
  font-size: 18px;
1927
1903
  font-weight: 900;
1928
1904
  }
1905
+ .tcw-metric-icon img {
1906
+ width: 22px;
1907
+ height: 22px;
1908
+ color: currentColor;
1909
+ }
1929
1910
  .tcw-metric-icon.blue { background: #e8f0ff; color: var(--tcw-primary); }
1930
1911
  .tcw-metric-icon.green { background: #e7f8ef; color: var(--tcw-success); }
1931
1912
  .tcw-metric-icon.orange { background: #fff2df; color: var(--tcw-warning); }
@@ -2041,7 +2022,7 @@ button, input, textarea, select { font: inherit; letter-spacing: 0; }
2041
2022
  body { background: var(--tcw-bg); letter-spacing: 0; }
2042
2023
  .tcw-shell {
2043
2024
  display: grid;
2044
- grid-template-columns: 248px minmax(0, 1fr) 300px;
2025
+ grid-template-columns: 248px minmax(0, 1fr);
2045
2026
  grid-template-rows: 1fr;
2046
2027
  gap: 0;
2047
2028
  min-height: 100vh;
@@ -2144,48 +2125,16 @@ body { background: var(--tcw-bg); letter-spacing: 0; }
2144
2125
  font-size: 11px;
2145
2126
  font-weight: 900;
2146
2127
  }
2128
+ .tcw-nav-icon img {
2129
+ width: 16px;
2130
+ height: 16px;
2131
+ color: currentColor;
2132
+ }
2147
2133
  .tcw-nav-icon.blue { background: #e8f0ff; color: var(--tcw-primary); }
2148
2134
  .tcw-nav-icon.green { background: #e7f8ef; color: var(--tcw-success); }
2149
2135
  .tcw-nav-icon.orange { background: #fff2df; color: var(--tcw-warning); }
2150
2136
  .tcw-nav-icon.violet { background: #f1eaff; color: var(--tcw-violet); }
2151
2137
  .tcw-nav-icon.slate { background: #eef2f6; color: var(--tcw-slate); }
2152
- .tcw-sidebar-section {
2153
- display: grid;
2154
- gap: 8px;
2155
- border-top: 1px solid var(--tcw-border);
2156
- padding: 14px 6px 0;
2157
- }
2158
- .tcw-sidebar-section h2 {
2159
- margin: 0;
2160
- color: var(--tcw-muted);
2161
- font-size: 12px;
2162
- }
2163
- .tcw-sidebar-section.compact p {
2164
- margin: 0;
2165
- color: var(--tcw-muted);
2166
- font-size: 12px;
2167
- line-height: 1.6;
2168
- }
2169
- .tcw-flow-list {
2170
- display: grid;
2171
- gap: 8px;
2172
- margin: 0;
2173
- padding: 0;
2174
- list-style: none;
2175
- color: var(--tcw-text);
2176
- font-size: 12px;
2177
- }
2178
- .tcw-flow-list li {
2179
- display: flex;
2180
- gap: 8px;
2181
- align-items: center;
2182
- }
2183
- .tcw-flow-list span {
2184
- width: 7px;
2185
- height: 7px;
2186
- border-radius: 999px;
2187
- background: var(--tcw-primary);
2188
- }
2189
2138
  .tcw-workspace {
2190
2139
  display: grid;
2191
2140
  grid-template-rows: auto 1fr;
@@ -2276,68 +2225,12 @@ body { background: var(--tcw-bg); letter-spacing: 0; }
2276
2225
  }
2277
2226
  .tcw-table td { background: var(--tcw-card); }
2278
2227
  .tcw-table tr:hover td { background: #fbfdff; }
2279
- .tcw-assistant {
2280
- display: grid;
2281
- align-content: start;
2282
- gap: 12px;
2283
- border-left: 1px solid var(--tcw-border);
2284
- background: var(--tcw-card);
2285
- padding: 18px 14px;
2286
- }
2287
- .tcw-assistant-head {
2288
- display: flex;
2289
- align-items: flex-start;
2290
- gap: 10px;
2291
- padding: 2px 4px 8px;
2292
- }
2293
- .tcw-assistant-mark {
2294
- display: grid;
2295
- place-items: center;
2296
- width: 32px;
2297
- height: 32px;
2298
- border-radius: 8px;
2299
- background: #e7f8ef;
2300
- color: var(--tcw-success);
2301
- font-size: 12px;
2302
- font-weight: 900;
2303
- }
2304
- .tcw-assistant-head strong { display: block; font-size: 15px; }
2305
- .tcw-assistant-head p {
2306
- margin: 3px 0 0;
2307
- color: var(--tcw-muted);
2308
- font-size: 12px;
2309
- line-height: 1.5;
2310
- }
2311
- .tcw-assistant-card {
2312
- display: grid;
2313
- gap: 8px;
2314
- border: 1px solid var(--tcw-border);
2315
- border-radius: 8px;
2316
- background: var(--tcw-soft);
2317
- padding: 12px;
2318
- }
2319
- .tcw-assistant-card h3 {
2320
- margin: 0;
2321
- font-size: 13px;
2322
- }
2323
- .tcw-assistant-card p {
2324
- margin: 0;
2325
- color: var(--tcw-muted);
2326
- font-size: 12px;
2327
- line-height: 1.6;
2328
- }
2329
- .tcw-assistant-actions {
2330
- display: flex;
2331
- flex-wrap: wrap;
2332
- gap: 8px;
2333
- }
2334
2228
  .tcw-status.ok { background: #e7f8ef; color: var(--tcw-success); }
2335
2229
  .tcw-status.warn { background: #fff2df; color: #b35b00; }
2336
2230
  .tcw-status.danger { background: #fde8e6; color: var(--tcw-danger); }
2337
2231
  .tcw-status.muted { background: #eef2f6; color: var(--tcw-muted); }
2338
2232
  @media (max-width: 1280px) {
2339
2233
  .tcw-shell { grid-template-columns: 230px minmax(0, 1fr); }
2340
- .tcw-assistant { display: none; }
2341
2234
  }
2342
2235
  @media (max-width: 900px) {
2343
2236
  .tcw-shell { grid-template-columns: 1fr; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chenchaolong/plugin-trade-compliance-workbench",
3
- "version": "0.1.45",
3
+ "version": "0.1.47",
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",