fix(t209): retain login inputs after failure

This commit is contained in:
QiuSW
2026-07-27 16:03:08 +08:00
parent f99744e2ed
commit 5782c3088d
4 changed files with 38 additions and 18 deletions
@@ -358,9 +358,7 @@ class MainActivity : ComponentActivity() {
state = procurementState,
readiness = readiness,
onLogin = { input: LoginInput ->
lifecycleScope.launch {
procurementRepository.login(input)
}
procurementRepository.login(input)
},
onClaim = {
lifecycleScope.launch {
@@ -34,6 +34,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -50,12 +51,13 @@ import com.roubao.autopilot.readiness.DeviceReadinessSnapshot
import com.roubao.autopilot.ui.theme.BaoziTheme
import java.time.Instant
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@Composable
fun ProcurementScreen(
state: ProcurementUiState,
readiness: DeviceReadinessSnapshot,
onLogin: (LoginInput) -> Unit,
onLogin: suspend (LoginInput) -> Boolean,
onClaim: () -> Unit,
onStart: (ExecutionMode) -> Unit,
onRelease: () -> Unit,
@@ -260,9 +262,10 @@ private fun ExecutionModeSelector(
@Composable
private fun LoginSection(
state: ProcurementUiState,
onLogin: (LoginInput) -> Unit
onLogin: suspend (LoginInput) -> Boolean
) {
val colors = BaoziTheme.colors
val coroutineScope = rememberCoroutineScope()
var backendUrl by remember(state.profile.backendUrl) {
mutableStateOf(state.profile.backendUrl)
}
@@ -274,6 +277,7 @@ private fun LoginSection(
mutableStateOf(state.profile.deviceId)
}
var deviceToken by remember { mutableStateOf("") }
var submitting by remember { mutableStateOf(false) }
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
Text(
@@ -329,19 +333,28 @@ private fun LoginSection(
)
Button(
onClick = {
onLogin(
LoginInput(
if (!submitting) {
val input = LoginInput(
backendUrl = backendUrl,
username = username,
password = password,
deviceId = deviceId,
deviceToken = deviceToken
)
)
password = ""
deviceToken = ""
submitting = true
coroutineScope.launch {
try {
if (onLogin(input)) {
password = ""
deviceToken = ""
}
} finally {
submitting = false
}
}
}
},
enabled = !state.busy,
enabled = !state.busy && !submitting,
modifier = Modifier.fillMaxWidth()
) {
Icon(Icons.Filled.Lock, contentDescription = null)
+6 -2
View File
@@ -5,7 +5,8 @@
## 当前快照
- 日期:2026-07-27
- 阶段:T-207 App 本地 VLM、候选、证据和结果回传完成,下一步 T-208
- 阶段:T-207 App 本地 VLM、候选、证据和结果回传完成;T-209 登录失败保留输入完成,
下一步 T-208
- Git:当前分支为 `main`;T-001 至 T-004、T-101 至 T-104、T-201 至 T-206
均已纳入 Git 历史;T-207 待本次提交
- 生产代码:`android-buyer/` 已接入 Roubao Android 源码
@@ -40,6 +41,8 @@
状态、严格 HTTPS/Debug loopback 地址策略、`HttpTaskSource`、参考图校验、手动领取、
预览/start 二次确认、release、30 秒前台 heartbeat、有限离线、`SAFE_STOPPED`、
取消确认和进程恢复;后台任务不读取或覆盖本地 VLM provider
- 登录重试:采购登录失败、本地校验失败或网络失败时保留当前页面输入,只有成功才清理
Compose 内存中的密码和设备密钥;敏感值不新增持久化或日志路径
- T-207 结果闭环:`execution_events`、受控截图、候选批次、模型出处、人工结论与
失败记录均按 execution 存储;Android 使用加密 outbox 按事件、截图、候选和终态
顺序回传,授权到期补报单独审计,所有终态固定 `order_submitted=false`。管理任务
@@ -91,6 +94,7 @@
| `docs/tasks/T-205.md` | DONE | 原子 claim、租约、execution 和取消安全确认 |
| `docs/tasks/T-206.md` | DONE | App 领取、默认 30 分钟有限离线执行、恢复和安全停止 |
| `docs/tasks/T-207.md` | DONE | App 本地 VLM、Key 加密、候选、事件、截图和结果回传 |
| `docs/tasks/T-209.md` | DONE | 登录失败保留采购员和设备输入以便直接重试 |
| `docs/design/` | 已确认 | T-202 原型索引、4 个管理页和 7 个 Android 页面 |
| `deepseek总结.txt` | 已有 | 历史讨论摘要,不是正式需求权威 |
| `android-buyer/` | 已有 | Roubao `main` 固定 commit 的 Android 基线 |
@@ -101,7 +105,7 @@
## 任务摘要
- 已完成:T-001 至 T-004、T-101 至 T-104、T-201 至 T-207。
- 已完成:T-001 至 T-004、T-101 至 T-104、T-201 至 T-207、T-209。
- 正在进行:无。
- 下一个可领取任务:T-208 候选决策数据与人工理由闭环。
- 后置任务:T-208 候选决策数据与人工理由闭环;不得跳过 T-206/T-207 提前实现。
+10 -5
View File
@@ -4,7 +4,7 @@ title: 保留失败采购登录的已填写凭证
phase: 2
deps:
- T-206
status: TODO
status: DONE
created: 2026-07-27
context_ref: d86a88e
work_branch: null
@@ -34,10 +34,10 @@ write_paths:
## 验收要点
- [ ] 服务端拒绝、网络失败和本地校验失败后,五个已填写字段可直接修改并重试。
- [ ] 成功登录后不保留登录页敏感输入,设备密钥只进入既有加密存储。
- [ ] 密码和设备密钥不进入日志、普通 Preferences 或错误文案。
- [ ] Android 单元测试与 Debug 构建通过。
- [x] 服务端拒绝、网络失败和本地校验失败后,五个已填写字段可直接修改并重试。
- [x] 成功登录后不保留登录页敏感输入,设备密钥只进入既有加密存储。
- [x] 密码和设备密钥不进入日志、普通 Preferences 或错误文案。
- [x] Android 单元测试与 Debug 构建通过。
## 边界
@@ -47,3 +47,8 @@ write_paths:
## 执行记录
- 2026-07-27:任务已登记,待实现。
- 2026-07-27:登录 UI 改为等待 Repository 布尔结果;失败时保留 Compose 内存中的
后台地址、账号、密码、设备 ID 和设备密钥,成功才清理敏感输入。新增本地提交锁,
防止请求尚未开始时重复点击。
- 2026-07-27:`./gradlew.bat :app:compileDebugKotlin :app:testDebugUnitTest
:app:assembleDebug` 通过;最新 Debug APK 已安装并冷启动至 PKG110,无 crash/ANR。