新增:用户管理增加充值功能与钱包流水查询
- 操作列新增"充值""流水信息"按钮,权限与修改一致(isOperation 控制) - 新增充值弹窗 rechargeUser.vue:展示账户名称(只读),金额单位元(校验大于0、最多两位小数),提交 userId/userName/amount/orderNo/description - 新增流水弹窗 walletLog.vue:展示充值与扣费明细(income/expense),金额元,后端分页(pageNum/pageSize) - 新增 recharge、getWalletLogs 接口,路径 shop-user-trade/account/controller/* - other.scss 补充 op-btn-recharge 固定绿色样式(含 dark 主题) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -70,6 +70,22 @@ export function deleteUser(ids: number[]) {
|
||||
});
|
||||
}
|
||||
|
||||
export function recharge(data: object) {
|
||||
return request({
|
||||
url: '/shop-user-trade/account/controller/recharge',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
export function getWalletLogs(userId: number, pageNum: number, pageSize: number) {
|
||||
return request({
|
||||
url: '/shop-user-trade/account/controller/logs',
|
||||
method: 'get',
|
||||
params: { userId, pageNum, pageSize },
|
||||
});
|
||||
}
|
||||
|
||||
export function checkIsSuperAdmin() {
|
||||
return request({
|
||||
url: '/admin-go/api/v1/system/user/checkIsSuperAdmin',
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
color: #f56c6c !important;
|
||||
}
|
||||
|
||||
.op-btn-recharge {
|
||||
color: #67c23a !important; // 充值 绿色
|
||||
}
|
||||
|
||||
[data-theme='dark'] {
|
||||
// textarea - css vars
|
||||
--w-e-textarea-bg-color: var(--el-color-white) !important;
|
||||
@@ -49,6 +53,10 @@
|
||||
color: #f56c6c !important; // 删除 红色
|
||||
}
|
||||
|
||||
.op-btn-recharge {
|
||||
color: #67c23a !important; // 充值 绿色
|
||||
}
|
||||
|
||||
// toolbar - css vars
|
||||
--w-e-toolbar-color: var(--el-text-color-primary) !important;
|
||||
--w-e-toolbar-bg-color: var(--el-color-white) !important;
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div class="system-recharge-user-container">
|
||||
<el-dialog title="用户充值" v-model="isShowDialog" width="520px">
|
||||
<el-form ref="formRef" :model="ruleForm" :rules="rules" size="default" label-width="110px">
|
||||
<el-form-item label="账户名称" prop="userName">
|
||||
<el-input v-model="ruleForm.userName" disabled placeholder="请输入账户名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="充值金额" prop="amount">
|
||||
<el-input v-model="ruleForm.amount" placeholder="请输入充值金额(单位:元)" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="外部订单号" prop="orderNo">
|
||||
<el-input v-model="ruleForm.orderNo" placeholder="请输入外部订单号(选填)" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述" prop="description">
|
||||
<el-input v-model="ruleForm.description" type="textarea" placeholder="请输入描述(选填)" maxlength="150"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="onCancel" size="default">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" size="default">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { reactive, toRefs, defineComponent, ref, unref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { recharge } from '/@/api/system/user';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'systemRechargeUser',
|
||||
setup() {
|
||||
const formRef = ref<HTMLElement | null>(null);
|
||||
const state = reactive({
|
||||
isShowDialog: false,
|
||||
ruleForm: {
|
||||
userId: 0,
|
||||
userName: '',
|
||||
amount: '',
|
||||
orderNo: '',
|
||||
description: '',
|
||||
},
|
||||
//表单校验
|
||||
rules: {
|
||||
amount: [
|
||||
{ required: true, message: '充值金额不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: (_rule: any, value: any, callback: any) => {
|
||||
if (!/^\d+(\.\d{1,2})?$/.test(value) || Number(value) <= 0) {
|
||||
callback(new Error('请输入大于 0 的金额(单位:元,最多两位小数)'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
// 打开弹窗
|
||||
const openDialog = (row: any) => {
|
||||
state.ruleForm = {
|
||||
userId: row.id,
|
||||
userName: row.userName,
|
||||
amount: '',
|
||||
orderNo: '',
|
||||
description: '',
|
||||
};
|
||||
state.isShowDialog = true;
|
||||
};
|
||||
// 关闭弹窗
|
||||
const closeDialog = () => {
|
||||
state.isShowDialog = false;
|
||||
};
|
||||
// 取消
|
||||
const onCancel = () => {
|
||||
closeDialog();
|
||||
};
|
||||
// 提交
|
||||
const onSubmit = () => {
|
||||
const formWrap = unref(formRef) as any;
|
||||
if (!formWrap) return;
|
||||
formWrap.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
recharge({
|
||||
userId: state.ruleForm.userId,
|
||||
userName: state.ruleForm.userName,
|
||||
amount: Number(state.ruleForm.amount),
|
||||
orderNo: state.ruleForm.orderNo,
|
||||
description: state.ruleForm.description,
|
||||
}).then(() => {
|
||||
ElMessage.success('充值成功');
|
||||
closeDialog();
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
return {
|
||||
openDialog,
|
||||
closeDialog,
|
||||
onCancel,
|
||||
onSubmit,
|
||||
formRef,
|
||||
...toRefs(state),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="system-wallet-log-container">
|
||||
<el-dialog title="钱包流水信息" v-model="isShowDialog" width="1000px">
|
||||
<el-table :data="logs" style="width: 100%" :max-height="420">
|
||||
<el-table-column prop="orderNo" label="业务单据号" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="transactionNo" label="账务流水号" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="type" label="类型" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.type === 'income' ? 'success' : 'danger'">{{ scope.row.type === 'income' ? '充值' : '扣费' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="amount" label="变动金额(元)" width="120" align="right"></el-table-column>
|
||||
<el-table-column prop="balanceBefore" label="变动前余额(元)" width="130" align="right"></el-table-column>
|
||||
<el-table-column prop="balanceAfter" label="变动后余额(元)" width="130" align="right"></el-table-column>
|
||||
<el-table-column prop="currency" label="货币" width="80" align="center"></el-table-column>
|
||||
<el-table-column prop="description" label="描述" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="createdAt" label="创建时间" width="170"></el-table-column>
|
||||
</el-table>
|
||||
<div class="system-wallet-log-pagination">
|
||||
<pagination :total="total" v-model:page="pageNum" v-model:limit="pageSize" @pagination="handlePagination" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { reactive, toRefs, defineComponent } from 'vue';
|
||||
import { getWalletLogs } from '/@/api/system/user';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'systemWalletLog',
|
||||
setup() {
|
||||
const state = reactive({
|
||||
isShowDialog: false,
|
||||
userId: 0,
|
||||
logs: [] as any[],
|
||||
total: 0,
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
// 请求流水数据(后端分页)
|
||||
const getLogs = () => {
|
||||
getWalletLogs(state.userId, state.pageNum, state.pageSize).then((res: any) => {
|
||||
state.logs = res.data.logs ?? [];
|
||||
state.total = res.data.total ?? 0;
|
||||
});
|
||||
};
|
||||
// 打开弹窗并加载流水
|
||||
const openDialog = (userId: number) => {
|
||||
state.userId = userId;
|
||||
state.logs = [];
|
||||
state.total = 0;
|
||||
state.pageNum = 1;
|
||||
state.isShowDialog = true;
|
||||
getLogs();
|
||||
};
|
||||
// 分页事件(pageNum/pageSize 已由 v-model 更新,重新请求当前页)
|
||||
const handlePagination = () => {
|
||||
getLogs();
|
||||
};
|
||||
return {
|
||||
openDialog,
|
||||
handlePagination,
|
||||
...toRefs(state),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -117,7 +117,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createdAt" label="创建时间" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="操作" width="200">
|
||||
<el-table-column label="操作" width="320">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
size="small"
|
||||
@@ -140,6 +140,25 @@
|
||||
>删除</el-button
|
||||
>
|
||||
<el-button size="small" text type="primary" v-debounce @click="handleResetPwd(scope.row)">重置</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
text
|
||||
type="primary"
|
||||
class="op-btn-recharge"
|
||||
:disabled="!scope.row.isOperation"
|
||||
v-debounce
|
||||
@click="onOpenRecharge(scope.row)"
|
||||
>充值</el-button
|
||||
>
|
||||
<el-button
|
||||
size="small"
|
||||
text
|
||||
type="primary"
|
||||
:disabled="!scope.row.isOperation"
|
||||
v-debounce
|
||||
@click="onOpenWalletLog(scope.row)"
|
||||
>流水信息</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -154,6 +173,8 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
<EditUser ref="editUserRef" :dept-data="deptData" :gender-data="sys_user_sex" @getUserList="userList" />
|
||||
<RechargeUser ref="rechargeUserRef" />
|
||||
<WalletLog ref="walletLogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -162,6 +183,8 @@ import { toRefs, reactive, onMounted, ref, defineComponent, watch, getCurrentIns
|
||||
import { ElMessageBox, ElMessage, ElTree, FormInstance } from 'element-plus';
|
||||
import { Search } from '@element-plus/icons-vue';
|
||||
import EditUser from '/@/views/system/user/component/editUser.vue';
|
||||
import RechargeUser from '/@/views/system/user/component/rechargeUser.vue';
|
||||
import WalletLog from '/@/views/system/user/component/walletLog.vue';
|
||||
import { getUserList, getDeptTree, resetUserPwd, changeUserStatus, deleteUser } from '/@/api/system/user/index';
|
||||
|
||||
interface TableDataState {
|
||||
@@ -186,11 +209,13 @@ interface TableDataState {
|
||||
|
||||
export default defineComponent({
|
||||
name: 'systemUser',
|
||||
components: { EditUser },
|
||||
components: { EditUser, RechargeUser, WalletLog },
|
||||
setup() {
|
||||
const { proxy } = <any>getCurrentInstance();
|
||||
const { sys_user_sex } = proxy.useDict('sys_user_sex');
|
||||
const editUserRef = ref();
|
||||
const rechargeUserRef = ref();
|
||||
const walletLogRef = ref();
|
||||
const queryRef = ref();
|
||||
const filterText = ref('');
|
||||
const treeRef = ref<InstanceType<typeof ElTree>>();
|
||||
@@ -259,6 +284,14 @@ export default defineComponent({
|
||||
const onOpenEditUser = (row: any) => {
|
||||
editUserRef.value.openDialog(row);
|
||||
};
|
||||
// 打开充值弹窗
|
||||
const onOpenRecharge = (row: any) => {
|
||||
rechargeUserRef.value.openDialog(row);
|
||||
};
|
||||
// 打开流水信息弹窗
|
||||
const onOpenWalletLog = (row: any) => {
|
||||
walletLogRef.value.openDialog(row.id);
|
||||
};
|
||||
// 删除用户
|
||||
const onRowDel = (row: any) => {
|
||||
let msg = '你确定要删除所选用户?';
|
||||
@@ -358,8 +391,12 @@ export default defineComponent({
|
||||
return {
|
||||
queryRef,
|
||||
editUserRef,
|
||||
rechargeUserRef,
|
||||
walletLogRef,
|
||||
onOpenAddUser,
|
||||
onOpenEditUser,
|
||||
onOpenRecharge,
|
||||
onOpenWalletLog,
|
||||
onRowDel,
|
||||
onHandleSizeChange,
|
||||
onHandleCurrentChange,
|
||||
|
||||
Reference in New Issue
Block a user