chore: 初始化项目结构与蓝图

- 配置 pnpm workspace monorepo 基础结构
- 初始化 .blueprint/ 蓝图:6 个业务模块、21 张任务卡
- 目标:Z Fold 6 折叠屏不动产物品摸底统计 App(React Native + Expo)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
lanrtop 2026-04-07 15:23:39 +09:00
commit a0929de768
32 changed files with 1185 additions and 0 deletions

222
.blueprint/manifest.yaml Normal file
View File

@ -0,0 +1,222 @@
version: 1
name: react-phone-apps
iteration: 1
updated: 2026-04-07
areas:
- id: infrastructure
name: 基础设施
color: "#6B7280"
- id: shared
name: 共享层
color: "#8B5CF6"
- id: data
name: 数据层
color: "#F59E0B"
- id: rn-app
name: RN 应用(不动产摸底)
color: "#10B981"
- id: frontend
name: 前端应用Web
color: "#3B82F6"
modules:
# ── 基础设施 ──────────────────────────────────────────────────
- id: monorepo-setup
name: Monorepo 工程配置
area: infrastructure
status: done
progress: 100
position: [80, 80]
# ── 共享层 ────────────────────────────────────────────────────
- id: shared-ui
name: 共享 UI 组件库
area: shared
status: concept
progress: 0
position: [380, 80]
- id: shared-utils
name: 共享工具函数库
area: shared
status: concept
progress: 0
position: [380, 240]
- id: shared-hooks
name: 共享 React Hooks
area: shared
status: concept
progress: 0
position: [380, 400]
- id: shared-types
name: 共享类型定义
area: shared
status: concept
progress: 0
position: [380, 560]
# ── 数据层 ────────────────────────────────────────────────────
- id: local-data-layer
name: 本地数据持久化层
area: data
status: planned
progress: 0
position: [680, 80]
# ── RN 应用(不动产摸底)────────────────────────────────────
- id: survey-app-shell
name: 应用外壳与折叠屏布局
area: rn-app
status: planned
progress: 0
position: [980, 80]
- id: floor-map
name: 楼层地图与标记点管理
area: rn-app
status: planned
progress: 0
position: [980, 280]
- id: item-form
name: 物品登记表单
area: rn-app
status: planned
progress: 0
position: [980, 480]
- id: photo-capture
name: 照片采集与管理
area: rn-app
status: planned
progress: 0
position: [980, 680]
- id: inventory-summary
name: 汇总列表与统计
area: rn-app
status: planned
progress: 0
position: [980, 880]
# ── 前端应用Web预留──────────────────────────────────────
- id: app-scaffold
name: 应用脚手架模板
area: frontend
status: concept
progress: 0
position: [1280, 80]
- id: routing
name: 路由与页面结构
area: frontend
status: concept
progress: 0
position: [1280, 240]
- id: theming
name: 主题与样式系统
area: frontend
status: concept
progress: 0
position: [1280, 400]
- id: state-management
name: 全局状态管理
area: frontend
status: concept
progress: 0
position: [1280, 560]
- id: api-client
name: API 客户端层
area: frontend
status: concept
progress: 0
position: [1280, 720]
edges:
# 基础设施 → 共享层
- from: monorepo-setup
to: shared-ui
type: dependency
- from: monorepo-setup
to: shared-utils
type: dependency
- from: monorepo-setup
to: shared-hooks
type: dependency
- from: monorepo-setup
to: shared-types
type: dependency
- from: monorepo-setup
to: local-data-layer
type: dependency
- from: monorepo-setup
to: survey-app-shell
type: dependency
# 共享类型 → 其他共享层
- from: shared-types
to: shared-ui
type: dependency
- from: shared-types
to: shared-utils
type: dependency
- from: shared-types
to: api-client
type: dependency
# 数据层 → RN 应用
- from: local-data-layer
to: survey-app-shell
type: dependency
- from: local-data-layer
to: floor-map
type: dependency
- from: local-data-layer
to: item-form
type: dependency
- from: local-data-layer
to: photo-capture
type: dependency
- from: local-data-layer
to: inventory-summary
type: dependency
# RN 应用内部依赖
- from: survey-app-shell
to: floor-map
type: dependency
- from: survey-app-shell
to: inventory-summary
type: dependency
- from: floor-map
to: item-form
type: dependency
- from: item-form
to: photo-capture
type: dependency
# Web 前端(预留)
- from: monorepo-setup
to: app-scaffold
type: dependency
- from: shared-ui
to: app-scaffold
type: dependency
- from: app-scaffold
to: routing
type: dependency
- from: app-scaffold
to: theming
type: dependency
- from: app-scaffold
to: state-management
type: dependency
- from: app-scaffold
to: api-client
type: dependency

View File

