# 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()
}
```