|
|
@@ -0,0 +1,390 @@
|
|
|
+<template>
|
|
|
+ <div class="new-app-container layout-vertical manual-audit-page">
|
|
|
+ <div class="content-panel">
|
|
|
+ <div class="filter-panel">
|
|
|
+ <div class="action-btns">
|
|
|
+ <el-button type="success" size="small" @click="openUpDialog">人工上分</el-button>
|
|
|
+ <el-button type="danger" size="small" @click="openDownDialog">人工下分</el-button>
|
|
|
+ </div>
|
|
|
+ <el-form inline :model="query" class="filter-form">
|
|
|
+ <el-form-item label="交易类型">
|
|
|
+ <el-select v-model="query.pay_type" clearable placeholder="请选择" style="width: 150px">
|
|
|
+ <el-option label="人工上分" value="up" />
|
|
|
+ <el-option label="人工下分" value="down" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="时间">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="query.dateRange"
|
|
|
+ type="daterange"
|
|
|
+ align="right"
|
|
|
+ unlink-panels
|
|
|
+ range-separator="至"
|
|
|
+ start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期"
|
|
|
+ value-format="yyyy-MM-dd HH:mm:ss"
|
|
|
+ format="yyyy年MM月dd日"
|
|
|
+ :default-time="['00:00:00', '23:59:59']"
|
|
|
+ :picker-options="pickerOptions"
|
|
|
+ style="width: 380px"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item class="filter-actions">
|
|
|
+ <el-button type="primary" size="small" :loading="loading" @click="handleSearch">查询</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="table-section">
|
|
|
+ <el-table v-loading="loading" :data="pagedData"
|
|
|
+ height="calc(100vh - 340px)" style="width: 100%; border-radius: 12px; overflow: hidden;"
|
|
|
+ empty-text="暂无数据">
|
|
|
+ <el-table-column type="index" label="序号" width="80" align="center" />
|
|
|
+ <el-table-column prop="member_account" label="会员账号" width="140" align="center" />
|
|
|
+ <el-table-column prop="member_name" label="会员昵称" width="140" align="center" />
|
|
|
+ <el-table-column prop="pay_type" label="支付类型" width="100" align="center" />
|
|
|
+ <el-table-column prop="before_level" label="充值前等级" width="110" align="center" />
|
|
|
+ <el-table-column prop="amount" label="充值金额" width="110" align="center">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <span style="color: #18C80A;">
|
|
|
+ {{ row.amount != null ? Number(row.amount).toFixed(2) : '--' }}
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="after_level" label="充值后等级" width="110" align="center" />
|
|
|
+ <el-table-column prop="status" label="状态" width="90" align="center">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <span :style="{ color: row.status === '成功' ? '#18C80A' : row.status === '失败' ? '#F56C6C' : '#909399' }">{{ row.status }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="remark" label="备注" min-width="140" align="center" />
|
|
|
+ <el-table-column prop="trade_date" label="交易日期" width="175" align="center" />
|
|
|
+ <el-table-column label="操作" width="90" align="center" fixed="right">
|
|
|
+ <template slot-scope="{ row }">
|
|
|
+ <el-button type="text" size="small" class="ym-view-btn" @click="handleView(row)">查看</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <el-pagination v-if="tableData.length" background
|
|
|
+ layout="total, prev, pager, next, jumper" :page-size="pageSize"
|
|
|
+ :page-sizes="[15, 30, 45, 60]" :current-page="page"
|
|
|
+ :total="tableData.length"
|
|
|
+ @current-change="page = $event" @size-change="handleSizeChange" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 人工上分弹窗 -->
|
|
|
+ <Dialog ref="upDialog" :dialog-actions="{ width: '480px', title: '人工上分' }" :loading="loading" @confirm="confirmUp">
|
|
|
+ <template slot="content">
|
|
|
+ <el-form ref="upFormRef" :rules="rulesData" :model="upForm" label-width="90px">
|
|
|
+ <el-form-item label="会员ID" prop="member_id">
|
|
|
+ <el-input v-model="upForm.member_id" placeholder="请输入会员ID" style="width: 280px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="充值类型" prop="change_type">
|
|
|
+ <el-select v-model="upForm.change_type" placeholder="请选择" style="width: 280px">
|
|
|
+ <el-option v-for="item in listTypes" :key="item" :label="item" :value="item" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="充值金额" prop="amount">
|
|
|
+ <el-input type="number" v-model="upForm.amount" placeholder="请输入金额" style="width: 280px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="说明" prop="remark">
|
|
|
+ <el-input v-model="upForm.remark" placeholder="请输入说明" style="width: 280px" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </template>
|
|
|
+ </Dialog>
|
|
|
+
|
|
|
+ <!-- 人工下分弹窗 -->
|
|
|
+ <Dialog ref="downDialog" :dialog-actions="{ width: '480px', title: '人工下分' }" :loading="loading" @confirm="confirmDown">
|
|
|
+ <template slot="content">
|
|
|
+ <el-form ref="downFormRef" :rules="rulesData" :model="downForm" label-width="90px">
|
|
|
+ <el-form-item label="会员ID" prop="member_id">
|
|
|
+ <el-input v-model="downForm.member_id" placeholder="请输入会员ID" style="width: 280px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="下分金额" prop="amount">
|
|
|
+ <el-input type="number" v-model="downForm.amount" placeholder="请输入金额" style="width: 280px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="说明" prop="remark">
|
|
|
+ <el-input v-model="downForm.remark" placeholder="请输入说明" style="width: 280px" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </template>
|
|
|
+ </Dialog>
|
|
|
+
|
|
|
+ <!-- 查看详情弹窗 -->
|
|
|
+ <Dialog ref="viewDialog" :dialog-actions="{
|
|
|
+ width: '820px',
|
|
|
+ title: '人工稽查详情',
|
|
|
+ confirmButtom: false,
|
|
|
+ }">
|
|
|
+ <template slot="content">
|
|
|
+ <div style="display: flex; flex-wrap: wrap; gap: 12px; padding: 10px 0; max-height: 400px; overflow-y: auto;">
|
|
|
+ <div v-for="field in viewFields" :key="field.prop"
|
|
|
+ style="flex: 0 0 calc(33.33% - 12px); background: #f5f7fa; border-radius: 6px; padding: 12px 16px; box-sizing: border-box; border: 1px solid #e4e7ed;">
|
|
|
+ <div style="font-size: 13px; color: #909399; margin-bottom: 4px;">{{ field.label }}</div>
|
|
|
+ <div :style="{ color: field.color || '#303133', fontSize: '15px' }">{{ field.value }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 操作按钮:充值/扣款 -->
|
|
|
+ <div style="margin-top: 16px; text-align: center; border-top: 1px solid #e4e7ed; padding-top: 16px;">
|
|
|
+ <el-button type="primary" size="small" @click="openViewUp">充值</el-button>
|
|
|
+ <el-button type="danger" size="small" @click="openViewDown">扣款</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </Dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { withdraw, walletdebiting, getChangeTypes } from '@/api/data'
|
|
|
+import Dialog from '@/components/Dialog/index.vue'
|
|
|
+
|
|
|
+// 假数据
|
|
|
+const MANUAL_AUDIT_MOCK = [
|
|
|
+ { id: 1, member_account: 'test01', member_name: 'test01', pay_type: '人工上分', before_level: '普通会员', amount: 2000, after_level: '普通会员', status: '成功', remark: '人工上分', trade_date: '2026-08-05 10:20:30' },
|
|
|
+ { id: 2, member_account: 'test02', member_name: 'test02', pay_type: '人工上分', before_level: '普通会员', amount: 5000, after_level: '白银会员', status: '成功', remark: '人工上分', trade_date: '2026-08-05 11:00:00' },
|
|
|
+ { id: 3, member_account: 'test03', member_name: 'test03', pay_type: '人工下分', before_level: '白银会员', amount: 1000, after_level: '普通会员', status: '成功', remark: '人工下分', trade_date: '2026-08-05 14:30:00' },
|
|
|
+ { id: 4, member_account: 'test04', member_name: 'test04', pay_type: '人工上分', before_level: '普通会员', amount: 8000, after_level: '黄金会员', status: '成功', remark: '人工上分', trade_date: '2026-08-06 09:15:00' },
|
|
|
+ { id: 5, member_account: 'test05', member_name: 'test05', pay_type: '人工下分', before_level: '黄金会员', amount: 3000, after_level: '白银会员', status: '失败', remark: '余额不足', trade_date: '2026-08-06 16:40:00' }
|
|
|
+]
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'ManualAudit',
|
|
|
+ components: {
|
|
|
+ Dialog
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ loading: false,
|
|
|
+ page: 1,
|
|
|
+ pageSize: 15,
|
|
|
+ tableData: [...MANUAL_AUDIT_MOCK],
|
|
|
+ filteredData: [...MANUAL_AUDIT_MOCK],
|
|
|
+ listTypes: [],
|
|
|
+ query: {
|
|
|
+ pay_type: '',
|
|
|
+ dateRange: [this.getDefaultDate(0) + ' 00:00:00', this.getDefaultDate(0) + ' 23:59:59']
|
|
|
+ },
|
|
|
+ upForm: {
|
|
|
+ member_id: '',
|
|
|
+ change_type: '',
|
|
|
+ amount: '',
|
|
|
+ remark: ''
|
|
|
+ },
|
|
|
+ downForm: {
|
|
|
+ member_id: '',
|
|
|
+ amount: '',
|
|
|
+ remark: ''
|
|
|
+ },
|
|
|
+ rulesData: {
|
|
|
+ member_id: [{ required: true, message: '请输入会员ID', trigger: 'blur' }],
|
|
|
+ change_type: [{ required: true, message: '请选择充值类型', trigger: 'change' }],
|
|
|
+ amount: [{ required: true, message: '请输入金额', trigger: 'blur' }]
|
|
|
+ },
|
|
|
+ viewRow: null,
|
|
|
+ pickerOptions: {
|
|
|
+ disabledDate(time) {
|
|
|
+ return time.getTime() > Date.now()
|
|
|
+ },
|
|
|
+ shortcuts: [
|
|
|
+ {
|
|
|
+ text: '今天',
|
|
|
+ onClick(picker) {
|
|
|
+ const start = new Date()
|
|
|
+ start.setHours(0, 0, 0, 0)
|
|
|
+ const end = new Date()
|
|
|
+ end.setHours(23, 59, 59, 999)
|
|
|
+ picker.$emit('pick', [start, end])
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '昨天',
|
|
|
+ onClick(picker) {
|
|
|
+ const start = new Date()
|
|
|
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 1)
|
|
|
+ start.setHours(0, 0, 0, 0)
|
|
|
+ const end = new Date()
|
|
|
+ end.setTime(end.getTime() - 3600 * 1000 * 24 * 1)
|
|
|
+ end.setHours(23, 59, 59, 999)
|
|
|
+ picker.$emit('pick', [start, end])
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '7天内',
|
|
|
+ onClick(picker) {
|
|
|
+ const start = new Date()
|
|
|
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
|
|
+ start.setHours(0, 0, 0, 0)
|
|
|
+ const end = new Date()
|
|
|
+ end.setHours(23, 59, 59, 999)
|
|
|
+ picker.$emit('pick', [start, end])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ pagedData() {
|
|
|
+ const start = (this.page - 1) * this.pageSize
|
|
|
+ return this.filteredData.slice(start, start + this.pageSize)
|
|
|
+ },
|
|
|
+ viewFields() {
|
|
|
+ if (!this.viewRow) return []
|
|
|
+ const row = this.viewRow
|
|
|
+ const statusColor = row.status === '成功' ? '#18C80A' : row.status === '失败' ? '#F56C6C' : '#909399'
|
|
|
+ return [
|
|
|
+ { label: '序号', prop: 'id', value: row.id },
|
|
|
+ { label: '会员账号', prop: 'member_account', value: row.member_account || '--' },
|
|
|
+ { label: '会员昵称', prop: 'member_name', value: row.member_name || '--' },
|
|
|
+ { label: '支付类型', prop: 'pay_type', value: row.pay_type || '--' },
|
|
|
+ { label: '充值前等级', prop: 'before_level', value: row.before_level || '--' },
|
|
|
+ { label: '充值金额', prop: 'amount', value: row.amount != null ? Number(row.amount).toFixed(2) : '--', color: '#18C80A' },
|
|
|
+ { label: '充值后等级', prop: 'after_level', value: row.after_level || '--' },
|
|
|
+ { label: '状态', prop: 'status', value: row.status || '--', color: statusColor },
|
|
|
+ { label: '备注', prop: 'remark', value: row.remark || '--' },
|
|
|
+ { label: '交易日期', prop: 'trade_date', value: row.trade_date || '--' }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ getDefaultDate(offsetDays) {
|
|
|
+ const d = new Date()
|
|
|
+ d.setDate(d.getDate() + offsetDays)
|
|
|
+ const pad = n => String(n).padStart(2, '0')
|
|
|
+ return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate())
|
|
|
+ },
|
|
|
+ handleSizeChange(val) {
|
|
|
+ this.pageSize = val
|
|
|
+ this.page = 1
|
|
|
+ },
|
|
|
+ handleSearch() {
|
|
|
+ this.page = 1
|
|
|
+ let filtered = [...this.tableData]
|
|
|
+ if (this.query.pay_type) {
|
|
|
+ filtered = filtered.filter(r => r.pay_type === (this.query.pay_type === 'up' ? '人工上分' : '人工下分'))
|
|
|
+ }
|
|
|
+ this.filteredData = filtered
|
|
|
+ },
|
|
|
+ openUpDialog() {
|
|
|
+ this.upForm = { member_id: '', change_type: '', amount: '', remark: '' }
|
|
|
+ this.$refs.upDialog.open()
|
|
|
+ getChangeTypes().then((res) => {
|
|
|
+ this.listTypes = res.data
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 查看弹窗内的充值操作
|
|
|
+ openViewUp() {
|
|
|
+ this.upForm = {
|
|
|
+ member_id: this.viewRow ? this.viewRow.member_id : '',
|
|
|
+ change_type: '',
|
|
|
+ amount: '',
|
|
|
+ remark: ''
|
|
|
+ }
|
|
|
+ this.$refs.upDialog.open()
|
|
|
+ getChangeTypes().then((res) => {
|
|
|
+ this.listTypes = res.data
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 查看弹窗内的扣款操作
|
|
|
+ openViewDown() {
|
|
|
+ this.downForm = {
|
|
|
+ member_id: this.viewRow ? this.viewRow.member_id : '',
|
|
|
+ amount: '',
|
|
|
+ remark: ''
|
|
|
+ }
|
|
|
+ this.$refs.downDialog.open()
|
|
|
+ },
|
|
|
+ handleView(row) {
|
|
|
+ this.viewRow = { ...row }
|
|
|
+ this.$refs.viewDialog.open()
|
|
|
+ },
|
|
|
+ openDownDialog() {
|
|
|
+ this.downForm = { member_id: '', amount: '', remark: '' }
|
|
|
+ this.$refs.downDialog.open()
|
|
|
+ },
|
|
|
+ confirmUp() {
|
|
|
+ this.$refs.upFormRef.validate((valid) => {
|
|
|
+ if (!valid) return
|
|
|
+ this.loading = true
|
|
|
+ withdraw({
|
|
|
+ member_id: this.upForm.member_id,
|
|
|
+ remark: this.upForm.remark,
|
|
|
+ amount: this.upForm.amount,
|
|
|
+ change_type: this.upForm.change_type
|
|
|
+ }).then((res) => {
|
|
|
+ this.loading = false
|
|
|
+ if (res.code === 0) {
|
|
|
+ this.$message.success('操作成功')
|
|
|
+ this.$refs.upDialog.close()
|
|
|
+ this.handleSearch()
|
|
|
+ } else {
|
|
|
+ this.$message.error(res.msg || '操作失败')
|
|
|
+ }
|
|
|
+ }).catch(() => {
|
|
|
+ this.loading = false
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ confirmDown() {
|
|
|
+ this.$refs.downFormRef.validate((valid) => {
|
|
|
+ if (!valid) return
|
|
|
+ this.loading = true
|
|
|
+ walletdebiting({
|
|
|
+ member_id: this.downForm.member_id,
|
|
|
+ remark: this.downForm.remark,
|
|
|
+ amount: this.downForm.amount
|
|
|
+ }).then((res) => {
|
|
|
+ this.loading = false
|
|
|
+ if (res.code === 0) {
|
|
|
+ this.$message.success('操作成功')
|
|
|
+ this.$refs.downDialog.close()
|
|
|
+ this.handleSearch()
|
|
|
+ } else {
|
|
|
+ this.$message.error(res.msg || '操作失败')
|
|
|
+ }
|
|
|
+ }).catch(() => {
|
|
|
+ this.loading = false
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.manual-audit-page {
|
|
|
+ padding: 16px;
|
|
|
+ background: #f5f7fa;
|
|
|
+}
|
|
|
+.content-panel {
|
|
|
+ min-height: calc(100vh - 82px);
|
|
|
+ overflow: hidden;
|
|
|
+ border-radius: 8px;
|
|
|
+ background: #fff;
|
|
|
+}
|
|
|
+.filter-panel {
|
|
|
+ padding: 16px 20px 0;
|
|
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
+ background: #fff;
|
|
|
+}
|
|
|
+.action-btns {
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+.filter-form {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.filter-actions {
|
|
|
+ margin-left: auto;
|
|
|
+}
|
|
|
+.table-section {
|
|
|
+ padding: 18px 20px 20px;
|
|
|
+}
|
|
|
+.el-pagination {
|
|
|
+ margin-top: 14px;
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+</style>
|