@ -0,0 +1,30 @@
---
id: api-client
name: API 客户端层
area: frontend
status: concept
---
## 概述
封装后端 API 调用,包含统一鉴权、错误处理和接口类型定义。以 packages/api 形式跨 app 共享,或在各 app 内独立维护。
## 任务卡
### 💭 HTTP 客户端实例配置
- status: concept
- complexity: M
- files: packages/utils/src/request.ts, apps/app-one/src/api/client.ts
- acceptance: 配置 baseURL、超时时间请求拦截器自动附加 Authorization header响应拦截器统一处理 401/403/500 错误码
### 💭 API 接口类型化封装
- status: concept
- complexity: M
- files: apps/app-one/src/api/types.ts, apps/app-one/src/api/auth.ts
- acceptance: 每个 API 模块导出类型安全的请求函数(入参和返回值均有 TS 类型),不使用 any
### 💭 数据请求缓存与 SWR 集成
- status: concept
- complexity: M
- files: apps/app-one/src/api/hooks/useAuthQuery.ts
- acceptance: 基于 SWR 或 React Query 封装常用接口 hook支持缓存、重试、乐观更新避免重复请求

View File

@ -0,0 +1,28 @@
---
id: app-scaffold
name: 应用脚手架模板
area: frontend
status: concept
---
## 概述
新 app 的起始模板,包含 Vite 项目配置、HTML 入口、React 根组件、环境变量规范。monorepo 中每个 app 从此模板派生。
## 任务卡
### 💭 创建第一个 Appapps/app-one
- status: concept
- complexity: M
- files: apps/app-one/package.json, apps/app-one/vite.config.ts, apps/app-one/index.html, apps/app-one/src/main.tsx, apps/app-one/src/App.tsx
- acceptance: pnpm dev 能启动pnpm build 产出 dist/src/App.tsx 渲染 Hello World正确引入 @repo/ui@repo/utils
### 💭 移动端视口基础配置
- status: concept
- complexity: S
- files: apps/app-one/index.html, apps/app-one/src/styles/global.css
- acceptance: meta viewport 设置 initial-scale=1禁用双击缩放全局 CSS reset 适配移动端100dvh、touch-action 等)
## 决策记录
- 每个 app 独立配置 Vite 而非共享一个构建进程:便于各 app 独立部署和差异化配置,构建缓存也可隔离

View File

@ -0,0 +1,40 @@
---
id: floor-map
name: 楼层地图与标记点管理
area: rn-app
status: planned
---
## 概述
以 SVG/Image 占位图为底图支持长按添加标记点、点击标记点进入编辑的交互逻辑。标记点坐标以相对比例0~1存储替换真实楼层图时无需修改数据。
## 任务卡
### 📋 平面图占位容器与坐标系
- status: todo
- complexity: M
- files: apps/property-survey/src/features/map/FloorMap.tsx
- depends: survey-app-shell
- acceptance: 渲染一个带灰色背景的矩形占位区域作为平面图,使用 onLayout 获取实际像素尺寸并转换相对坐标0~1容器宽高比固定为 4:3适配折叠/展开两种宽度
### 📋 长按手势添加标记点
- status: todo
- complexity: M
- files: apps/property-survey/src/features/map/useMarkerGesture.ts
- depends: floor-map
- acceptance: 在平面图区域长按 500ms 后触发,将触点位置转换为相对坐标并调用 insertMarker 写入数据库,新标记点立即在地图上显示,不误触短按事件
### 📋 标记点图标组件
- status: todo
- complexity: M
- files: apps/property-survey/src/features/map/MapMarker.tsx
- depends: floor-map
- acceptance: 在平面图上按相对坐标绝对定位渲染图钉图标,已有物品的标记点显示蓝色图钉 + 物品数量角标,空标记点显示灰色图钉,点击触发 onPress 回调
### 📋 当前楼层标记点数据加载
- status: todo
- complexity: S
- files: apps/property-survey/src/features/map/MarkerList.tsx
- depends: floor-map
- acceptance: 楼层切换时调用 getMarkersByFloor 重新查询,渲染该楼层所有 MapMarker删除标记点时弹出确认对话框含级联删除提示

View File

@ -0,0 +1,40 @@
---
id: inventory-summary
name: 汇总列表与统计
area: rn-app
status: planned
---
## 概述
汇总展示全部已登记物品,支持按楼层和物品名筛选,底部显示总件数和总金额统计。提供 CSV 导出通过系统分享面板发送备份。
## 任务卡
### 📋 汇总数据查询 Hook
- status: todo
- complexity: M
- files: apps/property-survey/src/features/summary/useSummaryData.ts
- depends: local-data-layer
- acceptance: 查询所有 items JOIN markers JOIN photos返回带楼层、坐标、物品名、数量、单价、备注、照片数的扁平列表支持按 floor1/2/3/全部)和 name 关键字过滤;数据写入后调用 refresh() 触发重新查询
### 📋 汇总列表与筛选栏
- status: todo
- complexity: M
- files: apps/property-survey/src/features/summary/SummaryList.tsx, apps/property-survey/src/features/summary/FilterBar.tsx
- depends: inventory-summary
- acceptance: 列表每行显示楼层标签、物品名、数量、单价、备注1FilterBar 提供楼层选择器1F/2F/3F/全部和物品名搜索框滚动性能流畅FlatList空数据时显示引导文案
### 📋 统计汇总卡片
- status: todo
- complexity: S
- files: apps/property-survey/src/features/summary/SummaryStats.tsx
- depends: inventory-summary
- acceptance: 固定在列表顶部,展示:登记点总数、物品种类数、总数量合计、总金额合计(数量×单价求和,单价为空则不计入),数值随筛选条件实时更新
### 📋 CSV 导出与系统分享
- status: todo
- complexity: M
- files: apps/property-survey/src/features/summary/exportData.ts
- depends: inventory-summary
- acceptance: 点击导出按钮,将当前筛选结果生成 UTF-8 BOM 的 CSV 文件(含表头:楼层/标记点名/物品名/数量/单价/备注1/备注2/照片数),写入临时目录后调用 expo-sharing 弹出系统分享面板,可发送到微信/邮件/云盘

