目录
- [1 创建数据模型](#1 创建数据模型)
- [2 搭建页面](#2 搭建页面)
- [3 获取部门信息](#3 获取部门信息)
- [4 前端读取](#4 前端读取)
- 总结
上一篇我们已经介绍了医院及院区信息的展示,有了院区之后,我们就需要在院区下建立科室。对于大型医院,通常科室是非常多的,而且科室下边还有子部门。
对于这种有多级结构的,我们通常使用树形结构来管理数据,本篇我们介绍一下科室管理的开发过程。
1 创建数据模型
对于这种父子关系的,我们在建表的时候需要建立自关联的关系。打开MySQL,创建数据模型,创建部门表,增加科室名称字段

增加科室编码字段

增加父部门,类型选择关联关系

增加层级字段

增加排序字段

增加科室简介字段

录入数据的时候就形成了一种层级关系

2 搭建页面
打开我们的后台应用,点击创建页面的图标,添加科室管理页面

在内容插槽里添加布局组件

我们用网格布局来将页面分为左右两部分

第一列添加树组件

第二列,我们用普通容器来搭建布局,形成上下两部分

上半部分,我们搭建一个布局显示当前选中部门的信息,可以添加子部门

下半部分添加数据表格组件,数据模型选择部门表

3 获取部门信息
因为科室是一颗树,但是我们表里的数据是以行进行组织的,所以需要写一个API将行结构改写为树结构。
打开扩展功能,点击+号创建API

选择自定义代码

输入API的名称和标识

修改一下方法名称和标识

输入如下代码
bash
/**
* API 标识: getDepartmentTree
* 类型: 自定义代码
*/
module.exports = async function (params, context) {
// 1. 从数据库获取所有部门数据
// 注意:默认分页限制为 200 条 。
// 如果部门超过 200,建议使用循环分页获取,此处演示单次获取。
const result = await context.callModel({
dataSourceName: 't_department', // 数据模型标识
methodName: 'wedaGetRecordsV2', // 查询多条方法 [cite: 467]
params: {
pageSize: 200,
pageNumber: 1,
select: {
$master: true, // 获取主表字段 [cite: 859]
// 确保获取 parent_id,这对于构建树至关重要
parent_id: true
}
}
});
const allDepts = result.records || [];
// 定义图标常量 (根据你的需求配置)
const ICONS = {
fold: "0a94df-1307578329.tcloudbaseapp.com/resources/2023-05/lowcode-1177832",
expand: "https://lowcode-1gk9y5ik310a94df-1307578329.tcloudbaseapp.com/resources/2023-05/lowcode-1177833",
leaf: "https://lowcode-1gk9y5ik310a94df-1307578329.tcloudbaseapp.com/resources/2023-05/lowcode-1177834"
};
// 2. 定义转换函数:将数据库行转换为 UI 组件节点格式
const transformNode = (dept) => {
return {
label: dept.name || '未命名部门', // 组件要求的 label
value: dept._id, // 组件要求的 value
// 这里的 parentId 处理要小心,关联关系通常返回对象 {_id: "..."}
parentId: dept.parent_id ? dept.parent_id._id : null,
foldIcon: ICONS.fold,
expendIcon: ICONS.expand,
// 预留 children 数组
children: []
};
};
// 3. 构建树的核心算法 (Map 映射法)
const buildTree = (items) => {
const tree = [];
const map = {};
// 第一轮遍历:初始化所有节点并存入 Map
items.forEach(item => {
const node = transformNode(item);
map[node.value] = node; // 以 ID 为 Key 存入 Map
});
// 第二轮遍历:利用引用组装树
items.forEach(item => {
const node = map[item._id];
const parentId = node.parentId;
if (parentId && map[parentId]) {
// 如果有父节点,且父节点在数据中存在,则加入父节点的 children
map[parentId].children.push(node);
} else {
// 如果没有父节点(或父节点找不到),则视为根节点
tree.push(node);
}
});
return tree;
};
// 4. 执行转换并返回
const treeData = buildTree(allDepts);
// 可选:后期处理,例如如果是叶子节点(children为空),可以赋予特定的 leafIcon
// 或处理 disabled 状态
return treeData;
};
上述代码主要是把扁平的数据重新组织成树形目录。这样做有一个问题,我们用个人版去开发API,他默认的是预览库,但是后台写入的是生产库,导致我们的API没办法读取到数据。
为了解决这个问题,我们用API写入一些测试数据,再添加一个API用来生成数据

输入如下代码
bash
/**
* API 标识: initTestData
* 名称: 初始化测试数据
* 类型: 自定义代码
*/
module.exports = async function (params, context) {
const dataSourceName = 't_department'; // 你的表名
// 🛠️ 定义一个通用的创建函数,简化代码
const createDept = async (name, parentId = null, level = 1) => {
// 构造数据对象
const record = {
name: name,
level: level,
// ⚠️ 关键点:关联关系的写法。
// 如果有 parentId,必须写成对象形式 {_id: "..."},否则写入失败
parent_id: parentId ? { _id: parentId } : null
};
// 调用微搭新建单条数据方法
const result = await context.callModel({
dataSourceName: dataSourceName,
methodName: 'wedaCreateV2',
params: {
data: record
}
});
// 返回新创建数据的 ID,供子节点使用
return result.id || result._id; // 兼容不同版本的返回字段
};
try {
console.log("开始生成测试数据...");
// 1️⃣ 第一层:创建根节点(医院)
const rootId = await createDept("内蒙古人民医院", null, 0);
console.log("根节点创建成功 ID:", rootId);
// 2️⃣ 第二层:创建分类(职能/临床)- 挂载到根节点
const adminDeptId = await createDept("职能处室", rootId, 1);
const clinicalDeptId = await createDept("临床科室", rootId, 1);
const researchDeptId = await createDept("科研中心", rootId, 1);
// 3️⃣ 第三层:创建具体科室 - 挂载到对应的第二层节点
// --> 挂载到"职能处室"
await createDept("人事处", adminDeptId, 2);
await createDept("医务处", adminDeptId, 2);
await createDept("办公室", adminDeptId, 2);
// --> 挂载到"临床科室"
await createDept("心血管内科", clinicalDeptId, 2);
await createDept("呼吸与危重症医学科", clinicalDeptId, 2);
await createDept("骨关节科", clinicalDeptId, 2);
// --> 挂载到"科研中心"
await createDept("医学科学院", researchDeptId, 2);
return {
success: true,
message: "✅ 测试数据生成完毕!请去验证 getDepartmentTree 接口。",
rootId: rootId
};
} catch (e) {
console.error("生成失败", e);
return {
success: false,
message: "❌ 生成失败,请查看日志",
error: e.message
};
}
};
4 前端读取
我们有了后端API,主要是解决数据构造的问题,需要在前端创建一个API来读取一下数据

变量设置好之后,就可以绑定到我们的树组件上

继续创建一个变量用来保存部门的名称

当选中叶子节点,将叶子节点的信息赋值给变量

把这个变量绑定给文本,就实现了选中叶子节点,在右边显示部门名称的效果

总结
本篇我们介绍了一个稍微复杂的功能,机构树。难点在设计数据模型你就要让表进行自关联,然后用API去构造机构树,在前端绑定好数据即可。