uni-app——uni-app 小程序 操作后功能未生效问题的排查与解决
操作后功能未生效问题的排查与解决问题背景在开发审批流程功能时遇到一个常见问题审批状态的数据点击撤回后功能没有生效。具体表现为点击撤回到草稿箱按钮后操作没有生效点击彻底删除后数据没有被删除反而出现在草稿箱中问题复现操作步骤提交一条审批申请在待审批状态下点击撤回按钮期望数据回到草稿箱但实际没有生效点击彻底删除数据没有删除反而出现在草稿箱问题分析通过代码分析发现问题主要出在以下几个方面1. 操作后页面未刷新从编辑/操作页面返回列表页时列表页的onLoad生命周期不会重新触发导致数据未刷新。2. API 调用后缺少状态同步撤回和删除操作调用 API 成功后前端状态没有正确更新。3. 接口参数传递错误删除和撤回接口需要的参数格式不正确导致后端处理失败但前端显示成功。解决方案方案一添加 onShow 生命周期刷新数据问题小程序/App 中页面返回时不触发onLoad只触发onShow。script setup import { ref } from vue; import { onLoad, onShow } from dcloudio/uni-app; const listData ref([]); const isFirstLoad ref(true); const currentStatus ref(pending); // pending/draft/deleted // 加载列表数据 const loadListData async () { try { const response await getApprovalList({ status: currentStatus.value, pageNum: 1, pageSize: 20, }); listData.value response.list || []; } catch (error) { console.error(加载失败:, error); } }; // 页面首次加载 onLoad((options) { if (options.status) { currentStatus.value options.status; } loadListData(); }); // 页面显示时刷新关键修复点 onShow(() { // 跳过首次加载避免重复请求 if (isFirstLoad.value) { isFirstLoad.value false; return; } // 从其他页面返回时重新加载数据 loadListData(); }); /script方案二撤回功能的正确实现script setup import { ref } from vue; // 撤回到草稿箱 const handleWithdraw async (item) { try { // 显示确认弹窗 const confirmed await showConfirmDialog({ title: 确认撤回, content: 撤回后将移至草稿箱确定要撤回吗, }); if (!confirmed) return; // 显示加载状态 showLoading(撤回中...); // 调用撤回接口 - 注意参数格式 const result await withdrawApproval({ instanceId: item.id, reason: 用户主动撤回, }); hideLoading(); if (result.success) { showToast(撤回成功); // 方式1从列表中移除该项推荐 const index listData.value.findIndex((i) i.id item.id); if (index -1) { listData.value.splice(index, 1); } // 方式2或者重新加载列表 // await loadListData(); } else { showToast(result.message || 撤回失败); } } catch (error) { hideLoading(); showToast(操作失败请重试); console.error(撤回失败:, error); } }; /script方案三删除功能的正确实现script setup // 彻底删除 const handleDelete async (item) { try { const confirmed await showConfirmDialog({ title: 确认删除, content: 删除后将无法恢复确定要删除吗, }); if (!confirmed) return; showLoading(删除中...); // 关键确保传递正确的参数 const result await deleteApproval({ instanceId: item.id, deleteType: permanent, // 彻底删除标识 }); hideLoading(); if (result.success) { showToast(删除成功); // 从列表中移除 listData.value listData.value.filter((i) i.id ! item.id); // 如果列表为空可以显示空状态或返回上一页 if (listData.value.length 0) { showEmptyState(); } } else { // 关键正确处理失败情况 showToast(result.message || 删除失败); } } catch (error) { hideLoading(); // 不要静默失败要给用户反馈 showToast(删除失败请重试); console.error(删除失败:, error); } }; /script方案四统一的操作结果处理// utils/approval.tsinterfaceOperationResult{success:boolean;message?:string;data?:any;}// 统一的操作处理函数exportasyncfunctionhandleApprovalOperation(operationType:withdraw|delete|submit,params:{instanceId:string|number;[key:string]:any},callbacks:{onSuccess?:(data:any)void;onError?:(error:any)void;onFinally?:()void;}{}):PromiseOperationResult{constoperationMap{withdraw:{api:withdrawApproval,loadingText:撤回中...,successText:撤回成功,},delete:{api:deleteApproval,loadingText:删除中...,successText:删除成功,},submit:{api:submitApproval,loadingText:提交中...,successText:提交成功,},};constoperationoperationMap[operationType];if(!operation){return{success:false,message:未知操作类型};}try{showLoading(operation.loadingText);constresultawaitoperation.api(params);hideLoading();if(result.success||result.code200){showToast(operation.successText);callbacks.onSuccess?.(result.data);return{success:true,data:result.data};}else{consterrorMsgresult.message||操作失败;showToast(errorMsg);callbacks.onError?.(newError(errorMsg));return{success:false,message:errorMsg};}}catch(error:any){hideLoading();consterrorMsgerror.message||网络异常请重试;showToast(errorMsg);callbacks.onError?.(error);return{success:false,message:errorMsg};}finally{callbacks.onFinally?.();}}// 使用示例consthandleWithdrawasync(item){constresultawaithandleApprovalOperation(withdraw,{instanceId:item.id},{onSuccess:(){// 从列表中移除listData.valuelistData.value.filter((i)i.id!item.id);},});};方案五API 接口层的错误处理// api/approval.tsimport{http}from/utils/request;// 撤回审批exportfunctionwithdrawApproval(data:{instanceId:number|string;reason?:string}){returnhttp({url:/approval/instance/withdraw,method:POST,data:{instanceId:Number(data.instanceId),// 确保类型正确reason:data.reason||,},});}// 删除审批exportfunctiondeleteApproval(data:{instanceId:number|string;deleteType?:string}){returnhttp({url:/approval/instance/delete,method:POST,data:{instanceId:Number(data.instanceId),// 确保类型正确deleteType:data.deleteType||permanent,},});}// 请求拦截器中添加响应处理http.interceptors.response.use((response){const{code,data,message}response.data;// 统一处理业务错误码if(code!200code!0){// 不要静默处理返回错误信息returnPromise.reject({success:false,code,message:message||请求失败,data:null,});}return{success:true,code,message,data,};},(error){// 网络错误处理console.error(请求错误:,error);returnPromise.reject({success:false,code:-1,message:error.message||网络异常,data:null,});});方案六完整的列表页面示例template view classapproval-list !-- 状态标签页 -- view classtabs view v-fortab in tabs :keytab.value :class[tab-item, { active: currentStatus tab.value }] clickswitchTab(tab.value) {{ tab.label }} text v-iftab.count classcount{{ tab.count }}/text /view /view !-- 列表内容 -- scroll-view scroll-y classlist-container scrolltolowerloadMore refresher-enabled :refresher-triggeredisRefreshing refresherrefreshonRefresh view v-iflistData.length 0 view v-foritem in listData :keyitem.id classapproval-item view classitem-header text classtitle{{ item.title }}/text text :class[status, item.status]{{ getStatusText(item.status) }}/text /view view classitem-content text申请时间{{ item.createTime }}/text text申请金额¥{{ item.amount }}/text /view !-- 操作按钮 -- view classitem-actions !-- 待审批状态可撤回 -- button v-ifitem.status pending classbtn btn-withdraw clickhandleWithdraw(item) 撤回 /button !-- 草稿状态可编辑和删除 -- template v-ifitem.status draft button classbtn btn-edit clickhandleEdit(item)编辑/button button classbtn btn-delete clickhandleDelete(item)删除/button /template /view /view /view !-- 空状态 -- view v-else classempty-state image src/static/empty.png classempty-image / text暂无数据/text /view /scroll-view /view /template script setup import { ref, computed } from vue; import { onLoad, onShow } from dcloudio/uni-app; import { getApprovalList, withdrawApproval, deleteApproval } from /api/approval; const tabs [ { label: 待审批, value: pending, count: 0 }, { label: 草稿箱, value: draft, count: 0 }, { label: 已完成, value: completed, count: 0 }, ]; const currentStatus ref(pending); const listData ref([]); const isRefreshing ref(false); const isFirstLoad ref(true); const pageNum ref(1); const hasMore ref(true); // 加载列表 const loadListData async (isLoadMore false) { try { if (!isLoadMore) { pageNum.value 1; hasMore.value true; } const response await getApprovalList({ status: currentStatus.value, pageNum: pageNum.value, pageSize: 20, }); const newList response.list || []; if (isLoadMore) { listData.value [...listData.value, ...newList]; } else { listData.value newList; } hasMore.value newList.length 20; } catch (error) { console.error(加载失败:, error); uni.showToast({ title: 加载失败, icon: none }); } }; // 切换标签 const switchTab (status) { if (currentStatus.value status) return; currentStatus.value status; loadListData(); }; // 下拉刷新 const onRefresh async () { isRefreshing.value true; await loadListData(); isRefreshing.value false; }; // 加载更多 const loadMore () { if (!hasMore.value) return; pageNum.value; loadListData(true); }; // 撤回操作 const handleWithdraw async (item) { try { const [error] await uni.showModal({ title: 确认撤回, content: 撤回后将移至草稿箱确定吗, }); if (error || !error.confirm) return; uni.showLoading({ title: 撤回中... }); const result await withdrawApproval({ instanceId: item.id }); uni.hideLoading(); if (result.success) { uni.showToast({ title: 撤回成功, icon: success }); // 从当前列表移除 listData.value listData.value.filter((i) i.id ! item.id); } else { uni.showToast({ title: result.message || 撤回失败, icon: none }); } } catch (error) { uni.hideLoading(); uni.showToast({ title: 操作失败, icon: none }); } }; // 删除操作 const handleDelete async (item) { try { const [error, res] await uni.showModal({ title: 确认删除, content: 删除后无法恢复确定吗, }); if (error || !res.confirm) return; uni.showLoading({ title: 删除中... }); const result await deleteApproval({ instanceId: item.id, deleteType: permanent, }); uni.hideLoading(); if (result.success) { uni.showToast({ title: 删除成功, icon: success }); listData.value listData.value.filter((i) i.id ! item.id); } else { uni.showToast({ title: result.message || 删除失败, icon: none }); } } catch (error) { uni.hideLoading(); uni.showToast({ title: 操作失败, icon: none }); } }; // 编辑 const handleEdit (item) { uni.navigateTo({ url: /pages/approval/edit?id${item.id}, }); }; // 获取状态文本 const getStatusText (status) { const map { pending: 待审批, draft: 草稿, completed: 已完成, rejected: 已驳回, }; return map[status] || status; }; // 生命周期 onLoad(() { loadListData(); }); // 关键页面显示时刷新数据 onShow(() { if (isFirstLoad.value) { isFirstLoad.value false; return; } // 从编辑页返回时刷新 loadListData(); }); /script style langscss scoped .approval-list { min-height: 100vh; background: #f5f5f5; } .tabs { display: flex; background: #fff; padding: 20rpx; gap: 20rpx; .tab-item { flex: 1; text-align: center; padding: 16rpx; border-radius: 8rpx; background: #f0f0f0; font-size: 28rpx; .active { background: #1890ff; color: #fff; } .count { margin-left: 8rpx; font-size: 24rpx; } } } .approval-item { background: #fff; margin: 20rpx; padding: 24rpx; border-radius: 12rpx; .item-header { display: flex; justify-content: space-between; margin-bottom: 16rpx; .title { font-size: 32rpx; font-weight: 500; } .status { font-size: 24rpx; padding: 4rpx 12rpx; border-radius: 4rpx; .pending { background: #fff7e6; color: #fa8c16; } .draft { background: #f0f0f0; color: #666; } } } .item-actions { display: flex; gap: 16rpx; margin-top: 20rpx; padding-top: 20rpx; border-top: 1rpx solid #eee; .btn { flex: 1; font-size: 28rpx; padding: 16rpx; border-radius: 8rpx; border: none; .btn-withdraw { background: #fff7e6; color: #fa8c16; } .btn-edit { background: #e6f7ff; color: #1890ff; } .btn-delete { background: #fff1f0; color: #ff4d4f; } } } } .empty-state { display: flex; flex-direction: column; align-items: center; padding: 100rpx; color: #999; } /style最佳实践总结1. 操作后必须更新前端状态API 调用成功后及时更新本地列表数据不要依赖页面刷新主动移除或修改列表项2. 正确处理页面生命周期小程序/App 使用onShow而非仅onLoad避免首次加载重复请求3. 完善的错误处理API 失败时给用户明确反馈不要静默失败4. 参数类型检查确保instanceId等参数类型正确后端可能要求数字类型前端传字符串会导致失败5. 用户体验优化操作前显示确认弹窗操作中显示 loading操作后显示结果提示关键词审批撤回、删除功能、状态同步、页面刷新、onShow生命周期适用场景审批流程、工单系统、任务管理等需要状态操作的业务场景

