处理问题

This commit is contained in:
WenC 2024-04-12 14:12:38 +08:00
parent 882336fa1f
commit d4a75e7933
21 changed files with 666 additions and 182 deletions

7
package-lock.json generated
View File

@ -8,6 +8,7 @@
"name": "ai-copyright", "name": "ai-copyright",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@ant-design/cssinjs": "^1.19.1",
"antd": "^5.15.2", "antd": "^5.15.2",
"axios": "^1.6.7", "axios": "^1.6.7",
"localforage": "^1.10.0", "localforage": "^1.10.0",
@ -70,9 +71,9 @@
} }
}, },
"node_modules/@ant-design/cssinjs": { "node_modules/@ant-design/cssinjs": {
"version": "1.18.4", "version": "1.19.1",
"resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.18.4.tgz", "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.19.1.tgz",
"integrity": "sha512-IrUAOj5TYuMG556C9gdbFuOrigyhzhU5ZYpWb3gYTxAwymVqRbvLzFCZg6OsjLBR6GhzcxYF3AhxKmjB+rA2xA==", "integrity": "sha512-hgQ3wiys3X0sqDKWkqCJ6EYdF79i9JCvtavmIGwuuPUKmoJXV8Ff0sY+yQQSxk2dRmMyam/bYKo/Bwor45hnZw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.11.1", "@babel/runtime": "^7.11.1",
"@emotion/hash": "^0.8.0", "@emotion/hash": "^0.8.0",

View File

@ -10,6 +10,7 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@ant-design/cssinjs": "^1.19.1",
"antd": "^5.15.2", "antd": "^5.15.2",
"axios": "^1.6.7", "axios": "^1.6.7",
"localforage": "^1.10.0", "localforage": "^1.10.0",

View File

@ -13,10 +13,10 @@ import {
WarningOutlined WarningOutlined
} from '@ant-design/icons'; } from '@ant-design/icons';
import {Button, ConfigProvider, Dropdown, Tag} from 'antd'; import {Button, ConfigProvider, Dropdown, Tag} from 'antd';
import {GenerateStatus, IProj, PayStatus} from "../../interfaces/proj/IProj.ts"; import {GenerateStatus, IProj, PayStatus, ProjChargeType} from "../../interfaces/proj/IProj.ts";
import {useNavigate} from "react-router-dom"; import {useNavigate} from "react-router-dom";
import {Axios, put} from "../../util/AjaxUtils.ts"; import {Axios, put} from "../../util/AjaxUtils.ts";
import {useContext, useState} from "react"; import {useContext, useEffect, useState} from "react";
import {IndexListContext} from "../../context/IndexListContext.ts"; import {IndexListContext} from "../../context/IndexListContext.ts";
import useMessage from "antd/es/message/useMessage"; import useMessage from "antd/es/message/useMessage";
@ -26,6 +26,7 @@ export default function CardProj(props: { item: IProj }) {
const [messageApi, messageContext] = useMessage(); const [messageApi, messageContext] = useMessage();
const [projCategoryId, setProjCategoryId] = useState(data.projCategoryId); const [projCategoryId, setProjCategoryId] = useState(data.projCategoryId);
const [projCategoryName, setProjCategoryName] = useState(data.projCategoryName); const [projCategoryName, setProjCategoryName] = useState(data.projCategoryName);
const [payCharge, setPayCharge] = useState('');
const indexListContext = useContext(IndexListContext); const indexListContext = useContext(IndexListContext);
/** /**
@ -108,12 +109,31 @@ export default function CardProj(props: { item: IProj }) {
) )
} }
useEffect(() => {
const charge = props.item.pay.charge.split(':')[0];
let chargeName = '';
if (charge == ProjChargeType.ALL) {
chargeName = '全托管';
} else if (charge == ProjChargeType.MATERIAL_AGENT) {
chargeName = '写材料+代理';
} else if (charge == ProjChargeType.MATERIAL_AGENT_URGENT) {
chargeName = '写材料+代理(加急)';
} else if (charge == ProjChargeType.MATERIAL) {
chargeName = '写材料';
} else {
chargeName = '免费试用';
}
setPayCharge(chargeName);
}, [])
return ( return (
<> <>
<div className="card-proj"> <div className="card-proj">
<div className="title"> <div className="title">
<div className="left"> <div className="left">
<a href="/#">{data.projName}</a> <span className="text-btn" onClick={() => {
nav(`/proj-edit/${data.projId}`)
}}>{data.projName}</span>
</div> </div>
<div className="right"> <div className="right">
<span className="context">{data.projContext}</span> <span className="context">{data.projContext}</span>
@ -125,34 +145,32 @@ export default function CardProj(props: { item: IProj }) {
<div className="body"> <div className="body">
<div className="line"> <div className="line">
<div className="left"> <div className="left">
<span>{data.pay.payment / 100}</span> <Tag color="magenta">{payCharge}</Tag>
<Tag color="gold">{data.pay.payment / 100}</Tag>
</div> </div>
<div className="right"> <div className="right">
{ {
data.generate.generateStatus == GenerateStatus.SUCCESS ? ( data.generate.generateStatus == GenerateStatus.SUCCESS ? (
<span> <span>
<SearchOutlined/> <SearchOutlined/>
<a href="/#" onClick={(e) => { <span className="text-btn" onClick={() => {
e.preventDefault();
nav(`/proj-edit/${data.projId}`) nav(`/proj-edit/${data.projId}`)
}}></a> }}></span>
</span> </span>
) : ( ) : (
<span> <span>
<EditOutlined/> <EditOutlined/>
<a href="/#" onClick={(e) => { <span className="text-btn" onClick={() => {
e.preventDefault();
nav(`/proj-edit/${data.projId}`) nav(`/proj-edit/${data.projId}`)
}}></a> }}></span>
</span> </span>
) )
} }
<span> <span>
<EyeOutlined/> <EyeOutlined/>
<a href="/#" onClick={(e) => { <span className="text-btn" onClick={() => {
e.stopPropagation();
window.open(`${Axios.defaults?.baseURL}/${data.previewUrl}`, '_blank') window.open(`${Axios.defaults?.baseURL}/${data.previewUrl}`, '_blank')
}}></a> }}></span>
</span> </span>
</div> </div>
</div> </div>
@ -162,10 +180,10 @@ export default function CardProj(props: { item: IProj }) {
data.generate.generateStatus == GenerateStatus.SUCCESS ? ( data.generate.generateStatus == GenerateStatus.SUCCESS ? (
<span> <span>
<SearchOutlined/> <SearchOutlined/>
<a href="/#" onClick={(e) => { <span className="text-btn" onClick={(e) => {
e.preventDefault(); e.preventDefault();
nav(`/agent-select/${data.projId}`); nav(`/agent-select/${data.projId}`);
}}></a> }}></span>
</span> </span>
) : <></> ) : <></>
} }
@ -187,7 +205,7 @@ export default function CardProj(props: { item: IProj }) {
} }
}}> }}>
<span> <span>
<a href="/#">{projCategoryId ? projCategoryName : '无目录'}</a> <span className="text-btn">{projCategoryId ? projCategoryName : '无目录'}</span>
<DownOutlined/> <DownOutlined/>
</span> </span>
</Dropdown> </Dropdown>

View File

@ -1,6 +1,6 @@
import './card-proj-agent.css' import './card-proj-agent.css'
import {OrderedListOutlined, BarsOutlined, SearchOutlined} from "@ant-design/icons"; import {OrderedListOutlined, BarsOutlined, SearchOutlined} from "@ant-design/icons";
import {Tag} from 'antd'; import {Badge, Tag} from 'antd';
import {IAgent} from "../../interfaces/agent/IAgent.ts"; import {IAgent} from "../../interfaces/agent/IAgent.ts";
import {useNavigate} from "react-router-dom"; import {useNavigate} from "react-router-dom";
@ -74,21 +74,25 @@ export default function CardProjAgent(props: IAgent) {
<span>{props.gmtCreate}</span> <span>{props.gmtCreate}</span>
</div> </div>
</div> </div>
<div className="line"> <div className="line" style={{height: '30px', lineHeight: '30px'}}>
<div className="left"> <div className="left">
<span> <span>
<OrderedListOutlined/> <OrderedListOutlined/>
<a href="/#" onClick={(e) => { <Badge dot count={props.orderAgreementStatus == 'AWAIT_SURE' ? 1 : 0}>
e.preventDefault(); <a href="/#" onClick={(e) => {
nav(`/agent-agreement/${props.orderId}`); e.preventDefault();
}}></a> nav(`/agent-agreement/${props.orderId}`);
}}></a>
</Badge>
</span> </span>
<span style={{marginLeft: '15px'}}> <span style={{marginLeft: '15px'}}>
<BarsOutlined /> <BarsOutlined/>
<a href="/#" onClick={(e) => { <Badge size="small" count={props.isOver == 0 && props.materialAmendApplyCount ? props.materialAmendApplyCount : 0}>
e.preventDefault(); <a href="/#" onClick={(e) => {
nav(`/agent-correction/${props.orderId}`); e.preventDefault();
}}>({props.materialAmendApplyCount})</a> nav(`/agent-correction/${props.orderId}`);
}}></a>
</Badge>
</span> </span>
</div> </div>
{ {

View File

@ -1,22 +1,22 @@
import './card-proj-loading.css'; import './card-proj-loading.css';
import {Loading3QuartersOutlined} from '@ant-design/icons'; import {Loading3QuartersOutlined} from '@ant-design/icons';
import {IProjLoading} from "../../interfaces/card/ICardProj.ts"; import {IProjLoading} from "../../interfaces/card/ICardProj.ts";
import {useState} from "react"; import {useEffect, useState} from "react";
export default function CardProjLoading(props: IProjLoading) { export default function CardProjLoading(props: IProjLoading) {
const [duration, setDuration] = useState(props.duration); const [duration, setDuration] = useState(props.duration);
const interval = setInterval(() => { useEffect(() => {
const last = duration - 1000; setTimeout(() => {
if (last <= 0) { const last = duration - 1000;
setDuration(0); if (last <= 0) {
clearInterval(interval); setDuration(0);
props.handleCountDownOver(); props.handleCountDownOver();
return; return;
} }
setDuration(last); setDuration(last);
}, 1000); }, 1000);
}, [duration])
return ( return (
<div className="card-proj-loading"> <div className="card-proj-loading">

View File

@ -15,7 +15,7 @@ export default function CardProjResult(props: IProjResult) {
<a href="/#" className="edit" onClick={(e) => { <a href="/#" className="edit" onClick={(e) => {
e.preventDefault(); e.preventDefault();
props.handleFeedback?.(); props.handleFeedback?.();
}}></a> }}></a>
} }
</div> </div>
) : <></> ) : <></>

View File

@ -62,6 +62,7 @@
} }
.card-proj .body .line .left { .card-proj .body .line .left {
width: unset;
display: flex; display: flex;
} }

View File

@ -92,6 +92,7 @@ export default function ListProjAgent() {
orderTypeName={item.orderTypeName} orderTypeName={item.orderTypeName}
overTime={item.overTime} overTime={item.overTime}
gmtCreate={item.gmtCreate} gmtCreate={item.gmtCreate}
orderAgreementStatus={item.orderAgreementStatus}
/> />
) )
} }

View File

@ -5,9 +5,9 @@ import {
PlusOutlined, PlusOutlined,
CloseOutlined, CloseOutlined,
EditOutlined, EditOutlined,
CheckOutlined
} from '@ant-design/icons'; } from '@ant-design/icons';
import {IMenuTree, IMenuTreeItem} from "../../interfaces/menu/IMenuTree.ts"; import {IMenuTree, IMenuTreeItem} from "../../interfaces/menu/IMenuTree.ts";
import {Popconfirm} from "antd";
export default function MenuTree(props: IMenuTree) { export default function MenuTree(props: IMenuTree) {
@ -22,20 +22,6 @@ export default function MenuTree(props: IMenuTree) {
} }
const renderBtnGroup = (item: IMenuTreeItem, index: number, parent?: IMenuTreeItem) => { const renderBtnGroup = (item: IMenuTreeItem, index: number, parent?: IMenuTreeItem) => {
if (item.isEdit) {
return (
<>
<CheckOutlined className="icon" onClick={(e) => {
e.stopPropagation();
props.handleEditSaveClick(item);
}}/>
<CloseOutlined className="icon" onClick={(e) => {
e.stopPropagation();
props.handleEditCancelClick(item);
}}/>
</>
)
}
return ( return (
<> <>
<EditOutlined className="icon" onClick={(e) => { <EditOutlined className="icon" onClick={(e) => {
@ -46,25 +32,33 @@ export default function MenuTree(props: IMenuTree) {
e.stopPropagation(); e.stopPropagation();
props.handleAddClick(item); props.handleAddClick(item);
}}/> }}/>
<CloseOutlined className="icon" onClick={(e) => { <Popconfirm title={false}
e.stopPropagation(); description="确认删除吗?"
props.handleRemoveClick(item, index, parent); okText="确认"
}}/> cancelText="取消"
okButtonProps={{
style: {
backgroundColor: 'var(--color-primary)'
}
}}
onConfirm={(e) => {
e?.stopPropagation();
props.handleRemoveClick(item, index, parent);
}}
onCancel={(e) => {
e?.stopPropagation();
}}
>
<CloseOutlined className="icon" onClick={(e) => {
e.stopPropagation();
}}/>
</Popconfirm>
</> </>
); );
} }
const renderLabel = (item: IMenuTreeItem) => { const renderLabel = (item: IMenuTreeItem) => {
if (item.isEdit) {
const width = 180 - 30 - item.level * 10;
return <input className="menu-name-input"
value={item.name}
style={{width: width}}
onChange={(e) => {
item.name = e.target.value;
props.handleNameChange(item);
}}/>
}
const icon = item.isOpen ? <CaretDownOutlined onClick={() => { const icon = item.isOpen ? <CaretDownOutlined onClick={() => {
triggerChildren(item) triggerChildren(item)
}}/> : <CaretRightOutlined onClick={() => { }}/> : <CaretRightOutlined onClick={() => {
@ -75,7 +69,12 @@ export default function MenuTree(props: IMenuTree) {
<> <>
{item.isParent ? icon : <></>} {item.isParent ? icon : <></>}
<span <span
className={item.active ? 'active' : ''}
style={{width: width}} style={{width: width}}
onClick={(e) => {
e.stopPropagation();
props.handleClick(item);
}}
onDoubleClick={() => { onDoubleClick={() => {
triggerChildren(item) triggerChildren(item)
}}>{item.name}</span> }}>{item.name}</span>
@ -90,10 +89,7 @@ export default function MenuTree(props: IMenuTree) {
const lis = children.map((item, index) => { const lis = children.map((item, index) => {
const renderChildrenMenu = renderMenu(item.children, item); const renderChildrenMenu = renderMenu(item.children, item);
return ( return (
<li className={item.active ? 'active' : ''} key={item.id} onClick={(e) => { <li key={item.id}>
e.stopPropagation();
props.handleClick(item);
}}>
<div className="menu-title"> <div className="menu-title">
<div className="label">{renderLabel(item)}</div> <div className="label">{renderLabel(item)}</div>
<div className="icon-group">{renderBtnGroup(item, index, parent)}</div> <div className="icon-group">{renderBtnGroup(item, index, parent)}</div>

View File

@ -5,7 +5,7 @@ import {useContext, useEffect, useState} from "react";
import {del, get, post, put} from "../../util/AjaxUtils.ts"; import {del, get, post, put} from "../../util/AjaxUtils.ts";
import useMessage from "antd/es/message/useMessage"; import useMessage from "antd/es/message/useMessage";
import {IndexListDataType, IndexListDispatchContext,} from "../../context/IndexListContext.ts"; import {IndexListDataType, IndexListDispatchContext,} from "../../context/IndexListContext.ts";
import {MenuProps} from "antd"; import {Input, MenuProps, Modal} from "antd";
type ProjCategoryDTO = { type ProjCategoryDTO = {
@ -24,11 +24,11 @@ class MenuTreeItem implements IMenuTreeItem {
id: string; id: string;
pId: string; pId: string;
level: number; level: number;
isEdit: boolean;
isOpen: boolean; isOpen: boolean;
isParent: boolean; isParent: boolean;
name: string; name: string;
oldName: string; oldName: string;
parent?: IMenuTreeItem | null;
constructor(id: string, pId: string, name: string, level: number) { constructor(id: string, pId: string, name: string, level: number) {
this.id = id; this.id = id;
@ -36,10 +36,10 @@ class MenuTreeItem implements IMenuTreeItem {
this.level = level; this.level = level;
this.name = name; this.name = name;
this.oldName = name; this.oldName = name;
this.isEdit = false;
this.isOpen = false; this.isOpen = false;
this.isParent = false; this.isParent = false;
this.children = null; this.children = null;
this.parent = null;
} }
} }
@ -50,7 +50,10 @@ export default function MenuTreeWithTopButton() {
const [messageApi, messageContext] = useMessage(); const [messageApi, messageContext] = useMessage();
const menuTrees: Array<IMenuTreeItem> = []; const menuTrees: Array<IMenuTreeItem> = [];
const [menuTreeArray, setMenuTreeArray] = useState(menuTrees); const [menuTreeArray, setMenuTreeArray] = useState(menuTrees);
const newCategoryName: string = '新目录'; const [saveCategory, setSaveCategory] = useState<IMenuTreeItem>(new MenuTreeItem('-1', '0', '新目录', 1));
const [editCategory, setEditCategory] = useState<IMenuTreeItem>(new MenuTreeItem('-1', '0', '新目录', 1));
const [saveModal, setSaveModal] = useState(false);
const [editModal, setEditModal] = useState(false);
const menuArray = (datas: ProjCategoryDTO[], level: number) => { const menuArray = (datas: ProjCategoryDTO[], level: number) => {
const menus: MenuTreeItem[] = []; const menus: MenuTreeItem[] = [];
@ -65,7 +68,7 @@ export default function MenuTreeWithTopButton() {
return menus; return menus;
} }
const menus2Dropdowns = (datas: MenuTreeItem[] | null) => { const menus2Dropdowns = (datas: IMenuTreeItem[] | null) => {
if (!datas) { if (!datas) {
return; return;
} }
@ -82,6 +85,15 @@ export default function MenuTreeWithTopButton() {
return dropdowns; return dropdowns;
} }
const clearActive = (array: IMenuTreeItem[]) => {
array.forEach(item => {
item.active = false;
if(item.children) {
clearActive(item.children)
}
})
}
useEffect(() => { useEffect(() => {
get<ProjCategoryDTO[]>({ get<ProjCategoryDTO[]>({
messageApi, messageApi,
@ -101,25 +113,8 @@ export default function MenuTreeWithTopButton() {
<> <>
<div className="menu-tree-with-top-button"> <div className="menu-tree-with-top-button">
<button type="button" className="btn btn-orange" onClick={() => { <button type="button" className="btn btn-orange" onClick={() => {
// 新增 setSaveCategory(new MenuTreeItem('-1', '0', '新目录', 1));
post<any>({ setSaveModal(true)
messageApi,
url: '/api/proj/category/save',
body: {
projCategoryParentId: '0',
projCategoryName: newCategoryName
},
onSuccess({data}) {
const menuTreeItem = new MenuTreeItem(`${data.data}`, '0', newCategoryName, 1);
menuTreeItem.isParent = false;
menuTreeArray.push(menuTreeItem);
setMenuTreeArray([...menuTreeArray]);
indexListDispatchContext({
type: IndexListDataType.CATEGORY,
value: menus2Dropdowns(menuTreeArray)
})
}
})
}}> }}>
</button> </button>
<MenuTree <MenuTree
@ -132,8 +127,8 @@ export default function MenuTreeWithTopButton() {
}} }}
handleClick={(item) => { handleClick={(item) => {
const isActive = item.active; const isActive = item.active;
menuTreeArray.forEach(item => item.active = false); clearActive(menuTreeArray);
if(!isActive) { if (!isActive) {
item.active = true; item.active = true;
} }
setMenuTreeArray([ setMenuTreeArray([
@ -143,42 +138,18 @@ export default function MenuTreeWithTopButton() {
type: IndexListDataType.CATEGORY_CHANGE, type: IndexListDataType.CATEGORY_CHANGE,
value: item.active ? item.id : '' value: item.active ? item.id : ''
}) })
console.log(item)
}} }}
handleExpand={() => { handleExpand={() => {
}} }}
handleAddClick={(item) => { handleAddClick={(item) => {
post<any>({ const menuTreeItem = new MenuTreeItem('-1', item.id, '新目录', item.level + 1);
messageApi, menuTreeItem.parent = item;
url: '/api/proj/category/save', setSaveCategory(menuTreeItem);
body: { setSaveModal(true)
projCategoryParentId: item.id,
projCategoryName: newCategoryName
},
onSuccess({data}) {
item.isParent = true;
item.isOpen = true;
if (!item.children) {
item.children = new Array<IMenuTreeItem>();
}
const menuTreeItem = new MenuTreeItem(`${data.data}`, item.id, newCategoryName, item.level + 1);
menuTreeItem.isParent = false;
item.children.push(menuTreeItem);
setMenuTreeArray([
...menuTreeArray
])
indexListDispatchContext({
type: IndexListDataType.CATEGORY,
value: menus2Dropdowns(menuTreeArray)
})
}
})
}} }}
handleEditClick={(item) => { handleEditClick={(item) => {
item.isEdit = true; setEditCategory(item);
setMenuTreeArray([ setEditModal(true);
...menuTreeArray
])
}} }}
handleRemoveClick={(item, index, parent) => { handleRemoveClick={(item, index, parent) => {
del<any>({ del<any>({
@ -200,38 +171,7 @@ export default function MenuTreeWithTopButton() {
} }
}) })
}} }}
handleEditSaveClick={(item) => {
// 这里发请求,成功之后修改,失败还原
if (item.name === '') {
return;
}
put<any>({
messageApi,
url: `/api/proj/category/update/${item.id}`,
body: {
projCategoryParentId: item.pId,
projCategoryName: item.name
},
onSuccess() {
item.oldName = item.name;
item.isEdit = false;
setMenuTreeArray([
...menuTreeArray
])
indexListDispatchContext({
type: IndexListDataType.CATEGORY,
value: menus2Dropdowns(menuTreeArray)
})
}
})
}}
handleEditCancelClick={(item) => {
item.name = item.oldName;
item.isEdit = false;
setMenuTreeArray([
...menuTreeArray
])
}}
handleNameChange={(item) => { handleNameChange={(item) => {
indexListDispatchContext({ indexListDispatchContext({
type: IndexListDataType.CATEGORY_CHANGE, type: IndexListDataType.CATEGORY_CHANGE,
@ -240,6 +180,112 @@ export default function MenuTreeWithTopButton() {
}} }}
/> />
</div> </div>
<Modal open={saveModal}
title="添加目录"
okText="确定"
cancelText="取消"
okButtonProps={{
style: {
backgroundColor: 'var(--color-primary)'
}
}}
onCancel={() => {
setSaveModal(false);
}}
onOk={() => {
if(!saveCategory.name) {
messageApi.error('请输入名称');
return;
}
// 新增
post<any>({
messageApi,
url: '/api/proj/category/save',
body: {
projCategoryParentId: saveCategory.pId,
projCategoryName: saveCategory.name
},
onSuccess({data}) {
if (!saveCategory.parent) {
const menuTreeItem = new MenuTreeItem(`${data.data}`, '0', saveCategory.name, 1);
menuTreeItem.isParent = false;
menuTreeArray.push(menuTreeItem);
setMenuTreeArray([...menuTreeArray]);
indexListDispatchContext({
type: IndexListDataType.CATEGORY,
value: menus2Dropdowns(menuTreeArray)
})
} else {
saveCategory.parent.isParent = true;
saveCategory.parent.isOpen = true;
if (!saveCategory.parent.children) {
saveCategory.parent.children = new Array<IMenuTreeItem>();
}
const menuTreeItem = new MenuTreeItem(`${data.data}`, saveCategory.id, saveCategory.name, saveCategory.level);
menuTreeItem.isParent = false;
saveCategory.parent.children.push(menuTreeItem);
setMenuTreeArray([
...menuTreeArray
])
indexListDispatchContext({
type: IndexListDataType.CATEGORY,
value: menus2Dropdowns(menuTreeArray)
})
}
setSaveModal(false);
}
})
}}
>
<Input value={saveCategory?.name} placeholder="请输入目录标题" maxLength={10} onChange={(e) => {
saveCategory.name = e.target.value;
setSaveCategory({...saveCategory})
}}/>
</Modal>
<Modal open={editModal}
title="编辑目录"
okText="确定"
cancelText="取消"
okButtonProps={{
style: {
backgroundColor: 'var(--color-primary)'
}
}}
onCancel={() => {
setEditModal(false);
}}
onOk={() => {
if (editCategory.name === '') {
messageApi.error('请输入名称');
return;
}
put<any>({
messageApi,
url: `/api/proj/category/update/${editCategory.id}`,
body: {
projCategoryParentId: editCategory.pId,
projCategoryName: editCategory.name
},
onSuccess() {
editCategory.oldName = editCategory.name;
setMenuTreeArray([
...menuTreeArray
])
indexListDispatchContext({
type: IndexListDataType.CATEGORY,
value: menus2Dropdowns(menuTreeArray)
})
setEditModal(false);
}
})
}}
>
<Input value={editCategory?.name} placeholder="请输入目录标题" maxLength={10} onChange={(e) => {
editCategory.name = e.target.value;
setEditCategory({...editCategory})
}}/>
</Modal>
{messageContext} {messageContext}
</> </>
) )

View File

@ -5,11 +5,6 @@
margin-left: 10px; margin-left: 10px;
} }
.menu-tree ul li { .menu-tree ul li {
}
.menu-tree ul li.active {
text-decoration-line: underline;
text-underline-offset: 5px;
} }
.menu-tree ul li .menu-title { .menu-tree ul li .menu-title {
@ -33,6 +28,12 @@
white-space: nowrap; white-space: nowrap;
height: 22px; height: 22px;
line-height: 22px; line-height: 22px;
user-select: none;
-webkit-user-select: none;
}
.menu-tree ul li .menu-title .label span.active {
text-decoration-line: underline;
text-underline-offset: 5px;
} }
.menu-tree ul li .menu-title .label .menu-name-input { .menu-tree ul li .menu-title .label .menu-name-input {

View File

@ -28,7 +28,7 @@ html, body {
} }
a { a {
color: var(--color-dark); color: var(--color-blue);
text-decoration-line: none; text-decoration-line: none;
} }
@ -38,6 +38,10 @@ ul {
padding: 0; padding: 0;
} }
.text-btn {
cursor: pointer;
}
.btn { .btn {
border: none; border: none;
border-radius: 3px; border-radius: 3px;

View File

@ -18,4 +18,5 @@ export interface IAgent {
orderTypeName: string; orderTypeName: string;
overTime: string; overTime: string;
gmtCreate: string; gmtCreate: string;
orderAgreementStatus: string;
} }

View File

@ -4,11 +4,11 @@ export interface IMenuTreeItem {
level: number; level: number;
name: string; name: string;
oldName: string; oldName: string;
isEdit: boolean;
isOpen: boolean; isOpen: boolean;
isParent: boolean; isParent: boolean;
active?: boolean; active?: boolean;
children: Array<IMenuTreeItem> | null; children: Array<IMenuTreeItem> | null;
parent?: IMenuTreeItem | null
} }
export interface IMenuTree { export interface IMenuTree {
@ -27,10 +27,6 @@ export interface IMenuTree {
handleRemoveClick(item: IMenuTreeItem, index: number, parent?: IMenuTreeItem): void; handleRemoveClick(item: IMenuTreeItem, index: number, parent?: IMenuTreeItem): void;
handleEditSaveClick(item: IMenuTreeItem): void;
handleEditCancelClick(tem: IMenuTreeItem): void;
handleNameChange(item: IMenuTreeItem): void; handleNameChange(item: IMenuTreeItem): void;
} }

View File

@ -75,6 +75,9 @@ export default function Head() {
<span className="title">退</span> <span className="title">退</span>
</div> </div>
), ),
onClick: () => {
window.location.href = '/copyright/logout'
}
}, },
] ]

View File

@ -1,9 +1,12 @@
import ReactDOM from 'react-dom/client' import ReactDOM from 'react-dom/client'
import App from './App.tsx' import App from './App.tsx'
import './index.css' import './index.css'
import {StyleProvider, legacyLogicalPropertiesTransformer} from "@ant-design/cssinjs";
ReactDOM.createRoot(document.getElementById('root')!).render( ReactDOM.createRoot(document.getElementById('root')!).render(
<StyleProvider hashPriority="high" transformers={[legacyLogicalPropertiesTransformer]}>
<App/> <App/>
</StyleProvider>
// <React.StrictMode> // <React.StrictMode>
// <App/> // <App/>
// </React.StrictMode>, // </React.StrictMode>,

View File

@ -55,7 +55,7 @@ export default function Index() {
} }
}, },
list: [ list: [
{id: 'ALL', name: '全部项目', active: true}, {id: 'ALL', name: '全部项目'},
{id: 'PROCESSING', name: '进行中的'}, {id: 'PROCESSING', name: '进行中的'},
{id: 'COMPLETE', name: '已完成的'} {id: 'COMPLETE', name: '已完成的'}
], ],

View File

@ -23,12 +23,13 @@ export default function ProjEdit() {
const [configArray, setConfigArray] = useState<IProjEdit[]>([]); const [configArray, setConfigArray] = useState<IProjEdit[]>([]);
const [isEditStepEdited, setIsEditStepEdited] = useState(false); const [isEditStepEdited, setIsEditStepEdited] = useState(false);
const [isConfigEdited, setIsConfigEdited] = useState(false); const [isConfigEdited, setIsConfigEdited] = useState(false);
// const [isAllStepEdited, setIsAllStepEdited] = useState(false);
const [canGenerate, setCanGenerate] = useState(false); const [canGenerate, setCanGenerate] = useState(false);
const [generateStatus, setGenerateStatus] = useState(GenerateStatus.NONE); const [generateStatus, setGenerateStatus] = useState(GenerateStatus.NONE);
const [generateEmainingTime, setGenerateEmainingTime] = useState(0); const [generateEmainingTime, setGenerateEmainingTime] = useState(0);
const [isGenerateModalOpen, setIsGenerateModalOpen] = useState(false); const [isGenerateModalOpen, setIsGenerateModalOpen] = useState(false);
const [previewUrl, setPreviewUrl] = useState(''); const [previewUrl, setPreviewUrl] = useState('');
const [generateErrorModal, setGenerateErrorModal] = useState(false);
const [generateErrorMsg, setGenerateErrorMsg] = useState('');
const height = window.innerHeight - 240; const height = window.innerHeight - 240;
@ -185,7 +186,7 @@ export default function ProjEdit() {
&& data.editSteps[3].editStatus == EditStepEnum.EDITED && data.editSteps[3].editStatus == EditStepEnum.EDITED
&& data.editSteps[4].editStatus == EditStepEnum.EDITED && data.editSteps[4].editStatus == EditStepEnum.EDITED
&& data.editSteps[5].editStatus == EditStepEnum.EDITED; && data.editSteps[5].editStatus == EditStepEnum.EDITED;
const isConfig = data.loginpage.loginpageId && MAX_MOD_SIZE > 0; const isConfig = data.loginpage.loginpageId && data.projModCount > MAX_MOD_SIZE;
const isGenerate = isEdited && isConfig; const isGenerate = isEdited && isConfig;
const isGenerateSuccess: boolean = data.generate.generateStatus == GenerateStatus.SUCCESS; const isGenerateSuccess: boolean = data.generate.generateStatus == GenerateStatus.SUCCESS;
renderEditStep(data.editSteps, isEdited, isGenerateSuccess); renderEditStep(data.editSteps, isEdited, isGenerateSuccess);
@ -193,7 +194,8 @@ export default function ProjEdit() {
setCanGenerate(isGenerate); setCanGenerate(isGenerate);
setGenerateStatus(data.generate.generateStatus); setGenerateStatus(data.generate.generateStatus);
setPreviewUrl(data.previewUrl); setPreviewUrl(data.previewUrl);
setGenerateEmainingTime(data.generate.emainingTime); setGenerateEmainingTime(data.generate.generateEmainingTime);
setGenerateErrorMsg(data.generate.generateMsg);
} }
}) })
} }
@ -309,6 +311,7 @@ export default function ProjEdit() {
<CardProjResult title="生成失败" <CardProjResult title="生成失败"
isSuccess={false} isSuccess={false}
handleFeedback={() => { handleFeedback={() => {
setGenerateErrorModal(true);
console.log('反馈') console.log('反馈')
}} }}
/> />
@ -385,6 +388,20 @@ export default function ProjEdit() {
}}> }}>
<div>便</div> <div>便</div>
</Modal> </Modal>
<Modal open={generateErrorModal}
title="出错信息"
okText="确定"
cancelText={false}
footer={false}
okButtonProps={{
style: {
backgroundColor: 'var(--color-primary)',
}
}}
onCancel={() => {setGenerateErrorModal(false)}}
>
<p style={{color: 'var(--color-red)'}}>{generateErrorMsg}</p>
</Modal>
</> </>
) )
} }

View File

@ -0,0 +1,390 @@
import './proj-edit.css';
import {Link, useNavigate, useParams} from "react-router-dom";
import {Breadcrumb, Button, message, Modal} from "antd";
import StepProjEdit from "../../components/step/StepProjEdit.tsx";
import CardProjEdit from "../../components/card/CardProjEdit.tsx";
import {Process} from "../../interfaces/step/IStepProj.ts";
import CardProjLoading from "../../components/card/CardProjLoading.tsx";
import CardProjResult from "../../components/card/CardProjResult.tsx";
import CardProjDownload from "../../components/card/CardProjDownload.tsx";
import CardProjJump from "../../components/card/CardProjJump.tsx";
import {useEffect, useState} from "react";
import {Axios, get, post} from "../../util/AjaxUtils.ts";
import {EditStepEnum, IProjEdit} from "../../interfaces/card/ICardProj.ts";
import {MAX_MOD_SIZE} from "./edit/ProjConfigModList.tsx";
import {GenerateStatus} from "../../interfaces/proj/IProj.ts";
export default function ProjEditAll() {
const nav = useNavigate();
const pathParams = useParams();
const [messageApi, contextHolder] = message.useMessage();
const [editStepArray, setEditStepArray] = useState<IProjEdit[]>([]);
const [configArray, setConfigArray] = useState<IProjEdit[]>([]);
const [isEditStepEdited, setIsEditStepEdited] = useState(false);
const [isConfigEdited, setIsConfigEdited] = useState(false);
// const [isAllStepEdited, setIsAllStepEdited] = useState(false);
const [canGenerate, setCanGenerate] = useState(false);
const [generateStatus, setGenerateStatus] = useState(GenerateStatus.NONE);
const [generateEmainingTime, setGenerateEmainingTime] = useState(0);
const [isGenerateModalOpen, setIsGenerateModalOpen] = useState(false);
const [previewUrl, setPreviewUrl] = useState('');
const height = window.innerHeight - 240;
const renderEditStep = (editSteps: any[], isEdited: boolean, isGenerateSuccess: boolean) => {
const editStepArray: IProjEdit[] = [];
editStepArray.push(
{
title: '标题简介',
desc: '完善代码、样式类型和详细介绍等内容',
step: 1,
btnName: !isGenerateSuccess ? '设置' : '查看',
status: editSteps[0].editStatus,
handleEdit() {
if (!isGenerateSuccess) {
nav(`/proj-edit/step1/${pathParams.projId}`)
} else {
nav(`/proj-edit/step1-show/${pathParams.projId}`)
}
}
},
{
title: '基本信息',
desc: '完善项目简介、编程语言、版本、公司等内容',
step: 2,
btnName: !isGenerateSuccess ? '设置' : '查看',
status: editSteps[1].editStatus,
handleEdit() {
if (generateStatus != GenerateStatus.SUCCESS) {
nav(`/proj-edit/step2/${pathParams.projId}`)
} else {
nav(`/proj-edit/step2-show/${pathParams.projId}`)
}
}
},
{
title: '软件功能特点',
desc: '请完善软件功能特点',
step: 3,
btnName: !isGenerateSuccess ? '设置' : '查看',
status: editSteps[2].editStatus,
handleEdit() {
if (!isGenerateSuccess) {
nav(`/proj-edit/step3/${pathParams.projId}`)
} else {
nav(`/proj-edit/step3-show/${pathParams.projId}`)
}
}
},
{
title: '著作人信息',
desc: '请完善著作人相关信息',
step: 4,
btnName: !isGenerateSuccess ? '设置' : '查看',
status: editSteps[3].editStatus,
handleEdit() {
if (!isGenerateSuccess) {
nav(`/proj-edit/step4/${pathParams.projId}`)
} else {
nav(`/proj-edit/step4-show/${pathParams.projId}`)
}
}
},
{
title: '申请人信息',
desc: '请完善申请人信息',
step: 5,
btnName: !isGenerateSuccess ? '设置' : '查看',
status: editSteps[4].editStatus,
handleEdit() {
if (!isGenerateSuccess) {
nav(`/proj-edit/step5/${pathParams.projId}`)
} else {
nav(`/proj-edit/step5-show/${pathParams.projId}`)
}
}
},
{
title: '选择登录页面',
desc: '选择软件的登录页面模板',
step: 6,
btnName: !isGenerateSuccess ? '设置' : '查看',
status: editSteps[5].editStatus,
handleEdit() {
if (!isGenerateSuccess) {
nav(`/proj-edit/step6/${pathParams.projId}`)
} else {
nav(`/proj-edit/step6-show/${pathParams.projId}`)
}
}
}
)
setEditStepArray(editStepArray);
setIsEditStepEdited(isEdited);
}
const renderSetting = (data: any, isConfig: boolean, isGenerateSuccess: boolean) => {
const configArray: IProjEdit[] = [];
configArray.push(
{
title: '登录界面设置',
desc: '请对登录界面完成个性化设置',
step: 1,
btnName: !isGenerateSuccess ? '设置' : '查看',
status: data.loginpage.loginpageId ? EditStepEnum.EDITED : EditStepEnum.UN_EDIT,
handleEdit() {
if (!isGenerateSuccess) {
nav(`/proj-edit/config-loginpage/${pathParams.projId}`)
} else {
nav(`/proj-edit/config-loginpage-show/${pathParams.projId}`)
}
}
},
{
title: '系统菜单管理',
desc: '请对系统菜单进行设置',
step: 2,
btnName: !isGenerateSuccess ? '设置' : '查看',
status: data.projModCount > MAX_MOD_SIZE ? EditStepEnum.EDITED : EditStepEnum.UN_EDIT,
handleEdit() {
if (!isGenerateSuccess) {
nav(`/proj-edit/config-mod-list/${pathParams.projId}`)
} else {
nav(`/proj-edit/config-mod-list-show/${pathParams.projId}`)
}
}
},
{
title: '菜单顺序',
desc: '调整菜单顺序',
step: 3,
btnName: !isGenerateSuccess ? '设置' : '查看',
status: data.projModCount > MAX_MOD_SIZE ? EditStepEnum.EDITED : EditStepEnum.UN_EDIT,
handleEdit() {
if (!isGenerateSuccess) {
nav(`/proj-edit/config-menu-list/${pathParams.projId}`)
} else {
nav(`/proj-edit/config-menu-list-show/${pathParams.projId}`)
}
}
}
)
setConfigArray(configArray);
setIsConfigEdited(isConfig);
}
const renderData = () => {
get<any>({
messageApi: messageApi,
url: `/api/proj/get/${pathParams.projId}`,
onSuccess({data}) {
const isEdited = data.editSteps[0].editStatus == EditStepEnum.EDITED
&& data.editSteps[1].editStatus == EditStepEnum.EDITED
&& data.editSteps[2].editStatus == EditStepEnum.EDITED
&& data.editSteps[3].editStatus == EditStepEnum.EDITED
&& data.editSteps[4].editStatus == EditStepEnum.EDITED
&& data.editSteps[5].editStatus == EditStepEnum.EDITED;
const isConfig = data.loginpage.loginpageId && MAX_MOD_SIZE > 0;
const isGenerate = isEdited && isConfig;
const isGenerateSuccess: boolean = data.generate.generateStatus == GenerateStatus.SUCCESS;
renderEditStep(data.editSteps, isEdited, isGenerateSuccess);
renderSetting(data, isConfig, isGenerateSuccess);
setCanGenerate(isGenerate);
setGenerateStatus(data.generate.generateStatus);
setPreviewUrl(data.previewUrl);
setGenerateEmainingTime(data.generate.emainingTime);
}
})
}
useEffect(() => {
renderData();
}, [])
return (
<>
{contextHolder}
<Breadcrumb
items={[
{title: <Link to={'/'}></Link>},
{title: <Link to={'/proj-create'}></Link>},
{title: '编辑项目'},
]}
/>
<div className="proj-edit" style={{height: `${height}px`}}>
<StepProjEdit step={1} process={isEditStepEdited ? Process.COMPLETE : Process.PROCESSING}
descTitle="完善信息"
descDetail="完善项目的基本信息"
hasNext={true}>
{
editStepArray.map((item, index) => {
return <CardProjEdit key={`editStep-${index}`}
title={item.title}
desc={item.desc}
status={item.status}
btnName={item.btnName}
handleEdit={item.handleEdit}
/>
})
}
</StepProjEdit>
<StepProjEdit step={2}
process={!isEditStepEdited ? Process.PENDING : (isConfigEdited ? Process.COMPLETE : Process.PROCESSING)}
descTitle="功能设置"
descDetail="设置系统的菜单功能" hasNext={true}>
{
configArray.map((item, index) => {
return <CardProjEdit key={`config-${index}`}
title={item.title}
desc={item.desc}
btnName={item.btnName}
canBtnClick={isEditStepEdited}
status={item.status}
handleEdit={item.handleEdit}
/>
})
}
{
isEditStepEdited && isConfigEdited ? (
<CardProjJump title="预览系统"
desc="点击查看预览系统"
handleJump={() => {
window.open(`${Axios.defaults?.baseURL}/${previewUrl}`, '_blank')
}}
/>
) : <></>
}
</StepProjEdit>
<StepProjEdit step={3}
process={generateStatus == GenerateStatus.SUCCESS ? Process.COMPLETE : (canGenerate ? Process.PROCESSING : Process.PENDING)}
descTitle="资料生成"
hasNext={true}>
{
generateStatus == GenerateStatus.NONE || generateStatus == GenerateStatus.FAILED ? (
<CardProjEdit title="资料生成"
desc="生成软著所需要的资料,此操作后项目无法再次编辑"
btnName="生成"
status={EditStepEnum.UN_EDIT}
canBtnClick={canGenerate}
handleEdit={() => {
setIsGenerateModalOpen(true);
}}
/>
) : <></>
}
{
generateStatus == GenerateStatus.PENDING ? (
<CardProjLoading title="正在排队"
desc="资料正在排队"
duration={generateEmainingTime}
handleCountDownOver={() => {
renderData();
}}
/>
) : <></>
}
{
generateStatus == GenerateStatus.GENERATING ? (
<CardProjLoading title="正在生成"
desc="资料正在生成"
duration={generateEmainingTime}
handleCountDownOver={() => {
renderData();
}}
/>
) : <></>
}
{
generateStatus == GenerateStatus.SUCCESS ? (
<CardProjResult title="生成成功"
isSuccess={true}
/>
) : <></>
}
{
generateStatus == GenerateStatus.FAILED ? (
<CardProjResult title="生成失败"
isSuccess={false}
handleFeedback={() => {
console.log('反馈')
}}
/>
) : <></>
}
</StepProjEdit>
<StepProjEdit step={4}
process={generateStatus == GenerateStatus.SUCCESS ? Process.PROCESSING : Process.PENDING}
descTitle="资料下载">
<CardProjDownload title="申请表"
desc="点击下载申请表"
canBtnClick={generateStatus == GenerateStatus.SUCCESS}
handleDownload={() => {
window.open(`${Axios.defaults?.baseURL}/route/proj/download/apply/${pathParams.projId}`)
}}
/>
<CardProjDownload title="操作手册"
desc="点击下载操作手册"
canBtnClick={generateStatus == GenerateStatus.SUCCESS}
handleDownload={() => {
window.open(`${Axios.defaults?.baseURL}/route/proj/download/manual/${pathParams.projId}`)
}}
/>
<CardProjDownload title="代码压缩包"
desc="点击下载代码压缩包"
canBtnClick={generateStatus == GenerateStatus.SUCCESS}
handleDownload={() => {
window.open(`${Axios.defaults?.baseURL}/route/proj/download/code-zip/${pathParams.projId}`)
}}
/>
<CardProjDownload title="代码文档"
desc="点击下载代码文档"
canBtnClick={generateStatus == GenerateStatus.SUCCESS}
handleDownload={() => {
window.open(`${Axios.defaults?.baseURL}/route/proj/download/code/${pathParams.projId}`)
}}
/>
<CardProjJump title="找代理"
desc="到软著代理完成软著申请"
handleJump={() => {
nav(`/agent-select/${pathParams.projId}`);
}}
/>
</StepProjEdit>
</div>
<div className="btn-container">
<Button size="large" style={{
width: '200px',
fontSize: '14px',
backgroundColor: 'var(--color-primary)',
color: 'var(--color-light)'
}} onClick={() => {
nav(-1);
}}></Button>
</div>
<Modal title="提示"
okText="确定"
cancelText="取消"
open={isGenerateModalOpen}
onOk={() => {
post({
messageApi,
url: `/api/proj/generate/proj-id/${pathParams.projId}`,
body: {},
onSuccess() {
messageApi.success('提交成功');
setIsGenerateModalOpen(false);
renderData();
}
})
}}
onCancel={() => {
setIsGenerateModalOpen(false);
}}>
<div>便</div>
</Modal>
</>
)
}

View File

@ -10,7 +10,7 @@ import {useEffect, useState} from "react";
import {EditOutlined, PlusOutlined, DeleteOutlined, SearchOutlined} from "@ant-design/icons"; import {EditOutlined, PlusOutlined, DeleteOutlined, SearchOutlined} from "@ant-design/icons";
import {del, get} from "../../../util/AjaxUtils.ts"; import {del, get} from "../../../util/AjaxUtils.ts";
export const MAX_MOD_SIZE = 15; export const MAX_MOD_SIZE = 5;
interface DataType { interface DataType {
projModId: string; projModId: string;

View File

@ -5,7 +5,8 @@ export const Axios = axios;
axios.defaults.baseURL = 'http://127.0.0.1:7025/copyright'; axios.defaults.baseURL = 'http://127.0.0.1:7025/copyright';
// axios.defaults.baseURL = '/copyright'; // axios.defaults.baseURL = '/copyright';
export const DevUserId: string = '80d3365e-0597-4988-979e-18ef1c3ec671'; // export const DevUserId: string = '80d3365e-0597-4988-979e-18ef1c3ec671'; // 18634604067
export const DevUserId: string = 'c2438eb8-2685-49a9-bf02-5111a5192d96'; // 18647109157
// export const DevUserId: string = ''; // export const DevUserId: string = '';
type Req<T> = { type Req<T> = {