活动介绍
file-type

使用JavaScript ShowLoading防止数据保存时被篡改

ZIP文件

下载需积分: 14 | 8KB | 更新于2025-01-28 | 45 浏览量 | 1 下载量 举报 收藏
download 立即下载
在Web开发中,尤其是在使用JavaScript进行前端开发时,确保用户在数据保存过程中不进行其他操作,从而保持数据一致性是非常重要的。这一点在进行表单提交或者数据持久化时尤其明显。本文将详细介绍如何使用JavaScript实现一个ShowLoading功能,以防止用户在数据保存过程中修改数据。 首先,我们需要理解ShowLoading的基本概念。ShowLoading通常是一个模态对话框,它会在数据保存的期间显示出来,提示用户当前系统正在处理数据保存操作,从而阻止用户进行其他可能干扰数据完整性的操作。用户必须等待模态对话框消失后,才能继续进行其他操作。 在实现ShowLoading功能之前,我们首先需要了解JavaScript的基本语法和DOM操作。JavaScript是一种高级的、解释型的编程语言,它能够实现网页的动态效果和用户交互。DOM(文档对象模型)则是浏览器用于表示文档的一种结构化API,通过JavaScript可以访问和修改网页的结构、样式和内容。 现在我们可以着手实现ShowLoading功能。主要步骤包括创建一个显示加载状态的遮罩层、监听数据保存操作的事件,并在数据保存期间展示加载遮罩层,以及数据保存完成后隐藏该遮罩层。 具体实现方法如下: 1. 创建遮罩层HTML结构: ```html <!-- 在HTML中添加一个用于显示加载状态的遮罩层 --> <div id="loadingMask" class="loading-mask" style="display:none;"> <div class="loading-content"> <span class="spinner"></span> <span>数据正在保存...</span> </div> </div> ``` 2. 创建加载遮罩层的CSS样式: ```css /* CSS样式定义遮罩层的外观 */ .loading-mask { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.7); display: flex; justify-content: center; align-items: center; z-index: 9999; } .loading-content { background: #fff; padding: 20px; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); } .spinner { width: 20px; height: 20px; border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } ``` 3. 使用JavaScript控制遮罩层的显示与隐藏: ```javascript // JavaScript函数用于显示和隐藏加载遮罩层 function showLoading() { document.getElementById('loadingMask').style.display = 'flex'; } function hideLoading() { document.getElementById('loadingMask').style.display = 'none'; } // 假设有一个函数用于处理数据保存 function saveData() { // 显示加载遮罩层 showLoading(); // 执行数据保存操作,此处为示例 setTimeout(function() { // 数据保存成功后,隐藏遮罩层 hideLoading(); }, 3000); // 假设数据保存需要3秒钟 } // 可以在需要触发数据保存操作的地方调用saveData函数 ``` 在上述代码中,我们首先创建了一个带有遮罩层样式的HTML结构,并通过CSS定义了它的视觉样式。然后,我们定义了JavaScript函数`showLoading`和`hideLoading`来控制遮罩层的显示和隐藏。在数据保存的函数`saveData`中,我们在开始保存数据前调用`showLoading`函数,然后使用`setTimeout`模拟异步操作(例如,调用后端API保存数据),并在数据保存完成后的回调函数中调用`hideLoading`函数以关闭遮罩层。 此外,由于在HTML文件列表中提到了“showLoading”,这可能意味着该JavaScript功能的源代码文件名是“showLoading.js”。在实际的项目中,我们通常会将JavaScript代码抽离到单独的文件中,以提高代码的可维护性和可复用性。 综上所述,通过本文的介绍,我们了解到ShowLoading功能在Web应用中防止数据在保存过程中被用户修改的重要性,并学习到了如何使用JavaScript、HTML和CSS实现这一功能。通过合理的用户界面反馈,我们可以提升用户体验,并保证Web应用数据操作的准确性和一致性。

相关推荐

filetype

// app.js const MiniProgramDataManager = require('./data/MiniProgramDataManager'); App({ onLaunch: function () { // 展示本地存储能力 var logs = wx.getStorageSync('logs') || [] logs.unshift(Date.now()) wx.setStorageSync('logs', logs) // 初始化数据管理器 this.initDataManager(); // 登录 wx.login({ success: res => { // 发送 res.code 到后台换取 openId, sessionKey, unionId } }) // 获取用户信息 wx.getSetting({ success: res => { if (res.authSetting['scope.userInfo']) { // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 wx.getUserInfo({ success: res => { // 可以将 res 发送给后台解码出 unionId this.globalData.userInfo = res.userInfo // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 // 所以此处加入 callback 以防止这种情况 if (this.userInfoReadyCallback) { this.userInfoReadyCallback(res) } } }) } } }) }, // 初始化数据管理器 initDataManager: function() { // 创建数据管理器实例 const baseUrl = 'http://192.168.1.11:8080'; // 实际API地址 this.globalData.dataManager = new MiniProgramDataManager(baseUrl); // 初始化数据管理器 this.globalData.dataManager.initialize().catch(error => { console.error('数据管理器初始化失败:', error); wx.showToast({ title: '数据加载失败,请重试', icon: 'none', duration: 2000 }); }); }, // 检查微信登录状态 checkWechatLogin: function() { // 检查本地存储中是否有userId const userId = wx.getStorageSync('userId'); if (userId) { console.log('用户已登录,userId:', userId); this.globalData.needLogin = false; } else { console.log('用户未登录'); this.globalData.needLogin = true; } return !this.globalData.needLogin; }, // 添加登录方法,保存用户信息 login: function(userInfo) { // 保存用户信息到全局数据 this.globalData.userInfo = userInfo; this.globalData.needLogin = false; // 保存用户ID到本地存储 wx.setStorageSync('userId', userInfo.id); wx.setStorageSync('role', userInfo.role); wx.setStorageSync('name', userInfo.name); // 保存登录状态到本地存储 wx.setStorageSync('loginInfo', { isLoggedIn: true, userInfo: userInfo }); }, // 添加微信登录方法 wechatLogin: function() { return new Promise((resolve, reject) => { wx.login({ success: res => { if (res.code) { // 发送code到后台获取用户信息 wx.request({ url: this.globalData.baseUrl + '/users/wechat-login', method: 'POST', data: { code: res.code }, success: loginRes => { if (loginRes.data.status === 200) { // 登录成功 const userInfo = loginRes.data.data; this.login(userInfo); resolve(userInfo); } else if (loginRes.data.status === 404) { // 用户不存在,需要注册 resolve({ openid: loginRes.data.openid, needRegister: true }); } else { // 其他错误 reject(loginRes.data.text || '微信登录失败'); } }, fail: err => { reject('网络错误,请稍后重试'); } }); } else { reject('获取微信授权失败'); } }, fail: err => { reject('微信登录失败'); } }); }); }, // 显示登录选择弹窗 showLoginModal: function(callback) { wx.showModal({ title: '应用名称', content: '请选择登录方式', confirmText: '微信登录', cancelText: '账号登录', success: res => { if (res.confirm) { // 用户点击了微信登录 wx.showLoading({ title: '登录中...', }); this.wechatLogin() .then(result => { wx.hideLoading(); if (result.needRegister) { // 需要注册,跳转到注册页面并传递openid wx.navigateTo({ url: `/pages/register/register?openid=${result.openid}` }); } else { // 登录成功,执行回调 if (typeof callback === 'function') { callback(true); } } }) .catch(error => { wx.hideLoading(); wx.showToast({ title: error, icon: 'none', duration: 2000 }); }); } else { // 用户点击了账号登录 wx.navigateTo({ url: '/pages/login/login' }); } } }); }, // 检查登录状态,如果未登录则显示登录选择弹窗 checkLoginStatus: function(pageObj) { if (!this.checkWechatLogin()) { console.log('未登录,显示登录选择弹窗'); this.showLoginModal(() => { // 登录成功后的回调,可以刷新页面或执行其他操作 if (pageObj && typeof pageObj.onLoad === 'function') { pageObj.onLoad(pageObj.options); } }); return false; } return true; }, globalData: { userInfo: null, dataManager: null, needLogin: true, baseUrl: 'http://192.168.1.11:8080' } })在全局app中注册

