feat(F006-W15): 订单售后/退款/支付回调 3 view 接前端 max-effort mock + 同步 DataTable selection
This commit is contained in:
parent
b3018fe7d7
commit
04d3992c52
@ -44,7 +44,7 @@ interface Column {
|
||||
label: string
|
||||
width?: number | string
|
||||
minWidth?: number | string
|
||||
type?: 'status' | 'text'
|
||||
type?: 'status' | 'text' | 'selection'
|
||||
statusMap?: Record<string, { label: string; type: string }>
|
||||
slot?: string
|
||||
formatter?: (row: any) => string
|
||||
@ -87,6 +87,7 @@ const emit = defineEmits<{
|
||||
(e: 'row-click', row: any): void
|
||||
(e: 'page-change', page: number): void
|
||||
(e: 'limit-change', limit: number): void
|
||||
(e: 'selection-change', rows: any[]): void
|
||||
}>()
|
||||
|
||||
const hasStatusCol = computed(() => props.columns.some(c => c.type === 'status'))
|
||||
@ -97,6 +98,7 @@ function getStatusMeta(col: Column, value: string) {
|
||||
return col.statusMap?.[value] || { label: value || '--', type: 'info' }
|
||||
}
|
||||
|
||||
function onSelectionChange(rows: any[]) { emit('selection-change', rows) }
|
||||
function onRowClick(row: any) {
|
||||
emit('row-click', row)
|
||||
}
|
||||
@ -118,6 +120,7 @@ function onLimitChange(l: number) {
|
||||
:row-key="rowKey"
|
||||
style="width: 100%"
|
||||
@row-click="onRowClick"
|
||||
@selection-change="onSelectionChange"
|
||||
row-class-name="rr-clickable-row"
|
||||
:header-row-style="{ height: '40px' }"
|
||||
:row-style="{ height: '52px' }"
|
||||
@ -141,9 +144,15 @@ function onLimitChange(l: number) {
|
||||
height: '52px'
|
||||
}"
|
||||
>
|
||||
<template v-for="(col, idx) in columns" :key="idx">
|
||||
<el-table-column
|
||||
v-for="(col, idx) in columns"
|
||||
:key="idx"
|
||||
v-if="col.type === 'selection'"
|
||||
type="selection"
|
||||
:width="col.width || 50"
|
||||
:align="col.align || 'center'"
|
||||
/>
|
||||
<el-table-column
|
||||
v-else
|
||||
:prop="col.type === 'status' || col.slot ? undefined : col.prop"
|
||||
:label="col.label"
|
||||
:width="col.width"
|
||||
@ -167,6 +176,7 @@ function onLimitChange(l: number) {
|
||||
{{ col.formatter?.(row) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
|
||||
<template #empty>
|
||||
<div class="rr-empty">
|
||||
|
||||
@ -71,6 +71,9 @@ export const MENU_LABELS: MenuLabel[] = [
|
||||
{ url: 'order/ordergood-commission', label: '实物订单分佣统计', icon: 'Coin', path: '/order/ordergood/commission', sort: 220 },
|
||||
{ url: 'order/serviceorder-commission', label: '服务订单分佣统计', icon: 'Coin', path: '/order/serviceorder/commission', sort: 221 },
|
||||
{ url: 'order/orderbase-price-analysis', label: '基础价格分析表', icon: 'TrendCharts', path: '/order/base-price-analysis', sort: 230 },
|
||||
{ url: 'order/orderpay', label: '订单支付回调', icon: 'Wallet', path: '/order/orderpay', sort: 240 },
|
||||
{ url: 'order/refund', label: '订单退款管理', icon: 'Refresh', path: '/order/refund', sort: 250 },
|
||||
{ url: 'order/aftersale', label: '售后订单', icon: 'Service', path: '/order/aftersale', sort: 260 },
|
||||
|
||||
// ===== 供应商模块 =====
|
||||
{ url: 'supplier/good', label: '实物商品', icon: 'Box', path: '/supplier/good', sort: 300 },
|
||||
|
||||
220
src/modules/order/aftersale/AftersaleListView.vue
Normal file
220
src/modules/order/aftersale/AftersaleListView.vue
Normal file
@ -0,0 +1,220 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* F006 实物订单售后 - W15.5
|
||||
*
|
||||
* 沿用老 vue order/orderafter.vue 字段:
|
||||
* afterSalesOrderId / shopType / afterSaleType / enterpriseName / name / title
|
||||
* returnQuantity / totalAmount / requestTime / status (1=发起 2=处理中 3=同意 4=不同意 5=寄回 6=完成 7=取消)
|
||||
*
|
||||
* 端点: /order/aftersale/page 探测; 404 → FALLBACK seed (14 条)
|
||||
*/
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { httpGet } from '@/utils/request'
|
||||
import PageHeader from '@/components/PageHeader/PageHeader.vue'
|
||||
import SearchBar from '@/components/SearchBar/SearchBar.vue'
|
||||
import DataTable from '@/components/DataTable/DataTable.vue'
|
||||
|
||||
interface AftersaleRow {
|
||||
afterSalesOrderId: string
|
||||
shopType: number
|
||||
afterSaleType: number
|
||||
enterpriseName: string
|
||||
name: string
|
||||
title: string
|
||||
returnQuantity: number
|
||||
totalAmount: number
|
||||
requestTime: string
|
||||
status: number
|
||||
reason: string
|
||||
}
|
||||
|
||||
const SHOP_LABEL: Record<number, string> = { 1: '实物商品', 2: '服务商品', 3: '拼团商品', 4: '虚拟商品' }
|
||||
const TYPE_LABEL: Record<number, string> = { 1: '仅退款', 2: '退货退款', 3: '换货', 4: '维修' }
|
||||
const STATUS_LABEL: Record<number, string> = { 1: '发起申请', 2: '处理中', 3: '同意退/换', 4: '不同意', 5: '货物寄回', 6: '完成', 7: '取消' }
|
||||
const STATUS_TYPE: Record<number, string> = { 1:'warning', 2:'primary', 3:'success', 4:'danger', 5:'info', 6:'success', 7:'info' }
|
||||
|
||||
const ENDPOINTS = ['/order/aftersale/page', '/order/aftersale/list', '/order/aftersale/search', '/order/aftersale/queryPage']
|
||||
|
||||
const FALLBACK: AftersaleRow[] = [
|
||||
{ afterSalesOrderId:'AS20260701001', shopType:1, afterSaleType:2, enterpriseName:'坚美建筑材料有限公司', name:'张老板', title:'国标槽钢 10# 6m 热镀锌', returnQuantity:5, totalAmount:3450.00, requestTime:'2026-07-01 14:20:00', status:3, reason:'型号发错' },
|
||||
{ afterSalesOrderId:'AS20260701002', shopType:1, afterSaleType:1, enterpriseName:'华建门窗厂', name:'李工', title:'断桥铝平开窗 60系列', returnQuantity:2, totalAmount:1800.00, requestTime:'2026-07-02 09:18:42', status:6, reason:'协商退款' },
|
||||
{ afterSalesOrderId:'AS20260702001', shopType:1, afterSaleType:2, enterpriseName:'融鑫管业', name:'王经理', title:'PPR给水管 dn25 4m', returnQuantity:20, totalAmount:1260.00, requestTime:'2026-07-02 16:32:11', status:2, reason:'包装破损' },
|
||||
{ afterSalesOrderId:'AS20260702002', shopType:1, afterSaleType:4, enterpriseName:'东方五金机械', name:'赵师傅', title:'电锤 GBH 2-28 800W', returnQuantity:1, totalAmount:680.00, requestTime:'2026-07-03 11:42:30', status:4, reason:'已过维保期' },
|
||||
{ afterSalesOrderId:'AS20260703001', shopType:1, afterSaleType:3, enterpriseName:'美洁涂料', name:'陈女士', title:'环保内墙乳胶漆 5L', returnQuantity:4, totalAmount:920.00, requestTime:'2026-07-03 13:28:00', status:5, reason:'颜色偏差' },
|
||||
{ afterSalesOrderId:'AS20260703002', shopType:1, afterSaleType:2, enterpriseName:'万家灯具', name:'周总', title:'LED投光灯 200W IP65', returnQuantity:3, totalAmount:1080.00, requestTime:'2026-07-04 08:15:55', status:1, reason:'不亮灯' },
|
||||
{ afterSalesOrderId:'AS20260704001', shopType:2, afterSaleType:1, enterpriseName:'顺达物流', name:'吴先生', title:'同城配送服务 (50km内)', returnQuantity:1, totalAmount:280.00, requestTime:'2026-07-04 16:48:22', status:7, reason:'客户主动取消' },
|
||||
{ afterSalesOrderId:'AS20260704002', shopType:1, afterSaleType:2, enterpriseName:'华建门窗厂', name:'林总', title:'铝合金推拉门 90系列', returnQuantity:1, totalAmount:2880.00, requestTime:'2026-07-05 10:14:42', status:3, reason:'尺寸不符' },
|
||||
{ afterSalesOrderId:'AS20260705001', shopType:3, afterSaleType:1, enterpriseName:'众成厨具', name:'黄总', title:'不锈钢汤锅 30cm', returnQuantity:1, totalAmount:128.00, requestTime:'2026-07-05 14:30:00', status:6, reason:'拼团失败退款' },
|
||||
{ afterSalesOrderId:'AS20260705002', shopType:1, afterSaleType:4, enterpriseName:'东方五金机械', name:'何师傅', title:'角磨机 100mm 720W', returnQuantity:1, totalAmount:380.00, requestTime:'2026-07-06 09:25:00', status:2, reason:'电机异响' },
|
||||
{ afterSalesOrderId:'AS20260706001', shopType:1, afterSaleType:2, enterpriseName:'坚美建筑材料', name:'钱老板', title:'国标角钢 50×5 6m', returnQuantity:8, totalAmount:2240.00, requestTime:'2026-07-06 11:02:18', status:3, reason:'厚度偏差' },
|
||||
{ afterSalesOrderId:'AS20260706002', shopType:1, afterSaleType:1, enterpriseName:'美洁涂料', name:'孙总', title:'环保外墙腻子粉 25kg', returnQuantity:6, totalAmount:780.00, requestTime:'2026-07-06 15:48:32', status:1, reason:'施工后剩余' },
|
||||
{ afterSalesOrderId:'AS20260706003', shopType:1, afterSaleType:2, enterpriseName:'融鑫管业', name:'李经理', title:'PE给水管 dn32 6m', returnQuantity:12, totalAmount:960.00, requestTime:'2026-07-06 17:33:21', status:2, reason:'现场清点异常' },
|
||||
{ afterSalesOrderId:'AS20260706004', shopType:2, afterSaleType:1, enterpriseName:'顺达物流', name:'郑总', title:'异地整车运输', returnQuantity:1, totalAmount:1680.00, requestTime:'2026-07-06 18:55:08', status:1, reason:'时效不达标' }
|
||||
]
|
||||
|
||||
const STATUS_TABS = [
|
||||
{ value: '', label: '全部' },
|
||||
{ value: '1', label: '发起申请' },
|
||||
{ value: '2', label: '处理中' },
|
||||
{ value: '3', label: '已同意' },
|
||||
{ value: '4', label: '已拒绝' },
|
||||
{ value: '5', label: '货物寄回' },
|
||||
{ value: '6', label: '已完成' },
|
||||
{ value: '7', label: '已取消' }
|
||||
]
|
||||
|
||||
type Col = {
|
||||
prop?: string; label: string; width?: number; slot?: string; fixed?: 'right' | true; type?: 'status' | 'text' | 'selection'
|
||||
}
|
||||
const columns: Col[] = [
|
||||
{ prop: 'afterSalesOrderId', label: '售后订单号', width: 180, fixed: true, slot: 'orderId' },
|
||||
{ type: 'status', prop: 'shopType', label: '商品类型', width: 110 },
|
||||
{ type: 'status', prop: 'afterSaleType', label: '售后类型', width: 100 },
|
||||
{ prop: 'enterpriseName', label: '供应商信息', width: 200 },
|
||||
{ prop: 'name', label: '用户信息', width: 120 },
|
||||
{ prop: 'title', label: '商品信息', width: 240, slot: 'title' },
|
||||
{ prop: 'returnQuantity', label: '售后数量', width: 90 },
|
||||
{ prop: 'totalAmount', label: '退款金额', width: 110 },
|
||||
{ prop: 'requestTime', label: '创建时间', width: 160, slot: 'time' },
|
||||
{ type: 'status', prop: 'status', label: '订单状态', width: 110 },
|
||||
{ prop: 'reason', label: '售后原因', width: 200, slot: 'reason' },
|
||||
{ prop: 'actions', label: '操作', width: 220, fixed: 'right', slot: 'actions' }
|
||||
]
|
||||
|
||||
const list = ref<AftersaleRow[]>([])
|
||||
const total = ref(0)
|
||||
const loading = ref(false)
|
||||
const page = ref(1)
|
||||
const limit = ref(10)
|
||||
const filterKw = ref('')
|
||||
const statusTab = ref('')
|
||||
const dataSource = ref<'api' | 'mock' | 'loading'>('loading')
|
||||
const apiError = ref<string>('')
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
dataSource.value = 'loading'
|
||||
for (const ep of ENDPOINTS) {
|
||||
try {
|
||||
const params: any = { page: page.value, limit: limit.value }
|
||||
const data: any = await httpGet<any>(ep, params)
|
||||
const rows: AftersaleRow[] = (data?.list || []).map((it: any) => ({ ...it }))
|
||||
list.value = rows
|
||||
total.value = Number(data?.total || rows.length)
|
||||
dataSource.value = 'api'
|
||||
apiError.value = ''
|
||||
loading.value = false
|
||||
return
|
||||
} catch {}
|
||||
}
|
||||
list.value = [...FALLBACK]
|
||||
total.value = FALLBACK.length
|
||||
dataSource.value = 'mock'
|
||||
apiError.value = '后端 API 暂未实装, 已加载前端示例数据'
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const filtered = computed(() => {
|
||||
const kw = filterKw.value.trim().toLowerCase()
|
||||
let rows = list.value
|
||||
if (statusTab.value) rows = rows.filter(r => String(r.status) === statusTab.value)
|
||||
if (kw) rows = rows.filter(r =>
|
||||
String(r.afterSalesOrderId).toLowerCase().includes(kw) ||
|
||||
String(r.enterpriseName).toLowerCase().includes(kw) ||
|
||||
String(r.name).toLowerCase().includes(kw) ||
|
||||
String(r.title).toLowerCase().includes(kw)
|
||||
)
|
||||
return rows
|
||||
})
|
||||
|
||||
const searchFields: Array<{ key: string; label: string; type: 'text' }> = [
|
||||
{ key: 'afterSalesOrderId', label: '售后订单号', type: 'text' },
|
||||
{ key: 'enterpriseName', label: '供应商', type: 'text' },
|
||||
{ key: 'title', label: '商品名', type: 'text' }
|
||||
]
|
||||
|
||||
const filters = reactive<Record<string, any>>({})
|
||||
function onSearch() {
|
||||
filterKw.value = String(filters.afterSalesOrderId || filters.enterpriseName || filters.title || '')
|
||||
page.value = 1
|
||||
}
|
||||
function onStatusTab(v: string) { statusTab.value = v; page.value = 1 }
|
||||
|
||||
async function onAgree(row: AftersaleRow) {
|
||||
try { await ElMessageBox.confirm(`确认通过售后申请「${row.afterSalesOrderId}」?`, '提示', { type: 'warning' }) } catch { return }
|
||||
row.status = 3
|
||||
ElMessage.success('已通过 (前端示例)')
|
||||
}
|
||||
async function onReject(row: AftersaleRow) {
|
||||
try {
|
||||
const { value } = await ElMessageBox.prompt('请填写拒绝原因', '拒绝售后', { inputPlaceholder: '原因', confirmButtonText: '拒绝', cancelButtonText: '取消' })
|
||||
row.status = 4
|
||||
row.reason = (value || '已拒绝').trim()
|
||||
ElMessage.success('已拒绝 (前端示例)')
|
||||
} catch {}
|
||||
}
|
||||
async function onComplete(row: AftersaleRow) {
|
||||
row.status = 6
|
||||
ElMessage.success('已标记完成')
|
||||
}
|
||||
function onView(row: AftersaleRow) {
|
||||
ElMessage.info(`打开售后详情 ${row.afterSalesOrderId}`)
|
||||
}
|
||||
function onExport() {
|
||||
ElMessage.success('已发起导出 (前端示例, 共 ' + filtered.value.length + ' 条)')
|
||||
}
|
||||
|
||||
onMounted(load)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="rr-page">
|
||||
<PageHeader title="实物订单售后" sub="实物商品的退/换/修售后流程审核" :data-source="dataSource" :api-error="apiError">
|
||||
<el-button type="primary" @click="onExport">导出明细</el-button>
|
||||
</PageHeader>
|
||||
|
||||
<el-tabs v-model="statusTab" @tab-change="onStatusTab" class="rr-tabs">
|
||||
<el-tab-pane v-for="t in STATUS_TABS" :key="t.value" :name="t.value" :label="t.label" />
|
||||
</el-tabs>
|
||||
|
||||
<SearchBar v-model:filters="filters" :fields="searchFields" @search="onSearch" />
|
||||
|
||||
<DataTable
|
||||
:columns="columns"
|
||||
:data="filtered"
|
||||
:loading="loading"
|
||||
:page="page"
|
||||
:limit="limit"
|
||||
:total="total"
|
||||
row-key="afterSalesOrderId"
|
||||
@page-change="(p: number) => { page = p; load() }"
|
||||
@limit-change="(l: number) => { limit = l; page = 1; load() }"
|
||||
>
|
||||
<template #orderId="{ row }">
|
||||
<el-link type="primary" :underline="false" @click="onView(row)">{{ row.afterSalesOrderId }}</el-link>
|
||||
</template>
|
||||
<template #title="{ row }">
|
||||
<span :class="{ 'rr-muted': !row.title }">{{ row.title || '--' }}</span>
|
||||
</template>
|
||||
<template #time="{ row }">{{ row.requestTime }}</template>
|
||||
<template #reason="{ row }">
|
||||
<span :class="{ 'rr-muted': !row.reason }">{{ row.reason || '--' }}</span>
|
||||
</template>
|
||||
<template #actions="{ row }">
|
||||
<template v-if="row.status === 1 || row.status === 2">
|
||||
<el-button type="success" link @click="onAgree(row)">同意</el-button>
|
||||
<el-button type="danger" link @click="onReject(row)">拒绝</el-button>
|
||||
</template>
|
||||
<el-button v-if="row.status === 5" type="success" link @click="onComplete(row)">确认收货完成</el-button>
|
||||
<el-button type="primary" link @click="onView(row)">详情</el-button>
|
||||
</template>
|
||||
</DataTable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.rr-page { padding: 16px; }
|
||||
.rr-tabs { margin-bottom: 12px; }
|
||||
.rr-muted { color: var(--ink-muted); }
|
||||
</style>
|
||||
214
src/modules/order/payment/PaymentCallbackListView.vue
Normal file
214
src/modules/order/payment/PaymentCallbackListView.vue
Normal file
@ -0,0 +1,214 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* F006 订单支付回调列表 - W15.2
|
||||
*
|
||||
* 沿用老 vue order/orderpay.vue 字段:
|
||||
* - 选择 + id + orderUserId + userType + orderId + goodDetailId
|
||||
* - orderGoodId + orderBatchId + payStatus + sum + couponMoney + couponId
|
||||
* - freight + payMoney + unitPrice + totalNum + payDate + isDel + pickupType
|
||||
*
|
||||
* 端点: /order/orderpay/page 探测 (按 5.18 4 URL + 老 vue 字段口径)
|
||||
* 端点 404 → 用 FALLBACK 前端 seed 数据 (15 条)
|
||||
*
|
||||
* 状态: payStatus 1=预付款 2=发货款 3=到货款 4=安装款 5=结算款 6=质保金 7=已结束
|
||||
*/
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { httpGet } from '@/utils/request'
|
||||
import PageHeader from '@/components/PageHeader/PageHeader.vue'
|
||||
import SearchBar from '@/components/SearchBar/SearchBar.vue'
|
||||
import DataTable from '@/components/DataTable/DataTable.vue'
|
||||
|
||||
interface PaymentRow {
|
||||
id: string
|
||||
orderUserId: string
|
||||
userType: number
|
||||
orderId: string
|
||||
goodDetailId: string
|
||||
orderGoodId: string
|
||||
orderBatchId: string
|
||||
payStatus: number
|
||||
sum: number
|
||||
couponMoney: number
|
||||
couponId: string
|
||||
freight: number
|
||||
payMoney: number
|
||||
unitPrice: number
|
||||
totalNum: number
|
||||
payDate: string
|
||||
isDel: number
|
||||
pickupType: number
|
||||
}
|
||||
|
||||
const PAY_STATUS_LABEL: Record<number, string> = {
|
||||
1: '预付款', 2: '发货款', 3: '到货款', 4: '安装款', 5: '结算款', 6: '质保金', 7: '已结束'
|
||||
}
|
||||
|
||||
const PICKUP_LABEL: Record<number, string> = { 1: '商家配送', 2: '买家自提' }
|
||||
const USER_TYPE_LABEL: Record<number, string> = { 1: 'C端用户', 2: '供应链' }
|
||||
|
||||
// 端点探测 (W5.18 教训: 4 URL 试探 + 老 vue 字段口径, 找不到走 FALLBACK seed)
|
||||
const ENDPOINTS = ['/order/orderpay/page', '/order/orderpay/list', '/order/orderpay/search', '/order/orderpay/queryPage']
|
||||
|
||||
const FALLBACK: PaymentRow[] = [
|
||||
{ id:'OP001', orderUserId:'u10086', userType:1, orderId:'O001', goodDetailId:'GD101', orderGoodId:'OG201', orderBatchId:'OB301', payStatus:7, sum:12800.00, couponMoney:300.00, couponId:'C202501', freight:0, payMoney:12500.00, unitPrice:1280.00, totalNum:10, payDate:'2026-07-01 14:32:11', isDel:0, pickupType:1 },
|
||||
{ id:'OP002', orderUserId:'u10112', userType:2, orderId:'O002', goodDetailId:'GD102', orderGoodId:'OG202', orderBatchId:'OB302', payStatus:3, sum:5600.00, couponMoney:0, couponId:'', freight:80.00, payMoney:5680.00, unitPrice:560.00, totalNum:10, payDate:'2026-07-02 09:18:42', isDel:0, pickupType:1 },
|
||||
{ id:'OP003', orderUserId:'u10133', userType:1, orderId:'O003', goodDetailId:'GD103', orderGoodId:'OG203', orderBatchId:'OB303', payStatus:5, sum:8800.00, couponMoney:200.00, couponId:'C202503', freight:100.00, payMoney:8700.00, unitPrice:880.00, totalNum:10, payDate:'2026-06-28 16:45:00', isDel:0, pickupType:1 },
|
||||
{ id:'OP004', orderUserId:'u10144', userType:1, orderId:'O004', goodDetailId:'GD104', orderGoodId:'OG204', orderBatchId:'OB304', payStatus:7, sum:2200.00, couponMoney:0, couponId:'', freight:0, payMoney:2200.00, unitPrice:220.00, totalNum:10, payDate:'2026-07-03 11:02:18', isDel:0, pickupType:2 },
|
||||
{ id:'OP005', orderUserId:'u10155', userType:2, orderId:'O005', goodDetailId:'GD105', orderGoodId:'OG205', orderBatchId:'OB305', payStatus:6, sum:4500.00, couponMoney:150.00, couponId:'C202505', freight:60.00, payMoney:4410.00, unitPrice:450.00, totalNum:10, payDate:'2026-07-04 08:30:55', isDel:0, pickupType:1 },
|
||||
{ id:'OP006', orderUserId:'u10166', userType:1, orderId:'O006', goodDetailId:'GD106', orderGoodId:'OG206', orderBatchId:'OB306', payStatus:2, sum:13800.00, couponMoney:500.00, couponId:'C202506', freight:200.00, payMoney:13500.00, unitPrice:1380.00, totalNum:10, payDate:'2026-07-05 13:25:30', isDel:0, pickupType:1 },
|
||||
{ id:'OP007', orderUserId:'u10177', userType:1, orderId:'O007', goodDetailId:'GD107', orderGoodId:'OG207', orderBatchId:'OB307', payStatus:4, sum:3200.00, couponMoney:0, couponId:'', freight:0, payMoney:3200.00, unitPrice:320.00, totalNum:10, payDate:'2026-07-06 10:12:00', isDel:0, pickupType:2 },
|
||||
{ id:'OP008', orderUserId:'u10188', userType:2, orderId:'O008', goodDetailId:'GD108', orderGoodId:'OG208', orderBatchId:'OB308', payStatus:1, sum:6800.00, couponMoney:0, couponId:'', freight:120.00, payMoney:6920.00, unitPrice:680.00, totalNum:10, payDate:'', isDel:0, pickupType:1 },
|
||||
{ id:'OP009', orderUserId:'u10199', userType:1, orderId:'O009', goodDetailId:'GD109', orderGoodId:'OG209', orderBatchId:'OB309', payStatus:3, sum:9800.00, couponMoney:280.00, couponId:'C202509', freight:0, payMoney:9520.00, unitPrice:980.00, totalNum:10, payDate:'2026-07-02 15:48:22', isDel:0, pickupType:1 },
|
||||
{ id:'OP010', orderUserId:'u10210', userType:1, orderId:'O010', goodDetailId:'GD110', orderGoodId:'OG210', orderBatchId:'OB310', payStatus:7, sum:5400.00, couponMoney:100.00, couponId:'C202510', freight:60.00, payMoney:5360.00, unitPrice:540.00, totalNum:10, payDate:'2026-06-30 12:30:00', isDel:0, pickupType:1 },
|
||||
{ id:'OP011', orderUserId:'u10221', userType:2, orderId:'O011', goodDetailId:'GD111', orderGoodId:'OG211', orderBatchId:'OB311', payStatus:5, sum:18800.00, couponMoney:600.00, couponId:'C202511', freight:300.00, payMoney:18500.00, unitPrice:1880.00, totalNum:10, payDate:'2026-07-03 09:55:08', isDel:0, pickupType:1 },
|
||||
{ id:'OP012', orderUserId:'u10232', userType:1, orderId:'O012', goodDetailId:'GD112', orderGoodId:'OG212', orderBatchId:'OB312', payStatus:6, sum:2400.00, couponMoney:0, couponId:'', freight:0, payMoney:2400.00, unitPrice:240.00, totalNum:10, payDate:'2026-07-04 16:20:14', isDel:0, pickupType:2 },
|
||||
{ id:'OP013', orderUserId:'u10243', userType:1, orderId:'O013', goodDetailId:'GD113', orderGoodId:'OG213', orderBatchId:'OB313', payStatus:7, sum:7200.00, couponMoney:240.00, couponId:'C202513', freight:80.00, payMoney:7040.00, unitPrice:720.00, totalNum:10, payDate:'2026-06-25 11:42:35', isDel:0, pickupType:1 },
|
||||
{ id:'OP014', orderUserId:'u10254', userType:2, orderId:'O014', goodDetailId:'GD114', orderGoodId:'OG214', orderBatchId:'OB314', payStatus:2, sum:11500.00, couponMoney:400.00, couponId:'C202514', freight:180.00, payMoney:11280.00, unitPrice:1150.00, totalNum:10, payDate:'2026-07-05 14:18:50', isDel:0, pickupType:1 },
|
||||
{ id:'OP015', orderUserId:'u10265', userType:1, orderId:'O015', goodDetailId:'GD115', orderGoodId:'OG215', orderBatchId:'OB315', payStatus:4, sum:4400.00, couponMoney:0, couponId:'', freight:50.00, payMoney:4450.00, unitPrice:440.00, totalNum:10, payDate:'2026-07-06 17:33:21', isDel:0, pickupType:2 }
|
||||
]
|
||||
|
||||
const STATUS_TABS = [
|
||||
{ value: '', label: '全部' },
|
||||
{ value: '1', label: '预付款' },
|
||||
{ value: '2', label: '发货款' },
|
||||
{ value: '3', label: '到货款' },
|
||||
{ value: '4', label: '安装款' },
|
||||
{ value: '5', label: '结算款' },
|
||||
{ value: '6', label: '质保金' },
|
||||
{ value: '7', label: '已结束' }
|
||||
]
|
||||
|
||||
type Col = {
|
||||
prop?: string; label: string; width?: number; slot?: string; fixed?: 'right' | true; type?: 'status' | 'text' | 'selection'
|
||||
}
|
||||
const columns: Col[] = [
|
||||
{ prop: 'id', label: 'ID', width: 90, fixed: true },
|
||||
{ prop: 'orderId', label: '订单编号', width: 180, slot: 'orderId' },
|
||||
{ prop: 'orderUserId', label: '用户ID', width: 100 },
|
||||
{ type: 'status', prop: 'userType', label: '用户类型', width: 100 },
|
||||
{ prop: 'orderGoodId', label: '小订单ID', width: 120 },
|
||||
{ type: 'status', prop: 'payStatus', label: '款项流程', width: 110 },
|
||||
{ prop: 'sum', label: '优惠前金额', width: 110 },
|
||||
{ prop: 'couponMoney', label: '优惠金额', width: 100 },
|
||||
{ prop: 'freight', label: '运费', width: 80 },
|
||||
{ prop: 'payMoney', label: '实际支付', width: 110 },
|
||||
{ prop: 'unitPrice', label: '单价', width: 90 },
|
||||
{ prop: 'totalNum', label: '待发货总数', width: 100 },
|
||||
{ type: 'status', prop: 'pickupType', label: '配送方式', width: 110 },
|
||||
{ prop: 'payDate', label: '支付时间', width: 160, slot: 'time' },
|
||||
{ prop: 'actions', label: '操作', width: 180, fixed: 'right', slot: 'actions' }
|
||||
]
|
||||
|
||||
const list = ref<PaymentRow[]>([])
|
||||
const total = ref(0)
|
||||
const loading = ref(false)
|
||||
const page = ref(1)
|
||||
const limit = ref(10)
|
||||
const filterKw = ref('')
|
||||
const statusTab = ref('')
|
||||
const dataSource = ref<'api' | 'mock' | 'loading'>('loading')
|
||||
const apiError = ref<string>('')
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
dataSource.value = 'loading'
|
||||
for (const ep of ENDPOINTS) {
|
||||
try {
|
||||
const params: any = { page: page.value, limit: limit.value }
|
||||
if (statusTab.value) params.payStatus = Number(statusTab.value)
|
||||
const data: any = await httpGet<any>(ep, params)
|
||||
const rows: PaymentRow[] = (data?.list || []).map((it: any) => ({ ...it, raw: it }))
|
||||
list.value = rows
|
||||
total.value = Number(data?.total || rows.length)
|
||||
dataSource.value = 'api'
|
||||
apiError.value = ''
|
||||
loading.value = false
|
||||
return
|
||||
} catch {}
|
||||
}
|
||||
// 全部失败 → 前端 seed
|
||||
list.value = [...FALLBACK]
|
||||
total.value = FALLBACK.length
|
||||
dataSource.value = 'mock'
|
||||
apiError.value = '后端 API 暂未实装, 已加载前端示例数据'
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const filtered = computed(() => {
|
||||
const kw = filterKw.value.trim().toLowerCase()
|
||||
let rows = list.value
|
||||
if (statusTab.value) rows = rows.filter(r => String(r.payStatus) === statusTab.value)
|
||||
if (kw) rows = rows.filter(r =>
|
||||
String(r.id).toLowerCase().includes(kw) ||
|
||||
String(r.orderId).toLowerCase().includes(kw) ||
|
||||
String(r.orderGoodId).toLowerCase().includes(kw)
|
||||
)
|
||||
return rows
|
||||
})
|
||||
|
||||
const searchFields: Array<{ key: string; label: string; type: 'text'; placeholder?: string }> = [
|
||||
{ key: 'id', label: 'ID', type: 'text', placeholder: '支付ID' },
|
||||
{ key: 'orderId', label: '订单ID', type: 'text', placeholder: '订单ID' },
|
||||
{ key: 'orderGoodId', label: '小订单ID', type: 'text', placeholder: '小订单ID' }
|
||||
]
|
||||
|
||||
const filters = reactive<Record<string, any>>({})
|
||||
function onSearch() {
|
||||
filterKw.value = String(filters.id || filters.orderId || filters.orderGoodId || '')
|
||||
page.value = 1
|
||||
}
|
||||
function onStatusTab(v: string) { statusTab.value = v; page.value = 1 }
|
||||
async function onMarkPaid(row: PaymentRow) {
|
||||
try { await ElMessageBox.confirm(`确认「${row.id}」该款项标记为已支付?`, '提示', { type: 'warning' }) } catch { return }
|
||||
ElMessage.success('已标记 (前端示例)')
|
||||
}
|
||||
function onViewOrder(row: PaymentRow) {
|
||||
ElMessage.info(`打开订单 ${row.orderId}`)
|
||||
}
|
||||
function onExport() {
|
||||
ElMessage.success('已发起导出 (前端示例, 共 ' + filtered.value.length + ' 条)')
|
||||
}
|
||||
|
||||
onMounted(load)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="rr-page">
|
||||
<PageHeader title="订单支付回调" sub="实物订单分阶段支付款项管理" :data-source="dataSource" :api-error="apiError">
|
||||
<el-button type="primary" @click="onExport">导出明细</el-button>
|
||||
</PageHeader>
|
||||
|
||||
<el-tabs v-model="statusTab" @tab-change="onStatusTab" class="rr-tabs">
|
||||
<el-tab-pane v-for="t in STATUS_TABS" :key="t.value" :name="t.value" :label="t.label" />
|
||||
</el-tabs>
|
||||
|
||||
<SearchBar v-model:filters="filters" :fields="searchFields" @search="onSearch" />
|
||||
|
||||
<DataTable
|
||||
:columns="columns"
|
||||
:data="filtered"
|
||||
:loading="loading"
|
||||
:page="page"
|
||||
:limit="limit"
|
||||
:total="total"
|
||||
row-key="id"
|
||||
@page-change="(p: number) => { page = p; load() }"
|
||||
@limit-change="(l: number) => { limit = l; page = 1; load() }"
|
||||
>
|
||||
<template #orderId="{ row }">
|
||||
<el-link type="primary" :underline="false" @click="onViewOrder(row)">{{ row.orderId }}</el-link>
|
||||
</template>
|
||||
<template #time="{ row }">{{ row.payDate || '--' }}</template>
|
||||
<template #actions="{ row }">
|
||||
<el-button type="primary" link @click="onViewOrder(row)">详情</el-button>
|
||||
<el-button v-if="row.payStatus !== 7" type="success" link @click="onMarkPaid(row)">标记已付</el-button>
|
||||
</template>
|
||||
</DataTable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.rr-page { padding: 16px; }
|
||||
.rr-tabs { margin-bottom: 12px; }
|
||||
</style>
|
||||
212
src/modules/order/refund/RefundProcessListView.vue
Normal file
212
src/modules/order/refund/RefundProcessListView.vue
Normal file
@ -0,0 +1,212 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* F006 订单退款管理 - W15.3
|
||||
*
|
||||
* 沿用老 vue order/orderrefund.vue 字段:
|
||||
* - 选择 + id + userId + supplierId + userEnterpriseId + enterpriseId
|
||||
* - supplierOrderCode + payStatus + payMoney + refundTime + requestTime + remark + delFlag
|
||||
*
|
||||
* 端点: /order/refund/page 探测; 404 → FALLBACK seed (12 条)
|
||||
*
|
||||
* 状态: payStatus 1=待支付 2=已支付 / 退款处理状态: 审核中/已退款/已拒绝
|
||||
*/
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { httpGet } from '@/utils/request'
|
||||
import PageHeader from '@/components/PageHeader/PageHeader.vue'
|
||||
import SearchBar from '@/components/SearchBar/SearchBar.vue'
|
||||
import DataTable from '@/components/DataTable/DataTable.vue'
|
||||
|
||||
interface RefundRow {
|
||||
id: string
|
||||
userId: string
|
||||
supplierId: string
|
||||
userEnterpriseId: string
|
||||
enterpriseId: string
|
||||
supplierOrderCode: string
|
||||
payStatus: number
|
||||
payMoney: number
|
||||
refundTime: string
|
||||
requestTime: string
|
||||
remark: string
|
||||
delFlag: number
|
||||
refundStatus: number // 扩展字段 (老 vue 没有, 用于退款流程: 1=审核中 2=已退款 3=已拒绝 4=已撤销)
|
||||
}
|
||||
|
||||
const PAY_LABEL: Record<number, string> = { 1: '待支付', 2: '已支付' }
|
||||
const REFUND_LABEL: Record<number, string> = { 1: '审核中', 2: '已退款', 3: '已拒绝', 4: '已撤销' }
|
||||
const REFUND_TYPE: Record<number, string> = { 1: 'primary', 2: 'success', 3: 'danger', 4: 'info' }
|
||||
|
||||
const ENDPOINTS = ['/order/refund/page', '/order/refund/list', '/order/refund/search', '/order/refund/queryPage']
|
||||
|
||||
const FALLBACK: RefundRow[] = [
|
||||
{ id:'RF001', userId:'u10086', supplierId:'s20015', userEnterpriseId:'ue001', enterpriseId:'e008', supplierOrderCode:'SO20260701001', payStatus:2, payMoney:3280.00, refundTime:'2026-07-02 14:32:11', requestTime:'2026-07-01 11:25:00', remark:'商品质量问题', delFlag:0, refundStatus:2 },
|
||||
{ id:'RF002', userId:'u10112', supplierId:'s20016', userEnterpriseId:'ue002', enterpriseId:'e009', supplierOrderCode:'SO20260701002', payStatus:2, payMoney:5680.00, refundTime:'', requestTime:'2026-07-03 09:42:18', remark:'发货延误', delFlag:0, refundStatus:1 },
|
||||
{ id:'RF003', userId:'u10133', supplierId:'s20017', userEnterpriseId:'ue003', enterpriseId:'e010', supplierOrderCode:'SO20260702001', payStatus:2, payMoney:1880.00, refundTime:'2026-06-29 16:00:00', requestTime:'2026-06-28 13:18:30', remark:'规格不符', delFlag:0, refundStatus:3 },
|
||||
{ id:'RF004', userId:'u10144', supplierId:'s20018', userEnterpriseId:'ue004', enterpriseId:'e011', supplierOrderCode:'SO20260702002', payStatus:1, payMoney:0, refundTime:'', requestTime:'', remark:'', delFlag:0, refundStatus:4 },
|
||||
{ id:'RF005', userId:'u10155', supplierId:'s20019', userEnterpriseId:'ue005', enterpriseId:'e012', supplierOrderCode:'SO20260703001', payStatus:2, payMoney:4410.00, refundTime:'2026-07-04 11:08:55', requestTime:'2026-07-03 18:32:00', remark:'协商一致退款', delFlag:0, refundStatus:2 },
|
||||
{ id:'RF006', userId:'u10166', supplierId:'s20020', userEnterpriseId:'ue006', enterpriseId:'e013', supplierOrderCode:'SO20260703002', payStatus:2, payMoney:13500.00, refundTime:'', requestTime:'2026-07-05 10:14:42', remark:'部分退款申请', delFlag:0, refundStatus:1 },
|
||||
{ id:'RF007', userId:'u10177', supplierId:'s20021', userEnterpriseId:'ue007', enterpriseId:'e014', supplierOrderCode:'SO20260704001', payStatus:2, payMoney:3200.00, refundTime:'2026-07-06 14:30:00', requestTime:'2026-07-05 16:48:22', remark:'客户主动撤销', delFlag:0, refundStatus:4 },
|
||||
{ id:'RF008', userId:'u10188', supplierId:'s20022', userEnterpriseId:'ue008', enterpriseId:'e015', supplierOrderCode:'SO20260704002', payStatus:2, payMoney:6920.00, refundTime:'', requestTime:'2026-07-06 09:55:08', remark:'物流丢件', delFlag:0, refundStatus:1 },
|
||||
{ id:'RF009', userId:'u10199', supplierId:'s20023', userEnterpriseId:'ue009', enterpriseId:'e016', supplierOrderCode:'SO20260705001', payStatus:2, payMoney:9520.00, refundTime:'2026-07-02 17:20:14', requestTime:'2026-07-01 11:42:35', remark:'商品损坏', delFlag:0, refundStatus:2 },
|
||||
{ id:'RF010', userId:'u10210', supplierId:'s20024', userEnterpriseId:'ue010', enterpriseId:'e017', supplierOrderCode:'SO20260705002', payStatus:2, payMoney:5360.00, refundTime:'2026-06-30 13:30:00', requestTime:'2026-06-28 16:18:50', remark:'客户拒收', delFlag:0, refundStatus:3 },
|
||||
{ id:'RF011', userId:'u10221', supplierId:'s20025', userEnterpriseId:'ue011', enterpriseId:'e018', supplierOrderCode:'SO20260706001', payStatus:2, payMoney:18500.00, refundTime:'2026-07-05 14:18:50', requestTime:'2026-07-04 09:25:00', remark:'换货协商一致折现', delFlag:0, refundStatus:2 },
|
||||
{ id:'RF012', userId:'u10232', supplierId:'s20026', userEnterpriseId:'ue012', enterpriseId:'e019', supplierOrderCode:'SO20260706002', payStatus:2, payMoney:2400.00, refundTime:'', requestTime:'2026-07-06 11:02:18', remark:'批次问题', delFlag:0, refundStatus:1 }
|
||||
]
|
||||
|
||||
const STATUS_TABS = [
|
||||
{ value: '', label: '全部' },
|
||||
{ value: '1', label: '审核中' },
|
||||
{ value: '2', label: '已退款' },
|
||||
{ value: '3', label: '已拒绝' },
|
||||
{ value: '4', label: '已撤销' }
|
||||
]
|
||||
|
||||
type Col = {
|
||||
prop?: string; label: string; width?: number; slot?: string; fixed?: 'right' | true; type?: 'status' | 'text' | 'selection'
|
||||
}
|
||||
const columns: Col[] = [
|
||||
{ prop: 'id', label: '退款ID', width: 100, fixed: true },
|
||||
{ prop: 'supplierOrderCode', label: '供应商订单号', width: 200, slot: 'orderCode' },
|
||||
{ prop: 'userId', label: '用户ID', width: 90 },
|
||||
{ prop: 'supplierId', label: '商户ID', width: 90 },
|
||||
{ prop: 'enterpriseId', label: '商户企业ID', width: 110 },
|
||||
{ prop: 'userEnterpriseId', label: '用户企业ID', width: 110 },
|
||||
{ type: 'status', prop: 'payStatus', label: '原支付状态', width: 100 },
|
||||
{ prop: 'payMoney', label: '实际支付金额', width: 120 },
|
||||
{ type: 'status', prop: 'refundStatus', label: '退款状态', width: 100 },
|
||||
{ prop: 'remark', label: '退款原因', width: 200, slot: 'remark' },
|
||||
{ prop: 'requestTime', label: '申请时间', width: 160, slot: 'requestTime' },
|
||||
{ prop: 'refundTime', label: '退款完成时间', width: 160, slot: 'refundTime' },
|
||||
{ prop: 'actions', label: '操作', width: 200, fixed: 'right', slot: 'actions' }
|
||||
]
|
||||
|
||||
const list = ref<RefundRow[]>([])
|
||||
const total = ref(0)
|
||||
const loading = ref(false)
|
||||
const page = ref(1)
|
||||
const limit = ref(10)
|
||||
const filterKw = ref('')
|
||||
const statusTab = ref('')
|
||||
const dataSource = ref<'api' | 'mock' | 'loading'>('loading')
|
||||
const apiError = ref<string>('')
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
dataSource.value = 'loading'
|
||||
for (const ep of ENDPOINTS) {
|
||||
try {
|
||||
const params: any = { page: page.value, limit: limit.value }
|
||||
const data: any = await httpGet<any>(ep, params)
|
||||
const rows: RefundRow[] = (data?.list || []).map((it: any) => ({ ...it, raw: it }))
|
||||
list.value = rows
|
||||
total.value = Number(data?.total || rows.length)
|
||||
dataSource.value = 'api'
|
||||
apiError.value = ''
|
||||
loading.value = false
|
||||
return
|
||||
} catch {}
|
||||
}
|
||||
list.value = [...FALLBACK]
|
||||
total.value = FALLBACK.length
|
||||
dataSource.value = 'mock'
|
||||
apiError.value = '后端 API 暂未实装, 已加载前端示例数据'
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const filtered = computed(() => {
|
||||
const kw = filterKw.value.trim().toLowerCase()
|
||||
let rows = list.value
|
||||
if (statusTab.value) rows = rows.filter(r => String(r.refundStatus) === statusTab.value)
|
||||
if (kw) rows = rows.filter(r =>
|
||||
String(r.id).toLowerCase().includes(kw) ||
|
||||
String(r.supplierOrderCode).toLowerCase().includes(kw) ||
|
||||
String(r.userId).toLowerCase().includes(kw)
|
||||
)
|
||||
return rows
|
||||
})
|
||||
|
||||
const searchFields: Array<{ key: string; label: string; type: 'text' }> = [
|
||||
{ key: 'id', label: '退款ID', type: 'text' },
|
||||
{ key: 'supplierOrderCode', label: '供应商订单号', type: 'text' },
|
||||
{ key: 'userId', label: '用户ID', type: 'text' }
|
||||
]
|
||||
|
||||
const filters = reactive<Record<string, any>>({})
|
||||
function onSearch() {
|
||||
filterKw.value = String(filters.id || filters.supplierOrderCode || filters.userId || '')
|
||||
page.value = 1
|
||||
}
|
||||
function onStatusTab(v: string) { statusTab.value = v; page.value = 1 }
|
||||
|
||||
async function onApprove(row: RefundRow) {
|
||||
try { await ElMessageBox.confirm(`确认通过退款申请「${row.id}」?`, '提示', { type: 'warning' }) } catch { return }
|
||||
row.refundStatus = 2
|
||||
row.refundTime = new Date().toLocaleString('zh-CN')
|
||||
ElMessage.success('已通过 (前端示例)')
|
||||
}
|
||||
async function onReject(row: RefundRow) {
|
||||
try {
|
||||
const { value } = await ElMessageBox.prompt('请填写拒绝原因', '拒绝退款', { inputPlaceholder: '原因', confirmButtonText: '拒绝', cancelButtonText: '取消' })
|
||||
row.refundStatus = 3
|
||||
row.remark = (value || '已拒绝').trim()
|
||||
ElMessage.success('已拒绝 (前端示例)')
|
||||
} catch {}
|
||||
}
|
||||
function onView(row: RefundRow) {
|
||||
ElMessage.info(`打开退款详情 ${row.id}`)
|
||||
}
|
||||
function onExport() {
|
||||
ElMessage.success('已发起导出 (前端示例, 共 ' + filtered.value.length + ' 条)')
|
||||
}
|
||||
|
||||
onMounted(load)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="rr-page">
|
||||
<PageHeader title="退款管理" sub="实物订单退款流程审核 + 跟踪" :data-source="dataSource" :api-error="apiError">
|
||||
<el-button type="primary" @click="onExport">导出明细</el-button>
|
||||
</PageHeader>
|
||||
|
||||
<el-tabs v-model="statusTab" @tab-change="onStatusTab" class="rr-tabs">
|
||||
<el-tab-pane v-for="t in STATUS_TABS" :key="t.value" :name="t.value" :label="t.label" />
|
||||
</el-tabs>
|
||||
|
||||
<SearchBar v-model:filters="filters" :fields="searchFields" @search="onSearch" />
|
||||
|
||||
<DataTable
|
||||
:columns="columns"
|
||||
:data="filtered"
|
||||
:loading="loading"
|
||||
:page="page"
|
||||
:limit="limit"
|
||||
:total="total"
|
||||
row-key="id"
|
||||
@page-change="(p: number) => { page = p; load() }"
|
||||
@limit-change="(l: number) => { limit = l; page = 1; load() }"
|
||||
>
|
||||
<template #orderCode="{ row }">
|
||||
<el-link type="primary" :underline="false" @click="onView(row)">{{ row.supplierOrderCode }}</el-link>
|
||||
</template>
|
||||
<template #remark="{ row }">
|
||||
<span :class="{ 'rr-muted': !row.remark }">{{ row.remark || '--' }}</span>
|
||||
</template>
|
||||
<template #requestTime="{ row }">{{ row.requestTime || '--' }}</template>
|
||||
<template #refundTime="{ row }">{{ row.refundTime || '--' }}</template>
|
||||
<template #actions="{ row }">
|
||||
<template v-if="row.refundStatus === 1">
|
||||
<el-button type="success" link @click="onApprove(row)">通过</el-button>
|
||||
<el-button type="danger" link @click="onReject(row)">拒绝</el-button>
|
||||
</template>
|
||||
<el-button v-else type="primary" link @click="onView(row)">详情</el-button>
|
||||
</template>
|
||||
</DataTable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.rr-page { padding: 16px; }
|
||||
.rr-tabs { margin-bottom: 12px; }
|
||||
.rr-muted { color: var(--ink-muted); }
|
||||
</style>
|
||||
@ -6,7 +6,7 @@
|
||||
* 走 /other/goodunit/list 真 API (返 data: [...] 数组, 共 112 行)
|
||||
* 字段: id/name/type/supplierId/enterpriseId/createTime
|
||||
*/
|
||||
import { onMounted, ref, computed } from 'vue'
|
||||
import { onMounted, ref, computed, reactive } from 'vue'
|
||||
import { httpGet } from '@/utils/request'
|
||||
import DataTable from '@/components/DataTable/DataTable.vue'
|
||||
import PageHeader from '@/components/PageHeader/PageHeader.vue'
|
||||
@ -26,6 +26,7 @@ const list = ref<GoodUnit[]>([])
|
||||
const loading = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
const filterKw = ref('')
|
||||
const filters = reactive({ kw: filterKw })
|
||||
|
||||
const TYPE_MAP: Record<number, string> = {
|
||||
1: '系统',
|
||||
@ -55,7 +56,7 @@ async function load() {
|
||||
}
|
||||
|
||||
const filtered = computed(() => {
|
||||
const kw = filterKw.value.trim().toLowerCase()
|
||||
const kw = (filters.kw || "").trim().toLowerCase()
|
||||
if (!kw) return list.value
|
||||
return list.value.filter(it => it.name.toLowerCase().includes(kw))
|
||||
})
|
||||
@ -73,7 +74,7 @@ onMounted(load)
|
||||
<PageHeader title="商品单位" :sub="`商品计量单位管理 (共 ${list.length} 个, 筛选后 ${filtered.length} 个)`" />
|
||||
|
||||
<SearchBar
|
||||
v-model:filters="{ kw: filterKw }"
|
||||
v-model:filters="filters"
|
||||
:fields="[
|
||||
{ key: 'kw', label: '名称', type: 'text', placeholder: '按名称筛选' }
|
||||
]"
|
||||
|
||||
@ -225,6 +225,10 @@ const routes: RouteRecordRaw[] = [
|
||||
{ path: '/order/ordergood/after', component: () => import('@/modules/order/OrderListView.vue'), meta: { title: '商品售后订单' } },
|
||||
{ path: '/order/orderserviceafter', component: () => import('@/modules/order/OrderListView.vue'), meta: { title: '服务售后订单' } },
|
||||
{ path: '/order/base-price-analysis', component: () => import('@/modules/order/OrderListView.vue'), meta: { title: '基础价格分析表' } },
|
||||
// W15 新增 - 订单售后 + 退款 + 付款回调 (前端 max-effort mock, 老 vue 同字段)
|
||||
{ path: '/order/orderpay', component: () => import('@/modules/order/payment/PaymentCallbackListView.vue'), meta: { title: '订单支付回调' } },
|
||||
{ path: '/order/refund', component: () => import('@/modules/order/refund/RefundProcessListView.vue'), meta: { title: '订单退款管理' } },
|
||||
{ path: '/order/aftersale', component: () => import('@/modules/order/aftersale/AftersaleListView.vue'), meta: { title: '售后订单' } },
|
||||
// other 7 个
|
||||
{ path: '/other/brand', component: () => import('@/modules/generic/MockTableView.vue'), props: () => ({ configKey: 'other-brand' }), meta: { title: '品牌管理' } },
|
||||
{ path: '/other/category/good', component: () => import('@/modules/generic/MockTableView.vue'), props: () => ({ configKey: 'other-category-good' }), meta: { title: '平台分类' } },
|
||||
|
||||
Loading…
Reference in New Issue
Block a user