# 自营网店买家前台 API

所有接口通过 `/api/index.php?r={route}` 访问，除支付回调外均需 `Authorization: Bearer {会员令牌}`。

- 卖家：`seller` 参数或当前登录用户 ID；不传时默认当前登录用户
- 买家：始终为当前登录会员
- 金额、库存、优惠券与运费全部由服务端重算，前端传参仅用于选择商品与数量
- 错误统一返回 `{"ok":false,"error":"中文提示"}`，HTTP 状态码对应 400 / 401 / 404 / 409 / 500

## 一、店铺与商品

| 方法 | 路由 | 参数 | 返回 |
| --- | --- | --- | --- |
| GET | `store/home` | `seller` | `shop`、`slides`、`categories`、`hot`、`new` |
| GET | `store/categories` | `seller` | `items` |
| GET | `store/products` | `seller`、`category_id`、`q`、`sort`（`sales` / `price_asc` / `price_desc`）、`page`、`limit` | `items`、`total`、`page`、`pages`、`categories` |
| GET | `store/product` | `seller`、`id` | `product`（不含 `virtual_content`）、`images`、`skus` |

## 二、购物车

| 方法 | 路由 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `store/cart` | `seller` | 当前买家购物车 |
| POST | `store/cart` | `seller`、`product_id`、`sku_id`、`qty` | 同商品同规格累加数量，超出库存返回 409 |
| PUT | `store/cart/{id}` | `qty` | 修改数量 |
| DELETE | `store/cart/{id}` | — | 删除一项 |
| POST | `store/cart/clear` | — | 清空购物车 |

## 三、地址与优惠券

| 方法 | 路由 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `store/addresses` | `seller` | 地址簿，默认地址优先 |
| POST | `store/addresses` | `name`、`phone`、`province`、`city`、`district`、`detail`、`is_default` | 新增；首个地址自动设为默认 |
| PUT | `store/addresses/{id}` | 同上 | 编辑；设为默认时清除其他默认 |
| DELETE | `store/addresses/{id}` | — | 删除 |
| GET | `store/coupons` | `seller` | 当前买家可用优惠券（含使用次数限制） |

## 四、报价与下单

### `POST store/quote`

请求：

```json
{
  "items": [{"product_id": 1, "sku_id": 0, "qty": 2}],
  "coupon_code": "NEW100"
}
```

不传 `items` 时按当前购物车报价。返回：

```json
{
  "ok": true,
  "items": [],
  "amount": 398,
  "discount": 100,
  "freight": 0,
  "pay_amount": 298,
  "coupon": {"id": 2, "code": "NEW100", "name": "新客礼遇 100 元券"},
  "promotion": null,
  "notes": ["优惠券「新客礼遇 100 元券」抵 100"],
  "all_virtual": false
}
```

### `POST store/order`

请求：

```json
{
  "items": [{"product_id": 1, "sku_id": 0, "qty": 2}],
  "address_id": 1,
  "coupon_code": "NEW100",
  "remark": "请尽快发货",
  "pay_method": "wechat"
}
```

- 实物订单必须有地址（`address_id` 或默认地址）；纯虚拟订单可不传
- 下单时扣减库存、写入订单项与「买家下单」时间轴
- 返回 201，`order` 结构见下文

## 五、买家订单

| 方法 | 路由 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `store/orders` | `status`（`all` / `unpaid` / `toship` / `shipped` / `completed`）、`page`、`limit` | 买家订单列表 |
| GET | `store/order` | `id` | 订单详情，含 `items`、`logistics`、`address` |
| POST | `store/order-cancel` | `id` | 仅 `pending` 可取消，回滚库存与优惠券 |
| POST | `store/order-confirm` | `id` | 仅 `shipped` 可确认收货 |
| GET | `store/logistics` | `order_id` | `order` + 物流时间轴 `items` |

订单详情字段：

```text
id, order_no, source_order_id, buyer_name, buyer_phone, buyer_address,
amount, freight, discount, pay_amount, status, pay_status,
payment_channel, paid_amount, tracking_no, shipping_company, coupon_code,
remark, created_at, paid_at, shipped_at, completed_at,
items[], logistics[], address{}
```

## 六、支付

| 方法 | 路由 | 参数 | 说明 |
| --- | --- | --- | --- |
| GET | `store/pay-channels` | `seller` | 微信 / 支付宝配置状态 |
| POST | `store/pay-create` | `order_id`、`channel`（`wechat` / `alipay`） | 微信返回 `qr_text`，支付宝返回 `pay_url` |
| GET | `store/pay-status` | `order_id` | 轮询支付结果，必要时服务端主动查单 |

未配置渠道时返回 400，例如「微信支付未启用或商户参数不完整」。首次下单后 30 分钟内重复发起支付会复用同一笔待支付流水。

## 七、卖家发货

| 方法 | 路由 | 参数 | 说明 |
| --- | --- | --- | --- |
| POST | `store/ship` | `id`、`shipping_company`、`tracking_no` | 仅订单归属卖家可发货；`paid` / `packed` → `shipped` |

## 八、支付回调（公开路由，无 auth）

| 方法 | 路由 | 说明 |
| --- | --- | --- |
| POST | `pay/store/wechat` | 微信 V3 回调，APIv3 Key 解密后以服务端查单为准 |
| POST | `pay/store/alipay` | 支付宝异步通知，RSA2 验签 |
| GET | `pay/store/alipay/return` | 支付宝同步跳回店铺前台 |

支付成功统一调用 `ShopStoreService::markPaid()`：

- 幂等更新 `pay_status`、`paid_amount`、`payment_channel`、`pay_trade_no`
- 写支付流水 `p_shop_payments`
- 全部商品为虚拟时自动 `completed` 并写发货内容
- 否则置 `paid`，等待卖家发货