filetype

// pages/kucunguanli/kucunguanli.js const app = getApp(); Page({ data: { bancai: null, // 当前板材 kucun: null, // 当前库存 unassignedList: [], // 未分配的dingdan_bancai assignedList: [], // 已分配的dingdan_bancai modifiedItems: new Map(), // 修改过的记录 stockInput: 0, // 库存输入 noteInput: '', // 备注 showEditModal: false, // 编辑模态框 unassignedTotal: 0, // 未分配库存总量 assignedTotal: 0 // 已分配库存总量 }, onLoad: function(options) { const bancaiId = parseInt(options.id, 10); // 转换为数字 this.loadData(bancaiId); }, onShow: function() { // 检查登录状态,如果未登录则显示登录选择弹窗 if (!app.checkLoginStatus(this)) { return; } // 已登录,继续执行页面逻辑 }, // 加载数据 // 修改后的 loadData 函数 loadData: function(bancaiId) { const dataManager = app.globalData.dataManager; // 加载板材和库存数据 const bancai = dataManager.data.bancais.find(b => b.id === bancaiId); const kucun = dataManager.data.kucuns.find(k => k.bancai && k.bancai.id === bancaiId); // 加载dingdan_bancai数据 const allDingdanBancai = dataManager.data.dingdan_bancais.filter(db => db.bancai && db.bancai.id === bancaiId ); // 分离未分配和已分配记录 const unassignedList = allDingdanBancai.filter(db => !db.dingdan); const assignedList = allDingdanBancai.filter(db => db.dingdan); // 计算总量 const unassignedTotal = unassignedList.reduce((sum, item) => sum + (item.shuliang || 0), 0); const assignedTotal = assignedList.reduce((sum, item) => sum + (item.shuliang || 0), 0); this.setData({ bancai: bancai, kucun: kucun, unassignedList: unassignedList, // 保留数据但不显示 assignedList: assignedList, unassignedTotal: unassignedTotal, assignedTotal: assignedTotal, stockInput: kucun ? kucun.shuliang : 0 }); }, // 打开编辑模态框 onEditStock: function() { this.setData({ showEditModal: true, noteInput: '' }); }, // 保存库存编辑 saveStock: function() { const { bancai, kucun, stockInput, noteInput } = this.data; const dataManager = app.globalData.dataManager; const newStock = parseInt(stockInput) || 0; if (!kucun) { wx.showToast({ title: '库存记录不存在', icon: 'none' }); return; } const oldStock = kucun.shuliang; const changeAmount = newStock - oldStock; if (changeAmount === 0) { wx.showToast({ title: '库存未变化', icon: 'none' }); this.setData({ showEditModal: false }); return; } // 使用事务API更新库存 dataManager.Transaction.updateStock({ kucunId: kucun.id, shuliang: newStock, text: noteInput||"", userId: wx.getStorageSync("userId") }) .then(() => { this.setData({ showEditModal: false }); wx.showToast({ title: '库存更新成功', icon: 'success' }); this.loadData(bancai.id); // 重新加载数据 }) .catch(error => { console.error('库存更新失败:', error); wx.showToast({ title: error.message || '库存更新失败', icon: 'none' }); }); }, // 处理数量输入 onQuantityInput: function(e) { const { id } = e.currentTarget.dataset; const value = parseInt(e.detail.value) || 0; const { assignedList, modifiedItems } = this.data; // 更新本地数据 const updatedList = assignedList.map(item => { if (item.id === id) { return { ...item, shuliang: value }; } return item; }); // 记录修改 modifiedItems.set(id, value); // 重新计算总量 const assignedTotal = updatedList.reduce((sum, item) => sum + (item.shuliang || 0), 0); const unassignedTotal = (this.data.kucun?.shuliang || 0) - assignedTotal; this.setData({ assignedList: updatedList, modifiedItems: modifiedItems, assignedTotal: assignedTotal, unassignedTotal: unassignedTotal }); }, // 保存所有修改 saveAllChanges: function() { const { assignedList, modifiedItems, bancai } = this.data; const dataManager = app.globalData.dataManager; if (modifiedItems.size === 0) { wx.showToast({ title: '没有修改需要保存', icon: 'none' }); return; } const promises = []; // 遍历修改过的记录 modifiedItems?.forEach((newValue, id) => { const record = assignedList.find(item => item.id === id); if (!record) return; const oldValue = record.originalShuliang || record.shuliang; const changeAmount = newValue - oldValue; if (changeAmount === 0) return; // 更新dingdan_bancai记录 promises.push( dataManager.updateEntity('dingdan_bancai', { id, shuliang: newValue }) .then(() => { // 创建进货记录 const jinhuoData = { shuliang: changeAmount, date: new Date().toISOString(), user: { id: wx.getStorageSync("userId") }, text: `调整订单分配数量: ${oldValue} → ${newValue}`, theTypeOfOperation: 4, // 订单分配调整类型 dingdan_bancai: { id } }; return dataManager.addEntity('jinhuo', jinhuoData); }) ); }); // 执行所有更新 Promise.all(promises) .then(() => { wx.showToast({ title: '保存成功', icon: 'success' }); this.loadData(bancai.id); // 重新加载数据 this.setData({ modifiedItems: new Map() }); // 清空修改记录 }) .catch(error => { console.error('保存失败:', error); wx.showToast({ title: error.message || '保存失败', icon: 'none' }); }); }, // 输入处理函数 onStockInput: function(e) { this.setData({ stockInput: e.detail.value }); }, onNoteInput: function(e) { this.setData({ noteInput: e.detail.value }); }, closeEditModal: function() { this.setData({ showEditModal: false }); } });saveAllChanges中的保存逻辑改成后端事务api,事务会批量的保存修改项并核对数据,前端也要核对一边,前端保存成功之前有个等待提示

filetype

