docs(private): 完善私有化部署开发计划和设计规范

- 增加实时进度和交接规则,定义任务状态枚举和更新格式
- 创建任务进度台账,涵盖P0-P5阶段全部开发任务
- 补充部署仓库交付边界确认和进度审计规范
- 完善MySQL/Redis双模式支持,增加external/managed选项
- 增加离线部署、安全治理、可观测性等完整交付能力
- 更新仓库结构设计,增加secrets.env、observability、data目录
- 补充健康检查、诊断脚本、升级回滚、备份恢复详细要求
- 优化应用商店审核状态查询逻辑,增加手动刷新接口
- 修复小米和VIVO商店状态查询中的版本匹配逻辑错误
- 增加缓存键版本隔离,防止不同版本状态混淆
- 优化厂商API连通性检查和审核状态轮询机制
这个提交包含在:
XuqmGroup 2026-05-18 19:00:38 +08:00
父节点 b77ccc663a
当前提交 a1e4d5741b
共有 2 个文件被更改,包括 48 次插入2 次删除

查看文件

@ -368,6 +368,13 @@ export const updateAdminApi = {
) )
}, },
refreshStoreReviewStatus(versionId: string) {
return updateClient.post<{ data: PreflightSubmitResultDto }>(
`/api/v1/updates/store/app/${versionId}/refresh-review-status`,
{},
)
},
deleteAppVersion(versionId: string) { deleteAppVersion(versionId: string) {
return updateClient.delete<{ data: null }>(`/api/v1/updates/app/${versionId}`) return updateClient.delete<{ data: null }>(`/api/v1/updates/app/${versionId}`)
}, },

查看文件

@ -564,10 +564,10 @@
<span v-else class="text-muted"></span> <span v-else class="text-muted"></span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="状态" width="120"> <el-table-column label="状态" width="160">
<template #default="{row}"> <template #default="{row}">
<el-tag :type="preflightTagType(row.reviewState)" size="small"> <el-tag :type="preflightTagType(row.reviewState)" size="small">
{{ preflightStateLabel(row.reviewState) }} {{ row.nonCurrentRelease ? '已上线(非本次发布)' : preflightStateLabel(row.reviewState) }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
@ -697,6 +697,12 @@
<el-empty v-else description="暂无商店状态数据" /> <el-empty v-else description="暂无商店状态数据" />
<template #footer> <template #footer>
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;"> <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
<el-button
type="primary"
plain
:loading="refreshingReviewStatus"
@click="handleRefreshReviewStatus()"
>刷新厂商状态</el-button>
<el-button <el-button
v-if="storeReviewDetailItems.some(i => isActiveState(i.state))" v-if="storeReviewDetailItems.some(i => isActiveState(i.state))"
type="danger" type="danger"
@ -1574,6 +1580,7 @@ type StoreReviewItem = {
const storeReviewDetailItems = ref<StoreReviewItem[]>([]) const storeReviewDetailItems = ref<StoreReviewItem[]>([])
const storeReviewDetailLive = ref(false) const storeReviewDetailLive = ref(false)
const cancellingReview = ref(false) const cancellingReview = ref(false)
const refreshingReviewStatus = ref(false)
const retryingStores = ref<Set<string>>(new Set()) const retryingStores = ref<Set<string>>(new Set())
const showPublishSchedule = ref(false) const showPublishSchedule = ref(false)
const publishScheduleType = ref<'IMMEDIATE' | 'SCHEDULED'>('IMMEDIATE') const publishScheduleType = ref<'IMMEDIATE' | 'SCHEDULED'>('IMMEDIATE')
@ -1629,6 +1636,38 @@ async function handleCancelReview(storeType?: string) {
} }
} }
async function handleRefreshReviewStatus() {
if (!storeReviewDetailVersion.value) return
refreshingReviewStatus.value = true
try {
const res = await updateAdminApi.refreshStoreReviewStatus(storeReviewDetailVersion.value.id)
const result = res.data.data
if (result && result.stores) {
// Merge refreshed states into the detail items
for (const s of result.stores) {
const idx = storeReviewDetailItems.value.findIndex(i => i.store === s.storeType)
if (idx >= 0) {
// Re-parse the row's storeReviewStatus to get updated fields from DB
const row = appVersions.value.find(v => v.id === storeReviewDetailVersion.value!.id)
if (row) {
const parsed = parseStoreReview(row.storeReviewStatus)
const updated = parsed.find(p => p.store === s.storeType)
if (updated) {
storeReviewDetailItems.value[idx] = updated
}
}
}
}
}
await loadAppVersions()
ElMessage.success('厂商状态已刷新')
} catch {
ElMessage.error('刷新失败,请稍后重试')
} finally {
refreshingReviewStatus.value = false
}
}
async function handleRetryStore(storeType: string) { async function handleRetryStore(storeType: string) {
if (!storeReviewDetailVersion.value) return if (!storeReviewDetailVersion.value) return
retryingStores.value = new Set([...retryingStores.value, storeType]) retryingStores.value = new Set([...retryingStores.value, storeType])