feat: 完善会员交易与任务管理流程
This commit is contained in:
+1036
-198
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ import { defRangeShortcuts } from '@/utils/dateUtil';
|
||||
const dict = useDictStore();
|
||||
|
||||
export interface MemberRecord {
|
||||
id: number; memberNo: string; username: string; mobileMask: string; realNameMask: string;
|
||||
id: number; memberNo: string; username: string; mobile: string; realNameMask: string;
|
||||
availableAmount: number; frozenAmount: number; parentId: number; parentUsername: string;
|
||||
inviteCode: string; memberStatus: number; riskStatus: number; autoDispatch: number; memberCategory: number;
|
||||
isTestAccount: number; lastLoginAt?: string; lastLoginIpMask: string; lastLoginRegion: string;
|
||||
@@ -30,7 +30,7 @@ export const columns = [
|
||||
{ title: 'ID', key: 'id', width: 80 },
|
||||
{ title: '会员编号', key: 'memberNo', width: 170 },
|
||||
{ title: '账号', key: 'username', width: 130 },
|
||||
{ title: '手机号', key: 'mobileMask', width: 130 },
|
||||
{ title: '手机号', key: 'mobile', width: 130 },
|
||||
{ title: '绑卡姓名', key: 'realNameMask', width: 100 },
|
||||
{ title: '可用余额', key: 'availableAmount', width: 120, render: (row: MemberRecord) => money(row.availableAmount) },
|
||||
{ title: '冻结余额', key: 'frozenAmount', width: 120, render: (row: MemberRecord) => money(row.frozenAmount) },
|
||||
|
||||
@@ -12,7 +12,7 @@ export const schemas = ref<FormSchema[]>([
|
||||
const tag = (type, value) => h(NTag, { type: dict.getType(type, value), bordered: false }, { default: () => dict.getLabel(type, value) || '-' });
|
||||
export const columns = [
|
||||
{ title: '申请单号', key: 'requestNo', width: 210 }, { title: '会员ID', key: 'memberId', width: 90 },
|
||||
{ title: '用户名', key: 'username', width: 120 }, { title: '手机号', key: 'mobileMask', width: 130 },
|
||||
{ title: '用户名', key: 'username', width: 120 }, { title: '手机号', key: 'mobile', width: 130 },
|
||||
{ title: '类型', key: 'adjustType', width: 110, render: (r) => tag('walletAdjustType', r.adjustType) },
|
||||
{ title: '方向', key: 'direction', width: 90, render: (r) => tag('walletDirection', r.direction) },
|
||||
{ title: '金额', key: 'amount', width: 120, render: (r) => `¥${((r.amount || 0) / 100).toFixed(2)}` },
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<n-descriptions v-if="detail.id" bordered :column="2">
|
||||
<n-descriptions-item label="任务">{{ detail.taskTitle }}</n-descriptions-item>
|
||||
<n-descriptions-item label="会员">
|
||||
{{ detail.username }} / {{ detail.mobileMask }}
|
||||
{{ detail.username }} / {{ detail.mobile }}
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="佣金">
|
||||
¥{{ ((detail.commissionAmount || 0) / 100).toFixed(2) }}
|
||||
@@ -110,6 +110,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, h, onMounted, reactive, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { BasicForm, useForm } from '@/components/Form';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
@@ -118,6 +119,7 @@
|
||||
import { columns, loadOptions, schemas } from './model';
|
||||
|
||||
const message = useMessage();
|
||||
const route = useRoute();
|
||||
const dict = useDictStore();
|
||||
const searchRef = ref();
|
||||
const tableRef = ref();
|
||||
@@ -152,7 +154,11 @@
|
||||
schemas,
|
||||
});
|
||||
|
||||
const loadTable = (params) => SubmissionList({ ...searchRef.value?.formModel, ...params });
|
||||
const loadTable = (params) => SubmissionList({
|
||||
...searchRef.value?.formModel,
|
||||
...params,
|
||||
tradeOrderId: Number(route.query.tradeOrderId) || undefined,
|
||||
});
|
||||
|
||||
function reload() {
|
||||
tableRef.value?.reload();
|
||||
|
||||
@@ -33,7 +33,7 @@ const tag = (k, v) =>
|
||||
export const columns = [
|
||||
{ title: '记录ID', key: 'id', width: 90 },
|
||||
{ title: '用户名', key: 'username', width: 130 },
|
||||
{ title: '手机号', key: 'mobileMask', width: 130 },
|
||||
{ title: '手机号', key: 'mobile', width: 130 },
|
||||
{ title: '任务标题', key: 'taskTitle', width: 180 },
|
||||
{ title: '等级', key: 'levelName', width: 110 },
|
||||
{
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
</n-modal>
|
||||
<n-modal v-model:show="showDetail" preset="card" title="订单详情" class="max-w-900px">
|
||||
<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.mobileMask }}</n-descriptions-item>
|
||||
<n-descriptions-item label="订单号">{{ detail.orderNo }}</n-descriptions-item><n-descriptions-item label="会员">{{ detail.username }} / {{ detail.mobile }}</n-descriptions-item>
|
||||
<n-descriptions-item label="商品/任务">{{ detail.productName || '-' }}</n-descriptions-item><n-descriptions-item label="规则等级ID">{{ detail.memberLevelId }}</n-descriptions-item>
|
||||
<n-descriptions-item label="订单金额">{{ yuan(detail.totalAmount) }}</n-descriptions-item><n-descriptions-item label="佣金">{{ yuan(detail.commissionAmount) }}</n-descriptions-item>
|
||||
<n-descriptions-item label="规则快照" :span="2"><n-code :code="JSON.stringify(detail.ruleSnapshot || {}, null, 2)" language="json" word-wrap /></n-descriptions-item>
|
||||
@@ -66,10 +66,11 @@
|
||||
</template>
|
||||
<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 { 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 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;
|
||||
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;
|
||||
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>();
|
||||
@@ -99,10 +100,14 @@ 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:180,title:'操作',key:'action',fixed:'right',render:(row)=>h(TableAction as any,{style:'button',actions:[
|
||||
{label:'匹配订单',type:'primary',disabled:!row.canMatch,title:row.canMatch?'匹配订单':'仅“匹配中”的订单可操作',onClick:()=>openMatch(row)},
|
||||
{label:'详情',onClick:()=>view(row)},
|
||||
]})});const scrollX=computed(()=>adaTableScrollX(columns,actionColumn.width));
|
||||
const actionColumn=reactive({width:210,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)});
|
||||
return h(TableAction as any,{style:'button',actions});
|
||||
}});const scrollX=computed(()=>adaTableScrollX(columns,actionColumn.width));
|
||||
watch(autoRefresh,(enabled)=>{
|
||||
clearInterval(timer);refreshCountdown.value=10;
|
||||
if(!enabled)return;
|
||||
|
||||
@@ -18,7 +18,7 @@ export const columns = [
|
||||
{ title: '订单号', key: 'orderNo', width: 210 },
|
||||
{ title: '绑卡姓名', key: 'realNameMask', width: 110 },
|
||||
{ title: '用户名', key: 'username', width: 120 },
|
||||
{ title: '手机号', key: 'mobileMask', width: 130 },
|
||||
{ title: '手机号', key: 'mobile', width: 130 },
|
||||
{ title: '自动派单', key: 'autoDispatch', width: 100, render: (r) => tag('tradeAutoDispatch', r.autoDispatch) },
|
||||
{ title: '余额', key: 'availableAmount', width: 120, render: (r) => yuan(r.availableAmount) },
|
||||
{ title: '当日交易', key: 'todayTradeCount', width: 90 },
|
||||
@@ -30,7 +30,9 @@ export const columns = [
|
||||
{ title: '下单时间', key: 'createdAt', width: 180 },
|
||||
{ title: '解冻时间', key: 'unfrozenAt', width: 180 },
|
||||
{ title: '消息', key: 'message', width: 180, ellipsis: { tooltip: true } },
|
||||
{ title: '订单状态', key: 'orderStatus', width: 100, render: (r) => tag('tradeOrderStatus', r.orderStatus) },
|
||||
{ title: '订单状态', key: 'orderStatus', width: 110, render: (r) => r.orderType === 2 && r.orderStatus === 2
|
||||
? h(NTag, { type: 'warning', bordered: false }, { default: () => '待会员提交' })
|
||||
: tag('tradeOrderStatus', r.orderStatus) },
|
||||
{ title: '冻结状态', key: 'freezeStatus', width: 110, render: (r) => tag('tradeFreezeStatus', r.freezeStatus) },
|
||||
];
|
||||
export const loadOptions = () => dict.loadOptions(['tradeOrderType', 'tradeOrderStatus', 'tradeFreezeStatus', 'tradeAutoDispatch', 'trade_exception_reason']);
|
||||
|
||||
@@ -22,7 +22,7 @@ const yuan = (value) => `¥${((value || 0) / 100).toFixed(2)}`;
|
||||
export const columns = [
|
||||
{ title: '订单号', key: 'rechargeNo', width: 210 },
|
||||
{ title: '真实姓名', key: 'realNameMask', width: 110 },
|
||||
{ title: '手机号', key: 'mobileMask', width: 130 },
|
||||
{ title: '手机号', key: 'mobile', width: 130 },
|
||||
{ title: '用户余额', key: 'availableAmount', width: 120, render: (row) => yuan(row.availableAmount) },
|
||||
{ title: '交易金额', key: 'requestAmount', width: 120, render: (row) => yuan(row.requestAmount) },
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user