feat: 联调
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
VITE_API_HOST=http://117.72.10.84:3010
|
||||
VITE_API_HOST=http://117.72.10.84:5000
|
||||
VITE_IMG_HOST=http://117.72.14.166:9000
|
@@ -23,6 +23,7 @@
|
||||
.content-box {
|
||||
width: 1439px;
|
||||
margin: 0 auto;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,35 +1,33 @@
|
||||
import React, { Fragment, useState, useEffect } from 'react';
|
||||
import React, { Fragment, useEffect, useState } from 'react'
|
||||
|
||||
import {
|
||||
RightOutlined,
|
||||
UpOutlined,
|
||||
DownOutlined,
|
||||
CaretDownOutlined,
|
||||
CaretUpOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import req from '@utils/request';
|
||||
import { Divider, Spin, Modal } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import './index.less';
|
||||
import { apiName } from './constant';
|
||||
import { imgObject } from '@constants'
|
||||
DownOutlined,
|
||||
RightOutlined,
|
||||
UpOutlined
|
||||
} from '@ant-design/icons'
|
||||
import req from '@utils/request'
|
||||
import { Divider, Modal, Spin } from 'antd'
|
||||
import _ from 'lodash'
|
||||
import { apiName } from './constant'
|
||||
import './index.less'
|
||||
|
||||
/**
|
||||
* 大分类中的背景图
|
||||
* 大分类中的背景图颜色
|
||||
*/
|
||||
export const categoryBackImg = {
|
||||
0: imgObject.backAllImg,
|
||||
1: imgObject.dataImg,
|
||||
2: imgObject.javaImg,
|
||||
3: imgObject.npmImg,
|
||||
4: imgObject.parallelComputingImg,
|
||||
5: imgObject.springbootImg,
|
||||
6: imgObject.sqlImg,
|
||||
7: imgObject.systemDesignImg,
|
||||
8: imgObject.algorithmImg,
|
||||
};
|
||||
const categoryBackColor = {
|
||||
0: '#23b2ff',
|
||||
1: '#ea7d4d',
|
||||
2: '#e93532',
|
||||
3: '#343d71',
|
||||
4: '#dc4ad6',
|
||||
5: '#72b633',
|
||||
6: '#9047de',
|
||||
7: '#dc4077'
|
||||
}
|
||||
|
||||
const categoryShowCount = 4;
|
||||
const categoryShowCount = 4
|
||||
|
||||
const cacheMap = {}
|
||||
|
||||
@@ -38,11 +36,11 @@ const cacheMap = {}
|
||||
* @param {*} total
|
||||
* @returns
|
||||
*/
|
||||
const formatTotal = (total) => {
|
||||
const formatTotal = total => {
|
||||
if (total >= 10000) {
|
||||
return Math.floor(total / 10000) + 'W+';
|
||||
return Math.floor(total / 10000) + 'W+'
|
||||
}
|
||||
return total;
|
||||
return total
|
||||
}
|
||||
|
||||
const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
||||
@@ -53,8 +51,7 @@ const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
||||
const [currentLabelIndex, setCurrentLabelIndex] = useState([])
|
||||
const [openMoreFlag, setOpenMoreFlag] = useState(false)
|
||||
|
||||
|
||||
const getLabels = (id) => {
|
||||
const getLabels = id => {
|
||||
return new Promise(resolve => {
|
||||
req({
|
||||
method: 'post',
|
||||
@@ -97,20 +94,18 @@ const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
||||
}
|
||||
}, [primaryCategoryId])
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 切换一级分类
|
||||
* @param {*} item
|
||||
* @returns
|
||||
*/
|
||||
const onChangeCategory = (item) => () => {
|
||||
const onChangeCategory = item => () => {
|
||||
if (currentActive.id === item.id) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
setCurrentActive(item)
|
||||
props.onChangeCategory(item);
|
||||
};
|
||||
props.onChangeCategory(item)
|
||||
}
|
||||
|
||||
/**
|
||||
* 一级分类模块
|
||||
@@ -118,56 +113,52 @@ const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
||||
*/
|
||||
const renderFirstContainer = () => {
|
||||
return (
|
||||
<div className="first-category-list">
|
||||
<div className='first-category-list'>
|
||||
{categoryList.slice(0, 7).map((categoryModuleItem, categoryModuleIndex) => {
|
||||
return (
|
||||
<div
|
||||
className={`first-category-item ${categoryModuleItem.id === currentActive.id &&
|
||||
'first-category-item-active'
|
||||
className={`first-category-item ${
|
||||
categoryModuleItem.id === currentActive.id && 'first-category-item-active'
|
||||
}`}
|
||||
key={`first_category_${categoryModuleItem.id}`}
|
||||
style={{
|
||||
backgroundImage: `url(${categoryBackImg[categoryModuleIndex]})`,
|
||||
backgroundColor: `${categoryBackColor[categoryModuleIndex]}`
|
||||
}}
|
||||
onClick={onChangeCategory(categoryModuleItem)}>
|
||||
<div className="first-category-item-title">
|
||||
{categoryModuleItem.categoryName}
|
||||
onClick={onChangeCategory(categoryModuleItem)}
|
||||
>
|
||||
<div className='first-category-item-title'>{categoryModuleItem.categoryName}</div>
|
||||
<div className='first-category-item-count'>{categoryModuleItem.count || 50}道题</div>
|
||||
</div>
|
||||
<div className="first-category-item-count">
|
||||
{categoryModuleItem.count || 50}道题
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
})}
|
||||
{categoryList.length > 7 && (
|
||||
<div className="first-category-more" onClick={() => setOpenMoreFlag(true)}>
|
||||
<div className='first-category-more' onClick={() => setOpenMoreFlag(true)}>
|
||||
更多
|
||||
<RightOutlined />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击更多的分类项
|
||||
* @param {*} id
|
||||
* @returns
|
||||
*/
|
||||
const onChangeCategoryMore = (cur) => () => {
|
||||
const onChangeCategoryMore = cur => () => {
|
||||
setOpenMoreFlag(false)
|
||||
setCurrentActive(cur)
|
||||
let list = [...categoryList].reduce((pre, item) => {
|
||||
if (item.id !== cur.id) {
|
||||
pre.push(item);
|
||||
pre.push(item)
|
||||
} else {
|
||||
pre.unshift(item);
|
||||
pre.unshift(item)
|
||||
}
|
||||
return pre
|
||||
}, [])
|
||||
props.onChangeCategoryMore && props.onChangeCategoryMore(cur.id, list)
|
||||
}
|
||||
return pre;
|
||||
}, []);
|
||||
props.onChangeCategoryMore && props.onChangeCategoryMore(cur.id, list);
|
||||
};
|
||||
|
||||
/**
|
||||
* 更多分类
|
||||
@@ -175,31 +166,27 @@ const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
||||
*/
|
||||
const renderMoreBox = () => {
|
||||
return (
|
||||
<div className="first-category-more-list">
|
||||
<div className='first-category-more-list'>
|
||||
{categoryList.slice(7).map((categoryModuleItem, categoryModuleIndex) => {
|
||||
return (
|
||||
<div
|
||||
className="first-category-item"
|
||||
className='first-category-item'
|
||||
key={`first_more_category_${categoryModuleItem.id}`}
|
||||
style={{
|
||||
backgroundImage: `url(${categoryBackImg[categoryModuleIndex]})`,
|
||||
backgroundColor: `${categoryBackColor[categoryModuleIndex]}`
|
||||
}}
|
||||
onClick={onChangeCategoryMore(
|
||||
categoryModuleItem
|
||||
)}
|
||||
onClick={onChangeCategoryMore(categoryModuleItem)}
|
||||
>
|
||||
<div className="first-category-item-title">
|
||||
{categoryModuleItem.categoryName}
|
||||
</div>
|
||||
<div className="first-category-item-count">
|
||||
<div className='first-category-item-title'>{categoryModuleItem.categoryName}</div>
|
||||
<div className='first-category-item-count'>
|
||||
{formatTotal(categoryModuleItem.subjectCount)}道题
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择标签-支持单选(多选)
|
||||
@@ -210,7 +197,7 @@ const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
||||
* @returns
|
||||
*/
|
||||
const onChangeLabel = (secondCategoryIndex, thirdCategoryIndex, active) => () => {
|
||||
const { isMultipleChoice } = props;
|
||||
const { isMultipleChoice } = props
|
||||
const list = _.cloneDeep(secondCategoryList)
|
||||
if (isMultipleChoice) {
|
||||
// 三级标签支持多选
|
||||
@@ -225,8 +212,11 @@ const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
||||
setCurrentLabelIndex([secondCategoryIndex, thirdCategoryIndex])
|
||||
setSecondCategoryList(list)
|
||||
}
|
||||
props.onChangeLabel(_.get(list, [secondCategoryIndex, 'id']), _.get(list, [secondCategoryIndex, 'children', thirdCategoryIndex, 'id']))
|
||||
};
|
||||
props.onChangeLabel(
|
||||
_.get(list, [secondCategoryIndex, 'id']),
|
||||
_.get(list, [secondCategoryIndex, 'children', thirdCategoryIndex, 'id'])
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 展开/收起
|
||||
@@ -235,16 +225,16 @@ const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
||||
*/
|
||||
const onChangeOpenStatus = (secondCategoryIndex, isOpen) => () => {
|
||||
const _list = _.cloneDeep(secondCategoryList)
|
||||
_.set(_list, [secondCategoryIndex, 'isOpen'], !isOpen);
|
||||
_.set(_list, [secondCategoryIndex, 'isOpen'], !isOpen)
|
||||
setSecondCategoryList(_list)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 展开/收起
|
||||
*/
|
||||
const onChangePutAway = () => {
|
||||
setIsPutAway(!isPutAway)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 二级分类模块
|
||||
@@ -253,74 +243,67 @@ const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
||||
const renderSecondContainer = () => {
|
||||
return (
|
||||
<Spin spinning={loading}>
|
||||
<div className="second-category-list">
|
||||
<div className='second-category-list'>
|
||||
{secondCategoryList.map((secondCategoryItem, secondCategoryIndex) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display:
|
||||
secondCategoryIndex >= categoryShowCount && isPutAway
|
||||
? 'none'
|
||||
: 'flex',
|
||||
display: secondCategoryIndex >= categoryShowCount && isPutAway ? 'none' : 'flex'
|
||||
}}
|
||||
className="second-category-item"
|
||||
key={`second_category_${secondCategoryItem.id}`}>
|
||||
<div className="second-category-item-title">
|
||||
className='second-category-item'
|
||||
key={`second_category_${secondCategoryItem.id}`}
|
||||
>
|
||||
<div className='second-category-item-title'>
|
||||
{secondCategoryItem.categoryName}:
|
||||
</div>
|
||||
{secondCategoryItem?.children?.length > 0 && (
|
||||
<div className="second-category-item-box">
|
||||
<div className='second-category-item-box'>
|
||||
<div
|
||||
style={{
|
||||
height: secondCategoryItem.isOpen ? 'auto' : 43,
|
||||
height: secondCategoryItem.isOpen ? 'auto' : 43
|
||||
}}
|
||||
className="second-category-item-list"
|
||||
id={`id_${secondCategoryIndex}`}>
|
||||
{secondCategoryItem.children.map(
|
||||
(thirdCategoryItem, thirdCategoryIndex) => {
|
||||
className='second-category-item-list'
|
||||
id={`id_${secondCategoryIndex}`}
|
||||
>
|
||||
{secondCategoryItem.children.map((thirdCategoryItem, thirdCategoryIndex) => {
|
||||
return (
|
||||
<div
|
||||
className={`third-category-item ${thirdCategoryItem.active
|
||||
? 'third-category-item-active'
|
||||
: ''
|
||||
className={`third-category-item ${
|
||||
thirdCategoryItem.active ? 'third-category-item-active' : ''
|
||||
}`}
|
||||
key={`third_category_${thirdCategoryItem.id}`}
|
||||
onClick={onChangeLabel(
|
||||
secondCategoryIndex,
|
||||
thirdCategoryIndex,
|
||||
(thirdCategoryItem.active || false)
|
||||
)}>
|
||||
thirdCategoryItem.active || false
|
||||
)}
|
||||
>
|
||||
{thirdCategoryItem.labelName}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)}
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
{
|
||||
secondCategoryItem.children.length > 5 ? <div
|
||||
{secondCategoryItem.children.length > 5 ? (
|
||||
<div
|
||||
id={`second_id_${secondCategoryIndex}`}
|
||||
className="second-category-item-status"
|
||||
className='second-category-item-status'
|
||||
onClick={onChangeOpenStatus(
|
||||
secondCategoryIndex,
|
||||
(secondCategoryItem.isOpen || false)
|
||||
)}>
|
||||
<div className="second-category-item-type" style={{ fontSize: 12 }}>
|
||||
secondCategoryItem.isOpen || false
|
||||
)}
|
||||
>
|
||||
<div className='second-category-item-type' style={{ fontSize: 12 }}>
|
||||
{secondCategoryItem.isOpen ? '收起' : '展开'}
|
||||
</div>
|
||||
<div className="second-category-item-icon" style={{ fontSize: 12 }}>
|
||||
{secondCategoryItem.isOpen ? (
|
||||
<UpOutlined />
|
||||
) : (
|
||||
<DownOutlined />
|
||||
)}
|
||||
<div className='second-category-item-icon' style={{ fontSize: 12 }}>
|
||||
{secondCategoryItem.isOpen ? <UpOutlined /> : <DownOutlined />}
|
||||
</div>
|
||||
</div> : null
|
||||
}
|
||||
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
})}
|
||||
{secondCategoryList?.length >= categoryShowCount && (
|
||||
<Divider
|
||||
@@ -330,7 +313,8 @@ const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
||||
marginTop: 10,
|
||||
fontSize: 13,
|
||||
cursor: 'pointer'
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{isPutAway ? '展开' : '收起'}
|
||||
{isPutAway ? (
|
||||
<CaretDownOutlined style={{ marginLeft: 4 }} />
|
||||
@@ -341,16 +325,13 @@ const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
||||
)}
|
||||
</div>
|
||||
</Spin>
|
||||
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="category-box">
|
||||
<div className='category-box'>
|
||||
<Fragment>{categoryList?.length && renderFirstContainer()}</Fragment>
|
||||
<Fragment>
|
||||
{secondCategoryList?.length > 0 && renderSecondContainer()}
|
||||
</Fragment>
|
||||
<Fragment>{secondCategoryList?.length > 0 && renderSecondContainer()}</Fragment>
|
||||
{/* {!this.props.isHideSec && (
|
||||
<Fragment>
|
||||
{secondCategoryList?.length > 0 && this.renderSecondContainer()}
|
||||
@@ -361,7 +342,8 @@ const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
||||
footer={null}
|
||||
closable={true}
|
||||
centered
|
||||
onCancel={() => setOpenMoreFlag(false)}>
|
||||
onCancel={() => setOpenMoreFlag(false)}
|
||||
>
|
||||
{renderMoreBox()}
|
||||
</Modal>
|
||||
</div>
|
||||
@@ -369,5 +351,3 @@ const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
|
||||
}
|
||||
|
||||
export default CategoryList
|
||||
|
||||
|
||||
|
@@ -5,29 +5,29 @@ const host = import.meta.env.VITE_IMG_HOST
|
||||
export const filterDifficulty = [
|
||||
{
|
||||
id: 0,
|
||||
title: '全部',
|
||||
title: '全部'
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: '初级',
|
||||
title: '初级'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '中级',
|
||||
title: '中级'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '高级',
|
||||
title: '高级'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '资深',
|
||||
title: '资深'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: '专家',
|
||||
},
|
||||
];
|
||||
title: '专家'
|
||||
}
|
||||
]
|
||||
|
||||
/**
|
||||
* 难度等级
|
||||
@@ -35,54 +35,28 @@ export const filterDifficulty = [
|
||||
export const gradeObject = {
|
||||
1: {
|
||||
color: 'rgba(60, 110, 238, 0.5)',
|
||||
title: '初级',
|
||||
title: '初级'
|
||||
},
|
||||
2: {
|
||||
color: 'rgba(60, 110, 238, 0.6)',
|
||||
title: '中级',
|
||||
title: '中级'
|
||||
},
|
||||
3: {
|
||||
color: 'rgba(60, 110, 238, 0.7)',
|
||||
title: '高级',
|
||||
title: '高级'
|
||||
},
|
||||
4: {
|
||||
color: 'rgba(60, 110, 238, 0.8)',
|
||||
title: '资深',
|
||||
title: '资深'
|
||||
},
|
||||
5: {
|
||||
color: 'rgba(60, 110, 238, 0.9)',
|
||||
title: '专家',
|
||||
},
|
||||
};
|
||||
title: '专家'
|
||||
}
|
||||
}
|
||||
|
||||
export const imgObject = {
|
||||
clickImg:
|
||||
host + '/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:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/110906/3/22471/3750/6214a3bfE392596cf/122c9e4b30948682.png',
|
||||
ranking2Img:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/211695/8/12987/4360/6214a3bfEd4679fde/4f3c55783bb9119c.png',
|
||||
ranking3Img:
|
||||
'https://img10.360buyimg.com/imagetools/jfs/t1/175261/19/28428/4566/6214a3bfE476e1b0f/ea59084c55001c06.png',
|
||||
rankingImg:
|
||||
'https://img11.360buyimg.com/imagetools/jfs/t1/167264/35/27633/603/6214a3bfEf8feff1d/8d833235e6bc468d.png',
|
||||
timeline:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/210387/35/7564/555/617f4fbbE0cb305c1/728913d21e650794.png',
|
||||
backAllImg:
|
||||
'https://img11.360buyimg.com/imagetools/jfs/t1/206213/24/13307/2603/617f4fc4E676d448d/622d5287fbf5a919.png',
|
||||
dataImg:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/207558/34/7606/3672/617f4fc4E1ca685fc/3953a92a6072fba4.png',
|
||||
javaImg: 'https://img14.360buyimg.com/imagetools/jfs/t1/213752/24/2703/4803/617f4fc4E037da291/5f8050641d4d73d2.png',
|
||||
npmImg: 'https://img11.360buyimg.com/imagetools/jfs/t1/200551/24/15367/3145/617f4fc4Ea153dc2e/b4bbf2de8807f42d.png',
|
||||
parallelComputingImg:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/207198/23/7638/3037/617f4fc4E0e20ab9d/40197a6c79c5a33f.png',
|
||||
springbootImg:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/171775/10/24915/4127/617f4fc4Eeb3d356e/cfbfe8d7c3155047.png',
|
||||
sqlImg: 'https://img13.360buyimg.com/imagetools/jfs/t1/208027/11/7347/3074/617f4fc4Ef11e9495/1093903301db1d1d.png',
|
||||
systemDesignImg:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/206967/24/7622/3629/617f4fc4E60a188b3/cb659847c5d4232a.png',
|
||||
algorithmImg:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/215758/34/2633/4128/617f4fc4E5dcdab66/727be155858a06a5.png',
|
||||
defaultImg:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/155957/24/22934/2028/617a147cE8bcbb57a/7a4885e4ae99a895.png',
|
||||
};
|
||||
host +
|
||||
'/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'
|
||||
}
|
||||
|
BIN
src/imgs/ranking1Img.png
Normal file
BIN
src/imgs/ranking1Img.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
BIN
src/imgs/ranking2Img.png
Normal file
BIN
src/imgs/ranking2Img.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
BIN
src/imgs/ranking3Img.png
Normal file
BIN
src/imgs/ranking3Img.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
BIN
src/imgs/rankingImg.png
Normal file
BIN
src/imgs/rankingImg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 603 B |
@@ -1,24 +1,25 @@
|
||||
import axios from 'axios';
|
||||
import { message, Modal } from 'antd';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { message } from 'antd'
|
||||
import axios from 'axios'
|
||||
|
||||
export const baseHttp = () => {
|
||||
const http = axios.create({
|
||||
baseURL: "/subject",
|
||||
baseURL: '/subject',
|
||||
timeout: 5 * 60 * 1000, // request timeout
|
||||
withCredentials: true, // send cookies when cross-domain requests
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
},
|
||||
});
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}
|
||||
})
|
||||
|
||||
return http;
|
||||
};
|
||||
return http
|
||||
}
|
||||
|
||||
export default function request(config, url) {
|
||||
console.log(config, url, 'config url')
|
||||
// const navigate = useNavigate()
|
||||
|
||||
const baseURL = url || '/subject';
|
||||
const userInfoStorage = localStorage.getItem('userInfo')
|
||||
const userInfo = userInfoStorage ? JSON.parse(userInfoStorage) : {}
|
||||
const baseURL = url || '/subject/subject'
|
||||
// 1.创建axios的实例
|
||||
const instance = axios.create({
|
||||
baseURL,
|
||||
@@ -26,41 +27,45 @@ export default function request(config, url) {
|
||||
withCredentials: true, // send cookies when cross-domain requests
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
},
|
||||
});
|
||||
[userInfo.tokenName]: 'jichi ' + userInfo.tokenValue
|
||||
}
|
||||
})
|
||||
|
||||
// 2.axios的拦截器
|
||||
// 2.1.请求拦截的作用
|
||||
instance.interceptors.request.use(
|
||||
(config) => {
|
||||
return config;
|
||||
config => {
|
||||
return config
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
err => {
|
||||
console.log(err)
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
// 2.2.响应拦截
|
||||
instance.interceptors.response.use(
|
||||
(res) => {
|
||||
let { code } = res.data;
|
||||
res => {
|
||||
let { code } = res.data
|
||||
if (code === 500) {
|
||||
message.error(res.data.message);
|
||||
message.error(res.data.message)
|
||||
}
|
||||
return res.data;
|
||||
if (code === 401) {
|
||||
window.location.replace('/login')
|
||||
}
|
||||
return res.data
|
||||
},
|
||||
(err) => {
|
||||
let { status } = err?.response ?? {};
|
||||
err => {
|
||||
let { status } = err?.response ?? {}
|
||||
if (status === 401 || !status) {
|
||||
message.info('页面异常')
|
||||
window.location.replace('/login')
|
||||
} else if (status === 500 || status === 503) {
|
||||
message.error('服务器错误');
|
||||
message.error('服务器错误')
|
||||
}
|
||||
return Promise.reject(err);
|
||||
return Promise.reject(err)
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
// 3.发送真正的网络请求
|
||||
return instance(config);
|
||||
return instance(config)
|
||||
}
|
||||
|
@@ -30,6 +30,10 @@
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
.qrcode-desc {
|
||||
padding: 20px 0;
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,45 +1,70 @@
|
||||
import { useState } from 'react'
|
||||
import { Input, Button, Space } from 'antd'
|
||||
import LoginQrcode from '@imgs/login_qrcode.jpg'
|
||||
import req from '@utils/request';
|
||||
import req from '@utils/request'
|
||||
import { Button, Input, Space, message } from 'antd'
|
||||
import { useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
import './index.less'
|
||||
|
||||
const loginApiName = '/user/doLogin'
|
||||
|
||||
const Login = () => {
|
||||
|
||||
const [validCode, setValidCode] = useState('')
|
||||
const navigate = useNavigate()
|
||||
|
||||
const changeCode = e => {
|
||||
setValidCode(e.target.value)
|
||||
}
|
||||
|
||||
const doLogin = () => {
|
||||
console.log(validCode)
|
||||
if (!validCode) return
|
||||
req({
|
||||
req(
|
||||
{
|
||||
method: 'get',
|
||||
url: loginApiName,
|
||||
data: { validCode }
|
||||
params: { validCode }
|
||||
},
|
||||
'/auth'
|
||||
).then(res => {
|
||||
if (res.success && res.data) {
|
||||
message.success('登录成功')
|
||||
localStorage.setItem('userInfo', JSON.stringify(res.data))
|
||||
setTimeout(() => {
|
||||
navigate('/question-bank')
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (<div className="login-box">
|
||||
return (
|
||||
<div className='login-box'>
|
||||
<div className='login-container-inner'>
|
||||
<div className='notes'>LeNet-5 诞生
|
||||
1998 年 11 月,早期经典卷积神经网络 LeNet-5 诞生。杨立昆、莱昂·伯托等发表经典论文“Gradient-Based Learning Applied to Document Recognition”,文章总结了应用于手写字符识别的各种模型并进行了比对,结果显示卷积神经网络表现超群。</div>
|
||||
<div className='notes'>
|
||||
LeNet-5 诞生 1998 年 11 月,早期经典卷积神经网络 LeNet-5
|
||||
诞生。杨立昆、莱昂·伯托等发表经典论文“Gradient-Based Learning Applied to Document
|
||||
Recognition”,文章总结了应用于手写字符识别的各种模型并进行了比对,结果显示卷积神经网络表现超群。
|
||||
</div>
|
||||
<div className='qrcode-box'>
|
||||
<div className='qrcode-desc'>
|
||||
<p>微信扫码关注公众号</p>
|
||||
<p>获取验证码登录</p>
|
||||
</div>
|
||||
<div className='qrcode-img'>
|
||||
<img src={LoginQrcode} alt="" />
|
||||
<img src={LoginQrcode} alt='' />
|
||||
</div>
|
||||
<div className='qrcode-form'>
|
||||
<Space>
|
||||
<Input maxLength={3} placeholder='验证码' onChange={changeCode} value={validCode} />
|
||||
<Button type='primary' ghost onClick={doLogin}>登录</Button>
|
||||
<Button type='primary' ghost onClick={doLogin}>
|
||||
登录
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>)
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Login
|
@@ -1,20 +1,23 @@
|
||||
import React from 'react'
|
||||
import { Popover, Spin } from 'antd'
|
||||
import ClickImg from '@/imgs/clickImg.png'
|
||||
import Ranking1Img from '@/imgs/ranking1Img.png'
|
||||
import Ranking2Img from '@/imgs/ranking2Img.png'
|
||||
import Ranking3Img from '@/imgs/ranking3Img.png'
|
||||
import RankingImg from '@/imgs/rankingImg.png'
|
||||
import { debounce } from '@utils'
|
||||
import { RankingTypeText, RankingTypeBtnText } from '../../constant'
|
||||
import { Popover, Spin, message } from 'antd'
|
||||
import React from 'react'
|
||||
import { RankingTypeBtnText, RankingTypeText } from '../../constant'
|
||||
import './index.less'
|
||||
import { message } from 'antd'
|
||||
import { imgObject } from '@constants'
|
||||
|
||||
const rankingBackImg = {
|
||||
0: imgObject.ranking1Img,
|
||||
1: imgObject.ranking2Img,
|
||||
2: imgObject.ranking3Img,
|
||||
0: Ranking1Img,
|
||||
1: Ranking2Img,
|
||||
2: Ranking3Img
|
||||
}
|
||||
|
||||
export default function RankingBox(props) {
|
||||
const { isLoading = false, currentActive, rankingType, contributionList } = props
|
||||
const onChangeRanking = (index) =>
|
||||
const onChangeRanking = index =>
|
||||
debounce(() => {
|
||||
props.onHandleRanking && props.onHandleRanking(index)
|
||||
})
|
||||
@@ -36,17 +39,19 @@ export default function RankingBox(props) {
|
||||
let rankingList = contributionList || []
|
||||
|
||||
return (
|
||||
<div className="ranking-list-box">
|
||||
<div className="ranking-list-header">
|
||||
<div className="ranking-list-title">{RankingTypeText[rankingType]}</div>
|
||||
<div className="ranking-list-btns">
|
||||
<div className='ranking-list-box'>
|
||||
<div className='ranking-list-header'>
|
||||
<div className='ranking-list-title'>{RankingTypeText[rankingType]}</div>
|
||||
<div className='ranking-list-btns'>
|
||||
{tabList.length > 0 &&
|
||||
tabList.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
key={`${rankingType}_${item.key}`}
|
||||
onClick={onChangeRanking(index)}
|
||||
className={`ranking-list-btn ${currentActive === index ? 'ranking-list-btn-active' : ''}`}
|
||||
className={`ranking-list-btn ${
|
||||
currentActive === index ? 'ranking-list-btn-active' : ''
|
||||
}`}
|
||||
>
|
||||
{item.tab}
|
||||
</div>
|
||||
@@ -55,56 +60,52 @@ export default function RankingBox(props) {
|
||||
</div>
|
||||
</div>
|
||||
<Spin spinning={isLoading}>
|
||||
<div className="ranking-list">
|
||||
<div className='ranking-list'>
|
||||
{rankingList?.length > 0 &&
|
||||
rankingList.map((item, index) => {
|
||||
return (
|
||||
<div className="ranking-item" key={item.id}>
|
||||
<div className="ranking-left">
|
||||
<div className='ranking-item' key={item.id}>
|
||||
<div className='ranking-left'>
|
||||
<div
|
||||
className="ranking-icon"
|
||||
className='ranking-icon'
|
||||
style={{
|
||||
backgroundImage: `url(${index <= 2 ? rankingBackImg[index] : imgObject.rankingImg})`,
|
||||
backgroundImage: `url(${index <= 2 ? rankingBackImg[index] : RankingImg})`
|
||||
}}
|
||||
>
|
||||
{index > 2 && index + 1}
|
||||
</div>
|
||||
<div className="ranking-head-img">
|
||||
<img src={item.headImg} className="ranking-head-icon" />
|
||||
<div className='ranking-head-img'>
|
||||
<img src={item.headImg} className='ranking-head-icon' />
|
||||
</div>
|
||||
<Popover
|
||||
title={
|
||||
<div>
|
||||
{item.name}
|
||||
</div>
|
||||
}
|
||||
title={<div>{item.name}</div>}
|
||||
content={
|
||||
<div className="tooltip-info">
|
||||
<div className='tooltip-info'>
|
||||
<div>{item.name}</div>
|
||||
{/* <div>{item.organizationFullName}</div> */}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="ranking-info">
|
||||
<div className="ranking-name">{item.name}</div>
|
||||
<div className='ranking-info'>
|
||||
<div className='ranking-name'>{item.name}</div>
|
||||
{/* <div className="ranking-department">{item.organizationName}</div> */}
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
<div className="ranking-right">🔥 {item.count}</div>
|
||||
<div className='ranking-right'>🔥 {item.count}</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Spin>
|
||||
<div className="ranking-btn-go" onClick={onJump}>
|
||||
<div className='ranking-btn-go' onClick={onJump}>
|
||||
<div
|
||||
className="ranking-btn-go-icon"
|
||||
className='ranking-btn-go-icon'
|
||||
style={{
|
||||
backgroundImage: `url(${imgObject.clickImg})`,
|
||||
backgroundImage: `url(${ClickImg})`
|
||||
}}
|
||||
></div>
|
||||
<div className="ranking-btn-text">{RankingTypeBtnText[rankingType]}</div>
|
||||
<div className='ranking-btn-text'>{RankingTypeBtnText[rankingType]}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@@ -1,10 +1,14 @@
|
||||
import Head from '@/imgs/head.jpg'
|
||||
import { LoadingOutlined, PlusOutlined } from '@ant-design/icons'
|
||||
import { Button, Card, Col, Form, Input, Radio, Row } from 'antd'
|
||||
import req from '@utils/request'
|
||||
import { Button, Card, Col, Form, Input, Radio, Row, message } from 'antd'
|
||||
import { memo, useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
import './index.less'
|
||||
|
||||
const { TextArea } = Input
|
||||
const apiName = '/user/update'
|
||||
|
||||
const layout = {
|
||||
labelCol: { span: 4 },
|
||||
@@ -15,9 +19,43 @@ const UserInfo = () => {
|
||||
const [form] = Form.useForm()
|
||||
const [editFlag, setEditFlag] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const navigate = useNavigate()
|
||||
|
||||
const onFinish = values => {
|
||||
console.log(values)
|
||||
const onFinish = () => {
|
||||
setLoading(true)
|
||||
const userInfoStorage = localStorage.getItem('userInfo')
|
||||
const { loginId = '' } = userInfoStorage ? JSON.parse(userInfoStorage) : {}
|
||||
const values = form.getFieldsValue()
|
||||
if (!Object.values(values).filter(Boolean).length) {
|
||||
setLoading(false)
|
||||
return
|
||||
}
|
||||
const params = {
|
||||
userName: loginId,
|
||||
...values
|
||||
}
|
||||
req(
|
||||
{
|
||||
method: 'post',
|
||||
url: apiName,
|
||||
data: { ...params }
|
||||
},
|
||||
'/auth'
|
||||
)
|
||||
.then(res => {
|
||||
if (res.success) {
|
||||
message.success('更新成功')
|
||||
setTimeout(() => {
|
||||
navigate('/question-bank')
|
||||
}, 1000)
|
||||
}
|
||||
setLoading(false)
|
||||
setEditFlag(false)
|
||||
})
|
||||
.catch(() => {
|
||||
message.error('更新失败')
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
|
||||
const uploadButton = (
|
||||
@@ -50,10 +88,7 @@ const UserInfo = () => {
|
||||
</Col>
|
||||
<Col span={16}>
|
||||
{editFlag ? (
|
||||
<Form.Item
|
||||
label='性 别'
|
||||
name='gender'
|
||||
>
|
||||
<Form.Item label='性 别' name='sex'>
|
||||
<Radio.Group>
|
||||
<Radio value={1}>男</Radio>
|
||||
<Radio value={2}>女</Radio>
|
||||
@@ -65,6 +100,17 @@ const UserInfo = () => {
|
||||
</Form.Item>
|
||||
)}
|
||||
</Col>
|
||||
<Col span={16}>
|
||||
{editFlag ? (
|
||||
<Form.Item label='手机号码' name='phone'>
|
||||
<Input placeholder='请输入手机号码' />
|
||||
</Form.Item>
|
||||
) : (
|
||||
<Form.Item label='手机号码'>
|
||||
<>暂无</>
|
||||
</Form.Item>
|
||||
)}
|
||||
</Col>
|
||||
<Col span={16}>
|
||||
{editFlag ? (
|
||||
<Form.Item
|
||||
@@ -95,7 +141,12 @@ const UserInfo = () => {
|
||||
<Form.Item wrapperCol={{ offset: 5 }}>
|
||||
{editFlag ? (
|
||||
<>
|
||||
<Button type='primary' style={{ marginRight: '20px' }} onClick={onFinish}>
|
||||
<Button
|
||||
type='primary'
|
||||
style={{ marginRight: '20px' }}
|
||||
onClick={onFinish}
|
||||
loading={loading}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
<Button onClick={() => setEditFlag(false)}>取消</Button>
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
const path = require('path')
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default ({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd());
|
||||
const env = loadEnv(mode, process.cwd())
|
||||
return defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
@@ -14,17 +14,21 @@ export default ({ mode }) => {
|
||||
'@utils': path.resolve(__dirname, 'src/utils'),
|
||||
'@components': path.resolve(__dirname, 'src/components'),
|
||||
'@imgs': path.resolve(__dirname, 'src/imgs'),
|
||||
'@constants': path.resolve(__dirname, 'src/constants'),
|
||||
'@constants': path.resolve(__dirname, 'src/constants')
|
||||
}
|
||||
},
|
||||
plugins: [react()],
|
||||
server: {
|
||||
proxy: {
|
||||
"/subject": {
|
||||
'/subject': {
|
||||
target: env.VITE_API_HOST,
|
||||
changeOrigin: true,
|
||||
},
|
||||
changeOrigin: true
|
||||
},
|
||||
'/auth': {
|
||||
target: env.VITE_API_HOST,
|
||||
changeOrigin: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user