// pages/admin/movies/movies.js Page({ data: { movies: [], // 电影列表 loading: false, // 是否加载中 hasMore: true, // 是否还有更多数据 page: 1, // 当前页码 pageSize: 10, // 每页数量 searchValue: '', // 搜索框值 showAddModal: false, // 是否显示添加电影模态框 movieForm: { name: '', poster: '', type: '', director: '', actors: '', description: '', rating: 0, releaseDate: '', duration: '', status: 1 }, formErrors: {} // 表单错误信息 }, onLoad: function(options) { this.getMovies(); }, // 获取电影列表 getMovies() { if (this.data.loading || !this.data.hasMore) return; this.setData({ loading: true }); wx.request({ url: `${getApp().globalData.baseUrl}/admin/api/movies`, data: { page: this.data.page, pageSize: this.data.pageSize, keyword: this.data.searchValue }, success: (res) => { if (res.data.code === 0) { const newMovies = res.data.data.list; const hasMore = res.data.data.list.length >= this.data.pageSize; this.setData({ movies: this.data.page === 1 ? newMovies : [...this.data.movies, ...newMovies], hasMore, page: this.data.page + 1 }); } }, complete: () => { this.setData({ loading: false }); } }); }, // 搜索框输入 onSearchInput(e) { this.setData({ searchValue: e.detail.value }); }, // 搜索确认 onSearchConfirm() { this.setData({ page: 1, hasMore: true, movies: [] }); this.getMovies(); }, // 显示添加电影模态框 showAddMovieModal() { this.setData({ showAddModal: true, movieForm: { name: '', poster: '', type: '', director: '', actors: '', description: '', rating: 0, releaseDate: '', duration: '', status: 1 }, formErrors: {} }); }, // 关闭添加电影模态框 closeAddMovieModal() { this.setData({ showAddModal: false }); }, // 表单输入 onFormInput(e) { const { field } = e.currentTarget.dataset; const { value } = e.detail; this.setData({ [`movieForm.${field}`]: value }); }, // 日期选择 onDateChange(e) { this.setData({ 'movieForm.releaseDate': e.detail.value }); }, // 评分选择 onRatingChange(e) { this.setData({ 'movieForm.rating': e.detail.value }); }, // 提交表单 submitForm() { const { movieForm } = this.data; const errors = {}; // 表单验证 if (!movieForm.name.trim()) { errors.name = '请输入电影名称'; } if (!movieForm.poster.trim()) { errors.poster = '请上传电影海报'; } if (!movieForm.type.trim()) { errors.type = '请输入电影类型'; } if (!movieForm.director.trim()) { errors.director = '请输入导演'; } if (!movieForm.actors.trim()) { errors.actors = '请输入主演'; } if (!movieForm.description.trim()) { errors.description = '请输入电影简介'; } if (!movieForm.releaseDate) { errors.releaseDate = '请选择上映日期'; } if (!movieForm.duration.trim()) { errors.duration = '请输入电影时长'; } if (Object.keys(errors).length > 0) { this.setData({ formErrors: errors }); return; } // 提交表单 wx.showLoading({ title: '提交中...', mask: true }); wx.request({ url: `${getApp().globalData.baseUrl}/admin/api/movies`, method: 'POST', data: movieForm, success: (res) => { if (res.data.code === 0) { wx.showToast({ title: '添加成功', icon: 'success' }); // 刷新电影列表 this.setData({ page: 1, hasMore: true, movies: [], showAddModal: false }); this.getMovies(); } else { wx.showToast({ title: res.data.message || '添加失败', icon: 'none' }); } }, fail: () => { wx.showToast({ title: '网络错误,请稍后重试', icon: 'none' }); }, complete: () => { wx.hideLoading(); } }); }, // 上传海报 uploadPoster() { wx.chooseImage({ count: 1, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success: (res) => { const tempFilePaths = res.tempFilePaths; // 上传图片到服务器 wx.showLoading({ title: '上传中...', }); wx.uploadFile({ url: `${getApp().globalData.baseUrl}/admin/api/upload`, filePath: tempFilePaths[0], name: 'file', success: (res) => { const data = JSON.parse(res.data); if (data.code === 0) { this.setData({ 'movieForm.poster': data.data.url }); wx.showToast({ title: '上传成功', icon: 'success' }); } else { wx.showToast({ title: data.message || '上传失败', icon: 'none' }); } }, fail: () => { wx.showToast({ title: '网络错误,请稍后重试', icon: 'none' }); }, complete: () => { wx.hideLoading(); } }); } }); }, // 编辑电影 editMovie(e) { const index = e.currentTarget.dataset.index; const movie = this.data.movies[index]; this.setData({ showAddModal: true, movieForm: { id: movie.id, name: movie.name, poster: movie.poster, type: movie.type, director: movie.director, actors: movie.actors, description: movie.description, rating: movie.rating, releaseDate: movie.releaseDate, duration: movie.duration, status: movie.status }, formErrors: {} }); }, // 删除电影 deleteMovie(e) { const index = e.currentTarget.dataset.index; const movieId = this.data.movies[index].id; wx.showModal({ title: '确认删除', content: '您确定要删除这部电影吗?', success: (res) => { if (res.confirm) { wx.showLoading({ title: '删除中...', }); wx.request({ url: `${getApp().globalData.baseUrl}/admin/api/movies/${movieId}`, method: 'DELETE', success: (res) => { if (res.data.code === 0) { // 从列表中删除电影 const movies = [...this.data.movies]; movies.splice(index, 1); this.setData({ movies }); wx.showToast({ title: '删除成功', icon: 'success' }); } else { wx.showToast({ title: res.data.message || '删除失败', icon: 'none' }); } }, fail: () => { wx.showToast({ title: '网络错误,请稍后重试', icon: 'none' }); }, complete: () => { wx.hideLoading(); } }); } } }); }, // 更改电影状态 changeMovieStatus(e) { const index = e.currentTarget.dataset.index; const movie = this.data.movies[index]; const newStatus = movie.status === 1 ? 0 : 1; wx.showLoading({ title: '更新中...', }); wx.request({ url: `${getApp().globalData.baseUrl}/admin/api/movies/${movie.id}/status`, method: 'POST', data: { status: newStatus }, success: (res) => { if (res.data.code === 0) { // 更新列表中的电影状态 const movies = [...this.data.movies]; movies[index].status = newStatus; this.setData({ movies }); wx.showToast({ title: newStatus === 1 ? '已上架' : '已下架', icon: 'success' }); } else { wx.showToast({ title: res.data.message || '更新失败', icon: 'none' }); } }, fail: () => { wx.showToast({ title: '网络错误,请稍后重试', icon: 'none' }); }, complete: () => { wx.hideLoading(); } }); } }); 有没有问题

filetype

