|
|
@@ -0,0 +1,387 @@
|
|
|
+<template>
|
|
|
+ <Dialog :title="dialogTitle" v-model="dialogVisible">
|
|
|
+ <el-form
|
|
|
+ ref="formRef"
|
|
|
+ :model="formData"
|
|
|
+ :rules="formRules"
|
|
|
+ label-width="80px"
|
|
|
+ v-loading="formLoading"
|
|
|
+ >
|
|
|
+ <el-form-item label="类型" prop="type">
|
|
|
+ <el-radio-group v-model="formData.type">
|
|
|
+ <el-radio label="single" border>单个</el-radio>
|
|
|
+ <el-radio label="batch" border>批量</el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 单个注册字段 -->
|
|
|
+ <template v-if="formData.type === 'single'">
|
|
|
+ <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="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 label="账号" prop="username">
|
|
|
+ <el-input v-model="formData.username" placeholder="请输入账号" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="密码" prop="password">
|
|
|
+ <el-input v-model="formData.password" placeholder="请输入密码" type="password" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="手机号" prop="mobile">
|
|
|
+ <el-input v-model="formData.mobile" placeholder="请输入手机号" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="角色" prop="roleIds">
|
|
|
+ <el-select v-model="formData.roleIds" multiple placeholder="请选择角色">
|
|
|
+ <el-option
|
|
|
+ v-for="item in roleList"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.name"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <!-- 批量注册字段 -->
|
|
|
+ <template v-else-if="formData.type === 'batch'">
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="用户昵称" prop="nickname">
|
|
|
+ <el-input v-model="formData.nickname" placeholder="默认采取手机号尾号4位数" :disabled="true" />
|
|
|
+ </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 label="账号" prop="username">
|
|
|
+ <el-input v-model="formData.username" placeholder="默认采取手机号" :disabled="true" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="密码" prop="password">
|
|
|
+ <el-input v-model="formData.password" placeholder="默认采取手机号" :disabled="true" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="角色" prop="roleIds">
|
|
|
+ <el-select v-model="formData.roleIds" multiple placeholder="请选择角色">
|
|
|
+ <el-option
|
|
|
+ v-for="item in roleList"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.name"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="短信通知" prop="sendSms">
|
|
|
+ <el-switch v-model="formData.sendSms" active-text="开启" inactive-text="关闭" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="手机号" prop="batchMobiles">
|
|
|
+ <el-input
|
|
|
+ v-model="batchMobilesText"
|
|
|
+ type="textarea"
|
|
|
+ placeholder="请输入多个手机号,每行一个"
|
|
|
+ rows="4"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <el-row>
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="备注" prop="remark">
|
|
|
+ <el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="submitForm" type="primary" :loading="formLoading">确 定</el-button>
|
|
|
+ <el-button @click="dialogVisible = false">取 消</el-button>
|
|
|
+ </template>
|
|
|
+ </Dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ParentClassRegisterApi, ParentClassRegisterVO } from '@/api/system/parentClassRegister'
|
|
|
+import * as DeptApi from '@/api/system/dept'
|
|
|
+import * as RoleApi from '@/api/system/role'
|
|
|
+import { defaultProps, handleTree } from '@/utils/tree'
|
|
|
+
|
|
|
+/** 家长课堂注册 表单 */
|
|
|
+defineOptions({ name: 'ParentClassRegisterForm' })
|
|
|
+
|
|
|
+const { t } = useI18n() // 国际化
|
|
|
+const message = useMessage() // 消息弹窗
|
|
|
+
|
|
|
+const dialogVisible = ref(false) // 弹窗的是否展示
|
|
|
+const dialogTitle = ref('') // 弹窗的标题
|
|
|
+const formLoading = ref(false) // 表单的加载中:提交的按钮禁用
|
|
|
+const formData = ref({
|
|
|
+ type: 'single', // 默认单个
|
|
|
+ nickname: '',
|
|
|
+ mobile: '',
|
|
|
+ batchMobiles: '', // 批量手机号字符串,用于textarea输入
|
|
|
+ username: '',
|
|
|
+ password: '',
|
|
|
+ deptId: '',
|
|
|
+ roleIds: [],
|
|
|
+ remark: '',
|
|
|
+ sendSms: true
|
|
|
+})
|
|
|
+
|
|
|
+const deptList = ref<Tree[]>([]) // 部门树形结构
|
|
|
+const roleList = ref<RoleApi.RoleVO[]>([]) // 角色列表
|
|
|
+
|
|
|
+// 用于批量手机号文本输入
|
|
|
+const batchMobilesText = computed({
|
|
|
+ get: () => formData.value.batchMobiles || '',
|
|
|
+ set: (val: string) => {
|
|
|
+ formData.value.batchMobiles = val
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const formRules = computed(() => {
|
|
|
+ const rules: Record<string, any> = {
|
|
|
+ type: [
|
|
|
+ { required: true, message: '请选择类型', trigger: 'change' }
|
|
|
+ ],
|
|
|
+ mobile: [
|
|
|
+ {
|
|
|
+ required: formData.value.type === 'single',
|
|
|
+ message: '请输入手机号',
|
|
|
+ trigger: 'blur'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ pattern: /^1[3-9]\d{9}$/,
|
|
|
+ message: '请输入正确的手机号码',
|
|
|
+ trigger: 'blur',
|
|
|
+ required: formData.value.type === 'single'
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ nickname: [
|
|
|
+ {
|
|
|
+ required: formData.value.type === 'single',
|
|
|
+ message: '请输入用户昵称',
|
|
|
+ trigger: 'blur'
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ username: [
|
|
|
+ {
|
|
|
+ required: formData.value.type === 'single',
|
|
|
+ message: '请输入账号',
|
|
|
+ trigger: 'blur'
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ deptId: [
|
|
|
+ {
|
|
|
+ required: formData.value.type === 'single',
|
|
|
+ message: '请选择归属部门',
|
|
|
+ trigger: 'change'
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ roleIds: [
|
|
|
+ {
|
|
|
+ required: formData.value.type === 'single' || formData.value.type === 'batch',
|
|
|
+ message: '请选择角色',
|
|
|
+ trigger: 'change'
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ password: [
|
|
|
+ {
|
|
|
+ required: formData.value.type === 'single',
|
|
|
+ message: '请输入密码',
|
|
|
+ trigger: 'blur'
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ batchMobiles: [
|
|
|
+ {
|
|
|
+ required: formData.value.type === 'batch',
|
|
|
+ message: '请输入手机号',
|
|
|
+ trigger: 'blur'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+
|
|
|
+ return rules
|
|
|
+})
|
|
|
+
|
|
|
+const formRef = ref() // 表单 Ref
|
|
|
+
|
|
|
+/** 打开弹窗 */
|
|
|
+const open = (type: string) => {
|
|
|
+ dialogVisible.value = true
|
|
|
+ dialogTitle.value = '家长课堂注册'
|
|
|
+ resetForm()
|
|
|
+
|
|
|
+ // 设置默认值
|
|
|
+ formData.value.type = 'single'
|
|
|
+
|
|
|
+ // 加载部门树和角色列表
|
|
|
+ loadDeptList()
|
|
|
+ loadRoleList()
|
|
|
+}
|
|
|
+
|
|
|
+/** 加载部门列表 */
|
|
|
+const loadDeptList = async () => {
|
|
|
+ try {
|
|
|
+ deptList.value = handleTree(await DeptApi.getSimpleDeptList())
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载部门列表失败:', error)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** 加载角色列表 */
|
|
|
+const loadRoleList = async () => {
|
|
|
+ try {
|
|
|
+ roleList.value = await RoleApi.getSimpleRoleList()
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载角色列表失败:', error)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 监听类型变化更新默认值
|
|
|
+watch(() => formData.value.type, (newType) => {
|
|
|
+ if (newType === 'single') {
|
|
|
+ // 切换到单个模式时,清空批量数据
|
|
|
+ formData.value.batchMobiles = ''
|
|
|
+ formData.value.nickname = ''
|
|
|
+ formData.value.username = ''
|
|
|
+ formData.value.password = ''
|
|
|
+ } else {
|
|
|
+ // 切换到批量模式时,清空单个数据并设置批量默认值
|
|
|
+ formData.value.mobile = ''
|
|
|
+ formData.value.nickname = '默认采取手机号后4位'
|
|
|
+ formData.value.username = '默认采取手机号'
|
|
|
+ formData.value.password = '默认采取手机号'
|
|
|
+ }
|
|
|
+}, { immediate: true })
|
|
|
+
|
|
|
+/** 提交表单 */
|
|
|
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
|
|
+const submitForm = async () => {
|
|
|
+ // 校验表单
|
|
|
+ await formRef.value.validate()
|
|
|
+
|
|
|
+ // 准备提交数据
|
|
|
+ const submitData = { ...formData.value }
|
|
|
+
|
|
|
+ // 如果是单个模式,对手机号进行格式校验
|
|
|
+ if (submitData.type === 'single') {
|
|
|
+ // 校验单个手机号格式
|
|
|
+ if (submitData.mobile && !/^1[3-9]\d{9}$/.test(submitData.mobile)) {
|
|
|
+ throw new Error('手机号格式不正确')
|
|
|
+ }
|
|
|
+ delete submitData.batchMobiles
|
|
|
+ }
|
|
|
+ // 如果是批量模式,处理批量手机号
|
|
|
+ else if (submitData.type === 'batch') {
|
|
|
+ // 处理批量手机号,将textarea中的手机号按换行符分割为数组
|
|
|
+ if (submitData.batchMobiles) {
|
|
|
+ submitData.batchMobiles = submitData.batchMobiles.split('\n').filter(phone => phone.trim())
|
|
|
+ }
|
|
|
+
|
|
|
+ // 对每个手机号进行格式校验
|
|
|
+ if (submitData.batchMobiles && submitData.batchMobiles.length > 0) {
|
|
|
+ const invalidMobiles = submitData.batchMobiles.filter(mobile => !/^1[3-9]\d{9}$/.test(mobile))
|
|
|
+ if (invalidMobiles.length > 0) {
|
|
|
+ throw new Error(`以下手机号格式不正确: ${invalidMobiles.join(', ')}`)
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+ throw new Error('请输入有效的手机号')
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清理批量模式下的默认值,避免提交给后端
|
|
|
+ if (submitData.nickname === '默认采取手机号尾号4位数') {
|
|
|
+ submitData.nickname = ''
|
|
|
+ }
|
|
|
+ if (submitData.username === '默认采取手机号') {
|
|
|
+ submitData.username = ''
|
|
|
+ }
|
|
|
+ if (submitData.password === '默认采取手机号') {
|
|
|
+ submitData.password = ''
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提交请求
|
|
|
+ formLoading.value = true
|
|
|
+ try {
|
|
|
+ const data = submitData as unknown as ParentClassRegisterVO
|
|
|
+ await ParentClassRegisterApi.registerParentClass(data)
|
|
|
+ message.success('家长课堂注册成功')
|
|
|
+ dialogVisible.value = false
|
|
|
+ // 发送操作成功的事件
|
|
|
+ emit('success')
|
|
|
+ } finally {
|
|
|
+ formLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** 重置表单 */
|
|
|
+const resetForm = () => {
|
|
|
+ formData.value = {
|
|
|
+ type: 'single',
|
|
|
+ nickname: '',
|
|
|
+ mobile: '',
|
|
|
+ batchMobiles: '',
|
|
|
+ username: '',
|
|
|
+ password: '',
|
|
|
+ deptId: '',
|
|
|
+ roleIds: [],
|
|
|
+ remark: '',
|
|
|
+ sendSms: true
|
|
|
+ }
|
|
|
+ formRef.value?.resetFields()
|
|
|
+}
|
|
|
+
|
|
|
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
|
|
+</script>
|