commits
This commit is contained in:
@@ -1,198 +1,198 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" title="修改密码" width="400px" @close="handleClose">
|
||||
<el-form :model="form">
|
||||
<!-- 用户账号(只读) -->
|
||||
<el-form-item label="账号">
|
||||
<el-input v-model="form.username" disabled />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 新密码 -->
|
||||
<el-form-item label="新密码">
|
||||
<el-input
|
||||
v-model="passwordForm.newPassword"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
show-password
|
||||
placeholder="请输入新密码(6-16位)"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 确认密码 -->
|
||||
<el-form-item label="确认密码">
|
||||
<el-input
|
||||
v-model="passwordForm.confirmPassword"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
show-password
|
||||
placeholder="请再次输入新密码"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<el-form-item v-if="passwordError">
|
||||
<el-alert :title="passwordError" type="error" :closable="false" style="color: #f56c6c;" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 对话框脚部 -->
|
||||
<template #footer>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确定修改</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { changePassword } from "@/api/user";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
userId: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'submit', 'close']);
|
||||
|
||||
const visible = ref(false);
|
||||
const passwordError = ref("");
|
||||
|
||||
const form = ref<any>({
|
||||
id: null,
|
||||
username: "",
|
||||
});
|
||||
|
||||
const passwordForm = ref<any>({
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
});
|
||||
|
||||
// 监听 modelValue
|
||||
watch(() => props.modelValue, (newVal) => {
|
||||
visible.value = newVal;
|
||||
if (newVal && props.userId) {
|
||||
form.value.id = props.userId;
|
||||
}
|
||||
});
|
||||
|
||||
// 监听 userId 变化
|
||||
watch(() => props.userId, (newVal) => {
|
||||
if (newVal) {
|
||||
form.value.id = newVal;
|
||||
}
|
||||
});
|
||||
|
||||
// 监听 visible 变化
|
||||
watch(visible, (newVal) => {
|
||||
if (!newVal) {
|
||||
emit('update:modelValue', false);
|
||||
}
|
||||
});
|
||||
|
||||
// 校验密码
|
||||
const validatePassword = (password: string) => {
|
||||
if (!password) {
|
||||
return "请输入密码";
|
||||
}
|
||||
if (password.length < 6) {
|
||||
return "密码长度不能小于6位";
|
||||
}
|
||||
if (password.length > 16) {
|
||||
return "密码长度不能大于16位";
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// 校验确认密码
|
||||
const validateConfirmPassword = (password: string, confirmPassword: string) => {
|
||||
if (!confirmPassword) {
|
||||
return "请再次输入密码";
|
||||
}
|
||||
if (confirmPassword !== password) {
|
||||
return "两次输入的密码不一致";
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
passwordForm.value = {
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
};
|
||||
passwordError.value = "";
|
||||
emit('close');
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
// 清除之前的错误
|
||||
passwordError.value = "";
|
||||
|
||||
try {
|
||||
if (!form.value.id) {
|
||||
passwordError.value = "用户ID不能为空";
|
||||
return;
|
||||
}
|
||||
|
||||
// 校验新密码格式
|
||||
const passwordCheck = validatePassword(passwordForm.value.newPassword);
|
||||
if (passwordCheck !== true) {
|
||||
passwordError.value = passwordCheck;
|
||||
return;
|
||||
}
|
||||
|
||||
// 校验确认密码
|
||||
const confirmCheck = validateConfirmPassword(
|
||||
passwordForm.value.newPassword,
|
||||
passwordForm.value.confirmPassword
|
||||
);
|
||||
if (confirmCheck !== true) {
|
||||
passwordError.value = confirmCheck;
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用接口修改密码
|
||||
const res = await changePassword(form.value.id, passwordForm.value);
|
||||
|
||||
if (res.code === 200 || res.msg === '修改成功') {
|
||||
ElMessage.success("密码修改成功");
|
||||
visible.value = false;
|
||||
emit('update:modelValue', false);
|
||||
emit('submit');
|
||||
} else {
|
||||
passwordError.value = res.msg || "密码修改失败";
|
||||
}
|
||||
} catch (e: any) {
|
||||
const errorMsg = e?.response?.data?.msg || e?.response?.data?.message || e?.message || "操作失败";
|
||||
passwordError.value = errorMsg;
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
open: (userId: number, username: string) => {
|
||||
form.value = {
|
||||
id: userId,
|
||||
username: username,
|
||||
};
|
||||
passwordForm.value = {
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
};
|
||||
passwordError.value = "";
|
||||
visible.value = true;
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
<template>
|
||||
<el-dialog v-model="visible" title="修改密码" width="400px" @close="handleClose">
|
||||
<el-form :model="form">
|
||||
<!-- 用户账号(只读) -->
|
||||
<el-form-item label="账号">
|
||||
<el-input v-model="form.username" disabled />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 新密码 -->
|
||||
<el-form-item label="新密码">
|
||||
<el-input
|
||||
v-model="passwordForm.newPassword"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
show-password
|
||||
placeholder="请输入新密码(6-16位)"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 确认密码 -->
|
||||
<el-form-item label="确认密码">
|
||||
<el-input
|
||||
v-model="passwordForm.confirmPassword"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
show-password
|
||||
placeholder="请再次输入新密码"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<el-form-item v-if="passwordError">
|
||||
<el-alert :title="passwordError" type="error" :closable="false" style="color: #f56c6c;" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 对话框脚部 -->
|
||||
<template #footer>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确定修改</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { changePassword } from "@/api/user";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
userId: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'submit', 'close']);
|
||||
|
||||
const visible = ref(false);
|
||||
const passwordError = ref("");
|
||||
|
||||
const form = ref<any>({
|
||||
id: null,
|
||||
username: "",
|
||||
});
|
||||
|
||||
const passwordForm = ref<any>({
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
});
|
||||
|
||||
// 监听 modelValue
|
||||
watch(() => props.modelValue, (newVal) => {
|
||||
visible.value = newVal;
|
||||
if (newVal && props.userId) {
|
||||
form.value.id = props.userId;
|
||||
}
|
||||
});
|
||||
|
||||
// 监听 userId 变化
|
||||
watch(() => props.userId, (newVal) => {
|
||||
if (newVal) {
|
||||
form.value.id = newVal;
|
||||
}
|
||||
});
|
||||
|
||||
// 监听 visible 变化
|
||||
watch(visible, (newVal) => {
|
||||
if (!newVal) {
|
||||
emit('update:modelValue', false);
|
||||
}
|
||||
});
|
||||
|
||||
// 校验密码
|
||||
const validatePassword = (password: string) => {
|
||||
if (!password) {
|
||||
return "请输入密码";
|
||||
}
|
||||
if (password.length < 6) {
|
||||
return "密码长度不能小于6位";
|
||||
}
|
||||
if (password.length > 16) {
|
||||
return "密码长度不能大于16位";
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// 校验确认密码
|
||||
const validateConfirmPassword = (password: string, confirmPassword: string) => {
|
||||
if (!confirmPassword) {
|
||||
return "请再次输入密码";
|
||||
}
|
||||
if (confirmPassword !== password) {
|
||||
return "两次输入的密码不一致";
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
passwordForm.value = {
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
};
|
||||
passwordError.value = "";
|
||||
emit('close');
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
// 清除之前的错误
|
||||
passwordError.value = "";
|
||||
|
||||
try {
|
||||
if (!form.value.id) {
|
||||
passwordError.value = "用户ID不能为空";
|
||||
return;
|
||||
}
|
||||
|
||||
// 校验新密码格式
|
||||
const passwordCheck = validatePassword(passwordForm.value.newPassword);
|
||||
if (passwordCheck !== true) {
|
||||
passwordError.value = passwordCheck;
|
||||
return;
|
||||
}
|
||||
|
||||
// 校验确认密码
|
||||
const confirmCheck = validateConfirmPassword(
|
||||
passwordForm.value.newPassword,
|
||||
passwordForm.value.confirmPassword
|
||||
);
|
||||
if (confirmCheck !== true) {
|
||||
passwordError.value = confirmCheck;
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用接口修改密码
|
||||
const res = await changePassword(form.value.id, passwordForm.value);
|
||||
|
||||
if (res.code === 200 || res.msg === '修改成功') {
|
||||
ElMessage.success("密码修改成功");
|
||||
visible.value = false;
|
||||
emit('update:modelValue', false);
|
||||
emit('submit');
|
||||
} else {
|
||||
passwordError.value = res.msg || "密码修改失败";
|
||||
}
|
||||
} catch (e: any) {
|
||||
const errorMsg = e?.response?.data?.msg || e?.response?.data?.message || e?.message || "操作失败";
|
||||
passwordError.value = errorMsg;
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
open: (userId: number, username: string) => {
|
||||
form.value = {
|
||||
id: userId,
|
||||
username: username,
|
||||
};
|
||||
passwordForm.value = {
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
};
|
||||
passwordError.value = "";
|
||||
visible.value = true;
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
|
||||
@@ -1,190 +1,190 @@
|
||||
<template>
|
||||
<el-drawer v-model="visible" title="用户信息预览" size="50%">
|
||||
<div class="user-preview" v-if="user">
|
||||
<div class="user-header">
|
||||
<div class="user-avatar">
|
||||
<el-avatar :size="80" :icon="UserFilled" />
|
||||
</div>
|
||||
<h2 class="user-name">{{ user.name || "未知用户" }}</h2>
|
||||
<el-tag :type="user.status === 1 ? 'success' : 'danger'" size="large">
|
||||
{{ user.status === 1 ? "启用" : "禁用" }}
|
||||
</el-tag>
|
||||
</div>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<div class="user-info">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="ID">
|
||||
{{ user.id }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="账号">
|
||||
{{ user.account || "未设置" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="姓名">
|
||||
{{ user.name || "未设置" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="性别">
|
||||
{{ user.sex === 1 ? "男" : "女" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="手机号">
|
||||
{{ user.phone || "未设置" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="QQ">
|
||||
{{ user.qq || "未设置" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="邮箱">
|
||||
{{ user.email || "未设置" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="角色">
|
||||
<el-tag :type="getRoleTagType(user.group_id)" size="small">
|
||||
{{ getRoleName(user.group_id) }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="最后登录IP">
|
||||
{{ user.last_login_ip || "未登录" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="登录次数">
|
||||
{{ user.login_count || 0 }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">
|
||||
{{ user.create_time || "未知" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="更新时间" :span="2">
|
||||
{{ user.update_time || "未知" }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-user">
|
||||
<el-empty description="暂无用户信息" />
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { UserFilled } from "@element-plus/icons-vue";
|
||||
import { getAllRoles } from "@/api/role";
|
||||
|
||||
interface User {
|
||||
id: number;
|
||||
account: string;
|
||||
name: string;
|
||||
phone: string;
|
||||
qq: string;
|
||||
email: string;
|
||||
sex: number;
|
||||
group_id: number;
|
||||
status: number;
|
||||
last_login_ip: string;
|
||||
login_count: number;
|
||||
create_time: string;
|
||||
update_time: string;
|
||||
}
|
||||
|
||||
interface Role {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
user: {
|
||||
type: Object as () => User | undefined,
|
||||
default: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
|
||||
const visible = ref(false);
|
||||
const roles = ref<Role[]>([]);
|
||||
|
||||
// 监听对话框显示状态
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
visible.value = newVal;
|
||||
}
|
||||
);
|
||||
|
||||
// 监听visible变化,同步给父组件
|
||||
watch(visible, (newVal) => {
|
||||
emit("update:modelValue", newVal);
|
||||
});
|
||||
|
||||
// 获取角色列表
|
||||
const fetchRoles = async () => {
|
||||
try {
|
||||
const res = await getAllRoles();
|
||||
roles.value = res.data || [];
|
||||
} catch (e) {
|
||||
roles.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 获取角色tag状态
|
||||
function getRoleTagType(group_id: number): string {
|
||||
const typeMap: Record<number, string> = {
|
||||
1: "primary",
|
||||
2: "success",
|
||||
3: "warning",
|
||||
4: "danger",
|
||||
};
|
||||
return typeMap[group_id] || "primary";
|
||||
}
|
||||
|
||||
// 获取角色名称
|
||||
function getRoleName(group_id: number): string {
|
||||
const role = roles.value.find((r) => r.id === group_id);
|
||||
return role?.name || "未知";
|
||||
}
|
||||
|
||||
// 暴露open方法供父组件调用
|
||||
const open = (userData?: User) => {
|
||||
visible.value = true;
|
||||
fetchRoles();
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
|
||||
// 初始化时获取角色列表
|
||||
fetchRoles();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.user-preview {
|
||||
padding: 20px;
|
||||
|
||||
.user-header {
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
|
||||
.user-avatar {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
margin: 15px 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
.user-info {
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.no-user {
|
||||
padding: 40px 0;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<el-drawer v-model="visible" title="用户信息预览" size="50%">
|
||||
<div class="user-preview" v-if="user">
|
||||
<div class="user-header">
|
||||
<div class="user-avatar">
|
||||
<el-avatar :size="80" :icon="UserFilled" />
|
||||
</div>
|
||||
<h2 class="user-name">{{ user.name || "未知用户" }}</h2>
|
||||
<el-tag :type="user.status === 1 ? 'success' : 'danger'" size="large">
|
||||
{{ user.status === 1 ? "启用" : "禁用" }}
|
||||
</el-tag>
|
||||
</div>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<div class="user-info">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="ID">
|
||||
{{ user.id }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="账号">
|
||||
{{ user.account || "未设置" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="姓名">
|
||||
{{ user.name || "未设置" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="性别">
|
||||
{{ user.sex === 1 ? "男" : "女" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="手机号">
|
||||
{{ user.phone || "未设置" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="QQ">
|
||||
{{ user.qq || "未设置" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="邮箱">
|
||||
{{ user.email || "未设置" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="角色">
|
||||
<el-tag :type="getRoleTagType(user.group_id)" size="small">
|
||||
{{ getRoleName(user.group_id) }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="最后登录IP">
|
||||
{{ user.last_login_ip || "未登录" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="登录次数">
|
||||
{{ user.login_count || 0 }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">
|
||||
{{ user.create_time || "未知" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="更新时间" :span="2">
|
||||
{{ user.update_time || "未知" }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-user">
|
||||
<el-empty description="暂无用户信息" />
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { UserFilled } from "@element-plus/icons-vue";
|
||||
import { getAllRoles } from "@/api/role";
|
||||
|
||||
interface User {
|
||||
id: number;
|
||||
account: string;
|
||||
name: string;
|
||||
phone: string;
|
||||
qq: string;
|
||||
email: string;
|
||||
sex: number;
|
||||
group_id: number;
|
||||
status: number;
|
||||
last_login_ip: string;
|
||||
login_count: number;
|
||||
create_time: string;
|
||||
update_time: string;
|
||||
}
|
||||
|
||||
interface Role {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
user: {
|
||||
type: Object as () => User | undefined,
|
||||
default: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
|
||||
const visible = ref(false);
|
||||
const roles = ref<Role[]>([]);
|
||||
|
||||
// 监听对话框显示状态
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
visible.value = newVal;
|
||||
}
|
||||
);
|
||||
|
||||
// 监听visible变化,同步给父组件
|
||||
watch(visible, (newVal) => {
|
||||
emit("update:modelValue", newVal);
|
||||
});
|
||||
|
||||
// 获取角色列表
|
||||
const fetchRoles = async () => {
|
||||
try {
|
||||
const res = await getAllRoles();
|
||||
roles.value = res.data || [];
|
||||
} catch (e) {
|
||||
roles.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 获取角色tag状态
|
||||
function getRoleTagType(group_id: number): string {
|
||||
const typeMap: Record<number, string> = {
|
||||
1: "primary",
|
||||
2: "success",
|
||||
3: "warning",
|
||||
4: "danger",
|
||||
};
|
||||
return typeMap[group_id] || "primary";
|
||||
}
|
||||
|
||||
// 获取角色名称
|
||||
function getRoleName(group_id: number): string {
|
||||
const role = roles.value.find((r) => r.id === group_id);
|
||||
return role?.name || "未知";
|
||||
}
|
||||
|
||||
// 暴露open方法供父组件调用
|
||||
const open = (userData?: User) => {
|
||||
visible.value = true;
|
||||
fetchRoles();
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
});
|
||||
|
||||
// 初始化时获取角色列表
|
||||
fetchRoles();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.user-preview {
|
||||
padding: 20px;
|
||||
|
||||
.user-header {
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
|
||||
.user-avatar {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
margin: 15px 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
.user-info {
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.no-user {
|
||||
padding: 40px 0;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,408 +1,408 @@
|
||||
<template>
|
||||
<el-drawer v-model="visible" :title="dialogTitle" width="500px">
|
||||
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
|
||||
<div class="form-title">账号信息</div>
|
||||
<!-- 账号 -->
|
||||
<el-form-item label="账号">
|
||||
<el-input v-model="form.account" :disabled="!isAdd" placeholder="请输入账号" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 密码 -->
|
||||
<el-form-item label="密码" prop="password" v-if="isAdd">
|
||||
<el-input
|
||||
v-model="form.password"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
show-password
|
||||
:placeholder="isAdd ? '请输入密码(至少6位)' : '留空则不修改密码'"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 确认密码 -->
|
||||
<el-form-item label="确认密码" prop="confirmPassword" v-if="isAdd">
|
||||
<el-input
|
||||
v-model="form.confirmPassword"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
show-password
|
||||
:placeholder="isAdd ? '请再次输入密码' : '留空则不修改密码'"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider></el-divider>
|
||||
<div class="form-title">个人信息</div>
|
||||
<!-- 姓名 -->
|
||||
<el-form-item label="姓名">
|
||||
<el-input v-model="form.name" placeholder="请输入姓名" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 电话 -->
|
||||
<el-form-item label="电话">
|
||||
<el-input v-model="form.phone" placeholder="请输入电话" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 邮箱 -->
|
||||
<el-form-item label="邮箱">
|
||||
<el-input v-model="form.email" placeholder="请输入邮箱" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- QQ -->
|
||||
<el-form-item label="QQ">
|
||||
<el-input v-model="form.qq" placeholder="请输入QQ" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 性别 -->
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="form.sex" placeholder="请选择性别">
|
||||
<el-radio-button label="男" :value="1" />
|
||||
<el-radio-button label="女" :value="2" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 状态 -->
|
||||
<el-form-item label="状态">
|
||||
<el-select
|
||||
v-model="form.status"
|
||||
placeholder="请选择状态"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option label="启用" :value="1" />
|
||||
<el-option label="禁用" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 对话框脚部 -->
|
||||
<template #footer>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">保存</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { addUser, editUser, getUserInfo } from "@/api/user";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isEdit: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
statusDict: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:modelValue", "submit", "close"]);
|
||||
|
||||
const visible = ref(false);
|
||||
const formRef = ref<any>(null);
|
||||
const isAdd = ref(false);
|
||||
|
||||
const form = ref<any>({
|
||||
id: null,
|
||||
account: "",
|
||||
name: "",
|
||||
phone: "",
|
||||
qq: "",
|
||||
sex: 1,
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
email: "",
|
||||
status: 1,
|
||||
});
|
||||
|
||||
const dialogTitle = computed(() => {
|
||||
return isAdd.value ? "添加用户" : "编辑用户";
|
||||
});
|
||||
|
||||
// 密码验证规则
|
||||
const validatePassword = (rule: any, value: any, callback: any) => {
|
||||
if (isAdd.value) {
|
||||
// 新增用户时,密码必填
|
||||
if (!value) {
|
||||
callback(new Error("请输入密码"));
|
||||
return;
|
||||
}
|
||||
if (value.length < 6) {
|
||||
callback(new Error("密码长度不能少于6位"));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 编辑用户时,如果填写了密码,则必须符合规则
|
||||
if (value && value.length < 6) {
|
||||
callback(new Error("密码长度不能少于6位"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
// 确认密码验证规则
|
||||
const validateConfirmPassword = (rule: any, value: any, callback: any) => {
|
||||
if (isAdd.value) {
|
||||
// 新增用户时,确认密码必填
|
||||
if (!value) {
|
||||
callback(new Error("请再次输入密码"));
|
||||
return;
|
||||
}
|
||||
if (value !== form.value.password) {
|
||||
callback(new Error("两次输入的密码不一致"));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 编辑用户时,如果填写了密码,则确认密码必须一致
|
||||
if (form.value.password && value !== form.value.password) {
|
||||
callback(new Error("两次输入的密码不一致"));
|
||||
return;
|
||||
}
|
||||
// 如果填写了确认密码但没填密码,提示错误
|
||||
if (value && !form.value.password) {
|
||||
callback(new Error("请先输入密码"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
// 表单验证规则
|
||||
const rules = {
|
||||
account: [
|
||||
{ required: true, message: "请输入账号", trigger: "blur" },
|
||||
{ min: 3, max: 20, message: "账号长度在 3 到 20 个字符", trigger: "blur" },
|
||||
],
|
||||
name: [{ required: true, message: "请输入姓名", trigger: "blur" }],
|
||||
password: [{ validator: validatePassword, trigger: "blur" }],
|
||||
confirmPassword: [{ validator: validateConfirmPassword, trigger: "blur" }],
|
||||
email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: "blur" }],
|
||||
};
|
||||
|
||||
// 监听 modelValue
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
visible.value = newVal;
|
||||
}
|
||||
);
|
||||
|
||||
// 监听 visible 变化
|
||||
watch(visible, (newVal) => {
|
||||
if (!newVal) {
|
||||
emit("update:modelValue", false);
|
||||
}
|
||||
});
|
||||
|
||||
// 监听 statusDict 变化,用于调试
|
||||
watch(
|
||||
() => props.statusDict,
|
||||
(newVal) => {},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
|
||||
const loadUserData = async (user: any) => {
|
||||
try {
|
||||
// 处理两种调用方式:传递用户对象或用户 ID
|
||||
const userId = typeof user === "number" ? user : user?.id || user?.userId;
|
||||
if (!userId) {
|
||||
throw new Error("未提供有效的用户 ID");
|
||||
}
|
||||
|
||||
const res = await getUserInfo(userId);
|
||||
|
||||
const data = res.data || res;
|
||||
|
||||
// 确保 sex 和 status 都是数字类型
|
||||
const sexValue =
|
||||
data.sex !== undefined && data.sex !== null
|
||||
? Number(data.sex)
|
||||
: 1;
|
||||
|
||||
const statusValue =
|
||||
data.status !== undefined && data.status !== null
|
||||
? Number(data.status)
|
||||
: 1;
|
||||
|
||||
form.value = {
|
||||
id: data.id,
|
||||
account: data.account,
|
||||
name: data.name,
|
||||
phone: data.phone,
|
||||
qq: data.qq,
|
||||
sex: sexValue,
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
email: data.email,
|
||||
status: statusValue,
|
||||
};
|
||||
} catch (e: any) {
|
||||
console.error("Failed to load user data:", e);
|
||||
const errorMsg = e?.response?.data?.message || e?.message || "加载用户失败";
|
||||
ElMessage.error(errorMsg);
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
// 表单验证
|
||||
if (!formRef.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
} catch (error) {
|
||||
ElMessage.warning("请检查表单填写是否正确");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证密码一致性
|
||||
if (isAdd.value) {
|
||||
// 新增用户时,密码必填
|
||||
if (!form.value.password) {
|
||||
ElMessage.error("请输入密码");
|
||||
return;
|
||||
}
|
||||
if (form.value.password !== form.value.confirmPassword) {
|
||||
ElMessage.error("两次输入的密码不一致");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 编辑用户时,如果填写了密码,则必须填写确认密码且一致
|
||||
if (form.value.password) {
|
||||
if (form.value.password !== form.value.confirmPassword) {
|
||||
ElMessage.error("两次输入的密码不一致");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (isAdd.value) {
|
||||
// 新增用户
|
||||
const submitData: any = {
|
||||
account: form.value.account,
|
||||
name: form.value.name,
|
||||
phone: form.value.phone,
|
||||
qq: form.value.qq,
|
||||
sex: form.value.sex,
|
||||
email: form.value.email,
|
||||
status: form.value.status,
|
||||
password: form.value.password,
|
||||
};
|
||||
|
||||
await addUser(submitData);
|
||||
ElMessage.success("添加成功");
|
||||
} else {
|
||||
// 编辑用户
|
||||
if (!form.value.id || form.value.id === 0) {
|
||||
ElMessage.error("用户ID不能为空");
|
||||
return;
|
||||
}
|
||||
|
||||
const submitData: any = {
|
||||
id: form.value.id,
|
||||
account: form.value.account,
|
||||
name: form.value.name,
|
||||
phone: form.value.phone,
|
||||
qq: form.value.qq,
|
||||
sex: form.value.sex,
|
||||
email: form.value.email,
|
||||
status: form.value.status,
|
||||
};
|
||||
|
||||
// 只有在填写了密码时才添加到提交数据中
|
||||
if (form.value.password) {
|
||||
submitData.password = form.value.password;
|
||||
}
|
||||
|
||||
await editUser(form.value.id, submitData);
|
||||
ElMessage.success("更新成功");
|
||||
}
|
||||
|
||||
visible.value = false;
|
||||
emit("submit");
|
||||
} catch (e: any) {
|
||||
const errorMsg = e?.response?.data?.message || e?.message || "操作失败";
|
||||
ElMessage.error(errorMsg);
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
loadUserData,
|
||||
openAdd: () => {
|
||||
isAdd.value = true;
|
||||
form.value = {
|
||||
id: 0,
|
||||
account: "",
|
||||
name: "",
|
||||
phone: "",
|
||||
qq: "",
|
||||
sex: 1,
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
email: "",
|
||||
status: 1,
|
||||
};
|
||||
visible.value = true;
|
||||
// 清除表单验证
|
||||
if (formRef.value) {
|
||||
formRef.value.clearValidate();
|
||||
}
|
||||
},
|
||||
openEdit: (user: any) => {
|
||||
isAdd.value = false;
|
||||
visible.value = true;
|
||||
// 清除表单验证
|
||||
if (formRef.value) {
|
||||
formRef.value.clearValidate();
|
||||
}
|
||||
// 异步加载用户详细信息
|
||||
loadUserData(user);
|
||||
},
|
||||
open: (user?: any) => {
|
||||
if (user) {
|
||||
isAdd.value = false;
|
||||
loadUserData(user);
|
||||
} else {
|
||||
isAdd.value = true;
|
||||
form.value = {
|
||||
id: 0,
|
||||
account: "",
|
||||
name: "",
|
||||
phone: "",
|
||||
qq: "",
|
||||
sex: 1,
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
email: "",
|
||||
status: 1,
|
||||
};
|
||||
}
|
||||
visible.value = true;
|
||||
// 清除表单验证
|
||||
if (formRef.value) {
|
||||
formRef.value.clearValidate();
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<el-drawer v-model="visible" :title="dialogTitle" width="500px">
|
||||
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
|
||||
<div class="form-title">账号信息</div>
|
||||
<!-- 账号 -->
|
||||
<el-form-item label="账号">
|
||||
<el-input v-model="form.account" :disabled="!isAdd" placeholder="请输入账号" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 密码 -->
|
||||
<el-form-item label="密码" prop="password" v-if="isAdd">
|
||||
<el-input
|
||||
v-model="form.password"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
show-password
|
||||
:placeholder="isAdd ? '请输入密码(至少6位)' : '留空则不修改密码'"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 确认密码 -->
|
||||
<el-form-item label="确认密码" prop="confirmPassword" v-if="isAdd">
|
||||
<el-input
|
||||
v-model="form.confirmPassword"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
show-password
|
||||
:placeholder="isAdd ? '请再次输入密码' : '留空则不修改密码'"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider></el-divider>
|
||||
<div class="form-title">个人信息</div>
|
||||
<!-- 姓名 -->
|
||||
<el-form-item label="姓名">
|
||||
<el-input v-model="form.name" placeholder="请输入姓名" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 电话 -->
|
||||
<el-form-item label="电话">
|
||||
<el-input v-model="form.phone" placeholder="请输入电话" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 邮箱 -->
|
||||
<el-form-item label="邮箱">
|
||||
<el-input v-model="form.email" placeholder="请输入邮箱" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- QQ -->
|
||||
<el-form-item label="QQ">
|
||||
<el-input v-model="form.qq" placeholder="请输入QQ" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 性别 -->
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="form.sex" placeholder="请选择性别">
|
||||
<el-radio-button label="男" :value="1" />
|
||||
<el-radio-button label="女" :value="2" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 状态 -->
|
||||
<el-form-item label="状态">
|
||||
<el-select
|
||||
v-model="form.status"
|
||||
placeholder="请选择状态"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option label="启用" :value="1" />
|
||||
<el-option label="禁用" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 对话框脚部 -->
|
||||
<template #footer>
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">保存</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { addUser, editUser, getUserInfo } from "@/api/user";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isEdit: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
statusDict: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:modelValue", "submit", "close"]);
|
||||
|
||||
const visible = ref(false);
|
||||
const formRef = ref<any>(null);
|
||||
const isAdd = ref(false);
|
||||
|
||||
const form = ref<any>({
|
||||
id: null,
|
||||
account: "",
|
||||
name: "",
|
||||
phone: "",
|
||||
qq: "",
|
||||
sex: 1,
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
email: "",
|
||||
status: 1,
|
||||
});
|
||||
|
||||
const dialogTitle = computed(() => {
|
||||
return isAdd.value ? "添加用户" : "编辑用户";
|
||||
});
|
||||
|
||||
// 密码验证规则
|
||||
const validatePassword = (rule: any, value: any, callback: any) => {
|
||||
if (isAdd.value) {
|
||||
// 新增用户时,密码必填
|
||||
if (!value) {
|
||||
callback(new Error("请输入密码"));
|
||||
return;
|
||||
}
|
||||
if (value.length < 6) {
|
||||
callback(new Error("密码长度不能少于6位"));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 编辑用户时,如果填写了密码,则必须符合规则
|
||||
if (value && value.length < 6) {
|
||||
callback(new Error("密码长度不能少于6位"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
// 确认密码验证规则
|
||||
const validateConfirmPassword = (rule: any, value: any, callback: any) => {
|
||||
if (isAdd.value) {
|
||||
// 新增用户时,确认密码必填
|
||||
if (!value) {
|
||||
callback(new Error("请再次输入密码"));
|
||||
return;
|
||||
}
|
||||
if (value !== form.value.password) {
|
||||
callback(new Error("两次输入的密码不一致"));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 编辑用户时,如果填写了密码,则确认密码必须一致
|
||||
if (form.value.password && value !== form.value.password) {
|
||||
callback(new Error("两次输入的密码不一致"));
|
||||
return;
|
||||
}
|
||||
// 如果填写了确认密码但没填密码,提示错误
|
||||
if (value && !form.value.password) {
|
||||
callback(new Error("请先输入密码"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
// 表单验证规则
|
||||
const rules = {
|
||||
account: [
|
||||
{ required: true, message: "请输入账号", trigger: "blur" },
|
||||
{ min: 3, max: 20, message: "账号长度在 3 到 20 个字符", trigger: "blur" },
|
||||
],
|
||||
name: [{ required: true, message: "请输入姓名", trigger: "blur" }],
|
||||
password: [{ validator: validatePassword, trigger: "blur" }],
|
||||
confirmPassword: [{ validator: validateConfirmPassword, trigger: "blur" }],
|
||||
email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: "blur" }],
|
||||
};
|
||||
|
||||
// 监听 modelValue
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
visible.value = newVal;
|
||||
}
|
||||
);
|
||||
|
||||
// 监听 visible 变化
|
||||
watch(visible, (newVal) => {
|
||||
if (!newVal) {
|
||||
emit("update:modelValue", false);
|
||||
}
|
||||
});
|
||||
|
||||
// 监听 statusDict 变化,用于调试
|
||||
watch(
|
||||
() => props.statusDict,
|
||||
(newVal) => {},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
|
||||
const loadUserData = async (user: any) => {
|
||||
try {
|
||||
// 处理两种调用方式:传递用户对象或用户 ID
|
||||
const userId = typeof user === "number" ? user : user?.id || user?.userId;
|
||||
if (!userId) {
|
||||
throw new Error("未提供有效的用户 ID");
|
||||
}
|
||||
|
||||
const res = await getUserInfo(userId);
|
||||
|
||||
const data = res.data || res;
|
||||
|
||||
// 确保 sex 和 status 都是数字类型
|
||||
const sexValue =
|
||||
data.sex !== undefined && data.sex !== null
|
||||
? Number(data.sex)
|
||||
: 1;
|
||||
|
||||
const statusValue =
|
||||
data.status !== undefined && data.status !== null
|
||||
? Number(data.status)
|
||||
: 1;
|
||||
|
||||
form.value = {
|
||||
id: data.id,
|
||||
account: data.account,
|
||||
name: data.name,
|
||||
phone: data.phone,
|
||||
qq: data.qq,
|
||||
sex: sexValue,
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
email: data.email,
|
||||
status: statusValue,
|
||||
};
|
||||
} catch (e: any) {
|
||||
console.error("Failed to load user data:", e);
|
||||
const errorMsg = e?.response?.data?.message || e?.message || "加载用户失败";
|
||||
ElMessage.error(errorMsg);
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
// 表单验证
|
||||
if (!formRef.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
} catch (error) {
|
||||
ElMessage.warning("请检查表单填写是否正确");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证密码一致性
|
||||
if (isAdd.value) {
|
||||
// 新增用户时,密码必填
|
||||
if (!form.value.password) {
|
||||
ElMessage.error("请输入密码");
|
||||
return;
|
||||
}
|
||||
if (form.value.password !== form.value.confirmPassword) {
|
||||
ElMessage.error("两次输入的密码不一致");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 编辑用户时,如果填写了密码,则必须填写确认密码且一致
|
||||
if (form.value.password) {
|
||||
if (form.value.password !== form.value.confirmPassword) {
|
||||
ElMessage.error("两次输入的密码不一致");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (isAdd.value) {
|
||||
// 新增用户
|
||||
const submitData: any = {
|
||||
account: form.value.account,
|
||||
name: form.value.name,
|
||||
phone: form.value.phone,
|
||||
qq: form.value.qq,
|
||||
sex: form.value.sex,
|
||||
email: form.value.email,
|
||||
status: form.value.status,
|
||||
password: form.value.password,
|
||||
};
|
||||
|
||||
await addUser(submitData);
|
||||
ElMessage.success("添加成功");
|
||||
} else {
|
||||
// 编辑用户
|
||||
if (!form.value.id || form.value.id === 0) {
|
||||
ElMessage.error("用户ID不能为空");
|
||||
return;
|
||||
}
|
||||
|
||||
const submitData: any = {
|
||||
id: form.value.id,
|
||||
account: form.value.account,
|
||||
name: form.value.name,
|
||||
phone: form.value.phone,
|
||||
qq: form.value.qq,
|
||||
sex: form.value.sex,
|
||||
email: form.value.email,
|
||||
status: form.value.status,
|
||||
};
|
||||
|
||||
// 只有在填写了密码时才添加到提交数据中
|
||||
if (form.value.password) {
|
||||
submitData.password = form.value.password;
|
||||
}
|
||||
|
||||
await editUser(form.value.id, submitData);
|
||||
ElMessage.success("更新成功");
|
||||
}
|
||||
|
||||
visible.value = false;
|
||||
emit("submit");
|
||||
} catch (e: any) {
|
||||
const errorMsg = e?.response?.data?.message || e?.message || "操作失败";
|
||||
ElMessage.error(errorMsg);
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
loadUserData,
|
||||
openAdd: () => {
|
||||
isAdd.value = true;
|
||||
form.value = {
|
||||
id: 0,
|
||||
account: "",
|
||||
name: "",
|
||||
phone: "",
|
||||
qq: "",
|
||||
sex: 1,
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
email: "",
|
||||
status: 1,
|
||||
};
|
||||
visible.value = true;
|
||||
// 清除表单验证
|
||||
if (formRef.value) {
|
||||
formRef.value.clearValidate();
|
||||
}
|
||||
},
|
||||
openEdit: (user: any) => {
|
||||
isAdd.value = false;
|
||||
visible.value = true;
|
||||
// 清除表单验证
|
||||
if (formRef.value) {
|
||||
formRef.value.clearValidate();
|
||||
}
|
||||
// 异步加载用户详细信息
|
||||
loadUserData(user);
|
||||
},
|
||||
open: (user?: any) => {
|
||||
if (user) {
|
||||
isAdd.value = false;
|
||||
loadUserData(user);
|
||||
} else {
|
||||
isAdd.value = true;
|
||||
form.value = {
|
||||
id: 0,
|
||||
account: "",
|
||||
name: "",
|
||||
phone: "",
|
||||
qq: "",
|
||||
sex: 1,
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
email: "",
|
||||
status: 1,
|
||||
};
|
||||
}
|
||||
visible.value = true;
|
||||
// 清除表单验证
|
||||
if (formRef.value) {
|
||||
formRef.value.clearValidate();
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,315 +1,315 @@
|
||||
<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>
|
||||
|
||||
<div class="filter-bar">
|
||||
<el-form inline>
|
||||
<el-form-item label="租户筛选">
|
||||
<el-select v-model="selectedTenantId" style="width: 220px" disabled>
|
||||
<el-option :label="`当前租户(ID: ${selectedTenantId || '-'})`" :value="selectedTenantId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 用户列表表格 -->
|
||||
<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="name" label="姓名" min-width="120" 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="group_id" label="角色" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getRoleTagType(scope.row.group_id)" size="small">
|
||||
{{ getRoleTagText(roles, scope.row.group_id) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="account" label="账号" min-width="180" align="center" />
|
||||
<el-table-column prop="phone" label="手机号" min-width="180" align="center" />
|
||||
<el-table-column prop="qq" label="QQ" min-width="180" align="center" />
|
||||
<el-table-column prop="last_login_ip" label="最后登录IP" width="120" align="center" />
|
||||
<el-table-column prop="login_count" label="登陆次数" width="120" 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 v-if="scope.row.username !== 'admin' && scope.row.id !== 1" 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 { getTenantUsers, deleteUser } from "@/api/user";
|
||||
import { getAllRoles } from "@/api/role";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import UserEditDialog from "./components/userEdit.vue";
|
||||
import ChangePasswordDialog from "./components/changePassword.vue";
|
||||
import PreviewDialog from "./components/preview.vue";
|
||||
|
||||
interface User {
|
||||
id: number;
|
||||
tid?: number;
|
||||
account: string;
|
||||
name: string;
|
||||
phone: string;
|
||||
qq: string;
|
||||
sex: number;
|
||||
group_id: number;
|
||||
status: number;
|
||||
last_login_ip: string;
|
||||
login_count: 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 authStore = useAuthStore();
|
||||
const selectedTenantId = ref<number>(Number(authStore.user.tid || 0));
|
||||
|
||||
// 组件引用
|
||||
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 getRoleTagType(group_id: number): string {
|
||||
const typeMap: Record<number, string> = {
|
||||
1: "primary",
|
||||
2: "success",
|
||||
3: "warning",
|
||||
4: "danger",
|
||||
};
|
||||
return typeMap[group_id] || "primary";
|
||||
}
|
||||
|
||||
// 获取角色tag文本
|
||||
function getRoleTagText(roles: Role[] | undefined, group_id: number): string {
|
||||
if (!roles || !Array.isArray(roles)) {
|
||||
return "未知";
|
||||
}
|
||||
return roles.find((role) => role.id === group_id)?.name || "未知";
|
||||
}
|
||||
|
||||
// 获取用户列表
|
||||
const fetchUsers = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
if (!selectedTenantId.value) {
|
||||
users.value = [];
|
||||
total.value = 0;
|
||||
return;
|
||||
}
|
||||
const res = await getTenantUsers(selectedTenantId.value);
|
||||
users.value = res?.data?.list || [];
|
||||
total.value = Number(res?.data?.total || 0);
|
||||
} catch (e) {
|
||||
users.value = [];
|
||||
total.value = 0;
|
||||
} 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 () => {
|
||||
selectedTenantId.value = Number(authStore.user.tid || 0);
|
||||
fetchUsers();
|
||||
fetchRoles();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.filter-bar {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.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>
|
||||
<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>
|
||||
|
||||
<div class="filter-bar">
|
||||
<el-form inline>
|
||||
<el-form-item label="租户筛选">
|
||||
<el-select v-model="selectedTenantId" style="width: 220px" disabled>
|
||||
<el-option :label="`当前租户(ID: ${selectedTenantId || '-'})`" :value="selectedTenantId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 用户列表表格 -->
|
||||
<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="name" label="姓名" min-width="120" 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="group_id" label="角色" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getRoleTagType(scope.row.group_id)" size="small">
|
||||
{{ getRoleTagText(roles, scope.row.group_id) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="account" label="账号" min-width="180" align="center" />
|
||||
<el-table-column prop="phone" label="手机号" min-width="180" align="center" />
|
||||
<el-table-column prop="qq" label="QQ" min-width="180" align="center" />
|
||||
<el-table-column prop="last_login_ip" label="最后登录IP" width="120" align="center" />
|
||||
<el-table-column prop="login_count" label="登陆次数" width="120" 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 v-if="scope.row.username !== 'admin' && scope.row.id !== 1" 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 { getTenantUsers, deleteUser } from "@/api/user";
|
||||
import { getAllRoles } from "@/api/role";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import UserEditDialog from "./components/userEdit.vue";
|
||||
import ChangePasswordDialog from "./components/changePassword.vue";
|
||||
import PreviewDialog from "./components/preview.vue";
|
||||
|
||||
interface User {
|
||||
id: number;
|
||||
tid?: number;
|
||||
account: string;
|
||||
name: string;
|
||||
phone: string;
|
||||
qq: string;
|
||||
sex: number;
|
||||
group_id: number;
|
||||
status: number;
|
||||
last_login_ip: string;
|
||||
login_count: 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 authStore = useAuthStore();
|
||||
const selectedTenantId = ref<number>(Number(authStore.user.tid || 0));
|
||||
|
||||
// 组件引用
|
||||
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 getRoleTagType(group_id: number): string {
|
||||
const typeMap: Record<number, string> = {
|
||||
1: "primary",
|
||||
2: "success",
|
||||
3: "warning",
|
||||
4: "danger",
|
||||
};
|
||||
return typeMap[group_id] || "primary";
|
||||
}
|
||||
|
||||
// 获取角色tag文本
|
||||
function getRoleTagText(roles: Role[] | undefined, group_id: number): string {
|
||||
if (!roles || !Array.isArray(roles)) {
|
||||
return "未知";
|
||||
}
|
||||
return roles.find((role) => role.id === group_id)?.name || "未知";
|
||||
}
|
||||
|
||||
// 获取用户列表
|
||||
const fetchUsers = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
if (!selectedTenantId.value) {
|
||||
users.value = [];
|
||||
total.value = 0;
|
||||
return;
|
||||
}
|
||||
const res = await getTenantUsers(selectedTenantId.value);
|
||||
users.value = res?.data?.list || [];
|
||||
total.value = Number(res?.data?.total || 0);
|
||||
} catch (e) {
|
||||
users.value = [];
|
||||
total.value = 0;
|
||||
} 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 () => {
|
||||
selectedTenantId.value = Number(authStore.user.tid || 0);
|
||||
fetchUsers();
|
||||
fetchRoles();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.filter-bar {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.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>
|
||||
|
||||
Reference in New Issue
Block a user