完成代理服务选择和列表

This commit is contained in:
WenC 2024-03-27 18:56:48 +08:00
parent 3bf300feee
commit c412ff3ec6
17 changed files with 698 additions and 389 deletions

View File

@ -2,6 +2,7 @@ import './card-agent.css';
import {Image} from "antd";
import {errorImage} from "../../util/CommonUtil.ts";
import {AgentMedalEnum, IAgent} from "../../interfaces/card/ICardProj.ts";
import {downloadUrl} from "../../util/AjaxUtils.ts";
export default function CardAgent(props: IAgent) {
@ -23,12 +24,12 @@ export default function CardAgent(props: IAgent) {
props.handleSelect();
}}>
<div className="card-agent-head">
{props.logo ? <Image width={30} src={props.logo} fallback={errorImage}/> : <></>}
{props.logo ? <Image width={30} src={downloadUrl(props.logo.split(',')[0], false)} fallback={errorImage}/> : <></>}
<span className="card-agent-title">{props.name}</span>
{renderMedal()}
</div>
<div className="card-agent-body">
<div className="card-agent-body-content">{props.desc}</div>
<div className="card-agent-body-content" dangerouslySetInnerHTML={{__html: props.desc}}></div>
<Image width={140} height={100} src={props.certificateImg} fallback={errorImage}/>
</div>
</div>

View File

