<template>
|
<el-dialog v-model="visible" :title="titleEnum[dialogMode]" :close-on-click-modal="false" width="800px">
|
<!-- 查看模式 -->
|
<div v-if="readonly" class="view-mode">
|
<el-row :gutter="16">
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">登录账号:</span>
|
{{ formData.account }}
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">用户姓名:</span>
|
{{ formData.realName }}
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">手机号码:</span>
|
{{ formData.phone }}
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">电子邮箱:</span>
|
{{ formData.email }}
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">用户性别:</span>
|
{{ getSexLabel(formData.sex) }}
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">用户生日:</span>
|
{{ formData.birthday }}
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">所属角色:</span>
|
{{ formData.roleName }}
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">所属部门:</span>
|
{{ formData.deptName }}
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">用户编号:</span>
|
{{ formData.code }}
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">账号状态:</span>
|
{{ formData.statusName }}
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">到期时间:</span>
|
{{ formData.expireTime }}
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">次数限制:</span>
|
{{ formData.maxLoginNum }}
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">飞行开始时间:</span>
|
{{ formData.flightStartTime }}
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="view-item">
|
<span class="label">飞行结束时间:</span>
|
{{ formData.flightEndTime }}
|
</div>
|
</el-col>
|
</el-row>
|
</div>
|
|
<!-- 编辑/新增模式 -->
|
<el-form v-else ref="formRef" :model="formData" :rules="rules" label-width="110px">
|
<el-divider content-position="left">基础信息</el-divider>
|
<el-row :gutter="16">
|
<el-col :span="12">
|
<el-form-item label="登录账号" prop="account">
|
<el-input v-model="formData.account" maxlength="50" placeholder="请输入" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12" v-if="dialogMode === 'add'">
|
<el-form-item label="密码" prop="password">
|
<el-input
|
v-model="formData.password"
|
type="password"
|
maxlength="50"
|
placeholder="请输入"
|
clearable
|
show-password
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12" v-if="dialogMode === 'add'">
|
<el-form-item label="确认密码" prop="password2">
|
<el-input
|
v-model="formData.password2"
|
type="password"
|
maxlength="50"
|
placeholder="请输入"
|
clearable
|
show-password
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-divider content-position="left">详细信息</el-divider>
|
<el-row :gutter="16">
|
<el-col :span="12">
|
<el-form-item label="用户姓名" prop="realName">
|
<el-input v-model="formData.realName" maxlength="50" placeholder="请输入" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="手机号码" prop="phone">
|
<el-input v-model="formData.phone" maxlength="20" placeholder="请输入" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="电子邮箱" prop="email">
|
<el-input v-model="formData.email" maxlength="50" placeholder="请输入" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="用户性别" prop="sex">
|
<el-select v-model="formData.sex" placeholder="请选择" clearable>
|
<el-option label="男" :value="1" />
|
<el-option label="女" :value="2" />
|
<el-option label="未知" :value="3" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="用户生日" prop="birthday">
|
<el-date-picker
|
v-model="formData.birthday"
|
type="datetime"
|
placeholder="请选择"
|
format="YYYY-MM-DD HH:mm:ss"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
clearable
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-divider content-position="left">职责信息</el-divider>
|
<el-row :gutter="16">
|
<el-col :span="12">
|
<el-form-item label="用户编号" prop="code">
|
<el-input v-model="formData.code" maxlength="50" placeholder="请输入" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="所属角色" prop="roleId">
|
<el-tree-select
|
v-model="formData.roleId"
|
:data="roleTree"
|
:props="treeProps"
|
node-key="id"
|
check-strictly
|
clearable
|
placeholder="请选择"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="所属部门" prop="deptId">
|
<el-tree-select
|
v-model="formData.deptId"
|
:data="deptTree"
|
:props="deptTreeSelectProps"
|
node-key="id"
|
check-strictly
|
clearable
|
placeholder="请选择"
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-divider content-position="left">登录限制</el-divider>
|
<el-row :gutter="16">
|
<el-col :span="12">
|
<el-form-item label="到期时间" prop="expireTime">
|
<el-date-picker
|
v-model="formData.expireTime"
|
type="datetime"
|
placeholder="请选择"
|
format="YYYY-MM-DD HH:mm:ss"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
clearable
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="次数限制" prop="maxLoginNum">
|
<el-input v-model="formData.maxLoginNum" placeholder="请输入" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="飞行开始时间" prop="flightStartTime">
|
<el-time-picker
|
v-model="formData.flightStartTime"
|
placeholder="请选择"
|
format="HH:mm"
|
value-format="HH:mm"
|
clearable
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="飞行结束时间" prop="flightEndTime">
|
<el-time-picker
|
v-model="formData.flightEndTime"
|
placeholder="请选择"
|
format="HH:mm"
|
value-format="HH:mm"
|
clearable
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
|
<template #footer>
|
<el-button @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button>
|
<el-button v-if="!readonly" type="primary" :loading="submitting" :disabled="submitting" @click="handleSubmit">
|
确定
|
</el-button>
|
</template>
|
</el-dialog>
|
</template>
|
|
<script setup>
|
import { computed, onMounted, ref } from 'vue'
|
import { ElMessage } from 'element-plus'
|
import { getUser, add, update } from '@/api/system/user'
|
import { getDeptTree } from '@/api/system/dept'
|
import { getRoleTree } from '@/api/system/role'
|
import func from '@/utils/func'
|
import { saveOperationLog } from '@ztzf/apis'
|
import { useRoute } from 'vue-router'
|
|
// 初始化表单
|
const initForm = () => ({
|
account: '',
|
password: '',
|
password2: '',
|
realName: '',
|
phone: '',
|
email: '',
|
sex: null,
|
birthday: '',
|
code: '',
|
roleId: '',
|
deptId: '',
|
expireTime: '',
|
maxLoginNum: '',
|
flightStartTime: '',
|
flightEndTime: '',
|
})
|
|
const treeProps = {
|
label: 'title',
|
children: 'children',
|
}
|
const deptTreeSelectProps = {
|
label: 'name',
|
value: 'id',
|
children: 'children',
|
}
|
|
const emit = defineEmits(['success'])
|
const formRef = ref(null)
|
const formData = ref(initForm())
|
const visible = defineModel()
|
const dialogMode = ref('add')
|
const submitting = ref(false)
|
const readonly = computed(() => dialogMode.value === 'view')
|
const titleEnum = ref({ edit: '编辑用户', view: '查看用户', add: '新增用户' })
|
const roleTree = ref([])
|
const deptTree = ref([])
|
const route = useRoute()
|
|
// 密码验证
|
const validatePass = (rule, value, callback) => {
|
if (value === '') {
|
callback(new Error('请输入密码'))
|
} else {
|
callback()
|
}
|
}
|
const validatePass2 = (rule, value, callback) => {
|
if (value === '') {
|
callback(new Error('请再次输入密码'))
|
} else if (value !== formData.value.password) {
|
callback(new Error('两次输入密码不一致!'))
|
} else {
|
callback()
|
}
|
}
|
|
const rules = {
|
account: [{ required: true, message: '请输入登录账号', trigger: 'blur' }],
|
password: [{ required: true, validator: validatePass, trigger: 'blur' }],
|
password2: [{ required: true, validator: validatePass2, trigger: 'blur' }],
|
realName: [
|
{ required: true, message: '请输入用户姓名', trigger: 'blur' },
|
{ min: 2, max: 50, message: '姓名长度在2到50个字符', trigger: 'blur' },
|
],
|
roleId: [{ required: true, message: '请选择所属角色', trigger: 'change' }],
|
deptId: [{ required: true, message: '请选择所属部门', trigger: 'change' }],
|
}
|
|
// 获取性别标签
|
function getSexLabel(sex) {
|
const map = { 1: '男', 2: '女', 3: '未知' }
|
return map[sex] || ''
|
}
|
|
// 获取角色树
|
async function getRoleTreeData() {
|
const res = await getRoleTree('000000')
|
roleTree.value = res.data.data
|
}
|
|
// 获取部门树
|
async function getDeptTreeData() {
|
const res = await getDeptTree('000000')
|
deptTree.value = res.data.data
|
}
|
|
// 关闭弹框
|
function handleCancel() {
|
visible.value = false
|
}
|
|
// 验证飞行时间
|
function validateFlightTime() {
|
if (formData.value.flightStartTime && formData.value.flightEndTime) {
|
const [startHours, startMinutes] = formData.value.flightStartTime.split(':').map(Number)
|
const [endHours, endMinutes] = formData.value.flightEndTime.split(':').map(Number)
|
const startTotalMinutes = startHours * 60 + startMinutes
|
const endTotalMinutes = endHours * 60 + endMinutes
|
if (endTotalMinutes < startTotalMinutes) {
|
ElMessage.error('飞行结束时间不能小于飞行开始时间')
|
return false
|
}
|
}
|
return true
|
}
|
|
// 提交新增/编辑
|
async function handleSubmit() {
|
const isValid = await formRef.value?.validate().catch(() => false)
|
if (!isValid) return
|
if (!validateFlightTime()) return
|
|
submitting.value = true
|
try {
|
const submitData = { ...formData.value }
|
submitData.roleId = func.toStr(submitData.roleId)
|
submitData.name = submitData.realName
|
|
if (dialogMode.value === 'add') {
|
await add(submitData)
|
saveOperationLog({
|
requestUri: route.path,
|
title: `${route.name || '用户管理01'}-新增`,
|
type: 1
|
})
|
ElMessage.success('新增成功')
|
} else {
|
await update(submitData)
|
saveOperationLog({
|
requestUri: route.path,
|
title: `${route.name || '用户管理01'}-编辑`,
|
type: 1
|
})
|
ElMessage.success('更新成功')
|
}
|
visible.value = false
|
emit('success')
|
} finally {
|
submitting.value = false
|
}
|
}
|
|
// 加载详情
|
async function loadDetail() {
|
if (!formData.value.id) return
|
const res = await getUser(formData.value.id)
|
const data = res?.data?.data ?? {}
|
// 处理 roleId
|
if (data.roleId) {
|
data.roleId = func.split(data.roleId)[0] || data.roleId
|
}
|
formData.value = data
|
}
|
|
// 打开弹框
|
async function open({ mode, row } = {}) {
|
dialogMode.value = mode || 'add'
|
if (dialogMode.value === 'add') {
|
formData.value = initForm()
|
} else {
|
formData.value = { id: row.id }
|
await loadDetail()
|
}
|
}
|
|
onMounted(() => {
|
getRoleTreeData()
|
getDeptTreeData()
|
})
|
|
defineExpose({ open })
|
</script>
|
|
<style scoped lang="scss">
|
.view-mode {
|
.view-item {
|
padding: 10px 0;
|
.label {
|
color: #606266;
|
font-weight: 500;
|
}
|
}
|
}
|
|
:deep(.el-select) {
|
width: 100%;
|
}
|
|
:deep(.el-date-editor) {
|
width: 100%;
|
}
|
|
:deep(.el-tree-select) {
|
width: 100%;
|
}
|
</style>
|