// 在 app.js 中添加插件查询方法 App({ // ... getPluginProviders() { try { // 获取小程序全局配置 const appConfig = wx.getAppBaseInfo && wx.getAppBaseInfo(); if (appConfig && appConfig.plugins) { const providers = {}; Object.entries(appConfig.plugins).forEach(([name, config]) => { providers[name] = config.provider; }); console.log('所有插件 Provider:', providers); return providers; }请帮我把上述代码融入到下列代码中,然后给我完整代码const pathConfig = require('./config/path'); App({ // 全局数据对象 globalData: { isDev: false, // 是否是开发环境 debugMode: false, // 手动调试模式标志 userInfo: null, // 用户信息 token: null, // 用户认证token systemInfo: null, // 系统信息 apiBaseUrl: 'https://api.lyqf.com', // API基础URL envConfig: { develop: { apiBaseUrl: 'https://dev-api.lyqf.com', skipLogin: true }, trial: { apiBaseUrl: 'https://test-api.lyqf.com', skipLogin: false }, release: { apiBaseUrl: 'https://api.lyqf.com', skipLogin: false } }, tabBarPages: [ // 标签页路径列表 '/pages/home/home', '/pages/auto-service/index', '/pages/product-mall/index', '/pages/finance-circle/index', '/pages/my/index' ], routes: { // 主要路由配置 welcome: '/pages/welcome/welcome', login: '/pages/login/login', phoneLogin: '/pages/phone-login/index', home: '/pages/home/home', autoService: '/pages/auto-service/index', productMall: '/pages/product-mall/index', financeCircle: '/pages/finance-circle/index', my: '/pages/my/index', settings: '/pages/settings/index', profile: '/pages/profile/index' }, pluginStatus: { // 插件状态信息 loaded: false, version: null, error: null } }, // 小程序初始化完成时触发 onLaunch(options) { console.log('小程序初始化完成', options); // 1. 获取系统信息 this.getSystemInfo(); // 2. 检测运行环境 this.checkEnvironment(options); // 3. 检查插件状态 this.checkPluginStatus(); // 4. 检查登录状态 this.checkLoginStatus(); // 5. 初始化全局事件监听 this.initGlobalEvents(); // 6. 开发环境自动跳转 - 注释掉 // this.handleDevRedirect(); }, // 获取系统信息 getSystemInfo() { try { const systemInfo = wx.getSystemInfoSync(); this.globalData.systemInfo = systemInfo; console.log('系统信息:', systemInfo); } catch (e) { console.error('获取系统信息失败:', e); } }, // 检测运行环境 checkEnvironment(options) { try { // 获取小程序版本信息 const accountInfo = wx.getAccountInfoSync(); const envVersion = accountInfo.miniProgram.envVersion || 'release'; // 设置全局环境标志 this.globalData.isDev = envVersion === 'develop'; // 应用环境配置 const envConfig = this.globalData.envConfig[envVersion] || {}; this.globalData.apiBaseUrl = envConfig.apiBaseUrl || this.globalData.apiBaseUrl; console.log(`当前环境: ${envVersion}, API地址: ${this.globalData.apiBaseUrl}`); // 检查URL参数中的调试标志 if (options && options.query && options.query.debug === 'true') { this.enableDebugMode(); } // 检查本地存储中的调试标志 const debugStorage = wx.getStorageSync('debugMode'); if (debugStorage === 'true') { this.enableDebugMode(); } } catch (e) { console.error('环境检测失败:', e); } }, // 检查插件状态 checkPluginStatus() { console.log('开始检查插件状态...'); // 检查插件是否已加载 try { const plugin = requirePlugin('myPlugin'); console.log('插件加载成功:', plugin); // 更新全局插件状态 this.globalData.pluginStatus.loaded = true; // 检查插件版本 wx.getPluginVersion({ plugin: 'wx2d8807e6add3eaee', success: (res) => { console.log('插件版本信息:', res); this.globalData.pluginStatus.version = res.version; if (res.version !== '1.11.7') { console.warn('插件版本不匹配:', res.version); this.showVersionAlert(res.version); } }, fail: (err) => { console.error('获取插件版本失败:', err); this.globalData.pluginStatus.error = '获取版本失败'; this.showPluginError('获取插件版本失败'); } }); } catch (error) { console.error('插件加载失败:', error); this.globalData.pluginStatus = { loaded: false, version: null, error: error.message }; this.showPluginError('插件加载失败'); } }, // 显示插件错误弹窗 showPluginError(message) { wx.showModal({ title: '插件错误', content: `${message},请检查以下可能原因: 1. 小程序后台是否已添加该插件 2. 插件版本是否配置正确 3. 网络连接是否正常`, confirmText: '前往设置', success: (res) => { if (res.confirm) { this.smartNavigateTo(this.globalData.routes.settings); } } }); }, // 显示版本不匹配弹窗 showVersionAlert(currentVersion) { wx.showModal({ title: '版本不匹配', content: `当前插件版本(${currentVersion})与配置版本(1.11.7)不一致`, confirmText: '刷新应用', success: (res) => { if (res.confirm) { wx.reLaunch({ url: '/' }); } } }); }, // 检查登录状态 checkLoginStatus() { try { const token = wx.getStorageSync('token'); const userInfo = wx.getStorageSync('userInfo'); if (token && userInfo) { this.globalData.token = token; this.globalData.userInfo = userInfo; console.log('检测到已登录用户:', userInfo); } else { console.log('用户未登录'); } } catch (e) { console.error('登录状态检查失败:', e); } }, // 初始化全局事件监听 initGlobalEvents() { // 监听网络状态变化 wx.onNetworkStatusChange((res) => { console.log('网络状态变化:', res); this.globalData.networkStatus = res; if (!res.isConnected) { wx.showToast({ title: '网络已断开', icon: 'none' }); // 网络断开时重新检查插件状态 this.checkPluginStatus(); } }); // 监听小程序切前台 wx.onAppShow((res) => { console.log('小程序切前台', res); // 每次回到前台时检查token是否过期 this.checkTokenExpiration(); // 检查插件状态(防止插件被卸载) this.checkPluginStatus(); }); // 监听小程序切后台 wx.onAppHide(() => { console.log('小程序切后台'); }); }, // 启用调试模式 enableDebugMode() { console.log('启用调试模式'); this.globalData.debugMode = true; wx.setStorageSync('debugMode', 'true'); }, // 禁用调试模式 disableDebugMode() { console.log('禁用调试模式'); this.globalData.debugMode = false; wx.setStorageSync('debugMode', 'false'); }, // 切换调试模式 toggleDebugMode() { const newMode = !this.globalData.debugMode; this.globalData.debugMode = newMode; wx.setStorageSync('debugMode', newMode.toString()); wx.showToast({ title: newMode ? '调试模式已开启' : '调试模式已关闭', icon: 'none' }); }, // 检查token过期 checkTokenExpiration() { if (!this.globalData.token) return; // 实际项目中应调用API验证token有效性 // 这里简化为检查本地存储的过期时间 const tokenExpire = wx.getStorageSync('tokenExpire'); if (tokenExpire && tokenExpire < Date.now()) { console.log('token已过期'); this.logout(); wx.showToast({ title: '登录已过期,请重新登录', icon: 'none' }); } }, // 用户登录方法 login(loginData, callback) { wx.showLoading({ title: '登录中...', mask: true }); wx.request({ url: `${this.globalData.apiBaseUrl}/auth/login`, method: 'POST', data: loginData, success: (res) => { wx.hideLoading(); if (res.data.code === 0) { // 登录成功 const token = res.data.token; const userInfo = res.data.userInfo; // 保存到全局数据和本地存储 this.globalData.token = token; this.globalData.userInfo = userInfo; wx.setStorageSync('token', token); wx.setStorageSync('userInfo', userInfo); // 保存token过期时间(假设有效期为7天) const expireTime = Date.now() + 7 * 24 * 60 * 60 * 1000; wx.setStorageSync('tokenExpire', expireTime); console.log('登录成功', userInfo); wx.showToast({ title: '登录成功', icon: 'success' }); // 执行回调 if (callback && typeof callback === 'function') { callback(true); } // 登录成功后跳转到首页 this.smartNavigateTo(this.globalData.routes.home); } else { wx.showToast({ title: res.data.msg || '登录失败', icon: 'none' }); if (callback && typeof callback === 'function') { callback(false, res.data.msg); } } }, fail: (err) => { wx.hideLoading(); wx.showToast({ title: '网络错误,请重试', icon: 'none' }); if (callback && typeof callback === 'function') { callback(false, '网络错误'); } } }); }, // 用户登出方法 logout() { // 清除全局数据 this.globalData.token = null; this.globalData.userInfo = null; // 清除本地存储 wx.removeStorageSync('token'); wx.removeStorageSync('userInfo'); wx.removeStorageSync('tokenExpire'); console.log('用户已登出'); // 跳转到登录页面 wx.reLaunch({ url: this.globalData.routes.login }); }, // 封装的请求方法 request(options) { // 添加token到请求头 const header = options.header || {}; if (this.globalData.token) { header['Authorization'] = `Bearer ${this.globalData.token}`; } // 合并配置 const mergedOptions = { url: `${this.globalData.apiBaseUrl}${options.url}`, method: options.method || 'GET', data: options.data || {}, header: header, success: (res) => { // 统一处理token过期 if (res.data.code === 401) { this.logout(); wx.showToast({ title: '登录已过期,请重新登录', icon: 'none' }); return; } if (options.success) { options.success(res); } }, fail: (err) => { if (options.fail) { options.fail(err); } else { wx.showToast({ title: '网络错误,请重试', icon: 'none' }); } }, complete: options.complete }; // 发送请求 wx.request(mergedOptions); }, // 检查用户权限 checkPermission(permission) { if (!this.globalData.userInfo || !this.globalData.userInfo.permissions) { return false; } return this.globalData.userInfo.permissions.includes(permission); }, // 增强智能路由跳转方法 smartNavigateTo(path) { // 确保路径格式正确 if (!path.startsWith('/')) { path = '/' + path; } // 检查页面是否在 tabBar 中 const isTabBarPage = this.globalData.tabBarPages.includes(path); // 获取当前页面栈 const pages = getCurrentPages(); const currentPage = pages.length > 0 ? pages[pages.length - 1] : null; // 计算当前页面路径 const currentPath = currentPage ? `/${currentPage.route}` : ''; // 检查是否已经在目标页面 if (currentPath === path) { console.log('已在目标页面,不跳转'); return; } try { if (isTabBarPage) { wx.switchTab({ url: path, success: () => console.log(`成功跳转至标签页: ${path}`), fail: (err) => { console.error(`标签页跳转失败: ${path}`, err); // 备选方案:使用 reLaunch this.fallbackNavigate(path); } }); } else { wx.navigateTo({ url: path, success: () => console.log(`成功跳转至页面: ${path}`), fail: (err) => { console.error(`页面跳转失败: ${path}`, err); // 检查页面栈深度 this.fallbackNavigate(path); } }); } } catch (error) { console.error('路由跳转异常:', error); this.fallbackNavigate(path); } }, // 备用跳转方法 fallbackNavigate(path) { // 尝试使用 reLaunch 作为最终备选 wx.reLaunch({ url: path, success: () => console.log(`reLaunch跳转成功: ${path}`), fail: (err) => { console.error(`reLaunch跳转失败: ${path}`, err); this.showNavigationError(); } }); }, // 显示导航错误提示 showNavigationError() { wx.showModal({ title: '跳转失败', content: '无法跳转到目标页面,请稍后重试', showCancel: false }); }, // 检查路由是否在 tabBar 中 isTabBarRoute(path) { return this.globalData.tabBarPages.includes(path); } });

