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

413 lines
17 KiB
TypeScript
Raw Normal View History

2024-04-19 18:20:51 +08:00
import {useContext, useEffect, useRef, useState} from "react";
import {GlobalContext} from "../../context/GlobalContext.ts";
import {put, WebSocketBaseUrl} from "../../util/AjaxUtils.ts";
2024-04-21 16:11:13 +08:00
import {Button, Col, Divider, Empty, Row, Space, Spin, Table, TableProps} from "antd";
2024-04-22 18:20:26 +08:00
import {CheckOutlined, EditOutlined, ReloadOutlined} from "@ant-design/icons";
2024-04-19 18:20:51 +08:00
import useMessage from "antd/es/message/useMessage";
2024-04-22 18:20:26 +08:00
import TextArea from "antd/es/input/TextArea";
2024-04-19 18:20:51 +08:00
type PropsType = {
projId: string;
projIntroduction?: string;
projDesc?: string;
2024-04-22 18:20:26 +08:00
projMods?: ProjModType[];
2024-04-19 18:20:51 +08:00
}
2024-04-19 21:09:09 +08:00
type ProjModType = {
name: string,
desc: string
}
2024-04-19 18:20:51 +08:00
export default function AiHelper(props: PropsType) {
const globalContext = useContext(GlobalContext);
const pingTimeout = useRef(-1);
const ws = useRef<WebSocket | null>(null);
const [messageApi, messageApiHolder] = useMessage();
const [projIntroduction, setProjIntroduction] = useState<string>(props.projIntroduction ? props.projIntroduction : '');
const [newProjIntroduction, setNewProjIntroduction] = useState<string>('');
2024-04-22 18:20:26 +08:00
const [isProjIntroductionEdit, setIsProjIntroductionEdit] = useState<boolean>(false);
const [isNewProjIntroductionEdit, setIsNewProjIntroductionEdit] = useState<boolean>(false);
2024-04-19 18:20:51 +08:00
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>('');
2024-04-22 18:20:26 +08:00
const [isProjDescEdit, setIsProjDescEdit] = useState<boolean>(false);
const [isNewProjDescEdit, setIsNewProjDescEdit] = useState<boolean>(false);
2024-04-19 18:20:51 +08:00
const [isProjDescLoading, setIsProjDescLoading] = useState(false);
2024-04-22 18:20:26 +08:00
const [projModArray, setProjModArray] = useState<ProjModType[]>(props.projMods ? props.projMods : []);
2024-04-19 21:09:09 +08:00
const [newProjModArray, setNewProjModArray] = useState<ProjModType[]>([]);
const [isProjModArrayLoading, setIsProjModArrayLoading] = useState(false);
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 = () => {
ws.current = new WebSocket(`${WebSocketBaseUrl}/ws/ai/${globalContext.user.userId}`);
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-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-04-19 21:09:09 +08:00
} else if (data.type == 'REFRESH_PROJ_MODS') {
setIsProjModArrayLoading(false);
const projMods = JSON.parse(data.content) as ProjModType[];
setNewProjModArray(projMods);
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-19 21:09:09 +08:00
const projModColumnArray: TableProps<ProjModType>['columns'] = [
2024-04-22 18:20:26 +08:00
{
title: '序号',
dataIndex: 'index',
key: 'index',
width: 60,
align: 'center',
render: (_value, _record, index) => {
return index + 1
}
},
2024-04-21 16:11:13 +08:00
{title: '模块名称', dataIndex: 'name', key: 'name', width: 200, align: 'center'},
2024-04-19 21:09:09 +08:00
{title: '模块描述', dataIndex: 'desc', key: 'desc', align: 'center'},
];
2024-04-19 18:20:51 +08:00
const generateProjIntroduction = () => {
ws.current?.send(JSON.stringify({
type: 'REFRESH_PROJ_INTRODUCTION',
projId: props.projId
}));
ping();
setIsProjIntroductionLoading(true);
}
const generateProjDesc = () => {
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);
},
onSuccess() {
messageApi.success('保存成功');
2024-04-22 18:20:26 +08:00
setProjIntroduction(content);
2024-04-19 18:20:51 +08:00
setNewProjIntroduction('');
},
onFinally() {
setIsProjIntroductionLoading(false)
}
})
}
/**
*
*/
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() {
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-04-22 18:20:26 +08:00
/**
*
*/
const updateProjModArray = () => {
put<any>({
messageApi,
url: `/api/proj-mod/update-mods/${props.projId}`,
body: {
list: newProjModArray
},
onBefore() {
setIsProjModArrayLoading(true);
},
onSuccess() {
messageApi.success('保存成功').then();
setProjModArray(newProjModArray);
setNewProjModArray([]);
},
onFinally() {
setIsProjModArrayLoading(false)
}
})
}
2024-04-19 18:20:51 +08:00
useEffect(() => {
if (!props.projId) {
return;
}
websocket();
}, [globalContext.user.userId, props.projId]);
2024-04-22 18:20:26 +08:00
/**
*
*/
const renderNewProjIntroductionBtn = () => {
if(!newProjIntroduction) {
if(!isProjIntroductionEdit) {
return (
<Space>
<Button type="link" style={{cursor: 'pointer'}} onClick={generateProjIntroduction}>AI生成</Button>
{
projIntroduction ? (
<Button type="link" style={{cursor: 'pointer'}} onClick={() => {
setIsProjIntroductionEdit(true);
}}><EditOutlined /> </Button>
) : <></>
}
</Space>
)
}
return (
<Space>
<Button type="link" style={{cursor: 'pointer'}} onClick={() => {
setIsProjIntroductionEdit(false);
updateProjIntroduction(projIntroduction);
}}><CheckOutlined/> </Button>
</Space>
)
}
if(!isNewProjIntroductionEdit) {
return (
<Space>
<Button type="link" style={{cursor: 'pointer'}} onClick={() => {
updateProjIntroduction(newProjIntroduction);
}}><CheckOutlined/> </Button>
<Button type="link" style={{cursor: 'pointer'}} onClick={generateProjIntroduction}><ReloadOutlined/> </Button>
<Button type="link" style={{cursor: 'pointer'}} onClick={() => {
setIsNewProjIntroductionEdit(true);
}}><EditOutlined /> </Button>
</Space>
)
}
return (
<Space>
<Button type="link" style={{cursor: 'pointer'}} onClick={() => {
setIsNewProjIntroductionEdit(false);
}}><CheckOutlined/> </Button>
</Space>
)
}
/**
*
*/
const renderNewProjDescBtn = () => {
if(!newProjDesc) {
if(!isProjDescEdit) {
return (
<Space>
<Button type="link" style={{cursor: 'pointer'}} onClick={generateProjDesc}>AI生成</Button>
{
projIntroduction ? (
<Button type="link" style={{cursor: 'pointer'}} onClick={() => {
setIsProjDescEdit(true);
}}><EditOutlined /> </Button>
) : <></>
}
</Space>
)
}
return (
<Space>
<Button type="link" style={{cursor: 'pointer'}} onClick={() => {
setIsProjDescEdit(false);
updateProjDesc(projDesc);
}}><CheckOutlined/> </Button>
</Space>
)
}
if(!isNewProjDescEdit) {
return (
<Space>
<Button type="link" style={{cursor: 'pointer'}} onClick={() => {
updateProjDesc(newProjDesc);
}}><CheckOutlined/> </Button>
<Button type="link" style={{cursor: 'pointer'}} onClick={generateProjDesc}><ReloadOutlined/> </Button>
<Button type="link" style={{cursor: 'pointer'}} onClick={() => {
setIsNewProjDescEdit(true);
}}><EditOutlined /> </Button>
</Space>
)
}
return (
<Space>
<Button type="link" style={{cursor: 'pointer'}} onClick={() => {
setIsNewProjDescEdit(false);
}}><CheckOutlined/> </Button>
</Space>
)
}
2024-04-19 18:20:51 +08:00
return (
<>
{messageApiHolder}
2024-04-21 16:11:13 +08:00
<Row>
<Col span={24}>
<div style={{padding: '5px 0 0 0', fontWeight: 'bold'}}></div>
<Spin tip="正在处理,请稍后..." size="small" spinning={isProjIntroductionLoading}>
<div style={{padding: '5px 0 0 0'}}>
{newProjIntroduction ? <Divider orientation="right" plain></Divider> : <></>}
2024-04-22 18:20:26 +08:00
{projIntroduction ? (
isProjIntroductionEdit ? <TextArea rows={10} value={projIntroduction} placeholder="请编辑简介" maxLength={1500} onChange={(e) => {
setProjIntroduction(e.currentTarget.value);
}}/>
: <div>{projIntroduction}</div>
) : <Empty description="暂无内容"/>}
2024-04-21 16:11:13 +08:00
{
newProjIntroduction ? (
<>
<Divider orientation="right" plain></Divider>
2024-04-22 18:20:26 +08:00
{
isNewProjIntroductionEdit ? (
<TextArea rows={10} value={newProjIntroduction} placeholder="请编辑简介" maxLength={1500} onChange={(e) => {
setNewProjIntroduction(e.currentTarget.value);
}}/>
) : <div>{newProjIntroduction}</div>
}
2024-04-21 16:11:13 +08:00
</>
) : <></>
}
</div>
<div style={{padding: '5px 0 0 0', textAlign: 'center'}}>
2024-04-22 18:20:26 +08:00
{renderNewProjIntroductionBtn()}
2024-04-21 16:11:13 +08:00
</div>
</Spin>
</Col>
<Col span={24}>
<Divider dashed/>
<div style={{padding: '5px 0 0 0', fontWeight: 'bold'}}></div>
<Spin tip="正在处理,请稍后..." size="small" spinning={isProjDescLoading}>
<div style={{padding: '5px 0 0 0'}}>
{newProjDesc ? <Divider orientation="right" plain></Divider> : <></>}
2024-04-22 18:20:26 +08:00
{projDesc ? (
isProjDescEdit ?
<TextArea rows={10} value={projDesc} placeholder="请编辑详情"
maxLength={1500} onChange={(e) => {
setProjDesc(e.currentTarget.value);
}}/>
: <div>{projDesc}</div>
) : <Empty description="暂无内容"/>}
2024-04-21 16:11:13 +08:00
{
newProjDesc ? (
<>
<Divider orientation="right" plain></Divider>
2024-04-22 18:20:26 +08:00
{
isNewProjDescEdit ? (
<TextArea rows={10} value={newProjDesc} placeholder="请编辑简介"
maxLength={1500} onChange={(e) => {
setNewProjDesc(e.currentTarget.value);
}}/>
) : <div>{newProjDesc}</div>
}
2024-04-21 16:11:13 +08:00
</>
) : <></>
}
</div>
<div style={{padding: '5px 0 0 0', textAlign: 'center'}}>
2024-04-22 18:20:26 +08:00
{renderNewProjDescBtn()}
2024-04-21 16:11:13 +08:00
</div>
</Spin>
</Col>
<Col span={24}>
<Divider dashed/>
<div style={{padding: '5px 0 0 0', fontWeight: 'bold'}}></div>
<Spin tip="正在处理,请稍后..." size="small" spinning={isProjModArrayLoading}>
<div style={{padding: '5px 0 0 0'}}>
{newProjModArray.length > 0 ? <Divider orientation="right" plain></Divider> : <></>}
2024-04-22 18:20:26 +08:00
<Table columns={projModColumnArray} dataSource={projModArray} size="small" bordered={true}
scroll={{y: 240}} pagination={{pageSize: 20}}/>
2024-04-21 16:11:13 +08:00
{
newProjModArray.length > 0 ? (
<>
<Divider orientation="right" plain></Divider>
2024-04-22 18:20:26 +08:00
<Table columns={projModColumnArray} dataSource={newProjModArray} size="small"
bordered={true} scroll={{y: 240}} pagination={{pageSize: 20}}/>
2024-04-21 16:11:13 +08:00
</>
) : <></>
}
</div>
<div style={{padding: '5px 0 0 0', textAlign: 'center'}}>
{
newProjModArray.length > 0 ? (
<Space>
<Button type="link" style={{cursor: 'pointer'}}
2024-04-22 18:20:26 +08:00
onClick={updateProjModArray}><CheckOutlined/> </Button>
2024-04-21 16:11:13 +08:00
<Button type="link" style={{cursor: 'pointer'}}
onClick={generateProjModArray}><ReloadOutlined/> </Button>
</Space>
) : <Button type="link" style={{cursor: 'pointer'}}
onClick={generateProjModArray}>AI生成</Button>
}
</div>
</Spin>
</Col>
</Row>
2024-04-19 18:20:51 +08:00
</>
2024-04-21 16:11:13 +08:00
)
2024-04-19 18:20:51 +08:00
}