diff --git a/code/app/app-rn/.trae/documents/项目分析与理解.md b/code/app/app-rn/.trae/documents/项目分析与理解.md new file mode 100644 index 00000000..df48c6f5 --- /dev/null +++ b/code/app/app-rn/.trae/documents/项目分析与理解.md @@ -0,0 +1,304 @@ +# 项目分析计划 + +## 一、项目概述 + +这是一个基于 **React Native (Expo)** 的跨平台移动应用,采用 **React Navigation** 路由 + **expo-router** 文件约定式路由架构。 + +## 二、技术栈 + +### 框架与核心库 + +| 库 | 版本 | 用途 | +| ------------ | --------- | ------- | +| expo | \~55.0.15 | 基础框架 | +| expo-router | \~55.0.12 | 文件约定式路由 | +| react-native | 0.83.4 | 原生视图层 | +| react | 19.2.0 | UI 框架 | + +### 状态管理 + +| 库 | 版本 | 用途 | +| ----------------------------------------- | ------- | ------ | +| zustand | ^5.0.12 | 轻量状态管理 | +| @react-native-async-storage/async-storage | ^2.2.0 | 持久化存储 | + +### 请求与数据 + +| 库 | 版本 | 用途 | +| -------------------- | ------- | --------- | +| alova | ^3.5.1 | 请求库 | +| @alova/adapter-axios | ^2.0.18 | Axios 适配器 | +| axios | ^1.15.0 | HTTP 客户端 | + +### UI 组件 + +| 库 | 版本 | 用途 | +| ----------------------- | ------ | ------- | +| heroui-native | ^1.0.1 | UI 组件库 | +| lucide-react-native | ^1.8.0 | 图标库 | +| react-native-reanimated | 4.2.1 | 动画库 | +| tailwindcss | ^4.2.2 | 原子化 CSS | + +## 三、项目架构 + +### 3.1 目录结构 + +``` +src/ +├── app/ # 页面 (expo-router 文件约定式路由) +│ ├── (tabs)/ # 底部 Tab 页面组 +│ │ ├── home/ # 首页 +│ │ ├── chat/ # 聊天页 +│ │ ├── star/ # 收藏页 +│ │ ├── my/ # 个人中心 +│ │ └── _layout.tsx # Tab 布局 +│ ├── auth/ # 认证页面 +│ │ └── login.tsx # 登录页 +│ ├── family/ # 家庭模块 +│ │ ├── entry.tsx # 家庭入口(创建/加入) +│ │ ├── settings.tsx # 家庭设置 +│ │ ├── user.tsx # 家庭成员 +│ │ └── member/[id].tsx # 成员详情 +│ ├── finance/ # 记账模块 +│ │ ├── (tabs)/ # 记账子 Tab +│ │ │ ├── home/ # 记账首页 +│ │ │ ├── analysis/ # 统计分析 +│ │ │ └── _layout.tsx +│ │ ├── add/ # 新增记账 +│ │ └── sub/ # 订阅管理 +│ ├── tools/ # 工具页面 +│ ├── _layout.tsx # 根布局 +│ └── index.tsx # 根页面 +├── components/ # 组件 +│ ├── iconfont/ # IconFont 图标组件 +│ └── layout/ # 布局组件 (Navbar, Tabbar) +├── configs/ # 配置 +│ └── pages.ts # 子应用配置 +├── hooks/ # 自定义 Hooks +│ ├── use-color-scheme.ts +│ └── use-theme-color.ts +├── layouts/ # 布局模板 +│ ├── AppLayout.tsx # App 主布局 (带 Navbar + Tabbar) +│ ├── ModuleLayout.tsx # 模块布局 (独立功能模块) +│ └── PageLayout.tsx # 页面布局 +├── request/ # 请求相关 +│ ├── api.ts # API 接口定义 +│ └── index.ts # Alova 实例 +├── store/ # Zustand 状态库 +│ ├── app.ts # App 全局状态 +│ ├── user.ts # 用户状态 +│ ├── finance.ts # 记账状态 +│ └── family.ts # 家庭状态 +├── types/ # TypeScript 类型 +│ └── auth.ts # 认证类型 +└── utils/ # 工具函数 + ├── http.ts # HTTP 封装 + ├── time.ts # 时间处理 + └── cn.ts # 样式合并 +``` + +### 3.2 路由架构 + +``` +根布局 (_layout.tsx) +├── 认证流程 +│ └── auth/login.tsx (未登录跳转) +├── 主应用 (已登录) +│ ├── (tabs) 底部 Tab 导航 +│ │ ├── home (首页) +│ │ ├── space (空间) +│ │ ├── tools (工具中心 - 中心按钮) +│ │ ├── chat (聊天) +│ │ └── my (我的) +│ └── 独立页面 +│ ├── family/entry (家庭入口) +│ ├── family/settings (家庭设置) +│ └── finance/(tabs) (记账模块 Tab) +│ ├── home (记账) +│ ├── add (新增 - 中心按钮) +│ └── analysis (分析) +``` + +### 3.3 布局系统 + +| 布局组件 | 用途 | 层级 | +| ------------ | ------------------------ | ---- | +| AppLayout | 主应用布局,提供 Navbar + Tabbar | 页面容器 | +| ModuleLayout | 功能模块布局,独立 Tabbar | 模块容器 | +| PageLayout | 页面基础布局,处理安全区域 | 内容容器 | + +## 四、API 接口分析 + +### 4.1 请求封装 + +使用 **Alova** 请求库,配合 **Axios** 适配器。请求基地址: `EXPO_PUBLIC_API_URL` (开发环境: `https://dev.api.com`) + +### 4.2 HTTP 拦截器 + +**请求拦截器**: + +* 白名单接口直接放行 (`/auth/login/**`) + +* 非白名单接口检查登录状态 + +* 未登录拦截并跳转登录页 + +* 已登录则注入 JWT Token 到 Header + +**响应拦截器**: + +* `code: 1000` → 成功 + +* `code: 1001` → Token 过期,跳转登录 + +* `code: 2000` → 业务错误,显示错误提示 + +* `code: 3000` → 系统错误,显示错误提示 + +* 其他 → 请求失败 + +### 4.3 核心 API + +| 接口 | 方法 | 参数 | 用途 | +| --------------------- | ---- | --------------------------------------------------------------- | ------- | +| `/auth/login/qq` | POST | openid, nickname, avatar | QQ 登录 | +| `/auth/login/wechat` | POST | code | 微信登录 | +| `/bind/qq` | POST | openid, nickname, avatar | 绑定 QQ | +| `/bind/wechat` | POST | code | 绑定微信 | +| `/data/getUniqueId` | POST | count | 获取自增 ID | +| `/data/loadData` | POST | view\_name, search\_condition, order\_by, search\_columns, args | 查询数据 | +| `/data/loadDataBySql` | POST | sql, args | SQL 查询 | +| `/data/saveData` | POST | table\_name, key\_field, inserts, updates, deletes | 保存数据 | +| `/s3/upload` | POST | files | 文件上传 | + +### 4.4 数据表结构 (推测) + +| 表名 | 用途 | +| ----------------------------- | --------- | +| b\_family | 家庭表 | +| b\_family\_member | 家庭成员表 | +| b\_finance\_category | 记账分类表 | +| b\_finance\_category\_default | 默认记账分类 | +| b\_finance\_record | 记账记录 (推测) | +| v\_family\_member | 家庭成员视图 | + +## 五、状态管理 + +### 5.1 Store 概览 + +| Store | 持久化 | 用途 | +| ------------ | -------------- | --------------- | +| userStore | ✅ AsyncStorage | 用户信息、Token、登录状态 | +| familyStore | ✅ AsyncStorage | 当前家庭 ID | +| financeStore | ❌ 内存 | 记账分类数据 | +| appStore | ❌ 内存 | App 全局状态 | + +### 5.2 用户状态 (userStore) + +```typescript +interface UserInfo { + id: number; + token: string; + nickname: string; + avatar: string; +} +``` + +### 5.3 家庭状态 (familyStore) + +```typescript +interface Family { + family_id: number; +} +``` + +## 六、第三方登录 + +### 6.1 QQ 登录 + +* 使用 `expo-qq` 库 + +* 需要配置 App ID: `102826474` + +### 6.2 微信登录 + +* 使用 `expo-wechat` 库 + +* 需要配置 App ID: `wxdab3e21a1f7e392f` + +## 七、核心业务流程 + +### 7.1 登录流程 + +``` +启动 → 检查登录状态 + ├── 未登录 → 跳转 /auth/login + │ ├── 微信登录 → 调接口 → 写入 Store → 跳转 /family/entry 或 /(tabs)/home + │ └── QQ 登录 → 调接口 → 写入 Store → 跳转 /family/entry 或 /(tabs)/home + │ + └── 已登录 → 跳转 /(tabs)/home +``` + +### 7.2 家庭流程 + +``` +首次登录 → /family/entry + ├── 创建家庭 → 生成邀请码 → 保存家庭 + 成员 → 跳转 /(tabs)/home + └── 加入家庭 → 输入邀请码 → 保存成员 → 跳转 /(tabs)/home +``` + +### 7.3 记账流程 + +``` +点击 Tab → /finance/home + ├── 查看记录 → 列表展示 + ├── 新增记账 → 点击中心 "+" → /finance/add + │ ├── 选择类别 + │ ├── 输入金额 + │ ├── 选择日期 + │ └── 保存 + └── 数据分析 → 点击 "分析" Tab → /finance/analysis +``` + +## 八、环境配置 + +| 环境变量 | 开发环境 | 生产环境 | +| ------------------------ | --------------------------- | ----- | +| EXPO\_PUBLIC\_API\_URL | | (待配置) | +| EXPO\_PUBLIC\_G3\_URL | | (待配置) | +| EXPO\_PUBLIC\_G3\_BUCKET | test | (待配置) | + +## 九、关键实现细节 + +### 9.1 路由跳转 + +* 使用 `expo-router` 的 `useRouter` 和 `router.push/replace` + +* 动态路由: `/family/member/[id].tsx` + +### 9.2 安全区域 + +* 使用 `useSafeAreaInsets()` 处理 iOS 刘海屏和 Android 挖孔屏 + +* Navbar 和 Tabbar 绝对定位,内容区占满屏幕 + +### 9.3 动画 + +* 使用 `react-native-reanimated` 实现 Tabbar 点击缩放动画 + +* `withTiming` 控制动画时长 + +### 9.4 主题 + +* 支持浅色/深色模式 + +* 使用 `useIsDark()` hook 判断当前主题 + +## 十、后续对话需关注的重点 + +1. **API 接口**: 所有后端交互通过 `src/request/api.ts` 封装 +2. **状态管理**: 核心状态使用 Zustand + AsyncStorage 持久化 +3. **路由**: 使用 expo-router 文件约定式路由 +4. **UI 组件**: 主要使用 heroui-native 组件库 +5. **登录机制**: JWT Token 存储在 userStore,通过 http.ts 拦截器自动注入 + diff --git a/code/jsp/.trae/documents/addInsertRows跳转功能实现计划.md b/code/jsp/.trae/documents/addInsertRows跳转功能实现计划.md new file mode 100644 index 00000000..21a19868 --- /dev/null +++ b/code/jsp/.trae/documents/addInsertRows跳转功能实现计划.md @@ -0,0 +1,85 @@ +# 计划:在 addInsertRows 中添加跳转到新增行第一页的功能 + +## 需求分析 + +在 `addInsertRows` 函数执行后,自动跳转到新增行所在的第一个页面。如果当前页已经是新增行所在的页,则不进行跳转。 + +## 代码分析 + +### 相关函数位置 + +* **addInsertRows**: [feegrid-manager.js:832-843](file:///d:/workspace/code/jsp/js/feegrid-manager.js#L832-L843) + +* **loadPage**: [feegrid-manager.js:644-743](file:///d:/workspace/code/jsp/js/feegrid-manager.js#L644-L743) + +* **pagination 状态**: state.pagination(包含 pageNumber, pageSize, remoteTotal) + +### 数据结构理解 + +1. `state.cacheManager.getInsertRows()` - 获取所有新增行(draftState === 'add') +2. `state.pagination.remoteTotal` - 远程数据的总条数 +3. 新增行始终位于所有数据的最末端(即 remoteTotal 之后) + +### 分页计算逻辑 + +* 总数据量 = remoteTotal + insertRows.length + +* 新增行的起始位置 = remoteTotal + +* 新增行第一行所在的页码 = Math.ceil((remoteTotal + 1) / pageSize) + +* 或者:Math.floor(remoteTotal / pageSize) + 1 + +## 实现步骤 + +### Step 1: 修改 addInsertRows 函数 + +在 `addInsertRows(rows)` 函数末尾添加逻辑: + +1. 获取所有新增行 `insertRows = state.cacheManager.getInsertRows()` +2. 如果 `insertRows.length === 0`,直接返回(不应该发生,但做防御性检查) +3. 计算新增行第一行所在的页码: + + * `var remoteTotal = state.pagination.remoteTotal` + + * `var pageSize = state.pagination.pageSize` + + * `var firstInsertPage = Math.floor(remoteTotal / pageSize) + 1` + + * (或者 `Math.ceil((remoteTotal + 1) / pageSize)`) +4. 获取当前页码 `var currentPage = state.pagination.pageNumber` +5. 如果 `firstInsertPage !== currentPage`,则调用 `loadPage(firstInsertPage)` 跳转 + +### Step 2: 代码放置位置 + +在 `addInsertRows` 函数的 for 循环之后(行842之后),在函数结束的大括号之前(行843之前)插入新逻辑。 + +## 预期代码变更 + +```javascript +function addInsertRows(rows) { + if (!$.isArray(rows)) rows = [rows]; + var cm = state.cacheManager; + + for (var i = 0; i < rows.length; i++) { + var row = rows[i]; + var key = cm.getRowKey(row); + if (!cm.getRowFromCache(key)) { + cm.setRowToCache(row, true); + } + } + + // 新增:跳转到新增行所在的第一页 + var insertRows = state.cacheManager.getInsertRows(); + if (insertRows.length > 0) { + var remoteTotal = state.pagination.remoteTotal; + var pageSize = state.pagination.pageSize; + var firstInsertPage = Math.floor(remoteTotal / pageSize) + 1; + var currentPage = state.pagination.pageNumber; + if (firstInsertPage !== currentPage) { + loadPage(firstInsertPage); + } + } +} +``` +