From c83637d1bc6ad2ed1f70548b613874972609276e Mon Sep 17 00:00:00 2001 From: WenC <450292408@qq.com> Date: Wed, 20 Mar 2024 18:30:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.cjs | 32 +++--- src/components/card/CardProjType.tsx | 23 +++- src/components/list/ListProj.tsx | 65 ++++++----- src/interfaces/proj/ICardProj.ts | 8 +- src/interfaces/proj/IProj.ts | 31 +++++- src/layout/body/Body.tsx | 4 +- src/main.tsx | 1 - src/route/proj/ProjCreate.tsx | 88 ++++++++++----- src/route/proj/ProjNew.tsx | 156 +++++++++++++++++++++------ src/util/AjaxUtils.ts | 100 ++++++++++++++++- 10 files changed, 392 insertions(+), 116 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index d6c9537..a160d90 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,18 +1,20 @@ module.exports = { - root: true, - env: { browser: true, es2020: true }, - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:react-hooks/recommended', - ], - ignorePatterns: ['dist', '.eslintrc.cjs'], - parser: '@typescript-eslint/parser', - plugins: ['react-refresh'], - rules: { - 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true }, + root: true, + env: {browser: true, es2020: true}, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', ], - }, + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': [ + 'warn', + {allowConstantExport: true}, + ], + // 去除any报错 + '@typescript-eslint/no-explicit-any': ['off'] + }, } diff --git a/src/components/card/CardProjType.tsx b/src/components/card/CardProjType.tsx index ab2fa65..5f77963 100644 --- a/src/components/card/CardProjType.tsx +++ b/src/components/card/CardProjType.tsx @@ -2,10 +2,13 @@ import './card-proj-type.css'; import {ICardProj, ICardProjChargeLine} from "../../interfaces/proj/ICardProj.ts"; import {Checkbox} from 'antd'; import {useState} from "react"; +import {ProjAdditionalType} from "../../interfaces/proj/IProj.ts"; export default function CardProjType(props: ICardProj) { const [chargeAmount, setChargeAmount] = useState(0); + const [pkg, setPkg] = useState(false); + const [videoDemo, setVideoDemo] = useState(false); const renderContents = (lineIndex: number, contents: string[]) => { return contents.map((item, index) =>
  • @@ -29,8 +32,18 @@ export default function CardProjType(props: ICardProj) { const onChargeChange = (checked: boolean, line: ICardProjChargeLine) => { if (checked) { + if (line.id == ProjAdditionalType.PKG) { + setPkg(true); + } else if (line.id == ProjAdditionalType.VIDEO_DEMO) { + setVideoDemo(true); + } setChargeAmount(chargeAmount + line.price); } else { + if (line.id == ProjAdditionalType.PKG) { + setPkg(false); + } else if (line.id == ProjAdditionalType.VIDEO_DEMO) { + setVideoDemo(false); + } setChargeAmount(chargeAmount - line.price); } } @@ -60,13 +73,15 @@ export default function CardProjType(props: ICardProj) { return props.buyArray.map((buy, index) => { return (
    -
    {buy.label}{buy.price + chargeAmount} 元
    +
    {buy.label}{(buy.price + chargeAmount) / 100} 元

    + buy.handleClick(props.head, { + pkg: pkg, + videoDemo: videoDemo + }); + }}>购买
    ) diff --git a/src/components/list/ListProj.tsx b/src/components/list/ListProj.tsx index 031735f..b667a83 100644 --- a/src/components/list/ListProj.tsx +++ b/src/components/list/ListProj.tsx @@ -1,9 +1,9 @@ import './list-proj.css' import CardProj from "../card/CardProj.tsx"; import {useRef, MutableRefObject, useState, useEffect} from "react"; -import {Input, Pagination} from 'antd'; +import {Input, Pagination, message} from 'antd'; import type {SearchProps} from 'antd/es/input/Search'; -import {Axios} from "../../util/AjaxUtils.ts"; +import {get} from "../../util/AjaxUtils.ts"; const {Search} = Input; @@ -17,25 +17,28 @@ export default function ListProj() { const listProjRef: MutableRefObject = useRef(null); const listRef: MutableRefObject = useRef(null); - const [page, _setPage] = useState(1); - const [total, _setTotal] = useState(0); - const [projs, _setProjs] = useState([]); + const [messageApi, contextHolder] = message.useMessage(); + const [page, setPage] = useState(1); + const [total, setTotal] = useState(0); + const [projs, setProjs] = useState([]); const domHeight = window.innerHeight - 280; - const renderData = () => { - Axios.get('/api/proj/listpage/self', { - params: { - page: page, - rows: 20 + const reqData = (currentPage: number) => { + get({ + messageApi: messageApi, + url: '/api/proj/listpage/self', + config: { + params: { + page: currentPage, + rows: 20 + } + }, + onSuccess({data}) { + setProjs(data.page); + setTotal(data.total); + setProjs(data.rows); } - }).then(res => { - const data = res.data; - _setProjs(data.page); - _setTotal(data.total); - _setProjs(data.rows); - }).catch(res => { - console.log(res); }) } @@ -44,22 +47,28 @@ export default function ListProj() { } useEffect(() => { - renderData(); + reqData(page); }, []) return ( -
    -
    - -
    -
    -
    - {renderList()} + <> + {contextHolder} +
    +
    +
    -
    - +
    +
    + {renderList()} +
    +
    + { + setPage(page); + reqData(page); + }}/> +
    -
    + ) } \ No newline at end of file diff --git a/src/interfaces/proj/ICardProj.ts b/src/interfaces/proj/ICardProj.ts index acfe14a..da83efe 100644 --- a/src/interfaces/proj/ICardProj.ts +++ b/src/interfaces/proj/ICardProj.ts @@ -1,18 +1,24 @@ + export interface ICardProjBodyLine { title: string; contents: string[]; } export interface ICardProjChargeLine { + id: string; title: string; price: number; } export interface ICardProjBuy { + id: string; label?: string, price: number; - handleClick(title: string, price: number): void; + handleClick(title: string, additional: { + pkg: boolean, + videoDemo: boolean + }): void; } export interface ICardProj { diff --git a/src/interfaces/proj/IProj.ts b/src/interfaces/proj/IProj.ts index b4490d3..1eefa8e 100644 --- a/src/interfaces/proj/IProj.ts +++ b/src/interfaces/proj/IProj.ts @@ -20,6 +20,34 @@ export enum GenerateStatus { ERROR = 'ERROR' } +export enum ProjChargeType { + ALL = 'ALL', + MATERIAL_AGENT = 'MATERIAL_AGENT', + MATERIAL_AGENT_URGENT = 'MATERIAL_AGENT_URGENT', + MATERIAL = 'MATERIAL', + FREE = 'FREE', +} + +export enum ProjAdditionalType { + PKG = 'PKG', + VIDEO_DEMO = 'VIDEO_DEMO' +} + +export interface IProjCharge { + proj: { + all: number; + materialAgent: number; + materialAgentUrgent: number; + material: number; + free: number; + }, + additional: { + pkg: number; + videoDemo: number; + } +} + + export interface IProj { projId: string, @@ -33,5 +61,4 @@ export interface IProj { gmtCreate: string, generateStatus: GenerateStatus - -} \ No newline at end of file +} diff --git a/src/layout/body/Body.tsx b/src/layout/body/Body.tsx index 9f0a804..e296284 100644 --- a/src/layout/body/Body.tsx +++ b/src/layout/body/Body.tsx @@ -16,11 +16,11 @@ const router = createBrowserRouter([ element: }, { - path: '/proj-new/:type/:price', + path: '/proj-new/:projChargeType', element: }, { - path: '/proj-edit', + path: '/proj-edit/:projId', element: }, { diff --git a/src/main.tsx b/src/main.tsx index 8224efa..08b21dc 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,4 +1,3 @@ -import React from 'react' import ReactDOM from 'react-dom/client' import App from './App.tsx' import './index.css' diff --git a/src/route/proj/ProjCreate.tsx b/src/route/proj/ProjCreate.tsx index 8255557..2ac2f3e 100644 --- a/src/route/proj/ProjCreate.tsx +++ b/src/route/proj/ProjCreate.tsx @@ -1,13 +1,42 @@ import './proj-create.css' import {Link, useNavigate} from "react-router-dom"; -import {Breadcrumb} from "antd"; +import {Breadcrumb, message} from "antd"; import CardProjType from "../../components/card/CardProjType.tsx"; +import {IProjCharge, ProjAdditionalType, ProjChargeType} from "../../interfaces/proj/IProj.ts"; +import {useEffect, useState} from "react"; +import {get} from "../../util/AjaxUtils.ts"; export default function ProjCreate() { + const [messageApi, contextHolder] = message.useMessage(); + const [charge, setCharge] = useState({ + proj: { + all: 0, + materialAgent: 0, + materialAgentUrgent: 0, + material: 0, + free: 0, + }, + additional: { + pkg: 0, + videoDemo: 0 + } + }); const nav = useNavigate(); const height = window.innerHeight - 150; + + useEffect(() => { + get({ + messageApi: messageApi, + url: '/api/proj/charge/get', + onSuccess({data}) { + setCharge(data); + } + }) + }, []) + return ( <> + {contextHolder} 首页}, @@ -15,7 +44,7 @@ export default function ProjCreate() { ]} />
    -
    +
    { - nav(`/proj-new/q/${price}`) + id: ProjChargeType.ALL, + price: charge.proj.all, + handleClick: () => { + nav(`/proj-new/${ProjChargeType.ALL}`) } } ]} @@ -72,27 +102,31 @@ export default function ProjCreate() { ]} chargeLineArray={[ { - price: 100, - title: '安装包100元' + id: ProjAdditionalType.PKG, + price: charge.additional.pkg, + title: `安装包 ${charge.additional.pkg / 100} 元` }, { - price: 50, - title: '系统演示视频文件50元' + id: ProjAdditionalType.VIDEO_DEMO, + price: charge.additional.videoDemo, + title: `系统演示视频文件 ${charge.additional.videoDemo / 100} 元` } ]} buyArray={[ { + id: ProjChargeType.MATERIAL_AGENT, label: '普件:', - price: 200, - handleClick: (_title, price) => { - nav(`/proj-new/xdp/${price}`) + price: charge.proj.materialAgent, + handleClick: (_title, additional) => { + nav(`/proj-new/${ProjChargeType.MATERIAL_AGENT}?pkg=${additional.pkg}&videoDemo=${additional.videoDemo}`) } }, { + id: ProjChargeType.MATERIAL_AGENT_URGENT, label: '加急:', - price: 300, - handleClick: (_title, price) => { - nav(`/proj-new/xdj/${price}`) + price: charge.proj.materialAgentUrgent, + handleClick: (_title, additional) => { + nav(`/proj-new/${ProjChargeType.MATERIAL_AGENT_URGENT}?pkg=${additional.pkg}&videoDemo=${additional.videoDemo}`) } } ]} @@ -123,19 +157,22 @@ export default function ProjCreate() { ]} chargeLineArray={[ { - price: 100, - title: '安装包100元' + id: ProjAdditionalType.PKG, + price: charge.additional.pkg, + title: `安装包 ${charge.additional.pkg / 100} 元` }, { - price: 50, - title: '系统演示视频文件50元' + id: ProjAdditionalType.VIDEO_DEMO, + price: charge.additional.videoDemo, + title: `系统演示视频文件 ${charge.additional.videoDemo / 100} 元` } ]} buyArray={[ { - price: 200, - handleClick: (_title, price) => { - nav(`/proj-new/x/${price}`) + id: ProjChargeType.MATERIAL, + price: charge.proj.material, + handleClick: () => { + nav(`/proj-new/${ProjChargeType.MATERIAL}`) } } ]} @@ -159,9 +196,10 @@ export default function ProjCreate() { ]} buyArray={[ { - price: 0, - handleClick: (_title, price) => { - nav(`/proj-new/m/${price}`) + id: ProjChargeType.FREE, + price: charge.proj.free, + handleClick: () => { + nav(`/proj-new/${ProjChargeType.FREE}`) } } ]} diff --git a/src/route/proj/ProjNew.tsx b/src/route/proj/ProjNew.tsx index c0848db..8ce38b9 100644 --- a/src/route/proj/ProjNew.tsx +++ b/src/route/proj/ProjNew.tsx @@ -1,38 +1,76 @@ import './proj-new.css'; -import {Link, useNavigate, useParams} from "react-router-dom"; -import {Breadcrumb, Button, Flex, Form, type FormProps, Input, Modal} from "antd"; -import {useState} from "react"; +import {Link, useNavigate, useParams, useSearchParams} from "react-router-dom"; +import {Breadcrumb, Button, Flex, Form, Input, message, Modal, Spin} from "antd"; +import {useEffect, useState} from "react"; +import {get, post} from "../../util/AjaxUtils.ts"; +import {IProjCharge, ProjAdditionalType, ProjChargeType} from "../../interfaces/proj/IProj.ts"; const {TextArea} = Input; -type FieldType = { - projTitle: string; - projDesc: string; +type ProjInfo = { + projName: string; + projIntroduction: string; }; export default function ProjNew() { - const height = window.innerHeight - 150; - const [isModalOpen, setIsModalOpen] = useState(false); const nav = useNavigate(); - const params = useParams(); + const pathParams = useParams(); + const [queryParams] = useSearchParams(); - const onFinish: FormProps["onFinish"] = (values) => { - console.log('Success:', values); - setIsModalOpen(true); - }; + const [messageApi, contextHolder] = message.useMessage(); + const [loading, setLoading] = useState(false); + const height = window.innerHeight - 150; + const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); + const [isEditModalOpen, setIsEditModalOpen] = useState(false); + const [chargePrice, setChargePrice] = useState(0); + const [projInfo, setProjInfo] = useState({ + projName: '', + projIntroduction: '', + }); + const listProjChargeAdditional: string[] = []; + let createProjId = ''; - const onFinishFailed: FormProps["onFinishFailed"] = (errorInfo) => { - console.log('Failed:', errorInfo); - }; - - const handleConfirmOk = () => { - // 扣款 - nav('/proj-edit'); - } - - const handleConfirmCancel = () => { - setIsModalOpen(false); - } + useEffect(() => { + get({ + messageApi: messageApi, + url: '/api/proj/charge/get', + onSuccess({data}) { + const charge = data as IProjCharge; + let price = 0; + switch (pathParams.projChargeType) { + case ProjChargeType.ALL: + price = charge.proj.all; + break; + case ProjChargeType.MATERIAL_AGENT: + price = charge.proj.materialAgent; + break; + case ProjChargeType.MATERIAL_AGENT_URGENT: + price = charge.proj.materialAgentUrgent; + break; + case ProjChargeType.MATERIAL: + price = charge.proj.material; + break; + case ProjChargeType.FREE: + price = charge.proj.free; + break; + default: + messageApi.error({ + type: 'error', + content: '价格类型错误', + }) + } + if (queryParams.get('pkg')) { + price += charge.additional.pkg; + listProjChargeAdditional.push(ProjAdditionalType.PKG); + } + if (queryParams.get('videoDemo')) { + price += charge.additional.videoDemo; + listProjChargeAdditional.push(ProjAdditionalType.VIDEO_DEMO); + } + setChargePrice(price); + } + }) + }, []); const onBack = () => { nav(-1); @@ -40,6 +78,7 @@ export default function ProjNew() { return ( <> + {contextHolder} 首页}, @@ -58,21 +97,26 @@ export default function ProjNew() { wrapperCol={{span: 24}} style={{width: 500}} initialValues={{remember: true}} - onFinish={onFinish} - onFinishFailed={onFinishFailed} + onFinish={(formData) => { + setIsCreateModalOpen(true); + setProjInfo({ + projName: formData.projName, + projIntroduction: formData.projIntroduction + }) + }} autoComplete="off" > - + label="系统标题" - name="projTitle" + name="projName" rules={[{required: true, message: '请输入系统标题'}]} > - + label="简单描述" - name="projDesc" + name="projIntroduction" rules={[{required: true, message: '请输入简单描述'}]} >