View File

@ -0,0 +1,33 @@
---
id: item-form
name: 物品登记表单
area: rn-app
status: planned
---
## 概述
点击地图标记点后弹出的物品编辑面板。折叠时以底部抽屉形式展现,展开时在右侧栏内联显示。支持单个标记点下的多条物品记录增删改。
## 任务卡
### 📋 底部抽屉/右栏容器
- status: todo
- complexity: M
- files: apps/property-survey/src/features/item/ItemFormSheet.tsx
- depends: survey-app-shell, floor-map
- acceptance: 折叠时从屏幕底部滑出BottomSheet展开时在 FoldableLayout 右栏内渲染;接受 markerId 和 onClose 两个 prop顶部显示标记点位置名称和所属楼层
### 📋 物品字段表单
- status: todo
- complexity: M
- files: apps/property-survey/src/features/item/ItemFields.tsx, apps/property-survey/src/features/item/useItemForm.ts
- depends: item-form
- acceptance: 包含物品名称必填文本、数量数字键盘、单价数字键盘可选、备注1多行文本、备注2多行文本五个字段保存时校验物品名称非空useItemForm 管理字段状态和 insertItem / updateItem 调用
### 📋 标记点下物品列表
- status: todo
- complexity: M
- files: apps/property-survey/src/features/item/ItemList.tsx
- depends: item-form
- acceptance: 在表单上方列出当前标记点的所有物品(物品名 + 数量 + 单价),点击条目进入编辑,左滑显示删除按钮,点击「+新增物品」清空表单进入新增模式

View File

@ -0,0 +1,39 @@
---
id: local-data-layer
name: 本地数据持久化层
area: data
status: planned
---
## 概述
基于 Expo SQLite 的本地数据库层,管理标记点、物品记录和照片路径三张核心表。所有写操作使用事务保证原子性,供上层功能模块调用。
## 任务卡
### 📋 SQLite 初始化与 Schema 建表
- status: todo
- complexity: M
- files: apps/property-survey/src/db/database.ts, apps/property-survey/src/db/schema.ts
- acceptance: App 启动时自动执行 CREATE TABLE IF NOT EXISTS建立 markers / items / photos 三张表,重复启动不报错,字段与设计文档一致
### 📋 标记点 CRUD 操作
- status: todo
- complexity: M
- files: apps/property-survey/src/db/markers.ts
- depends: local-data-layer
- acceptance: 提供 insertMarker / getMarkersByFloor / updateMarker / deleteMarker 四个函数deleteMarker 级联删除关联 items 和 photos所有函数返回类型安全的 Promise
### 📋 物品记录 CRUD 操作
- status: todo
- complexity: M
- files: apps/property-survey/src/db/items.ts
- depends: local-data-layer
- acceptance: 提供 insertItem / getItemsByMarker / updateItem / deleteItem 四个函数,支持批量查询(传入 marker_id 数组),返回带关联照片数量的扩展类型
### 📋 照片路径 CRUD 操作
- status: todo
- complexity: S
- files: apps/property-survey/src/db/photos.ts
- depends: local-data-layer
- acceptance: 提供 insertPhoto / getPhotosByItem / deletePhoto / reorderPhotos 四个函数deletePhoto 同步删除设备文件系统中的对应图片文件

View File

