家校通小程序实战教程10部门管理前后端连接

目录

  • 1 加载后端的数据
  • 2 为什么不直接给变量赋值
  • 3 保存部门信息
  • 4 最终的效果
  • 5 总结

现在部门管理已经完成了后端功能和前端开发,就需要在前端调用后端的数据完成界面的展示,而且在录入部门信息后需要提交到数据库里,本篇我们介绍一下前后端如何交互。

1 加载后端的数据

现在后端API已经有了,页面加载的时候需要从后端读取数据。打开应用,点击编辑JSX代码

在这里插入图片描述
输入如下代码

export default function DepartmentTree(props: JSXCompProps) {const { $w, contentSlot1, style } = props;const { Modal, Input, Tree, Button, Form } = antd;const [treeData, setTreeData] = React.useState([]);const [selectedNode, setSelectedNode] = React.useState(null);const [addChildModalVisible, setAddChildModalVisible] = React.useState(false);const [newDepartmentName, setNewDepartmentName] = React.useState("");const [contextMenuTargetId, setContextMenuTargetId] = React.useState(null);const [contextMenuPosition, setContextMenuPosition] = React.useState(null);const [form] = Form.useForm();// 初始化获取部门数据React.useEffect(() => {async function fetchDepartments() {try {const result = await $w.cloud.callDataSource({dataSourceName: "departmentManagement_adpurdw",methodName: "getAllDepartments",params: {}});if (result && result.data) {setTreeData(result.data);} else {Modal.warning({ title: "数据加载失败", content: "未获取到部门数据。" });}} catch (error) {console.error("Error fetching departments:", error);Modal.error({ title: "加载失败", content: "获取部门数据时出错,请稍后重试。" });}}fetchDepartments();}, [$w]);// 点击节点事件const handleNodeClick = (node) => {setSelectedNode(node);setContextMenuTargetId(null);form.setFieldsValue({ name: node.name });};// 切换节点展开/收起const toggleNode = (node) => {node.isOpen = !node.isOpen;setTreeData([...treeData]);};// 递归更新树节点const updateTree = (nodes, callback) => {return nodes.map((node) => {if (callback(node)) {return { ...node };}if (node.children) {return { ...node, children: updateTree(node.children, callback) };}return node;});};// 添加子部门逻辑const handleAddChild = () => {if (!newDepartmentName.trim()) {return Modal.warning({title: "部门名称不能为空",content: "请输入部门名称后重试。"});}const newChild = {id: Date.now(),name: newDepartmentName,parentId: contextMenuTargetId,children: [],isOpen: false};setTreeData((prevTreeData) =>updateTree(prevTreeData, (node) => {if (node.id === contextMenuTargetId) {node.children = [...(node.children || []), newChild];return true;}return false;}));setAddChildModalVisible(false);setNewDepartmentName("");};// 保存表单修改const handleSaveForm = () => {form.validateFields().then((values) => {setTreeData((prevTreeData) =>updateTree(prevTreeData, (node) => {if (node.id === selectedNode.id) {node.name = values.name;return true;}return false;}));Modal.success({ title: "保存成功", content: "部门信息已更新。" });}).catch((info) => console.error("Validate Failed:", info));};// 右键点击事件const handleRightClick = (e, node) => {e.preventDefault();setContextMenuTargetId(node.id);setContextMenuPosition({ x: e.clientX, y: e.clientY });};// 渲染树节点const renderTree = (nodes) =>nodes.map((node) => (<Tree.TreeNodekey={node.id}title={<spanonClick={() => handleNodeClick(node)}onContextMenu={(e) => handleRightClick(e, node)}>{node.name}</span>}>{node.children && renderTree(node.children)}</Tree.TreeNode>));return (<div style={{ display: "flex", ...style }}>{/* 左侧树 */}<divstyle={{flex: "1",borderRight: "1px solid #ddd",overflowY: "auto",padding: "10px",minHeight: "300px"}}><Tree showLine defaultExpandAll>{renderTree(treeData)}</Tree></div>{/* 右侧表单 */}<divstyle={{flex: "2",padding: "10px",minHeight: "300px"}}>{selectedNode ? (<Form form={form} layout="vertical"><h3>部门信息</h3><Form.Itemlabel="部门名称"name="name"rules={[{ required: true, message: "请输入部门名称" }]}><Input /></Form.Item><Form.Item label="部门编号"><Input value={selectedNode.id} disabled /></Form.Item><div style={{ marginTop: "10px" }}><Buttontype="primary"onClick={handleSaveForm}style={{ marginRight: "10px" }}>保存</Button><Button onClick={() => form.resetFields()}>取消</Button></div></Form>) : (<p>请选择左侧树节点以查看或编辑部门信息。</p>)}</div>{/* 添加子部门 Modal */}<Modaltitle="添加子部门"visible={addChildModalVisible}onOk={handleAddChild}onCancel={() => setAddChildModalVisible(false)}><Inputplaceholder="请输入部门名称"value={newDepartmentName}onChange={(e) => setNewDepartmentName(e.target.value)}/></Modal>{/* 右键菜单 */}{contextMenuPosition && (<divstyle={{position: "absolute",top: contextMenuPosition.y,left: contextMenuPosition.x,backgroundColor: "#fff",boxShadow: "0 2px 8px rgba(0,0,0,0.15)",borderRadius: "4px",zIndex: 1000}}onMouseLeave={() => setContextMenuPosition(null)}><divonClick={() => setAddChildModalVisible(true)}style={{padding: "8px 16px",cursor: "pointer",borderBottom: "1px solid #f0f0f0"}}>添加子部门</div></div>)}{/* 插槽 */}<div>{contentSlot1}</div></div>);
}

