用户原话: 不是让你沿用老vue页面内容了吗, 只是更换成新版本的UI 用户原话: 要能够交付使用, 像原有的vue平台一样使用 整改 (5 个 view 从严重简化变完整版): - OrderListView 240 行: 订单号/合同号/供应商/状态/时间范围 完整搜索, 8 种状态 tab, 操作 (详情/付款/发货/收货/退款/取消/打印), 批量导出, type 自适应 good/service/group - OrderDetailView 582 行: 完整 4-tab (订单信息/商品明细/物流/付款发票), 状态卡 + 操作按钮 (按状态动态显示), 9 种订单状态, 推广信息, 多状态按需渲染 - GoodListView 507 行: 12 列表格 (封面/商品/供应商/3 级分类/品牌/单位/铺货/审核/状态), 4 种状态 tab, 5 种操作 (详情/审核/上下架/改分类/删除), 5 种批量操作, 详情弹窗含 SKU 列表 (编码/原价/现价/秒杀价/拼团价/库存) - ServiceGoodListView 302 行: 同上针对服务商品 - InquiryDetailView 229 行: 询价基本信息 (产品/品牌/规格/数量/收货地址/交货日期/价格有效), 附件下载, 报价列表 (供应商/状态/金额/次数/来源/查看报价) 字段 100% 沿用老 vue (supplierGoodId/contractCode/groupNumber/acceptNum 等), 新增 mock 数据 (3-8 条覆盖各种业务场景), 弹窗/操作/批量/导出 全部走通 (mock 实现) + W3.x C P0-P2 累计 30+ 个 view 文件补 commit (inquiry/openapi/order/sys 等 11+ 模块) router 调整: 9 个 order 路由统一到 OrderListView (type 自动推断) + /supplier/servicegood 路由独立 (避免被 tree-shake)
156 lines
4.5 KiB
TypeScript
156 lines
4.5 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { ref, computed } from 'vue'
|
|
import { httpGet, httpPost } from '@/utils/request'
|
|
|
|
/**
|
|
* 询价 Store
|
|
* W3.7 改用 httpGet 统一封装
|
|
*
|
|
* F002 W2 起调真 API:
|
|
* - GET /sys/openapi/inquiry/list?page=&limit=&status=
|
|
* - GET /sys/openapi/inquiry/info?id=
|
|
* - POST /sys/openapi/inquiry/publish
|
|
* - POST /sys/openapi/inquiry/quote
|
|
* - POST /sys/openapi/inquiry/cancel
|
|
*
|
|
* 字段映射(后端 db 字段 -> 前端展示):
|
|
* - id -> 单号
|
|
* - customerName -> 客户
|
|
* - productName -> 商品
|
|
* - purchaseQuantity+unit -> 数量
|
|
* - status -> 状态
|
|
* - createDate -> 时间
|
|
*/
|
|
|
|
export type InquiryStatus = 'pending' | 'quoting' | 'done' | 'cancelled' | string
|
|
|
|
export interface Inquiry {
|
|
id: string
|
|
customer: string
|
|
product: string
|
|
qty: string
|
|
status: InquiryStatus
|
|
time: string
|
|
raw?: any
|
|
}
|
|
|
|
export interface InquiryListResult {
|
|
list: Inquiry[]
|
|
total: number
|
|
page: number
|
|
limit: number
|
|
isLive: boolean
|
|
error?: string
|
|
}
|
|
|
|
const STATUS_MAP: Record<string, { label: string; type: string }> = {
|
|
pending: { label: '待报价', type: 'primary' },
|
|
quoting: { label: '报价中', type: 'warning' },
|
|
done: { label: '已成交', type: 'success' },
|
|
cancelled: { label: '已取消', type: 'danger' }
|
|
}
|
|
|
|
export const STATUS_OPTIONS = [
|
|
{ value: '', label: '全部' },
|
|
{ value: 'pending', label: '待报价' },
|
|
{ value: 'quoting', label: '报价中' },
|
|
{ value: 'done', label: '已成交' },
|
|
{ value: 'cancelled', label: '已取消' }
|
|
]
|
|
|
|
export function statusLabel(s: string) {
|
|
return STATUS_MAP[s]?.label || s || '未知'
|
|
}
|
|
export function statusType(s: string): any {
|
|
return (STATUS_MAP[s]?.type || 'info') as any
|
|
}
|
|
|
|
function normalizeInquiry(it: any): Inquiry {
|
|
return {
|
|
id: String(it.id || it.rfqId || it.inquiryId || 'RFQ-?'),
|
|
customer: it.customerName || it.customer || it.customerCode || '--',
|
|
product: it.productName || it.product || it.productCode || '--',
|
|
qty: it.purchaseQuantity
|
|
? `${it.purchaseQuantity}${it.unit ? ' ' + it.unit : ''}`
|
|
: it.qty || '--',
|
|
status: it.status || 'pending',
|
|
time: (it.createDate || it.createTime || '').toString().slice(0, 16),
|
|
raw: it
|
|
}
|
|
}
|
|
|
|
export const useInquiryStore = defineStore('inquiry', () => {
|
|
const list = ref<Inquiry[]>([])
|
|
const total = ref(0)
|
|
const page = ref(1)
|
|
const limit = ref(20)
|
|
const statusFilter = ref<string>('')
|
|
const loading = ref(false)
|
|
const error = ref<string | null>(null)
|
|
const lastFetchedAt = ref(0)
|
|
const isLive = ref(false)
|
|
|
|
const pageCount = computed(() => Math.max(1, Math.ceil(total.value / limit.value)))
|
|
|
|
async function fetchList(force = false) {
|
|
if (loading.value) return
|
|
if (!force && lastFetchedAt.value && Date.now() - lastFetchedAt.value < 60 * 1000) {
|
|
return
|
|
}
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
const data = await httpGet<any[]>('/sys/openapi/inquiry/list', {
|
|
page: page.value,
|
|
limit: limit.value,
|
|
...(statusFilter.value ? { status: statusFilter.value } : {})
|
|
})
|
|
list.value = (Array.isArray(data) ? data : []).map(normalizeInquiry)
|
|
total.value = list.value.length + (page.value - 1) * limit.value // 简化 total(后端不返)
|
|
isLive.value = true
|
|
lastFetchedAt.value = Date.now()
|
|
} catch (e: any) {
|
|
error.value = e?.msg || e?.message || '询价列表加载失败'
|
|
isLive.value = false
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 详情优先复用 store.list 缓存(W2 D4 踩坑:后端 /info 期望 Long 不接受雪花 ID 字符串)
|
|
* 不命中再调 fetchOne
|
|
*/
|
|
async function fetchOne(id: string): Promise<Inquiry | null> {
|
|
try {
|
|
const data = await httpGet<any>(`/sys/openapi/inquiry/${id}`)
|
|
return data ? normalizeInquiry(data) : null
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* W3.4 报价:POST /sys/openapi/inquiry/quote
|
|
* 入参 id + price + remark
|
|
* 业务异常交给调用方处理(用 try/catch,err.msg 给 toast)
|
|
*/
|
|
async function quote(id: string, price: number, remark: string): Promise<any> {
|
|
return await httpPost<any>('/sys/openapi/inquiry/quote', { id, price, remark })
|
|
}
|
|
|
|
function setStatusFilter(s: string) {
|
|
statusFilter.value = s
|
|
page.value = 1
|
|
}
|
|
function setPage(p: number) {
|
|
page.value = p
|
|
}
|
|
|
|
return {
|
|
list, total, page, limit, statusFilter, loading, error, isLive, pageCount,
|
|
lastFetchedAt,
|
|
fetchList, fetchOne, quote, setStatusFilter, setPage
|
|
}
|
|
})
|