pangu-user-platform/frontend/src/views/business/school/components/SchoolDialog.vue

363 lines
9.9 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>
<el-dialog
v-model="dialogVisible"
:title="dialogTitle"
width="600px"
:close-on-click-modal="false"
destroy-on-close
>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="100px"
>
<el-form-item v-if="isEdit" label="学校编码">
<el-input v-model="form.schoolCode" disabled />
</el-form-item>
<el-form-item label="学校名称" prop="schoolName">
<el-input v-model="form.schoolName" placeholder="请输入学校名称" maxlength="100" show-word-limit />
</el-form-item>
<el-form-item label="学校类型" prop="schoolType">
<el-select v-model="form.schoolType" placeholder="请选择学校类型" style="width: 100%">
<el-option label="小学" value="1" />
<el-option label="初中" value="2" />
<el-option label="高中" value="3" />
<el-option label="中专" value="4" />
<el-option label="大学" value="5" />
</el-select>
</el-form-item>
<el-form-item label="上级部门" prop="deptId">
<el-tree-select
v-model="form.deptId"
:data="deptTree"
:props="{ value: 'id', label: 'label', children: 'children' }"
value-key="id"
placeholder="请选择上级部门(分公司)"
check-strictly
style="width: 100%"
/>
</el-form-item>
<el-form-item label="所属区域" prop="regionId">
<el-cascader
v-model="form.regionIds"
:options="regionTree"
:props="{
value: 'regionId',
label: 'regionName',
children: 'children',
checkStrictly: true
}"
placeholder="请选择所属区域"
clearable
style="width: 100%"
@change="handleRegionChange"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-switch
v-model="form.status"
active-value="0"
inactive-value="1"
active-text="正常"
inactive-text="停用"
/>
</el-form-item>
<!-- 新增时显示年级选择区域 -->
<el-form-item v-if="!isEdit && gradeList.length > 0" label="初始年级">
<div class="grade-select-wrapper">
<el-checkbox-group v-model="selectedGradeIds">
<el-checkbox
v-for="grade in gradeList"
:key="grade.gradeId"
:value="grade.gradeId"
:label="grade.gradeId"
>
{{ grade.gradeName }}
</el-checkbox>
</el-checkbox-group>
<div class="grade-tip">
<el-text type="info" size="small">
已选择 {{ selectedGradeIds.length }} 个年级,将在学校创建后自动添加
</el-text>
</div>
</div>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
</template>
</el-dialog>
</template>
<script setup>
/**
* 学校新增/编辑弹窗
* @author pangu
*/
import { ElMessage } from 'element-plus'
import { computed, ref, watch } from 'vue'
import { addSchool, updateSchool } from '@/api/pangu/school'
import { deptTreeSelect } from '@/api/system/user'
import request from '@/utils/request'
// 接收父组件传递的区域树
const props = defineProps({
regionTree: {
type: Array,
default: () => []
}
})
// 部门树数据
const deptTree = ref([])
const emit = defineEmits(['success'])
const dialogVisible = ref(false)
const submitLoading = ref(false)
const formRef = ref(null)
const isEdit = ref(false)
// 年级列表和选中的年级ID
const gradeList = ref([])
const selectedGradeIds = ref([])
// 表单数据
const form = ref({
schoolId: null,
schoolCode: '',
schoolName: '',
schoolType: '',
deptId: null,
regionId: null,
regionIds: [],
regionName: '',
status: '0'
})
// 弹窗标题 - 根据需求文档:编辑-学校
const dialogTitle = computed(() => isEdit.value ? '编辑-学校' : '新增学校')
// 表单验证规则
const rules = {
schoolName: [
{ required: true, message: '请输入学校名称', trigger: 'blur' }
],
schoolType: [
{ required: true, message: '请选择学校类型', trigger: 'change' }
],
deptId: [
{ required: true, message: '请选择上级部门', trigger: 'change' }
],
regionId: [
{ required: true, message: '请选择所属区域', trigger: 'change' }
]
}
// 获取区域完整路径名称
const getRegionPath = (ids, tree) => {
const names = []
const findPath = (nodes, targetId, path) => {
for (const node of nodes) {
if (ids.includes(node.regionId)) {
path.push(node.regionName)
}
if (node.children) {
findPath(node.children, targetId, path)
}
}
}
findPath(tree, ids[ids.length - 1], names)
return names.join('/')
}
// 区域选择变化
const handleRegionChange = (value) => {
if (value && value.length > 0) {
form.value.regionId = value[value.length - 1]
form.value.regionName = getRegionPath(value, props.regionTree)
} else {
form.value.regionId = null
form.value.regionName = ''
}
}
// 学校类型对应学段映射(与 pg_grade.stage 一致1小学 2初中 3高中 4中专 5大学
const getStagesBySchoolType = (schoolType) => {
const map = {
'1': ['1'], // 小学
'2': ['2'], // 初中
'3': ['3'], // 高中
'4': ['4'], // 中专
'5': ['5'] // 大学
}
return map[schoolType] || []
}
// 根据学校类型加载年级列表
const loadGradesBySchoolType = async (schoolType) => {
const stages = getStagesBySchoolType(schoolType)
if (stages.length === 0) {
gradeList.value = []
selectedGradeIds.value = []
return
}
try {
const res = await request.get('/business/grade/listAll', {
params: { stages: stages.join(',') }
})
if (res.code === 200) {
gradeList.value = res.data || []
// 默认全选
selectedGradeIds.value = gradeList.value.map(g => g.gradeId)
}
} catch (error) {
console.error('加载年级列表失败:', error)
}
}
// 监听学校类型变化,自动加载对应年级(仅新增模式)
watch(() => form.value.schoolType, async (newType) => {
if (!isEdit.value && newType) {
await loadGradesBySchoolType(newType)
} else if (!newType) {
gradeList.value = []
selectedGradeIds.value = []
}
})
// 加载部门树
const loadDeptTree = async () => {
try {
const res = await deptTreeSelect()
if (res.code === 200) {
deptTree.value = res.data
}
} catch (error) {
console.error('加载部门树失败:', error)
}
}
// 打开弹窗
// row: 编辑时传入学校数据新增时为null
// defaultRegionId: 新增时默认选中的区域ID从列表页带入
const open = async (row, defaultRegionId = null) => {
dialogVisible.value = true
isEdit.value = !!row
// 加载部门树
await loadDeptTree()
if (row) {
// 编辑模式:回显数据
form.value = {
schoolId: row.schoolId,
schoolCode: row.schoolCode || '',
schoolName: row.schoolName,
schoolType: row.schoolType,
deptId: row.deptId,
regionId: row.regionId,
regionIds: getRegionIdPath(row.regionId),
regionName: row.regionName,
status: row.status
}
} else {
// 新增模式:重置表单,如果有默认区域则带入
const regionIds = defaultRegionId ? getRegionIdPath(defaultRegionId) : []
form.value = {
schoolId: null,
schoolCode: '',
schoolName: '',
schoolType: '',
deptId: null,
regionId: defaultRegionId,
regionIds: regionIds,
regionName: defaultRegionId ? getRegionPath(regionIds, props.regionTree) : '',
status: '0'
}
// 重置年级选择
gradeList.value = []
selectedGradeIds.value = []
}
}
// 根据区域ID获取完整的ID路径用于级联选择器回显
const getRegionIdPath = (regionId) => {
if (!regionId) return []
// 递归遍历树查找目标节点,返回从根到目标的完整路径
const findPath = (nodes, targetId, path = []) => {
for (const node of nodes) {
const currentPath = [...path, node.regionId]
if (node.regionId === targetId) {
return currentPath
}
if (node.children && node.children.length > 0) {
const result = findPath(node.children, targetId, currentPath)
if (result.length > 0) {
return result
}
}
}
return []
}
return findPath(props.regionTree, regionId)
}
// 提交表单
const handleSubmit = async () => {
if (!formRef.value) return
await formRef.value.validate(async (valid) => {
if (!valid) return
submitLoading.value = true
try {
const submitData = {
...form.value,
regionIds: undefined, // 不提交级联选择器的数组
gradeIds: isEdit.value ? undefined : selectedGradeIds.value // 新增时携带年级ID列表
}
const res = form.value.schoolId
? await updateSchool(submitData)
: await addSchool(submitData)
if (res.code === 200) {
const gradeCount = selectedGradeIds.value.length
const msg = isEdit.value
? '修改成功'
: (gradeCount > 0 ? `新增成功,已自动添加 ${gradeCount} 个年级` : '新增成功')
ElMessage.success(msg)
dialogVisible.value = false
emit('success')
}
} catch (error) {
console.error('提交失败:', error)
} finally {
submitLoading.value = false
}
})
}
// 暴露方法给父组件
defineExpose({ open })
</script>
<style scoped>
.grade-select-wrapper {
width: 100%;
}
.grade-select-wrapper .el-checkbox {
margin-right: 16px;
margin-bottom: 8px;
}
.grade-tip {
margin-top: 8px;
}
</style>