2026-01-31 17:55:58 +08:00
|
|
|
|
# 盘古用户平台 - 基础数据模块前端开发文档
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
| 文档信息 | 内容 |
|
|
|
|
|
|
| -------- | --------------------------- |
|
|
|
|
|
|
| **文档版本** | V1.0 |
|
|
|
|
|
|
| **项目名称** | 盘古用户平台(Pangu User Platform) |
|
|
|
|
|
|
| **模块名称** | 基础数据管理-前端开发 |
|
|
|
|
|
|
| **编写团队** | pangu |
|
|
|
|
|
|
| **创建日期** | 2026-01-31 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 开发环境要求
|
|
|
|
|
|
|
|
|
|
|
|
| 环境 | 版本要求 | 说明 |
|
|
|
|
|
|
| -------- | --------- | --------- |
|
|
|
|
|
|
| Node.js | ≥18.0.0 | 运行环境 |
|
|
|
|
|
|
| npm | ≥9.0.0 | 包管理器 |
|
|
|
|
|
|
| Vue | 3.5.x | 前端框架 |
|
|
|
|
|
|
| Vite | 7.3.x | 构建工具 |
|
|
|
|
|
|
| Element Plus | 2.13.x | UI组件库 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 目录结构
|
|
|
|
|
|
|
|
|
|
|
|
```
|
2026-02-03 20:56:15 +08:00
|
|
|
|
frontend/src/
|
2026-01-31 17:55:58 +08:00
|
|
|
|
├── api/ # API接口定义
|
|
|
|
|
|
│ ├── grade.js # 年级管理API
|
|
|
|
|
|
│ ├── class.js # 班级管理API
|
|
|
|
|
|
│ ├── subject.js # 学科管理API
|
|
|
|
|
|
│ └── region.js # 区域管理API
|
|
|
|
|
|
├── mock/ # Mock数据
|
|
|
|
|
|
│ ├── grade.js # 年级Mock
|
|
|
|
|
|
│ ├── class.js # 班级Mock
|
|
|
|
|
|
│ ├── subject.js # 学科Mock
|
|
|
|
|
|
│ └── region.js # 区域Mock
|
|
|
|
|
|
├── views/base/ # 页面组件
|
|
|
|
|
|
│ ├── grade/
|
|
|
|
|
|
│ │ └── index.vue # 年级管理页面
|
|
|
|
|
|
│ ├── class/
|
|
|
|
|
|
│ │ └── index.vue # 班级管理页面
|
|
|
|
|
|
│ ├── subject/
|
|
|
|
|
|
│ │ └── index.vue # 学科管理页面
|
|
|
|
|
|
│ └── region/
|
|
|
|
|
|
│ └── index.vue # 区域管理页面
|
|
|
|
|
|
└── router/
|
|
|
|
|
|
└── index.js # 路由配置
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. API接口定义
|
|
|
|
|
|
|
|
|
|
|
|
### 3.1 年级管理API(api/grade.js)
|
|
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 年级管理API
|
2026-01-31 23:14:11 +08:00
|
|
|
|
* @author pangu
|
2026-01-31 17:55:58 +08:00
|
|
|
|
*/
|
|
|
|
|
|
import request from '@/utils/request'
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取年级分页列表
|
|
|
|
|
|
* @param {Object} params - 查询参数
|
|
|
|
|
|
* @param {string} params.gradeName - 年级名称(模糊查询)
|
|
|
|
|
|
* @param {string} params.status - 状态(0正常 1停用)
|
|
|
|
|
|
* @param {number} params.pageNum - 页码
|
|
|
|
|
|
* @param {number} params.pageSize - 每页条数
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getGradeList(params) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/grade/list',
|
|
|
|
|
|
method: 'get',
|
|
|
|
|
|
params
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取年级选项列表(下拉选择用)
|
|
|
|
|
|
* @returns {Promise} 返回启用状态的年级列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getGradeOptions() {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/grade/options',
|
|
|
|
|
|
method: 'get'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取年级详情
|
|
|
|
|
|
* @param {number} gradeId - 年级ID
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getGradeDetail(gradeId) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: `/api/grade/${gradeId}`,
|
|
|
|
|
|
method: 'get'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 新增年级
|
|
|
|
|
|
* @param {Object} data - 年级数据
|
|
|
|
|
|
* @param {string} data.gradeName - 年级名称(必填)
|
|
|
|
|
|
* @param {number} data.orderNum - 排序号
|
|
|
|
|
|
* @param {string} data.status - 状态
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function addGrade(data) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/grade',
|
|
|
|
|
|
method: 'post',
|
|
|
|
|
|
data
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 修改年级
|
|
|
|
|
|
* @param {Object} data - 年级数据(含gradeId)
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function updateGrade(data) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/grade',
|
|
|
|
|
|
method: 'put',
|
|
|
|
|
|
data
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 删除年级
|
|
|
|
|
|
* @param {number} gradeId - 年级ID
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function deleteGrade(gradeId) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: `/api/grade/${gradeId}`,
|
|
|
|
|
|
method: 'delete'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3.2 班级管理API(api/class.js)
|
|
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 班级管理API
|
2026-01-31 23:14:11 +08:00
|
|
|
|
* @author pangu
|
2026-01-31 17:55:58 +08:00
|
|
|
|
*/
|
|
|
|
|
|
import request from '@/utils/request'
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取班级分页列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getClassList(params) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/class/list',
|
|
|
|
|
|
method: 'get',
|
|
|
|
|
|
params
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取班级选项列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getClassOptions() {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/class/options',
|
|
|
|
|
|
method: 'get'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取班级详情
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getClassDetail(classId) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: `/api/class/${classId}`,
|
|
|
|
|
|
method: 'get'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 新增班级
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function addClass(data) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/class',
|
|
|
|
|
|
method: 'post',
|
|
|
|
|
|
data
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 修改班级
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function updateClass(data) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/class',
|
|
|
|
|
|
method: 'put',
|
|
|
|
|
|
data
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 删除班级
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function deleteClass(classId) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: `/api/class/${classId}`,
|
|
|
|
|
|
method: 'delete'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3.3 学科管理API(api/subject.js)
|
|
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 学科管理API
|
2026-01-31 23:14:11 +08:00
|
|
|
|
* @author pangu
|
2026-01-31 17:55:58 +08:00
|
|
|
|
*/
|
|
|
|
|
|
import request from '@/utils/request'
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取学科分页列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getSubjectList(params) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/subject/list',
|
|
|
|
|
|
method: 'get',
|
|
|
|
|
|
params
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取学科选项列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getSubjectOptions() {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/subject/options',
|
|
|
|
|
|
method: 'get'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取学科详情
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getSubjectDetail(subjectId) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: `/api/subject/${subjectId}`,
|
|
|
|
|
|
method: 'get'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 新增学科
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function addSubject(data) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/subject',
|
|
|
|
|
|
method: 'post',
|
|
|
|
|
|
data
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 修改学科
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function updateSubject(data) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/subject',
|
|
|
|
|
|
method: 'put',
|
|
|
|
|
|
data
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 删除学科
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function deleteSubject(subjectId) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: `/api/subject/${subjectId}`,
|
|
|
|
|
|
method: 'delete'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3.4 区域管理API(api/region.js)
|
|
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 区域管理API
|
2026-01-31 23:14:11 +08:00
|
|
|
|
* @author pangu
|
2026-01-31 17:55:58 +08:00
|
|
|
|
*/
|
|
|
|
|
|
import request from '@/utils/request'
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取区域树
|
|
|
|
|
|
* @returns {Promise} 返回树形结构的区域数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getRegionTree() {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/region/tree',
|
|
|
|
|
|
method: 'get'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取区域详情
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function getRegionDetail(regionId) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: `/api/region/${regionId}`,
|
|
|
|
|
|
method: 'get'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 新增区域
|
|
|
|
|
|
* @param {Object} data - 区域数据
|
|
|
|
|
|
* @param {number} data.parentId - 父区域ID(0为顶级)
|
|
|
|
|
|
* @param {string} data.regionName - 区域名称
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function addRegion(data) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/region',
|
|
|
|
|
|
method: 'post',
|
|
|
|
|
|
data
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 修改区域
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function updateRegion(data) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: '/api/region',
|
|
|
|
|
|
method: 'put',
|
|
|
|
|
|
data
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 删除区域
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function deleteRegion(regionId) {
|
|
|
|
|
|
return request({
|
|
|
|
|
|
url: `/api/region/${regionId}`,
|
|
|
|
|
|
method: 'delete'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 页面组件开发
|
|
|
|
|
|
|
|
|
|
|
|
### 4.1 年级管理页面(views/base/grade/index.vue)
|
|
|
|
|
|
|
|
|
|
|
|
```vue
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<div class="app-container">
|
|
|
|
|
|
<!-- 搜索区域 -->
|
|
|
|
|
|
<el-card shadow="never" class="search-wrapper">
|
|
|
|
|
|
<el-form :model="queryParams" :inline="true">
|
|
|
|
|
|
<el-form-item label="年级名称">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="queryParams.gradeName"
|
|
|
|
|
|
placeholder="请输入年级名称"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
style="width: 200px"
|
|
|
|
|
|
@keyup.enter="handleQuery"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="状态">
|
|
|
|
|
|
<el-select
|
|
|
|
|
|
v-model="queryParams.status"
|
|
|
|
|
|
placeholder="全部"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
style="width: 100px"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-option label="正常" value="0" />
|
|
|
|
|
|
<el-option label="停用" value="1" />
|
|
|
|
|
|
</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>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 表格区域 -->
|
|
|
|
|
|
<el-card shadow="never" style="margin-top: 12px">
|
|
|
|
|
|
<el-row :gutter="10" style="margin-bottom: 12px">
|
|
|
|
|
|
<el-col :span="1.5">
|
|
|
|
|
|
<el-button type="primary" :icon="Plus" @click="handleAdd">新增</el-button>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
<el-table
|
|
|
|
|
|
v-loading="loading"
|
|
|
|
|
|
:data="tableData"
|
|
|
|
|
|
border
|
|
|
|
|
|
stripe
|
|
|
|
|
|
:header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-table-column prop="gradeName" label="年级名称" min-width="150" />
|
|
|
|
|
|
<el-table-column prop="gradeCode" label="年级编码" width="120" />
|
|
|
|
|
|
<el-table-column prop="orderNum" label="排序" width="80" align="center" />
|
|
|
|
|
|
<el-table-column prop="status" label="状态" width="80" align="center">
|
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
|
<el-tag :type="row.status === '0' ? 'success' : 'danger'">
|
|
|
|
|
|
{{ row.status === '0' ? '正常' : '停用' }}
|
|
|
|
|
|
</el-tag>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="createTime" label="创建时间" width="160" />
|
|
|
|
|
|
<el-table-column label="操作" width="150" fixed="right" align="center">
|
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
|
<el-button type="primary" link :icon="Edit" @click="handleEdit(row)">编辑</el-button>
|
|
|
|
|
|
<el-button type="danger" link :icon="Delete" @click="handleDelete(row)">删除</el-button>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 分页 -->
|
|
|
|
|
|
<el-pagination
|
|
|
|
|
|
v-model:current-page="queryParams.pageNum"
|
|
|
|
|
|
v-model:page-size="queryParams.pageSize"
|
|
|
|
|
|
:page-sizes="[10, 20, 50, 100]"
|
|
|
|
|
|
:total="total"
|
|
|
|
|
|
layout="total, sizes, prev, pager, next, jumper"
|
|
|
|
|
|
style="margin-top: 16px; justify-content: flex-end"
|
|
|
|
|
|
@size-change="getList"
|
|
|
|
|
|
@current-change="getList"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 新增/编辑弹窗 -->
|
|
|
|
|
|
<el-dialog
|
|
|
|
|
|
v-model="dialogVisible"
|
|
|
|
|
|
:title="dialogTitle"
|
|
|
|
|
|
width="500px"
|
|
|
|
|
|
:close-on-click-modal="false"
|
|
|
|
|
|
destroy-on-close
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
|
|
|
|
|
<el-form-item label="年级名称" prop="gradeName">
|
|
|
|
|
|
<el-input v-model="form.gradeName" placeholder="请输入年级名称" maxlength="50" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="年级编码">
|
|
|
|
|
|
<el-input v-model="form.gradeCode" placeholder="自动生成" disabled />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="排序" prop="orderNum">
|
|
|
|
|
|
<el-input-number v-model="form.orderNum" :min="0" :max="999" />
|
|
|
|
|
|
</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>
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<el-button @click="dialogVisible = false">取消</el-button>
|
|
|
|
|
|
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">确定</el-button>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 年级管理页面
|
2026-01-31 23:14:11 +08:00
|
|
|
|
* @author pangu
|
2026-01-31 17:55:58 +08:00
|
|
|
|
*/
|
|
|
|
|
|
import { Delete, Edit, Plus, Refresh, Search } from '@element-plus/icons-vue'
|
|
|
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
|
|
|
import { onMounted, ref } from 'vue'
|
|
|
|
|
|
import { getGradeList, addGrade, updateGrade, deleteGrade } from '@/api/grade'
|
|
|
|
|
|
|
|
|
|
|
|
// 状态变量
|
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
|
const submitLoading = ref(false)
|
|
|
|
|
|
const tableData = ref([])
|
|
|
|
|
|
const total = ref(0)
|
|
|
|
|
|
|
|
|
|
|
|
// 查询参数
|
|
|
|
|
|
const queryParams = ref({
|
|
|
|
|
|
pageNum: 1,
|
|
|
|
|
|
pageSize: 10,
|
|
|
|
|
|
gradeName: '',
|
|
|
|
|
|
status: ''
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 弹窗相关
|
|
|
|
|
|
const dialogVisible = ref(false)
|
|
|
|
|
|
const dialogTitle = ref('')
|
|
|
|
|
|
const formRef = ref()
|
|
|
|
|
|
const form = ref({
|
|
|
|
|
|
gradeId: null,
|
|
|
|
|
|
gradeName: '',
|
|
|
|
|
|
gradeCode: '',
|
|
|
|
|
|
orderNum: 0,
|
|
|
|
|
|
status: '0'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 表单校验规则
|
|
|
|
|
|
const rules = {
|
|
|
|
|
|
gradeName: [
|
|
|
|
|
|
{ required: true, message: '请输入年级名称', trigger: 'blur' },
|
|
|
|
|
|
{ max: 50, message: '年级名称长度不能超过50个字符', trigger: 'blur' }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取年级列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
const getList = async () => {
|
|
|
|
|
|
loading.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await getGradeList(queryParams.value)
|
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
|
tableData.value = res.rows
|
|
|
|
|
|
total.value = res.total
|
|
|
|
|
|
}
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
loading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 搜索
|
|
|
|
|
|
*/
|
|
|
|
|
|
const handleQuery = () => {
|
|
|
|
|
|
queryParams.value.pageNum = 1
|
|
|
|
|
|
getList()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 重置搜索
|
|
|
|
|
|
*/
|
|
|
|
|
|
const resetQuery = () => {
|
|
|
|
|
|
queryParams.value = {
|
|
|
|
|
|
pageNum: 1,
|
|
|
|
|
|
pageSize: 10,
|
|
|
|
|
|
gradeName: '',
|
|
|
|
|
|
status: ''
|
|
|
|
|
|
}
|
|
|
|
|
|
getList()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 新增年级
|
|
|
|
|
|
*/
|
|
|
|
|
|
const handleAdd = () => {
|
|
|
|
|
|
dialogTitle.value = '新增年级'
|
|
|
|
|
|
form.value = {
|
|
|
|
|
|
gradeId: null,
|
|
|
|
|
|
gradeName: '',
|
|
|
|
|
|
gradeCode: '(自动生成)',
|
|
|
|
|
|
orderNum: tableData.value.length + 1,
|
|
|
|
|
|
status: '0'
|
|
|
|
|
|
}
|
|
|
|
|
|
dialogVisible.value = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 编辑年级
|
|
|
|
|
|
*/
|
|
|
|
|
|
const handleEdit = (row) => {
|
|
|
|
|
|
dialogTitle.value = '编辑年级'
|
|
|
|
|
|
form.value = { ...row }
|
|
|
|
|
|
dialogVisible.value = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 提交表单
|
|
|
|
|
|
*/
|
|
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
|
|
await formRef.value?.validate()
|
|
|
|
|
|
submitLoading.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
const isEdit = !!form.value.gradeId
|
|
|
|
|
|
const res = isEdit
|
|
|
|
|
|
? await updateGrade(form.value)
|
|
|
|
|
|
: await addGrade(form.value)
|
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
|
ElMessage.success(isEdit ? '修改成功' : '新增成功')
|
|
|
|
|
|
dialogVisible.value = false
|
|
|
|
|
|
getList()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ElMessage.error(res.msg || '操作失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
submitLoading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 删除年级
|
|
|
|
|
|
*/
|
|
|
|
|
|
const handleDelete = (row) => {
|
|
|
|
|
|
ElMessageBox.confirm(
|
|
|
|
|
|
`确定要删除年级"${row.gradeName}"吗?删除后不可恢复!`,
|
|
|
|
|
|
'删除确认',
|
|
|
|
|
|
{
|
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
|
type: 'warning'
|
|
|
|
|
|
}
|
|
|
|
|
|
).then(async () => {
|
|
|
|
|
|
const res = await deleteGrade(row.gradeId)
|
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
|
ElMessage.success('删除成功')
|
|
|
|
|
|
getList()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 被引用时显示后端返回的提示
|
|
|
|
|
|
ElMessage.error(res.msg || '删除失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
}).catch(() => {
|
|
|
|
|
|
// 用户取消删除
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 页面加载时获取数据
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
getList()
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.app-container {
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.search-wrapper {
|
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 4.2 区域管理页面(views/base/region/index.vue)
|
|
|
|
|
|
|
|
|
|
|
|
```vue
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<div class="app-container">
|
|
|
|
|
|
<!-- 操作区域 -->
|
|
|
|
|
|
<el-card shadow="never">
|
|
|
|
|
|
<el-row :gutter="10">
|
|
|
|
|
|
<el-col :span="1.5">
|
|
|
|
|
|
<el-button type="primary" :icon="Plus" @click="handleAdd">新增</el-button>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="1.5">
|
|
|
|
|
|
<el-button :icon="Sort" @click="toggleExpandAll">
|
|
|
|
|
|
{{ isExpandAll ? '折叠全部' : '展开全部' }}
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 树形表格 -->
|
|
|
|
|
|
<el-card shadow="never" style="margin-top: 12px">
|
|
|
|
|
|
<el-table
|
|
|
|
|
|
v-if="refreshTable"
|
|
|
|
|
|
v-loading="loading"
|
|
|
|
|
|
:data="treeData"
|
|
|
|
|
|
row-key="regionId"
|
|
|
|
|
|
border
|
|
|
|
|
|
:default-expand-all="isExpandAll"
|
|
|
|
|
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
|
|
|
|
|
:header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-table-column prop="regionName" label="区域名称" min-width="200" />
|
|
|
|
|
|
<el-table-column prop="regionCode" label="区域编码" width="150" />
|
|
|
|
|
|
<el-table-column prop="level" label="层级" width="80" align="center">
|
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
|
<el-tag :type="getLevelType(row.level)">
|
|
|
|
|
|
{{ getLevelText(row.level) }}
|
|
|
|
|
|
</el-tag>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="orderNum" label="排序" width="80" align="center" />
|
|
|
|
|
|
<el-table-column prop="createTime" label="创建时间" width="160" />
|
|
|
|
|
|
<el-table-column label="操作" width="200" fixed="right" align="center">
|
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
|
<!-- 只有省、市级可以新增下级 -->
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
v-if="row.level < 3"
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
link
|
|
|
|
|
|
:icon="Plus"
|
|
|
|
|
|
@click="handleAddChild(row)"
|
|
|
|
|
|
>
|
|
|
|
|
|
新增下级
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
<el-button type="primary" link :icon="Edit" @click="handleEdit(row)">编辑</el-button>
|
|
|
|
|
|
<el-button type="danger" link :icon="Delete" @click="handleDelete(row)">删除</el-button>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 新增/编辑弹窗 -->
|
|
|
|
|
|
<el-dialog
|
|
|
|
|
|
v-model="dialogVisible"
|
|
|
|
|
|
:title="dialogTitle"
|
|
|
|
|
|
width="500px"
|
|
|
|
|
|
:close-on-click-modal="false"
|
|
|
|
|
|
destroy-on-close
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
|
|
|
|
|
<el-form-item label="上级区域" v-if="form.parentId !== 0">
|
|
|
|
|
|
<el-input v-model="form.parentName" disabled />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="区域名称" prop="regionName">
|
|
|
|
|
|
<el-input v-model="form.regionName" placeholder="请输入区域名称" maxlength="100" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="区域编码" v-if="form.regionId">
|
|
|
|
|
|
<el-input v-model="form.regionCode" disabled />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="排序" prop="orderNum">
|
|
|
|
|
|
<el-input-number v-model="form.orderNum" :min="0" :max="999" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<el-button @click="dialogVisible = false">取消</el-button>
|
|
|
|
|
|
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">确定</el-button>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 区域管理页面
|
2026-01-31 23:14:11 +08:00
|
|
|
|
* @author pangu
|
2026-01-31 17:55:58 +08:00
|
|
|
|
*/
|
|
|
|
|
|
import { Delete, Edit, Plus, Sort } from '@element-plus/icons-vue'
|
|
|
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
|
|
|
import { nextTick, onMounted, ref } from 'vue'
|
|
|
|
|
|
import { getRegionTree, addRegion, updateRegion, deleteRegion } from '@/api/region'
|
|
|
|
|
|
|
|
|
|
|
|
// 状态变量
|
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
|
const submitLoading = ref(false)
|
|
|
|
|
|
const treeData = ref([])
|
|
|
|
|
|
const isExpandAll = ref(false)
|
|
|
|
|
|
const refreshTable = ref(true)
|
|
|
|
|
|
|
|
|
|
|
|
// 弹窗相关
|
|
|
|
|
|
const dialogVisible = ref(false)
|
|
|
|
|
|
const dialogTitle = ref('')
|
|
|
|
|
|
const formRef = ref()
|
|
|
|
|
|
const form = ref({
|
|
|
|
|
|
regionId: null,
|
|
|
|
|
|
parentId: 0,
|
|
|
|
|
|
parentName: '',
|
|
|
|
|
|
regionName: '',
|
|
|
|
|
|
regionCode: '',
|
|
|
|
|
|
orderNum: 0
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 表单校验规则
|
|
|
|
|
|
const rules = {
|
|
|
|
|
|
regionName: [
|
|
|
|
|
|
{ required: true, message: '请输入区域名称', trigger: 'blur' },
|
|
|
|
|
|
{ max: 100, message: '区域名称长度不能超过100个字符', trigger: 'blur' }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取区域树
|
|
|
|
|
|
*/
|
|
|
|
|
|
const getTree = async () => {
|
|
|
|
|
|
loading.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await getRegionTree()
|
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
|
treeData.value = res.data
|
|
|
|
|
|
}
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
loading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 展开/折叠全部
|
|
|
|
|
|
*/
|
|
|
|
|
|
const toggleExpandAll = () => {
|
|
|
|
|
|
refreshTable.value = false
|
|
|
|
|
|
isExpandAll.value = !isExpandAll.value
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
refreshTable.value = true
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取层级文本
|
|
|
|
|
|
*/
|
|
|
|
|
|
const getLevelText = (level) => {
|
|
|
|
|
|
const map = { 1: '省', 2: '市', 3: '区/县' }
|
|
|
|
|
|
return map[level] || '未知'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取层级标签类型
|
|
|
|
|
|
*/
|
|
|
|
|
|
const getLevelType = (level) => {
|
|
|
|
|
|
const map = { 1: 'primary', 2: 'success', 3: 'info' }
|
|
|
|
|
|
return map[level] || 'info'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 新增顶级区域
|
|
|
|
|
|
*/
|
|
|
|
|
|
const handleAdd = () => {
|
|
|
|
|
|
dialogTitle.value = '新增区域'
|
|
|
|
|
|
form.value = {
|
|
|
|
|
|
regionId: null,
|
|
|
|
|
|
parentId: 0,
|
|
|
|
|
|
parentName: '',
|
|
|
|
|
|
regionName: '',
|
|
|
|
|
|
regionCode: '',
|
|
|
|
|
|
orderNum: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
dialogVisible.value = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 新增下级区域
|
|
|
|
|
|
*/
|
|
|
|
|
|
const handleAddChild = (row) => {
|
|
|
|
|
|
dialogTitle.value = '新增下级区域'
|
|
|
|
|
|
form.value = {
|
|
|
|
|
|
regionId: null,
|
|
|
|
|
|
parentId: row.regionId,
|
|
|
|
|
|
parentName: row.regionName,
|
|
|
|
|
|
regionName: '',
|
|
|
|
|
|
regionCode: '',
|
|
|
|
|
|
orderNum: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
dialogVisible.value = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 编辑区域
|
|
|
|
|
|
*/
|
|
|
|
|
|
const handleEdit = (row) => {
|
|
|
|
|
|
dialogTitle.value = '编辑区域'
|
|
|
|
|
|
form.value = {
|
|
|
|
|
|
regionId: row.regionId,
|
|
|
|
|
|
parentId: row.parentId,
|
|
|
|
|
|
parentName: findParentName(row.parentId),
|
|
|
|
|
|
regionName: row.regionName,
|
|
|
|
|
|
regionCode: row.regionCode,
|
|
|
|
|
|
orderNum: row.orderNum
|
|
|
|
|
|
}
|
|
|
|
|
|
dialogVisible.value = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 查找父区域名称
|
|
|
|
|
|
*/
|
|
|
|
|
|
const findParentName = (parentId) => {
|
|
|
|
|
|
if (parentId === 0) return ''
|
|
|
|
|
|
const findNode = (nodes, id) => {
|
|
|
|
|
|
for (const node of nodes) {
|
|
|
|
|
|
if (node.regionId === id) return node.regionName
|
|
|
|
|
|
if (node.children) {
|
|
|
|
|
|
const found = findNode(node.children, id)
|
|
|
|
|
|
if (found) return found
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return ''
|
|
|
|
|
|
}
|
|
|
|
|
|
return findNode(treeData.value, parentId)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 提交表单
|
|
|
|
|
|
*/
|
|
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
|
|
await formRef.value?.validate()
|
|
|
|
|
|
submitLoading.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
const isEdit = !!form.value.regionId
|
|
|
|
|
|
const res = isEdit
|
|
|
|
|
|
? await updateRegion(form.value)
|
|
|
|
|
|
: await addRegion(form.value)
|
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
|
ElMessage.success(isEdit ? '修改成功' : '新增成功')
|
|
|
|
|
|
dialogVisible.value = false
|
|
|
|
|
|
getTree()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ElMessage.error(res.msg || '操作失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
submitLoading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 删除区域
|
|
|
|
|
|
*/
|
|
|
|
|
|
const handleDelete = (row) => {
|
|
|
|
|
|
// 前端先检查是否有子级
|
|
|
|
|
|
if (row.children && row.children.length > 0) {
|
|
|
|
|
|
ElMessage.warning('存在下级区域,不能删除')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ElMessageBox.confirm(
|
|
|
|
|
|
`确定要删除区域"${row.regionName}"吗?`,
|
|
|
|
|
|
'删除确认',
|
|
|
|
|
|
{
|
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
|
type: 'warning'
|
|
|
|
|
|
}
|
|
|
|
|
|
).then(async () => {
|
|
|
|
|
|
const res = await deleteRegion(row.regionId)
|
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
|
ElMessage.success('删除成功')
|
|
|
|
|
|
getTree()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 被学校/会员引用时显示后端提示
|
|
|
|
|
|
ElMessage.error(res.msg || '删除失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
}).catch(() => {
|
|
|
|
|
|
// 用户取消删除
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 页面加载时获取数据
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
getTree()
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.app-container {
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 5. Mock数据配置
|
|
|
|
|
|
|
|
|
|
|
|
### 5.1 年级Mock(mock/grade.js)
|
|
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 年级管理Mock数据
|
2026-01-31 23:14:11 +08:00
|
|
|
|
* @author pangu
|
2026-01-31 17:55:58 +08:00
|
|
|
|
*/
|
|
|
|
|
|
import Mock from 'mockjs'
|
|
|
|
|
|
|
|
|
|
|
|
// 年级预置数据
|
|
|
|
|
|
const gradeData = [
|
|
|
|
|
|
{ gradeId: 1, gradeName: '一年级', gradeCode: 'GRD001', orderNum: 1, status: '0', createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ gradeId: 2, gradeName: '二年级', gradeCode: 'GRD002', orderNum: 2, status: '0', createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ gradeId: 3, gradeName: '三年级', gradeCode: 'GRD003', orderNum: 3, status: '0', createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ gradeId: 4, gradeName: '四年级', gradeCode: 'GRD004', orderNum: 4, status: '0', createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ gradeId: 5, gradeName: '五年级', gradeCode: 'GRD005', orderNum: 5, status: '0', createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ gradeId: 6, gradeName: '六年级', gradeCode: 'GRD006', orderNum: 6, status: '0', createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ gradeId: 7, gradeName: '七年级', gradeCode: 'GRD007', orderNum: 7, status: '0', createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ gradeId: 8, gradeName: '八年级', gradeCode: 'GRD008', orderNum: 8, status: '0', createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ gradeId: 9, gradeName: '九年级', gradeCode: 'GRD009', orderNum: 9, status: '0', createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ gradeId: 10, gradeName: '高一', gradeCode: 'GRD010', orderNum: 10, status: '0', createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ gradeId: 11, gradeName: '高二', gradeCode: 'GRD011', orderNum: 11, status: '0', createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ gradeId: 12, gradeName: '高三', gradeCode: 'GRD012', orderNum: 12, status: '0', createTime: '2026-01-01 10:00:00' }
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// 获取年级列表
|
|
|
|
|
|
Mock.mock(/\/api\/grade\/list/, 'get', (options) => {
|
|
|
|
|
|
const url = new URL('http://localhost' + options.url)
|
|
|
|
|
|
const gradeName = url.searchParams.get('gradeName') || ''
|
|
|
|
|
|
const status = url.searchParams.get('status')
|
|
|
|
|
|
const pageNum = parseInt(url.searchParams.get('pageNum')) || 1
|
|
|
|
|
|
const pageSize = parseInt(url.searchParams.get('pageSize')) || 10
|
|
|
|
|
|
|
|
|
|
|
|
let list = gradeData.filter(item => {
|
|
|
|
|
|
let match = true
|
|
|
|
|
|
if (gradeName) {
|
|
|
|
|
|
match = match && item.gradeName.includes(gradeName)
|
|
|
|
|
|
}
|
|
|
|
|
|
if (status !== null && status !== '') {
|
|
|
|
|
|
match = match && item.status === status
|
|
|
|
|
|
}
|
|
|
|
|
|
return match
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const total = list.length
|
|
|
|
|
|
const start = (pageNum - 1) * pageSize
|
|
|
|
|
|
const rows = list.slice(start, start + pageSize)
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 200,
|
|
|
|
|
|
msg: '查询成功',
|
|
|
|
|
|
total,
|
|
|
|
|
|
rows
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 获取年级选项
|
|
|
|
|
|
Mock.mock(/\/api\/grade\/options/, 'get', () => {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 200,
|
|
|
|
|
|
msg: '查询成功',
|
|
|
|
|
|
data: gradeData.filter(item => item.status === '0').map(item => ({
|
|
|
|
|
|
gradeId: item.gradeId,
|
|
|
|
|
|
gradeName: item.gradeName,
|
|
|
|
|
|
gradeCode: item.gradeCode
|
|
|
|
|
|
}))
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 新增年级
|
|
|
|
|
|
Mock.mock('/api/grade', 'post', () => {
|
|
|
|
|
|
return { code: 200, msg: '新增成功' }
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 修改年级
|
|
|
|
|
|
Mock.mock('/api/grade', 'put', () => {
|
|
|
|
|
|
return { code: 200, msg: '修改成功' }
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 删除年级
|
|
|
|
|
|
Mock.mock(/\/api\/grade\/\d+/, 'delete', () => {
|
|
|
|
|
|
// 模拟被引用时的删除失败
|
|
|
|
|
|
// return { code: 500, msg: '该年级已被学校使用,不能删除' }
|
|
|
|
|
|
return { code: 200, msg: '删除成功' }
|
|
|
|
|
|
})
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 5.2 区域Mock(mock/region.js)
|
|
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 区域管理Mock数据
|
2026-01-31 23:14:11 +08:00
|
|
|
|
* @author pangu
|
2026-01-31 17:55:58 +08:00
|
|
|
|
*/
|
|
|
|
|
|
import Mock from 'mockjs'
|
|
|
|
|
|
|
|
|
|
|
|
// 区域树形数据
|
|
|
|
|
|
const regionTree = [
|
|
|
|
|
|
{
|
|
|
|
|
|
regionId: 1,
|
|
|
|
|
|
parentId: 0,
|
|
|
|
|
|
regionName: '湖北',
|
|
|
|
|
|
regionCode: 'REG01',
|
|
|
|
|
|
level: 1,
|
|
|
|
|
|
orderNum: 1,
|
|
|
|
|
|
createTime: '2026-01-01 10:00:00',
|
|
|
|
|
|
children: [
|
|
|
|
|
|
{
|
|
|
|
|
|
regionId: 11,
|
|
|
|
|
|
parentId: 1,
|
|
|
|
|
|
regionName: '武汉',
|
|
|
|
|
|
regionCode: 'REG0101',
|
|
|
|
|
|
level: 2,
|
|
|
|
|
|
orderNum: 1,
|
|
|
|
|
|
createTime: '2026-01-01 10:00:00',
|
|
|
|
|
|
children: [
|
|
|
|
|
|
{ regionId: 111, parentId: 11, regionName: '武昌区', regionCode: 'REG010101', level: 3, orderNum: 1, createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ regionId: 112, parentId: 11, regionName: '汉口区', regionCode: 'REG010102', level: 3, orderNum: 2, createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ regionId: 113, parentId: 11, regionName: '汉阳区', regionCode: 'REG010103', level: 3, orderNum: 3, createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ regionId: 114, parentId: 11, regionName: '江夏区', regionCode: 'REG010104', level: 3, orderNum: 4, createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ regionId: 115, parentId: 11, regionName: '新洲区', regionCode: 'REG010105', level: 3, orderNum: 5, createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ regionId: 116, parentId: 11, regionName: '黄陂区', regionCode: 'REG010106', level: 3, orderNum: 6, createTime: '2026-01-01 10:00:00' }
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
regionId: 12,
|
|
|
|
|
|
parentId: 1,
|
|
|
|
|
|
regionName: '黄冈',
|
|
|
|
|
|
regionCode: 'REG0102',
|
|
|
|
|
|
level: 2,
|
|
|
|
|
|
orderNum: 2,
|
|
|
|
|
|
createTime: '2026-01-01 10:00:00',
|
|
|
|
|
|
children: [
|
|
|
|
|
|
{ regionId: 121, parentId: 12, regionName: '黄州区', regionCode: 'REG010201', level: 3, orderNum: 1, createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ regionId: 122, parentId: 12, regionName: '红安县', regionCode: 'REG010202', level: 3, orderNum: 2, createTime: '2026-01-01 10:00:00' },
|
|
|
|
|
|
{ regionId: 123, parentId: 12, regionName: '麻城市', regionCode: 'REG010203', level: 3, orderNum: 3, createTime: '2026-01-01 10:00:00' }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
{ regionId: 2, parentId: 0, regionName: '北京', regionCode: 'REG02', level: 1, orderNum: 2, createTime: '2026-01-01 10:00:00', children: [] },
|
|
|
|
|
|
{ regionId: 3, parentId: 0, regionName: '香港', regionCode: 'REG03', level: 1, orderNum: 3, createTime: '2026-01-01 10:00:00', children: [] },
|
|
|
|
|
|
{ regionId: 4, parentId: 0, regionName: '吉宁', regionCode: 'REG04', level: 1, orderNum: 4, createTime: '2026-01-01 10:00:00', children: [] }
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// 获取区域树
|
|
|
|
|
|
Mock.mock('/api/region/tree', 'get', () => {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 200,
|
|
|
|
|
|
msg: '查询成功',
|
|
|
|
|
|
data: regionTree
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 新增区域
|
|
|
|
|
|
Mock.mock('/api/region', 'post', () => {
|
|
|
|
|
|
return { code: 200, msg: '新增成功' }
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 修改区域
|
|
|
|
|
|
Mock.mock('/api/region', 'put', () => {
|
|
|
|
|
|
return { code: 200, msg: '修改成功' }
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 删除区域
|
|
|
|
|
|
Mock.mock(/\/api\/region\/\d+/, 'delete', () => {
|
|
|
|
|
|
return { code: 200, msg: '删除成功' }
|
|
|
|
|
|
})
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 路由配置
|
|
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
|
// router/index.js
|
|
|
|
|
|
import { createRouter, createWebHistory } from 'vue-router'
|
|
|
|
|
|
import Layout from '@/layout/index.vue'
|
|
|
|
|
|
|
|
|
|
|
|
const routes = [
|
|
|
|
|
|
// ... 其他路由
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
path: '/base',
|
|
|
|
|
|
component: Layout,
|
|
|
|
|
|
redirect: '/base/grade',
|
|
|
|
|
|
name: 'Base',
|
|
|
|
|
|
meta: { title: '基础数据', icon: 'Setting' },
|
|
|
|
|
|
children: [
|
|
|
|
|
|
{
|
|
|
|
|
|
path: 'grade',
|
|
|
|
|
|
name: 'Grade',
|
|
|
|
|
|
component: () => import('@/views/base/grade/index.vue'),
|
|
|
|
|
|
meta: { title: '年级管理' }
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
path: 'class',
|
|
|
|
|
|
name: 'Class',
|
|
|
|
|
|
component: () => import('@/views/base/class/index.vue'),
|
|
|
|
|
|
meta: { title: '班级管理' }
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
path: 'subject',
|
|
|
|
|
|
name: 'Subject',
|
|
|
|
|
|
component: () => import('@/views/base/subject/index.vue'),
|
|
|
|
|
|
meta: { title: '学科管理' }
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
path: 'region',
|
|
|
|
|
|
name: 'Region',
|
|
|
|
|
|
component: () => import('@/views/base/region/index.vue'),
|
|
|
|
|
|
meta: { title: '区域管理' }
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
const router = createRouter({
|
|
|
|
|
|
history: createWebHistory(),
|
|
|
|
|
|
routes
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
export default router
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 7. 开发检查清单
|
|
|
|
|
|
|
|
|
|
|
|
### 7.1 年级管理
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] API接口封装(api/grade.js)
|
|
|
|
|
|
- [ ] Mock数据配置(mock/grade.js)
|
|
|
|
|
|
- [ ] 页面组件开发(views/base/grade/index.vue)
|
|
|
|
|
|
- [ ] 列表查询功能
|
|
|
|
|
|
- [ ] 分页功能
|
|
|
|
|
|
- [ ] 新增功能
|
|
|
|
|
|
- [ ] 编辑功能
|
|
|
|
|
|
- [ ] 删除功能(含删除确认)
|
|
|
|
|
|
- [ ] 表单校验
|
|
|
|
|
|
|
|
|
|
|
|
### 7.2 班级管理
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] API接口封装
|
|
|
|
|
|
- [ ] Mock数据配置
|
|
|
|
|
|
- [ ] 页面组件开发
|
|
|
|
|
|
- [ ] CRUD功能
|
|
|
|
|
|
|
|
|
|
|
|
### 7.3 学科管理
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] API接口封装
|
|
|
|
|
|
- [ ] Mock数据配置
|
|
|
|
|
|
- [ ] 页面组件开发
|
|
|
|
|
|
- [ ] CRUD功能
|
|
|
|
|
|
|
|
|
|
|
|
### 7.4 区域管理
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] API接口封装
|
|
|
|
|
|
- [ ] Mock数据配置
|
|
|
|
|
|
- [ ] 页面组件开发(树形表格)
|
|
|
|
|
|
- [ ] 展开/折叠全部功能
|
|
|
|
|
|
- [ ] 新增下级功能
|
|
|
|
|
|
- [ ] 删除前子级检查
|
|
|
|
|
|
|
|
|
|
|
|
### 7.5 路由配置
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] 基础数据菜单配置
|
|
|
|
|
|
- [ ] 四个子页面路由配置
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
*文档结束*
|