feat: AI 审核自动驳回 + 功效词可配置 + UI 修复
- AI 自动驳回:法规/品牌安全 HIGH 违规或总分<40 自动打回上传阶段 - 功效词可配置:从硬编码改为品牌方在规则页面自行管理 - 驳回通知:AI 驳回时只通知达人,含具体原因 - 达人端:脚本/视频页面展示 AI 驳回原因 + 重新上传入口 - 规则页面:新增"功效词"分类 - 种子数据:新增 6 条默认功效词 - 其他:代理商管理下拉修复、AI 配置模型列表扩展、视觉模型标签修正、规则编辑放开限制 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
0ef7650c09
commit
0b3dfa3c52
@@ -35,6 +35,8 @@ type ScriptTaskUI = {
|
||||
brandName: string
|
||||
scriptStatus: string
|
||||
scriptFile: string | null
|
||||
aiAutoRejected?: boolean
|
||||
aiRejectReason?: string
|
||||
aiResult: null | {
|
||||
score: number
|
||||
dimensions?: ReviewDimensions
|
||||
@@ -56,8 +58,11 @@ type BriefUI = {
|
||||
function mapApiToScriptUI(task: TaskResponse): ScriptTaskUI {
|
||||
const stage = task.stage
|
||||
let status = 'pending_upload'
|
||||
const aiAutoRejected = task.script_ai_result?.ai_auto_rejected === true
|
||||
switch (stage) {
|
||||
case 'script_upload': status = 'pending_upload'; break
|
||||
case 'script_upload':
|
||||
status = aiAutoRejected ? 'ai_rejected' : 'pending_upload'
|
||||
break
|
||||
case 'script_ai_review': status = 'ai_reviewing'; break
|
||||
case 'script_agency_review': status = 'agent_reviewing'; break
|
||||
case 'script_brand_review': status = 'brand_reviewing'; break
|
||||
@@ -99,6 +104,8 @@ function mapApiToScriptUI(task: TaskResponse): ScriptTaskUI {
|
||||
brandName: task.project?.brand_name || '',
|
||||
scriptStatus: status,
|
||||
scriptFile: task.script_file_name || null,
|
||||
aiAutoRejected,
|
||||
aiRejectReason: task.script_ai_result?.ai_reject_reason,
|
||||
aiResult,
|
||||
agencyReview,
|
||||
brandReview,
|
||||
@@ -596,7 +603,7 @@ export default function CreatorScriptPage() {
|
||||
|
||||
const getStatusDisplay = () => {
|
||||
const map: Record<string, string> = {
|
||||
pending_upload: '待上传脚本', ai_reviewing: 'AI 审核中', ai_result: 'AI 审核完成',
|
||||
pending_upload: '待上传脚本', ai_rejected: 'AI 审核未通过', ai_reviewing: 'AI 审核中', ai_result: 'AI 审核完成',
|
||||
agent_reviewing: '代理商审核中', agent_rejected: '代理商驳回',
|
||||
brand_reviewing: '品牌方终审中', brand_passed: '审核通过', brand_rejected: '品牌方驳回',
|
||||
}
|
||||
@@ -622,6 +629,23 @@ export default function CreatorScriptPage() {
|
||||
<AgencyBriefSection toast={toast} briefData={briefData} />
|
||||
|
||||
{task.scriptStatus === 'pending_upload' && <UploadSection taskId={taskId} onUploaded={loadTask} />}
|
||||
{task.scriptStatus === 'ai_rejected' && (
|
||||
<>
|
||||
<Card className="border-accent-coral/30 bg-accent-coral/5">
|
||||
<CardContent className="py-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<XCircle size={20} className="text-accent-coral mt-0.5 flex-shrink-0" />
|
||||
<div>
|
||||
<p className="text-text-primary font-medium">AI 审核未通过,请修改后重新上传</p>
|
||||
{task.aiRejectReason && <p className="text-sm text-text-secondary mt-1">{task.aiRejectReason}</p>}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<AIResultSection task={task} />
|
||||
<UploadSection taskId={taskId} onUploaded={loadTask} />
|
||||
</>
|
||||
)}
|
||||
{task.scriptStatus === 'ai_reviewing' && <AIReviewingSection />}
|
||||
{task.scriptStatus === 'ai_result' && <><AIResultSection task={task} /><WaitingSection message="等待代理商审核" /></>}
|
||||
{task.scriptStatus === 'agent_reviewing' && <><AIResultSection task={task} /><WaitingSection message="等待代理商审核" /></>}
|
||||
|
||||
@@ -22,6 +22,8 @@ type VideoTaskUI = {
|
||||
brandName: string
|
||||
videoStatus: string
|
||||
videoFile: string | null
|
||||
aiAutoRejected?: boolean
|
||||
aiRejectReason?: string
|
||||
aiResult: null | {
|
||||
score: number
|
||||
hardViolations: Array<{ type: string; content: string; timestamp: number; suggestion: string }>
|
||||
@@ -36,8 +38,9 @@ type VideoTaskUI = {
|
||||
function mapApiToVideoUI(task: TaskResponse): VideoTaskUI {
|
||||
const stage = task.stage
|
||||
let status = 'pending_upload'
|
||||
const aiAutoRejected = task.video_ai_result?.ai_auto_rejected === true
|
||||
switch (stage) {
|
||||
case 'video_upload': status = 'pending_upload'; break
|
||||
case 'video_upload': status = aiAutoRejected ? 'ai_rejected' : 'pending_upload'; break
|
||||
case 'video_ai_review': status = 'ai_reviewing'; break
|
||||
case 'video_agency_review': status = 'agent_reviewing'; break
|
||||
case 'video_brand_review': status = 'brand_reviewing'; break
|
||||
@@ -80,6 +83,8 @@ function mapApiToVideoUI(task: TaskResponse): VideoTaskUI {
|
||||
brandName: task.project?.brand_name || '',
|
||||
videoStatus: status,
|
||||
videoFile: task.video_file_name || null,
|
||||
aiAutoRejected,
|
||||
aiRejectReason: task.video_ai_result?.ai_reject_reason,
|
||||
aiResult,
|
||||
agencyReview,
|
||||
brandReview,
|
||||
@@ -371,7 +376,7 @@ export default function CreatorVideoPage() {
|
||||
|
||||
const getStatusDisplay = () => {
|
||||
const map: Record<string, string> = {
|
||||
pending_upload: '待上传视频', ai_reviewing: 'AI 审核中', ai_result: 'AI 审核完成',
|
||||
pending_upload: '待上传视频', ai_rejected: 'AI 审核未通过', ai_reviewing: 'AI 审核中', ai_result: 'AI 审核完成',
|
||||
agent_reviewing: '代理商审核中', agent_rejected: '代理商驳回',
|
||||
brand_reviewing: '品牌方终审中', brand_passed: '审核通过', brand_rejected: '品牌方驳回',
|
||||
}
|
||||
@@ -395,6 +400,23 @@ export default function CreatorVideoPage() {
|
||||
<Card><CardContent className="py-4"><ReviewSteps steps={getReviewSteps(task.videoStatus)} /></CardContent></Card>
|
||||
|
||||
{task.videoStatus === 'pending_upload' && <UploadSection taskId={taskId} onUploaded={loadTask} />}
|
||||
{task.videoStatus === 'ai_rejected' && (
|
||||
<>
|
||||
<Card className="border-accent-coral/30 bg-accent-coral/5">
|
||||
<CardContent className="py-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<XCircle size={20} className="text-accent-coral mt-0.5 flex-shrink-0" />
|
||||
<div>
|
||||
<p className="text-text-primary font-medium">视频 AI 审核未通过,请修改后重新上传</p>
|
||||
{task.aiRejectReason && <p className="text-sm text-text-secondary mt-1">{task.aiRejectReason}</p>}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<AIResultSection task={task} />
|
||||
<UploadSection taskId={taskId} onUploaded={loadTask} />
|
||||
</>
|
||||
)}
|
||||
{task.videoStatus === 'ai_reviewing' && <AIReviewingSection />}
|
||||
{task.videoStatus === 'ai_result' && <><AIResultSection task={task} /><WaitingSection message="等待代理商审核" /></>}
|
||||
{task.videoStatus === 'agent_reviewing' && <><AIResultSection task={task} /><WaitingSection message="等待代理商审核" /></>}
|
||||
|
||||
Reference in New Issue
Block a user