Files
pengcheng-exam-teacher/src/views/exam/teacher/TeacherForm.vue
2025-08-13 09:02:54 +08:00

288 lines
9.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<Dialog v-model="dialogVisible" :title="dialogTitle">
<el-form
ref="formRef"
v-loading="formLoading"
:model="formData"
:rules="formRules"
label-width="80px"
>
<el-row>
<el-col :span="12">
<el-form-item label="教师姓名" prop="nickname">
<el-input v-model="formData.nickname" placeholder="请输入教师姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手机号码" prop="mobile">
<el-input v-model="formData.mobile" maxlength="11" placeholder="请输入手机号码" />
</el-form-item>
</el-col>
<!-- <el-col :span="12">-->
<!-- <el-form-item label="归属部门" prop="deptId">-->
<!-- <el-tree-select-->
<!-- v-model="formData.deptId"-->
<!-- :data="deptList"-->
<!-- :props="defaultProps"-->
<!-- check-strictly-->
<!-- node-key="id"-->
<!-- placeholder="请选择归属部门"-->
<!-- />-->
<!-- </el-form-item>-->
<!-- </el-col>-->
</el-row>
<el-row>
<el-col :span="12">
<el-form-item v-if="formData.id === undefined" label="教师账号" prop="username">
<el-input v-model="formData.username" placeholder="请输入教师账号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="formData.id === undefined" label="密码" prop="password">
<el-input
v-model="formData.password"
placeholder="请输入密码"
show-password
type="password"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="性别">
<el-select v-model="formData.sex" placeholder="请选择">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="班级">
<el-select v-model="formData.classIds" multiple placeholder="请选择">
<el-option
v-for="item in classList"
:key="item.id"
:label="item.name"
:value="item.id!"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="formData.remark" placeholder="请输入内容" type="textarea" />
</el-form-item>
<el-form-item label="头像" prop="avatar">
<UploadImg v-model="formData.avatar" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="专业权限">
<el-card class="w-full h-400px !overflow-y-scroll" shadow="never">
<template #header>
全选/全不选:
<el-switch
v-model="treeNodeAll"
active-text=""
inactive-text=""
inline-prompt
@change="handleCheckedTreeNodeAll"
/>
全部展开/折叠:
<el-switch
v-model="menuExpand"
active-text="展开"
inactive-text="折叠"
inline-prompt
@change="handleCheckedTreeExpand"
/>
</template>
<el-tree
ref="treeRef"
:data="menuOptions"
:props="defaultProps"
empty-text="加载中请稍候"
node-key="id"
show-checkbox
/>
</el-card>
</el-form-item>
</el-form>
<template #footer>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script lang="ts" setup>
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { CommonStatusEnum } from '@/utils/constants'
import {defaultProps, handleTree} from '@/utils/tree'
import * as DeptApi from '@/api/system/dept'
import * as UserApi from '@/api/system/user'
import * as ClassApi from '@/api/exam/class'
import * as SpecialtyApi from '@/api/exam/specialty'
import { FormRules } from 'element-plus'
import * as PermissionApi from "@/api/system/permission";
defineOptions({ name: 'SystemUserForm' })
const treeNodeAll = ref(false) // 全选/全不选
const menuExpand = ref(false) // 展开/折叠
const treeRef = ref() // 菜单树组件 Ref
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const menuOptions = ref<any[]>([]) // 菜单树形结构
const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用
const formType = ref('') // 表单的类型create - 新增update - 修改
const formData = ref({
userType: '1',
nickname: '',
deptId: '',
mobile: '',
email: '',
id: undefined,
username: '',
password: '',
sex: undefined,
classIds: [],
remark: '',
avatar: '',
status: CommonStatusEnum.ENABLE,
roleIds: [],
specialtyIds: []
})
const formRules = reactive<FormRules>({
username: [{ required: true, message: '教师账号不能为空', trigger: 'blur' }],
nickname: [{ required: true, message: '教师姓名不能为空', trigger: 'blur' }],
password: [{ required: true, message: '教师密码不能为空', trigger: 'blur' }],
mobile: [
{
pattern: /^(?:(?:\+|00)86)?1(?:3[\d]|4[5-79]|5[0-35-9]|6[5-7]|7[0-8]|8[\d]|9[189])\d{8}$/,
message: '请输入正确的手机号码',
trigger: 'blur'
}
]
})
const formRef = ref() // 表单 Ref
const deptList = ref<Tree[]>([]) // 树形结构
const classList = ref([] as ClassApi.ClassIdVO[] ) // 岗位列表
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
// 加载 Menu 列表。注意,必须放在前面,不然下面 setChecked 没数据节点
menuOptions.value = handleTree(await SpecialtyApi.getSpecialtyPart())
// 修改时,设置数据
if (id) {
formLoading.value = true
try {
formData.value = await UserApi.getUser(id)
try {
formData.value.specialtyIds = await PermissionApi.getTeacherSpecialtyList(id)
// 设置选中
formData.value.specialtyIds.forEach((menuId: number) => {
treeRef.value.setChecked(menuId, true, false)
})
} finally {
formLoading.value = false
}
} finally {
formLoading.value = false
}
}
// 加载部门树
deptList.value = handleTree(await DeptApi.getSimpleDeptList())
// 加载岗位列表
classList.value = await ClassApi.ClassApi.getClassIdName()
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const submitForm = async () => {
// 校验表单
if (!formRef) return
const valid = await formRef.value.validate()
formData.value.userType = "1"
if (!valid) return
// 提交请求
formLoading.value = true
try {
const datas = {
menuIds: [
...(treeRef.value.getCheckedKeys(false) as unknown as Array<number>), // 获得当前选中节点
...(treeRef.value.getHalfCheckedKeys() as unknown as Array<number>) // 获得半选中的父节点
]
}
formData.value.specialtyIds = datas.menuIds
console.log(formData.value)
const data = formData.value as unknown as UserApi.UserVO
if (formType.value === 'create') {
await UserApi.createTeacher(data)
message.success(t('common.createSuccess'))
} else {
await UserApi.updateTeacher(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
// 发送操作成功的事件
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
userType: '0',
nickname: '',
deptId: '',
mobile: '',
email: '',
id: undefined,
username: '',
password: '',
sex: undefined,
postIds: [],
remark: '',
status: CommonStatusEnum.ENABLE,
roleIds: [],
specialtyIds: []
}
treeNodeAll.value = false
formRef.value?.resetFields()
}
/** 全选/全不选 */
const handleCheckedTreeNodeAll = () => {
treeRef.value.setCheckedNodes(treeNodeAll.value ? menuOptions.value : [])
}
/** 展开/折叠全部 */
const handleCheckedTreeExpand = () => {
const nodes = treeRef.value?.store.nodesMap
for (let node in nodes) {
if (nodes[node].expanded === menuExpand.value) {
continue
}
nodes[node].expanded = menuExpand.value
}
}
</script>