Files
PartsInquiry/doc/openapi.yaml
2025-09-27 22:57:59 +08:00

2923 lines
98 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

openapi: 3.0.3
info:
title: PartsInquiry API
version: 0.2.0
description: >-
所有接口定义集中于此文件。每个 path 在 summary/description 中标注实现状态。
2025-09-27新增管理端公告、VIP 管理接口说明;管理员登录接口尚未与前端集成,保持「❌ Partially Implemented」。
servers:
- url: /
paths:
/api/user/me:
get:
summary: 用户端-我的资料(✅ Fully Implemented
description: 返回当前登录用户的基础资料name/phone/email/avatarUrl。在使用默认用户调试模式时需携带 `X-User-Id`。
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id: { type: integer, format: int64 }
shopId: { type: integer, format: int64 }
phone: { type: string, nullable: true }
email: { type: string, nullable: true }
name: { type: string }
avatarUrl: { type: string, nullable: true }
put:
summary: 用户端-更新资料(✅ Fully Implemented
description: 支持修改 `name` 与 `avatarUrl`头像为URL保存后端校验域名、类型与大小。默认用户模式必须附带 `X-User-Id`。
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name: { type: string, nullable: true }
avatarUrl: { type: string, nullable: true }
responses: { '200': { description: 成功 } }
/api/user/me/password:
put:
summary: 用户端-修改密码(✅ Fully Implemented
description: 若当前已设置密码则需要提供 `oldPassword` 验证新密码至少6位。
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
oldPassword: { type: string, nullable: true }
newPassword: { type: string }
required: [newPassword]
responses: { '200': { description: 成功 } }
/api/user/me/phone:
put:
summary: 用户端-保存手机号(✅ Fully Implemented
description: 直接保存新的手机号,后端进行格式校验与唯一约束检查(不需要验证码)。当前在无 Token 的情况下需通过 `X-User-Id` 头完成身份传递。
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
phone: { type: string }
required: [phone]
responses: { '200': { description: 成功 } }
/api/barcode/scan:
post:
summary: 条码识别-任意码制(❌ Partially Implemented
description: 前端(小程序/安卓)尚未接入,后端代理接口已完成,将图片转发到 Python FastAPI 服务 `POST /api/barcode/scan` 识别条码。优先返回 EAN-13若无则返回任意码制如 CODE128/ITF/QRCODE 等)的第一个结果;同时返回 others 列表供前端兜底展示。
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
required: [file]
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
success: { type: boolean }
barcodeType: { type: string, nullable: true, description: '如 EAN13/CODE128/QRCODE 等' }
barcode: { type: string, nullable: true }
others:
type: array
items:
type: object
properties:
type: { type: string }
code: { type: string }
'400':
description: 识别失败或文件错误
/api/admin/auth/login:
post:
summary: 管理端-管理员登录(❌ Partially Implemented
description: 使用用户名或手机号+密码登录,成功返回 Bearer Token同时兼容旧方案 `X-Admin-Id` 头部。
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
username: { type: string, nullable: true }
phone: { type: string, nullable: true }
password: { type: string }
oneOf:
- required: [username, password]
- required: [phone, password]
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
token: { type: string }
expiresIn: { type: integer }
admin:
type: object
properties:
adminId: { type: integer, format: int64 }
username: { type: string }
phone: { type: string, nullable: true }
/api/admin/users:
get:
summary: 管理端-用户列表(✅ Fully Implemented
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
parameters:
- in: query
name: shopId
schema: { type: integer, format: int64 }
- in: query
name: kw
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
list:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
name: { type: string }
phone: { type: string }
role: { type: string }
status: { type: integer, enum: [0,1] }
isOwner: { type: boolean }
shopId: { type: integer, format: int64 }
shopName: { type: string }
/api/admin/users/{id}:
put:
summary: 管理端-更新用户(✅ Fully Implemented
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name: { type: string }
phone: { type: string }
role: { type: string }
status: { type: integer, enum: [0,1] }
isOwner: { type: boolean }
responses: { '200': { description: 成功 } }
/api/admin/users/{id}/blacklist:
put:
summary: 管理端-拉黑用户(✅ Fully Implemented
description: 将用户 `status` 置为 0被拉黑用户登录将返回"你已被管理员拉黑"。
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
responses: { '200': { description: 成功 } }
/api/admin/users/{id}/restore:
put:
summary: 管理端-解除拉黑(✅ Fully Implemented
description: 将用户 `status` 置为 1恢复正常登录。
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
responses: { '200': { description: 成功 } }
/api/admin/parts:
get:
summary: 管理端-用户配件列表(✅ Fully Implemented
description: 返回商品列表;支持 shopId/kw 分页查询。
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
parameters:
- in: query
name: shopId
schema: { type: integer, format: int64 }
- in: query
name: kw
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
list:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
userId: { type: integer, format: int64 }
shopId: { type: integer, format: int64 }
shopName: { type: string }
name: { type: string }
brand: { type: string }
model: { type: string }
spec: { type: string }
images:
type: array
items: { type: string, description: '图片URL可能为绝对或以 / 开头的相对路径' }
/api/admin/parts/{id}:
put:
summary: 管理端-更新配件(✅ Fully Implemented
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
brand: { type: string, nullable: true }
model: { type: string, nullable: true }
spec: { type: string, nullable: true }
images:
oneOf:
- type: array
items: { type: string, description: '图片URL' }
- type: string
description: '逗号分隔的图片URL兼容'
responses: { '200': { description: 成功 } }
/api/admin/parts/{id}/restore:
put:
summary: 管理端-配件恢复(✅ Fully Implemented
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
responses: { '200': { description: 成功 } }
/api/consults:
post:
summary: 用户端-创建咨询(✅ Fully Implemented
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
topic: { type: string }
message: { type: string }
required: [message]
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id: { type: integer, format: int64 }
get:
summary: 用户端-获取最近一次咨询(✅ Fully Implemented
description: 返回当前用户最近一次咨询及最新回复(如有)。
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id: { type: integer, format: int64 }
topic: { type: string }
message: { type: string }
status: { type: string, enum: [open, resolved, closed] }
createdAt: { type: string, format: date-time }
replied: { type: boolean }
latestReply: { type: string, nullable: true }
latestReplyAt: { type: string, format: date-time, nullable: true }
/api/consults/{id}:
get:
summary: 用户端-咨询详情(✅ Fully Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id: { type: integer, format: int64 }
shopId: { type: integer, format: int64 }
userId: { type: integer, format: int64 }
topic: { type: string }
message: { type: string }
status: { type: string }
createdAt: { type: string, format: date-time }
replies:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
userId: { type: integer, format: int64 }
content: { type: string }
createdAt: { type: string, format: date-time }
/api/consults/{id}/ack:
put:
summary: 用户端-确认已读回复并恢复为"咨询"(✅ Fully Implemented
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
updated: { type: integer }
/api/admin/consults:
get:
summary: 管理端-咨询列表(✅ Fully Implemented
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
parameters:
- in: query
name: shopId
schema: { type: integer, format: int64 }
- in: query
name: status
schema: { type: string, enum: [open, resolved, closed] }
- in: query
name: kw
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
list:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
userId: { type: integer, format: int64 }
shopId: { type: integer, format: int64 }
shopName: { type: string }
topic: { type: string }
message: { type: string }
status: { type: string }
createdAt: { type: string, format: date-time }
/api/admin/consults/{id}/reply:
post:
summary: 管理端-回复咨询(✅ Fully Implemented仅允许一次回复
description: 当该咨询已存在回复时返回 409。
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
content: { type: string }
required: [content]
responses:
'200': { description: 成功 }
'409': { description: 该咨询已被回复 }
/api/admin/consults/{id}/resolve:
put:
summary: 管理端-标记咨询已解决(✅ Fully Implemented
responses: { '200': { description: 成功 } }
/api/admin/consults/users/{userId}/history:
get:
summary: 管理端-查看用户历史咨询与回复(✅ Fully Implemented
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
parameters:
- in: path
name: userId
required: true
schema: { type: integer, format: int64 }
- in: query
name: shopId
schema: { type: integer, format: int64 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
list:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
topic: { type: string }
message: { type: string }
status: { type: string }
createdAt: { type: string, format: date-time }
replies:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
userId: { type: integer, format: int64 }
content: { type: string }
createdAt: { type: string, format: date-time }
/api/admin/notices:
get:
summary: 管理端-公告列表(✅ Fully Implemented
description: 返回公告列表,支持状态/关键字过滤。公告数据已在管理端页面 `/notice/list` 使用。
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
- in: query
name: status
schema: { type: string, enum: [draft, published, offline] }
- in: query
name: kw
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
list:
type: array
items:
$ref: '#/components/schemas/Notice'
post:
summary: 管理端-创建公告(✅ Fully Implemented
description: 新增公告。后台限制标题最长120字符内容500字符。
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title: { type: string }
content: { type: string }
tag: { type: string, nullable: true }
pinned: { type: boolean, nullable: true }
status: { type: string, enum: [draft, published, offline], nullable: true }
startsAt: { type: string, format: date-time, nullable: true }
endsAt: { type: string, format: date-time, nullable: true }
required: [title, content]
responses: { '200': { description: 成功 } }
/api/admin/notices/{id}:
put:
summary: 管理端-更新公告(❌ Partially Implemented
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title: { type: string, nullable: true }
content: { type: string, nullable: true }
tag: { type: string, nullable: true }
pinned: { type: boolean, nullable: true }
status: { type: string, enum: [draft, published, offline], nullable: true }
startsAt: { type: string, format: date-time, nullable: true }
endsAt: { type: string, format: date-time, nullable: true }
responses: { '200': { description: 成功 } }
/api/admin/notices/{id}/publish:
post:
summary: 管理端-发布公告(❌ Partially Implemented
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
responses: { '200': { description: 成功 } }
/api/admin/notices/{id}/offline:
post:
summary: 管理端-下线公告(❌ Partially Implemented
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
responses: { '200': { description: 成功 } }
/api/finance/categories:
get:
summary: 财务分类(✅ Fully Implemented
description: 返回其他收入/支出的分类。读取顺序finance_categories 表 → system_parameters → app.finance.* 默认配置前端已接入开单页分类chips。
parameters:
- in: header
name: X-Shop-Id
required: false
schema: { type: integer }
description: 店铺ID缺省 1
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
incomeCategories:
type: array
items:
type: object
properties:
key: { type: string }
label: { type: string }
expenseCategories:
type: array
items:
type: object
properties:
key: { type: string }
label: { type: string }
/api/dashboard/overview:
get:
summary: 首页概览(✅ Fully Implemented
description: 订单口径的今日销售额approved、近似本月毛利按当前进价近似与库存总量。支持 X-Shop-Id 或 X-User-Id优先从用户解析店铺。后端与前端均已接入。
parameters:
- in: header
name: X-Shop-Id
required: false
schema:
type: integer
description: 店铺ID缺省为 1
- in: header
name: X-User-Id
required: false
schema:
type: integer
description: 用户ID当未提供 X-Shop-Id 时将用其所属店铺进行统计
responses:
'200':
description: 成功
content:
application/json:
schema:
$ref: '#/components/schemas/DashboardOverview'
/api/notices:
get:
summary: 公告列表(✅ Fully Implemented
description: 返回全局公告列表(与租户无关)。后端与前端均已接入。
responses:
'200':
description: 成功
/api/vip/status:
get:
summary: 用户端-VIP状态查询❌ Partially Implemented
description: 返回当前用户的 VIP 有效状态与到期时间。判定规则status=1 && is_vip=1 && (expireAt 为空或 >= now)。
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
isVip: { type: boolean }
status: { type: integer, enum: [0,1] }
expireAt: { type: string, format: date-time, nullable: true }
price: { type: number, description: '当前平台统一会员单月价格,来自 vip_price' }
nonVipRetentionDays: { type: integer, description: '非VIP数据保留天数默认60' }
/api/vip/pay:
post:
summary: 用户端-一键开通VIP❌ Partially Implemented
description: 临时方案点击即视为支付成功。行为若非VIP或已过期则开通若在有效期内则从当前时间起顺延 durationDays。写入/更新 vip_users。
responses:
'200':
description: 成功
/api/normal-admin/apply:
post:
summary: 普通管理员-提交申请(❌ Partially Implemented
description: 需已登录用户X-User-Id默认要求 VIP 有效;根据配置可自动通过。
responses:
'200': { description: 成功 }
/api/admin/normal-admin/applications:
get:
summary: 平台-普通管理员申请列表(❌ Partially Implemented
description: 返回最后状态为 apply 且尚未被通过/驳回的申请。
parameters:
- in: query
name: kw
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
list: { type: array, items: { type: object } }
total: { type: integer }
/api/admin/normal-admin/applications/{userId}/approve:
post:
summary: 平台-审批通过普通管理员(❌ Partially Implemented
parameters:
- in: path
name: userId
required: true
schema: { type: integer, format: int64 }
responses:
'200': { description: 成功 }
/api/admin/normal-admin/applications/{userId}/reject:
post:
summary: 平台-驳回普通管理员申请(❌ Partially Implemented
parameters:
- in: path
name: userId
required: true
schema: { type: integer, format: int64 }
responses:
'200': { description: 成功 }
/api/admin/normal-admin/users/{userId}/revoke:
post:
summary: 平台-撤销普通管理员权限(❌ Partially Implemented
parameters:
- in: path
name: userId
required: true
schema: { type: integer, format: int64 }
responses:
'200': { description: 成功 }
/api/normal-admin/parts/submissions:
get:
summary: 普通管理端-配件提交列表(❌ Partially Implemented
description: 与平台管理端一致,但范围强制限定为当前用户所属店铺。
parameters:
- in: query
name: status
schema: { type: string, enum: [pending, approved, rejected] }
- in: query
name: kw
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
responses:
'200': { description: 成功 }
/api/normal-admin/parts/submissions/{id}:
get:
summary: 普通管理端-提交详情(❌ Partially Implemented
parameters: [ { in: path, name: id, required: true, schema: { type: integer, format: int64 } } ]
responses: { '200': { description: 成功 } }
put:
summary: 普通管理端-编辑提交内容(❌ Partially Implemented
requestBody:
required: true
content:
application/json:
schema:
type: object
responses: { '200': { description: 成功 } }
/api/normal-admin/parts/submissions/{id}/approve:
post:
summary: 普通管理端-审核通过(❌ Partially Implemented
responses: { '200': { description: 成功 } }
/api/normal-admin/parts/submissions/{id}/reject:
post:
summary: 普通管理端-审核驳回(❌ Partially Implemented
responses: { '200': { description: 成功 } }
content:
application/json:
schema:
type: object
properties:
isVip: { type: boolean }
status: { type: integer, enum: [0,1] }
expireAt: { type: string, format: date-time }
/api/vip/recharges:
get:
summary: 用户端-VIP支付记录✅ Fully Implemented
description: 返回当前用户的 VIP 充值记录,按时间倒序;读取 `X-User-Id`。
parameters:
- in: header
name: X-User-Id
required: true
schema: { type: integer, format: int64 }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
list:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
price: { type: number }
durationDays: { type: integer }
expireFrom: { type: string, format: date-time, nullable: true }
expireTo: { type: string, format: date-time }
channel: { type: string }
createdAt: { type: string, format: date-time }
/api/admin/vip/price:
get:
summary: 管理端-读取VIP价格✅ Fully Implemented
description: 平台统一价,读取 `vip_price` 表(仅一条记录)。管理端页面 `/vip/system` 使用。
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
price: { type: number }
put:
summary: 管理端-设置VIP价格❌ Partially Implemented
description: 覆盖写入 vip_price.price。
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
price: { type: number }
required: [price]
responses:
'200': { description: 成功 }
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Notice'
/api/metrics/overview:
get:
summary: 概览统计(❌ Partially Implemented
description: 返回今日/本月销售额、本月利润与库存商品数量。前端已接入,后端待实现。
responses:
'200':
description: 成功
content:
application/json:
schema:
$ref: '#/components/schemas/MetricsOverview'
/api/accounts:
get:
summary: 账户列表(❌ Partially Implemented
description: 返回启用账户列表;支持数组或 {list:[]} 两种返回格式以兼容前端。
parameters:
- in: query
name: kw
schema: { type: string }
- in: query
name: status
schema: { type: integer, enum: [0,1] }
description: 仅后台使用;前端默认不传即等同 status=1
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 50 }
responses:
'200':
description: 成功
content:
application/json:
schema:
oneOf:
- type: array
items:
$ref: '#/components/schemas/Account'
- type: object
properties:
list:
type: array
items:
$ref: '#/components/schemas/Account'
post:
summary: 新增账户(❌ Partially Implemented
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateAccountRequest'
responses:
'200': { description: 成功 }
/api/accounts/{id}:
put:
summary: 更新账户(❌ Partially Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateAccountRequest'
responses:
'200': { description: 成功 }
/api/accounts/{id}/ledger:
get:
summary: 账户流水(❌ Partially Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
- in: query
name: startDate
schema: { type: string, format: date }
- in: query
name: endDate
schema: { type: string, format: date }
- in: query
name: kw
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
opening: { type: number }
income: { type: number }
expense: { type: number }
ending: { type: number }
list:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
txTime: { type: string, format: date-time }
direction: { type: string, enum: [in, out] }
amount: { type: number }
src: { type: string, description: 'sale|purchase|other' }
category: { type: string, nullable: true }
remark: { type: string, nullable: true }
/api/suppliers:
get:
summary: 供应商搜索(✅ Fully Implemented
parameters:
- in: query
name: kw
schema:
type: string
- in: query
name: debtOnly
schema:
type: boolean
- in: query
name: page
schema:
type: integer
default: 1
- in: query
name: size
schema:
type: integer
default: 50
responses:
'200':
description: 成功
content:
application/json:
schema:
oneOf:
- type: array
items:
$ref: '#/components/schemas/Supplier'
- type: object
properties:
list:
type: array
items:
$ref: '#/components/schemas/Supplier'
post:
summary: 新建供应商(✅ Fully Implemented
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateSupplierRequest'
responses:
'200': { description: 成功 }
/api/suppliers/{id}:
get:
summary: 供应商详情(✅ Fully Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id: { type: integer, format: int64 }
name: { type: string }
contactName: { type: string, nullable: true }
mobile: { type: string, nullable: true }
phone: { type: string, nullable: true }
address: { type: string, nullable: true }
apOpening: { type: number }
apPayable: { type: number }
remark: { type: string, nullable: true }
put:
summary: 更新供应商(✅ Fully Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateSupplierRequest'
responses:
'200': { description: 成功 }
/api/other-transactions:
post:
summary: 新建其他收入/支出(✅ Fully Implemented
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateOtherTransactionRequest'
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id:
type: integer
format: int64
/api/products:
get:
summary: 商品搜索(✅ Fully Implemented
description: 支持 kw/page/size/categoryId返回 {list:[]} 以兼容前端。
parameters:
- in: query
name: kw
schema:
type: string
- in: query
name: page
schema:
type: integer
default: 1
- in: query
name: size
schema:
type: integer
default: 50
responses:
'200':
description: 成功
content:
application/json:
schema:
oneOf:
- type: array
items:
$ref: '#/components/schemas/Product'
- type: object
properties:
list:
type: array
items:
$ref: '#/components/schemas/Product'
post:
summary: 新建商品(✅ Fully Implemented
description: 保存商品、价格、库存与图片(当前图片统一占位图 URL
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateProductRequest'
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id:
type: integer
format: int64
/api/products/{id}:
get:
summary: 商品详情(✅ Fully Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer }
responses:
'200':
description: 成功
content:
application/json:
schema:
$ref: '#/components/schemas/ProductDetail'
put:
summary: 更新商品(✅ Fully Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer }
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateProductRequest'
responses:
'200':
description: 成功
/api/product-categories:
get:
summary: 类别列表(✅ Fully Implemented
description: 仅返回全局字典shop_id=0的类别列表。
responses:
'200':
description: 成功
content:
application/json:
schema:
oneOf:
- type: array
items: { $ref: '#/components/schemas/Category' }
- type: object
properties:
list:
type: array
items: { $ref: '#/components/schemas/Category' }
post:
summary: 新增类别(❌ Partially Implemented
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name: { type: string }
/api/product-categories/{id}:
put:
summary: 更新类别(❌ Partially Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer }
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name: { type: string }
delete:
summary: 删除类别(❌ Partially Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer }
responses: { '200': { description: 成功 } }
/api/product-units:
get:
summary: 单位列表(✅ Fully Implemented
description: 仅返回全局字典shop_id=0的单位列表。
responses:
'200':
description: 成功
content:
application/json:
schema:
oneOf:
- type: array
items: { $ref: '#/components/schemas/Unit' }
- type: object
properties:
list:
type: array
items: { $ref: '#/components/schemas/Unit' }
post:
summary: 新增单位(❌ Partially Implemented
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name: { type: string }
/api/product-units/{id}:
put:
summary: 更新单位(❌ Partially Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer }
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name: { type: string }
delete:
summary: 删除单位(❌ Partially Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer }
responses: { '200': { description: 成功 } }
/api/product-settings:
get:
summary: 货品设置读取(❌ Partially Implemented
responses:
'200':
description: 成功
content:
application/json:
schema:
$ref: '#/components/schemas/ProductSettings'
put:
summary: 货品设置保存(❌ Partially Implemented
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProductSettings'
responses: { '200': { description: 成功 } }
/api/customers:
get:
summary: 客户搜索(✅ Fully Implemented
description: 支持 kw/page/size/debtOnly返回 {list:[]},含动态计算的 receivable 字段。
parameters:
- in: query
name: kw
schema:
type: string
- in: query
name: debtOnly
schema:
type: boolean
- in: query
name: page
schema:
type: integer
default: 1
- in: query
name: size
schema:
type: integer
default: 50
responses:
'200':
description: 成功
content:
application/json:
schema:
oneOf:
- type: array
items:
$ref: '#/components/schemas/Customer'
- type: object
properties:
list:
type: array
items:
$ref: '#/components/schemas/Customer'
post:
summary: 新建客户(✅ Fully Implemented
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateCustomerRequest'
responses:
'200':
description: 成功
/api/orders:
post:
summary: 新建单据(✅ Fully Implemented
description: 销售/进货出入库与退货:保存即 approved后端重算金额并联动库存。
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateOrderRequest'
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id:
type: integer
format: int64
orderNo:
type: string
/api/orders:
get:
summary: 单据列表查询(✅ Fully Implemented
description: 支持按时间范围与关键字筛选;参数 biz=sale|purchasetype=out|in|return返回 {list:[]}。后端已返回驼峰字段与名称sale: customerNamepurchase: supplierName
parameters:
- in: query
name: biz
schema: { type: string }
- in: query
name: type
schema: { type: string }
- in: query
name: kw
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
- in: query
name: startDate
schema: { type: string, format: date }
- in: query
name: endDate
schema: { type: string, format: date }
/api/payments/{biz}:
post:
summary: 创建收款/付款(✅ Fully Implemented
description: biz=sale|purchase根据 payments 写入多条记录,可选挂单并累加订单已付金额。
parameters:
- in: path
name: biz
required: true
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/PaymentItem'
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
paymentIds:
type: array
items: { type: integer, format: int64 }
description: 收/付款创建。注意根据约束sale/purchase 收/付款必须绑定订单orderId 不可为空)。
parameters:
- in: query
name: kw
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
- in: query
name: startDate
schema: { type: string, format: date }
- in: query
name: endDate
schema: { type: string, format: date }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
list:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
orderNo: { type: string }
orderTime: { type: string, format: date-time }
amount: { type: number }
customerName: { type: string }
/api/purchase-orders:
get:
summary: 进货单列表查询(✅ Fully Implemented
parameters:
- in: query
name: kw
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
- in: query
name: startDate
schema: { type: string, format: date }
- in: query
name: endDate
schema: { type: string, format: date }
- in: query
name: status
schema:
type: string
enum: [draft, approved, void, returned]
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
list:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
orderNo: { type: string }
orderTime: { type: string, format: date-time }
amount: { type: number }
supplierName: { type: string }
/api/payments:
get:
summary: 收付款流水列表(✅ Fully Implemented
parameters:
- in: query
name: kw
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
- in: query
name: startDate
schema: { type: string, format: date }
- in: query
name: endDate
schema: { type: string, format: date }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
totalAmount: { type: number }
list:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
bizType: { type: string }
direction: { type: string }
orderTime: { type: string, format: date-time, description: '支付时间,原 payTime' }
amount: { type: number }
accountName: { type: string }
category: { type: string, nullable: true }
/api/inventories/logs:
get:
summary: 库存/盘点流水列表(✅ Fully Implemented
parameters:
- in: query
name: kw
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
- in: query
name: startDate
schema: { type: string, format: date }
- in: query
name: endDate
schema: { type: string, format: date }
- in: query
name: productId
schema: { type: integer, format: int64 }
- in: query
name: reason
schema: { type: string }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
totalAmount: { type: number }
list:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
txTime: { type: string, format: date-time }
amount: { type: number, description: '金额变化若无则0' }
remark: { type: string }
productId: { type: integer, format: int64 }
qtyDelta: { type: number }
amountDelta: { type: number, nullable: true }
/api/orders/{id}:
get:
summary: 销售单详情(✅ Fully Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id: { type: integer, format: int64 }
orderNo: { type: string }
orderTime: { type: string, format: date-time }
status: { type: string }
amount: { type: number }
paidAmount: { type: number }
customerId: { type: integer, format: int64, nullable: true }
customerName: { type: string, nullable: true }
remark: { type: string, nullable: true }
items:
type: array
items:
type: object
properties:
productId: { type: integer, format: int64 }
name: { type: string }
spec: { type: string }
quantity: { type: number }
unitPrice: { type: number }
discountRate: { type: number }
amount: { type: number }
payments:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
amount: { type: number }
payTime: { type: string, format: date-time }
accountId: { type: integer, format: int64 }
accountName: { type: string }
direction: { type: string }
/api/purchase-orders/{id}:
get:
summary: 进货单详情(✅ Fully Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id: { type: integer, format: int64 }
orderNo: { type: string }
orderTime: { type: string, format: date-time }
status: { type: string }
amount: { type: number }
paidAmount: { type: number }
supplierId: { type: integer, format: int64, nullable: true }
supplierName: { type: string, nullable: true }
remark: { type: string, nullable: true }
items:
type: array
items:
type: object
properties:
productId: { type: integer, format: int64 }
name: { type: string }
spec: { type: string }
quantity: { type: number }
unitPrice: { type: number }
amount: { type: number }
payments:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
amount: { type: number }
payTime: { type: string, format: date-time }
accountId: { type: integer, format: int64 }
accountName: { type: string }
direction: { type: string }
/api/attachments:
post:
summary: 上传附件(✅ Fully Implemented
description: 直传本地存储。后端校验大小与类型,计算内容哈希并存储于配置目录。返回可直接访问的 `url``/api/attachments/content/{sha256}`)。
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
ownerType:
type: string
ownerId:
type: string
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
url:
type: string
contentType:
type: string
contentLength:
type: integer
format: int64
/api/attachments/validate-url:
post:
summary: 校验图片URL✅ Fully Implemented
description: 提交外部图片URL后端进行白名单、SSR防护、类型与大小校验返回标准化后的可用URL和元信息。支持 `application/json` 与 `application/x-www-form-urlencoded`。
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
url: { type: string }
required: [url]
application/x-www-form-urlencoded:
schema:
type: object
properties:
url: { type: string }
required: [url]
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
url: { type: string }
contentType: { type: string }
contentLength: { type: integer, format: int64, nullable: true }
/api/attachments/placeholder:
get:
summary: 附件占位图读取(✅ Fully Implemented
/api/attachments/content/{sha256}:
get:
summary: 读取附件内容(✅ Fully Implemented
parameters:
- in: path
name: sha256
required: true
schema: { type: string }
responses:
'200':
description: 图片二进制
content:
image/*:
schema:
type: string
format: binary
description: 返回后端配置的本地占位图内容,路径由 `attachments.placeholder.image-path` 指定。
responses:
'200':
description: 图片二进制
content:
image/png:
schema:
type: string
format: binary
/api/auth/register:
post:
summary: 手机号注册创建店铺与店主(✅ Fully Implemented
description: |
直接提交手机号进行注册若手机号尚不存在则创建店铺与店主用户owner`users.is_owner=1`),并初始化默认账户(现金/银行存款/微信)。
若手机号已存在,则直接签发 JWT 并返回用户/店铺信息。
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
phone: { type: string }
name: { type: string, nullable: true }
password: { type: string, nullable: true, description: '预留字段,当前不校验' }
required: [phone]
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
token: { type: string }
expiresIn: { type: integer }
user:
type: object
properties:
userId: { type: integer }
shopId: { type: integer }
phone: { type: string }
/api/auth/email/send:
post:
summary: 邮箱验证码发送(✅ Fully Implemented
description: 后端已实现 SMTP 发信并写入 email_codes。scene 支持 login/register/reset。
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
email: { type: string }
scene: { type: string, nullable: true, default: login }
required: [email]
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
ok: { type: boolean }
cooldownSec: { type: integer }
/api/auth/sms/login:
post:
summary: 短信验证码登录/注册(❌ Partially Implemented
description: 校验通过后若手机号不存在则自动创建店铺与店主用户owner并签发 JWT包含 phone 声明)。
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
phone: { type: string }
code: { type: string }
name: { type: string, nullable: true, description: '展示名:若提供则保存到 users.name否则按手机号脱敏生成' }
required: [phone, code]
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
token: { type: string }
expiresIn: { type: integer }
user:
type: object
properties:
userId: { type: integer }
shopId: { type: integer }
phone: { type: string }
/api/auth/email/login:
post:
summary: 邮箱验证码登录(✅ Fully Implemented
/api/auth/email/register:
post:
summary: 邮箱注册(设置密码,需验证码)(✅ Fully Implemented
description: 使用邮箱+验证码注册并设置密码;若邮箱已存在则更新密码。
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
email: { type: string }
code: { type: string }
name: { type: string, nullable: true }
password: { type: string }
required: [email, code, password]
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
token: { type: string }
expiresIn: { type: integer }
user:
type: object
properties:
userId: { type: integer }
shopId: { type: integer }
email: { type: string }
description: 校验通过后若邮箱不存在则自动创建店铺与店主用户owner保存密码并签发 JWT。
/api/auth/email/reset-password:
post:
summary: 邮箱重置密码(✅ Fully Implemented
description: 使用邮箱验证码更新已存在用户的密码;验证码场景为 reset。
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
email: { type: string }
code: { type: string }
password: { type: string }
required: [email, code, password]
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
ok: { type: boolean }
/api/admin/vips:
get:
summary: 管理端-会员列表(✅ Fully Implemented
description: 返回店铺会员(或待启用)列表,基于 `vip_users` 表。管理端页面 `/vip/list` 已接入。
parameters:
- in: query
name: phone
schema: { type: string }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
list:
type: array
items:
$ref: '#/components/schemas/VipUser'
total: { type: integer }
post:
summary: 管理端-新增/申请会员(❌ Partially Implemented
description: 向 `vip_users` 插入一条记录,支持作为"申请"进入待启用状态。
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateVipUserRequest'
responses:
'200':
description: 成功
/api/admin/vips/{id}:
put:
summary: 管理端-更新会员(❌ Partially Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateVipUserRequest'
responses:
'200':
description: 成功
/api/admin/vips/{id}/approve:
post:
summary: [已移除]
description: 审核流程已取消;请改用 /api/vip/pay 一键开通与 /api/admin/vip/system 接口。
responses:
'410': { description: Gone }
/api/admin/vips/{id}/reject:
post:
summary: [已移除]
description: 审核流程已取消;请改用 /api/vip/pay 一键开通与 /api/admin/vip/system 接口。
responses:
'410': { description: Gone }
/api/admin/dicts/units:
post:
summary: 管理端-新增主单位(✅ Fully Implemented
description: 仅平台管理员可用;写入 `shop_id=0` 全局字典。
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name: { type: string }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id: { type: integer, format: int64 }
/api/admin/dicts/units/{id}:
put:
summary: 管理端-更新主单位(✅ Fully Implemented
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name: { type: string }
responses: { '200': { description: 成功 } }
delete:
summary: 管理端-删除主单位(✅ Fully Implemented
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
responses: { '200': { description: 成功 } }
/api/admin/dicts/categories:
post:
summary: 管理端-新增主类别(✅ Fully Implemented
description: 仅平台管理员可用;写入 `shop_id=0` 全局字典。
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name: { type: string }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id: { type: integer, format: int64 }
/api/admin/dicts/categories/{id}:
put:
summary: 管理端-更新主类别(✅ Fully Implemented
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name: { type: string }
responses: { '200': { description: 成功 } }
delete:
summary: 管理端-删除主类别(✅ Fully Implemented
parameters:
- in: header
name: X-Admin-Id
required: true
schema: { type: integer, format: int64 }
description: 管理员ID来自 admins 表)
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
responses: { '200': { description: 成功 } }
/api/report/sales:
get:
summary: 销售报表(✅ Fully Implemented
description: 按客户或按货品聚合销售额与成本,自动计算利润和利润率。后端已对接,前端待接入。
parameters:
- in: header
name: X-Shop-Id
required: false
schema: { type: integer, format: int64 }
description: 指定店铺ID缺省使用当前默认店铺
- in: query
name: dimension
required: false
schema:
type: string
enum: [customer, product]
description: 聚合维度,默认为 customer
- in: query
name: startDate
required: false
schema: { type: string, format: date }
description: 起始日期(含),格式 yyyy-MM-dd缺省不限制
- in: query
name: endDate
required: false
schema: { type: string, format: date }
description: 结束日期(含),格式 yyyy-MM-dd缺省不限制
responses:
'200':
description: 成功
content:
application/json:
schema:
$ref: '#/components/schemas/SalesReportResponse'
/api/products/submissions:
post:
summary: 用户端-提交配件(✅ Fully Implemented
description: 用户提交配件资料进入待审核列表;型号全局唯一(需标准化为大写并去除首尾空格)。
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
model: { type: string }
name: { type: string, nullable: true }
brand: { type: string, nullable: true }
spec: { type: string, nullable: true }
origin: { type: string, nullable: true }
barcode: { type: string, nullable: true }
unitId: { type: integer, format: int64, nullable: true }
categoryId: { type: integer, format: int64, nullable: true }
parameters: { type: object, additionalProperties: true, nullable: true }
images:
type: array
items: { type: string }
remark: { type: string, nullable: true }
safeMin: { type: number, nullable: true }
safeMax: { type: number, nullable: true }
required: [model]
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id: { type: integer, format: int64 }
status: { type: string }
get:
summary: 用户端-提交记录列表(✅ Fully Implemented
parameters:
- in: query
name: status
schema: { type: string, enum: [pending, approved, rejected] }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
list:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
name: { type: string, nullable: true }
model: { type: string }
brand: { type: string, nullable: true }
status: { type: string }
createdAt: { type: string, format: date-time }
reviewedAt: { type: string, format: date-time, nullable: true }
total: { type: integer }
page: { type: integer }
size: { type: integer }
/api/products/submissions/{id}:
get:
summary: 用户端-提交详情(✅ Fully Implemented
description: 仅允许查询当前用户的提交记录。
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
id: { type: integer, format: int64 }
model: { type: string }
name: { type: string, nullable: true }
brand: { type: string, nullable: true }
spec: { type: string, nullable: true }
origin: { type: string, nullable: true }
barcode: { type: string, nullable: true }
unitId: { type: integer, format: int64, nullable: true }
categoryId: { type: integer, format: int64, nullable: true }
parameters: { type: object, additionalProperties: true, nullable: true }
images:
type: array
items: { type: string }
remark: { type: string, nullable: true }
safeMin: { type: number, nullable: true }
safeMax: { type: number, nullable: true }
status: { type: string }
reviewerId: { type: integer, format: int64, nullable: true }
reviewRemark: { type: string, nullable: true }
reviewedAt: { type: string, format: date-time, nullable: true }
createdAt: { type: string, format: date-time }
/api/admin/parts/submissions:
get:
summary: 管理端-配件提交列表(✅ Fully Implemented
description: 管理员按状态/关键字/时间筛选用户提交记录。
parameters:
- in: query
name: status
schema: { type: string, enum: [pending, approved, rejected] }
- in: query
name: kw
schema: { type: string }
- in: query
name: shopId
schema: { type: integer, format: int64 }
- in: query
name: reviewerId
schema: { type: integer, format: int64 }
- in: query
name: startAt
schema: { type: string, format: date-time }
- in: query
name: endAt
schema: { type: string, format: date-time }
- in: query
name: page
schema: { type: integer, default: 1 }
- in: query
name: size
schema: { type: integer, default: 20 }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
list:
type: array
items:
type: object
properties:
id: { type: integer, format: int64 }
model: { type: string }
name: { type: string, nullable: true }
brand: { type: string, nullable: true }
status: { type: string }
shopId: { type: integer, format: int64 }
createdAt: { type: string, format: date-time }
reviewedAt: { type: string, format: date-time, nullable: true }
total: { type: integer }
page: { type: integer }
size: { type: integer }
/api/admin/parts/submissions/{id}:
get:
summary: 管理端-提交详情(✅ Fully Implemented
parameters:
- in: path
name: id
required: true
schema: { type: integer, format: int64 }
responses:
'200':
description: 成功
put:
summary: 管理端-编辑提交内容(✅ Fully Implemented
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name: { type: string, nullable: true }
brand: { type: string, nullable: true }
spec: { type: string, nullable: true }
unitId: { type: integer, format: int64, nullable: true }
categoryId: { type: integer, format: int64, nullable: true }
parameters: { type: object, additionalProperties: true, nullable: true }
images:
type: array
items: { type: string }
remark: { type: string, nullable: true }
barcode: { type: string, nullable: true }
responses:
'200': { description: 成功 }
/api/admin/parts/submissions/{id}/approve:
post:
summary: 管理端-审核通过(✅ Fully Implemented
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
remark: { type: string, nullable: true }
assignGlobalSkuId: { type: integer, format: int64, nullable: true }
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
ok: { type: boolean }
productId: { type: integer, format: int64 }
globalSkuId: { type: integer, format: int64, nullable: true }
/api/admin/parts/submissions/{id}/reject:
post:
summary: 管理端-审核驳回(✅ Fully Implemented
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
remark: { type: string }
required: [remark]
responses:
'200': { description: 成功 }
/api/admin/parts/submissions/export:
get:
summary: 管理端-提交记录导出(✅ Fully Implemented
description: 按当前筛选条件导出 Excel限制 2000 条以内的同步导出。
parameters:
- in: query
name: status
schema: { type: string, enum: [pending, approved, rejected] }
- in: query
name: kw
schema: { type: string }
- in: query
name: shopId
schema: { type: integer, format: int64 }
- in: query
name: reviewerId
schema: { type: integer, format: int64 }
- in: query
name: startAt
schema: { type: string, format: date-time }
- in: query
name: endAt
schema: { type: string, format: date-time }
responses:
'200':
description: 成功
content:
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:
schema:
type: string
format: binary
/api/admin/part-templates:
get:
summary: 管理端-模板列表(❌ Partially Implemented
responses: { '200': { description: 成功 } }
post:
summary: 管理端-创建模板(❌ Partially Implemented
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
categoryId: { type: integer, format: int64 }
name: { type: string }
modelRule: { type: string, nullable: true }
status: { type: integer, enum: [0,1], default: 1 }
params:
type: array
items:
type: object
properties:
fieldKey: { type: string }
fieldLabel: { type: string }
type: { type: string, enum: [string, number, boolean, enum, date] }
required: { type: boolean }
unit: { type: string, nullable: true }
enumOptions: { type: array, items: { type: string }, nullable: true }
searchable: { type: boolean }
dedupeParticipate: { type: boolean }
sortOrder: { type: integer }
responses: { '200': { description: 成功 } }
/api/admin/part-templates/{id}:
get:
summary: 管理端-模板详情(❌ Partially Implemented
parameters: [ { in: path, name: id, required: true, schema: { type: integer, format: int64 } } ]
responses: { '200': { description: 成功 } }
put:
summary: 管理端-更新模板(❌ Partially Implemented
parameters: [ { in: path, name: id, required: true, schema: { type: integer, format: int64 } } ]
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
categoryId: { type: integer, format: int64, nullable: true }
name: { type: string, nullable: true }
modelRule: { type: string, nullable: true }
status: { type: integer, enum: [0,1], nullable: true }
deleteAllRelatedProductsAndSubmissions: { type: boolean, default: true }
params:
type: array
items:
type: object
properties:
fieldKey: { type: string }
fieldLabel: { type: string }
type: { type: string, enum: [string, number, boolean, enum, date] }
required: { type: boolean }
unit: { type: string, nullable: true }
enumOptions: { type: array, items: { type: string }, nullable: true }
searchable: { type: boolean }
dedupeParticipate: { type: boolean }
sortOrder: { type: integer }
responses: { '200': { description: 成功 } }
/api/products/submissions/check-model:
post:
summary: 型号查重(❌ Partially Implemented
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
templateId: { type: integer, format: int64, nullable: true }
name: { type: string, nullable: true }
model: { type: string }
required: [model]
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
available: { type: boolean }
model: { type: string }
similarAcrossTemplates: { type: integer, description: '跨模板同名同型号的命中数量(提示用)' }
components:
schemas:
SalesReportItem:
type: object
properties:
key: { type: integer, format: int64, nullable: true, description: 聚合键客户ID或商品ID为0/NULL表示未指定 }
name: { type: string, description: 客户或货品名称 }
spec: { type: string, nullable: true, description: 货品规格,仅在按货品维度时返回 }
salesAmount: { type: number, description: 销售额(退货为负值) }
costAmount: { type: number, description: 成本额(退货为负值) }
profit: { type: number, description: 利润 = 销售额 - 成本额 }
profitRate: { type: number, description: 利润率(%),单位:百分比,保留两位小数 }
SalesReportSummary:
type: object
properties:
salesAmount: { type: number, description: 汇总销售额,已扣除退货 }
costAmount: { type: number, description: 汇总成本额,退货为负值 }
profit: { type: number, description: 汇总利润 = 销售额 - 成本额 }
profitRate: { type: number, description: 汇总利润率(%),保留两位小数 }
itemCount: { type: integer, description: 聚合项数量 }
SalesReportResponse:
type: object
properties:
dimension: { type: string, enum: [customer, product] }
startDate: { type: string, nullable: true }
endDate: { type: string, nullable: true }
summary: { $ref: '#/components/schemas/SalesReportSummary' }
items:
type: array
items: { $ref: '#/components/schemas/SalesReportItem' }
VipUser:
type: object
properties:
id: { type: integer, format: int64 }
userId: { type: integer, format: int64 }
isVip: { type: integer, enum: [0,1] }
status: { type: integer, enum: [0,1] }
expireAt: { type: string, format: date-time, nullable: true }
remark: { type: string, nullable: true }
reviewerId: { type: integer, format: int64, nullable: true }
reviewedAt: { type: string, format: date-time, nullable: true }
CreateVipUserRequest:
type: object
properties:
userId: { type: integer, format: int64 }
isVip: { type: integer, enum: [0,1], default: 1 }
expireAt: { type: string, format: date-time, nullable: true }
remark: { type: string, nullable: true }
UpdateVipUserRequest:
type: object
properties:
isVip: { type: integer, enum: [0,1] }
status: { type: integer, enum: [0,1] }
expireAt: { type: string, format: date-time, nullable: true }
remark: { type: string, nullable: true }
DashboardOverview:
type: object
properties:
todaySalesAmount:
type: number
example: 1250.00
monthSalesAmount:
type: number
example: 26500.00
monthGrossProfit:
type: number
example: 3560.25
stockTotalQuantity:
type: number
example: 1300
Notice:
type: object
properties:
id:
type: integer
format: int64
title:
type: string
content:
type: string
tag:
type: string
nullable: true
pinned:
type: boolean
startsAt:
type: string
format: date-time
nullable: true
endsAt:
type: string
format: date-time
nullable: true
status:
type: string
enum: [draft, published, offline]
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
MetricsOverview:
type: object
properties:
todaySales:
type: string
example: '1234.56'
monthSales:
type: string
example: '23456.78'
monthProfit:
type: string
example: '3456.78'
stockCount:
type: string
example: '1200'
Account:
type: object
properties:
id:
type: integer
format: int64
name:
type: string
type:
type: string
enum: [cash, bank, alipay, wechat, other]
balance:
type: number
bankName:
type: string
nullable: true
bankAccount:
type: string
nullable: true
CreateAccountRequest:
type: object
properties:
name: { type: string }
type: { type: string, enum: [cash, bank, alipay, wechat, other] }
bankName: { type: string, nullable: true }
bankAccount: { type: string, nullable: true }
openingBalance: { type: number, nullable: true }
status: { type: integer, enum: [0,1], default: 1 }
Supplier:
type: object
properties:
id: { type: integer, format: int64 }
name: { type: string }
contactName: { type: string, nullable: true }
mobile: { type: string, nullable: true }
phone: { type: string, nullable: true }
address: { type: string, nullable: true }
apOpening: { type: number }
apPayable: { type: number }
remark: { type: string, nullable: true }
CreateSupplierRequest:
type: object
properties:
name: { type: string }
contactName: { type: string, nullable: true }
mobile: { type: string, nullable: true }
phone: { type: string, nullable: true }
address: { type: string, nullable: true }
apOpening: { type: number, nullable: true }
apPayable: { type: number, nullable: true }
remark: { type: string, nullable: true }
CreateOtherTransactionRequest:
type: object
properties:
type:
type: string
enum: [income, expense]
category:
type: string
counterpartyType:
type: string
enum: [customer, supplier, other]
counterpartyId:
type: integer
format: int64
nullable: true
accountId:
type: integer
format: int64
amount:
type: number
txTime:
type: string
format: date
remark:
type: string
endsAt:
type: string
format: date-time
status:
type: string
enum: [DRAFT, PUBLISHED, OFFLINE]
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
Product:
type: object
properties:
id:
type: integer
format: int64
code:
type: string
name:
type: string
price:
type: number
stock:
type: number
ProductDetail:
allOf:
- $ref: '#/components/schemas/Product'
- type: object
properties:
brand: { type: string }
model: { type: string }
spec: { type: string }
categoryId: { type: integer, format: int64, nullable: true }
unitId: { type: integer, format: int64 }
safeMin: { type: number, nullable: true }
safeMax: { type: number, nullable: true }
purchasePrice: { type: number }
retailPrice: { type: number }
distributionPrice: { type: number }
wholesalePrice: { type: number }
bigClientPrice: { type: number }
images:
type: array
items:
type: object
properties: { url: { type: string } }
CreateProductRequest:
type: object
properties:
name: { type: string }
barcode: { type: string, nullable: true }
brand: { type: string, nullable: true }
model: { type: string, nullable: true }
spec: { type: string, nullable: true }
categoryId: { type: integer, format: int64, nullable: true }
unitId: { type: integer, format: int64 }
safeMin: { type: number, nullable: true }
safeMax: { type: number, nullable: true }
prices:
type: object
properties:
purchasePrice: { type: number }
retailPrice: { type: number }
distributionPrice: { type: number }
wholesalePrice: { type: number }
bigClientPrice: { type: number }
stock: { type: number, nullable: true }
images:
type: array
items: { type: string, description: '图片URL' }
Category:
type: object
properties:
id: { type: integer, format: int64 }
name: { type: string }
Unit:
type: object
properties:
id: { type: integer, format: int64 }
name: { type: string }
ProductSettings:
type: object
properties:
hideZeroStock: { type: boolean }
hidePurchasePrice: { type: boolean }
Customer:
type: object
properties:
id: { type: integer, format: int64 }
name: { type: string }
contactName: { type: string }
mobile: { type: string }
phone: { type: string }
priceLevel: { type: string, enum: [零售价, 批发价, 大单报价] }
remark: { type: string }
receivable: { type: number }
CreateCustomerRequest:
type: object
properties:
name: { type: string }
priceLevel: { type: string, enum: [零售价, 批发价, 大单报价] }
contactName: { type: string, nullable: true }
mobile: { type: string, nullable: true }
phone: { type: string, nullable: true }
address: { type: string, nullable: true }
arOpening: { type: number, nullable: true }
remark: { type: string, nullable: true }
CreateOrderRequest:
type: object
properties:
type:
type: string
description: 'sale.out/sale.return/sale.collect/purchase.in/purchase.return/purchase.pay'
orderTime:
type: string
format: date-time
customerId:
type: integer
format: int64
nullable: true
supplierId:
type: integer
format: int64
nullable: true
items:
type: array
items:
type: object
properties:
productId:
type: integer
format: int64
quantity:
type: number
unitPrice:
type: number
discountRate:
type: number
amount:
type: number
payments:
type: array
items:
$ref: '#/components/schemas/PaymentItem'
PaymentItem:
type: object
properties:
method: { type: string, enum: [cash, bank, wechat] }
amount: { type: number }
orderId: { type: integer, format: int64, nullable: true }