30 KiB
30 KiB
盘古用户平台 - 基础数据模块前端开发文档
| 文档信息 | 内容 |
|---|---|
| 文档版本 | 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. 目录结构
frontend/src/
├── 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)
/**
* 年级管理API
* @author pangu
*/
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)
/**
* 班级管理API
* @author pangu
*/
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)
/**
* 学科管理API
* @author pangu
*/
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)
/**
* 区域管理API
* @author pangu
*/
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)
<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>
/**
* 年级管理页面
* @author pangu
*/
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)
<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>
/**
* 区域管理页面
* @author pangu
*/
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)
/**
* 年级管理Mock数据
* @author pangu
*/
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)
/**
* 区域管理Mock数据
* @author pangu
*/
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. 路由配置
// 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 路由配置
- 基础数据菜单配置
- 四个子页面路由配置
文档结束