相关新闻

YOLO26涨点改进 | 独家创新,卷积改进篇 | TGRS 2025 | 引入RFEM感受野增强模块,增强特征的全局结构和上下文表达能力,含多种创新改进,助力恶劣天气条件目标检测任务有效涨点

YOLO26涨点改进 | 独家创新,卷积改进篇 | TGRS 2025 | 引入RFEM感受野增强模块,增强特征的全局结构和上下文表达能力,含多种创新改进,助力恶劣天气条件目标检测任务有效涨点

一、本文介绍 🔥本文给大家介绍利用 RFEM 感受野增强模块 改进 YOLO26网络模型,可通过扩展感受野和多尺度上下文建模增强网络对目标整体结构的感知能力,使模型在复杂背景或退化场景下更稳定地捕获目标轮廓信息。RFEM 在不显著增加计算开销的前提下抑制局部噪声干扰,提升…

2026/7/3 12:45:22 阅读更多 →
常用算法(下)---拷贝、替换、算术生成、集合算法

常用算法(下)---拷贝、替换、算术生成、集合算法

常用算法&#xff08;下&#xff09; 一、常用拷贝和替换算法 1.copy 容器内指定范围内的元素拷贝到另一容器中。函数原型&#xff1a; copy(iterator beg,iterator end,iterator dest);使用示例&#xff1a; void print01(int val) {cout << val << " "…

