admin_new/src/stores/inquiry.ts
Sisyphus 59a235d56c feat(F006-W5xx5): 关键 view 完整化 (沿用老 vue 字段/操作/弹窗) + W3.x C 补 commit
用户原话: 不是让你沿用老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)
2026-07-05 12:12:41 +08:00

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
}
})