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|purchase,type=out|in|return;返回 {list:[]}。后端已返回驼峰字段与名称(sale: customerName;purchase: 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 }