commit e257f2009e6f810ec2120dad049ebde1b177457c
Author: xxk <2584008029@qq.com>
Date: Thu Jun 11 09:53:11 2026 +0800
第一次上传
diff --git a/ad.txt b/ad.txt
new file mode 100644
index 0000000..40c8e93
--- /dev/null
+++ b/ad.txt
@@ -0,0 +1,24 @@
+=== 插屏
+// 在页面中定义插屏广告
+let interstitialAd = null
+
+// 在页面onLoad回调事件中创建插屏广告实例
+if (wx.createInterstitialAd) {
+ interstitialAd = wx.createInterstitialAd({
+ adUnitId: 'adunit-0abc32053b19a4e9'
+ })
+ interstitialAd.onLoad(() => {})
+ interstitialAd.onError((err) => {
+ console.error('插屏广告加载失败', err)
+ })
+ interstitialAd.onClose(() => {})
+}
+
+// 在适合的场景显示插屏广告
+if (interstitialAd) {
+ interstitialAd.show().catch((err) => {
+ console.error('插屏广告显示失败', err)
+ })
+}
+
+=== 原生广告
\ No newline at end of file
diff --git a/demant.txt b/demant.txt
new file mode 100644
index 0000000..83551a1
--- /dev/null
+++ b/demant.txt
@@ -0,0 +1,73 @@
+微信小程序「账单小管家」精简版开发需求报告
+
+一、项目概述
+
+定位:极简无广告、面向年轻人(学生/职场新人/情侣/合租党)的轻量化记账工具,核心解决“快速记账、清晰控支、多人AA”需求,适配微信生态,操作极简、数据安全。
+
+技术基础:本地存储(无需云开发),微信授权登录(仅用于身份标识,数据不上传),无需单独注册,数据仅保存在本地设备。
+
+设计风格:简约清新,支持深色模式,无广告,记账步骤≤3步。
+
+二、核心功能模块(必做+高价值)
+
+1. 首页(核心入口)
+
+- 实时显示今日/本月收支、结余、预算进度条
+
+- 悬浮一键记账按钮,常用分类快捷入口
+
+- 最近账单快速查看,下拉刷新,长按编辑/删除
+
+2. 账单管理(核心功能)
+
+- 新增/编辑/删除账单:支持收支切换、金额输入、分类选择、备注、时间调整、账户选择
+
+- 筛选查询:按时间、分类、账户、金额区间筛选,关键词搜索
+
+- 支持批量删除账单
+
+3. 预算管理
+
+- 设置月度总预算、分类单独预算
+
+- 超支提醒(小程序红点+微信服务通知)
+
+- 显示剩余日均可花金额
+
+4. 数据统计与报表
+
+- 可视化图表:支出分类饼图、每日趋势折线图、月度对比柱状图
+
+- 支持Excel账单导出、月度消费海报生成(可分享)
+
+6. 个人中心与设置
+
+- 微信授权登录,主题切换(浅/深色)
+
+- 数据本地备份(导出本地文件)与恢复,清除缓存
+
+- 反馈入口、关于我们
+
+三、增强功能(二期迭代)
+
+- 固定收支管理(自动记账)
+
+- 存款目标设置与进度显示
+
+- 记账习惯打卡、月度勋章
+
+四、技术与微信能力要求
+
+- 本地存储:设计用户、账单、分类等相关本地数据表,确保数据仅保存在设备本地,不进行云端上传。
+
+- 微信能力:仅保留授权登录(身份标识)、海报生成(本地生成,不涉及云端)功能,无需云存储、好友/群分享、服务通知。
+
+- 交互:手势操作、柔和动画,适配手机各机型
+
+五、开发优先级
+
+- 一期(必做):首页+账单管理+预算管理+报表+个人中心
+
+- 二期(迭代):固定收支+存款目标+记账打卡(均为本地功能)
+
+- 三期(迭代):增强功能+细节优化
diff --git a/uniapp.zip b/uniapp.zip
new file mode 100644
index 0000000..242ab16
Binary files /dev/null and b/uniapp.zip differ
diff --git a/uniapp/App.vue b/uniapp/App.vue
new file mode 100644
index 0000000..aa0b1ec
--- /dev/null
+++ b/uniapp/App.vue
@@ -0,0 +1,185 @@
+
+
+
+
+
diff --git a/uniapp/components/AppTabBar.vue b/uniapp/components/AppTabBar.vue
new file mode 100644
index 0000000..48a08e4
--- /dev/null
+++ b/uniapp/components/AppTabBar.vue
@@ -0,0 +1,85 @@
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
diff --git a/uniapp/components/BillEditorPopup.vue b/uniapp/components/BillEditorPopup.vue
new file mode 100644
index 0000000..1b8e12b
--- /dev/null
+++ b/uniapp/components/BillEditorPopup.vue
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
diff --git a/uniapp/components/SectionCard.vue b/uniapp/components/SectionCard.vue
new file mode 100644
index 0000000..c903d95
--- /dev/null
+++ b/uniapp/components/SectionCard.vue
@@ -0,0 +1,45 @@
+
+
+
+
+ {{ title }}
+ {{ subtitle }}
+
+
+
+
+
+
+
+
+
+
diff --git a/uniapp/index.html b/uniapp/index.html
new file mode 100644
index 0000000..b5d330d
--- /dev/null
+++ b/uniapp/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uniapp/main.js b/uniapp/main.js
new file mode 100644
index 0000000..c1caf36
--- /dev/null
+++ b/uniapp/main.js
@@ -0,0 +1,22 @@
+import App from './App'
+
+// #ifndef VUE3
+import Vue from 'vue'
+import './uni.promisify.adaptor'
+Vue.config.productionTip = false
+App.mpType = 'app'
+const app = new Vue({
+ ...App
+})
+app.$mount()
+// #endif
+
+// #ifdef VUE3
+import { createSSRApp } from 'vue'
+export function createApp() {
+ const app = createSSRApp(App)
+ return {
+ app
+ }
+}
+// #endif
\ No newline at end of file
diff --git a/uniapp/manifest.json b/uniapp/manifest.json
new file mode 100644
index 0000000..6a4a017
--- /dev/null
+++ b/uniapp/manifest.json
@@ -0,0 +1,65 @@
+{
+ "name" : "账单小管家",
+ "appid" : "__UNI__8989AB7",
+ "description" : "本地记账、预算管理与消费统计微信小程序",
+ "versionName" : "1.0.0",
+ "versionCode" : "100",
+ "transformPx" : false,
+ "app-plus" : {
+ "usingComponents" : true,
+ "nvueStyleCompiler" : "uni-app",
+ "compilerVersion" : 3,
+ "splashscreen" : {
+ "alwaysShowBeforeRender" : true,
+ "waiting" : true,
+ "autoclose" : true,
+ "delay" : 0
+ },
+ "modules" : {},
+ "distribute" : {
+ "android" : {
+ "permissions" : [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ]
+ },
+ "ios" : {},
+ "sdkConfigs" : {}
+ }
+ },
+ "quickapp" : {},
+ "mp-weixin" : {
+ "appid" : "wx8a928bb8a3945a16",
+ "setting" : {
+ "urlCheck" : false,
+ "minified" : true
+ },
+ "usingComponents" : true
+ },
+ "mp-alipay" : {
+ "usingComponents" : true
+ },
+ "mp-baidu" : {
+ "usingComponents" : true
+ },
+ "mp-toutiao" : {
+ "usingComponents" : true
+ },
+ "uniStatistics" : {
+ "enable" : false
+ },
+ "vueVersion" : "3"
+}
diff --git a/uniapp/pages.json b/uniapp/pages.json
new file mode 100644
index 0000000..5f988ca
--- /dev/null
+++ b/uniapp/pages.json
@@ -0,0 +1,66 @@
+{
+ "pages": [
+ {
+ "path": "pages/home/index",
+ "style": {
+ "navigationBarTitleText": "首页",
+ "enablePullDownRefresh": true
+ }
+ },
+ {
+ "path": "pages/bills/index",
+ "style": {
+ "navigationBarTitleText": "账单管理",
+ "enablePullDownRefresh": true
+ }
+ },
+ {
+ "path": "pages/budget/index",
+ "style": {
+ "navigationBarTitleText": "预算管理"
+ }
+ },
+ {
+ "path": "pages/stats/index",
+ "style": {
+ "navigationBarTitleText": "数据报表"
+ }
+ },
+ {
+ "path": "pages/mine/index",
+ "style": {
+ "navigationBarTitleText": "我的"
+ }
+ },
+ {
+ "path": "pages/mine/profile/index",
+ "style": {
+ "navigationBarTitleText": "账户资料"
+ }
+ },
+ {
+ "path": "pages/mine/backup/index",
+ "style": {
+ "navigationBarTitleText": "备份与恢复"
+ }
+ },
+ {
+ "path": "pages/mine/guide/index",
+ "style": {
+ "navigationBarTitleText": "使用帮助"
+ }
+ },
+ {
+ "path": "pages/mine/about/index",
+ "style": {
+ "navigationBarTitleText": "关于与隐私"
+ }
+ }
+ ],
+ "globalStyle": {
+ "navigationBarTextStyle": "black",
+ "navigationBarBackgroundColor": "#F4EDE3",
+ "backgroundColor": "#F4EDE3",
+ "backgroundTextStyle": "dark"
+ }
+}
diff --git a/uniapp/pages/bills/index.vue b/uniapp/pages/bills/index.vue
new file mode 100644
index 0000000..2577d24
--- /dev/null
+++ b/uniapp/pages/bills/index.vue
@@ -0,0 +1,492 @@
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+ {{ item.label }}
+
+
+ {{ selectedMonthLabel }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ selectedCategoryName }}分类
+
+
+ {{ selectedAccountName }}账户
+
+
+
+ 清空筛选
+ 新增账单
+
+
+
+
+
+ {{ selectionMode ? '退出批量' : '批量删除' }}
+
+
+
+ 支出
+
+ {{ formatCurrency(summaryExpense) }}
+
+
+ 收入
+
+ {{ formatCurrency(summaryIncome) }}
+
+
+ 结余
+
+ {{ formatCurrency(summaryIncome - summaryExpense) }}
+
+
+
+
+
+
+
+
+ {{ getCategory(bill).name || '未分类' }}
+ {{ getAccount(bill).name || '账户' }} · {{ formatDateLabel(bill.date) }} · {{ bill.note || '无备注' }}
+
+
+
+ {{ bill.type === 'income' ? '+' : '-' }}{{ formatCurrency(bill.amount).replace('¥', '') }}
+
+
+
+
+ 当前筛选条件下没有符合条件的账单记录。
+
+
+
+
+ 已选 {{ selectedIds.length }} 笔
+ 全选
+ 删除所选
+
+
+
+
+
+
+
+
+
+
diff --git a/uniapp/pages/budget/index.vue b/uniapp/pages/budget/index.vue
new file mode 100644
index 0000000..46e0f54
--- /dev/null
+++ b/uniapp/pages/budget/index.vue
@@ -0,0 +1,233 @@
+
+
+
+
+
+ 本月总预算
+ {{ formatCurrency(totalBudget) }}
+
+
+ 本月已支出
+ {{ formatCurrency(spentTotal) }}
+
+
+
+
+
+
+
+
+
+ 保存
+
+
+
+
+
+
+ {{ item.name }}
+ 预算 {{ formatCurrency(item.budget) }},已支出 {{ formatCurrency(item.spent) }}
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+ 已花 {{ formatCurrency(item.spent) }}
+
+
+
+
+
+
+
+ 保存
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uniapp/pages/home/index.vue b/uniapp/pages/home/index.vue
new file mode 100644
index 0000000..110c037
--- /dev/null
+++ b/uniapp/pages/home/index.vue
@@ -0,0 +1,473 @@
+
+
+
+ {{ todayLabel }}
+ 账单小管家
+
+
+
+ 今日支出
+ {{ formatCurrency(todayExpense) }}
+
+
+ 本月支出
+ {{ formatCurrency(monthExpense) }}
+
+
+ 本月收入
+ {{ formatCurrency(monthIncome) }}
+
+
+ 本月结余
+ {{ formatCurrency(balance) }}
+
+
+
+
+
+
+
+
+ {{ formatCurrency(remainingBudget) }}
+
+ 剩余预算
+
+
+ 预算使用
+
+ {{ budgetProgressLabel }}
+
+
+
+
+
+
+ {{ totalBudget ? `总预算 ${formatCurrency(totalBudget)}` : '当前尚未设置月预算' }}
+ {{ dailyBudgetText }}
+
+
+ 去设置预算
+
+
+
+
+
+ 记录支出
+ 记录收入
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+ 查看全部
+
+
+
+
+
+
+ {{ getCategory(bill).name || '未分类' }}
+ {{ getAccount(bill).name || '账户' }} · {{ formatDateLabel(bill.date) }}
+
+
+
+
+ {{ bill.type === 'income' ? '+' : '-' }}{{ formatCurrency(bill.amount).replace('¥', '') }}
+
+ {{ bill.note || '无备注' }}
+
+
+
+
+ 还没有账单记录,先记下第一笔收支。
+ 立即记账
+
+
+
+ + 记一笔
+
+
+
+
+
+
+
+
diff --git a/uniapp/pages/index/index.vue b/uniapp/pages/index/index.vue
new file mode 100644
index 0000000..ec0ec26
--- /dev/null
+++ b/uniapp/pages/index/index.vue
@@ -0,0 +1,52 @@
+
+
+
+
+ {{title}}
+
+
+
+
+
+
+
diff --git a/uniapp/pages/mine/about/index.vue b/uniapp/pages/mine/about/index.vue
new file mode 100644
index 0000000..9941e3d
--- /dev/null
+++ b/uniapp/pages/mine/about/index.vue
@@ -0,0 +1,177 @@
+
+
+
+ ABOUT
+ 关于与隐私
+ 查看应用定位、数据说明与发布前应补齐的正式信息。
+
+
+ 发布说明
+
+
+
+
+
+ 账单小管家
+
+ 定位为轻量、无广告的本地记账工具,适合学生、情侣、合租和个人日常记账场景。
+
+
+
+
+
+
+ 本地存储
+ 账单、预算、分类、账户和设置默认保存在当前设备本地。
+
+
+ 本地昵称
+ 昵称仅保存在当前设备,用于个人页展示和首字头像。
+
+
+ 数据迁移
+ 如需换机迁移,可在“备份与恢复”中导出 JSON 并在新设备恢复。
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uniapp/pages/mine/backup/index.vue b/uniapp/pages/mine/backup/index.vue
new file mode 100644
index 0000000..31323fb
--- /dev/null
+++ b/uniapp/pages/mine/backup/index.vue
@@ -0,0 +1,277 @@
+
+
+
+ BACKUP
+ 备份与恢复
+ 导出本地 JSON 备份,恢复时覆盖当前设备数据,适合换机或手动留档。
+
+ 本地文件
+ {{ store.state.settings.lastBackupAt ? '最近已备份' : '尚未备份' }}
+
+
+
+
+
+
+ 安全备份当前数据
+ 所有数据均为本地文件,不会自动上传服务器。
+
+ {{ store.state.settings.lastBackupAt ? '可继续备份' : '建议先备份' }}
+
+
+ 导出备份
+
+ 最近备份:{{ store.state.settings.lastBackupAt }}
+
+
+
+
+
+
+
+ 清空内容
+ 开始恢复
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uniapp/pages/mine/guide/index.vue b/uniapp/pages/mine/guide/index.vue
new file mode 100644
index 0000000..ef6ecff
--- /dev/null
+++ b/uniapp/pages/mine/guide/index.vue
@@ -0,0 +1,217 @@
+
+
+
+ GUIDE
+ 使用帮助
+ 通过上手步骤、常见问题和快捷入口,快速熟悉整个记账流程。
+
+ 4 个步骤
+ FAQ 指南
+
+
+
+
+
+
+ {{ item.index }}
+
+ {{ item.title }}
+ {{ item.desc }}
+
+
+
+
+
+
+
+
+ {{ item.q }}
+ {{ item.a }}
+
+
+
+
+
+
+
+ 首页记账
+
+
+ 预算设置
+
+
+ 查看报表
+
+
+ 备份恢复
+
+
+
+
+
+
+
+
+
+
diff --git a/uniapp/pages/mine/index.vue b/uniapp/pages/mine/index.vue
new file mode 100644
index 0000000..aa38acb
--- /dev/null
+++ b/uniapp/pages/mine/index.vue
@@ -0,0 +1,136 @@
+
+
+
+
+ {{ avatarText }}
+
+ {{ profileName }}
+
+
+ {{right}}
+
+
+ 浅色
+ 深色
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uniapp/pages/mine/profile/index.vue b/uniapp/pages/mine/profile/index.vue
new file mode 100644
index 0000000..897bd74
--- /dev/null
+++ b/uniapp/pages/mine/profile/index.vue
@@ -0,0 +1,255 @@
+
+
+
+ ACCOUNT
+ 账户资料
+ 管理本地昵称、显示资料与本机记账模式说明。
+
+ 本地资料
+ 本地存储
+
+
+
+
+
+ {{ avatarText }}
+
+ {{ profileName }}
+ 当前昵称仅保存在本地设备,可随时修改。
+
+ 本地
+
+
+
+
+
+ 留空时页面会统一显示“用户”。
+
+
+ 清空昵称
+ 保存昵称
+
+
+
+
+
+
+
+ 昵称首字头像
+ 当前显示 {{ avatarText }},自动根据昵称生成
+
+ 已启用
+
+
+
+ 本机记账模式
+ 账单与预算默认仅保存在当前设备本地
+
+ 默认
+
+
+
+
+
+
+
+ 0{{ index + 1 }}
+ {{ tip }}
+
+
+
+
+
+
+
+
+
diff --git a/uniapp/pages/stats/index.vue b/uniapp/pages/stats/index.vue
new file mode 100644
index 0000000..d6e2156
--- /dev/null
+++ b/uniapp/pages/stats/index.vue
@@ -0,0 +1,445 @@
+
+
+
+
+
+ {{ selectedMonthLabel }}
+
+
+
+
+ 支出
+ {{ formatCurrency(monthExpenseTotal) }}
+
+
+ 收入
+ {{ formatCurrency(monthIncomeTotal) }}
+
+
+ 结余
+ {{ formatCurrency(monthIncomeTotal - monthExpenseTotal) }}
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+ {{ formatCurrency(item.total) }} · {{ item.percentLabel }}
+
+
+
+
+ 当前月份暂无支出数据,记一笔后会自动生成图表。
+
+
+
+
+
+
+ {{ item.label }}
+ {{ item.value === 0 ? '-' : item.value }}
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+ {{ formatCurrency(item.expense) }} / {{ formatCurrency(item.income) }}
+
+
+
+
+
+
+ 导出 CSV
+ 分享摘要
+
+
+
+
+
+
+
+ {{ selectedMonthLabel }}
+ 收支月报
+ 支出 {{ formatCurrency(monthExpenseTotal) }}
+ 收入 {{ formatCurrency(monthIncomeTotal) }}
+ 结余 {{ formatCurrency(monthIncomeTotal - monthExpenseTotal) }}
+ 内容本地生成,可复制摘要或直接截图分享。
+
+
+ 复制摘要
+ 关闭
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uniapp/static/logo.png b/uniapp/static/logo.png
new file mode 100644
index 0000000..b5771e2
Binary files /dev/null and b/uniapp/static/logo.png differ
diff --git a/uniapp/uni.promisify.adaptor.js b/uniapp/uni.promisify.adaptor.js
new file mode 100644
index 0000000..5fec4f3
--- /dev/null
+++ b/uniapp/uni.promisify.adaptor.js
@@ -0,0 +1,13 @@
+uni.addInterceptor({
+ returnValue (res) {
+ if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
+ return res;
+ }
+ return new Promise((resolve, reject) => {
+ res.then((res) => {
+ if (!res) return resolve(res)
+ return res[0] ? reject(res[0]) : resolve(res[1])
+ });
+ });
+ },
+});
\ No newline at end of file
diff --git a/uniapp/uni.scss b/uniapp/uni.scss
new file mode 100644
index 0000000..b9249e9
--- /dev/null
+++ b/uniapp/uni.scss
@@ -0,0 +1,76 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+
+/* 颜色变量 */
+
+/* 行为相关颜色 */
+$uni-color-primary: #007aff;
+$uni-color-success: #4cd964;
+$uni-color-warning: #f0ad4e;
+$uni-color-error: #dd524d;
+
+/* 文字基本颜色 */
+$uni-text-color:#333;//基本色
+$uni-text-color-inverse:#fff;//反色
+$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
+$uni-text-color-placeholder: #808080;
+$uni-text-color-disable:#c0c0c0;
+
+/* 背景颜色 */
+$uni-bg-color:#ffffff;
+$uni-bg-color-grey:#f8f8f8;
+$uni-bg-color-hover:#f1f1f1;//点击状态颜色
+$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
+
+/* 边框颜色 */
+$uni-border-color:#c8c7cc;
+
+/* 尺寸变量 */
+
+/* 文字尺寸 */
+$uni-font-size-sm:12px;
+$uni-font-size-base:14px;
+$uni-font-size-lg:16px;
+
+/* 图片尺寸 */
+$uni-img-size-sm:20px;
+$uni-img-size-base:26px;
+$uni-img-size-lg:40px;
+
+/* Border Radius */
+$uni-border-radius-sm: 2px;
+$uni-border-radius-base: 3px;
+$uni-border-radius-lg: 6px;
+$uni-border-radius-circle: 50%;
+
+/* 水平间距 */
+$uni-spacing-row-sm: 5px;
+$uni-spacing-row-base: 10px;
+$uni-spacing-row-lg: 15px;
+
+/* 垂直间距 */
+$uni-spacing-col-sm: 4px;
+$uni-spacing-col-base: 8px;
+$uni-spacing-col-lg: 12px;
+
+/* 透明度 */
+$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
+
+/* 文章场景相关 */
+$uni-color-title: #2C405A; // 文章标题颜色
+$uni-font-size-title:20px;
+$uni-color-subtitle: #555555; // 二级标题颜色
+$uni-font-size-subtitle:26px;
+$uni-color-paragraph: #3F536E; // 文章段落颜色
+$uni-font-size-paragraph:15px;
diff --git a/uniapp/unpackage/dist/build/mp-weixin/app.js b/uniapp/unpackage/dist/build/mp-weixin/app.js
new file mode 100644
index 0000000..3179563
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/app.js
@@ -0,0 +1 @@
+"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./common/vendor.js");Math;const o={onLaunch(){console.log("Bill Helper Launch")}};function t(){return{app:e.createSSRApp(o)}}t().app.mount("#app"),exports.createApp=t;
diff --git a/uniapp/unpackage/dist/build/mp-weixin/app.json b/uniapp/unpackage/dist/build/mp-weixin/app.json
new file mode 100644
index 0000000..2e89195
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/app.json
@@ -0,0 +1,20 @@
+{
+ "pages": [
+ "pages/home/index",
+ "pages/bills/index",
+ "pages/budget/index",
+ "pages/stats/index",
+ "pages/mine/index",
+ "pages/mine/profile/index",
+ "pages/mine/backup/index",
+ "pages/mine/guide/index",
+ "pages/mine/about/index"
+ ],
+ "window": {
+ "navigationBarTextStyle": "black",
+ "navigationBarBackgroundColor": "#F4EDE3",
+ "backgroundColor": "#F4EDE3",
+ "backgroundTextStyle": "dark"
+ },
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/app.wxss b/uniapp/unpackage/dist/build/mp-weixin/app.wxss
new file mode 100644
index 0000000..e3f217d
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/app.wxss
@@ -0,0 +1,2 @@
+page{background:#f4ede3;color:#16202a;font-family:PingFang SC,HarmonyOS Sans SC,sans-serif;--bg-app: #f4ede3;--bg-accent: linear-gradient(135deg, #102a43 0%, #1f6f5f 100%);--surface-card: rgba(255, 255, 255, .9);--surface-strong: #ffffff;--surface-muted: rgba(255, 255, 255, .68);--text-primary: #16202a;--text-secondary: #617081;--text-muted: #91a0af;--line-soft: rgba(22, 32, 42, .08);--brand: #1f6f5f;--brand-soft: rgba(31, 111, 95, .14);--danger: #d25543;--danger-soft: rgba(210, 85, 67, .14);--warning: #c48a1f;--shadow-card: 0 18rpx 40rpx rgba(16, 42, 67, .08)}view,text,button,input,textarea,scroll-view{box-sizing:border-box}button{margin:0;padding:0;background:transparent;line-height:1;border:0}button:after{border:0}.app-page{display:flex;flex-direction:column;gap:24rpx;min-height:100vh;padding:28rpx 28rpx 188rpx;background:radial-gradient(circle at top right,rgba(31,111,95,.16),transparent 32%),var(--bg-app);color:var(--text-primary)}.theme-dark{--bg-app: #0f1720;--bg-accent: linear-gradient(135deg, #09111a 0%, #1d4e46 100%);--surface-card: rgba(19, 29, 40, .92);--surface-strong: #162331;--surface-muted: rgba(24, 35, 49, .76);--text-primary: #eef5fb;--text-secondary: #9db0c2;--text-muted: #7c90a3;--line-soft: rgba(255, 255, 255, .08);--brand: #64c6a9;--brand-soft: rgba(100, 198, 169, .14);--danger: #ff8c78;--danger-soft: rgba(255, 140, 120, .14);--warning: #f2c56d;--shadow-card: 0 18rpx 48rpx rgba(0, 0, 0, .28)}.surface-card{background:var(--surface-card);border:1rpx solid var(--line-soft);border-radius:30rpx;box-shadow:var(--shadow-card);-webkit-backdrop-filter:blur(12rpx);backdrop-filter:blur(12rpx)}.surface-strong{background:var(--surface-strong)}.section-title{font-size:34rpx;font-weight:600;color:var(--text-primary)}.section-subtitle{font-size:24rpx;color:var(--text-secondary)}.pill-button{display:inline-flex;align-items:center;justify-content:center;padding:18rpx 24rpx;border-radius:999rpx;background:var(--surface-muted);color:var(--text-secondary);font-size:24rpx}.pill-button.active{background:var(--brand);color:#fff}.primary-button{display:inline-flex;align-items:center;justify-content:center;padding:22rpx 28rpx;border-radius:24rpx;background:var(--bg-accent);color:#fff;font-size:28rpx;font-weight:600}.ghost-button{display:inline-flex;align-items:center;justify-content:center;padding:20rpx 26rpx;border-radius:22rpx;background:var(--brand-soft);color:var(--brand);font-size:26rpx;font-weight:600}.danger-button{background:var(--danger-soft);color:var(--danger)}.input-shell{display:flex;align-items:center;min-height:86rpx;padding:0 24rpx;border-radius:24rpx;background:var(--surface-muted);border:1rpx solid transparent}.input-shell input,.input-shell textarea{width:100%;font-size:28rpx;color:var(--text-primary)}.muted-text{color:var(--text-secondary)}.tiny-text{font-size:22rpx;color:var(--text-muted)}.positive{color:var(--brand)}.negative{color:var(--danger)}
+page{--status-bar-height:25px;--top-window-height:0px;--window-top:0px;--window-bottom:0px;--window-left:0px;--window-right:0px;--window-magin:0px}[data-c-h="true"]{display: none !important;}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/common/vendor.js b/uniapp/unpackage/dist/build/mp-weixin/common/vendor.js
new file mode 100644
index 0000000..0da861d
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/common/vendor.js
@@ -0,0 +1,7 @@
+"use strict";
+/**
+* @vue/shared v3.4.21
+* (c) 2018-present Yuxi (Evan) You and Vue contributors
+* @license MIT
+**/
+function e(e,t){const n=new Set(e.split(","));return t?e=>n.has(e.toLowerCase()):e=>n.has(e)}const t={},n=[],o=()=>{},r=()=>!1,s=e=>111===e.charCodeAt(0)&&110===e.charCodeAt(1)&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),i=e=>e.startsWith("onUpdate:"),c=Object.assign,a=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},l=Object.prototype.hasOwnProperty,u=(e,t)=>l.call(e,t),f=Array.isArray,p=e=>"[object Map]"===x(e),d=e=>"[object Set]"===x(e),h=e=>"function"==typeof e,g=e=>"string"==typeof e,m=e=>"symbol"==typeof e,v=e=>null!==e&&"object"==typeof e,_=e=>(v(e)||h(e))&&h(e.then)&&h(e.catch),y=Object.prototype.toString,x=e=>y.call(e),b=e=>"[object Object]"===x(e),w=e=>g(e)&&"NaN"!==e&&"-"!==e[0]&&""+parseInt(e,10)===e,$=e(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),S=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},k=/-(\w)/g,O=S((e=>e.replace(k,((e,t)=>t?t.toUpperCase():"")))),P=/\B([A-Z])/g,C=S((e=>e.replace(P,"-$1").toLowerCase())),E=S((e=>e.charAt(0).toUpperCase()+e.slice(1))),I=S((e=>e?`on${E(e)}`:"")),A=(e,t)=>!Object.is(e,t),j=(e,t)=>{for(let n=0;n{const t=parseFloat(e);return isNaN(t)?e:t};function L(e){let t="";if(g(e))t=e;else if(f(e))for(let n=0;nt&&t.__v_isRef?T(e,t.value):p(t)?{[`Map(${t.size})`]:[...t.entries()].reduce(((e,[t,n],o)=>(e[M(t,o)+" =>"]=n,e)),{})}:d(t)?{[`Set(${t.size})`]:[...t.values()].map((e=>M(e)))}:m(t)?M(t):!v(t)||f(t)||b(t)?t:String(t),M=(e,t="")=>{var n;return m(e)?`Symbol(${null!=(n=e.description)?n:t})`:e};function V(e,t=null){let n;return(...o)=>(e&&(n=e.apply(t,o),e=null),n)}function D(e,t){if(!g(t))return;const n=(t=t.replace(/\[(\d+)\]/g,".$1")).split(".");let o=n[0];return e||(e={}),1===n.length?e[o]:D(e[o],n.slice(1).join("."))}function H(e){let t={};return b(e)&&Object.keys(e).sort().forEach((n=>{const o=n;t[o]=e[o]})),Object.keys(t)?t:e}const N=/:/g;const B=encodeURIComponent;function U(e,t=B){const n=e?Object.keys(e).map((n=>{let o=e[n];return void 0===typeof o||null===o?o="":b(o)&&(o=JSON.stringify(o)),t(n)+"="+t(o)})).filter((e=>e.length>0)).join("&"):null;return n?`?${n}`:""}const W=["onInit","onLoad","onShow","onHide","onUnload","onBackPress","onPageScroll","onTabItemTap","onReachBottom","onPullDownRefresh","onShareTimeline","onShareAppMessage","onShareChat","onAddToFavorites","onSaveExitState","onNavigationBarButtonTap","onNavigationBarSearchInputClicked","onNavigationBarSearchInputChanged","onNavigationBarSearchInputConfirmed","onNavigationBarSearchInputFocusChanged"];const z=["onShow","onHide","onLaunch","onError","onThemeChange","onPageNotFound","onUnhandledRejection","onExit","onInit","onLoad","onReady","onUnload","onResize","onBackPress","onPageScroll","onTabItemTap","onReachBottom","onPullDownRefresh","onShareTimeline","onAddToFavorites","onShareAppMessage","onShareChat","onSaveExitState","onNavigationBarButtonTap","onNavigationBarSearchInputClicked","onNavigationBarSearchInputChanged","onNavigationBarSearchInputConfirmed","onNavigationBarSearchInputFocusChanged"],F=(()=>({onPageScroll:1,onShareAppMessage:2,onShareTimeline:4,onShareChat:8}))();function K(e,t,n=!0){return!(n&&!h(t))&&(z.indexOf(e)>-1||0===e.indexOf("on"))}let q;const G=[];const J=V(((e,t)=>t(e))),Z=function(){};Z.prototype={_id:1,on:function(e,t,n){var o=this.e||(this.e={});return(o[e]||(o[e]=[])).push({fn:t,ctx:n,_id:this._id}),this._id++},once:function(e,t,n){var o=this;function r(){o.off(e,r),t.apply(n,arguments)}return r._=t,this.on(e,r,n)},emit:function(e){for(var t=[].slice.call(arguments,1),n=((this.e||(this.e={}))[e]||[]).slice(),o=0,r=n.length;o=0;s--)if(o[s].fn===t||o[s].fn._===t||o[s]._id===t){o.splice(s,1);break}r=o}return r.length?n[e]=r:delete n[e],this}};var Q=Z;function X(e,t){if(!e)return;if(e=e.trim().replace(/_/g,"-"),t&&t[e])return e;if("chinese"===(e=e.toLowerCase()))return"zh-Hans";if(0===e.indexOf("zh"))return e.indexOf("-hans")>-1?"zh-Hans":e.indexOf("-hant")>-1?"zh-Hant":(n=e,["-tw","-hk","-mo","-cht"].find((e=>-1!==n.indexOf(e)))?"zh-Hant":"zh-Hans");var n;let o=["en","fr","es"];t&&Object.keys(t).length>0&&(o=Object.keys(t));const r=function(e,t){return t.find((t=>0===e.indexOf(t)))}(e,o);return r||void 0}function Y(e){return function(){try{return e.apply(e,arguments)}catch(t){console.error(t)}}}let ee=1;const te={};function ne(e,t,n){if("number"==typeof e){const o=te[e];if(o)return o.keepAlive||delete te[e],o.callback(t,n)}return t}const oe="success",re="fail",se="complete";function ie(e,t={},{beforeAll:n,beforeSuccess:o}={}){b(t)||(t={});const{success:r,fail:s,complete:i}=function(e){const t={};for(const n in e){const o=e[n];h(o)&&(t[n]=Y(o),delete e[n])}return t}(t),c=h(r),a=h(s),l=h(i),u=ee++;return function(e,t,n,o=!1){te[e]={name:t,keepAlive:o,callback:n}}(u,e,(u=>{(u=u||{}).errMsg=function(e,t){return e&&-1!==e.indexOf(":fail")?t+e.substring(e.indexOf(":fail")):t+":ok"}(u.errMsg,e),h(n)&&n(u),u.errMsg===e+":ok"?(h(o)&&o(u,t),c&&r(u)):a&&s(u),l&&i(u)})),u}const ce="success",ae="fail",le="complete",ue={},fe={};function pe(e,t){return function(n){return e(n,t)||n}}function de(e,t,n){let o=!1;for(let r=0;re(t),catch(){}}}function he(e,t={}){return[ce,ae,le].forEach((n=>{const o=e[n];if(!f(o))return;const r=t[n];t[n]=function(e){de(o,e,t).then((e=>h(r)&&r(e)||e))}})),t}function ge(e,t){const n=[];f(ue.returnValue)&&n.push(...ue.returnValue);const o=fe[e];return o&&f(o.returnValue)&&n.push(...o.returnValue),n.forEach((e=>{t=e(t)||t})),t}function me(e){const t=Object.create(null);Object.keys(ue).forEach((e=>{"returnValue"!==e&&(t[e]=ue[e].slice())}));const n=fe[e];return n&&Object.keys(n).forEach((e=>{"returnValue"!==e&&(t[e]=(t[e]||[]).concat(n[e]))})),t}function ve(e,t,n,o){const r=me(e);if(r&&Object.keys(r).length){if(f(r.invoke)){return de(r.invoke,n).then((n=>t(he(me(e),n),...o)))}return t(he(r,n),...o)}return t(n,...o)}function _e(e,t){return(n={},...o)=>function(e){return!(!b(e)||![oe,re,se].find((t=>h(e[t]))))}(n)?ge(e,ve(e,t,c({},n),o)):ge(e,new Promise(((r,s)=>{ve(e,t,c({},n,{success:r,fail:s}),o)})))}function ye(e,t,n,o={}){const r=t+":fail";let s="";return s=n?0===n.indexOf(r)?n:r+" "+n:r,delete o.errCode,ne(e,c({errMsg:s},o))}function xe(e,t,n,o){const r=function(e,t){e[0]}(t);if(r)return r}function be(e,t,n,o){return n=>{const r=ie(e,n,o),s=xe(0,[n]);return s?ye(r,e,s):t(n,{resolve:t=>function(e,t,n){return ne(e,c(n||{},{errMsg:t+":ok"}))}(r,e,t),reject:(t,n)=>ye(r,e,function(e){return!e||g(e)?e:e.stack?("undefined"!=typeof globalThis&&globalThis.harmonyChannel||console.error(e.message+"\n"+e.stack),e.message):e}(t),n)})}}function we(e,t,n,o){return function(e,t,n,o){return(...e)=>{const n=xe(0,e);if(n)throw new Error(n);return t.apply(null,e)}}(0,t)}let $e=!1,Se=0,ke=0;const Oe=we(0,((e,t)=>{if(0===Se&&function(){var e,t;let n,o,r;{const s=(null===(e=wx.getWindowInfo)||void 0===e?void 0:e.call(wx))||wx.getSystemInfoSync(),i=(null===(t=wx.getDeviceInfo)||void 0===t?void 0:t.call(wx))||wx.getSystemInfoSync();n=s.windowWidth,o=s.pixelRatio,r=i.platform}Se=n,ke=o,$e="ios"===r}(),0===(e=Number(e)))return 0;let n=e/750*(t||Se);return n<0&&(n=-n),n=Math.floor(n+1e-4),0===n&&(n=1!==ke&&$e?.5:1),e<0?-n:n}));function Pe(e,t){Object.keys(t).forEach((n=>{h(t[n])&&(e[n]=function(e,t){const n=t?e?e.concat(t):f(t)?t:[t]:e;return n?function(e){const t=[];for(let n=0;n{const o=e[n],r=t[n];f(o)&&h(r)&&a(o,r)}))}const Ee=we(0,((e,t)=>{g(e)&&b(t)?Pe(fe[e]||(fe[e]={}),t):b(e)&&Pe(ue,e)})),Ie=we(0,((e,t)=>{g(e)?b(t)?Ce(fe[e],t):delete fe[e]:b(e)&&Ce(ue,e)}));const Ae=new class{constructor(){this.$emitter=new Q}on(e,t){return this.$emitter.on(e,t)}once(e,t){return this.$emitter.once(e,t)}off(e,t){e?this.$emitter.off(e,t):this.$emitter.e={}}emit(e,...t){this.$emitter.emit(e,...t)}},je=we(0,((e,t)=>(Ae.on(e,t),()=>Ae.off(e,t)))),Re=we(0,((e,t)=>(Ae.once(e,t),()=>Ae.off(e,t)))),Le=we(0,((e,t)=>{f(e)||(e=e?[e]:[]),e.forEach((e=>{Ae.off(e,t)}))})),Te=we(0,((e,...t)=>{Ae.emit(e,...t)}));let Me,Ve,De;function He(e){try{return JSON.parse(e)}catch(t){}return e}const Ne=[];function Be(e,t){Ne.forEach((n=>{n(e,t)})),Ne.length=0}const Ue=_e(We="getPushClientId",function(e,t,n,o){return be(e,t,0,o)}(We,((e,{resolve:t,reject:n})=>{Promise.resolve().then((()=>{void 0===De&&(De=!1,Me="",Ve="uniPush is not enabled"),Ne.push(((e,o)=>{e?t({cid:e}):n(o)})),void 0!==Me&&Be(Me,Ve)}))}),0,ze));var We,ze;const Fe=[],Ke=/^\$|__f__|getLocale|setLocale|sendNativeEvent|restoreGlobal|requireGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|rpx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64|getDeviceInfo|getAppBaseInfo|getWindowInfo|getSystemSetting|getAppAuthorizeSetting/,qe=/^create|Manager$/,Ge=["createBLEConnection"],Je=["request","downloadFile","uploadFile","connectSocket"],Ze=["createBLEConnection"],Qe=/^on|^off/;function Xe(e){return qe.test(e)&&-1===Ge.indexOf(e)}function Ye(e){return Ke.test(e)&&-1===Ze.indexOf(e)}function et(e){return-1!==Je.indexOf(e)}function tt(e){return!(Xe(e)||Ye(e)||function(e){return Qe.test(e)&&"onPush"!==e}(e))}function nt(e,t){return tt(e)&&h(t)?function(n={},...o){return h(n.success)||h(n.fail)||h(n.complete)?ge(e,ve(e,t,c({},n),o)):ge(e,new Promise(((r,s)=>{ve(e,t,c({},n,{success:r,fail:s}),o)})))}:t}Promise.prototype.finally||(Promise.prototype.finally=function(e){const t=this.constructor;return this.then((n=>t.resolve(e&&e()).then((()=>n))),(n=>t.resolve(e&&e()).then((()=>{throw n}))))});const ot=["success","fail","cancel","complete"];const rt=()=>{const e=h(getApp)&&getApp({allowDefault:!0});return e&&e.$vm?e.$vm.$locale:function(){var e;let t="";{const n=(null===(e=wx.getAppBaseInfo)||void 0===e?void 0:e.call(wx))||wx.getSystemInfoSync();t=X(n&&n.language?n.language:"en")||"en"}return t}()},st=[];"undefined"!=typeof global&&(global.getLocale=rt);let it;function ct(e=wx){return function(t,n){it=it||e.getStorageSync("__DC_STAT_UUID"),it||(it=Date.now()+""+Math.floor(1e7*Math.random()),wx.setStorage({key:"__DC_STAT_UUID",data:it})),n.deviceId=it}}function at(e,t){if(e.safeArea){const n=e.safeArea;t.safeAreaInsets={top:n.top,left:n.left,right:e.windowWidth-n.right,bottom:e.screenHeight-n.bottom}}}function lt(e,t){let n="",o="";switch(n=e.split(" ")[0]||t,o=e.split(" ")[1]||"",n=n.toLowerCase(),n){case"harmony":case"ohos":case"openharmony":n="harmonyos";break;case"iphone os":n="ios";break;case"mac":case"darwin":n="macos";break;case"windows_nt":n="windows"}return{osName:n,osVersion:o}}function ut(e,t){let n=e.deviceType||"phone";{const e={ipad:"pad",windows:"pc",mac:"pc"},o=Object.keys(e),r=t.toLowerCase();for(let t=0;t{at(e,t),ct()(e,t),function(e,t){const{brand:n="",model:o="",system:r="",language:s="",theme:i,version:a,platform:l,fontSizeSetting:u,SDKVersion:f,pixelRatio:p,deviceOrientation:d}=e,{osName:h,osVersion:g}=lt(r,l);let m=a,v=ut(e,o),_=ft(n),y=dt(e),x=d,b=p,w=f;const $=(s||"").replace(/_/g,"-"),S={appId:"__UNI__8989AB7",appName:"账单小管家",appVersion:"1.0.0",appVersionCode:"100",appLanguage:pt($),uniCompileVersion:"4.87",uniCompilerVersion:"4.87",uniRuntimeVersion:"4.87",uniPlatform:"mp-weixin",deviceBrand:_,deviceModel:o,deviceType:v,devicePixelRatio:b,deviceOrientation:x,osName:h,osVersion:g,hostTheme:i,hostVersion:m,hostLanguage:$,hostName:y,hostSDKVersion:w,hostFontSizeSetting:u,windowTop:0,windowBottom:0,osLanguage:void 0,osTheme:void 0,ua:void 0,hostPackageName:void 0,browserName:void 0,browserVersion:void 0,isUniAppX:!1};c(t,S)}(e,t)}},gt=ht,mt={args(e,t){let n=parseInt(e.current);if(isNaN(n))return;const o=e.urls;if(!f(o))return;const r=o.length;return r?(n<0?n=0:n>=r&&(n=r-1),n>0?(t.current=o[n],t.urls=o.filter(((e,t)=>!(t{const{brand:n,model:o,system:r="",platform:s=""}=e;let i=ut(e,o),a=ft(n);ct()(e,t);const{osName:l,osVersion:u}=lt(r,s);t=H(c(t,{deviceType:i,deviceBrand:a,deviceModel:o,osName:l,osVersion:u}))}},yt={returnValue:(e,t)=>{const{version:n,language:o,SDKVersion:r,theme:s}=e;let i=dt(e),a=(o||"").replace(/_/g,"-");const l={hostVersion:n,hostLanguage:a,hostName:i,hostSDKVersion:r,hostTheme:s,appId:"__UNI__8989AB7",appName:"账单小管家",appVersion:"1.0.0",appVersionCode:"100",appLanguage:pt(a),isUniAppX:!1,uniPlatform:"mp-weixin",uniCompileVersion:"4.87",uniCompilerVersion:"4.87",uniRuntimeVersion:"4.87"};c(t,l)}},xt={returnValue:(e,t)=>{at(e,t),t=H(c(t,{windowTop:0,windowBottom:0}))}},bt={args(e){const t=getApp({allowDefault:!0})||{};t.$vm?nr("onError",e,t.$vm.$):(wx.$onErrorHandlers||(wx.$onErrorHandlers=[]),wx.$onErrorHandlers.push(e))}},wt={args(e){const t=getApp({allowDefault:!0})||{};if(t.$vm){if(e.__weh){const n=t.$vm.$.onError;if(n){const t=n.indexOf(e.__weh);t>-1&&n.splice(t,1)}}}else{if(!wx.$onErrorHandlers)return;const t=wx.$onErrorHandlers.findIndex((t=>t===e));-1!==t&&wx.$onErrorHandlers.splice(t,1)}}},$t={args(){if(wx.__uni_console__){if(wx.__uni_console_warned__)return;wx.__uni_console_warned__=!0,console.warn("开发模式下小程序日志回显会使用 socket 连接,为了避免冲突,建议使用 SocketTask 的方式去管理 WebSocket 或手动关闭日志回显功能。[详情](https://uniapp.dcloud.net.cn/tutorial/run/mp-log.html)")}}},St=$t,kt={$on:je,$off:Le,$once:Re,$emit:Te,upx2px:Oe,rpx2px:Oe,interceptors:{},addInterceptor:Ee,removeInterceptor:Ie,onCreateVueApp:function(e){if(q)return e(q);G.push(e)},invokeCreateVueAppHook:function(e){q=e,G.forEach((t=>t(e)))},getLocale:rt,setLocale:e=>{const t=h(getApp)&&getApp();if(!t)return!1;return t.$vm.$locale!==e&&(t.$vm.$locale=e,st.forEach((t=>t({locale:e}))),!0)},onLocaleChange:e=>{-1===st.indexOf(e)&&st.push(e)},getPushClientId:Ue,onPushMessage:e=>{-1===Fe.indexOf(e)&&Fe.push(e)},offPushMessage:e=>{if(e){const t=Fe.indexOf(e);t>-1&&Fe.splice(t,1)}else Fe.length=0},invokePushCallback:function(e){if("enabled"===e.type)De=!0;else if("clientId"===e.type)Me=e.cid,Ve=e.errMsg,Be(Me,e.errMsg);else if("pushMsg"===e.type){const t={type:"receive",data:He(e.message)};for(let e=0;e{t({type:"click",data:He(e.message)})}))},__f__:function(e,t,...n){t&&n.push(t),console[e].apply(console,n)}};const Ot=["qy","env","error","version","lanDebug","cloud","serviceMarket","router","worklet","__webpack_require_UNI_MP_PLUGIN__"],Pt=["lanDebug","router","worklet"],Ct=wx.getLaunchOptionsSync?wx.getLaunchOptionsSync():null;function Et(e){return(!Ct||1154!==Ct.scene||!Pt.includes(e))&&(Ot.indexOf(e)>-1||"function"==typeof wx[e])}function It(){const e={};for(const t in wx)Et(t)&&(e[t]=wx[t]);return"undefined"!=typeof globalThis&&"undefined"==typeof requireMiniProgram&&(globalThis.wx=e),e}const At=["__route__","__wxExparserNodeId__","__wxWebviewId__"],jt=(Rt={oauth:["weixin"],share:["weixin"],payment:["wxpay"],push:["weixin"]},function({service:e,success:t,fail:n,complete:o}){let r;Rt[e]?(r={errMsg:"getProvider:ok",service:e,provider:Rt[e]},h(t)&&t(r)):(r={errMsg:"getProvider:fail:服务["+e+"]不存在"},h(n)&&n(r)),h(o)&&o(r)});var Rt;const Lt=It();Lt.canIUse("getAppBaseInfo")||(Lt.getAppBaseInfo=Lt.getSystemInfoSync),Lt.canIUse("getWindowInfo")||(Lt.getWindowInfo=Lt.getSystemInfoSync),Lt.canIUse("getDeviceInfo")||(Lt.getDeviceInfo=Lt.getSystemInfoSync);let Tt=Lt.getAppBaseInfo&&Lt.getAppBaseInfo();Tt||(Tt=Lt.getSystemInfoSync());const Mt=Tt?Tt.host:null,Vt=Mt&&"SAAASDK"===Mt.env?Lt.miniapp.shareVideoMessage:Lt.shareVideoMessage;var Dt=Object.freeze({__proto__:null,createSelectorQuery:function(){const e=Lt.createSelectorQuery(),t=e.in;return e.in=function(e){return e.$scope?t.call(this,e.$scope):t.call(this,function(e){const t=Object.create(null);return At.forEach((n=>{t[n]=e[n]})),t}(e))},e},getProvider:jt,shareVideoMessage:Vt});const Ht={args(e,t){e.compressedHeight&&!t.compressHeight&&(t.compressHeight=e.compressedHeight),e.compressedWidth&&!t.compressWidth&&(t.compressWidth=e.compressedWidth)}};var Nt=Object.freeze({__proto__:null,compressImage:Ht,getAppAuthorizeSetting:{returnValue:function(e,t){const{locationReducedAccuracy:n}=e;t.locationAccuracy="unsupported",!0===n?t.locationAccuracy="reduced":!1===n&&(t.locationAccuracy="full")}},getAppBaseInfo:yt,getDeviceInfo:_t,getSystemInfo:ht,getSystemInfoSync:gt,getWindowInfo:xt,offError:wt,onError:bt,onSocketMessage:St,onSocketOpen:$t,previewImage:mt,redirectTo:{},showActionSheet:vt});const Bt=It();var Ut=function(e,t,n=wx){const o=function(e){function t(e,t,n){return function(r){return t(o(e,r,n))}}function n(e,n,o={},r={},s=!1){if(b(n)){const i=!0===s?n:{};h(o)&&(o=o(n,i)||{});for(const c in n)if(u(o,c)){let t=o[c];h(t)&&(t=t(n[c],n,i)),t?g(t)?i[t]=n[c]:b(t)&&(i[t.name?t.name:c]=t.value):console.warn(`微信小程序 ${e} 暂不支持 ${c}`)}else if(-1!==ot.indexOf(c)){const o=n[c];h(o)&&(i[c]=t(e,o,r))}else s||u(i,c)||(i[c]=n[c]);return i}return h(n)&&(h(o)&&o(n,{}),n=t(e,n,r)),n}function o(t,o,r,s=!1){return h(e.returnValue)&&(o=e.returnValue(t,o)),n(t,o,r,{},s||!1)}return function(t,r){const s=u(e,t);if(!s&&"function"!=typeof wx[t])return r;const i=s||h(e.returnValue)||Xe(t)||et(t),c=s||h(r);if(!s&&!r)return function(){console.error(`微信小程序 暂不支持${t}`)};if(!i||!c)return r;const a=e[t];return function(e,r){let s=a||{};h(a)&&(s=a(e));const i=[e=n(t,e,s.args,s.returnValue)];void 0!==r&&i.push(r);const c=wx[s.name||t].apply(wx,i);return(Xe(t)||et(t))&&c&&!c.__v_skip&&(c.__v_skip=!0),Ye(t)?o(t,c,s.returnValue,Xe(t)):c}}}(t);return new Proxy({},{get:(t,r)=>u(t,r)?t[r]:u(e,r)?nt(r,e[r]):u(kt,r)?nt(r,kt[r]):nt(r,o(r,n[r]))})}(Dt,Nt,Bt);let Wt,zt;class Ft{constructor(e=!1){this.detached=e,this._active=!0,this.effects=[],this.cleanups=[],this.parent=Wt,!e&&Wt&&(this.index=(Wt.scopes||(Wt.scopes=[])).push(this)-1)}get active(){return this._active}run(e){if(this._active){const t=Wt;try{return Wt=this,e()}finally{Wt=t}}}on(){Wt=this}off(){Wt=this.parent}stop(e){if(this._active){let t,n;for(t=0,n=this.effects.length;t=4))break}1===this._dirtyLevel&&(this._dirtyLevel=0),en()}return this._dirtyLevel>=4}set dirty(e){this._dirtyLevel=e?4:0}run(){if(this._dirtyLevel=0,!this.active)return this.fn();let e=Zt,t=zt;try{return Zt=!0,zt=this,this._runnings++,qt(this),this.fn()}finally{Gt(this),this._runnings--,zt=t,Zt=e}}stop(){var e;this.active&&(qt(this),Gt(this),null==(e=this.onStop)||e.call(this),this.active=!1)}}function qt(e){e._trackId++,e._depsLength=0}function Gt(e){if(e.deps.length>e._depsLength){for(let t=e._depsLength;t{const n=new Map;return n.cleanup=e,n.computed=t,n},an=new WeakMap,ln=Symbol(""),un=Symbol("");function fn(e,t,n){if(Zt&&zt){let t=an.get(e);t||an.set(e,t=new Map);let o=t.get(n);o||t.set(n,o=cn((()=>t.delete(n)))),on(zt,o)}}function pn(e,t,n,o,r,s){const i=an.get(e);if(!i)return;let c=[];if("clear"===t)c=[...i.values()];else if("length"===n&&f(e)){const e=Number(o);i.forEach(((t,n)=>{("length"===n||!m(n)&&n>=e)&&c.push(t)}))}else switch(void 0!==n&&c.push(i.get(n)),t){case"add":f(e)?w(n)&&c.push(i.get("length")):(c.push(i.get(ln)),p(e)&&c.push(i.get(un)));break;case"delete":f(e)||(c.push(i.get(ln)),p(e)&&c.push(i.get(un)));break;case"set":p(e)&&c.push(i.get(ln))}tn();for(const a of c)a&&sn(a,4);nn()}const dn=e("__proto__,__v_isRef,__isVue"),hn=new Set(Object.getOwnPropertyNames(Symbol).filter((e=>"arguments"!==e&&"caller"!==e)).map((e=>Symbol[e])).filter(m)),gn=mn();function mn(){const e={};return["includes","indexOf","lastIndexOf"].forEach((t=>{e[t]=function(...e){const n=no(this);for(let t=0,r=this.length;t{e[t]=function(...e){Yt(),tn();const n=no(this)[t].apply(this,e);return nn(),en(),n}})),e}function vn(e){const t=no(this);return fn(t,0,e),t.hasOwnProperty(e)}class _n{constructor(e=!1,t=!1){this._isReadonly=e,this._isShallow=t}get(e,t,n){const o=this._isReadonly,r=this._isShallow;if("__v_isReactive"===t)return!o;if("__v_isReadonly"===t)return o;if("__v_isShallow"===t)return r;if("__v_raw"===t)return n===(o?r?Gn:qn:r?Kn:Fn).get(e)||Object.getPrototypeOf(e)===Object.getPrototypeOf(n)?e:void 0;const s=f(e);if(!o){if(s&&u(gn,t))return Reflect.get(gn,t,n);if("hasOwnProperty"===t)return vn}const i=Reflect.get(e,t,n);return(m(t)?hn.has(t):dn(t))?i:(o||fn(e,0,t),r?i:lo(i)?s&&w(t)?i:i.value:v(i)?o?Qn(i):Zn(i):i)}}class yn extends _n{constructor(e=!1){super(!1,e)}set(e,t,n,o){let r=e[t];if(!this._isShallow){const t=eo(r);if(to(n)||eo(n)||(r=no(r),n=no(n)),!f(e)&&lo(r)&&!lo(n))return!t&&(r.value=n,!0)}const s=f(e)&&w(t)?Number(t)e,kn=e=>Reflect.getPrototypeOf(e);function On(e,t,n=!1,o=!1){const r=no(e=e.__v_raw),s=no(t);n||(A(t,s)&&fn(r,0,t),fn(r,0,s));const{has:i}=kn(r),c=o?Sn:n?so:ro;return i.call(r,t)?c(e.get(t)):i.call(r,s)?c(e.get(s)):void(e!==r&&e.get(t))}function Pn(e,t=!1){const n=this.__v_raw,o=no(n),r=no(e);return t||(A(e,r)&&fn(o,0,e),fn(o,0,r)),e===r?n.has(e):n.has(e)||n.has(r)}function Cn(e,t=!1){return e=e.__v_raw,!t&&fn(no(e),0,ln),Reflect.get(e,"size",e)}function En(e){e=no(e);const t=no(this);return kn(t).has.call(t,e)||(t.add(e),pn(t,"add",e,e)),this}function In(e,t){t=no(t);const n=no(this),{has:o,get:r}=kn(n);let s=o.call(n,e);s||(e=no(e),s=o.call(n,e));const i=r.call(n,e);return n.set(e,t),s?A(t,i)&&pn(n,"set",e,t):pn(n,"add",e,t),this}function An(e){const t=no(this),{has:n,get:o}=kn(t);let r=n.call(t,e);r||(e=no(e),r=n.call(t,e)),o&&o.call(t,e);const s=t.delete(e);return r&&pn(t,"delete",e,void 0),s}function jn(){const e=no(this),t=0!==e.size,n=e.clear();return t&&pn(e,"clear",void 0,void 0),n}function Rn(e,t){return function(n,o){const r=this,s=r.__v_raw,i=no(s),c=t?Sn:e?so:ro;return!e&&fn(i,0,ln),s.forEach(((e,t)=>n.call(o,c(e),c(t),r)))}}function Ln(e,t,n){return function(...o){const r=this.__v_raw,s=no(r),i=p(s),c="entries"===e||e===Symbol.iterator&&i,a="keys"===e&&i,l=r[e](...o),u=n?Sn:t?so:ro;return!t&&fn(s,0,a?un:ln),{next(){const{value:e,done:t}=l.next();return t?{value:e,done:t}:{value:c?[u(e[0]),u(e[1])]:u(e),done:t}},[Symbol.iterator](){return this}}}}function Tn(e){return function(...t){return"delete"!==e&&("clear"===e?void 0:this)}}function Mn(){const e={get(e){return On(this,e)},get size(){return Cn(this)},has:Pn,add:En,set:In,delete:An,clear:jn,forEach:Rn(!1,!1)},t={get(e){return On(this,e,!1,!0)},get size(){return Cn(this)},has:Pn,add:En,set:In,delete:An,clear:jn,forEach:Rn(!1,!0)},n={get(e){return On(this,e,!0)},get size(){return Cn(this,!0)},has(e){return Pn.call(this,e,!0)},add:Tn("add"),set:Tn("set"),delete:Tn("delete"),clear:Tn("clear"),forEach:Rn(!0,!1)},o={get(e){return On(this,e,!0,!0)},get size(){return Cn(this,!0)},has(e){return Pn.call(this,e,!0)},add:Tn("add"),set:Tn("set"),delete:Tn("delete"),clear:Tn("clear"),forEach:Rn(!0,!0)};return["keys","values","entries",Symbol.iterator].forEach((r=>{e[r]=Ln(r,!1,!1),n[r]=Ln(r,!0,!1),t[r]=Ln(r,!1,!0),o[r]=Ln(r,!0,!0)})),[e,n,t,o]}const[Vn,Dn,Hn,Nn]=Mn();function Bn(e,t){const n=t?e?Nn:Hn:e?Dn:Vn;return(t,o,r)=>"__v_isReactive"===o?!e:"__v_isReadonly"===o?e:"__v_raw"===o?t:Reflect.get(u(n,o)&&o in t?n:t,o,r)}const Un={get:Bn(!1,!1)},Wn={get:Bn(!1,!0)},zn={get:Bn(!0,!1)},Fn=new WeakMap,Kn=new WeakMap,qn=new WeakMap,Gn=new WeakMap;function Jn(e){return e.__v_skip||!Object.isExtensible(e)?0:function(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}((e=>x(e).slice(8,-1))(e))}function Zn(e){return eo(e)?e:Xn(e,!1,bn,Un,Fn)}function Qn(e){return Xn(e,!0,wn,zn,qn)}function Xn(e,t,n,o,r){if(!v(e))return e;if(e.__v_raw&&(!t||!e.__v_isReactive))return e;const s=r.get(e);if(s)return s;const i=Jn(e);if(0===i)return e;const c=new Proxy(e,2===i?o:n);return r.set(e,c),c}function Yn(e){return eo(e)?Yn(e.__v_raw):!(!e||!e.__v_isReactive)}function eo(e){return!(!e||!e.__v_isReadonly)}function to(e){return!(!e||!e.__v_isShallow)}function no(e){const t=e&&e.__v_raw;return t?no(t):e}function oo(e){return Object.isExtensible(e)&&((e,t,n)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})})(e,"__v_skip",!0),e}const ro=e=>v(e)?Zn(e):e,so=e=>v(e)?Qn(e):e;class io{constructor(e,t,n,o){this.getter=e,this._setter=t,this.dep=void 0,this.__v_isRef=!0,this.__v_isReadonly=!1,this.effect=new Kt((()=>e(this._value)),(()=>ao(this,2===this.effect._dirtyLevel?2:3))),this.effect.computed=this,this.effect.active=this._cacheable=!o,this.__v_isReadonly=n}get value(){const e=no(this);return e._cacheable&&!e.effect.dirty||!A(e._value,e._value=e.effect.run())||ao(e,4),co(e),e.effect._dirtyLevel>=2&&ao(e,2),e._value}set value(e){this._setter(e)}get _dirty(){return this.effect.dirty}set _dirty(e){this.effect.dirty=e}}function co(e){var t;Zt&&zt&&(e=no(e),on(zt,null!=(t=e.dep)?t:e.dep=cn((()=>e.dep=void 0),e instanceof io?e:void 0)))}function ao(e,t=4,n){const o=(e=no(e)).dep;o&&sn(o,t)}function lo(e){return!(!e||!0!==e.__v_isRef)}function uo(e){return function(e,t){if(lo(e))return e;return new fo(e,t)}(e,!1)}class fo{constructor(e,t){this.__v_isShallow=t,this.dep=void 0,this.__v_isRef=!0,this._rawValue=t?e:no(e),this._value=t?e:ro(e)}get value(){return co(this),this._value}set value(e){const t=this.__v_isShallow||to(e)||eo(e);e=t?e:no(e),A(e,this._rawValue)&&(this._rawValue=e,this._value=t?e:ro(e),ao(this,4))}}function po(e){return lo(e)?e.value:e}const ho={get:(e,t,n)=>po(Reflect.get(e,t,n)),set:(e,t,n,o)=>{const r=e[t];return lo(r)&&!lo(n)?(r.value=n,!0):Reflect.set(e,t,n,o)}};function go(e){return Yn(e)?e:new Proxy(e,ho)}function mo(e,t,n,o){try{return o?e(...o):e()}catch(r){_o(r,t,n)}}function vo(e,t,n,o){if(h(e)){const r=mo(e,t,n,o);return r&&_(r)&&r.catch((e=>{_o(e,t,n)})),r}const r=[];for(let s=0;s>>1,r=wo[o],s=Lo(r);snull==e.id?1/0:e.id,To=(e,t)=>{const n=Lo(e)-Lo(t);if(0===n){if(e.pre&&!t.pre)return-1;if(t.pre&&!e.pre)return 1}return n};function Mo(e){bo=!1,xo=!0,wo.sort(To);try{for($o=0;$oLo(e)-Lo(t)));if(So.length=0,ko)return void ko.push(...e);for(ko=e,Oo=0;Oog(e)?e.trim():e))),n&&(s=o.map(R))}let a,l=r[a=I(n)]||r[a=I(O(n))];!l&&i&&(l=r[a=I(C(n))]),l&&vo(l,e,6,s);const u=r[a+"Once"];if(u){if(e.emitted){if(e.emitted[a])return}else e.emitted={};e.emitted[a]=!0,vo(u,e,6,s)}}function Do(e,t,n=!1){const o=t.emitsCache,r=o.get(e);if(void 0!==r)return r;const s=e.emits;let i={},a=!1;if(!h(e)){const o=e=>{const n=Do(e,t,!0);n&&(a=!0,c(i,n))};!n&&t.mixins.length&&t.mixins.forEach(o),e.extends&&o(e.extends),e.mixins&&e.mixins.forEach(o)}return s||a?(f(s)?s.forEach((e=>i[e]=null)):c(i,s),v(e)&&o.set(e,i),i):(v(e)&&o.set(e,null),null)}function Ho(e,t){return!(!e||!s(t))&&(t=t.slice(2).replace(/Once$/,""),u(e,t[0].toLowerCase()+t.slice(1))||u(e,C(t))||u(e,t))}let No=null;function Bo(e){const t=No;return No=e,e&&e.type.__scopeId,t}const Uo={};function Wo(e,t,n){return zo(e,t,n)}function zo(e,n,{immediate:r,deep:s,flush:i,once:c,onTrack:l,onTrigger:u}=t){if(n&&c){const e=n;n=(...t)=>{e(...t),k()}}const p=zr,d=e=>!0===s?e:qo(e,!1===s?1:void 0);let g,m,v=!1,_=!1;if(lo(e)?(g=()=>e.value,v=to(e)):Yn(e)?(g=()=>d(e),v=!0):f(e)?(_=!0,v=e.some((e=>Yn(e)||to(e))),g=()=>e.map((e=>lo(e)?e.value:Yn(e)?d(e):h(e)?mo(e,p,2):void 0))):g=h(e)?n?()=>mo(e,p,2):()=>(m&&m(),vo(e,p,3,[y])):o,n&&s){const e=g;g=()=>qo(e())}let y=e=>{m=$.onStop=()=>{mo(e,p,4),m=$.onStop=void 0}},x=_?new Array(e.length).fill(Uo):Uo;const b=()=>{if($.active&&$.dirty)if(n){const e=$.run();(s||v||(_?e.some(((e,t)=>A(e,x[t]))):A(e,x)))&&(m&&m(),vo(n,p,3,[e,x===Uo?void 0:_&&x[0]===Uo?[]:x,y]),x=e)}else $.run()};let w;b.allowRecurse=!!n,"sync"===i?w=b:"post"===i?w=()=>Hr(b,p&&p.suspense):(b.pre=!0,p&&(b.id=p.uid),w=()=>Io(b));const $=new Kt(g,o,w),S=Wt,k=()=>{$.stop(),S&&a(S.effects,$)};return n?r?b():x=$.run():"post"===i?Hr($.run.bind($),p&&p.suspense):$.run(),k}function Fo(e,t,n){const o=this.proxy,r=g(e)?e.includes(".")?Ko(o,e):()=>o[e]:e.bind(o,o);let s;h(t)?s=t:(s=t.handler,n=t);const i=Gr(this),c=zo(r,s.bind(o),n);return i(),c}function Ko(e,t){const n=t.split(".");return()=>{let t=e;for(let e=0;e0){if(n>=t)return e;n++}if((o=o||new Set).has(e))return e;if(o.add(e),lo(e))qo(e.value,t,n,o);else if(f(e))for(let r=0;r{qo(e,t,n,o)}));else if(b(e))for(const r in e)qo(e[r],t,n,o);return e}function Go(){return{app:null,config:{isNativeTag:r,performance:!1,globalProperties:{},optionMergeStrategies:{},errorHandler:void 0,warnHandler:void 0,compilerOptions:{}},mixins:[],components:{},directives:{},provides:Object.create(null),optionsCache:new WeakMap,propsCache:new WeakMap,emitsCache:new WeakMap}}let Jo=0;let Zo=null;function Qo(e,t,n=!1){const o=zr||No;if(o||Zo){const r=o?null==o.parent?o.vnode.appContext&&o.vnode.appContext.provides:o.parent.provides:Zo._context.provides;if(r&&e in r)return r[e];if(arguments.length>1)return n&&h(t)?t.call(o&&o.proxy):t}}function Xo(e,t){er(e,"a",t)}function Yo(e,t){er(e,"da",t)}function er(e,t,n=zr){const o=e.__wdc||(e.__wdc=()=>{let t=n;for(;t;){if(t.isDeactivated)return;t=t.parent}return e()});if(nr(t,o,n),n){let e=n.parent;for(;e&&e.parent;)e.parent.vnode.type.__isKeepAlive&&tr(o,t,n,e),e=e.parent}}function tr(e,t,n,o){const r=nr(t,e,o,!0);lr((()=>{a(o[t],r)}),n)}function nr(e,t,n=zr,o=!1){if(n){(function(e){return W.indexOf(e)>-1})(e)&&(n=n.root);const r=n[e]||(n[e]=[]),s=t.__weh||(t.__weh=(...o)=>{if(n.isUnmounted)return;Yt();const r=Gr(n),s=vo(t,n,e,o);return r(),en(),s});return o?r.unshift(s):r.push(s),s}}const or=e=>(t,n=zr)=>(!Qr||"sp"===e)&&nr(e,((...e)=>t(...e)),n),rr=or("bm"),sr=or("m"),ir=or("bu"),cr=or("u"),ar=or("bum"),lr=or("um"),ur=or("sp"),fr=or("rtg"),pr=or("rtc");function dr(e,t=zr){nr("ec",e,t)}const hr=e=>e?Zr(e)?es(e)||e.proxy:hr(e.parent):null;const gr=c(Object.create(null),{$:function(e){return e},$el:e=>e.__$el||(e.__$el={}),$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>hr(e.parent),$root:e=>hr(e.root),$emit:e=>e.emit,$options:e=>$r(e),$forceUpdate:e=>e.f||(e.f=()=>{e.effect.dirty=!0,Io(e.update)}),$watch:e=>Fo.bind(e)}),mr=(e,n)=>e!==t&&!e.__isScriptSetup&&u(e,n),vr={get({_:e},n){const{ctx:o,setupState:r,data:s,props:i,accessCache:c,type:a,appContext:l}=e;let f;if("$"!==n[0]){const a=c[n];if(void 0!==a)switch(a){case 1:return r[n];case 2:return s[n];case 4:return o[n];case 3:return i[n]}else{if(mr(r,n))return c[n]=1,r[n];if(s!==t&&u(s,n))return c[n]=2,s[n];if((f=e.propsOptions[0])&&u(f,n))return c[n]=3,i[n];if(o!==t&&u(o,n))return c[n]=4,o[n];yr&&(c[n]=0)}}const p=gr[n];let d,h;return p?("$attrs"===n&&fn(e,0,n),p(e)):(d=a.__cssModules)&&(d=d[n])?d:o!==t&&u(o,n)?(c[n]=4,o[n]):(h=l.config.globalProperties,u(h,n)?h[n]:void 0)},set({_:e},n,o){const{data:r,setupState:s,ctx:i}=e;return mr(s,n)?(s[n]=o,!0):r!==t&&u(r,n)?(r[n]=o,!0):!u(e.props,n)&&(("$"!==n[0]||!(n.slice(1)in e))&&(i[n]=o,!0))},has({_:{data:e,setupState:n,accessCache:o,ctx:r,appContext:s,propsOptions:i}},c){let a;return!!o[c]||e!==t&&u(e,c)||mr(n,c)||(a=i[0])&&u(a,c)||u(r,c)||u(gr,c)||u(s.config.globalProperties,c)},defineProperty(e,t,n){return null!=n.get?e._.accessCache[t]=0:u(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}};function _r(e){return f(e)?e.reduce(((e,t)=>(e[t]=null,e)),{}):e}let yr=!0;function xr(e){const t=$r(e),n=e.proxy,r=e.ctx;yr=!1,t.beforeCreate&&br(t.beforeCreate,e,"bc");const{data:s,computed:i,methods:c,watch:a,provide:l,inject:u,created:p,beforeMount:d,mounted:g,beforeUpdate:m,updated:_,activated:y,deactivated:x,beforeDestroy:b,beforeUnmount:w,destroyed:$,unmounted:S,render:k,renderTracked:O,renderTriggered:P,errorCaptured:C,serverPrefetch:E,expose:I,inheritAttrs:A,components:j,directives:R,filters:L}=t;if(u&&function(e,t,n=o){f(e)&&(e=Pr(e));for(const o in e){const n=e[o];let r;r=v(n)?"default"in n?Qo(n.from||o,n.default,!0):Qo(n.from||o):Qo(n),lo(r)?Object.defineProperty(t,o,{enumerable:!0,configurable:!0,get:()=>r.value,set:e=>r.value=e}):t[o]=r}}(u,r,null),c)for(const o in c){const e=c[o];h(e)&&(r[o]=e.bind(n))}if(s){const t=s.call(n,n);v(t)&&(e.data=Zn(t))}if(yr=!0,i)for(const f in i){const e=i[f],t=h(e)?e.bind(n,n):h(e.get)?e.get.bind(n,n):o,s=!h(e)&&h(e.set)?e.set.bind(n):o,c=ts({get:t,set:s});Object.defineProperty(r,f,{enumerable:!0,configurable:!0,get:()=>c.value,set:e=>c.value=e})}if(a)for(const o in a)wr(a[o],r,n,o);function T(e,t){f(t)?t.forEach((t=>e(t.bind(n)))):t&&e(t.bind(n))}if(function(){if(l){const e=h(l)?l.call(n):l;Reflect.ownKeys(e).forEach((t=>{!function(e,t){if(zr){let n=zr.provides;const o=zr.parent&&zr.parent.provides;o===n&&(n=zr.provides=Object.create(o)),n[e]=t,"app"===zr.type.mpType&&zr.appContext.app.provide(e,t)}}(t,e[t])}))}}(),p&&br(p,e,"c"),T(rr,d),T(sr,g),T(ir,m),T(cr,_),T(Xo,y),T(Yo,x),T(dr,C),T(pr,O),T(fr,P),T(ar,w),T(lr,S),T(ur,E),f(I))if(I.length){const t=e.exposed||(e.exposed={});I.forEach((e=>{Object.defineProperty(t,e,{get:()=>n[e],set:t=>n[e]=t})}))}else e.exposed||(e.exposed={});k&&e.render===o&&(e.render=k),null!=A&&(e.inheritAttrs=A),j&&(e.components=j),R&&(e.directives=R),e.ctx.$onApplyOptions&&e.ctx.$onApplyOptions(t,e,n)}function br(e,t,n){vo(f(e)?e.map((e=>e.bind(t.proxy))):e.bind(t.proxy),t,n)}function wr(e,t,n,o){const r=o.includes(".")?Ko(n,o):()=>n[o];if(g(e)){const n=t[e];h(n)&&Wo(r,n)}else if(h(e))Wo(r,e.bind(n));else if(v(e))if(f(e))e.forEach((e=>wr(e,t,n,o)));else{const o=h(e.handler)?e.handler.bind(n):t[e.handler];h(o)&&Wo(r,o,e)}}function $r(e){const t=e.type,{mixins:n,extends:o}=t,{mixins:r,optionsCache:s,config:{optionMergeStrategies:i}}=e.appContext,c=s.get(t);let a;return c?a=c:r.length||n||o?(a={},r.length&&r.forEach((e=>Sr(a,e,i,!0))),Sr(a,t,i)):a=t,v(t)&&s.set(t,a),a}function Sr(e,t,n,o=!1){const{mixins:r,extends:s}=t;s&&Sr(e,s,n,!0),r&&r.forEach((t=>Sr(e,t,n,!0)));for(const i in t)if(o&&"expose"===i);else{const o=kr[i]||n&&n[i];e[i]=o?o(e[i],t[i]):t[i]}return e}const kr={data:Or,props:Ir,emits:Ir,methods:Er,computed:Er,beforeCreate:Cr,created:Cr,beforeMount:Cr,mounted:Cr,beforeUpdate:Cr,updated:Cr,beforeDestroy:Cr,beforeUnmount:Cr,destroyed:Cr,unmounted:Cr,activated:Cr,deactivated:Cr,errorCaptured:Cr,serverPrefetch:Cr,components:Er,directives:Er,watch:function(e,t){if(!e)return t;if(!t)return e;const n=c(Object.create(null),e);for(const o in t)n[o]=Cr(e[o],t[o]);return n},provide:Or,inject:function(e,t){return Er(Pr(e),Pr(t))}};function Or(e,t){return t?e?function(){return c(h(e)?e.call(this,this):e,h(t)?t.call(this,this):t)}:t:e}function Pr(e){if(f(e)){const t={};for(let n=0;n{d=!0;const[t,n]=Lr(e,o,!0);c(l,t),n&&p.push(...n)};!r&&o.mixins.length&&o.mixins.forEach(t),e.extends&&t(e.extends),e.mixins&&e.mixins.forEach(t)}if(!a&&!d)return v(e)&&s.set(e,n),n;if(f(a))for(let n=0;n-1,o[1]=n<0||t-1||u(o,"default"))&&p.push(e)}}}const g=[l,p];return v(e)&&s.set(e,g),g}function Tr(e){return"$"!==e[0]&&!$(e)}function Mr(e){if(null===e)return"null";if("function"==typeof e)return e.name||"";if("object"==typeof e){return e.constructor&&e.constructor.name||""}return""}function Vr(e,t){return Mr(e)===Mr(t)}function Dr(e,t){return f(t)?t.findIndex((t=>Vr(t,e))):h(t)&&Vr(t,e)?0:-1}const Hr=jo;function Nr(e){return e?Yn(t=e)||eo(t)||"__vInternal"in e?c({},e):e:null;var t}const Br=Go();let Ur=0;function Wr(e,n,o){const r=e.type,s=(n?n.appContext:e.appContext)||Br,i={uid:Ur++,vnode:e,type:r,parent:n,appContext:s,root:null,next:null,subTree:null,effect:null,update:null,scope:new Ft(!0),render:null,proxy:null,exposed:null,exposeProxy:null,withProxy:null,provides:n?n.provides:Object.create(s.provides),accessCache:null,renderCache:[],components:null,directives:null,propsOptions:Lr(r,s),emitsOptions:Do(r,s),emit:null,emitted:null,propsDefaults:t,inheritAttrs:r.inheritAttrs,ctx:t,data:t,props:t,attrs:t,slots:t,refs:t,setupState:t,setupContext:null,attrsProxy:null,slotsProxy:null,suspense:o,suspenseId:o?o.pendingId:0,asyncDep:null,asyncResolved:!1,isMounted:!1,isUnmounted:!1,isDeactivated:!1,bc:null,c:null,bm:null,m:null,bu:null,u:null,um:null,bum:null,da:null,a:null,rtg:null,rtc:null,ec:null,sp:null,$uniElements:new Map,$templateUniElementRefs:[],$templateUniElementStyles:{},$eS:{},$eA:{}};return i.ctx={_:i},i.root=n?n.root:i,i.emit=Vo.bind(null,i),e.ce&&e.ce(i),i}let zr=null;const Fr=()=>zr||No;let Kr,qr;Kr=e=>{zr=e},qr=e=>{Qr=e};const Gr=e=>{const t=zr;return Kr(e),e.scope.on(),()=>{e.scope.off(),Kr(t)}},Jr=()=>{zr&&zr.scope.off(),Kr(null)};function Zr(e){return 4&e.vnode.shapeFlag}let Qr=!1;function Xr(e,t=!1){t&&qr(t);const{props:n}=e.vnode,o=Zr(e);Ar(e,n,o,t);const r=o?function(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=oo(new Proxy(e.ctx,vr));const{setup:o}=n;if(o){const t=e.setupContext=o.length>1?function(e){const t=t=>{e.exposed=t||{}};return{get attrs(){return function(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get:(t,n)=>(fn(e,0,"$attrs"),t[n])}))}(e)},slots:e.slots,emit:e.emit,expose:t}}(e):null,n=Gr(e);Yt();const r=mo(o,e,0,[e.props,t]);en(),n(),_(r)?r.then(Jr,Jr):function(e,t,n){h(t)?e.render=t:v(t)&&(e.setupState=go(t));Yr(e)}(e,r)}else Yr(e)}(e):void 0;return t&&qr(!1),r}function Yr(e,t,n){const r=e.type;e.render||(e.render=r.render||o);{const t=Gr(e);Yt();try{xr(e)}finally{en(),t()}}}function es(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy(go(oo(e.exposed)),{get:(t,n)=>n in t?t[n]:e.proxy[n],has:(e,t)=>t in e||t in gr}))}const ts=(e,t)=>{const n=function(e,t,n=!1){let r,s;const i=h(e);return i?(r=e,s=o):(r=e.get,s=e.set),new io(r,s,i||!s,n)}(e,0,Qr);return n},ns="3.4.21";function os(e){return po(e)}const rs="[object Array]",ss="[object Object]";function is(e,t){const n={};return cs(e,t),as(e,t,"",n),n}function cs(e,t){if((e=os(e))===t)return;const n=x(e),o=x(t);if(n==ss&&o==ss)for(let r in t){const n=e[r];void 0===n?e[r]=null:cs(n,t[r])}else n==rs&&o==rs&&e.length>=t.length&&t.forEach(((t,n)=>{cs(e[n],t)}))}function as(e,t,n,o){if((e=os(e))===t)return;const r=x(e),s=x(t);if(r==ss)if(s!=ss||Object.keys(e).length{as(e,s[t],(""==n?"":n+".")+i+"["+t+"]",o)}));else if(c==ss)if(a!=ss||Object.keys(r).length{as(e,t[r],n+"["+r+"]",o)})):ls(o,n,e)}function ls(e,t,n){e[t]=n}function us(e){const t=e.ctx.__next_tick_callbacks;if(t&&t.length){const e=t.slice(0);t.length=0;for(let t=0;t{t?mo(t.bind(e.proxy),e,14):o&&o(e.proxy)})),new Promise((e=>{o=e}))}function ps(e,t){const n=typeof(e=os(e));if("object"===n&&null!==e){let n=t.get(e);if(void 0!==n)return n;if(f(e)){const o=e.length;n=new Array(o),t.set(e,n);for(let r=0;r{o[e]=n[e]})),o}(r,s));Object.keys(i).length?(o.__next_tick_pending=!0,r.setData(i,(()=>{o.__next_tick_pending=!1,us(e)})),Ro()):us(e)}}function gs(e,t,n){t.appContext.config.globalProperties.$applyOptions(e,t,n);const o=e.computed;if(o){const e=Object.keys(o);if(e.length){const n=t.ctx;n.$computedKeys||(n.$computedKeys=[]),n.$computedKeys.push(...e)}}delete t.ctx.$onApplyOptions}function ms(e,t=!1){const{setupState:n,$templateRefs:o,$templateUniElementRefs:r,ctx:{$scope:s,$mpPlatform:i}}=e;if("mp-alipay"===i)return;if(!s||!o&&!r)return;if(t)return o&&o.forEach((e=>vs(e,null,n))),void(r&&r.forEach((e=>vs(e,null,n))));const c="mp-baidu"===i||"mp-toutiao"===i,a=e=>{if(0===e.length)return[];const t=(s.selectAllComponents(".r")||[]).concat(s.selectAllComponents(".r-i-f")||[]);return e.filter((e=>{const o=function(e,t){const n=e.find((e=>e&&(e.properties||e.props).uI===t));if(n){const e=n.$vm;return e?es(e.$)||e:function(e){v(e)&&oo(e);return e}(n)}return null}(t,e.i);return!(!c||null!==o)||(vs(e,o,n),!1)}))},l=()=>{if(o){const t=a(o);t.length&&e.proxy&&e.proxy.$scope&&e.proxy.$scope.setData({r1:1},(()=>{a(t)}))}};r&&r.length&&fs(e,(()=>{r.forEach((e=>{f(e.v)?e.v.forEach((t=>{vs(e,t,n)})):vs(e,e.v,n)}))})),s._$setRef?s._$setRef(l):fs(e,l)}function vs({r:e,f:t},n,o){if(h(e))e(n,{});else{const r=g(e),s=lo(e);if(r||s)if(t){if(!s)return;f(e.value)||(e.value=[]);const t=e.value;if(-1===t.indexOf(n)){if(t.push(n),!n)return;n.$&&ar((()=>a(t,n)),n.$)}}else r?u(o,e)&&(o[e]=n):lo(e)&&(e.value=n)}}const _s=jo;function ys(e,t){const n=e.component=Wr(e,t.parentComponent,null);return n.renderer=t.mpType?t.mpType:"component",n.ctx.$onApplyOptions=gs,n.ctx.$children=[],"app"===t.mpType&&(n.render=o),t.onBeforeSetup&&t.onBeforeSetup(n,t),Xr(n),t.parentComponent&&n.proxy&&t.parentComponent.ctx.$children.push(es(n)||n.proxy),function(e){const t=ws.bind(e);e.$updateScopedSlots=()=>Eo((()=>Io(t)));const n=()=>{if(e.isMounted){const{next:t,bu:n,u:o}=e;$s(e,!1),Yt(),Ro(),en(),n&&j(n),$s(e,!0),hs(e,xs(e)),o&&_s(o)}else ar((()=>{ms(e,!0)}),e),hs(e,xs(e))},r=e.effect=new Kt(n,o,(()=>Io(s)),e.scope),s=e.update=()=>{r.dirty&&r.run()};s.id=e.uid,$s(e,!0),s()}(n),n.proxy}function xs(e){const{type:t,vnode:n,proxy:o,withProxy:r,props:i,propsOptions:[c],slots:a,attrs:l,emit:u,render:f,renderCache:p,data:d,setupState:h,ctx:g,uid:m,appContext:{app:{config:{globalProperties:{pruneComponentPropsCache:v}}}},inheritAttrs:_}=e;let y;e.$uniElementIds=new Map,e.$templateRefs=[],e.$templateUniElementRefs=[],e.$templateUniElementStyles={},e.$ei=0,v(m),e.__counter=0===e.__counter?1:0;const x=Bo(e);try{if(4&n.shapeFlag){bs(_,i,c,l);const e=r||o;y=f.call(e,e,p,i,h,d,g)}else{bs(_,i,c,t.props?l:(e=>{let t;for(const n in e)("class"===n||"style"===n||s(n))&&((t||(t={}))[n]=e[n]);return t})(l));const e=t;y=e.length>1?e(i,{attrs:l,slots:a,emit:u}):e(i,null)}}catch(b){_o(b,e,1),y=!1}return ms(e),Bo(x),y}function bs(e,t,n,o){if(t&&o&&!1!==e){const e=Object.keys(o).filter((e=>"class"!==e&&"style"!==e));if(!e.length)return;n&&e.some(i)?e.forEach((e=>{i(e)&&e.slice(9)in n||(t[e]=o[e])})):e.forEach((e=>t[e]=o[e]))}}function ws(){const e=this.$scopedSlotsData;if(!e||0===e.length)return;const t=this.ctx.$scope,n=t.data,o=Object.create(null);e.forEach((({path:e,index:t,data:r})=>{const s=D(n,e),i=g(t)?`${e}.${t}`:`${e}[${t}]`;if(void 0===s||void 0===s[t])o[i]=r;else{const e=is(r,s[t]);Object.keys(e).forEach((t=>{o[i+"."+t]=e[t]}))}})),e.length=0,Object.keys(o).length&&t.setData(o)}function $s({effect:e,update:t},n){e.allowRecurse=t.allowRecurse=n}const Ss=function(e,t=null){h(e)||(e=c({},e)),null==t||v(t)||(t=null);const n=Go(),o=new WeakSet,r=n.app={_uid:Jo++,_component:e,_props:t,_container:null,_context:n,_instance:null,version:ns,get config(){return n.config},set config(e){},use:(e,...t)=>(o.has(e)||(e&&h(e.install)?(o.add(e),e.install(r,...t)):h(e)&&(o.add(e),e(r,...t))),r),mixin:e=>(n.mixins.includes(e)||n.mixins.push(e),r),component:(e,t)=>t?(n.components[e]=t,r):n.components[e],directive:(e,t)=>t?(n.directives[e]=t,r):n.directives[e],mount(){},unmount(){},provide:(e,t)=>(n.provides[e]=t,r),runWithContext(e){const t=Zo;Zo=r;try{return e()}finally{Zo=t}}};return r};function ks(e,t=null){("undefined"!=typeof window?window:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof global?global:"undefined"!=typeof my?my:void 0).__VUE__=!0;const n=Ss(e,t),r=n._context;r.config.globalProperties.$nextTick=function(e){return fs(this.$,e)};const s=e=>(e.appContext=r,e.shapeFlag=6,e),i=function(e,t){return ys(s(e),t)},c=function(e){return e&&function(e){const{bum:t,scope:n,update:o,um:r}=e;t&&j(t);{const t=e.parent;if(t){const n=t.ctx.$children,o=es(e)||e.proxy,r=n.indexOf(o);r>-1&&n.splice(r,1)}}n.stop(),o&&(o.active=!1),r&&_s(r),_s((()=>{e.isUnmounted=!0}))}(e.$)};return n.mount=function(){e.render=o;const t=ys(s({type:e}),{mpType:"app",mpInstance:null,parentComponent:null,slots:[],props:null});return n._instance=t.$,t.$app=n,t.$createComponent=i,t.$destroyComponent=c,r.$appInstance=t,t},n.unmount=function(){},n}function Os(e,t,n,o){h(t)&&nr(e,t.bind(n),o)}function Ps(e,t,n){!function(e,t,n){const o=e.mpType||n.$mpType;!o||"component"===o||"page"===o&&"component"===t.renderer||Object.keys(e).forEach((o=>{if(K(o,e[o],!1)){const r=e[o];f(r)?r.forEach((e=>Os(o,e,n,t))):Os(o,r,n,t)}}))}(e,t,n)}function Cs(e,t,n){return e[t]=n}function Es(e,...t){const n=this[e];return n?n(...t):(console.error(`method ${e} not found`),null)}function Is(e){const t=e.config.errorHandler;return function(n,o,r){t&&t(n,o,r);const s=e._instance;if(!s||!s.proxy)throw n;s.onError?s.proxy.$callHook("onError",n):yo(n,0,o&&o.$.vnode,!1)}}function As(e,t){return e?[...new Set([].concat(e,t))]:t}let js;const Rs="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",Ls=/^(?:[A-Za-z\d+/]{4})*?(?:[A-Za-z\d+/]{2}(?:==)?|[A-Za-z\d+/]{3}=?)?$/;function Ts(){const e=Ut.getStorageSync("uni_id_token")||"",t=e.split(".");if(!e||3!==t.length)return{uid:null,role:[],permission:[],tokenExpired:0};let n;try{n=JSON.parse((o=t[1],decodeURIComponent(js(o).split("").map((function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)})).join(""))))}catch(r){throw new Error("获取当前用户信息出错,详细错误信息为:"+r.message)}var o;return n.tokenExpired=1e3*n.exp,delete n.exp,delete n.iat,n}function Ms(e){const t=e.config;var n;t.errorHandler=J(e,Is),n=t.optionMergeStrategies,z.forEach((e=>{n[e]=As}));const o=t.globalProperties;!function(e){e.uniIDHasRole=function(e){const{role:t}=Ts();return t.indexOf(e)>-1},e.uniIDHasPermission=function(e){const{permission:t}=Ts();return this.uniIDHasRole("admin")||t.indexOf(e)>-1},e.uniIDTokenValid=function(){const{tokenExpired:e}=Ts();return e>Date.now()}}(o),o.$set=Cs,o.$applyOptions=Ps,o.$callMethod=Es,Ut.invokeCreateVueAppHook(e)}js="function"!=typeof atob?function(e){if(e=String(e).replace(/[\t\n\f\r ]+/g,""),!Ls.test(e))throw new Error("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");var t;e+="==".slice(2-(3&e.length));for(var n,o,r="",s=0;s>16&255):64===o?String.fromCharCode(t>>16&255,t>>8&255):String.fromCharCode(t>>16&255,t>>8&255,255&t);return r}:atob;const Vs=Object.create(null);function Ds(e){delete Vs[e]}function Hs(e){if(!e)return;const[t,n]=e.split(",");return Vs[t]?Vs[t][parseInt(n)]:void 0}var Ns={install(e){Ms(e),e.config.globalProperties.pruneComponentPropsCache=Ds;const t=e.mount;e.mount=function(n){const o=t.call(e,n),r=function(){const e="createApp";if("undefined"!=typeof global&&void 0!==global[e])return global[e];if("undefined"!=typeof my)return my[e]}();return r?r(o):"undefined"!=typeof createMiniProgramApp&&createMiniProgramApp(o),o}}};function Bs(e,t){const n=Fr(),r=n.ctx,s=void 0===t||"mp-weixin"!==r.$mpPlatform&&"mp-qq"!==r.$mpPlatform&&"mp-xhs"!==r.$mpPlatform||!g(t)&&"number"!=typeof t?"":"_"+t,i="e"+n.$ei+++s,a=r.$scope;if(!e)return delete a[i],i;const l=a[i];return l?l.value=e:a[i]=function(e,t){const n=e=>{var r;(r=e).type&&r.target&&(r.preventDefault=o,r.stopPropagation=o,r.stopImmediatePropagation=o,u(r,"detail")||(r.detail={}),u(r,"markerId")&&(r.detail="object"==typeof r.detail?r.detail:{},r.detail.markerId=r.markerId),b(r.detail)&&u(r.detail,"checked")&&!u(r.detail,"value")&&(r.detail.value=r.detail.checked),b(r.detail)&&(r.target=c({},r.target,r.detail)));let s=[e];t&&t.ctx.$getTriggerEventDetail&&"number"==typeof e.detail&&(e.detail=t.ctx.$getTriggerEventDetail(e.detail)),e.detail&&e.detail.__args__&&(s=e.detail.__args__);const i=n.value,a=()=>vo(function(e,t){if(f(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n&&n.call(e),e._stopped=!0},t.map((e=>t=>!t._stopped&&e(t)))}return t}(e,i),t,5,s),l=e.target,p=!!l&&(!!l.dataset&&"true"===String(l.dataset.eventsync));if(!Us.includes(e.type)||p){const t=a();if("input"===e.type&&(f(t)||_(t)))return;return t}setTimeout(a)};return n.value=e,n}(e,n),i}const Us=["tap","longpress","longtap","transitionend","animationstart","animationiteration","animationend","touchforcechange"];const Ws=function(e,t=null){return e&&(e.mpType="app"),ks(e,t).use(Ns)};const zs=["externalClasses"];const Fs=/_(.*)_worklet_factory_/;function Ks(e,t){const n=e.$children;for(let r=n.length-1;r>=0;r--){const e=n[r];if(e.$scope._$vueId===t)return e}let o;for(let r=n.length-1;r>=0;r--)if(o=Ks(n[r],t),o)return o}const qs=["createSelectorQuery","createIntersectionObserver","selectAllComponents","selectComponent"];function Gs(e,t){const n=e.ctx;n.mpType=t.mpType,n.$mpType=t.mpType,n.$mpPlatform="mp-weixin",n.$scope=t.mpInstance,Object.defineProperties(n,{virtualHostId:{get(){const e=this.$scope.data.virtualHostId;return void 0===e?"":e}}}),n.$mp={},n._self={},e.slots={},f(t.slots)&&t.slots.length&&(t.slots.forEach((t=>{e.slots[t]=!0})),e.slots.d&&(e.slots.default=!0)),n.getOpenerEventChannel=function(){return t.mpInstance.getOpenerEventChannel()},n.$hasHook=Js,n.$callHook=Zs,e.emit=function(e,t){return function(n,...o){const r=t.$scope;if(r&&n){const e={__args__:o};r.triggerEvent(n,e)}return e.apply(this,[n,...o])}}(e.emit,n)}function Js(e){const t=this.$[e];return!(!t||!t.length)}function Zs(e,t){"mounted"===e&&(Zs.call(this,"bm"),this.$.isMounted=!0,e="m");const n=this.$[e];return n&&((e,t)=>{let n;for(let o=0;o{K(n,e[n])&&t.add(n)}));{const{extends:n,mixins:o}=e;o&&o.forEach((e=>Xs(e,t))),n&&Xs(n,t)}}return t}function Ys(e,t,n){-1!==n.indexOf(t)||u(e,t)||(e[t]=function(e){return this.$vm&&this.$vm.$callHook(t,e)})}const ei=["onReady"];function ti(e,t,n=ei){t.forEach((t=>Ys(e,t,n)))}function ni(e,t,n=ei){Xs(t).forEach((t=>Ys(e,t,n)))}const oi=V((()=>{const e=[],t=h(getApp)&&getApp({allowDefault:!0});if(t&&t.$vm&&t.$vm.$){const n=t.$vm.$.appContext.mixins;if(f(n)){const t=Object.keys(F);n.forEach((n=>{t.forEach((t=>{u(n,t)&&!e.includes(t)&&e.push(t)}))}))}}return e}));const ri=["onShow","onHide","onError","onThemeChange","onPageNotFound","onUnhandledRejection"];function si(e,t){const n=e.$,o={globalData:e.$options&&e.$options.globalData||{},$vm:e,onLaunch(t){this.$vm=e;const o=n.ctx;this.$vm&&o.$scope&&o.$callHook||(Gs(n,{mpType:"app",mpInstance:this,slots:[]}),o.globalData=this.globalData,e.$callHook("onLaunch",t))}},r=wx.$onErrorHandlers;r&&(r.forEach((e=>{nr("onError",e,n)})),r.length=0),function(e){const t=uo(function(){var e;let t="";{const n=(null===(e=wx.getAppBaseInfo)||void 0===e?void 0:e.call(wx))||wx.getSystemInfoSync();t=X(n&&n.language?n.language:"en")||"en"}return t}());Object.defineProperty(e,"$locale",{get:()=>t.value,set(e){t.value=e}})}(e);const s=e.$.type;ti(o,ri),ni(o,s);{const e=s.methods;e&&c(o,e)}return o}function ii(e,t){if(h(e.onLaunch)){const t=wx.getLaunchOptionsSync&&wx.getLaunchOptionsSync();e.onLaunch(t)}h(e.onShow)&&wx.onAppShow&&wx.onAppShow((e=>{t.$callHook("onShow",e)})),h(e.onHide)&&wx.onAppHide&&wx.onAppHide((e=>{t.$callHook("onHide",e)}))}const ci=["eO","uR","uRIF","uI","uT","uP","uS"];function ai(e){e.properties||(e.properties={}),c(e.properties,function(e,t=!1){const n={};if(!t){let e=function(e){const t=Object.create(null);e&&e.forEach((e=>{t[e]=!0})),this.setData({$slots:t})};ci.forEach((e=>{n[e]={type:null,value:""}})),n.uS={type:null,value:[]},n.uS.observer=e}return e.behaviors&&e.behaviors.includes("wx://form-field")&&(e.properties&&e.properties.name||(n.name={type:null,value:""}),e.properties&&e.properties.value||(n.value={type:null,value:""})),n}(e),function(e){const t={};return e&&e.virtualHost&&(t.virtualHostStyle={type:null,value:""},t.virtualHostClass={type:null,value:""},t.virtualHostHidden={type:null,value:""},t.virtualHostId={type:null,value:""}),t}(e.options))}const li=[String,Number,Boolean,Object,Array,null];function ui(e,t){const n=function(e,t){return f(e)&&1===e.length?e[0]:e}(e);return-1!==li.indexOf(n)?n:null}function fi(e,t){return(t?function(e){const t={};b(e)&&Object.keys(e).forEach((n=>{-1===ci.indexOf(n)&&(t[n]=e[n])}));return t}(e):Hs(e.uP))||{}}function pi(e){const t=function(){const e=this.properties.uP;e&&(this.$vm?function(e,t){const n=no(t.props),o=Hs(e)||{};di(n,o)&&(!function(e,t,n,o){const{props:r,attrs:s,vnode:{patchFlag:i}}=e,c=no(r),[a]=e.propsOptions;let l=!1;if(!(o||i>0)||16&i){let o;jr(e,t,r,s)&&(l=!0);for(const s in c)t&&(u(t,s)||(o=C(s))!==s&&u(t,o))||(a?!n||void 0===n[s]&&void 0===n[o]||(r[s]=Rr(a,c,s,void 0,e,!0)):delete r[s]);if(s!==c)for(const e in s)t&&u(t,e)||(delete s[e],l=!0)}else if(8&i){const n=e.vnode.dynamicProps;for(let o=0;o-1&&function(e){const t=wo.indexOf(e);t>$o&&wo.splice(t,1)}(t.update),t.update());var r}(e,this.$vm.$):"m"===this.properties.uT&&function(e,t){const n=t.properties,o=Hs(e)||{};di(n,o,!1)&&t.setData(o)}(e,this))};e.observers||(e.observers={}),e.observers.uP=t}function di(e,t,n=!0){const o=Object.keys(t);if(n&&o.length!==Object.keys(e).length)return!0;for(let r=0;r{o.push(e.replace("uni://","wx://")),"uni://form-field"===e&&(f(n)?(n.push("name"),n.push("modelValue")):(n.name={type:String,default:""},n.modelValue={type:[String,Number,Boolean,Array,Object,Date],default:""}))})),o}(t)}function gi(e,{parse:t,mocks:n,isPage:o,isPageInProject:r,initRelation:s,handleLink:i,initLifetimes:a}){e=e.default||e;const l={multipleSlots:!0,addGlobalClass:!0,pureDataPattern:/^uP$/};f(e.mixins)&&e.mixins.forEach((e=>{v(e.options)&&c(l,e.options)})),e.options&&c(l,e.options);const p={options:l,lifetimes:a({mocks:n,isPage:o,initRelation:s,vueOptions:e}),pageLifetimes:{show(){this.$vm&&this.$vm.$callHook("onPageShow")},hide(){this.$vm&&this.$vm.$callHook("onPageHide")},resize(e){this.$vm&&this.$vm.$callHook("onPageResize",e)}},methods:{__l:i}};var d,h,g,m;return hi(p,e),ai(p),pi(p),function(e,t){zs.forEach((n=>{u(t,n)&&(e[n]=t[n])}))}(p,e),d=p.methods,h=e.wxsCallMethods,f(h)&&h.forEach((e=>{d[e]=function(t){return this.$vm[e](t)}})),g=p.methods,(m=e.methods)&&Object.keys(m).forEach((e=>{const t=e.match(Fs);if(t){const n=t[1];g[e]=m[e],g[n]=m[n]}})),t&&t(p,{handleLink:i}),p}let mi,vi;function _i(){return getApp().$vm}function yi(e,t){const{parse:n,mocks:o,isPage:r,initRelation:s,handleLink:i,initLifetimes:c}=t,a=gi(e,{mocks:o,isPage:r,isPageInProject:!0,initRelation:s,handleLink:i,initLifetimes:c});!function({properties:e},t){f(t)?t.forEach((t=>{e[t]={type:String,value:""}})):b(t)&&Object.keys(t).forEach((n=>{const o=t[n];if(b(o)){let t=o.default;h(t)&&(t=t());const r=o.type;o.type=ui(r),e[n]={type:o.type,value:t}}else e[n]={type:ui(o)}}))}(a,(e.default||e).props);const l=a.methods;return l.onLoad=function(e){var t;return this.options=e,this.$page={fullPath:(t=this.route+U(e),function(e){return 0===e.indexOf("/")}(t)?t:"/"+t)},this.$vm&&this.$vm.$callHook("onLoad",e)},ti(l,Qs),ni(l,e),function(e,t){if(!t)return;Object.keys(F).forEach((n=>{t&F[n]&&Ys(e,n,[])}))}(l,e.__runtimeHooks),ti(l,oi()),n&&n(a,{handleLink:i}),a}const xi=Page,bi=Component;function wi(e){const t=e.triggerEvent,n=function(n,...o){return t.apply(e,[(r=n,O(r.replace(N,"-"))),...o]);var r};try{e.triggerEvent=n}catch(o){e._triggerEvent=n}}function $i(e,t,n){const o=t[e];t[e]=o?function(...e){return wi(this),o.apply(this,e)}:function(){wi(this)}}Page=function(e){return $i("onLoad",e),xi(e)},Component=function(e){$i("created",e);return e.properties&&e.properties.uP||(ai(e),pi(e)),bi(e)};var Si=Object.freeze({__proto__:null,handleLink:function(e){const t=e.detail||e.value,n=t.vuePid;let o;n&&(o=Ks(this.$vm,n)),o||(o=this.$vm),t.parent=o},initLifetimes:function({mocks:e,isPage:t,initRelation:n,vueOptions:o}){return{attached(){let r=this.properties;!function(e,t){if(!e)return;const n=e.split(","),o=n.length;1===o?t._$vueId=n[0]:2===o&&(t._$vueId=n[0],t._$vuePid=n[1])}(r.uI,this);const s={vuePid:this._$vuePid};n(this,s);const i=this,c=t(i);let a=r;this.$vm=function(e,t){mi||(mi=_i().$createComponent);const n=mi(e,t);return es(n.$)||n}({type:o,props:fi(a,c)},{mpType:c?"page":"component",mpInstance:i,slots:r.uS||{},parentComponent:s.parent&&s.parent.$,onBeforeSetup(t,n){!function(e,t){Object.defineProperty(e,"refs",{get(){const e={};return function(e,t,n){e.selectAllComponents(t).forEach((e=>{const t=e.properties.uR;n[t]=e.$vm||e}))}(t,".r",e),t.selectAllComponents(".r-i-f").forEach((t=>{const n=t.properties.uR;n&&(e[n]||(e[n]=[]),e[n].push(t.$vm||t))})),e}})}(t,i),function(e,t,n){const o=e.ctx;n.forEach((n=>{u(t,n)&&(e[n]=o[n]=t[n])}))}(t,i,e),function(e,t){Gs(e,t);const n=e.ctx;qs.forEach((e=>{n[e]=function(...t){const o=n.$scope;if(o&&o[e])return o[e].apply(o,t)}}))}(t,n)}}),c||function(e){const t=e.$options;f(t.behaviors)&&t.behaviors.includes("uni://form-field")&&e.$watch("modelValue",(()=>{e.$scope&&e.$scope.setData({name:e.name,value:e.modelValue})}),{immediate:!0})}(this.$vm)},ready(){this.$vm&&(this.$vm.$callHook("mounted"),this.$vm.$callHook("onReady"))},detached(){var e;this.$vm&&(Ds(this.$vm.$.uid),e=this.$vm,vi||(vi=_i().$destroyComponent),vi(e))}}},initRelation:function(e,t){e.triggerEvent("__l",t)},isPage:function(e){return!!e.route},mocks:["__route__","__wxExparserNodeId__","__wxWebviewId__"]});const ki=function(e){return App(si(e))},Oi=(Pi=Si,function(e){return Component(yi(e,Pi))});var Pi;const Ci=function(e){return function(t){return Component(gi(t,e))}}(Si),Ei=function(e){ii(si(e),e)},Ii=function(e){const t=si(e),n=h(getApp)&&getApp({allowDefault:!0});if(!n)return;e.$.ctx.$scope=n;const o=n.globalData;o&&Object.keys(t.globalData).forEach((e=>{u(o,e)||(o[e]=t.globalData[e])})),Object.keys(t).forEach((e=>{u(n,e)||(n[e]=t[e])})),ii(t,e)};!function(){if(h(wx.preloadAssets)){const e=String.fromCharCode(99,100,110,49,46,100,99,108,111,117,100,46,110,101,116,46,99,110);setTimeout((()=>{wx.preloadAssets({data:[{type:"image",src:"https://"+e+"/4f446b344f5546434e79556c6433673459546b794f474a694f47457a4f54513159544532/img/shadow-grey.png"}]})}),3e3)}}(),wx.createApp=global.createApp=ki,wx.createPage=Oi,wx.createComponent=Ci,wx.createPluginApp=global.createPluginApp=Ei,wx.createSubpackageApp=global.createSubpackageApp=Ii;const Ai=(e,t=0)=>(t,n=Fr())=>{!Qr&&nr(e,t,n)},ji=Ai("onShow",3),Ri=Ai("onLoad",2),Li=Ai("onPullDownRefresh",2),Ti=Ai("onShareAppMessage",2);exports._export_sfc=(e,t)=>{const n=e.__vccOpts||e;for(const[o,r]of t)n[o]=r;return n},exports.computed=ts,exports.createSSRApp=Ws,exports.e=(e,...t)=>c(e,...t),exports.f=(e,t)=>function(e,t){let n;if(f(e)||g(e)){n=new Array(e.length);for(let o=0,r=e.length;ot(e,n,n)));else{const o=Object.keys(e);n=new Array(o.length);for(let r=0,s=o.length;rL(e),exports.o=(e,t)=>Bs(e,t),exports.onLoad=Ri,exports.onPullDownRefresh=Li,exports.onShareAppMessage=Ti,exports.onShow=ji,exports.p=e=>function(e){const{uid:t,__counter:n}=Fr();return t+","+((Vs[t]||(Vs[t]=[])).push(Nr(e))-1)+","+n}(e),exports.reactive=Zn,exports.ref=uo,exports.t=e=>(e=>g(e)?e:null==e?"":f(e)||v(e)&&(e.toString===y||!h(e.toString))?JSON.stringify(e,T,2):String(e))(e),exports.unref=po,exports.watch=Wo,exports.wx$1=Bt;
diff --git a/uniapp/unpackage/dist/build/mp-weixin/components/AppTabBar.js b/uniapp/unpackage/dist/build/mp-weixin/components/AppTabBar.js
new file mode 100644
index 0000000..6b63149
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/components/AppTabBar.js
@@ -0,0 +1 @@
+"use strict";const e=require("../common/vendor.js"),t={__name:"AppTabBar",props:{current:{type:String,default:"home"}},setup(t){const a=t,o=[{id:"home",label:"首页",path:"/pages/home/index",color:"#1f6f5f"},{id:"bills",label:"账单",path:"/pages/bills/index",color:"#d36c43"},{id:"budget",label:"预算",path:"/pages/budget/index",color:"#5f8df5"},{id:"stats",label:"报表",path:"/pages/stats/index",color:"#7f56d9"},{id:"mine",label:"我的",path:"/pages/mine/index",color:"#44546a"}];return(r,d)=>({a:e.f(o,((o,r,d)=>({a:t.current===o.id?o.color:"var(--line-soft)",b:e.t(o.label),c:o.id,d:t.current===o.id?1:"",e:e.o((t=>function(t){t.id!==a.current&&e.index.redirectTo({url:t.path})}(o)),o.id)})))})}},a=e._export_sfc(t,[["__scopeId","data-v-c3788da6"]]);wx.createComponent(a);
diff --git a/uniapp/unpackage/dist/build/mp-weixin/components/AppTabBar.json b/uniapp/unpackage/dist/build/mp-weixin/components/AppTabBar.json
new file mode 100644
index 0000000..e8cfaaf
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/components/AppTabBar.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/components/AppTabBar.wxml b/uniapp/unpackage/dist/build/mp-weixin/components/AppTabBar.wxml
new file mode 100644
index 0000000..976b378
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/components/AppTabBar.wxml
@@ -0,0 +1 @@
+{{item.b}}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/components/AppTabBar.wxss b/uniapp/unpackage/dist/build/mp-weixin/components/AppTabBar.wxss
new file mode 100644
index 0000000..cdbecc2
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/components/AppTabBar.wxss
@@ -0,0 +1 @@
+.tabbar.data-v-c3788da6{position:fixed;left:24rpx;right:24rpx;bottom:24rpx;display:flex;align-items:center;justify-content:space-between;padding:18rpx 12rpx env(safe-area-inset-bottom);z-index:20}.tab-item.data-v-c3788da6{flex:1;display:flex;flex-direction:column;align-items:center;gap:10rpx;padding:14rpx 0;border-radius:22rpx}.tab-item.active.data-v-c3788da6{background:var(--brand-soft)}.tab-dot.data-v-c3788da6{width:18rpx;height:18rpx;border-radius:50%}.tab-label.data-v-c3788da6{font-size:22rpx;color:var(--text-secondary)}.tab-item.active .tab-label.data-v-c3788da6{color:var(--text-primary);font-weight:600}
diff --git a/uniapp/unpackage/dist/build/mp-weixin/components/BillEditorPopup.js b/uniapp/unpackage/dist/build/mp-weixin/components/BillEditorPopup.js
new file mode 100644
index 0000000..158026d
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/components/BillEditorPopup.js
@@ -0,0 +1 @@
+"use strict";const e=require("../common/vendor.js"),t=require("../utils/date.js"),a={__name:"BillEditorPopup",props:{visible:{type:Boolean,default:!1},entry:{type:Object,default:null},categories:{type:Object,required:!0},accounts:{type:Array,required:!0},defaultType:{type:String,default:"expense"},initialCategoryId:{type:String,default:""}},emits:["close","save"],setup(a,{emit:o}){const d=a,i=o,c=[{label:"支出",value:"expense"},{label:"收入",value:"income"}],n=e.reactive({id:"",type:"expense",amount:"",categoryId:"",accountId:"",date:t.toDateKey(),note:"",createdAt:0}),l=e.computed((()=>d.categories[n.type]||[]));function u(e){n.date=e.detail.value}function r(){Number(n.amount)?n.categoryId&&n.accountId?(i("save",{id:n.id,type:n.type,amount:Number(n.amount),categoryId:n.categoryId,accountId:n.accountId,date:n.date,note:n.note.trim(),createdAt:n.createdAt}),i("close")):e.index.showToast({title:"请选择分类和账户",icon:"none"}):e.index.showToast({title:"请输入有效金额",icon:"none"})}return e.watch((()=>d.visible),(e=>{e&&function(){var e,a,o;const i=d.entry||{},c=i.type||d.defaultType||"expense",l=d.initialCategoryId&&(d.categories[c]||[]).some((e=>e.id===d.initialCategoryId))?d.initialCategoryId:(null==(a=null==(e=d.categories[c])?void 0:e[0])?void 0:a.id)||"";n.id=i.id||"",n.type=c,n.amount=i.amount?String(i.amount):"",n.categoryId=i.categoryId||l,n.accountId=i.accountId||(null==(o=d.accounts[0])?void 0:o.id)||"",n.date=i.date||t.toDateKey(),n.note=i.note||"",n.createdAt=i.createdAt||0}()}),{immediate:!0}),e.watch((()=>n.type),(e=>{const t=(d.categories[e]||[]).map((e=>e.id));t.includes(n.categoryId)||(n.categoryId=t[0]||"")})),(t,o)=>e.e({a:a.visible},a.visible?{b:e.o((e=>i("close"))),c:e.t(n.id?"编辑账单":"新增账单"),d:e.o((e=>i("close"))),e:e.f(c,((t,a,o)=>({a:e.t(t.label),b:t.value,c:n.type===t.value?1:"",d:e.o((e=>n.type=t.value),t.value)}))),f:n.amount,g:e.o((e=>n.amount=e.detail.value)),h:e.f(l.value,((t,a,o)=>({a:t.color,b:e.t(t.name),c:t.id,d:n.categoryId===t.id?1:"",e:e.o((e=>n.categoryId=t.id),t.id)}))),i:e.f(a.accounts,((t,a,o)=>({a:t.color,b:e.t(t.name),c:t.id,d:n.accountId===t.id?1:"",e:e.o((e=>n.accountId=t.id),t.id)}))),j:e.t(n.date),k:n.date,l:e.o(u),m:n.note,n:e.o((e=>n.note=e.detail.value)),o:e.o((e=>i("close"))),p:e.o(r),q:e.o((()=>{}))}:{})}},o=e._export_sfc(a,[["__scopeId","data-v-eeef8b0e"]]);wx.createComponent(o);
diff --git a/uniapp/unpackage/dist/build/mp-weixin/components/BillEditorPopup.json b/uniapp/unpackage/dist/build/mp-weixin/components/BillEditorPopup.json
new file mode 100644
index 0000000..e8cfaaf
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/components/BillEditorPopup.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/components/BillEditorPopup.wxml b/uniapp/unpackage/dist/build/mp-weixin/components/BillEditorPopup.wxml
new file mode 100644
index 0000000..e956737
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/components/BillEditorPopup.wxml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/components/BillEditorPopup.wxss b/uniapp/unpackage/dist/build/mp-weixin/components/BillEditorPopup.wxss
new file mode 100644
index 0000000..ce27f47
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/components/BillEditorPopup.wxss
@@ -0,0 +1 @@
+.popup-shell.data-v-eeef8b0e{position:fixed;top:0;right:0;bottom:0;left:0;z-index:50}.popup-mask.data-v-eeef8b0e{position:absolute;top:0;right:0;bottom:0;left:0;background:rgba(3,12,21,.42)}.popup-panel.data-v-eeef8b0e{position:absolute;left:16rpx;right:16rpx;bottom:16rpx;max-height:84vh;padding:28rpx 28rpx 32rpx;display:flex;flex-direction:column;gap:24rpx}.popup-head.data-v-eeef8b0e{display:flex;align-items:flex-start;justify-content:space-between;gap:16rpx}.close-text.data-v-eeef8b0e{padding:10rpx 0;font-size:24rpx;color:var(--text-secondary)}.popup-body.data-v-eeef8b0e{max-height:58vh}.field-block.data-v-eeef8b0e{display:flex;flex-direction:column;gap:18rpx;margin-bottom:24rpx}.field-label.data-v-eeef8b0e{font-size:26rpx;font-weight:600;color:var(--text-primary)}.pill-row.data-v-eeef8b0e,.chip-grid.data-v-eeef8b0e{display:flex;flex-wrap:wrap;gap:16rpx}.chip-item.data-v-eeef8b0e{display:flex;align-items:center;gap:10rpx;padding:16rpx 20rpx;border-radius:22rpx;background:var(--surface-muted);color:var(--text-secondary);font-size:24rpx}.chip-item.active.data-v-eeef8b0e{background:var(--brand-soft);color:var(--text-primary)}.chip-dot.data-v-eeef8b0e{width:14rpx;height:14rpx;border-radius:50%}.amount-shell.data-v-eeef8b0e{gap:12rpx}.prefix-text.data-v-eeef8b0e{font-size:36rpx;font-weight:600;color:var(--text-primary)}.picker-shell.data-v-eeef8b0e{justify-content:space-between}.textarea-shell.data-v-eeef8b0e{padding:20rpx 24rpx;min-height:160rpx;align-items:flex-start}.textarea-shell textarea.data-v-eeef8b0e{min-height:120rpx}.popup-foot.data-v-eeef8b0e{display:flex;align-items:center;gap:16rpx}.popup-foot .ghost-button.data-v-eeef8b0e{flex:0 0 180rpx}.save-button.data-v-eeef8b0e{flex:1}
diff --git a/uniapp/unpackage/dist/build/mp-weixin/components/SectionCard.js b/uniapp/unpackage/dist/build/mp-weixin/components/SectionCard.js
new file mode 100644
index 0000000..6194c7e
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/components/SectionCard.js
@@ -0,0 +1 @@
+"use strict";const t=require("../common/vendor.js"),e={__name:"SectionCard",props:{title:{type:String,default:""},subtitle:{type:String,default:""}},setup:e=>(i,s)=>t.e({a:e.title||e.subtitle||i.$slots.action},e.title||e.subtitle||i.$slots.action?t.e({b:e.title},e.title?{c:t.t(e.title)}:{},{d:e.subtitle},e.subtitle?{e:t.t(e.subtitle)}:{}):{})},i=t._export_sfc(e,[["__scopeId","data-v-55faa340"]]);wx.createComponent(i);
diff --git a/uniapp/unpackage/dist/build/mp-weixin/components/SectionCard.json b/uniapp/unpackage/dist/build/mp-weixin/components/SectionCard.json
new file mode 100644
index 0000000..e8cfaaf
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/components/SectionCard.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/components/SectionCard.wxml b/uniapp/unpackage/dist/build/mp-weixin/components/SectionCard.wxml
new file mode 100644
index 0000000..52cd708
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/components/SectionCard.wxml
@@ -0,0 +1 @@
+{{c}}{{e}}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/components/SectionCard.wxss b/uniapp/unpackage/dist/build/mp-weixin/components/SectionCard.wxss
new file mode 100644
index 0000000..6800c16
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/components/SectionCard.wxss
@@ -0,0 +1 @@
+.card.data-v-55faa340{padding:28rpx}.head.data-v-55faa340{display:flex;align-items:flex-start;justify-content:space-between;gap:16rpx;margin-bottom:24rpx}.title-group.data-v-55faa340{display:flex;flex-direction:column;gap:10rpx}
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/bills/index.js b/uniapp/unpackage/dist/build/mp-weixin/pages/bills/index.js
new file mode 100644
index 0000000..c475e27
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/bills/index.js
@@ -0,0 +1 @@
+"use strict";const e=require("../../common/vendor.js"),t=require("../../utils/store.js"),a=require("../../utils/date.js"),u=require("../../utils/money.js");Math||(n+o+l)();const n=()=>"../../components/SectionCard.js",o=()=>"../../components/AppTabBar.js",l=()=>"../../components/BillEditorPopup.js",r={__name:"index",setup(n){const o=t.useAppStore(),l=e.ref(!1),r=e.ref(null),i=e.ref(!1),c=e.ref([]),d=e.computed((()=>"dark"===o.state.settings.theme?"theme-dark":"")),m=e.reactive({type:"all",period:"month",month:a.toMonthKey(),keyword:"",categoryId:"",accountId:"",minAmount:"",maxAmount:""}),v=[{label:"全部",value:"all"},{label:"支出",value:"expense"},{label:"收入",value:"income"}],s=[{label:"本月",value:"month"},{label:"近 7 天",value:"7d"},{label:"近 30 天",value:"30d"},{label:"全部",value:"all"}],p=e.computed((()=>[...o.state.bills].sort(((e,t)=>t.createdAt-e.createdAt)))),f=e.computed((()=>[{id:"",name:"全部分类"},..."all"===m.type?[...o.state.categories.expense,...o.state.categories.income]:o.state.categories[m.type]])),y=e.computed((()=>[{id:"",name:"全部账户"},...o.state.accounts])),h=e.computed((()=>f.value.map((e=>e.name)))),b=e.computed((()=>y.value.map((e=>e.name)))),g=e.computed((()=>Math.max(0,f.value.findIndex((e=>e.id===m.categoryId))))),x=e.computed((()=>Math.max(0,y.value.findIndex((e=>e.id===m.accountId))))),I=e.computed((()=>{var e;return(null==(e=f.value[g.value])?void 0:e.name)||"全部分类"})),w=e.computed((()=>{var e;return(null==(e=y.value[x.value])?void 0:e.name)||"全部账户"})),A=e.computed((()=>a.formatMonthLabel(m.month))),k=e.computed((()=>m.month));function M(e){const t=new Date,u=a.parseDate(e);return(t.getTime()-u.getTime())/864e5}const j=e.computed((()=>p.value.filter((e=>{if("all"!==m.type&&e.type!==m.type)return!1;if("month"===m.period&&!a.isSameMonth(e.date,m.month))return!1;if("7d"===m.period&&M(e.date)>7)return!1;if("30d"===m.period&&M(e.date)>30)return!1;if(m.categoryId&&e.categoryId!==m.categoryId)return!1;if(m.accountId&&e.accountId!==m.accountId)return!1;if(m.minAmount&&Number(e.amount)Number(m.maxAmount))return!1;if(m.keyword){const t=B(e).name||"",a=D(e).name||"",u=m.keyword.trim().toLowerCase();if(!`${e.note||""} ${t} ${a}`.toLowerCase().includes(u))return!1}return!0})))),N=e.computed((()=>j.value.filter((e=>"expense"===e.type)).reduce(((e,t)=>e+Number(t.amount)),0))),C=e.computed((()=>j.value.filter((e=>"income"===e.type)).reduce(((e,t)=>e+Number(t.amount)),0)));function B(e){return(o.state.categories[e.type]||[]).find((t=>t.id===e.categoryId))||{}}function D(e){return o.state.accounts.find((t=>t.id===e.accountId))||{}}function L(e){var t;m.categoryId=(null==(t=f.value[Number(e.detail.value)])?void 0:t.id)||""}function T(e){var t;m.accountId=(null==(t=y.value[Number(e.detail.value)])?void 0:t.id)||""}function $(e){m.month=String(e.detail.value).slice(0,7),m.period="month"}function _(){m.type="all",m.period="month",m.month=a.toMonthKey(),m.keyword="",m.categoryId="",m.accountId="",m.minAmount="",m.maxAmount=""}function q(e=null){r.value=e?{...e}:null,l.value=!0}function S(){l.value=!1,r.value=null}function P(t){o.saveBill(t),e.index.showToast({title:t.id?"账单已更新":"账单已保存",icon:"none"})}function K(t){e.index.showActionSheet({itemList:["编辑账单","删除账单"],success:({tapIndex:a})=>{0===a&&q(t),1===a&&function(t){e.index.showModal({title:"删除账单",content:`确认删除 ${B(t).name||"该账单"} 吗?`,success:({confirm:e})=>{e&&o.deleteBill(t.id)}})}(t)}})}function E(){i.value=!i.value,c.value=[]}function R(){c.value=j.value.map((e=>e.id))}function z(){c.value.length?e.index.showModal({title:"批量删除",content:`确认删除 ${c.value.length} 笔账单吗?`,success:({confirm:e})=>{e&&(o.deleteBills(c.value),c.value=[],i.value=!1)}}):e.index.showToast({title:"请选择账单",icon:"none"})}return e.onPullDownRefresh((()=>{setTimeout((()=>{e.index.stopPullDownRefresh()}),200)})),(t,n)=>e.e({a:e.f(v,((t,a,u)=>({a:e.t(t.label),b:t.value,c:m.type===t.value?1:"",d:e.o((e=>{m.type=t.value,m.categoryId=""}),t.value)}))),b:e.f(s,((t,a,u)=>({a:e.t(t.label),b:t.value,c:m.period===t.value?1:"",d:e.o((e=>m.period=t.value),t.value)}))),c:e.t(A.value),d:k.value,e:e.o($),f:m.keyword,g:e.o((e=>m.keyword=e.detail.value)),h:m.minAmount,i:e.o((e=>m.minAmount=e.detail.value)),j:m.maxAmount,k:e.o((e=>m.maxAmount=e.detail.value)),l:e.t(I.value),m:h.value,n:g.value,o:e.o(L),p:e.t(w.value),q:b.value,r:x.value,s:e.o(T),t:e.o(_),v:e.o((e=>q())),w:e.p({title:"账单筛选",subtitle:"按月份、分类、账户、金额区间和关键词组合查询"}),x:e.t(i.value?"退出批量":"批量删除"),y:e.o(E),z:e.t(e.unref(u.formatCurrency)(N.value)),A:e.t(e.unref(u.formatCurrency)(C.value)),B:e.t(e.unref(u.formatCurrency)(C.value-N.value)),C:j.value.length},j.value.length?{D:e.f(j.value,((t,n,o)=>e.e(i.value?{a:c.value.includes(t.id)?1:""}:{},{b:B(t).color||"#7b8794",c:e.t(B(t).name||"未分类"),d:e.t(D(t).name||"账户"),e:e.t(e.unref(a.formatDateLabel)(t.date)),f:e.t(t.note||"无备注"),g:e.t("income"===t.type?"+":"-"),h:e.t(e.unref(u.formatCurrency)(t.amount).replace("¥","")),i:e.n("income"===t.type?"positive":"negative"),j:t.id,k:e.o((e=>{return i.value?(a=t.id,void(i.value&&(c.value=c.value.includes(a)?c.value.filter((e=>e!==a)):[...c.value,a]))):q(t);var a}),t.id),l:e.o((e=>K(t)),t.id)}))),E:i.value}:{},{F:e.p({title:"账单概览",subtitle:`共 ${j.value.length} 笔记录,点击编辑,长按可删除`}),G:i.value},i.value?{H:e.t(c.value.length),I:e.o(R),J:e.o(z)}:{},{K:e.p({current:"bills"}),L:e.o(S),M:e.o(P),N:e.p({visible:l.value,entry:r.value,categories:e.unref(o).state.categories,accounts:e.unref(o).state.accounts}),O:e.n(d.value)})}},i=e._export_sfc(r,[["__scopeId","data-v-ff523969"]]);wx.createPage(i);
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/bills/index.json b/uniapp/unpackage/dist/build/mp-weixin/pages/bills/index.json
new file mode 100644
index 0000000..b95a9cf
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/bills/index.json
@@ -0,0 +1,9 @@
+{
+ "navigationBarTitleText": "账单管理",
+ "enablePullDownRefresh": true,
+ "usingComponents": {
+ "section-card": "../../components/SectionCard",
+ "app-tab-bar": "../../components/AppTabBar",
+ "bill-editor-popup": "../../components/BillEditorPopup"
+ }
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/bills/index.wxml b/uniapp/unpackage/dist/build/mp-weixin/pages/bills/index.wxml
new file mode 100644
index 0000000..db47404
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/bills/index.wxml
@@ -0,0 +1 @@
+{{item.a}}{{item.a}}{{c}}{{l}}分类{{p}}账户清空筛选新增账单{{x}}支出{{z}}收入{{A}}结余{{B}}{{bill.c}}{{bill.d}} · {{bill.e}} · {{bill.f}}{{bill.g}}{{bill.h}}当前筛选条件下没有符合条件的账单记录。已选 {{H}} 笔全选删除所选
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/bills/index.wxss b/uniapp/unpackage/dist/build/mp-weixin/pages/bills/index.wxss
new file mode 100644
index 0000000..f3d0796
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/bills/index.wxss
@@ -0,0 +1 @@
+.chip-row.data-v-ff523969,.action-row.data-v-ff523969,.picker-row.data-v-ff523969,.summary-row.data-v-ff523969{display:flex;flex-wrap:wrap;gap:16rpx}.compact-row.data-v-ff523969{margin-top:16rpx}.mini-pill.data-v-ff523969{padding:16rpx 22rpx}.form-grid.data-v-ff523969{display:flex;flex-direction:column;gap:16rpx;margin:18rpx 0}.double-grid.data-v-ff523969,.picker-row.data-v-ff523969{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16rpx}.picker-shell.data-v-ff523969{justify-content:space-between}.action-row.data-v-ff523969{margin-top:18rpx}.action-row .ghost-button.data-v-ff523969,.action-row .primary-button.data-v-ff523969{flex:1}.section-link.data-v-ff523969{font-size:24rpx;color:var(--brand)}.summary-item.data-v-ff523969{flex:1;padding:22rpx;border-radius:24rpx}.summary-value.data-v-ff523969{margin-top:10rpx;font-size:30rpx;font-weight:700;color:var(--text-primary)}.bill-list.data-v-ff523969{display:flex;flex-direction:column;gap:16rpx;margin-top:22rpx}.bill-row.data-v-ff523969{display:flex;align-items:center;justify-content:space-between;gap:16rpx;padding:22rpx;border-radius:24rpx;background:var(--surface-muted)}.row-main.data-v-ff523969{display:flex;align-items:center;gap:16rpx;flex:1}.check-box.data-v-ff523969{width:30rpx;height:30rpx;border-radius:10rpx;border:2rpx solid var(--brand)}.check-box.checked.data-v-ff523969{background:var(--brand)}.bill-dot.data-v-ff523969{width:16rpx;height:16rpx;border-radius:50%}.bill-body.data-v-ff523969{flex:1}.bill-title.data-v-ff523969,.bill-amount.data-v-ff523969{font-size:28rpx;font-weight:600;color:var(--text-primary)}.bill-meta.data-v-ff523969{margin-top:8rpx;font-size:22rpx;color:var(--text-secondary);line-height:1.5}.empty-card.data-v-ff523969{padding:40rpx 0 10rpx;text-align:center}.batch-bar.data-v-ff523969{position:fixed;left:24rpx;right:24rpx;bottom:176rpx;display:flex;align-items:center;gap:16rpx;padding:20rpx 22rpx;z-index:18}.batch-text.data-v-ff523969{flex:1;font-size:26rpx;color:var(--text-primary)}
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/budget/index.js b/uniapp/unpackage/dist/build/mp-weixin/pages/budget/index.js
new file mode 100644
index 0000000..9d1f5c2
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/budget/index.js
@@ -0,0 +1 @@
+"use strict";const e=require("../../common/vendor.js"),t=require("../../utils/store.js"),a=require("../../utils/date.js"),u=require("../../utils/money.js");Math||(r+n)();const r=()=>"../../components/SectionCard.js",n=()=>"../../components/AppTabBar.js",o={__name:"index",setup(r){const n=t.useAppStore(),o=e.computed((()=>a.toMonthKey())),s=e.computed((()=>"dark"===n.state.settings.theme?"theme-dark":"")),l=e.ref(String(n.state.budgets.total||"")),d=e.reactive({}),c=e.computed((()=>n.state.bills.filter((e=>"expense"===e.type&&a.isSameMonth(e.date,o.value))))),i=e.computed((()=>c.value.reduce(((e,t)=>e+Number(t.amount)),0))),m=e.computed((()=>Number(n.state.budgets.total)||0)),p=e.computed((()=>m.value-i.value)),v=e.computed((()=>Math.max(p.value,0)/Math.max(1,a.getDaysLeftInMonth(o.value)))),g=e.computed((()=>m.value?u.formatPercent(i.value/Math.max(m.value,1)):"未设置")),f=e.computed((()=>u.clampPercent(i.value/Math.max(m.value||1,1)))),b=e.computed((()=>n.state.categories.expense.map((e=>{const t=c.value.filter((t=>t.categoryId===e.id)).reduce(((e,t)=>e+Number(t.amount)),0),a=Number(n.state.budgets.categoryBudgets[e.id]||0);return{...e,spent:t,budget:a,progressLabel:a?u.formatPercent(t/Math.max(a,1)):"未设置",progressWidth:u.clampPercent(t/Math.max(a||1,1))}})))),h=e.computed((()=>b.value.filter((e=>e.budget>0&&e.spent>e.budget))));function y(){n.setBudgetTotal(l.value),e.index.showToast({title:"总预算已保存",icon:"none"})}return e.watch((()=>n.state.budgets.total),(e=>{l.value=String(e||"")}),{immediate:!0}),e.watch(b,(e=>{e.forEach((e=>{d[e.id]=String(e.budget||"")}))}),{immediate:!0}),(t,a)=>e.e({a:e.t(e.unref(u.formatCurrency)(m.value)),b:e.t(e.unref(u.formatCurrency)(i.value)),c:f.value,d:e.t(g.value),e:e.t(p.value>=0?`剩余 ${e.unref(u.formatCurrency)(p.value)}`:`已超支 ${e.unref(u.formatCurrency)(Math.abs(p.value))}`),f:e.t(m.value?`日均可用 ${e.unref(u.formatCurrency)(v.value)}`:"设置预算后可查看剩余额度分配"),g:l.value,h:e.o((e=>l.value=e.detail.value)),i:e.o(y),j:e.p({title:"月度预算",subtitle:"设置总预算与分类预算,控制消费节奏"}),k:h.value.length},h.value.length?{l:e.f(h.value,((t,a,r)=>({a:e.t(t.name),b:e.t(e.unref(u.formatCurrency)(t.budget)),c:e.t(e.unref(u.formatCurrency)(t.spent)),d:t.id}))),m:e.p({title:"超支提醒",subtitle:"当前分类预算已被突破,建议尽快调整"})}:{},{n:e.f(b.value,((t,a,r)=>({a:t.color,b:e.t(t.name),c:e.t(e.unref(u.formatCurrency)(t.spent)),d:t.progressWidth,e:e.t(e.unref(u.formatCurrency)(t.budget)),f:e.t(t.progressLabel),g:e.n(t.budget>0&&t.spent>t.budget?"negative":""),h:d[t.id],i:e.o((e=>d[t.id]=e.detail.value),t.id),j:e.o((a=>{return u=t.id,n.setCategoryBudget(u,d[u]),void e.index.showToast({title:"分类预算已保存",icon:"none"});var u}),t.id),k:t.id}))),o:e.p({title:"分类预算",subtitle:"为高频分类分别设置预算,减少超支风险"}),p:e.p({current:"budget"}),q:e.n(s.value)})}},s=e._export_sfc(o,[["__scopeId","data-v-a56ca0c4"]]);wx.createPage(s);
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/budget/index.json b/uniapp/unpackage/dist/build/mp-weixin/pages/budget/index.json
new file mode 100644
index 0000000..0d9953d
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/budget/index.json
@@ -0,0 +1,7 @@
+{
+ "navigationBarTitleText": "预算管理",
+ "usingComponents": {
+ "section-card": "../../components/SectionCard",
+ "app-tab-bar": "../../components/AppTabBar"
+ }
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/budget/index.wxml b/uniapp/unpackage/dist/build/mp-weixin/pages/budget/index.wxml
new file mode 100644
index 0000000..b8afc43
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/budget/index.wxml
@@ -0,0 +1 @@
+本月总预算{{a}}本月已支出{{b}}保存{{item.a}}预算 {{item.b}},已支出 {{item.c}}{{item.b}}已花 {{item.c}}保存
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/budget/index.wxss b/uniapp/unpackage/dist/build/mp-weixin/pages/budget/index.wxss
new file mode 100644
index 0000000..38ff1a3
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/budget/index.wxss
@@ -0,0 +1 @@
+.budget-hero.data-v-a56ca0c4,.category-card.data-v-a56ca0c4{padding:24rpx;border-radius:24rpx}.budget-hero.data-v-a56ca0c4,.category-head.data-v-a56ca0c4,.category-title-row.data-v-a56ca0c4,.budget-foot.data-v-a56ca0c4,.editor-row.data-v-a56ca0c4{display:flex;align-items:center;justify-content:space-between;gap:16rpx}.secondary-foot.data-v-a56ca0c4{margin-top:10rpx}.budget-number.data-v-a56ca0c4{display:block;margin-top:10rpx;font-size:34rpx;font-weight:700;color:var(--text-primary)}.progress-track.data-v-a56ca0c4{overflow:hidden;height:18rpx;margin:24rpx 0 16rpx;border-radius:999rpx;background:var(--surface-muted)}.thin-track.data-v-a56ca0c4{height:14rpx;margin:18rpx 0 14rpx}.progress-fill.data-v-a56ca0c4{height:100%;border-radius:inherit;background:linear-gradient(90deg,#5f8df5,#1f6f5f)}.editor-row.data-v-a56ca0c4{margin-top:20rpx}.editor-row .input-shell.data-v-a56ca0c4{flex:1}.save-btn.data-v-a56ca0c4{flex:0 0 180rpx}.alert-list.data-v-a56ca0c4,.category-list.data-v-a56ca0c4{display:flex;flex-direction:column;gap:18rpx}.alert-item.data-v-a56ca0c4{padding:20rpx 22rpx;border-radius:22rpx;background:var(--danger-soft)}.alert-title.data-v-a56ca0c4{font-size:28rpx;font-weight:600;color:var(--danger)}.alert-text.data-v-a56ca0c4{display:block;margin-top:8rpx;font-size:22rpx;color:var(--danger)}.category-dot.data-v-a56ca0c4{width:16rpx;height:16rpx;border-radius:50%}.category-title.data-v-a56ca0c4{font-size:28rpx;font-weight:600;color:var(--text-primary)}
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/home/index.js b/uniapp/unpackage/dist/build/mp-weixin/pages/home/index.js
new file mode 100644
index 0000000..a87b675
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/home/index.js
@@ -0,0 +1 @@
+"use strict";const e=require("../../common/vendor.js"),t=require("../../utils/store.js"),a=require("../../utils/date.js"),u=require("../../utils/money.js");Math||(o+n+r)();const o=()=>"../../components/SectionCard.js",n=()=>"../../components/AppTabBar.js",r=()=>"../../components/BillEditorPopup.js",l={__name:"index",setup(o){const n=t.useAppStore(),r=e.ref(!1),l=e.ref(null),c=e.ref(""),i=e.ref("expense"),s=e.computed((()=>a.toDateKey())),d=e.computed((()=>a.toMonthKey())),m=e.computed((()=>"dark"===n.state.settings.theme?"theme-dark":"")),v=e.computed((()=>a.formatDateLabel(s.value))),p=e.computed((()=>[...n.state.bills].sort(((e,t)=>t.createdAt-e.createdAt)))),f=e.computed((()=>p.value.slice(0,5))),x=e.computed((()=>p.value.filter((e=>e.date===s.value)))),h=e.computed((()=>p.value.filter((e=>a.isSameMonth(e.date,d.value))))),y=e.computed((()=>x.value.filter((e=>"expense"===e.type)).reduce(((e,t)=>e+Number(t.amount)),0))),b=e.computed((()=>h.value.filter((e=>"expense"===e.type)).reduce(((e,t)=>e+Number(t.amount)),0))),g=e.computed((()=>h.value.filter((e=>"income"===e.type)).reduce(((e,t)=>e+Number(t.amount)),0))),C=e.computed((()=>g.value-b.value)),w=e.computed((()=>Number(n.state.budgets.total)||0)),M=e.computed((()=>w.value-b.value)),j=e.computed((()=>Math.max(M.value,0)/Math.max(1,a.getDaysLeftInMonth(d.value)))),A=e.computed((()=>u.clampPercent(b.value/Math.max(w.value||1,1)))),I=e.computed((()=>w.value?u.formatPercent(b.value/Math.max(w.value,1)):"未设置")),_=e.computed((()=>w.value?M.value<0?`已超支 ${u.formatCurrency(Math.abs(M.value))}`:`日均可用 ${u.formatCurrency(j.value)}`:"设置预算后可查看日均可用额度")),D=e.computed((()=>n.state.categories.expense.slice(0,6)));function L(e){return(n.state.categories[e.type]||[]).find((t=>t.id===e.categoryId))||{}}function P(e){return n.state.accounts.find((t=>t.id===e.accountId))||{}}function S(e="",t="expense"){c.value=e,i.value=t,l.value=null,r.value=!0}function T(){r.value=!1,l.value=null,c.value="",i.value="expense"}function $(t){n.saveBill(t),e.index.showToast({title:t.id?"账单已更新":"账单已保存",icon:"none"})}function q(t){e.index.showActionSheet({itemList:["编辑账单","删除账单"],success:({tapIndex:a})=>{0===a&&(l.value={...t},r.value=!0),1===a&&function(t){e.index.showModal({title:"删除账单",content:`确认删除 ${L(t).name||"这笔账单"} 吗?`,success:({confirm:e})=>{e&&n.deleteBill(t.id)}})}(t)}})}function B(){e.index.redirectTo({url:"/pages/bills/index"})}function k(){e.index.redirectTo({url:"/pages/budget/index"})}e.onPullDownRefresh((()=>{setTimeout((()=>{e.index.stopPullDownRefresh()}),200)}));const N=e.ref(!1);function E(){if(N.value)return;N.value=!0;let t=null;e.wx$1.createInterstitialAd&&(t=e.wx$1.createInterstitialAd({adUnitId:"adunit-0abc32053b19a4e9"}),t.onLoad((()=>{})),t.onError((e=>{console.error("插屏广告加载失败",e)})),t.onClose((()=>{}))),setTimeout((()=>{t&&(t.show().catch((e=>{console.error("插屏广告显示失败",e)})),N.value=!1)}),5480)}return e.onLoad((()=>{E()})),e.onShow((()=>{E()})),e.onShareAppMessage((e=>({title:"账单助手",desc:"本地单机极简记账,支持收支记录、预算管控、消费报表,数据安全私密,轻便好用的个人账单管家。",path:"/pages/home/index"}))),(t,o)=>e.e({a:e.t(v.value),b:e.t(e.unref(u.formatCurrency)(y.value)),c:e.t(e.unref(u.formatCurrency)(b.value)),d:e.t(e.unref(u.formatCurrency)(g.value)),e:e.t(e.unref(u.formatCurrency)(C.value)),f:e.t(e.unref(u.formatCurrency)(M.value)),g:e.t(I.value),h:A.value,i:e.t(w.value?`总预算 ${e.unref(u.formatCurrency)(w.value)}`:"当前尚未设置月预算"),j:e.t(_.value),k:!w.value},w.value?{}:{l:e.o(k)},{m:e.p({title:"预算概览",subtitle:"实时查看预算执行情况与剩余额度"}),n:e.o((e=>S("","expense"))),o:e.o((e=>S("","income"))),p:e.f(D.value,((t,a,u)=>({a:t.color,b:e.t(t.name),c:t.id,d:e.o((e=>S(t.id,"expense")),t.id)}))),q:e.p({title:"快捷记账",subtitle:"常用场景一步录入,提高日常记录效率"}),r:e.o(B),s:f.value.length},f.value.length?{t:e.f(f.value,((t,o,n)=>({a:L(t).color||"#7b8794",b:e.t(L(t).name||"未分类"),c:e.t(P(t).name||"账户"),d:e.t(e.unref(a.formatDateLabel)(t.date)),e:e.t("income"===t.type?"+":"-"),f:e.t(e.unref(u.formatCurrency)(t.amount).replace("¥","")),g:e.n("income"===t.type?"positive":"negative"),h:e.t(t.note||"无备注"),i:t.id,j:e.o((e=>q(t)),t.id)})))}:{v:e.o((e=>S("","expense")))},{w:e.p({title:"最近记录",subtitle:"保留最近 5 笔账单,长按可编辑或删除"}),x:e.o((e=>S("","expense"))),y:e.p({current:"home"}),z:e.o(T),A:e.o($),B:e.p({visible:r.value,entry:l.value,categories:e.unref(n).state.categories,accounts:e.unref(n).state.accounts,"default-type":i.value,"initial-category-id":c.value}),C:e.n(m.value)})}},c=e._export_sfc(l,[["__scopeId","data-v-a0f5ea5d"]]);l.__runtimeHooks=2,wx.createPage(c);
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/home/index.json b/uniapp/unpackage/dist/build/mp-weixin/pages/home/index.json
new file mode 100644
index 0000000..21c987c
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/home/index.json
@@ -0,0 +1,9 @@
+{
+ "navigationBarTitleText": "首页",
+ "enablePullDownRefresh": true,
+ "usingComponents": {
+ "section-card": "../../components/SectionCard",
+ "app-tab-bar": "../../components/AppTabBar",
+ "bill-editor-popup": "../../components/BillEditorPopup"
+ }
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/home/index.wxml b/uniapp/unpackage/dist/build/mp-weixin/pages/home/index.wxml
new file mode 100644
index 0000000..3ed8809
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/home/index.wxml
@@ -0,0 +1 @@
+{{a}}账单小管家今日支出{{b}}本月支出{{c}}本月收入{{d}}本月结余{{e}}{{f}}剩余预算预算使用{{g}}{{i}}{{j}}去设置预算记录支出记录收入{{item.b}}查看全部{{bill.b}}{{bill.c}} · {{bill.d}}{{bill.e}}{{bill.f}}{{bill.h}}还没有账单记录,先记下第一笔收支。立即记账+ 记一笔
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/home/index.wxss b/uniapp/unpackage/dist/build/mp-weixin/pages/home/index.wxss
new file mode 100644
index 0000000..2dcdc65
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/home/index.wxss
@@ -0,0 +1 @@
+.hero-card.data-v-a0f5ea5d{display:flex;flex-direction:column;gap:18rpx;padding:32rpx;background:var(--bg-accent);color:#fff}.hero-date.data-v-a0f5ea5d,.hero-subtitle.data-v-a0f5ea5d,.hero-card .tiny-text.data-v-a0f5ea5d{color:rgba(255,255,255,.76)}.hero-title.data-v-a0f5ea5d{font-size:46rpx;font-weight:700}.hero-subtitle.data-v-a0f5ea5d{font-size:24rpx;line-height:1.7}.hero-metrics.data-v-a0f5ea5d{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18rpx;margin-top:10rpx}.metric-block.data-v-a0f5ea5d{padding:20rpx;border-radius:24rpx;background:rgba(255,255,255,.12)}.metric-value.data-v-a0f5ea5d{display:block;margin-top:10rpx;font-size:32rpx;font-weight:700;color:#fff}.budget-head.data-v-a0f5ea5d,.budget-note-row.data-v-a0f5ea5d,.quick-action-row.data-v-a0f5ea5d{display:flex;align-items:center;justify-content:space-between;gap:18rpx}.budget-side.data-v-a0f5ea5d{text-align:right}.budget-value.data-v-a0f5ea5d,.budget-percent.data-v-a0f5ea5d{font-size:36rpx;font-weight:700;color:var(--text-primary)}.progress-track.data-v-a0f5ea5d{overflow:hidden;height:18rpx;margin:24rpx 0 16rpx;border-radius:999rpx;background:var(--surface-muted)}.progress-fill.data-v-a0f5ea5d{height:100%;border-radius:inherit;background:linear-gradient(90deg,#d36c43,#1f6f5f)}.budget-action-row.data-v-a0f5ea5d{margin-top:18rpx}.quick-action-row .quick-main.data-v-a0f5ea5d{flex:1}.quick-grid.data-v-a0f5ea5d{display:flex;flex-wrap:wrap;gap:16rpx;margin-top:18rpx}.quick-chip.data-v-a0f5ea5d{display:flex;align-items:center;gap:12rpx;padding:16rpx 18rpx;border-radius:22rpx;background:var(--surface-muted);font-size:24rpx;color:var(--text-secondary)}.quick-dot.data-v-a0f5ea5d,.bill-dot.data-v-a0f5ea5d{width:16rpx;height:16rpx;border-radius:50%}.section-link.data-v-a0f5ea5d{font-size:24rpx;color:var(--brand)}.bill-list.data-v-a0f5ea5d{display:flex;flex-direction:column;gap:18rpx}.bill-item.data-v-a0f5ea5d{display:flex;align-items:center;justify-content:space-between;gap:16rpx;padding:22rpx;border-radius:24rpx;background:var(--surface-muted)}.bill-leading.data-v-a0f5ea5d{display:flex;align-items:center;gap:16rpx;flex:1}.bill-right.data-v-a0f5ea5d{display:flex;flex-direction:column;align-items:flex-end;gap:8rpx}.bill-title.data-v-a0f5ea5d,.bill-amount.data-v-a0f5ea5d{font-size:28rpx;font-weight:600;color:var(--text-primary)}.bill-meta.data-v-a0f5ea5d{margin-top:8rpx;font-size:22rpx;color:var(--text-secondary)}.empty-card.data-v-a0f5ea5d{padding:28rpx 0 8rpx;text-align:center}.empty-action.data-v-a0f5ea5d{margin-top:18rpx}.fab-button.data-v-a0f5ea5d{position:fixed;right:32rpx;bottom:348rpx;padding:24rpx 30rpx;border-radius:999rpx;background:var(--bg-accent);color:#fff;font-size:28rpx;font-weight:700;box-shadow:0 20rpx 42rpx rgba(16,42,67,.24);z-index:18}
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/about/index.js b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/about/index.js
new file mode 100644
index 0000000..ea1cb6c
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/about/index.js
@@ -0,0 +1 @@
+"use strict";const e=require("../../../common/vendor.js"),t=require("../../../utils/store.js");Math||o();const o=()=>"../../../components/SectionCard.js",r={__name:"index",setup(o){const r=t.useAppStore();e.onShow((()=>{!function(){let t=null;e.wx$1.createInterstitialAd&&(t=e.wx$1.createInterstitialAd({adUnitId:"adunit-0abc32053b19a4e9"}),t.onLoad((()=>{})),t.onError((e=>{console.error("插屏广告加载失败",e)})),t.onClose((()=>{})));setTimeout((()=>{t&&t.show().catch((e=>{console.error("插屏广告显示失败",e)}))}),2280)}()}));const s=e.computed((()=>"dark"===r.state.settings.theme?"theme-dark":""));return(t,o)=>({a:e.p({title:"关于应用",subtitle:"面向日常收支记录、预算控制与月度复盘的轻量工具"}),b:e.p({title:"隐私与数据",subtitle:""}),c:e.n(s.value)})}},s=e._export_sfc(r,[["__scopeId","data-v-5d1e9385"]]);wx.createPage(s);
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/about/index.json b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/about/index.json
new file mode 100644
index 0000000..ec0a983
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/about/index.json
@@ -0,0 +1,6 @@
+{
+ "navigationBarTitleText": "关于与隐私",
+ "usingComponents": {
+ "section-card": "../../../components/SectionCard"
+ }
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/about/index.wxml b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/about/index.wxml
new file mode 100644
index 0000000..c7334e7
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/about/index.wxml
@@ -0,0 +1 @@
+ABOUT关于与隐私查看应用定位、数据说明与发布前应补齐的正式信息。发布说明账单小管家定位为轻量、无广告的本地记账工具,适合学生、情侣、合租和个人日常记账场景。本地存储账单、预算、分类、账户和设置默认保存在当前设备本地。本地昵称昵称仅保存在当前设备,用于个人页展示和首字头像。数据迁移如需换机迁移,可在“备份与恢复”中导出 JSON 并在新设备恢复。
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/about/index.wxss b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/about/index.wxss
new file mode 100644
index 0000000..ca98927
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/about/index.wxss
@@ -0,0 +1 @@
+.page-hero.data-v-5d1e9385{padding:30rpx;background:linear-gradient(145deg,rgba(16,42,67,.96),rgba(31,111,95,.88) 60%,rgba(212,108,67,.82));color:#fff}.hero-kicker.data-v-5d1e9385,.hero-desc.data-v-5d1e9385,.hero-tag.soft.data-v-5d1e9385{color:rgba(255,255,255,.76)}.hero-kicker.data-v-5d1e9385{font-size:20rpx;letter-spacing:4rpx}.hero-title.data-v-5d1e9385{display:block;margin-top:12rpx;font-size:44rpx;font-weight:700}.hero-desc.data-v-5d1e9385{display:block;margin-top:14rpx;font-size:24rpx;line-height:1.7}.hero-tags.data-v-5d1e9385{display:flex;flex-wrap:wrap;gap:14rpx;margin-top:22rpx}.hero-tag.data-v-5d1e9385{padding:12rpx 18rpx;border-radius:999rpx;background:rgba(255,255,255,.16);font-size:22rpx}.about-card.data-v-5d1e9385,.info-item.data-v-5d1e9385,.tips-card.data-v-5d1e9385{padding:26rpx;border-radius:28rpx}.app-name.data-v-5d1e9385,.info-title.data-v-5d1e9385{display:block;font-size:31rpx;font-weight:700;color:var(--text-primary)}.app-version.data-v-5d1e9385{display:block;margin-top:10rpx;font-size:23rpx;color:var(--brand)}.about-text.data-v-5d1e9385,.info-text.data-v-5d1e9385,.tip-line.data-v-5d1e9385{display:block;margin-top:12rpx;font-size:24rpx;line-height:1.8;color:var(--text-secondary)}.info-list.data-v-5d1e9385{display:flex;flex-direction:column;gap:16rpx}.tip-row.data-v-5d1e9385{display:flex;align-items:flex-start;gap:16rpx;padding:10rpx 0}.tip-index.data-v-5d1e9385{width:56rpx;font-size:24rpx;font-weight:700;color:var(--brand)}
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/backup/index.js b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/backup/index.js
new file mode 100644
index 0000000..98b14be
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/backup/index.js
@@ -0,0 +1 @@
+"use strict";const t=require("../../../common/vendor.js"),e=require("../../../utils/store.js");Math||a();const a=()=>"../../../components/SectionCard.js",n={__name:"index",setup(a){const n=e.useAppStore(),o=t.ref(""),s=t.computed((()=>"dark"===n.state.settings.theme?"theme-dark":""));function i(){!function(e){const a=(new Date).toLocaleString();if(void 0!==t.wx$1&&t.wx$1.getFileSystemManager){const o=`${t.wx$1.env.USER_DATA_PATH}/bill-helper-backup.json`;t.wx$1.getFileSystemManager().writeFile({filePath:o,data:e,encoding:"utf8",success:()=>{n.markBackup(a),t.index.showModal({title:"备份成功",content:`文件已生成:${o}`,showCancel:!1})},fail:()=>{t.index.setClipboardData({data:e})}})}else n.markBackup(a),t.index.setClipboardData({data:e})}(n.exportBackup())}function l(){if(o.value.trim())try{n.importBackup(o.value),o.value="",t.index.showToast({title:"备份恢复成功",icon:"none"})}catch(e){t.index.showToast({title:"备份内容无效",icon:"none"})}else t.index.showToast({title:"请先粘贴备份内容",icon:"none"})}function c(){t.index.setClipboardData({data:n.exportBackup()})}function r(){t.index.showModal({title:"清空全部数据",content:"确认删除当前设备中的账单、预算和设置吗?此操作不可撤销。",success:({confirm:e})=>{e&&(n.resetAll(),t.index.showToast({title:"本地数据已清空",icon:"none"}))}})}return t.onShow((()=>{!function(){let e=null;t.wx$1.createInterstitialAd&&(e=t.wx$1.createInterstitialAd({adUnitId:"adunit-0abc32053b19a4e9"}),e.onLoad((()=>{})),e.onError((t=>{console.error("插屏广告加载失败",t)})),e.onClose((()=>{})));setTimeout((()=>{e&&e.show().catch((t=>{console.error("插屏广告显示失败",t)}))}),2280)}()})),(e,a)=>t.e({a:t.t(t.unref(n).state.settings.lastBackupAt?"最近已备份":"尚未备份"),b:t.t(t.unref(n).state.settings.lastBackupAt?"可继续备份":"建议先备份"),c:t.o(i),d:t.unref(n).state.settings.lastBackupAt},t.unref(n).state.settings.lastBackupAt?{e:t.t(t.unref(n).state.settings.lastBackupAt)}:{},{f:t.p({title:"导出备份",subtitle:"将账单、预算和设置导出为 JSON 文件,便于迁移设备或手动保存"}),g:o.value,h:t.o((t=>o.value=t.detail.value)),i:t.o((t=>o.value="")),j:t.o(l),k:t.p({title:"恢复备份",subtitle:"粘贴之前导出的 JSON 内容,恢复后将覆盖当前设备数据"}),l:t.o(c),m:t.o(r),n:t.p({title:"数据操作",subtitle:"谨慎执行不可撤销的本地清理操作"}),o:t.n(s.value)})}},o=t._export_sfc(n,[["__scopeId","data-v-15765fe6"]]);wx.createPage(o);
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/backup/index.json b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/backup/index.json
new file mode 100644
index 0000000..c5c339f
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/backup/index.json
@@ -0,0 +1,6 @@
+{
+ "navigationBarTitleText": "备份与恢复",
+ "usingComponents": {
+ "section-card": "../../../components/SectionCard"
+ }
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/backup/index.wxml b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/backup/index.wxml
new file mode 100644
index 0000000..7ab2af6
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/backup/index.wxml
@@ -0,0 +1 @@
+BACKUP备份与恢复导出本地 JSON 备份,恢复时覆盖当前设备数据,适合换机或手动留档。本地文件{{a}}安全备份当前数据所有数据均为本地文件,不会自动上传服务器。{{b}}导出备份最近备份:{{e}}清空内容开始恢复
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/backup/index.wxss b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/backup/index.wxss
new file mode 100644
index 0000000..21de8cf
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/backup/index.wxss
@@ -0,0 +1 @@
+.page-hero.data-v-15765fe6{padding:30rpx;background:linear-gradient(145deg,rgba(16,42,67,.96),rgba(61,102,178,.92));color:#fff}.hero-kicker.data-v-15765fe6,.hero-desc.data-v-15765fe6,.hero-tag.soft.data-v-15765fe6{color:rgba(255,255,255,.76)}.hero-kicker.data-v-15765fe6{font-size:20rpx;letter-spacing:4rpx}.hero-title.data-v-15765fe6{display:block;margin-top:12rpx;font-size:44rpx;font-weight:700}.hero-desc.data-v-15765fe6{display:block;margin-top:14rpx;font-size:24rpx;line-height:1.7}.hero-tags.data-v-15765fe6{display:flex;flex-wrap:wrap;gap:14rpx;margin-top:22rpx}.hero-tag.data-v-15765fe6,.status-chip.data-v-15765fe6{padding:12rpx 18rpx;border-radius:999rpx;background:rgba(255,255,255,.16);font-size:22rpx}.hero-panel.data-v-15765fe6,.menu-item.data-v-15765fe6,.action-row.data-v-15765fe6{display:flex;align-items:center;gap:16rpx}.hero-panel.data-v-15765fe6,.menu-item.data-v-15765fe6{padding:26rpx;border-radius:28rpx}.hero-panel.data-v-15765fe6{justify-content:space-between}.panel-title.data-v-15765fe6,.menu-title.data-v-15765fe6{display:block;font-size:31rpx;font-weight:700;color:var(--text-primary)}.panel-desc.data-v-15765fe6,.status-chip.data-v-15765fe6{background:var(--brand-soft);color:var(--brand)}.action-row.data-v-15765fe6{margin-top:18rpx}.single-row .primary-button.data-v-15765fe6,.action-row .ghost-button.data-v-15765fe6,.action-row .primary-button.data-v-15765fe6{flex:1}.info-line.data-v-15765fe6{display:block;margin-top:16rpx}.textarea-shell.data-v-15765fe6{align-items:flex-start;min-height:280rpx;padding:20rpx 24rpx}.textarea-shell textarea.data-v-15765fe6{min-height:240rpx}.menu-list.data-v-15765fe6{display:flex;flex-direction:column;gap:16rpx}.menu-item.data-v-15765fe6{justify-content:space-between}.danger-shell.data-v-15765fe6{border:1rpx solid rgba(210,85,67,.12)}.danger-text.data-v-15765fe6{font-size:24rpx;color:var(--danger)}
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/guide/index.js b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/guide/index.js
new file mode 100644
index 0000000..d08db4e
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/guide/index.js
@@ -0,0 +1 @@
+"use strict";const e=require("../../../common/vendor.js"),t=require("../../../utils/store.js");Math||i();const i=()=>"../../../components/SectionCard.js",n={__name:"index",setup(i){const n=t.useAppStore(),s=e.computed((()=>"dark"===n.state.settings.theme?"theme-dark":"")),o=[{index:"01",title:"先设置月预算",desc:"进入预算页设置总预算与分类预算,首页会同步显示剩余额度。"},{index:"02",title:"用首页快捷记账",desc:"首页支持支出/收入快速录入,也能通过常用分类一键记账。"},{index:"03",title:"到账单页做筛选",desc:"账单页支持按月份、账户、金额区间和关键词精确筛选。"},{index:"04",title:"每月查看报表",desc:"报表页可导出 CSV,并查看支出结构、近 7 日趋势和月度对比。"}],a=[{q:"账单数据保存在哪里?",a:"默认仅保存在当前设备的本地存储中,不会自动上传云端。"},{q:"换手机后如何迁移?",a:"先进入“备份与恢复”导出 JSON 备份,再在新设备粘贴恢复。"},{q:"为什么预算进度显示超出 100%?",a:"这代表本月支出已经超过预算,条形进度会封顶,但文字会继续显示真实比例。"},{q:"昵称可以怎么修改?",a:"进入“我的-账户资料”后可直接修改本地昵称,留空时默认显示为“用户”。"}];function d(t){e.index.navigateTo({url:t})}return e.onShow((()=>{!function(){let t=null;e.wx$1.createInterstitialAd&&(t=e.wx$1.createInterstitialAd({adUnitId:"adunit-0abc32053b19a4e9"}),t.onLoad((()=>{})),t.onError((e=>{console.error("插屏广告加载失败",e)})),t.onClose((()=>{})));setTimeout((()=>{t&&t.show().catch((e=>{console.error("插屏广告显示失败",e)}))}),2280)}()})),(t,i)=>({a:e.f(o,((t,i,n)=>({a:e.t(t.index),b:e.t(t.title),c:e.t(t.desc),d:t.title}))),b:e.p({title:"快速上手",subtitle:"初次使用建议先完成下面 4 个动作"}),c:e.f(a,((t,i,n)=>({a:e.t(t.q),b:e.t(t.a),c:t.q}))),d:e.p({title:"常见问题",subtitle:""}),e:e.o((e=>d("/pages/home/index"))),f:e.o((e=>d("/pages/budget/index"))),g:e.o((e=>d("/pages/stats/index"))),h:e.o((e=>d("/pages/mine/backup/index"))),i:e.p({title:"功能入口",subtitle:"需要操作时可直接跳转到对应模块"}),j:e.n(s.value)})}},s=e._export_sfc(n,[["__scopeId","data-v-7f3520d8"]]);wx.createPage(s);
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/guide/index.json b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/guide/index.json
new file mode 100644
index 0000000..4f77f39
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/guide/index.json
@@ -0,0 +1,6 @@
+{
+ "navigationBarTitleText": "使用帮助",
+ "usingComponents": {
+ "section-card": "../../../components/SectionCard"
+ }
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/guide/index.wxml b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/guide/index.wxml
new file mode 100644
index 0000000..5639a14
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/guide/index.wxml
@@ -0,0 +1 @@
+GUIDE使用帮助通过上手步骤、常见问题和快捷入口,快速熟悉整个记账流程。4 个步骤FAQ 指南{{item.a}}{{item.b}}{{item.c}}{{item.a}}{{item.b}}首页记账预算设置查看报表备份恢复
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/guide/index.wxss b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/guide/index.wxss
new file mode 100644
index 0000000..72ea2fb
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/guide/index.wxss
@@ -0,0 +1 @@
+.page-hero.data-v-7f3520d8{padding:30rpx;background:linear-gradient(145deg,rgba(16,42,67,.96),rgba(127,86,217,.9));color:#fff}.hero-kicker.data-v-7f3520d8,.hero-desc.data-v-7f3520d8,.hero-tag.soft.data-v-7f3520d8{color:rgba(255,255,255,.76)}.hero-kicker.data-v-7f3520d8{font-size:20rpx;letter-spacing:4rpx}.hero-title.data-v-7f3520d8{display:block;margin-top:12rpx;font-size:44rpx;font-weight:700}.hero-desc.data-v-7f3520d8{display:block;margin-top:14rpx;font-size:24rpx;line-height:1.7}.hero-tags.data-v-7f3520d8{display:flex;flex-wrap:wrap;gap:14rpx;margin-top:22rpx}.hero-tag.data-v-7f3520d8{padding:12rpx 18rpx;border-radius:999rpx;background:rgba(255,255,255,.16);font-size:22rpx}.step-list.data-v-7f3520d8,.faq-list.data-v-7f3520d8{display:flex;flex-direction:column;gap:16rpx}.step-item.data-v-7f3520d8,.faq-item.data-v-7f3520d8{padding:24rpx;border-radius:28rpx}.step-item.data-v-7f3520d8{display:flex;gap:18rpx}.step-index.data-v-7f3520d8{width:74rpx;font-size:30rpx;font-weight:700;color:var(--brand)}.step-body.data-v-7f3520d8{flex:1}.step-title.data-v-7f3520d8,.faq-question.data-v-7f3520d8,.entry-title.data-v-7f3520d8{display:block;font-size:29rpx;font-weight:700;color:var(--text-primary)}.step-desc.data-v-7f3520d8,.faq-answer.data-v-7f3520d8{display:block;margin-top:10rpx;font-size:24rpx;line-height:1.75;color:var(--text-secondary)}.entry-grid.data-v-7f3520d8{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16rpx}.entry-item.data-v-7f3520d8{display:flex;align-items:center;justify-content:center;padding:28rpx 20rpx;border-radius:28rpx;text-align:center}
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/index.js b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/index.js
new file mode 100644
index 0000000..4625235
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/index.js
@@ -0,0 +1 @@
+"use strict";const e=require("../../common/vendor.js"),t=require("../../utils/store.js");Math||(n+s)();const n=()=>"../../components/SectionCard.js",s=()=>"../../components/AppTabBar.js",a={__name:"index",setup(n){const s=t.useAppStore(),a=e.computed((()=>"dark"===s.state.settings.theme?"theme-dark":"")),i=e.computed((()=>s.state.settings.profile.nickname||"用户")),o=e.computed((()=>(s.state.settings.profile.nickname||"用户").slice(0,1))),r=e.ref(">");function u(e){s.setTheme(e)}function p(t){e.index.navigateTo({url:t})}return(t,n)=>({a:e.t(o.value),b:e.t(i.value),c:e.t(r.value),d:e.o((e=>p("/pages/mine/profile/index"))),e:"light"===e.unref(s).state.settings.theme?1:"",f:e.o((e=>u("light"))),g:"dark"===e.unref(s).state.settings.theme?1:"",h:e.o((e=>u("dark"))),i:e.p({title:"账户概览",subtitle:"集中管理本地昵称与主题设置"}),j:e.t(r.value),k:e.o((e=>p("/pages/mine/backup/index"))),l:e.t(r.value),m:e.o((e=>p("/pages/mine/guide/index"))),n:e.t(r.value),o:e.o((e=>p("/pages/mine/about/index"))),p:e.p({title:"数据管理",subtitle:"备份、恢复和清理等高频操作统一收口"}),q:e.p({current:"mine"}),r:e.n(a.value)})}},i=e._export_sfc(a,[["__scopeId","data-v-a8ac4929"]]);wx.createPage(i);
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/index.json b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/index.json
new file mode 100644
index 0000000..ec681ad
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/index.json
@@ -0,0 +1,7 @@
+{
+ "navigationBarTitleText": "我的",
+ "usingComponents": {
+ "section-card": "../../components/SectionCard",
+ "app-tab-bar": "../../components/AppTabBar"
+ }
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/index.wxml b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/index.wxml
new file mode 100644
index 0000000..4813f1e
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/index.wxml
@@ -0,0 +1 @@
+{{a}}{{b}}{{c}}浅色深色
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/index.wxss b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/index.wxss
new file mode 100644
index 0000000..4cbce7a
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/index.wxss
@@ -0,0 +1 @@
+.profile-card.data-v-a8ac4929,.theme-row.data-v-a8ac4929,.menu-item.data-v-a8ac4929{display:flex;align-items:center;gap:16rpx}.profile-card.data-v-a8ac4929{padding:24rpx;border-radius:24rpx}.avatar-shell.data-v-a8ac4929{width:88rpx;height:88rpx;border-radius:50%;background:var(--bg-accent);color:#fff;display:flex;align-items:center;justify-content:center;font-size:34rpx;font-weight:700}.profile-body.data-v-a8ac4929{flex:1}.profile-name.data-v-a8ac4929,.menu-title.data-v-a8ac4929{font-size:30rpx;font-weight:600;color:var(--text-primary)}.arrow-text.data-v-a8ac4929{font-size:32rpx}.theme-row.data-v-a8ac4929{margin-top:18rpx}.theme-row .pill-button.data-v-a8ac4929{flex:1}.menu-list.data-v-a8ac4929,.action-grid.data-v-a8ac4929{display:flex;flex-direction:column;gap:16rpx}.menu-item.data-v-a8ac4929{justify-content:space-between;padding:22rpx;border-radius:24rpx;background:var(--surface-muted)}
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/profile/index.js b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/profile/index.js
new file mode 100644
index 0000000..d2f7f64
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/profile/index.js
@@ -0,0 +1 @@
+"use strict";const e=require("../../../common/vendor.js"),t=require("../../../utils/store.js");Math||a();const a=()=>"../../../components/SectionCard.js",i={__name:"index",setup(a){const i=t.useAppStore(),n=e.computed((()=>"dark"===i.state.settings.theme?"theme-dark":"")),s=e.computed((()=>i.state.settings.profile.nickname||"用户")),o=e.computed((()=>s.value.slice(0,1))),l=e.ref(i.state.settings.profile.nickname||""),r=["昵称仅用于个人页展示和首字头像,不参与账单计算。","账单、预算和设置默认不会自动上传云端。","如需更换设备,请先在“备份与恢复”页面导出 JSON 备份。"];function u(){const t=l.value.trim();i.setProfile({authorized:!1,nickname:t,avatarUrl:""}),e.index.showToast({title:"昵称已保存",icon:"none"})}function c(){l.value="",i.setProfile({authorized:!1,nickname:"",avatarUrl:""}),e.index.showToast({title:"昵称已清空",icon:"none"})}return e.watch((()=>i.state.settings.profile.nickname),(e=>{l.value=e||""})),(t,a)=>({a:e.t(o.value),b:e.t(s.value),c:l.value,d:e.o((e=>l.value=e.detail.value)),e:e.o(c),f:e.o(u),g:e.p({title:"昵称设置",subtitle:"修改后仅用于个人页展示和首字头像,不参与账单计算"}),h:e.t(o.value),i:e.p({title:"显示与模式",subtitle:"集中展示当前账户页的生效状态"}),j:e.f(r,((t,a,i)=>({a:e.t(a+1),b:e.t(t),c:t}))),k:e.p({title:"使用提示",subtitle:"帮助用户理解昵称显示与数据边界"}),l:e.n(n.value)})}},n=e._export_sfc(i,[["__scopeId","data-v-94494afd"]]);wx.createPage(n);
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/profile/index.json b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/profile/index.json
new file mode 100644
index 0000000..756dce7
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/profile/index.json
@@ -0,0 +1,6 @@
+{
+ "navigationBarTitleText": "账户资料",
+ "usingComponents": {
+ "section-card": "../../../components/SectionCard"
+ }
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/profile/index.wxml b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/profile/index.wxml
new file mode 100644
index 0000000..7990dac
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/profile/index.wxml
@@ -0,0 +1 @@
+ACCOUNT账户资料管理本地昵称、显示资料与本机记账模式说明。本地资料本地存储{{a}}{{b}}当前昵称仅保存在本地设备,可随时修改。本地留空时页面会统一显示“用户”。清空昵称保存昵称昵称首字头像当前显示 {{h}},自动根据昵称生成已启用本机记账模式账单与预算默认仅保存在当前设备本地默认0{{tip.a}}{{tip.b}}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/mine/profile/index.wxss b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/profile/index.wxss
new file mode 100644
index 0000000..4e0f638
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/mine/profile/index.wxss
@@ -0,0 +1 @@
+.page-hero.data-v-94494afd{padding:30rpx;background:linear-gradient(145deg,rgba(16,42,67,.96),rgba(31,111,95,.92));color:#fff}.hero-kicker.data-v-94494afd,.hero-desc.data-v-94494afd,.hero-tag.soft.data-v-94494afd{color:rgba(255,255,255,.76)}.hero-kicker.data-v-94494afd{font-size:20rpx;letter-spacing:4rpx}.hero-title.data-v-94494afd{display:block;margin-top:12rpx;font-size:44rpx;font-weight:700}.hero-desc.data-v-94494afd{display:block;margin-top:14rpx;font-size:24rpx;line-height:1.7}.hero-tags.data-v-94494afd{display:flex;flex-wrap:wrap;gap:14rpx;margin-top:22rpx}.hero-tag.data-v-94494afd{padding:12rpx 18rpx;border-radius:999rpx;background:rgba(255,255,255,.16);font-size:22rpx}.profile-card.data-v-94494afd,.info-item.data-v-94494afd,.action-row.data-v-94494afd,.tip-row.data-v-94494afd{display:flex;align-items:center;gap:16rpx}.profile-card.data-v-94494afd,.tips-card.data-v-94494afd{padding:26rpx;border-radius:28rpx}.avatar-shell.data-v-94494afd{width:108rpx;height:108rpx;border-radius:32rpx;background:var(--bg-accent);color:#fff;display:flex;align-items:center;justify-content:center;font-size:40rpx;font-weight:700;box-shadow:0 18rpx 32rpx rgba(16,42,67,.16)}.profile-body.data-v-94494afd{flex:1}.profile-name.data-v-94494afd,.info-title.data-v-94494afd{display:block;font-size:31rpx;font-weight:700;color:var(--text-primary)}.profile-meta.data-v-94494afd,.info-desc.data-v-94494afd,.tip-line.data-v-94494afd{display:block;margin-top:10rpx;font-size:24rpx;line-height:1.7;color:var(--text-secondary)}.status-badge.data-v-94494afd,.info-mark.data-v-94494afd{padding:10rpx 18rpx;border-radius:999rpx;background:var(--brand-soft);font-size:22rpx;color:var(--brand)}.editor-block.data-v-94494afd{margin-top:18rpx}.editor-tip.data-v-94494afd{display:block;margin-top:12rpx}.action-row.data-v-94494afd{margin-top:18rpx}.action-row .ghost-button.data-v-94494afd,.action-row .primary-button.data-v-94494afd{flex:1}.info-list.data-v-94494afd{display:flex;flex-direction:column;gap:16rpx}.info-item.data-v-94494afd{justify-content:space-between;padding:24rpx;border-radius:26rpx}.tip-row.data-v-94494afd{align-items:flex-start;padding:12rpx 0}.tip-index.data-v-94494afd{width:56rpx;font-size:24rpx;font-weight:700;color:var(--brand)}
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/stats/index.js b/uniapp/unpackage/dist/build/mp-weixin/pages/stats/index.js
new file mode 100644
index 0000000..7f65a9f
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/stats/index.js
@@ -0,0 +1 @@
+"use strict";const e=require("../../common/vendor.js"),t=require("../../utils/store.js"),a=require("../../utils/date.js"),u=require("../../utils/money.js");Math||(n+r)();const n=()=>"../../components/SectionCard.js",r=()=>"../../components/AppTabBar.js",o={__name:"index",setup(n){const r=t.useAppStore(),o=e.ref(a.toMonthKey()),l=e.ref(!1),i=e.computed((()=>"dark"===r.state.settings.theme?"theme-dark":"")),c=e.computed((()=>o.value.slice(0,7))),s=e.computed((()=>a.formatMonthLabel(c.value))),m=e.computed((()=>o.value)),d=e.computed((()=>r.state.bills.filter((e=>a.isSameMonth(e.date,c.value))))),p=e.computed((()=>d.value.filter((e=>"expense"===e.type)))),f=e.computed((()=>p.value.reduce(((e,t)=>e+Number(t.amount)),0))),v=e.computed((()=>d.value.filter((e=>"income"===e.type)).reduce(((e,t)=>e+Number(t.amount)),0))),b=e.computed((()=>{const e=Math.max(f.value,1);return r.state.categories.expense.map((t=>{const a=p.value.filter((e=>e.categoryId===t.id)).reduce(((e,t)=>e+Number(t.amount)),0);return{...t,total:a,percentLabel:u.formatPercent(a/e),percentWidth:u.clampPercent(a/e)}})).filter((e=>e.total>0)).sort(((e,t)=>t.total-e.total))})),h=e.computed((()=>{const[e,t]=c.value.split("-").map(Number),u=a.toDateKey(),n=new Date(e,t,0),r=a.toMonthKey(u)===c.value?new Date:n,o=a.getRecentDateKeys(7,r),l=Math.max(1,...o.map((e=>p.value.filter((t=>t.date===e)).reduce(((e,t)=>e+Number(t.amount)),0))));return o.map((e=>{const t=p.value.filter((t=>t.date===e)).reduce(((e,t)=>e+Number(t.amount)),0);return{date:e,label:e.slice(5),value:Number(t.toFixed(2)),height:`${Math.max(8,t/l*100)}%`}}))})),x=e.computed((()=>{const e=a.getMonthSeries(6,c.value),t=Math.max(1,...e.map((e=>r.state.bills.filter((t=>"expense"===t.type&&a.isSameMonth(t.date,e))).reduce(((e,t)=>e+Number(t.amount)),0)))),u=Math.max(1,...e.map((e=>r.state.bills.filter((t=>"income"===t.type&&a.isSameMonth(t.date,e))).reduce(((e,t)=>e+Number(t.amount)),0))));return e.map((e=>{const n=r.state.bills.filter((t=>"expense"===t.type&&a.isSameMonth(t.date,e))).reduce(((e,t)=>e+Number(t.amount)),0),o=r.state.bills.filter((t=>"income"===t.type&&a.isSameMonth(t.date,e))).reduce(((e,t)=>e+Number(t.amount)),0);return{month:e,label:e.slice(5),expense:n,income:o,expenseWidth:`${Math.max(8,n/t*100)}%`,incomeWidth:`${Math.max(8,o/u*100)}%`}}))}));function y(e){o.value=String(e.detail.value).slice(0,7)}function g(e){var t;return(null==(t=(r.state.categories[e.type]||[]).find((t=>t.id===e.categoryId)))?void 0:t.name)||"未分类"}function M(e){var t;return(null==(t=r.state.accounts.find((t=>t.id===e.accountId)))?void 0:t.name)||"未知账户"}function C(e){const t=String(e??"");return/[",\n]/.test(t)?`"${t.replace(/"/g,'""')}"`:t}function $(){const t=d.value.map((e=>[C(e.date),C("income"===e.type?"收入":"支出"),C(g(e)),C(M(e)),C(Number(e.amount).toFixed(2)),C(e.note||"")].join(",")));!function(t,a,u){if(void 0!==e.wx$1&&e.wx$1.getFileSystemManager){const n=`${e.wx$1.env.USER_DATA_PATH}/${t}`;e.wx$1.getFileSystemManager().writeFile({filePath:n,data:a,encoding:"utf8",success:()=>{e.index.showModal({title:u,content:`文件已生成:${n}`,showCancel:!1})},fail:()=>{e.index.setClipboardData({data:a})}})}else e.index.setClipboardData({data:a})}(`账单-${c.value}.csv`,["\ufeff日期,类型,分类,账户,金额,备注",...t].join("\n"),"CSV 导出成功")}function S(){const t=`${s.value},支出 ${u.formatCurrency(f.value)},收入 ${u.formatCurrency(v.value)},结余 ${u.formatCurrency(v.value-f.value)}。`;e.index.setClipboardData({data:t})}return e.onShareAppMessage((()=>({title:`${s.value}收支摘要`,path:"/pages/stats/index"}))),(t,a)=>e.e({a:e.t(s.value),b:m.value,c:e.o(y),d:e.t(e.unref(u.formatCurrency)(f.value)),e:e.t(e.unref(u.formatCurrency)(v.value)),f:e.t(e.unref(u.formatCurrency)(v.value-f.value)),g:e.p({title:"报表总览",subtitle:"按月份查看收支分布、消费趋势和月度对比"}),h:b.value.length},b.value.length?{i:e.f(b.value,((t,a,n)=>({a:t.color,b:e.t(t.name),c:e.t(e.unref(u.formatCurrency)(t.total)),d:e.t(t.percentLabel),e:t.percentWidth,f:t.color,g:t.id})))}:{},{j:e.p({title:"支出分类",subtitle:"查看本月主要消费去向与占比结构"}),k:e.f(h.value,((t,a,u)=>({a:t.height,b:e.t(t.label),c:e.t(0===t.value?"-":t.value),d:t.date}))),l:e.p({title:"近 7 日趋势",subtitle:"观察近一周消费变化,便于发现异常高峰"}),m:e.f(x.value,((t,a,n)=>({a:e.t(t.label),b:t.expenseWidth,c:t.incomeWidth,d:e.t(e.unref(u.formatCurrency)(t.expense)),e:e.t(e.unref(u.formatCurrency)(t.income)),f:t.month}))),n:e.p({title:"月度对比",subtitle:"最近 6 个月收入与支出走势一目了然"}),o:e.o($),p:e.o((e=>l.value=!0)),q:e.p({title:"导出与分享",subtitle:"支持导出当月 CSV 账单与生成分享文案"}),r:l.value},l.value?{s:e.o((e=>l.value=!1)),t:e.t(s.value),v:e.t(e.unref(u.formatCurrency)(f.value)),w:e.t(e.unref(u.formatCurrency)(v.value)),x:e.t(e.unref(u.formatCurrency)(v.value-f.value)),y:e.o(S),z:e.o((e=>l.value=!1)),A:e.o((()=>{}))}:{},{B:e.p({current:"stats"}),C:e.n(i.value)})}},l=e._export_sfc(o,[["__scopeId","data-v-7cab36fb"]]);o.__runtimeHooks=2,wx.createPage(l);
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/stats/index.json b/uniapp/unpackage/dist/build/mp-weixin/pages/stats/index.json
new file mode 100644
index 0000000..a9b9bb1
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/stats/index.json
@@ -0,0 +1,7 @@
+{
+ "navigationBarTitleText": "数据报表",
+ "usingComponents": {
+ "section-card": "../../components/SectionCard",
+ "app-tab-bar": "../../components/AppTabBar"
+ }
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/stats/index.wxml b/uniapp/unpackage/dist/build/mp-weixin/pages/stats/index.wxml
new file mode 100644
index 0000000..a3ffd4a
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/stats/index.wxml
@@ -0,0 +1 @@
+{{a}}支出{{d}}收入{{e}}结余{{f}}{{item.b}}{{item.c}} · {{item.d}}当前月份暂无支出数据,记一笔后会自动生成图表。{{item.b}}{{item.c}}{{item.a}}{{item.d}} / {{item.e}}导出 CSV分享摘要{{t}}收支月报支出 {{v}}收入 {{w}}结余 {{x}}内容本地生成,可复制摘要或直接截图分享。复制摘要关闭
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/pages/stats/index.wxss b/uniapp/unpackage/dist/build/mp-weixin/pages/stats/index.wxss
new file mode 100644
index 0000000..eeff5be
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/pages/stats/index.wxss
@@ -0,0 +1 @@
+.summary-row.data-v-7cab36fb,.action-grid.data-v-7cab36fb{display:flex;gap:16rpx}.summary-item.data-v-7cab36fb{flex:1;padding:22rpx;border-radius:24rpx}.summary-value.data-v-7cab36fb{display:block;margin-top:10rpx;font-size:30rpx;font-weight:700;color:var(--text-primary)}.section-link.data-v-7cab36fb{font-size:24rpx;color:var(--brand)}.chart-list.data-v-7cab36fb,.compare-list.data-v-7cab36fb{display:flex;flex-direction:column;gap:18rpx}.chart-head.data-v-7cab36fb,.chart-title-row.data-v-7cab36fb,.compare-row.data-v-7cab36fb{display:flex;align-items:center;justify-content:space-between;gap:16rpx}.chart-dot.data-v-7cab36fb{width:16rpx;height:16rpx;border-radius:50%}.chart-title.data-v-7cab36fb{font-size:28rpx;font-weight:600;color:var(--text-primary)}.bar-track.data-v-7cab36fb,.mini-track.data-v-7cab36fb,.column-track.data-v-7cab36fb{overflow:hidden;border-radius:999rpx;background:var(--surface-muted)}.bar-track.data-v-7cab36fb{height:16rpx;margin-top:12rpx}.bar-fill.data-v-7cab36fb,.mini-fill.data-v-7cab36fb{height:100%;border-radius:inherit}.column-chart.data-v-7cab36fb{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:12rpx;align-items:end;height:260rpx}.column-item.data-v-7cab36fb{display:flex;flex-direction:column;align-items:center;gap:10rpx}.column-track.data-v-7cab36fb{display:flex;align-items:flex-end;justify-content:center;width:100%;height:180rpx;padding:0 6rpx}.column-fill.data-v-7cab36fb{width:100%;border-radius:999rpx 999rpx 16rpx 16rpx;background:linear-gradient(180deg,#5f8df5,#1f6f5f)}.compare-label.data-v-7cab36fb{width:64rpx;font-size:24rpx;color:var(--text-secondary)}.compare-bars.data-v-7cab36fb{flex:1;display:flex;flex-direction:column;gap:10rpx}.mini-track.data-v-7cab36fb{height:12rpx}.expense-fill.data-v-7cab36fb{background:#d36c43}.income-fill.data-v-7cab36fb{background:#1f6f5f}.action-grid.data-v-7cab36fb{margin-top:8rpx}.action-grid .primary-button.data-v-7cab36fb,.action-grid .ghost-button.data-v-7cab36fb{flex:1}.empty-card.data-v-7cab36fb{padding:32rpx 0 10rpx;text-align:center}.poster-shell.data-v-7cab36fb{position:fixed;top:0;right:0;bottom:0;left:0;z-index:50}.poster-mask.data-v-7cab36fb{position:absolute;top:0;right:0;bottom:0;left:0;background:rgba(4,12,18,.42)}.poster-panel.data-v-7cab36fb{position:absolute;left:24rpx;right:24rpx;top:16vh;padding:28rpx}.poster-card.data-v-7cab36fb{padding:32rpx;border-radius:28rpx;background:linear-gradient(145deg,#102a43,#1f6f5f);color:#fff;margin-bottom:20rpx}.poster-month.data-v-7cab36fb,.poster-tip.data-v-7cab36fb{color:rgba(255,255,255,.76)}.poster-title.data-v-7cab36fb{display:block;margin:12rpx 0 20rpx;font-size:42rpx;font-weight:700}.poster-line.data-v-7cab36fb{display:block;margin-bottom:12rpx;font-size:28rpx}.poster-tip.data-v-7cab36fb{display:block;margin-top:24rpx;font-size:22rpx;line-height:1.6}
diff --git a/uniapp/unpackage/dist/build/mp-weixin/project.config.json b/uniapp/unpackage/dist/build/mp-weixin/project.config.json
new file mode 100644
index 0000000..81c3416
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/project.config.json
@@ -0,0 +1,36 @@
+{
+ "description": "项目配置文件。",
+ "packOptions": {
+ "ignore": []
+ },
+ "setting": {
+ "urlCheck": false,
+ "es6": true,
+ "postcss": false,
+ "minified": true,
+ "newFeature": true,
+ "bigPackageSizeSupport": true
+ },
+ "compileType": "miniprogram",
+ "libVersion": "",
+ "appid": "wx64fbe7ae2180912a",
+ "projectname": "账单小管家",
+ "condition": {
+ "search": {
+ "current": -1,
+ "list": []
+ },
+ "conversation": {
+ "current": -1,
+ "list": []
+ },
+ "game": {
+ "current": -1,
+ "list": []
+ },
+ "miniprogram": {
+ "current": -1,
+ "list": []
+ }
+ }
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/project.private.config.json b/uniapp/unpackage/dist/build/mp-weixin/project.private.config.json
new file mode 100644
index 0000000..d90fdb6
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/project.private.config.json
@@ -0,0 +1,22 @@
+{
+ "libVersion": "3.14.3",
+ "projectname": "mp-weixin",
+ "condition": {},
+ "setting": {
+ "urlCheck": false,
+ "coverView": false,
+ "lazyloadPlaceholderEnable": false,
+ "skylineRenderEnable": false,
+ "preloadBackgroundData": false,
+ "autoAudits": false,
+ "useApiHook": true,
+ "showShadowRootInWxmlPanel": false,
+ "useStaticServer": false,
+ "useLanDebug": false,
+ "showES6CompileOption": false,
+ "compileHotReLoad": true,
+ "checkInvalidKey": true,
+ "ignoreDevUnusedFiles": true,
+ "bigPackageSizeSupport": true
+ }
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/build/mp-weixin/static/logo.png b/uniapp/unpackage/dist/build/mp-weixin/static/logo.png
new file mode 100644
index 0000000..b5771e2
Binary files /dev/null and b/uniapp/unpackage/dist/build/mp-weixin/static/logo.png differ
diff --git a/uniapp/unpackage/dist/build/mp-weixin/utils/constants.js b/uniapp/unpackage/dist/build/mp-weixin/utils/constants.js
new file mode 100644
index 0000000..1bc5375
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/utils/constants.js
@@ -0,0 +1 @@
+"use strict";const a=[{id:"food",name:"餐饮",color:"#d36c43"},{id:"transport",name:"交通",color:"#5a8dee"},{id:"rent",name:"住房",color:"#6e5ef7"},{id:"shopping",name:"购物",color:"#d14b7d"},{id:"entertainment",name:"娱乐",color:"#f0a33a"},{id:"medical",name:"医疗",color:"#17a589"},{id:"travel",name:"旅行",color:"#008b8b"},{id:"daily",name:"日用",color:"#7b8794"}],e=[{id:"salary",name:"工资",color:"#1f8f6d"},{id:"bonus",name:"奖金",color:"#3c9d5e"},{id:"allowance",name:"生活费",color:"#5f8df5"},{id:"refund",name:"退款",color:"#e39b2d"},{id:"sidejob",name:"副业",color:"#7f56d9"}],o=[{id:"wechat",name:"微信",color:"#1aad19"},{id:"alipay",name:"支付宝",color:"#1677ff"},{id:"cash",name:"现金",color:"#ff8a3d"},{id:"bank",name:"银行卡",color:"#44546a"}];exports.createDefaultData=function(){return{categories:{expense:[...a],income:[...e]},accounts:[...o],bills:[],budgets:{total:0,categoryBudgets:{}},settings:{theme:"light",profile:{authorized:!1,nickname:"",avatarUrl:""},lastBackupAt:""}}};
diff --git a/uniapp/unpackage/dist/build/mp-weixin/utils/date.js b/uniapp/unpackage/dist/build/mp-weixin/utils/date.js
new file mode 100644
index 0000000..16788f0
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/utils/date.js
@@ -0,0 +1 @@
+"use strict";function t(t){return String(t).padStart(2,"0")}function e(t=new Date){if(t instanceof Date)return new Date(t.getTime());if("number"==typeof t)return new Date(t);if("string"==typeof t){if(/^\d{4}-\d{2}-\d{2}$/.test(t)){const[e,n,r]=t.split("-").map(Number);return new Date(e,n-1,r)}if(/^\d{4}-\d{2}$/.test(t)){const[e,n]=t.split("-").map(Number);return new Date(e,n-1,1)}return new Date(t.replace(/-/g,"/"))}return new Date}function n(n=new Date){const r=e(n);return`${r.getFullYear()}-${t(r.getMonth()+1)}-${t(r.getDate())}`}function r(n=new Date){const r=e(n);return`${r.getFullYear()}-${t(r.getMonth()+1)}`}function o(t){const[e,n]=t.split("-").map(Number);return new Date(e,n,0).getDate()}exports.formatDateLabel=function(t){if(!t)return"";const n=e(t);return`${n.getMonth()+1}月${n.getDate()}日 ${["周日","周一","周二","周三","周四","周五","周六"][n.getDay()]}`},exports.formatMonthLabel=function(t){if(!t)return"";const[e,n]=t.split("-");return`${e}年${Number(n)}月`},exports.getDaysLeftInMonth=function(t){const e=new Date;return r(e)!==t?o(t):o(t)-e.getDate()+1},exports.getMonthSeries=function(t,e=r()){const[n,o]=e.split("-").map(Number),a=new Date(n,o-1,1),s=[];for(let u=t-1;u>=0;u-=1){const t=new Date(a);t.setMonth(a.getMonth()-u),s.push(r(t))}return s},exports.getRecentDateKeys=function(t,r=new Date){const o=[],a=e(r);for(let e=t-1;e>=0;e-=1){const t=new Date(a);t.setDate(a.getDate()-e),o.push(n(t))}return o},exports.isSameMonth=function(t,e){return r(t)===e},exports.parseDate=e,exports.toDateKey=n,exports.toMonthKey=r;
diff --git a/uniapp/unpackage/dist/build/mp-weixin/utils/money.js b/uniapp/unpackage/dist/build/mp-weixin/utils/money.js
new file mode 100644
index 0000000..a6aa933
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/utils/money.js
@@ -0,0 +1 @@
+"use strict";function r(r){return Math.max(0,Math.round(100*(Number(r)||0)))}exports.clampPercent=function(t){return`${Math.min(100,r(t))}%`},exports.formatCurrency=function(r){return`¥${Number(r||0).toFixed(2)}`},exports.formatPercent=function(t){return`${r(t)}%`};
diff --git a/uniapp/unpackage/dist/build/mp-weixin/utils/store.js b/uniapp/unpackage/dist/build/mp-weixin/utils/store.js
new file mode 100644
index 0000000..fbdaa3d
--- /dev/null
+++ b/uniapp/unpackage/dist/build/mp-weixin/utils/store.js
@@ -0,0 +1 @@
+"use strict";const e=require("../common/vendor.js"),t=require("./constants.js"),s="bill-helper-miniapp-v1";function n(e){return JSON.parse(JSON.stringify(e))}function i(e){var s,n,i,l,o,a,c,r,u,g,d,p;const f=t.createDefaultData(),b=e||{};return{categories:{expense:Array.isArray(null==(s=b.categories)?void 0:s.expense)&&b.categories.expense.length?b.categories.expense:f.categories.expense,income:Array.isArray(null==(n=b.categories)?void 0:n.income)&&b.categories.income.length?b.categories.income:f.categories.income},accounts:Array.isArray(b.accounts)&&b.accounts.length?b.accounts:f.accounts,bills:Array.isArray(b.bills)?b.bills:f.bills,budgets:{total:Number(null==(i=b.budgets)?void 0:i.total)||f.budgets.total,categoryBudgets:(null==(l=b.budgets)?void 0:l.categoryBudgets)||f.budgets.categoryBudgets},settings:{theme:(null==(o=b.settings)?void 0:o.theme)||f.settings.theme,profile:{authorized:Boolean(null==(c=null==(a=b.settings)?void 0:a.profile)?void 0:c.authorized),nickname:(null==(u=null==(r=b.settings)?void 0:r.profile)?void 0:u.nickname)||f.settings.profile.nickname,avatarUrl:(null==(d=null==(g=b.settings)?void 0:g.profile)?void 0:d.avatarUrl)||""},lastBackupAt:(null==(p=b.settings)?void 0:p.lastBackupAt)||""}}}const l=e.reactive(i(function(){try{const n=e.index.getStorageSync(s);if(!n){const n=t.createDefaultData();return e.index.setStorageSync(s,n),n}return i(n)}catch(n){return t.createDefaultData()}}()));function o(e){l.categories.expense.splice(0,l.categories.expense.length,...e.categories.expense),l.categories.income.splice(0,l.categories.income.length,...e.categories.income),l.accounts.splice(0,l.accounts.length,...e.accounts),l.bills.splice(0,l.bills.length,...e.bills),l.budgets.total=Number(e.budgets.total)||0,l.budgets.categoryBudgets={...e.budgets.categoryBudgets},l.settings.theme=e.settings.theme,l.settings.profile={...e.settings.profile},l.settings.lastBackupAt=e.settings.lastBackupAt||""}function a(){e.index.setStorageSync(s,n(l))}exports.useAppStore=function(){return{state:l,saveBill:function(e){const t=function(e){return{id:e.id||`bill-${Date.now()}`,type:e.type||"expense",amount:Number(e.amount)||0,categoryId:e.categoryId||"",accountId:e.accountId||"",note:e.note||"",date:e.date,createdAt:e.createdAt||Date.now()}}(e),s=l.bills.findIndex((e=>e.id===t.id));-1===s?l.bills.unshift(t):l.bills.splice(s,1,t),a()},deleteBill:function(e){l.bills.splice(0,l.bills.length,...l.bills.filter((t=>t.id!==e))),a()},deleteBills:function(e){const t=new Set(e);l.bills.splice(0,l.bills.length,...l.bills.filter((e=>!t.has(e.id)))),a()},setBudgetTotal:function(e){l.budgets.total=Number(e)||0,a()},setCategoryBudget:function(e,t){l.budgets.categoryBudgets={...l.budgets.categoryBudgets,[e]:Number(t)||0},a()},setTheme:function(e){l.settings.theme=e,a()},setProfile:function(e){l.settings.profile={...l.settings.profile,...e},a()},markBackup:function(e){l.settings.lastBackupAt=e,a()},exportBackup:function(){return JSON.stringify(n(l),null,2)},importBackup:function(e){o(i(JSON.parse(e))),a()},resetAll:function(){o(t.createDefaultData()),a()}}};
diff --git a/uniapp/unpackage/dist/cache/.vite/deps/_metadata.json b/uniapp/unpackage/dist/cache/.vite/deps/_metadata.json
new file mode 100644
index 0000000..e3245c0
--- /dev/null
+++ b/uniapp/unpackage/dist/cache/.vite/deps/_metadata.json
@@ -0,0 +1,8 @@
+{
+ "hash": "cd0b394e",
+ "configHash": "0843ca34",
+ "lockfileHash": "e3b0c442",
+ "browserHash": "9273fc72",
+ "optimized": {},
+ "chunks": {}
+}
\ No newline at end of file
diff --git a/uniapp/unpackage/dist/cache/.vite/deps/package.json b/uniapp/unpackage/dist/cache/.vite/deps/package.json
new file mode 100644
index 0000000..3dbc1ca
--- /dev/null
+++ b/uniapp/unpackage/dist/cache/.vite/deps/package.json
@@ -0,0 +1,3 @@
+{
+ "type": "module"
+}
diff --git a/uniapp/utils/constants.js b/uniapp/utils/constants.js
new file mode 100644
index 0000000..18c58df
--- /dev/null
+++ b/uniapp/utils/constants.js
@@ -0,0 +1,52 @@
+export const EXPENSE_CATEGORIES = [
+ { id: 'food', name: '餐饮', color: '#d36c43' },
+ { id: 'transport', name: '交通', color: '#5a8dee' },
+ { id: 'rent', name: '住房', color: '#6e5ef7' },
+ { id: 'shopping', name: '购物', color: '#d14b7d' },
+ { id: 'entertainment', name: '娱乐', color: '#f0a33a' },
+ { id: 'medical', name: '医疗', color: '#17a589' },
+ { id: 'travel', name: '旅行', color: '#008b8b' },
+ { id: 'daily', name: '日用', color: '#7b8794' }
+]
+
+export const INCOME_CATEGORIES = [
+ { id: 'salary', name: '工资', color: '#1f8f6d' },
+ { id: 'bonus', name: '奖金', color: '#3c9d5e' },
+ { id: 'allowance', name: '生活费', color: '#5f8df5' },
+ { id: 'refund', name: '退款', color: '#e39b2d' },
+ { id: 'sidejob', name: '副业', color: '#7f56d9' }
+]
+
+export const DEFAULT_ACCOUNTS = [
+ { id: 'wechat', name: '微信', color: '#1aad19' },
+ { id: 'alipay', name: '支付宝', color: '#1677ff' },
+ { id: 'cash', name: '现金', color: '#ff8a3d' },
+ { id: 'bank', name: '银行卡', color: '#44546a' }
+]
+
+export const DEFAULT_THEME = 'light'
+
+export function createDefaultData() {
+ return {
+ categories: {
+ expense: [...EXPENSE_CATEGORIES],
+ income: [...INCOME_CATEGORIES]
+ },
+ accounts: [...DEFAULT_ACCOUNTS],
+ bills: [],
+ budgets: {
+ total: 0,
+ categoryBudgets: {}
+ },
+ settings: {
+ theme: DEFAULT_THEME,
+ profile: {
+ authorized: false,
+ nickname: '',
+ avatarUrl: ''
+ },
+ lastBackupAt: ''
+ }
+ }
+}
+
diff --git a/uniapp/utils/date.js b/uniapp/utils/date.js
new file mode 100644
index 0000000..9f6d56b
--- /dev/null
+++ b/uniapp/utils/date.js
@@ -0,0 +1,103 @@
+function pad(value) {
+ return String(value).padStart(2, '0')
+}
+
+export function parseDate(input = new Date()) {
+ if (input instanceof Date) {
+ return new Date(input.getTime())
+ }
+
+ if (typeof input === 'number') {
+ return new Date(input)
+ }
+
+ if (typeof input === 'string') {
+ if (/^\d{4}-\d{2}-\d{2}$/.test(input)) {
+ const [year, month, day] = input.split('-').map(Number)
+ return new Date(year, month - 1, day)
+ }
+
+ if (/^\d{4}-\d{2}$/.test(input)) {
+ const [year, month] = input.split('-').map(Number)
+ return new Date(year, month - 1, 1)
+ }
+
+ return new Date(input.replace(/-/g, '/'))
+ }
+
+ return new Date()
+}
+
+export function toDateKey(input = new Date()) {
+ const date = parseDate(input)
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
+}
+
+export function toMonthKey(input = new Date()) {
+ const date = parseDate(input)
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}`
+}
+
+export function formatDateLabel(value) {
+ if (!value) {
+ return ''
+ }
+
+ const date = parseDate(value)
+ const weekMap = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
+ return `${date.getMonth() + 1}月${date.getDate()}日 ${weekMap[date.getDay()]}`
+}
+
+export function formatMonthLabel(monthKey) {
+ if (!monthKey) {
+ return ''
+ }
+
+ const [year, month] = monthKey.split('-')
+ return `${year}年${Number(month)}月`
+}
+
+export function isSameMonth(dateValue, monthKey) {
+ return toMonthKey(dateValue) === monthKey
+}
+
+export function getMonthDays(monthKey) {
+ const [year, month] = monthKey.split('-').map(Number)
+ return new Date(year, month, 0).getDate()
+}
+
+export function getDaysLeftInMonth(monthKey) {
+ const today = new Date()
+ if (toMonthKey(today) !== monthKey) {
+ return getMonthDays(monthKey)
+ }
+
+ return getMonthDays(monthKey) - today.getDate() + 1
+}
+
+export function getRecentDateKeys(days, endDate = new Date()) {
+ const result = []
+ const end = parseDate(endDate)
+
+ for (let index = days - 1; index >= 0; index -= 1) {
+ const current = new Date(end)
+ current.setDate(end.getDate() - index)
+ result.push(toDateKey(current))
+ }
+
+ return result
+}
+
+export function getMonthSeries(length, endMonthKey = toMonthKey()) {
+ const [year, month] = endMonthKey.split('-').map(Number)
+ const cursor = new Date(year, month - 1, 1)
+ const result = []
+
+ for (let index = length - 1; index >= 0; index -= 1) {
+ const current = new Date(cursor)
+ current.setMonth(cursor.getMonth() - index)
+ result.push(toMonthKey(current))
+ }
+
+ return result
+}
diff --git a/uniapp/utils/money.js b/uniapp/utils/money.js
new file mode 100644
index 0000000..e1ce9d0
--- /dev/null
+++ b/uniapp/utils/money.js
@@ -0,0 +1,15 @@
+export function formatCurrency(value) {
+ return `¥${Number(value || 0).toFixed(2)}`
+}
+
+function toPercentNumber(value) {
+ return Math.max(0, Math.round((Number(value) || 0) * 100))
+}
+
+export function formatPercent(value) {
+ return `${toPercentNumber(value)}%`
+}
+
+export function clampPercent(value) {
+ return `${Math.min(100, toPercentNumber(value))}%`
+}
diff --git a/uniapp/utils/store.js b/uniapp/utils/store.js
new file mode 100644
index 0000000..bba8317
--- /dev/null
+++ b/uniapp/utils/store.js
@@ -0,0 +1,179 @@
+import { reactive } from 'vue'
+import { createDefaultData } from './constants'
+
+const STORAGE_KEY = 'bill-helper-miniapp-v1'
+
+function deepClone(value) {
+ return JSON.parse(JSON.stringify(value))
+}
+
+function normalizeData(raw) {
+ const fallback = createDefaultData()
+ const source = raw || {}
+
+ return {
+ categories: {
+ expense: Array.isArray(source.categories?.expense) && source.categories.expense.length
+ ? source.categories.expense
+ : fallback.categories.expense,
+ income: Array.isArray(source.categories?.income) && source.categories.income.length
+ ? source.categories.income
+ : fallback.categories.income
+ },
+ accounts: Array.isArray(source.accounts) && source.accounts.length ? source.accounts : fallback.accounts,
+ bills: Array.isArray(source.bills) ? source.bills : fallback.bills,
+ budgets: {
+ total: Number(source.budgets?.total) || fallback.budgets.total,
+ categoryBudgets: source.budgets?.categoryBudgets || fallback.budgets.categoryBudgets
+ },
+ settings: {
+ theme: source.settings?.theme || fallback.settings.theme,
+ profile: {
+ authorized: Boolean(source.settings?.profile?.authorized),
+ nickname: source.settings?.profile?.nickname || fallback.settings.profile.nickname,
+ avatarUrl: source.settings?.profile?.avatarUrl || ''
+ },
+ lastBackupAt: source.settings?.lastBackupAt || ''
+ }
+ }
+}
+
+function loadData() {
+ try {
+ const raw = uni.getStorageSync(STORAGE_KEY)
+ if (!raw) {
+ const seeded = createDefaultData()
+ uni.setStorageSync(STORAGE_KEY, seeded)
+ return seeded
+ }
+ return normalizeData(raw)
+ } catch (error) {
+ return createDefaultData()
+ }
+}
+
+const state = reactive(normalizeData(loadData()))
+
+function patchState(nextState) {
+ state.categories.expense.splice(0, state.categories.expense.length, ...nextState.categories.expense)
+ state.categories.income.splice(0, state.categories.income.length, ...nextState.categories.income)
+ state.accounts.splice(0, state.accounts.length, ...nextState.accounts)
+ state.bills.splice(0, state.bills.length, ...nextState.bills)
+ state.budgets.total = Number(nextState.budgets.total) || 0
+ state.budgets.categoryBudgets = { ...nextState.budgets.categoryBudgets }
+ state.settings.theme = nextState.settings.theme
+ state.settings.profile = { ...nextState.settings.profile }
+ state.settings.lastBackupAt = nextState.settings.lastBackupAt || ''
+}
+
+function persist() {
+ uni.setStorageSync(STORAGE_KEY, deepClone(state))
+}
+
+function buildBillPayload(payload) {
+ return {
+ id: payload.id || `bill-${Date.now()}`,
+ type: payload.type || 'expense',
+ amount: Number(payload.amount) || 0,
+ categoryId: payload.categoryId || '',
+ accountId: payload.accountId || '',
+ note: payload.note || '',
+ date: payload.date,
+ createdAt: payload.createdAt || Date.now()
+ }
+}
+
+export function useAppStore() {
+ function saveBill(payload) {
+ const nextBill = buildBillPayload(payload)
+ const index = state.bills.findIndex((item) => item.id === nextBill.id)
+
+ if (index === -1) {
+ state.bills.unshift(nextBill)
+ } else {
+ state.bills.splice(index, 1, nextBill)
+ }
+
+ persist()
+ }
+
+ function deleteBill(id) {
+ state.bills.splice(
+ 0,
+ state.bills.length,
+ ...state.bills.filter((item) => item.id !== id)
+ )
+ persist()
+ }
+
+ function deleteBills(ids) {
+ const idSet = new Set(ids)
+ state.bills.splice(
+ 0,
+ state.bills.length,
+ ...state.bills.filter((item) => !idSet.has(item.id))
+ )
+ persist()
+ }
+
+ function setBudgetTotal(value) {
+ state.budgets.total = Number(value) || 0
+ persist()
+ }
+
+ function setCategoryBudget(categoryId, value) {
+ state.budgets.categoryBudgets = {
+ ...state.budgets.categoryBudgets,
+ [categoryId]: Number(value) || 0
+ }
+ persist()
+ }
+
+ function setTheme(theme) {
+ state.settings.theme = theme
+ persist()
+ }
+
+ function setProfile(profile) {
+ state.settings.profile = {
+ ...state.settings.profile,
+ ...profile
+ }
+ persist()
+ }
+
+ function markBackup(timeLabel) {
+ state.settings.lastBackupAt = timeLabel
+ persist()
+ }
+
+ function exportBackup() {
+ return JSON.stringify(deepClone(state), null, 2)
+ }
+
+ function importBackup(payload) {
+ const parsed = normalizeData(JSON.parse(payload))
+ patchState(parsed)
+ persist()
+ }
+
+ function resetAll() {
+ patchState(createDefaultData())
+ persist()
+ }
+
+ return {
+ state,
+ saveBill,
+ deleteBill,
+ deleteBills,
+ setBudgetTotal,
+ setCategoryBudget,
+ setTheme,
+ setProfile,
+ markBackup,
+ exportBackup,
+ importBackup,
+ resetAll
+ }
+}