feat: 推送新闻前进行异常确认
This commit is contained in:
parent
227688be25
commit
17b0348ca6
@ -550,4 +550,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-count-normal {
|
||||
color:rgba(87, 148, 247, 1);
|
||||
}
|
||||
.modal-count-warning {
|
||||
color:rgba(255, 0, 4, 0.85);
|
||||
}
|
@ -152,5 +152,18 @@
|
||||
"title_generated_time": "Time stamp",
|
||||
"title_operation": "",
|
||||
"title_thumb": "Cover"
|
||||
},
|
||||
"modal": {
|
||||
"warning": "Warning",
|
||||
"push_article": {
|
||||
"content_normal": "<span class=\"modal-count-normal\">{{count}}</span> news are selected, do you want to transfer them into videos?",
|
||||
"content_normal_single": "<span class=\"modal-count-normal\">{{count}}</span> news is selected. Do you want to transfer it to a video?",
|
||||
"content_error": "<span class=\"modal-count-normal\">{{count}}</span> news are selected, and metahuman contents are too short in the news below. Do you want to transfer them to videos?",
|
||||
"content_error_single": "<span class=\"modal-count-normal\">{{count}}</span> news is selected, and the metahuman content is too short in this news. Do you want to transfer it to a video?",
|
||||
"error_title": "Abnormal news",
|
||||
"action_cancel": "Cancel",
|
||||
"action_skip": "Skip the news",
|
||||
"action_all": "Still generating"
|
||||
}
|
||||
}
|
||||
}
|
@ -152,5 +152,18 @@
|
||||
"title_generated_time": "生成时间",
|
||||
"title_operation": "操作",
|
||||
"title_thumb": "缩略图"
|
||||
},
|
||||
"modal": {
|
||||
"warning": "操作提示",
|
||||
"push_article": {
|
||||
"content_normal": "已选中<span class=\"modal-count-normal\">{{count}}</span>条新闻,是否全部生成?",
|
||||
"content_normal_single": "已选中<span class=\"modal-count-normal\">{{count}}</span>条新闻,是否生成?",
|
||||
"content_error": "已选中<span class=\"modal-count-normal\">{{count}}</span>条新闻,<span class=\"modal-count-warning\">{{error_count}}</span>条新闻数字人播报字数过少,是否生成全部<span class=\"modal-count-normal\">{{count}}</span>条视频?",
|
||||
"content_error_single": "已选中<span class=\"modal-count-normal\">{{count}}</span>条新闻,<span class=\"modal-count-warning\">{{error_count}}</span>条新闻数字人播报字数过少,是否生成全部<span class=\"modal-count-normal\">{{count}}</span>条视频?",
|
||||
"error_title": "异常新闻",
|
||||
"action_cancel": "全部取消",
|
||||
"action_skip": "跳过异常新闻",
|
||||
"action_all": "全部生成"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +1,44 @@
|
||||
import React, {useState} from "react";
|
||||
import {showErrorToast, showToast} from "@/components/message.ts";
|
||||
import {push2video} from "@/service/api/article.ts";
|
||||
import {IconArrowRight} from "@/components/icons";
|
||||
import {Modal, Space, Button} from "antd";
|
||||
import {useNavigate} from "react-router-dom";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {useSetState} from "ahooks";
|
||||
|
||||
import {showErrorToast, showToast} from "@/components/message.ts";
|
||||
import {push2video} from "@/service/api/article.ts";
|
||||
import {IconArrowRight, IconWarningCircle} from "@/components/icons";
|
||||
|
||||
export default function ButtonPush2Video(props: { ids: Id[]; onSuccess?: () => void; }) {
|
||||
export enum ProcessResult {
|
||||
All,
|
||||
Skip,
|
||||
Cancel
|
||||
}
|
||||
|
||||
type PushVideoProps = {
|
||||
ids: Id[];
|
||||
articles?: ListArticleItem[];
|
||||
onResult?: (result: ProcessResult, errorIds: Id[]) => void;
|
||||
}
|
||||
export default function ButtonPush2Video(props: PushVideoProps) {
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [state, setState] = useSetState<{
|
||||
modalVisible?: boolean;
|
||||
errorTitle?: string[];
|
||||
errorIds: Id[]
|
||||
}>({
|
||||
errorIds: []
|
||||
})
|
||||
const {t} = useTranslation()
|
||||
const navigate = useNavigate()
|
||||
const handlePush = () => {
|
||||
const handlePush = (action: ProcessResult) => {
|
||||
setLoading(true)
|
||||
push2video(props.ids).then(() => {
|
||||
const skip = action === ProcessResult.Skip && state.errorIds.length > 0
|
||||
const ids = !skip ? props.ids : props.ids.filter(id => !state.errorIds.includes(id));
|
||||
push2video(ids).then(() => {
|
||||
if (skip) {
|
||||
props.onResult?.(ProcessResult.Skip, state.errorIds || [])
|
||||
return;
|
||||
}
|
||||
showToast(t('news.push_stream_success'), 'success')
|
||||
navigate('/create?state=push-success', {
|
||||
state: 'push-success'
|
||||
@ -22,18 +48,64 @@ export default function ButtonPush2Video(props: { ids: Id[]; onSuccess?: () => v
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
// double check 25-02-15 https://pu7y37y121.feishu.cn/docx/FwRrddAFWotRZlxgbr5cP7b6nud
|
||||
// 1.normal 数字人播报部分有内容,不少于50字;或者数字人播报部分无内容
|
||||
// 2.error 数字人播报部分有内容,但是少于50字
|
||||
const checkArticleContent = () => {
|
||||
const errors: string[] = [], ids: Id[] = [];
|
||||
|
||||
props.articles?.filter(s => {
|
||||
return props.ids.includes(s.id) && (s.metahuman_text && s.metahuman_text.length < 50)
|
||||
}).forEach(s => {
|
||||
errors.push(s.title)
|
||||
ids.push(s.id)
|
||||
})
|
||||
return {errors, ids}
|
||||
}
|
||||
|
||||
const onPushClick = () => {
|
||||
if (loading) return;
|
||||
if (props.ids.length === 0) {
|
||||
showToast(t('news.push_stream_empty'), 'warning')
|
||||
return
|
||||
}
|
||||
// Modal.confirm({
|
||||
// title: '操作提示',
|
||||
// content: '是否确定一键开播选中新闻?',
|
||||
// onOk: handlePush
|
||||
// check article content
|
||||
const result = checkArticleContent()
|
||||
setState({modalVisible: true, errorTitle: result.errors, errorIds: result.ids})
|
||||
//
|
||||
// const instance = modal.confirm({
|
||||
// title: <div className="text-base pt-0.5">{t('modal.warning')}</div>,
|
||||
// wrapClassName: 'root-modal-confirm',
|
||||
// centered: true,
|
||||
// width: 440,
|
||||
// icon: <span className="anticon anticon-exclamation-circle"><IconWarningCircle/></span>,
|
||||
// content: <div className="confirm-message-wrapper pl-7">
|
||||
// <div className="message text-gray-600">
|
||||
// {t(
|
||||
// errors && errors.length > 0
|
||||
// ? (props.ids.length == 1 ? 'modal.push_article.content_error_single' : 'modal.push_article.content_error')
|
||||
// : (props.ids.length == 1 ? 'modal.push_article.content_normal_single' : 'modal.push_article.content_normal'),
|
||||
// {count: props.ids.length, error_count: errors?.length})}
|
||||
// </div>
|
||||
// {errors && errors.length > 0 && <div className="error-list text-red-400 mt-6">
|
||||
// <div className="title">{t('modal.push_article.error_title')}:</div>
|
||||
// <div className="max-h-[100px] overflow-auto" style={{lineHeight: '20px'}}>
|
||||
// {errors.map(s => <div
|
||||
// className="error-item overflow-hidden text-nowrap overflow-ellipsis">{s}</div>)}
|
||||
// </div>
|
||||
// </div>}
|
||||
// </div>,
|
||||
// footer: <div className="flex justify-end mt-6">
|
||||
// <Space>
|
||||
// <Button onClick={() => {
|
||||
// instance.destroy()
|
||||
// }}>{t('modal.push_article.action_cancel')}</Button>
|
||||
// <Button type="primary">{t('modal.push_article.action_skip')}</Button>
|
||||
// <Button>{t('modal.push_article.action_all')}</Button>
|
||||
// </Space>
|
||||
// </div>,
|
||||
// })
|
||||
handlePush();
|
||||
// handlePush();
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
@ -45,6 +117,51 @@ export default function ButtonPush2Video(props: { ids: Id[]; onSuccess?: () => v
|
||||
<span className={'text'}>{loading ? t('news.push_streaming') : t('news.generate_video')}</span>
|
||||
<IconArrowRight className={'text-white'}/>
|
||||
</button>
|
||||
<Modal
|
||||
open={state.modalVisible}
|
||||
centered
|
||||
closeIcon={false}
|
||||
footer={null}
|
||||
width={440}
|
||||
>
|
||||
<div className="modal-title flex items-center">
|
||||
<div className="anticon anticon-exclamation-circle text-red-400 w-10"><IconWarningCircle
|
||||
style={{fontSize: 24, color: 'rgba(250, 173, 20, 1)'}}/></div>
|
||||
<div className="text-base">{t('modal.warning')}</div>
|
||||
</div>
|
||||
<div className="confirm-message-wrapper flex mt-2">
|
||||
<div className="min-w-10"></div>
|
||||
<div>
|
||||
<div className="message text-gray-600" dangerouslySetInnerHTML={{
|
||||
__html: t(
|
||||
state.errorTitle && state.errorTitle.length > 0
|
||||
? (props.ids.length == 1 ? 'modal.push_article.content_error_single' : 'modal.push_article.content_error')
|
||||
: (props.ids.length == 1 ? 'modal.push_article.content_normal_single' : 'modal.push_article.content_normal'),
|
||||
{count: props.ids.length, error_count: state.errorTitle?.length})
|
||||
}}>
|
||||
</div>
|
||||
{state.errorTitle && state.errorTitle.length > 0 &&
|
||||
<div className="error-list text-red-400 mt-6 w-[350px]">
|
||||
<div className="title">{t('modal.push_article.error_title')}:</div>
|
||||
<div className="max-h-[100px] overflow-auto" style={{lineHeight: '20px'}}>
|
||||
{state.errorTitle.map(s => <div
|
||||
className="error-item overflow-hidden pr-1 text-nowrap overflow-ellipsis">{s}</div>)}
|
||||
</div>
|
||||
</div>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end mt-6">
|
||||
<Space>
|
||||
<Button onClick={() => {
|
||||
setState({modalVisible: false})
|
||||
}}>{t('modal.push_article.action_cancel')}</Button>
|
||||
{state.errorIds?.length > 0 && <Button type="primary"
|
||||
onClick={() => handlePush(ProcessResult.Skip)}>{t('modal.push_article.action_skip')}</Button>}
|
||||
<Button type={state.errorIds.length == 0 ? 'primary' : 'default'}
|
||||
onClick={() => handlePush(ProcessResult.All)}>{t('modal.push_article.action_all')}</Button>
|
||||
</Space>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -6,7 +6,7 @@ import {formatTime} from "@/util/strings.ts";
|
||||
import ArticleEditModal from "@/components/article/edit-modal.tsx";
|
||||
import {deleteByIds, getList} from "@/service/api/article.ts";
|
||||
import EditSearchForm from "@/pages/news/components/edit-search-form.tsx";
|
||||
import ButtonPush2Video from "@/pages/news/components/button-push2video.tsx";
|
||||
import ButtonPush2Video, {ProcessResult} from "@/pages/news/components/button-push2video.tsx";
|
||||
|
||||
import styles from './components/style.module.scss'
|
||||
import InfiniteScroller, {InfiniteScrollerRef} from "@/components/scoller/infinite-scroller.tsx";
|
||||
@ -73,6 +73,12 @@ export default function NewEdit() {
|
||||
showToast(t('delete_success'), 'success')
|
||||
}).catch(showErrorToast)
|
||||
}
|
||||
const handlePushProcessResult = (result: ProcessResult,errorIds: Id[])=>{
|
||||
if(result == ProcessResult.Skip){
|
||||
// 跳过
|
||||
setSelectedRowKeys(errorIds)
|
||||
}
|
||||
}
|
||||
|
||||
return (<div className="container pb-5 news-edit">
|
||||
<div className="search-panel-container my-5">
|
||||
@ -157,7 +163,7 @@ export default function NewEdit() {
|
||||
</div>
|
||||
</div>
|
||||
})}
|
||||
<div className="h-[100px]"></div>
|
||||
<div className="h-[130px]"></div>
|
||||
</div>
|
||||
</InfiniteScroller>
|
||||
</div>
|
||||
@ -165,7 +171,7 @@ export default function NewEdit() {
|
||||
<div className="page-action">
|
||||
<ButtonToTop visible={state.showToTop} onClick={() => scrollerRef.current?.scrollToPosition(0)}/>
|
||||
{selectedRowKeys?.length > 0 && <ButtonDeleteBatch ids={selectedRowKeys} onSuccess={refresh}/>}
|
||||
<ButtonPush2Video ids={selectedRowKeys} onSuccess={refresh}/>
|
||||
<ButtonPush2Video ids={selectedRowKeys} articles={data?.list} onResult={handlePushProcessResult}/>
|
||||
</div>
|
||||
</div>
|
||||
<ArticleEditModal
|
||||
|
1
src/types/api.d.ts
vendored
1
src/types/api.d.ts
vendored
@ -59,6 +59,7 @@ interface BasicArticleInfo {
|
||||
id: number;
|
||||
title: string;
|
||||
summary: string;
|
||||
metahuman_text: string;
|
||||
publish_time: string;
|
||||
media_name: string;
|
||||
column_name?: string;
|
||||
|
Loading…
x
Reference in New Issue
Block a user