|
|
@@ -46,6 +46,16 @@
|
|
|
/>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
+ <el-form-item label="学校类型" prop="examTypes">
|
|
|
+ <el-select v-model="queryParams.examTypes" placeholder="请选择学校类型" clearable style="width: 170px">
|
|
|
+ <el-option
|
|
|
+ v-for="dict in exam_type"
|
|
|
+ :key="dict.value"
|
|
|
+ :label="dict.label"
|
|
|
+ :value="dict.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
<el-form-item>
|
|
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
|
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
|
|
@@ -96,7 +106,7 @@
|
|
|
|
|
|
<el-table v-loading="loading" :data="schoolList" @selection-change="handleSelectionChange">
|
|
|
<el-table-column type="selection" width="55" align="center" />
|
|
|
- <el-table-column label="ID" align="center" prop="id" />
|
|
|
+ <el-table-column label="ID" align="center" prop="id" width="80" />
|
|
|
<el-table-column label="名称" align="center" prop="name" />
|
|
|
<!-- <el-table-column label="归属机构" align="center" key="deptName" prop="dept.deptName" :show-overflow-tooltip="true" />-->
|
|
|
<!-- <el-table-column label="省份" align="center" prop="location" />-->
|
|
|
@@ -106,6 +116,11 @@
|
|
|
<dict-tag :options="bool_values" :value="scope.row.status"/>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
+ <el-table-column label="学校类型" align="center" prop="examTypes">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ formatExamTypes(scope.row.examTypes) }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
<el-table-column label="备注" align="center" prop="remark" />
|
|
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
|
|
<template #default="scope">
|
|
|
@@ -136,11 +151,22 @@
|
|
|
<!-- <el-form-item label="归属机构" prop="deptId">-->
|
|
|
<!-- <el-tree-select v-model="form.deptId" :data="enabledDeptOptions" :props="{ value: 'id', label: 'label', children: 'children' }" value-key="id" placeholder="请选择归属机构" clearable check-strictly />-->
|
|
|
<!-- </el-form-item>-->
|
|
|
- <el-form-item label="省份" prop="location">
|
|
|
+ <!-- <el-form-item label="省份" prop="location">
|
|
|
<el-input v-model="form.location" placeholder="请输入省份" />
|
|
|
+ </el-form-item> -->
|
|
|
+ <el-form-item label="省市区" prop="areaIds">
|
|
|
+ <AddressSelect v-model="areaIds" style="width: 100%" />
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="省市区" prop="areaIds" style="width: 220px;">
|
|
|
- <AddressSelect class="w-[198px]" v-model="areaIds" />
|
|
|
+
|
|
|
+ <el-form-item label="学校类型" prop="examTypes">
|
|
|
+ <el-select v-model="form.examTypes" placeholder="请选择学校类型" multiple>
|
|
|
+ <el-option
|
|
|
+ v-for="dict in exam_type"
|
|
|
+ :key="dict.value"
|
|
|
+ :label="dict.label"
|
|
|
+ :value="dict.value"
|
|
|
+ ></el-option>
|
|
|
+ </el-select>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="状态" prop="status">
|
|
|
<el-select v-model="form.status" placeholder="请选择状态">
|
|
|
@@ -167,16 +193,17 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup name="School">
|
|
|
- import { listSchool, getSchool, delSchool, addSchool, updateSchool } from "@/api/dz/school"
|
|
|
+ import { listSchool, getSchool, delSchool, addSchool, updateSchool, checkSchoolName } from "@/api/dz/school"
|
|
|
import { deptTreeSelect } from "@/api/system/user"
|
|
|
import useAppStore from '@/store/modules/app'
|
|
|
import { Splitpanes, Pane } from "splitpanes"
|
|
|
import "splitpanes/dist/splitpanes.css"
|
|
|
import AddressSelect from '@/components/AddressSelect';
|
|
|
+ import { debounce } from '@/utils/index';
|
|
|
|
|
|
const { proxy } = getCurrentInstance()
|
|
|
const appStore = useAppStore()
|
|
|
- const { bool_values } = proxy.useDict('bool_values')
|
|
|
+ const { bool_values, exam_type } = proxy.useDict('bool_values', 'exam_type')
|
|
|
const deptName = ref("")
|
|
|
const deptOptions = ref(undefined)
|
|
|
const enabledDeptOptions = ref(undefined)
|
|
|
@@ -195,6 +222,9 @@
|
|
|
const areaIds = ref([]);
|
|
|
let selectedIds = [];
|
|
|
|
|
|
+ const schoolRef = ref(null);
|
|
|
+
|
|
|
+ // 先创建 data 对象,但先不定义 rules
|
|
|
const data = reactive({
|
|
|
form: {},
|
|
|
queryParams: {
|
|
|
@@ -207,19 +237,67 @@
|
|
|
city: null,
|
|
|
area: null,
|
|
|
status: null,
|
|
|
+ examTypes: null,
|
|
|
},
|
|
|
- rules: {
|
|
|
- // status: [
|
|
|
- // { required: true, message: "状态不能为空", trigger: "change" },
|
|
|
- // { required: true, message: "机构不能为空", trigger: "change" }
|
|
|
- // ],
|
|
|
- }
|
|
|
+ rules: {}
|
|
|
})
|
|
|
|
|
|
+ // 名称校验函数(在 data 定义之后,可以访问 data.form)
|
|
|
+ const validateSchoolName = (rule, value, callback) => {
|
|
|
+ if (!value) {
|
|
|
+ callback()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const schoolId = data.form.id || null
|
|
|
+ checkSchoolName(value, schoolId).then(response => {
|
|
|
+ if (response.data) {
|
|
|
+ callback()
|
|
|
+ } else {
|
|
|
+ callback(new Error('学校名称已存在,请使用其他名称'))
|
|
|
+ }
|
|
|
+ }).catch(() => {
|
|
|
+ callback()
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置 rules(在 validateSchoolName 定义之后)
|
|
|
+ data.rules = {
|
|
|
+ name: [
|
|
|
+ { required: true, message: "名称不能为空", trigger: "blur" },
|
|
|
+ { validator: validateSchoolName, trigger: "blur" }
|
|
|
+ ]
|
|
|
+ // status: [
|
|
|
+ // { required: true, message: "状态不能为空", trigger: "change" },
|
|
|
+ // { required: true, message: "机构不能为空", trigger: "change" }
|
|
|
+ // ],
|
|
|
+ }
|
|
|
+
|
|
|
const { queryParams, form, rules } = toRefs(data)
|
|
|
const queryRef = ref(null);
|
|
|
const dateRange = ref([]);
|
|
|
|
|
|
+ // 防抖校验函数
|
|
|
+ const debouncedValidateName = debounce((name) => {
|
|
|
+ if (!name || !schoolRef.value) return
|
|
|
+ const schoolId = form.value.id || null
|
|
|
+ checkSchoolName(name, schoolId).then(response => {
|
|
|
+ if (!response.data) {
|
|
|
+ // 名称不唯一,触发校验错误
|
|
|
+ schoolRef.value.validateField('name', () => {})
|
|
|
+ } else {
|
|
|
+ // 名称唯一,清除错误
|
|
|
+ schoolRef.value.clearValidate('name')
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }, 500)
|
|
|
+
|
|
|
+ // 监听名称变化(仅在对话框打开时校验)
|
|
|
+ watch(() => form.value.name, (newName) => {
|
|
|
+ if (open.value && newName && newName.trim()) {
|
|
|
+ debouncedValidateName(newName.trim())
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
/** 查询机构校区列表 */
|
|
|
function getList() {
|
|
|
loading.value = true
|
|
|
@@ -299,10 +377,16 @@
|
|
|
city: null,
|
|
|
area: null,
|
|
|
status: null,
|
|
|
+ examTypes: [],
|
|
|
createTime: null,
|
|
|
updateTime: null
|
|
|
}
|
|
|
- proxy.resetForm("schoolRef")
|
|
|
+ // 清空省市区选择
|
|
|
+ areaIds.value = []
|
|
|
+ if (schoolRef.value) {
|
|
|
+ schoolRef.value.resetFields()
|
|
|
+ schoolRef.value.clearValidate()
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/** 搜索按钮操作 */
|
|
|
@@ -346,6 +430,25 @@
|
|
|
const _id = row.id || ids.value
|
|
|
getSchool(_id).then(response => {
|
|
|
form.value = response.data
|
|
|
+ // 将 examTypes 字符串转换为数组(如果是逗号分隔的字符串)
|
|
|
+ if (form.value.examTypes && typeof form.value.examTypes === 'string') {
|
|
|
+ form.value.examTypes = form.value.examTypes.split(',').filter(item => item.trim())
|
|
|
+ } else if (!form.value.examTypes) {
|
|
|
+ form.value.examTypes = []
|
|
|
+ }
|
|
|
+ // 将省市区数据转换为 areaIds 数组格式,用于 AddressSelect 组件回显
|
|
|
+ // 按照顺序构建数组:[省, 市, 区],只包含有值的部分
|
|
|
+ const areaArray = []
|
|
|
+ if (form.value.pro) {
|
|
|
+ areaArray.push(form.value.pro)
|
|
|
+ if (form.value.city) {
|
|
|
+ areaArray.push(form.value.city)
|
|
|
+ if (form.value.area) {
|
|
|
+ areaArray.push(form.value.area)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ areaIds.value = areaArray
|
|
|
open.value = true
|
|
|
title.value = "修改机构校区"
|
|
|
})
|
|
|
@@ -353,7 +456,7 @@
|
|
|
|
|
|
/** 提交按钮 */
|
|
|
function submitForm() {
|
|
|
- proxy.$refs["schoolRef"].validate(valid => {
|
|
|
+ schoolRef.value.validate(valid => {
|
|
|
if (valid) {
|
|
|
// 构建省市区对象
|
|
|
let areaObj = {
|
|
|
@@ -362,10 +465,19 @@
|
|
|
area: areaIds.value?.[2] || ''
|
|
|
};
|
|
|
|
|
|
+ // 处理 examTypes:如果是数组,转换为逗号分隔的字符串
|
|
|
+ let examTypesValue = form.value.examTypes
|
|
|
+ if (Array.isArray(examTypesValue)) {
|
|
|
+ examTypesValue = examTypesValue.length > 0 ? examTypesValue.join(',') : null
|
|
|
+ } else if (!examTypesValue) {
|
|
|
+ examTypesValue = null
|
|
|
+ }
|
|
|
+
|
|
|
// 合并表单数据和省市区数据
|
|
|
const submitData = {
|
|
|
...form.value,
|
|
|
- ...areaObj
|
|
|
+ ...areaObj,
|
|
|
+ examTypes: examTypesValue
|
|
|
};
|
|
|
|
|
|
if (form.value.id != null) {
|
|
|
@@ -405,6 +517,21 @@
|
|
|
}, `school_${new Date().getTime()}.xlsx`)
|
|
|
}
|
|
|
|
|
|
+ /** 格式化学校类型显示 */
|
|
|
+ function formatExamTypes(examTypes) {
|
|
|
+ if (!examTypes) return ''
|
|
|
+ // 将字符串按逗号分割
|
|
|
+ const types = String(examTypes).split(',').map(item => item.trim()).filter(item => item)
|
|
|
+ if (types.length === 0) return ''
|
|
|
+ // 根据字典查找对应的标签
|
|
|
+ const labels = types.map(type => {
|
|
|
+ const dictItem = exam_type.value.find(item => item.value === type)
|
|
|
+ return dictItem ? dictItem.label : type
|
|
|
+ })
|
|
|
+ // 用英文逗号连接
|
|
|
+ return labels.join(',')
|
|
|
+ }
|
|
|
+
|
|
|
onMounted(() => {
|
|
|
// getDeptTree()
|
|
|
getList()
|