system-copyright-react/src/components/ai/AiHelper.tsx

522 lines
22 KiB
TypeScript
Raw Normal View History

2024-06-14 15:50:34 +08:00
import './ai-helper.css'
import { useContext, useEffect, useRef, useState } from "react";
import { GlobalContext } from "../../context/GlobalContext.ts";
import { del, get, post, put, websocketUrl } from "../../util/AjaxUtils.ts";
2024-06-21 16:18:01 +08:00
import {
2024-06-14 15:50:34 +08:00
// Col, Divider, Row,
2024-06-21 16:18:01 +08:00
Spin
} from "antd";
2024-04-19 18:20:51 +08:00
import useMessage from "antd/es/message/useMessage";
2024-04-24 18:03:44 +08:00
import AiHelperText from "./text/AiHelperText.tsx";
import AiHelperMod from "./mod/AiHelperMod.tsx";
2024-06-14 15:50:34 +08:00
import { IProjMod } from "../../interfaces/proj/IProj.ts";
import { MAX_MOD_SIZE } from "../../route/proj/edit/ProjConfigModList.tsx";
2024-06-21 16:18:01 +08:00
import {
useNavigate,
// useParams
} from "react-router-dom";
2024-06-14 15:50:34 +08:00
import { uuid } from "../../util/CommonUtil.ts";
2024-04-19 18:20:51 +08:00
type PropsType = {
projId: string;
projIntroduction?: string;
projDesc?: string;
2024-04-25 15:37:50 +08:00
isFree: boolean;
2024-06-21 16:18:01 +08:00
renderData: any
2024-04-19 18:20:51 +08:00
}
2024-04-19 21:09:09 +08:00
type ProjModType = {
2024-04-24 18:03:44 +08:00
id: string,
2024-04-19 21:09:09 +08:00
name: string,
desc: string
}
2024-04-19 18:20:51 +08:00
export default function AiHelper(props: PropsType) {
2024-06-21 16:18:01 +08:00
// const pathParams = useParams();
// const [openModal ,setOpenModal] = useState(false) //是提示替换弹框
2024-06-14 15:50:34 +08:00
// const height = window.innerHeight - 280;
2024-04-19 18:20:51 +08:00
const globalContext = useContext(GlobalContext);
const pingTimeout = useRef(-1);
const ws = useRef<WebSocket | null>(null);
const [messageApi, messageApiHolder] = useMessage();
2024-06-14 15:50:34 +08:00
const [activeTab, setActiveTab] = useState('简介') //tab栏选中
2024-04-19 18:20:51 +08:00
const [projIntroduction, setProjIntroduction] = useState<string>(props.projIntroduction ? props.projIntroduction : '');
2024-06-21 16:18:01 +08:00
// 中间量
2024-04-19 18:20:51 +08:00
const [newProjIntroduction, setNewProjIntroduction] = useState<string>('');
const [isProjIntroductionLoading, setIsProjIntroductionLoading] = useState(false);
2024-04-22 18:20:26 +08:00
2024-04-19 18:20:51 +08:00
const [projDesc, setProjDesc] = useState<string>(props.projDesc ? props.projDesc : '');
const [newProjDesc, setNewProjDesc] = useState<string>('');
const [isProjDescLoading, setIsProjDescLoading] = useState(false);
2024-04-22 18:20:26 +08:00
2024-04-24 18:03:44 +08:00
const [projModArray, setProjModArray] = useState<IProjMod[]>([]);
2024-04-19 21:09:09 +08:00
const [newProjModArray, setNewProjModArray] = useState<ProjModType[]>([]);
const [isProjModArrayLoading, setIsProjModArrayLoading] = useState(false);
2024-04-25 15:37:50 +08:00
const nav = useNavigate();
2024-06-21 16:18:01 +08:00
// const [showText,setShowText] = useState('保存成功') //提示信息
// // 获取项目信息
// const renderData = () => {
// get<any>({
// messageApi: messageApi,
// url: `/api/proj/get/${pathParams.projId}`,
// onSuccess({ data }) {
// setProjIntroduction(data.projIntroduction)
// setProjDesc(data.projDesc)
// }
// })
2024-04-19 18:20:51 +08:00
2024-06-21 16:18:01 +08:00
// }
2024-04-24 18:03:44 +08:00
2024-04-19 18:20:51 +08:00
const ping = () => {
clearTimeout(pingTimeout.current);
pingTimeout.current = setTimeout(() => {
if (!ws.current) {
return;
}
ws.current.send("PING");
ping();
}, 3000);
}
const websocket = () => {
2024-04-25 15:37:50 +08:00
ws.current = new WebSocket(`${websocketUrl()}/ws/ai/${globalContext.user.userId}`);
2024-04-19 18:20:51 +08:00
ws.current.onopen = (event) => {
console.log('打开', event);
ping();
}
ws.current.onmessage = (event) => {
if (event.data == 'PONE') {
return;
}
const data = JSON.parse(event.data);
2024-04-19 21:09:09 +08:00
if (data.projId != props.projId) {
return;
}
2024-04-19 18:20:51 +08:00
if (data.type == 'REFRESH_PROJ_INTRODUCTION') {
setIsProjIntroductionLoading(false);
setNewProjIntroduction(data.content);
2024-06-21 16:18:01 +08:00
// if (!projIntroduction) {
// setProjIntroduction(data.content)
// updateProjIntroduction(data.content);
// }
2024-04-19 21:09:09 +08:00
} else if (data.type == 'REFRESH_PROJ_DESC') {
2024-04-19 18:20:51 +08:00
setIsProjDescLoading(false);
setNewProjDesc(data.content);
2024-06-21 16:18:01 +08:00
// if (!projDesc) {
// setProjDesc(data.content)
// updateProjDesc(data.content)
// }
2024-04-19 21:09:09 +08:00
} else if (data.type == 'REFRESH_PROJ_MODS') {
setIsProjModArrayLoading(false);
const projMods = JSON.parse(data.content) as ProjModType[];
2024-04-25 15:37:50 +08:00
projMods.forEach(projMod => projMod.id = uuid())
2024-04-19 21:09:09 +08:00
setNewProjModArray(projMods);
2024-04-24 18:03:44 +08:00
} else if (data.type == 'REFRESH_PROJ_MOD_FIELDS') {
listMods();
2024-04-19 18:20:51 +08:00
}
}
ws.current.onerror = (event) => {
console.log('error', event);
}
ws.current.onclose = (event) => {
console.log('close', event);
websocket()
}
}
2024-04-24 18:03:44 +08:00
const listMods = () => {
get<IProjMod[]>({
messageApi,
url: `/api/proj-mod/list/proj-id/${props.projId}`,
onBefore() {
setIsProjModArrayLoading(true);
},
2024-06-14 15:50:34 +08:00
onSuccess({ data }) {
2024-04-24 18:03:44 +08:00
setProjModArray(data);
},
onFinally() {
setIsProjModArrayLoading(false);
2024-04-22 18:20:26 +08:00
}
2024-04-24 18:03:44 +08:00
})
}
2024-04-19 21:09:09 +08:00
2024-04-19 18:20:51 +08:00
const generateProjIntroduction = () => {
2024-06-21 16:18:01 +08:00
2024-04-19 18:20:51 +08:00
ws.current?.send(JSON.stringify({
type: 'REFRESH_PROJ_INTRODUCTION',
projId: props.projId
}));
ping();
setIsProjIntroductionLoading(true);
}
const generateProjDesc = () => {
2024-06-21 16:18:01 +08:00
2024-04-19 18:20:51 +08:00
ws.current?.send(JSON.stringify({
type: 'REFRESH_PROJ_DESC',
projId: props.projId
}));
ping();
setIsProjDescLoading(true);
}
2024-04-19 21:09:09 +08:00
const generateProjModArray = () => {
ws.current?.send(JSON.stringify({
type: 'REFRESH_PROJ_MODS',
projId: props.projId
}));
ping();
setIsProjModArrayLoading(true);
}
2024-04-19 18:20:51 +08:00
/**
*
*/
2024-04-22 18:20:26 +08:00
const updateProjIntroduction = (content: string) => {
2024-04-19 18:20:51 +08:00
put<any>({
messageApi,
url: `/api/proj/update-introduction/${props.projId}`,
body: {
2024-04-22 18:20:26 +08:00
content: content
2024-04-19 18:20:51 +08:00
},
onBefore() {
setIsProjIntroductionLoading(true);
},
2024-06-21 16:18:01 +08:00
onSuccess(data) {
messageApi.success('保存成功,点击编辑按钮可继续修改项目简介');
2024-04-22 18:20:26 +08:00
setProjIntroduction(content);
2024-04-19 18:20:51 +08:00
setNewProjIntroduction('');
2024-06-21 16:18:01 +08:00
console.log('更新成功',data);
2024-04-19 18:20:51 +08:00
},
onFinally() {
setIsProjIntroductionLoading(false)
2024-06-21 16:18:01 +08:00
// renderData()
2024-04-19 18:20:51 +08:00
}
})
}
/**
*
*/
2024-04-22 18:20:26 +08:00
const updateProjDesc = (content: string) => {
2024-04-19 18:20:51 +08:00
put<any>({
messageApi,
url: `/api/proj/update-desc/${props.projId}`,
body: {
2024-04-22 18:20:26 +08:00
content: content
2024-04-19 18:20:51 +08:00
},
onBefore() {
setIsProjDescLoading(true);
},
onSuccess() {
2024-06-21 16:18:01 +08:00
messageApi.success('保存成功,点击编辑按钮可继续修改项目详情').then();
2024-04-22 18:20:26 +08:00
setProjDesc(content);
2024-04-19 18:20:51 +08:00
setNewProjDesc('');
},
onFinally() {
setIsProjDescLoading(false)
2024-06-21 16:18:01 +08:00
// renderData()
2024-04-19 18:20:51 +08:00
}
})
}
useEffect(() => {
if (!props.projId) {
return;
}
2024-06-21 16:18:01 +08:00
2024-04-24 18:03:44 +08:00
listMods();
2024-04-19 18:20:51 +08:00
websocket();
}, [globalContext.user.userId, props.projId]);
2024-06-21 16:18:01 +08:00
useEffect(()=>{
},[])
2024-04-19 18:20:51 +08:00
return (
2024-06-14 15:50:34 +08:00
<div className='aiTab'>
2024-04-19 18:20:51 +08:00
{messageApiHolder}
2024-06-14 15:50:34 +08:00
{/* <Row>
2024-04-21 16:11:13 +08:00
<Col span={24}>
<Spin tip="正在处理,请稍后..." size="small" spinning={isProjIntroductionLoading}>
2024-04-24 18:03:44 +08:00
<AiHelperText title="项目简介"
text={projIntroduction}
newText={newProjIntroduction}
maxLength={1500}
handleGenerate={() => {
generateProjIntroduction();
}}
handleSave={(text) => {
updateProjIntroduction(text);
}}
/>
2024-04-21 16:11:13 +08:00
</Spin>
</Col>
<Col span={24}>
<Divider dashed/>
<Spin tip="正在处理,请稍后..." size="small" spinning={isProjDescLoading}>
2024-04-24 18:03:44 +08:00
<AiHelperText title="项目详情"
text={projDesc}
newText={newProjDesc}
maxLength={1500}
handleGenerate={() => {
generateProjDesc();
}}
handleSave={(text) => {
updateProjDesc(text);
}}
/>
2024-04-21 16:11:13 +08:00
</Spin>
</Col>
<Col span={24}>
<Divider dashed/>
<Spin tip="正在处理,请稍后..." size="small" spinning={isProjModArrayLoading}>
2024-04-24 18:03:44 +08:00
<AiHelperMod mods={projModArray}
newMods={newProjModArray}
handleGenerate={() => {
generateProjModArray();
}}
handleSave={(index, mod) => {
if(projModArray.length > MAX_MOD_SIZE) {
messageApi.error(`模块最大数量为${MAX_MOD_SIZE}`);
return;
}
post<any>({
messageApi,
url: `/api/proj-mod/save-ai/${props.projId}`,
body: {
name: mod.name,
desc: mod.desc,
},
onBefore() {
setIsProjModArrayLoading(true);
},
onSuccess() {
messageApi.success('提交成功')
listMods();
newProjModArray.splice(index, 1);
setNewProjModArray([
...newProjModArray
]);
},
onFinally() {
setIsProjModArrayLoading(false);
}
})
}}
handleResaveField={(_index, projModId) => {
post<any>({
messageApi,
url: `/api/proj-mod/resave-ai-field/${props.projId}/${projModId}`,
onBefore() {
setIsProjModArrayLoading(true);
},
onSuccess() {
messageApi.success('提交成功')
listMods();
},
onFinally() {
setIsProjModArrayLoading(false);
}
})
}}
2024-04-25 15:37:50 +08:00
handleEdit={(_index, projModId, item) => {
if(item.aiFieldStatus != 'SUCCESS') {
messageApi.error('模块未处理完毕不能编辑');
return;
}
if(props.isFree) {
nav(`/proj-edit/config-mod-fedit/${props.projId}/${projModId}`)
} else {
nav(`/proj-edit/config-mod-edit/${props.projId}/${projModId}`)
}
}}
handleRemove={(_index, projModId, item) => {
if(item.aiFieldStatus != 'SUCCESS') {
messageApi.error('模块未处理完毕不能删除');
return;
}
del<any>({
messageApi,
url: `/api/proj-mod/remove/proj-id/${props.projId}/${projModId}`,
onBefore() {
setIsProjModArrayLoading(true);
},
onSuccess() {
messageApi.success('删除成功');
listMods();
},
onFinally() {
setIsProjModArrayLoading(false);
}
})
}}
2024-04-24 18:03:44 +08:00
/>
2024-04-21 16:11:13 +08:00
</Spin>
</Col>
2024-04-24 18:03:44 +08:00
2024-06-14 15:50:34 +08:00
</Row> */}
<div className="aiTabBtnBox">
<div className={activeTab == '简介' ? 'tabActive' : "aiTabBtn"}
onClick={() => {
setActiveTab('简介')
}}
>
</div>
<div className={activeTab == '详情' ? 'tabActive' : "aiTabBtn"}
onClick={() => {
setActiveTab('详情')
}}
>
</div>
<div className={activeTab == '模块' ? 'tabActive' : "aiTabBtn"}
onClick={() => {
setActiveTab('模块')
}}
>
</div>
</div>
<div className='aiTabContent'>
<div style={{ display: activeTab == '简介' ? 'block' : 'none' }}>
<Spin tip="正在处理,请稍后..." size="small" spinning={isProjIntroductionLoading}>
<AiHelperText
title="项目简介"
text={projIntroduction}
newText={newProjIntroduction}
maxLength={1500}
handleGenerate={() => {
generateProjIntroduction();
2024-06-21 16:18:01 +08:00
// setProjIntroduction(newProjIntroduction)
2024-06-14 15:50:34 +08:00
}}
handleSave={(text) => {
updateProjIntroduction(text);
}}
2024-06-21 16:18:01 +08:00
2024-06-14 15:50:34 +08:00
></AiHelperText>
</Spin>
</div>
<div style={{ display: activeTab == '详情' ? 'block' : 'none' }}>
<Spin tip="正在处理,请稍后..." size="small" spinning={isProjDescLoading}>
<AiHelperText title="项目详情"
text={projDesc}
newText={newProjDesc}
maxLength={1500}
handleGenerate={() => {
generateProjDesc();
}}
handleSave={(text) => {
updateProjDesc(text);
}}
2024-06-21 16:18:01 +08:00
2024-06-14 15:50:34 +08:00
/>
</Spin>
</div>
<div style={{ display: activeTab == '模块' ? 'block' : 'none' }}>
<Spin tip="正在处理,请稍后..." size="small" spinning={isProjModArrayLoading}>
<AiHelperMod mods={projModArray}
newMods={newProjModArray}
handleGenerate={() => {
generateProjModArray();
}}
handleSave={(index, mod) => {
if (projModArray.length > MAX_MOD_SIZE) {
messageApi.error(`模块最大数量为${MAX_MOD_SIZE}`);
return;
}
post<any>({
messageApi,
url: `/api/proj-mod/save-ai/${props.projId}`,
body: {
name: mod.name,
desc: mod.desc,
},
onBefore() {
setIsProjModArrayLoading(true);
},
onSuccess() {
messageApi.success('提交成功')
listMods();
newProjModArray.splice(index, 1);
setNewProjModArray([
...newProjModArray
]);
},
onFinally() {
setIsProjModArrayLoading(false);
}
})
}}
handleResaveField={(_index, projModId) => {
post<any>({
messageApi,
url: `/api/proj-mod/resave-ai-field/${props.projId}/${projModId}`,
onBefore() {
setIsProjModArrayLoading(true);
},
onSuccess() {
messageApi.success('提交成功')
listMods();
},
onFinally() {
setIsProjModArrayLoading(false);
}
})
}}
handleEdit={(_index, projModId, item) => {
if (item.aiFieldStatus != 'SUCCESS') {
messageApi.error('模块未处理完毕不能编辑');
return;
}
if (props.isFree) {
nav(`/proj-edit/config-mod-fedit/${props.projId}/${projModId}`)
} else {
nav(`/proj-edit/config-mod-edit/${props.projId}/${projModId}`)
}
}}
handleRemove={(_index, projModId, item) => {
if (item.aiFieldStatus != 'SUCCESS') {
messageApi.error('模块未处理完毕不能删除');
return;
}
del<any>({
messageApi,
url: `/api/proj-mod/remove/proj-id/${props.projId}/${projModId}`,
onBefore() {
setIsProjModArrayLoading(true);
},
onSuccess() {
messageApi.success('删除成功');
listMods();
},
onFinally() {
setIsProjModArrayLoading(false);
}
})
}}
/>
</Spin>
</div>
</div>
{/* <div className='proIntroduction'>
</div>
<div className='proDetail'>
</div> */}
</div>
2024-04-21 16:11:13 +08:00
)
2024-04-19 18:20:51 +08:00
}