/** * Demo 模板页 Mock API(本地内存,不依赖后端) * 供 views/demo/* 与 product-view-dialog 使用 */ import { fetchUserList } from '@/api/admin' import { demoCategories, demoOrders, demoProducts, demoRegions, demoUnits } from './mock-data' import { DEFAULT_LIST_PAGE_SIZE } from '@/utils/table/tableConfig' import request from '@/utils/http' type PageParams = { page?: number; pageSize?: number; keyword?: string } const delay = (ms = 120) => new Promise((resolve) => setTimeout(resolve, ms)) function paginate(list: T[], page = 1, pageSize = DEFAULT_LIST_PAGE_SIZE) { const p = Math.max(1, page) const ps = Math.max(1, pageSize) const start = (p - 1) * ps const slice = list.slice(start, start + ps) return { list: slice, total: list.length, page: p, pageSize: ps, totalPages: Math.max(1, Math.ceil(list.length / ps)) } } function filterKeyword>( list: T[], keys: string[], keyword?: string ) { const kw = (keyword || '').trim().toLowerCase() if (!kw) return list return list.filter((row) => keys.some((k) => String(row[k] ?? '').toLowerCase().includes(kw))) } const units = [...demoUnits] const categories = [...demoCategories] const products = [...demoProducts] const orders = [...demoOrders] function newId(prefix: string) { return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}` } // ─── 物品单位 ───────────────────────────────────────── export async function fetchItemUnitList(params?: PageParams) { await delay() const filtered = filterKeyword(units, ['unitName', 'unitCode'], params?.keyword) return paginate(filtered, params?.page, params?.pageSize) } export async function fetchCreateItemUnit(data: { unitCode: string unitName: string orderNum?: number remark?: string }) { await delay() const row: Api.ItemUnit.ItemUnitItem = { id: newId('demo-unit'), unitCode: data.unitCode, unitName: data.unitName, tenantNo: 'demo', orderNum: data.orderNum ?? 0, remark: data.remark || '', createTime: new Date().toISOString().slice(0, 19).replace('T', ' '), updateTime: new Date().toISOString().slice(0, 19).replace('T', ' ') } units.unshift(row) return row } export async function fetchUpdateItemUnit( id: string, data: Partial<{ unitCode: string; unitName: string; orderNum: number; remark: string }> ) { await delay() const idx = units.findIndex((u) => u.id === id) if (idx >= 0) units[idx] = { ...units[idx], ...data } return units[idx] } export async function fetchDeleteItemUnit(id: string) { await delay() const idx = units.findIndex((u) => u.id === id) if (idx >= 0) units.splice(idx, 1) return { success: true } } // ─── 分类 ─────────────────────────────────────────── export async function fetchCategoryList(params?: PageParams & { isActive?: boolean }) { await delay() let list = [...categories] if (params?.isActive != null) list = list.filter((c) => c.isActive === params.isActive) list = filterKeyword(list, ['name'], params?.keyword) return paginate(list, params?.page, params?.pageSize) } export async function fetchCreateCategory(data: { name: string parentId?: string sortOrder?: number imageUrl?: string }) { await delay() const row: Api.Category.CategoryItem = { id: newId('demo-cat'), name: data.name, parentId: data.parentId || '0', sortOrder: data.sortOrder ?? 0, isActive: true, imageUrl: data.imageUrl || '', createAt: new Date().toISOString().slice(0, 19).replace('T', ' ') } categories.push(row) return row } export async function fetchUpdateCategory(id: string, data: Partial) { await delay() const idx = categories.findIndex((c) => c.id === id) if (idx >= 0) categories[idx] = { ...categories[idx], ...data } return categories[idx] } export async function fetchDeleteCategory(id: string) { await delay() const idx = categories.findIndex((c) => c.id === id) if (idx >= 0) categories.splice(idx, 1) return { success: true } } export async function fetchUploadCategoryImage(_data: FormData) { await delay() return { fileUrl: '', fileName: 'demo.png' } } export async function fetchProductParameterSimple() { await delay() return { list: [] as Api.Product.ProductParameterSimple[], total: 0 } } export async function fetchCategoryParameters(_categoryId: string) { await delay() return { list: [] as Api.Product.CategoryParameter[], total: 0 } } export async function fetchUpdateCategoryParameters(_categoryId: string, _items: unknown[]) { await delay() return { success: true } } // ─── 商品单位(Unit 命名,商品页用) ───────────────── export async function fetchUnitList(params?: PageParams) { await delay() const list: Api.Unit.UnitItem[] = units.map((u) => ({ id: u.id, name: u.unitName, code: u.unitCode, isActive: true, createAt: u.createTime })) const filtered = filterKeyword(list, ['name', 'code'], params?.keyword) return paginate(filtered, params?.page, params?.pageSize) } // ─── 商品 ─────────────────────────────────────────── export async function fetchProductList(params?: PageParams & { categoryId?: string }) { await delay() let list = [...products] if (params?.categoryId) list = list.filter((p) => p.categoryId === params.categoryId) list = filterKeyword(list, ['name'], params?.keyword) return paginate(list, params?.page, params?.pageSize) } export async function fetchProductDetail(id: string) { await delay() const base = products.find((p) => p.id === id) if (!base) throw new Error('商品不存在') return { ...base, updateAt: base.createAt, updateBy: 'demo', skuCode: 'SKU-DEMO', measureValue: 1, detailContent: '' } as Api.Product.ProductDetail & { skuCode?: string; measureValue?: number; detailContent?: string } } export async function fetchCreateProduct(data: Partial & { name: string }) { await delay() const row: Api.Product.ProductItem = { id: newId('demo-prod'), name: data.name, categoryId: data.categoryId, categoryName: categories.find((c) => c.id === data.categoryId)?.name, unitId: data.unitId, unitName: units.find((u) => u.id === data.unitId)?.unitName, description: data.description || '', imageUrl: data.imageUrl || '', isActive: data.isActive ?? true, createAt: new Date().toISOString().slice(0, 19).replace('T', ' ') } products.unshift(row) return row } export async function fetchUpdateProduct(id: string, data: Partial) { await delay() const idx = products.findIndex((p) => p.id === id) if (idx >= 0) products[idx] = { ...products[idx], ...data } return products[idx] } export async function fetchDeleteProduct(id: string) { await delay() const idx = products.findIndex((p) => p.id === id) if (idx >= 0) products.splice(idx, 1) return { success: true } } export async function fetchProductBannerList(_productId: string) { await delay() return { list: [] as Api.Product.ProductBanner[], total: 0 } } export async function fetchCreateProductBanners(_productId: string, _items: unknown[]) { await delay() return { success: true } } export async function fetchUpdateProductBannerSort(_productId: string, _items: unknown[]) { await delay() return { success: true } } export async function fetchDeleteProductBanner(_id: string) { await delay() return { success: true } } export async function fetchProductDetailMediaList(_productId: string) { await delay() return { list: [] as Api.Product.ProductDetailMedia[], total: 0 } } export async function fetchCreateProductDetailMedia(_productId: string, _items: unknown[]) { await delay() return { success: true } } export async function fetchUpdateProductDetailMediaSort(_productId: string, _items: unknown[]) { await delay() return { success: true } } export async function fetchDeleteProductDetailMedia(_id: string) { await delay() return { success: true } } export async function fetchProductParameterValues(_productId: string) { await delay() return { list: [] as Api.Product.ProductParameterValue[], total: 0 } } export async function fetchSaveProductParameterValues(_productId: string, _values: unknown[]) { await delay() return { success: true } } export async function fetchProductRegionPrices(_productId: string) { await delay() return { list: demoRegions.map((r) => ({ regionId: r.id, regionName: r.name, price: 100, unitId: null, unitName: null })) } } // ─── 区域 / 用户(订单页) ─────────────────────────── export async function fetchNotDeletedRegions() { await delay() return [...demoRegions] } export { fetchUserList } // ─── business.ts 订单等 ───────────────────────────── export async function fetchOrderList(params?: PageParams & Record) { await delay() let list = [...orders] list = filterKeyword(list, ['orderNo', 'clientName'], params?.keyword as string | undefined) return paginate(list, params?.page, params?.pageSize) } export async function fetchOrderDetail(id: string) { await delay() const base = orders.find((o) => o.id === id) if (!base) throw new Error('订单不存在') return { ...base, items: [], remark: 'Demo 订单详情' } as Api.Order.OrderDetail } export async function fetchAssignDelivery(_data: unknown) { await delay() return { success: true } } export async function fetchReviewCancel(_data: unknown) { await delay() return { success: true } } export async function fetchCancelOrder(_data: unknown) { await delay() return { success: true } } export async function fetchOrderItems(_orderId: string) { await delay() return { list: [] } } export async function fetchAdjustOrder(_data: unknown) { await delay() return { success: true } } export async function fetchOrderAdjusts(_orderId: string) { await delay() return { list: [] } } export async function fetchPriceVersionDetail(_id: string) { await delay() return { id: _id, name: 'Demo 价目表' } } export async function fetchUploadAttachment(_data: FormData) { await delay() return { id: newId('att'), fileName: 'demo.pdf', fileUrl: '#', fileSize: 0 } } export async function fetchUploadProductImage(_data: FormData) { await delay() return { fileUrl: '', fileName: 'demo.png' } } export async function fetchSystemConfig() { await delay() return { orderCancelReasons: ['客户取消', '库存不足'], paymentMethods: [ { value: 'cash', label: '现金' }, { value: 'transfer', label: '转账' } ] } } export async function fetchAttachmentDownloadUrl(_data: { fileUrl: string; fileName?: string }) { await delay() return { downloadUrl: '#' } } const DEMO_PRODUCT_EXPORT_COLS = [ { field: 'id', title: 'id' }, { field: 'name', title: '商品名称' }, { field: 'skuCode', title: 'SKU编码' }, { field: 'categoryName', title: '分类' }, { field: 'measureValue', title: '计量' }, { field: 'unitName', title: '单位' }, { field: 'imageUrl', title: '图片URL' }, { field: 'isActive', title: '状态' }, { field: 'createAt', title: '创建时间' } ] const DEMO_CATEGORY_EXPORT_COLS = [ { field: 'id', title: 'id' }, { field: 'name', title: '分类名称' }, { field: 'parentId', title: '父分类ID' }, { field: 'parentName', title: '父分类名称' }, { field: 'sortOrder', title: '排序' }, { field: 'priceCoefficient', title: '价格系数(%)' }, { field: 'isActive', title: '状态' }, { field: 'imageUrl', title: '图片URL' } ] function pickExportColumns( all: { field: string; title: string }[], visible?: string[] ) { if (!visible?.length) return all const set = new Set(visible) const picked = all.filter((c) => set.has(c.field)) return picked.length ? picked : all } /** Demo 商品列表导出(Mock 筛行 + 后端 xlsx) */ export async function fetchExportDemoProducts(payload: Record = {}) { await delay() let list = [...products] if (payload.categoryId) list = list.filter((p) => p.categoryId === payload.categoryId) if (payload.isActive === true || payload.isActive === false) { list = list.filter((p) => p.isActive === payload.isActive) } list = filterKeyword(list, ['name', 'skuCode'], payload.keyword) if (payload.ids?.length) { const idSet = new Set(payload.ids.map(String)) list = list.filter((p) => idSet.has(String(p.id))) } const cols = pickExportColumns(DEMO_PRODUCT_EXPORT_COLS, payload.columns) const rows = list.map((row) => ({ id: row.id, name: row.name, skuCode: (row as any).skuCode || 'SKU-DEMO', categoryName: row.categoryName, measureValue: (row as any).measureValue ?? 1, unitName: row.unitName, imageUrl: row.imageUrl, isActive: row.isActive ? '启用' : '禁用', createAt: row.createAt })) return request.post({ url: '/web/admin/demo/xlsx-export', data: { sheetTitle: '商品数据', filenameStem: '商品数据', columns: cols, rows }, responseType: 'blob' }) } /** Demo 分类列表导出(Mock 筛行 + 后端 xlsx) */ export async function fetchExportDemoCategories(payload: Record = {}) { await delay() let list = [...categories] if (payload.isActive === true || payload.isActive === false) { list = list.filter((c) => c.isActive === payload.isActive) } list = filterKeyword(list, ['name'], payload.keyword) if (payload.ids?.length) { const idSet = new Set(payload.ids.map(String)) list = list.filter((c) => idSet.has(String(c.id))) } const idToName = new Map(list.map((c) => [c.id, c.name])) // parent may be outside filtered set — use full categories map const allNames = new Map(categories.map((c) => [c.id, c.name])) const cols = pickExportColumns(DEMO_CATEGORY_EXPORT_COLS, payload.columns) const rows = list.map((row) => ({ id: row.id, name: row.name, parentId: row.parentId || '', parentName: row.parentId ? allNames.get(row.parentId) || '' : '', sortOrder: row.sortOrder, priceCoefficient: row.priceCoefficient ?? 0, isActive: row.isActive ? '启用' : '禁用', imageUrl: row.imageUrl || '' })) return request.post({ url: '/web/admin/demo/xlsx-export', data: { sheetTitle: '分类数据', filenameStem: '分类数据', columns: cols, rows }, responseType: 'blob' }) }