diff --git a/src/api/system/recharge.js b/src/api/system/recharge.js index e9509f6..9da4992 100644 --- a/src/api/system/recharge.js +++ b/src/api/system/recharge.js @@ -79,3 +79,13 @@ export function refundBill(billId, refundAmount) { } }) } + + +// 关闭订单 +export function closeBill(data) { + return request({ + url: `/system/bill/close`, + method: 'put', + data + }) +} diff --git a/src/utils/constants.js b/src/utils/constants.js index bb60b8b..b703d33 100644 --- a/src/utils/constants.js +++ b/src/utils/constants.js @@ -110,3 +110,16 @@ export const PayBillStatus = { REFUNDING: "5", // 退款中 REFUNDED: "6", // 已退款 } + +// 充值订单状态 +export const RechargeStatus = { + WAIT_PAY: "1", // 未支付 + PAY_SUCCESS: "2", // 支付成功 + REFUNDED: "3", // 已退款 + USER_CANCEL: "4", // 用户取消 + SYS_CANCEL: "5", // 系统超时取消 + PAYING: "6", // 支付中 + REFUNDING: "7", // 退款中 + DEPOSIT_WAIT_PAY: "8", // 押金待支付 + DEPOSIT_SUCCESS: "9", // 押金已支付 +} diff --git a/src/views/system/recharge/index.vue b/src/views/system/recharge/index.vue index 7b869a8..4a8026b 100644 --- a/src/views/system/recharge/index.vue +++ b/src/views/system/recharge/index.vue @@ -88,70 +88,60 @@ v-hasPermi="['system:bill:export']" >导出</el-button> </el-col> - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar> </el-row> - <el-table v-loading="loading" :data="billList" @selection-change="handleSelectionChange"> + <el-table v-loading="loading" :data="billList" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="onSortChange"> <el-table-column type="selection" width="55" align="center" /> - <el-table-column label="订单ID" align="center" prop="billId" width="80"/> - <el-table-column label="时间" align="center" prop="createTime" width="180"/> - <el-table-column label="订单编号" align="center" prop="billNo" min-width="130"> - <recharge-link slot-scope="d" :bill-id="d.row.billId" :text="d.row.billNo"/> - </el-table-column> - <el-table-column label="充值用户" align="center" prop="userName" > - <user-link slot-scope="d" :id="d.row.userId" :name="d.row.userName"/> - </el-table-column> - <el-table-column label="设备名称/SN" align="center" prop="deviceName" width="180"> - <device-link slot-scope="d" :id="d.row.deviceId" :text="`${d.row.deviceName ? d.row.deviceName : '--'} (${d.row.deviceNo})`"/> - </el-table-column> - <el-table-column label="收款用户" align="center" prop="mchName" > - <user-link slot-scope="d" :id="d.row.mchId" :name="d.row.mchName"/> - </el-table-column> - <el-table-column label="交易金额" align="center"> - <template slot-scope="d"> - {{d.row.money | money}} 元 - </template> - </el-table-column> - <el-table-column label="到账金额" align="center"> - <template slot-scope="d"> - {{d.row.arrivalAmount | money}} 元 - </template> - </el-table-column> - <el-table-column label="手续费" align="center"> - <template slot-scope="d"> - {{d.row.serviceCharge | money | defaultValue}} 元 - </template> - </el-table-column> - <el-table-column label="成本" align="center"> - <template slot-scope="d"> - {{d.row.channelCost | money}} 元 - </template> - </el-table-column> - <el-table-column label="利润" align="center"> - <template slot-scope="d"> - {{d.row.serviceCharge - d.row.channelCost | money}} 元 - </template> - </el-table-column> - <el-table-column label="收费模式" align="center"> - <template slot-scope="d"> - <dict-tag :value="d.row.suitFeeMode" :options="dict.type.suit_fee_mode"/> - </template> - </el-table-column> - <el-table-column label="收费方式" align="center"> - <template slot-scope="d"> - <dict-tag :value="d.row.suitFeeType" :options="dict.type.suit_fee_type"/> - </template> - </el-table-column> - <el-table-column label="交易状态" align="center"> - <template slot-scope="d"> - <dict-tag :value="d.row.status" :options="dict.type.sm_transaction_bill_status"/> - </template> - </el-table-column> - <el-table-column label="使用中" align="center"> - <template slot-scope="d"> - <el-tag :type="d.row.isUsing ? 'success' : 'danger'">{{d.row.isUsing ? '是' : '否'}}</el-tag> - </template> - </el-table-column> + <template v-for="column of showColumns"> + <el-table-column + :key="column.key" + :label="column.label" + :prop="column.key" + :align="column.align" + :min-width="column.minWidth" + :sort-orders="orderSorts" + :sortable="column.sortable" + :show-overflow-tooltip="column.overflow" + :width="column.width" + > + <template slot-scope="d"> + <template v-if="column.key === 'billId'"> + {{d.row[column.key]}} + </template> + <template v-else-if="column.key === 'billNo'"> + <recharge-link :bill-id="d.row.billId" :text="d.row.billNo"/> + </template> + <template v-else-if="column.key === 'userName'"> + <user-link :id="d.row.userId" :name="d.row.userName"/> + </template> + <template v-else-if="column.key === 'deviceName'"> + <device-link :id="d.row.deviceId" :text="`${d.row.deviceName ? d.row.deviceName : '--'} (${d.row.deviceNo})`"/> + </template> + <template v-else-if="column.key === 'mchName'"> + <user-link :id="d.row.mchId" :name="d.row.mchName"/> + </template> + <template v-else-if="column.key === 'suitFeeMode'"> + <dict-tag :value="d.row.suitFeeMode" :options="dict.type.suit_fee_mode"/> + </template> + <template v-else-if="column.key === 'suitFeeType'"> + <dict-tag :value="d.row.suitFeeType" :options="dict.type.suit_fee_type"/> + </template> + <template v-else-if="column.key === 'status'"> + <dict-tag :value="d.row.status" :options="dict.type.sm_transaction_bill_status"/> + </template> + <template v-else-if="column.key === 'isUsing'"> + <el-tag :type="d.row.isUsing ? 'success' : 'danger'">{{d.row.isUsing ? '是' : '否'}}</el-tag> + </template> + <template v-else-if="['money', 'serviceCharge', 'channelCost', 'arrivalAmount'].includes(column.key)"> + {{d.row.money | money | defaultValue}} 元 + </template> + <template v-else> + {{d.row[column.key] | defaultValue}} + </template> + </template> + </el-table-column> + </template> <el-table-column label="操作" align="center" fixed="right" width="200"> <template slot-scope="d"> <el-button @@ -171,18 +161,26 @@ <el-button size="small" type="text" - icon="el-icon-refresh" + icon="el-icon-s-promotion" @click="rechargeDevice(d.row.billId)" v-if="canRechargeDevice(d.row)" >手动设备充值</el-button> <el-button size="small" type="text" - icon="el-icon-refresh" + icon="el-icon-bank-card" @click="handleRefund(d.row)" v-has-permi="['system:bill:refund']" v-show="canRefund(d.row)" >订单退款</el-button> + <el-button + size="small" + type="text" + icon="el-icon-document-delete" + @click="handleClose(d.row)" + v-has-permi="['system:bill:close']" + v-show="canClose(d.row)" + >结束订单</el-button> </template> </el-table-column> </el-table> @@ -231,19 +229,47 @@ import { updateBill, refreshPayResult, rechargeDevice, - refundBill + refundBill, closeBill } from '@/api/system/recharge' import UserLink from '@/components/Business/SmUser/UserLink.vue' import DeviceLink from '@/components/Business/Device/DeviceLink.vue' import RechargeLink from '@/components/Business/Transaction/RechargeLink.vue' -import { SuitFeeType } from '@/utils/constants' +import { RechargeStatus, SuitFeeType } from '@/utils/constants' +import { $showColumns } from '@/utils/mixins' + +// 默认排序字段 +const defaultSort = { + prop: "createTime", + order: "descending" +} export default { name: "Bill", + mixins: [$showColumns], components: { RechargeLink, DeviceLink, UserLink }, dicts: ['channel_type','sm_transaction_bill_status', 'sm_transaction_bill_device_recharge_status', 'suit_fee_mode', 'suit_fee_type'], data() { return { + defaultSort, + // 排序方式 + orderSorts: ['ascending', 'descending', null], + // 字段列表 + columns: [ + {key: 'billId', visible: false, label: '订单ID', minWidth: null, sortable: true, overflow: false, align: 'center', width: "80"}, + {key: 'createTime', visible: true, label: '时间', minWidth: null, sortable: true, overflow: false, align: 'center', width: "100"}, + {key: 'billNo', visible: true, label: '订单编号', minWidth: null, sortable: true, overflow: false, align: 'center', width: "100"}, + {key: 'userName', visible: true, label: '充值用户', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'deviceName', visible: true, label: '设备名称/SN', minWidth: null, sortable: true, overflow: false, align: 'center', width: "120"}, + {key: 'mchName', visible: true, label: '商户', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'money', visible: true, label: '交易金额', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'arrivalAmount', visible: true, label: '到账金额', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'serviceCharge', visible: true, label: '手续费', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'channelCost', visible: true, label: '成本', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'suitFeeMode', visible: true, label: '收费模式', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'suitFeeType', visible: true, label: '收费方式', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'status', visible: true, label: '交易状态', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + {key: 'isUsing', visible: true, label: '使用中', minWidth: null, sortable: true, overflow: false, align: 'center', width: null}, + ], // 遮罩层 loading: true, // 选中数组 @@ -266,6 +292,8 @@ export default { queryParams: { pageNum: 1, pageSize: 10, + orderByColumn: defaultSort.prop, + isAsc: defaultSort.order, userName: null, deviceName: null, landlordName: null, @@ -301,12 +329,43 @@ export default { return (row) => { return row.status === '2'; } + }, + canClose() { + return (row) => { + return [RechargeStatus.PAY_SUCCESS, RechargeStatus.DEPOSIT_SUCCESS].includes(row.status) && !row.isFinished; + } } }, created() { this.getList(); }, methods: { + // 结束订单 + handleClose(row) { + this.$confirm(`确定结束订单【${row.billNo}】吗?`, { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(() => { + closeBill({billId: row.billId, totalEle: null}).then(res => { + if (res.code === 200) { + this.$message.success("操作成功"); + this.getList(); + } + }) + }) + }, + /** 当排序按钮被点击时触发 **/ + onSortChange(column) { + if (column.order == null) { + this.queryParams.orderByColumn = defaultSort.prop; + this.queryParams.isAsc = defaultSort.order; + } else { + this.queryParams.orderByColumn = column.prop; + this.queryParams.isAsc = column.order; + } + this.getList(); + }, submitRefund() { this.refundLoading = true; refundBill(this.refundForm.billId, this.refundForm.refundAmount).then(res => {