## 模型目标
- 为运营提供“发货统计”独立表，脱离业务在线查询复杂度，支持导出与审计。
- 字段覆盖：产品、价格、发货数量、用户收件信息、物流、订单聚合、盈亏、来源、垫付人、时间。

## 表结构（DDL）
```sql
CREATE TABLE IF NOT EXISTS ops_shipping_stats (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  shipped_at DATETIME NOT NULL COMMENT '发货时间',
  product_id BIGINT NULL,
  product_name VARCHAR(255) NOT NULL,
  product_price_cents BIGINT NOT NULL COMMENT '单位：分',
  shipped_qty BIGINT NOT NULL,
  user_id BIGINT NOT NULL,
  user_name VARCHAR(100) NOT NULL,
  user_address_text VARCHAR(512) NOT NULL,
  express_code VARCHAR(64) NULL,
  express_no VARCHAR(128) NULL,
  order_id BIGINT NULL,
  order_no VARCHAR(64) NULL,
  order_qty BIGINT NULL,
  order_amount_cents BIGINT NULL COMMENT '单位：分',
  profit_loss_cents BIGINT NULL COMMENT '单位：分',
  order_source_type INT NULL,
  order_source_text VARCHAR(32) NULL,
  payer VARCHAR(128) NULL COMMENT '垫付人，后续录入或从remark规范解析',
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  KEY idx_shipped_at(shipped_at),
  KEY idx_product(product_id),
  KEY idx_order(order_id),
  KEY idx_express(express_no)
) COMMENT='运营发货统计';
```

## 明细数据入库（INSERT…SELECT）
```sql
/* 参数：@start_date, @end_date */
INSERT INTO ops_shipping_stats (
  shipped_at, product_id, product_name, product_price_cents, shipped_qty,
  user_id, user_name, user_address_text, express_code, express_no,
  order_id, order_no, order_qty, order_amount_cents, profit_loss_cents,
  order_source_type, order_source_text, payer
)
SELECT
  sr.shipped_at,
  COALESCE(sr.product_id, oi.product_id)                                           AS product_id,
  COALESCE(oi.title, p.name)                                                       AS product_name,
  COALESCE(sr.price, oi.price, p.price)                                           AS product_price_cents,
  sr.quantity                                                                      AS shipped_qty,
  ua.user_id                                                                       AS user_id,
  ua.name                                                                          AS user_name,
  CONCAT(ua.province, ua.city, ua.district, ua.address)                            AS user_address_text,
  sr.express_code,
  sr.express_no,
  o.id                                                                             AS order_id,
  o.order_no                                                                       AS order_no,
  os.total_qty                                                                     AS order_qty,
  o.actual_amount                                                                  AS order_amount_cents,
  /* 盈亏：行价格×发货数量 − 订单实付金额（可根据口径调整） */
  COALESCE(sr.price, oi.price, p.price) * sr.quantity - o.actual_amount            AS profit_loss_cents,
  o.source_type                                                                    AS order_source_type,
  CASE o.source_type WHEN 1 THEN '商城直购' WHEN 2 THEN '抽奖票据' WHEN 3 THEN '其他' ELSE CONCAT('未知-', o.source_type) END AS order_source_text,
  /* 垫付人：暂为空，后续从 remark 或新增字段填充 */
  NULL                                                                             AS payer
FROM shipping_records sr
LEFT JOIN order_items oi ON oi.id = sr.order_item_id
LEFT JOIN products p     ON p.id = COALESCE(sr.product_id, oi.product_id)
LEFT JOIN orders o       ON o.id = sr.order_id
LEFT JOIN (
  SELECT order_id, SUM(quantity) AS total_qty
  FROM order_items
  GROUP BY order_id
) os ON os.order_id = o.id
LEFT JOIN user_addresses ua ON ua.id = COALESCE(sr.address_id, o.user_address_id)
WHERE sr.status IN (2,3) /* 已发货/已签收 */
  AND sr.shipped_at BETWEEN @start_date AND @end_date;
```

## 查询（导出）
```sql
/* 查询明细（元） */
SELECT
  product_name,
  ROUND(product_price_cents/100, 2) AS product_price_yuan,
  shipped_qty,
  user_name,
  user_address_text,
  express_code,
  express_no,
  order_no,
  order_qty,
  ROUND(order_amount_cents/100, 2)  AS order_amount_yuan,
  ROUND(profit_loss_cents/100, 2)   AS profit_loss_yuan,
  order_source_text,
  payer,
  shipped_at
FROM ops_shipping_stats
WHERE shipped_at BETWEEN @start_date AND @end_date
ORDER BY shipped_at DESC;
```

## 口径与可调整项
- 盈亏口径：当前为“行价格×发货数量 − 订单实付金额”；如需改为“订单行应付总额（`oi.total_amount`） − 订单实付金额”，可替换。
- 下单数量：当前为订单维度总件数（聚合）；如需改为行数量，改用 `oi.quantity`。
- 垫付人：建议在 `shipping_records` 增加 `payer` 字段或在 `remark` 规范写入 `payer:xxx`，入库时解析填充。

## 后续实现建议
- 管理后台增加导出按钮，直接查询 `ops_shipping_stats` 并输出 CSV/Excel。
- 每日定时任务或发货事件触发增量写入，保证统计表实时/准实时更新。