AI摘要

本文介绍了一个基于uni-app和Vant组件开发的健身会员管理系统H5前端项目。项目采用Vue 3、Vite、Axios和uni-app技术栈,实现了会员信息管理、课程进度跟踪和到期提醒等功能。文章详细阐述了项目的API设计、请求配置、拦截器、API方法封装、权限管理和微信通知功能的实现。这个项目为学习uni-app开发提供了一个很好的参考案例,展示了如何组织代码、处理API请求和管理状态等实际开发中的问题。
本文介绍了

基于uni-app的健身会员管理系统前端技术分析

项目背景

  • 本来是打算做一个会员管理的wx小程序,由于我开始前未弄清楚wx小程序原生语言和uniapp都分别支持什么组件,只知道uniapp可以开发小程序,直接就使用了vue3+vant4组件。
  • 做到最后要打包为微信小程序时傻了眼,成堆报错,查了查错误后才知道几乎都是vant4组件的错,根本用不了。
  • 查了查才知道vant weapp是专门用于小程序和app的组件,所以我就全部替换了,发现还是不行:页内跳转方法不对,底部导航栏导航方法也不对。。。
  • 于是索性不改了,还好备份过,h5就h5吧。
  • 业主后来想通过微信小程序来给他的会员发送到期请续费的通知(服务号通知)。但是经过我对这块狠狠地补习后,我发现目前的系统并不能做到这点,需要让会员们通过微信授权登录进来(但是感觉纯H5网站实现微信授权登录挺麻烦的),这样的话可以获取到他们的微信用户信息,就能通过服务号发送给每位授权登录的会员。
  • 我突然想到可不可以使用微信原生框架开发一个只做登录,登录的请求和返回都对应做好的这个h5网站,这样的话既能用微信官方登录接口,登录后的画面是这个h5网站,两全其美。
  • 但是哪有我想的这莫简单,微信虽然有一个<webview>可以做外部网站的显示容器,但是需要设置授权,所以行不通。后面我会单独发一篇文章,关于微信小程序开发方式以及我碰到的全部麻烦。
  • 最后我找到了一个公众号,专门转发这种通知,但有限制。所以最后到期通知只能发给业主自己,且没有会员登录的功能。后面会发一篇后端和数据库的实现以及如何部署。

项目概述

这是一个基于uni-app开发的健身会员管理系统,主要用于管理会员信息、课程进度以及发送到期提醒等功能。项目采用了Vue 3 + Vite的技术栈,整体架构清晰,代码组织规范。

技术栈

  • 前端框架:Vue 3
  • 构建工具:Vite
  • UI组件库:Vant weapp
  • HTTP请求:Axios
  • 跨端框架:uni-app

API设计与实现

1. 请求配置与拦截器

项目使用了axios进行HTTP请求,并配置了完整的请求拦截和响应拦截机制。让我们来看看具体的实现:

// 后端API配置 const backendAPI = { baseUrl: "/api", } // 创建axios实例 const instance = axios.create({ baseURL: backendAPI.baseUrl, timeout: 30000, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, withCredentials: true })

这段代码创建了一个axios实例,设置了基本的请求配置:

  • baseURL: 设置API的基础路径
  • timeout: 设置请求超时时间为30秒
  • headers: 设置请求头,指定内容类型为JSON
  • withCredentials: 允许跨域请求携带cookie

API路径配置详解

在代码中出现的 /api 是一个API的基础路径(base URL),它表示:

  1. 代理路径

    • 在开发环境中,这个 /api 通常会被配置为代理路径
    • 比如当你在本地开发时,请求 /api/member/list 实际上会被代理到 http://localhost:3000/member/list 这样的实际后端地址
  2. 实际作用

    • 它作为所有API请求的前缀
    • 比如 getMemberList 方法实际请求的完整URL是 /api/member/list
    • 这样可以统一管理所有API的路径
  3. 配置方式

    • vite.config.js 中通常会配置代理,类似这样:

      server: { proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true } } }
  4. 实际部署时

    • 在生产环境中,这个 /api 可能会指向实际的服务器地址
    • 比如 https://api.yourdomain.com

这样设计的好处是:

  • 开发时可以使用代理避免跨域问题
  • 部署时只需要修改代理配置,不需要改代码
  • 统一管理所有API请求的路径前缀

    2. 请求拦截器

instance.interceptors.request.use( config => { const token = uni.getStorageSync('token') if (token) { config.headers['Authorization'] = `Bearer ${token.trim()}` } return config }, error => { return Promise.reject(error) } )

