/** * 文件职责:商品管理模块 API 与 DTO 定义。 * 1. 维护商品列表、分类、详情、批量操作契约。 * 2. 提供分类、规格、加料、标签、时段供应等扩展模块接口。 */ import type { PaginatedResult } from '#/api/store'; import { requestClient } from '#/api/request'; /** 商品状态。 */ export type ProductStatus = 'off_shelf' | 'on_sale' | 'sold_out'; /** 商品类型。 */ export type ProductKind = 'combo' | 'single'; /** 沽清模式。 */ export type ProductSoldoutMode = 'permanent' | 'timed' | 'today'; /** SKU 异步保存任务状态。 */ export type ProductSkuSaveJobStatus = | 'canceled' | 'failed' | 'queued' | 'running' | 'succeeded'; /** 商品异步保存中的 SKU 任务状态。 */ export type ProductSaveAsyncSkuJobStatus = | 'failed' | 'not_required' | 'queued' | 'running'; /** 分类展示渠道。 */ export type ProductCategoryChannel = 'dine_in' | 'pickup' | 'wm'; /** 通用启停状态。 */ export type ProductSwitchStatus = 'disabled' | 'enabled'; /** 规格做法模板类型。 */ export type ProductSpecType = 'method' | 'spec'; /** 规格做法选择方式。 */ export type ProductSpecSelectionType = 'multi' | 'single'; /** 商品选择器项。 */ export interface ProductPickerItemDto { categoryId: string; categoryName: string; id: string; name: string; price: number; spuCode: string; status: ProductStatus; } /** 商品选择器查询参数。 */ export interface ProductPickerQuery { categoryId?: string; keyword?: string; limit?: number; storeId: string; } /** 分类信息(列表页侧栏)。 */ export interface ProductCategoryDto { id: string; name: string; productCount: number; sort: number; } /** 分类管理项。 */ export interface ProductCategoryManageDto extends ProductCategoryDto { channels: ProductCategoryChannel[]; description: string; icon: string; status: ProductSwitchStatus; } /** 分类管理查询参数。 */ export interface ProductCategoryManageQuery { keyword?: string; status?: ProductSwitchStatus; storeId: string; } /** 保存分类参数。 */ export interface SaveProductCategoryDto { channels: ProductCategoryChannel[]; description: string; icon: string; id?: string; name: string; sort: number; status: ProductSwitchStatus; storeId: string; } /** 删除分类参数。 */ export interface DeleteProductCategoryDto { categoryId: string; storeId: string; } /** 分类状态变更参数。 */ export interface ChangeProductCategoryStatusDto { categoryId: string; status: ProductSwitchStatus; storeId: string; } /** 分类排序项。 */ export interface ProductCategorySortItemDto { categoryId: string; sort: number; } /** 分类排序参数。 */ export interface SortProductCategoryDto { items: ProductCategorySortItemDto[]; storeId: string; } /** 分类绑定商品参数。 */ export interface BindCategoryProductsDto { categoryId: string; productIds: string[]; storeId: string; } /** 分类解绑商品参数。 */ export interface UnbindCategoryProductDto { categoryId: string; productId: string; storeId: string; } /** 商品列表项。 */ export interface ProductListItemDto { categoryId: string; categoryName: string; id: string; imageUrl: string; kind: ProductKind; name: string; originalPrice: null | number; price: number; salesMonthly: number; soldoutMode: null | ProductSoldoutMode; spuCode: string; status: ProductStatus; stock: number; subtitle: string; tags: string[]; } /** 套餐分组商品。 */ export interface ProductComboGroupItemDto { productId: string; productName: string; quantity: number; sortOrder: number; } /** 套餐分组。 */ export interface ProductComboGroupDto { id: string; items: ProductComboGroupItemDto[]; maxSelect: number; minSelect: number; name: string; sortOrder: number; } /** SKU 规格属性。 */ export interface ProductSkuAttributeDto { optionId: string; templateId: string; } /** SKU 详情。 */ export interface ProductSkuDto { attributes: ProductSkuAttributeDto[]; id: string; isEnabled: boolean; originalPrice: null | number; price: number; skuCode: string; sortOrder: number; stock: number; } /** 商品详情。 */ export interface ProductDetailDto extends ProductListItemDto { addonGroupIds: string[]; comboGroups: ProductComboGroupDto[]; description: string; imageUrls: string[]; labelIds: string[]; notifyManager: boolean; packingFee: null | number; recoverAt: null | string; remainStock: number; skus: ProductSkuDto[]; soldoutReason: string; sortWeight: number; specTemplateIds: string[]; syncToPlatform: boolean; timedOnShelfAt: null | string; warningStock: null | number; } /** 商品列表查询参数。 */ export interface ProductListQuery { categoryId?: string; kind?: ProductKind; keyword?: string; page: number; pageSize: number; status?: ProductStatus; storeId: string; } /** 查询详情参数。 */ export interface ProductDetailQuery { productId: string; storeId: string; } /** 保存商品参数。 */ export interface SaveProductDto { addonGroupIds?: string[]; categoryId: string; comboGroups?: Array<{ items: Array<{ productId: string; quantity: number; sortOrder: number; }>; maxSelect: number; minSelect: number; name: string; sortOrder: number; }>; description: string; id?: string; imageUrls?: string[]; labelIds?: string[]; kind?: ProductKind; name: string; originalPrice: null | number; packingFee?: null | number; price: number; skus?: Array<{ attributes: Array<{ optionId: string; templateId: string; }>; isEnabled: boolean; originalPrice: null | number; price: number; skuCode?: string; sortOrder: number; stock: number; }>; shelfMode: 'draft' | 'now' | 'scheduled'; sortWeight?: number; specTemplateIds?: string[]; spuCode?: string; status: ProductStatus; stock: number; storeId: string; subtitle: string; tags?: string[]; timedOnShelfAt?: string; warningStock?: null | number; } /** 商品异步保存响应。 */ export interface SaveProductAsyncDto { message: null | string; productId: string; skuJobId: null | string; skuJobStatus: ProductSaveAsyncSkuJobStatus; storeId: string; } /** 创建 SKU 异步保存任务参数。 */ export interface CreateProductSkuSaveJobDto { productId: string; skus: Array<{ attributes: Array<{ optionId: string; templateId: string; }>; isEnabled: boolean; originalPrice: null | number; price: number; skuCode?: string; sortOrder: number; stock: number; }>; specTemplateIds?: string[]; storeId: string; } /** 查询 SKU 异步保存任务参数。 */ export interface ProductSkuSaveJobQuery { jobId: string; storeId: string; } /** SKU 异步保存任务结果。 */ export interface ProductSkuSaveJobDto { errorMessage: null | string; failedCount: number; finishedAt: null | string; jobId: string; productId: string; progressProcessed: number; progressTotal: number; startedAt: null | string; status: ProductSkuSaveJobStatus; storeId: string; } /** 删除商品参数。 */ export interface DeleteProductDto { productId: string; storeId: string; } /** 修改商品状态参数。 */ export interface ChangeProductStatusDto { productId: string; status: ProductStatus; storeId: string; } /** 商品沽清参数。 */ export interface SoldoutProductDto { mode: ProductSoldoutMode; notifyManager: boolean; productId: string; reason: string; recoverAt?: string; remainStock: number; storeId: string; syncToPlatform: boolean; } /** 批量动作类型。 */ export type BatchProductActionType = | 'batch_delete' | 'batch_off' | 'batch_on' | 'batch_soldout'; /** 批量商品操作参数。 */ export interface BatchProductActionDto { action: BatchProductActionType; notifyManager?: boolean; productIds: string[]; reason?: string; recoverAt?: string; remainStock?: number; storeId: string; syncToPlatform?: boolean; } /** 批量操作返回。 */ export interface BatchProductActionResultDto { action: BatchProductActionType; failedCount: number; successCount: number; totalCount: number; } /** 规格值。 */ export interface ProductSpecValueDto { extraPrice: number; id: string; name: string; sort: number; } /** 规格配置。 */ export interface ProductSpecDto { id: string; isRequired: boolean; name: string; productCount: number; productIds: string[]; selectionType: ProductSpecSelectionType; sort: number; status: ProductSwitchStatus; type: ProductSpecType; updatedAt: string; values: ProductSpecValueDto[]; } /** 规格查询参数。 */ export interface ProductSpecQuery { keyword?: string; status?: ProductSwitchStatus; storeId: string; type?: ProductSpecType; } /** 保存规格参数。 */ export interface SaveProductSpecDto { id?: string; isRequired: boolean; name: string; productIds: string[]; selectionType: ProductSpecSelectionType; sort: number; status: ProductSwitchStatus; storeId: string; type: ProductSpecType; values: Array<{ extraPrice: number; id?: string; name: string; sort: number; }>; } /** 删除规格参数。 */ export interface DeleteProductSpecDto { specId: string; storeId: string; } /** 规格状态变更参数。 */ export interface ChangeProductSpecStatusDto { specId: string; status: ProductSwitchStatus; storeId: string; } /** 复制规格参数。 */ export interface CopyProductSpecDto { newName?: string; specId: string; storeId: string; } /** 加料项。 */ export interface ProductAddonItemDto { id: string; name: string; price: number; stock: number; sort: number; status: ProductSwitchStatus; } /** 加料组。 */ export interface ProductAddonGroupDto { description: string; id: string; items: ProductAddonItemDto[]; maxSelect: number; minSelect: number; name: string; productCount: number; productIds: string[]; required: boolean; sort: number; status: ProductSwitchStatus; updatedAt: string; } /** 加料组查询参数。 */ export interface ProductAddonQuery { keyword?: string; status?: ProductSwitchStatus; storeId: string; } /** 保存加料组参数。 */ export interface SaveProductAddonGroupDto { description: string; id?: string; items: Array<{ id?: string; name: string; price: number; sort: number; status: ProductSwitchStatus; stock: number; }>; maxSelect: number; minSelect: number; name: string; productIds: string[]; required: boolean; sort: number; status: ProductSwitchStatus; storeId: string; } /** 删除加料组参数。 */ export interface DeleteProductAddonGroupDto { groupId: string; storeId: string; } /** 加料组状态变更参数。 */ export interface ChangeProductAddonGroupStatusDto { groupId: string; status: ProductSwitchStatus; storeId: string; } /** 绑定加料组商品参数。 */ export interface BindProductAddonGroupProductsDto { groupId: string; productIds: string[]; storeId: string; } /** 商品标签。 */ export interface ProductLabelDto { color: string; id: string; name: string; productCount: number; sort: number; status: ProductSwitchStatus; updatedAt: string; } /** 标签查询参数。 */ export interface ProductLabelQuery { keyword?: string; status?: ProductSwitchStatus; storeId: string; } /** 保存标签参数。 */ export interface SaveProductLabelDto { color: string; id?: string; name: string; sort: number; status: ProductSwitchStatus; storeId: string; } /** 删除标签参数。 */ export interface DeleteProductLabelDto { labelId: string; storeId: string; } /** 标签状态变更参数。 */ export interface ChangeProductLabelStatusDto { labelId: string; status: ProductSwitchStatus; storeId: string; } /** 时段模板。 */ export interface ProductScheduleDto { endTime: string; id: string; name: string; productCount: number; productIds: string[]; startTime: string; status: ProductSwitchStatus; updatedAt: string; weekDays: number[]; } /** 时段查询参数。 */ export interface ProductScheduleQuery { keyword?: string; status?: ProductSwitchStatus; storeId: string; } /** 保存时段参数。 */ export interface SaveProductScheduleDto { endTime: string; id?: string; name: string; productIds: string[]; startTime: string; status: ProductSwitchStatus; storeId: string; weekDays: number[]; } /** 删除时段参数。 */ export interface DeleteProductScheduleDto { scheduleId: string; storeId: string; } /** 时段状态变更参数。 */ export interface ChangeProductScheduleStatusDto { scheduleId: string; status: ProductSwitchStatus; storeId: string; } /** 批量范围。 */ export interface ProductBatchScopeDto { categoryId?: string; categoryIds?: string[]; productIds?: string[]; type: 'all' | 'category' | 'manual' | 'selected'; } /** 批量调价预览参数。 */ export interface ProductBatchPriceAdjustPreviewDto { amount: number; amountType: 'fixed' | 'percent'; direction: 'down' | 'up'; scope: ProductBatchScopeDto; storeId: string; } /** 批量调价参数。 */ export interface ProductBatchPriceAdjustDto { amount: number; amountType: 'fixed' | 'percent'; direction: 'down' | 'up'; scope: ProductBatchScopeDto; storeId: string; } /** 调价预览项。 */ export interface ProductBatchPricePreviewItemDto { deltaPrice: number; newPrice: number; originalPrice: number; productId: string; productName: string; } /** 调价预览结果。 */ export interface ProductBatchPricePreviewDto { items: ProductBatchPricePreviewItemDto[]; totalCount: number; } /** 批量移动分类参数。 */ export interface ProductBatchMoveCategoryDto { scope: ProductBatchScopeDto; sourceCategoryId?: string; storeId: string; targetCategoryId: string; } /** 批量上下架参数。 */ export interface ProductBatchSaleSwitchDto { action: 'off' | 'on'; scope: ProductBatchScopeDto; storeId: string; } /** 批量同步门店参数。 */ export interface ProductBatchSyncStoreDto { productIds: string[]; sourceStoreId: string; syncPrice?: boolean; syncStatus?: boolean; syncStock?: boolean; targetStoreIds: string[]; } /** 批量工具通用结果。 */ export interface ProductBatchToolResultDto { failedCount: number; skippedCount: number; successCount: number; totalCount: number; } /** 批量导出请求参数。 */ export interface ProductBatchExportDto { scope: ProductBatchScopeDto; storeId: string; } /** Excel 文件回执。 */ export interface ProductBatchExcelFileDto { failedCount: number; fileContentBase64: string; fileName: string; successCount: number; totalCount: number; } /** 批量导入参数。 */ export interface ProductBatchImportDto { file: File; storeId: string; } /** 批量导入错误项。 */ export interface ProductBatchImportErrorItemDto { message: string; rowNo: number; } /** 批量导入回执。 */ export interface ProductBatchImportResultDto extends ProductBatchToolResultDto { errors: ProductBatchImportErrorItemDto[]; fileName: string; } /** 获取商品分类(侧栏口径)。 */ export async function getProductCategoryListApi(storeId: string) { return requestClient.get('/product/category/list', { params: { storeId }, }); } /** 获取分类管理列表。 */ export async function getProductCategoryManageListApi( params: ProductCategoryManageQuery, ) { return requestClient.get( '/product/category/manage/list', { params, }, ); } /** 保存分类。 */ export async function saveProductCategoryApi(data: SaveProductCategoryDto) { return requestClient.post( '/product/category/manage/save', data, ); } /** 删除分类。 */ export async function deleteProductCategoryApi(data: DeleteProductCategoryDto) { return requestClient.post('/product/category/manage/delete', data); } /** 修改分类状态。 */ export async function changeProductCategoryStatusApi( data: ChangeProductCategoryStatusDto, ) { return requestClient.post('/product/category/manage/status', data); } /** 批量排序分类。 */ export async function sortProductCategoryApi(data: SortProductCategoryDto) { return requestClient.post('/product/category/manage/sort', data); } /** 将商品绑定到分类。 */ export async function bindCategoryProductsApi(data: BindCategoryProductsDto) { return requestClient.post('/product/category/manage/products/bind', data); } /** 从分类解绑单个商品。 */ export async function unbindCategoryProductApi(data: UnbindCategoryProductDto) { return requestClient.post('/product/category/manage/products/unbind', data); } /** 获取商品列表。 */ export async function getProductListApi(params: ProductListQuery) { return requestClient.get>( '/product/list', { params, }, ); } /** 获取商品详情。 */ export async function getProductDetailApi(params: ProductDetailQuery) { return requestClient.get('/product/detail', { params, }); } /** 保存商品(新增/编辑)。 */ export async function saveProductApi(data: SaveProductDto) { return requestClient.post('/product/save', data); } /** 异步保存商品(基础信息落库 + SKU 入队)。 */ export async function saveProductAsyncApi(data: SaveProductDto) { return requestClient.post('/product/save-async', data); } /** 创建 SKU 异步保存任务。 */ export async function createProductSkuSaveJobApi( data: CreateProductSkuSaveJobDto, ) { return requestClient.post( '/product/sku-save-jobs', data, ); } /** 查询 SKU 异步保存任务。 */ export async function getProductSkuSaveJobApi(params: ProductSkuSaveJobQuery) { const { jobId, ...query } = params; return requestClient.get( `/product/sku-save-jobs/${jobId}`, { params: query, }, ); } /** 删除商品。 */ export async function deleteProductApi(data: DeleteProductDto) { return requestClient.post('/product/delete', data); } /** 修改商品状态。 */ export async function changeProductStatusApi(data: ChangeProductStatusDto) { return requestClient.post('/product/status/change', data); } /** 提交沽清。 */ export async function soldoutProductApi(data: SoldoutProductDto) { return requestClient.post('/product/soldout', data); } /** 批量商品操作(列表页)。 */ export async function batchProductActionApi(data: BatchProductActionDto) { return requestClient.post( '/product/batch', data, ); } /** 获取规格列表。 */ export async function getProductSpecListApi(params: ProductSpecQuery) { return requestClient.get('/product/spec/list', { params, }); } /** 保存规格。 */ export async function saveProductSpecApi(data: SaveProductSpecDto) { return requestClient.post('/product/spec/save', data); } /** 删除规格。 */ export async function deleteProductSpecApi(data: DeleteProductSpecDto) { return requestClient.post('/product/spec/delete', data); } /** 修改规格状态。 */ export async function changeProductSpecStatusApi( data: ChangeProductSpecStatusDto, ) { return requestClient.post('/product/spec/status', data); } /** 复制规格模板。 */ export async function copyProductSpecApi(data: CopyProductSpecDto) { return requestClient.post('/product/spec/copy', data); } /** 获取加料组列表。 */ export async function getProductAddonGroupListApi(params: ProductAddonQuery) { return requestClient.get( '/product/addon/group/list', { params, }, ); } /** 保存加料组。 */ export async function saveProductAddonGroupApi(data: SaveProductAddonGroupDto) { return requestClient.post( '/product/addon/group/save', data, ); } /** 删除加料组。 */ export async function deleteProductAddonGroupApi( data: DeleteProductAddonGroupDto, ) { return requestClient.post('/product/addon/group/delete', data); } /** 修改加料组状态。 */ export async function changeProductAddonGroupStatusApi( data: ChangeProductAddonGroupStatusDto, ) { return requestClient.post('/product/addon/group/status', data); } /** 绑定加料组商品。 */ export async function bindProductAddonGroupProductsApi( data: BindProductAddonGroupProductsDto, ) { return requestClient.post( '/product/addon/group/products/bind', data, ); } /** 获取标签列表。 */ export async function getProductLabelListApi(params: ProductLabelQuery) { return requestClient.get('/product/label/list', { params, }); } /** 保存标签。 */ export async function saveProductLabelApi(data: SaveProductLabelDto) { return requestClient.post('/product/label/save', data); } /** 删除标签。 */ export async function deleteProductLabelApi(data: DeleteProductLabelDto) { return requestClient.post('/product/label/delete', data); } /** 修改标签状态。 */ export async function changeProductLabelStatusApi( data: ChangeProductLabelStatusDto, ) { return requestClient.post('/product/label/status', data); } /** 获取时段列表。 */ export async function getProductScheduleListApi(params: ProductScheduleQuery) { return requestClient.get('/product/schedule/list', { params, }); } /** 保存时段。 */ export async function saveProductScheduleApi(data: SaveProductScheduleDto) { return requestClient.post('/product/schedule/save', data); } /** 删除时段。 */ export async function deleteProductScheduleApi(data: DeleteProductScheduleDto) { return requestClient.post('/product/schedule/delete', data); } /** 修改时段状态。 */ export async function changeProductScheduleStatusApi( data: ChangeProductScheduleStatusDto, ) { return requestClient.post('/product/schedule/status', data); } /** 批量调价预览。 */ export async function batchPreviewProductPriceApi( data: ProductBatchPriceAdjustPreviewDto, ) { return requestClient.post( '/product/batch/price-adjust/preview', data, ); } /** 批量调价。 */ export async function batchAdjustProductPriceApi( data: ProductBatchPriceAdjustDto, ) { return requestClient.post( '/product/batch/price-adjust', data, ); } /** 批量移动分类。 */ export async function batchMoveProductCategoryApi( data: ProductBatchMoveCategoryDto, ) { return requestClient.post( '/product/batch/move-category', data, ); } /** 批量上下架。 */ export async function batchSwitchProductSaleApi( data: ProductBatchSaleSwitchDto, ) { return requestClient.post( '/product/batch/sale-switch', data, ); } /** 批量同步门店。 */ export async function batchSyncProductStoreApi(data: ProductBatchSyncStoreDto) { return requestClient.post( '/product/batch/store-sync', data, ); } /** 批量导入。 */ export async function batchImportProductApi(data: ProductBatchImportDto) { const formData = new FormData(); formData.append('storeId', data.storeId); formData.append('file', data.file); return requestClient.post( '/product/batch/import', formData, ); } /** 下载导入模板。 */ export async function batchDownloadProductImportTemplateApi(storeId: string) { return requestClient.get( '/product/batch/import/template', { params: { storeId }, }, ); } /** 批量导出。 */ export async function batchExportProductApi(data: ProductBatchExportDto) { return requestClient.post( '/product/batch/export', data, ); } /** 商品选择器列表。 */ export async function searchProductPickerApi(params: ProductPickerQuery) { return requestClient.get('/product/picker/list', { params, }); }