filetype

<template> <view class="container"> <view class="user-info-section"> <view class="avatar-container"> <image src="/https/wenku.csdn.net/static/workbanch/banner/workbench/4.jpg" class="avatar-image" mode="aspectFill" /> <view class="avatar-frame"></view> </view> <view class="user-details"> <text class="welcome-text">您好,</text> <text class="username">{{ userName || '加载中...' }}</text> <view class="user-meta"> <text class="user-role">{{ userRole }}</text> <text class="user-dept">{{ userDept }}</text> <text class="user-phone" v-if="userPhone">电话:{{ userPhone }}</text> </view> </view> </view> <view class="function-section"> <view class="function-item" @click="handleResetPassword" @touchstart="handleTouchStart('reset')" @touchend="handleTouchEnd('reset')" > <view class="item-left"> <image src="/https/wenku.csdn.net/static/workbanch/icons/reset-password.png" class="item-icon" /> <text class="item-text">重置密码</text> </view> <view v-if="showResetModal" class="modal-overlay" @click.self="closeResetModal"> <view class="modal-content"> <input v-model="oldPassword" type="password" placeholder="请输入旧密码" /> <input v-model="newPassword" type="password" placeholder="请输入新密码" /> <input v-model="confirmPassword" type="password" placeholder="请确认新密码" /> <view class="modal-buttons"> <button @click="submitResetPassword">保存</button> <button @click="closeResetModal">关闭</button> </view> </view> </view> <view class="arrow-icon">›</view> </view> <view class="divider"></view> <view class="function-item logout-item" @click="handleLogout" @touchstart="handleTouchStart('logout')" @touchend="handleTouchEnd('logout')" > <view class="item-left"> <image src="/https/wenku.csdn.net/static/workbanch/icons/logout.png" class="item-icon" /> <text class="item-text">退出登录</text> </view> <view class="arrow-icon">›</view> </view> </view> </view> </template> <script setup> import { ref } from 'vue'; import { onShow, onTabItemTap } from '@dcloudio/uni-app'; // 用户信息相关 const userName = ref(''); const userRole = ref(''); const userDept = ref(''); const userPhone = ref(''); // 重置密码 const showResetModal = ref(false); const oldPassword = ref(''); const newPassword = ref(''); const confirmPassword = ref(''); // 触摸状态 const touchState = ref({ reset: false, logout: false }); // 页面显示时加载数据 onShow(() => { // console.log('onShow 被触发'); loadUserInfo(); // 加载用户信息 }); // tabbar 页面被点击时触发 onTabItemTap(() => { // console.log('tabbar 页面被点击'); loadUserInfo(); // 强制刷新数据 }); const forceRefresh = true; // 加载用户信息 const loadUserInfo = async () => { try { const userInfo = uni.getStorageSync('userInfo'); // console.log('本地缓存 userInfo:', userInfo); if (!forceRefresh && userInfo && userInfo.userName) { // 使用缓存 userName.value = userInfo.nickName || userInfo.userName || '未知用户'; userRole.value = userInfo.roles?.[0]?.roleName || '普通用户'; userDept.value = userInfo.dept?.deptName || '未分配部门'; userPhone.value = userInfo.phonenumber || '暂无电话'; } else { // console.log('开始请求用户信息...'); const res = await uni.request({ url: 'http://172.26.26.43/dev-api/system/user/profile', method: 'GET', header: { 'Authorization': 'Bearer ' + uni.getStorageSync('token') } }); // console.log('接口返回结果:', res); if (res.statusCode === 200 && res.data.code === 200) { const userData = res.data.data; uni.setStorageSync('userInfo', userData); userName.value = userData.nickName || userData.userName || '未知用户'; userRole.value = userData.roles?.[0]?.roleName || '普通用户'; userDept.value = userData.dept?.deptName || '未分配部门'; userPhone.value = userData.phonenumber || '暂无电话'; } else { uni.showToast({ title: '获取用户信息失败', icon: 'none' }); uni.redirectTo({ url: '/pages/login/login' }); } } } catch (error) { console.error('加载用户信息失败:', error); uni.showToast({ title: '加载用户信息失败', icon: 'none' }); uni.redirectTo({ url: '/pages/login/login' }); } }; // 处理触摸开始 const handleTouchStart = (type) => { touchState.value[type] = true; }; // 处理触摸结束 const handleTouchEnd = (type) => { touchState.value[type] = false; }; // 显示弹窗 const handleResetPassword = () => { uni.vibrateShort(); // 震动反馈 showResetModal.value = true; }; // 关闭弹窗 const closeResetModal = () => { showResetModal.value = false; }; // 提交重置密码 const submitResetPassword = async () => { const { oldPassword: oldPass, newPassword: newPass, confirmPassword: confirmPass } = { oldPassword: oldPassword.value, newPassword: newPassword.value, confirmPassword: confirmPassword.value }; if (!oldPass || !newPass || !confirmPass) { uni.showToast({ title: '所有密码都必须填写', icon: 'none' }); return; } if (newPass !== confirmPass) { uni.showToast({ title: '新密码与确认密码不一致', icon: 'none' }); return; } uni.showLoading({ title: '提交中...' }); try { const res = await uni.request({ url: 'http://172.26.26.43/dev-api/system/user/profile/updatePwd', method: 'POST', header: { 'Authorization': 'Bearer ' + uni.getStorageSync('token'), 'Content-Type': 'application/json' }, data: { oldPassword: oldPass, newPassword: newPass } }); uni.hideLoading(); if (res.statusCode === 200 && res.data.code === 200) { uni.showToast({ title: '密码修改成功', icon: 'success' }); uni.removeStorageSync('token'); uni.removeStorageSync('userInfo'); setTimeout(() => { uni.reLaunch({ url: '/pages/login/login' }); }, 1500); } else { uni.showToast({ title: '密码修改失败', icon: 'none' }); } } catch (error) { uni.hideLoading(); uni.showToast({ title: '网络请求失败', icon: 'none' }); console.error('请求失败:', error); } closeResetModal(); }; // 处理退出登录 const handleLogout = () => { uni.vibrateShort(); // 添加震动反馈 uni.showModal({ title: '确认退出', content: '您确定要退出当前账号吗?', confirmText: '退出登录', confirmColor: '#e74c3c', success: (res) => { if (res.confirm) { // 清除用户相关数据 uni.removeStorageSync('token'); uni.removeStorageSync('userInfo'); uni.removeStorageSync('savedUsername'); // 显示退出提示 uni.showToast({ title: '已退出登录', icon: 'success', duration: 1500 }); // 跳转到登录页 setTimeout(() => { uni.reLaunch({ url: '/pages/login/login' }); }, 1500); } } }); }; </script> <style lang="scss" scoped> .container { padding: 20rpx; background-color: #f5f7fa; min-height: 100vh; } /* 用户信息区域样式 */ .user-info-section { display: flex; align-items: center; padding: 30rpx; margin: 20rpx 0; background: linear-gradient(135deg, #3498db, #8e44ad); color: white; position: relative; overflow: hidden; border-radius: 24rpx; &::before { content: ''; position: absolute; top: -50%; right: -50%; width: 200%; height: 200%; background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0) 70%); pointer-events: none; } } .user-phone { display: block; font-size: 24rpx; // margin-top: 10rpx; color: rgba(255, 255, 255, 0.8); background: rgba(255, 255, 255, 0.2); padding: 4rpx 12rpx; border-radius: 20rpx; backdrop-filter: blur(10px); } .avatar-container { position: relative; width: 120rpx; height: 120rpx; margin-right: 30rpx; } .avatar-image { width: 100%; height: 100%; border-radius: 50%; background-color: #fff; } .avatar-frame { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 4rpx solid rgba(255, 255, 255, 0.3); border-radius: 50%; box-sizing: border-box; } .user-details { flex: 1; } .welcome-text { font-size: 28rpx; opacity: 0.9; } .username { display: block; font-size: 40rpx; font-weight: bold; margin: 8rpx 0; text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.2); } .user-meta { display: flex; flex-wrap: wrap; gap: 15rpx; margin-top: 15rpx; } .user-role, .user-dept { font-size: 24rpx; background: rgba(255, 255, 255, 0.2); padding: 4rpx 12rpx; border-radius: 20rpx; backdrop-filter: blur(10px); } /* 功能板块区域 - 宽度优化 */ .function-section { background-color: #fff; border-radius: 24rpx; margin: 30rpx 40rpx; /* 左右边距增加 */ box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); overflow: hidden; } .function-item { display: flex; align-items: center; justify-content: space-between; padding: 30rpx 35rpx; /* 增加左右内边距 */ position: relative; transition: all 0.2s ease; /* 点击效果 - 缩放 */ &:active { transform: scale(0.98); background-color: #f8f8f8; } /* 触摸效果 - 高亮 */ &.touch-active { background-color: #f0f9ff; transform: scale(0.98); .item-text { font-weight: bold; } } } .logout-item { .item-text { color: #e74c3c; } &.touch-active { background-color: #fff0f0; } } .item-left { display: flex; align-items: center; } .item-icon { width: 44rpx; height: 44rpx; margin-right: 20rpx; transition: transform 0.2s ease; .touch-active & { transform: scale(1.1); } } .item-text { font-size: 32rpx; color: #333; transition: all 0.2s ease; .touch-active & { transform: translateX(5px); } } .arrow-icon { font-size: 40rpx; color: #999; transform: scale(1.5, 1.5); transition: all 0.2s ease; .touch-active & { transform: scale(1.5, 1.5) translateX(-5px); } } .divider { height: 1rpx; background-color: #f0f0f0; margin: 0 35rpx; /* 与内边距一致 */ } /* 动画效果 */ @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .pulse { animation: pulse 0.3s ease; } //重置密码 .modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 9999; } .modal-content { background-color: #fff; padding: 30rpx; border-radius: 20rpx; width: 80%; box-sizing: border-box; display: flex; flex-direction: column; gap: 20rpx; } .modal-content input { border: 1px solid #ddd; padding: 20rpx; border-radius: 10rpx; } .modal-buttons { display: flex; justify-content: space-between; gap: 20rpx; } .modal-buttons button { flex: 1; } </style> 帮我优化一下这段代码,尤其是重置密码弹窗这块,点击重置密码出现弹窗后我在输入过程中每次点击弹窗都会弹一下,点击返回没有隐藏该弹窗并返回该界面,点击保存没有效果

