fix(t209): retain login inputs after failure
This commit is contained in:
@@ -358,9 +358,7 @@ class MainActivity : ComponentActivity() {
|
||||
state = procurementState,
|
||||
readiness = readiness,
|
||||
onLogin = { input: LoginInput ->
|
||||
lifecycleScope.launch {
|
||||
procurementRepository.login(input)
|
||||
}
|
||||
},
|
||||
onClaim = {
|
||||
lifecycleScope.launch {
|
||||
|
||||
+19
-6
@@ -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
|
||||
)
|
||||
)
|
||||
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)
|
||||
|
||||
@@ -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
@@ -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。
|
||||
|
||||
Reference in New Issue
Block a user