|
|
@@ -3,7 +3,7 @@
|
|
|
<el-row :gutter="20">
|
|
|
<splitpanes :horizontal="appStore.device === 'mobile'" class="default-theme">
|
|
|
<!--机构数据-->
|
|
|
- <pane size="16">
|
|
|
+ <!-- <pane size="16">
|
|
|
<el-col>
|
|
|
<div class="head-container">
|
|
|
<el-input v-model="deptName" placeholder="请输入机构名称" clearable prefix-icon="Search"
|
|
|
@@ -15,30 +15,46 @@
|
|
|
highlight-current default-expand-all @node-click="handleNodeClick" />
|
|
|
</div>
|
|
|
</el-col>
|
|
|
- </pane>
|
|
|
- <pane size="84">
|
|
|
+ </pane> -->
|
|
|
+ <pane size="100">
|
|
|
<el-col>
|
|
|
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
|
|
|
- <el-form-item label="名称" prop="name">
|
|
|
- <el-input v-model="queryParams.name" placeholder="请输入名称" clearable @keyup.enter="handleQuery" />
|
|
|
+ <el-form-item label="校区名称" prop="name">
|
|
|
+ <el-select
|
|
|
+ v-model="queryParams.id"
|
|
|
+ placeholder="请选择或输入校区名称"
|
|
|
+ filterable
|
|
|
+ clearable
|
|
|
+ style="width: 200px"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="campus in allCampusList"
|
|
|
+ :key="campus.id"
|
|
|
+ :label="campus.name"
|
|
|
+ :value="campus.id"
|
|
|
+ />
|
|
|
+ </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 label="省份" prop="location">-->
|
|
|
- <!-- <el-input-->
|
|
|
- <!-- v-model="queryParams.location"-->
|
|
|
- <!-- placeholder="请输入省份"-->
|
|
|
- <!-- clearable-->
|
|
|
- <!-- @keyup.enter="handleQuery"-->
|
|
|
- <!-- />-->
|
|
|
- <!-- </el-form-item>-->
|
|
|
<el-form-item label="省市区" prop="areaIds">
|
|
|
<AddressSelect class="w-[198px]" v-model="areaIds" />
|
|
|
</el-form-item>
|
|
|
|
|
|
- <el-form-item label="状态" prop="status">
|
|
|
+ <!-- <el-form-item label="状态" prop="status">
|
|
|
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 170px">
|
|
|
<el-option v-for="dict in bool_values" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
</el-select>
|
|
|
- </el-form-item>
|
|
|
+ </el-form-item> -->
|
|
|
+
|
|
|
<el-form-item>
|
|
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
|
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
|
|
@@ -67,7 +83,7 @@
|
|
|
|
|
|
<el-table v-loading="loading" :data="campusList" @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="机构ID" align="center" prop="deptId" />-->
|
|
|
<el-table-column label="归属机构" align="center" key="deptName" prop="dept.deptName"
|
|
|
@@ -83,6 +99,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" min-width="140" fixed="right">
|
|
|
<template #default="scope">
|
|
|
@@ -115,11 +136,11 @@
|
|
|
: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" style="width: 220px;">
|
|
|
- <AddressSelect class="w-[198px]" v-model="areaIds" />
|
|
|
+ </el-form-item> -->
|
|
|
+ <el-form-item label="省市区" prop="areaIds">
|
|
|
+ <AddressSelect v-model="formAreaIds" style="width: 100%" />
|
|
|
</el-form-item>
|
|
|
<!-- <el-form-item label="省" prop="pro">-->
|
|
|
<!-- <el-input v-model="form.pro" placeholder="请输入省" />-->
|
|
|
@@ -130,6 +151,16 @@
|
|
|
<!-- <el-form-item label="区" prop="area">-->
|
|
|
<!-- <el-input v-model="form.area" placeholder="请输入区" />-->
|
|
|
<!-- </el-form-item>-->
|
|
|
+ <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="请选择状态">
|
|
|
<el-option v-for="dict in bool_values" :key="dict.value" :label="dict.label"
|
|
|
@@ -151,7 +182,8 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup name="Campus">
|
|
|
-import { listCampus, getCampus, delCampus, addCampus, updateCampus } from "@/api/dz/campus"
|
|
|
+import { listCampus, getCampus, delCampus, addCampus, updateCampus, checkCampusName } from "@/api/dz/campus"
|
|
|
+import { debounce } from '@/utils/index';
|
|
|
import { deptTreeSelect } from "@/api/system/user"
|
|
|
import useAppStore from '@/store/modules/app'
|
|
|
import { Splitpanes, Pane } from "splitpanes"
|
|
|
@@ -160,12 +192,13 @@ import AddressSelect from '@/components/AddressSelect';
|
|
|
|
|
|
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)
|
|
|
|
|
|
const campusList = ref([])
|
|
|
+const allCampusList = ref([]) // 所有校区列表(用于下拉选择)
|
|
|
const open = ref(false)
|
|
|
const loading = ref(true)
|
|
|
const showSearch = ref(true)
|
|
|
@@ -176,14 +209,19 @@ const total = ref(0)
|
|
|
const title = ref("")
|
|
|
|
|
|
const dataList = ref([]);
|
|
|
-const areaIds = ref([]);
|
|
|
+const areaIds = ref([]); // 筛选条件中的省市区
|
|
|
+const formAreaIds = ref([]); // 表单对话框中的省市区
|
|
|
let selectedIds = [];
|
|
|
|
|
|
+const campusRef = ref(null);
|
|
|
+
|
|
|
+// 先创建 data 对象,但先不定义 rules
|
|
|
const data = reactive({
|
|
|
form: {},
|
|
|
queryParams: {
|
|
|
pageNum: 1,
|
|
|
pageSize: 10,
|
|
|
+ id: null, // 校区ID(用于精确查询)
|
|
|
name: null,
|
|
|
deptId: null,
|
|
|
location: null,
|
|
|
@@ -191,24 +229,74 @@ const data = reactive({
|
|
|
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 validateCampusName = (rule, value, callback) => {
|
|
|
+ if (!value) {
|
|
|
+ callback()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const campusId = data.form.id || null
|
|
|
+ checkCampusName(value, campusId).then(response => {
|
|
|
+ if (response.data) {
|
|
|
+ callback()
|
|
|
+ } else {
|
|
|
+ callback(new Error('校区名称已存在,请使用其他名称'))
|
|
|
+ }
|
|
|
+ }).catch(() => {
|
|
|
+ callback()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 设置 rules(在 validateCampusName 定义之后)
|
|
|
+data.rules = {
|
|
|
+ name: [
|
|
|
+ { required: true, message: "名称不能为空", trigger: "blur" },
|
|
|
+ { validator: validateCampusName, trigger: "blur" }
|
|
|
+ ]
|
|
|
+}
|
|
|
+
|
|
|
const { queryParams, form, rules } = toRefs(data)
|
|
|
const queryRef = ref(null);
|
|
|
const dateRange = ref([]);
|
|
|
|
|
|
+// 防抖校验函数
|
|
|
+const debouncedValidateName = debounce((name) => {
|
|
|
+ if (!name || !campusRef.value) return
|
|
|
+ const campusId = form.value.id || null
|
|
|
+ checkCampusName(name, campusId).then(response => {
|
|
|
+ if (!response.data) {
|
|
|
+ // 名称不唯一,触发校验错误
|
|
|
+ campusRef.value.validateField('name', () => {})
|
|
|
+ } else {
|
|
|
+ // 名称唯一,清除错误
|
|
|
+ campusRef.value.clearValidate('name')
|
|
|
+ }
|
|
|
+ })
|
|
|
+}, 500)
|
|
|
+
|
|
|
+// 监听名称变化(仅在对话框打开时校验)
|
|
|
+watch(() => form.value.name, (newName) => {
|
|
|
+ if (open.value && newName && newName.trim()) {
|
|
|
+ debouncedValidateName(newName.trim())
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
/** 查询机构校区列表 */
|
|
|
function getList() {
|
|
|
loading.value = true
|
|
|
let areaObj = { pro: areaIds.value?.[0] || '', city: areaIds.value?.[1] || '', area: areaIds.value?.[2] || '' };
|
|
|
+ // 如果选择了校区ID,则根据ID精确查询,清空name参数
|
|
|
let params = { ...proxy.addDateRange(queryParams.value), ...areaObj }
|
|
|
+ if (params.id) {
|
|
|
+ params.name = null // 如果选择了ID,则不再使用name查询
|
|
|
+ } else {
|
|
|
+ params.id = null // 如果没有选择ID,则清空id参数
|
|
|
+ }
|
|
|
listCampus(params).then(response => {
|
|
|
campusList.value = response.rows
|
|
|
total.value = response.total
|
|
|
@@ -216,6 +304,13 @@ function getList() {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+/** 加载所有校区列表(用于下拉选择) */
|
|
|
+function loadAllCampusList() {
|
|
|
+ listCampus({ pageNum: 1, pageSize: 9999, campus: true }).then(response => {
|
|
|
+ allCampusList.value = response.rows || []
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
/** 通过条件过滤节点 */
|
|
|
const filterNode = (value, data) => {
|
|
|
if (!value) return true
|
|
|
@@ -282,10 +377,16 @@ function reset() {
|
|
|
city: null,
|
|
|
area: null,
|
|
|
status: null,
|
|
|
+ examTypes: [],
|
|
|
createTime: null,
|
|
|
updateTime: null
|
|
|
}
|
|
|
- proxy.resetForm("campusRef")
|
|
|
+ // 清空表单中的省市区选择
|
|
|
+ formAreaIds.value = []
|
|
|
+ if (campusRef.value) {
|
|
|
+ campusRef.value.resetFields()
|
|
|
+ campusRef.value.clearValidate()
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/** 搜索按钮操作 */
|
|
|
@@ -301,8 +402,10 @@ function resetQuery() {
|
|
|
// 清空机构名称
|
|
|
deptName.value = ""
|
|
|
// 取消树节点的选中状态
|
|
|
- proxy.$refs.deptTreeRef.setCurrentKey(null)
|
|
|
+ // proxy.$refs.deptTreeRef.setCurrentKey(null)
|
|
|
proxy.resetForm("queryRef")
|
|
|
+ // 清空校区ID(下拉选择框的值)
|
|
|
+ queryParams.value.id = null
|
|
|
// 清空省市区选择
|
|
|
areaIds.value = []
|
|
|
|
|
|
@@ -329,6 +432,25 @@ function handleUpdate(row) {
|
|
|
const _id = row.id || ids.value
|
|
|
getCampus(_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 = []
|
|
|
+ }
|
|
|
+ // 将省市区数据转换为 formAreaIds 数组格式,用于 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)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ formAreaIds.value = areaArray
|
|
|
open.value = true
|
|
|
title.value = "修改机构校区"
|
|
|
})
|
|
|
@@ -336,19 +458,28 @@ function handleUpdate(row) {
|
|
|
|
|
|
/** 提交按钮 */
|
|
|
function submitForm() {
|
|
|
- proxy.$refs["campusRef"].validate(valid => {
|
|
|
+ campusRef.value.validate(valid => {
|
|
|
if (valid) {
|
|
|
- // 构建省市区对象
|
|
|
+ // 构建省市区对象(使用表单中的 formAreaIds)
|
|
|
let areaObj = {
|
|
|
- pro: areaIds.value?.[0] || '',
|
|
|
- city: areaIds.value?.[1] || '',
|
|
|
- area: areaIds.value?.[2] || ''
|
|
|
+ pro: formAreaIds.value?.[0] || '',
|
|
|
+ city: formAreaIds.value?.[1] || '',
|
|
|
+ area: formAreaIds.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) {
|
|
|
@@ -388,8 +519,24 @@ function handleExport() {
|
|
|
}, `campus_${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()
|
|
|
+ loadAllCampusList() // 加载所有校区列表
|
|
|
getList()
|
|
|
})
|
|
|
</script>
|