微信小程序记账类MVP实战:从本地存储到云开发的架构演进
微信小程序记账类MVP实战:从本地存储到云开发的架构演进
本文记录「猪猪记账罐」小程序的架构选型与工程实践,供类似项目参考。
1. 背景与目标
项目背景
「猪猪记账罐」是一款面向个人用户的微信记账小程序。
以下是小程序的一些截图,供大家学习参考。
核心诉求
- 覆盖记账全流程:记账→统计→预算→目标→导入导出
- 不做过度复杂度,保持轻量
- 保留从本地存储到云开发的演进空间
技术挑战
- 微信小程序包体积限制
- 离线可用与数据同步的平衡
- 多人协作场景的权限控制
2. 技术栈概览
| 层级 | 技术选型 |
|---|---|
| 框架 | 微信小程序原生(WXML/WXSS/JS) |
| UI 组件 | TDesign 小程序组件(按需引入) |
| 图表 | ECharts(小程序适配版) |
| 数据层 | api/封装业务逻辑,utils/负责存储 |
| 同步策略 | 本地存储 ↔ 云开发,可通过开关切换 |
3. 数据模型设计
核心实体
// 账单记录{id:string,// UUIDamount:number,// 金额(分为单位避免精度问题)type:'income'|'expense',category:string,// 分类IDcategoryName:string,// 分类名称(冗余存储便于展示)categoryIcon:string,// 分类图标account:string,// 账户IDaccountName:string,// 账户名称date:string,// YYYY-MM-DDnote:string,// 备注createdAt:number,// 创建时间戳updatedAt:number// 更新时间戳}// 分类{id:string,name:string,icon:string,type:'income'|'expense',order:number,isDefault:boolean}// 账户{id:string,name:string,type:'cash'|'wechat'|'alipay'|'bankcard'|'other',balance:number,order:number}// 预算{id:string,year:number,month:number,type:'total'|'category',categoryId:string|null,amount:number,alertThreshold:number// 提醒阈值(如0.8)}// 储蓄目标{id:string,name:string,targetAmount:number,currentAmount:number,deadline:string|null,createdAt:number}索引设计
// 本地存储键设计constStorageKeys={RECORDS:'piggy_records',// 账单列表CATEGORIES:'piggy_categories',// 分类列表ACCOUNTS:'piggy_accounts',// 账户列表BUDGETS:'piggy_budgets',// 预算列表GOALS:'piggy_goals',// 储蓄目标SETTINGS:'piggy_settings',// 用户设置LAST_SYNC:'piggy_last_sync'// 最后同步时间};4. 模块划分
按用户动线拆页面:
├── pages/index # 首页/快捷记账入口 ├── pages/record # 记一笔(完整版) ├── pages/flow # 流水列表 ├── pages/statistics # 统计图表 ├── pages/budget # 预算管理 ├── pages/goal # 储蓄目标 ├── pages/category # 分类管理 ├── pages/account # 账户管理 ├── pages/import # 导入导出 ├── pages/mine # 我的/设置 └── pages/family # 家庭账本(扩展)分包策略
{"subPackages":[{"root":"pages/category","name":"category"},{"root":"pages/account","name":"account"},{"root":"pages/family","name":"family"}]}非核心页面放入分包,控制主包体积。
5. 核心功能实现
5.1 记一笔流程
// 简化流程asyncfunctionaddRecord(data){// 1. 验证数据if(!data.amount||data.amount<=0){thrownewError('金额必须大于0');}// 2. 构建记录constrecord={id:generateUUID(),...data,createdAt:Date.now(),updatedAt:Date.now()};// 3. 保存到本地awaitsaveRecord(record);// 4. 更新账户余额awaitupdateAccountBalance(data.account,data.type,data.amount);// 5. 检查预算提醒awaitcheckBudgetAlert(record);returnrecord;}5.2 预算提醒
asyncfunctioncheckBudgetAlert(record){if(record.type!=='expense')return;// 获取本月该分类支出constmonthTotal=awaitgetMonthCategoryTotal(record.category,record.date);// 获取预算constbudget=awaitgetBudget(record.category,record.date);if(!budget)return;// 检查是否超过阈值constused=monthTotal/budget.amount;if(used>=budget.alertThreshold){constpercent=Math.round(used*100);wx.showToast({title:`预算${percent}%已用完`,icon:'warning'});}}5.3 统计计算
asyncfunctiongetMonthStatistics(year,month){constrecords=awaitgetRecordsByMonth(year,month);// 按分类聚合constbyCategory={};lettotalExpense=0;lettotalIncome=0;records.forEach(r=>{if(r.type==='expense'){totalExpense+=r.amount;byCategory[r.categoryName]=(byCategory[r.categoryName]||0)+r.amount;}else{totalIncome+=r.amount;}});// 计算百分比constcategoryStats=Object.entries(byCategory).map(([name,amount])=>({name,amount,percent:Math.round((amount/totalExpense)*100)})).sort((a,b)=>b.amount-a.amount);return{totalIncome,totalExpense,balance:totalIncome-totalExpense,byCategory:categoryStats};}6. CSV 导入导出
6.1 导入流程
asyncfunctionimportFromCSV(filePath){// 1. 选择文件const[{path}]=awaitwx.chooseMessageFile({count:1});// 2. 读取文件constresult=awaitwx.getFileSystemManager().readFile({filePath:path,encoding:'utf-8'});// 3. 解析CSVconstlines=result.data.split('\n');constheaders=parseCSVLine(lines[0]);// 4. 字段映射(支付宝/微信格式对齐)constmapping={'交易时间':'date','交易对方':'note','金额':'amount','收/支':'type'};// 5. 逐行解析并导入constrecords=[];for(leti=1;i<lines.length;i++){constvalues=parseCSVLine(lines[i]);constrecord=mapToRecord(values,headers,mapping);if(record)records.push(record);}// 6. 去重检查constexisting=awaitgetAllRecords();constnewRecords=records.filter(r=>!isDuplicate(r,existing));// 7. 批量保存awaitsaveRecords(newRecords);return{total:records.length,imported:newRecords.length};}6.2 导出功能
functionexportToCSV(records){constheaders=['日期','类型','分类','账户','金额','备注'];constrows=records.map(r=>[r.date,r.type==='income'?'收入':'支出',r.categoryName,r.accountName,(r.amount/100).toFixed(2),r.note]);constcsv=[headers,...rows].map(row=>row.join(',')).join('\n');wx.getFileSystemManager().writeFile({filePath:`${wx.env.USER_DATA_PATH}/export.csv`,data:csv,success:()=>{wx.showModal({title:'导出成功',content:'文件已保存,是否打开?',success:(res)=>{if(res.confirm){wx.openDocument({filePath:`${wx.env.USER_DATA_PATH}/export.csv`});}}});}});}7. 性能优化
按需加载图表
// 统计页使用条件加载onLoad(){if(needChart){import('../../lib/echarts'asec).then(ec=>{this.initChart(ec);});}}TDesign 按需引入
{"usingComponents":{"t-button":"tdesign-miniprogram/button/button","t-icon":"tdesign-miniprogram/icon/icon","t-navbar":"tdesign-miniprogram/navbar/navbar","t-dialog":"tdesign-miniprogram/dialog/dialog","t-toast":"tdesign-miniprogram/toast/toast"}}安全区处理
<!-- 自定义导航栏 --><viewclass="custom-nav"style="padding-top:{{statusBarHeight}}px"><t-navbartitle="猪猪记账罐"/></view>8. 云开发演进思路
本地优先
MVP 阶段优先本地存储,保证离线可用。
云函数设计
// 云函数:添加记录asyncfunctionaddRecord(event){const{OPENID}=wx.cloud.getUserInfo();constdb=wx.cloud.database();returnawaitdb.collection('records').add({data:{openid:OPENID,...event.data,createdAt:db.serverDate()}});}数据同步策略
- 写入:先本地,再异步同步到云端
- 读取:优先本地,失败则拉取云端
- 冲突:按时间戳,以最新为准
9. 后续迭代方向
- 强化统计可视化(更多图表类型)
- 家庭账本协作能力
- PDF 月报导出
- 合规探索下的 AI 录入辅助
- 预算智能推荐
10. 总结
「猪猪记账罐」是一个典型的微信小程序 MVP 项目:
- 技术选型:小程序原生 + TDesign,平衡开发效率与体验
- 架构设计:本地优先,云开发可演进
- 性能优化:按需加载,控制包体积
- 用户体验:路径短,功能实用,不做过度复杂
希望本文能为类似项目提供参考。
Tags:微信小程序云开发TDesignMVP前端开发记账应用JavaScript
