@@ -1,6 +1,6 @@
< template >
< div >
< div class = "n-layout-page-header" > < n-card :bordered = "false" title = "订单列表" > 仅 “ 手动领取 ” 且 “ 匹配中 ” 的订单可在操作栏选择商品完成匹配 ; 自动领取订单由系统自动匹配 。 < / n-card > < / div >
< div class = "n-layout-page-header" > < n-card :bordered = "false" title = "订单列表" > 手动派单模式由客服匹配订单 , 会员确认时校验余额 ; 自动派单模式仅匹配余额内订单并直接完成 。 < / n-card > < / div >
< n-card :bordered = "false" class = "proCard" >
< BasicForm ref = "searchFormRef" @register ="register" @submit ="reloadTable" @reset ="reloadTable" / >
< BasicTable ref = "actionRef" :columns = "columns" :request = "loadDataTable" :row-key = "(row)=>row.id" :action-column = "actionColumn" :scroll-x = "scrollX" :resize-height-offset = "-10000" >
@@ -54,6 +54,15 @@
</n-space>
</template>
</n-modal>
<n-modal v-model:show=" showAmount " preset=" card " title=" 更改金额 " class=" amount - modal " :mask-closable=" false ">
<n-form label-placement=" left " :label-width=" 90 ">
<n-form-item label=" 用户名称 "><n-input :value=" amountMember . username " disabled /></n-form-item>
<n-form-item label=" 账号余额 "><n-input :value=" yuanPlain ( amountMember . availableAmount ) " disabled /></n-form-item>
<n-form-item label=" 更改金额 "><n-input-number v-model:value=" amountForm . amount " :min=" 0.01 " :precision=" 2 " class=" w - full " /></n-form-item>
<n-form-item label=" 更改数量 "><n-input-number v-model:value=" amountForm . quantity " :min=" 1 " :max=" 999 " class=" w - full " /></n-form-item>
</n-form>
<template #action><n-space><n-button @click=" showAmount = false ">取消</n-button><n-button type=" primary " :loading=" amountSubmitting " @click=" confirmAmount ">确定</n-button></n-space></template>
</n-modal>
<n-modal v-model:show=" showDetail " preset=" card " title=" 订单详情 " class=" max - w - 900 px ">
<n-descriptions v-if=" detail " bordered label-placement=" left " :column=" 2 ">
<n-descriptions-item label=" 订单号 ">{{ detail.orderNo }}</n-descriptions-item><n-descriptions-item label=" 会员 ">{{ detail.username }} / {{ detail.mobile }}</n-descriptions-item>
@@ -67,15 +76,18 @@
<script lang=" ts " setup>
import { computed, h, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import { NButton, NImage, NTag, useMessage } from 'naive-ui';
import { NButton, NImage, NTag, useDialog, useMessage } from 'naive-ui';
import { BasicTable, TableAction } from '@/components/Table';import { BasicForm,useForm } from '@/components/Form';import { adaTableScrollX } from '@/utils/hotgo';
import { TradeOrderList,TradeOrderMatch,TradeOrderMatchProducts,TradeOrderView } from '@/api/trade';import { columns,schemas,loadOptions } from './model';
const message=useMessage();const router=useRouter();const actionRef=ref(),searchFormRef=ref<any>({}),showDetail=ref(false),showMatch=ref(false),detail=ref<any>(),current=ref<any>(),autoRefresh=ref(false),refreshCountdown=ref(10);let timer:any;
import { TradeOrderForcePay,TradeOrderFreeze, TradeOrderList,TradeOrderMatch,TradeOrderMatchProducts,TradeOrderUpdateAmount, TradeOrderView } from '@/api/trade';import { columns,schemas,loadOptions } from './model';
const message=useMessage();const dialog=useDialog();const router=useRouter();const actionRef=ref(),searchFormRef=ref<any>({}),showDetail=ref(false),showMatch=ref(false),showAmount=ref(false), detail=ref<any>(),current=ref<any>(),autoRefresh=ref(false),refreshCountdown=ref(10);let timer:any;
const [register]=useForm({gridProps:{cols:'1 s:1 m:2 l:3 xl:5'},labelWidth:80,schemas});const loadDataTable=(res)=>TradeOrderList({...searchFormRef.value?.formModel,...res});const reloadTable=()=>actionRef.value?.reload();const yuan=(v)=>`¥${((v||0)/100).toFixed(2)}`;
const yuanPlain=(v)=>((v||0)/100).toFixed(2);
const matchLoading=ref(false),productLoading=ref(false),matchSubmitting=ref(false),products=ref<any[]>([]),selectedProduct=ref<any>();
const matchMember=reactive({id:0,username:'',availableAmount:0,frozenAmount:0});
const matchForm=reactive({id:0,productId:0,quantity:1});
const amountMember=reactive({username:'',availableAmount:0});
const amountForm=reactive<{id:number;amount:number|null;quantity:number}>({id:0,amount:null,quantity:1});
const amountSubmitting=ref(false);
const productFilter=reactive<{name:string;priceMin:number|null;priceMax:number|null}>({name:'',priceMin:null,priceMax:null});
const productPager=reactive({page:1,pageSize:10,total:0});
const productColumns=[
@@ -100,12 +112,20 @@ async function confirmMatch(){
matchSubmitting.value=true;try{await TradeOrderMatch(matchForm);message.success('订单匹配成功');showMatch.value=false;reloadTable()}finally{matchSubmitting.value=false}
}
async function view(row){detail.value=await TradeOrderView({id:row.id});showDetail.value=true}
const actionColumn=reactive({width:210,title:'操作',key:'action',fixed:'right',render:(row)=>{
function openAmount(row){Object.assign(amountMember,{username:row.username,availableAmount:row.availableAmount});Object.assign(amountForm,{id:row.id,amount:Number(row.totalAmount||0)/100,quantity:row.quantity||1});showAmount.value=true}
async function confirmAmount(){if(!amountForm.amount||amountForm.amount<=0){message.error('请输入正确金额');return}amountSubmitting.value=true;try{await TradeOrderUpdateAmount({id:amountForm.id,amount:amountForm.amount.toFixed(2),quantity:amountForm.quantity});message.success('订单金额已更改');showAmount.value=false;reloadTable()}finally{amountSubmitting.value=false}}
function forcePay(row){dialog.warning({title:'强制付款',content:`确认对订单 ${row.orderNo} 执行强制付款吗?允许付款后余额为负数。`,positiveText:'确认付款',negativeText:'取消',onPositiveClick:async()=>{await TradeOrderForcePay({id:row.id});message.success('强制付款成功');reloadTable()}})}
function freezeOrder(row){dialog.warning({title:'冻结订单',content:`确认冻结订单 ${row.orderNo} 吗?冻结后会员需要联系客服处理。`,positiveText:'确认冻结',negativeText:'取消',onPositiveClick:async()=>{await TradeOrderFreeze({id:row.id});message.success('订单已冻结');reloadTable()}})}
const actionColumn=reactive({width:300,title:'操作',key:'action',fixed:'right',render:(row)=>{
const actions:any[]=[];
if(row.canMatch)actions.push({label:'匹配订单',type:'primary',onClick:()=>openMatch(row)});
if(row.orderType===2&&row.orderStatus===2&&row.canReview )actions.push({label:'审核任务 ',type:'warning ',onClick:()=>router.push({name:'task_submission_list',query:{tradeOrderId:String(row.id)}} )});
else if(row.orderType===2&&row.orderStatus===2)actions.push({label:'等待会员提交',disabled:true,title:'会员提交任务凭证后即可审核' });
actions.push({label:'详情 ',onClick:()=>view (row)});
if(row.canChangeAmount )actions.push({label:'更改金额 ',type:'primary ',onClick:()=>openAmount(row )});
if(row.canForcePay)actions.push({label:'强制付款',type:'primary',onClick:()=>forcePay(row) });
if(row.canFreeze) actions.push({label:'冻结订单',type:'warning ',onClick:()=>freezeOrder (row)});
const hasManualActions=row.canChangeAmount||row.canForcePay||row.canFreeze;
if(!hasManualActions&&row.orderType===2&&row.orderStatus===2&&row.canReview)actions.push({label:'审核任务',type:'warning',onClick:()=>router.push({name:'task_submission_list',query:{tradeOrderId:String(row.id)}})});
else if(!hasManualActions&&row.orderType===2&&row.orderStatus===2)actions.push({label:'等待会员付款',disabled:true,title:'等待会员完成付款'});
if(!hasManualActions)actions.push({label:'详情',onClick:()=>view(row)});
return h(TableAction as any,{style:'button',actions});
}});const scrollX=computed(()=>adaTableScrollX(columns,actionColumn.width));
watch(autoRefresh,(enabled)=>{
@@ -121,6 +141,7 @@ onBeforeUnmount(()=>clearInterval(timer));onMounted(loadOptions);
</script>
<style lang=" less " scoped >
: deep ( . match - order - modal ) { width : min ( 1040 px , 94 vw ) ; }
: deep ( . amount - modal ) { width : min ( 620 px , 92 vw ) ; }
. match - product - area { width : 100 % ; }
. filter - name { width : 180 px ; }
. filter - price { width : 130 px ; }