我们追加了一个代码,主要是要异步调用后端API的

  // 初始化获取部门数据React.useEffect(() => {async function fetchDepartments() {try {const result = await $w.cloud.callDataSource({dataSourceName: "departmentManagement_adpurdw",methodName: "getAllDepartments",params: {}});if (result && result.data) {setTreeData(result.data);} else {Modal.warning({ title: "数据加载失败", content: "未获取到部门数据。" });}} catch (error) {console.error("Error fetching departments:", error);Modal.error({ title: "加载失败", content: "获取部门数据时出错,请稍后重试。" });}}fetchDepartments();}, [$w]);

这里的dataSourceName和methodName是从我们的API里获取的
在这里插入图片描述
部门管理旁边的相当于我们的dataSourceName,而标识相当于我们的methodName

2 为什么不直接给变量赋值

我一开始认为,我直接获取数据就可以,比如这样

const treeData = $w.cloud.callDataSource({dataSourceName: "departmentManagement_adpurdw",methodName: "getAllDepartments",params: {}
});

但这种操作发现树是空的,并没有从后台读取数据过来。主要的原因是两方面,首先callDataSource是异步的,你这个执行完了数据其实是没返回的

两一方面,数据加载完毕并不会通知React重新渲染组件。改成useEffect的好处是,在组件首次渲染后启动数据加载任务。当数据加载完成后,通过 setTreeData 更新组件状态,React 会自动重新渲染组件并展示新数据。

尤其如果部门比较多的情况下,界面可以先出来,等数据获取完毕组装好了再次渲染树形组件,这种体验就比较好了

3 保存部门信息

数据我们现在已经可以从变量中读取了,剩下就是添加的时候将新增的部门信息保存到数据源里。这里我们调用微搭的写入方法,修改如下代码

// 添加子部门逻辑const handleAddChild = () => {if (!newDepartmentName.trim()) {return Modal.warning({title: "部门名称不能为空",content: "请输入部门名称后重试。",});}// 调用数据源写入新部门$w.cloud.callDataSource({dataSourceName: "bmb", // 数据源名称methodName: "wedaCreateV2", // 假设存在 createDepartment 方法params: {data: {bmmc: newDepartmentName, // 部门名称fbm: { _id: contextMenuTargetId }, // 父部门ID},},}).then((response) => {const newId = response?.id; // 从响应中获取新节点的 IDif (!newId) {throw new Error("数据源未返回有效ID");}const newChild = {id: newId, // 使用后端返回的 IDname: newDepartmentName,parentId: contextMenuTargetId,children: [],isOpen: false,};// 更新前端树数据setTreeData((prevTreeData) =>updateTree(prevTreeData, (node) => {if (node.id === contextMenuTargetId) {node.children = [...(node.children || []), newChild];return true;}return false;}));// 关闭模态框并清空输入setAddChildModalVisible(false);setNewDepartmentName("");Modal.success({title: "添加成功",content: `子部门 "${newDepartmentName}" 已成功添加。`,});}).catch((error) => {console.error("数据源写入失败", error);Modal.error({title: "操作失败",content: "添加子部门时出现错误,请稍后重试。",});});};