2026/6/29 19:30:44 阅读更多 →
2月3日面试题整理 字节跳动后端开发相关

2月3日面试题整理 字节跳动后端开发相关

介绍一下什么是索引?拿书举例&#xff0c;索引相当于目录计算机科学方面&#xff0c;类比可以得出索引是帮助 mysql 高效获取数据的数据结构mysql 的 InnoDB 存储引擎主要使用的是 B树 数据结构作为索引构建出属于表的索引书&#xff0c;走索引查询&#xff0c;可以减少磁盘 I…

2026/7/3 3:13:44 阅读更多 →

最新新闻

TPS65263三重输出降压转换器在STM32嵌入式系统中的应用

TPS65263三重输出降压转换器在STM32嵌入式系统中的应用

1. 项目背景与核心需求在嵌入式系统设计中&#xff0c;电源管理模块往往是最容易被忽视却又至关重要的部分。当系统需要为处理器核心、外设接口和传感器网络提供多种电压时&#xff0c;传统的分立式LDO方案会面临效率低下、PCB空间占用大和热管理困难等问题。TPS65263这款三重输…

2026/7/3 13:14:21 阅读更多 →
4-20mA电流环与INA196在工业自动化中的应用

4-20mA电流环与INA196在工业自动化中的应用

1. 4-20mA电流环基础与行业应用场景 工业现场最头疼的问题莫过于信号在长距离传输中的衰减和干扰。4-20mA电流环之所以成为工业自动化领域的黄金标准&#xff0c;核心在于电流信号对线路电阻变化不敏感的特性。与电压信号不同&#xff0c;电流信号在传输过程中不会因线路阻抗导…

