fix(creator): 权限开通后的状态显示 + 同步范围可选可查
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s

- 权限显示:实测今天 display/status 已变成 1,但 tip 是「数据正在更新中,请耐心等待」,
  作品仍是 0 条。原逻辑只在未开通时显示提示条,于是会一边写着「数据已开通」一边列不出
  作品,自相矛盾。现在只要后台有话要说就显示,并按状态区分措辞。
- 同步范围:原本写死 90 天,界面上既看不见也改不了。现在可选 7/30/90/180/365/730 天,
  与后端校验上限一致。
- 新增 creator_account.last_sync_days,记录上次实际使用的范围 —— 否则界面只能说
  「同步过了」,说不清覆盖的是哪一段。选择器也会对齐到它,避免上次同步 1 年、这次
  点一下悄悄缩回 90 天。
This commit is contained in:
2026-10-08 07:52:28 +08:00
parent bef0a4fbde
commit fa227600fe
4 changed files with 79 additions and 11 deletions
+3
View File
@@ -73,6 +73,9 @@ class CreatorAccount(MonitorBase):
last_checked_at: Mapped[Optional[int]] = mapped_column(BigInteger)
last_synced_at: Mapped[Optional[int]] = mapped_column(BigInteger)
# 上次同步用的时间范围(天,按发布时间)。当前展示的数据就是这个范围的产物 ——
# 不记下来的话,界面只能说明"同步过了",说不清是哪一段。
last_sync_days: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
last_error: Mapped[Optional[str]] = mapped_column(Text)
created_at: Mapped[int] = mapped_column(BigInteger, nullable=False)
+3
View File
@@ -64,6 +64,7 @@ def _account_dict(account: CreatorAccount, note_count: int = 0) -> Dict[str, Any
"permission_tip": account.permission_tip,
"last_checked_at": account.last_checked_at,
"last_synced_at": account.last_synced_at,
"last_sync_days": account.last_sync_days,
"last_error": account.last_error,
"has_cookie": bool(account.cookie),
"created_at": account.created_at,
@@ -344,6 +345,7 @@ async def sync_account(
)
account.last_synced_at = now
account.last_sync_days = days
account.last_error = None
account.updated_at = now
await refresh_permission(session, account)
@@ -352,6 +354,7 @@ async def sync_account(
return {
"account_id": account_id,
"fetched": len(collected),
"days": days,
"permission_status": account.permission_status,
"permission_tip": account.permission_tip,
}
+71 -11
View File
@@ -1,4 +1,4 @@
import { useState } from 'react'
import { useEffect, useState } from 'react'
import {
AlertTriangle,
Briefcase,
@@ -11,6 +11,13 @@ import {
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import {
useCheckCreatorAccount,
useCreatorAccount,
@@ -33,6 +40,17 @@ const PERMISSION_LABEL: Record<CreatorPermissionStatus, { text: string; tone: st
unknown: { text: '权限未知', tone: 'text-cyber-text-muted' },
}
// 后台按**发布时间**筛选,所以这是"作品发布距今多少天",不是"最近多少天的数据"。
// 上限 730 天与后端校验一致。
const RANGE_OPTIONS = [
{ value: '7', label: '近 7 天' },
{ value: '30', label: '近 30 天' },
{ value: '90', label: '近 90 天' },
{ value: '180', label: '近 180 天' },
{ value: '365', label: '近 1 年' },
{ value: '730', label: '近 2 年' },
]
const SUMMARY_TILES: Array<{ key: keyof CreatorNote; label: string }> = [
{ key: 'exposure', label: '曝光' },
{ key: 'views', label: '观看' },
@@ -112,6 +130,16 @@ function AccountPanel({ accountId }: { accountId: number }) {
const sync = useSyncCreatorAccount()
const check = useCheckCreatorAccount()
const remove = useDeleteCreatorAccount()
// 拉取范围是**同步参数**,不是展示筛选:数据按这个范围取回来存库。
// 默认 90 天,与后端的默认值一致。
const [days, setDays] = useState('90')
// 选择器对齐到上次实际用的范围。不对齐的话,上次同步了 1 年、这次点同步会悄悄
// 缩回 90 天,而界面上没有任何迹象。
const lastDays = data?.account.last_sync_days ?? 0
useEffect(() => {
if (lastDays > 0) setDays(String(lastDays))
}, [lastDays])
if (isLoading || !data) {
return <p className="py-10 text-center text-[11px] font-mono text-cyber-text-muted">加载中…</p>
@@ -139,6 +167,9 @@ function AccountPanel({ accountId }: { accountId: number }) {
</span>
<span className="ml-1 text-[10px] font-mono text-cyber-text-muted">
上次同步 {account.last_synced_at ? formatRelative(account.last_synced_at) : '从未'}
{/* 当前列出的作品就是上一次同步范围里的产物,所以要说清是哪一段 ——
否则只看"同步过了"分不清覆盖了多少。 */}
{account.last_sync_days > 0 && ` · 覆盖近 ${account.last_sync_days} 天发布的`}
</span>
<div className="ml-auto flex items-center gap-2">
@@ -151,7 +182,23 @@ function AccountPanel({ accountId }: { accountId: number }) {
<RefreshCw className={`w-3 h-3 mr-1 ${check.isPending ? 'animate-spin' : ''}`} />
检测
</Button>
<Button size="sm" disabled={sync.isPending} onClick={() => sync.mutate({ id: account.id })}>
<Select value={days} onValueChange={setDays}>
<SelectTrigger className="h-7 w-[104px] text-[10px] font-mono">
<SelectValue />
</SelectTrigger>
<SelectContent>
{RANGE_OPTIONS.map((option) => (
<SelectItem key={option.value} value={option.value} className="text-[11px]">
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
<Button
size="sm"
disabled={sync.isPending}
onClick={() => sync.mutate({ id: account.id, days: Number(days) })}
>
<RefreshCw className={`w-3 h-3 mr-1 ${sync.isPending ? 'animate-spin' : ''}`} />
同步数据
</Button>
@@ -162,18 +209,31 @@ function AccountPanel({ accountId }: { accountId: number }) {
</div>
<div className="flex-1 overflow-y-auto terminal-scroll px-3 py-3 space-y-3">
{/* 权限状态必须显眼:它解释了"为什么没有数据"。后台的原话照抄,不改写。 */}
{account.permission_status !== 'active' && (
<div className="flex items-start gap-2 rounded-md border border-cyber-neon-orange/30 bg-cyber-neon-orange/5 px-3 py-2">
<Clock className="w-3.5 h-3.5 mt-0.5 flex-shrink-0 text-cyber-neon-orange" />
{/* 只要后台有话要说就显示,**包括已经开通的时候**。
实测开通后的原话是「数据正在更新中,请耐心等待」—— 若只在未开通时才显示,
就会一边写着"数据已开通"、一边列不出作品,自相矛盾。 */}
{account.permission_tip && (
<div
className={`flex items-start gap-2 rounded-md border px-3 py-2 ${
account.permission_status === 'active'
? 'border-cyber-border-DEFAULT bg-cyber-bg-tertiary/40'
: 'border-cyber-neon-orange/30 bg-cyber-neon-orange/5'
}`}
>
<Clock
className={`w-3.5 h-3.5 mt-0.5 flex-shrink-0 ${
account.permission_status === 'active'
? 'text-cyber-text-muted'
: 'text-cyber-neon-orange'
}`}
/>
<div className="text-[11px] font-mono leading-relaxed">
<span className={permission.tone}>{permission.text}</span>
{account.permission_tip && (
<span className="ml-2 text-cyber-text-secondary">{account.permission_tip}</span>
)}
<span className="ml-2 text-cyber-text-secondary">{account.permission_tip}</span>
<div className="mt-0.5 text-cyber-text-muted">
数据权限由创作者后台按天开通。在此之前同步会成功但返回 0 条 —— 那是正常的,
不是采集失败。
{account.permission_status === 'active'
? '权限已开通,但后台的数据可能还在准备中 —— 稍后重新同步即可。'
: '数据权限由创作者后台按天开通。在此之前同步会成功但返回 0 条 —— 那是正常的,不是采集失败。'}
</div>
</div>
</div>
+2
View File
@@ -23,6 +23,8 @@ export interface CreatorAccount {
permission_tip: string
last_checked_at: number | null
last_synced_at: number | null
/** 上次同步用的范围(天)。0 表示从未同步过。 */
last_sync_days: number
last_error: string | null
has_cookie: boolean
created_at: number