NGToolsAdmin/pages/uni-stat/pay-order/list/list.vue
2024-09-13 16:39:31 +08:00

508 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view>
<view class="uni-header">
<view class="uni-group">
<uni-stat-breadcrumb />
</view>
<view class="uni-group">
<button class="uni-button" type="default" size="mini" @click="search">搜索</button>
<download-excel class="hide-on-phone" :fields="exportExcel.fields" :data="exportExcelData" :type="exportExcel.type" :name="exportExcel.filename">
<button class="uni-button" type="primary" size="mini">导出 Excel</button>
</download-excel>
</view>
</view>
<view class="uni-container">
<view class="uni-stat--x">
<uni-stat-tabs label="平台选择" type="boldLine" mode="platform" v-model="query.platform" @change="platformChange" />
</view>
<unicloud-db ref="udb" :collection="collectionList" field="user_id,nickname,provider,provider_pay_type,uni_platform,status,type,order_no,out_trade_no,transaction_id,device_id,client_ip,openid,description,err_msg,total_fee,refund_fee,refund_count,refund_list,provider_appid,appid,user_order_success,create_date,pay_date,notify_date,cancel_date" :where="where" page-data="replace"
:orderby="orderby" :getcount="true" :page-size="options.pageSize" :page-current="options.pageCurrent"
v-slot:default="{data,pagination,loading,error,options}" :options="options" loadtime="manual" @load="onqueryload">
<uni-table ref="table" :loading="loading" :emptyText="error.message || loading ? '请求中...' : '没有更多数据'" border stripe type="" @selection-change="selectionChange" style="min-height: 900px;">
<uni-tr>
<uni-th align="center">序号</uni-th>
<uni-th ref="user_id" align="center" :filterDefaultValue="filterDefaultValueUserId" filter-type="search" @filter-change="filterChange($event, 'user_id')" sortable @sort-change="sortChange($event, 'user_id')">用户</uni-th>
<uni-th align="center" filter-type="select" :filter-data="options.filterData.provider_localdata" @filter-change="filterChange($event, 'provider')">支付供应商</uni-th>
<uni-th align="center" filter-type="search" @filter-change="filterChange($event, 'provider_pay_type')" sortable @sort-change="sortChange($event, 'provider_pay_type')">支付方式</uni-th>
<uni-th align="center" filter-type="search" @filter-change="filterChange($event, 'uni_platform')" sortable @sort-change="sortChange($event, 'uni_platform')">应用平台</uni-th>
<uni-th align="center" filter-type="select" :filter-data="options.filterData.status_localdata" @filter-change="filterChange($event, 'status')">订单状态</uni-th>
<uni-th align="center" filter-type="search" @filter-change="filterChange($event, 'type')" sortable @sort-change="sortChange($event, 'type')">订单类型</uni-th>
<uni-th align="center" filter-type="search" @filter-change="filterChange($event, 'order_no')" sortable @sort-change="sortChange($event, 'order_no')">业务系统订单号</uni-th>
<uni-th align="center" filter-type="search" @filter-change="filterChange($event, 'out_trade_no')" sortable @sort-change="sortChange($event, 'out_trade_no')">支付插件订单号</uni-th>
<uni-th align="center" filter-type="search" @filter-change="filterChange($event, 'transaction_id')" sortable @sort-change="sortChange($event, 'transaction_id')">交易单号</uni-th>
<uni-th align="center" filter-type="search" @filter-change="filterChange($event, 'description')" sortable @sort-change="sortChange($event, 'description')">支付描述</uni-th>
<uni-th align="center" filter-type="range" @filter-change="filterChange($event, 'total_fee', 0.01)" sortable @sort-change="sortChange($event, 'total_fee')">订单支付金额</uni-th>
<uni-th align="center" filter-type="range" @filter-change="filterChange($event, 'refund_fee', 0.01)" sortable @sort-change="sortChange($event, 'refund_fee')">订单退款金额</uni-th>
<uni-th align="center" filter-type="range" @filter-change="filterChange($event, 'refund_count')" sortable @sort-change="sortChange($event, 'refund_count')">当前退款笔数</uni-th>
<uni-th align="center" sortable @sort-change="sortChange($event, 'user_order_success')">回调状态</uni-th>
<uni-th align="center" filter-type="timestamp" @filter-change="filterChange($event, 'create_date')" sortable @sort-change="sortChange($event, 'create_date')">创建时间</uni-th>
<uni-th align="center" filter-type="timestamp" @filter-change="filterChange($event, 'pay_date')" sortable @sort-change="sortChange($event, 'pay_date')">支付时间</uni-th>
<uni-th align="center" filter-type="timestamp" @filter-change="filterChange($event, 'cancel_date')" sortable @sort-change="sortChange($event, 'cancel_date')">取消时间</uni-th>
<uni-th align="center" filter-type="search" @filter-change="filterChange($event, 'provider_appid')" sortable @sort-change="sortChange($event, 'provider_appid')">开放平台appid</uni-th>
<uni-th align="center" filter-type="search" @filter-change="filterChange($event, 'appid')" sortable @sort-change="sortChange($event, 'appid')">DCloud AppId</uni-th>
<uni-th align="center" filter-type="search" @filter-change="filterChange($event, 'device_id')" sortable @sort-change="sortChange($event, 'device_id')">设备ID</uni-th>
<uni-th align="center" filter-type="search" @filter-change="filterChange($event, 'client_ip')" sortable @sort-change="sortChange($event, 'client_ip')">客户端IP</uni-th>
<uni-th align="center" filter-type="search" @filter-change="filterChange($event, 'openid')" sortable @sort-change="sortChange($event, 'openid')">openid</uni-th>
</uni-tr>
<uni-tr v-for="(item,index) in data" :key="index">
<uni-td align="center">{{ parseInt((index+1) + (pagination.current-1) * pagination.size) }} </uni-td>
<uni-td align="center"><text class="text-btn" @click="pageToUser(item)">{{ nameFormat(item) }}</text> </uni-td>
<uni-td align="center">{{options.provider_valuetotext[item.provider]}}</uni-td>
<uni-td align="center">{{item.provider_pay_type}}</uni-td>
<uni-td align="center">{{item.uni_platform}}</uni-td>
<uni-td align="center">{{options.status_valuetotext[item.status]}}</uni-td>
<uni-td align="center">{{item.type}}</uni-td>
<uni-td align="center">{{item.order_no}}</uni-td>
<uni-td align="center">{{item.out_trade_no}}</uni-td>
<uni-td align="center">{{item.transaction_id}}</uni-td>
<uni-td align="center">{{item.description}}</uni-td>
<uni-td align="center">{{ (item.total_fee * 0.01).toFixed(2) }}</uni-td>
<uni-td align="center">{{ (item.refund_fee * 0.01).toFixed(2) }}</uni-td>
<uni-td align="center">{{item.refund_count}}</uni-td>
<uni-td align="center">
<view v-if="item.user_order_success === true" style="color:#18bc37">✔正常</view>
<view v-else-if="[-1,0].indexOf(item.status) > -1 ">-</view>
<view v-else style="color:#e43d33">●异常</view>
</uni-td>
<uni-td align="center">
<uni-dateformat :threshold="[0, 0]" :date="item.create_date"></uni-dateformat>
</uni-td>
<uni-td align="center">
<uni-dateformat :threshold="[0, 0]" :date="item.pay_date"></uni-dateformat>
</uni-td>
<uni-td align="center">
<uni-dateformat :threshold="[0, 0]" :date="item.cancel_date"></uni-dateformat>
</uni-td>
<uni-td align="center">{{item.provider_appid}}</uni-td>
<uni-td align="center">{{item.appid}}</uni-td>
<uni-td align="center">{{item.device_id}}</uni-td>
<uni-td align="center">{{item.client_ip}}</uni-td>
<uni-td align="center">{{item.openid}}</uni-td>
</uni-tr>
</uni-table>
<view class="uni-pagination-box">
<uni-pagination show-icon :page-size="pagination.size" v-model="pagination.current" :total="pagination.count" @change="onPageChanged" />
</view>
</unicloud-db>
</view>
<uni-popup ref="popup" type="center" :animation="false">
<view style="padding: 30px;background-color: #ffffff;width: 500px;">
<view style="margin-bottom: 20px;text-align: center;font-size: 20px;font-weight: bold;">退款确认</view>
<uni-forms ref="refundForm" :modelValue="refundFormData" label-position="left" labelWidth="100px" :rules="refundFormRules">
<uni-forms-item label="退款金额" name="refund_fee">
<uni-easyinput type="text" v-model.number="refundFormData.refund_fee" placeholder="请输入退款金额" :clearable="false" ></uni-easyinput>
<view style="color: #666;margin-top: 5px;font-size: 12px;">最大可退{{ refundFormData.max_refund_fee }}</view>
</uni-forms-item>
<uni-forms-item label="退款原因" name="refund_desc">
<uni-easyinput type="textarea" v-model="refundFormData.refund_desc" placeholder="请输入退款原因" :clearable="false" />
</uni-forms-item>
<button type="warn" style="width: 100px;height: 40px;font-size: 16px;" @click="confirmRefund(refundFormData);">确定</button>
</uni-forms>
</view>
</uni-popup>
</view>
</template>
<script>
import { enumConverter, filterToWhere } from '../../../../js_sdk/validator/uni-pay-orders.js';
// 引入支付云对象
const uniPayCo = uniCloud.importObject("uni-pay-co");
const db = uniCloud.database();
// 表查询配置
const dbOrderBy = 'create_date desc'; // 排序字段
const dbSearchFields = ['order_no', 'out_trade_no', 'transaction_id']; // 模糊搜索字段,支持模糊搜索的字段列表。联表查询格式: 主表字段名.副表字段名,例如用户表关联角色表 role.role_name
// 分页配置
const pageSize = 20;
const pageCurrent = 1;
const orderByMapping = {
"ascending": "asc",
"descending": "desc"
};
import {
mapfields,
stringifyQuery,
stringifyField,
stringifyGroupField,
getTimeOfSomeDayAgo,
division,
format,
formatDate,
parseDateTime,
getFieldTotal,
debounce
} from '@/js_sdk/uni-stat/util.js'
export default {
data() {
return {
collectionList: "uni-pay-orders",
query: {
appid: '',
platform_id: '',
uni_platform: '',
version: '',
pay_date: [],
},
where: '',
orderby: dbOrderBy,
orderByFieldName: "",
selectedIndexs: [],
filterDefaultValueUserId: "",
refundFormData:{
out_trade_no: "",
max_refund_fee: "",
refund_fee:"",
refund_desc: ""
},
refundFormRules:{
refund_fee: {
rules:[
// 校验 name 不能为空
{ required: true,errorMessage: '退款金额必须>0' },
// 对name字段进行长度验证
{
minimum: 0.01,
maximum: 0,
errorMessage: '最大可退 {maximum} 元',
}
],
},
refund_desc: {
rules:[
// 校验 name 不能为空
{ required: true,errorMessage: '请输入退款原因' },
],
}
},
options: {
pageSize,
pageCurrent,
filterData: {
"provider_localdata": [{
"text": "微信支付",
"value": "wxpay"
},
{
"text": "支付宝",
"value": "alipay"
},
{
"text": "苹果应用内支付",
"value": "appleiap"
}
],
"status_localdata": [{
"text": "已关闭",
"value": -1
},
{
"text": "未支付",
"value": 0
},
{
"text": "已支付",
"value": 1
},
{
"text": "已部分退款",
"value": 2
},
{
"text": "已全额退款",
"value": 3
}
]
},
...enumConverter
},
imageStyles: {
width: 64,
height: 64
},
exportExcel: {
"filename": "uni-pay-orders.xls",
"type": "xls",
"fields": {
"用户ID": "user_id",
"用户昵称": "nickname",
"支付供应商": "provider",
"支付方式": "provider_pay_type",
"应用平台": "uni_platform",
"订单状态": "status",
"支付失败原因": "err_msg",
"订单类型": "type",
"业务系统订单号": "order_no",
"支付插件订单号": "out_trade_no",
"交易单号": "transaction_id",
"支付描述": "description",
"订单支付金额": "total_fee",
"订单退款金额": "refund_fee",
"当前退款笔数": "refund_count",
"退款详情": "refund_list",
"回调状态": "user_order_success",
"创建时间": "create_date",
"支付时间": "pay_date",
"异步通知时间": "notify_date",
"取消时间": "cancel_date",
"开放平台appid": "provider_appid",
"DCloud AppId": "appid",
"设备ID": "device_id",
"客户端IP": "client_ip",
"openid": "openid",
}
},
exportExcelData: []
}
},
onLoad(e) {
this._filter = {}
if (e.user_id) {
this.filterDefaultValueUserId = e.user_id;
this.filterChange({
filterType: "search",
filter: e.user_id,
}, "user_id");
}
},
onReady() {
this.$refs.udb.loadData()
},
methods: {
onqueryload(data) {
this.exportExcelData = data
},
getWhere() {
let where = "";
let {
pay_date,
appid,
version,
uni_platform,
//query, // 模糊查询
} = this.query;
if (pay_date && pay_date.length == 2) {
where += ` && pay_date>=${pay_date[0]} && pay_date<=${pay_date[1]}`;
}
if (appid) {
where += ` && appid=='${appid}'`;
}
if (version) {
where += ` && stat_data.app_version=='${version}'`;
}
if (uni_platform) {
where += ` && stat_data.platform=='${uni_platform}'`;
}
// if (query) {
// const queryRe = new RegExp(query, 'i');
// let queryReStr = dbSearchFields.map(name => queryRe + '.test(' + name + ')').join(' || ');
// where += ` && (${queryReStr})`;
// }
where = where.substring(3).trim();
// console.log('where: ', where)
return where;
},
search() {
const newWhere = this.getWhere()
this.where = newWhere
this.$nextTick(() => {
this.loadData()
})
},
loadData(clear = true) {
this.$refs.udb.loadData({
clear
})
},
onPageChanged(e) {
this.selectedIndexs.length = 0
this.$refs.table.clearSelection()
this.$refs.udb.loadData({
current: e.current
})
},
navigateTo(url, clear) {
// clear 表示刷新列表时是否清除页码true 表示刷新并回到列表第 1 页,默认为 true
uni.navigateTo({
url,
events: {
refreshData: () => {
this.loadData(clear)
}
}
})
},
// 多选处理
selectedItems() {
let dataList = this.$refs.udb.dataList
return this.selectedIndexs.map(i => dataList[i]._id)
},
// 批量删除
delTable() {
this.$refs.udb.remove(this.selectedItems(), {
success: (res) => {
this.$refs.table.clearSelection()
}
})
},
// 多选
selectionChange(e) {
this.selectedIndexs = e.detail.index
},
refundPopup(key, item){
if (key) {
let {
total_fee = 0,
refund_fee = 0,
out_trade_no
} = item;
let max_refund_fee = Number(((total_fee - refund_fee) / 100).toFixed(2));
this.refundFormData.max_refund_fee = max_refund_fee;
this.refundFormData.refund_fee = max_refund_fee;
this.refundFormData.out_trade_no = out_trade_no;
this.refundFormRules.refund_fee.rules[1].maximum = max_refund_fee;
this.$refs.popup.open();
} else {
this.refundFormData.max_refund_fee = "";
this.refundFormData.refund_fee = "";
this.refundFormData.out_trade_no = "";
this.refundFormRules.refund_fee.rules[1].maximum = 0;
this.$refs.popup.close();
}
},
// 主动退款
async confirmRefund(item) {
let {
total_fee = 0,
refund_fee = 0,
out_trade_no,
refund_desc
} = item;
item.refund_fee = Number((item.refund_fee).toFixed(2));
this.$refs.refundForm.validate().then(async formData=>{
//console.log('表单数据信息:', formData);
let apply_refund_fee = Number(refund_fee);
if (isNaN(apply_refund_fee) || apply_refund_fee <= 0) {
uni.showToast({
title: "请输入正确的退款金额",
icon: 'none',
success: () => {
setTimeout(() => {
this.confirmRefund(item);
}, 500);
}
})
return;
}
let refundData = {
out_trade_no,
refund_fee: parseInt(apply_refund_fee * 100), // 金额已分为单位100 = 1元
refund_desc,
};
//console.log('refundData: ', refundData)
let res = await uniPayCo.refund(refundData);
if (!res.errCode) {
this.refundPopup(false);
this.loadData(false);
}
}).catch(err =>{
//console.log('表单错误信息:', err);
});
},
sortChange(e, name) {
this.orderByFieldName = name;
if (e.order) {
this.orderby = name + ' ' + orderByMapping[e.order]
} else {
this.orderby = ''
}
this.$refs.table.clearSelection()
this.$nextTick(() => {
this.$refs.udb.loadData()
})
},
filterChange(e, name, k) {
if (k && e.filter) {
if (typeof e.filter == "object") {
if (typeof e.filter[0] === "number") e.filter[0] = e.filter[0] / k;
if (typeof e.filter[1] === "number") e.filter[1] = e.filter[1] / k;
}
}
this._filter[name] = {
type: e.filterType,
value: e.filter,
}
let newWhere = filterToWhere(this._filter, db.command)
if (Object.keys(newWhere).length) {
this.where = newWhere
} else {
this.where = ''
}
this.$nextTick(() => {
this.$refs.udb.loadData()
})
},
platformChange(id, index, name, item) {
this.query.version = 0
this.query.uni_platform = item.code
},
nameFormat(item) {
if (!item.user_id) {
return "匿名用户";
} else if (item.nickname) {
return `${item.user_id}${item.nickname}`
} else {
return item.user_id;
}
},
pageToUser(item) {
let { user_id } = item;
uni.navigateTo({
url: `/pages/system/user/list?id=${user_id}`
});
},
},
watch: {
query: {
deep: true,
handler(val) {
this.search()
}
}
},
computed: {
versionQuery() {
const {
appid,
uni_platform
} = this.query
const query = stringifyQuery({
appid,
uni_platform
})
return query
}
},
}
</script>
<style lang="scss" scoped>
.text-btn{
color: $uni-color-primary;
cursor: pointer;
margin: 0 5px;
}
</style>