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 = { 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([]) const total = ref(0) const page = ref(1) const limit = ref(20) const statusFilter = ref('') const loading = ref(false) const error = ref(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('/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 { try { const data = await httpGet(`/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 { return await httpPost('/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 } })