Files
shanxia2.0/web-admin/src/api/demo/mock-api.ts
T
2026-08-22 09:08:05 +08:00

501 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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<T>(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<T extends Record<string, any>>(
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<Api.Category.CategoryItem>) {
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<Api.Product.ProductItem> & { 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<Api.Product.ProductItem>) {
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<string, unknown>) {
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<string, any> = {}) {
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<string, any> = {}) {
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'
})
}