filetype

<template> <view class="container"> <web-view :src="webviewPath" id="targetWebview" @message="handleWebviewMessage" ></web-view> <cover-view class="bottom-action-area"> <cover-view class="capture-btn" @click="generatePDF"> <cover-view class="btn-text">生成PDF证据</cover-view > </cover-view > </cover-view > <cover-view v-if="showPreview" class="pdf-preview"> <cover-view class="preview-header"> <cover-view class="title-container"> <cover-view class="preview-title">证据预览</cover-view > </cover-view > </cover-view > <web-view v-if="pdfPreviewUrl" :src="pdfPreviewUrl" class="preview-iframe" ></web-view> <cover-view class="action-buttons"> <cover-view class="action-btn cancel-btn" @click="closePreview">放弃</cover-view > <cover-view class="action-btn confirm-btn" @click="savePDF">保存证据</cover-view > </cover-view > </cover-view > </view> </template> <script setup lang="ts"> import { ref, onMounted } from 'vue'; import { onLoad, onReady } from '@dcloudio/uni-app'; import html2canvas from 'html2canvas'; // 状态管理 const webviewPath = ref(''); const showPreview = ref(false); const pdfPreviewUrl = ref(''); const pdfFilePath = ref(''); const currentWebview = ref<any>(null); const platform = ref(''); const ws = ref<any>(null); // 初始化 onLoad((options: any) => { if (options.url) { webviewPath.value = decodeURIComponent(options.url); } // 获取平台信息 const systemInfo = uni.getSystemInfoSync(); platform.value = systemInfo.platform || ''; }); // 准备阶段获取 WebView 实例 onReady(() => { // #ifdef APP-PLUS const pages = getCurrentPages(); const page = pages[pages.length - 1]; const webview = page.$getAppWebview(); setTimeout(() => { if (webview.children().length > 0) { const wv = webview.children()[0]; ws.value = wv; console.log(ws.value) } }, 1000); // #endif }); // 生成PDF const generatePDF = () => { uni.showLoading({ title: '生成证据中...', mask: true }); // #ifdef APP-PLUS if (!ws.value) { uni.showToast({ title: '网页未加载完成', icon: 'none' }); return; } const timestamp = new Date().getTime(); const pdfPath = `_doc/evidence_${timestamp}.pdf`; // 使用 plus.draw 生成PDF ws.value.draw(ws, { format: 'pdf', filename: pdfPath, background: '#FFFFFF', success: (res:any) => { pdfFilePath.value = res.filePath; preparePDFPreview(res.filePath); uni.hideLoading(); }, fail: (err:any) => { console.error('PDF生成失败:', err); uni.hideLoading(); uni.showToast({ title: `生成失败: ${err.message}`, icon: 'none' }); } }); // #endif // #ifdef H5 // H5环境使用html2canvas + jsPDF generatePDFForH5(); // #endif }; // 准备PDF预览 const preparePDFPreview = (filePath: string) => { // #ifdef APP-PLUS plus.io.resolveLocalFileSystemURL( filePath, (entry) => { const localUrl = entry.toLocalURL(); // 使用PDF.js预览 pdfPreviewUrl.value = `/static/pdfjs/web/viewer.html?file=${encodeURIComponent(localUrl)}`; showPreview.value = true; }, (err) => { console.error('文件访问失败:', err); uni.showToast({ title: '文件访问失败', icon: 'none' }); } ); // #endif }; // 保存PDF到相册 const savePDF = () => { // #ifdef APP-PLUS if (!pdfFilePath.value) return; // plus.gallery.save( // pdfFilePath.value, // { filename: `evidence_${Date.now()}.pdf` }, // () => { // uni.showToast({ title: '证据保存成功' }); // closePreview(); // }, // (err) => { // uni.showToast({ title: `保存失败: ${err.message}`, icon: 'none' }); // } // ); // #endif // #ifdef H5 // H5环境下载PDF const link = document.createElement('a'); link.href = pdfFilePath.value; link.download = `evidence_${Date.now()}.pdf`; link.click(); closePreview(); // #endif }; // 关闭预览 const closePreview = () => { showPreview.value = false; pdfPreviewUrl.value = ''; }; // H5环境PDF生成(使用html2canvas + jsPDF) const generatePDFForH5 = () => { // #ifdef H5 // const iframe = document.getElementById('targetWebview') as HTMLIFrameElement; // if (!iframe || !iframe.contentWindow) return; // const iframeDoc = iframe.contentWindow.document; // html2canvas(iframeDoc.body, { // useCORS: true, // scale: 2 // }).then(canvas => { // const imgData = canvas.toDataURL('image/jpeg', 0.95); // const pdf = new jsPDF('p', 'mm', 'a4'); // const imgWidth = pdf.internal.pageSize.getWidth(); // const imgHeight = (canvas.height * imgWidth) / canvas.width; // pdf.addImage(imgData, 'JPEG', 0, 0, imgWidth, imgHeight); // const pdfBlob = pdf.output('blob'); // pdfFilePath.value = URL.createObjectURL(pdfBlob); // // H5环境预览 // pdfPreviewUrl.value = pdfFilePath.value; // showPreview.value = true; // uni.hideLoading(); // }).catch(err => { // console.error('H5 PDF生成失败:', err); // uni.hideLoading(); // uni.showToast({ title: '生成失败', icon: 'none' }); // }); // #endif }; // 处理WebView消息 const handleWebviewMessage = (e: any) => { console.log('收到WebView消息:', e.detail); }; </script> <style scoped> .container { position: relative; height: 100vh; overflow: hidden; } #targetWebview { width: 100%; height: calc(100vh - 100px); } .bottom-action-area { position: fixed; bottom: 0; left: 0; right: 0; z-index: 100; background-color: #007aff; padding: 15px; display: flex; justify-content: center; padding-bottom: calc(10rpx + constant(safe-area-inset-bottom)); padding-bottom: calc(10rpx + env(safe-area-inset-bottom)); } .capture-btn { width: 100%; height: 90rpx; padding: 12px; background-color: #007aff; border-radius: 8px; display: flex; align-items: center; justify-content: center; } .btn-text { color: white; font-size: 14px; font-weight: 500; } /* PDF预览样式 */ .pdf-preview { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 1000; background-color: white; display: flex; flex-direction: column; } .preview-header { background-color: #007aff; padding: 15px; } .title-container { display: flex; justify-content: center; } .preview-title { color: white; font-size: 18px; font-weight: bold; } .preview-iframe { flex: 1; width: 100%; border: none; } .action-buttons { display: flex; padding: 15px; background-color: #f5f5f5; } .action-btn { flex: 1; padding: 12px; border-radius: 8px; text-align: center; font-weight: 500; } .cancel-btn { background-color: #f5f5f5; color: #333; margin-right: 10px; } .confirm-btn { background-color: #007aff; color: white; margin-left: 10px; } </style> 一直显示生成证据中怎样修改

