docs: 发版前评审/安全审计报告、迁移 runbook、CLAUDE.md 表格口径更新
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
This commit is contained in:
@@ -249,7 +249,7 @@ cd client && flutter test
|
||||
|
||||
### 响应式 / 移动端适配
|
||||
- 断点判定统一用 `context.isMobile`(`client/lib/core/responsive/responsive.dart`,宽度 < 600 为窄屏/手机),**禁止**在各处散落 `MediaQuery.width < 600` 这类魔法数
|
||||
- **列表屏**:用 `DataTableCard` 时必须同时传 `mobileCards`(窄屏渲染卡片流),卡片复用 `MobileListCard` / `MobileCardField`(`widgets/mobile_list_card.dart`);宽屏仍走原表格,行为不变
|
||||
- **列表屏**:统一用 `DsTable`(`widgets/ds/ds_table.dart`,真相源表格:toolbar+列+pager);窄屏卡片流复用 `MobileListCard` / `MobileCardField`(`widgets/mobile_list_card.dart`)。旧 `DataTableCard` 已删除(2026-07-03),勿再引用
|
||||
- **弹窗固定宽度**:一律用 `context.dialogWidth(X)`(≤ 屏宽 92%),**禁止**裸写 `width: <固定值>` 导致窄屏溢出
|
||||
- **导航**:窄屏(手机)用 Drawer 抽屉(`app_shell.dart`),宽屏保持侧边栏;新增页面无需单独处理,挂在 shell 下即可
|
||||
- 平台判断仍遵守上面「前端平台判断」规则(`kIsWeb` 先于 `dart:io`)
|
||||
|
||||
@@ -0,0 +1,684 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>数据库 Schema — 酒库管理系统</title>
|
||||
<style>
|
||||
:root{
|
||||
--primary:#2563AC; --primary-dark:#154072; --danger:#D14343; --danger-bg:#FDECEC;
|
||||
--success:#2E8B57; --success-bg:#E6F3EC; --warn:#B45309; --warn-bg:#FFF4E5; --accent:#8B2331;
|
||||
--ink:#232934; --muted:#6E7888; --border:#DCE2EB; --paper:#F5F7FA; --head:#F0F4FF;
|
||||
}
|
||||
*{box-sizing:border-box;font-family:-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;}
|
||||
body{margin:0;background:var(--paper);color:var(--ink);line-height:1.6;}
|
||||
.layout{display:flex;align-items:flex-start;}
|
||||
nav{position:sticky;top:0;align-self:flex-start;width:210px;height:100vh;overflow:auto;background:#fff;border-right:1px solid var(--border);padding:18px 14px;flex:0 0 auto;}
|
||||
nav .navgroup{margin-bottom:14px;}
|
||||
nav .navtitle{font-size:11px;font-weight:700;color:var(--primary-dark);text-transform:uppercase;letter-spacing:.5px;margin-bottom:5px;}
|
||||
nav a{display:block;font-size:12px;color:var(--muted);text-decoration:none;padding:2px 0;}
|
||||
nav a:hover{color:var(--primary);}
|
||||
nav a code{font-family:ui-monospace,Menlo,monospace;font-size:11.5px;}
|
||||
main{flex:1 1 auto;padding:26px 30px;max-width:1100px;min-width:0;}
|
||||
h1{font-size:22px;margin:0 0 4px;}
|
||||
.sub{color:var(--muted);font-size:13px;margin-bottom:6px;}
|
||||
.stats{display:flex;gap:22px;font-size:12px;color:var(--muted);margin:10px 0 4px;}
|
||||
.stats b{color:var(--ink);font-size:15px;}
|
||||
h2{font-size:17px;margin:34px 0 6px;color:var(--primary-dark);border-bottom:2px solid var(--head);padding-bottom:6px;}
|
||||
.gdesc{font-size:12.5px;color:var(--muted);margin:6px 0 12px;}
|
||||
h3{font-size:14px;margin:0 0 10px;display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;}
|
||||
.tname{font-family:ui-monospace,Menlo,monospace;font-size:14px;background:var(--primary-dark);color:#fff;padding:2px 9px;border-radius:5px;}
|
||||
.tcomment{font-size:12.5px;color:var(--muted);font-weight:400;}
|
||||
.card{background:#fff;border:1px solid var(--border);border-radius:10px;padding:16px 18px;margin:14px 0;}
|
||||
table{width:100%;border-collapse:collapse;font-size:12.5px;margin:6px 0;}
|
||||
th{background:var(--head);color:var(--primary-dark);font-weight:600;font-size:11.5px;text-align:left;padding:7px 9px;border-bottom:1px solid var(--border);}
|
||||
td{padding:6px 9px;border-bottom:1px solid #EEF1F6;vertical-align:top;}
|
||||
tr:last-child td{border-bottom:0;}
|
||||
.mono{font-family:ui-monospace,Menlo,monospace;}
|
||||
td.ty{color:var(--accent);font-size:11.5px;}
|
||||
td.df{color:var(--muted);font-size:11.5px;}
|
||||
td.ctr{text-align:center;}
|
||||
code{font-family:ui-monospace,Menlo,monospace;font-size:11.5px;background:#EEF2F8;padding:1px 5px;border-radius:4px;color:var(--primary-dark);}
|
||||
.tag{display:inline-block;font-size:10px;padding:0 6px;border-radius:9px;font-weight:600;line-height:16px;}
|
||||
.tag.pk{background:#FDECEC;color:var(--danger);}
|
||||
.tag.uk{background:#E5EEF9;color:var(--primary);}
|
||||
.tag.ix{background:#EEE;color:var(--muted);}
|
||||
.tag.ft{background:var(--warn-bg);color:var(--warn);}
|
||||
.tag.tnt{background:var(--success-bg);color:var(--success);}
|
||||
.keys{margin-top:8px;font-size:11.5px;line-height:1.9;border-top:1px dashed var(--border);padding-top:8px;}
|
||||
.keys .kd{color:var(--muted);}
|
||||
.callout{border-left:4px solid var(--primary);background:#F0F6FF;padding:9px 13px;border-radius:4px;margin:8px 0 12px;font-size:12.5px;}
|
||||
.callout.danger{border-color:var(--danger);background:var(--danger-bg);}
|
||||
.callout.warn{border-color:var(--warn);background:var(--warn-bg);}
|
||||
.callout.ok{border-color:var(--success);background:var(--success-bg);}
|
||||
.legend{display:flex;gap:16px;flex-wrap:wrap;font-size:12px;color:var(--muted);margin:8px 0 0;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layout">
|
||||
<nav>
|
||||
<div style="font-size:13px;font-weight:700;color:var(--primary-dark);margin-bottom:14px;">📊 数据库 Schema</div>
|
||||
<div class="navgroup"><div class="navtitle">租户 · 用户 · 安全</div><a href="#shops"><code>shops</code></a><a href="#users"><code>users</code></a><a href="#user_sessions"><code>user_sessions</code></a><a href="#login_attempts"><code>login_attempts</code></a></div><div class="navgroup"><div class="navtitle">授权 · 兑换券</div><a href="#licenses"><code>licenses</code></a><a href="#license_devices"><code>license_devices</code></a><a href="#license_codes"><code>license_codes</code></a></div><div class="navgroup"><div class="navtitle">商品主数据</div><a href="#products"><code>products</code></a><a href="#product_categories"><code>product_categories</code></a><a href="#product_images"><code>product_images</code></a><a href="#product_name_options"><code>product_name_options</code></a><a href="#product_series_options"><code>product_series_options</code></a><a href="#product_spec_options"><code>product_spec_options</code></a><a href="#product_origin_options"><code>product_origin_options</code></a><a href="#product_shelf_life_options"><code>product_shelf_life_options</code></a><a href="#product_storage_options"><code>product_storage_options</code></a><a href="#product_description_docs"><code>product_description_docs</code></a></div><div class="navgroup"><div class="navtitle">仓库 · 往来单位</div><a href="#warehouses"><code>warehouses</code></a><a href="#partners"><code>partners</code></a></div><div class="navgroup"><div class="navtitle">出入库单据</div><a href="#stock_in_orders"><code>stock_in_orders</code></a><a href="#stock_in_items"><code>stock_in_items</code></a><a href="#stock_out_orders"><code>stock_out_orders</code></a><a href="#stock_out_items"><code>stock_out_items</code></a></div><div class="navgroup"><div class="navtitle">库存 · 流水 · 盘点</div><a href="#inventories"><code>inventories</code></a><a href="#inventory_logs"><code>inventory_logs</code></a><a href="#inventory_checks"><code>inventory_checks</code></a><a href="#inventory_check_items"><code>inventory_check_items</code></a></div><div class="navgroup"><div class="navtitle">财务</div><a href="#finance_records"><code>finance_records</code></a></div><div class="navgroup"><div class="navtitle">配置 · 运维 · 反馈</div><a href="#number_rules"><code>number_rules</code></a><a href="#feedbacks"><code>feedbacks</code></a><a href="#error_reports"><code>error_reports</code></a></div>
|
||||
</nav>
|
||||
<main>
|
||||
<h1>数据库 Schema · 酒库管理系统</h1>
|
||||
<div class="sub">MySQL 8.0+ · 多租户(所有业务表含 <code>shop_id</code> 隔离)· 启动时 GORM AutoMigrate</div>
|
||||
<div class="stats"><div><b>31</b> 张表</div><div><b>365</b> 个字段</div><div>来源:<code>backend/schema/schema.sql</code> + model AutoMigrate</div></div>
|
||||
<div class="legend">
|
||||
<span><span class="tag pk">PK</span> 主键</span>
|
||||
<span><span class="tag uk">UNIQUE</span> 唯一键</span>
|
||||
<span><span class="tag ix">INDEX</span> 普通索引</span>
|
||||
<span><span class="tag ft">FULLTEXT</span> 全文索引</span>
|
||||
<span><span class="tag tnt">租户</span> 多租户隔离列</span>
|
||||
</div>
|
||||
<section><h2>租户 · 用户 · 安全</h2><p class="gdesc">多租户根表与登录/会话/审计。所有业务表的 shop_id 都指向 shops。</p><div class="card" id="shops">
|
||||
<h3><code class="tname">shops</code> <span class="tcomment">门店(租户)</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">name</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">否</td><td class="mono df">—</td><td>门店名称</td></tr>
|
||||
<tr><td class="mono">code</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">否</td><td class="mono df">—</td><td>门店编号(唯一)</td></tr>
|
||||
<tr><td class="mono">address</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">phone</td><td class="mono ty">VARCHAR(30)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">manager_name</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>负责人</td></tr>
|
||||
<tr><td class="mono">description</td><td class="mono ty">TEXT</td><td class="ctr">是</td><td class="mono df">NULL</td><td>店铺简介</td></tr>
|
||||
<tr><td class="mono">logo_url</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">—</td><td>门店 logo URL</td></tr>
|
||||
<tr><td class="mono">business_license</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>营业执照照片URL</td></tr>
|
||||
<tr><td class="mono">shop_photos</td><td class="mono ty">JSON</td><td class="ctr">是</td><td class="mono df">NULL</td><td>门店照片URL数组</td></tr>
|
||||
<tr><td class="mono">custom_fields</td><td class="mono ty">JSON</td><td class="ctr">是</td><td class="mono df">NULL</td><td>扩展字段</td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag uk">UNIQUE uk_code</span> <span class="mono kd">(`code`)</span><br><span class="tag ix">INDEX idx_deleted_at</span> <span class="mono kd">(`deleted_at`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="users">
|
||||
<h3><code class="tname">users</code> <span class="tcomment">用户</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">username</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">password_hash</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">否</td><td class="mono df">—</td><td>bcrypt</td></tr>
|
||||
<tr><td class="mono">real_name</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">phone</td><td class="mono ty">VARCHAR(30)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">role</td><td class="mono ty">ENUM('admin','operator','readonly','superadmin')</td><td class="ctr">否</td><td class="mono df">operator</td><td></td></tr>
|
||||
<tr><td class="mono">is_active</td><td class="mono ty">TINYINT(1)</td><td class="ctr">否</td><td class="mono df">1</td><td></td></tr>
|
||||
<tr><td class="mono">last_login_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td>最近登录时间</td></tr>
|
||||
<tr><td class="mono">custom_fields</td><td class="mono ty">JSON</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag uk">UNIQUE uk_shop_username</span> <span class="mono kd">(`shop_id`, `username`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span><br><span class="tag ix">INDEX idx_deleted_at</span> <span class="mono kd">(`deleted_at`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="user_sessions">
|
||||
<h3><code class="tname">user_sessions</code> <span class="tcomment">登录会话</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">user_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">sid</td><td class="mono ty">VARCHAR(64)</td><td class="ctr">否</td><td class="mono df">—</td><td>嵌入 JWT 的会话标识</td></tr>
|
||||
<tr><td class="mono">device_id</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">device_name</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">platform</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>windows|macos|linux|android|ios|web</td></tr>
|
||||
<tr><td class="mono">platform_class</td><td class="mono ty">VARCHAR(20)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>desktop|mobile|web</td></tr>
|
||||
<tr><td class="mono">ip</td><td class="mono ty">VARCHAR(64)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">user_agent</td><td class="mono ty">VARCHAR(512)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">refresh_jti</td><td class="mono ty">VARCHAR(64)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>当前有效 refresh token 的 jti,用于轮换+重用检测</td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">last_seen_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">revoked_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">revoked_reason</td><td class="mono ty">VARCHAR(30)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>kicked|logout|admin|disabled|reuse|pwd_reset</td></tr>
|
||||
<tr><td class="mono">revoked_by</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td>吊销操作人 user_id;系统/自助吊销为 NULL</td></tr>
|
||||
<tr><td class="mono">refresh_exp_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag uk">UNIQUE uk_session_sid</span> <span class="mono kd">(`sid`)</span><br><span class="tag ix">INDEX idx_session_shop_user</span> <span class="mono kd">(`shop_id`, `user_id`)</span><br><span class="tag ix">INDEX idx_session_class</span> <span class="mono kd">(`platform_class`)</span><br><span class="tag ix">INDEX idx_session_revoked</span> <span class="mono kd">(`revoked_at`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="login_attempts">
|
||||
<h3><code class="tname">login_attempts</code> <span class="tcomment">登录尝试审计</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_code</td><td class="mono ty">VARCHAR(64)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">username</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">ip</td><td class="mono ty">VARCHAR(64)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">user_agent</td><td class="mono ty">VARCHAR(512)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">success</td><td class="mono ty">TINYINT(1)</td><td class="ctr">否</td><td class="mono df">0</td><td></td></tr>
|
||||
<tr><td class="mono">reason</td><td class="mono ty">VARCHAR(40)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>invalid_shop|invalid_user|bad_password|locked|inactive|platform_not_allowed</td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_attempt_user</span> <span class="mono kd">(`username`, `created_at`)</span><br><span class="tag ix">INDEX idx_attempt_ip</span> <span class="mono kd">(`ip`, `created_at`)</span></div>
|
||||
</div></section><section><h2>授权 · 兑换券</h2><p class="gdesc">门店授权与时长兑换券码池(ed25519/HMAC 已退役,改时长兑换券模型)。</p><div class="card" id="licenses">
|
||||
<h3><code class="tname">licenses</code> <span class="tcomment">许可证</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">license_key</td><td class="mono ty">VARCHAR(768)</td><td class="ctr">否</td><td class="mono df">—</td><td>Ed25519 signed token</td></tr>
|
||||
<tr><td class="mono">device_id</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>deprecated: use license_devices</td></tr>
|
||||
<tr><td class="mono">type</td><td class="mono ty">ENUM('trial','monthly','annual','lifetime')</td><td class="ctr">否</td><td class="mono df">trial</td><td></td></tr>
|
||||
<tr><td class="mono">tier</td><td class="mono ty">VARCHAR(32)</td><td class="ctr">否</td><td class="mono df">standard</td><td>权益档位钩子(pro/max-like),当前默认 standard</td></tr>
|
||||
<tr><td class="mono">expires_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td>NULL=永久</td></tr>
|
||||
<tr><td class="mono">is_active</td><td class="mono ty">TINYINT(1)</td><td class="ctr">否</td><td class="mono df">1</td><td></td></tr>
|
||||
<tr><td class="mono">max_devices</td><td class="mono ty">INT</td><td class="ctr">否</td><td class="mono df">3</td><td>最大绑定设备数</td></tr>
|
||||
<tr><td class="mono">features</td><td class="mono ty">JSON</td><td class="ctr">是</td><td class="mono df">NULL</td><td>功能开关 {"finance":true}</td></tr>
|
||||
<tr><td class="mono">activated_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td>deprecated</td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag uk">UNIQUE uk_license_key</span> <span class="mono kd">(`license_key`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="license_devices">
|
||||
<h3><code class="tname">license_devices</code> <span class="tcomment">许可证设备绑定</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">license_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">device_id</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">device_name</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">platform</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>windows|macos|android|ios|web</td></tr>
|
||||
<tr><td class="mono">activated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">last_seen_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag uk">UNIQUE uk_license_device</span> <span class="mono kd">(`license_id`, `device_id`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span><br><span class="tag ix">INDEX idx_license_id</span> <span class="mono kd">(`license_id`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="license_codes">
|
||||
<h3><code class="tname">license_codes</code> <span class="tcomment">兑换券码池</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">code</td><td class="mono ty">VARCHAR(32)</td><td class="ctr">否</td><td class="mono df">—</td><td>归一化大写无连字符</td></tr>
|
||||
<tr><td class="mono">type</td><td class="mono ty">ENUM('trial','monthly','annual','lifetime')</td><td class="ctr">否</td><td class="mono df">annual</td><td>计费/时长标签</td></tr>
|
||||
<tr><td class="mono">tier</td><td class="mono ty">VARCHAR(32)</td><td class="ctr">否</td><td class="mono df">standard</td><td>档位钩子(pro/max-like),当前默认 standard</td></tr>
|
||||
<tr><td class="mono">duration_days</td><td class="mono ty">INT</td><td class="ctr">否</td><td class="mono df">0</td><td>授予时长;0=永久(lifetime)</td></tr>
|
||||
<tr><td class="mono">max_devices</td><td class="mono ty">INT</td><td class="ctr">否</td><td class="mono df">0</td><td>授予设备上限;0=不改变现值</td></tr>
|
||||
<tr><td class="mono">status</td><td class="mono ty">ENUM('unused','redeemed','void')</td><td class="ctr">否</td><td class="mono df">unused</td><td></td></tr>
|
||||
<tr><td class="mono">redeemed_shop_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td>被哪个门店兑换</td></tr>
|
||||
<tr><td class="mono">redeemed_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">redeemed_device_id</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>兑换设备(审计)</td></tr>
|
||||
<tr><td class="mono">batch</td><td class="mono ty">VARCHAR(64)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>发放批次/活动名</td></tr>
|
||||
<tr><td class="mono">note</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag uk">UNIQUE uk_code</span> <span class="mono kd">(`code`)</span><br><span class="tag ix">INDEX idx_status</span> <span class="mono kd">(`status`)</span><br><span class="tag ix">INDEX idx_redeemed_shop</span> <span class="mono kd">(`redeemed_shop_id`)</span></div>
|
||||
</div></section><section><h2>商品主数据</h2><p class="gdesc">products 每行 = 一个特有产品/序列号(非 SKU),是商品信息的单一来源。基础数据字典为入库选文本服务。</p><div class="card" id="products">
|
||||
<h3><code class="tname">products</code> <span class="tcomment">商品</span></h3>
|
||||
<div class="callout ok"><b>单一来源铁律:</b>批次号 <code>batch_no</code>、生产日期 <code>production_date</code>、进价、图片、public_id 均以此表为准。每行 = 一个序列号(<code>uk_product_code</code> 同店唯一)。</div>
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">code</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>商品编号</td></tr>
|
||||
<tr><td class="mono">barcode</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>条码</td></tr>
|
||||
<tr><td class="mono">name</td><td class="mono ty">VARCHAR(200)</td><td class="ctr">否</td><td class="mono df">—</td><td>商品名称</td></tr>
|
||||
<tr><td class="mono">series</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>系列</td></tr>
|
||||
<tr><td class="mono">spec</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>规格</td></tr>
|
||||
<tr><td class="mono">unit</td><td class="mono ty">VARCHAR(20)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>单位</td></tr>
|
||||
<tr><td class="mono">category_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">brand</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>品牌</td></tr>
|
||||
<tr><td class="mono">purchase_price</td><td class="mono ty">DECIMAL(16,2)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>参考进价</td></tr>
|
||||
<tr><td class="mono">sale_price</td><td class="mono ty">DECIMAL(16,2)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>参考售价</td></tr>
|
||||
<tr><td class="mono">public_id</td><td class="mono ty">CHAR(36)</td><td class="ctr">否</td><td class="mono df">—</td><td>UUID,公开URL使用</td></tr>
|
||||
<tr><td class="mono">min_stock</td><td class="mono ty">INT</td><td class="ctr">是</td><td class="mono df">0</td><td>库存预警值</td></tr>
|
||||
<tr><td class="mono">description</td><td class="mono ty">TEXT</td><td class="ctr">是</td><td class="mono df">NULL</td><td>商品描述</td></tr>
|
||||
<tr><td class="mono">custom_fields</td><td class="mono ty">JSON</td><td class="ctr">是</td><td class="mono df">NULL</td><td>动态扩展字段</td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span><br><span class="tag ix">INDEX idx_category</span> <span class="mono kd">(`category_id`)</span><br><span class="tag ix">INDEX idx_deleted_at</span> <span class="mono kd">(`deleted_at`)</span><br><span class="tag uk">UNIQUE uk_product_code</span> <span class="mono kd">(`shop_id`, `code`)</span><br><span class="tag uk">UNIQUE uk_public_id</span> <span class="mono kd">(`public_id`)</span><br><span class="tag ft">FULLTEXT ft_name</span> <span class="mono kd">(`name`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="product_categories">
|
||||
<h3><code class="tname">product_categories</code> <span class="tcomment">商品分类</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">name</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">parent_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td>父分类,支持二级</td></tr>
|
||||
<tr><td class="mono">sort_order</td><td class="mono ty">INT</td><td class="ctr">否</td><td class="mono df">0</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="product_images">
|
||||
<h3><code class="tname">product_images</code> <span class="tcomment">商品图片</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">product_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">url</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">否</td><td class="mono df">—</td><td>相对路径,如 /images/products/1/xxx.jpg</td></tr>
|
||||
<tr><td class="mono">sort_order</td><td class="mono ty">INT</td><td class="ctr">否</td><td class="mono df">0</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_product_id</span> <span class="mono kd">(`product_id`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="product_name_options">
|
||||
<h3><code class="tname">product_name_options</code> <span class="tcomment">商品名称选项</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">code</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>选项编号</td></tr>
|
||||
<tr><td class="mono">name</td><td class="mono ty">VARCHAR(200)</td><td class="ctr">否</td><td class="mono df">—</td><td>名称</td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span><br><span class="tag ix">INDEX idx_deleted_at</span> <span class="mono kd">(`deleted_at`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="product_series_options">
|
||||
<h3><code class="tname">product_series_options</code> <span class="tcomment">商品系列选项</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">code</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>选项编号</td></tr>
|
||||
<tr><td class="mono">name</td><td class="mono ty">VARCHAR(200)</td><td class="ctr">否</td><td class="mono df">—</td><td>系列名称</td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span><br><span class="tag ix">INDEX idx_deleted_at</span> <span class="mono kd">(`deleted_at`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="product_spec_options">
|
||||
<h3><code class="tname">product_spec_options</code> <span class="tcomment">商品规格选项</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">code</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>选项编号</td></tr>
|
||||
<tr><td class="mono">name</td><td class="mono ty">VARCHAR(200)</td><td class="ctr">否</td><td class="mono df">—</td><td>规格名称</td></tr>
|
||||
<tr><td class="mono">quantity</td><td class="mono ty">INT</td><td class="ctr">是</td><td class="mono df">0</td><td>单品数量</td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span><br><span class="tag ix">INDEX idx_deleted_at</span> <span class="mono kd">(`deleted_at`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="product_origin_options">
|
||||
<h3><code class="tname">product_origin_options</code> <span class="tcomment">商品产地选项(基础数据·AutoMigrate)</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td>租户隔离</td></tr>
|
||||
<tr><td class="mono">code</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">—</td><td>选项编号</td></tr>
|
||||
<tr><td class="mono">name</td><td class="mono ty">VARCHAR(200)</td><td class="ctr">否</td><td class="mono df">—</td><td>名称</td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">created_at / updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td>软删除</td></tr></tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="card" id="product_shelf_life_options">
|
||||
<h3><code class="tname">product_shelf_life_options</code> <span class="tcomment">商品保质期选项(如「24个月」「无限期」·AutoMigrate)</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td>租户隔离</td></tr>
|
||||
<tr><td class="mono">code</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">—</td><td>选项编号</td></tr>
|
||||
<tr><td class="mono">name</td><td class="mono ty">VARCHAR(200)</td><td class="ctr">否</td><td class="mono df">—</td><td>名称</td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">created_at / updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td>软删除</td></tr></tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="card" id="product_storage_options">
|
||||
<h3><code class="tname">product_storage_options</code> <span class="tcomment">商品储存条件选项(如「阴凉避光」·AutoMigrate)</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td>租户隔离</td></tr>
|
||||
<tr><td class="mono">code</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">—</td><td>选项编号</td></tr>
|
||||
<tr><td class="mono">name</td><td class="mono ty">VARCHAR(200)</td><td class="ctr">否</td><td class="mono df">—</td><td>名称</td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">created_at / updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td>软删除</td></tr></tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="card" id="product_description_docs">
|
||||
<h3><code class="tname">product_description_docs</code> <span class="tcomment">商品介绍文档(富文本·AutoMigrate)</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td>租户隔离</td></tr>
|
||||
<tr><td class="mono">title</td><td class="mono ty">VARCHAR(200)</td><td class="ctr">否</td><td class="mono df">—</td><td>标题</td></tr>
|
||||
<tr><td class="mono">content</td><td class="mono ty">TEXT</td><td class="ctr">是</td><td class="mono df">—</td><td>正文</td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">created_at / updated_at / deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">—</td><td class="mono df">—</td><td></td></tr></tbody>
|
||||
</table>
|
||||
|
||||
</div></section><section><h2>仓库 · 往来单位</h2><div class="card" id="warehouses">
|
||||
<h3><code class="tname">warehouses</code> <span class="tcomment">仓库</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">name</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">location</td><td class="mono ty">VARCHAR(200)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">is_default</td><td class="mono ty">TINYINT(1)</td><td class="ctr">否</td><td class="mono df">0</td><td></td></tr>
|
||||
<tr><td class="mono">custom_fields</td><td class="mono ty">JSON</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="partners">
|
||||
<h3><code class="tname">partners</code> <span class="tcomment">往来单位</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">code</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">name</td><td class="mono ty">VARCHAR(200)</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">type</td><td class="mono ty">SET('supplier','customer')</td><td class="ctr">否</td><td class="mono df">supplier</td><td>可同时是供应商和客户</td></tr>
|
||||
<tr><td class="mono">contact</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>联系人</td></tr>
|
||||
<tr><td class="mono">phone</td><td class="mono ty">VARCHAR(30)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">address</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">bank_account</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>银行账号</td></tr>
|
||||
<tr><td class="mono">status</td><td class="mono ty">ENUM('enabled','disabled')</td><td class="ctr">否</td><td class="mono df">enabled</td><td>正常/禁用</td></tr>
|
||||
<tr><td class="mono">custom_fields</td><td class="mono ty">JSON</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span><br><span class="tag ix">INDEX idx_deleted_at</span> <span class="mono kd">(`deleted_at`)</span></div>
|
||||
</div></section><section><h2>出入库单据</h2><p class="gdesc">单据明细含「快照列」(product_code/name/series/spec/batch_no/production_date):导入/审核时拷贝,作历史保真+显示兜底。</p><div class="card" id="stock_in_orders">
|
||||
<h3><code class="tname">stock_in_orders</code> <span class="tcomment">入库单</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">order_no</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">否</td><td class="mono df">—</td><td>入库单号</td></tr>
|
||||
<tr><td class="mono">type</td><td class="mono ty">VARCHAR(30)</td><td class="ctr">否</td><td class="mono df">purchase</td><td>入库类型: purchase采购/return退货/other其他</td></tr>
|
||||
<tr><td class="mono">warehouse_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">partner_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td>供应商</td></tr>
|
||||
<tr><td class="mono">operator_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td>经办人</td></tr>
|
||||
<tr><td class="mono">creator_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td>制单人</td></tr>
|
||||
<tr><td class="mono">reviewer_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td>审核人</td></tr>
|
||||
<tr><td class="mono">status</td><td class="mono ty">ENUM('draft','pending','approved','rejected')</td><td class="ctr">否</td><td class="mono df">draft</td><td></td></tr>
|
||||
<tr><td class="mono">order_date</td><td class="mono ty">DATE</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">total_amount</td><td class="mono ty">DECIMAL(16,2)</td><td class="ctr">否</td><td class="mono df">0</td><td></td></tr>
|
||||
<tr><td class="mono">reviewed_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">custom_fields</td><td class="mono ty">JSON</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag uk">UNIQUE uk_order_no</span> <span class="mono kd">(`shop_id`, `order_no`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span><br><span class="tag ix">INDEX idx_warehouse</span> <span class="mono kd">(`warehouse_id`)</span><br><span class="tag ix">INDEX idx_order_date</span> <span class="mono kd">(`order_date`)</span><br><span class="tag ix">INDEX idx_status</span> <span class="mono kd">(`status`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="stock_in_items">
|
||||
<h3><code class="tname">stock_in_items</code> <span class="tcomment">入库单明细</span></h3>
|
||||
<div class="callout warn"><b>快照列:</b><code>product_code/product_name/series/spec/batch_no/production_date</code> 在导入/录入时拷贝,product_id 可为 0(历史导入占位)。<b>库存页的批次/生产日期实际从这里取(见 inventories 说明)。</b></div>
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">order_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">product_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">product_code</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>商品编号(源流水号,历史导入)</td></tr>
|
||||
<tr><td class="mono">product_name</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>商品名称(历史导入快照)</td></tr>
|
||||
<tr><td class="mono">series</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>系列(历史导入快照)</td></tr>
|
||||
<tr><td class="mono">spec</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>规格(历史导入快照)</td></tr>
|
||||
<tr><td class="mono">quantity</td><td class="mono ty">DECIMAL(12,3)</td><td class="ctr">否</td><td class="mono df">—</td><td>数量</td></tr>
|
||||
<tr><td class="mono">unit_price</td><td class="mono ty">DECIMAL(16,2)</td><td class="ctr">否</td><td class="mono df">0</td><td>单价</td></tr>
|
||||
<tr><td class="mono">total_price</td><td class="mono ty">DECIMAL(16,2)</td><td class="ctr">否</td><td class="mono df">0</td><td></td></tr>
|
||||
<tr><td class="mono">batch_no</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>批次号</td></tr>
|
||||
<tr><td class="mono">production_date</td><td class="mono ty">DATE</td><td class="ctr">是</td><td class="mono df">NULL</td><td>生产日期</td></tr>
|
||||
<tr><td class="mono">expire_date</td><td class="mono ty">DATE</td><td class="ctr">是</td><td class="mono df">NULL</td><td>有效期</td></tr>
|
||||
<tr><td class="mono">custom_fields</td><td class="mono ty">JSON</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_order_id</span> <span class="mono kd">(`order_id`)</span><br><span class="tag ix">INDEX idx_shop_product</span> <span class="mono kd">(`shop_id`, `product_id`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="stock_out_orders">
|
||||
<h3><code class="tname">stock_out_orders</code> <span class="tcomment">出库单</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">order_no</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">type</td><td class="mono ty">VARCHAR(30)</td><td class="ctr">否</td><td class="mono df">sale</td><td>sale销售/return退货/other其他</td></tr>
|
||||
<tr><td class="mono">warehouse_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">partner_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td>客户</td></tr>
|
||||
<tr><td class="mono">operator_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">creator_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td>制单人</td></tr>
|
||||
<tr><td class="mono">reviewer_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">status</td><td class="mono ty">ENUM('draft','pending','approved','rejected')</td><td class="ctr">否</td><td class="mono df">draft</td><td></td></tr>
|
||||
<tr><td class="mono">order_date</td><td class="mono ty">DATE</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">total_amount</td><td class="mono ty">DECIMAL(16,2)</td><td class="ctr">否</td><td class="mono df">0</td><td></td></tr>
|
||||
<tr><td class="mono">reviewed_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">custom_fields</td><td class="mono ty">JSON</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag uk">UNIQUE uk_order_no</span> <span class="mono kd">(`shop_id`, `order_no`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span><br><span class="tag ix">INDEX idx_warehouse</span> <span class="mono kd">(`warehouse_id`)</span><br><span class="tag ix">INDEX idx_order_date</span> <span class="mono kd">(`order_date`)</span><br><span class="tag ix">INDEX idx_status</span> <span class="mono kd">(`status`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="stock_out_items">
|
||||
<h3><code class="tname">stock_out_items</code> <span class="tcomment">出库单明细</span></h3>
|
||||
<div class="callout danger"><b>当前问题相关:</b>出库行快照 <code>batch_no/production_date</code> 在 App 建单时常为空(选货按 product 聚合、未带批次)。打印回退到 <code>products</code> 主记录——若该 product 也没填,就显示空白,但库存页仍能显示(取自入库明细)。<code>unit_price</code>=成本、<code>sale_price</code>=售价。</div>
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">order_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">product_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">product_code</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>商品编号(源流水号,历史导入)</td></tr>
|
||||
<tr><td class="mono">product_name</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>商品名称(历史导入快照)</td></tr>
|
||||
<tr><td class="mono">series</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>系列(历史导入快照)</td></tr>
|
||||
<tr><td class="mono">spec</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>规格(历史导入快照)</td></tr>
|
||||
<tr><td class="mono">quantity</td><td class="mono ty">DECIMAL(12,3)</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">unit_price</td><td class="mono ty">DECIMAL(16,2)</td><td class="ctr">否</td><td class="mono df">0</td><td>成本单价(入库成本快照)</td></tr>
|
||||
<tr><td class="mono">sale_price</td><td class="mono ty">DECIMAL(16,2)</td><td class="ctr">否</td><td class="mono df">0</td><td>售价(出库实际销售单价,应收按售价×数量)</td></tr>
|
||||
<tr><td class="mono">total_price</td><td class="mono ty">DECIMAL(16,2)</td><td class="ctr">否</td><td class="mono df">0</td><td>成本小计(unit_price×quantity)</td></tr>
|
||||
<tr><td class="mono">batch_no</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>批次号</td></tr>
|
||||
<tr><td class="mono">production_date</td><td class="mono ty">DATE</td><td class="ctr">是</td><td class="mono df">NULL</td><td>生产日期</td></tr>
|
||||
<tr><td class="mono">custom_fields</td><td class="mono ty">JSON</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_order_id</span> <span class="mono kd">(`order_id`)</span><br><span class="tag ix">INDEX idx_shop_product</span> <span class="mono kd">(`shop_id`, `product_id`)</span><br><span class="tag ix">INDEX idx_so_items_shop_code</span> <span class="mono kd">(`shop_id`, `product_code`)</span></div>
|
||||
</div></section><section><h2>库存 · 流水 · 盘点</h2><p class="gdesc">库存为批次模式:每条 inventories 记录 = 一个入库批次,经 stock_in_item_id 关联其入库明细。</p><div class="card" id="inventories">
|
||||
<h3><code class="tname">inventories</code> <span class="tcomment">库存批次记录</span></h3>
|
||||
<div class="callout warn"><b>批次模式 + 显示口径:</b>每行 = 一个入库批次。列表查询的批次/生产日期取 <code>COALESCE(DATE(sii.production_date), DATE(inv.production_date))</code>、<code>COALESCE(NULLIF(sii.batch_no,''), inv.batch_no)</code>——优先关联入库明细 <code>sii</code>,<b>不读 products</b>。本表 batch_no/production_date 为快照兜底。</div>
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td>主键</td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td>所属门店(多租户隔离,所有查询必带)</td></tr>
|
||||
<tr><td class="mono">warehouse_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td>所在仓库;NULL 表示历史导入未指定仓</td></tr>
|
||||
<tr><td class="mono">product_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td>指向 products 的特有产品/序列号;历史导入占位单据可为 NULL/0</td></tr>
|
||||
<tr><td class="mono">stock_in_item_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td>来源入库明细行。批次/生产日期显示优先从此关联取(sii),是本表的「真值上游」</td></tr>
|
||||
<tr><td class="mono">inventory_check_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td>若由盘点调整产生,指向盘点单 inventory_checks</td></tr>
|
||||
<tr><td class="mono">quantity</td><td class="mono ty">DECIMAL(12,3)</td><td class="ctr">否</td><td class="mono df">0</td><td>当前批次结存数量(出入库审核时在事务内增减)</td></tr>
|
||||
<tr><td class="mono">product_code</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>商品编号快照(拷贝自入库时),product 缺失时兜底显示</td></tr>
|
||||
<tr><td class="mono">product_name</td><td class="mono ty">VARCHAR(200)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>商品名称快照,兜底显示</td></tr>
|
||||
<tr><td class="mono">series</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>系列快照(语义=型号),兜底显示</td></tr>
|
||||
<tr><td class="mono">spec</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>规格快照(语义=版本),兜底显示</td></tr>
|
||||
<tr><td class="mono">unit</td><td class="mono ty">VARCHAR(20)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>单位快照</td></tr>
|
||||
<tr><td class="mono">warehouse_name</td><td class="mono ty">VARCHAR(100)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>仓库名快照,warehouse 关联缺失时兜底</td></tr>
|
||||
<tr><td class="mono">unit_price</td><td class="mono ty">DECIMAL(16,2)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>入库成本单价快照</td></tr>
|
||||
<tr><td class="mono">production_date</td><td class="mono ty">DATE</td><td class="ctr">是</td><td class="mono df">NULL</td><td>生产日期快照兜底(显示口径见上方:优先取 stock_in_item)</td></tr>
|
||||
<tr><td class="mono">batch_no</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>批次号快照兜底(显示口径见上方:优先取 stock_in_item)</td></tr>
|
||||
<tr><td class="mono">supplier_name</td><td class="mono ty">VARCHAR(200)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>供应商名快照(入库来源)</td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>备注</td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td>创建时间(FIFO 排序依据 idx_fifo 用到)</td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td>更新时间</td></tr>
|
||||
<tr><td class="mono">deleted_at</td><td class="mono ty">DATETIME</td><td class="ctr">是</td><td class="mono df">NULL</td><td>软删除标记,NULL=有效</td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span><br><span class="tag ix">INDEX idx_fifo</span> <span class="mono kd">(`shop_id`, `warehouse_id`, `product_id`, `created_at`)</span><br><span class="tag ix">INDEX idx_shop_wh_product</span> <span class="mono kd">(`shop_id`, `warehouse_id`, `product_id`)</span><br><span class="tag ix">INDEX idx_stock_in_item</span> <span class="mono kd">(`stock_in_item_id`)</span><br><span class="tag ix">INDEX idx_inventory_check</span> <span class="mono kd">(`inventory_check_id`)</span><br><span class="tag ix">INDEX idx_deleted_at</span> <span class="mono kd">(`deleted_at`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="inventory_logs">
|
||||
<h3><code class="tname">inventory_logs</code> <span class="tcomment">库存流水</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">warehouse_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">product_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">direction</td><td class="mono ty">ENUM('in','out')</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">quantity</td><td class="mono ty">DECIMAL(12,3)</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">qty_before</td><td class="mono ty">DECIMAL(12,3)</td><td class="ctr">否</td><td class="mono df">—</td><td>变动前数量</td></tr>
|
||||
<tr><td class="mono">qty_after</td><td class="mono ty">DECIMAL(12,3)</td><td class="ctr">否</td><td class="mono df">—</td><td>变动后数量</td></tr>
|
||||
<tr><td class="mono">ref_type</td><td class="mono ty">VARCHAR(30)</td><td class="ctr">否</td><td class="mono df">—</td><td>stock_in/stock_out/check</td></tr>
|
||||
<tr><td class="mono">ref_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td>关联单据ID</td></tr>
|
||||
<tr><td class="mono">operator_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_shop_product</span> <span class="mono kd">(`shop_id`, `product_id`)</span><br><span class="tag ix">INDEX idx_ref</span> <span class="mono kd">(`ref_type`, `ref_id`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="inventory_checks">
|
||||
<h3><code class="tname">inventory_checks</code> <span class="tcomment">库存盘点单</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">check_no</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">warehouse_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">operator_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">status</td><td class="mono ty">ENUM('draft','completed')</td><td class="ctr">否</td><td class="mono df">draft</td><td></td></tr>
|
||||
<tr><td class="mono">check_date</td><td class="mono ty">DATE</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag uk">UNIQUE uk_check_no</span> <span class="mono kd">(`shop_id`, `check_no`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="inventory_check_items">
|
||||
<h3><code class="tname">inventory_check_items</code> <span class="tcomment">盘点明细</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">check_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">product_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">system_qty</td><td class="mono ty">DECIMAL(12,3)</td><td class="ctr">否</td><td class="mono df">—</td><td>系统数量</td></tr>
|
||||
<tr><td class="mono">actual_qty</td><td class="mono ty">DECIMAL(12,3)</td><td class="ctr">否</td><td class="mono df">—</td><td>实际盘点数量</td></tr>
|
||||
<tr><td class="mono">diff_qty</td><td class="mono ty">DECIMAL(12,3)</td><td class="ctr">是</td><td class="mono df">计算列</td><td>差异</td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(255)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_check_id</span> <span class="mono kd">(`check_id`)</span></div>
|
||||
</div></section><section><h2>财务</h2><div class="card" id="finance_records">
|
||||
<h3><code class="tname">finance_records</code> <span class="tcomment">财务流水</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">partner_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">type</td><td class="mono ty">ENUM('receivable','payable','receipt','payment')</td><td class="ctr">否</td><td class="mono df">—</td><td>应收/应付/收款/付款</td></tr>
|
||||
<tr><td class="mono">amount</td><td class="mono ty">DECIMAL(16,2)</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">balance</td><td class="mono ty">DECIMAL(16,2)</td><td class="ctr">否</td><td class="mono df">—</td><td>操作后余额</td></tr>
|
||||
<tr><td class="mono">status</td><td class="mono ty">ENUM('open','closed')</td><td class="ctr">否</td><td class="mono df">open</td><td>结清状态(payable/receivable 有效)</td></tr>
|
||||
<tr><td class="mono">ref_type</td><td class="mono ty">VARCHAR(30)</td><td class="ctr">是</td><td class="mono df">NULL</td><td>关联单据类型</td></tr>
|
||||
<tr><td class="mono">ref_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">operator_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">record_date</td><td class="mono ty">DATE</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">custom_fields</td><td class="mono ty">JSON</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">remark</td><td class="mono ty">VARCHAR(500)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span><br><span class="tag ix">INDEX idx_partner</span> <span class="mono kd">(`partner_id`)</span><br><span class="tag ix">INDEX idx_record_date</span> <span class="mono kd">(`record_date`)</span></div>
|
||||
</div></section><section><h2>配置 · 运维 · 反馈</h2><div class="card" id="number_rules">
|
||||
<h3><code class="tname">number_rules</code> <span class="tcomment">单号规则</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">type</td><td class="mono ty">VARCHAR(30)</td><td class="ctr">否</td><td class="mono df">—</td><td>stock_in/stock_out/check</td></tr>
|
||||
<tr><td class="mono">prefix</td><td class="mono ty">VARCHAR(20)</td><td class="ctr">是</td><td class="mono df">—</td><td>前缀</td></tr>
|
||||
<tr><td class="mono">current_no</td><td class="mono ty">INT</td><td class="ctr">否</td><td class="mono df">0</td><td>当前序号</td></tr>
|
||||
<tr><td class="mono">date_format</td><td class="mono ty">VARCHAR(20)</td><td class="ctr">是</td><td class="mono df">YYYYMMDD</td><td>日期格式</td></tr>
|
||||
<tr><td class="mono">updated_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag uk">UNIQUE uk_shop_type</span> <span class="mono kd">(`shop_id`, `type`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="feedbacks">
|
||||
<h3><code class="tname">feedbacks</code> <span class="tcomment">用户意见反馈</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">否</td><td class="mono df">CURRENT_TIMESTAMP</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">shop_code</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">user_id</td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">username</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">role</td><td class="mono ty">VARCHAR(20)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">type</td><td class="mono ty">VARCHAR(20)</td><td class="ctr">否</td><td class="mono df">—</td><td>bug / suggestion</td></tr>
|
||||
<tr><td class="mono">content</td><td class="mono ty">TEXT</td><td class="ctr">是</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">images</td><td class="mono ty">JSON</td><td class="ctr">是</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">app_version</td><td class="mono ty">VARCHAR(30)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">platform</td><td class="mono ty">VARCHAR(20)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">client_ip</td><td class="mono ty">VARCHAR(60)</td><td class="ctr">是</td><td class="mono df">NULL</td><td></td></tr>
|
||||
<tr><td class="mono">status</td><td class="mono ty">VARCHAR(20)</td><td class="ctr">否</td><td class="mono df">new</td><td></td></tr></tbody>
|
||||
</table>
|
||||
<div class="keys"><span class="tag pk">PRIMARY</span> <span class="mono kd">(`id`)</span><br><span class="tag ix">INDEX idx_shop_id</span> <span class="mono kd">(`shop_id`)</span><br><span class="tag ix">INDEX idx_user_id</span> <span class="mono kd">(`user_id`)</span><br><span class="tag ix">INDEX idx_type</span> <span class="mono kd">(`type`)</span><br><span class="tag ix">INDEX idx_status</span> <span class="mono kd">(`status`)</span></div>
|
||||
</div>
|
||||
<div class="card" id="error_reports">
|
||||
<h3><code class="tname">error_reports</code> <span class="tcomment">客户端异常上报(AutoMigrate,无 shop 软删除)</span></h3>
|
||||
|
||||
<table>
|
||||
<thead><tr><th style="width:23%">列名</th><th style="width:20%">类型</th><th style="width:7%">可空</th><th style="width:16%">默认</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td class="mono"><b>id</b> <span class="tag pk">PK</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">否</td><td class="mono df">AUTO_INC</td><td></td></tr>
|
||||
<tr><td class="mono">error_type</td><td class="mono ty">VARCHAR(30)</td><td class="ctr">否</td><td class="mono df">—</td><td>flutter_error / zone_error / caught_exception</td></tr>
|
||||
<tr><td class="mono">app_version</td><td class="mono ty">VARCHAR(30)</td><td class="ctr">是</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">platform</td><td class="mono ty">VARCHAR(20)</td><td class="ctr">是</td><td class="mono df">—</td><td>ios/android/web/windows/macos</td></tr>
|
||||
<tr><td class="mono">username</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">shop_id <span class="tag tnt">租户</span></td><td class="mono ty">BIGINT UNSIGNED</td><td class="ctr">是</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">shop_no</td><td class="mono ty">VARCHAR(50)</td><td class="ctr">是</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">role</td><td class="mono ty">VARCHAR(20)</td><td class="ctr">是</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">product_info</td><td class="mono ty">VARCHAR(200)</td><td class="ctr">是</td><td class="mono df">—</td><td>设备/系统信息</td></tr>
|
||||
<tr><td class="mono">client_ip</td><td class="mono ty">VARCHAR(60)</td><td class="ctr">是</td><td class="mono df">—</td><td></td></tr>
|
||||
<tr><td class="mono">error_msg</td><td class="mono ty">TEXT</td><td class="ctr">否</td><td class="mono df">—</td><td>错误信息</td></tr>
|
||||
<tr><td class="mono">stack_trace</td><td class="mono ty">TEXT</td><td class="ctr">是</td><td class="mono df">—</td><td>堆栈</td></tr>
|
||||
<tr><td class="mono">occurred_at</td><td class="mono ty">DATETIME</td><td class="ctr">—</td><td class="mono df">—</td><td>发生时间</td></tr>
|
||||
<tr><td class="mono">created_at</td><td class="mono ty">DATETIME</td><td class="ctr">—</td><td class="mono df">—</td><td>上报时间</td></tr></tbody>
|
||||
</table>
|
||||
|
||||
</div></section>
|
||||
<p class="sub" style="margin-top:30px;">生成时间:2026-06-26 · 字段以 schema.sql 为准;产地/保质期/储存/介绍文档/异常上报等表由 GORM AutoMigrate 建,列信息取自 <code>backend/internal/model/</code>。</p>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,121 @@
|
||||
# 代码审查报告 — 提交前复审(auth 双屏重建 + DS 原子扩展 + 备案 https 回切)
|
||||
|
||||
**审查时间**:2026-07-03(第二轮,接 `docs/review/2026-07-03-uncommitted-review.md`)
|
||||
**变更范围**:git diff HEAD 210 个文件(+11354 / −10986)+ 约 90 个未跟踪文件(auth_shared / ds_toast / ds_menu / users_screen / golden 基线等)
|
||||
**已验证事实**(调用方提供):`flutter analyze` 0 error、251 测试全过、`check_ds_code` 0 违规、`go build/vet/test` 全过
|
||||
|
||||
## 总体评价
|
||||
|
||||
本轮新增改动质量高,无阻塞提交的问题。登录/注册双屏照原型重建后,dispose 路径(Timer/OverlayEntry/FocusNode/Controller)总体齐全;上一轮 6 条 should-fix 中 4 条已修复(https 回切一并解决 SHOULD-001/002,manual.yml 兼容变量解决 003,DsButton 置灰解决 004),SEC-001/002/003 修复无回归且补了跨租户回归测试。剩余问题集中在登录屏两处小竞态/生命周期缝隙和几条运维/文档收尾项。
|
||||
|
||||
---
|
||||
|
||||
## 必须修复(blocking)
|
||||
|
||||
无。
|
||||
|
||||
---
|
||||
|
||||
## 建议改进(should-fix,non-blocking)
|
||||
|
||||
### [SHOULD-101] 登录中途导航离开 → catch 分支 setState 打在已 dispose 的 State 上
|
||||
**文件**:`client/lib/screens/auth/login_screen.dart:306-311`
|
||||
**问题**:`_login()` 里 `await AuthRepository.login(...)` 期间,「注册新门店 →」「忘记密码?」链接**未随 `_loading` 禁用**,用户可在等待网络时点走(`context.go('/register')`)。此后:
|
||||
- 失败路径:`on AuthException catch` / `catch` 里的 `setState(() => _errorMessage = ...)` 无 `mounted` 守卫(对照 finally 是有的),在已 dispose 的 State 上抛 FlutterError,经全局捕获还会打进错误上报;
|
||||
- 成功路径:`await ref.read(authStateProvider.notifier).login(user)` 在 dispose 后使用 `ref` 同样会抛,且被泛型 catch 捕到后再次走无守卫的 setState。
|
||||
|
||||
**建议**:
|
||||
```dart
|
||||
} on AuthException catch (e) {
|
||||
if (!mounted) return;
|
||||
setState(() => _errorMessage = e.message);
|
||||
}
|
||||
```
|
||||
两个 catch 都补 `mounted` 守卫;或更简单——`_loading` 时把两个 `_Link` 的 onTap 置空。
|
||||
|
||||
### [SHOULD-102] 历史下拉:失焦关闭 Timer 在重新聚焦时未取消,会误关刚打开的下拉
|
||||
**文件**:`client/lib/screens/auth/login_screen.dart:81-95, 97-111`
|
||||
**问题**:失焦分支安排 `_closeShopTimer = Timer(150ms, _closeShop)`;但 `hasFocus` 分支只调 `_closeShop()` 不取消该 Timer。序列「聚焦 → 点外部失焦(Timer 起跑)→ 150ms 内再点回字段(下拉重新打开)→ 旧 Timer 到点」会把刚打开的下拉关掉,且箭头图标状态与实际不符。username 侧同构。
|
||||
**建议**:`hasFocus` 分支先 `_closeShopTimer?.cancel()` / `_closeUsernameTimer?.cancel()` 再开下拉。
|
||||
|
||||
### [SHOULD-103] SEC-004 残留:盘点建单仍未校验 warehouse_id / product_id 归属
|
||||
**文件**:`backend/internal/handler/inventory.go:240-271`(`CreateCheck`)
|
||||
**问题**:本轮 `finance.Create` 已补 `ensureShopRefOpt`(finance.go:96-100),stock_in/out 的 Create/Update 也都补了;但审计报告 SEC-004 点名的另一处 `CreateCheck` 依旧直存请求里的 `req.WarehouseID` 与 `Items[i].ProductID`,塞他店 id 会留下跨店脏引用。读取侧已按 shop_id 收口(Preload 带条件、system_qty 查询带 shop_id),**无信息泄露**,但脏数据会让该盘点行 system_qty 恒为 0、`Items.Product` 恒为 nil。
|
||||
**建议**:对齐 stock_in.Create 的写法:
|
||||
```go
|
||||
if err := ensureShopRef(h.db, "warehouses", req.WarehouseID, shopID); err != nil { ... }
|
||||
for i := range req.Items {
|
||||
if err := ensureShopRef(h.db, "products", req.Items[i].ProductID, shopID); err != nil { ... }
|
||||
}
|
||||
```
|
||||
|
||||
### [SHOULD-104] 证书续期路径依赖营销站 webroot,8 月底到期前需确认打通
|
||||
**文件**:`deploy/nginx-jiu-ali.conf:107-112`(80 → 443 无条件 301)、注释第 8-9 行
|
||||
**问题**:证书 2026-08-28 到期(不足两个月)。80 端口整站 `return 301`,certbot HTTP-01 会跟随跳转到 443,challenge 最终落在 `location /` 的 `root /opt/jiu/marketing`。两个脆弱点:① certbot `--webroot` 必须恰好指向 `/opt/jiu/marketing`;② `deploy-site.sh` 若用 `rsync --delete` 同步营销站,续期窗口内可能删掉 challenge 文件。
|
||||
**建议**:在 80 的 server 块里、`return 301` 之前加一个独立 challenge 位置,让续期与营销站部署解耦:
|
||||
```nginx
|
||||
location ^~ /.well-known/acme-challenge/ { root /opt/jiu/acme; }
|
||||
```
|
||||
并在 baize 台账登记续期命令用同一 webroot。
|
||||
|
||||
### [SHOULD-105] 项目 CLAUDE.md 仍强制使用本轮已删除的 DataTableCard
|
||||
**文件**:`/Users/wangjia/code/jiu/CLAUDE.md`(「表格列头筛选」「响应式 / 移动端适配」两节)
|
||||
**问题**:`client/lib/widgets/data_table_card.dart` 本轮已删(连同 form_dialog / page_scaffold / search_chip / select_product_dialog / tab_state_provider,经全量 grep 确认**零残留引用**),但项目规则仍写「用 `DataTableCard` 时必须同时传 `mobileCards`」「可筛选列使用 `FilterableColumnHeader`」。规则与代码脱节,后续 agent 会照死文档施工。(`ColDef` 仍存活于 `multi_select_dropdown.dart`,该行不受影响。)
|
||||
**建议**:随本次提交把这两节改写为 DS 重建后的真实套路(ds_atoms / MobileListCard 现状)。
|
||||
|
||||
### [SHOULD-106] 测试失败截图混在未跟踪文件里,勿随本次提交入库
|
||||
**文件**:`client/test/failures/tmp_date_menu_{isolatedDiff,maskedDiff,masterImage,testImage}.png`
|
||||
**问题**:golden 失败产物;`client/.gitignore` 只忽略 `test/golden/failures/`,没盖住 `test/failures/`,`git add -A` 会把 4 张调试图带进仓库(违背「截图放 tmp 不落 repo」约定)。
|
||||
**建议**:`client/.gitignore` 补一行 `test/failures/`,并删除这 4 个文件(用 git clean)。
|
||||
|
||||
### [SHOULD-107](上轮 SHOULD-005 收尾)结清后 financePartnerRowsProvider 仍陈旧
|
||||
**文件**:`client/lib/screens/stock_in/stock_in_list_screen.dart:1117-1119`(stock_out 同构)
|
||||
**问题**:本轮已补 `reload()` 刷新列表(好),但 `financePartnerRowsProvider` 是**非 autoDispose** 的 FutureProvider(finance_provider.dart:113),结清后切到财务屏仍显示结清前的应收应付,直到财务屏自己的刷新路径触发。
|
||||
**建议**:closeByRef 成功后追加 `ref.invalidate(financePartnerRowsProvider)`(一行)。
|
||||
|
||||
---
|
||||
|
||||
## 细节(nit)
|
||||
|
||||
### [NIT-101] 登录历史下拉定宽 340,窄屏溢出字段甚至屏幕
|
||||
**文件**:`client/lib/screens/auth/login_screen.dart:202`
|
||||
`context.dialogWidth(340)` 只按屏宽 92% 封顶。360dp 手机上字段实际宽约 248(440 卡 − 24 外距 − 32 内距 ×2),下拉 331 宽从字段左缘起排,右侧超出屏幕约 27px 被裁。建议宽度取锚点字段实宽(LayoutBuilder 或缓存 RenderBox size)。
|
||||
|
||||
### [NIT-102] `replaceFirst('AuthException: ', '')` 是死代码
|
||||
**文件**:`client/lib/screens/auth/register_screen.dart:136`
|
||||
`AuthException.toString()` 直接返回 message(auth_repository.dart:17),该前缀永不出现。无害,删掉即可。
|
||||
|
||||
### [NIT-103] `_resetPassword` 的 TextEditingController 仍未 dispose(上轮 NIT-003 未修)
|
||||
**文件**:`client/lib/screens/settings/users_screen.dart:465`
|
||||
另:该对话框用裸 Material `TextField` + `InputDecoration(hintText)`,与 DS 的 `DsInput` 不一致(check_ds_code 未拦,属风格缝隙)。
|
||||
|
||||
### [NIT-104] 授权锁定判定靠英文文案子串匹配
|
||||
**文件**:`client/lib/screens/auth/login_screen.dart:60-64`
|
||||
`m.contains('license') && (lock|expire)` 与后端 `service.ErrLicenseLocked` 固定文案强耦合,后端一旦本地化/改文案即静默失效退回普通错误条。注释已写明来源,可接受;更稳做法是后端返回错误 code。
|
||||
|
||||
### [NIT-105] 注册页「确认密码」与「登录密码」共用一个 `_obscure`
|
||||
**文件**:`client/lib/screens/auth/register_screen.dart:280-297`
|
||||
点密码框的眼睛会同时明文显示确认框。行为可辩护(对照确认更方便),确认是有意为之即可。
|
||||
|
||||
### [NIT-106] 登录/注册页脚年份硬编码「© 2026」
|
||||
**文件**:`client/lib/screens/auth/login_screen.dart:562`
|
||||
跨年需手改。原型如此则属 1:1 还原,提请知悉。
|
||||
|
||||
---
|
||||
|
||||
## 值得肯定的地方
|
||||
|
||||
- **上轮反馈闭环干净**:https 回切一举解决 SHOULD-001(mixed content)与 SHOULD-002——5 个 `compile-*.sh` 的 `BASE_URL` 全部回到 `https://jiu.51yanmei.com`,Android `usesCleartextTraffic`、iOS/macOS `NSAllowsArbitraryLoads` 明文豁免**全部撤除**(工作树与 HEAD 一致,经 PlistBuddy/grep 逐一确认);`manual.yml` 补 `EC2_* = ALI_*` 兼容变量解决旧 tag 回滚炸 unbound variable(SHOULD-003);`DsButton` disabled 态 `Opacity(0.55)`(SHOULD-004)✅
|
||||
- **SEC 修复无回归且加了防回归测试**:`ownership.go` 写入侧 `ensureShopRef` + 读取侧全部 `Preload("X", "shop_id = ?", shopID)` 双防线,`TestStockInHandler_CrossTenantRefs` 覆盖「跨店外键 400 + 存量脏引用不带出 PII」两条路径;`main.go` 生产模式空/默认 JWT secret 直接拒启(SEC-002);三个运维 workflow 的 DB 密码改从容器内 `$MYSQL_ROOT_PASSWORD` 取、不再走命令行(SEC-003),`DB_PASSWORD` secret 引用清零 ✅
|
||||
- **登录屏生命周期总体严谨**:`dispose()` 中 Timer cancel、OverlayEntry remove、3 controller + 2 FocusNode 全 dispose;`ds_toast` 单例 `_entry.mounted` 守卫 + `_entry == entry` 比对避免关错新 toast;「被顶下线漏提示」的 initState 首帧补读修法正确且注释讲清了根因 ✅
|
||||
- **`fillStockOutItemSnapshots` 顺带完成了出库明细 product 归属校验**(`shop_id = ? AND id IN ?` + 缺行报错),比逐行 ensureShopRef 还省往返 ✅
|
||||
- **死文件清理彻底**:6 个删除文件在 lib/ 与 test/ 均无残留引用(analyze 0 error 交叉印证)✅
|
||||
- **注册契约核对无误**:`AuthRepository.register` 六字段与后端 `service.RegisterInput`(auth.go:424-432)逐一对应,密码 min=6 与前端校验一致,与原型差异(无编号/兑换券字段、地址必填)在文件头注释里如实登记 ✅
|
||||
|
||||
---
|
||||
|
||||
## 结论
|
||||
|
||||
- [x] 0 处 blocking,可以提交
|
||||
- [ ] should-fix 7 处:SHOULD-101/102(登录屏两行守卫,建议顺手修掉再提交)、SHOULD-106(.gitignore + 删 4 张失败截图,**建议提交前处理**以免脏图入库)、SHOULD-105(CLAUDE.md 同步)、SHOULD-103/104/107 可随后续迭代
|
||||
- [ ] nit 6 处,不阻塞
|
||||
@@ -0,0 +1,96 @@
|
||||
# 代码审查报告 — 未提交变更集(出入库 rolling30 + DS 重构 + CI ali 单轨化)
|
||||
|
||||
**审查时间**:2026-07-03
|
||||
**变更文件**:200 个文件,+10283 行,−9665 行(含 staged 删除 `client/lib/widgets/data_table_card.dart`)
|
||||
**验证结果**:`go build ./...` / `go vet ./...` / `go test ./...` 全部通过;`flutter analyze` 0 error(3 warning 均在 test/,96 info)
|
||||
|
||||
## 总体评价
|
||||
|
||||
变更集质量整体很高。后端 rolling30 窗口边界数学正确、窗口相接不重叠、有测试覆盖,新增查询多租户 `shop_id` 条件齐全;客户端大规模 DS 重构后,我逐一核对了全部 40+ 处确认弹窗的「按钮标签 ↔ onPressed ↔ pop 值」语义,未发现批量正则转换导致的错位;CI ali 单轨化的 `DEPLOY_*` 变量在 workflows / lib-forgejo.sh / deploy-*.sh / backup-db.sh 之间自洽。无阻塞合并的问题;「裸 IP 明文 HTTP」是用户拍板的备案过渡方案,但有两条具体的破坏路径需要确认(见 SHOULD-001/002)。
|
||||
|
||||
---
|
||||
|
||||
## 必须修复(blocking)
|
||||
|
||||
无。
|
||||
|
||||
---
|
||||
|
||||
## 建议改进(should-fix,non-blocking 但建议尽快处理/确认)
|
||||
|
||||
### [SHOULD-001] Web 版 mixed content:https 域名入口下 API 全被浏览器拦截
|
||||
**文件**:`scripts/ci/compile-client-web.sh:20-21`(同模式见 `compile-android.sh:44`、`compile-ios.sh:106`、`compile-macos.sh:33`、`compile-windows.sh:43`、`scripts/local_test.sh:33`)
|
||||
**问题**:Web 构建的 `BASE_URL` 硬编码为 `http://182.92.213.171:8443`。`deploy-client.yml:183-184` 注释说明 EC2 仍保留 `jiu.51yanmei.com` 反代桥接到 ali——若任何用户仍从 `https://jiu.51yanmei.com/app` 打开 Web 版,页面是 https 源、XHR 目标是 http,浏览器会以 active mixed content 直接拦截所有 API 请求,登录静默失败(native 桌面/移动端无此策略,不受影响)。
|
||||
**建议**:三选一——① Web 构建 `BASE_URL` 留空走同源相对路径(`AppConfig` 里 Web 分支取 `Uri.base`),天然兼容 http/https 两个入口;② 确认 EC2 桥已把 `/app` 路径 301 到 `http://182.92.213.171:8443/app`;③ 明确弃用域名 Web 入口并在 baize 台账登记。
|
||||
|
||||
### [SHOULD-002] 明文 HTTP 承载登录口令与 JWT(过渡期已知风险,建议登记回切项)
|
||||
**文件**:`scripts/ci/compile-*.sh`(同上)、`client/android/app/src/main/AndroidManifest.xml:11`、`client/ios/Runner/Info.plist:11`、`client/macos/Runner/Info.plist:37`
|
||||
**问题**:备案过渡期所有客户端流量(含 `/auth/login` 的明文密码、后续每个请求的 JWT)走公网明文 HTTP;三端又同时开了全局明文豁免(Android `usesCleartextTraffic="true"`、iOS/macOS `NSAllowsArbitraryLoads=true`)。注释里已写「备案后应移除」,但散落在 6 个 compile 脚本 + 3 个平台清单共 9 处。另注意:iOS 带 `NSAllowsArbitraryLoads=true` 提交 App Store/TestFlight 可能被要求填写豁免理由。
|
||||
**建议**:用 todo skill 登记一条「备案通过后回切 https」任务,列全 9 处文件清单,避免遗漏;iOS 可考虑收窄为 `NSExceptionDomains` 只豁免该 IP。
|
||||
|
||||
### [SHOULD-003] manual.yml 回滚到割接前的旧 tag 会失败
|
||||
**文件**:`.gitea/workflows/manual.yml:22-24, 31-35`
|
||||
**问题**:manual 回滚 `checkout ref: inputs.version` 后执行**旧 tag 里的** deploy 脚本。割接前的 tag(deploy 脚本尚未支持 `DEPLOY_*` 回退写法、直接引用 `${EC2_HOST}`)在 `set -u` 下会因 unbound variable 直接失败——而回滚恰恰最可能选旧版本。
|
||||
**建议**:要么在 manual.yml env 里同时兼容传一份 `EC2_* = ALI_*`(让旧脚本也指向 ali),要么在 workflow 注释里写明「最早可回滚 tag」的下限。
|
||||
|
||||
### [SHOULD-004] DsButton 无 disabled 视觉态,加载中按钮看起来仍可点
|
||||
**文件**:`client/lib/widgets/ds/ds_atoms.dart:47`(`InkWell(onTap: onPressed)`)
|
||||
**问题**:`onPressed: null` 时(如 `about_screen.dart:758` 提交反馈、`stock_in_form_screen.dart` 暂存/提交的 `_submitting ? null : ...`)按钮仅失去点击响应,颜色/边框与可用态完全一致,用户无从感知「提交中」。旧 Material 按钮自带 disabled 置灰,本次批量替换后此反馈丢失。
|
||||
**建议**:在 `DsButton.build` 里对 `onPressed == null` 做 `Opacity(0.5)` 或 fg/bg 换 `t.muted`/`t.bg`(对齐原型 `.btn:disabled` 若有定义;没有则先在原型 atoms.css 登记再实现,遵守设计系统单一真源)。
|
||||
|
||||
### [SHOULD-005] 结清成功后不刷新列表/财务数据
|
||||
**文件**:`client/lib/screens/stock_in/stock_in_list_screen.dart:1101-1135`、`client/lib/screens/stock_out/stock_out_list_screen.dart`(同构 `_confirmSettle`)
|
||||
**问题**:`closeByRef` 成功后只弹 snackbar,既不 `reload()` 列表也不 `invalidate` 财务相关 provider。若详情抽屉/行内展示了应收应付状态徽章,会显示过期状态;财务屏的 `financePartnerRowsProvider` 非 autoDispose 时也会陈旧(`finance_screen.dart:105` 有手动 invalidate,但只在财务屏自己的刷新路径里)。
|
||||
**建议**:结清成功后补 `ref.read(stockXxListProvider.notifier).reload()` 并 `ref.invalidate(financePartnerRowsProvider)`。
|
||||
|
||||
### [SHOULD-006] finance Trend 循环发 2N 条 SQL(months=24 时 48 条)
|
||||
**文件**:`backend/internal/handler/finance.go:198-215`
|
||||
**问题**:每个月对 `stock_in_orders`/`stock_out_orders` 各发一条 SUM 查询,`months` 上限 24 → 单请求最多 48 次往返。数据量小时无碍,但属于典型可合并聚合。
|
||||
**建议**:各表一条 `GROUP BY strftime/DATE_FORMAT(order_date, '%Y-%m')`(或按窗口一条 SQL 取回后内存分桶),把 2N 降到 2。注意保持 MySQL/SQLite 双方言兼容(现有代码用日期串比较正是为此,分桶在 Go 内存里做最稳)。
|
||||
|
||||
---
|
||||
|
||||
## 细节(nit)
|
||||
|
||||
### [NIT-001] 出库列表头部计数回退值口径混用
|
||||
**文件**:`client/lib/screens/stock_out/stock_out_list_screen.dart:466`
|
||||
`'近30天 ${...summary30...monthCount ?? total}'`——summary 未加载时回退到 `total`(当前筛选下的分页总数,非 30 天口径),文案与数值短暂不符。入库侧 `stock_in_list_screen.dart:426` 同构,建议未加载时显示 `—`。
|
||||
|
||||
### [NIT-002] DsSelect<Warehouse> 按对象同一性判等
|
||||
**文件**:`client/lib/screens/inventory/inventory_check_screen.dart:227`
|
||||
`o.$1 == value` 依赖实例同一性(`Warehouse` 未重写 `==`)。仓库列表 provider 因换店/网络恢复重建后,`_selectedWarehouse` 指向旧实例,选中标签会回落成「请选择仓库」。建议 `DsSelect<int>` 用 `warehouse.id` 做 value,或给模型加 `==`/`hashCode`。
|
||||
|
||||
### [NIT-003] `_resetPassword` 的 TextEditingController 未 dispose
|
||||
**文件**:`client/lib/screens/settings/users_screen.dart:461`
|
||||
对话框关闭后 `ctrl` 泄漏(对照 `stock_in_list_screen.dart:1084` 的 `_confirmCost` 是有 dispose 的)。低危但建议补齐。
|
||||
|
||||
### [NIT-004] finance Summary 的 GROUP BY 依赖 MySQL 函数依赖推导
|
||||
**文件**:`backend/internal/handler/finance.go:233-247`
|
||||
`SELECT COALESCE(p.name,'')` 但 `GROUP BY f.partner_id, f.type`。MySQL 5.7+ 的 `ONLY_FULL_GROUP_BY` 能识别 `p.id = f.partner_id` 的函数依赖所以现在能跑,但把 `p.name` 显式加进 GROUP BY 更防御(不同版本/方言行为差异)。
|
||||
|
||||
### [NIT-005] deploy 脚本头注释仍写 EC2 为默认目标
|
||||
**文件**:`scripts/ci/deploy-client.sh:5`、`deploy-site.sh:4`、`deploy-server.sh:21`(`DEPLOY_TARGET:-ec2` 默认值)
|
||||
割接后 EC2 轨已从 workflows 移除,但脚本注释与 `DEPLOY_TARGET` 默认值仍是 ec2。行为不受影响(workflow 显式传 ali),属文档漂移;下次动这些脚本时顺手更正即可。
|
||||
|
||||
### [NIT-006] 确认进价对话框:全部留空点「确认」无任何反馈
|
||||
**文件**:`client/lib/screens/stock_in/stock_in_list_screen.dart:1087`
|
||||
`ok == true` 但 `items` 为空时静默 return,用户不知道为什么没生效。建议 snackbar 提示「未填写任何进价」。
|
||||
|
||||
---
|
||||
|
||||
## 值得肯定的地方
|
||||
|
||||
- **rolling30 窗口边界正确**:`summaryBounds`(`backend/internal/handler/stock_in.go:170-180`)当前窗 `[今-29d, 明)` 与对照窗 `[今-59d, 今-29d)` 各 30 天、首尾相接不重叠;默认分支与原 `monthBounds` 行为完全等价;`stock_in_test.go:167-179` 补了 -40 天单据落对照窗的边界测试 ✅
|
||||
- **多租户无缺口**:本次触及的全部查询(stock_in/out Summary 的 agg 与 pending 计数、finance Trend 的 `sum`、finance Summary 的 Raw SQL、inventory summary 月初快照)均带 `shop_id = ?`;`shopID` 一律取自 `middleware.GetShopID(c)`,无一处从请求参数读 ✅
|
||||
- **批量转换零错位**:逐一核对 40+ 处 `DsButton` 弹窗动作——取消一律 pop(false/null/void)、确认语义键一律 pop(true),`_detailActionGroups` 中标签与 `_confirmDelete/Submit/Approve/Reject/Withdraw/Return/Settle` 的映射全部对应正确 ✅
|
||||
- **除零防御到位**:`_momDelta`(inventory_list_screen.dart:474)、`StockSummary.countDeltaPct/amountDeltaPct`(stock_summary.dart:27-32)、`DsBarChart` 的 `max<=0→1`(ds_bar_chart.dart:41)均有保护 ✅
|
||||
- **口径拆分清晰**:`stockXxSummaryProvider`(自然月,财务屏用)与 `stockXxSummary30Provider`(rolling30,列表 KPI 用)并存,避免财务屏被列表口径变更波及,注释写明了用户拍板缘由 ✅
|
||||
- **CI ali 单轨化自洽**:`DEPLOY_SSH_KEY/HOST/USER` 在 `lib-forgejo.sh:114-115`、三个 deploy 脚本、`backup-db.sh:20` 的 `${DEPLOY_*:-$EC2_*}` 回退写法一致;backup/manual/deploy-client/site/server 五个 workflow 均已切 `ALI_*` secrets ✅
|
||||
- **reload 保留旧数据**(inventory_provider.dart:105 `copyWithPrevious`)消除筛选切换白屏;`WheelDatePanel` 起止倒置时自动交换(wheel_date_picker.dart:285-287);stock_out 表单空明细在提交与渲染两处都有守卫 ✅
|
||||
|
||||
---
|
||||
|
||||
## 结论
|
||||
|
||||
- [x] 0 处 blocking 问题,可以合并
|
||||
- [ ] 建议改进 6 处(SHOULD-001/002 建议在下次发版前确认/登记回切项;003-006 可随后续迭代处理),nit 6 处不阻塞
|
||||
@@ -0,0 +1,821 @@
|
||||
inventory_id,shop_id,warehouse_id,product_id,shang_pin_bian_ma,name,series,spec,current_qty,pack_size,dirty_pack_eq_qty,suggest_qty
|
||||
1,1,1,1,NULL,NULL,NULL,NULL,108.000,,N,
|
||||
2,1,1,2,NULL,NULL,NULL,NULL,54.000,,N,
|
||||
3,1,1,3,NULL,NULL,NULL,NULL,36.000,,N,
|
||||
4,1,1,4,NULL,NULL,NULL,NULL,36.000,,N,
|
||||
5,1,1,5,NULL,NULL,NULL,NULL,24.000,,N,
|
||||
7,1,2,8,NULL,NULL,NULL,NULL,24.000,,N,
|
||||
1141,7,NULL,1166,ZXZ027280,茅台春夏秋冬动物2025,普通/53度,500ML*24/套,24.000,24,Y,1
|
||||
2276,6,NULL,2301,ZXZ027280,茅台春夏秋冬动物2025,普通/53度,500ML*24/套,24.000,24,Y,1
|
||||
3482,1,NULL,3507,ZXZ027280,茅台春夏秋冬动物2025,普通/53度,500ML*24/套,24.000,24,Y,1
|
||||
4760,8,10,4785,ZXZ027280,茅台春夏秋冬动物2025,普通/53度,500ML*24/套,24.000,24,Y,1
|
||||
4759,8,10,4784,ZXZ024282,杜康·河南,普通/53度,500ml*20/件,20.000,20,Y,1
|
||||
1140,7,NULL,1165,ZXZ024282,杜康·河南,普通/53度,500ml*20/件,20.000,20,Y,1
|
||||
2275,6,NULL,2300,ZXZ024282,杜康·河南,普通/53度,500ml*20/件,20.000,20,Y,1
|
||||
3481,1,NULL,3506,ZXZ024282,杜康·河南,普通/53度,500ml*20/件,20.000,20,Y,1
|
||||
6,1,2,7,NULL,NULL,NULL,NULL,18.000,,N,
|
||||
9412,8,10,4830,P1297,茅台公斤大件2005原件,普通/53度,1.00L*12/件,12.000,12,Y,1
|
||||
1126,7,NULL,1151,ZXZ010092,茅台大件2002,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4743,8,10,4768,ZXZ010092,茅台大件2002,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2261,6,NULL,2286,ZXZ010092,茅台大件2002,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3465,1,NULL,3490,ZXZ010092,茅台大件2002,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2262,6,NULL,2287,ZXZ010155,汾酒2000,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3466,1,NULL,3491,ZXZ010155,汾酒2000,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
1127,7,NULL,1152,ZXZ010155,汾酒2000,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4744,8,10,4769,ZXZ010155,汾酒2000,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4745,8,10,4770,ZXZ011928,茅台远望楼2010原箱,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2263,6,NULL,2288,ZXZ011928,茅台远望楼2010原箱,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3467,1,NULL,3492,ZXZ011928,茅台远望楼2010原箱,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
1128,7,NULL,1153,ZXZ011928,茅台远望楼2010原箱,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2153,6,NULL,2178,ZXZ014241,茅台2009大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3338,1,NULL,3363,ZXZ014241,茅台2009大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2264,6,NULL,2289,ZXZ014660,茅台博鳌亚洲论坛2012大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3468,1,NULL,3493,ZXZ014660,茅台博鳌亚洲论坛2012大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4746,8,10,4771,ZXZ014660,茅台博鳌亚洲论坛2012大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
1129,7,NULL,1154,ZXZ014660,茅台博鳌亚洲论坛2012大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
1130,7,NULL,1155,ZXZ014666,茅台五星2007大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2265,6,NULL,2290,ZXZ014666,茅台五星2007大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3469,1,NULL,3494,ZXZ014666,茅台五星2007大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4747,8,10,4772,ZXZ014666,茅台五星2007大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4748,8,10,4773,ZXZ021857,茅台白皮飞天1998原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
1131,7,NULL,1156,ZXZ021857,茅台白皮飞天1998原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2266,6,NULL,2291,ZXZ021857,茅台白皮飞天1998原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3470,1,NULL,3495,ZXZ021857,茅台白皮飞天1998原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2267,6,NULL,2292,ZXZ022311,茅台大件2008,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3471,1,NULL,3496,ZXZ022311,茅台大件2008,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4749,8,10,4774,ZXZ022311,茅台大件2008,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
1132,7,NULL,1157,ZXZ022311,茅台大件2008,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
1133,7,NULL,1158,ZXZ022498,茅台白皮1999原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2268,6,NULL,2293,ZXZ022498,茅台白皮1999原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3472,1,NULL,3497,ZXZ022498,茅台白皮1999原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4750,8,10,4775,ZXZ022498,茅台白皮1999原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4751,8,10,4776,ZXZ022499,茅台铁盖1993原开,普通/53度,200ml*12/件,12.000,12,Y,1
|
||||
1134,7,NULL,1159,ZXZ022499,茅台铁盖1993原开,普通/53度,200ml*12/件,12.000,12,Y,1
|
||||
2269,6,NULL,2294,ZXZ022499,茅台铁盖1993原开,普通/53度,200ml*12/件,12.000,12,Y,1
|
||||
3473,1,NULL,3498,ZXZ022499,茅台铁盖1993原开,普通/53度,200ml*12/件,12.000,12,Y,1
|
||||
6899,7,NULL,1159,ZXZ022500,茅台铁盖1993原开,普通/53度,200ml*12/件,12.000,12,Y,1
|
||||
9347,8,10,7269,ZXZ022500,茅台铁盖1993原开,普通/53度,200ml*12/件,12.000,12,Y,1
|
||||
4752,8,10,4777,ZXZ026149,茅台大件2011原箱,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2270,6,NULL,2295,ZXZ026149,茅台大件2011原箱,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3474,1,NULL,3499,ZXZ026149,茅台大件2011原箱,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
1135,7,NULL,1160,ZXZ026149,茅台大件2011原箱,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
1136,7,NULL,1161,ZXZ026326,茅台大件2011原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4753,8,10,4778,ZXZ026326,茅台大件2011原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2271,6,NULL,2296,ZXZ026326,茅台大件2011原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3475,1,NULL,3500,ZXZ026326,茅台大件2011原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2272,6,NULL,2297,ZXZ026602,茅台小白条2023原件,普通/53度,500ml*5/件,12.000,5,N,
|
||||
1137,7,NULL,1162,ZXZ026602,茅台小白条2023原件,普通/53度,500ml*5/件,12.000,5,N,
|
||||
1138,7,NULL,1163,ZXZ026827,贵州茅台酒2011,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2273,6,NULL,2298,ZXZ026827,贵州茅台酒2011,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3476,1,NULL,3501,ZXZ026827,贵州茅台酒2011,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
9348,8,10,7270,ZXZ026827,茅台大件2011原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
9349,8,10,7271,ZXZ026828,茅台大件2011原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
6900,7,NULL,1163,ZXZ026828,贵州茅台酒2011,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
6901,7,NULL,1163,ZXZ026829,贵州茅台酒2011,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
9350,8,10,7272,ZXZ026829,茅台大件2011原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
9351,8,10,7273,ZXZ026830,茅台大件2011原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
6902,7,NULL,1163,ZXZ026830,贵州茅台酒2011,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
6903,7,NULL,1163,ZXZ026831,贵州茅台酒2011,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
9352,8,10,7274,ZXZ026831,茅台大件2011原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
9353,8,10,7275,ZXZ026832,茅台大件2011原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
2274,6,NULL,2299,ZXZ026832,茅台2011原箱,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3477,1,NULL,3502,ZXZ026832,茅台2011原箱,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
1139,7,NULL,1164,ZXZ026832,茅台2011原箱,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
9354,8,10,7276,ZXZ026833,茅台大件2011原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
6904,7,NULL,1164,ZXZ026833,茅台2011原箱,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
6905,7,NULL,1043,ZXZ026936,茅台2009大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
6906,7,NULL,1043,ZXZ026937,茅台2009大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
9355,8,10,7277,ZXZ026937,茅台2009大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
6907,7,NULL,1043,ZXZ026938,茅台2009大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
9356,8,10,7278,ZXZ028054,茅台2009大件,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3478,1,NULL,3503,ZXZ028055,茅台公斤大件2009,普通/53度,1.00L*12/件,12.000,12,Y,1
|
||||
4754,8,10,4779,ZXZ028055,茅台公斤大件2009,普通/53度,1.00L*12/件,12.000,12,Y,1
|
||||
4755,8,10,4780,ZXZ028574,茅台大件2011,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3479,1,NULL,3504,ZXZ028574,茅台大件2011,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
3480,1,NULL,3505,ZXZ028684,茅台大件2006原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4756,8,10,4781,ZXZ028684,茅台大件2006原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4757,8,10,4782,ZXZ029443,铁盖郎酒1996原箱,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4758,8,10,4783,ZXZ029459,茅台和平鸽2017大件原开,普通/53度,500ml*12/件,12.000,12,Y,1
|
||||
4741,8,10,4766,ZXZ002041,茅台1998白皮,普通/53度,500ml*11/件,11.000,11,Y,1
|
||||
1124,7,NULL,1149,ZXZ002041,茅台1998白皮,普通/53度,500ml*11/件,11.000,11,Y,1
|
||||
2259,6,NULL,2284,ZXZ002041,茅台1998白皮,普通/53度,500ml*11/件,11.000,11,Y,1
|
||||
3463,1,NULL,3488,ZXZ002041,茅台1998白皮,普通/53度,500ml*11/件,11.000,11,Y,1
|
||||
2260,6,NULL,2285,ZXZ017445,茅台特供陈酿大件2013,普通/53度,500ml*11/件,11.000,11,Y,1
|
||||
3464,1,NULL,3489,ZXZ017445,茅台特供陈酿大件2013,普通/53度,500ml*11/件,11.000,11,Y,1
|
||||
4742,8,10,4767,ZXZ017445,茅台特供陈酿大件2013,普通/53度,500ml*11/件,11.000,11,Y,1
|
||||
1125,7,NULL,1150,ZXZ017445,茅台特供陈酿大件2013,普通/53度,500ml*11/件,11.000,11,Y,1
|
||||
1123,7,NULL,1148,ZXZ025203,酒鬼1999年,普通/54度,540ml*10/件,10.000,10,Y,1
|
||||
2258,6,NULL,2283,ZXZ025203,酒鬼1999年,普通/54度,540ml*10/件,10.000,10,Y,1
|
||||
3462,1,NULL,3487,ZXZ026602,茅台小白条2023原件,普通/53度,500ml*5/件,10.000,5,N,
|
||||
4740,8,10,4765,ZXZ026602,茅台小白条2023原件,普通/53度,500ml*5/件,10.000,5,N,
|
||||
4739,8,10,4764,ZXZ002042,茅台白皮1999,普通/53度,500ml*8/件,8.000,8,Y,1
|
||||
1122,7,NULL,1147,ZXZ002042,茅台白皮1999,普通/53度,500ml*8/件,8.000,8,Y,1
|
||||
2257,6,NULL,2282,ZXZ002042,茅台白皮1999,普通/53度,500ml*8/件,8.000,8,Y,1
|
||||
3461,1,NULL,3486,ZXZ002042,茅台白皮1999,普通/53度,500ml*8/件,8.000,8,Y,1
|
||||
9405,8,10,4816,P1283,茅台彩釉珍品2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3360,1,NULL,3385,ZXZ000997,茅台酱色2018,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4632,8,10,4657,ZXZ000997,茅台酱色2018,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1031,7,NULL,1056,ZXZ000997,茅台酱色2018,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2166,6,NULL,2191,ZXZ000997,茅台酱色2018,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1032,7,NULL,1057,ZXZ002635,茅台三十年原开2005,普通/53度,375ml*6/件,6.000,6,Y,1
|
||||
2167,6,NULL,2192,ZXZ002635,茅台三十年原开2005,普通/53度,375ml*6/件,6.000,6,Y,1
|
||||
3361,1,NULL,3386,ZXZ002635,茅台三十年原开2005,普通/53度,375ml*6/件,6.000,6,Y,1
|
||||
4633,8,10,4658,ZXZ002635,茅台三十年原开2005,普通/53度,375ml*6/件,6.000,6,Y,1
|
||||
3362,1,NULL,3387,ZXZ015001,茅台2013小件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4634,8,10,4659,ZXZ015001,茅台2013小件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1033,7,NULL,1058,ZXZ015001,茅台2013小件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2168,6,NULL,2193,ZXZ015001,茅台2013小件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6788,7,NULL,1058,ZXZ016627,茅台2013小件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9225,8,10,7147,ZXZ016627,茅台2013小件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1034,7,NULL,1059,ZXZ017131,茅台十五年2019,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2169,6,NULL,2194,ZXZ017131,茅台十五年2019,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3363,1,NULL,3388,ZXZ017131,茅台十五年2019,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4635,8,10,4660,ZXZ017131,茅台十五年2019,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3364,1,NULL,3389,ZXZ017428,五粮液2020,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
4636,8,10,4661,ZXZ017428,五粮液2020,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
1035,7,NULL,1060,ZXZ017428,五粮液2020,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
2170,6,NULL,2195,ZXZ017428,五粮液2020,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
1036,7,NULL,1061,ZXZ017436,茅台同码2021,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2171,6,NULL,2196,ZXZ017436,茅台同码2021,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3365,1,NULL,3390,ZXZ017436,茅台同码2021,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4637,8,10,4662,ZXZ017436,茅台同码2021,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3366,1,NULL,3391,ZXZ017973,茅台小件2014,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4638,8,10,4663,ZXZ017973,茅台小件2014,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1037,7,NULL,1062,ZXZ017973,茅台小件2014,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2172,6,NULL,2197,ZXZ017973,茅台小件2014,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1038,7,NULL,1063,ZXZ018113,茅台十五年2007,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2173,6,NULL,2198,ZXZ018113,茅台十五年2007,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3367,1,NULL,3392,ZXZ018113,茅台十五年2007,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4639,8,10,4664,ZXZ018113,茅台十五年2007,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3368,1,NULL,3393,ZXZ019821,茅台十五年2005,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4640,8,10,4665,ZXZ019821,茅台十五年2005,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1039,7,NULL,1064,ZXZ019821,茅台十五年2005,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2174,6,NULL,2199,ZXZ019821,茅台十五年2005,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1040,7,NULL,1065,ZXZ021176,茅台鼠年原箱2020,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2175,6,NULL,2200,ZXZ021176,茅台鼠年原箱2020,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1041,7,NULL,1066,ZXZ021178,五粮液1618/2022原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2176,6,NULL,2201,ZXZ021178,五粮液1618/2022原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3369,1,NULL,3394,ZXZ021178,五粮液1618/2022原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4641,8,10,4666,ZXZ021178,五粮液1618/2022原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6789,7,NULL,1062,ZXZ021454,茅台小件2014,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9226,8,10,7148,ZXZ021454,茅台小件2014,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3370,1,NULL,3395,ZXZ021456,茅台小件2018,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4642,8,10,4667,ZXZ021456,茅台小件2018,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1042,7,NULL,1067,ZXZ021456,茅台小件2018,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2177,6,NULL,2202,ZXZ021456,茅台小件2018,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1043,7,NULL,1068,ZXZ022977,五粮液2005原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2178,6,NULL,2203,ZXZ022977,五粮液2005原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3371,1,NULL,3396,ZXZ022977,五粮液2005原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4643,8,10,4668,ZXZ022977,五粮液2005原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3372,1,NULL,3397,ZXZ022979,五粮夜2010原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4644,8,10,4669,ZXZ022979,五粮夜2010原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1044,7,NULL,1069,ZXZ022979,五粮夜2010原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2179,6,NULL,2204,ZXZ022979,五粮夜2010原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1045,7,NULL,1070,ZXZ023067,钓鱼台雅品2017原开,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2180,6,NULL,2205,ZXZ023067,钓鱼台雅品2017原开,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3373,1,NULL,3398,ZXZ023067,钓鱼台雅品2017原开,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4645,8,10,4670,ZXZ023067,钓鱼台雅品2017原开,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3374,1,NULL,3399,ZXZ023299,青花汾酒三十年2016原开,普通/48度,500ml*6/件,6.000,6,Y,1
|
||||
4646,8,10,4671,ZXZ023299,青花汾酒三十年2016原开,普通/48度,500ml*6/件,6.000,6,Y,1
|
||||
1046,7,NULL,1071,ZXZ023299,青花汾酒三十年2016原开,普通/48度,500ml*6/件,6.000,6,Y,1
|
||||
2181,6,NULL,2206,ZXZ023299,青花汾酒三十年2016原开,普通/48度,500ml*6/件,6.000,6,Y,1
|
||||
1047,7,NULL,1072,ZXZ023392,汾酒青花20年2024原箱,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
2182,6,NULL,2207,ZXZ023392,汾酒青花20年2024原箱,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
3375,1,NULL,3400,ZXZ023392,汾酒青花20年2024原箱,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
4647,8,10,4672,ZXZ023392,汾酒青花20年2024原箱,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
3376,1,NULL,3401,ZXZ023941,五粮液2017原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4648,8,10,4673,ZXZ023941,五粮液2017原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1048,7,NULL,1073,ZXZ023941,五粮液2017原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2183,6,NULL,2208,ZXZ023941,五粮液2017原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1049,7,NULL,1074,ZXZ024375,茅台十五年2017,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2184,6,NULL,2209,ZXZ024375,茅台十五年2017,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3377,1,NULL,3402,ZXZ024375,茅台十五年2017,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3378,1,NULL,3403,ZXZ024715,茅台定制尊享2019原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4649,8,10,4674,ZXZ024715,茅台定制尊享2019原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1050,7,NULL,1075,ZXZ024715,茅台定制尊享2019原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2185,6,NULL,2210,ZXZ024715,茅台定制尊享2019原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1051,7,NULL,1076,ZXZ024864,青花汾二十2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2186,6,NULL,2211,ZXZ024864,青花汾二十2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3379,1,NULL,3404,ZXZ024864,青花汾二十2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4650,8,10,4675,ZXZ024864,青花汾二十2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3380,1,NULL,3405,ZXZ025086,五粮液2018原箱,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
4651,8,10,4676,ZXZ025086,五粮液2018原箱,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
1052,7,NULL,1077,ZXZ025086,五粮液2018原箱,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
2187,6,NULL,2212,ZXZ025086,五粮液2018原箱,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
1053,7,NULL,1078,ZXZ025087,五粮液2018原开,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
2188,6,NULL,2213,ZXZ025087,五粮液2018原开,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
3381,1,NULL,3406,ZXZ025087,五粮液2018原开,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
4652,8,10,4677,ZXZ025087,五粮液2018原开,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
1054,7,NULL,1079,ZXZ025166,泸州老窖特曲,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2189,6,NULL,2214,ZXZ025166,泸州老窖特曲,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1055,7,NULL,1080,ZXZ025308,剑南春2014原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2190,6,NULL,2215,ZXZ025308,剑南春2014原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3382,1,NULL,3407,ZXZ025308,剑南春2014原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4653,8,10,4678,ZXZ025308,剑南春2014原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1056,7,NULL,1081,ZXZ025310,五粮液45度,普通/45度,500ml*6/件,6.000,6,Y,1
|
||||
2191,6,NULL,2216,ZXZ025310,五粮液45度,普通/45度,500ml*6/件,6.000,6,Y,1
|
||||
1057,7,NULL,1082,ZXZ025319,复兴版青花2023原开,普通/48度,500ml*6/件,6.000,6,Y,1
|
||||
2192,6,NULL,2217,ZXZ025319,复兴版青花2023原开,普通/48度,500ml*6/件,6.000,6,Y,1
|
||||
3383,1,NULL,3408,ZXZ025319,复兴版青花2023原开,普通/48度,500ml*6/件,6.000,6,Y,1
|
||||
4654,8,10,4679,ZXZ025319,复兴版青花2023原开,普通/48度,500ml*6/件,6.000,6,Y,1
|
||||
9227,8,10,7149,ZXZ025627,五粮液2017原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6790,7,NULL,1073,ZXZ025627,五粮液2017原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3384,1,NULL,3409,ZXZ026123,茅台公斤原件2024,普通/53度,1.00L*6/件,6.000,6,Y,1
|
||||
4655,8,10,4680,ZXZ026123,茅台公斤原件2024,普通/53度,1.00L*6/件,6.000,6,Y,1
|
||||
1058,7,NULL,1083,ZXZ026123,茅台公斤原件2024,普通/53度,1.00L*6/件,6.000,6,Y,1
|
||||
2193,6,NULL,2218,ZXZ026123,茅台公斤原件2024,普通/53度,1.00L*6/件,6.000,6,Y,1
|
||||
1059,7,NULL,1084,ZXZ026196,茅台小件2019,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2194,6,NULL,2219,ZXZ026196,茅台小件2019,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3385,1,NULL,3410,ZXZ026196,茅台小件2019,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4656,8,10,4681,ZXZ026196,茅台小件2019,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1060,7,NULL,1085,ZXZ026355,茅台小件2022,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2195,6,NULL,2220,ZXZ026355,茅台小件2022,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1061,7,NULL,1086,ZXZ026363,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2196,6,NULL,2221,ZXZ026363,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2162,6,NULL,2187,ZXZ026475,茅台小件2024,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6791,7,NULL,1085,ZXZ026477,茅台小件2022,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1062,7,NULL,1087,ZXZ026608,茅台2022年原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2197,6,NULL,2222,ZXZ026608,茅台2022年原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3386,1,NULL,3411,ZXZ026608,茅台2022年原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3343,1,NULL,3368,ZXZ026646,茅台小件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2158,6,NULL,2183,ZXZ026646,茅台小件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1063,7,NULL,1088,ZXZ026648,茅台精品2021原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2198,6,NULL,2223,ZXZ026648,茅台精品2021原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3387,1,NULL,3412,ZXZ026648,茅台精品2021原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3388,1,NULL,3413,ZXZ026650,茅台小可爱生日礼盒,普通/53度,100ML*6,6.000,6,Y,1
|
||||
4657,8,10,4682,ZXZ026650,茅台小可爱生日礼盒,普通/53度,100ML*6,6.000,6,Y,1
|
||||
1064,7,NULL,1089,ZXZ026650,茅台小可爱生日礼盒,普通/53度,100ML*6,6.000,6,Y,1
|
||||
2199,6,NULL,2224,ZXZ026650,茅台小可爱生日礼盒,普通/53度,100ML*6,6.000,6,Y,1
|
||||
6792,7,NULL,1089,ZXZ026651,茅台小可爱生日礼盒,普通/53度,100ML*6,6.000,6,Y,1
|
||||
9228,8,10,7150,ZXZ026651,茅台小可爱生日礼盒,普通/53度,100ML*6,6.000,6,Y,1
|
||||
9229,8,10,7151,ZXZ026653,茅台小可爱生日礼盒,普通/53度,100ML*6,6.000,6,Y,1
|
||||
6793,7,NULL,1089,ZXZ026653,茅台小可爱生日礼盒,普通/53度,100ML*6,6.000,6,Y,1
|
||||
6794,7,NULL,1086,ZXZ026675,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3389,1,NULL,3414,ZXZ026675,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4658,8,10,4683,ZXZ026675,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3390,1,NULL,3415,ZXZ026704,五粮液2019原开,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
4659,8,10,4684,ZXZ026704,五粮液2019原开,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
1065,7,NULL,1090,ZXZ026704,五粮液2019原开,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
2200,6,NULL,2225,ZXZ026704,五粮液2019原开,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
6795,7,NULL,1052,ZXZ026801,茅台小件2024,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3391,1,NULL,3416,ZXZ026826,五粮液2021原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4660,8,10,4685,ZXZ026826,五粮液2021原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1066,7,NULL,1091,ZXZ026826,五粮液2021原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2201,6,NULL,2226,ZXZ026826,五粮液2021原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2159,6,NULL,2184,ZXZ026841,茅台小件2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3344,1,NULL,3369,ZXZ026841,茅台小件2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3353,1,NULL,3378,ZXZ026856,五粮液原箱2025,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2163,6,NULL,2188,ZXZ026856,五粮液原箱2025,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1067,7,NULL,1092,ZXZ026858,五粮液2024原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2202,6,NULL,2227,ZXZ026858,五粮液2024原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3392,1,NULL,3417,ZXZ026858,五粮液2024原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4661,8,10,4686,ZXZ026858,五粮液2024原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3393,1,NULL,3418,ZXZ026878,茅台小件2020,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4662,8,10,4687,ZXZ026878,茅台小件2020,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1068,7,NULL,1093,ZXZ026878,茅台小件2020,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2203,6,NULL,2228,ZXZ026878,茅台小件2020,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6796,7,NULL,1093,ZXZ026879,茅台小件2020,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9230,8,10,7152,ZXZ026879,茅台小件2020,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9231,8,10,7153,ZXZ026903,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6797,7,NULL,1086,ZXZ026903,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6798,7,NULL,1048,ZXZ026926,茅台小件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9232,8,10,7154,ZXZ026926,茅台小件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4663,8,10,4688,ZXZ026989,五粮液2026原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1069,7,NULL,1094,ZXZ026989,五粮液2026原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2204,6,NULL,2229,ZXZ026989,五粮液2026原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3394,1,NULL,3419,ZXZ026989,五粮液2026原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6799,7,NULL,1053,ZXZ026990,五粮液原箱2025,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9233,8,10,7155,ZXZ026990,五粮液原箱2025,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4664,8,10,4689,ZXZ026991,五粮液2025,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3395,1,NULL,3420,ZXZ026991,五粮液2025,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1070,7,NULL,1095,ZXZ026991,五粮液2025,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2205,6,NULL,2230,ZXZ026991,五粮液2025,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6800,7,NULL,1066,ZXZ027008,五粮液1618/2022原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9234,8,10,7156,ZXZ027008,五粮液1618/2022原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4665,8,10,4690,ZXZ027009,五粮液1618/2024原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1071,7,NULL,1096,ZXZ027009,五粮液1618/2024原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2206,6,NULL,2231,ZXZ027009,五粮液1618/2024原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3396,1,NULL,3421,ZXZ027009,五粮液1618/2024原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6801,7,NULL,934,ZXZ027061,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6802,7,NULL,934,ZXZ027062,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9235,8,10,7157,ZXZ027062,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9236,8,10,7158,ZXZ027064,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6803,7,NULL,934,ZXZ027064,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6804,7,NULL,934,ZXZ027066,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9237,8,10,7159,ZXZ027066,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9238,8,10,7160,ZXZ027067,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6805,7,NULL,934,ZXZ027067,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6806,7,NULL,934,ZXZ027068,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9239,8,10,7161,ZXZ027068,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6807,7,NULL,934,ZXZ027069,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3109,1,NULL,3134,ZXZ027069,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6808,7,NULL,934,ZXZ027070,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9240,8,10,7162,ZXZ027070,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9241,8,10,7163,ZXZ027071,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6809,7,NULL,934,ZXZ027071,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6810,7,NULL,934,ZXZ027072,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9242,8,10,7164,ZXZ027072,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9243,8,10,7165,ZXZ027073,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6811,7,NULL,934,ZXZ027073,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6812,7,NULL,934,ZXZ027074,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9244,8,10,7166,ZXZ027074,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9245,8,10,7167,ZXZ027075,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6813,7,NULL,934,ZXZ027075,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6814,7,NULL,934,ZXZ027076,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9246,8,10,7168,ZXZ027076,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9247,8,10,7169,ZXZ027077,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6815,7,NULL,934,ZXZ027077,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6816,7,NULL,934,ZXZ027078,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9248,8,10,7170,ZXZ027078,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9249,8,10,7171,ZXZ027079,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6817,7,NULL,934,ZXZ027079,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2044,6,NULL,2069,ZXZ027080,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1072,7,NULL,1097,ZXZ027081,茅台十五年2021原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2207,6,NULL,2232,ZXZ027081,茅台十五年2021原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3397,1,NULL,3422,ZXZ027081,茅台十五年2021原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4666,8,10,4691,ZXZ027081,茅台十五年2021原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2161,6,NULL,2186,ZXZ027084,茅台1935/2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6818,7,NULL,1051,ZXZ027085,茅台1935/2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2164,6,NULL,2189,ZXZ027086,贵州君品习酒2025原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6819,7,NULL,1054,ZXZ027087,贵州君品习酒2025原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9250,8,10,7172,ZXZ027087,贵州君品习酒2025原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6820,7,NULL,1054,ZXZ027088,贵州君品习酒2025原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3345,1,NULL,3370,ZXZ027088,贵州君品习酒2025原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9251,8,10,7173,ZXZ027089,贵州习酒1988原箱2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1073,7,NULL,1098,ZXZ027089,贵州习酒1988原箱2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2208,6,NULL,2233,ZXZ027089,贵州习酒1988原箱2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3354,1,NULL,3379,ZXZ027090,贵州习酒1988原箱2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6821,7,NULL,1098,ZXZ027090,贵州习酒1988原箱2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4667,8,10,4692,ZXZ027169,奔富bin8红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
1074,7,NULL,1099,ZXZ027169,奔富bin8红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
2209,6,NULL,2234,ZXZ027169,奔富bin8红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
3398,1,NULL,3423,ZXZ027169,奔富bin8红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
3399,1,NULL,3424,ZXZ027181,奔富28红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
4668,8,10,4693,ZXZ027181,奔富28红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
1075,7,NULL,1100,ZXZ027181,奔富28红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
2210,6,NULL,2235,ZXZ027181,奔富28红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
1076,7,NULL,1101,ZXZ027193,奔富128红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
2211,6,NULL,2236,ZXZ027193,奔富128红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
3400,1,NULL,3425,ZXZ027193,奔富128红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
4669,8,10,4694,ZXZ027193,奔富128红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
1077,7,NULL,1102,ZXZ027205,奔富389红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
2212,6,NULL,2237,ZXZ027205,奔富389红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
1078,7,NULL,1103,ZXZ027217,奔富407红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
2213,6,NULL,2238,ZXZ027217,奔富407红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
4670,8,10,4695,ZXZ027217,奔富407红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
3401,1,NULL,3426,ZXZ027217,奔富407红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
1079,7,NULL,1104,ZXZ027229,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2214,6,NULL,2239,ZXZ027229,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4671,8,10,4696,ZXZ027229,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6822,7,NULL,1104,ZXZ027230,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3402,1,NULL,3427,ZXZ027231,汾酒青花20年2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9252,8,10,7174,ZXZ027231,汾酒青花20年2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1080,7,NULL,1105,ZXZ027231,汾酒青花20年2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2215,6,NULL,2240,ZXZ027231,汾酒青花20年2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6823,7,NULL,1105,ZXZ027232,汾酒青花20年2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6824,7,NULL,1104,ZXZ027233,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9253,8,10,7175,ZXZ027233,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9254,8,10,7176,ZXZ027234,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6825,7,NULL,1104,ZXZ027234,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6826,7,NULL,1104,ZXZ027235,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9255,8,10,7177,ZXZ027235,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9256,8,10,7178,ZXZ027236,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6827,7,NULL,1104,ZXZ027236,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1081,7,NULL,1106,ZXZ027237,汾酒青花20年2026原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
2216,6,NULL,2241,ZXZ027237,汾酒青花20年2026原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
3352,1,NULL,3377,ZXZ027237,汾酒青花20年2026原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
6828,7,NULL,1106,ZXZ027239,汾酒青花20年2026原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
9257,8,10,7179,ZXZ027239,汾酒青花20年2026原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
1082,7,NULL,1107,ZXZ027250,老白汾酒原开2025,普通/53度,475ML*6/件,6.000,6,Y,1
|
||||
2217,6,NULL,2242,ZXZ027250,老白汾酒原开2025,普通/53度,475ML*6/件,6.000,6,Y,1
|
||||
3346,1,NULL,3371,ZXZ027251,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6829,7,NULL,1104,ZXZ027251,汾酒青花20年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4672,8,10,4697,ZXZ027252,青花郎原件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1083,7,NULL,1108,ZXZ027252,青花郎原件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2218,6,NULL,2243,ZXZ027252,青花郎原件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3403,1,NULL,3428,ZXZ027252,青花郎原件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6830,7,NULL,1108,ZXZ027253,青花郎原件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9258,8,10,7180,ZXZ027253,青花郎原件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4673,8,10,4698,ZXZ027255,红花郎红十2025原开,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3404,1,NULL,3429,ZXZ027255,红花郎红十2025原开,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1084,7,NULL,1109,ZXZ027255,红花郎红十2025原开,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2219,6,NULL,2244,ZXZ027255,红花郎红十2025原开,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1085,7,NULL,1110,ZXZ027256,玛安蒂云峰珍藏梅洛红葡萄酒2024,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
2220,6,NULL,2245,ZXZ027256,玛安蒂云峰珍藏梅洛红葡萄酒2024,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
4674,8,10,4699,ZXZ027256,玛安蒂云峰珍藏梅洛红葡萄酒2024,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
3405,1,NULL,3430,ZXZ027256,玛安蒂云峰珍藏梅洛红葡萄酒2024,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
9259,8,10,7181,ZXZ027257,玛安蒂云峰珍藏梅洛红葡萄酒2024,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
6831,7,NULL,1110,ZXZ027257,玛安蒂云峰珍藏梅洛红葡萄酒2024,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
6832,7,NULL,1110,ZXZ027258,玛安蒂云峰珍藏梅洛红葡萄酒2024,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
9260,8,10,7182,ZXZ027258,玛安蒂云峰珍藏梅洛红葡萄酒2024,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
9261,8,10,7183,ZXZ027259,玛安蒂云峰珍藏梅洛红葡萄酒2024,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
6833,7,NULL,1110,ZXZ027259,玛安蒂云峰珍藏梅洛红葡萄酒2024,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
6834,7,NULL,1110,ZXZ027260,玛安蒂云峰珍藏梅洛红葡萄酒2024,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
9262,8,10,7184,ZXZ027260,玛安蒂云峰珍藏梅洛红葡萄酒2024,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
3406,1,NULL,3431,ZXZ027267,玛安蒂丹峰佳美娜红葡萄酒2021,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
1086,7,NULL,1111,ZXZ027267,玛安蒂丹峰佳美娜红葡萄酒2021,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
2221,6,NULL,2246,ZXZ027267,玛安蒂丹峰佳美娜红葡萄酒2021,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
4675,8,10,4700,ZXZ027267,玛安蒂丹峰佳美娜红葡萄酒2021,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
6835,7,NULL,1111,ZXZ027268,玛安蒂丹峰佳美娜红葡萄酒2021,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
9263,8,10,7185,ZXZ027268,玛安蒂丹峰佳美娜红葡萄酒2021,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
9264,8,10,7186,ZXZ027269,玛安蒂丹峰佳美娜红葡萄酒2021,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
6836,7,NULL,1111,ZXZ027269,玛安蒂丹峰佳美娜红葡萄酒2021,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
6837,7,NULL,1111,ZXZ027270,玛安蒂丹峰佳美娜红葡萄酒2021,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
9265,8,10,7187,ZXZ027270,玛安蒂丹峰佳美娜红葡萄酒2021,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
9266,8,10,7188,ZXZ027271,玛安蒂丹峰佳美娜红葡萄酒2021,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
6838,7,NULL,1111,ZXZ027271,玛安蒂丹峰佳美娜红葡萄酒2021,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
4676,8,10,4701,ZXZ027272,玛安蒂C-15赤霞珠红葡萄酒2022,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
3407,1,NULL,3432,ZXZ027272,玛安蒂C-15赤霞珠红葡萄酒2022,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
1087,7,NULL,1112,ZXZ027272,玛安蒂C-15赤霞珠红葡萄酒2022,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
2222,6,NULL,2247,ZXZ027272,玛安蒂C-15赤霞珠红葡萄酒2022,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
6839,7,NULL,1112,ZXZ027273,玛安蒂C-15赤霞珠红葡萄酒2022,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
9267,8,10,7189,ZXZ027273,玛安蒂C-15赤霞珠红葡萄酒2022,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
4677,8,10,4702,ZXZ027281,奔富bin6红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
1088,7,NULL,1113,ZXZ027281,奔富bin6红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
2223,6,NULL,2248,ZXZ027281,奔富bin6红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
3408,1,NULL,3433,ZXZ027281,奔富bin6红酒,14%vol,750ml*6/件,6.000,6,Y,1
|
||||
3409,1,NULL,3434,ZXZ027338,国窖2022原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1089,7,NULL,1114,ZXZ027338,国窖2022原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2224,6,NULL,2249,ZXZ027338,国窖2022原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6840,7,NULL,1053,ZXZ027339,五粮液原箱2025,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9268,8,10,7190,ZXZ027339,五粮液原箱2025,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6841,7,NULL,1086,ZXZ027352,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1090,7,NULL,1115,ZXZ027359,茅台十五年原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2225,6,NULL,2250,ZXZ027359,茅台十五年原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1091,7,NULL,1116,ZXZ027361,茅台三十年2025原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2226,6,NULL,2251,ZXZ027361,茅台三十年2025原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1092,7,NULL,1117,ZXZ027367,汾酒青花三十复兴版2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2227,6,NULL,2252,ZXZ027367,汾酒青花三十复兴版2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4678,8,10,4703,ZXZ027367,汾酒青花三十复兴版2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3410,1,NULL,3435,ZXZ027367,汾酒青花三十复兴版2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1093,7,NULL,1118,ZXZ027424,茅台精品2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2228,6,NULL,2253,ZXZ027424,茅台精品2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1094,7,NULL,1119,ZXZ027437,汾酒青花三十2025复兴版原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
2229,6,NULL,2254,ZXZ027437,汾酒青花三十2025复兴版原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
3411,1,NULL,3436,ZXZ027437,汾酒青花三十2025复兴版原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
4679,8,10,4704,ZXZ027437,汾酒青花三十2025复兴版原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
4680,8,10,4705,ZXZ027438,汾酒青花26原箱2025,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
1095,7,NULL,1120,ZXZ027438,汾酒青花26原箱2025,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
2230,6,NULL,2255,ZXZ027438,汾酒青花26原箱2025,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
3412,1,NULL,3437,ZXZ027438,汾酒青花26原箱2025,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
6842,7,NULL,1120,ZXZ027439,汾酒青花26原箱2025,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
9269,8,10,7191,ZXZ027439,汾酒青花26原箱2025,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
3358,1,NULL,3383,ZXZ027440,汾酒青花26原箱2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1096,7,NULL,1121,ZXZ027440,汾酒青花26原箱2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2231,6,NULL,2256,ZXZ027440,汾酒青花26原箱2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9270,8,10,7192,ZXZ027441,汾酒青花26原箱2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6843,7,NULL,1121,ZXZ027441,汾酒青花26原箱2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4681,8,10,4706,ZXZ027462,汾酒青花三十复兴版2025原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
1097,7,NULL,1122,ZXZ027462,汾酒青花三十复兴版2025原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
2232,6,NULL,2257,ZXZ027462,汾酒青花三十复兴版2025原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
3413,1,NULL,3438,ZXZ027462,汾酒青花三十复兴版2025原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
6844,7,NULL,1122,ZXZ027463,汾酒青花三十复兴版2025原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
9271,8,10,7193,ZXZ027463,汾酒青花三十复兴版2025原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
4682,8,10,4707,ZXZ027474,茅台2016原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3414,1,NULL,3439,ZXZ027474,茅台2016原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1098,7,NULL,1123,ZXZ027474,茅台2016原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2233,6,NULL,2258,ZXZ027474,茅台2016原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1099,7,NULL,1124,ZXZ027526,五粮液2023原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2234,6,NULL,2259,ZXZ027526,五粮液2023原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4683,8,10,4708,ZXZ027526,五粮液2023原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3415,1,NULL,3440,ZXZ027526,五粮液2023原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3416,1,NULL,3441,ZXZ027527,五粮液2020原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1100,7,NULL,1125,ZXZ027527,五粮液2020原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2235,6,NULL,2260,ZXZ027527,五粮液2020原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4684,8,10,4709,ZXZ027527,五粮液2020原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6845,7,NULL,1091,ZXZ027528,五粮液2021原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9272,8,10,7194,ZXZ027528,五粮液2021原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9273,8,10,7195,ZXZ027529,五粮液2020原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6846,7,NULL,1125,ZXZ027529,五粮液2020原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4685,8,10,4710,ZXZ027530,五粮液2019原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3417,1,NULL,3442,ZXZ027530,五粮液2019原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1101,7,NULL,1126,ZXZ027530,五粮液2019原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2236,6,NULL,2261,ZXZ027530,五粮液2019原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1102,7,NULL,1127,ZXZ027531,五粮液2018原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2237,6,NULL,2262,ZXZ027531,五粮液2018原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4686,8,10,4711,ZXZ027531,五粮液2018原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3418,1,NULL,3443,ZXZ027531,五粮液2018原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9274,8,10,7196,ZXZ027532,五粮液2019原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6847,7,NULL,1126,ZXZ027532,五粮液2019原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6848,7,NULL,1127,ZXZ027533,五粮液2018原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9275,8,10,7197,ZXZ027533,五粮液2018原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3419,1,NULL,3444,ZXZ027534,五粮液2019原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1103,7,NULL,1128,ZXZ027534,五粮液2019原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2238,6,NULL,2263,ZXZ027534,五粮液2019原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4687,8,10,4712,ZXZ027534,五粮液2019原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4688,8,10,4713,ZXZ027535,五粮液2010原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3420,1,NULL,3445,ZXZ027535,五粮液2010原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1104,7,NULL,1129,ZXZ027535,五粮液2010原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2239,6,NULL,2264,ZXZ027535,五粮液2010原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6849,7,NULL,1073,ZXZ027536,五粮液2017原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9276,8,10,7198,ZXZ027536,五粮液2017原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6850,7,NULL,1128,ZXZ027537,五粮液2019原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4689,8,10,4714,ZXZ027538,五粮液2021原箱,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
1105,7,NULL,1130,ZXZ027538,五粮液2021原箱,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
2240,6,NULL,2265,ZXZ027538,五粮液2021原箱,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
3421,1,NULL,3446,ZXZ027538,五粮液2021原箱,普通/39度,500ml*6/件,6.000,6,Y,1
|
||||
6851,7,NULL,1125,ZXZ027568,五粮液2020原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9277,8,10,7199,ZXZ027568,五粮液2020原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4690,8,10,4715,ZXZ027582,五粮液2014原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3422,1,NULL,3447,ZXZ027582,五粮液2014原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1106,7,NULL,1131,ZXZ027582,五粮液2014原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2241,6,NULL,2266,ZXZ027582,五粮液2014原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1107,7,NULL,1132,ZXZ027583,五粮液2016原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2242,6,NULL,2267,ZXZ027583,五粮液2016原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4691,8,10,4716,ZXZ027583,五粮液2016原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3423,1,NULL,3448,ZXZ027583,五粮液2016原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9278,8,10,7200,ZXZ027599,茅台小件2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6852,7,NULL,1049,ZXZ027599,茅台小件2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6853,7,NULL,1092,ZXZ027626,五粮液2024原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9279,8,10,7201,ZXZ027626,五粮液2024原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3424,1,NULL,3449,ZXZ027627,茅台精品原箱2024,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1108,7,NULL,1133,ZXZ027627,茅台精品原箱2024,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2243,6,NULL,2268,ZXZ027627,茅台精品原箱2024,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4692,8,10,4717,ZXZ027627,茅台精品原箱2024,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3425,1,NULL,3450,ZXZ027644,2024年汾酒青花25,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
1109,7,NULL,1134,ZXZ027644,2024年汾酒青花25,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
2244,6,NULL,2269,ZXZ027644,2024年汾酒青花25,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
1110,7,NULL,1135,ZXZ027645,茅台2019原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2245,6,NULL,2270,ZXZ027645,茅台2019原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4693,8,10,4718,ZXZ027645,茅台2019原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3426,1,NULL,3451,ZXZ027645,茅台2019原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6854,7,NULL,1133,ZXZ027646,茅台精品原箱2024,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4694,8,10,4719,ZXZ027675,汾酒巴拿马黑坛20年2025原件,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
1111,7,NULL,1136,ZXZ027675,汾酒巴拿马黑坛20年2025原件,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
2246,6,NULL,2271,ZXZ027675,汾酒巴拿马黑坛20年2025原件,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
3427,1,NULL,3452,ZXZ027675,汾酒巴拿马黑坛20年2025原件,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
6855,7,NULL,1136,ZXZ027676,汾酒巴拿马黑坛20年2025原件,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
9280,8,10,7202,ZXZ027676,汾酒巴拿马黑坛20年2025原件,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
4695,8,10,4720,ZXZ027739,茅台2010原件,普通/43度,500ml*6/件,6.000,6,Y,1
|
||||
3428,1,NULL,3453,ZXZ027739,茅台2010原件,普通/43度,500ml*6/件,6.000,6,Y,1
|
||||
1112,7,NULL,1137,ZXZ027739,茅台2010原件,普通/43度,500ml*6/件,6.000,6,Y,1
|
||||
2247,6,NULL,2272,ZXZ027739,茅台2010原件,普通/43度,500ml*6/件,6.000,6,Y,1
|
||||
1113,7,NULL,1138,ZXZ027740,五粮液2025原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2248,6,NULL,2273,ZXZ027740,五粮液2025原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3429,1,NULL,3454,ZXZ027740,五粮液2025原开,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6856,7,NULL,1086,ZXZ027754,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4696,8,10,4721,ZXZ027789,茅台十五年原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6857,7,NULL,1115,ZXZ027789,茅台十五年原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3430,1,NULL,3455,ZXZ027789,茅台十五年原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6858,7,NULL,1115,ZXZ027790,茅台十五年原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6859,7,NULL,1115,ZXZ027791,茅台十五年原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6860,7,NULL,1115,ZXZ027792,茅台十五年原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9281,8,10,7203,ZXZ027792,茅台十五年原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9282,8,10,7204,ZXZ027793,茅台十五年原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6861,7,NULL,1115,ZXZ027793,茅台十五年原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6862,7,NULL,1115,ZXZ027794,茅台十五年原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4697,8,10,4722,ZXZ027795,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3431,1,NULL,3456,ZXZ027795,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1114,7,NULL,1139,ZXZ027795,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2249,6,NULL,2274,ZXZ027795,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6863,7,NULL,1139,ZXZ027796,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6864,7,NULL,1139,ZXZ027797,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6865,7,NULL,1139,ZXZ027798,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6866,7,NULL,1139,ZXZ027799,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9283,8,10,7205,ZXZ027799,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6867,7,NULL,1139,ZXZ027800,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9284,8,10,7206,ZXZ027812,国窖2025原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
1115,7,NULL,1140,ZXZ027812,国窖2025原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2250,6,NULL,2275,ZXZ027812,国窖2025原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9285,8,10,7207,ZXZ027813,国窖2025原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6868,7,NULL,1140,ZXZ027813,国窖2025原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6869,7,NULL,1140,ZXZ027814,国窖2025原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
3355,1,NULL,3380,ZXZ027814,国窖2025原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
6870,7,NULL,1140,ZXZ027815,国窖2025原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9286,8,10,7208,ZXZ027815,国窖2025原件,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
2251,6,NULL,2276,ZXZ027816,钓鱼台双羽酒,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1116,7,NULL,1141,ZXZ027816,钓鱼台双羽酒,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1117,7,NULL,1142,ZXZ027853,茅台2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2252,6,NULL,2277,ZXZ027853,茅台2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2253,6,NULL,2278,ZXZ027860,茅台公斤2026原件,普通/53度,1.00L*6/件,6.000,6,Y,1
|
||||
1118,7,NULL,1143,ZXZ027860,茅台公斤2026原件,普通/53度,1.00L*6/件,6.000,6,Y,1
|
||||
6871,7,NULL,1139,ZXZ027900,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6872,7,NULL,1139,ZXZ027901,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6873,7,NULL,1139,ZXZ027902,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6874,7,NULL,1139,ZXZ027903,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6875,7,NULL,1139,ZXZ027904,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1119,7,NULL,1144,ZXZ027915,2011年鸟巢原开,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2254,6,NULL,2279,ZXZ027915,2011年鸟巢原开,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6876,7,NULL,1139,ZXZ027923,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6877,7,NULL,1139,ZXZ027924,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6878,7,NULL,1142,ZXZ027927,茅台2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6879,7,NULL,1139,ZXZ027928,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6880,7,NULL,1142,ZXZ027929,茅台2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6881,7,NULL,1142,ZXZ027930,茅台2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4698,8,10,4723,ZXZ027946,茅台生日礼盒2024,普通/53度,100ML*6,6.000,6,Y,1
|
||||
2255,6,NULL,2280,ZXZ027946,茅台生日礼盒2024,普通/53度,100ML*6,6.000,6,Y,1
|
||||
3432,1,NULL,3457,ZXZ027946,茅台生日礼盒2024,普通/53度,100ML*6,6.000,6,Y,1
|
||||
1120,7,NULL,1145,ZXZ027946,茅台生日礼盒2024,普通/53度,100ML*6,6.000,6,Y,1
|
||||
6882,7,NULL,1145,ZXZ027947,茅台生日礼盒2024,普通/53度,100ML*6,6.000,6,Y,1
|
||||
9287,8,10,7209,ZXZ027947,茅台生日礼盒2024,普通/53度,100ML*6,6.000,6,Y,1
|
||||
9288,8,10,7210,ZXZ027948,茅台生日礼盒2024,普通/53度,100ML*6,6.000,6,Y,1
|
||||
6883,7,NULL,1145,ZXZ027948,茅台生日礼盒2024,普通/53度,100ML*6,6.000,6,Y,1
|
||||
6884,7,NULL,1145,ZXZ027949,茅台生日礼盒2024,普通/53度,100ML*6,6.000,6,Y,1
|
||||
9289,8,10,7211,ZXZ027949,茅台生日礼盒2024,普通/53度,100ML*6,6.000,6,Y,1
|
||||
9290,8,10,7212,ZXZ027950,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6885,7,NULL,1139,ZXZ027950,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6886,7,NULL,1139,ZXZ027951,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9291,8,10,7213,ZXZ027951,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6887,7,NULL,1139,ZXZ027952,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6888,7,NULL,1139,ZXZ027953,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6889,7,NULL,1139,ZXZ027954,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6890,7,NULL,1139,ZXZ027955,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6891,7,NULL,1139,ZXZ027956,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6892,7,NULL,1139,ZXZ027957,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6893,7,NULL,1139,ZXZ027958,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6894,7,NULL,1139,ZXZ027959,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6895,7,NULL,1139,ZXZ027960,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6896,7,NULL,1139,ZXZ027961,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
1121,7,NULL,1146,ZXZ027962,茅台精品原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
2256,6,NULL,2281,ZXZ027962,茅台精品原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6897,7,NULL,1146,ZXZ027963,茅台精品原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
6898,7,NULL,1146,ZXZ027964,茅台精品原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9292,8,10,7214,ZXZ028050,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9293,8,10,7215,ZXZ028105,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4699,8,10,4724,ZXZ028138,茅台2024原箱,普通/43度,500ml*6/件,6.000,6,Y,1
|
||||
3433,1,NULL,3458,ZXZ028138,茅台2024原箱,普通/43度,500ml*6/件,6.000,6,Y,1
|
||||
3434,1,NULL,3459,ZXZ028276,汾二十五2025原箱,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
4700,8,10,4725,ZXZ028276,汾二十五2025原箱,普通/42度,475ML*6/件,6.000,6,Y,1
|
||||
9294,8,10,7216,ZXZ028371,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3435,1,NULL,3460,ZXZ028415,茅台香溢五洲2021原开,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3436,1,NULL,3461,ZXZ028419,茅台蛇年2025原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4701,8,10,4726,ZXZ028419,茅台蛇年2025原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4702,8,10,4727,ZXZ028484,茅台兔年原箱2022,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3437,1,NULL,3462,ZXZ028484,茅台兔年原箱2022,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9295,8,10,7217,ZXZ028513,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9296,8,10,7218,ZXZ028514,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9297,8,10,7219,ZXZ028515,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9298,8,10,7220,ZXZ028518,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9299,8,10,7221,ZXZ028520,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3438,1,NULL,3463,ZXZ028522,茅台精品2023原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9300,8,10,7222,ZXZ028529,茅台小件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3439,1,NULL,3464,ZXZ028573,五粮液2012/1618,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4703,8,10,4728,ZXZ028573,五粮液2012/1618,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
4704,8,10,4729,ZXZ028631,茅台龙年小件2024,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3440,1,NULL,3465,ZXZ028631,茅台龙年小件2024,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3441,1,NULL,3466,ZXZ028633,茅台精品小件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4705,8,10,4730,ZXZ028633,茅台精品小件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4706,8,10,4731,ZXZ028635,茅台精品原件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3442,1,NULL,3467,ZXZ028635,茅台精品原件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3443,1,NULL,3468,ZXZ028636,茅台精品原箱2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9301,8,10,7223,ZXZ028639,茅台小件2026,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3444,1,NULL,3469,ZXZ028672,茅台2023年原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4707,8,10,4732,ZXZ028672,茅台2023年原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9302,8,10,7224,ZXZ028673,茅台2023年原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9303,8,10,7225,ZXZ028679,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4708,8,10,4733,ZXZ028693,茅台精品2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3445,1,NULL,3470,ZXZ028693,茅台精品2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9304,8,10,7226,ZXZ028700,茅台2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3446,1,NULL,3471,ZXZ028701,茅台十五年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4709,8,10,4734,ZXZ028702,茅台十五年2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4710,8,10,4735,ZXZ028754,茅台十五年2022原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3447,1,NULL,3472,ZXZ028754,茅台十五年2022原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3448,1,NULL,3473,ZXZ028755,茅台十五年2023原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4711,8,10,4736,ZXZ028755,茅台十五年2023原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9305,8,10,7227,ZXZ028757,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3449,1,NULL,3474,ZXZ028758,茅台2022年原箱,普通/53度,500ml/单品,6.000,,N,
|
||||
3450,1,NULL,3475,ZXZ028771,茅台2013原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4712,8,10,4737,ZXZ028771,茅台2013原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4713,8,10,4738,ZXZ028910,汾酒青花20年2021原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3451,1,NULL,3476,ZXZ028910,汾酒青花20年2021原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3452,1,NULL,3477,ZXZ028911,汾酒青花20年2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4714,8,10,4739,ZXZ028911,汾酒青花20年2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4715,8,10,4740,ZXZ028933,茅台2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3453,1,NULL,3478,ZXZ028933,茅台2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3454,1,NULL,3479,ZXZ028934,茅台小件2024,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4716,8,10,4741,ZXZ028934,茅台小件2024,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9306,8,10,7228,ZXZ028997,茅台小件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9307,8,10,7229,ZXZ028998,茅台小件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9308,8,10,7230,ZXZ028999,茅台小件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4717,8,10,4742,ZXZ029003,钓鱼台V20/2022原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3455,1,NULL,3480,ZXZ029003,钓鱼台V20/2022原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
3456,1,NULL,3481,ZXZ029004,钓鱼台V20/2022原开,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4718,8,10,4743,ZXZ029004,钓鱼台V20/2022原开,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4719,8,10,4744,ZXZ029024,老白汾酒2025年原件,普通/53度,475ML*6/件,6.000,6,Y,1
|
||||
3457,1,NULL,3482,ZXZ029024,老白汾酒2025年原件,普通/53度,475ML*6/件,6.000,6,Y,1
|
||||
9309,8,10,7231,ZXZ029025,汾酒青花20年2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9310,8,10,7232,ZXZ029026,汾酒青花20年2026原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
9311,8,10,7233,ZXZ029027,汾酒青花20年2026原箱,普通/42度,500ml*6/件,6.000,6,Y,1
|
||||
3458,1,NULL,3483,ZXZ029028,老白汾酒2025年原件,普通/53度,500ml/单品,6.000,,N,
|
||||
3459,1,NULL,3484,ZXZ029029,老白汾酒2024年原件,普通/53度,500ml/单品,6.000,,N,
|
||||
4720,8,10,4745,ZXZ029029,老白汾酒2024年原件,普通/53度,500ml/单品,6.000,,N,
|
||||
3460,1,NULL,3485,ZXZ029034,茅台五十年2026原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9312,8,10,7234,ZXZ029051,茅台2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9313,8,10,7235,ZXZ029056,茅台精品2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9314,8,10,7236,ZXZ029058,茅台精品2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4721,8,10,4746,ZXZ029122,茅台人民大会堂特供陈酿2006小件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4722,8,10,4747,ZXZ029144,茅台十五年2021,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9315,8,10,7237,ZXZ029145,茅台十五年2021,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9316,8,10,7238,ZXZ029146,茅台十五年2021,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9317,8,10,7239,ZXZ029147,茅台十五年2022原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9318,8,10,7240,ZXZ029148,茅台十五年2021原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4723,8,10,4748,ZXZ029184,茅台2015原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4724,8,10,4749,ZXZ029185,茅台2018原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4725,8,10,4750,ZXZ029186,茅台五星原件2015,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4726,8,10,4751,ZXZ029187,茅台精品原件2018,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4727,8,10,4752,ZXZ029188,茅台2015小件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9319,8,10,7241,ZXZ029190,茅台小件2014,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4728,8,10,4753,ZXZ029191,茅台小件2022,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4729,8,10,4754,ZXZ029336,茅台精品2022原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9320,8,10,7242,ZXZ029339,茅台小件2025,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9321,8,10,7243,ZXZ029347,茅台精品2022原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4730,8,10,4755,ZXZ029394,茅台2020原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9322,8,10,7244,ZXZ029397,茅台2020原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9323,8,10,7245,ZXZ029408,茅台2020原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9324,8,10,7246,ZXZ029411,茅台2020原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9325,8,10,7247,ZXZ029415,茅台2020原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9326,8,10,7248,ZXZ029416,茅台2020原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9327,8,10,7249,ZXZ029419,茅台2020原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9328,8,10,7250,ZXZ029420,茅台2020原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9329,8,10,7251,ZXZ029421,茅台2020原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9330,8,10,7252,ZXZ029422,茅台2020原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9331,8,10,7253,ZXZ029423,茅台2020原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9332,8,10,7254,ZXZ029424,茅台2020原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4731,8,10,4756,ZXZ029444,汉酱2022原箱,普通/51度,500ml*6/件,6.000,6,Y,1
|
||||
4732,8,10,4757,ZXZ029451,茅台2026原箱,普通/53度,1.00L*6/件,6.000,6,Y,1
|
||||
4733,8,10,4758,ZXZ029452,茅台公斤原件2025,普通/53度,1.00L*6/件,6.000,6,Y,1
|
||||
9333,8,10,7255,ZXZ029453,茅台公斤原件2025,普通/53度,1.00L*6/件,6.000,6,Y,1
|
||||
4734,8,10,4759,ZXZ029454,茅台十五年2024原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9334,8,10,7256,ZXZ029461,茅台十五年2019,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9335,8,10,7257,ZXZ029468,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9336,8,10,7258,ZXZ029477,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9337,8,10,7259,ZXZ029478,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9338,8,10,7260,ZXZ029493,茅台十五年2022原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9339,8,10,7261,ZXZ029494,茅台十五年2022原件,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9340,8,10,7262,ZXZ029542,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9341,8,10,7263,ZXZ029543,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9342,8,10,7264,ZXZ029548,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4735,8,10,4760,ZXZ029595,茅台1935/2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9343,8,10,7265,ZXZ029596,茅台2025原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4736,8,10,4761,ZXZ029597,茅台2022年原箱,普通/53度,880ml*6/件,6.000,6,Y,1
|
||||
4737,8,10,4762,ZXZ029598,茅台2023原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4738,8,10,4763,ZXZ029619,五粮液2025原箱,普通/52度,500ml*6/件,6.000,6,Y,1
|
||||
9344,8,10,7266,ZXZ029669,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9345,8,10,7267,ZXZ029715,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
9346,8,10,7268,ZXZ029716,茅台2026原箱,普通/53度,500ml*6/件,6.000,6,Y,1
|
||||
4627,8,10,4652,ZXZ027440,汾酒青花26原箱2025,普通/53度,500ml*6/件,5.000,6,N,
|
||||
4628,8,10,4653,ZXZ027644,2024年汾酒青花25,普通/42度,475ML*6/件,5.000,6,N,
|
||||
3359,1,NULL,3384,ZXZ027807,贵州茅台酒2025,普通/53度,200mL*5/件,5.000,5,Y,1
|
||||
4629,8,10,4654,ZXZ027807,贵州茅台酒2025,普通/53度,200mL*5/件,5.000,5,Y,1
|
||||
1030,7,NULL,1055,ZXZ027807,贵州茅台酒2025,普通/53度,200mL*5/件,5.000,5,Y,1
|
||||
2165,6,NULL,2190,ZXZ027807,贵州茅台酒2025,普通/53度,200mL*5/件,5.000,5,Y,1
|
||||
6785,7,NULL,1055,ZXZ027808,贵州茅台酒2025,普通/53度,200mL*5/件,5.000,5,Y,1
|
||||
9222,8,10,7144,ZXZ027808,贵州茅台酒2025,普通/53度,200mL*5/件,5.000,5,Y,1
|
||||
6786,7,NULL,1055,ZXZ027809,贵州茅台酒2025,普通/53度,200mL*5/件,5.000,5,Y,1
|
||||
9223,8,10,7145,ZXZ027809,贵州茅台酒2025,普通/53度,200mL*5/件,5.000,5,Y,1
|
||||
6787,7,NULL,1055,ZXZ027810,贵州茅台酒2025,普通/53度,200mL*5/件,5.000,5,Y,1
|
||||
9224,8,10,7146,ZXZ027810,贵州茅台酒2025,普通/53度,200mL*5/件,5.000,5,Y,1
|
||||
4630,8,10,4655,ZXZ029583,小白条2020,普通/53度,50ML*5,5.000,5,Y,1
|
||||
4631,8,10,4656,ZXZ029584,茅台小金条2020,普通/53度,50ML*5,5.000,5,Y,1
|
||||
1027,7,NULL,1052,ZXZ026475,茅台小件2024,普通/53度,500ml*6/件,4.000,6,N,
|
||||
1028,7,NULL,1053,ZXZ026856,五粮液原箱2025,普通/52度,500ml*6/件,4.000,6,N,
|
||||
9219,8,10,7141,ZXZ027061,钓鱼台景泰蓝酒咖啡金2021原件,普通/53度,500ml*6/件,4.000,6,N,
|
||||
1029,7,NULL,1054,ZXZ027086,贵州君品习酒2025原件,普通/53度,500ml*6/件,4.000,6,N,
|
||||
4621,8,10,4646,ZXZ027090,贵州习酒1988原箱2025,普通/53度,500ml*6/件,4.000,6,N,
|
||||
4622,8,10,4647,ZXZ027814,国窖2025原件,普通/52度,500ml*6/件,4.000,6,N,
|
||||
3356,1,NULL,3381,ZXZ028420,茅台2025原箱,普通/53度,500ml*4/件,4.000,4,Y,1
|
||||
4623,8,10,4648,ZXZ028420,茅台2025原箱,普通/53度,500ml*4/件,4.000,4,Y,1
|
||||
9220,8,10,7142,ZXZ028421,茅台2025原箱,普通/53度,500ml*4/件,4.000,4,Y,1
|
||||
9221,8,10,7143,ZXZ028423,茅台2025原箱,普通/53度,500ml*4/件,4.000,4,Y,1
|
||||
3357,1,NULL,3382,ZXZ028912,梦之蓝M3 2019原件,40.8%,500ml*4/件,4.000,4,Y,1
|
||||
4624,8,10,4649,ZXZ028912,梦之蓝M3 2019原件,40.8%,500ml*4/件,4.000,4,Y,1
|
||||
4625,8,10,4650,ZXZ029028,老白汾酒2025年原件,普通/53度,500ml/单品,4.000,,N,
|
||||
4626,8,10,4651,ZXZ029647,茅台蛇年2025原件,普通/53度,375ml*2/盒,4.000,2,N,
|
||||
4619,8,10,4644,ZXZ026856,五粮液原箱2025,普通/52度,500ml*6/件,3.000,6,N,
|
||||
3111,1,NULL,3136,ZXZ027084,茅台1935/2025原箱,普通/53度,500ml*6/件,3.000,6,N,
|
||||
1026,7,NULL,1051,ZXZ027084,茅台1935/2025原箱,普通/53度,500ml*6/件,3.000,6,N,
|
||||
9218,8,10,7140,ZXZ027085,茅台1935/2025原箱,普通/53度,500ml*6/件,3.000,6,N,
|
||||
4620,8,10,4645,ZXZ027232,汾酒青花20年2026原箱,普通/53度,500ml*6/件,3.000,6,N,
|
||||
4608,8,10,4633,ZXZ014241,茅台2009大件,普通/53度,500ml*12/件,2.000,12,N,
|
||||
1018,7,NULL,1043,ZXZ014241,茅台2009大件,普通/53度,500ml*12/件,2.000,12,N,
|
||||
1019,7,NULL,1044,ZXZ020036,刘洋河礼盒2001,普通/45度,500ml*2/盒,2.000,2,Y,1
|
||||
2154,6,NULL,2179,ZXZ020036,刘洋河礼盒2001,普通/45度,500ml*2/盒,2.000,2,Y,1
|
||||
3339,1,NULL,3364,ZXZ020036,刘洋河礼盒2001,普通/45度,500ml*2/盒,2.000,2,Y,1
|
||||
4609,8,10,4634,ZXZ020036,刘洋河礼盒2001,普通/45度,500ml*2/盒,2.000,2,Y,1
|
||||
3340,1,NULL,3365,ZXZ022472,郎酒1988,普通/53度,50ml*2/盒,2.000,2,Y,1
|
||||
4610,8,10,4635,ZXZ022472,郎酒1988,普通/53度,50ml*2/盒,2.000,2,Y,1
|
||||
1020,7,NULL,1045,ZXZ022472,郎酒1988,普通/53度,50ml*2/盒,2.000,2,Y,1
|
||||
2155,6,NULL,2180,ZXZ022472,郎酒1988,普通/53度,50ml*2/盒,2.000,2,Y,1
|
||||
1021,7,NULL,1046,ZXZ026141,五粮液礼盒2022,普通/52度,500ml*2/盒,2.000,2,Y,1
|
||||
2156,6,NULL,2181,ZXZ026141,五粮液礼盒2022,普通/52度,500ml*2/盒,2.000,2,Y,1
|
||||
3341,1,NULL,3366,ZXZ026141,五粮液礼盒2022,普通/52度,500ml*2/盒,2.000,2,Y,1
|
||||
4611,8,10,4636,ZXZ026141,五粮液礼盒2022,普通/52度,500ml*2/盒,2.000,2,Y,1
|
||||
3342,1,NULL,3367,ZXZ026512,茅台虎年礼盒375ml,普通/53度,375ml*2/盒,2.000,2,Y,1
|
||||
4612,8,10,4637,ZXZ026512,茅台虎年礼盒375ml,普通/53度,375ml*2/盒,2.000,2,Y,1
|
||||
1022,7,NULL,1047,ZXZ026512,茅台虎年礼盒375ml,普通/53度,375ml*2/盒,2.000,2,Y,1
|
||||
2157,6,NULL,2182,ZXZ026512,茅台虎年礼盒375ml,普通/53度,375ml*2/盒,2.000,2,Y,1
|
||||
1023,7,NULL,1048,ZXZ026646,茅台小件2025,普通/53度,500ml*6/件,2.000,6,N,
|
||||
1024,7,NULL,1049,ZXZ026841,茅台小件2026,普通/53度,500ml*6/件,2.000,6,N,
|
||||
4613,8,10,4638,ZXZ026841,茅台小件2026,普通/53度,500ml*6/件,2.000,6,N,
|
||||
4614,8,10,4639,ZXZ027088,贵州君品习酒2025原件,普通/53度,500ml*6/件,2.000,6,N,
|
||||
1025,7,NULL,1050,ZXZ027377,茅台马年礼盒2026,普通/53度,500ml*2/盒,2.000,2,Y,1
|
||||
2160,6,NULL,2185,ZXZ027377,茅台马年礼盒2026,普通/53度,500ml*2/盒,2.000,2,Y,1
|
||||
3347,1,NULL,3372,ZXZ028245,国窖2022年,普通/43度,100ml*2/盒,2.000,2,Y,1
|
||||
4615,8,10,4640,ZXZ028245,国窖2022年,普通/43度,100ml*2/盒,2.000,2,Y,1
|
||||
3348,1,NULL,3373,ZXZ028561,贵州茅台酒2020,普通/53度,50ml*2/盒,2.000,2,Y,1
|
||||
4616,8,10,4641,ZXZ028561,贵州茅台酒2020,普通/53度,50ml*2/盒,2.000,2,Y,1
|
||||
3349,1,NULL,3374,ZXZ028675,茅台三斤原件2024,普通/53度,1.50L*2/件,2.000,2,Y,1
|
||||
3350,1,NULL,3375,ZXZ028929,红花郎.红十2024,普通/53度,500ml*2/盒,2.000,2,Y,1
|
||||
3351,1,NULL,3376,ZXZ028930,红花郎.红十2025,普通/53度,500ml*2/盒,2.000,2,Y,1
|
||||
4617,8,10,4642,ZXZ028930,红花郎.红十2025,普通/53度,500ml*2/盒,2.000,2,Y,1
|
||||
4618,8,10,4643,ZXZ029676,小国窖礼盒,普通/53度,50ml*2/盒,2.000,2,Y,1
|
||||
|
@@ -0,0 +1,93 @@
|
||||
# 库存「装箱数被当成数量」脏数据排查报告
|
||||
|
||||
> 排查日期:2026-06-22 · 只读核查,**未修改任何生产数据**
|
||||
> 明细清单:`docs/review/inventory-qty-packsize-dirty.csv`(820 行)
|
||||
|
||||
## 一、起因
|
||||
|
||||
用户反馈「商品编号 P1297 有 12 个库存,正常只有一个」,并认为「库存都是 1,quantity 字段可以删」。排查后两个判断都需要修正。
|
||||
|
||||
## 二、P1297 真相
|
||||
|
||||
P1297 = product `4830`(shop 8),**只有 1 条库存行**(inventory id 9412),不是 12 条:
|
||||
|
||||
| 字段 | 值 |
|
||||
|---|---|
|
||||
| 商品名称 | 茅台公斤大件2005原件 |
|
||||
| 规格 | `1.00L*12/件`(一件装 12 瓶) |
|
||||
| 单位 | (空) |
|
||||
| 当前数量 | **12.000** |
|
||||
| 来源 | 入库明细 32353 / 入库单 7976,**录入数量本身就是 12** |
|
||||
|
||||
即 inventory 忠实快照了入库单的 12,不是代码 bug。问题在于**导入时把规格里的「装箱数 12」当成了库存数量**,用户预期是「1 件」。
|
||||
|
||||
## 三、系统性结论:装箱数泄漏
|
||||
|
||||
这不是个例。全库 **9412 条活跃库存中,820 条 quantity > 1**,其中 **784 条的数量恰好等于规格里的装箱数**(`*N/件` → 数量 N):
|
||||
|
||||
- qty=12 的行:82 条里 80 条规格含 `*12`
|
||||
- qty=6 的行:641 条里绝大多数规格含 `*6`
|
||||
- 判定规则:规格 `\*(\d+)` 捕获的装箱数 == 当前数量 → 标记 `dirty_pack_eq_qty=Y`
|
||||
|
||||
### 按门店分布(疑似脏 dirty=Y)
|
||||
|
||||
| shop_id | 脏行数 | 备注 |
|
||||
|---|---|---|
|
||||
| 8 | 279 | 主力门店 |
|
||||
| 7 | 239 | |
|
||||
| 1 | 142 | 疑似 seed/demo(商品信息多为 NULL) |
|
||||
| 6 | 124 | |
|
||||
| **合计** | **784** | |
|
||||
|
||||
### 另有 36 行 quantity>1 但装箱数≠数量(`dirty=N`)
|
||||
|
||||
需**人工复核**,不能机械归 1。典型:
|
||||
- shop 1 的 seed 数据:数量 108/54/36/24…,商品编码/规格全 NULL(demo,可忽略)。
|
||||
- `ZXZ026602 茅台小白条2023原件` 规格 `500ml*5/件`,数量却是 12 / 10 —— 装箱数 5,数量非整箱倍数,真实库存存疑。
|
||||
|
||||
## 四、quantity 字段能否删除
|
||||
|
||||
**不能删**(用户原设想不成立):
|
||||
|
||||
1. 数据层面:并非「都是 1」,真有 820 行多单位(其中 784 是脏数据,但删字段前必须先治脏,且仍有真实多单位场景)。
|
||||
2. 代码层面:`quantity` 被 FIFO 扣减、出库库存校验、库存流水 `inventory_logs`、财务对账、公开商品在库量、盘点全链路依赖,删列等于重构整个库存系统。
|
||||
|
||||
本轮已按决策**仅在前端隐藏库存数量列**(库存列表表格 + 手机卡片),DB 字段与后端逻辑保留;缺货/预警/流水不动。
|
||||
|
||||
## 五、建议(待决策,本轮不执行)
|
||||
|
||||
1. **784 行脏数据按「件」归正为 1**:把「规格装箱数 == 数量」的行,数量统一改为 1(视作 1 件);同步修对应入库明细 `stock_in_items.quantity`,保持单据与库存一致。执行前**先备份**,并对照 CSV 的 `suggest_qty` 列逐店确认。
|
||||
2. **36 行 dirty=N 单独人工核对**:shop 1 demo 可忽略;`*5/件` 却数量 12/10 等异常逐条问业务。
|
||||
3. **根治导入器**:库存/入库导入时,遇到 `规格含 *N` 且「数量列恰好等于 N」的情况给出告警或按件折算,避免再次把装箱数写进数量。
|
||||
|
||||
> 是否执行第 1 项数据归正,请确认后另行单独处理(需备份 + 逐店复核 + 影响行数预览)。
|
||||
|
||||
---
|
||||
|
||||
## 六、全量数据质量审计(2026-06-22 补充)
|
||||
|
||||
对全部活跃库存(9412 行 / 7282 distinct product)逐类核查:
|
||||
|
||||
| 类别 | 行数 | 说明 |
|
||||
|---|---|---|
|
||||
| 数量 ≤ 0 | 0 | 干净 |
|
||||
| product_id=0(无主数据) | 0 | 干净 |
|
||||
| 孤儿(product_id 指向不存在 product) | 0 | 干净 |
|
||||
| 快照商品编码为空 | 24 | 轻微,无法定位编号 |
|
||||
| **快照编码 ≠ 所指 product.code(错指)** | **2130** | **重大,全在 shop 7** |
|
||||
| 装箱数=数量(脏数量) | 784 | 见上文,跨 shop 8/7/6/1 |
|
||||
|
||||
### 重大:shop 7 的 product_id 错指(与 shop 8 旧损坏同款)
|
||||
|
||||
`shop 7` 有 **2130 条库存行错指**,涉及 **514 个被多编码共享的 product**(每个 product 名下挂多个不同商品编号)。典型:product `234` 名下有 **130 条库存行、130 个不同商品编码**——即 130 个真实商品编号的库存全部指向了同一个 product。这正是上次给 shop 8 修过的「按名称合并导致 product_id 搞混」根因。
|
||||
|
||||
各店对比:
|
||||
|
||||
| shop | 活跃库存行 | 错指行 | 状态 |
|
||||
|---|---|---|---|
|
||||
| 1 | 1213 | 0 | 干净 |
|
||||
| 6 | 1134 | 0 | 干净 |
|
||||
| 7 | 3286 | **2130** | ❌ 未修复 |
|
||||
| 8 | 3779 | 0 | 已修复(本次之前) |
|
||||
|
||||
**建议**:对 shop 7 跑既有的 `backend/cmd/fix-inventory-products` 工具(按库存快照编码重建 per-code product),流程同 shop 8——**先备份** → dry-run 预览 → 执行 → 复核「错指=0、distinct product 数=活跃行去重数」。需你确认后单独执行。
|
||||
@@ -0,0 +1,33 @@
|
||||
# Lint 检查报告 — 2026-07-03
|
||||
|
||||
## Go 后端
|
||||
|
||||
### ✅ 全部通过
|
||||
- `gofmt -l .`:无格式问题
|
||||
- `go vet ./...`:无问题
|
||||
|
||||
## Flutter 前端
|
||||
|
||||
### ✅ 已自动修复
|
||||
- `dart format lib test`:70 个文件格式化
|
||||
- `dart fix --apply --code=unnecessary_import`:移除 10 处多余 import(涉及 kpi_card / label_preview_dialog / wheel_date_picker / product_detail_screen 及 5 个 test 文件)
|
||||
- `client/pubspec.yaml`:修正 `flutter_web_plugins: any` → `sdk: flutter`(原写法导致 `flutter pub get` 直接失败,属本轮未提交改动引入的构建阻断问题;`pubspec.lock` 随之更新)
|
||||
|
||||
### ⚠️ 需要手动修复(warning,本轮改动文件)
|
||||
- `client/test/product_repository_test.dart:142` / `:161`:`unnecessary_type_check`——类型判断结果恒为 true,断言无效,建议改为有意义的断言或删除
|
||||
|
||||
### ⚠️ 需要手动修复(warning,存量代码,非本轮改动)
|
||||
- `client/lib/core/platform/single_instance.dart:7`:`unused_element`——私有声明 `_server` 未被引用
|
||||
|
||||
### ℹ️ info 级别(82 处,不阻断 DoD,择机清理)
|
||||
- `use_build_context_synchronously` ×46:主要集中在 `stock_in_list_screen.dart` / `stock_out_list_screen.dart` 的 async 回调中跨 await 使用 context(mounted 检查对象不匹配)
|
||||
- `prefer_const_constructors` ×19 + `prefer_const_literals_to_create_immutables` ×1
|
||||
- `deprecated_member_use` ×7:`withOpacity` → `withValues()`(inventory_check_screen / label_preview_dialog / multi_select_dropdown / order_print_preview_dialog)
|
||||
- `curly_braces_in_flow_control_structures` ×7
|
||||
- `no_wildcard_variable_uses` ×2:`app_shell.dart:581/586` 引用了通配符变量 `_`
|
||||
|
||||
### 重点关注目录
|
||||
- `client/lib/screens/auth/`、`client/lib/widgets/ds/`:**零问题**,干净
|
||||
|
||||
## 结论
|
||||
0 error;3 处 warning 需手动处理(2 处在本轮改动的测试文件、1 处存量);pubspec 构建阻断问题已修复。整体可提交。
|
||||
@@ -0,0 +1,143 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>出入库明细空字段 × 库存可补 数据统计 — 酒库管理系统</title>
|
||||
<style>
|
||||
:root{
|
||||
--primary:#2563AC; --primary-dark:#154072; --danger:#D14343; --danger-bg:#FDECEC;
|
||||
--success:#2E8B57; --success-bg:#E6F3EC; --warn:#B45309; --warn-bg:#FFF4E5; --accent:#8B2331;
|
||||
--ink:#232934; --muted:#6E7888; --border:#DCE2EB; --paper:#F5F7FA; --head:#F0F4FF;
|
||||
}
|
||||
*{box-sizing:border-box;font-family:-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;}
|
||||
body{margin:0;background:var(--paper);color:var(--ink);padding:28px;line-height:1.65;max-width:1000px;margin:0 auto;}
|
||||
h1{font-size:22px;margin:0 0 4px;}
|
||||
h2{font-size:17px;margin:30px 0 10px;color:var(--primary-dark);border-bottom:2px solid var(--head);padding-bottom:6px;}
|
||||
h3{font-size:14px;margin:18px 0 6px;color:var(--accent);}
|
||||
.sub{color:var(--muted);font-size:13px;margin-bottom:8px;}
|
||||
.stats{display:flex;gap:22px;flex-wrap:wrap;font-size:12.5px;color:var(--muted);margin:10px 0;}
|
||||
.stats b{color:var(--ink);font-size:16px;}
|
||||
.card{background:#fff;border:1px solid var(--border);border-radius:10px;padding:14px 18px;margin:12px 0;}
|
||||
table{width:100%;border-collapse:collapse;font-size:13px;margin:6px 0;}
|
||||
th{background:var(--head);color:var(--primary-dark);font-weight:600;font-size:12px;text-align:left;padding:8px 10px;border-bottom:1px solid var(--border);}
|
||||
td{padding:7px 10px;border-bottom:1px solid #EEF1F6;}
|
||||
tr:last-child td{border-bottom:0;}
|
||||
td.n{text-align:right;font-family:ui-monospace,Menlo,monospace;}
|
||||
.mono{font-family:ui-monospace,Menlo,monospace;font-size:12px;}
|
||||
code{font-family:ui-monospace,Menlo,monospace;font-size:12px;background:#EEF2F8;padding:1px 5px;border-radius:4px;color:var(--primary-dark);}
|
||||
.hi{color:var(--danger);font-weight:700;}
|
||||
.ok{color:var(--success);font-weight:700;}
|
||||
.callout{border-left:4px solid var(--primary);background:#F0F6FF;padding:10px 14px;border-radius:4px;margin:12px 0;font-size:13px;}
|
||||
.callout.danger{border-color:var(--danger);background:var(--danger-bg);}
|
||||
.callout.warn{border-color:var(--warn);background:var(--warn-bg);}
|
||||
.callout.ok{border-color:var(--success);background:var(--success-bg);}
|
||||
ul{margin:6px 0;padding-left:20px;} li{margin:4px 0;font-size:13px;}
|
||||
.tag{display:inline-block;font-size:10px;padding:1px 7px;border-radius:9px;font-weight:600;}
|
||||
.tag.fix{background:var(--success-bg);color:var(--success);}
|
||||
.tag.no{background:#EEE;color:var(--muted);}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>出入库明细 空字段 × 库存可补 · 数据统计</h1>
|
||||
<div class="sub">数据源:生产库每日备份 <code>jiu_db_20260626_020210.sql.gz</code>(2026-06-26 02:02)· 单租户(鼎晟酒行)</div>
|
||||
<div class="stats">
|
||||
<div>出库明细 <b>26,693</b> 行</div>
|
||||
<div>入库明细 <b>28,443</b> 行</div>
|
||||
<div>库存批次 <b>13,120</b> 行</div>
|
||||
<div>商品 <b>9,525</b> 行</div>
|
||||
</div>
|
||||
|
||||
<div class="callout">
|
||||
<b>口径说明:</b>「库存能找到值」= 该字段在库存表的<b>显示值</b>非空,即 <code>COALESCE(NULLIF(sii.batch_no,''), inv.batch_no)</code>(用户在库存页看到的值)。出库明细按 <code>product_id</code> 匹配库存;入库明细按 <code>stock_in_item_id</code> 直连。<br>
|
||||
「打印必空白」= 明细行快照为空 <b>且</b> 该行 <code>product</code> 主记录也为空(两者都空,打印才会留白)。
|
||||
</div>
|
||||
|
||||
<h2>一、核心结论</h2>
|
||||
<div class="card">
|
||||
<ul>
|
||||
<li><b>出库单打印空白、且能从库存补回的,只有约 <span class="hi">18~20 行</span>(集中在 <span class="hi">13 张单</span>)</b>,全部是 <b>2026-06-20 ~ 06-24</b> 的近期 App 新建单(含截图 <code>CK20260623000007</code>)。这正是「出库单显示对齐库存口径」能解决的部分。</li>
|
||||
<li>出库明细批次号为空共 <b>5,528 行</b>,但其中 <span class="hi">99.7% 在库存里也查不到值</span>(商品已售罄无在库批次 / 源数据本就没录批次)——属源数据缺失,<b>非显示 bug,无法从库存补</b>。</li>
|
||||
<li><b>入库单批次/生产日期可补数 = <span class="hi">0</span></b>(库存、product 主记录都补不出)。因为<b>入库是数据录入源头</b>,源头空则下游全空,无上游可回填——与出库不同,<b>不是显示 bug,"显示对齐库存口径"对入库无意义</b>。空批次跨 2023-04~2026-06 整段历史。</li>
|
||||
<li>根因复述:批次/生产日期的值真实落在 <code>inventories</code> 表<b>自身的快照列</b>上(不是 stock_in_item、也不是 product 主记录);出库打印却回退读 <code>product</code> 主记录,对不上。详见 <a href="../db-schema.html#inventories">db-schema</a>。</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2>二、出库明细 stock_out_items</h2>
|
||||
<p class="sub">product_id 全部有值(无占位行)。</p>
|
||||
|
||||
<h3>① 宽口径:明细字段为空 ÷ 其中库存能找到值</h3>
|
||||
<div class="card"><table>
|
||||
<thead><tr><th>字段</th><th>明细为空</th><th>占比</th><th>其中库存有值</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>batch_no</code> 批次号</td><td class="n">5,557</td><td class="n">20.8%</td><td class="n">46</td></tr>
|
||||
<tr><td><code>production_date</code> 生产日期</td><td class="n">66</td><td class="n">0.25%</td><td class="n">48</td></tr>
|
||||
<tr><td><code>product_code</code> 商品编号</td><td class="n">62</td><td class="n">0.23%</td><td class="n">48</td></tr>
|
||||
<tr><td><code>series</code> 系列</td><td class="n">63</td><td class="n">0.24%</td><td class="n">48</td></tr>
|
||||
<tr><td><code>spec</code> 规格</td><td class="n">63</td><td class="n">0.24%</td><td class="n">48</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
|
||||
<h3>② 打印口径:明细空 且 product 主记录也空(= 打印必空白)÷ 库存可补</h3>
|
||||
<div class="card"><table>
|
||||
<thead><tr><th>字段</th><th>打印空白行</th><th><span class="tag fix">库存可补</span></th><th>涉及出库单</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>batch_no</code> 批次号</td><td class="n">5,528</td><td class="n ok">18</td><td class="n">1,207</td></tr>
|
||||
<tr><td><code>production_date</code> 生产日期</td><td class="n">37</td><td class="n ok">20</td><td class="n">22</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
|
||||
<h2>三、入库明细 stock_in_items</h2>
|
||||
<p class="sub">与出库<b>完全同口径</b>:库存按 <code>product_id</code> 匹配;并额外列出能否从 <code>product</code> 主记录补值。</p>
|
||||
<div class="card"><table>
|
||||
<thead><tr><th>字段</th><th>明细为空</th><th><span class="tag fix">库存可补</span></th><th>product 主记录可补</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>batch_no</code> 批次号</td><td class="n">6,876</td><td class="n hi">0</td><td class="n hi">0</td></tr>
|
||||
<tr><td><code>production_date</code> 生产日期</td><td class="n">16</td><td class="n hi">0</td><td class="n hi">0</td></tr>
|
||||
<tr><td><code>product_code</code> 商品编号</td><td class="n">25</td><td class="n">10</td><td class="n">25</td></tr>
|
||||
<tr><td><code>series</code> 系列</td><td class="n">27</td><td class="n">12</td><td class="n">26</td></tr>
|
||||
<tr><td><code>spec</code> 规格</td><td class="n">27</td><td class="n">12</td><td class="n">25</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
<div class="callout warn">
|
||||
<b>入库单批次号/生产日期:可补数 = 0(库存、product 主记录都补不出)。</b>这是结构性的——<b>入库是数据录入的源头</b>:批次若在入库时就空着,由它建的 product 也空、由它生成的库存批次同样空,没有任何上游能反过来填。出库之所以能补,是因为出库引用的是「别的、已录过批次的库存批次」。<br>
|
||||
入库空批次跨度 <b>2023-04 ~ 2026-06</b>(整段历史都有,非 App 期专属),属源头从未录入,<b>不是显示 bug,与出库的「显示对齐库存口径」无关</b>。商品编号/系列/规格少量空行(25~27)可从 product 主记录补,但属商品身份字段、与本次批次问题无关。</div>
|
||||
|
||||
<h2>四、受影响(打印空白但库存可补)出库单清单</h2>
|
||||
<p class="sub">20 个明细行,13 张单,全部为近期 App 新建单。这些单据打印时批次/生产日期留白,但库存里有值。</p>
|
||||
<div class="card"><table>
|
||||
<thead><tr><th>出库单号</th><th>日期</th><th>product_id</th><th>库存批次</th><th>库存生产日期</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td class="mono">CK20260624000021</td><td>2026-06-24</td><td class="mono">4779</td><td class="mono">2015674600</td><td class="mono">2009-04-16</td></tr>
|
||||
<tr><td class="mono">CK20260623000001</td><td>2026-06-23</td><td class="mono">9448</td><td class="mono">2023-003/AI013453</td><td class="mono">2025-02-27</td></tr>
|
||||
<tr><td class="mono">CK20260623000001</td><td>2026-06-23</td><td class="mono">4430</td><td class="mono">1</td><td class="mono">2012-01-01</td></tr>
|
||||
<tr><td class="mono">CK20260623000001</td><td>2026-06-23</td><td class="mono">9449</td><td class="mono">2023-003/AI013441</td><td class="mono">2025-02-27</td></tr>
|
||||
<tr><td class="mono">CK20260623000001</td><td>2026-06-23</td><td class="mono">9486</td><td class="mono">2006-01/03008</td><td class="mono">2006-12-01</td></tr>
|
||||
<tr><td class="mono">CK20260623000003</td><td>2026-06-23</td><td class="mono">4617</td><td class="mono">2026-001/YC025400</td><td class="mono">2026-03-19</td></tr>
|
||||
<tr><td class="mono">CK20260623000004</td><td>2026-06-23</td><td class="mono">9477</td><td class="mono">2025-023/AA007333</td><td class="mono">2025-12-18</td></tr>
|
||||
<tr><td class="mono">CK20260623000004</td><td>2026-06-23</td><td class="mono">9478</td><td class="mono">2025-023/AA007191</td><td class="mono">2025-12-18</td></tr>
|
||||
<tr><td class="mono">CK20260623000004</td><td>2026-06-23</td><td class="mono">4722</td><td class="mono">2025-127/441066145489</td><td class="mono">2026-03-14</td></tr>
|
||||
<tr><td class="mono"><b>CK20260623000007</b> <span class="tag fix">截图</span></td><td>2026-06-23</td><td class="mono">4382</td><td class="mono">2022-001/AH000108</td><td class="mono">2023-12-28</td></tr>
|
||||
<tr><td class="mono">CK20260623000009</td><td>2026-06-23</td><td class="mono">4247</td><td class="mono">(批次空)</td><td class="mono">2024-08-21</td></tr>
|
||||
<tr><td class="mono">CK20260623000010</td><td>2026-06-23</td><td class="mono">4717</td><td class="mono">2022-014/664667600053</td><td class="mono">2024-01-31</td></tr>
|
||||
<tr><td class="mono">CK20260623000010</td><td>2026-06-23</td><td class="mono">9503</td><td class="mono">2023-004/654105250904</td><td class="mono">2024-07-11</td></tr>
|
||||
<tr><td class="mono">CK20260623000013</td><td>2026-06-23</td><td class="mono">4026</td><td class="mono">2022-091/AA019835</td><td class="mono">2023-07-25</td></tr>
|
||||
<tr><td class="mono">CK20260623000014</td><td>2026-06-23</td><td class="mono">9499</td><td class="mono">2022-006/AI008438</td><td class="mono">2024-05-11</td></tr>
|
||||
<tr><td class="mono">CK20260623000014</td><td>2026-06-23</td><td class="mono">9500</td><td class="mono">2022-005/AH003630</td><td class="mono">2024-03-28</td></tr>
|
||||
<tr><td class="mono">CK20260623000015</td><td>2026-06-23</td><td class="mono">4645</td><td class="mono">(批次空)</td><td class="mono">2026-01-19</td></tr>
|
||||
<tr><td class="mono">CK20260623000016</td><td>2026-06-23</td><td class="mono">4732</td><td class="mono">2022-030/799689408820</td><td class="mono">2023-02-14</td></tr>
|
||||
<tr><td class="mono">CK20260623000017</td><td>2026-06-23</td><td class="mono">4757</td><td class="mono">2025-102/006679240592</td><td class="mono">2026-02-13</td></tr>
|
||||
<tr><td class="mono">CK20260620000001</td><td>2026-06-20</td><td class="mono">3510</td><td class="mono">RK20260613000004-01</td><td class="mono">2026-06-09</td></tr>
|
||||
</tbody>
|
||||
</table></div>
|
||||
|
||||
<h2>五、对修复方案的指向</h2>
|
||||
<div class="callout ok">
|
||||
<b>「出库单显示对齐库存口径」(已选方案)足以覆盖真实问题:</b>对近期 App 出库单(上表 13 张)打印时按 <code>product → inventory</code> 取批次/生产日期即可即时补全,无需动数据、无需重发。<br>
|
||||
<b>历史海量空批次(5,500+ 行)不在修复范围:</b>它们在 product / 库存 / 入库明细中均无值,属源数据从未录入,任何「显示口径」都补不出来。<br>
|
||||
<b>入库单方向收益≈0:</b>入库明细与库存几乎无可用关联,且入库明细空批次同样源数据缺失。
|
||||
</div>
|
||||
|
||||
<p class="sub" style="margin-top:24px;">统计方法:将备份导入临时库 <code>jiu_analyze</code>,按上述口径 SQL 聚合,完成后删除临时库。生成时间 2026-06-26。</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,218 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>EC2 → 阿里云 迁移计划(定稿)— 酒库管理系统</title>
|
||||
<style>
|
||||
:root{
|
||||
--primary:#2563AC; --primary-dark:#154072; --danger:#D14343; --danger-bg:#FDECEC;
|
||||
--success:#2E8B57; --success-bg:#E6F3EC; --warn:#B45309; --warn-bg:#FFF4E5; --accent:#8B2331;
|
||||
--ink:#232934; --muted:#6E7888; --border:#DCE2EB; --paper:#F5F7FA; --head:#F0F4FF;
|
||||
}
|
||||
*{box-sizing:border-box;font-family:-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;}
|
||||
body{margin:0;background:var(--paper);color:var(--ink);padding:28px;line-height:1.65;}
|
||||
h1{font-size:22px;margin:0 0 4px;}
|
||||
h2{font-size:17px;margin:30px 0 12px;color:var(--primary-dark);border-bottom:2px solid var(--head);padding-bottom:6px;}
|
||||
h3{font-size:14px;margin:18px 0 8px;color:var(--accent);}
|
||||
.sub{color:var(--muted);font-size:13px;margin-bottom:18px;}
|
||||
.card{background:#fff;border:1px solid var(--border);border-radius:10px;padding:16px 20px;margin:14px 0;}
|
||||
.lead{font-size:13.5px;color:var(--ink);}
|
||||
table{width:100%;border-collapse:collapse;font-size:13px;margin:8px 0;}
|
||||
th{background:var(--head);color:var(--primary-dark);font-weight:600;font-size:12px;text-align:left;padding:9px 10px;border-bottom:1px solid var(--border);}
|
||||
td{padding:8px 10px;border-bottom:1px solid #EEF1F5;vertical-align:top;}
|
||||
.mono{font-family:ui-monospace,Menlo,monospace;font-size:12.5px;}
|
||||
code{font-family:ui-monospace,Menlo,monospace;font-size:12px;background:#EEF2F8;padding:1px 5px;border-radius:4px;color:var(--primary-dark);}
|
||||
pre{background:#1E2430;color:#D8E0EC;border-radius:8px;padding:12px 14px;overflow:auto;font-size:12px;line-height:1.55;}
|
||||
pre .c{color:#7A8699;}
|
||||
.tag{display:inline-block;font-size:11px;padding:1px 8px;border-radius:10px;font-weight:600;}
|
||||
.tag.keep{background:var(--success-bg);color:var(--success);}
|
||||
.tag.move{background:#E5EEF9;color:var(--primary);}
|
||||
.tag.drop{background:#EEE;color:var(--muted);}
|
||||
.tag.risk{background:var(--danger-bg);color:var(--danger);}
|
||||
.tag.ok{background:var(--success-bg);color:var(--success);}
|
||||
.callout{border-left:4px solid var(--primary);background:#F0F6FF;padding:10px 14px;border-radius:4px;margin:12px 0;font-size:13px;}
|
||||
.callout.danger{border-color:var(--danger);background:var(--danger-bg);}
|
||||
.callout.warn{border-color:var(--warn);background:var(--warn-bg);}
|
||||
.callout.ok{border-color:var(--success);background:var(--success-bg);}
|
||||
.callout b{color:var(--ink);}
|
||||
ul,ol{margin:6px 0;padding-left:22px;}
|
||||
li{margin:3px 0;font-size:13px;}
|
||||
.phase{display:flex;align-items:center;gap:10px;margin:22px 0 6px;}
|
||||
.phase .num{flex:0 0 auto;width:30px;height:30px;border-radius:50%;background:var(--primary);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:12px;}
|
||||
.phase .num.gate{background:var(--danger);}
|
||||
.phase h2{margin:0;border:0;padding:0;font-size:16px;}
|
||||
.chk{list-style:none;padding-left:0;}
|
||||
.chk li{padding-left:24px;position:relative;margin:5px 0;}
|
||||
.chk li::before{content:"☐";position:absolute;left:0;color:var(--primary);font-size:14px;}
|
||||
.meta{display:flex;gap:26px;flex-wrap:wrap;font-size:12px;color:var(--muted);margin-top:4px;}
|
||||
.meta b{color:var(--ink);}
|
||||
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:14px;}
|
||||
@media(max-width:720px){.grid2{grid-template-columns:1fr;}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>EC2 → 阿里云 迁移计划 <span class="tag ok">定稿</span></h1>
|
||||
<div class="sub">酒库管理系统(jiu)· 把 jiu 的服务 / 数据 / 文件 / DB / 域名解析 / CI 接入从 AWS EC2 整体切到阿里云 ECS。<b>共享机上的 pangolin / marzban / blog 原地不动</b>。核心策略:<b>DB 主从实时复制 + ICP 备案期间双轨部署,最后几秒提升从库为主 + 切 DNS</b>。</div>
|
||||
<div class="meta">
|
||||
<span><b>源</b> AWS EC2 · ap-southeast-1(新加坡)· Amazon Linux 2023 · <span class="mono">18.136.60.128</span></span>
|
||||
<span><b>目标</b> 阿里云 ECS · 大陆地域(需备案)</span>
|
||||
<span><b>切流停机</b> 仅几秒(提升从库)</span>
|
||||
<span><b>定稿日</b> 2026-06-23</span>
|
||||
</div>
|
||||
|
||||
<h3>已拍定的关键决策</h3>
|
||||
<table>
|
||||
<tr><th>项</th><th>定论</th></tr>
|
||||
<tr><td>接入架构</td><td><b>阿里独立 nginx 直连 443</b>,不复刻 pangolin(pangolin 后续单独迁走)</td></tr>
|
||||
<tr><td>证书</td><td><b>certbot DNS-01 + Cloudflare API</b> 预签(与机器 IP/端口/解析解耦,切流前即可备好)</td></tr>
|
||||
<tr><td>数据库切换</td><td><b>MySQL 主从复制</b>(EC2 主 → 阿里从,实时同步),切流时提升从库为主,写冻结仅几秒</td></tr>
|
||||
<tr><td>CI/CD</td><td><b>双轨</b>:编译/测试/发布不变,Deploy 拆成 EC2 + Ali 两步并存,迁移期每次发版同步两边</td></tr>
|
||||
<tr><td>域名</td><td>注册商先从 Cloudflare 转入阿里万网(备案前置),<b>转移不影响解析</b>,全程仍指 EC2,备案过后再切 A 记录</td></tr>
|
||||
</table>
|
||||
|
||||
<div class="callout danger">
|
||||
<b>⚠ 头号前置 — 域名注册商转移 + ICP 备案:</b>
|
||||
<code>51yanmei.com</code> 现注册在 <b>Cloudflare(海外)</b>,不在工信部名单 → 大陆备案前必须把<b>注册商转入阿里万网</b>(转出流程 5–7 天,期间解析不中断)。
|
||||
备案本身 1–3 周。<b>这两件事决定整个时间表,且 EC2 在此期间照常对外服务。</b>
|
||||
注意:<b>注册商转移 ≠ 改解析</b>——转入阿里万网后 A 记录照样指 EC2,线上零影响。
|
||||
</div>
|
||||
|
||||
<!-- ============ 1. 迁移盘点 ============ -->
|
||||
<h2>一、迁移盘点(搬什么 / 不搬什么)</h2>
|
||||
<p class="lead">EC2 是<b>多服务共享机</b>,本次只迁 jiu。</p>
|
||||
|
||||
<h3>① 要迁移的 jiu 资产 <span class="tag move">MOVE</span></h3>
|
||||
<table>
|
||||
<tr><th>类别</th><th>内容</th><th>位置 / 体量</th><th>迁移方式</th></tr>
|
||||
<tr><td>后端服务</td><td>systemd <code>jiu.service</code> → <span class="mono">jiu-server</span>(+ <span class="mono">jiu-gencode</span>)</td><td><span class="mono">/opt/jiu/backend</span> · 64M</td><td>CI 双轨重新部署</td></tr>
|
||||
<tr><td>数据库</td><td>MySQL 8.0 容器 <code>jiu_mysql</code> / 库 <code>jiu_db</code></td><td>35.3 MB</td><td><b>主从复制实时同步</b>(非一次性 dump)</td></tr>
|
||||
<tr><td>配置</td><td><span class="mono">production.env</span>(含密钥)、<span class="mono">version.yaml</span></td><td><span class="mono">/opt/jiu/config</span></td><td>scp 拷贝;域名不变 → 内容照搬</td></tr>
|
||||
<tr><td>上传文件</td><td>商品图片</td><td><span class="mono">/opt/jiu/images</span> · 2M</td><td><code>rsync</code>(<b>不在 DB 复制范围</b>,切流前再补一次)</td></tr>
|
||||
<tr><td>前端 / 官网 / 安装包</td><td>Flutter web、Eleventy 站、apk/zip/exe</td><td><span class="mono">/opt/jiu/{web,marketing,downloads}</span></td><td>CI 双轨下发 / rsync</td></tr>
|
||||
<tr><td>反代配置</td><td>nginx <code>jiu.conf</code></td><td>pangolin-edge 容器内</td><td>改造为<b>独立 nginx(listen 443)</b></td></tr>
|
||||
<tr><td>TLS 证书</td><td><code>jiu.51yanmei.com</code></td><td>EC2 letsencrypt</td><td>阿里机 <b>DNS-01 预签</b></td></tr>
|
||||
<tr><td>域名解析</td><td><code>jiu.51yanmei.com</code> A 记录</td><td>Cloudflare → <span class="mono">18.136.60.128</span> · 未代理</td><td>备案后切到阿里 IP(唯一一条 DNS 改动)</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>② 留在 EC2 / 不动 <span class="tag keep">KEEP</span></h3>
|
||||
<p class="lead">pangolin-edge / pangolin-singbox(共享反代,后续单独迁)、marzban、blog 全家桶(blog/umami/postgres)、blog/vpn 证书、blog/pay/vpn 解析。</p>
|
||||
|
||||
<h3>③ NAS(群晖 <span class="mono">192.168.3.200</span>)不搬,仅改配置 <span class="tag keep">KEEP</span></h3>
|
||||
<div class="callout ok">
|
||||
Forgejo(<code>git.51yanmei.com:2222</code>)+ act_runner 在<b>内网群晖</b>,<code>git.51yanmei.com</code> 解析的是<b>内网 IP</b>,与 EC2 无关。迁移只需:① 加 <span class="mono">ALI_*</span> Secrets;② 改 <code>deploy-server.sh</code> 的 nginx reload 命令。
|
||||
</div>
|
||||
|
||||
<h3>④ 顺手清理 <span class="tag drop">DROP</span></h3>
|
||||
<p class="lead"><span class="mono">/opt/jiu/web-old</span>、<span class="mono">/opt/jiu/web_old</span> —— 历史残留,不迁。</p>
|
||||
|
||||
<!-- ============ 2. 数据库主从 ============ -->
|
||||
<h2>二、数据库主从复制(方案核心)</h2>
|
||||
<div class="callout ok"><b>EC2 主库已就绪、零重启:</b><span class="mono">log_bin=ON</span> · <span class="mono">binlog_format=ROW</span> · <span class="mono">server_id=1</span> · <span class="mono">gtid=OFF</span> · <span class="mono">binlog 保留 30 天</span>。→ 用<b>经典 binlog 位点复制</b>,不碰主库、不停现网;隧道断几天也能靠 30 天 binlog 自动追上。</div>
|
||||
<h3>网络通路:SSH 隧道(不暴露 DB 公网)</h3>
|
||||
<pre><span class="c"># 阿里机用 autossh 保活隧道,从库连本机 13306 → EC2 的 jiu_mysql:3306</span>
|
||||
autossh -M 0 -fN -L 13306:127.0.0.1:3306 ec2 <span class="c"># systemd 托管,断线自动重连</span></pre>
|
||||
<h3>搭建(EC2 纯新增,不影响现网)</h3>
|
||||
<pre><span class="c"># 1) EC2 主库建复制账号</span>
|
||||
CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY '<pass>';
|
||||
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
|
||||
|
||||
<span class="c"># 2) 带位点快照 → 导入阿里从库</span>
|
||||
docker exec jiu_mysql sh -c 'mysqldump -uroot -p$MYSQL_ROOT_PASSWORD \
|
||||
--single-transaction --master-data=2 jiu_db' | gzip > snap.sql.gz
|
||||
|
||||
<span class="c"># 3) 阿里从库(容器 command 加 --server-id=2 --read-only)挂主库开追</span>
|
||||
CHANGE REPLICATION SOURCE TO SOURCE_HOST='127.0.0.1', SOURCE_PORT=13306,
|
||||
SOURCE_USER='repl', SOURCE_PASSWORD='<pass>',
|
||||
SOURCE_LOG_FILE='<dump里的file>', SOURCE_LOG_POS=<dump里的pos>;
|
||||
START REPLICA; <span class="c"># SHOW REPLICA STATUS\G → Seconds_Behind_Source=0 即追平</span></pre>
|
||||
|
||||
<!-- ============ 3. 分阶段步骤 ============ -->
|
||||
<h2>三、迁移步骤(分阶段)</h2>
|
||||
|
||||
<div class="phase"><div class="num">0</div><h2>P0 · 域名注册商转移 + 提交备案(并行,EC2 照常服务)</h2></div>
|
||||
<ul class="chk">
|
||||
<li>买阿里 ECS(大陆,公网 IP,满足备案对实例时长要求),记 <span class="mono"><ALI_IP></span></li>
|
||||
<li>Cloudflare 解锁 <code>51yanmei.com</code> → 取 auth code → 阿里万网发起<b>注册商转入</b>(5–7 天,解析不中断)</li>
|
||||
<li>决定 DNS 托管:继续留 Cloudflare(保持 NS)或搬阿里云 DNS(先抄全部记录再切 NS)</li>
|
||||
<li>提交 <b>ICP 备案</b>(阿里接入),等 1–3 周;EC2 全程照常对外</li>
|
||||
</ul>
|
||||
|
||||
<div class="phase"><div class="num">1</div><h2>P1 · 阿里机基础搭建(无停机)</h2></div>
|
||||
<ul class="chk">
|
||||
<li>安全组放行 22/80/443,<b>3306 不对公网</b>;装 docker / docker-compose / nginx / certbot(cloudflare 插件)</li>
|
||||
<li>建 <span class="mono">/opt/jiu/{backend,config,images,downloads,web,marketing}</span>;生成<b>新部署 SSH 密钥对</b></li>
|
||||
<li>scp <code>production.env</code> / <code>version.yaml</code>;rsync <code>images/</code> <code>downloads/</code></li>
|
||||
</ul>
|
||||
|
||||
<div class="phase"><div class="num">2</div><h2>P2 · 起从库实时同步(见第二节)</h2></div>
|
||||
<ul class="chk">
|
||||
<li>起 <code>jiu_mysql</code>(<span class="mono">--server-id=2 --read-only</span>)→ autossh 隧道 → 导入带位点快照 → <code>START REPLICA</code></li>
|
||||
<li>确认 <span class="mono">Seconds_Behind_Source=0</span>,挂个延迟监控告警</li>
|
||||
</ul>
|
||||
|
||||
<div class="phase"><div class="num">3</div><h2>P3 · nginx + 证书 + 后端(仍未切流,--resolve 自测)</h2></div>
|
||||
<ul class="chk">
|
||||
<li>certbot <b>DNS-01</b> 为 <code>jiu.51yanmei.com</code> 预签证书(无需解析指过来)</li>
|
||||
<li>落地改造版 nginx(<span class="mono">listen 443 ssl</span> 直连),<code>nginx -t</code> 通过</li>
|
||||
<li>装 <code>jiu.service</code>;用 <code>curl --resolve jiu.51yanmei.com:443:<ALI_IP></code> 验证 health/version/官网/静态</li>
|
||||
<li class="">⚠ <b>后端跑在只读副本上</b>:AutoMigrate 无 schema 变更时是 no-op 能过;写链路(登录/出入库)要等切流提升为主后才完整可测</li>
|
||||
</ul>
|
||||
|
||||
<div class="phase"><div class="num">4</div><h2>P4 · CI/CD 双轨</h2></div>
|
||||
<table>
|
||||
<tr><th>对象</th><th>改动</th></tr>
|
||||
<tr><td>Secrets</td><td>新增 <span class="mono">ALI_HOST / ALI_SSH_KEY / ALI_USER</span>(EC2_* 保留不动)</td></tr>
|
||||
<tr><td>deploy-server/site/client.yml</td><td>Deploy 拆两步:<b>「Deploy → EC2」在前,「Deploy → Ali」在后</b>,均 <code>if: always()</code>(一边失败不挡发版)</td></tr>
|
||||
<tr><td><span class="mono">deploy-server.sh</span></td><td>参数化目标 host/key + nginx reload 方式:EC2 走 <code>docker exec pangolin-edge</code>,Ali 走独立 <code>nginx -s reload</code>(配置落 <span class="mono">/etc/nginx/conf.d/jiu.conf</span>)</td></tr>
|
||||
<tr><td><span class="mono">deploy/nginx-jiu.conf</span></td><td><span class="mono">listen 127.0.0.1:8445 ssl</span> → <span class="mono">listen 443 ssl</span></td></tr>
|
||||
</table>
|
||||
<div class="callout warn"><b>Schema 变更版本的顺序:</b>带新列/索引的发版,靠「EC2 先部署 → DDL 经复制流到达阿里副本 → Ali 再部署即 no-op」化解。workflow 里 EC2 步骤排在 Ali 之前,天然满足。</div>
|
||||
|
||||
<div class="phase"><div class="num gate">5</div><h2>P5 · 【备案通过后】切流:提升从库为主 + 切 DNS(写冻结仅几秒)</h2></div>
|
||||
<pre>0. 切前两边各全备一份(提升后 EC2 库即过时,留底兜底)
|
||||
1. 提前把 jiu.51yanmei.com TTL 降到 60–120s
|
||||
2. 最后一次 rsync EC2:/opt/jiu/images → Ali <span class="c"># 文件不走复制</span>
|
||||
3. EC2: systemctl stop jiu <span class="c"># 停写</span>
|
||||
4. Ali: 确认 Seconds_Behind_Source=0(追平最后一笔)
|
||||
5. Ali: STOP REPLICA; RESET REPLICA ALL; SET GLOBAL read_only=OFF; <span class="c"># 转独立主库</span>
|
||||
6. Ali: systemctl restart jiu <span class="c"># AutoMigrate 跑在可写库,no-op</span>
|
||||
7. Cloudflare: A 记录 18.136.60.128 → <ALI_IP></pre>
|
||||
|
||||
<div class="phase"><div class="num">6</div><h2>P6 · 公网验证</h2></div>
|
||||
<ul class="chk">
|
||||
<li>/health、/version、HTTPS 证书;登录 + 出入库审核(写链路);传图 → /images 可访问</li>
|
||||
<li>官网 / 下载 / <span class="mono">/app</span> / 扫码 <span class="mono">/product/:id</span> OG 标签</li>
|
||||
<li>触发一次 <code>backup-db</code> workflow 确认打到阿里机</li>
|
||||
</ul>
|
||||
|
||||
<div class="phase"><div class="num">7</div><h2>P7 · 观察后拆 EC2</h2></div>
|
||||
<ul class="chk">
|
||||
<li>观察 3–7 天无异常 → EC2:删 <code>jiu.service</code>、停删 <code>jiu_mysql</code>+volume、删 <span class="mono">/opt/jiu</span>、删 pangolin <span class="mono">conf.d/jiu.conf</span></li>
|
||||
<li>删 EC2 上 jiu 证书;TTL 调回;CI 删掉「Deploy → EC2」一轨</li>
|
||||
<li>更新 <span class="mono">docs/deployment-nas-gitea.md</span> 与 CLAUDE.md 中部署主机描述</li>
|
||||
</ul>
|
||||
|
||||
<!-- ============ 4. 风险与回滚 ============ -->
|
||||
<h2>四、风险与回滚</h2>
|
||||
<table>
|
||||
<tr><th>风险</th><th>等级</th><th>对策</th></tr>
|
||||
<tr><td>注册商转移 + 备案周期长</td><td><span class="tag risk">高</span></td><td>EC2 全程照常服务;阿里机后台先搭好、双轨同步,备案不阻塞日常发版</td></tr>
|
||||
<tr><td>图片文件不在 DB 复制范围</td><td><span class="tag risk">中</span></td><td>P5 切流前最后 rsync 一次 <code>images/</code>;切流后新图直接落阿里</td></tr>
|
||||
<tr><td>提升从库即 DB 不可逆</td><td><span class="tag risk">中</span></td><td>P5 第 0 步两边全备;低 TTL,出问题 A 记录改回 EC2 + 拿备份恢复</td></tr>
|
||||
<tr><td>autossh 隧道断 → 复制暂停</td><td><span class="tag risk">低</span></td><td>binlog 留 30 天,重连自动追上;挂延迟告警</td></tr>
|
||||
<tr><td>schema 变更版本在副本上 AutoMigrate 失败</td><td><span class="tag risk">低</span></td><td>双轨 EC2 先于 Ali,DDL 先复制到位</td></tr>
|
||||
</table>
|
||||
|
||||
<!-- ============ 5. 剩余小决策 ============ -->
|
||||
<h2>五、剩余小决策</h2>
|
||||
<table>
|
||||
<tr><th>#</th><th>决策点</th><th>推荐</th></tr>
|
||||
<tr><td>①</td><td>DNS 托管:留 Cloudflare / 搬阿里云 DNS</td><td>留 Cloudflare(记录已在此,改动最小)</td></tr>
|
||||
<tr><td>②</td><td>P5 切流时段</td><td>夜间低峰(写冻结仅几秒,影响极小)</td></tr>
|
||||
</table>
|
||||
|
||||
<hr style="border:0;border-top:1px solid var(--border);margin:28px 0 10px;">
|
||||
<div class="sub">文档:<span class="mono">/Users/wangjia/code/jiu/docs/runbooks/ec2-to-ali-migration.html</span> · 已登记 <span class="mono">docs/index.html</span></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,102 @@
|
||||
# 安全审计报告 — 2026-07-03
|
||||
|
||||
**审计范围**:后端 `backend/`(router / 全部 handler / middleware / service / config / model)与部署链路(`.gitea/workflows/*`、`scripts/ci/*`、`deploy/*`)。重点核查本会话新增的 `summaryBounds`/`rolling30`(出入库 KPI)、`finance.Trend`、库存/出入库搜索的 `EXISTS/IN` 子查询与 LIKE 拼接、`?window` 参数处理、新增路由鉴权、CI secrets 使用、`backup-db.sh` 密码处理、公开端点暴露面。
|
||||
|
||||
**发现问题**:Critical 1,High 2,Medium 3,Low 4
|
||||
|
||||
---
|
||||
|
||||
## Critical — 必须立即修复
|
||||
|
||||
### SEC-001: 关联对象(Partner / Warehouse)跨租户信息泄露
|
||||
**文件**:
|
||||
- `backend/internal/model/stock.go:26-27,80-81`、`backend/internal/model/finance.go:20`(关联定义只按 `foreignKey`,无 shop 作用域)
|
||||
- `backend/internal/handler/stock_in.go:208-212`(`Get` Preload Partner/Warehouse)
|
||||
- `backend/internal/handler/stock_out.go:142-144`(`Get` Preload Partner/Warehouse)
|
||||
- `backend/internal/handler/finance.go:70`(`ListRecords` Preload Partner)、`finance.go:232-245`(`Summary` `LEFT JOIN partners p ON p.id = f.partner_id`,无 `p.shop_id` 约束)
|
||||
- 写入侧不校验归属:`stock_in.go:220-268`(Create 直接透传 `req.PartnerID`/`req.WarehouseID`)、`stock_out.go:190-239`、`finance.go:81-127`(Create 透传 `partner_id`)
|
||||
|
||||
**描述**:下单/建财务记录接口接收请求体里的 `partner_id`、`warehouse_id`,**不校验这些 ID 是否属于当前门店**。读取时用 GORM `Preload("Partner")` / `Preload("Warehouse")`(或 finance Summary 的 `LEFT JOIN partners`)按外键直接回连,**没有再按 `shop_id` 二次过滤**。因此攻击者能引用其他门店的 `partner_id`/`warehouse_id`,读回时把对方数据带出来。
|
||||
|
||||
**攻击场景**:攻击者登录 A 店,POST 一张草稿入库单 `{"warehouse_id":1,"partner_id":<枚举 N>,...}`,随后 GET `/api/v1/stock-in/orders/:id`,响应中的 `partner` 对象会返回 B 店该往来单位的 `name / contact / phone / address / bank_account / credit_limit / balance`(见 `model/partner.go` 字段)。循环枚举 `partner_id` 即可导出全平台所有门店的客户/供应商联系人、电话、地址、银行账号——多租户隔离被彻底击穿,且泄露 PII。finance `ListRecords`/`Summary` 同理会带出他店往来单位名。
|
||||
|
||||
**修复建议**:
|
||||
1. 写入侧:Create/Update 时校验 `partner_id`、`warehouse_id` 归属当前 `shop_id`(`SELECT 1 FROM partners WHERE id=? AND shop_id=?`),不符则 400。
|
||||
2. 读取侧纵深防御:Preload 加租户条件,如 `Preload("Partner", "shop_id = ?", shopID)`、`Preload("Warehouse", "shop_id = ?", shopID)`;finance Summary/ListRecords 的 join/preload 同样补 `p.shop_id = f.shop_id`。
|
||||
3. 同类需一并修:`inventory.CreateCheck`(item.ProductID 未验归属)→ `GetCheck`/`CompleteCheck` 的 `Preload("Items.Product")` 会带出他店 product。
|
||||
|
||||
**验证方式**:用 A、B 两店 token;A 建单引用 B 的 partner_id,GET 单据确认 `partner` 为 null 或 400,而非返回 B 店数据。
|
||||
|
||||
---
|
||||
|
||||
## High — 本次发布前修复
|
||||
|
||||
### SEC-002: 默认 JWT / License 密钥随仓库提交,且 release 模式无校验
|
||||
**文件**:`backend/config/config.yaml:10,15`、`backend/main.go:24-28`
|
||||
**描述**:`config.yaml`(已进 git)内含 `jwt.secret: "change-this-to-a-random-secret-in-production"` 与 `license.hmac_secret: "change-this-license-secret-in-production"`。`main.go` 仅在 release 模式校验 `cors_origin != "*"`,**未校验 JWT secret 是否仍为默认值**。生产靠 `production.env` 的 `JWT_SECRET` 覆盖,但一旦漏配 env / 配置加载顺序异常,服务会以仓库里公开的默认密钥启动。
|
||||
**攻击场景**:攻击者用公开的默认 secret 自签任意 `{user_id, shop_id, role:"superadmin"}` 的 JWT(`middleware/auth.go:46-48` 只验签名),无 sid 的 token 走「存量放行」分支(`auth.go:56` 注释),直接以任意门店超管身份访问全部接口——完全绕过认证。
|
||||
**修复建议**:在 `main.go` release 前置检查里追加:`jwt.secret` 为空或等于默认占位串时 `log.Fatal`;同理校验 license hmac_secret。默认值不应是可用值。
|
||||
**验证方式**:release 模式下不设 `JWT_SECRET` 启动,应直接 fatal 退出。
|
||||
|
||||
### SEC-003: 运维 workflow 在命令行内联 DB 密码(`mysql -p${DB_PASSWORD}`)
|
||||
**文件**:`.gitea/workflows/reset-db.yml:38,45,60,64`、`.gitea/workflows/debug-db.yml:23-42`、`.gitea/workflows/seed.yml:44,59`
|
||||
**描述**:这三个 workflow 把 `${{ secrets.DB_PASSWORD }}` 以 `-p${DB_PASSWORD}` 形式内联进通过 SSH 下发到生产/容器执行的 `mysql`/`docker exec` 命令。`debug-db.yml` 用未加引号的 `<< EOF` heredoc,密码在 runner 本地展开后拼进远端命令串。风险:(a) 目标主机 `ps aux` 可见明文密码;(b) mysql 会打印 "password on the command line is insecure";(c) 若任一步骤开 `set -x` 或命令回显,CI 日志泄露密码。对比 `scripts/ci/backup-db.sh:33-34` 已用 `MYSQL_PWD` env 正确处理——说明团队知道正确姿势,只是这三个 workflow 没跟上。
|
||||
**修复建议**:改为 `docker exec -e MYSQL_PWD="$DB_PASSWORD" jiu_mysql mysql -uroot ...`,去掉 `-p`;heredoc 用单引号 `<< 'EOF'` 让密码只在远端环境变量里展开,不进命令行。
|
||||
**验证方式**:远端 `ps -ef | grep mysql` 执行期间看不到密码;CI 日志无密码串。
|
||||
|
||||
---
|
||||
|
||||
## Medium — 近期修复
|
||||
|
||||
### SEC-004: finance / 库存盘点写入未校验外键归属(SEC-001 写入侧的独立体现)
|
||||
**文件**:`backend/internal/handler/finance.go:81-127`、`backend/internal/handler/inventory.go:239-271`
|
||||
**描述**:即便按 SEC-001 修好读取侧 Preload,写入侧仍应独立校验:`finance.Create` 存任意 `partner_id`、`CreateCheck` 存任意 `product_id`,会在本店数据里留下指向他店实体的脏引用,破坏数据一致性与后续对账。
|
||||
**修复建议**:所有接收外键的写接口统一做「归属当前 shop」前置校验,抽成公共 helper。
|
||||
|
||||
### SEC-005: 公开错误上报端点可伪造身份字段、`error_msg` 无长度上限
|
||||
**文件**:`backend/internal/handler/error_report.go:19-72`、路由 `router.go:78`
|
||||
**描述**:`POST /api/v1/public/errors` 无需认证,`shop_id / username / role / shop_no` 全部取自请求体,攻击者可任意伪造,污染 superadmin 后台的错误列表(`admin/errors`)。`stack_trace` 截断到 4000,但 `error_msg` 未设上限,可提交超大 body 撑存储(仅 IP 限流 30/min 缓解)。
|
||||
**修复建议**:`error_msg` 加长度上限(如 2000);后台展示对这些「客户端自报字段」标注不可信;考虑对 `shop_id` 做存在性校验或改标为 `reported_shop_id`。
|
||||
|
||||
### SEC-006: 生产库密码经 `python3 re.search` 从 DSN 裸解析,DSN 特殊字符易误解析
|
||||
**文件**:`scripts/ci/backup-db.sh:33`
|
||||
**描述**:`re.match(r"[^:]+:([^@]+)@", d)` 从 DSN 提取密码,若密码含 `@` 或 `:` 会截断/错取,导致备份静默失败(虽有 100KB 体积兜底,但错误密码下 dump 会直接失败退出,属可用性风险而非泄露)。当前实现本身不泄露密码(走 `MYSQL_PWD`,正确)。
|
||||
**修复建议**:改为在远端 source `production.env` 后用 shell 参数解析,或约束 DB 密码字符集;此条为健壮性加固。
|
||||
|
||||
---
|
||||
|
||||
## Low — 备案,酌情处理
|
||||
|
||||
### SEC-007: 兑换码熵与取模偏置
|
||||
**文件**:`backend/internal/util/redeem_code.go:16-31`
|
||||
**描述**:兑换码 8 位 × 31 字母表 ≈ 40 bit;`int(b)%len(codeAlphabet)`(256 % 31 ≠ 0)引入轻微取模偏置,进一步压缩有效熵。`/license/activate` 需登录且受 per-shop 限流(20rps),在线爆破 40bit 不现实,风险低。
|
||||
**修复建议**:用 `rand.Int(rand.Reader, big.NewInt(len))` 消除偏置;如担心批量猜码可加每店激活失败限速。
|
||||
|
||||
### SEC-008: `product_option` / `product_attr` keyword 搜索 LIKE 通配未转义
|
||||
**文件**:`backend/internal/handler/product_option.go:31,97,163,231` 等
|
||||
**描述**:`"%"+kw+"%"` 参数化传入(无注入),但用户传入的 `%`/`_` 会被当通配符,可致模糊匹配范围异常(功能性,非安全边界)。同现象遍布各列表搜索。
|
||||
**修复建议**:如需精确前缀/包含语义,转义 `%`、`_`。
|
||||
|
||||
### SEC-009: CORS 允许头未含限流/凭证约束,`*` 仅靠 release 守卫
|
||||
**文件**:`backend/main.go:57-68`、`config.go:93`
|
||||
**描述**:默认 `cors_origin: "*"`,release 模式已 fatal 拦截 `*`(`main.go:25-27`),debug 模式放开属预期。当前无 `Allow-Credentials`,风险低。保持现状即可,备案。
|
||||
|
||||
### SEC-010: 公开商品接口暴露面
|
||||
**文件**:`backend/internal/handler/public.go`(`GetProduct`/`ListShopProducts`/`ProductPage`)、`version.go`、`/health`
|
||||
**描述**:`/health` 仅回 `{"status":"ok"}`,`/version` 与 `/public/release` 实时读 `version.yaml`(无敏感信息)。`public/shops/:shop_code/products` 按 shop_code 列出有库存商品(含 sale_price)——属商品公开展示的设计意图,已加最紧 IP 限流(`shop_list_per_min`)。`ProductPage` 注入的 OG 字段均经 `html.EscapeString`(`public.go:355,411-418`),无 XSS。暴露面可接受,备案。
|
||||
|
||||
---
|
||||
|
||||
## 通过检查项
|
||||
|
||||
- ✅ 本会话新增代码多租户隔离到位:`summaryBounds`/`rolling30`、`stockIn/Out.Summary`(`stock_in.go:191-200`/`stock_out.go:90-99`)、`finance.Trend`(`finance.go:198-205`)、`inventory.Summary`(`inventory.go:187-207`)所有聚合均带 `shop_id = ?`。
|
||||
- ✅ 库存/出入库搜索的 `EXISTS/IN` 子查询含 `it.shop_id = ?`(`stock_in.go:63-68,139-144`、`stock_out.go:59-65`、`inventory.go:115-121`);`itemsTable` 为硬编码常量非用户输入(`stock_in.go:87` 注释确认),`series/spec` 多值用 `strings.Repeat("?,")` 生成占位符后参数化,无拼接注入。
|
||||
- ✅ 所有 LIKE/keyword 均走 GORM `?` 参数化,未见字符串拼接进 SQL。
|
||||
- ✅ `?window` 参数只用 `== "rolling30"` 相等判断,不参与 SQL(`stock_in.go:173`);`months` 经 `strconv.Atoi` + `1..24` 范围校验(`finance.go:186`)。
|
||||
- ✅ 新增路由 `/finance/trend`(`router.go:216`)在 `api.Use(JWT)` + `ReadOnly` + `LicenseGuard` 组内,为 GET 只读;所有写操作路由都在 `ReadOnly()` 之后;`/users` 挂 `AdminOnly`、`/admin/*` 挂 `SuperAdminOnly`。
|
||||
- ✅ 密码 bcrypt 哈希(`service/auth.go:443,496`),`PasswordHash` 标 `json:"-"`(`model/user.go:9`)不外泄。
|
||||
- ✅ JWT 会话校验支持踢人/禁用即时失效(`middleware/auth.go:56-80`),登录按账号+IP 双重失败锁定、多档 IP/店限流。
|
||||
- ✅ 库存扣减/单号生成用事务 + `FOR UPDATE` 行锁(`inventory.go:348`、`service/stock.go` GenerateOrderNo);`admin.ClearData` 用表名白名单 + `shop_id` 过滤(`admin.go:30-51`)。
|
||||
- ✅ CI secrets 通过 `${{ secrets.* }}` 注入 env,未见 `echo`/`set -x` 打印密钥;`setup_ssh` 私钥写盘后 `teardown_ssh`/`if: always()` 清理(`lib-forgejo.sh:128-130`、各 workflow cleanup 步骤)。`backup-db.sh` 用 `MYSQL_PWD` env 传密码(正确)。
|
||||
- ✅ `SetTrustedProxies(127.0.0.1/::1)` + `RemoteIPHeaders=X-Real-IP`,客户端无法伪造限流/审计所依赖的真实 IP(`main.go:54-55`)。
|
||||
- ✅ 图片上传校验:解码校验真实格式、限 1MB、限每商品 5 张、UUID 文件名、按 productID 归档(`product_image.go:49-96`)。
|
||||
@@ -0,0 +1,90 @@
|
||||
# 安全审计报告(发版前增量) — 2026-07-03
|
||||
|
||||
**审计范围**:分支 `worktree-front-refactor` 的全部未提交改动(`git diff HEAD` + 未跟踪文件),聚焦**本日首轮审计(`docs/security/2026-07-03-audit.md`,Critical/High 已修复)之后**的新增/变更部分:
|
||||
|
||||
1. `client/lib/screens/auth/`(登录/注册屏全新重写)+ `client/lib/core/storage/login_history.dart`(记住我)+ `client/lib/repositories/auth_repository.dart`
|
||||
2. `deploy/nginx-jiu-ali.conf`(443 TLS 回切 + 80→443 跳转,8443 拆除)
|
||||
3. `scripts/ci/*` + `.gitea/workflows/*`(EC2→Ali URL/secret 回切)
|
||||
4. 三端明文豁免(ATS / usesCleartextTraffic)还原核查
|
||||
5. `backend/` 改动回归扫描(新增 `handler/ownership.go`、多租户 Preload/写入侧校验、`main.go` SEC-002 修复)
|
||||
|
||||
**发现问题**:Critical 0,High 0,Medium 2,Low 4
|
||||
|
||||
**总体结论**:首轮审计的 Critical(SEC-001 跨租户泄露)与 High(SEC-002 默认密钥、SEC-003 CI 内联 DB 密码)在本轮改动中**均已闭环修复且实现正确**。新增的登录/注册屏、nginx 回切、CI 回切**未引入新的 Critical/High**。剩余为纵深加固项(HSTS、盘点写入侧归属校验、商品字典外键归属),可发版后处理。
|
||||
|
||||
---
|
||||
|
||||
## Critical — 必须立即修复
|
||||
|
||||
无。
|
||||
|
||||
---
|
||||
|
||||
## High — 本次发布前修复
|
||||
|
||||
无。
|
||||
|
||||
---
|
||||
|
||||
## Medium — 近期修复
|
||||
|
||||
### SEC-P01: 盘点建单(CreateCheck)写入侧未校验 product_id / warehouse_id 归属
|
||||
**文件**:`backend/internal/handler/inventory.go:239-273`(`CreateCheck`,无 `ensureShopRef`)、`inventory.go:307-345`(`CompleteCheck` 盘盈按 `item.ProductID` 建 `Inventory` 行)
|
||||
**描述**:本轮为 stock-in / stock-out / finance 的写接口补齐了 `ensureShopRef`/`ensureShopRefOpt` 外键归属校验(`ownership.go`),但**盘点建单 `CreateCheck` 漏了同款校验**——`req.Items[i].ProductID` 与 `req.WarehouseID` 直接透传入库。首轮审计 SEC-001 修复说明第 3 条已点名此处待修,读取侧 `Preload("Items.Product", "shop_id = ?", shopID)` 现已补上(跨店 product 读不出来),但写入侧仍缺。
|
||||
**攻击/影响场景**:攻击者登录 A 店,`POST /api/v1/inventory/checks` 提交 `items:[{product_id:<B 店的 id>}]`;随后 `CompleteCheck` 走盘盈分支会在 **A 店 inventory 表**新建一行 `product_id=B店id` 的库存记录(`inventory.go:331-343`),snapshot 列因 `item.Product` 被 shop 作用域 Preload 置 nil 而为空。结果:不是直接跨租户读取(读侧已挡),而是**在本店数据里留下指向他店 product 的脏引用**,破坏库存一致性与后续对账/显示兜底。盘亏分支 FIFO 扣减带 `shop_id AND product_id` 双条件,跨店 id 匹配不到批次,无副作用。
|
||||
**修复建议**:在 `CreateCheck` 复用 `ensureShopRef(h.db, "warehouses", req.WarehouseID, shopID)` 与逐条 `ensureShopRef(h.db, "products", item.ProductID, shopID)`,不符即 400。与 stock-in/out 保持同一道防线。
|
||||
**验证方式**:A 店 token 提交引用 B 店 product_id 的盘点单,应 400 拒绝,而非建单成功。
|
||||
|
||||
### SEC-P02: nginx 443 回切后缺失 HSTS,且 TLS/安全响应头未加固
|
||||
**文件**:`deploy/nginx-jiu-ali.conf:15-23`(server 块无 `Strict-Transport-Security` / `ssl_prefer_server_ciphers` / `X-Frame-Options` / `X-Content-Type-Options`)
|
||||
**描述**:8443 明文过渡口刚拆除、回切 443 TLS(`ssl_protocols TLSv1.2 TLSv1.3` 正确,已排除 TLSv1.0/1.1),并新增 80→443 跳转(`:107-112`)。但:
|
||||
- **无 HSTS**:首次通过 80 访问的用户在被 301 跳转前存在一次明文窗口,可被 SSL-strip 中间人拦截(尤其刚从明文 8443 时代迁移、部分设备可能仍缓存 http 直连习惯)。
|
||||
- `ssl_ciphers HIGH:!aNULL:!MD5` 较宽松,未配 `ssl_prefer_server_ciphers on`,未启用 OCSP stapling / `ssl_session_cache`,仍允许部分 TLSv1.2 CBC 套件。
|
||||
- 无 `X-Content-Type-Options: nosniff` / `X-Frame-Options`(`/app/` 管理端 + 营销站 `location /` 都由此块服务,存在点击劫持/嗅探面)。
|
||||
**影响**:非直接可利用漏洞,属传输层与浏览器侧纵深加固缺口;在「刚结束明文过渡」的时点尤其值得补 HSTS。
|
||||
**修复建议**:443 server 块加 `add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;`(确认所有 51yanmei 子域都已上 HTTPS 后再考虑 `preload`);补 `ssl_prefer_server_ciphers on;` + 收敛 cipher 列表(Mozilla intermediate);对 `/app/` 与 `location /` 补 `X-Content-Type-Options nosniff`、`X-Frame-Options SAMEORIGIN`。
|
||||
**验证方式**:`curl -sI https://jiu.51yanmei.com/ | grep -i strict-transport`;SSL Labs 评级 A 以上。
|
||||
|
||||
---
|
||||
|
||||
## Low — 备案,酌情处理
|
||||
|
||||
### SEC-P03: 商品字典外键(origin/shelf_life/storage/category/description_doc)无归属校验,读侧 Preload 未按 shop_id 作用域
|
||||
**文件**:`backend/internal/handler/product.go:193-206`(Update 透传 `category_id/origin_id/shelf_life_id/storage_id/description_doc_id`,无 `ensureShopRef`)、`product.go:224-225`(Detail `Preload("Category").Preload("Origin").Preload("ShelfLife").Preload("Storage")` 无 `shop_id` 作用域)、`public.go:40-44,335`(公开页同样无 shop 作用域 Preload)
|
||||
**描述**:`ownership.go` 的归属校验模式本轮只覆盖了 partner/warehouse/product,**未延伸到商品字典类外键**。用户可把自家 product 的 `origin_id` 等设成他店字典项 id,Detail/公开页会按外键回连读出他店字典的 `Name/Remark`(这些表 = `TenantBase` 门店级)。注意 `product.go` 本轮未改动,属存量残余;且泄露内容为低敏感字典文本(如「酱香型白酒」「阴凉避光保存」),非 PII。
|
||||
**修复建议**:product Create/Update 对上述 5 个外键复用 `ensureShopRefOpt`(对应表 `product_origin_options` / `product_shelf_life_options` / `product_storage_options` / `product_categories` / `product_description_docs`);Detail/public 的 Preload 补 `"shop_id = ?", shopID`(公开页用 product 自身 shop_id)。抽成与 SEC-001 同源的统一收口。
|
||||
**验证方式**:A 店 product 设 B 店 origin_id,GET detail 应返回 origin=null 或建单时 400。
|
||||
|
||||
### SEC-P04: 「记住我」默认开启,门店编号+登录账号明文留在设备 SharedPreferences
|
||||
**文件**:`client/lib/core/storage/login_history.dart:15,34-47`(`getRemember` 默认 `true`;`record` 存 hotel code + username 到 `SharedPreferences`)、`login_screen.dart:52,124-139`
|
||||
**描述**:`_remember` 默认 `true`,登录成功后把门店编号与登录账号(各最多 5 条)明文写入 `SharedPreferences`,下拉历史展示给下一位使用者。**已正确规避:密码从不落盘/不入历史**(仅内存 `TextEditingController`,`dispose` 释放;无任何 password 日志)——这是本项的关键安全边界,已达标。残余点是共享设备上门店编号/账号可被他人枚举,属账号名泄露(非凭证泄露),且是「记住我」标准取舍。
|
||||
**修复建议**:可接受现状。如需更严:共享/多用户场景下默认 `false`,或提供「清除登录历史」入口。
|
||||
**验证方式**:登录后检查 `SharedPreferences`,确认 `login_history_*` 只含 shop code / username,无 password 键。
|
||||
|
||||
### SEC-P05: 自助注册字段无长度上限,可提交超大 body
|
||||
**文件**:`backend/internal/service/auth.go:423-431`(`RegisterInput` 仅 `binding:"required"` + 密码 `min=6`,各字段无 `max`)、`handler/auth.go:76-90`
|
||||
**描述**:`/api/v1/public/register` 无需认证,`shop_name/address/manager_name/phone/description` 均无长度上限,可提交超大字符串撑存储/日志。已由 per-IP 限流缓解(`register_per_min=5`,`router.go:79`),且创建时套事务;单次滥用成本有限。同类现象亦见于注册可无限建试用门店(业务滥用,非安全漏洞,限流已缓解)。
|
||||
**修复建议**:各字段加 `max`(如 name ≤100、address ≤255、phone ≤20、description ≤500);phone 加格式校验。
|
||||
**验证方式**:提交 100KB 的 shop_name,应 400 而非入库。
|
||||
|
||||
### SEC-P06: 443 `default_server` + `server_name "... _"` 使裸 IP/任意 Host 均命中 jiu 块
|
||||
**文件**:`deploy/nginx-jiu-ali.conf:17-18`
|
||||
**描述**:`listen 443 ssl http2 default_server;` 且 `server_name jiu.51yanmei.com _;`,意味着任意 Host 头(含 `https://182.92.213.171` 裸 IP)都会命中该块并用 jiu 证书应答(证书 CN 不匹配裸 IP,浏览器告警,但 API/静态仍可达)。这是 default_server 的预期行为、也是「存量客户端域名 BASE_URL 回切即恢复」所需,暴露面与回切前一致,无新增可利用点。
|
||||
**修复建议**:可接受。如需收紧,可为裸 IP/未知 Host 单设一个 `return 444` 的默认块,仅 jiu 域名走业务块。
|
||||
**验证方式**:`curl -k -H 'Host: x' https://<ip>/health` 行为符合预期即可。
|
||||
|
||||
---
|
||||
|
||||
## 通过检查项(本轮重点复核)
|
||||
|
||||
- ✅ **SEC-001 跨租户泄露闭环**:新增 `backend/internal/handler/ownership.go`(`ensureShopRef`/`ensureShopRefOpt`,table 为调用点硬编码常量、非用户输入)。写入侧已挂:`stock_in.go:235-240,301-306`(Create/Update warehouse+partner)、`stock_out.go:206-211,273-278`、`finance.go:97`(Create partner)。读取侧 Preload 全部补 `"shop_id = ?", shopID`:`stock_in.go:133-136,209-211`、`stock_out.go:145-149,271-273`、`finance.go:19`(ListRecords)、`finance.go:244`(Summary `LEFT JOIN partners ... AND p.shop_id = f.shop_id`)、`inventory.go:233-234,278,293`(Logs/GetCheck/CompleteCheck)。partner/warehouse 双向防线完整。
|
||||
- ✅ **SEC-002 默认 JWT 密钥**:`main.go:28-33` release 模式新增前置校验,`jwt.secret` 为空或等于仓库默认占位串即 `log.Fatal`,杜绝带公开密钥上线。
|
||||
- ✅ **SEC-003 CI 内联 DB 密码**:`debug-db.yml:28-40` / `reset-db.yml:31,59-64` / `seed.yml:43,58` 已全部改为 `docker exec jiu_mysql sh -c 'exec mysql -uroot -p\$MYSQL_ROOT_PASSWORD ...'`——密码从**容器内环境变量**读取,不再以 `-p${DB_PASSWORD}` 出现在下发到远端的命令行,且从 workflow 移除了 `DB_PASSWORD` secret 依赖。远端 `ps` 与 CI 日志均不再暴露密码。`backup-db.sh:31-33` 仍走 `MYSQL_PWD` env(正确)。
|
||||
- ✅ **CI/workflow 回切无 secret 泄漏**:EC2→Ali 改用 `ALI_SSH_KEY/ALI_HOST/ALI_USER`(`backup.yml`/`reset-db.yml`/`seed.yml`/`debug-db.yml`/`manual.yml`),经 `${{ secrets.* }}` 注入 env,无 echo/`set -x` 打印。`manual.yml:31-40` 将旧 `EC2_*` 同值指向 Ali(回滚旧 tag 时不复活 EC2),`setup_ssh` 私钥写盘后 `teardown_ssh`/cleanup 清理。`notify.sh`/`release-client.sh`/`deploy-server.sh`/`local_test.sh` 仅注释/URL 说明变更,全部 `https://jiu.51yanmei.com`,无明文残留。
|
||||
- ✅ **三端明文豁免已还原且无残留**:`git diff HEAD` 对 `client/android/app/src/main/AndroidManifest.xml`、`client/ios/Runner/Info.plist` 无改动;全仓 grep `usesCleartextTraffic`/`cleartext`/`network_security_config`/`NSAllowsArbitraryLoads`/`NSExceptionDomains` 于 `client/android`、`client/ios`、`client/macos` 均**零命中**。前端 `AppConfig` 基址走 `https://` 域名,回切后自动恢复加密传输。
|
||||
- ✅ **nginx 回切暴露面收敛**:8443 明文口拆除(减少一个明文入口);443 `ssl_protocols TLSv1.2 TLSv1.3`(已排除弱协议);未鉴权 `(public|auth)/`、`/product/`、`/app/product/` 均挂 `limit_req zone=jiu_pub`;`X-Real-IP $remote_addr` 透传供后端限流/审计取真实 IP。
|
||||
- ✅ **登录/注册屏无凭证泄露**:密码仅存内存 `TextEditingController`,`dispose` 释放;`login_history.dart` 只存门店编号+账号,**不存密码**;`api_client.dart:135-139` 的 5xx 上报只发 `[method] path → status`,**不含请求体**(登录失败为 401 不触发上报,即便 5xx 也不带 password);注册成功弹窗仅回显门店编号,无敏感信息。
|
||||
- ✅ **shop_id 全程取自 JWT**:登录/注册屏及后端改动无从请求参数读取 `shop_id` 的路径;所有查询经 `middleware.GetShopID(c)`。
|
||||
- ✅ **注册鉴权与限流**:`/public/register` 挂 `registerIP`(5/min/IP);`/auth/login` 挂 `loginIP`(10/min/IP);密码入库 bcrypt(`service/auth.go:443`)。
|
||||
- ✅ **会话失效提示链路**:`login_screen.dart:116-120,334-340` 首帧主动读 + `ref.listen` 双通道捕获 `sessionEndedMessageProvider`,被顶下线有弹窗;消息内容无敏感信息。
|
||||
- ✅ **model 改动为纯 gofmt 对齐**:`user_session.go`/`license_device.go`/`license.go` 等仅列对齐空白变更,无语义/字段/tag 改动,多租户索引与 `json:"-"`(`RefreshJTI`)保持不变。
|
||||
Reference in New Issue
Block a user