Browse Source

学校与校区修改

jinxia.mo 1 day ago
parent
commit
a8540d43a9

+ 9 - 0
back-ui/src/api/dz/campus.js

@@ -51,3 +51,12 @@ export function delCampus(id) {
     method: 'delete'
   })
 }
+
+// 校验校区名称是否唯一
+export function checkCampusName(name, id) {
+  return request({
+    url: '/dz/campus/checkCampusName',
+    method: 'get',
+    params: { name, id }
+  })
+}

+ 184 - 37
back-ui/src/views/dz/campus/index.vue

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

+ 2 - 0
back-ui/src/views/dz/school/index.vue

@@ -428,6 +428,8 @@
     // 取消树节点的选中状态
     // proxy.$refs.deptTreeRef.setCurrentKey(null)
     proxy.resetForm("queryRef")
+    // 清空学校ID(下拉选择框的值)
+    queryParams.value.id = null
     // 清空省市区选择
     areaIds.value = []
 

+ 10 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzCampusController.java

@@ -149,4 +149,14 @@ public class DzCampusController extends BaseController
     {
         return toAjax(dzSchoolService.deleteDzSchoolByIds(ids));
     }
+
+    /**
+     * 校验校区名称是否唯一
+     */
+    @GetMapping("/checkCampusName")
+    public AjaxResult checkCampusName(@RequestParam("name") String name, @RequestParam(value = "id", required = false) Long id)
+    {
+        boolean isUnique = dzSchoolService.checkSchoolName(name, id);
+        return AjaxResult.success(isUnique);
+    }
 }

+ 6 - 1
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzSchoolController.java

@@ -70,6 +70,7 @@ public class DzSchoolController extends BaseController
 //        }else {
 //            dzSchool.setCampus(false);
 //        }
+        dzSchool.setCampus(false);
         startPage();
         List<DzSchool> list= dzSchoolService.selectDzSchoolList(dzSchool);
         //处理省市区
@@ -133,6 +134,7 @@ public class DzSchoolController extends BaseController
 //        }else {
 //            dzSchool.setCampus(false);
 //        }
+        dzSchool.setCampus(false);
         List<DzSchool> list = dzSchoolService.selectDzSchoolList(dzSchool);
         return AjaxResult.success(list);
     }
@@ -143,7 +145,9 @@ public class DzSchoolController extends BaseController
     @GetMapping("/getAllSchool")
     public AjaxResult getAllSchool()
     {
-        List<DzSchool> list = dzSchoolService.selectDzSchoolList(new DzSchool());
+        DzSchool dzSchool = new DzSchool();
+        dzSchool.setCampus(false);
+        List<DzSchool> list = dzSchoolService.selectDzSchoolList(dzSchool);
         return AjaxResult.success(list);
     }
 
@@ -155,6 +159,7 @@ public class DzSchoolController extends BaseController
     @PostMapping("/export")
     public void export(HttpServletResponse response, DzSchool dzSchool)
     {
+        dzSchool.setCampus(false);
         List<DzSchool> list = dzSchoolService.selectDzSchoolList(dzSchool);
         ExcelUtil<DzSchool> util = new ExcelUtil<DzSchool>(DzSchool.class);
         util.exportExcel(response, list, "机构校区数据");

+ 1 - 1
ie-system/src/main/resources/mapper/dz/DzSchoolMapper.xml

@@ -53,7 +53,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="area != null "> and t1.area = #{area}</if>
             <if test="status != null "> and t1.status = #{status}</if>
             <if test="campus != null and campus"> and t1.dept_id &gt; 0</if>
-            <if test="campus != null and not campus"> and (t1.dept_id = 0 or t1.dept_id is null)</if>
+            <if test="campus != null and not campus"> and (t1.dept_id is null or t1.dept_id = 0)</if>
         </where>
         order by t1.id desc
     </select>