diff --git a/src/App.tsx b/src/App.tsx index 6568bc5..ea818e8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,20 +1,46 @@ import Head from './layout/head/Head.tsx'; import Body from './layout/body/Body.tsx'; import Foot from './layout/foot/Foot.tsx'; -import {GlobalContext, GlobalData} from "./context/GlobalContext.ts"; - +import { + GlobalContext, + GlobalData, + GlobalDataAction, + GlobalDataActionType, + GlobalDispatchContext +} from "./context/GlobalContext.ts"; +import {Reducer, useReducer} from "react"; const App: React.FC = () => { - - const globalData: GlobalData = { + const globalDataReducer = (state: GlobalData, action: GlobalDataAction) => { + if (action.type == GlobalDataActionType.REFRESH_SELF) { + if(action.user) { + state.user.balance = action.user.balance; + state.user.nickname = action.user.nickname; + state.user.username = action.user.username; + state.user.hasUserInfo = action.user.hasUserInfo; + } + } + return { + ...state + } } + const [globalData, dispatch] = useReducer>(globalDataReducer, { + user: { + balance: '0', + username: '', + nickname: '', + hasUserInfo: false + } + }); return ( <> - - - + + + + + ); diff --git a/src/components/balance/BalanceHead.tsx b/src/components/balance/BalanceHead.tsx index f74ea5a..b99267b 100644 --- a/src/components/balance/BalanceHead.tsx +++ b/src/components/balance/BalanceHead.tsx @@ -1,15 +1,16 @@ import './balance-head.css' +import {useContext} from "react"; +import {GlobalContext} from "../../context/GlobalContext.ts"; export default function BalanceHead() { - - const handleClick = () => { - console.log('查看余额') - } + const globalContext = useContext(GlobalContext); return (
余额¥: - 800 + { + console.log('查看余额') + }}>{globalContext.user.balance}
) } \ No newline at end of file diff --git a/src/components/card/CardProj.tsx b/src/components/card/CardProj.tsx index a924012..8563e71 100644 --- a/src/components/card/CardProj.tsx +++ b/src/components/card/CardProj.tsx @@ -1,48 +1,51 @@ import './card-proj.css'; import { + CheckOutlined, + ClockCircleOutlined, + CloseCircleOutlined, + CreditCardOutlined, DownloadOutlined, EditOutlined, EyeOutlined, FolderOutlined, + LoadingOutlined, SearchOutlined, SettingOutlined, - ClockCircleOutlined, - LoadingOutlined, - CheckOutlined, - WarningOutlined, - CloseCircleOutlined, - CreditCardOutlined + WarningOutlined } from '@ant-design/icons'; import {Button, ConfigProvider, Tag} from 'antd'; import {GenerateStatus, IProj, PayStatus} from "../../interfaces/proj/IProj.ts"; +import {useNavigate} from "react-router-dom"; +import {Axios} from "../../util/AjaxUtils.ts"; export default function CardProj(props: { item: IProj }) { + const nav = useNavigate(); const data = props.item; /** * 生成状态 */ const renderGenerateStatus = () => { - if (data.generateStatus == GenerateStatus.PENDING) { + if (data.generate.generateStatus == GenerateStatus.PENDING) { return 等待生成 } - if (data.generateStatus == GenerateStatus.GENERATING) { + if (data.generate.generateStatus == GenerateStatus.GENERATING) { return 正在生成 } - if (data.generateStatus == GenerateStatus.SUCCESS) { + if (data.generate.generateStatus == GenerateStatus.SUCCESS) { return 生成成功 } - if (data.generateStatus == GenerateStatus.FAILED) { + if (data.generate.generateStatus == GenerateStatus.FAILED) { return 生成失败 } - if (data.generateStatus == GenerateStatus.NONE) { + if (data.generate.generateStatus == GenerateStatus.NONE) { return 未生成 } return 错误 } const renderOption = () => { - if(data.payStatus == PayStatus.UNPAID) { + if(data.pay.payStatus == PayStatus.UNPAID) { return ( <>
@@ -54,17 +57,44 @@ export default function CardProj(props: { item: IProj }) { return ( <>
- - - + + +
{ - data.generateStatus == GenerateStatus.SUCCESS ? ( + data.generate.generateStatus == GenerateStatus.SUCCESS ? (
- - - - + + + +
) : <> } @@ -88,22 +118,33 @@ export default function CardProj(props: { item: IProj }) {
- 金额¥:{data.payment / 100} + 金额¥:{data.pay.payment / 100}
- - - 编辑 - - - - 查看 - + { + data.generate.generateStatus == GenerateStatus.SUCCESS ? ( + + + { + e.preventDefault(); + nav(`/proj-edit/${data.projId}`) + }}>查看 + + ) : ( + + + { + e.preventDefault(); + nav(`/proj-edit/${data.projId}`) + }}>编辑 + + ) + } { e.stopPropagation(); - window.open(data.previewUrl, '_blank') + window.open(`${Axios.defaults?.baseURL}/${data.previewUrl}`, '_blank') }}>预览
diff --git a/src/components/card/CardProjDownload.tsx b/src/components/card/CardProjDownload.tsx index c38f6a7..ea201bf 100644 --- a/src/components/card/CardProjDownload.tsx +++ b/src/components/card/CardProjDownload.tsx @@ -5,12 +5,21 @@ export default function CardProjDownload(props: IProjDownload) { return (
{props.title}
-
请完善软件的介绍,详细介绍等基本信息
+
{props.desc}
) diff --git a/src/context/GlobalContext.ts b/src/context/GlobalContext.ts index ca3b7b4..025f8b7 100644 --- a/src/context/GlobalContext.ts +++ b/src/context/GlobalContext.ts @@ -1,8 +1,33 @@ -import {createContext} from "react"; +import {createContext, Dispatch} from "react"; -export interface GlobalData { +export enum GlobalDataActionType { + REFRESH_SELF } -const Data: GlobalData = {} +export interface User { + balance: string; + nickname: string; + username: string; + hasUserInfo: boolean; +} -export const GlobalContext = createContext(Data); +export interface GlobalData { + user: User; +} + + + +export interface GlobalDataAction { + type: number; + user?: User; +} + +export const GlobalContext = createContext({ + user: { + balance: '0', + nickname: '', + username: '', + hasUserInfo: false + } +}); +export const GlobalDispatchContext = createContext>(() => {}); diff --git a/src/interfaces/card/ICardProj.ts b/src/interfaces/card/ICardProj.ts index 30628a2..b402e63 100644 --- a/src/interfaces/card/ICardProj.ts +++ b/src/interfaces/card/ICardProj.ts @@ -32,6 +32,7 @@ export interface IProjResult { export interface IProjDownload { title: string; desc: string; + canBtnClick?: boolean; handleDownload(): void; } diff --git a/src/interfaces/proj/IProj.ts b/src/interfaces/proj/IProj.ts index 1eefa8e..5a2e29d 100644 --- a/src/interfaces/proj/IProj.ts +++ b/src/interfaces/proj/IProj.ts @@ -47,18 +47,30 @@ export interface IProjCharge { } } +export interface IProjGenerate { + generateStatus: GenerateStatus; +} + +export interface IProjPay { + charge: string; + gmtPay: string; + payStatus: PayStatus; + payment: number; + chargeAdditionals: string; +} + export interface IProj { projId: string, projName: string; projContext: string; - projCodeType: ProjCodeType, - payStatus: PayStatus, - payment: number, - projStyleType: ProjStyleType, - previewUrl: string, - gmtCreate: string, - generateStatus: GenerateStatus + projCodeType: ProjCodeType; + projStyleType: ProjStyleType; + previewUrl: string; + gmtCreate: string; + + generate: IProjGenerate; + pay: IProjPay; } diff --git a/src/layout/head/Head.tsx b/src/layout/head/Head.tsx index 0eb9975..fe2c06c 100644 --- a/src/layout/head/Head.tsx +++ b/src/layout/head/Head.tsx @@ -1,11 +1,41 @@ import './head.css' import BalanceHead from '../../components/balance/BalanceHead.tsx'; import RechargeHead from '../../components/recharge/RechargeHead.tsx'; -import MessageHead from '../../components/message/MessageHead.tsx'; -import {Divider, Dropdown, MenuProps, Space} from "antd"; +import {Divider, Dropdown, MenuProps, message, Modal, Space, Spin} from "antd"; import {DownOutlined, UserOutlined, KeyOutlined, LogoutOutlined} from "@ant-design/icons"; +import {useContext, useEffect, useState} from "react"; +import {get, put} from "../../util/AjaxUtils.ts"; +import {GlobalContext, GlobalDataActionType, GlobalDispatchContext} from "../../context/GlobalContext.ts"; +import UserEdit from "../../route/user/UserEdit.tsx"; export default function Head() { + const globalContext = useContext(GlobalContext); + const globalDispatchContext = useContext(GlobalDispatchContext); + const [messageApi, contextHolder] = message.useMessage(); + const [modal, modalHolder] = Modal.useModal(); + const [loading, setLoading] = useState(false); + const [isSelfModalOpen, setIsSelfModalOpen] = useState(false); + + useEffect(() => { + get({ + messageApi, + url: '/api/user-info/get-user-self', + onSuccess({data}) { + globalDispatchContext({ + type: GlobalDataActionType.REFRESH_SELF, + user: { + balance: (Math.floor(data.accountMoney) / 100).toFixed(2), + nickname: data.nickname, + username: data.username, + hasUserInfo: data.hasUserInfo, + } + }) + if(!data.hasUserInfo) { + setIsSelfModalOpen(true); + } + } + }) + }, [globalContext.user]); const items: MenuProps['items'] = [ { @@ -16,6 +46,9 @@ export default function Head() { 个人信息
), + onClick: () => { + setIsSelfModalOpen(true); + } }, { key: 'changePass', @@ -38,29 +71,76 @@ export default function Head() { ] return ( -
-
-
- AI引擎软著 - - 软件著作权一站式服务平台 -
-
- - - -
- - - 您好:18888888 - - - + <> +
+
+
+ AI引擎软著 + + 软件著作权一站式服务平台 +
+
+ + + {/**/} +
+ + + 您好:{globalContext.user.nickname} + + + +
-
+ { + if(!globalContext.user.hasUserInfo) { + messageApi.info('请完善个人信息'); + return; + } + setIsSelfModalOpen(false) + }} > + { + modal.confirm({ + title: 'Confirm', + content: '确定保存吗?', + okText: '确认', + cancelText: '取消', + okButtonProps: { + style: { + backgroundColor: 'var(--color-primary)' + } + }, + onOk: () => { + setIsSelfModalOpen(false); + put({ + messageApi, + url: '/api/user-info/update-self', + body: data, + onBefore() { + setLoading(true); + }, + onSuccess() { + messageApi.success('修改成功'); + }, + onFinally() { + setLoading(false); + } + }) + console.log(data); + } + }); + }}/> + + + {contextHolder} + {modalHolder} + ) } diff --git a/src/route/proj/ProjEdit.tsx b/src/route/proj/ProjEdit.tsx index 7896078..6502f51 100644 --- a/src/route/proj/ProjEdit.tsx +++ b/src/route/proj/ProjEdit.tsx @@ -320,30 +320,30 @@ export default function ProjEdit() { descTitle="资料下载"> { window.open(`${Axios.defaults?.baseURL}/route/proj/download/apply/${pathParams.projId}`) - console.log('下载') }} /> { window.open(`${Axios.defaults?.baseURL}/route/proj/download/manual/${pathParams.projId}`) - console.log('下载') }} /> { window.open(`${Axios.defaults?.baseURL}/route/proj/download/code-zip/${pathParams.projId}`) - console.log('下载') }} /> { window.open(`${Axios.defaults?.baseURL}/route/proj/download/code/${pathParams.projId}`) - console.log('下载') }} /> >[0]; + +const dateFormat = 'YYYY年MM月DD日'; + +export interface IUserEditProps { + + handleConfirm(data: FormDataType): void; +} + +export default function UserEdit(props: IUserEditProps) { + + const [messageApi, contextHolder] = message.useMessage(); + const [form] = Form.useForm(); + const [userInfoType, setUserInfoType] = useState('PERSONAL'); + const [idCardFrontImgArray, setIdCardFrontImgArray] = useState([]); + const [idCardBackImgArray, setIdCardBackImgArray] = useState([]); + const [loading, setLoading] = useState(false); + + const beforeUpload = (file: FileType) => { + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; + if (!isJpgOrPng) { + message.error('只能上传 JPG/PNG 格式文件!'); + } + return isJpgOrPng; + }; + + useEffect(() => { + get({ + messageApi, + url: 'api/user-info/get-self', + onSuccess({data}) { + form.setFieldsValue({ + userId: data.userId, + userInfoId: data.userInfoId, + userInfoName: data.userInfoName, + userInfoType: data.userInfoType, + contactAddress: data.contactAddress, + contactPhone: data.contactPhone, + establishDate: data.establishDate ? dayjs(data.establishDate, 'YYYY-MM-DD') : '', + idCardNumber: data.idCardNumber, + idCardFront: data.idCardFront, + idCardStartDate: data.idCardStartDate ? dayjs(data.idCardStartDate, 'YYYY-MM-DD') : '', + idCardBack: data.idCardBack, + idCardEndDate: data.idCardEndDate ? dayjs(data.idCardEndDate, 'YYYY-MM-DD') : '', + idCardType: data.idCardType, + legalPerson: data.legalPerson, + }) + if (data.idCardFront) { + const url = downloadUrl(data.idCardFront); + idCardFrontImgArray.splice(0, 1, { + uid: data.idCardFront, + name: 'front.png', + status: 'done', + url: url, + thumbUrl: url, + }) + setIdCardFrontImgArray([ + ...idCardFrontImgArray, + ]) + } + if (data.idCardBack) { + const url = downloadUrl(data.idCardBack); + idCardBackImgArray.splice(0, 1, { + uid: data.idCardBack, + name: 'back.png', + status: 'done', + url: url, + thumbUrl: url, + }) + setIdCardBackImgArray([ + ...idCardBackImgArray, + ]) + } + setUserInfoType(data.userInfoType); + } + }) + }, [form]) + + return ( + <> +
{ + props.handleConfirm({ + userId: form.getFieldValue('userId'), + userInfoId: form.getFieldValue('userInfoId'), + userInfoName: form.getFieldValue('userInfoName'), + userInfoType: form.getFieldValue('userInfoType'), + contactAddress: form.getFieldValue('contactAddress'), + contactPhone: form.getFieldValue('contactPhone'), + establishDate: form.getFieldValue('establishDate') ? form.getFieldValue('establishDate').format(dateFormat) : '', + idCardBack: form.getFieldValue('idCardBack'), + idCardEndDate: form.getFieldValue('idCardEndDate') ? form.getFieldValue('idCardEndDate').format(dateFormat) : '', + idCardFront: form.getFieldValue('idCardFront'), + idCardNumber: form.getFieldValue('idCardNumber'), + idCardStartDate: form.getFieldValue('idCardStartDate') ? form.getFieldValue('idCardStartDate').format(dateFormat) : '', + idCardType: form.getFieldValue('idCardType'), + legalPerson: form.getFieldValue('legalPerson'), + }); + }} + > + + { + setUserInfoType(e.target.value); + if (e.target.value === 'PERSONAL') { + form.setFieldValue('idCardType', 'ID_CARD'); + } + if (e.target.value === 'ENTERPRISE') { + form.setFieldValue('idCardType', 'ORGANIZATION_CODE'); + } + }}> + 个人 + 企业 + + + + + + { + userInfoType == 'PERSONAL' ? ( + + + 身份证 + + + ) : <> + } + { + userInfoType == 'ENTERPRISE' ? ( + + + 组织机构代码证 + + + ) : <> + } + + + + + + + + { + if (info.file.status === 'uploading') { + setLoading(true); + return; + } + if (info.file.status === 'done') { + setLoading(false); + const fileId = info.file.response.data.fileId; + const url = downloadUrl(fileId); + idCardFrontImgArray[0] = { + uid: info.file.response.data.fileId, + name: 'bg.png', + status: 'done', + url: url, + thumbUrl: url, + } + setIdCardFrontImgArray([ + ...idCardFrontImgArray + ]) + form.setFieldValue('idCardFront', fileId); + return; + } + }} + onRemove={() => { + idCardFrontImgArray.splice(0) + setIdCardFrontImgArray([ + ...idCardFrontImgArray + ]) + }} + > + + + + + { + userInfoType == 'PERSONAL' ? ( + + + { + if (info.file.status === 'uploading') { + setLoading(true); + return; + } + if (info.file.status === 'done') { + setLoading(false); + const fileId = info.file.response.data.fileId; + const url = downloadUrl(fileId); + idCardBackImgArray[0] = { + uid: info.file.response.data.fileId, + name: 'bg.png', + status: 'done', + url: url, + thumbUrl: url, + } + setIdCardBackImgArray([ + ...idCardBackImgArray + ]) + form.setFieldValue('idCardBack', fileId); + return; + } + }} + onRemove={() => { + idCardBackImgArray.splice(0) + setIdCardBackImgArray([ + ...idCardBackImgArray + ]) + }} + > + + + + + ) : <> + } + + + + + label="证件开始时间" + name="idCardStartDate" + rules={[{required: true, message: '请选择证件开始时间'}]} + > + + + + + + label="证件结束时间" + name="idCardEndDate" + rules={[{required: true, message: '请选择证件结束时间'}]} + > + + + + + { + userInfoType == 'ENTERPRISE' ? ( + + + + + + + + + label="成立时间" + name="establishDate" + rules={[{required: true, message: '请选择成立时间'}]} + > + + + + + ) : <> + } + + + + + + + + + + + + + + + + + +
+ + {contextHolder} + + ) + +} \ No newline at end of file