# uniapp记账app **Repository Path**: xx_sir/uniapp-accounting-app ## Basic Information - **Project Name**: uniapp记账app - **Description**: 基于 uniapp + sqlite 开发的离线记账app - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 6 - **Created**: 2024-03-09 - **Last Updated**: 2024-03-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 离线记账app 根目录下有 apk 文件, 可直接安装查看 - 账单明细: - 显示当月收支明细, 月收入, 月支出, 月结余 - 左滑编辑/删除明细 - 账单: 显示当年收支明细, 年收入, 年支出, 年结余 - 统计: 显示记账至今收入, 支出, 结余; 年度收支明细 - 设置 - 数据迁移: 由于数据库存在本地, 更换设备前需要导出数据, 在新设备导入旧数据 - 记账: - 选择收入或支出类型, 输入金额, 备注(可选), 选择日期, 图片(可选) - 添加, 编辑, 删除 自定义类型 - 图表 - 按照周, 月, 年 显示收入或支出折线图, 饼图, 排行榜 - 排行榜分类详情 ## 运行 - 使用 hbuiderX 打开项目, 点击 运行 -> 运行到手机或模拟器 -> 运行到APP基座 ## 打包 - 点击 发行 -> 原生app云打包 ## 插件 - uni-ui - 秋云chart - image-tool base64转path 实现保存base64图片到本地相册 - pinia - windi-css - sqlite ## 数据库 ### 数据表 - 收支类型数据表 tb_type | 字段 | 字段类型 | 描述 | | --------- | -------- | ------------------------------- | | id | integer | 主键 | | title | text | 类型名称 | | icon | text | 图标类名 | | type | integer | 1收入,0支出 | | is_custom | integer | 1自定义类型,0初始化类型;默认0 | - 账单记录表 tb_record | 字段 | 字段类型 | 描述 | | ----------- | -------- | -------- | | id | integer | 主键 | | type_id | integer | 类型id | | num | real | 金额 | | create_time | text | 创建时间 | | remark | text | 备注内容 | | image | blob | 图片 | ### 数据库初始化 #### 连接sqlite数据库 使用 5+app 的 plus.sqlite,增删改查方法已封装在 common/sqlite.js 中 #### 创建数据库表 在本地存储一个初始化标志,若标志为 0,创建数据表,插入基本数据 app.vue ```js onLaunch: async function() { const isInitSqlite = uni.getStorageSync('isInitSqlite') || '0' // 初始化数据库 if(isInitSqlite==0) { uni.showLoading({title:'正在初始化...'}) await init() } // 将收支类型数据存储到pinia const typeStore = useTypeStore() await typeStore.getData() }, ``` api/api.js ```js // 创建收支类型表,并插入初始数据 async function createType() { // 删除原数据表 try{ await db.dropTable('tb_type') }catch(e){ //TODO handle the exception console.log(e) return false } // 创建类型表 const data = '"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"title" TEXT,"icon" TEXT,"type" integer, "is_custom" integer DEFAULT 0'; try{ await db.createTable('tb_type',data) }catch(e){ //TODO handle the exception console.log(e) return false } // 字段 const col = "'title','icon','type'" // 数据 const payType = [ { title:'餐饮', icon:'icon-canyin', },{ title:'购物', icon:'icon-cart', },{ title:'日用', icon:'icon-shijin', },{ title:'交通', icon:'icon-jiaotong', },{ title:'蔬菜', icon:'icon-huluobu', },{ title:'水果', icon:'icon-shuiguo', },{ title:'零食', icon:'icon-lingshi', },{ title:'运动', icon:'icon-sport', },{ title:'娱乐', icon:'icon-yule', },{ title:'服饰', icon:'icon-Txu', },{ title:'美容', icon:'icon-huazhuangjing', },{ title:'住房', icon:'icon-zhufang', },{ title:'居家', icon:'icon-jujiashenghuo', },{ title:'社交', icon:'icon-juhui', },{ title:'旅行', icon:'icon-feiji', },{ title:'数码', icon:'icon-shujuxian', },{ title:'汽车', icon:'icon-qiche', },{ title:'医疗', icon:'icon-yiliao', },{ title:'学习', icon:'icon-xuexi', },{ title:'礼金', icon:'icon-hongbao', },{ title:'办公', icon:'icon-bangongyongpin', },{ title:'维修', icon:'icon-weixiu', },{ title:'捐赠', icon:'icon-gongyi01', },{ title:'快递', icon:'icon-kuaidi1', }] const incomeType = [ { title:'工资', icon:'icon-gongziqiarenzheng', },{ title:'兼职', icon:'icon-jianzhi', },{ title:'理财', icon:'icon-licai', },{ title:'礼金', icon:'icon-hongbao', },{ title:'转账', icon:'icon-zhuanzhang', },{ title:'其它', icon:'icon-yulebao', } ] const dataStr = (payType.map(item => `('${item.title}','${item.icon}',0)`)).join(',')+','+(incomeType.map(item => `('${item.title}','${item.icon}',1)`)).join(',') // 插入类型数据 try{ await db.insertTableData('tb_type',dataStr,col) }catch(e){ //TODO handle the exception console.log(JSON.stringify(e)) return false } return true } // 创建记录表 async function createRecord() { // 删除原数据表 try{ await db.dropTable('tb_record') }catch(e){ //TODO handle the exception return false } // 创建记录表 const data = `"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"type_id" INTEGER,"num" real,"create_time" text,"remark" TEXT, "image" blob DEFAULT ''` try{ await db.createTable('tb_record',data) }catch(e){ //TODO handle the exception return false } return true } export async function init() { await openDB(); const bolType = await createType() const bolRecord = await createRecord() uni.hideLoading(); if(bolType&&bolRecord) { uni.showToast({ title:'初始化成功!', }) uni.setStorageSync('isInitSqlite', '1'); } else { uni.showModal({ title:'提示', content:"初始化数据失败,请重新进入app", showCancel:false }) } await closeDB() } ```