@ -0,0 +1,40 @@
---
id: monorepo-setup
name: Monorepo 工程配置
area: infrastructure
status: done
---
## 概述
pnpm workspace 单体仓库基础配置,涵盖包管理、构建脚本和 Node.js 引擎约束。所有 apps/* 和 packages/* 自动纳入 workspace。
## 任务卡
### ✅ 初始化 pnpm workspace
- status: done
- complexity: S
- files: package.json, pnpm-workspace.yaml
- acceptance: pnpm-workspace.yaml 正确声明 apps/* 和 packages/*,根 package.json 包含 dev/build/lint 脚本engines 约束 node>=18 pnpm>=8
### 💭 统一 TypeScript 基础配置
- status: concept
- complexity: S
- files: tsconfig.base.json
- acceptance: 根目录提供 tsconfig.base.json各子包通过 extends 继承,启用 strict 模式
### 💭 统一 ESLint / Prettier 配置
- status: concept
- complexity: S
- files: eslint.config.js, .prettierrc
- acceptance: 根目录提供共享 lint 规则,各子包可通过 overrides 扩展pnpm lint 从根目录一键运行
### 💭 构建工具链选型
- status: concept
- complexity: M
- files: packages/build-config/package.json, packages/build-config/vite.base.ts
- acceptance: 封装 Vite 基础配置到 packages/build-config各 app 通过 extends 引入,减少重复配置
## 决策记录
- 选择 pnpm workspace 而非 Turborepo/Nx初期项目规模小pnpm 原生 workspace 足够,避免引入额外工具链复杂度

View File

@ -0,0 +1,26 @@
---
id: photo-capture
name: 照片采集与管理
area: rn-app
status: planned
---
## 概述
调用设备摄像头或相册为物品条目添加多张照片,照片压缩后存储到 App 专属目录,路径写入 SQLite photos 表。
## 任务卡
### 📋 摄像头调用与图片压缩
- status: todo
- complexity: M
- files: apps/property-survey/src/features/photo/usePhotoCapture.ts
- depends: local-data-layer
- acceptance: 使用 expo-image-picker 提供「拍照」和「从相册选择」两种入口;拍摄/选择后自动压缩至最大宽度 1080px、JPEG quality 0.75;将压缩后的文件复制到 expo-file-system 的 App 专属目录;调用 insertPhoto 写入数据库;全流程有权限检查,拒绝权限时给出提示
### 📋 照片网格预览与删除
- status: todo
- complexity: M
- files: apps/property-survey/src/features/photo/PhotoGrid.tsx, apps/property-survey/src/features/photo/PhotoPicker.tsx
- depends: photo-capture
- acceptance: 以 3 列网格展示已添加的照片缩略图;点击照片全屏预览(支持左右滑动切换);长按照片显示「删除」确认弹窗,删除时同步调用 deletePhoto含文件系统删除末尾显示「+」按钮触发 PhotoPicker 添加更多

View File

@ -0,0 +1,30 @@
---
id: routing
name: 路由与页面结构
area: frontend
status: concept
---
## 概述
基于 React Router 的单页应用路由体系,含懒加载、受保护路由和移动端页面切换动画。
## 任务卡
### 💭 路由基础配置
- status: concept
- complexity: M
- files: apps/app-one/src/router/index.tsx, apps/app-one/src/router/routes.ts
- acceptance: 使用 react-router-dom v6 createBrowserRouter配置首页和 404 页支持代码分割lazy + Suspense
### 💭 受保护路由(需登录)
- status: concept
- complexity: M
- files: apps/app-one/src/router/ProtectedRoute.tsx
- acceptance: 未登录访问受保护路由自动跳转登录页,登录后重定向回原目标页,支持角色权限扩展
### 💭 移动端页面切换动画
- status: concept
- complexity: M
- files: apps/app-one/src/router/PageTransition.tsx
- acceptance: 路由切换时有 slide-in/slide-out 动画,与浏览器前进/后退方向一致,不影响首屏性能

View File

@ -0,0 +1,36 @@
---
id: shared-hooks
name: 共享 React Hooks
area: shared
status: concept
---
## 概述
跨 app 复用的 React 自定义 Hooks以 packages/hooks 形式发布。依赖 React不依赖具体 UI 框架。
## 任务卡
### 💭 搭建 hooks 库骨架
- status: concept
- complexity: S
- files: packages/hooks/package.json, packages/hooks/src/index.ts
- acceptance: packages/hooks 可被 workspace 内任意 React 应用通过 @repo/hooks 引入peer dependency 声明 react
### 💭 数据请求 HookuseRequest
- status: concept
- complexity: M
- files: packages/hooks/src/useRequest.ts
- acceptance: 支持 loading/data/error 三态支持手动触发和依赖自动触发支持取消请求AbortController
### 💭 移动端交互 Hooks
- status: concept
- complexity: M
- files: packages/hooks/src/useTouch.ts, packages/hooks/src/useScrollLock.ts, packages/hooks/src/useVirtualKeyboard.ts
- acceptance: useTouch 处理 swipe 手势useScrollLock 控制 body 滚动useVirtualKeyboard 检测键盘弹出并调整视口
### 💭 持久化状态 HookuseLocalStorage
- status: concept
- complexity: S
- files: packages/hooks/src/useLocalStorage.ts
- acceptance: 封装 useState + localStorage 同步,支持 SSR 安全(无 window 时优雅降级TypeScript 泛型

View File

@ -0,0 +1,30 @@
---
id: shared-types
name: 共享类型定义
area: shared
status: concept
---
## 概述
跨 app 和 packages 共享的 TypeScript 类型定义,以 packages/types 形式发布。纯类型文件,无运行时代码。
## 任务卡
### 💭 搭建类型包骨架
- status: concept
- complexity: S
- files: packages/types/package.json, packages/types/src/index.ts
- acceptance: packages/types 仅包含 .d.ts 或 type-only TS 文件,被引入时不产生任何运行时代码
### 💭 通用业务类型
- status: concept
- complexity: S
- files: packages/types/src/common.ts
- acceptance: 定义 ApiResponse<T>、PaginatedResult<T>、Nullable<T> 等通用泛型类型,供所有 app 和 packages 使用
### 💭 环境与配置类型
- status: concept
- complexity: S
- files: packages/types/src/env.d.ts
- acceptance: 声明 import.meta.env 类型扩展,各 app 的环境变量在 IDE 中有类型提示

View File

@ -0,0 +1,36 @@
---
id: shared-ui
name: 共享 UI 组件库
area: shared
status: concept
---
## 概述
跨 app 复用的 React UI 组件集合,以 packages/ui 形式发布到 workspace 内部。面向移动端适配(触摸友好、响应式)。
## 任务卡
### 💭 搭建组件库骨架
- status: concept
- complexity: M
- files: packages/ui/package.json, packages/ui/src/index.ts, packages/ui/vite.config.ts
- acceptance: packages/ui 可被 apps/* 通过 workspace:* 引入,支持 tree-shaking导出类型声明文件
### 💭 基础原子组件
- status: concept
- complexity: M
- files: packages/ui/src/components/Button.tsx, packages/ui/src/components/Input.tsx, packages/ui/src/components/Card.tsx
- acceptance: Button/Input/Card 组件覆盖常用变体props 类型完整,支持 className 扩展
### 💭 移动端导航组件
- status: concept
- complexity: M
- files: packages/ui/src/components/BottomNav.tsx, packages/ui/src/components/TopBar.tsx
- acceptance: BottomNav 支持图标+文字标签TopBar 支持返回按钮和标题插槽,两者均适配 safe-area-inset
### 💭 反馈类组件Toast / Modal / Loading
- status: concept
- complexity: M
- files: packages/ui/src/components/Toast.tsx, packages/ui/src/components/Modal.tsx, packages/ui/src/components/Loading.tsx
- acceptance: Toast 支持 success/error/info 三种类型Modal 支持受控和非受控Loading 可全屏覆盖

View File

@ -0,0 +1,36 @@
---
id: shared-utils
name: 共享工具函数库
area: shared
status: concept
---
## 概述
跨 app 复用的纯函数工具集,以 packages/utils 形式发布到 workspace 内部。不依赖 React可在任何环境使用。
## 任务卡
### 💭 搭建工具库骨架
- status: concept
- complexity: S
- files: packages/utils/package.json, packages/utils/src/index.ts
- acceptance: packages/utils 可被 workspace 内任意包通过 @repo/utils 引入,导出类型声明文件
### 💭 格式化工具集
- status: concept
- complexity: S
- files: packages/utils/src/format.ts
- acceptance: 提供日期格式化、数字格式化(货币/百分比)、手机号脱敏等常用函数,每个函数有单元测试
### 💭 本地存储工具
- status: concept
- complexity: S
- files: packages/utils/src/storage.ts
- acceptance: 封装 localStorage/sessionStorage支持 JSON 序列化和过期时间TypeScript 泛型推导
### 💭 HTTP 请求工具
- status: concept
- complexity: M
- files: packages/utils/src/request.ts
- acceptance: 基于 fetch 封装,支持请求/响应拦截器、统一错误处理、超时控制,返回类型安全的 Promise

View File

@ -0,0 +1,28 @@
---
id: state-management
name: 全局状态管理
area: frontend
status: concept
---
## 概述
跨组件的全局状态方案覆盖用户会话、UI 状态等场景。轻量优先Zustand避免过度设计。
## 任务卡
### 💭 用户会话 Store
- status: concept
- complexity: M
- files: apps/app-one/src/stores/authStore.ts
- acceptance: 使用 Zustand 管理 user/token/isLoggedIn提供 login/logout actiontoken 持久化到 localStorage
### 💭 全局 UI 状态 Store
- status: concept
- complexity: S
- files: apps/app-one/src/stores/uiStore.ts
- acceptance: 管理全局 loading、toast 消息队列、modal 开关状态,与 packages/ui 的反馈组件联动
## 决策记录
- 选择 Zustand 而非 Redux移动端场景状态相对简单Zustand API 更轻量,无需 boilerplateTypeScript 支持良好

View File

@ -0,0 +1,39 @@
---
id: survey-app-shell
name: 应用外壳与折叠屏布局
area: rn-app
status: planned
---
## 概述
React Native (Expo SDK 52 + Expo Router) 应用骨架,实现 Z Fold 6 折叠/展开双形态布局切换。折叠时单栏显示,展开时左侧地图 + 右侧表单双栏并排。
## 任务卡
### 📋 Expo 应用骨架初始化
- status: todo
- complexity: M
- files: apps/property-survey/app.json, apps/property-survey/package.json, apps/property-survey/app/_layout.tsx, apps/property-survey/app/index.tsx, apps/property-survey/app/summary.tsx
- depends: local-data-layer
- acceptance: `pnpm --filter property-survey start` 能在 Expo Go 或开发构建中启动底部导航可在「登记」和「汇总」两个页面间切换SQLite 数据库在启动时完成初始化
### 📋 折叠屏状态感知 Hook
- status: todo
- complexity: S
- files: apps/property-survey/src/layout/useFoldState.ts
- acceptance: useFoldState 返回 `{ isUnfolded: boolean, windowWidth: number }`,以 720px 为断点区分折叠/展开状态useWindowDimensions 变化时自动更新,在模拟器宽度调整时可观察到状态切换
### 📋 双栏/单栏自适应布局容器
- status: todo
- complexity: M
- files: apps/property-survey/src/layout/FoldableLayout.tsx
- depends: survey-app-shell
- acceptance: 展开时渲染左右两栏(左侧 flexGrow:1 地图区,右侧 380px 详情区),折叠时只渲染左侧(地图全屏),接受 `left``right` 两个 ReactNode 插槽
### 📋 楼层切换标签组件
- status: todo
- complexity: S
- files: apps/property-survey/src/layout/FloorTabs.tsx
- depends: survey-app-shell
- acceptance: 显示 1F / 2F / 3F 三个标签选中项高亮onChange 回调传出当前楼层数字1/2/3组件宽度自适应容器

View File

@ -0,0 +1,30 @@
---
id: theming
name: 主题与样式系统
area: frontend
status: concept
---
## 概述
基于 CSS 变量的主题系统,支持亮色/暗色模式切换,结合 Tailwind CSS 或 CSS Modules 实现统一的视觉风格。
## 任务卡
### 💭 设计 Token 与 CSS 变量
- status: concept
- complexity: S
- files: packages/ui/src/styles/tokens.css
- acceptance: 定义颜色、间距、字体、圆角等设计 token 为 CSS 变量dark 模式通过 prefers-color-scheme 或 [data-theme] 切换
### 💭 主题切换逻辑
- status: concept
- complexity: S
- files: apps/app-one/src/hooks/useTheme.ts
- acceptance: 提供 useTheme hook支持手动切换和跟随系统偏好持久化到 localStorage
### 💭 Tailwind 配置集成
- status: concept
- complexity: S
- files: packages/build-config/tailwind.base.ts, apps/app-one/tailwind.config.ts
- acceptance: 共享 Tailwind 配置,设计 token 与 Tailwind 主题颜色/间距对齐,各 app 可扩展

28
.blueprint/usage.json Normal file
View File

@ -0,0 +1,28 @@
{
"project_name": "react-phone-apps",
"snapshots": [
{
"at": "2026-04-07T06:17:15Z",
"blocked_reasons": [],
"conventions_version": "unknown",
"iteration": 1,
"modules": {
"blocked": 0,
"concept": 9,
"done": 1,
"in_progress": 0,
"planned": 0,
"stalled": [],
"total": 10
},
"tasks": {
"blocked": 0,
"dispatched": 0,
"done": 1,
"in_progress": 0,
"todo": 0,
"total": 32
}
}
]
}

8
.claude/settings.json Normal file
View File

@ -0,0 +1,8 @@
{
"mcpServers": {
"lian-jing:group-da6dc719": {
"type": "http",
"url": "http://localhost:27190/mcp/group/da6dc719"
}
}
}

1
.codemap/main-panel.json Normal file
View File

@ -0,0 +1 @@
[]

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
node_modules/
dist/
.next/
*.log
.env
.env.*
!.env.example
# Windows 保留设备名(误创建的空文件)
/nul

2
.npmrc Normal file
View File

@ -0,0 +1,2 @@
strict-peer-dependencies=false
auto-install-peers=true

0
apps/.gitkeep Normal file
View File

134
fix-scoop-git.ps1 Normal file
View File

@ -0,0 +1,134 @@
Write-Host "修复 Scoop 和 Git 安装..."
$scoopDir = "E:\Scoop"
$appsDir = "$scoopDir\apps"
$shimsDir = "$scoopDir\shims"
# 1. 修复 7zip shim
Write-Host "1. 修复 7zip shim..."
$7zShim = "$shimsDir\7z.shim"
$7zPath = "$appsDir\7zip\25.01\7z.exe"
if (Test-Path $7zPath) {
if (Test-Path $7zShim) {
Set-Content $7zShim "path = `"$7zPath`""
Write-Host " 更新 7z.shim 指向: $7zPath"
} else {
Write-Host " 错误: 7z.shim 不存在"
}
} else {
Write-Host " 错误: 7z.exe 未找到,请先安装 7-zip: scoop install 7zip"
exit 1
}
# 2. 修复 7zip current 符号链接
Write-Host "2. 修复 7zip current 符号链接..."
$7zipCurrent = "$appsDir\7zip\current"
if (-not (Test-Path $7zipCurrent)) {
cmd /c mklink /J "$7zipCurrent" "$appsDir\7zip\25.01" 2>$null
if (Test-Path $7zipCurrent) {
Write-Host " 创建 current 符号链接"
} else {
Write-Host " 警告: 无法创建符号链接,使用绝对路径"
}
} else {
Write-Host " current 符号链接已存在"
}
# 3. 手动提取 Git
Write-Host "3. 手动提取 Git..."
$gitDir = "$appsDir\git\2.53.0.2"
$dl7z = "$gitDir\dl.7z"
if (Test-Path $dl7z) {
Write-Host " 找到 dl.7z: $dl7z"
# 创建目标目录
if (-not (Test-Path $gitDir)) {
New-Item -ItemType Directory -Path $gitDir -Force | Out-Null
}
# 使用 7z 提取
Write-Host " 正在提取文件..."
& $7zPath x "-o$gitDir" "-y" "$dl7z" | Out-Null
if (Test-Path "$gitDir\bin\git.exe") {
Write-Host " 提取成功: git.exe 已存在"
} else {
Write-Host " 警告: 提取可能失败,检查目录内容"
Get-ChildItem $gitDir -Recurse -File | Select-Object -First 10 | ForEach-Object { Write-Host " $_" }
}
} else {
Write-Host " 错误: dl.7z 未找到,请重新下载"
Write-Host " 运行: scoop cache rm git; scoop download git"
exit 1
}
# 4. 创建 Git shims
Write-Host "4. 创建 Git shims..."
# git shim
$gitShim = "$shimsDir\git.shim"
$gitExe = "$gitDir\bin\git.exe"
if (Test-Path $gitExe) {
Set-Content $gitShim "path = `"$gitExe`""
Write-Host " 创建 git.shim"
# 复制 shim 可执行文件
$shimExe = "$shimsDir\git.exe"
if (-not (Test-Path $shimExe)) {
Copy-Item "$shimsDir\7z.exe" $shimExe -ErrorAction SilentlyContinue
if (Test-Path $shimExe) {
Write-Host " 创建 git.exe shim"
}
}
} else {
Write-Host " 错误: git.exe 未找到"
}
# sh (bash) shim
$shShim = "$shimsDir\sh.shim"
$shExe = "$gitDir\bin\sh.exe"
if (Test-Path $shExe) {
Set-Content $shShim "path = `"$shExe`""
Write-Host " 创建 sh.shim"
} else {
Write-Host " 警告: sh.exe 未找到"
}
# git-bash shim
$gitBashShim = "$shimsDir\git-bash.shim"
$gitBashExe = "$gitDir\git-bash.exe"
if (Test-Path $gitBashExe) {
Set-Content $gitBashShim "path = `"$gitBashExe`""
Write-Host " 创建 git-bash.shim"
}
# 5. 更新 PATH 并测试
Write-Host "5. 测试安装..."
$env:Path = "$shimsDir;$env:Path"
Write-Host "`n测试命令:"
try {
$gitVersion = git --version 2>$null
if ($gitVersion) {
Write-Host " ✓ git: $gitVersion"
} else {
Write-Host " ✗ git: 命令失败"
Write-Host " 临时使用: $gitExe"
}
} catch {
Write-Host " ✗ git: 错误: $_"
}
try {
$7zVersion = 7z --help 2>$null | Select-Object -First 1
if ($7zVersion) {
Write-Host " ✓ 7z: 可用"
}
} catch {
Write-Host " ✗ 7z: 错误"
}
Write-Host "`n修复完成!"
Write-Host "如果命令仍然不可用,请重启终端或运行:"
Write-Host " `$env:Path = `"$shimsDir;`$env:Path`""
Write-Host "`n然后测试: git --version"

69
fix-scoop.ps1 Normal file
View File

@ -0,0 +1,69 @@
Write-Host "Fixing Scoop shims for git..."
$scoopDir = "E:\Scoop"
$gitDir = "E:\Scoop\apps\git\2.53.0"
$shimsDir = "E:\Scoop\shims"
Write-Host "1. Checking git installation..."
if (-not (Test-Path "$gitDir\bin\git.exe")) {
Write-Host "ERROR: git.exe not found at $gitDir\bin\git.exe"
exit 1
}
Write-Host " git.exe found"
Write-Host "2. Fixing sh.shim..."
$shShim = "$shimsDir\sh.shim"
if (Test-Path $shShim) {
$content = Get-Content $shShim
if ($content -match "current") {
Set-Content $shShim 'path = "E:\Scoop\apps\git\2.53.0\bin\sh.exe"'
Write-Host " Updated sh.shim to use absolute path"
} else {
Write-Host " sh.shim already uses absolute path"
}
} else {
Write-Host " ERROR: sh.shim not found"
}
Write-Host "3. Creating git shim..."
$gitShim = "$shimsDir\git.shim"
if (-not (Test-Path $gitShim)) {
Set-Content $gitShim 'path = "E:\Scoop\apps\git\2.53.0\bin\git.exe"'
Write-Host " Created git.shim"
} else {
Write-Host " git.shim already exists"
}
Write-Host "4. Creating git.exe shim executable..."
$gitExe = "$shimsDir\git.exe"
if (-not (Test-Path $gitExe)) {
$sourceShim = "$shimsDir\7z.exe"
if (Test-Path $sourceShim) {
Copy-Item $sourceShim $gitExe
Write-Host " Copied 7z.exe to git.exe"
} else {
Write-Host " ERROR: No source shim executable found"
}
} else {
Write-Host " git.exe already exists"
}
Write-Host "5. Testing git command..."
$env:Path = "$shimsDir;$env:Path"
try {
git --version
Write-Host " SUCCESS: git command works!"
} catch {
Write-Host " WARNING: git command may not work directly, but you can use full path: $gitDir\bin\git.exe"
}
Write-Host "6. Testing sh command..."
try {
sh --version
Write-Host " SUCCESS: sh command works!"
} catch {
Write-Host " WARNING: sh command may not work"
}
Write-Host "`nFix complete. If commands still don't work, try restarting your terminal or running:"
Write-Host " . `$env:Path = `"E:\Scoop\shims;`$env:Path`""

49
init-git.ps1 Normal file
View File

@ -0,0 +1,49 @@
Write-Host "初始化 Git 仓库..."
# 检查是否已经是 Git 仓库
if (Test-Path .git) {
Write-Host "✓ 已经是 Git 仓库"
git status
exit 0
}
# 初始化 Git
Write-Host "初始化 Git 仓库..."
git init
# 配置用户信息(如果未设置)
$gitUser = git config --global user.name
$gitEmail = git config --global user.email
if (-not $gitUser) {
Write-Host "提示: 请设置 Git 用户信息:"
Write-Host " git config --global user.name 'Your Name'"
Write-Host " git config --global user.email 'your.email@example.com'"
}
# 添加文件
Write-Host "添加文件到暂存区..."
git add .
# 检查是否有文件被添加
$staged = git status --porcelain
if (-not $staged) {
Write-Host "警告: 没有文件被添加到暂存区,可能是 .gitignore 过滤了所有文件"
Write-Host "查看当前状态:"
git status
exit 0
}
# 创建初始提交
Write-Host "创建初始提交..."
git commit -m "Initial commit: React phone apps project"
Write-Host "`n✓ Git 仓库初始化完成!"
Write-Host "当前分支: $(git branch --show-current)"
Write-Host "提交记录:"
git log --oneline -3
Write-Host "`n下一步:"
Write-Host "1. 连接到远程仓库: git remote add origin <repository-url>"
Write-Host "2. 推送到远程: git push -u origin main"
Write-Host "3. 查看状态: git status"

13
package.json Normal file
View File

@ -0,0 +1,13 @@
{
"name": "react-phone-apps",
"private": true,
"scripts": {
"dev": "pnpm -r --filter './apps/**' dev",
"build": "pnpm -r --filter './apps/**' build",
"lint": "pnpm -r lint"
},
"engines": {
"node": ">=18",
"pnpm": ">=8"
}
}

0
packages/.gitkeep Normal file
View File

9
pnpm-lock.yaml generated Normal file
View File

@ -0,0 +1,9 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.: {}

3
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,3 @@
packages:
- 'apps/*'
- 'packages/*'

35
test.ps1 Normal file
View File

@ -0,0 +1,35 @@
Write-Host "Testing git installation..."
$gitPath = "E:\Scoop\apps\git\2.53.0\bin\git.exe"
if (Test-Path $gitPath) {
Write-Host "Git executable exists at: $gitPath"
& $gitPath --version
} else {
Write-Host "Git executable not found"
}
Write-Host "`nChecking current symlink..."
$currentLink = "E:\Scoop\apps\git\current"
if (Test-Path $currentLink) {
Write-Host "Current link exists"
$target = Get-Item $currentLink | Select-Object -ExpandProperty Target
Write-Host "Current link target: $target"
} else {
Write-Host "Current link does not exist"
}
Write-Host "`nChecking sh.exe..."
$shPath = "E:\Scoop\apps\git\current\bin\sh.exe"
if (Test-Path $shPath) {
Write-Host "sh.exe exists at: $shPath"
} else {
Write-Host "sh.exe not found at: $shPath"
}
Write-Host "`nChecking shim..."
$shimPath = "E:\Scoop\shims\sh.shim"
if (Test-Path $shimPath) {
Write-Host "sh.shim exists"
Get-Content $shimPath
} else {
Write-Host "sh.shim not found"
}

61
修复Git安装步骤.txt Normal file
View File

@ -0,0 +1,61 @@
修复 Scoop Git 安装步骤
请在新终端CMD 或 PowerShell中逐条执行以下命令
1. 检查并修复 7zip shim
打开文件 E:\Scoop\shims\7z.shim确保内容为
path = "E:\Scoop\apps\7zip\25.01\7z.exe"
如果不同,请编辑或运行:
echo path = "E:\Scoop\apps\7zip\25.01\7z.exe" > "E:\Scoop\shims\7z.shim"
2. 创建 7zip current 符号链接
以管理员身份运行 CMD执行
mklink /J "E:\Scoop\apps\7zip\current" "E:\Scoop\apps\7zip\25.01"
如果无法创建符号链接,可以直接跳过此步,但需确保后续使用绝对路径。
3. 手动提取 Git 安装包
在 PowerShell 中执行:
& "E:\Scoop\apps\7zip\25.01\7z.exe" x "E:\Scoop\apps\git\2.53.0.2\dl.7z" -o"E:\Scoop\apps\git\2.53.0.2" -y
等待提取完成。
4. 检查提取结果
执行:
dir "E:\Scoop\apps\git\2.53.0.2"
应该看到 bin、cmd、etc 等目录。
5. 创建 Git shim 文件
创建 E:\Scoop\shims\git.shim
echo path = "E:\Scoop\apps\git\2.53.0.2\bin\git.exe" > "E:\Scoop\shims\git.shim"
创建 shim 可执行文件:
copy "E:\Scoop\shims\7z.exe" "E:\Scoop\shims\git.exe"
6. 创建 sh (bash) shim
echo path = "E:\Scoop\apps\git\2.53.0.2\bin\sh.exe" > "E:\Scoop\shims\sh.shim"
7. 创建 git-bash shim
echo path = "E:\Scoop\apps\git\2.53.0.2\git-bash.exe" > "E:\Scoop\shims\git-bash.shim"
8. 更新 PATH 环境变量(临时)
在 PowerShell 中执行:
$env:Path = "E:\Scoop\shims;$env:Path"
9. 测试安装
执行:
git --version
sh --version
如果显示版本信息,则安装成功。
10. 永久添加 PATH可选
将 E:\Scoop\shims 添加到系统 PATH 环境变量:
[Environment]::SetEnvironmentVariable("Path", "E:\Scoop\shims;" + [Environment]::GetEnvironmentVariable("Path", "User"), "User")
重启终端使更改生效。
如果仍有问题,可以临时使用完整路径:
E:\Scoop\apps\git\2.53.0.2\bin\git.exe