You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

332 lines
8.8 KiB

<script setup lang="ts">
/**
* 用户管理页面
*/
import {ref, reactive, onMounted, watch} from 'vue';
import {useVbenVxeGrid} from '#/adapter/vxe-table';
import {useVbenModal} from '@vben/common-ui';
import {useVbenForm} from '#/adapter/form';
import dayjs from 'dayjs';
import {columns} from './data';
import {formSchema} from './form';
import { {{entity}}Api } from '#/api/{{entity}}';
// ========== 状态变量 ==========
const currentRow = ref(null);
const isEdit = ref(false);
const modalTitle = ref('新增');
// ========== 动态生成的查询表单 Schema ==========
const querySchema = ref([]);
// ========== 枚举数据配置 ==========
const enumData = reactive({
loading: true,
list: [], // 存储接口返回的原始枚举数据
});
//todo 枚举数据在查询里面不展示的配置
const hiddenColumns = ref(['createdAt', 'updatedBy', 'updatedAt', 'userPassword', 'userId', 'userSys', 'deletedFlag', "userFace"])
// ========== 初始化枚举数据和查询表单 ==========
async function initEnumData() {
try {
enumData.loading = true;
// 调用枚举列表接口
const res = await userApi.enumList({});
const enums = res.result || res;
// 保存原始枚举数据
enumData.list = enums;
// 根据 queryFields 和枚举数据动态生成查询表单 schema`
querySchema.value = formSchema.filter(formItem => {
// 2. 排除隐藏的字段
if (hiddenColumns.value.includes(formItem.fieldName)) {
console.log('跳过隐藏字段:', formItem.fieldName)
return false;
}
return true;
}).map(formSchemaTmp => {
// 在枚举列表中查找匹配的字段
const matchedEnums = enums.filter(item => item.fieldName === formSchemaTmp.fieldName);
// 合并相同 fieldName 的所有 options
const allOptions = matchedEnums.reduce((acc, item) => {
if (item.options && Array.isArray(item.options)) {
return [...acc, ...item.options];
}
return acc;
}, []);
// 判断是否有匹配的枚举选项
if (allOptions.length > 0) {
return {
component: 'Select',
fieldName: formSchemaTmp.fieldName,
label: formSchemaTmp.label,
componentProps: {
placeholder: `请选择`,
allowClear: true,
options: allOptions.map(opt => ({
label: opt.label,
value: String(opt.value), // 确保 value 是字符串
})),
},
};
} else {
// ❌ 未匹配到枚举 → 使用 Input 组件
return {
component: 'Input',
fieldName: formSchemaTmp.fieldName,
label: formSchemaTmp.label,
componentProps: {
placeholder: `请输入${formSchemaTmp.label}`,
allowClear: true,
},
};
}
});
} catch (error) {
} finally {
enumData.loading = false;
}
}
// 页面加载时自动执行初始化
onMounted(() => {
initEnumData();
});
// ========== 查询表单配置 (初始为空 schema) ==========
const [QueryForm, queryFormApi] = useVbenForm({
schema: [], // 初始化为空数组
layout: 'inline',
showDefaultActions: false,
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-5',
})
// ========== 监听 querySchema 变化并更新表单 ==========
watch(
querySchema,
(newSchema) => {
if (newSchema && newSchema.length > 0) {
console.log('🔄 更新查询表单 schema:', newSchema);
// ✅ 使用 setState 方法更新 schema
queryFormApi.setState({
schema: newSchema,
});
}
},
{immediate: false}
);
// ========== 表格配置 ==========
const gridOptions = {
columns: [
...columns,
{
field: 'action',
title: '操作',
width: 120,
fixed: 'right',
slots: {default: 'action'},
},
],
proxyConfig: {
ajax: {
query: async ({page}) => {
try {
// 获取查询表单的值
const queryValues = await queryFormApi.getValues();
console.log('=== 查询参数 ===', {
pageNum: page?.currentPage || 1,
pageSize: page?.pageSize || 10,
...queryValues,
})
const res = await userApi.page({
pageNum: page?.currentPage || 1,
pageSize: page?.pageSize || 10,
...queryValues, // 携带查询条件
})
const data = res.error?.result || res.result || res
return {
items: data.records || [],
total: data.total || 0
}
} catch (error) {
console.error('查询用户列表失败:', error)
throw error
}
}
},
response: {
result: 'items',
total: 'total'
}
},
pagerConfig: {
enabled: true,
pageSize: 10,
},
}
const [Grid, gridApi] = useVbenVxeGrid({gridOptions})
// ========== 弹窗配置 ==========
const [Modal, modalApi] = useVbenModal({
centered: true,
closable: true,
maskClosable: false,
draggable: true,
width: 800,
onCancel() {
modalApi.close();
},
onConfirm: async () => {
try {
const values = await formApi.validateAndSubmitForm();
if (!values) return;
// 处理日期格式,将 Day.js 对象转换为字符串
const submitValues = {
...values,
userBirthday: values.userBirthday ? dayjs(values.userBirthday).format('YYYY-MM-DD') : null,
};
if (isEdit.value && currentRow.value?.id) {
await userApi.save({...submitValues, id: currentRow.value.id});
} else {
await userApi.save(submitValues);
}
modalApi.close();
gridApi.reload();
} catch (error) {
console.error('保存失败:', error);
}
},
onOpenChange(isOpen: boolean) {
if (!isOpen && !isEdit.value) {
formApi.resetForm();
}
},
})
// ========== 表单配置 ==========
const [Form, formApi] = useVbenForm({
schema: formSchema,
showDefaultActions: false,
wrapperClass: 'grid-cols-1 md:grid-cols-2',
commonConfig: {
componentProps: {
class: 'w-full',
autocomplete: 'off',
},
},
})
// ========== 打开新增弹窗 ==========
function handleAdd() {
isEdit.value = false;
modalTitle.value = '新增用户';
formApi.resetForm();
modalApi.open();
}
// ========== 打开编辑弹窗 ==========
function handleEdit(row: any) {
isEdit.value = true;
currentRow.value = row;
modalTitle.value = '编辑用户';
// 设置表单值,过滤掉不必要的字段,并处理日期格式
const formValues = {
id: row.id,
userName: row.userName,
userPhone: row.userPhone,
userRealName: row.userRealName,
userGender: row.userGender,
userPassword: row.userPassword,
userBirthday: row.userBirthday,
userFace: row.userFace,
userEmail: row.userEmail,
userAddress: row.userAddress,
userId: row.userId,
userSys: row.userSys,
userPhoneModel: row.userPhoneModel,
userStatus: row.userStatus,
userCid: row.userCid,
userIp: row.userIp,
};
formApi.setValues(formValues);
modalApi.open();
}
// ========== 删除确认 ==========
function handleDelete(row: any) {
if (!row.id) return;
window.confirm(`确定要删除 "${row.userName}" 吗?`) &&
userApi.remove(row.id).then(() => {
gridApi.reload();
});
}
// ========== 查询功能 ==========
function handleSearch() {
console.log('=== 点击查询按钮 ===')
// 先重置到第一页,然后执行查询
gridApi.query();
}
// ========== 重置查询 ==========
function handleReset() {
queryFormApi.resetForm();
gridApi.reload();
}
</script>
<template>
<div style="height: 100vh; padding: 16px; box-sizing: border-box;">
<!-- 查询表单 -->
<div class="bg-card mb-4 p-4 rounded shadow">
<h3 class="text-lg font-semibold mb-3">查询条件</h3>
<QueryForm/>
<div class="mt-3 flex gap-2">
<button @click="handleSearch"
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
🔍 查询
</button>
<button @click="handleReset"
class="bg-gray-500 text-white px-4 py-2 rounded hover:bg-gray-600">
🔄 重置
</button>
</div>
</div>
<!-- 数据表格 -->
<Grid>
<template #toolbar-tools>
<button @click="handleAdd" class="mr-2">➕ 新增</button>
<button @click="() => gridApi.reload()">🔄 刷新</button>
</template>
<template #action="{ row }">
<div class="flex gap-2">
<button @click="() => handleEdit(row)" class="text-blue-500 hover:text-blue-700">✏️ 编辑
</button>
<button @click="() => handleDelete(row)" class="text-red-500 hover:text-red-700">🗑️ 删除
</button>
</div>
</template>
</Grid>
<Modal :title="modalTitle">
<Form/>
</Modal>
</div>
</template>