From 67cf30b6e858486dbf67b7d21a3e3dd074e1b29f Mon Sep 17 00:00:00 2001 From: zzh <1368735060@qq.com> Date: Thu, 9 Jul 2026 18:36:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=87=AA=E5=8A=A8=E8=A7=A6=E5=8F=91?= =?UTF-8?q?=E5=85=AC=E5=BC=8F=E5=BC=95=E6=93=8E=E3=80=81=E6=9F=A5=E4=BB=B7?= =?UTF-8?q?=E5=88=86=E7=BB=84=E8=BF=90=E8=BE=93=E6=96=B9=E5=BC=8F=E4=B8=8E?= =?UTF-8?q?=E9=94=80=E5=94=AE=E4=BA=A7=E5=93=81=E9=A2=84=E8=A7=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增自动触发中文公式编辑/测试、查价运输方式 Tab 分组选择,并完善销售产品字段预览与菜单展示。 Co-authored-by: Cursor --- .eslintrc-auto-import.json | 1 + docs/oms系统设计-050801.md | 373 ++++++++- pnpm-lock.yaml | 773 +++++++++++++++++- src/api/channel/autoTrigger.ts | 32 + src/api/order/index.ts | 53 ++ src/auto-imports.d.ts | 7 + src/components/breadcrumb/index.vue | 15 +- src/components/tab-bar/tab-item.vue | 2 +- src/components/top-nav/index.vue | 33 +- src/composables/useMenuDisplay.ts | 38 + src/locale/en-US.ts | 27 + src/locale/zh-CN.ts | 27 + src/store/modules/tab-bar/index.ts | 30 +- src/utils/menu-display.ts | 93 +++ .../components/FormulaConditionEditor.vue | 301 +++++++ .../channel/autoTrigger/conditionUtils.ts | 71 ++ src/views/channel/autoTrigger/formulaMeta.ts | 313 +++++++ src/views/channel/autoTrigger/index.vue | 607 ++++++++++---- .../ChannelReferencePreviewModal.vue | 245 ++++++ .../components/FormLabelWithPreview.vue | 74 ++ src/views/channel/salesProducts/index.vue | 151 +++- .../components/ShippingMethodTabSelect.vue | 278 +++++++ src/views/order/priceCheck/index.vue | 39 +- 23 files changed, 3355 insertions(+), 228 deletions(-) create mode 100644 src/composables/useMenuDisplay.ts create mode 100644 src/utils/menu-display.ts create mode 100644 src/views/channel/autoTrigger/components/FormulaConditionEditor.vue create mode 100644 src/views/channel/autoTrigger/conditionUtils.ts create mode 100644 src/views/channel/autoTrigger/formulaMeta.ts create mode 100644 src/views/channel/salesProducts/components/ChannelReferencePreviewModal.vue create mode 100644 src/views/channel/salesProducts/components/FormLabelWithPreview.vue create mode 100644 src/views/order/priceCheck/components/ShippingMethodTabSelect.vue diff --git a/.eslintrc-auto-import.json b/.eslintrc-auto-import.json index 564b6e2..6a93a31 100644 --- a/.eslintrc-auto-import.json +++ b/.eslintrc-auto-import.json @@ -214,6 +214,7 @@ "useMediaQuery": true, "useMemoize": true, "useMemory": true, + "useMenuDisplay": true, "useMessageStore": true, "useModel": true, "useMounted": true, diff --git a/docs/oms系统设计-050801.md b/docs/oms系统设计-050801.md index 06bf38c..f12e926 100644 --- a/docs/oms系统设计-050801.md +++ b/docs/oms系统设计-050801.md @@ -2351,7 +2351,7 @@ JWT → mapId(user.userid INT) - **发布记录**:买价与规则的发布历史,支持查看版本内容、回滚到指定版本。 - **黑名单区/偏远分区/价格分区**:共用 KpiArea 表,仅通过 `AreaType` 区分;支持分区及明细(国家/省/市/邮编区间)的增删改查。 - **计重规则/计重进位**:配置计费重量规则与进位方式,明细结构与分区类似。 -- **自动触发**:配置下单/入库/出库时的自动拦截、警告、问题件等触发规则。 +- **自动触发**:配置下单/入库/出库时的自动拦截、警告、问题件等触发规则;**V2 目标**为订单校验规则引擎(结构化条件 + 全字段 + 预报同步拦截),见 **§5.3.0.6.1**。 - **问题模板**:按组织维护问题件话术与通知方式,供标记问题件与自动触发消费(一期 CRUD)。 - **标签设计**:保存 vg-print 导出的标签模板 JSON,支持尾程/客户/入库/出库/sku 等类型。 @@ -3028,7 +3028,368 @@ JWT → mapId(user.userid INT) | `POST .../delete` | 软删 | | `POST .../toggleStatus` | 更新 `Status` | -> **运行时触发引擎**(订单/仓储事件消费规则)**尚未在 oms0414-back 实现**;当前仅为规则 CRUD 落库。 +> **运行时(现状)**:`AutoTriggerRuntimeService` **已部分落地**(见 **§9.2.5**):预报成功 / 入库 / 出库后异步执行;条件匹配器仅支持 **关键字子串** 与 **少量 JSON 等值**,**不支持** 表达式、重量尺寸、客户名称等字段;**拦截** 为预报成功后写 `IsIntercept=1`,**不能阻止下单**。 +> +> **目标(V2 设计稿)**:见 **§5.3.0.6.1**,将自动触发升级为 **订单校验与限制规则引擎**——结构化条件、全量订单字段、比较/集合/逻辑运算符;**预报时机 + 拦截** 在提交前 **同步拒绝** 并返回 `promptMessage`。 + +##### 5.3.0.6.1 自动触发规则引擎 V2(设计稿 · 订单校验与限制) + +> **状态**:设计稿(2026-07-09),**尚未开发**。本节为 `/channel/autoTrigger` 页面与 `AutoTriggerRuntimeService` 的下一版目标设计,服务于 **订单校验、限制下单、自动预警、自动问题件**。 +> +> **业务目标**:运营可在渠道模块配置规则,在 **预报 / 入库 / 出库** 等节点,按 **订单全量相关字段**(主表、件重尺、收发件人、申报内件、客户、产品等)组合条件;动作为 **拦截(禁止继续)**、**警告(通知)**、**问题件(走问题模板)**。 + +###### 1)现状与差距 + +| 维度 | 现状(代码) | V2 目标 | +| --- | --- | --- | +| 配置页 | 触发时机/条件为 **纯文本**;操作三选一硬编码 | 时机/操作走字典;**可视化条件构建器**(字段 + 运算符 + 值) | +| 条件语法 | 关键字子串;JSON 仅 `orderStatus/productCode/channelCode/keyword` 等值 | **结构化 AST**(AND/OR/NOT 分组 + 比较表达式) | +| 可用字段 | 运单号、客户单号、跟踪号、产品/渠道编码 | **订单域全字段**(见 §5.3.0.6.1.4) | +| 运算符 | 无(仅 contains 式关键字) | `>`、`>=`、`<`、`<=`、`=`、`!=`、`between`、`in`、`notIn`、`contains`、`notContains`、`isEmpty`… | +| 预报 + 拦截 | 预报 **成功后** 写 `IsIntercept=1` | **预报提交前同步校验**;命中 **拦截** → **拒绝下单/预报**,返回 `promptMessage` | +| 尺寸/重量 | 未读取 `t_order_weight`、内件 | 支持 **按件重尺类型**(forecast/receive/ship/downstream)及 **内件聚合** | +| 客户 | 未参与匹配 | 支持 `customer.name` / `customer.code` / `customer.group` 等 | +| 规则优先级 | 全部启用规则依次执行 | 增加 `Priority`(数字越小越先);**拦截** 命中即短路 | + +###### 2)核心概念 + +**触发时机(TriggerTiming)** — 字典 `auto_trigger_timing`(扩展): + +| dictCode | 名称 | 挂钩点 | 执行方式 | +| --- | --- | --- | --- | +| `forecast` | 预报 | `POST /order/parcel/create`、批量下单、Excel 导入(均走 `CreateParcelCoreAsync`) | **同步**(提交前) | +| `inbound` | 入库 | `POST /operation/inbound/create` | 异步(扫描成功后) | +| `outbound` | 出库 | `POST /operation/outbound/create` | 异步(扫描成功后) | + +> 兼容:旧数据 `下单`/`order_create`/`预报` 等文本,运行时归一化为 `forecast`。 + +**操作(Operation)** — 字典 `auto_trigger_operation`: + +| dictCode | 名称 | 预报时机行为 | 入库/出库时机行为 | +| --- | --- | --- | --- | +| `intercept` | 拦截 | **拒绝**本次下单/预报,`HTTP` 业务错误文案 = `PromptMessage` | 订单已存在 → 设 `IsIntercept=1` | +| `warn` | 警告 | 允许成功,发站内信(+ 模板占位符) | 同左 | +| `problem` | 问题件 | 允许成功,按 `issueType` 匹配问题模板并标记 | 同左 | + +**两类执行阶段**: + +```mermaid +flowchart LR + A[请求进入] --> B{时机=forecast?} + B -->|是| C[PreCommit 同步评估] + C -->|命中 intercept| D[抛 BusinessException\nPromptMessage] + C -->|未命中或 warn/problem| E[继续预报主流程] + E --> F[预报成功] + F --> G[PostCommit 异步评估\nwarn / problem / 入库出库 intercept] +``` + +- **PreCommit(同步校验)**:仅 `forecast`;用于 **拦截下单**;必须在 `OrderRepository.InsertAsync` **之前**(或至少在写 `predeclared` 之前)调用。 +- **PostCommit(异步处置)**:现有 `AutoTriggerRuntimeService.FireAsync` 演进;用于警告、问题件、以及入库/出库拦截标记。 + +###### 3)示例规则(超尺寸 · 英国 · 指定客户 · 排除产品) + +**业务描述**(运营可读): + +- **触发时机**:预报 +- **触发条件**: + - (单件最大长度 > 60 **或** 单件最大宽度 > 46 **或** 单件长+宽+高 > 150) + - **且** 收件国家包含 `GB` + - **且** 客户名称包含 `阿里国际站/深圳一达通` + - **且** 销售产品 **不包含** `EX_ASP_HKDHL_YD` +- **操作**:拦截 +- **提示语**:`{serviceNo}超尺寸,禁止下单`(预报前尚无运单号时可用固定文案:`超尺寸,禁止下单`) + +**结构化条件(`TriggerCondition` JSON · version=2)**: + +```json +{ + "version": 2, + "logic": "and", + "children": [ + { + "logic": "or", + "children": [ + { "field": "piece.maxLength", "op": "gt", "value": 60 }, + { "field": "piece.maxWidth", "op": "gt", "value": 46 }, + { "field": "piece.sumLwh", "op": "gt", "value": 150 } + ] + }, + { "field": "receiver.countryCode", "op": "in", "value": ["GB"] }, + { "field": "customer.name", "op": "contains", "value": "阿里国际站/深圳一达通" }, + { "field": "productCode", "op": "notIn", "value": ["EX_ASP_HKDHL_YD"] } + ] +} +``` + +**字段取值说明(本例)**: + +| 字段 token | 含义 | 数据来源(预报 PreCommit) | +| --- | --- | --- | +| `piece.maxLength` | 单件最大长度(cm) | `max(包裹预报长宽高, 各内件对应尺寸)`;单包裹场景 = `input.Length` | +| `piece.maxWidth` | 单件最大宽度(cm) | 同上 → `input.Width` | +| `piece.sumLwh` | 单件长+宽+高(cm) | `Length + Width + Height`(按件取 max 后再比) | +| `receiver.countryCode` | 收件国家二字码 | `input.Receiver.CountryCode` 归一化后 | +| `customer.name` | 客户名称 | `t_customer.CustomerName`(`input.CustomerId` 解析) | +| `productCode` | 销售产品编码 | `input.ProductCode` | + +###### 4)条件表达式模型 + +**叶子节点(比较)**: + +```json +{ "field": "forecast.chargeableWeight", "op": "gt", "value": 30 } +``` + +| 属性 | 说明 | +| --- | --- | +| `field` | 字段 token,见 §5.3.0.6.1.5 | +| `op` | 运算符 code,见 §5.3.0.6.1.6 | +| `value` | 标量 / 数组 / 区间 `{ "min": 1, "max": 10 }`(`between`) | + +**分组节点**: + +```json +{ "logic": "and|or", "children": [ /* 叶子或分组 */ ] } +``` + +**否定(可选)**: + +```json +{ "logic": "not", "children": [ { "field": "...", "op": "...", "value": "..." } ] } +``` + +**存储**:继续复用 `t_auto_trigger.TriggerCondition`(TEXT),内容为 **JSON**;`version: 2` 表示新引擎。`version` 缺失或 `version: 1`/纯文本 → 走 **兼容适配器**(映射到现有关键字匹配器,逐步迁移)。 + +###### 5)运算符一览 + +| op | 名称 | 适用类型 | 说明 | +| --- | --- | --- | --- | +| `eq` | 等于 | 字符串/数字/布尔 | | +| `ne` | 不等于 | 同上 | | +| `gt` | 大于 | 数字 | | +| `gte` | 大于等于 | 数字 | | +| `lt` | 小于 | 数字 | | +| `lte` | 小于等于 | 数字 | | +| `between` | 区间内 | 数字 | `value: { min, max }` 闭区间 | +| `in` | 在集合中 | 字符串/数字 | `value: []` | +| `notIn` | 不在集合中 | 字符串/数字 | | +| `contains` | 包含 | 字符串 | 子串,忽略大小写 | +| `notContains` | 不包含 | 字符串 | | +| `startsWith` | 前缀 | 字符串 | | +| `endsWith` | 后缀 | 字符串 | | +| `isEmpty` | 为空 | 任意 | 无需 value | +| `isNotEmpty` | 不为空 | 任意 | | + +> 页面按字段 **值类型** 过滤可选运算符(如数字字段不展示 `contains`)。 + +###### 6)订单相关字段目录(规则引擎可用 token) + +> 下列为 **V2 一期** 拟支持字段;页面左侧按分组展示,右侧选运算符与值。带 `[]` 表示内件聚合。 + +**A. 订单主表 `order.*`** + +| token | 说明 | +| --- | --- | +| `order.serviceNo` | 运单号 | +| `order.clientNo` | 客户单号 | +| `order.trackNo` | 跟踪号 | +| `order.productCode` | 销售产品编码 | +| `order.channelCode` | 服务渠道编码 | +| `order.orderStatus` | 订单状态 | +| `order.cargoAttribute` | 货物属性 | +| `order.exportCustomsMode` | 出口报关方式 | +| `order.warehouseId` | 仓库 ID | +| `order.quantity` | 件数 | +| `order.declaredCurrency` / `order.declaredSum` | 申报币种/总金额 | +| `order.isCod` / `order.codCurrency` / `order.codSum` | COD | +| `order.isIntercept` / `order.isRemote` / `order.isPaid` | 标志位 | +| `order.consigneeCountry` / `order.consigneeCountryName` | 收件国家码/名 | +| `order.salesProductRulesVersion` / `order.salesProductPriceVersion` | 绑定版本 | +| `order.predeclareFailReason` | 预报失败原因 | + +**B. 件重尺 `forecast.*` / `receive.*` / `ship.*` / `downstream.*`** + +| token | 说明 | +| --- | --- | +| `{type}.length` / `width` / `height` | 长/宽/高(cm) | +| `{type}.actualWeight` | 实重(kg) | +| `{type}.volumetricWeight` | 体积重(kg) | +| `{type}.chargeableWeight` | 计费重(kg) | +| `{type}.cubic` | 体积 | +| `{type}.sumLwh` | 长+宽+高 | + +`{type}` ∈ `forecast`(预报,**PreCommit 默认**)、`receive`(收货)、`ship`(发货)、`downstream`(下游)。 + +**C. 包裹/单件聚合 `piece.*`(预报常用)** + +| token | 说明 | +| --- | --- | +| `piece.maxLength` / `piece.maxWidth` / `piece.maxHeight` | 单件最大长宽高 | +| `piece.sumLwh` | 单件长+宽+高(对当前包裹) | +| `piece.maxChargeableWeight` | 单件最大计费重 | + +**D. 收件人 `receiver.*` → `t_order_recipient` / 下单入参** + +`recipientsName`, `companyName`, `phone`, `telePhone`, `email`, `countryCode`, `province`, `city`, `zipCode`, `streetNumber`, `streetAddress1~3`, `taxType`, `taxNo`, `certificateType`, `certificateNo`, `eori`, `vat` + +**E. 发件人 `sender.*` → `t_order_sender` / 下单入参** + +`senderName`, `company`, `phone`, `telePhone`, `email`, `countryCode`, `province`, `city`, `zipCode`, `streetAddress1~3`, `houseNumber` + +**F. 客户 `customer.*` → `t_customer`** + +| token | 说明 | +| --- | --- | +| `customer.id` | 客户 ID | +| `customer.code` | 客户编码 | +| `customer.name` | 客户名称(**本例「客户包含」**) | +| `customer.group` | 客户组 | +| `customer.phone` / `customer.email` | 联系方式 | +| `customer.salesman` / `customer.customerService` | 销售/客服 | + +**G. 销售产品 `product.*` → `t_sales_product`(按 `productCode` 关联)** + +`product.code`, `product.name`, `product.group`, `product.minTimeliness`, `product.maxTimeliness` + +**H. 申报内件聚合 `items.*`** + +| token | 说明 | +| --- | --- | +| `items.count` | 内件行数 | +| `items.totalQuantity` | 数量合计 | +| `items.totalWeight` / `items.totalAmount` | 重量/金额合计 | +| `items.maxUnitWeight` | 最大单重 | +| `items.anyCnName` / `items.anyEnName` | 任一品名包含(需配合 `contains`) | +| `items.anySku` / `items.anyHsCode` | SKU/税号 | +| `items.anyIsMagnetic` | 是否存在带磁内件 | + +**I. 费用快照(二期,可选)** + +`fee.receivable.total` / `fee.payable.total` — 当前阶段应收/应付合计。 + +###### 7)提示语占位符 + +`PromptMessage` 支持 `IssuePlaceholderRenderer` 同款占位符,另增尺寸类: + +| 占位符 | 说明 | +| --- | --- | +| `{serviceNo}` / `{运单号}` | 运单号(PreCommit 未生成时可空) | +| `{clientNo}` / `{客户单号}` | 客户单号 | +| `{productCode}` / `{产品代码}` | 销售产品 | +| `{receiverCountry}` / `{收件国家}` | 国家码 | +| `{pieceMaxLength}` 等 | 触发时计算的聚合值 | + +本例落地文案:**`超尺寸,禁止下单`** 或 **`{clientNo}超尺寸,禁止下单`**。 + +###### 8)配置页 `/channel/autoTrigger` UI 设计 + +**列表页(保持 TablePro/Handsontable)**,列增加:`规则名称`、`优先级`、条件摘要(人类可读)、启用状态。 + +**新增/编辑弹窗**: + +``` +┌─────────────────────────────────────────────────────────┐ +│ 规则名称 * [ 英国阿里超尺寸拦截 ] │ +│ 状态 (•) 启用 ( ) 禁用 │ +│ 触发时机 * [ 预报 ▼ ] (字典 auto_trigger_timing)│ +│ 操作 * [ 拦截 ▼ ] (字典 auto_trigger_operation)│ +│ 优先级 [ 100 ] 数字越小越先执行 │ +├─────────────────────────────────────────────────────────┤ +│ 触发条件 * [+ 添加条件组] │ +│ ┌ 满足 [全部 AND ▼] ─────────────────────────────────┐ │ +│ │ ┌ 满足 [任一 OR ▼] ───────────────────────────────┐ │ │ +│ │ │ [单件最大长度 ▼] [大于 ▼] [ 60 ] [删除] │ │ │ +│ │ │ [单件最大宽度 ▼] [大于 ▼] [ 46 ] [删除] │ │ │ +│ │ │ [单件长+宽+高 ▼] [大于 ▼] [ 150 ] [删除] │ │ │ +│ │ └ [+ 添加条件] │ │ │ +│ │ [收件国家 ▼] [在列表中 ▼] [ GB (+) ] [删除]│ │ +│ │ [客户名称 ▼] [包含 ▼] [ 阿里国际站/深圳一达通 ] │ │ +│ │ [销售产品 ▼] [不在列表 ▼] [ EX_ASP_HKDHL_YD ] │ │ +│ └ [+ 添加条件组] │ │ +├─────────────────────────────────────────────────────────┤ +│ 提示语 * [ 超尺寸,禁止下单 ] │ +│ 通知人 [ 用户多选,仅警告/问题件 ] │ +└─────────────────────────────────────────────────────────┘ +``` + +**交互要点**: + +- 字段下拉分组:订单 / 件重尺 / 收件人 / 发件人 / 客户 / 产品 / 内件聚合。 +- 运算符随字段类型变化;`in`/`notIn` 用多选或标签输入。 +- 底部 **「预览 JSON」** 只读(给研发调试);运营默认不展开。 +- 保存时前端 `condition` 序列化为 §4 JSON,`TriggerTiming`/`Operation` 存 **dictCode**(`forecast`/`intercept`)。 + +###### 9)表结构与接口变更(建议) + +**`t_auto_trigger` 增字段(迁移脚本)**: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| `RuleName` | VARCHAR(128) | 规则名称 | +| `Priority` | INT | 优先级,默认 100 | +| `ConditionVersion` | TINYINT | 条件版本,默认 2 | + +**新增接口(可选)**: + +| 方法 | 路径 | 说明 | +| --- | --- | --- | +| GET | `/channel/auto-trigger/meta` | 返回字段目录、运算符、时机/操作字典(供构建器) | +| POST | `/channel/auto-trigger/test` | 传入样例订单 JSON + 规则 ID,返回是否命中(运营调试) | + +CRUD 入参/出参增加 `ruleName`、`priority`;`triggerCondition` 存 JSON。 + +###### 10)后端评估器设计 + +**新组件**: + +| 类 | 职责 | +| --- | --- | +| `OrderRuleEvaluationContext` | 聚合 `OrderParcelCreateInput`(PreCommit)或 `Order`+子表(PostCommit) | +| `OrderRuleFieldResolver` | token → 强类型值 | +| `OrderRuleConditionEvaluator` | 解析 JSON AST,递归求值 | +| `OrderAutoTriggerService` | 加载启用规则 → 排序 → PreCommit/PostCommit 分流 | + +**PreCommit 调用点**(`OrderService.ParcelBilling.CreateParcelCoreAsync`): + +``` +ValidateParcelCreateInputAsync + → 销售产品/黑名单等硬编码校验 + → OrderAutoTriggerService.EvaluatePreCommitAsync(input, timing=forecast) // 新增 + → InsertAsync(order) ... + → ... 预报成功 ... + → OrderAutoTriggerService.EvaluatePostCommitAsync(order, timing=forecast) // 替代原 FireAsync 或内部转调 +``` + +**拦截短路**:PreCommit 命中 `intercept` → `throw new BusinessException(promptMessage)`;批量下单逐行失败,错误写入任务明细。 + +**PostCommit**:保留警告/问题件/入库出库拦截标记;失败 **仅记日志**,不影响主流程(与现网一致)。 + +###### 11)与硬编码校验的关系 + +| 机制 | 定位 | +| --- | --- | +| 代码内校验(产品存在、黑名单、分区匹配等) | **系统不变量**,不可由运营关闭 | +| 自动触发 V2 | **可配置业务规则**,运营可启停;优先级低于安全类硬编码 | + +黑名单(KPI 分区)与自动触发 **并存**;均命中时 **先执行的** 抛出错误(PreCommit 顺序:硬编码 → 自动触发按 `Priority`)。 + +###### 12)实施分期 + +| 阶段 | 范围 | +| --- | --- | +| **P0** | 表字段 + 条件 JSON 存储 + `OrderRuleConditionEvaluator` + 预报 PreCommit 拦截 + 字段目录 API | +| **P1** | 配置页可视化构建器 + 字典化时机/操作 + 本例超尺寸规则可配置 | +| **P2** | 入库/出库字段(`receive.*`/`ship.*`)+ 测试接口 + 条件人类可读摘要 | +| **P3** | 费用字段、正则、规则命中审计日志 `t_auto_trigger_hit_log` | + +###### 13)验收标准(本例) + +1. 在 `/channel/autoTrigger` 配置 §3 示例规则并启用。 +2. 预报一单:GB、客户名含「阿里国际站/深圳一达通」、尺寸 61×40×40、产品非 `EX_ASP_HKDHL_YD` → **接口失败**,文案「超尺寸,禁止下单」,**不产生** `predeclared` 订单。 +3. 将产品改为 `EX_ASP_HKDHL_YD` → **放行**。 +4. 尺寸改为 50×40×40 → **放行**。 + +--- ##### 5.3.0.7 问题模板(`IssueTemplateService`) @@ -3058,7 +3419,7 @@ JWT → mapId(user.userid INT) | 发布后同步 Redis + 刷新计费内存 | **未实现**;下单读 DB 发布表或 Live 组装(§4.3.5) | | 发布时旧版本 `Status` 置失效 | **未显式**更新历史记录状态;算价按 **`PublishTime <= bindTime` 取最新一条** | | 服务渠道 `publish/preview` | 与卖价对称 | **已落地**:`GET /channel/service-channel/publish/preview` | -| 自动触发执行 | **无**后台消费者 | +| 自动触发执行 | **部分落地** | `AutoTriggerRuntimeService` 已挂钩;**V2 规则引擎见 §5.3.0.6.1** | #### 5.3.1 销售产品 @@ -7477,7 +7838,7 @@ GET /customer/account-flow/list?page=1&pageSize=50&bizType=orderPay&startTime=20 | `/operation/outbound/create` | 出库、outbound、ship、发货 | - **问题件**:按 `triggerCondition` 解析 `issueType`(支持 JSON `{"issueType":"address",...}` 或纯 code),匹配 **问题模板** 后自动标记并通知。 -- **拦截**:`IsIntercept=1`。 +- **拦截**:`IsIntercept=1`(**事后标记**;**不能阻止预报**,预报同步拦截见 **§5.3.0.6.1**)。 - **警告**:仅发站内信(不改编订单状态)。 ### 9.3 20260627-02 差异明细(规则快照下游元数据 + 订单绑定) @@ -7650,7 +8011,7 @@ GET /customer/account-flow/list?page=1&pageSize=50&bizType=orderPay&startTime=20 | 入库 / 出库 | 触发 §4.3.4 分阶段算价 | **仅**作业记录表 | | 管理员订单列表 | §4.4.0 客户门户 | **管理员不过滤** `CustomerId` | | 渠道发布后 Redis 同步 | 写 Redis + 刷新计费内存 | **仅写 DB** 发布记录 | -| 自动触发规则 | 订单/仓储事件消费 | **仅 CRUD 落库**,无运行时引擎 | +| 自动触发规则 | 订单/仓储事件消费 | **部分落地**(关键字匹配 + 事后拦截);**V2 结构化条件 + 预报同步拦截见 §5.3.0.6.1** | | 服务渠道 publish/preview | 同销售产品 | **已落地** | #### 9.6.4 渠道模块已落地要点(详见 §5.3.0) @@ -7836,7 +8197,7 @@ GET /customer/account-flow/list?page=1&pageSize=50&bizType=orderPay&startTime=20 | `/channel/kpi-area/*` | 已落地 | 10 个端点:主表 CRUD + 明细分页 CRUD + **Excel 导入/模板** | | `/channel/weight-rule/*` | 已落地 | 8 个端点:主表 + info 子表 CRUD(POST 路由) | | `/channel/weight-rounding/*` | 已落地 | 8 个端点:同上 | -| `/channel/auto-trigger/*` | 部分 | CRUD + toggleStatus **已落地**;**运行时触发未实现** | +| `/channel/auto-trigger/*` | 部分 | CRUD + toggleStatus + **部分运行时**(事后拦截/警告/问题件);**V2 规则引擎 §5.3.0.6.1 未实现** | | `/channel/label-template/save` | 已落地 | upsert,`Name+TemplateType` 唯一 | **渠道发布与订单算价衔接**:发布快照写入 DB 后,订单 **`ResolveSnapshotBindingAsync`** 按 `PublishTime <= bindTime` 读取;**Redis 同步未实现**(§5.2.6.2)。 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cfdc209..d20d38b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -89,6 +89,9 @@ importers: marked: specifier: ^18.0.4 version: 18.0.5 + mermaid: + specifier: ^11.16.0 + version: 11.16.0 mitt: specifier: ^3.0.0 version: 3.0.1 @@ -454,9 +457,15 @@ packages: resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} engines: {node: '>=6.9.0'} + '@braintree/sanitize-url@7.1.2': + resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} + '@bufbuild/protobuf@2.10.1': resolution: {integrity: sha512-ckS3+vyJb5qGpEYv/s1OebUHDi/xSNtfgw1wqKZo7MR9F2z+qXr0q5XagafAG/9O0QPVIUfST0smluYSTpYFkg==} + '@chevrotain/types@11.1.2': + resolution: {integrity: sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==} + '@claviska/jquery-minicolors@2.3.6': resolution: {integrity: sha512-8Ro6D4GCrmOl41+6w4NFhEOpx8vjxwVRI69bulXsFDt49uVRKhLU5TnzEV7AmOJrylkVq+ugnYNMiGHBieeKUQ==} peerDependencies: @@ -956,6 +965,9 @@ packages: '@iconify/utils@2.3.0': resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==} + '@iconify/utils@3.1.4': + resolution: {integrity: sha512-b1S7B1k9ohZ+iNTi2ATxbRYG9fTrJmUT0rc46bvVnNxqNRGW7dyo/vRREwyniI5IRN2RSJHDcm+s3BjWrSAjHw==} + '@interactjs/types@1.10.27': resolution: {integrity: sha512-BUdv0cvs4H5ODuwft2Xp4eL8Vmi3LcihK42z0Ft/FbVJZoRioBsxH+LlsBdK4tAie7PqlKGy+1oyOncu1nQ6eA==} @@ -1020,6 +1032,9 @@ packages: '@marijn/find-cluster-break@1.0.2': resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} + '@mermaid-js/parser@1.2.0': + resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==} + '@mrmlnc/readdir-enhanced@2.2.1': resolution: {integrity: sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==} engines: {node: '>=4'} @@ -1316,6 +1331,99 @@ packages: '@tybys/wasm-util@0.10.0': resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.4': + resolution: {integrity: sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/diff-match-patch@1.0.36': resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==} @@ -1325,6 +1433,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/glob@7.2.0': resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} @@ -1684,6 +1795,9 @@ packages: cpu: [x64] os: [win32] + '@upsetjs/venn.js@2.0.0': + resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} + '@vitejs/plugin-vue-jsx@2.1.1': resolution: {integrity: sha512-JgDhxstQlwnHBvZ1BSnU5mbmyQ14/t5JhREc6YH5kWyu2QdAAOsLF6xgHoIWarj8tddaiwFrNzLbWJPudpXKYA==} engines: {node: ^14.18.0 || >=16.0.0} @@ -2326,6 +2440,10 @@ packages: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} @@ -2403,6 +2521,12 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + cosmiconfig-typescript-loader@4.4.0: resolution: {integrity: sha512-BabizFdC3wBHhbI4kJh0VkQP9GkBfoHPydD0COMce1nJ1kJAB3F2TmJ/I7diULBKtmEWSwEbuN/KDtgnmUUVmw==} engines: {node: '>=v14.21.3'} @@ -2508,10 +2632,166 @@ packages: engines: {node: '>=10'} hasBin: true + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.34.0: + resolution: {integrity: sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + d@1.0.2: resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} engines: {node: '>=0.12'} + dagre-d3-es@7.0.14: + resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} + dargs@7.0.0: resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} engines: {node: '>=8'} @@ -2534,6 +2814,9 @@ packages: dayjs@1.11.19: resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + dayjs@1.11.21: + resolution: {integrity: sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==} + de-indent@1.0.2: resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} @@ -2645,6 +2928,9 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + delaunator@5.1.0: + resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -2719,6 +3005,9 @@ packages: dompurify@3.3.0: resolution: {integrity: sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==} + dompurify@3.4.11: + resolution: {integrity: sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==} + domutils@1.7.0: resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==} @@ -2832,6 +3121,9 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + es-toolkit@1.49.0: + resolution: {integrity: sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==} + es5-ext@0.10.64: resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} engines: {node: '>=0.10'} @@ -3593,6 +3885,9 @@ packages: resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} engines: {node: '>=10'} + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + handsontable@16.2.0: resolution: {integrity: sha512-4zhMQON9DPyip/6YIPH2G7jN+QEJ0uabCZruhrhOqTqr3Qf/FDjsTInUaEzMCmhhdii5MbA6PGyLfUad6t1sXA==} @@ -3786,6 +4081,9 @@ packages: resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} engines: {node: '>=8'} + import-meta-resolve@4.2.0: + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} + importx@0.4.4: resolution: {integrity: sha512-Lo1pukzAREqrBnnHC+tj+lreMTAvyxtkKsMxLY8H15M/bvLl54p3YuoTI70Tz7Il0AsgSlD7Lrk/FaApRcBL7w==} @@ -3825,6 +4123,13 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + into-stream@3.1.0: resolution: {integrity: sha512-TcdjPibTksa1NQximqep2r17ISRiNE9fwlfbg3F8ANdvP5/yrFTew86VcO//jk4QTaMlbjypPBq76HN2zaKfZQ==} engines: {node: '>=4'} @@ -4246,12 +4551,19 @@ packages: resolution: {integrity: sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==} engines: {node: '>=8'} + katex@0.16.47: + resolution: {integrity: sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==} + hasBin: true + keyv@3.0.0: resolution: {integrity: sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==} keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + kind-of@3.2.2: resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} engines: {node: '>=0.10.0'} @@ -4273,6 +4585,12 @@ packages: kolorist@1.8.0: resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + less@4.4.0: resolution: {integrity: sha512-kdTwsyRuncDfjEs0DlRILWNvxhDG/Zij4YLO4TMJgDLW+8OzpfkdPnRgrsRuY1o+oaxJGWsps5f/RVBgGmmN0w==} engines: {node: '>=14'} @@ -4483,6 +4801,11 @@ packages: markdown-table@1.1.3: resolution: {integrity: sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==} + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} + engines: {node: '>= 20'} + hasBin: true + marked@18.0.5: resolution: {integrity: sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w==} engines: {node: '>= 20'} @@ -4534,6 +4857,9 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + mermaid@11.16.0: + resolution: {integrity: sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA==} + micromatch@3.1.10: resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} engines: {node: '>=0.10.0'} @@ -4996,6 +5322,9 @@ packages: path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + path-dirname@1.0.2: resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} @@ -5123,6 +5452,12 @@ packages: engines: {node: '>=10'} hasBin: true + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + posix-character-classes@0.1.1: resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} engines: {node: '>=0.10.0'} @@ -5490,6 +5825,9 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + robust-predicates@3.0.3: + resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} + rollup-plugin-visualizer@5.14.0: resolution: {integrity: sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA==} engines: {node: '>=18'} @@ -5513,9 +5851,15 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} @@ -6144,6 +6488,9 @@ packages: engines: {node: '>=6'} hasBin: true + stylis@4.4.0: + resolution: {integrity: sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==} + sugarss@2.0.0: resolution: {integrity: sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==} @@ -6309,6 +6656,10 @@ packages: trough@1.0.5: resolution: {integrity: sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==} + ts-dedent@2.3.0: + resolution: {integrity: sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==} + engines: {node: '>=6.10'} + ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true @@ -6546,6 +6897,10 @@ packages: utrie@1.0.2: resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==} + uuid@14.0.1: + resolution: {integrity: sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==} + hasBin: true + uuid@3.4.0: resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). @@ -7133,8 +7488,12 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@braintree/sanitize-url@7.1.2': {} + '@bufbuild/protobuf@2.10.1': {} + '@chevrotain/types@11.1.2': {} + '@claviska/jquery-minicolors@2.3.6(jquery@3.7.1)': dependencies: jquery: 3.7.1 @@ -7585,6 +7944,12 @@ snapshots: transitivePeerDependencies: - supports-color + '@iconify/utils@3.1.4': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@iconify/types': 2.0.0 + import-meta-resolve: 4.2.0 + '@interactjs/types@1.10.27': {} '@intlify/core-base@9.14.5': @@ -7663,6 +8028,10 @@ snapshots: '@marijn/find-cluster-break@1.0.2': {} + '@mermaid-js/parser@1.2.0': + dependencies: + '@chevrotain/types': 11.1.2 + '@mrmlnc/readdir-enhanced@2.2.1': dependencies: call-me-maybe: 1.0.2 @@ -7874,6 +8243,123 @@ snapshots: tslib: 2.8.1 optional: true + '@types/d3-array@3.2.2': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.2 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.4': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.4 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + '@types/diff-match-patch@1.0.36': {} '@types/eslint@8.56.12': @@ -7883,6 +8369,8 @@ snapshots: '@types/estree@1.0.8': {} + '@types/geojson@7946.0.16': {} + '@types/glob@7.2.0': dependencies: '@types/minimatch': 6.0.0 @@ -8312,6 +8800,11 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + '@upsetjs/venn.js@2.0.0': + optionalDependencies: + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + '@vitejs/plugin-vue-jsx@2.1.1(vite@6.3.5(@types/node@20.5.1)(jiti@1.21.7)(less@4.4.0)(sass-embedded@1.93.3)(sass@1.93.3)(sugarss@2.0.0)(tsx@4.20.3))(vue@3.5.18(typescript@4.9.5))': dependencies: '@babel/core': 7.28.0 @@ -9079,6 +9572,8 @@ snapshots: commander@7.2.0: {} + commander@8.3.0: {} + commondir@1.0.1: {} compare-func@2.0.0: @@ -9146,6 +9641,14 @@ snapshots: core-util-is@1.0.3: {} + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + cosmiconfig-typescript-loader@4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@4.9.5))(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.5))(typescript@4.9.5): dependencies: '@types/node': 20.5.1 @@ -9259,11 +9762,195 @@ snapshots: bin-build: 3.0.0 bin-wrapper: 4.1.0 + cytoscape-cose-bilkent@4.1.0(cytoscape@3.34.0): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.34.0 + + cytoscape-fcose@2.2.0(cytoscape@3.34.0): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.34.0 + + cytoscape@3.34.0: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.1.0 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.2: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.2 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + d@1.0.2: dependencies: es5-ext: 0.10.64 type: 2.7.3 + dagre-d3-es@7.0.14: + dependencies: + d3: 7.9.0 + lodash-es: 4.17.23 + dargs@7.0.0: {} data-view-buffer@1.0.2: @@ -9288,6 +9975,8 @@ snapshots: dayjs@1.11.19: {} + dayjs@1.11.21: {} + de-indent@1.0.2: {} debug@2.6.9: @@ -9392,6 +10081,10 @@ snapshots: defu@6.1.4: {} + delaunator@5.1.0: + dependencies: + robust-predicates: 3.0.3 + delayed-stream@1.0.0: {} destr@2.0.5: {} @@ -9463,6 +10156,10 @@ snapshots: optionalDependencies: '@types/trusted-types': 2.0.7 + dompurify@3.4.11: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@1.7.0: dependencies: dom-serializer: 0.2.2 @@ -9675,6 +10372,8 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + es-toolkit@1.49.0: {} + es5-ext@0.10.64: dependencies: es6-iterator: 2.0.3 @@ -10609,6 +11308,8 @@ snapshots: dependencies: duplexer: 0.1.2 + hachure-fill@0.5.2: {} + handsontable@16.2.0: dependencies: '@handsontable/pikaday': 1.0.0 @@ -10730,7 +11431,6 @@ snapshots: iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 - optional: true ieee754@1.2.1: {} @@ -10810,6 +11510,8 @@ snapshots: import-lazy@4.0.0: {} + import-meta-resolve@4.2.0: {} + importx@0.4.4: dependencies: bundle-require: 5.1.0(esbuild@0.23.1) @@ -10853,6 +11555,10 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + internmap@1.0.1: {} + + internmap@2.0.3: {} + into-stream@3.1.0: dependencies: from2: 2.3.0 @@ -11213,6 +11919,10 @@ snapshots: junk@3.1.0: {} + katex@0.16.47: + dependencies: + commander: 8.3.0 + keyv@3.0.0: dependencies: json-buffer: 3.0.0 @@ -11221,6 +11931,8 @@ snapshots: dependencies: json-buffer: 3.0.1 + khroma@2.1.0: {} + kind-of@3.2.2: dependencies: is-buffer: 1.1.6 @@ -11237,6 +11949,10 @@ snapshots: kolorist@1.8.0: {} + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + less@4.4.0: dependencies: copy-anything: 2.0.6 @@ -11451,6 +12167,8 @@ snapshots: markdown-table@1.1.3: {} + marked@16.4.2: {} + marked@18.0.5: {} math-intrinsics@1.1.0: {} @@ -11536,6 +12254,30 @@ snapshots: merge2@1.4.1: {} + mermaid@11.16.0: + dependencies: + '@braintree/sanitize-url': 7.1.2 + '@iconify/utils': 3.1.4 + '@mermaid-js/parser': 1.2.0 + '@types/d3': 7.4.3 + '@upsetjs/venn.js': 2.0.0 + cytoscape: 3.34.0 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.34.0) + cytoscape-fcose: 2.2.0(cytoscape@3.34.0) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.14 + dayjs: 1.11.21 + dompurify: 3.4.11 + es-toolkit: 1.49.0 + katex: 0.16.47 + khroma: 2.1.0 + marked: 16.4.2 + roughjs: 4.6.6 + stylis: 4.4.0 + ts-dedent: 2.3.0 + uuid: 14.0.1 + micromatch@3.1.10: dependencies: arr-diff: 4.0.0 @@ -12019,6 +12761,8 @@ snapshots: path-browserify@1.0.1: {} + path-data-parser@0.1.0: {} + path-dirname@1.0.2: {} path-exists@2.1.0: @@ -12118,6 +12862,13 @@ snapshots: bin-wrapper: 4.1.0 execa: 4.1.0 + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + posix-character-classes@0.1.1: {} possible-typed-array-names@1.1.0: {} @@ -12499,6 +13250,8 @@ snapshots: dependencies: glob: 7.2.3 + robust-predicates@3.0.3: {} + rollup-plugin-visualizer@5.14.0(rollup@4.46.2): dependencies: open: 8.4.2 @@ -12538,10 +13291,19 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.46.2 fsevents: 2.3.3 + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + rw@1.3.3: {} + rxjs@7.8.2: dependencies: tslib: 2.8.1 @@ -12573,8 +13335,7 @@ snapshots: dependencies: ret: 0.1.15 - safer-buffer@2.1.2: - optional: true + safer-buffer@2.1.2: {} sass-embedded-all-unknown@1.93.3: dependencies: @@ -13265,6 +14026,8 @@ snapshots: transitivePeerDependencies: - supports-color + stylis@4.4.0: {} + sugarss@2.0.0: dependencies: postcss: 7.0.39 @@ -13440,6 +14203,8 @@ snapshots: trough@1.0.5: {} + ts-dedent@2.3.0: {} + ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.5): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -13756,6 +14521,8 @@ snapshots: dependencies: base64-arraybuffer: 1.0.2 + uuid@14.0.1: {} + uuid@3.4.0: {} v8-compile-cache-lib@3.0.1: {} diff --git a/src/api/channel/autoTrigger.ts b/src/api/channel/autoTrigger.ts index ba62ea2..e119114 100644 --- a/src/api/channel/autoTrigger.ts +++ b/src/api/channel/autoTrigger.ts @@ -30,3 +30,35 @@ export async function toggleAutoTriggerStatus(id: number | string, status: numbe const res = await axiosInstance.post(omsUrl('/channel/auto-trigger/toggleStatus'), { id, status }) assertBusinessOk(res.data) } + +export async function getAutoTriggerMeta() { + const res = await axiosInstance.get(omsUrl('/channel/auto-trigger/meta')) + return unwrapData(res.data) +} + +export async function testAutoTriggerFormula(body: { + expression?: string + triggerCondition?: string + orderId?: number + sample?: { + productCode?: string + channelCode?: string + consigneeCountry?: string + consigneeCountryName?: string + customerId?: number + customerName?: string + clientNo?: string + length?: number + width?: number + height?: number + actualWeight?: number + } +}) { + const res = await axiosInstance.post(omsUrl('/channel/auto-trigger/test'), body) + return unwrapData(res.data) as { + matched: boolean + expression?: string + contextType?: string + error?: string + } +} diff --git a/src/api/order/index.ts b/src/api/order/index.ts index cb769ee..cec7748 100644 --- a/src/api/order/index.ts +++ b/src/api/order/index.ts @@ -801,6 +801,59 @@ export function parsePriceCheckResponse(resBody: any): { return { items: itemList, failures } } +export type PriceCheckShippingOption = { + productId: number + productCode: string + productName: string + label: string +} + +export type PriceCheckShippingGroup = { + groupCode: string + groupName: string + products: PriceCheckShippingOption[] +} + +function normalizeShippingOption(raw: any): PriceCheckShippingOption | null { + const productCode = String(raw?.productCode ?? raw?.ProductCode ?? '').trim() + if (!productCode) return null + const productName = String(raw?.productName ?? raw?.ProductName ?? '').trim() + const label = String(raw?.label ?? raw?.Label ?? '').trim() + return { + productId: Number(raw?.productId ?? raw?.ProductId ?? 0), + productCode, + productName, + label: label || (productName ? `${productName} ${productCode}` : productCode), + } +} + +function normalizeShippingGroup(raw: any): PriceCheckShippingGroup | null { + const groupCode = String(raw?.groupCode ?? raw?.GroupCode ?? '').trim() + const groupName = String(raw?.groupName ?? raw?.GroupName ?? '').trim() + const productsRaw = raw?.products ?? raw?.Products ?? [] + const products = (Array.isArray(productsRaw) ? productsRaw : []) + .map(normalizeShippingOption) + .filter((item): item is PriceCheckShippingOption => Boolean(item)) + if (!groupCode && !groupName && products.length === 0) return null + return { + groupCode: groupCode || groupName, + groupName: groupName || groupCode, + products, + } +} + +export async function getOrderPriceCheckShippingOptions(): Promise { + const res = await axiosInstance.get(orderUrl('/order/price-check/shipping-options')) + const body = res.data + assertBusinessOk(body) + const payload = body?.data ?? body?.Data ?? body + const groupsRaw = payload?.groups ?? payload?.Groups ?? [] + return (Array.isArray(groupsRaw) ? groupsRaw : []) + .map(normalizeShippingGroup) + .filter((item): item is PriceCheckShippingGroup => Boolean(item)) + .filter((item) => item.products.length > 0) +} + export async function postOrderPriceCheck(params: PriceCheckRequest): Promise<{ items: any[] failures: PriceCheckFailure[] diff --git a/src/auto-imports.d.ts b/src/auto-imports.d.ts index fcd0c4f..6ea6eb7 100644 --- a/src/auto-imports.d.ts +++ b/src/auto-imports.d.ts @@ -202,6 +202,7 @@ declare global { const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery'] const useMemoize: typeof import('@vueuse/core')['useMemoize'] const useMemory: typeof import('@vueuse/core')['useMemory'] + const useMenuDisplay: typeof import('./composables/useMenuDisplay')['useMenuDisplay'] const useMessageStore: typeof import('./store/index')['useMessageStore'] const useModel: typeof import('vue')['useModel'] const useMounted: typeof import('@vueuse/core')['useMounted'] @@ -311,6 +312,9 @@ declare global { export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue' import('vue') // @ts-ignore + export type { ScanFeedbackType } from './composables/useOperationScanFeedback' + import('./composables/useOperationScanFeedback') + // @ts-ignore export type { WarehouseItem } from './composables/useWarehouseList' import('./composables/useWarehouseList') } @@ -516,6 +520,7 @@ declare module 'vue' { readonly useMediaQuery: UnwrapRef readonly useMemoize: UnwrapRef readonly useMemory: UnwrapRef + readonly useMenuDisplay: UnwrapRef readonly useMessageStore: UnwrapRef readonly useModel: UnwrapRef readonly useMounted: UnwrapRef @@ -529,7 +534,9 @@ declare module 'vue' { readonly useObjectUrl: UnwrapRef readonly useOffsetPagination: UnwrapRef readonly useOnline: UnwrapRef + readonly useOperationScanFeedback: UnwrapRef readonly useOperationScanFocus: UnwrapRef + readonly useOperationVoiceBroadcast: UnwrapRef readonly usePageLeave: UnwrapRef readonly useParallax: UnwrapRef readonly usePermission: UnwrapRef diff --git a/src/components/breadcrumb/index.vue b/src/components/breadcrumb/index.vue index c3090cd..ea84445 100644 --- a/src/components/breadcrumb/index.vue +++ b/src/components/breadcrumb/index.vue @@ -4,13 +4,16 @@ - {{ $t(item) }} + {{ formatBreadcrumbLabel(item) }} diff --git a/src/views/channel/autoTrigger/conditionUtils.ts b/src/views/channel/autoTrigger/conditionUtils.ts new file mode 100644 index 0000000..6a5c881 --- /dev/null +++ b/src/views/channel/autoTrigger/conditionUtils.ts @@ -0,0 +1,71 @@ +import { FORMULA_MAX_LENGTH, OVERSIZE_EXAMPLE_FORMULA } from './formulaMeta' + +export type StoredConditionMeta = { + expression: string + ruleName?: string + priority?: number + legacyText?: string +} + +/** 从库中读出:支持纯公式文本,或 { version:'formula', expression, ruleName, priority } */ +export function parseStoredCondition(text: string | undefined | null): StoredConditionMeta { + const trimmed = String(text ?? '').trim() + if (!trimmed) { + return { expression: '' } + } + if (!trimmed.startsWith('{')) { + return { expression: trimmed } + } + try { + const obj = JSON.parse(trimmed) as Record + if (Number(obj.version) === 2 && Array.isArray(obj.children)) { + return { expression: trimmed, legacyText: '旧版结构化条件,请改用公式重新配置' } + } + if (obj.version === 'formula' || obj.expression != null) { + return { + expression: String(obj.expression ?? '').trim(), + ruleName: obj.ruleName != null ? String(obj.ruleName) : undefined, + priority: obj.priority != null ? Number(obj.priority) || 100 : undefined, + } + } + return { expression: trimmed, legacyText: trimmed } + } catch { + return { expression: trimmed } + } +} + +/** 保存:附带规则名/优先级元数据,expression 为公式正文 */ +export function serializeStoredCondition( + expression: string, + meta?: { ruleName?: string; priority?: number } +): string { + const expr = expression.trim() + const ruleName = meta?.ruleName?.trim() + const priority = meta?.priority ?? 100 + if (!ruleName && priority === 100) return expr + return JSON.stringify({ + version: 'formula', + ruleName: ruleName || undefined, + priority, + expression: expr, + }) +} + +export function formatConditionSummary(text: string | undefined | null): string { + const { expression, legacyText } = parseStoredCondition(text) + if (legacyText && !expression.startsWith('(')) return legacyText + const summary = expression.replace(/\s+/g, ' ').trim() + if (!summary) return '—' + return summary.length > 120 ? `${summary.slice(0, 120)}…` : summary +} + +export function validateFormulaExpression(expression: string): string | null { + const expr = expression.trim() + if (!expr) return '请填写条件公式' + if (expr.length > FORMULA_MAX_LENGTH) return `条件公式不能超过 ${FORMULA_MAX_LENGTH} 字` + return null +} + +export function getOversizeExampleFormula(): string { + return OVERSIZE_EXAMPLE_FORMULA +} diff --git a/src/views/channel/autoTrigger/formulaMeta.ts b/src/views/channel/autoTrigger/formulaMeta.ts new file mode 100644 index 0000000..df6ac68 --- /dev/null +++ b/src/views/channel/autoTrigger/formulaMeta.ts @@ -0,0 +1,313 @@ +export type FieldValueType = 'string' | 'number' | 'boolean' | 'datetime' + +/** 表分类:key 为库表名,label 为中文 */ +export const ORDER_TABLE_CATEGORIES: { key: string; label: string }[] = [ + { key: 't_order', label: '订单' }, + { key: 't_order_recipient', label: '收件人' }, + { key: 't_order_sender', label: '发件人' }, + { key: 't_order_declaration', label: '申报' }, + { key: 't_order_weight', label: '件重尺' }, + { key: 't_order_fee', label: '费用' }, + { key: 't_customer', label: '客户' }, + { key: '_virtual', label: '常用' }, +] + +export type OrderTableFieldDef = { + table: string + field: string + /** 公式与按钮上使用的中文名称(唯一) */ + label: string + valueType: FieldValueType +} + +export type FormulaFieldRef = { + table: string + field: string + /** 非库表字段(如单件最大长度) */ + virtual?: boolean +} + +/** 中文名称 → 库表字段映射(后端解析公式时使用) */ +export const FORMULA_LABEL_TO_REF: Record = {} + +function registerRef(label: string, ref: FormulaFieldRef) { + FORMULA_LABEL_TO_REF[label] = ref +} + +function fieldRef(table: string, field: string): FormulaFieldRef { + return { table, field } +} + +function virtualRef(field: string): FormulaFieldRef { + return { table: '_virtual', field, virtual: true } +} + +/** + * 订单及关联表字段中文映射(label 唯一)。 + * 不含 IsDeleted / CreateUserId / CreateTime / UpdateUserId / UpdateTime。 + */ +export const ORDER_TABLE_FIELDS: OrderTableFieldDef[] = [ + // —— t_order —— + { table: 't_order', field: 'RequestId', label: '请求标识', valueType: 'string' }, + { table: 't_order', field: 'ServiceNo', label: '运单号', valueType: 'string' }, + { table: 't_order', field: 'ClientNo', label: '客户单号', valueType: 'string' }, + { table: 't_order', field: 'TrackNo', label: '跟踪号', valueType: 'string' }, + { table: 't_order', field: 'ProductCode', label: '销售产品', valueType: 'string' }, + { table: 't_order', field: 'ChannelCode', label: '收货渠道', valueType: 'string' }, + { table: 't_order', field: 'DownstreamSupplierCode', label: '下游服务商', valueType: 'string' }, + { table: 't_order', field: 'DownstreamAppKey', label: '下游AppKey', valueType: 'string' }, + { table: 't_order', field: 'DownstreamAppId', label: '下游AppId', valueType: 'number' }, + { table: 't_order', field: 'ChannelForecastCode', label: '渠道预报编码', valueType: 'string' }, + { table: 't_order', field: 'ConsigneeCountry', label: '国家', valueType: 'string' }, + { table: 't_order', field: 'ConsigneeCountryName', label: '收件国家名称', valueType: 'string' }, + { table: 't_order', field: 'CargoAttribute', label: '货物属性', valueType: 'string' }, + { table: 't_order', field: 'ExportCustomsMode', label: '出口报关方式', valueType: 'string' }, + { table: 't_order', field: 'PredeclareFailReason', label: '预报失败原因', valueType: 'string' }, + { table: 't_order', field: 'SalesProductRulesVersion', label: '规则版本号', valueType: 'string' }, + { table: 't_order', field: 'SalesProductPriceVersion', label: '价格版本号', valueType: 'string' }, + { table: 't_order', field: 'OrderStatus', label: '订单状态', valueType: 'string' }, + { table: 't_order', field: 'HandleStatus', label: '处理子状态', valueType: 'string' }, + { table: 't_order', field: 'IssueType', label: '问题类型', valueType: 'string' }, + { table: 't_order', field: 'IssueTitle', label: '问题标题', valueType: 'string' }, + { table: 't_order', field: 'IssueContent', label: '问题内容', valueType: 'string' }, + { table: 't_order', field: 'IssueTemplateId', label: '问题模板', valueType: 'number' }, + { table: 't_order', field: 'IssueRemark', label: '问题备注', valueType: 'string' }, + { table: 't_order', field: 'IssueTime', label: '问题件时间', valueType: 'datetime' }, + { table: 't_order', field: 'ClaimType', label: '理赔类型', valueType: 'string' }, + { table: 't_order', field: 'ClaimAmount', label: '索赔金额', valueType: 'number' }, + { table: 't_order', field: 'ClaimCurrency', label: '索赔币种', valueType: 'string' }, + { table: 't_order', field: 'ClaimReason', label: '理赔原因', valueType: 'string' }, + { table: 't_order', field: 'ClaimTime', label: '理赔时间', valueType: 'datetime' }, + { table: 't_order', field: 'PreviousOrderStatus', label: '异常前状态', valueType: 'string' }, + { table: 't_order', field: 'WarehouseId', label: '仓库', valueType: 'number' }, + { table: 't_order', field: 'CustomerId', label: '订单客户', valueType: 'number' }, + { table: 't_order', field: 'OrganizationId', label: '组织', valueType: 'string' }, + { table: 't_order', field: 'SecretLevel', label: '密级', valueType: 'number' }, + { table: 't_order', field: 'SenderId', label: '发件人关联', valueType: 'number' }, + { table: 't_order', field: 'RecipientId', label: '收件人关联', valueType: 'number' }, + { table: 't_order', field: 'DeclarationId', label: '申报关联', valueType: 'number' }, + { table: 't_order', field: 'ReceiveTime', label: '收货时间', valueType: 'datetime' }, + { table: 't_order', field: 'ShipTime', label: '发货时间', valueType: 'datetime' }, + { table: 't_order', field: 'PayTime', label: '支付时间', valueType: 'datetime' }, + { table: 't_order', field: 'IsPaid', label: '是否已支付', valueType: 'boolean' }, + { table: 't_order', field: 'SignTime', label: '签收时间', valueType: 'datetime' }, + { table: 't_order', field: 'IsCod', label: '是否COD', valueType: 'boolean' }, + { table: 't_order', field: 'CodCurrency', label: 'COD币种', valueType: 'string' }, + { table: 't_order', field: 'CodSum', label: 'COD金额', valueType: 'number' }, + { table: 't_order', field: 'DeclaredCurrency', label: '申报币种', valueType: 'string' }, + { table: 't_order', field: 'DeclaredSum', label: '申报总金额', valueType: 'number' }, + { table: 't_order', field: 'Quantity', label: '订单件数', valueType: 'number' }, + { table: 't_order', field: 'IsIntercept', label: '是否拦截', valueType: 'boolean' }, + { table: 't_order', field: 'IsRemote', label: '是否偏远', valueType: 'boolean' }, + + // —— t_order_recipient —— + { table: 't_order_recipient', field: 'RecipientsName', label: '收件人姓名', valueType: 'string' }, + { table: 't_order_recipient', field: 'CompanyName', label: '收件人公司', valueType: 'string' }, + { table: 't_order_recipient', field: 'Country', label: '收件人国家', valueType: 'number' }, + { table: 't_order_recipient', field: 'Phone', label: '收件人手机', valueType: 'string' }, + { table: 't_order_recipient', field: 'TelePhone', label: '收件人电话', valueType: 'string' }, + { table: 't_order_recipient', field: 'ZipCode', label: '收件人邮编', valueType: 'string' }, + { table: 't_order_recipient', field: 'Province', label: '收件人省州', valueType: 'string' }, + { table: 't_order_recipient', field: 'City', label: '收件人城市', valueType: 'string' }, + { table: 't_order_recipient', field: 'StreetNumber', label: '收件人门牌号', valueType: 'string' }, + { table: 't_order_recipient', field: 'StreetAddress1', label: '收件人地址1', valueType: 'string' }, + { table: 't_order_recipient', field: 'StreetAddress2', label: '收件人地址2', valueType: 'string' }, + { table: 't_order_recipient', field: 'StreetAddress3', label: '收件人地址3', valueType: 'string' }, + { table: 't_order_recipient', field: 'Email', label: '收件人邮箱', valueType: 'string' }, + { table: 't_order_recipient', field: 'TaxType', label: '收件人税号类型', valueType: 'number' }, + { table: 't_order_recipient', field: 'TaxNo', label: '收件人税号', valueType: 'string' }, + { table: 't_order_recipient', field: 'CertificateType', label: '收件人证件类型', valueType: 'number' }, + { table: 't_order_recipient', field: 'CertificateNo', label: '收件人证件号', valueType: 'string' }, + { table: 't_order_recipient', field: 'Eori', label: '收件人EORI', valueType: 'string' }, + { table: 't_order_recipient', field: 'Vat', label: '收件人VAT', valueType: 'string' }, + + // —— t_order_sender —— + { table: 't_order_sender', field: 'SenderName', label: '发件人姓名', valueType: 'string' }, + { table: 't_order_sender', field: 'Company', label: '发件人公司', valueType: 'string' }, + { table: 't_order_sender', field: 'Country', label: '发件人国家', valueType: 'number' }, + { table: 't_order_sender', field: 'Province', label: '发件人省州', valueType: 'string' }, + { table: 't_order_sender', field: 'City', label: '发件人城市', valueType: 'string' }, + { table: 't_order_sender', field: 'ZipCode', label: '发件人邮编', valueType: 'string' }, + { table: 't_order_sender', field: 'StreetAddress1', label: '发件人地址1', valueType: 'string' }, + { table: 't_order_sender', field: 'StreetAddress2', label: '发件人地址2', valueType: 'string' }, + { table: 't_order_sender', field: 'StreetAddress3', label: '发件人地址3', valueType: 'string' }, + { table: 't_order_sender', field: 'HouseNumber', label: '发件人门牌号', valueType: 'string' }, + { table: 't_order_sender', field: 'Phone', label: '发件人手机', valueType: 'string' }, + { table: 't_order_sender', field: 'TelePhone', label: '发件人电话', valueType: 'string' }, + { table: 't_order_sender', field: 'Email', label: '发件人邮箱', valueType: 'string' }, + { table: 't_order_sender', field: 'IsDefault', label: '发件人是否默认', valueType: 'boolean' }, + + // —— t_order_declaration —— + { table: 't_order_declaration', field: 'CnName', label: '中文品名', valueType: 'string' }, + { table: 't_order_declaration', field: 'EnName', label: '英文品名', valueType: 'string' }, + { table: 't_order_declaration', field: 'Sku', label: 'SKU', valueType: 'string' }, + { table: 't_order_declaration', field: 'Unit', label: '申报单位', valueType: 'string' }, + { table: 't_order_declaration', field: 'UnitPrice', label: '申报单价', valueType: 'number' }, + { table: 't_order_declaration', field: 'UnitWeight', label: '申报单重', valueType: 'number' }, + { table: 't_order_declaration', field: 'Quantity', label: '申报数量', valueType: 'number' }, + { table: 't_order_declaration', field: 'Amount', label: '申报金额', valueType: 'number' }, + { table: 't_order_declaration', field: 'Weight', label: '申报总重', valueType: 'number' }, + { table: 't_order_declaration', field: 'HsCode', label: 'HS编码', valueType: 'string' }, + { table: 't_order_declaration', field: 'ImHsCode', label: '进口HS编码', valueType: 'string' }, + { table: 't_order_declaration', field: 'ExHsCode', label: '出口HS编码', valueType: 'string' }, + { table: 't_order_declaration', field: 'Category', label: '申报类别', valueType: 'string' }, + { table: 't_order_declaration', field: 'Brand', label: '品牌', valueType: 'string' }, + { table: 't_order_declaration', field: 'BrandType', label: '品牌类型', valueType: 'string' }, + { table: 't_order_declaration', field: 'IsMagnetic', label: '是否带磁带电', valueType: 'boolean' }, + { table: 't_order_declaration', field: 'Distribution', label: '配货信息', valueType: 'string' }, + { table: 't_order_declaration', field: 'Material', label: '材质', valueType: 'string' }, + { table: 't_order_declaration', field: 'EnMaterial', label: '英文材质', valueType: 'string' }, + { table: 't_order_declaration', field: 'Purpose', label: '用途', valueType: 'string' }, + { table: 't_order_declaration', field: 'Attributes', label: '申报属性', valueType: 'string' }, + { table: 't_order_declaration', field: 'OriginCountry', label: '原产国', valueType: 'string' }, + { table: 't_order_declaration', field: 'SalesLink', label: '销售链接', valueType: 'string' }, + { table: 't_order_declaration', field: 'Model', label: '型号', valueType: 'string' }, + { table: 't_order_declaration', field: 'Specifications', label: '规格', valueType: 'string' }, + { table: 't_order_declaration', field: 'Comment', label: '申报备注', valueType: 'string' }, + + // —— t_order_weight —— + { table: 't_order_weight', field: 'Type', label: '件重尺类型', valueType: 'string' }, + { table: 't_order_weight', field: 'Length', label: '长度', valueType: 'number' }, + { table: 't_order_weight', field: 'Width', label: '宽度', valueType: 'number' }, + { table: 't_order_weight', field: 'Height', label: '高度', valueType: 'number' }, + { table: 't_order_weight', field: 'ActualWeight', label: '实重', valueType: 'number' }, + { table: 't_order_weight', field: 'VolumetricWeight', label: '体积重', valueType: 'number' }, + { table: 't_order_weight', field: 'ChargeableWeight', label: '计费重', valueType: 'number' }, + { table: 't_order_weight', field: 'Cubic', label: '体积', valueType: 'number' }, + + // —— t_order_fee —— + { table: 't_order_fee', field: 'Type', label: '费用类型', valueType: 'string' }, + { table: 't_order_fee', field: 'CostItem', label: '费用项', valueType: 'string' }, + { table: 't_order_fee', field: 'Amount', label: '费用金额', valueType: 'number' }, + { table: 't_order_fee', field: 'Currency', label: '费用币种', valueType: 'string' }, + { table: 't_order_fee', field: 'DownstreamProvider', label: '费用下游服务商', valueType: 'string' }, + { table: 't_order_fee', field: 'PriceNo', label: '价格编号', valueType: 'string' }, + { table: 't_order_fee', field: 'PriceEffectiveTime', label: '价格生效时间', valueType: 'datetime' }, + { table: 't_order_fee', field: 'ChargingStage', label: '计费阶段', valueType: 'string' }, + + // —— t_customer —— + { table: 't_customer', field: 'CustomerCode', label: '客户编码', valueType: 'string' }, + { table: 't_customer', field: 'CustomerName', label: '客户', valueType: 'string' }, + { table: 't_customer', field: 'Email', label: '客户邮箱', valueType: 'string' }, + { table: 't_customer', field: 'Phone', label: '客户手机', valueType: 'string' }, + { table: 't_customer', field: 'Balance', label: '客户余额', valueType: 'number' }, + { table: 't_customer', field: 'TotalQuota', label: '客户总额度', valueType: 'number' }, + { table: 't_customer', field: 'UsedQuota', label: '客户已用额度', valueType: 'number' }, + { table: 't_customer', field: 'Status', label: '客户状态', valueType: 'string' }, + { table: 't_customer', field: 'Remark', label: '客户备注', valueType: 'string' }, + { table: 't_customer', field: 'Salesman', label: '销售', valueType: 'string' }, + { table: 't_customer', field: 'CustomerService', label: '客服', valueType: 'string' }, + { table: 't_customer', field: 'CustomerGroup', label: '客户组', valueType: 'string' }, +] + +/** 虚拟/聚合字段(无直接库表列,后端按中文名解析) */ +export const VIRTUAL_FORMULA_FIELDS: OrderTableFieldDef[] = [ + { table: '_virtual', field: 'PieceMaxLength', label: '单件最大长度', valueType: 'number' }, + { table: '_virtual', field: 'PieceMaxWidth', label: '单件最大宽度', valueType: 'number' }, + { table: '_virtual', field: 'PieceMaxHeight', label: '单件最大高度', valueType: 'number' }, + { table: '_virtual', field: 'PieceSumLwh', label: '单件长宽高之和', valueType: 'number' }, +] + +export type FormulaChip = { + table: string + /** 按钮展示中文名 */ + label: string + /** 插入公式片段(中文) */ + insert: string + /** 悬停提示:映射库表字段 */ + refHint: string +} + +function buildInsert(def: OrderTableFieldDef): string { + if (def.valueType === 'string' || def.valueType === 'datetime') { + return `${def.label}包含('')` + } + if (def.valueType === 'boolean') { + return `${def.label}()==1` + } + return `${def.label}()` +} + +function buildRefHint(def: OrderTableFieldDef): string { + if (def.table === '_virtual') { + return `虚拟字段 · ${def.field}` + } + return `${def.table}.${def.field}` +} + +function buildChipsFromFields(fields: OrderTableFieldDef[]): FormulaChip[] { + return fields.map((def) => { + registerRef( + def.label, + def.table === '_virtual' ? virtualRef(def.field) : fieldRef(def.table, def.field) + ) + return { + table: def.table, + label: def.label, + insert: buildInsert(def), + refHint: buildRefHint(def), + } + }) +} + +export const FORMULA_CHIPS: FormulaChip[] = buildChipsFromFields([ + ...ORDER_TABLE_FIELDS, + ...VIRTUAL_FORMULA_FIELDS, +]) + +export type FormulaOperator = { + label: string + insert: string +} + +export const FORMULA_OPERATORS: FormulaOperator[] = [ + { label: '+', insert: '+' }, + { label: '-', insert: '-' }, + { label: '×', insert: '*' }, + { label: '÷', insert: '/' }, + { label: '=', insert: '==' }, + { label: '≠', insert: '!=' }, + { label: '≥', insert: '>=' }, + { label: '>', insert: '>' }, + { label: '≤', insert: '<=' }, + { label: '<', insert: '<' }, + { label: '(', insert: '(' }, + { label: ')', insert: ')' }, + { label: '非', insert: '!' }, + { label: '与', insert: '&&' }, + { label: '或', insert: '||' }, +] + +/** 超尺寸示例(中文字段名,与运营习惯一致) */ +export const OVERSIZE_EXAMPLE_FORMULA = + "(单件最大长度()>60||单件最大宽度()>46||((单件最大长度()+单件最大宽度()+单件最大高度())>150))&&国家包含('GB')&&客户包含('阿里国际站/深圳一达通')&&!销售产品包含('EX_ASP_HKDHL_YD')" + +export const FORMULA_MAX_LENGTH = 10000 + +export const TIMING_SAVE_LABEL: Record = { + forecast: '预报', + order_create: '下单', + inbound: '入库', + outbound: '出库', +} + +export const OPERATION_SAVE_LABEL: Record = { + intercept: '拦截', + warn: '警告', + problem: '问题件', +} + +export function chipsByTable(table: string): FormulaChip[] { + return FORMULA_CHIPS.filter((c) => c.table === table) +} + +export function resolveFormulaLabel(label: string): FormulaFieldRef | undefined { + return FORMULA_LABEL_TO_REF[label] +} + +export function getDbFieldPath(label: string): string { + const ref = resolveFormulaLabel(label) + if (!ref) return label + if (ref.virtual) return ref.field + return `${ref.table}.${ref.field}` +} diff --git a/src/views/channel/autoTrigger/index.vue b/src/views/channel/autoTrigger/index.vue index 3198cda..3ab71b1 100644 --- a/src/views/channel/autoTrigger/index.vue +++ b/src/views/channel/autoTrigger/index.vue @@ -1,21 +1,31 @@ @@ -822,6 +933,99 @@ onMounted(() => { background: #fff1f0; color: #cf1322; } + +:deep(.condition-summary-cell) { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-align: left; + line-height: 1.4; + font-size: 12px; + color: #4e5969; +} + +.auto-trigger-form { + display: flex; + flex-direction: column; + gap: 16px; + max-height: 70vh; + overflow-y: auto; + padding-right: 4px; +} + +.legacy-alert { + margin-bottom: 0; +} + +.form-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 12px 16px; +} + +.form-row { + display: flex; + flex-direction: column; + gap: 6px; + + &.full { + grid-column: 1 / -1; + } +} + +.form-label { + font-size: 14px; + font-weight: 500; + color: #262626; + + &.required::before { + content: '*'; + color: #f53f3f; + margin-right: 4px; + } +} + +.condition-section { + display: flex; + flex-direction: column; + gap: 8px; + + .section-head { + display: flex; + align-items: center; + justify-content: space-between; + } + + .section-actions { + display: flex; + align-items: center; + gap: 4px; + } +} + +.test-sample-panel { + margin-top: 8px; + padding: 12px; + border: 1px dashed #e5e6eb; + border-radius: 6px; + background: #fafbfc; + + .test-sample-title { + font-size: 13px; + font-weight: 500; + color: #4e5969; + margin-bottom: 8px; + } + + .test-sample-grid { + margin-bottom: 8px; + } + + .test-result-alert { + margin-top: 8px; + } +} diff --git a/src/views/order/priceCheck/components/ShippingMethodTabSelect.vue b/src/views/order/priceCheck/components/ShippingMethodTabSelect.vue new file mode 100644 index 0000000..32a1c31 --- /dev/null +++ b/src/views/order/priceCheck/components/ShippingMethodTabSelect.vue @@ -0,0 +1,278 @@ + + + + + diff --git a/src/views/order/priceCheck/index.vue b/src/views/order/priceCheck/index.vue index cfa8338..2b68ce8 100644 --- a/src/views/order/priceCheck/index.vue +++ b/src/views/order/priceCheck/index.vue @@ -6,12 +6,12 @@ import { useRouter } from 'vue-router'; import PaginationPro from '@/components/PaginationPro/index.vue'; import { useTableContainerHeight } from '@/composables/useTableContainerHeight'; - import { postOrderPriceCheck } from '@/api/order'; + import { postOrderPriceCheck, getOrderPriceCheckShippingOptions, type PriceCheckShippingGroup } from '@/api/order'; import { getCountryList } from '@/api/system/country'; import { getDictListAll } from '@/api/system/dict'; - import { getSalesProductList } from '@/api/channel/salesProduct'; import { getWarehouseList } from '@/api/system/warehouse'; import CustomerGuideDrawer from './components/CustomerGuideDrawer.vue'; + import ShippingMethodTabSelect from './components/ShippingMethodTabSelect.vue'; defineOptions({ name: 'PriceCheck', @@ -259,7 +259,7 @@ type SelectOption = { value: string; label: string }; const countryOptions = ref([]); - const shippingMethodOptions = ref([]); + const shippingMethodGroups = ref([]); const cargoTypeOptions = ref([]); const warehouseOptions = ref>([]); const optionsLoading = ref(false); @@ -270,12 +270,6 @@ return { code, name }; } - function normalizeProductRow(row: any) { - const code = String(row?.productCode ?? row?.ProductCode ?? '').trim(); - const name = String(row?.productName ?? row?.ProductName ?? '').trim(); - return { code, name }; - } - function normalizeDictRow(row: any) { const code = String(row?.dictCode ?? row?.DictCode ?? '').trim(); const name = String(row?.dictName ?? row?.DictName ?? '').trim(); @@ -292,9 +286,9 @@ async function loadPriceCheckOptions() { optionsLoading.value = true; try { - const [countryRes, productRes, dictRows, warehouseRes] = await Promise.all([ + const [countryRes, shippingGroups, dictRows, warehouseRes] = await Promise.all([ getCountryList(), - getSalesProductList({ page: 1, pageSize: 500, isActive: 1 }), + getOrderPriceCheckShippingOptions(), getDictListAll({ dictType: 'cargo_attribute' }), getWarehouseList({ page: 1, pageSize: 500 }), ]); @@ -307,14 +301,7 @@ })); countryOptions.value = countries; - const products = (productRes.items ?? []) - .map(normalizeProductRow) - .filter((p) => p.code) - .map((p) => ({ - value: p.code, - label: p.name ? `${p.name} ${p.code}` : p.code, - })); - shippingMethodOptions.value = products; + shippingMethodGroups.value = shippingGroups ?? []; const cargoOpts = (dictRows ?? []) .map(normalizeDictRow) @@ -336,7 +323,7 @@ } catch (e: any) { Message.error(e?.message || '加载筛选项失败'); countryOptions.value = []; - shippingMethodOptions.value = []; + shippingMethodGroups.value = []; cargoTypeOptions.value = []; warehouseOptions.value = []; } finally { @@ -463,17 +450,13 @@
- - - {{ option.label }} - - + />