pangu-user-platform/frontend/src/views/business/member/components/EducationDialog.vue

371 lines
9.5 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.

<!--
任教信息编辑弹窗
@author pangu
-->
<template>
<el-dialog
v-model="visible"
:title="isEdit ? '编辑任教信息' : '添加任教信息'"
width="550px"
:close-on-click-modal="false"
destroy-on-close
>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="80px"
>
<el-form-item label="区域" prop="regionId">
<el-cascader
v-model="regionIds"
:options="regionTree"
:props="{ value: 'regionId', label: 'regionName', checkStrictly: true }"
placeholder="请选择区域"
clearable
style="width: 100%"
@change="handleRegionChange"
/>
</el-form-item>
<el-form-item label="学校" prop="schoolId">
<el-select v-model="form.schoolId" placeholder="请选择学校" clearable style="width: 100%" @change="handleSchoolChange">
<el-option v-for="item in schoolList" :key="item.schoolId" :label="item.schoolName" :value="item.schoolId" />
</el-select>
</el-form-item>
<el-form-item label="年级" prop="schoolGradeId">
<el-select v-model="form.schoolGradeId" placeholder="请选择年级" clearable style="width: 100%" @change="handleGradeChange">
<el-option v-for="item in gradeList" :key="item.id" :label="item.gradeName" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="班级" prop="schoolClassId">
<el-select v-model="form.schoolClassId" placeholder="请选择班级" clearable style="width: 100%">
<el-option v-for="item in classList" :key="item.id" :label="item.className" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="学科" prop="subjectId">
<el-select v-model="form.subjectId" placeholder="请选择学科(可选)" clearable style="width: 100%">
<el-option v-for="item in subjectList" :key="item.subjectId" :label="item.subjectName" :value="item.subjectId" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
</template>
</el-dialog>
</template>
<script setup>
import request from '@/utils/request'
import { ElMessage } from 'element-plus'
import { reactive, ref, watch } from 'vue'
import useBaseDataStore from '@/store/modules/baseData'
const baseDataStore = useBaseDataStore()
const props = defineProps({
// 默认区域路径(用于新增时预填)
defaultRegionPath: {
type: Array,
default: () => []
}
})
const emit = defineEmits(['success', 'add', 'update'])
const visible = ref(false)
const isEdit = ref(false)
const formRef = ref(null)
const submitLoading = ref(false)
// 会员ID和任教信息IDmemberId 为 null 表示本地模式)
const memberId = ref(null)
const educationId = ref(null)
// 本地模式下的临时索引
const localIndex = ref(null)
// 区域ID数组用于级联选择器
const regionIds = ref([])
// 表单数据
const form = reactive({
regionId: null,
schoolId: null,
schoolGradeId: null,
schoolClassId: null,
subjectId: null
})
// 表单验证规则
const rules = {
schoolId: [{ required: true, message: '请选择学校', trigger: 'change' }],
schoolGradeId: [{ required: true, message: '请选择年级', trigger: 'change' }],
schoolClassId: [{ required: true, message: '请选择班级', trigger: 'change' }]
}
// 下拉选项数据
const regionTree = ref([])
const schoolList = ref([])
const gradeList = ref([])
const classList = ref([])
const subjectList = ref([])
/**
* 打开弹窗
* @param {Long} mId 会员IDnull 表示本地模式)
* @param {Object} row 编辑时传入任教信息数据
* @param {Number} index 本地模式下的数组索引
*/
const open = async (mId, row, index) => {
resetForm()
memberId.value = mId
isEdit.value = !!row
localIndex.value = index ?? null
visible.value = true
// 加载基础数据
await Promise.all([loadRegionTree(), loadSubjectList()])
// 编辑模式
if (row) {
educationId.value = row.educationId
form.schoolId = row.schoolId
form.schoolGradeId = row.schoolGradeId
form.schoolClassId = row.schoolClassId
form.subjectId = row.subjectId
// 加载关联数据
if (row.regionId) {
// 本地模式下 regionIds 可能已有值
if (row.regionIds) {
regionIds.value = row.regionIds
} else {
regionIds.value = await getRegionPath(row.regionId)
}
form.regionId = row.regionId
await loadSchoolList(row.regionId)
}
if (row.schoolId) {
await loadGradeList(row.schoolId)
}
if (row.schoolGradeId) {
await loadClassList(row.schoolGradeId)
}
} else {
// 新增模式:如果有默认区域路径,使用它
applyDefaultRegion()
}
}
/**
* 应用默认区域路径
*/
const applyDefaultRegion = async () => {
if (props.defaultRegionPath && props.defaultRegionPath.length > 0 && regionIds.value.length === 0) {
regionIds.value = [...props.defaultRegionPath]
form.regionId = props.defaultRegionPath[props.defaultRegionPath.length - 1]
await loadSchoolList(form.regionId)
}
}
/**
* 重置表单
*/
const resetForm = () => {
educationId.value = null
regionIds.value = []
form.regionId = null
form.schoolId = null
form.schoolGradeId = null
form.schoolClassId = null
form.subjectId = null
schoolList.value = []
gradeList.value = []
classList.value = []
}
/**
* 加载区域树(使用 Store 缓存)
*/
const loadRegionTree = async () => {
try {
regionTree.value = await baseDataStore.fetchRegionTree()
} catch (e) {
regionTree.value = []
}
}
/**
* 加载学科列表(使用 Store 缓存)
*/
const loadSubjectList = async () => {
try {
subjectList.value = await baseDataStore.fetchSubjects()
} catch (e) {
subjectList.value = []
}
}
/**
* 加载学校列表
*/
const loadSchoolList = async (regionId) => {
try {
const res = await request.get('/business/school/listAll', { params: { regionId } })
schoolList.value = res.data || []
} catch (e) {
schoolList.value = []
}
}
/**
* 加载年级列表
*/
const loadGradeList = async (schoolId) => {
try {
const res = await request.get(`/business/school/${schoolId}/grades`)
gradeList.value = res.data || []
} catch (e) {
gradeList.value = []
}
}
/**
* 加载班级列表
*/
const loadClassList = async (schoolGradeId) => {
try {
const res = await request.get(`/business/school/grade/${schoolGradeId}/classes`)
classList.value = res.data || []
} catch (e) {
classList.value = []
}
}
/**
* 获取区域路径(用于回显)
*/
const getRegionPath = async (regionId) => {
try {
const res = await request.get(`/business/region/${regionId}/path`)
return res.data || []
} catch (e) {
return []
}
}
/**
* 区域变更
*/
const handleRegionChange = (val) => {
form.regionId = val && val.length ? val[val.length - 1] : null
form.schoolId = null
form.schoolGradeId = null
form.schoolClassId = null
schoolList.value = []
gradeList.value = []
classList.value = []
if (form.regionId) {
loadSchoolList(form.regionId)
}
}
/**
* 学校变更
*/
const handleSchoolChange = () => {
form.schoolGradeId = null
form.schoolClassId = null
gradeList.value = []
classList.value = []
if (form.schoolId) {
loadGradeList(form.schoolId)
}
}
/**
* 年级变更
*/
const handleGradeChange = () => {
form.schoolClassId = null
classList.value = []
if (form.schoolGradeId) {
loadClassList(form.schoolGradeId)
}
}
/**
* 提交表单
*/
const handleSubmit = async () => {
try {
await formRef.value?.validate()
} catch (e) {
return
}
// 构建数据(包含名称用于本地展示)
const data = {
regionId: form.regionId,
regionIds: [...regionIds.value],
schoolId: form.schoolId,
schoolGradeId: form.schoolGradeId,
schoolClassId: form.schoolClassId,
subjectId: form.subjectId,
// 添加名称用于列表展示
schoolName: schoolList.value.find(s => s.schoolId === form.schoolId)?.schoolName || '',
gradeName: gradeList.value.find(g => g.id === form.schoolGradeId)?.gradeName || '',
className: classList.value.find(c => c.id === form.schoolClassId)?.className || '',
subjectName: subjectList.value.find(s => s.subjectId === form.subjectId)?.subjectName || ''
}
// 本地模式:返回数据给父组件
if (!memberId.value) {
visible.value = false
if (isEdit.value) {
emit('update', data, localIndex.value)
} else {
emit('add', data)
}
return
}
// 远程模式:调用 API
submitLoading.value = true
try {
const apiData = {
regionId: form.regionId,
schoolId: form.schoolId,
schoolGradeId: form.schoolGradeId,
schoolClassId: form.schoolClassId,
subjectId: form.subjectId
}
if (isEdit.value) {
const res = await request.put(`/business/member/${memberId.value}/educations/${educationId.value}`, apiData)
if (res.code === 200) {
ElMessage.success('修改成功')
visible.value = false
emit('success')
}
} else {
const res = await request.post(`/business/member/${memberId.value}/educations`, apiData)
if (res.code === 200) {
ElMessage.success('添加成功')
visible.value = false
emit('success')
}
}
} finally {
submitLoading.value = false
}
}
defineExpose({ open })
</script>