大家好,我是java1234_小锋老师,分享一套微信小程序系统小店会员管理(适合理发店,宠物店等各种小店),使用 云函数 + 云数据库 。
项目简介
随着移动互联网的快速发展和微信生态的日益完善,微信小程序凭借其"即用即走"、无需安装的特点,成为线下商户数字化转型的重要工具。传统线下小店在会员管理方面普遍存在管理方式落后、信息化程度低、会员信息易丢失等问题,严重影响了门店的运营效率和服务质量。
本文设计并实现了一个基于微信小程序的小店会员管理系统,采用微信云开发技术架构,前端使用微信小程序原生框架(WXML/WXSS/JS),后端采用云函数(Node.js)作为服务层,数据存储使用微信云数据库(文档型NoSQL数据库)。系统实现了用户手机号授权登录、会员储值充值、消费扣费管理、消费与充值流水查询、店铺信息展示与管理、消费项目与常用价格维护等核心功能。系统采用单云函数多路由架构,通过中间件管道实现了鉴权、限流和操作日志等横切关注点。
源码下载
链接: pan.baidu.com/s/1Ae2eAF4A…
提取码: 1234
相关截图
核心代码
const cloud = require('wx-server-sdk')
// 云函数初始化:使用当前环境变量动态选择环境
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
// 鉴权:判断是否已注册/是否管理员等
const { authenticate } = require('./middleware/auth')
// 频率限制:限制单用户/管理员群体的调用次数
const { checkRateLimit } = require('./middleware/rateLimit')
// 操作日志:记录管理员/会员的关键操作
const { logOperation } = require('./middleware/logger')
// 业务控制器:用户相关接口
const userCtrl = require('./controllers/user')
// 业务控制器:店铺信息相关接口
const shopCtrl = require('./controllers/shop')
// 业务控制器:会员查询相关接口
const memberCtrl = require('./controllers/member')
// 业务控制器:充值/消费/记录查询相关接口
const financeCtrl = require('./controllers/finance')
// 业务控制器:后台配置(项目/价格/警报/日志)相关接口
const systemCtrl = require('./controllers/system')
// 开发期:初始化集合与测试数据(生产应禁用)
const initDbCtrl = require('./controllers/initDb')
// 无需登录即可访问的接口(仅做 openid 校验)
const PUBLIC_ACTIONS = ['user.login', 'user.getProfile']
// 开发期:允许免鉴权执行的接口(仍校验 openid)
const DEV_NO_AUTH_ACTIONS = ['initDb.run']
// 需要管理员权限的接口列表
const ADMIN_ACTIONS = [
'shop.updateInfo',
'member.list', 'member.getByMemberNo',
'finance.recharge', 'finance.consume', 'finance.getMemberRecords',
'system.getItems', 'system.addItem', 'system.deleteItem',
'system.getPrices', 'system.addPrice', 'system.deletePrice',
'system.getAlerts', 'system.dismissAlert', 'system.getAdminLogs',
// 'system.initDB' 已移除(改为启动自动 initDb.run)
]
// action -> 处理函数 的路由映射表
const ROUTE_MAP = {
'user.login': userCtrl.login,
'user.getProfile': userCtrl.getProfile,
'user.updateName': userCtrl.updateName,
'shop.getInfo': shopCtrl.getInfo,
'shop.updateInfo': shopCtrl.updateInfo,
'member.list': memberCtrl.list,
'member.getByMemberNo': memberCtrl.getByMemberNo,
'finance.recharge': financeCtrl.recharge,
'finance.consume': financeCtrl.consume,
'finance.getMyRecords': financeCtrl.getMyRecords,
'finance.getMemberRecords': financeCtrl.getMemberRecords,
'system.getItems': systemCtrl.getItems,
'system.addItem': systemCtrl.addItem,
'system.deleteItem': systemCtrl.deleteItem,
'system.getPrices': systemCtrl.getPrices,
'system.addPrice': systemCtrl.addPrice,
'system.deletePrice': systemCtrl.deletePrice,
'system.getAlerts': systemCtrl.getAlerts,
'system.dismissAlert': systemCtrl.dismissAlert,
'system.getAdminLogs': systemCtrl.getAdminLogs,
'initDb.run': initDbCtrl.run
}
/**
* 云函数入口。
* - **入参**: event.action 指定路由;其余字段为各接口参数
* - **鉴权**: 基于 openid 判断登录/管理员权限
* - **限流**: 按月/按日统计并触发警报
* - **返回**: { code, data|message }
*/
exports.main = async (event, context) => {
try {
// 前端传入的动作名(如 'user.login')
const { action } = event
if (!action || !ROUTE_MAP[action]) {
return { code: 400, message: '无效的操作' }
}
// 微信上下文(包含 OPENID 等身份信息)
const wxContext = cloud.getWXContext()
// 当前调用者 openid(唯一标识)
const openid = wxContext.OPENID
if (!openid) {
return { code: 401, message: '身份验证失败,无法获取openid' }
}
// 开发期:启动自动初始化(无鉴权,但仍校验 openid)
if (DEV_NO_AUTH_ACTIONS.includes(action)) {
const handler = ROUTE_MAP[action]
const result = await handler(event)
return { code: 0, data: result }
}
// 鉴权结果:registered/isAdmin/userInfo/phone 等
const authResult = await authenticate(openid)
// 限流检查(管理员与普通用户规则不同)
const rateLimitResult = await checkRateLimit(openid, authResult.isAdmin, authResult.phone)
if (rateLimitResult.limited) {
return { code: 429, message: rateLimitResult.message }
}
// 非公开接口必须先完成手机号授权登录
if (!PUBLIC_ACTIONS.includes(action) && !authResult.registered) {
return { code: 403, message: '请先完成手机号授权登录' }
}
// 管理员接口:校验管理员权限
if (ADMIN_ACTIONS.includes(action) && !authResult.isAdmin) {
return { code: 403, message: '权限不足,需要管理员权限' }
}
// 命中路由并执行处理器
const handler = ROUTE_MAP[action]
const result = await handler(event, authResult)
// 异步写操作日志(不影响主流程返回)
logOperation(authResult, action, event).catch(err => {
console.error('日志记录失败:', err)
})
return { code: 0, data: result }
} catch (err) {
console.error('云函数执行错误:', err)
return { code: 500, message: err.message || '服务器内部错误' }
}
}