请求拦截器的主要作用是:

  • 在每次请求前自动添加token到请求头
  • 使用uni.getStorageSync获取本地存储的token
  • 如果存在token,则添加到请求头的Authorization字段

3. 响应拦截器

instance.interceptors.response.use( response => { return response.data; }, async error => { // 错误处理逻辑 if (!error.response) { uni.showToast({ title: '网络连接失败,请检查网络设置', icon: 'none', duration: 2000 }); } // ... 其他错误处理 return Promise.reject(error); } )

响应拦截器的主要功能:

  • 统一处理响应数据,直接返回response.data
  • 处理各种错误情况,如网络错误、服务器错误等
  • 使用uni-app的showToast方法展示错误提示

4. API方法封装

项目将所有的API请求方法进行了统一封装,例如:

export const { adminLogin, getAdminProfile, getMemberList, // ... 其他方法 } = { adminLogin: (username, password) => instance.post('/admin/login', { username, password }) .then(response => { if (response.code === 200 && response.data.token) { uni.setStorageSync('token', response.data.token) uni.setStorageSync('adminInfo', response.data.admin) return response } return Promise.reject(new Error(response.message || '登录失败')) }), getAdminProfile: () => instance.get('/admin/profile'), getMemberList: () => instance.get('/member/list'), // ... 其他方法实现 }

这种封装方式的优点:

  • 统一管理所有API请求
  • 每个方法都有清晰的错误处理
  • 登录成功后自动保存token和用户信息
  • 使用Promise链式调用,代码更易读

登录后保存的token

登录后保存的token

登录后保存的adminInfo
登录后保存的adminInfo

5. 权限管理实现

项目中使用了基于token的权限管理机制,主要通过以下方式实现:

  1. 登录认证

    adminLogin: (username, password) => instance.post('/admin/login', { username, password }) .then(response => { if (response.code === 200 && response.data.token) { // 保存token和用户信息 uni.setStorageSync('token', response.data.token) uni.setStorageSync('adminInfo', response.data.admin) uni.setStorageSync('tokenExpireTime', Date.now() + `365 *` 24 * 60 * 60 * 1000) return response } return Promise.reject(new Error(response.message || '登录失败')) })
  2. Token验证

    • 每次请求都会在请求头中携带token
    • 通过请求拦截器自动添加token

      instance.interceptors.request.use( config => { const token = uni.getStorageSync('token') if (token) { config.headers['Authorization'] = `Bearer ${token.trim()}` } return config } )
  3. 权限控制

    • 401错误处理:当token无效或过期时,自动跳转到登录页

      if (error.response.status === 401) { uni.removeStorageSync('token') uni.removeStorageSync('adminInfo') uni.removeStorageSync('tokenExpireTime') uni.showToast({ title: '登录已过期,请重新登录', icon: 'none', duration: 2000 }); setTimeout(() => { uni.reLaunch({ url: '/pages/login/index' }); }, 2000); }
  4. 权限特点

    • 使用JWT(JSON Web Token)进行身份验证
    • token有效期设置为1年(我设置的*365,默认是一天)
    • 自动处理token过期情况
    • 统一的权限错误处理机制
    • 登录状态持久化存储
  5. 安全措施

    • token存储在本地存储中
    • 请求时自动添加Bearer认证
    • 敏感操作需要重新验证
    • 登出时清除所有认证信息

这种权限管理方式的优点:

  • 无状态:服务器不需要存储session
  • 安全性:使用JWT保证数据完整性
  • 灵活性:可以携带用户信息
  • 可扩展:易于添加新的权限控制
  • 用户体验:自动处理登录状态

系统权限扩展建议

由于该系统我只实现了管理员登录,如果要支持普通用户和会员登录,可以按以下方式扩展(仅供参考):

  1. 用户角色设计(数据库设计也可以按此方式)

    // 用户角色分类 const UserRole = { ADMIN: 'admin', // 管理员 MEMBER: 'member', // 会员 USER: 'user' // 普通用户 } // 权限级别 const PermissionLevel = { SUPER_ADMIN: 3, // 超级管理员 ADMIN: 2, // 普通管理员 MEMBER: 1, // 会员 USER: 0 // 普通用户 }
  2. 登录接口扩展

    // 扩展登录方法 export const { userLogin, // 普通用户登录 memberLogin, // 会员登录 adminLogin // 管理员登录 } = { userLogin: (username, password) => instance.post('/user/login', { username, password }) .then(response => { if (response.code === 200) { uni.setStorageSync('token', response.data.token) uni.setStorageSync('userInfo', response.data.user) uni.setStorageSync('userRole', UserRole.USER) return response } return Promise.reject(new Error(response.message || '登录失败')) }), memberLogin: (username, password) => instance.post('/member/login', { username, password }) .then(response => { if (response.code === 200) { uni.setStorageSync('token', response.data.token) uni.setStorageSync('memberInfo', response.data.member) uni.setStorageSync('userRole', UserRole.MEMBER) return response } return Promise.reject(new Error(response.message || '登录失败')) }) }
  3. 权限验证中间件

    // 权限验证工具 const checkPermission = (requiredLevel) => { const userRole = uni.getStorageSync('userRole') const currentLevel = PermissionLevel[userRole.toUpperCase()] return currentLevel >= requiredLevel } // 路由守卫 const routerGuard = (to, from, next) => { const token = uni.getStorageSync('token') if (!token) { next('/login') return } // 根据路由meta信息检查权限 if (to.meta.requiredLevel && !checkPermission(to.meta.requiredLevel)) { uni.showToast({ title: '权限不足', icon: 'none' }) next(from.path) return } next() }
  4. API权限控制

    // 请求拦截器中添加角色验证 instance.interceptors.request.use( config => { const token = uni.getStorageSync('token') const userRole = uni.getStorageSync('userRole') if (token) { config.headers['Authorization'] = `Bearer ${token.trim()}` config.headers['X-User-Role'] = userRole } return config } )
  5. 功能权限控制示例

    // 会员管理功能 const memberManagement = { // 只有管理员可以查看所有会员 getAllMembers: () => { if (!checkPermission(PermissionLevel.ADMIN)) { return Promise.reject(new Error('权限不足')) } return instance.get('/member/list') }, // 会员可以查看自己的信息 getMemberInfo: (id) => { const currentUserId = uni.getStorageSync('memberInfo')?.id if (id !== currentUserId && !checkPermission(PermissionLevel.ADMIN)) { return Promise.reject(new Error('权限不足')) } return instance.get(`/member/${id}`) } }
  6. 页面权限控制

    // 页面配置示例 const pages = [ { path: '/admin/dashboard', meta: { requiredLevel: PermissionLevel.ADMIN, title: '管理后台' } }, { path: '/member/profile', meta: { requiredLevel: PermissionLevel.MEMBER, title: '会员中心' } }, { path: '/user/home', meta: { requiredLevel: PermissionLevel.USER, title: '用户首页' } } ]

6. 微信通知功能

项目中还实现了微信通知功能 (我这里是用的是一个第三方服务号发送的通知),用于提醒会员到期:

sendWechatNotification: (expiringMembers, expiredMembers) => { const token = 'dyhrw3Uf5Q*****8orF7J8yW0'; const title = 'XX健身-会员到期提醒'; // 格式化日期 const currentDate = new Date().toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit' }); // 构建通知内容 let content = `提醒时间: ${currentDate}\n\n`; // ... 构建会员信息内容 // 发送请求 return new Promise((resolve, reject) => { uni.request({ url: `/api/wx-push/${token}.send`, method: 'POST', data: { text: title, desp: content }, success: (res) => resolve(res.data), fail: (err) => reject(err) }); }); }

这个功能的特点:

  • 使用uni.request发送请求
  • 支持Promise异步处理
  • 格式化日期显示
  • 构建结构化的通知内容

总结

这个项目展示了如何在一个uni-app项目中:

  1. 使用axios进行API请求管理
  2. 实现完整的请求拦截和响应拦截
  3. 统一处理错误和提示
  4. 封装API方法
  5. 实现微信通知等特色功能

对于想要学习uni-app开发的同学来说,这个项目是一个很好的参考案例。它展示了如何组织代码、处理API请求、管理状态等实际开发中常见的问题。

学习建议

  1. 先理解项目的基本架构和目录结构
  2. 重点学习API请求的封装方式
  3. 掌握错误处理和拦截器的使用
  4. 了解uni-app特有的API(如uni.request、uni.showToast等)
  5. 尝试自己实现一些简单的功能,如会员信息的增删改查
如果觉得我的文章对你有用,请随意赞赏
END
本文作者:
文章标题:基于uniapp+vant的健身会员管理系统h5前端
本文地址:https://blog.ybyq.wang/archives/18.html
版权说明:若无注明,本文皆Xuan's blog原创,转载请保留文章出处。