From f917e5bfd67bdb864dfd5f6ee70ef267684e861b Mon Sep 17 00:00:00 2001 From: Liuxinyu176 <1041316040@qq.com> Date: Sat, 10 Oct 2026 02:34:27 +0800 Subject: [PATCH] =?UTF-8?q?fix(wb):=20=E5=9B=BD=E9=99=85=E7=89=88=E6=97=A0?= =?UTF-8?q?=E7=8B=AC=E7=AB=8B=E7=AD=BE=E5=88=B0=E6=B4=BB=E5=8A=A8=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E5=86=8D=E8=B0=83=20daily-checkin=EF=BC=8C=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E9=A1=B5=E5=B1=95=E7=A4=BA=E8=AF=B4=E6=98=8E=E5=8D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/WorkBuddyRepository.kt | 46 +++++++++++++++-- .../ui/servicedetail/ServiceDetailScreen.kt | 51 +++++++++++++++---- app/src/main/res/values-b+zh+Hans/strings.xml | 3 ++ app/src/main/res/values-b+zh+Hant/strings.xml | 3 ++ app/src/main/res/values/strings.xml | 3 ++ 5 files changed, 92 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/rainy/token/data/repository/WorkBuddyRepository.kt b/app/src/main/java/com/rainy/token/data/repository/WorkBuddyRepository.kt index 5da36eb..bd04cba 100644 --- a/app/src/main/java/com/rainy/token/data/repository/WorkBuddyRepository.kt +++ b/app/src/main/java/com/rainy/token/data/repository/WorkBuddyRepository.kt @@ -459,7 +459,9 @@ private fun parseResourceDetail(body: String): Map? { /** 今日已签到(幂等) */ ALREADY, /** 签到失败(服务端给了原因,见 message) */ - FAILED + FAILED, + /** 国际站无签到活动(活动未开启/未上线,非错误) */ + NO_CAMPAIGN } /** @@ -486,6 +488,12 @@ private fun parseResourceDetail(body: String): Map? { if (credential !is Credential.WorkBuddyCredential) { return@withContext Result.failure(RepositoryError.InvalidCredential()) } + // 国际版没有独立签到档案:积分来自网页/客户端活跃使用,直接返回“无活动”。 + if (credential.isIntlRegion()) { + return@withContext Result.success( + CheckinStatus(false, false, 0, 0, 0, "", "", CheckinOutcome.NO_CAMPAIGN) + ) + } // 两条候选路径 fallback(cpa-plugin 实测:activity-status 优先,旧路径 checkin-status 兜底) // 共享轮换状态:前一条路径轮换出的新 token 会用于下一条,且失败也先落库。 val body = authedPostFirstSuccessful( @@ -517,6 +525,12 @@ private fun parseResourceDetail(body: String): Map? { if (credential !is Credential.WorkBuddyCredential) { return@withContext Result.failure(RepositoryError.InvalidCredential()) } + // 国际版不调用 daily-checkin(无签到营业),直接按无活动处理,避免每次刷新都报错。 + if (credential.isIntlRegion()) { + return@withContext Result.success( + CheckinStatus(false, false, 0, 0, 0, "", "", CheckinOutcome.NO_CAMPAIGN) + ) + } val body = when (val r = authedPost(credential, "/v2/billing/meter/daily-checkin")) { is AuthedPostResult.Ok -> { persistCheckinOutcome(credential, accountId, r.rotatedCredential) @@ -550,8 +564,15 @@ private fun parseResourceDetail(body: String): Map? { ?: (r["data"] as? JsonObject)?.scalar("msg", "message", "Message") }.getOrNull().orEmpty() val status = fetchCheckinStatus(accountId).getOrNull() - // 已签到语义与上游 cpa-multi-plugins 对齐:code=10001 或文案含「已签/今日/already」。 val lowerMsg = msg.lowercase() + // 国际站无签到活动:接口可能返回 data.active=false 或「活动未开启/已过期」。 + val inactive = runCatching { + val r = json.parseToJsonElement(body).jsonObject + ((r["data"] as? JsonObject)?.get("active") as? JsonPrimitive)?.contentOrNull?.equals("false", true) == true + }.getOrDefault(false) + val noCampaign = inactive || msg.contains("活动未开启") || msg.contains("已过期") || + lowerMsg.contains("not active") + // 已签到语义与上游 cpa-multi-plugins 对齐:code=10001 或文案含「已签/今日/already」。 val already = code == 10001L || msg.contains("已签") || msg.contains("已经签到") || msg.contains("今日") || lowerMsg.contains("already") || lowerMsg.contains("checked") || lowerMsg.contains("claimed") @@ -566,6 +587,12 @@ private fun parseResourceDetail(body: String): Map? { outcome = CheckinOutcome.SUCCESS ) ) + noCampaign -> Result.success( + (status ?: CheckinStatus(false, false, 0, 0, 0, "")).copy( + message = msg, + outcome = CheckinOutcome.NO_CAMPAIGN + ) + ) already -> Result.success( (status ?: CheckinStatus(true, true, 0, 0, 0, "")).copy( outcome = CheckinOutcome.ALREADY @@ -617,8 +644,21 @@ private fun parseResourceDetail(body: String): Map? { val request = Request.Builder() .url(credential.originBase() + path) .addHeader("Authorization", "Bearer " + access) - .addHeader("Accept", "application/json") + .addHeader("Accept", "application/json, text/plain, */*") .addHeader("Content-Type", "application/json") + .addHeader("User-Agent", "CLI/2.63.2 CodeBuddy/2.63.2") + .addHeader("Origin", credential.originBase()) + .addHeader("Referer", credential.originBase() + "/profile/growth-center") + .addHeader("X-CodeBuddy-Request", "1") + .addHeader("Accept-Language", if (credential.isIntlRegion()) "en-US" else "zh-CN") + .apply { + if (credential.isIntlRegion()) { + addHeader("X-Domain", "www.workbuddy.ai") + addHeader("X-No-Enterprise-Id", "1") + } else { + addHeader("X-No-Enterprise-Id", "1") + } + } .post("{}".toRequestBody(jsonMedia)) .build() val resp = try { diff --git a/app/src/main/java/com/rainy/token/ui/servicedetail/ServiceDetailScreen.kt b/app/src/main/java/com/rainy/token/ui/servicedetail/ServiceDetailScreen.kt index b68dadc..544a946 100644 --- a/app/src/main/java/com/rainy/token/ui/servicedetail/ServiceDetailScreen.kt +++ b/app/src/main/java/com/rainy/token/ui/servicedetail/ServiceDetailScreen.kt @@ -265,17 +265,23 @@ fun ServiceDetailScreen( } } ServiceType.WORKBUDDY -> { - item { - if (uiState.hasCredential) { - CheckinCard( - state = checkinState, - todayCheckedIn = checkinInfo?.todayCheckedIn == true, - streakDays = checkinInfo?.streakDays ?: 0L, - isTrae = false, - onCheckin = { viewModel.checkin() } - ) - } else { - CheckinNeedCredentialCard() + val wbIntl = uiState.region != null && uiState.region.equals("INTL", ignoreCase = true) + if (wbIntl) { + // 国际版没有独立签到体系:积分来自网页/客户端活跃使用,直接展示说明卡 + item { WorkBuddyIntlNoCheckinCard() } + } else { + item { + if (uiState.hasCredential) { + CheckinCard( + state = checkinState, + todayCheckedIn = checkinInfo?.todayCheckedIn == true, + streakDays = checkinInfo?.streakDays ?: 0L, + isTrae = false, + onCheckin = { viewModel.checkin() } + ) + } else { + CheckinNeedCredentialCard() + } } } // 资源明细(资源 ID 美化为「资源 #007」+ 余额;套餐/冻结/付费信息归账户信息) @@ -1801,6 +1807,29 @@ private fun TraeIntlNoCheckinCard() { } } +@Composable +private fun WorkBuddyIntlNoCheckinCard() { + Card( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(20.dp), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), + elevation = CardDefaults.cardElevation(defaultElevation = 0.dp) + ) { + Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(4.dp)) { + Text( + text = stringResource(R.string.wb_intl_no_checkin_title), + style = MaterialTheme.typography.titleSmall, + fontWeight = FontWeight.SemiBold + ) + Text( + text = stringResource(R.string.wb_intl_no_checkin_desc), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.outline + ) + } + } +} + @Composable internal fun WorkBuddyResourcesCard(state: State) { val balance = when (state) { diff --git a/app/src/main/res/values-b+zh+Hans/strings.xml b/app/src/main/res/values-b+zh+Hans/strings.xml index d996177..51663ff 100644 --- a/app/src/main/res/values-b+zh+Hans/strings.xml +++ b/app/src/main/res/values-b+zh+Hans/strings.xml @@ -228,6 +228,7 @@ 签到成功 今日已签到 今日已签到(连签 %1$d 天) + 暂无可领取的签到活动 签到失败,请检查凭据 该服务不支持签到 今日已签到 @@ -801,6 +802,8 @@ 充值 / 升级 套餐 基础用量已用 +国际版无独立签到 + WorkBuddy 国际版积分来自网页/客户端活跃使用,没有独立签到活动。 国际版没有每日签到 Trae 国际版按美元计费,使用月度请求额度,没有签到积分体系。 月配额 diff --git a/app/src/main/res/values-b+zh+Hant/strings.xml b/app/src/main/res/values-b+zh+Hant/strings.xml index 40e61b3..237ae7b 100644 --- a/app/src/main/res/values-b+zh+Hant/strings.xml +++ b/app/src/main/res/values-b+zh+Hant/strings.xml @@ -228,6 +228,7 @@ 簽到成功 今日已簽到 今日已簽到(連簽 %1$d 天) + 暫無可領取的簽到活動 簽到失敗,請檢查憑證 該服務不支援簽到 今日已簽到 @@ -801,6 +802,8 @@ 儲值 / 升級 套餐 基礎用量已用 +國際版無獨立簽到 + WorkBuddy 國際版積分來自網頁/客戶端活躍使用,沒有獨立簽到活動。 國際版沒有每日簽到 Trae 國際版按美元計費,使用月度請求額度,沒有簽到積分體系。 月額度 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 59f6e38..8e5150b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -231,6 +231,7 @@ Check-in successful Already checked in today Already checked in (streak %1$d days) + No active check-in campaign Check-in failed, please check credentials This service does not support check-in Checked in today @@ -806,6 +807,8 @@ Upgrade / Top up Plan Basic usage used +No daily check-in on international + WorkBuddy international credits are earned through active usage, not a check-in campaign. International edition has no daily check-in TRAE International uses USD billing with monthly request quotas instead of credit check-ins. Monthly quota