filetype

// pages/tianjia/tianjia.js Page({ data: { dingdans: [], chanpins: [], zujians: [], bancais: [], currentDingdan: null, currentChanpin: null, currentZujian: null, currentBancai: null, currentDingdanIndex: -1, currentChanpinIndex: -1, currentZujianIndex: -1, currentBancaiIndex: -1, currentDingdanId: null, currentDingdanChanpinId: null, currentChanpinZujianId: null, orderQuantity: '', canSubmit: false }, onLoad: function() { this.checkPermission(); this.initPage(); }, checkPermission: function() { const role = parseInt(wx.getStorageSync('role') || '0'); if (role <= 1) { wx.showModal({ title: '权限不足', content: '抱歉,您没有访问此页面的权限。只有管理员可以管理用户。', showCancel: false, success: () => wx.navigateBack() }); return false; } return true; }, initPage: function() { this.dataManager = getApp().globalData.dataManager; this.dataManager.registerCallback('all', this.handleDataUpdate.bind(this)); this.refreshDingdanList(); this.refreshBancaiList(); }, handleDataUpdate: function(operation, entity, data) { if (['refresh', 'add', 'update', 'delete'].includes(operation)) { if (entity === 'dingdan') { this.refreshDingdanList(data.id); } else if (entity === 'dingdan_chanpin') { this.refreshChanpinList(data.dingdan?.id, data.chanpin?.id); } else if (entity === 'chanpin_zujian') { this.refreshZujianList(data.chanpin?.id, data.id); } else if (entity === 'bancai') { this.refreshBancaiList(null, data.id); } } }, refreshDingdanList: function(dingdanId) { const dingdans = this.dataManager.data.dingdans || []; dingdans.sort((a, b) => new Date(b.xiadan) - new Date(a.xiadan)); const formattedDingdans = dingdans.map(d => ({ ...d, displayName: `${d.number} (${this.formatDate(d.xiadan)})` })); this.setData({ dingdans: formattedDingdans }); if (dingdanId) { const index = formattedDingdans.findIndex(d => d.id === dingdanId); if (index !== -1) { this.setData({ currentDingdanIndex: index, currentDingdan: formattedDingdans[index], currentDingdanId: dingdanId }); this.refreshChanpinList(dingdanId); } } }, refreshChanpinList: function(dingdanId, chanpinId) { if (!dingdanId) dingdanId = this.data.currentDingdanId; if (!dingdanId) { this.resetSelections(); return; } const dingdanChanpins = this.dataManager.data.dingdan_chanpins || []; const relatedChanpins = dingdanChanpins.filter(dc => dc.dingdan?.id == dingdanId); const formattedChanpins = relatedChanpins.map(dc => ({ ...dc, displayName: dc.chanpin ? `${dc.chanpin.bianhao} (数量: ${dc.shuliang})` : '' })); this.setData({ chanpins: formattedChanpins }); if (chanpinId) { const dc = relatedChanpins.find(dc => dc.chanpin?.id == chanpinId); if (dc) { const index = formattedChanpins.findIndex(c => c.id === dc.id); if (index !== -1) { this.setData({ currentChanpinIndex: index, currentChanpin: formattedChanpins[index], currentDingdanChanpinId: dc.id }); this.refreshZujianList(dc.id); } } } else { this.resetSelections(); } }, refreshZujianList: function(dingdanChanpinId, zujianId) { if (!dingdanChanpinId) dingdanChanpinId = this.data.currentDingdanChanpinId; if (!dingdanChanpinId) { this.resetSelections(); return; } const dingdanChanpin = this.dataManager.data.dingdan_chanpins.find(dc => dc.id == dingdanChanpinId); if (!dingdanChanpin?.chanpin) return; const chanpinId = dingdanChanpin.chanpin.id; const chanpinZujians = this.dataManager.data.chanpin_zujians.filter(cz => cz.chanpin?.id == chanpinId); const formattedZujians = chanpinZujians.map(cz => ({ ...cz, displayName: cz.zujian ? `${cz.zujian.name} (产量: ${cz.one_howmany})` : '' })); this.setData({ zujians: formattedZujians }); if (zujianId) { const cz = chanpinZujians.find(cz => cz.zujian?.id == zujianId); if (cz) { const index = formattedZujians.findIndex(z => z.id === cz.id); if (index !== -1) { this.setData({ currentZujianIndex: index, currentZujian: formattedZujians[index], currentChanpinZujianId: cz.id }); this.refreshBancaiList(cz.id); } } } else { this.resetSelections(); } }, refreshBancaiList: function(chanpinZujianId, bancaiId) { if (chanpinZujianId) { const chanpinZujian = this.dataManager.data.chanpin_zujians.find(cz => cz.id == chanpinZujianId); if (!chanpinZujian?.bancai) return; const formattedBancai = { ...chanpinZujian.bancai, displayName: this.formatBancaiInfo(chanpinZujian.bancai) }; this.setData({ bancais: [formattedBancai], currentBancai: formattedBancai, currentBancaiIndex: 0, orderQuantity: '' }); } else { const bancais = this.dataManager.data.bancais || []; const formattedBancais = bancais.map(b => ({ ...b, displayName: this.formatBancaiInfo(b) })); this.setData({ bancais: formattedBancais }); if (bancaiId) { const index = formattedBancais.findIndex(b => b.id === bancaiId); if (index !== -1) { this.setData({ currentBancaiIndex: index, currentBancai: formattedBancais[index] }); } } } this.checkSubmitCondition(); }, resetSelections: function() { this.setData({ zujians: [], currentZujian: null, currentZujianIndex: -1, currentChanpinZujianId: null, bancais: [], currentBancai: null, currentBancaiIndex: -1, orderQuantity: '', canSubmit: false }); this.refreshBancaiList(); }, formatBancaiInfo: function(bancai) { let info = `厚度: ${bancai.houdu}mm, 材质: ${bancai.caizhi?.name || ''}`; if (bancai.mupi1) info += `, 木皮1: ${bancai.mupi1.name}${bancai.mupi1.you ? ' (油)' : ''}`; if (bancai.mupi2) info += `, 木皮2: ${bancai.mupi2.name}${bancai.mupi2.you ? ' (油)' : ''}`; return info; }, checkSubmitCondition: function() { const canSubmit = this.data.currentBancai && parseInt(this.data.orderQuantity) > 0; this.setData({ canSubmit }); }, onDingdanChange: function(e) { const index = e.detail.value; const dingdan = this.data.dingdans[index]; this.setData({ currentDingdanIndex: index, currentDingdan: dingdan, currentDingdanId: dingdan.id }); this.refreshChanpinList(dingdan.id); }, onChanpinChange: function(e) { const index = e.detail.value; const chanpin = this.data.chanpins[index]; this.setData({ currentChanpinIndex: index, currentChanpin: chanpin, currentDingdanChanpinId: chanpin.id }); this.refreshZujianList(chanpin.id); }, onZujianChange: function(e) { const index = e.detail.value; const zujian = this.data.zujians[index]; this.setData({ currentZujianIndex: index, currentZujian: zujian, currentChanpinZujianId: zujian.id }); this.refreshBancaiList(zujian.id); }, onBancaiChange: function(e) { const index = e.detail.value; const bancai = this.data.bancais[index]; this.setData({ currentBancaiIndex: index, currentBancai: bancai }); this.checkSubmitCondition(); }, onQuantityInput: function(e) { this.setData({ orderQuantity: e.detail.value }); this.checkSubmitCondition(); }, // 添加订单按钮事件 addDingdan: function() { this.showAddDingdanModal(); }, // 添加产品按钮事件 addChanpin: function() { if (!this.data.currentDingdanId) { wx.showToast({ title: '请先选择订单', icon: 'none' }); return; } this.showAddChanpinModal(); }, // 添加组件按钮事件 addZujian: function() { if (!this.data.currentDingdanChanpinId) { wx.showToast({ title: '请先选择产品', icon: 'none' }); return; } const dingdanChanpin = this.dataManager.data.dingdan_chanpins.find( dc => dc.id == this.data.currentDingdanChanpinId ); if (!dingdanChanpin || !dingdanChanpin.chanpin) { wx.showToast({ title: '未找到产品信息', icon: 'none' }); return; } this.showAddZujianModal(dingdanChanpin.chanpin.id); }, // 添加板材按钮事件 addBancai: function() { this.showAddBancaiModal(); }, // 显示添加订单模态框 showAddDingdanModal: function() { wx.showModal({ title: '新增订单', content: '请前往订单管理页面添加新订单', showCancel: true, confirmText: '确定', success: (res) => { if (res.confirm) { wx.navigateTo({ url: '/pages/dingdan/dingdan' }); } } }); }, // 显示添加产品模态框 showAddChanpinModal: function() { wx.showModal({ title: '添加产品', content: '请前往产品管理页面添加产品', showCancel: true, confirmText: '确定', success: (res) => { if (res.confirm) { wx.navigateTo({ url: '/pages/chanpin/chanpin' }); } } }); }, // 显示添加组件模态框 showAddZujianModal: function(chanpinId) { wx.showModal({ title: '添加组件', content: '请前往组件管理页面添加组件', showCancel: true, confirmText: '确定', success: (res) => { if (res.confirm) { wx.navigateTo({ url: '/pages/zujian/zujian' }); } } }); }, // 显示添加板材模态框 showAddBancaiModal: function() { wx.showModal({ title: '添加板材', content: '请前往板材管理页面添加板材', showCancel: true, confirmText: '确定', success: (res) => { if (res.confirm) { wx.navigateTo({ url: '/pages/bancai/bancai' }); } } }); }, // 刷新数据按钮事件 refreshData: function() { wx.showLoading({ title: '刷新中...' }); this.dataManager.syncData() .then(() => { wx.hideLoading(); wx.showToast({ title: '刷新成功',

