feat: 添加完整的前端管理系统 (VbenAdmin)
- 添加基于 VbenAdmin + Vue3 + Element Plus 的前端管理系统 - 包含完整的 UI 组件库和工具链 - 支持多应用架构 (web-ele, backend-mock, playground) - 包含完整的开发规范和配置 - 修复 admin 目录的子模块问题,确保正确提交
This commit is contained in:
722
admin/apps/web-ele/src/views/common/user/member/index.vue
Normal file
722
admin/apps/web-ele/src/views/common/user/member/index.vue
Normal file
@@ -0,0 +1,722 @@
|
||||
<template>
|
||||
<div class="member-user-page">
|
||||
<!-- 搜索表单 -->
|
||||
<div class="search-form">
|
||||
<el-form :model="searchForm" inline>
|
||||
<el-form-item label="用户名">
|
||||
<el-input
|
||||
v-model="searchForm.keyword"
|
||||
placeholder="请输入用户名或手机号"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="searchForm.status" placeholder="请选择状态" clearable>
|
||||
<el-option label="正常" :value="1" />
|
||||
<el-option label="禁用" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="会员等级">
|
||||
<el-select v-model="searchForm.memberLevel" placeholder="请选择会员等级" clearable>
|
||||
<el-option label="普通会员" :value="1" />
|
||||
<el-option label="银牌会员" :value="2" />
|
||||
<el-option label="金牌会员" :value="3" />
|
||||
<el-option label="钻石会员" :value="4" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">
|
||||
<Icon icon="ep:search" class="mr-1" />
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button @click="handleReset">
|
||||
<Icon icon="ep:refresh" class="mr-1" />
|
||||
重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="action-buttons mb-4">
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
<Icon icon="ep:plus" class="mr-1" />
|
||||
新增会员
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
:disabled="!selectedRows.length"
|
||||
@click="handleBatchDelete"
|
||||
>
|
||||
<Icon icon="ep:delete" class="mr-1" />
|
||||
批量删除
|
||||
</el-button>
|
||||
<el-button type="success" @click="handleExport">
|
||||
<Icon icon="ep:download" class="mr-1" />
|
||||
导出数据
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="memberId" label="ID" width="80" />
|
||||
<el-table-column prop="username" label="用户名" min-width="120" />
|
||||
<el-table-column prop="nickname" label="昵称" min-width="120" />
|
||||
<el-table-column prop="mobile" label="手机号" min-width="120" />
|
||||
<el-table-column prop="sex" label="性别" width="80">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getSexTagType(row.sex)">
|
||||
{{ getSexText(row.sex) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="memberLevel" label="会员等级" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getLevelTagType(row.memberLevel)">
|
||||
{{ getLevelText(row.memberLevel) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="point" label="积分" width="80" />
|
||||
<el-table-column prop="balance" label="余额" width="100">
|
||||
<template #default="{ row }">
|
||||
¥{{ (row.balance / 100).toFixed(2) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="80">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
|
||||
{{ row.status === 1 ? '正常' : '禁用' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="注册时间" width="180">
|
||||
<template #default="{ row }">
|
||||
{{ formatTime(row.createTime) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="250" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" size="small" @click="handleEdit(row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button type="warning" size="small" @click="handleBalance(row)">
|
||||
余额
|
||||
</el-button>
|
||||
<el-button type="info" size="small" @click="handlePoint(row)">
|
||||
积分
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="handleDelete(row)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
v-model:current-page="pagination.page"
|
||||
v-model:page-size="pagination.limit"
|
||||
:total="pagination.total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑对话框 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
width="600px"
|
||||
@close="handleDialogClose"
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input
|
||||
v-model="formData.username"
|
||||
placeholder="请输入用户名"
|
||||
:disabled="isEdit"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input
|
||||
v-model="formData.password"
|
||||
type="password"
|
||||
placeholder="请输入密码"
|
||||
show-password
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号" prop="mobile">
|
||||
<el-input v-model="formData.mobile" placeholder="请输入手机号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="昵称" prop="nickname">
|
||||
<el-input v-model="formData.nickname" placeholder="请输入昵称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="性别" prop="sex">
|
||||
<el-radio-group v-model="formData.sex">
|
||||
<el-radio :label="1">男</el-radio>
|
||||
<el-radio :label="2">女</el-radio>
|
||||
<el-radio :label="0">未知</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="会员等级" prop="memberLevel">
|
||||
<el-select v-model="formData.memberLevel" placeholder="请选择会员等级">
|
||||
<el-option label="普通会员" :value="1" />
|
||||
<el-option label="银牌会员" :value="2" />
|
||||
<el-option label="金牌会员" :value="3" />
|
||||
<el-option label="钻石会员" :value="4" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="积分" prop="point">
|
||||
<el-input-number v-model="formData.point" :min="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="余额" prop="balance">
|
||||
<el-input-number v-model="formData.balance" :min="0" :precision="2" />
|
||||
<span class="ml-2 text-gray-500">元</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio :label="1">正常</el-radio>
|
||||
<el-radio :label="0">禁用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">
|
||||
确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 余额调整对话框 -->
|
||||
<el-dialog v-model="balanceDialogVisible" title="余额调整" width="400px">
|
||||
<el-form :model="balanceForm" label-width="100px">
|
||||
<el-form-item label="当前余额">
|
||||
<span>¥{{ (currentMember?.balance || 0) / 100 }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="调整类型">
|
||||
<el-radio-group v-model="balanceForm.changeType">
|
||||
<el-radio label="increase">增加</el-radio>
|
||||
<el-radio label="decrease">减少</el-radio>
|
||||
<el-radio label="set">设置</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="调整金额">
|
||||
<el-input-number
|
||||
v-model="balanceForm.amount"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
placeholder="请输入金额"
|
||||
/>
|
||||
<span class="ml-2 text-gray-500">元</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input
|
||||
v-model="balanceForm.remark"
|
||||
type="textarea"
|
||||
placeholder="请输入调整原因"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="balanceDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSaveBalance" :loading="balanceLoading">
|
||||
确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 积分调整对话框 -->
|
||||
<el-dialog v-model="pointDialogVisible" title="积分调整" width="400px">
|
||||
<el-form :model="pointForm" label-width="100px">
|
||||
<el-form-item label="当前积分">
|
||||
<span>{{ currentMember?.point || 0 }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="调整类型">
|
||||
<el-radio-group v-model="pointForm.changeType">
|
||||
<el-radio label="increase">增加</el-radio>
|
||||
<el-radio label="decrease">减少</el-radio>
|
||||
<el-radio label="set">设置</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="调整积分">
|
||||
<el-input-number
|
||||
v-model="pointForm.amount"
|
||||
:min="0"
|
||||
placeholder="请输入积分"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input
|
||||
v-model="pointForm.remark"
|
||||
type="textarea"
|
||||
placeholder="请输入调整原因"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="pointDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSavePoint" :loading="pointLoading">
|
||||
确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// 1. Vue 相关导入
|
||||
import { ref, reactive, onMounted, computed, type FormInstance } from 'vue';
|
||||
|
||||
// 2. Element Plus 组件导入
|
||||
import {
|
||||
ElButton,
|
||||
ElCard,
|
||||
ElCol,
|
||||
ElDialog,
|
||||
ElForm,
|
||||
ElFormItem,
|
||||
ElInput,
|
||||
ElInputNumber,
|
||||
ElMessage,
|
||||
ElMessageBox,
|
||||
ElOption,
|
||||
ElPagination,
|
||||
ElRadio,
|
||||
ElRadioGroup,
|
||||
ElRow,
|
||||
ElSelect,
|
||||
ElSpace,
|
||||
ElSwitch,
|
||||
ElTable,
|
||||
ElTableColumn,
|
||||
ElTag,
|
||||
} from 'element-plus';
|
||||
|
||||
// 3. 图标组件导入
|
||||
import { Icon } from '@iconify/vue';
|
||||
|
||||
// 4. Vben 组件导入
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
// 5. 项目内部导入
|
||||
import {
|
||||
getMemberListApi,
|
||||
createMemberApi,
|
||||
updateMemberApi,
|
||||
deleteMemberApi,
|
||||
batchDeleteMemberApi,
|
||||
updateMemberBalanceApi,
|
||||
updateMemberPointApi,
|
||||
type Member,
|
||||
type CreateMemberParams,
|
||||
type UpdateMemberParams,
|
||||
} from '#/api/common/user';
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false);
|
||||
const submitLoading = ref(false);
|
||||
const balanceLoading = ref(false);
|
||||
const pointLoading = ref(false);
|
||||
const tableData = ref<Member[]>([]);
|
||||
const selectedRows = ref<Member[]>([]);
|
||||
const currentMember = ref<Member | null>(null);
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
keyword: '',
|
||||
status: undefined as number | undefined,
|
||||
memberLevel: undefined as number | undefined,
|
||||
});
|
||||
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
limit: 20,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
// 对话框
|
||||
const dialogVisible = ref(false);
|
||||
const balanceDialogVisible = ref(false);
|
||||
const pointDialogVisible = ref(false);
|
||||
const isEdit = ref(false);
|
||||
const formRef = ref<FormInstance>();
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive<CreateMemberParams & { memberId?: number; balance: number }>({
|
||||
username: '',
|
||||
password: '',
|
||||
mobile: '',
|
||||
nickname: '',
|
||||
sex: 0,
|
||||
memberLevel: 1,
|
||||
point: 0,
|
||||
balance: 0,
|
||||
status: 1,
|
||||
});
|
||||
|
||||
// 余额调整表单
|
||||
const balanceForm = reactive({
|
||||
changeType: 'increase',
|
||||
amount: 0,
|
||||
remark: '',
|
||||
});
|
||||
|
||||
// 积分调整表单
|
||||
const pointForm = reactive({
|
||||
changeType: 'increase',
|
||||
amount: 0,
|
||||
remark: '',
|
||||
});
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = {
|
||||
username: [
|
||||
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
||||
{ min: 3, max: 20, message: '用户名长度在 3 到 20 个字符', trigger: 'blur' },
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||
{ min: 6, max: 20, message: '密码长度在 6 到 20 个字符', trigger: 'blur' },
|
||||
],
|
||||
mobile: [
|
||||
{ required: true, message: '请输入手机号', trigger: 'blur' },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' },
|
||||
],
|
||||
nickname: [
|
||||
{ required: true, message: '请输入昵称', trigger: 'blur' },
|
||||
],
|
||||
};
|
||||
|
||||
// 计算属性
|
||||
const dialogTitle = computed(() => (isEdit.value ? '编辑会员' : '新增会员'));
|
||||
|
||||
// 方法
|
||||
const formatTime = (timestamp: number) => {
|
||||
if (!timestamp) return '-';
|
||||
return new Date(timestamp * 1000).toLocaleString();
|
||||
};
|
||||
|
||||
const getSexText = (sex: number) => {
|
||||
const map = { 0: '未知', 1: '男', 2: '女' };
|
||||
return map[sex as keyof typeof map] || '未知';
|
||||
};
|
||||
|
||||
const getSexTagType = (sex: number) => {
|
||||
const map = { 0: 'info', 1: 'primary', 2: 'success' };
|
||||
return map[sex as keyof typeof map] || 'info';
|
||||
};
|
||||
|
||||
const getLevelText = (level: number) => {
|
||||
const map = { 1: '普通', 2: '银牌', 3: '金牌', 4: '钻石' };
|
||||
return map[level as keyof typeof map] || '普通';
|
||||
};
|
||||
|
||||
const getLevelTagType = (level: number) => {
|
||||
const map = { 1: 'info', 2: 'warning', 3: 'success', 4: 'danger' };
|
||||
return map[level as keyof typeof map] || 'info';
|
||||
};
|
||||
|
||||
const loadData = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const params = {
|
||||
page: pagination.page,
|
||||
limit: pagination.limit,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
status: searchForm.status,
|
||||
};
|
||||
const result = await getMemberListApi(params);
|
||||
tableData.value = result.list;
|
||||
pagination.total = result.total;
|
||||
} catch (error) {
|
||||
ElMessage.error('加载数据失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.page = 1;
|
||||
loadData();
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
searchForm.keyword = '';
|
||||
searchForm.status = undefined;
|
||||
searchForm.memberLevel = undefined;
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
const handleSizeChange = (size: number) => {
|
||||
pagination.limit = size;
|
||||
loadData();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (page: number) => {
|
||||
pagination.page = page;
|
||||
loadData();
|
||||
};
|
||||
|
||||
const handleSelectionChange = (selection: Member[]) => {
|
||||
selectedRows.value = selection;
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
isEdit.value = false;
|
||||
resetForm();
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleEdit = (row: Member) => {
|
||||
isEdit.value = true;
|
||||
Object.assign(formData, {
|
||||
memberId: row.memberId,
|
||||
username: row.username,
|
||||
password: '',
|
||||
mobile: row.mobile,
|
||||
nickname: row.nickname,
|
||||
sex: row.sex,
|
||||
memberLevel: row.memberLevel,
|
||||
point: row.point,
|
||||
balance: row.balance / 100, // 转换为元
|
||||
status: row.status,
|
||||
});
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleDelete = async (row: Member) => {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定要删除会员 "${row.username}" 吗?`,
|
||||
'确认删除',
|
||||
{
|
||||
type: 'warning',
|
||||
}
|
||||
);
|
||||
await deleteMemberApi(row.memberId);
|
||||
ElMessage.success('删除成功');
|
||||
loadData();
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error('删除失败');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleBatchDelete = async () => {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定要删除选中的 ${selectedRows.value.length} 个会员吗?`,
|
||||
'确认删除',
|
||||
{
|
||||
type: 'warning',
|
||||
}
|
||||
);
|
||||
const memberIds = selectedRows.value.map(row => row.memberId);
|
||||
await batchDeleteMemberApi(memberIds);
|
||||
ElMessage.success('删除成功');
|
||||
loadData();
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error('删除失败');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleExport = () => {
|
||||
ElMessage.info('导出功能开发中...');
|
||||
};
|
||||
|
||||
const handleBalance = (row: Member) => {
|
||||
currentMember.value = row;
|
||||
balanceForm.changeType = 'increase';
|
||||
balanceForm.amount = 0;
|
||||
balanceForm.remark = '';
|
||||
balanceDialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handlePoint = (row: Member) => {
|
||||
currentMember.value = row;
|
||||
pointForm.changeType = 'increase';
|
||||
pointForm.amount = 0;
|
||||
pointForm.remark = '';
|
||||
pointDialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleSaveBalance = async () => {
|
||||
if (!currentMember.value || !balanceForm.amount) {
|
||||
ElMessage.warning('请输入调整金额');
|
||||
return;
|
||||
}
|
||||
|
||||
balanceLoading.value = true;
|
||||
try {
|
||||
let newBalance = balanceForm.amount * 100; // 转换为分
|
||||
if (balanceForm.changeType === 'decrease') {
|
||||
newBalance = -newBalance;
|
||||
} else if (balanceForm.changeType === 'set') {
|
||||
newBalance = balanceForm.amount * 100;
|
||||
}
|
||||
|
||||
await updateMemberBalanceApi(
|
||||
currentMember.value.memberId,
|
||||
newBalance,
|
||||
balanceForm.changeType,
|
||||
balanceForm.remark
|
||||
);
|
||||
|
||||
ElMessage.success('余额调整成功');
|
||||
balanceDialogVisible.value = false;
|
||||
loadData();
|
||||
} catch (error) {
|
||||
ElMessage.error('余额调整失败');
|
||||
} finally {
|
||||
balanceLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleSavePoint = async () => {
|
||||
if (!currentMember.value || !pointForm.amount) {
|
||||
ElMessage.warning('请输入调整积分');
|
||||
return;
|
||||
}
|
||||
|
||||
pointLoading.value = true;
|
||||
try {
|
||||
let newPoint = pointForm.amount;
|
||||
if (pointForm.changeType === 'decrease') {
|
||||
newPoint = -newPoint;
|
||||
}
|
||||
|
||||
await updateMemberPointApi(
|
||||
currentMember.value.memberId,
|
||||
newPoint,
|
||||
pointForm.changeType,
|
||||
pointForm.remark
|
||||
);
|
||||
|
||||
ElMessage.success('积分调整成功');
|
||||
pointDialogVisible.value = false;
|
||||
loadData();
|
||||
} catch (error) {
|
||||
ElMessage.error('积分调整失败');
|
||||
} finally {
|
||||
pointLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return;
|
||||
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
submitLoading.value = true;
|
||||
|
||||
if (isEdit.value) {
|
||||
const updateData: UpdateMemberParams = {
|
||||
memberId: formData.memberId!,
|
||||
username: formData.username,
|
||||
mobile: formData.mobile,
|
||||
nickname: formData.nickname,
|
||||
sex: formData.sex,
|
||||
memberLevel: formData.memberLevel,
|
||||
point: formData.point,
|
||||
balance: Math.round(formData.balance * 100), // 转换为分
|
||||
status: formData.status,
|
||||
};
|
||||
if (formData.password) {
|
||||
updateData.password = formData.password;
|
||||
}
|
||||
await updateMemberApi(updateData);
|
||||
ElMessage.success('更新成功');
|
||||
} else {
|
||||
const createData: CreateMemberParams = {
|
||||
...formData,
|
||||
balance: Math.round(formData.balance * 100), // 转换为分
|
||||
};
|
||||
await createMemberApi(createData);
|
||||
ElMessage.success('创建成功');
|
||||
}
|
||||
|
||||
dialogVisible.value = false;
|
||||
loadData();
|
||||
} catch (error) {
|
||||
ElMessage.error(isEdit.value ? '更新失败' : '创建失败');
|
||||
} finally {
|
||||
submitLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleDialogClose = () => {
|
||||
formRef.value?.resetFields();
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
Object.assign(formData, {
|
||||
memberId: undefined,
|
||||
username: '',
|
||||
password: '',
|
||||
mobile: '',
|
||||
nickname: '',
|
||||
sex: 0,
|
||||
memberLevel: 1,
|
||||
point: 0,
|
||||
balance: 0,
|
||||
status: 1,
|
||||
});
|
||||
};
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.member-user-page {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user