feat: 个人信息
@@ -20,6 +20,10 @@
|
|||||||
-moz-user-select: none; /* Firefox */
|
-moz-user-select: none; /* Firefox */
|
||||||
-ms-user-select: none; /* Internet Explorer/Edge */
|
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||||
user-select: none; /* Non-prefixed version, currently not supported by any browser */
|
user-select: none; /* Non-prefixed version, currently not supported by any browser */
|
||||||
|
.content-box{
|
||||||
|
width: 1439px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-navigator {
|
.header-navigator {
|
||||||
|
56
src/App.tsx
@@ -1,55 +1,7 @@
|
|||||||
import { useEffect, memo } from 'react';
|
import { useEffect, memo } from 'react';
|
||||||
import './App.less';
|
import './App.less';
|
||||||
import { useLocation, useNavigate, Outlet } from 'react-router-dom';
|
import { useLocation, useNavigate, Outlet } from 'react-router-dom';
|
||||||
import PubSub from 'pubsub-js';
|
import Header from '@views/header'
|
||||||
import { Input } from 'antd';
|
|
||||||
import Logo from '@views/imgs/logo.jpg'
|
|
||||||
import Head from '@views/imgs/head.jpg'
|
|
||||||
import TopMenu from '@components/top-menu'
|
|
||||||
|
|
||||||
const { Search } = Input;
|
|
||||||
|
|
||||||
const NavTop = () => {
|
|
||||||
const { pathname } = window.location;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="head-navigator-box">
|
|
||||||
<div className="head-navigator">
|
|
||||||
<div className="head-navigator-left">
|
|
||||||
<div
|
|
||||||
className="head-navigator-logo"
|
|
||||||
onClick={() =>
|
|
||||||
(window.location.href = '/question-bank')
|
|
||||||
}>
|
|
||||||
<img src={Logo} style={{ height: 50 }} />
|
|
||||||
</div>
|
|
||||||
<TopMenu />
|
|
||||||
</div>
|
|
||||||
<div className="head-navigator-user-box">
|
|
||||||
<div className="time-box"></div>
|
|
||||||
{'/question-bank' == pathname && (
|
|
||||||
<div className="head-navigator-input-box">
|
|
||||||
<Search
|
|
||||||
placeholder="请输入感兴趣的内容~"
|
|
||||||
onSearch={(value) => console.log(value)}
|
|
||||||
style={{ width: 300, borderRadius: '10px' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="head-navigator-bell">
|
|
||||||
{/* <Icon type="bell" /> */}
|
|
||||||
</div>
|
|
||||||
<div className="head-navigator-user-img">
|
|
||||||
<img
|
|
||||||
src={Head}
|
|
||||||
style={{ width: 36, height: 36 }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -61,8 +13,10 @@ const App = () => {
|
|||||||
}, [location])
|
}, [location])
|
||||||
return (
|
return (
|
||||||
<div className="app-main">
|
<div className="app-main">
|
||||||
<NavTop />
|
<Header />
|
||||||
<Outlet />
|
<div className='content-box'>
|
||||||
|
<Outlet />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -80,7 +80,7 @@ const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
|||||||
let list = res.data
|
let list = res.data
|
||||||
for (let i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
list[i].children = await getLabels(list[i].id)
|
list[i].children = await getLabels(list[i].id)
|
||||||
if (i === 0) {
|
if (i === 0 && list[i].children.length) {
|
||||||
list[i].children[0].active = true
|
list[i].children[0].active = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -65,8 +65,8 @@ export const imgObject = {
|
|||||||
'https://img11.360buyimg.com/imagetools/jfs/t1/206213/24/13307/2603/617f4fc4E676d448d/622d5287fbf5a919.png',
|
'https://img11.360buyimg.com/imagetools/jfs/t1/206213/24/13307/2603/617f4fc4E676d448d/622d5287fbf5a919.png',
|
||||||
dataImg:
|
dataImg:
|
||||||
'https://img12.360buyimg.com/imagetools/jfs/t1/207558/34/7606/3672/617f4fc4E1ca685fc/3953a92a6072fba4.png',
|
'https://img12.360buyimg.com/imagetools/jfs/t1/207558/34/7606/3672/617f4fc4E1ca685fc/3953a92a6072fba4.png',
|
||||||
javaImg:
|
// javaImg:
|
||||||
'../../views/imgs/javaImg.png',
|
// '../../views/imgs/javaImg.png',
|
||||||
npmImg: 'https://img11.360buyimg.com/imagetools/jfs/t1/200551/24/15367/3145/617f4fc4Ea153dc2e/b4bbf2de8807f42d.png',
|
npmImg: 'https://img11.360buyimg.com/imagetools/jfs/t1/200551/24/15367/3145/617f4fc4Ea153dc2e/b4bbf2de8807f42d.png',
|
||||||
parallelComputingImg:
|
parallelComputingImg:
|
||||||
'https://img14.360buyimg.com/imagetools/jfs/t1/207198/23/7638/3037/617f4fc4E0e20ab9d/40197a6c79c5a33f.png',
|
'https://img14.360buyimg.com/imagetools/jfs/t1/207198/23/7638/3037/617f4fc4E0e20ab9d/40197a6c79c5a33f.png',
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import React, { Component, useState, memo } from 'react'
|
import React, { useState, memo, useEffect } from 'react'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
import './index.less'
|
import './index.less'
|
||||||
// 顶部tab
|
// 顶部tab
|
||||||
@@ -37,6 +37,16 @@ const TopMenu = () => {
|
|||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const cur = MENULIST.filter(t => t.route === location.pathname)
|
||||||
|
if (cur.length) {
|
||||||
|
setCurrentKey(cur[0].key)
|
||||||
|
} else {
|
||||||
|
setCurrentKey('')
|
||||||
|
}
|
||||||
|
}, [location.pathname]);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 切换item
|
* 切换item
|
||||||
* @param {*} item
|
* @param {*} item
|
||||||
@@ -46,6 +56,7 @@ const TopMenu = () => {
|
|||||||
if (item.key === "questionBank") {
|
if (item.key === "questionBank") {
|
||||||
if (location.pathname === '/question-bank') return
|
if (location.pathname === '/question-bank') return
|
||||||
navigate('/question-bank')
|
navigate('/question-bank')
|
||||||
|
setCurrentKey(item.key)
|
||||||
} else {
|
} else {
|
||||||
return message.info("敬请期待")
|
return message.info("敬请期待")
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
@@ -3,6 +3,8 @@ import App from '@/App'
|
|||||||
import QuestionBank from '@views/question-bank';
|
import QuestionBank from '@views/question-bank';
|
||||||
import UploadQuestions from '@views/upload-questions';
|
import UploadQuestions from '@views/upload-questions';
|
||||||
import BrushQuestions from '@views/brush-questions'
|
import BrushQuestions from '@views/brush-questions'
|
||||||
|
import Login from '@views/login'
|
||||||
|
import UserInfo from '@views/user-info'
|
||||||
import {
|
import {
|
||||||
createBrowserRouter,
|
createBrowserRouter,
|
||||||
} from "react-router-dom";
|
} from "react-router-dom";
|
||||||
@@ -24,6 +26,14 @@ const router = createBrowserRouter([
|
|||||||
path: "upload-question",
|
path: "upload-question",
|
||||||
element: <UploadQuestions />,
|
element: <UploadQuestions />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'login',
|
||||||
|
element: <Login />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'user-info',
|
||||||
|
element: <UserInfo />
|
||||||
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { message } from 'antd';
|
import { message, Modal } from 'antd';
|
||||||
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
export const baseHttp = () => {
|
export const baseHttp = () => {
|
||||||
const http = axios.create({
|
const http = axios.create({
|
||||||
@@ -15,6 +16,8 @@ export const baseHttp = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function request(config, url) {
|
export default function request(config, url) {
|
||||||
|
// const navigate = useNavigate()
|
||||||
|
|
||||||
const baseURL = url || '/subject';
|
const baseURL = url || '/subject';
|
||||||
// 1.创建axios的实例
|
// 1.创建axios的实例
|
||||||
const instance = axios.create({
|
const instance = axios.create({
|
||||||
@@ -50,6 +53,7 @@ export default function request(config, url) {
|
|||||||
let { status } = err?.response ?? {};
|
let { status } = err?.response ?? {};
|
||||||
if (status === 401 || !status) {
|
if (status === 401 || !status) {
|
||||||
message.info('页面异常')
|
message.info('页面异常')
|
||||||
|
window.location.replace('/login')
|
||||||
} else if (status === 500 || status === 503) {
|
} else if (status === 500 || status === 503) {
|
||||||
message.error('服务器错误');
|
message.error('服务器错误');
|
||||||
}
|
}
|
||||||
|
97
src/views/header/index.tsx
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import { Input, Dropdown, message } from 'antd';
|
||||||
|
import Logo from '@/imgs/logo.jpg'
|
||||||
|
import Head from '@/imgs/head.jpg'
|
||||||
|
import TopMenu from '@components/top-menu'
|
||||||
|
import { UserOutlined, HeartOutlined, LikeOutlined, LoginOutlined } from '@ant-design/icons'
|
||||||
|
|
||||||
|
const { Search } = Input;
|
||||||
|
|
||||||
|
const menuItems = [
|
||||||
|
{
|
||||||
|
label: '个人中心',
|
||||||
|
key: 1,
|
||||||
|
icon: <UserOutlined style={{ fontSize: '16px' }} />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '我的收藏',
|
||||||
|
key: 2,
|
||||||
|
icon: <HeartOutlined style={{ fontSize: '16px' }} />
|
||||||
|
}, {
|
||||||
|
label: '我的点赞',
|
||||||
|
key: 3,
|
||||||
|
icon: <LikeOutlined style={{ fontSize: '16px' }} />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '退出',
|
||||||
|
key: 4,
|
||||||
|
icon: <LoginOutlined style={{ fontSize: '16px' }} />
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const Header = () => {
|
||||||
|
const { pathname } = window.location;
|
||||||
|
|
||||||
|
|
||||||
|
const handleMenuClick = e => {
|
||||||
|
console.log(e)
|
||||||
|
if (e.key != 1) {
|
||||||
|
return message.info('敬请期待')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="head-navigator-box">
|
||||||
|
<div className="head-navigator">
|
||||||
|
<div className="head-navigator-left">
|
||||||
|
<div
|
||||||
|
className="head-navigator-logo"
|
||||||
|
onClick={() =>
|
||||||
|
(window.location.href = '/question-bank')
|
||||||
|
}>
|
||||||
|
<img src={Logo} style={{ height: 50 }} />
|
||||||
|
</div>
|
||||||
|
<TopMenu />
|
||||||
|
</div>
|
||||||
|
<div className="head-navigator-user-box">
|
||||||
|
<div className="time-box"></div>
|
||||||
|
{'/question-bank' == pathname && (
|
||||||
|
<div className="head-navigator-input-box">
|
||||||
|
<Search
|
||||||
|
placeholder="请输入感兴趣的内容~"
|
||||||
|
onSearch={(value) => console.log(value)}
|
||||||
|
style={{ width: 300, borderRadius: '10px' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="head-navigator-bell">
|
||||||
|
{/* <Icon type="bell" /> */}
|
||||||
|
</div>
|
||||||
|
<div className="head-navigator-user-img">
|
||||||
|
<Dropdown
|
||||||
|
menu={{
|
||||||
|
items: menuItems,
|
||||||
|
onClick: handleMenuClick,
|
||||||
|
}}
|
||||||
|
placement="bottom"
|
||||||
|
trigger={['click']}
|
||||||
|
destroyPopupOnHide
|
||||||
|
overlayStyle={{
|
||||||
|
width: '150px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={Head}
|
||||||
|
style={{ width: 36, height: 36 }}
|
||||||
|
/>
|
||||||
|
</Dropdown>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Header
|
8
src/views/login/index.tsx
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
const Login = () => {
|
||||||
|
return (<div>
|
||||||
|
login
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Login
|
@@ -1,4 +1,4 @@
|
|||||||
import JavaImg from '@views/imgs/javaImg.png'
|
// import JavaImg from '@views/imgs/javaImg.png'
|
||||||
/**
|
/**
|
||||||
* 难度等级
|
* 难度等级
|
||||||
*/
|
*/
|
||||||
@@ -73,7 +73,7 @@ export const apiName = {
|
|||||||
|
|
||||||
export const imgObject = {
|
export const imgObject = {
|
||||||
clickImg:
|
clickImg:
|
||||||
'https://img13.360buyimg.com/imagetools/jfs/t1/222669/25/807/6590/617f4f06Eb2094586/64c39ce3769b8a16.png',
|
'http://117.72.14.166:9000/jichi/icon/%E7%83%AD%E9%97%A8.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20231102%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20231102T153146Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=e6b8cdb3231b1c3d7114212cb9278ecc17cf6d4ec0f759ea0200e04156d4c8b7',
|
||||||
ranking1Img:
|
ranking1Img:
|
||||||
'https://img12.360buyimg.com/imagetools/jfs/t1/110906/3/22471/3750/6214a3bfE392596cf/122c9e4b30948682.png',
|
'https://img12.360buyimg.com/imagetools/jfs/t1/110906/3/22471/3750/6214a3bfE392596cf/122c9e4b30948682.png',
|
||||||
ranking2Img:
|
ranking2Img:
|
||||||
@@ -88,7 +88,7 @@ export const imgObject = {
|
|||||||
'https://img11.360buyimg.com/imagetools/jfs/t1/206213/24/13307/2603/617f4fc4E676d448d/622d5287fbf5a919.png',
|
'https://img11.360buyimg.com/imagetools/jfs/t1/206213/24/13307/2603/617f4fc4E676d448d/622d5287fbf5a919.png',
|
||||||
dataImg:
|
dataImg:
|
||||||
'https://img12.360buyimg.com/imagetools/jfs/t1/207558/34/7606/3672/617f4fc4E1ca685fc/3953a92a6072fba4.png',
|
'https://img12.360buyimg.com/imagetools/jfs/t1/207558/34/7606/3672/617f4fc4E1ca685fc/3953a92a6072fba4.png',
|
||||||
javaImg: JavaImg,
|
// javaImg: JavaImg,
|
||||||
npmImg: 'https://img11.360buyimg.com/imagetools/jfs/t1/200551/24/15367/3145/617f4fc4Ea153dc2e/b4bbf2de8807f42d.png',
|
npmImg: 'https://img11.360buyimg.com/imagetools/jfs/t1/200551/24/15367/3145/617f4fc4Ea153dc2e/b4bbf2de8807f42d.png',
|
||||||
parallelComputingImg:
|
parallelComputingImg:
|
||||||
'https://img14.360buyimg.com/imagetools/jfs/t1/207198/23/7638/3037/617f4fc4E0e20ab9d/40197a6c79c5a33f.png',
|
'https://img14.360buyimg.com/imagetools/jfs/t1/207198/23/7638/3037/617f4fc4E0e20ab9d/40197a6c79c5a33f.png',
|
||||||
|
4
src/views/user-info/index.less
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
.user-info-box{
|
||||||
|
background-color: white;
|
||||||
|
height: 100%;
|
||||||
|
}
|
60
src/views/user-info/index.tsx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { useState } from 'react'
|
||||||
|
import { Form, Row, Col, Input, Button, Card } from 'antd'
|
||||||
|
|
||||||
|
import './index.less'
|
||||||
|
|
||||||
|
const layout = {
|
||||||
|
labelCol: { span: 4 },
|
||||||
|
wrapperCol: { span: 10, offset: 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserInfo = () => {
|
||||||
|
|
||||||
|
const [editFields, setEditFields] = useState<Record<string, any>>({
|
||||||
|
nickName: false,
|
||||||
|
gender: false,
|
||||||
|
introduce: false,
|
||||||
|
birth: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const changeEditFields = (field: string) => {
|
||||||
|
setEditFields({
|
||||||
|
...editFields,
|
||||||
|
[field]: !editFields[field]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className='user-info-box'>
|
||||||
|
<Card title='基本信息'>
|
||||||
|
<Form {...layout} colon={false}>
|
||||||
|
<Row >
|
||||||
|
<Col span={16}>
|
||||||
|
<Form.Item label='用户昵称'>
|
||||||
|
{editFields.nickName ? <Input placeholder='请输入昵称' /> : <>
|
||||||
|
昵称
|
||||||
|
</>}
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={16}>
|
||||||
|
<Form.Item label='性 别'>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={16}>
|
||||||
|
<Form.Item label='个人简介'>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={16}>
|
||||||
|
<Form.Item label='出生日期'>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Form>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserInfo
|