openapi: 3.0.3 info: title: PartsInquiry API version: 0.1.0 description: >- 所有接口定义集中于此文件。每个 path 在 summary/description 中标注实现状态。 servers: - url: / paths: /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: 成功 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: 'payments/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}: 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' 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) 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) 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: 成功 } } - type: object properties: list: type: array items: $ref: '#/components/schemas/Product' /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 } /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: 上传附件(❌ Partially Implemented,已废弃:采用纯URL引用) description: 方案A采用纯URL引用,不再支持文件直传。历史兼容:此接口仍存在但返回占位图 URL,建议前端改用 `/api/attachments/validate-url` 进行URL校验后直接写入业务字段。 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 /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) description: 返回后端配置的本地占位图内容,路径由 `attachments.placeholder.image-path` 指定。 responses: '200': description: 图片二进制 content: image/png: schema: type: string format: binary components: schemas: 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 pinned: type: boolean startsAt: type: string format: date-time 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 } level: { type: string } priceLevel: { type: string, enum: [零售价, 批发价, 大单报价] } remark: { type: string } receivable: { type: number } CreateCustomerRequest: type: object properties: name: { type: string } level: { type: string, nullable: true } 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 }