@ -1,27 +1,74 @@
import './card-proj-agent.css'
import {OrderedListOutlined, NumberOutlined, SearchOutlined} from "@ant-design/icons";
import { Tag } from 'antd';
import {IAgent} from "../../interfaces/agent/IAgent.ts";
export default function CardProjAgent(props: IAgent) {
/**
*
*/
const renderTakeStatus = () => {
if(props.isTake == 0) {
return <Tag color="default"></Tag>;
}
if(props.isTake == 1) {
return <Tag color="success"></Tag>;
}
if(props.isTake == 2) {
return <Tag color="error"></Tag>;
}
return <></>;
}
/**
*
*/
const renderAgreementStatus = () => {
if(props.isAgreement == 0) {
return <Tag color="error"></Tag>;
}
if(props.isAgreement == 1) {
return <Tag color="success"></Tag>;
}
return <></>;
}
/**
*
*/
const renderOverStatus = () => {
if(props.isOver == 0) {
return <Tag color="default"></Tag>;
}
if(props.isOver == 1) {
return <Tag color="success"></Tag>;
}
if(props.isOver == 2) {
return <Tag color="error"></Tag>
}
return <></>;
}
export default function CardProjAgent() {
return (
<div className="card-proj-agent">
<div className="title">
<div className="left">
<a href="/#"></a>
<a href="/#">{props.projName}</a>
</div>
<div className="right">
<span className="agent">SDFSDF</span>
<span className="orderNo">XXXXXXXXXXXXX</span>
<span className="agent">{props.basicsName}</span>
<span className="orderNo">{props.orderNumber}</span>
</div>
</div>
<hr/>
<div className="body">
<div className="line">
<div className="left">
<span>500</span>
<span>{props.orderShoppingAmount / 100}</span>
</div>
<div className="right">
<span>2024-03-05 17:22:02</span>
<span>{props.gmtCreate}</span>
</div>
</div>
<div className="line">
@ -32,7 +79,7 @@ export default function CardProjAgent() {
</span>
<span>
<NumberOutlined />
<a href="/#"></a>
<a href="/#">({props.materialAmendApplyCount})</a>
</span>
</div>
<div className="right">
@ -45,20 +92,9 @@ export default function CardProjAgent() {
</div>
<hr/>
<div className="tail">
<span className="status order-status">
<Tag color="default"></Tag>
<Tag color="success"></Tag>
<Tag color="error"></Tag>
</span>
<span className="status agreement-status">
<Tag color="success"></Tag>
<Tag color="error"></Tag>
</span>
<span className="status process-status">
<Tag color="default"></Tag>
<Tag color="success"></Tag>
<Tag color="error"></Tag>
</span>
<span className="status order-status">{renderTakeStatus()}</span>
<span className="status agreement-status">{renderAgreementStatus()}</span>
<span className="status process-status">{renderOverStatus()}</span>
</div>
</div>
)

View File

@ -63,10 +63,10 @@
.card-agent .card-agent-body .card-agent-body-content {
width: 200px;
height: 100px;
height: 93px;
overflow: hidden;
display: -webkit-box;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 5;
-webkit-line-clamp: 4;
}

View File

@ -1,42 +1,50 @@
import './list-proj.css'
import CardProj from "../card/CardProj.tsx";
import {useRef, MutableRefObject, useState, useEffect} from "react";
import {Input, Pagination, message} from 'antd';
import type {SearchProps} from 'antd/es/input/Search';
import {useRef, MutableRefObject, useState, useEffect, useContext} from "react";
import {Input, Pagination, message, Spin} from 'antd';
import {get} from "../../util/AjaxUtils.ts";
import {IndexListContext} from "../../context/IndexListContext.ts";
import {IListPage} from "../../interfaces/listpage/IListPage.ts";
import {IProj} from "../../interfaces/proj/IProj.ts";
const {Search} = Input;
const onSearch: SearchProps['onSearch'] = (value, _e, info) => {
console.log(info?.source, value)
};
export default function ListProj() {
const indexListContext = useContext(IndexListContext);
const listProjRef: MutableRefObject<HTMLDivElement | null> = useRef(null);
const listRef: MutableRefObject<HTMLDivElement | null> = useRef(null);
const [messageApi, contextHolder] = message.useMessage();
const [page, setPage] = useState(1);
const [total, setTotal] = useState(0);
const [projs, setProjs] = useState([]);
const [projs, setProjs] = useState<IProj[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [keywords, setKeywords] = useState('');
const domHeight = window.innerHeight - 280;
const reqData = (currentPage: number) => {
get({
get<IListPage<IProj>>({
messageApi: messageApi,
url: '/api/proj/listpage/self',
config: {
params: {
page: currentPage,
rows: 20
rows: 20,
keywords: keywords,
status: indexListContext.status ? indexListContext.status : ''
}
},
onBefore() {
setIsLoading(true);
},
onSuccess({data}) {
setProjs(data.page);
setPage(data.page);
setTotal(data.total);
setProjs(data.rows);
},
onFinally() {
setIsLoading(false);
}
})
}
@ -47,25 +55,28 @@ export default function ListProj() {
useEffect(() => {
reqData(page);
}, [])
}, [indexListContext.status, keywords, page])
return (
<>
{contextHolder}
<div className="list-proj" ref={listProjRef}>
<div className="top">
<Search placeholder="按项目名搜索" onSearch={onSearch} style={{width: 200}}/>
<Search placeholder="按项目名搜索" onSearch={(value) => {
setKeywords(value)
}} style={{width: 200}}/>
</div>
<div className="body">
<div className="list" ref={listRef} style={{height: `${domHeight}px`}}>
{renderList()}
</div>
<div className="page">
<Pagination defaultCurrent={page} total={total} onChange={(page) => {
setPage(page);
reqData(page);
}}/>
</div>
<Spin tip="加载中..." spinning={isLoading}>
<div className="list" ref={listRef} style={{height: `${domHeight}px`}}>
{renderList()}
</div>
<div className="page">
<Pagination defaultCurrent={page} total={total} onChange={(page) => {
setPage(page);
}}/>
</div>
</Spin>
</div>
</div>
</>

View File

@ -1,40 +1,99 @@
import './list-proj-agent.css';
import CardProjAgent from "../card/CardProjAgent.tsx";
import {useRef, MutableRefObject} from "react";
import {Input, Pagination} from 'antd';
import type {SearchProps} from 'antd/es/input/Search';
import {useRef, MutableRefObject, useEffect, useState, useContext} from "react";
import {Input, Pagination, Spin} from 'antd';
import {get} from "../../util/AjaxUtils.ts";
import useMessage from "antd/es/message/useMessage";
import {IListPage} from "../../interfaces/listpage/IListPage.ts";
import {IndexListContext} from "../../context/IndexListContext.ts";
import {IAgent} from "../../interfaces/agent/IAgent.ts";
const {Search} = Input;
const onSearch: SearchProps['onSearch'] = (value, _e, info) => {
console.log(info?.source, value)
};
export default function ListProjAgent() {
const indexListContext = useContext(IndexListContext);
const [messageApi, messageApiHolder] = useMessage();
const listProjRef: MutableRefObject<HTMLDivElement | null> = useRef(null);
const listRef: MutableRefObject<HTMLDivElement | null> = useRef(null);
const domHeight = window.innerHeight - 301;
const [page, setPage] = useState(1);
const [total, setTotal] = useState(0);
const [agents, setAgents] = useState<IAgent[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [keywords, setKeywords] = useState('');
const domHeight = window.innerHeight - 280;
useEffect(() => {
get<IListPage<IAgent>>({
messageApi,
url: `/api/agent/order/listpage`,
config: {
params: {
page: page,
rows: 20,
keywords: keywords,
status: indexListContext.status ? indexListContext.status : ''
}
},
onBefore() {
setIsLoading(true);
},
onSuccess({data}) {
setPage(data.page);
setTotal(data.total);
setAgents(data.rows);
},
onFinally() {
setIsLoading(false);
}
})
}, [indexListContext.status, keywords, page])
return (
<div className="list-proj-agent" ref={listProjRef}>
<div className="top">
<Search placeholder="按项目名搜索" onSearch={onSearch} style={{width: 200}}/>
</div>
<div className="body">
<div className="list" ref={listRef} style={{height: `${domHeight}px`}}>
<CardProjAgent />
<CardProjAgent />
<CardProjAgent />
<CardProjAgent />
<CardProjAgent />
<CardProjAgent />
<>
<div className="list-proj-agent" ref={listProjRef}>
<div className="top">
<Search placeholder="按项目名搜索" onSearch={(value) => {
setKeywords(value)
}} style={{width: 200}}/>
</div>
<div className="page">
<Pagination defaultCurrent={1} total={50}/>
<div className="body">
<Spin tip="加载中..." spinning={isLoading}>
<div className="list" ref={listRef} style={{height: `${domHeight}px`}}>
{
agents.map(item => <CardProjAgent key={item.orderNumber}
projId={item.projId}
projName={item.projName}
projOrderNo={item.projOrderNo}
agentBasicsId={item.agentBasicsId}
basicsName={item.basicsName}
isAgreement={item.isAgreement}
isOver={item.isOver}
isResult={item.isResult}
isTake={item.isTake}
materialAmendApplyCount={item.materialAmendApplyCount}
orderId={item.orderId}
orderNote={item.orderNote}
orderNumber={item.orderNumber}
orderShoppingAmount={item.orderShoppingAmount}
orderType={item.orderType}
orderTypeAmount={item.orderTypeAmount}
orderTypeName={item.orderTypeName}
overTime={item.overTime}
gmtCreate={item.gmtCreate}
/>)
}
</div>
</Spin>
<div className="page">
<Pagination defaultCurrent={page} total={total}/>
</div>
</div>
</div>
</div>
{messageApiHolder}
</>
)
}

View File

@ -15,8 +15,6 @@ export interface GlobalData {
user: User;
}
export interface GlobalDataAction {
type: number;
user?: User;

View File

@ -0,0 +1,22 @@
import {createContext, Dispatch} from "react";
export enum IndexListDataType {
PROJ,
AGENT,
}
export interface ListData {
type: IndexListDataType;
status?: string;
}
export interface ListAction {
type: IndexListDataType;
value: string;
}
export const IndexListContext = createContext<ListData>({
type: IndexListDataType.PROJ
})
export const IndexListDispatchContext = createContext<Dispatch<ListAction>>(() => {})

View File

@ -0,0 +1,21 @@
export interface IAgent {
projId: string;
projName: string;
projOrderNo: string;
agentBasicsId: string;
basicsName: string;
isAgreement: number;
isOver: number;
isResult: number;
isTake: number;
materialAmendApplyCount: number;
orderId: string;
orderNote: string;
orderNumber: string;
orderShoppingAmount: number;
orderType: string;
orderTypeAmount: number;
orderTypeName: string;
overTime: string;
gmtCreate: string;
}

View File

@ -0,0 +1,5 @@
export interface IListPage<T> {
page: number;
total: number;
rows: T[]
}

View File

@ -1,139 +1,6 @@
import './body.css'
import {createBrowserRouter, RouterProvider} from 'react-router-dom';
import Index from '../../route/index';
import ProjCreate from "../../route/proj/ProjCreate.tsx";
import ProjNew from "../../route/proj/ProjNew.tsx";
import ProjEdit from "../../route/proj/ProjEdit.tsx";
import AgentSelect from "../../route/agent/AgentSelect.tsx";
import ProjEditStep1 from "../../route/proj/edit/ProjEditStep1.tsx";
import ProjEditStep2 from "../../route/proj/edit/ProjEditStep2.tsx";
import ProjEditStep3 from "../../route/proj/edit/ProjEditStep3.tsx";
import ProjEditStep4 from "../../route/proj/edit/ProjEditStep4.tsx";
import ProjEditStep5 from "../../route/proj/edit/ProjEditStep5.tsx";
import ProjEditStep6 from "../../route/proj/edit/ProjEditStep6.tsx";
import ProjConfigLoginpage from "../../route/proj/edit/ProjConfigLoginpage.tsx";
import ProjConfigModList from "../../route/proj/edit/ProjConfigModList.tsx";
import ProjConfigModSave from "../../route/proj/edit/ProjConfigModSave.tsx";
import ProjConfigModEdit from "../../route/proj/edit/ProjConfigModEdit.tsx";
import ProjConfigModShow from "../../route/proj/edit/ProjConfigModShow.tsx";
import ProjConfigMenuList from "../../route/proj/edit/ProjConfigMenuList.tsx";
import ProjEditStep1Show from "../../route/proj/edit/ProjEditStep1Show.tsx";
import ProjEditStep2Show from "../../route/proj/edit/ProjEditStep2Show.tsx";
import ProjEditStep3Show from "../../route/proj/edit/ProjEditStep3Show.tsx";
import ProjEditStep4Show from "../../route/proj/edit/ProjEditStep4Show.tsx";
import ProjEditStep5Show from "../../route/proj/edit/ProjEditStep5Show.tsx";
import ProjEditStep6Show from "../../route/proj/edit/ProjEditStep6Show.tsx";
import ProjConfigLoginpageShow from "../../route/proj/edit/ProjConfigLoginpageShow.tsx";
import ProjConfigMenuListShow from "../../route/proj/edit/ProjConfigMenuListShow.tsx";
import ProjConfigModListShow from "../../route/proj/edit/ProjConfigModListShow.tsx";
const router = createBrowserRouter([
{
path: '/',
element: <Index/>
},
{
path: '/proj-create',
element: <ProjCreate/>
},
{
path: '/proj-new/:projChargeType',
element: <ProjNew/>
},
{
path: '/proj-edit/:projId',
element: <ProjEdit/>
},
{
path: '/proj-edit/step1/:projId',
element: <ProjEditStep1/>
},
{
path: '/proj-edit/step1-show/:projId',
element: <ProjEditStep1Show/>
},
{
path: '/proj-edit/step2/:projId',
element: <ProjEditStep2/>
},
{
path: '/proj-edit/step2-show/:projId',
element: <ProjEditStep2Show/>
},
{
path: '/proj-edit/step3/:projId',
element: <ProjEditStep3/>
},
{
path: '/proj-edit/step3-show/:projId',
element: <ProjEditStep3Show/>
},
{
path: '/proj-edit/step4/:projId',
element: <ProjEditStep4/>
},
{
path: '/proj-edit/step4-show/:projId',
element: <ProjEditStep4Show/>
},
{
path: '/proj-edit/step5/:projId',
element: <ProjEditStep5/>
},
{
path: '/proj-edit/step5-show/:projId',
element: <ProjEditStep5Show/>
},
{
path: '/proj-edit/step6/:projId',
element: <ProjEditStep6/>
},
{
path: '/proj-edit/step6-show/:projId',
element: <ProjEditStep6Show/>
},
{
path: '/proj-edit/config-loginpage/:projId',
element: <ProjConfigLoginpage/>
},
{
path: '/proj-edit/config-loginpage-show/:projId',
element: <ProjConfigLoginpageShow/>
},
{
path: '/proj-edit/config-mod-list/:projId',
element: <ProjConfigModList/>
},
{
path: '/proj-edit/config-mod-list-show/:projId',
element: <ProjConfigModListShow/>
},
{
path: '/proj-edit/config-mod-save/:projId',
element: <ProjConfigModSave/>
},
{
path: '/proj-edit/config-mod-edit/:projId/:projModId',
element: <ProjConfigModEdit/>
},
{
path: '/proj-edit/config-mod-show/:projId/:projModId',
element: <ProjConfigModShow/>
},
{
path: '/proj-edit/config-menu-list/:projId',
element: <ProjConfigMenuList/>
},
{
path: '/proj-edit/config-menu-list-show/:projId',
element: <ProjConfigMenuListShow/>
},
{
path: '/agent-select/:projId',
element: <AgentSelect/>
}
])
import {RouterProvider} from 'react-router-dom';
import {router} from "../../route/router.tsx";
export default function Body() {
const winHeight: number = window.innerHeight

View File

@ -19,7 +19,7 @@ export default function Head() {
const [isPasswordModalOpen, setIsPasswordModalOpen] = useState(false);
useEffect(() => {
get({
get<any>({
messageApi,
url: '/api/user-info/get-user-self',
onSuccess({data}) {

View File

@ -1,39 +1,124 @@
import './agent-select.css';
import {Link, useNavigate} from "react-router-dom";
import {Breadcrumb, Button, Divider, Image, Radio, RadioChangeEvent} from "antd";
import {Link, useNavigate, useParams} from "react-router-dom";
import {Breadcrumb, Button, Divider, Image, message, Modal, Radio, RadioChangeEvent, Spin} from "antd";
import CardAgent from "../../components/card/CardAgent.tsx";
import {errorImage} from "../../util/CommonUtil.ts";
import {useState} from "react";
import {useEffect, useState} from "react";
import {AgentMedalEnum} from "../../interfaces/card/ICardProj.ts";
import NoData from '../../assets/no-data.png';
import {get, downloadUrl, post} from "../../util/AjaxUtils.ts";
import {IListPage} from "../../interfaces/listpage/IListPage.ts";
enum AgentPriceType {
NORMAL = 'NORMAL',
URGENT = 'URGENT'
}
type AgentPrice = {
priceType: AgentPriceType;
priceTypeText: string;
typePrice: number;
}
type AgentDTO = {
basicsAddresss: string;
basicsCertification: string;
basicsContactNumber: string;
basicsContactPerson: string;
basicsId: string;
basicsIntro: string;
basicsLogo: string;
basicsName: string;
priceDTOS: AgentPrice[];
}
type Agent = {
id: string,
logo: string,
name: string,
desc: string,
medal: AgentMedalEnum,
certificateImg: string,
selected: false
}
export default function AgentSelect() {
const [value, setValue] = useState(1);
const [messageApi, contextHolder] = message.useMessage();
const nav = useNavigate();
// const params = useParams();
const pathParams = useParams();
const height = window.innerHeight - 150;
const [modal, modalHolder] = Modal.useModal();
const [page, setPage] = useState(1);
const [agentList, setAgentList] = useState<Agent[]>([]);
const [selectedAgentId, setSelectedAgentId] = useState('0');
const [selectedAgent, setSelectedAgent] = useState({});
const [showAgentMoreBtn, setShowAgentMoreBtn] = useState(true);
const [isAgentListLoading, setIsAgentListLoading] = useState(false);
const [selectedAgent, setSelectedAgent] = useState<AgentDTO>();
const [isAgentLoading, setIsAgentLoading] = useState(false);
const [selectedPriceValue, setSelectedPriceValue] = useState('');
const [isConfirmLoading, setIsConfirmLoading] = useState(false);
// 列表
const [agentList, setAgentList] = useState([{
id: '1',
logo: '1',
name: '标题1',
desc: '描述1',
medal: AgentMedalEnum.GOLD,
certificateImg: '1',
selected: false
}, {
id: '2',
logo: '2',
name: '标题2',
desc: '描述2',
medal: AgentMedalEnum.GOLD,
certificateImg: '1',
selected: false
}]);
const getSelectedAgentData = (basicsId: string) => {
get<AgentDTO>({
messageApi,
url: `/api/agent/get/${basicsId}`,
onBefore() {
setIsAgentLoading(true);
},
onSuccess({data}) {
setSelectedAgent({
...data
});
setSelectedPriceValue(`${data.priceDTOS[0].priceType}:${data.priceDTOS[0].typePrice}`)
},
onFinally() {
setIsAgentLoading(false);
}
})
}
useEffect(() => {
get<IListPage<AgentDTO>>({
messageApi,
url: `/api/agent/listpage`,
config: {
params: {
page: page,
rows: 10
}
},
onBefore() {
setIsAgentListLoading(true);
},
onSuccess({data}) {
if (data.rows.length == 0) {
setShowAgentMoreBtn(false);
return;
}
data.rows.forEach((item) => {
agentList.push({
id: item.basicsId,
logo: item.basicsLogo,
name: item.basicsName,
desc: item.basicsIntro,
medal: AgentMedalEnum.NORMAL,
certificateImg: item.basicsCertification,
selected: false
})
})
setAgentList([
...agentList
])
},
onFinally() {
setIsAgentListLoading(false);
}
})
}, [page])
const renderAgent = () => {
return agentList.map((item, index) => {
@ -46,22 +131,45 @@ export default function AgentSelect() {
selected={selectedAgentId == item.id}
handleSelect={() => {
setSelectedAgentId(item.id);
setSelectedAgent(item);
getSelectedAgentData(item.id);
}}
/>
)
})
}
/**
*
* @param certification
*/
const renderCertifications = (certification: string) => {
if (certification) {
return <></>
}
return certification.split(',').map(id => (
<Image width={270}
height={170}
src={downloadUrl(id, false)}
fallback={errorImage}
/>
))
}
const renderPrice = (prices: AgentPrice[]) => {
if (!prices) {
return <></>
}
return prices.map((price, index) => <Radio value={`${price.priceType}:${price.typePrice}`}
key={`p${index}`}>{price.priceTypeText}{(price.typePrice / 100)}</Radio>)
}
const renderSelectedAgent = () => {
if (Object.keys(selectedAgent).length == 0) {
if (!selectedAgent) {
return (
<>
<div className="no-data">
<Image src={NoData}/>
<span></span>
</div>
</>
<div className="no-data">
<Image src={NoData}/>
<span></span>
</div>
)
}
return (
@ -69,44 +177,25 @@ export default function AgentSelect() {
<div className="agent-info">
<div className="agent-title"></div>
<div className="agent-body">
<div className="agent-name"></div>
<div className="agent-desc">
西西
</div>
<div className="agent-name">{selectedAgent.basicsName}</div>
<div className="agent-desc" dangerouslySetInnerHTML={{__html: selectedAgent.basicsIntro}}></div>
<Divider dashed style={{
marginTop: '10px',
marginBottom: '10px'
}}/>
<div className="agent-img-title"></div>
<div className="agent-img-list">
<Image width={270}
height={170}
fallback={errorImage}
/>
<Image width={270}
height={170}
fallback={errorImage}
/>
<Image width={270}
height={170}
fallback={errorImage}
/>
<Image width={270}
height={170}
fallback={errorImage}
/>
</div>
<div className="agent-img-list">{renderCertifications(selectedAgent.basicsId)}</div>
<Divider dashed style={{
marginTop: '10px',
marginBottom: '10px'
}}/>
<div className="agent-contact">
<div className="line">
<span>XXXXXX</span>
<span>13888888888</span>
<span>{selectedAgent.basicsContactPerson}</span>
<span>{selectedAgent.basicsContactNumber}</span>
</div>
<div className="line">
<span>XXXXXX</span>
<span>{selectedAgent.basicsAddresss}</span>
</div>
</div>
</div>
@ -114,15 +203,51 @@ export default function AgentSelect() {
<div className="agent-price">
<span className="label"></span>
<Radio.Group onChange={(e: RadioChangeEvent) => {
console.log('radio checked', e.target.value);
setValue(e.target.value);
}} value={value}>
<Radio value={1}>200</Radio>
<Radio value={2}>400</Radio>
</Radio.Group>
setSelectedPriceValue(e.target.value);
}} defaultValue={selectedPriceValue}>{renderPrice(selectedAgent.priceDTOS)}</Radio.Group>
</div>
<div style={{marginTop: '15px', textAlign: 'center'}}>
<Button type="primary" style={{backgroundColor: 'var(--color-primary)'}}></Button>
<Button type="primary" style={{backgroundColor: 'var(--color-primary)'}} onClick={() => {
if (!selectedPriceValue) {
messageApi.error('请选择价格种类');
return;
}
modal.confirm({
title: '提示',
content: '确定选择此代理商吗?确认后,会扣除相应金额。',
okText: '确认',
cancelText: '取消',
okButtonProps: {
style: {
backgroundColor: 'var(--color-primary)'
}
},
onOk: () => {
const priceArray = selectedPriceValue.split(':');
post({
messageApi,
url: `api/proj/save-agent-order/proj-id/${pathParams.projId}`,
body: {
basicsId: selectedAgent.basicsId,
basicsName: selectedAgent.basicsName,
priceType: priceArray[0],
price: priceArray[1]
},
onBefore() {
setIsConfirmLoading(true);
},
onSuccess() {
messageApi.success('提交成功', 1000, () => {
nav(-1);
});
},
onFinally() {
setIsConfirmLoading(false);
}
})
}
});
}}></Button>
</div>
</>
)
@ -134,42 +259,38 @@ export default function AgentSelect() {
items={[
{title: <Link to="/"></Link>},
{title: <Link to="/proj-create"></Link>},
{
title: <a href="/#" onClick={(e) => {
e.preventDefault();
nav(-1)
}}></a>
},
{title: <Link to={`/proj-edit/${pathParams.projId}`}></Link>},
{title: '找代理'},
]}
/>
<div className="agent-select" style={{height: `${height}px`}}>
<div className="agent-select-left">
<div className="list">
<div className="list-item">
{renderAgent()}
</div>
<div className="load">
<Button type="text" onClick={() => {
setAgentList([
...agentList,
{
id: '3',
logo: '3',
name: '标题3',
desc: '描述3',
medal: AgentMedalEnum.SILVER,
certificateImg: '3',
selected: false
}
])
}}>...</Button>
</div>
<Spin tip="正在加载" spinning={isAgentListLoading}>
<div className="list-item">
{renderAgent()}
</div>
{
showAgentMoreBtn ? (
<div className="load">
<Button type="text" onClick={() => {
setPage(page + 1);
}}>...</Button>
</div>
) : <></>
}
</Spin>
</div>
</div>
<div className="agent-select-right">{renderSelectedAgent()}</div>
<Spin tip="正在加载" spinning={isAgentLoading}>
<div className="agent-select-right" style={{height: `${height - 30}px`}}>
{renderSelectedAgent()}
</div>
</Spin>
</div>
<Spin tip="正在提交" spinning={isConfirmLoading}/>
{contextHolder}
{modalHolder}
</>
)
}

113
src/route/index/Index.tsx Normal file
View File

@ -0,0 +1,113 @@
import './index.css';
import {MouseEvent, Reducer, useReducer} from "react";
import {Link, useNavigate} from "react-router-dom";
import {IMenuListItem, IMenuWithTopButton} from "../../interfaces/menu/IMenuWithTopButton.ts";
import MenuWithTopButton from "../../components/menu/MenuWithTopButton.tsx";
import MenuTreeWithTopButton from "../../components/menu/MenuTreeWithTopButton.tsx";
import ListProj from "../../components/list/ListProj.tsx";
import ListProjAgent from "../../components/list/ListProjAgent.tsx";
import {Breadcrumb} from 'antd';
import {
IndexListContext,
IndexListDataType,
IndexListDispatchContext,
ListAction,
ListData
} from "../../context/IndexListContext.ts";
export default function Index() {
const nav = useNavigate();
const listReducer = (state: ListData, action: ListAction) => {
if(action.type == IndexListDataType.PROJ) {
state.type = IndexListDataType.PROJ;
state.status = action.value;
} else if(action.type == IndexListDataType.AGENT) {
state.type = IndexListDataType.AGENT;
state.status = action.value;
}
return {
...state
};
}
const [listData, dispatch] = useReducer<Reducer<ListData, ListAction>>(listReducer, {
type: IndexListDataType.PROJ
});
const projMenu: IMenuWithTopButton = {
button: {
name: '创建项目',
handle() {
nav('/proj-create')
}
},
list: [
{id: 'ALL', name: '全部项目'},
{id: 'PROCESSING', name: '进行中的'},
{id: 'COMPLETE', name: '已完成的'}
],
handleListItem(_e, _index,item: IMenuListItem) {
dispatch({
type: IndexListDataType.PROJ,
value: item.id
})
}
}
const agentMenu: IMenuWithTopButton = {
button: {
name: '代理服务',
handle() {
}
},
list: [
{id: 'ALL', name: '全部项目'},
{id: 'PROCESSING', name: '进行中的'},
{id: 'COMPLETE', name: '已完成的'},
],
handleListItem(_e: MouseEvent<HTMLLIElement>, _index: number, item: IMenuListItem) {
dispatch({
type: IndexListDataType.AGENT,
value: item.id
})
}
}
return (
<>
<Breadcrumb
items={[
{title: <Link to={'/'}></Link>}
]}
/>
<IndexListContext.Provider value={listData}>
<IndexListDispatchContext.Provider value={dispatch}>
<div className="index">
<div className="left">
<MenuWithTopButton
button={projMenu.button}
list={projMenu.list}
handleListItem={projMenu.handleListItem}
/>
<MenuTreeWithTopButton/>
<MenuWithTopButton
button={agentMenu.button}
list={agentMenu.list}
handleListItem={agentMenu.handleListItem}
/>
</div>
<div className="right">
{
listData.type === IndexListDataType.PROJ ? <ListProj/> : (
listData.type == IndexListDataType.AGENT ? <ListProjAgent/> : <></>
)
}
</div>
</div>
</IndexListDispatchContext.Provider>
</IndexListContext.Provider>
</>
)
}

View File

@ -1,79 +0,0 @@
import './index.css';
import {MouseEvent, useState} from "react";
import {Link, useNavigate} from "react-router-dom";
import {IMenuListItem, IMenuWithTopButton} from "../../interfaces/menu/IMenuWithTopButton.ts";
import MenuWithTopButton from "../../components/menu/MenuWithTopButton.tsx";
import MenuTreeWithTopButton from "../../components/menu/MenuTreeWithTopButton.tsx";
import ListProj from "../../components/list/ListProj.tsx";
import ListProjAgent from "../../components/list/ListProjAgent.tsx";
import {Breadcrumb} from 'antd';
export default function Index() {
const [listType, setListType] = useState('proj');
const nav = useNavigate();
const projMenu: IMenuWithTopButton = {
button: {
name: '创建项目',
handle() {
nav('/proj-create')
}
},
list: [
{id: 'proj1', name: '全部项目'},
{id: 'proj2', name: '进行中的'},
{id: 'proj3', name: '已完成的'}
],
handleListItem(e: MouseEvent<HTMLLIElement>, index: number, item: IMenuListItem) {
console.log(e);
console.log(index);
console.log(item)
setListType('proj');
}
}
const agentMenu: IMenuWithTopButton = {
button: {
name: '代理服务',
handle(e: MouseEvent<HTMLButtonElement>) {
console.log(e)
}
},
list: [
{id: 'agent1', name: '全部项目'},
{id: 'agent2', name: '进行中的'},
{id: 'agent3', name: '已完成的'},
],
handleListItem(e: MouseEvent<HTMLLIElement>, index: number, item: IMenuListItem) {
console.log(e);
console.log(index);
console.log(item)
setListType('projAgent');
}
}
return (
<>
<Breadcrumb
items={[
{title: <Link to={'/'}></Link>}
]}
/>
<div className="index">
<div className="left">
<MenuWithTopButton
button={projMenu.button}
list={projMenu.list}
handleListItem={projMenu.handleListItem}
/>
<MenuTreeWithTopButton/>
<MenuWithTopButton
button={agentMenu.button}
list={agentMenu.list}
handleListItem={agentMenu.handleListItem}
/>
</div>
<div className="right">{listType === 'proj' ? <ListProj/> : <ListProjAgent/>}</div>
</div>
</>
)
}

View File

@ -175,7 +175,7 @@ export default function ProjEdit() {
}
const renderData = () => {
get({
get<any>({
messageApi: messageApi,
url: `/api/proj/get/${pathParams.projId}`,
onSuccess({data}) {
@ -346,10 +346,10 @@ export default function ProjEdit() {
window.open(`${Axios.defaults?.baseURL}/route/proj/download/code/${pathParams.projId}`)
}}
/>
<CardProjJump title="跳转"
desc="请完善软件的介绍,详细介绍等基本信息"
<CardProjJump title="找代理"
desc="到软著代理完成软著申请"
handleJump={() => {
nav('/agent-select/2');
nav(`/agent-select/${pathParams.projId}`);
}}
/>
</StepProjEdit>

134
src/route/router.tsx Normal file
View File

@ -0,0 +1,134 @@
import {createBrowserRouter} from "react-router-dom";
import Index from "../route/index/Index.tsx";
import ProjCreate from "./proj/ProjCreate.tsx";
import ProjNew from "./proj/ProjNew.tsx";
import ProjEdit from "./proj/ProjEdit.tsx";
import ProjEditStep1 from "./proj/edit/ProjEditStep1.tsx";
import ProjEditStep1Show from "./proj/edit/ProjEditStep1Show.tsx";
import ProjEditStep2 from "./proj/edit/ProjEditStep2.tsx";
import ProjEditStep2Show from "./proj/edit/ProjEditStep2Show.tsx";
import ProjEditStep3 from "./proj/edit/ProjEditStep3.tsx";
import ProjEditStep3Show from "./proj/edit/ProjEditStep3Show.tsx";
import ProjEditStep4 from "./proj/edit/ProjEditStep4.tsx";
import ProjEditStep4Show from "./proj/edit/ProjEditStep4Show.tsx";
import ProjEditStep5 from "./proj/edit/ProjEditStep5.tsx";
import ProjEditStep5Show from "./proj/edit/ProjEditStep5Show.tsx";
import ProjEditStep6 from "./proj/edit/ProjEditStep6.tsx";
import ProjEditStep6Show from "./proj/edit/ProjEditStep6Show.tsx";
import ProjConfigLoginpage from "./proj/edit/ProjConfigLoginpage.tsx";
import ProjConfigLoginpageShow from "./proj/edit/ProjConfigLoginpageShow.tsx";
import ProjConfigModList from "./proj/edit/ProjConfigModList.tsx";
import ProjConfigModListShow from "./proj/edit/ProjConfigModListShow.tsx";
import ProjConfigModSave from "./proj/edit/ProjConfigModSave.tsx";
import ProjConfigModEdit from "./proj/edit/ProjConfigModEdit.tsx";
import ProjConfigModShow from "./proj/edit/ProjConfigModShow.tsx";
import ProjConfigMenuList from "./proj/edit/ProjConfigMenuList.tsx";
import ProjConfigMenuListShow from "./proj/edit/ProjConfigMenuListShow.tsx";
import AgentSelect from "./agent/AgentSelect.tsx";
export const router = createBrowserRouter([
{
path: '/',
element: <Index />
},
{
path: '/proj-create',
element: <ProjCreate />
},
{
path: '/proj-new/:projChargeType',
element: <ProjNew/>
},
{
path: '/proj-edit/:projId',
element: <ProjEdit/>
},
{
path: '/proj-edit/step1/:projId',
element: <ProjEditStep1/>
},
{
path: '/proj-edit/step1-show/:projId',
element: <ProjEditStep1Show/>
},
{
path: '/proj-edit/step2/:projId',
element: <ProjEditStep2/>
},
{
path: '/proj-edit/step2-show/:projId',
element: <ProjEditStep2Show/>
},
{
path: '/proj-edit/step3/:projId',
element: <ProjEditStep3/>
},
{
path: '/proj-edit/step3-show/:projId',
element: <ProjEditStep3Show/>
},
{
path: '/proj-edit/step4/:projId',
element: <ProjEditStep4/>
},
{
path: '/proj-edit/step4-show/:projId',
element: <ProjEditStep4Show/>
},
{
path: '/proj-edit/step5/:projId',
element: <ProjEditStep5/>
},
{
path: '/proj-edit/step5-show/:projId',
element: <ProjEditStep5Show/>
},
{
path: '/proj-edit/step6/:projId',
element: <ProjEditStep6/>
},
{
path: '/proj-edit/step6-show/:projId',
element: <ProjEditStep6Show/>
},
{
path: '/proj-edit/config-loginpage/:projId',
element: <ProjConfigLoginpage/>
},
{
path: '/proj-edit/config-loginpage-show/:projId',
element: <ProjConfigLoginpageShow/>
},
{
path: '/proj-edit/config-mod-list/:projId',
element: <ProjConfigModList/>
},
{
path: '/proj-edit/config-mod-list-show/:projId',
element: <ProjConfigModListShow/>
},
{
path: '/proj-edit/config-mod-save/:projId',
element: <ProjConfigModSave/>
},
{
path: '/proj-edit/config-mod-edit/:projId/:projModId',
element: <ProjConfigModEdit/>
},
{
path: '/proj-edit/config-mod-show/:projId/:projModId',
element: <ProjConfigModShow/>
},
{
path: '/proj-edit/config-menu-list/:projId',
element: <ProjConfigMenuList/>
},
{
path: '/proj-edit/config-menu-list-show/:projId',
element: <ProjConfigMenuListShow/>
},
{
path: '/agent-select/:projId',
element: <AgentSelect/>
}
])

View File

@ -4,13 +4,13 @@ import type {MessageInstance} from "antd/es/message/interface";
export const Axios = axios;
export const DevUserId: string = '80d3365e-0597-4988-979e-18ef1c3ec671';
type Req = {
type Req<T> = {
messageApi: MessageInstance;
url: string;
body?: any;
config?: AxiosRequestConfig;
onBefore?(): void;
onSuccess(data: AxiosResponse): void;
onSuccess(data: AxiosResponse<T>): void;
onFinally?(): void;
}
@ -37,7 +37,7 @@ export function uploadFileUrl() {
return `${Axios.defaults?.baseURL}/api/file/v2/upload-file`;
}
export function get<T>(req: Req) {
export function get<T>(req: Req<T>) {
req.onBefore?.();
Axios.get<T>(req.url, req.config).then(res => {
req.onSuccess(res);
@ -56,7 +56,7 @@ export function get<T>(req: Req) {
})
}
export function post<T>(req: Req) {
export function post<T>(req: Req<T>) {
req.onBefore?.();
Axios.post<T>(req.url, req.body, req.config).then(res => {
req.onSuccess(res);
@ -75,7 +75,7 @@ export function post<T>(req: Req) {
})
}
export function put<T>(req: Req) {
export function put<T>(req: Req<T>) {
req.onBefore?.();
Axios.put<T>(req.url, req.body, req.config).then(res => {
req.onSuccess(res);
@ -94,7 +94,7 @@ export function put<T>(req: Req) {
})
}
export function del<T>(req: Req) {
export function del<T>(req: Req<T>) {
req.onBefore?.();
Axios.delete<T>(req.url, req.config).then(res => {
req.onSuccess(res);