filetype
1. 用户与身体信息管理模块 用户信息管理: 注册登录:支持手机号 / 邮箱注册,密码加密存储,提供第三方快捷登录(模拟) 个人资料:记录基本信息(姓名、年龄、性别、身高、体重、职业) 健康目标:用户设置目标(如 “减重 5kg”“增肌”“维持健康”)及期望周期 身体状态跟踪: 体重记录:定期录入体重数据,生成体重变化曲线(折线图) 身体指标:记录 BMI(自动计算)、体脂率(可选)、基础代谢率(根据身高体重估算) 健康状况:用户可填写特殊情况(如糖尿病、过敏食物、素食偏好),系统据此调整推荐 2. 膳食记录与食物数据库模块 食物数据库: 基础信息:包含常见食物(如米饭、鸡蛋、牛肉)的名称、类别(主食 / 肉类 / 蔬菜等)、每份重量 营养成分:记录每 100g 食物的热量(kcal)、蛋白质、脂肪、碳水化合物、维生素、矿物质含量 数据库维护:管理员可添加新食物、更新营养数据,支持按名称 / 类别检索 膳食记录功能: 快速记录:用户选择食物、输入食用量(克 / 份),系统自动计算摄入的营养成分 餐次分类:按早餐 / 午餐 / 晚餐 / 加餐分类记录,支持上传餐食照片(可选) 批量操作:提供常见套餐模板(如 “三明治 + 牛奶”),一键添加到记录 历史记录:按日期查看过往膳食记录,支持编辑 / 删除错误记录 3. 营养分析模块 每日营养摄入分析: 核心指标计算:统计当日摄入的总热量、蛋白质 / 脂肪 / 碳水化合物占比(按每日推荐量对比) 微量营养素分析:检查维生素(如维生素 C、钙、铁)的摄入是否达标 平衡评估:生成 “营养平衡度” 评分(0-100 分),指出摄入过剩或不足的营养素 趋势分析: 周 / 月营养趋势:用折线图展示近 7 天 / 30 天的热量、三大营养素摄入变化 对比分析:将实际摄入与推荐量对比(如 “蛋白质摄入仅达到推荐量的 70%”) 目标达成率:针对健
Daniel799
  • 粉丝: 47
上传资源 快速赚钱