platform-vue/src/views/apps/babyhealth/users/index.vue
2026-04-01 15:14:37 +08:00

329 lines
8.1 KiB
Vue

<template>
<div class="container-box">
<div class="header-bar">
<h2>用户管理</h2>
<div class="header-actions">
<el-button type="primary" @click="handleAddUser">
<el-icon><Plus /></el-icon>
添加用户
</el-button>
<el-button @click="refresh">
<el-icon><Refresh /></el-icon>
刷新
</el-button>
</div>
</div>
<el-divider></el-divider>
<!-- 用户列表表格 -->
<el-table :data="users" style="width: 100%" v-loading="loading">
<el-table-column
prop="id"
label="ID"
align="center"
fixed="left"
/>
<el-table-column prop="account" label="账号" align="center" />
<el-table-column
prop="name"
label="姓名"
align="center"
>
<template #default="scope">
<span class="name-link" @click="handlePreview(scope.row)">{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column prop="sex" label="性别" align="center">
<template #default="scope">
<el-tag
:type="getSexTagType(scope.row.sex)"
size="small"
>
{{ getSexTagText(scope.row.sex) }}
</el-tag>
</template>
</el-table-column>
<el-table-column
prop="phone"
label="手机号"
align="center"
/>
<el-table-column
prop="email"
label="email"
width="180"
align="center"
/>
<el-table-column prop="status" label="状态" width="80" align="center">
<template #default="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">{{
scope.row.status === 1 ? "启用" : "禁用"
}}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="240" align="center" fixed="right">
<template #default="scope">
<el-button size="small" @click="handleEdit(scope.row)"
>编辑</el-button
>
<el-button
size="small"
type="warning"
@click="handleChangePassword(scope.row)"
>
修改密码
</el-button>
<el-button
size="small"
type="danger"
@click="handleDelete(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination-bar">
<el-pagination
:current-page="page"
:page-size="pageSize"
:total="total"
@current-change="handlePageChange"
layout="total, prev, pager, next"
/>
</div>
<!-- 编辑用户对话框组件 -->
<UserEditDialog
ref="userEditRef"
:modelValue="editDialogVisible"
@update:modelValue="editDialogVisible = $event"
:is-edit="isEdit"
@submit="handleEditSuccess"
@close="editDialogVisible = false"
/>
<!-- 修改密码对话框组件 -->
<ChangePasswordDialog
ref="changePasswordRef"
:modelValue="passwordDialogVisible"
@update:modelValue="passwordDialogVisible = $event"
:user-id="currentUserId"
@submit="handlePasswordChangeSuccess"
@close="passwordDialogVisible = false"
/>
<!-- 预览用户对话框组件 -->
<PreviewDialog
ref="previewDialogRef"
:modelValue="previewDialogVisible"
@update:modelValue="previewDialogVisible = $event"
:user="currentUser"
/>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { Plus, Refresh } from "@element-plus/icons-vue";
import { getUserList, deleteUser } from "@/api/babyhealth";
import UserEditDialog from "./components/userEdit.vue";
import ChangePasswordDialog from "./components/changePassword.vue";
import PreviewDialog from "./components/preview.vue";
interface User {
id: number;
account: string;
name: string;
phone: string;
qq: string;
sex: number;
rid: number;
status: number;
last_login_ip: string;
email: number;
create_time: string;
update_time: string;
}
interface Role {
id: number;
name: string;
status?: number;
rights?: string;
create_time?: string;
update_time?: string;
}
const page = ref(1);
const pageSize = ref(10);
const total = ref(0);
const users = ref<User[]>([]);
const roles = ref<Role[]>([]);
const loading = ref(false);
// 组件引用
const userEditRef = ref();
const changePasswordRef = ref();
const previewDialogRef = ref();
// 编辑/密码对话框状态
const editDialogVisible = ref(false);
const passwordDialogVisible = ref(false);
const previewDialogVisible = ref(false);
const editDialogTitle = ref("添加用户");
const isEdit = ref(false);
const currentUserId = ref<number | undefined>(undefined);
const currentUser = ref<User | undefined>(undefined);
//刷新
const refresh = async () => {
await fetchUsers();
};
// 获取角色列表
const fetchRoles = async () => {
try {
const res = await getAllRoles();
roles.value = res.data || [];
} catch (e) {
roles.value = [];
}
};
// 获取性别tag类型
function getSexTagType(sex: number): string {
if (sex === 1) return 'primary'; // 男
if (sex === 2) return 'danger'; // 女
return 'info'; // 未知
}
// 获取性别tag文本
function getSexTagText(sex: number): string {
if (sex === 1) return '男';
if (sex === 2) return '女';
return '未知';
}
// 获取用户列表
const fetchUsers = async () => {
loading.value = true;
try {
const res = await getUserList();
users.value = res.data || [];
} catch (e) {
users.value = [];
} finally {
loading.value = false;
}
};
// 添加用户
const handleAddUser = () => {
isEdit.value = false;
editDialogVisible.value = true;
if (userEditRef.value) {
userEditRef.value.open();
}
};
// 编辑用户
const handleEdit = (user: User) => {
isEdit.value = true;
editDialogVisible.value = true;
if (userEditRef.value) {
userEditRef.value.open(user);
}
};
// 预览用户
const handlePreview = (user: User) => {
currentUser.value = user;
previewDialogVisible.value = true;
if (previewDialogRef.value) {
previewDialogRef.value.open(user);
}
};
//修改密码
const handleChangePassword = async (user: User) => {
changePasswordRef.value.open(user.id, user.account);
passwordDialogVisible.value = true;
currentUserId.value = user.id;
};
// 编辑成功回调
const handleEditSuccess = () => {
editDialogVisible.value = false;
ElMessage.success(isEdit.value ? "编辑成功" : "添加成功");
fetchUsers();
};
// 密码修改成功回调
const handlePasswordChangeSuccess = () => {
passwordDialogVisible.value = false;
ElMessage.success("密码修改成功");
};
// 分页改变
const handlePageChange = (val: number) => {
page.value = val;
fetchUsers();
};
// 删除用户
const handleDelete = async (user: User) => {
ElMessageBox.confirm("确认删除该用户?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(async () => {
try {
await deleteUser(user.id);
ElMessage.success("删除成功");
fetchUsers();
} catch (e) {
ElMessage.error("删除失败");
}
});
};
onMounted(async () => {
fetchUsers();
fetchRoles();
});
</script>
<style lang="less" scoped>
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
span {
font-size: 1.4rem;
font-weight: 700;
}
}
:deep(.el-alert__title) {
color: #f56c6c !important;
}
.name-link {
color: #3973ff;
cursor: pointer;
text-decoration: none;
transition: color 0.3s;
&:hover {
color: #66b1ff;
text-decoration: underline;
}
}
</style>