2026/7/3 13:12:20 阅读更多 →
STM32与LV30构建高性能嵌入式条码识别系统

STM32与LV30构建高性能嵌入式条码识别系统

1. 项目背景与核心需求在工业自动化、零售仓储和物流管理领域&#xff0c;条码识别技术扮演着至关重要的角色。传统激光扫描器在面对破损、污损或低对比度条码时往往力不从心&#xff0c;而基于图像的读码技术则展现出明显优势。LV30作为一款高性能图像式条码扫描器&#xff0c…

2026/7/3 13:12:20 阅读更多 →
柔性供应链架构设计:应对多批次小订单生产的管理逻辑与技术演进

柔性供应链架构设计:应对多批次小订单生产的管理逻辑与技术演进

随着消费需求向个性化与多元化转型&#xff0c;“多批次、小订单”已成为服装行业的主流生产模式。根据中国服装协会2025年发布的报告&#xff0c;约72%的服装企业正面临此类模式带来的效率下降与成本上升等挑战。如何在保证柔性交付的同时优化运营成本&#xff0c;已成为行业数…

2026/7/3 13:07:58 阅读更多 →
不会逆向工程怎么玩转网安?全方位讲解漏洞挖掘与攻防实战技巧

不会逆向工程怎么玩转网安?全方位讲解漏洞挖掘与攻防实战技巧