需要把上边给的完整代码的handleAddChild 进行替换,这里主要是调用了微搭的创建单条的API。在创建的时候需要传递对应的数据,因为我们的父部门是关联关系,新版的关联关系是对象类型,所以我们是按照对象的结构组织了数据。

4 最终的效果

现在已经可以从数据库里读取部门的信息,并且按照树形的结构进行展示
在这里插入图片描述
点击右键的时候可以添加部门,数据库里可以看到写入的数据
在这里插入图片描述

5 总结

我们本篇介绍了如何将前后端的功能连接起来,从代码上来讲还是比较复杂的,主要需要考虑react组件加载的机制,副作用的理解,以及微搭的异步加载机制。要想理解好这些概念需要你亲自做一遍,才会有深入的体会。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/63066.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java并发编程学习(二)

线程的状态 有说5种的&#xff0c;有说6种的 5种的&#xff0c;从操作系统层面来讲 初始状态&#xff1a;也就是语言层面创建了线程对象&#xff0c;还未与操作系统线程关联。Java中也就是new了一个线程&#xff0c;还未调用。可运行状态&#xff1a;&#xff08;就绪状态&a…

Docker方式安装人人影视离线完整安装包

本文软件由网友 ルリデ 推荐&#xff1b; 上周&#xff0c;人人影视创始人宣布将人人影视二十年字幕数据开源分享 目前提供了两种使用方式&#xff1a; “在线应用” &#xff1a;意味着需要有互联网才可以使用。官方提供了网站&#xff1a;https://yyets.click “离线使用” …

SpringBoot 学习

SpringBoot 学习 什么是 Springboot Spring Boot 是 Spring 提供的一个子项目&#xff0c;用于快速构建 Spring 应用程序 传统的问题&#xff1a; 导入依赖繁琐项目配置繁琐 SpringBoot 的特性 起步依赖&#xff1a;整合所有 web 的依赖配置好了自动配置&#xff1a;bean…

最新全开源IM即时通讯系统源码(PC+WEB+IOS+Android)部署指南

全开源IM&#xff08;即时通讯&#xff09;系统源码部署是一个复杂但系统的过程&#xff0c;涉及多个组件和步骤。以下是一个详细的部署指南&#xff0c;旨在帮助开发者或系统管理员成功部署一个全开源的IM系统&#xff0c;如OpenIM。      IM即时通讯系统源码准备工作   …

CAD c# 生成略缩图预览

代码如下&#xff1a; using (Transaction tr currentdb.TransactionManager.StartTransaction()){//当前数据库开启事务using (Database tempdb new Database(false, true)) //创建临时数据库(两个参数&#xff1a;是否创建符号表&#xff0c;不与当前文档关联){try{Bitmap …

[面试题]--索引用了什么数据结构?有什么特点?

答&#xff1a;使用了B树&#xff1a; 时间复杂度&#xff1a;O(logN),可以有效控制树高 B树特点&#xff1a; 1.叶子节点之间有相互链接的作用&#xff0c;会指向下一个相近的兄弟节点。 MySQL在组织叶子节点使用的是双向链表 2.非叶子节点的值都保存在叶子节点当中 MySQL非叶…

ansible自动化运维(五)roles角色管理

Roles角色管理 角色&#xff08;roles&#xff09;是ansible自1.2版本开始引入的新特性&#xff0c;用于层次性&#xff0c;结构化地组织playbook。 roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单的…

操作系统:文件系统

目录 1、文件 概念&#xff1a; UNIX文件分类&#xff1a; 2、文件系统 3、文件的访问方式 顺序访问 随机访问 4、文件的组织 逻辑组织 物理组织 5、倒排结构&#xff08;了解&#xff09; 5、文件目录 文件控制块&#xff08;FCB&#xff09; ​编辑 目录项 单…

单元测试-FATAL ERROR in native method: processing of -javaagent failed

文章目录 前言单元测试-FATAL ERROR in native method: processing of -javaagent failed1. 报错信息2. 解决方案 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天的运…

决策曲线分析(DCA)中平均净收益用于评价模型算法(R自定义函数)

