diff --git a/src/components/ai/AiHelper.tsx b/src/components/ai/AiHelper.tsx index 35e3194..4db3ccf 100644 --- a/src/components/ai/AiHelper.tsx +++ b/src/components/ai/AiHelper.tsx @@ -1,20 +1,24 @@ -import {useContext, useEffect, useRef, useState} from "react"; -import {GlobalContext} from "../../context/GlobalContext.ts"; -import {del, get, post, put, websocketUrl} from "../../util/AjaxUtils.ts"; -import {Col, Divider, Row, Spin} from "antd"; +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"; +import { + // Col, Divider, Row, + Spin } from "antd"; import useMessage from "antd/es/message/useMessage"; import AiHelperText from "./text/AiHelperText.tsx"; import AiHelperMod from "./mod/AiHelperMod.tsx"; -import {IProjMod} from "../../interfaces/proj/IProj.ts"; -import {MAX_MOD_SIZE} from "../../route/proj/edit/ProjConfigModList.tsx"; -import {useNavigate} from "react-router-dom"; -import {uuid} from "../../util/CommonUtil.ts"; +import { IProjMod } from "../../interfaces/proj/IProj.ts"; +import { MAX_MOD_SIZE } from "../../route/proj/edit/ProjConfigModList.tsx"; +import { useNavigate } from "react-router-dom"; +import { uuid } from "../../util/CommonUtil.ts"; type PropsType = { projId: string; projIntroduction?: string; projDesc?: string; isFree: boolean; + } type ProjModType = { @@ -24,10 +28,14 @@ type ProjModType = { } export default function AiHelper(props: PropsType) { + // const height = window.innerHeight - 280; const globalContext = useContext(GlobalContext); const pingTimeout = useRef(-1); const ws = useRef(null); const [messageApi, messageApiHolder] = useMessage(); + + const [activeTab, setActiveTab] = useState('简介') //tab栏选中 + const [projIntroduction, setProjIntroduction] = useState(props.projIntroduction ? props.projIntroduction : ''); const [newProjIntroduction, setNewProjIntroduction] = useState(''); const [isProjIntroductionLoading, setIsProjIntroductionLoading] = useState(false); @@ -98,7 +106,7 @@ export default function AiHelper(props: PropsType) { onBefore() { setIsProjModArrayLoading(true); }, - onSuccess({data}) { + onSuccess({ data }) { setProjModArray(data); }, onFinally() { @@ -191,9 +199,9 @@ export default function AiHelper(props: PropsType) { }, [globalContext.user.userId, props.projId]); return ( - <> +
{messageApiHolder} - + {/* - - + */} +
+
{ + setActiveTab('简介') + }} + > + 项目简介 +
+
{ + setActiveTab('详情') + }} + > + 项目详情 +
+
{ + setActiveTab('模块') + }} + > + 模块管理 +
+
+ +
+
+ + { + generateProjIntroduction(); + }} + handleSave={(text) => { + updateProjIntroduction(text); + }} + + > + +
+ +
+ + { + generateProjDesc(); + }} + handleSave={(text) => { + updateProjDesc(text); + }} + /> + +
+
+ + { + generateProjModArray(); + }} + handleSave={(index, mod) => { + if (projModArray.length > MAX_MOD_SIZE) { + messageApi.error(`模块最大数量为${MAX_MOD_SIZE}`); + return; + } + post({ + 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({ + 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({ + messageApi, + url: `/api/proj-mod/remove/proj-id/${props.projId}/${projModId}`, + onBefore() { + setIsProjModArrayLoading(true); + }, + onSuccess() { + messageApi.success('删除成功'); + listMods(); + }, + onFinally() { + setIsProjModArrayLoading(false); + } + }) + }} + /> + +
+
+ + {/*
+ 项目简介 +
+
+ 项目详情 +
*/} + +
) } \ No newline at end of file diff --git a/src/components/ai/ai-helper.css b/src/components/ai/ai-helper.css new file mode 100644 index 0000000..32c4099 --- /dev/null +++ b/src/components/ai/ai-helper.css @@ -0,0 +1,42 @@ +.aiTab { + padding: 20px; +} + +.aiTabBtnBox { + display: flex; + width: 100%; + /* background-color: red; */ + /* border-bottom: 1px solid #D5D5D5; */ +} + +.aiTabBtn { + width: 109px; + height: 39px; + background: #F1F1F1; + font-size: 14px; + color: #5A5A5A; + text-align: center; + line-height: 39px; + cursor: pointer; + font-weight: 700; +} + +.tabActive { + width: 109px; + height: 39px; + background: #FF7E00; + font-size: 14px; + color: #FFFFFF; + text-align: center; + line-height: 39px; + cursor: pointer; + font-weight: 700; + + +} + +.aiTabContent { + width: 100%; + + /* background-color: pink; */ +} \ No newline at end of file diff --git a/src/components/ai/mod/AiHelperMod.tsx b/src/components/ai/mod/AiHelperMod.tsx index d0a3d52..a8abccd 100644 --- a/src/components/ai/mod/AiHelperMod.tsx +++ b/src/components/ai/mod/AiHelperMod.tsx @@ -1,5 +1,12 @@ -import { Button, Divider, Dropdown, Space, Table, TableProps, Modal } from "antd"; -import { CheckOutlined, LoadingOutlined, ReloadOutlined, RedoOutlined } from "@ant-design/icons"; +import './ai-helper-mod.css' +import { Button, + // Divider, Dropdown, Space, + Table, TableProps, Modal } from "antd"; +import { + // CheckOutlined, + LoadingOutlined, + // ReloadOutlined, + RedoOutlined } from "@ant-design/icons"; import { useEffect, useState } from "react"; import { IProjMod } from "../../../interfaces/proj/IProj.ts"; import EditModal from '../../EditModal/EditModal.tsx' @@ -7,6 +14,7 @@ import ConfigModModal from '../../ConfigModModal/ConfigModModal.tsx' import { get } from "../../../util/AjaxUtils.ts"; import { useParams } from "react-router-dom"; import { SearchOutlined } from '@ant-design/icons'; +import noTextImg from '../../../static/noText.png' import { message } from "antd"; @@ -26,13 +34,14 @@ type ProjModType = { } export default function AiHelperMod(props: PropsType) { + const height = window.innerHeight - 265; // 菜单状态是否可以编辑 const [messageApi] = message.useMessage(); const [modArray, setModArray] = useState([]); const [newModArray, setNewModArray] = useState([]); const [id, setId] = useState('') - const[configModal,setConfigModal] = useState(false) + const [configModal, setConfigModal] = useState(false) const [editModal, setEditModal] = useState(false) const [updata, setUpdata] = useState([]) const [status, setStatus] = useState('') @@ -86,10 +95,12 @@ export default function AiHelperMod(props: PropsType) { return '处理中' } if (value == 'FAILED') { - return '失败' + return ( + 失败 + ) } if (value == 'SUCCESS') { - return '成功' + return 成功 } } }, @@ -97,7 +108,7 @@ export default function AiHelperMod(props: PropsType) { title: '操作', dataIndex: 'option', key: 'option', - width: 80, + // width: 80, align: 'center', render: (_value, record, index) => { if (status == 'SUCCESS') { @@ -123,27 +134,49 @@ export default function AiHelperMod(props: PropsType) { }}> } return ( - { - // props.handleEdit(index, record.projModId, record); - setId(record.projModId) - setEditModal(true) - } - }, { - key: 'remove', - label: '删除', - onClick: () => { - props.handleRemove(index, record.projModId, record); - } - }, - ] - }} placement="bottom" arrow> - - +
+ { + setId(record.projModId) + setEditModal(true) + }} + >编辑 + { + props.handleRemove(index, record.projModId, record); + }} + >删除 +
+ + // { + // // props.handleEdit(index, record.projModId, record); + // setId(record.projModId) + // setEditModal(true) + // } + // }, { + // key: 'remove', + // label: '删除', + // onClick: () => { + // props.handleRemove(index, record.projModId, record); + // } + // }, + // ] + // }} placement="bottom" arrow> + // + // ) } // if (record.aiFieldStatus == 'GENERATING') { @@ -230,61 +263,163 @@ export default function AiHelperMod(props: PropsType) { { title: '模块名称', dataIndex: 'name', key: 'name', width: 200, align: 'center' }, { title: '模块描述', dataIndex: 'desc', key: 'desc', align: 'center' }, { - title: '确认', + title: '操作', dataIndex: 'option', key: 'option', width: 80, align: 'center', render: (_value, record, index) => { return ( - + // + { + props.handleSave(index, record); + }} + > + 添加 + ) } }, ]; return ( - <> -
模块管理
-
- {newModArray.length > 0 ? 原模块 : <>} - - { - newModArray.length > 0 ? ( - <> - 新模块 + // <> + //
模块管理
+ //
+ // {newModArray.length > 0 ? 原模块 : <>} + //
+ // { + // newModArray.length > 0 ? ( + // <> + // 新模块 + //
+ // + // ) : <> + // } + // + //
+ // { + // newModArray.length > 0 ? ( + // + // + // + // ) : + // } + //
+ // { setEditModal(false) }} width={1200} > + // < EditModal id={id} onConfirm={() => setEditModal(false)} setUpdata={setUpdata} /> + // + // { setConfigModal(false) }} width={1200} > + // setConfigModal(false)} > + // + // + +
+
+ {modArray.length > 0 ? + <> +
+
+ + {/*
+ +
*/} + + : +
+
+ +
+ 暂无内容点击 + { + props.handleGenerate() + }} + >自动生成 +
+
+
+ } + + +
+ +
+
+
+ {newModArray.length > 0 ? + +
- - ) : <> - } - -
- { - newModArray.length > 0 ? ( - - - - ) :
+ : + <> + 点击AI自动生成后可自动生成模块管理... + } + + +
+ - } + props.handleGenerate() + }} + >AI生成 +
- { setEditModal(false) }} width={1200} > + { setEditModal(false) }} width={1200} > < EditModal id={id} onConfirm={() => setEditModal(false)} setUpdata={setUpdata} /> - { setConfigModal(false) }} width={1200} > + { setConfigModal(false) }} width={1200} > setConfigModal(false)} > - + ) } \ No newline at end of file diff --git a/src/components/ai/mod/ai-helper-mod.css b/src/components/ai/mod/ai-helper-mod.css new file mode 100644 index 0000000..56ac034 --- /dev/null +++ b/src/components/ai/mod/ai-helper-mod.css @@ -0,0 +1,35 @@ +.aiMod-top{ + height: calc(50% - 21px); + padding: 21px; + box-sizing: border-box; +} +.aiMod-top-table{ + height: 100%; + /* background-color: pink; */ + overflow: auto; + border: 1px solid #f0f0f0; + border-radius: 10px; +} +.aiMod-bot-table{ + /* border: 1px solid #f0f0f0; + border-radius: 10px; */ + + height: 88%; + /* background-color: pink; */ + overflow: auto; +} +.aiMod-bot-btn{ + margin-top: 10px; + display: flex; + justify-content: flex-end; +} +.aiMod-center{ + height: 42px; + background: #EFEFEF; +} +.aiMod-bot{ + /* background-color: red; */ + height: calc(50% - 21px); + padding: 21px; + box-sizing: border-box; +} diff --git a/src/components/ai/text/AiHelperText.tsx b/src/components/ai/text/AiHelperText.tsx index d63eb25..eb7a702 100644 --- a/src/components/ai/text/AiHelperText.tsx +++ b/src/components/ai/text/AiHelperText.tsx @@ -1,9 +1,14 @@ -import {Button, Divider, Empty, Space} from "antd"; +import { + Button, + // Divider, Empty, Space +} from "antd"; +import './ai-helper-text.css' import TextArea from "antd/es/input/TextArea"; -import {useEffect, useState} from "react"; -import {CheckOutlined, EditOutlined, ReloadOutlined} from "@ant-design/icons"; +import { useEffect, useState } from "react"; +// import { CheckOutlined, EditOutlined, ReloadOutlined } from "@ant-design/icons"; import { get } from "../../../util/AjaxUtils.ts"; import { useParams } from "react-router-dom"; +import noTextImg from '../../../static/noText.png' import { message } from "antd"; @@ -17,6 +22,7 @@ type PropsType = { } export default function AiHelperText(props: PropsType) { + const height = window.innerHeight - 265; const pathParams = useParams(); const [status, setStatus] = useState('') @@ -37,108 +43,141 @@ export default function AiHelperText(props: PropsType) { const [text, setText] = useState(''); const [newText, setNewText] = useState(''); const [isTextEdit, setIsTextEdit] = useState(false); - const [isNewTextEdit, setIsNewTextEdit] = useState(false); + // const [isNewTextEdit, setIsNewTextEdit] = useState(false); useEffect(() => { setText(props.text); setNewText(props.newText); }, [props.text, props.newText]) - const renderTextBtn = () => { - if (!newText) { - if (!isTextEdit) { - return ( - - - { - text ? ( - - ) : <> - } - - ) - } - return ( - - - - ) - } - if (!isNewTextEdit) { - return ( - - - - - - ) - } - return ( - - - - ) - } + // const renderTextBtn = () => { + // if (!newText) { + // if (!isTextEdit) { + // return ( + // + // + // { + // text ? ( + // + // ) : <> + // } + // + // ) + // } + // return ( + // + // + // + // ) + // } + // if (!isNewTextEdit) { + // return ( + // + // + // + // + // + // ) + // } + // return ( + // + // + // + // ) + // } + // const renderTextDom = () => { + // if (!text) { + // return + // } + // if (!isTextEdit) { + // return (
{text}
) + // } + // return ( + // ) } + // const renderNewTextDom = () => { + // if (!newText) { + // return <> + // } + // if (!isNewTextEdit) { + // return ( + // <> + // 新{props.title} + //
{newText}
+ // + // ) + // } + // return ( + // <> + // 新{props.title} + //