Guard the news detail panel against stale responses and load errors

The detail is now a persistent side panel, so quick clicks can interleave
requests: only the latest request's result is applied, and a failed load
shows an error state with a retry button instead of spinning forever.

Also correct the position history comments: only plans from before plan
3.1 could hand their position over to a replacing plan.
This commit is contained in:
eezd committed 2026-10-16 11:05:18 +08:00
1 parent fb63ebb697
commit a2e51a3011
3 files changed
+32 -7

No files matched your search

+1 -1
View File
@@ -149,7 +149,7 @@ class PositionHistoryOut(BaseModel):
opened_at: datetime
closed_at: datetime
close_reason: str
# 本计划的入场成交;计划被替换时持仓由新计划接管,新计划没有自己的入场成交,这两项为空
# 本计划的入场成交。计划 3.1 之前,替换计划时持仓会交给新计划接管(如 #8),这类旧记录没有自己的入场成交,这两项为空
quantity: Decimal | None
entry_price: Decimal | None
# 止盈、止损、市价平仓的成交均价;外部平仓(如网页手动平仓)没有成交记录,为空
+1 -1
View File
@@ -275,7 +275,7 @@ export interface PositionHistory {
opened_at: string
closed_at: string
close_reason: string
/** 计划被替换后接管持仓的新计划没有自己的入场成交,为空 */
/** 计划 3.1 之前替换计划时会接管旧计划的持仓,这类旧记录没有自己的入场成交,为空 */
quantity: string | null
entry_price: string | null
/** 外部平仓没有成交记录,为空 */
+30 -5
View File
@@ -13,16 +13,36 @@ const revisions = ref<Revision[]>([])
const activeTab = ref("content")
// 当前查看的修订序号,与上一版对比
const selectedRevision = ref<number>()
// 加载失败(错误提示已由 http 拦截器弹出):停止转圈,显示重试
const failed = ref(false)
// 连续点击不同新闻时,只采用最后一次请求的结果
let requestSeq = 0
watch(() => props.newsId, async (id) => {
if (id == null)
return
activeTab.value = "content"
detail.value = undefined
async function load(id: number) {
const seq = ++requestSeq
failed.value = false
try {
const [news, revs] = await Promise.all([getNews(id), listRevisions(id)])
if (seq !== requestSeq)
return
detail.value = news
revisions.value = revs
selectedRevision.value = revs[0]?.revision_no
} catch (error) {
if (seq === requestSeq)
failed.value = true
throw error
}
}
watch(() => props.newsId, (id) => {
activeTab.value = "content"
detail.value = undefined
revisions.value = []
if (id == null)
requestSeq++
else
load(id)
})
// 第三方正文放进无脚本权限的 sandbox iframe,避免其中的脚本访问本站
@@ -110,6 +130,11 @@ const diffStats = computed(() => ({
</el-tab-pane>
</el-tabs>
</template>
<el-empty v-else-if="failed" description="加载失败" class="m-auto">
<el-button type="primary" @click="load(newsId)">
重试
</el-button>
</el-empty>
<div v-else v-loading="true" class="h-full" />
</el-card>
</template>