决策曲线分析&#xff08;DCA&#xff09;中平均净收益用于评价模型算法 DCA分析虽然不强调用来评价模型算法或者变量组合的优劣&#xff0c;但是实际应用过程中感觉DCA曲线的走势和模型的效能具有良好的一致性&#xff0c;其实这种一致性也可以找到内在的联系&#xff0c;比如…

在Ubuntu服务器上备份文件到自己的百度网盘

文章目录 概述安装bypy同步文件定时任务脚本 概述 之前自购了一台阿里云服务器&#xff0c;系统镜像为Ubuntu 22.04&#xff0c; 并且搭建了LNMP开发环境&#xff08;可以参考&#xff1a;《Ubuntu搭建PHP开发环境操作步骤(保姆级教程)》&#xff09;。由于项目运行中会产生附…

safe area helper插件

概述 显示不同机型的必能显示的区域 实现步骤 引入safearea&#xff0c;引入其中的safearea的csharp 为cancas加入gameobject gameobject中加入safearea脚本 将UI作为这个gameobject的子物体&#xff0c;就可以完成显示

Unity 获取鼠标点击位置物体贴图颜色

实现 Ray ray Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out RaycastHit hit)) {textureCoord hit.textureCoord;textureCoord.x * textureMat.width;textureCoord.y * textureMat.height;textureColor textureMat.GetPixel(Mathf.Flo…

基于深度学习的猫狗识别系统【深度学习课设】

&#x1f3c6; 作者简介&#xff1a;席万里 ⚡ 个人网站&#xff1a;https://dahua.bloggo.chat/ ✍️ 一名后端开发小趴菜&#xff0c;同时略懂Vue与React前端技术&#xff0c;也了解一点微信小程序开发。 &#x1f37b; 对计算机充满兴趣&#xff0c;愿意并且希望学习更多的技…

05、GC基础知识

JVM程序在跑起来之后&#xff0c;在数据的交互过程中&#xff0c;就会有一些数据是过期不用的&#xff0c;这些数据可以看做是垃圾&#xff0c;JVM中&#xff0c;这些垃圾是不用开发者管的&#xff0c;它自己会有一套垃圾回收系统自动回收这些内存垃圾&#xff0c;以备后面继续…

2024.12.15 TCP/IP 网络模型有哪几层?(二)

2024.12.15 TCP/IP 网络模型有哪几层?&#xff08;二&#xff09; 上节课我们学习了网络模型有四部分构成&#xff0c;有应用层、传输层、网络层、网络接口层。 生成了 IP 头部之后&#xff0c;接下来要交给网络接口层(Link Layer)在 IP 头部的前面加上 MAC 头部&#xff0c…

51c深度学习~合集9

我自己的原文哦~ https://blog.51cto.com/whaosoft/12750420 #傅里叶特征 (Fourier Feature&#xff09;与核回归 位置编码背后的理论解释 本文探讨了位置编码背后的理论基础&#xff0c;特别是傅里叶特征&#xff08;Fourier Feature&#xff09;与核回归&#xff08;Kern…

Flutter Navigator2.0的原理和Web端实践

01 背景与动机 在Navigator 2.0推出之前&#xff0c;Flutter主要通过Navigator 1.0和其提供的 API&#xff08;如push(), pop(), pushNamed()等&#xff09;来管理页面路由。然而&#xff0c;Navigator 1.0存在一些局限性&#xff0c;如难以实现复杂的页面操作&#xff08;如移…

数据冒险、控制冒险、结构冒险

计算机组成原理 数据冒险、控制冒险、结构冒险 对所有用户&#xff08;所有程序员&#xff09;可见&#xff1a;PSW、PC、通用寄存器 PSW&#xff08;条件转移需要用到&#xff0c;程序员使用CMP指令的时候也需要用到所以是对用户可见&#xff09;PC&#xff08;跳转指令需要…

基于32单片机的RS485综合土壤传感器检测土壤PH、氮磷钾的使用(超详细)

1-3为RS485综合土壤传感器的基本内容 4-5为基于STM32F103C8T6单片机使用RS485传感器检测土壤PH、氮磷钾并显示在OLED显示屏的相关配置内容 注意&#xff1a;本篇文件讲解使用的是PH、氮磷钾四合一RS485综合土壤传感器&#xff0c;但里面的讲解内容适配市面上的所有多合一的RS…