第一部分&#xff1a;什么是网络安全的逆向工程&#xff1f; 简单来说&#xff0c;逆向工程 就像一个“黑盒拆解师”。在常规的软件开发&#xff08;正向工程&#xff09;中&#xff0c;你是从蓝图&#xff08;源代码&#xff09;开始&#xff0c;最终建成一座大楼&#xff08…

2026/7/3 13:07:58 阅读更多 →
计算机毕业设计之 基于大语言模型的课程答疑系统的设计与实现

计算机毕业设计之 基于大语言模型的课程答疑系统的设计与实现

在当今数字化教育蓬勃发展的时代&#xff0c;课程学习方式日益多元化&#xff0c;但学生在学习过程中遇到疑问时&#xff0c;往往难以得到及时且精准的解答。传统的答疑模式&#xff0c;如课堂集中答疑、课后教师单独辅导等&#xff0c;存在时间和空间上的局限性&#xff0c;无…

2026/7/3 13:05:58 阅读更多 →

日新闻

Nginx防御TLS重协商攻击实战:从原理到配置与监控

Nginx防御TLS重协商攻击实战:从原理到配置与监控

1. 项目概述&#xff1a;为什么TLS重协商攻击至今仍需警惕十多年前的CVE-2011-1473&#xff0c;一个关于TLS/SSL协议重协商机制的漏洞&#xff0c;现在提起来还有必要吗&#xff1f;很多运维和开发朋友可能会觉得&#xff0c;这都老掉牙了&#xff0c;现代服务器和客户端不都默…

2026/7/3 0:03:59 阅读更多 →
华为防火墙双通道远程管理实战:Web与SSH配置详解

华为防火墙双通道远程管理实战:Web与SSH配置详解

1. 项目概述&#xff1a;为什么需要双通道远程管理防火墙&#xff1f;在任何一个稍具规模的企业网络里&#xff0c;防火墙都是那个默默守护在边界的关键角色。作为网络工程师&#xff0c;我们不可能每次都跑到机房&#xff0c;插上console线去配置它。远程管理能力&#xff0c;…

2026/7/3 0:03:59 阅读更多 →
AD74413R与PIC18F65K40的高精度工业数据采集方案

AD74413R与PIC18F65K40的高精度工业数据采集方案

1. 项目概述&#xff1a;AD74413R与PIC18F65K40的协同工作在工业自动化和精密测量领域&#xff0c;同时实现高精度模数转换(ADC)和数模转换(DAC)功能是许多复杂系统的核心需求。AD74413R作为一款四通道可配置模拟输入/输出器件&#xff0c;与PIC18F65K40微控制器的组合&#xf…

2026/7/3 0:05:59 阅读更多 →

周新闻

月新闻