2024-12-24 21:00:20 +08:00

167 lines
4.9 KiB
TypeScript

import {Modal} from "antd";
import ArticleGroup from "@/components/article/group.tsx";
import {useEffect, useState} from "react";
import {useSetState} from "ahooks";
import * as article from "@/service/api/article.ts";
import {regenerate} from "@/service/api/video.ts";
import {push2video} from "@/service/api/article.ts";
import {showErrorToast, showToast} from "@/components/message.ts";
type Props = {
id?: number;
type: 'news' | 'video';
onClose?: (saved?: boolean) => void;
}
const DEFAULT_STATE = {
loading: false,
open: false,
msgTitle: '',
msgGroup: '',
error: ''
}
function pushBlocksToGroup(blocks: BlockContent[], groups: BlockContent[][]) {
const lastGroup = groups[groups.length - 1]
if (lastGroup && lastGroup.filter(s => s.type == 'text').length == 0) {
// 如果上一个group中没有文本则直接合并
lastGroup.push(...blocks)
} else {
groups.push(blocks)
}
}
function rebuildGroups(groups: BlockContent[][]) {
const _groups: BlockContent[][] = [];
if (!groups || groups.length == 0) return _groups;
groups.forEach((blocks, index) => {
if (!blocks) return;
blocks = blocks.filter(s => !!s).sort((a, b) => {
if (a.type == 'text' && b.type == 'text') return 1;
return a.type == 'text' ? -1 : 1
})
if (blocks.length == 1) {
if (index == 0) _groups.push(blocks)
else pushBlocksToGroup(blocks, _groups)
} else {
if (index == 0) {
_groups.push([blocks[0]])
_groups.push(blocks.slice(1))
} else {
pushBlocksToGroup(blocks, _groups)
}
}
});
if (_groups.length < 2) {
Array(2 - _groups.length).fill([{type: 'text', content: ''}]).forEach((it) => {
_groups.push(it)
})
}
console.log('rebuildGroups', _groups)
return _groups;
}
export default function ArticleEditModal(props: Props) {
const [groups, setGroups] = useState<BlockContent[][]>([]);
const [title, setTitle] = useState('')
const [state, setState] = useSetState({
...DEFAULT_STATE,
generating:false
})
// 保存数据
const handleSave = () => {
setState({error: ''})
if (!title) {
// setState({msgTitle: '请输入标题内容'});
return;
}
if (groups.length == 0 || groups[0].length == 0 || !groups[0][0].content) {
// setState({msgGroup: '请输入正文文本内容'});
return;
}
const save = props.type == 'news' ? article.save : regenerate
setState({loading: true})
save(title, groups, props.id && props.id > 0 ? props.id : undefined).then(() => {
props.onClose?.(true)
}).catch(e => {
setState({error: e.data || '保存失败,请重试!'})
}).finally(() => {
setState({loading: false})
});
}
const handlePush2Video = () =>{
if(!props.id || state.generating) return;
setState({generating:true})
push2video([props.id]).then(() => {
showToast('推流成功', 'success')
// navigate('/create?state=push-success',{
// state: 'push-success'
// })
// props.onSuccess?.()
}).catch(showErrorToast).finally(()=>{
setState({generating:false})
})
}
useEffect(() => {
setState({...DEFAULT_STATE})
if (typeof (props.id) != 'undefined') {
if (props.id > 0) {
article.getById(props.id).then(res => {
setGroups(rebuildGroups(res.content_group))
setTitle(res.title)
})
} else {
// 新增
setGroups([])
setTitle('')
}
}
}, [props.id])
return (<Modal
title={null}
centered={true}
rootClassName={"article-edit-modal"}
open={props.id != undefined && props.id >= 0}
maskClosable={false}
keyboard={false}
width={'1200px'}
footer={null}
closeIcon={null}
onCancel={() => props.onClose?.()}
okButtonProps={{loading: state.loading}}
onOk={handleSave}
okText={props.type == 'news' ? '确定' : '重新生成'}
>
<div className="article-title mt-5">
<input className={'input-box text-lg'} value={title} onChange={e => {
setTitle(e.target.value)
setState({msgTitle: e.target.value ? '' : '请输入标题内容'})
}} placeholder={'请输入文章标题'}/>
<div className="text-red-500">{state.msgTitle}</div>
</div>
<div className="article-body">
<div className="box">
<ArticleGroup
errorMessage={state.msgGroup} editable groups={groups}
onChange={list => {
setGroups(() => list)
setState({msgGroup: (list.length == 0 || list[0].length == 0 || !list[0][0].content) ? '请输入正文文本内容' : ''});
}}
/>
</div>
{state.error && <div className="text-red-500">{state.error}</div>}
</div>
<div className="modal-control-footer flex justify-end">
<div className="flex gap-10 ">
{props.type == 'news' && props.id ? <button className="text-gray-400 hover:text-gray-800" onClick={handlePush2Video}>{state.generating?'推送中...':'生成视频'}</button> : null}
<button className="text-gray-400 hover:text-gray-800" onClick={() => props.onClose?.()}></button>
<button onClick={handleSave} className="text-gray-800 hover:text-blue-500">{props.type == 'news' ? '确定' : '重新生成'}</button>
</div>
</div>
</Modal>);
}