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

363 lines
9.9 KiB
Vue
Raw Normal View History

<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>