feat: 采集失败KOC补交截图闭环 + 任务中心分发详情弹窗
公开数据补交闭环(F1): - distributions 新增 public_metrics_screenshot_key(mysql/0022 迁移) - KOC 门户:链接已回填但采集失败时展示补交数据截图入口(kind=public-metrics) - 运营端:回收队列"核对补录"支持公开互动数据(赞/藏/评),按补交截图补录后采集状态置成功 - 企微催办:采集失败纳入待办(公开数据待补交) - task-result-image 支持 kind=publish 输出发布截图 门户文案(F2): - 自动采集数据明确"由系统每天自动采集,无需你填写",仅识别失败时才手动填写曝光/阅读 任务中心分发详情: - 任务中心/数据回收的分发表行可点击,弹窗查看详情 - 详情按任务类型适配:发布阶段/数据回收(自动采集)/创作者数据(第7天)/截图回收四区块三段式布局
This commit is contained in:
@@ -1683,6 +1683,28 @@ footer {
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
/* 公开数据自动采集状态行:让 KOC 明白数据不用每天手动填 */
|
||||
.auto-collect-line {
|
||||
margin: 10px 0 0;
|
||||
padding: 8px 11px;
|
||||
border-radius: 8px;
|
||||
background: #e9f5f0;
|
||||
border: 1px solid #cdeade;
|
||||
color: #27775b;
|
||||
font-size: 8px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 公开数据补交(采集失败兜底)区块 */
|
||||
.metrics-fallback {
|
||||
border-top-color: #f3c6cf;
|
||||
}
|
||||
|
||||
.metrics-fallback .creator-recovery-heading > span {
|
||||
background: #ffeef1;
|
||||
color: #be123c;
|
||||
}
|
||||
|
||||
.screenshot-picker.compact {
|
||||
min-height: 96px;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,12 @@ type Assignment = {
|
||||
ocr_status: string;
|
||||
exposure: number | null;
|
||||
views: number | null;
|
||||
collection_status?: string | null;
|
||||
latest_likes?: number | null;
|
||||
latest_comments?: number | null;
|
||||
latest_collects?: number | null;
|
||||
collection_updated_at?: string | null;
|
||||
public_metrics_screenshot_key?: string | null;
|
||||
title: string;
|
||||
body: string;
|
||||
source_row: number | null;
|
||||
@@ -460,6 +466,7 @@ export default function Home() {
|
||||
const [creatorScreenshot, setCreatorScreenshot] = useState<File | null>(null);
|
||||
const [creatorExposure, setCreatorExposure] = useState("");
|
||||
const [creatorViews, setCreatorViews] = useState("");
|
||||
const [publicMetricsShot, setPublicMetricsShot] = useState<File | null>(null);
|
||||
const [entryMode, setEntryMode] = useState<"claim" | "recover">("claim");
|
||||
const [recoveredClaims, setRecoveredClaims] = useState<RecoveredClaim[]>([]);
|
||||
const [wecomIdentity, setWecomIdentity] = useState<WecomPortalIdentity | null>(
|
||||
@@ -485,6 +492,7 @@ export default function Home() {
|
||||
const batchWorkbookInputRef = useRef<HTMLInputElement | null>(null);
|
||||
const publishScreenshotPreview = useFilePreview(screenshot);
|
||||
const creatorScreenshotPreview = useFilePreview(creatorScreenshot);
|
||||
const publicMetricsPreview = useFilePreview(publicMetricsShot);
|
||||
const taskResultPreviews = useMemo(
|
||||
() =>
|
||||
taskResultScreenshots.map((file) => ({
|
||||
@@ -678,6 +686,7 @@ export default function Home() {
|
||||
setScreenshot(null);
|
||||
setTaskResultScreenshots([]);
|
||||
setCreatorScreenshot(null);
|
||||
setPublicMetricsShot(null);
|
||||
setCreatorExposure(
|
||||
selected.exposure === null ? "" : String(selected.exposure),
|
||||
);
|
||||
@@ -844,6 +853,36 @@ export default function Home() {
|
||||
return `${adminOrigin}/api/partner-image?${params}`;
|
||||
};
|
||||
|
||||
const publicMetricsImageUrl = () => {
|
||||
if (!selected) return "";
|
||||
const params = new URLSearchParams({
|
||||
distribution: selected.id,
|
||||
index: "1",
|
||||
kind: "public-metrics",
|
||||
});
|
||||
if (delegationToken) params.set("share", delegationToken);
|
||||
else {
|
||||
params.set("task", taskToken);
|
||||
params.set("claim", claimToken);
|
||||
}
|
||||
return `${adminOrigin}/api/partner-image?${params}`;
|
||||
};
|
||||
|
||||
const submitPublicMetricsShot = async () => {
|
||||
if (!selected || !publicMetricsShot) return;
|
||||
try {
|
||||
setWorking(true);
|
||||
await uploadEvidence(selected, publicMetricsShot, "public-metrics");
|
||||
setPublicMetricsShot(null);
|
||||
await loadTask(taskToken, claimToken, delegationToken);
|
||||
setToast("数据截图已补交,运营核对后会补录公开数据");
|
||||
} catch (reason) {
|
||||
setToast(reason instanceof Error ? reason.message : "数据截图上传失败");
|
||||
} finally {
|
||||
setWorking(false);
|
||||
}
|
||||
};
|
||||
|
||||
const evidenceImageUrl = (
|
||||
item: Assignment,
|
||||
kind: "publish" | "creator",
|
||||
@@ -1207,7 +1246,7 @@ export default function Home() {
|
||||
const uploadEvidence = async (
|
||||
selectedItem: Assignment,
|
||||
file: File,
|
||||
kind: "publish" | "creator-center" | "task-result",
|
||||
kind: "publish" | "creator-center" | "task-result" | "public-metrics",
|
||||
): Promise<{ exposure?: number | null; views?: number | null; ocrStatus?: string }> => {
|
||||
const compressed = await compressScreenshot(file);
|
||||
const headers: Record<string, string> = {
|
||||
@@ -1678,6 +1717,85 @@ export default function Home() {
|
||||
{selected.publish_time && (
|
||||
<p className="submitted-at">上次回填:{formatDate(selected.publish_time, true)}</p>
|
||||
)}
|
||||
{selected.publish_url && selected.collection_status === "failed" && (
|
||||
<section className="creator-recovery metrics-fallback">
|
||||
<div className="creator-recovery-heading">
|
||||
<div>
|
||||
<p className="micro">公开数据补交</p>
|
||||
<h3>自动采集失败,请补交数据截图</h3>
|
||||
</div>
|
||||
<span className={selected.public_metrics_screenshot_key ? "done" : ""}>
|
||||
{selected.public_metrics_screenshot_key ? "已补交,待核对" : "待补交"}
|
||||
</span>
|
||||
</div>
|
||||
<p className="creator-recovery-tip">
|
||||
系统自动采集这篇笔记的公开数据失败了。请打开笔记页面,
|
||||
截一张包含点赞、收藏、评论数字的截图上传,运营核对后会补录数据。
|
||||
</p>
|
||||
<div className="evidence-field compact-field">
|
||||
<span>数据截图</span>
|
||||
<div
|
||||
className={`screenshot-picker compact ${
|
||||
publicMetricsShot || selected.public_metrics_screenshot_key
|
||||
? "has-file preview-mode"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{publicMetricsShot || selected.public_metrics_screenshot_key ? (
|
||||
<button
|
||||
type="button"
|
||||
className="evidence-preview-button compact-preview"
|
||||
onClick={() =>
|
||||
setPreviewImage({
|
||||
src:
|
||||
publicMetricsPreview ||
|
||||
publicMetricsImageUrl(),
|
||||
alt: "公开数据截图",
|
||||
})
|
||||
}
|
||||
>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={publicMetricsPreview || publicMetricsImageUrl()}
|
||||
alt="公开数据截图"
|
||||
/>
|
||||
<span>点击查看大图</span>
|
||||
</button>
|
||||
) : (
|
||||
<div className="evidence-empty-state">
|
||||
<b>+</b>
|
||||
<strong>点击上传笔记数据页截图</strong>
|
||||
<small>需包含点赞、收藏、评论数字,最大8MB</small>
|
||||
</div>
|
||||
)}
|
||||
<label className="evidence-upload-action">
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={(event) =>
|
||||
setPublicMetricsShot(event.target.files?.[0] ?? null)
|
||||
}
|
||||
/>
|
||||
{publicMetricsShot || selected.public_metrics_screenshot_key
|
||||
? "重新选择"
|
||||
: "选择图片"}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="creator-submit"
|
||||
disabled={!publicMetricsShot || working}
|
||||
onClick={() => void submitPublicMetricsShot()}
|
||||
>
|
||||
{working
|
||||
? "正在上传…"
|
||||
: selected.public_metrics_screenshot_key
|
||||
? "更新数据截图"
|
||||
: "提交数据截图"}
|
||||
</button>
|
||||
</section>
|
||||
)}
|
||||
{selected.publish_url && (
|
||||
<section className="creator-recovery">
|
||||
<div className="creator-recovery-heading">
|
||||
@@ -1689,8 +1807,23 @@ export default function Home() {
|
||||
{creatorDataReady ? "已提交" : "待提交"}
|
||||
</span>
|
||||
</div>
|
||||
{selected.latest_likes !== null &&
|
||||
selected.latest_likes !== undefined ? (
|
||||
<p className="auto-collect-line">
|
||||
公开数据系统自动采集中:赞 {selected.latest_likes ?? "—"} · 藏{" "}
|
||||
{selected.latest_collects ?? "—"} · 评 {selected.latest_comments ?? "—"}
|
||||
{selected.collection_updated_at
|
||||
? `(${formatDate(selected.collection_updated_at, true)})`
|
||||
: ""}
|
||||
,无需你填写。
|
||||
</p>
|
||||
) : (
|
||||
<p className="auto-collect-line">
|
||||
点赞、收藏、评论等公开数据由系统每天自动采集,无需你填写。
|
||||
</p>
|
||||
)}
|
||||
<p className="creator-recovery-tip">
|
||||
请在发布满7天后,上传创作者中心数据页完整截图,并填写页面显示的数据。
|
||||
这一步只需做一次:发布满7天后,上传创作者中心数据页截图,系统自动识别曝光量和阅读量;仅当识别失败时才需要手动填写这两个数字。
|
||||
{creatorDueAt && ` 建议上传日期:${formatDate(creatorDueAt)}。`}
|
||||
</p>
|
||||
<div className="evidence-field compact-field">
|
||||
@@ -1772,6 +1905,9 @@ export default function Home() {
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<small className="task-result-hint">
|
||||
两个数字一般由截图自动识别填入;只有识别失败时才需要手动修改。
|
||||
</small>
|
||||
<button
|
||||
type="button"
|
||||
className="creator-submit"
|
||||
|
||||
Reference in New Issue
Block a user