This commit is contained in:
zlwu committed 2026-06-30 23:44:22 +08:00
1 parent d84f4b944c
commit 7c838cfb2d
249 files changed
+50600 -18556

No files matched your search

+2 -2
View File
@@ -22,7 +22,7 @@ function unwrapData(res: any) {
function mapListQuery(query: ClueQuery = {}): Record<string, any> {
const body: Record<string, any> = {
page: query.pageNum ?? 1,
pageSize: query.pageSize ?? 10
pageSize: query.pageSize ?? 20
}
if (query.clueName) body.clueName = query.clueName
if (query.company) body.company = query.company
@@ -197,7 +197,7 @@ export async function listClueFollow(query: ClueFollowQuery) {
data: {
clueId: String(query.clueId),
page: query.pageNum ?? 1,
pageSize: query.pageSize ?? 10
pageSize: query.pageSize ?? 20
}
})
const data = unwrapData(res)
+1 -1
View File
@@ -13,7 +13,7 @@ function unwrapData(res: any) {
function mapListQuery(query: ApprovalQuery = {}): Record<string, any> {
const params: Record<string, any> = {
pageNum: query.pageNum ?? 1,
pageSize: query.pageSize ?? 10
pageSize: query.pageSize ?? 20
}
;[
'contractNo',
+1 -1
View File
@@ -13,7 +13,7 @@ function unwrapData(res: any) {
function mapListQuery(query: ChangeQuery = {}): Record<string, any> {
const params: Record<string, any> = {
pageNum: query.pageNum ?? 1,
pageSize: query.pageSize ?? 10
pageSize: query.pageSize ?? 20
}
;['contractNo', 'contractName', 'changeType', 'approvalStatus', 'beginTime', 'endTime'].forEach((key) => {
const val = (query as any)[key]
+1 -1
View File
@@ -13,7 +13,7 @@ function unwrapData(res: any) {
function mapListQuery(query: ContractQuery = {}): Record<string, any> {
const params: Record<string, any> = {
pageNum: query.pageNum ?? 1,
pageSize: query.pageSize ?? 10
pageSize: query.pageSize ?? 20
}
const fields: (keyof ContractQuery)[] = [
'contractNo',
+1 -1
View File
@@ -13,7 +13,7 @@ function unwrapData(res: any) {
function mapListQuery(query: TemplateQuery = {}): Record<string, any> {
const params: Record<string, any> = {
pageNum: query.pageNum ?? 1,
pageSize: query.pageSize ?? 10
pageSize: query.pageSize ?? 20
}
;['templateNo', 'templateName', 'templateType', 'beginTime', 'endTime'].forEach((key) => {
const val = (query as any)[key]
+3 -3
View File
@@ -25,7 +25,7 @@ function unwrapData(res: any) {
function mapListQuery(query: OpportunityQuery = {}): Record<string, any> {
const body: Record<string, any> = {
page: query.pageNum ?? 1,
pageSize: query.pageSize ?? 10
pageSize: query.pageSize ?? 20
}
if (query.opportunityName) body.opportunityName = query.opportunityName
if (query.customerName) body.customerName = query.customerName
@@ -177,7 +177,7 @@ export async function listOpportunityProduct(query?: OpportunityProductQuery) {
url: `${BASE}/product/list`,
data: {
page: query?.pageNum ?? 1,
pageSize: query?.pageSize ?? 10,
pageSize: query?.pageSize ?? 20,
opportunityId: query?.opportunityId != null ? String(query.opportunityId) : undefined,
productId: query?.productId != null ? String(query.productId) : undefined
}
@@ -232,7 +232,7 @@ export async function listOpportunityFollow(query?: OpportunityFollowQuery) {
url: `${BASE}/follow/list`,
data: {
page: query?.pageNum ?? 1,
pageSize: query?.pageSize ?? 10,
pageSize: query?.pageSize ?? 20,
opportunityId: query?.opportunityId != null ? String(query.opportunityId) : undefined,
followType: query?.followType,
followBy: query?.followBy != null ? String(query.followBy) : undefined
+1 -1
View File
@@ -22,7 +22,7 @@ function unwrapData(res: any) {
function mapListQuery(query: QuoteQuery = {}): Record<string, any> {
const body: Record<string, any> = {
page: query.pageNum ?? 1,
pageSize: query.pageSize ?? 10
pageSize: query.pageSize ?? 20
}
const fields: (keyof QuoteQuery)[] = [
'keyword',
+2 -2
View File
@@ -48,7 +48,7 @@ export async function listSupplierInfo(query: SupplierInfoQuery = {}) {
url: `${BASE}/list`,
data: {
page: query.pageNum ?? 1,
pageSize: query.pageSize ?? 10,
pageSize: query.pageSize ?? 20,
supplierName: query.supplierName,
status: query.status
}
@@ -92,7 +92,7 @@ export async function exportSupplierInfo(query: SupplierInfoQuery) {
url: `${BASE}/export`,
data: {
page: query.pageNum ?? 1,
pageSize: query.pageSize ?? 10,
pageSize: query.pageSize ?? 20,
supplierName: query.supplierName,
status: query.status
},
+2
View File
@@ -0,0 +1,2 @@
/** Demo 模板页 API 统一出口(Mock,无后端) */
export * from './mock-api'
+389
View File
@@ -0,0 +1,389 @@
/**
* 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'
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: '#' }
}
+141
View File
@@ -0,0 +1,141 @@
/** Demo 模板页本地种子数据(无后端依赖) */
export const demoUnits: Api.ItemUnit.ItemUnitItem[] = [
{
id: 'demo-unit-1',
unitCode: 'KG',
unitName: '千克',
tenantNo: 'demo',
orderNum: 1,
remark: 'Demo 示例',
createTime: '2026-01-01 10:00:00',
updateTime: '2026-01-01 10:00:00'
},
{
id: 'demo-unit-2',
unitCode: 'TON',
unitName: '吨',
tenantNo: 'demo',
orderNum: 2,
remark: '',
createTime: '2026-01-02 10:00:00',
updateTime: '2026-01-02 10:00:00'
}
]
export const demoCategories: Api.Category.CategoryItem[] = [
{
id: 'demo-cat-1',
name: '化工原料',
parentId: '0',
sortOrder: 1,
isActive: true,
imageUrl: '',
createAt: '2026-01-01 10:00:00'
},
{
id: 'demo-cat-2',
name: '树脂类',
parentId: 'demo-cat-1',
sortOrder: 1,
isActive: true,
imageUrl: '',
createAt: '2026-01-01 10:00:00'
},
{
id: 'demo-cat-3',
name: '溶剂类',
parentId: 'demo-cat-1',
sortOrder: 2,
isActive: true,
imageUrl: '',
createAt: '2026-01-01 10:00:00'
}
]
export const demoProducts: Api.Product.ProductItem[] = [
{
id: 'demo-prod-1',
name: '环氧树脂 E-51',
categoryId: 'demo-cat-2',
categoryName: '树脂类',
unitId: 'demo-unit-1',
unitName: '千克',
description: 'Demo 商品示例',
imageUrl: '',
isActive: true,
createAt: '2026-01-03 10:00:00'
},
{
id: 'demo-prod-2',
name: '丙酮',
categoryId: 'demo-cat-3',
categoryName: '溶剂类',
unitId: 'demo-unit-2',
unitName: '吨',
description: '',
imageUrl: '',
isActive: true,
createAt: '2026-01-04 10:00:00'
}
]
export const demoOrders: Api.Order.OrderItem[] = [
{
id: 'demo-order-1',
orderNo: 'DD202601001',
clientId: 'demo-client-1',
clientName: '示例客户 A',
regionId: 'demo-region-1',
regionName: '华东区',
priceListId: 'demo-price-1',
totalAmount: '12800.00',
paidAmount: '12800.00',
receivableAmount: '0.00',
refundAmount: '0.00',
status: 'completed',
paymentMethod: 'transfer',
contactPerson: '张三',
contactPhone: '13800000001',
deliveryAddress: '浙江省杭州市示例路 1 号',
createAt: '2026-01-10 09:30:00'
},
{
id: 'demo-order-2',
orderNo: 'DD202601002',
clientId: 'demo-client-2',
clientName: '示例客户 B',
regionId: 'demo-region-2',
regionName: '华南区',
priceListId: 'demo-price-1',
totalAmount: '5600.00',
paidAmount: '0.00',
receivableAmount: '5600.00',
refundAmount: '0.00',
status: 'pending_payment',
paymentMethod: 'cash',
contactPerson: '李四',
contactPhone: '13800000002',
deliveryAddress: '广东省广州市示例路 2 号',
createAt: '2026-01-11 14:20:00'
}
]
export const demoRegions: Api.Region.RegionItem[] = [
{
id: 'demo-region-1',
name: '华东区',
code: 'EAST',
isActive: true,
sortOrder: 1,
createAt: '2026-01-01 10:00:00'
},
{
id: 'demo-region-2',
name: '华南区',
code: 'SOUTH',
isActive: true,
sortOrder: 2,
createAt: '2026-01-01 10:00:00'
}
]
+40 -6
View File
@@ -2,11 +2,18 @@
* 运输计划管理 API
*/
import request from '@/utils/http/bx'
import { pickBxList, pickBxPageResult } from '@/utils/http/bx'
import type { TransportResourceSnapshot } from '@/utils/pl-transport-resource-snapshot'
// =============================================================================
// 基础数据 API
// =============================================================================
export interface PlListResponse<T> {
total: number
list: T[]
}
// 承运商
export interface Carrier {
id: string
@@ -32,10 +39,13 @@ export interface CarrierQuery {
q?: string
status?: string
auditStatus?: string
page?: number
pageSize?: number
}
export const carrierApi = {
list: (params?: CarrierQuery) => request.get<Carrier[]>('/transport/carrier', { params }),
list: (params?: CarrierQuery) =>
request.get<PlListResponse<Carrier>>('/transport/carrier', { params }),
get: (id: string) => request.get<Carrier>(`/transport/carrier/${id}`),
create: (data: Partial<Carrier>) => request.post<Carrier>('/transport/carrier', data),
update: (id: string, data: Partial<Carrier>) => request.put<Carrier>(`/transport/carrier/${id}`, data),
@@ -116,10 +126,13 @@ export interface VehicleQuery {
carrierId?: string
vehicleStatus?: string
excludeIneligibleCarrier?: boolean
page?: number
pageSize?: number
}
export const vehicleApi = {
list: (params?: VehicleQuery) => request.get<Vehicle[]>('/transport/vehicle', { params }),
list: (params?: VehicleQuery) =>
request.get<PlListResponse<Vehicle>>('/transport/vehicle', { params }),
get: (id: string) => request.get<VehicleDetail>(`/transport/vehicle/${id}`),
create: (data: VehiclePayload) => request.post<VehicleDetail>('/transport/vehicle', data),
update: (id: string, data: Partial<VehiclePayload>) =>
@@ -157,10 +170,13 @@ export interface PersonnelPayload {
export interface PersonnelQuery {
q?: string
status?: string
page?: number
pageSize?: number
}
export const personnelApi = {
list: (params?: PersonnelQuery) => request.get<Personnel[]>('/transport/personnel', { params }),
list: (params?: PersonnelQuery) =>
request.get<PlListResponse<Personnel>>('/transport/personnel', { params }),
get: (id: string) => request.get<PersonnelDetail>(`/transport/personnel/${id}`),
create: (data: PersonnelPayload) => request.post<PersonnelDetail>('/transport/personnel', data),
update: (id: string, data: Partial<PersonnelPayload>) =>
@@ -186,6 +202,8 @@ export interface Driver {
export interface DriverQuery {
q?: string
page?: number
pageSize?: number
}
function personnelToDriver(p: Personnel): Driver {
@@ -211,9 +229,19 @@ function driverToPersonnelPayload(data: Partial<Driver>): PersonnelPayload {
export const driverApi = {
list: async (params?: DriverQuery) => {
const res = await personnelApi.list({ q: params?.q })
const rows = (res.data ?? res) as Personnel[]
return { ...res, data: rows.map(personnelToDriver) }
const res = await personnelApi.list({
q: params?.q,
page: params?.page,
pageSize: params?.pageSize
})
const { list, total } = pickBxPageResult<Personnel>(res)
return {
...res,
data: {
total,
list: list.map(personnelToDriver)
}
}
},
get: async (id: string) => {
const res = await personnelApi.get(id)
@@ -304,8 +332,11 @@ export interface Plan {
destinationNotes?: string
vehicleId?: string
licensePlate?: string
trailerNo?: string
driverId?: string
driverName?: string
personnelSummary?: string
resourceSnapshot?: TransportResourceSnapshot
transportId?: string
transportNo?: string
totalAmount: number
@@ -455,9 +486,11 @@ export interface Transport {
transportNo: string
vehicleId?: string
licensePlate?: string
trailerNo?: string
driverId?: string
driverName?: string
driverPhone?: string
resourceSnapshot?: TransportResourceSnapshot
carrierId?: string
carrierName?: string
transportMedium?: string
@@ -719,6 +752,7 @@ export const freightApi = {
request.post<FreightSettlement>('/transport/freight/', data),
update: (id: string, data: Partial<FreightSettlement>) =>
request.put<FreightSettlement>(`/transport/freight/${id}`, data),
cancel: (id: string) => request.post<FreightSettlement>(`/transport/freight/${id}/cancel`),
delete: (id: string) => request.delete(`/transport/freight/${id}`),
submitApproval: (id: string, data: FreightSettlementSubmitBody) =>
request.post<FreightSettlement>(`/transport/freight/${id}/submit-approval`, data),