Commit Graph
5 Commits
Author SHA1 Message Date
steven b3cd115bd9 feat(design): 主色由墨松绿改为景泰蓝蓝系,Logo 与图标同步
CI / backend (push) Canceled after 0s
纸白底改冷调与主色同轴;语义色 sage/wheat/rust 不变,sky 提亮与主色区分。Logo 三段线改浅蓝白、圆点改亮蓝;favicon/PWA 图标/安卓自适应图标/状态栏一并重绘,新增 tools/make-icons.py 作为唯一出处。
2026-11-01 18:48:26 +08:00
dadao 0a3b0f3ca0 fix(android): 真机登录不上——明文流量被网络配置拦住,且地址写死在模拟器网段
CI / backend (push) Canceled after 0s
用户反馈"app 端登录不上去"。查下来是两个叠在一起的问题,都不是"后台没开":

1) 主清单设了 android:networkSecurityConfig(白名单只有 10.0.2.2 / 127.0.0.1 / localhost),
   而它的优先级高于 debug 清单里的 android:usesCleartextTraffic="true"。
   所以真机连 http://192.168.8.x:8100 会被系统拦成 CLEARTEXT communication not permitted,
   表现成登录无反应;模拟器因为地址在白名单里,一切正常,很容易误判。
   → 新增 app/src/debug/res/xml/network_security_config.xml,debug 放开明文;
     release 仍只有白名单,线上必须 HTTPS。

2) 后端地址编译期写死 BuildConfig.API_BASE = http://10.0.2.2:8100,那是模拟器专用地址。
   → 登录页加「服务器:… / 改地址」:可改、可「测试连接」、存在 TokenStore 里,
     改一次就记住,不用重新打包。地址缺失协议时自动补 http://。

顺带把网络异常翻成人话:以前 OkHttp 抛 IOException 原样冒到界面,
现在统一成「连不上 <地址> —— 具体该去查什么」,并区分了
"10.0.2.2 是模拟器地址"、"127.0.0.1 在手机上指的是手机自己"两种情况;
连不上时自动展开地址面板。

后端这边没有代码改动,但真机要用 --host 0.0.0.0 启动(原来只监听 127.0.0.1),
已写进 DEVELOPMENT.md 与 android/README.md,附防火墙放行命令。

实测:模拟器内把地址改成 http://192.168.8.151:8100 → 测试连接「连得通」→
取码(开发环境验证码回显)→ 登录成功进入工作区列表。
2026-10-28 23:38:21 +08:00
dadao f683436689 feat(android): 安卓端第一次真跑起来,修两个联调才暴露的解析 bug
CI / backend (push) Canceled after 0s
上一轮只是"能编译"。这一轮在模拟器上真装了、真登录、真点了,才发现两个问题:

1. workspaces() / members() 直接按 List 解析,但服务端列表接口返回的是
   {"items": [...]}。表现就是登录成功后首页红字「响应格式异常(HTTP 200)」,
   而且工作区永远显示为空。新增 WorkspacePage / MemberPage 容器类型。
2. 之前 Api.kt 的请求体全是没加 @Serializable 的普通 data class(上一提交已修),
   这次把成员/工作区的解析也按同样思路收口。

环境侧(写进 android/README + 新增 android/scripts/emulator.ps1):
- sdkmanager 拉不到远端索引,系统镜像是直连 dl.google.com 手动装的;
  压缩包里多一层 x86_64/,要把内容提上一层,否则 AGP 找不到 system.img
- AVD 放工程内(~/.android 受限不可写),建 AVD 与启动都靠 ANDROID_USER_HOME / ANDROID_AVD_HOME
- 无头启动要 -no-window -gpu swiftshader_indirect
- 点按坐标要拿 uiautomator dump 的 bounds,别拿降采样截图猜
- adb shell input text 打不了中文(NPE),中文数据走接口或直接写库

验证(模拟器 API 35,连 fnsvr-01 的真库):
登录 → 建工作区 ShipFast → 任务列表显示 4 条中文任务(状态、截止日都对)
→ 勾选完成,条目从「进行中」消失(乐观锁生效)→ 工单页、知识页均正常渲染。
截图放进 2.Design/screens/android-{login,tasks}.png。
2026-10-28 17:04:35 +08:00
dadao 4565fad255 chore(android): 让安卓端第一次真正编译出 APK
CI / backend (push) Canceled after 0s
之前安卓代码一行都没编译过,这次从零把编译链搭起来,第一遍编译就炸了 5 处。

代码 bug(5 个):
- Api.kt 的 SmsRequest/LoginRequest/WorkspaceCreateRequest/RefreshRequest 都没加
  @Serializable,json.encodeToString(x) 于是匹配到 encodeToString(strategy, value) 重载,
  报 "SerializationStrategy<T> expected" + "No value passed for parameter 'value'"
- 三处 mapOf/buildMap 拼请求体(Map<String, Any>)没法序列化,全换成具名 @Serializable 请求类
- ticketAction 的 body 参数从 Map<String, Any> 改成 String,避免把序列化责任散在调用方
- KnowledgeScreen 的 Card(Modifier, onClick=…) 命中无点击的重载,参数重名报错,
  改成 Card(onClick=…, modifier=…)
- 补 import kotlinx.serialization.encodeToString

环境固化(写进仓库,附理由注释,避免下次重踩):
- gradle.properties 加 kotlin.compiler.execution.strategy=in-process
  (受限环境里 Kotlin 编译守护进程连不回来)
- settings.gradle.kts 先走阿里云镜像再回落 google()/mavenCentral(),依赖下载从 5 分钟 2MB 变 90 秒 94MB
- 工程内 debug keystore(android/keystore/debug.keystore)+ app/build.gradle.kts 显式指向
  (受限用户对 ~/.android 无写权限,用系统默认 debug.keystore 会 AccessDenied)
- app/src/debug/AndroidManifest.xml 给 debug 变体放开明文 HTTP:
  真机连 http://192.168.8.x:8100 需要它,release 仍受 network_security_config 白名单约束
- android/README.md 换成实测过的构建/安装说明 + 坑表

结果:BUILD SUCCESSFUL,app-debug.apk 9.94 MB。
未验证:本机没有 system-image、也没连设备,所以只到"能编译、能装",没跑过界面。
2026-10-28 15:35:47 +08:00
Steven 0c53aa7062 feat(m0): 后端骨架 + Web/安卓前端骨架 + 设计文档
- backend: FastAPI 应用工厂、统一错误信封、JWT、短信登录、工作区/成员/邀请、幂等中间件
- alembic 0001: workspace/member/invitation/audit_log/app_user + RLS 策略 + 双角色 GRANT
- tests: 认证/工作区/租户隔离/幂等 四组用例(尚未在本机执行)
- web: React18+Vite 骨架(登录、工作区、邀请落地页)
- android: Compose 骨架(登录、工作区列表)
- 2.Design: PRODUCT-PLAN / ROADMAP-M0-M1 / NAMING / DEVELOPMENT
2026-10-28 02:38:53 +08:00