openapi: 3.0.3 info: title: PartsInquiry API version: 0.1.0 description: >- 所有接口定义集中于此文件。每个 path 在 summary/description 中标注实现状态。 servers: - url: / paths: /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: 返回当前店铺可见的公告列表。后端与前端均已接入。 parameters: - in: header name: X-Shop-Id required: false schema: type: integer description: 店铺ID,缺省为 1 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:[]} 皆可。 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' /api/suppliers: get: summary: 供应商搜索(❌ Partially Implemented) parameters: - in: query name: kw schema: type: string 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' /api/other-transactions: post: summary: 新建其他收入/支出(❌ Partially 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: 单据列表查询(❌ Partially Implemented) description: 支持按时间范围与关键字筛选;参数 biz=sale|purchase,type=out|in|return;返回 {list:[]}。 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: 支持按时间范围与关键字筛选;返回 {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: 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: 进货单列表查询(❌ Partially 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: 收付款流水列表(❌ Partially 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: list: type: array items: type: object properties: id: { type: integer, format: int64 } bizType: { type: string } direction: { type: string } payTime: { type: string, format: date-time } amount: { type: number } accountName: { type: string } /api/inventories/logs: get: summary: 库存/盘点流水列表(❌ Partially 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: list: type: array items: type: object properties: id: { type: integer, format: int64 } bizType: { type: string } txTime: { type: string, format: date-time } amount: { type: number } remark: { type: string } productId: { type: integer, format: int64 } qtyDelta: { type: number } amountDelta: { type: number, nullable: true } /api/attachments: post: summary: 上传附件(✅ Fully Implemented,占位图方案) description: 接收 multipart 上传但忽略文件内容,始终返回占位图 URL(后端配置项 `attachments.placeholder.image-path` 指向本地占位图片;URL 固定 `/api/attachments/placeholder` 可通过 `attachments.placeholder.url-path` 覆盖)。 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/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 shopId: type: integer format: int64 userId: type: integer format: int64 title: type: string content: type: string tag: type: string pinned: type: boolean startsAt: 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 Supplier: type: object properties: id: type: integer format: int64 name: type: string mobile: type: string CreateOtherTransactionRequest: type: object properties: type: type: string enum: [income, expense] category: type: string 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: [retail, distribution, wholesale, big_client] } remark: { type: string } receivable: { type: number } CreateCustomerRequest: type: object properties: name: { type: string } level: { type: string, nullable: true } priceLevel: { type: string, enum: [retail, distribution, wholesale, big_client] } 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 }