diff --git a/.env.development b/.env.development
index 204eaff..6a06899 100644
--- a/.env.development
+++ b/.env.development
@@ -1,2 +1,2 @@
-VITE_API_HOST=http://117.72.10.84:3010
-VITE_IMG_HOST=http://117.72.14.166:9000
\ No newline at end of file
+VITE_API_HOST=http://117.72.10.84:5000
+VITE_IMG_HOST=http://117.72.14.166:9000
diff --git a/src/App.less b/src/App.less
index cb96a0e..8b051e6 100644
--- a/src/App.less
+++ b/src/App.less
@@ -1,159 +1,160 @@
@import '@assets/base.less';
.app-main {
- display: flex;
- flex-direction: row;
- border-radius: 4px;
+ display: flex;
+ flex-direction: row;
+ border-radius: 4px;
+ margin: 0 auto;
+ position: absolute;
+ min-width: 1439px;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #f3f4f6;
+ padding: 66px 16px 32px;
+ overflow: hidden;
+ -webkit-touch-callout: none; /* iOS Safari */
+ -webkit-user-select: none; /* Chrome/Safari/Opera */
+ -khtml-user-select: none; /* Konqueror */
+ -moz-user-select: none; /* Firefox */
+ -ms-user-select: none; /* Internet Explorer/Edge */
+ user-select: none; /* Non-prefixed version, currently not supported by any browser */
+ .content-box {
+ width: 1439px;
margin: 0 auto;
- position: absolute;
- min-width: 1439px;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: #f3f4f6;
- padding: 66px 16px 32px;
- overflow: hidden;
- -webkit-touch-callout: none; /* iOS Safari */
- -webkit-user-select: none; /* Chrome/Safari/Opera */
- -khtml-user-select: none; /* Konqueror */
- -moz-user-select: none; /* Firefox */
- -ms-user-select: none; /* Internet Explorer/Edge */
- user-select: none; /* Non-prefixed version, currently not supported by any browser */
- .content-box{
- width: 1439px;
- margin: 0 auto;
- }
+ overflow: auto;
+ }
}
.header-navigator {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- height: 50px;
- min-width: 1439px;
- background-color: #fff;
- border-radius: 4px;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 50px;
+ min-width: 1439px;
+ background-color: #fff;
+ border-radius: 4px;
}
.nav-title {
- display: flex;
- justify-content: space-between;
- cursor: pointer;
- width: 1407px;
- margin: 0 auto;
- line-height: 50px;
- color: #1890ff;
- font-size: 24px;
- // font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", 微软雅黑,
- // Arial, sans-serif;
+ display: flex;
+ justify-content: space-between;
+ cursor: pointer;
+ width: 1407px;
+ margin: 0 auto;
+ line-height: 50px;
+ color: #1890ff;
+ font-size: 24px;
+ // font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", 微软雅黑,
+ // Arial, sans-serif;
}
.header-navigator .user {
- width: 36px;
- height: 36px;
- float: right;
- /* background: #1890ff; */
- border-radius: 50%;
- color: #fff;
- margin-top: 7px;
- line-height: 36px;
- text-align: center;
- font-size: 16px;
- overflow: hidden;
- box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
+ width: 36px;
+ height: 36px;
+ float: right;
+ /* background: #1890ff; */
+ border-radius: 50%;
+ color: #fff;
+ margin-top: 7px;
+ line-height: 36px;
+ text-align: center;
+ font-size: 16px;
+ overflow: hidden;
+ box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
}
.jump-box {
- font-size: 14px;
- margin-right: 20px;
+ font-size: 14px;
+ margin-right: 20px;
}
.info-time-box {
- display: flex;
+ display: flex;
}
.time-box {
- margin-top: 8px;
- margin-right: 120px;
+ margin-top: 8px;
+ margin-right: 120px;
}
.head-navigator-box {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- height: 50px;
- background-color: #fff;
- border-radius: 4px;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 50px;
+ background-color: #fff;
+ border-radius: 4px;
}
.head-navigator {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin: 0 auto;
- width: 1435px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin: 0 auto;
+ width: 1435px;
}
.head-navigator-left {
- display: flex;
- align-items: center;
+ display: flex;
+ align-items: center;
}
.head-navigator-logo {
- margin-right: 20px;
- // line-height: 50px;
- cursor: pointer;
- color: #1890ff;
- font-size: 24px;
- // font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, 微软雅黑,
- // Arial, sans-serif;
+ margin-right: 20px;
+ // line-height: 50px;
+ cursor: pointer;
+ color: #1890ff;
+ font-size: 24px;
+ // font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, 微软雅黑,
+ // Arial, sans-serif;
}
.head-navigator-select-box {
- display: flex;
- justify-content: space-between;
- align-items: center;
- width: 500px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 500px;
}
.head-navigator-menu-box {
- display: flex;
+ display: flex;
}
.head-navigator-menu-box .ant-menu-horizontal {
- border-bottom: 0;
+ border-bottom: 0;
}
.ant-menu-horizontal > .ant-menu-item,
.ant-menu-horizontal > .ant-menu-submenu {
- padding: 0px;
- margin: 0 12px;
+ padding: 0px;
+ margin: 0 12px;
}
.head-navigator-input-box {
- margin-right: 24px;
+ margin-right: 24px;
}
.head-navigator-input-box .ant-input {
- border-radius: 16px;
+ border-radius: 16px;
}
.head-navigator-user-box {
- display: flex;
- justify-content: center;
- align-items: center;
+ display: flex;
+ justify-content: center;
+ align-items: center;
}
.head-navigator-bell {
- display: flex;
- justify-content: center;
- align-items: center;
- margin-right: 24px;
- width: 28px;
- height: 28px;
- border-radius: 50%;
- cursor: pointer;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-right: 24px;
+ width: 28px;
+ height: 28px;
+ border-radius: 50%;
+ cursor: pointer;
}
.head-navigator-bell:hover {
- background-color: rgba(0, 10, 32, 0.03);
+ background-color: rgba(0, 10, 32, 0.03);
}
.head-navigator-user-img {
- width: 36px;
- height: 36px;
- color: #fff;
- cursor: pointer;
- border-radius: 50%;
- box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
+ width: 36px;
+ height: 36px;
+ color: #fff;
+ cursor: pointer;
+ border-radius: 50%;
+ box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
}
diff --git a/src/components/category-list/index.jsx b/src/components/category-list/index.jsx
index 02a68ac..efec0c5 100644
--- a/src/components/category-list/index.jsx
+++ b/src/components/category-list/index.jsx
@@ -1,373 +1,353 @@
-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'
+ CaretDownOutlined,
+ CaretUpOutlined,
+ 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 = {}
/**
- * 上万后展示 W+
- * @param {*} total
- * @returns
- */
-const formatTotal = (total) => {
- if (total >= 10000) {
- return Math.floor(total / 10000) + 'W+';
- }
- return total;
+ * 上万后展示 W+
+ * @param {*} total
+ * @returns
+ */
+const formatTotal = total => {
+ if (total >= 10000) {
+ return Math.floor(total / 10000) + 'W+'
+ }
+ return total
}
const CategoryList = ({ primaryCategoryId, categoryList, ...props }) => {
- const [secondCategoryList, setSecondCategoryList] = useState([])
- const [currentActive, setCurrentActive] = useState(categoryList[0])
- const [isPutAway, setIsPutAway] = useState(true)
- const [loading, setLoading] = useState(false)
- const [currentLabelIndex, setCurrentLabelIndex] = useState([])
- const [openMoreFlag, setOpenMoreFlag] = useState(false)
+ const [secondCategoryList, setSecondCategoryList] = useState([])
+ const [currentActive, setCurrentActive] = useState(categoryList[0])
+ const [isPutAway, setIsPutAway] = useState(true)
+ const [loading, setLoading] = useState(false)
+ const [currentLabelIndex, setCurrentLabelIndex] = useState([])
+ const [openMoreFlag, setOpenMoreFlag] = useState(false)
-
- const getLabels = (id) => {
- return new Promise(resolve => {
- req({
- method: 'post',
- url: apiName.queryLabelByCategoryId,
- data: { categoryId: id }
- }).then(res => {
- if (cacheMap[id]) {
- resolve(cacheMap[id])
- } else {
- cacheMap[id] = res.data
- resolve(res.data)
- }
- })
- })
- }
-
- // 获取大类下分类
- const getCategoryByPrimary = () => {
- req({
- method: 'post',
- url: apiName.queryCategoryByPrimary,
- data: { categoryType: 2, parentId: currentActive.id }
- }).then(async res => {
- let list = res.data
- for (let i = 0; i < list.length; i++) {
- list[i].children = await getLabels(list[i].id)
- if (i === 0 && list[i].children.length) {
- list[i].children[0].active = true
- }
- }
- setSecondCategoryList(_.cloneDeep(list))
- setCurrentLabelIndex([0, 0])
- props.onChangeLabel(_.get(list, [0, 'id']), _.get(list, [0, 'children', 0, 'id']))
- })
- }
-
- useEffect(() => {
- if (primaryCategoryId) {
- getCategoryByPrimary()
- }
- }, [primaryCategoryId])
-
-
-
- /**
- * 切换一级分类
- * @param {*} item
- * @returns
- */
- const onChangeCategory = (item) => () => {
- if (currentActive.id === item.id) {
- return;
- }
- setCurrentActive(item)
- props.onChangeCategory(item);
- };
-
- /**
- * 一级分类模块
- * @returns
- */
- const renderFirstContainer = () => {
- return (
-
- {categoryList.slice(0, 7).map((categoryModuleItem, categoryModuleIndex) => {
- return (
-
-
- {categoryModuleItem.categoryName}
-
-
- {categoryModuleItem.count || 50}道题
-
-
- );
- })}
- {categoryList.length > 7 && (
-
setOpenMoreFlag(true)}>
- 更多
-
-
- )}
-
- );
- };
-
-
- /**
- * 点击更多的分类项
- * @param {*} id
- * @returns
- */
- const onChangeCategoryMore = (cur) => () => {
- setOpenMoreFlag(false)
- setCurrentActive(cur)
- let list = [...categoryList].reduce((pre, item) => {
- if (item.id !== cur.id) {
- pre.push(item);
- } else {
- pre.unshift(item);
- }
- return pre;
- }, []);
- props.onChangeCategoryMore && props.onChangeCategoryMore(cur.id, list);
- };
-
- /**
- * 更多分类
- * @returns
- */
- const renderMoreBox = () => {
- return (
-
- {categoryList.slice(7).map((categoryModuleItem, categoryModuleIndex) => {
- return (
-
-
- {categoryModuleItem.categoryName}
-
-
- {formatTotal(categoryModuleItem.subjectCount)}道题
-
-
- );
- })}
-
- );
- };
-
- /**
- * 选择标签-支持单选(多选)
- * @param {*} categoryId 一级分类id
- * @param {*} secondCategoryIndex 二级分类对象index
- * @param {*} thirdCategoryIndex 三级标签index
- * @param {*} active 三级标签当前的选中状态
- * @returns
- */
- const onChangeLabel = (secondCategoryIndex, thirdCategoryIndex, active) => () => {
- const { isMultipleChoice } = props;
- const list = _.cloneDeep(secondCategoryList)
- if (isMultipleChoice) {
- // 三级标签支持多选
- _.set(list, [secondCategoryIndex, 'children', thirdCategoryIndex, 'active'], !active)
- setSecondCategoryList(list)
+ const getLabels = id => {
+ return new Promise(resolve => {
+ req({
+ method: 'post',
+ url: apiName.queryLabelByCategoryId,
+ data: { categoryId: id }
+ }).then(res => {
+ if (cacheMap[id]) {
+ resolve(cacheMap[id])
} else {
- // 三级标签支持单选
- if (currentLabelIndex.length) {
- _.set(list, [currentLabelIndex[0], 'children', currentLabelIndex[1], 'active'], false)
- }
- _.set(list, [secondCategoryIndex, 'children', thirdCategoryIndex, 'active'], !active)
- setCurrentLabelIndex([secondCategoryIndex, thirdCategoryIndex])
- setSecondCategoryList(list)
+ cacheMap[id] = res.data
+ resolve(res.data)
}
- props.onChangeLabel(_.get(list, [secondCategoryIndex, 'id']), _.get(list, [secondCategoryIndex, 'children', thirdCategoryIndex, 'id']))
- };
+ })
+ })
+ }
- /**
- * 展开/收起
- * @param {*} secondCategoryIndex
- * @returns
- */
- const onChangeOpenStatus = (secondCategoryIndex, isOpen) => () => {
- const _list = _.cloneDeep(secondCategoryList)
- _.set(_list, [secondCategoryIndex, 'isOpen'], !isOpen);
- setSecondCategoryList(_list)
- };
+ // 获取大类下分类
+ const getCategoryByPrimary = () => {
+ req({
+ method: 'post',
+ url: apiName.queryCategoryByPrimary,
+ data: { categoryType: 2, parentId: currentActive.id }
+ }).then(async res => {
+ let list = res.data
+ for (let i = 0; i < list.length; i++) {
+ list[i].children = await getLabels(list[i].id)
+ if (i === 0 && list[i].children.length) {
+ list[i].children[0].active = true
+ }
+ }
+ setSecondCategoryList(_.cloneDeep(list))
+ setCurrentLabelIndex([0, 0])
+ props.onChangeLabel(_.get(list, [0, 'id']), _.get(list, [0, 'children', 0, 'id']))
+ })
+ }
- /**
- * 展开/收起
- */
- const onChangePutAway = () => {
- setIsPutAway(!isPutAway)
- };
+ useEffect(() => {
+ if (primaryCategoryId) {
+ getCategoryByPrimary()
+ }
+ }, [primaryCategoryId])
- /**
- * 二级分类模块
- * @returns
- */
- const renderSecondContainer = () => {
- return (
-
-
- {secondCategoryList.map((secondCategoryItem, secondCategoryIndex) => {
- return (
-
= categoryShowCount && isPutAway
- ? 'none'
- : 'flex',
- }}
- className="second-category-item"
- key={`second_category_${secondCategoryItem.id}`}>
-
- {secondCategoryItem.categoryName}:
-
- {secondCategoryItem?.children?.length > 0 && (
-
-
- {secondCategoryItem.children.map(
- (thirdCategoryItem, thirdCategoryIndex) => {
- return (
-
- {thirdCategoryItem.labelName}
-
- );
- }
- )}
-
- {
- secondCategoryItem.children.length > 5 ?
-
- {secondCategoryItem.isOpen ? '收起' : '展开'}
-
-
- {secondCategoryItem.isOpen ? (
-
- ) : (
-
- )}
-
-
: null
- }
-
-
- )}
-
- );
- })}
- {secondCategoryList?.length >= categoryShowCount && (
-
- {isPutAway ? '展开' : '收起'}
- {isPutAway ? (
-
- ) : (
-
- )}
-
- )}
-
-
-
- );
- };
+ /**
+ * 切换一级分类
+ * @param {*} item
+ * @returns
+ */
+ const onChangeCategory = item => () => {
+ if (currentActive.id === item.id) {
+ return
+ }
+ setCurrentActive(item)
+ props.onChangeCategory(item)
+ }
+ /**
+ * 一级分类模块
+ * @returns
+ */
+ const renderFirstContainer = () => {
return (
-
-
{categoryList?.length && renderFirstContainer()}
-
- {secondCategoryList?.length > 0 && renderSecondContainer()}
-
- {/* {!this.props.isHideSec && (
+
+ {categoryList.slice(0, 7).map((categoryModuleItem, categoryModuleIndex) => {
+ return (
+
+
{categoryModuleItem.categoryName}
+
{categoryModuleItem.count || 50}道题
+
+ )
+ })}
+ {categoryList.length > 7 && (
+
setOpenMoreFlag(true)}>
+ 更多
+
+
+ )}
+
+ )
+ }
+
+ /**
+ * 点击更多的分类项
+ * @param {*} id
+ * @returns
+ */
+ const onChangeCategoryMore = cur => () => {
+ setOpenMoreFlag(false)
+ setCurrentActive(cur)
+ let list = [...categoryList].reduce((pre, item) => {
+ if (item.id !== cur.id) {
+ pre.push(item)
+ } else {
+ pre.unshift(item)
+ }
+ return pre
+ }, [])
+ props.onChangeCategoryMore && props.onChangeCategoryMore(cur.id, list)
+ }
+
+ /**
+ * 更多分类
+ * @returns
+ */
+ const renderMoreBox = () => {
+ return (
+
+ {categoryList.slice(7).map((categoryModuleItem, categoryModuleIndex) => {
+ return (
+
+
{categoryModuleItem.categoryName}
+
+ {formatTotal(categoryModuleItem.subjectCount)}道题
+
+
+ )
+ })}
+
+ )
+ }
+
+ /**
+ * 选择标签-支持单选(多选)
+ * @param {*} categoryId 一级分类id
+ * @param {*} secondCategoryIndex 二级分类对象index
+ * @param {*} thirdCategoryIndex 三级标签index
+ * @param {*} active 三级标签当前的选中状态
+ * @returns
+ */
+ const onChangeLabel = (secondCategoryIndex, thirdCategoryIndex, active) => () => {
+ const { isMultipleChoice } = props
+ const list = _.cloneDeep(secondCategoryList)
+ if (isMultipleChoice) {
+ // 三级标签支持多选
+ _.set(list, [secondCategoryIndex, 'children', thirdCategoryIndex, 'active'], !active)
+ setSecondCategoryList(list)
+ } else {
+ // 三级标签支持单选
+ if (currentLabelIndex.length) {
+ _.set(list, [currentLabelIndex[0], 'children', currentLabelIndex[1], 'active'], false)
+ }
+ _.set(list, [secondCategoryIndex, 'children', thirdCategoryIndex, 'active'], !active)
+ setCurrentLabelIndex([secondCategoryIndex, thirdCategoryIndex])
+ setSecondCategoryList(list)
+ }
+ props.onChangeLabel(
+ _.get(list, [secondCategoryIndex, 'id']),
+ _.get(list, [secondCategoryIndex, 'children', thirdCategoryIndex, 'id'])
+ )
+ }
+
+ /**
+ * 展开/收起
+ * @param {*} secondCategoryIndex
+ * @returns
+ */
+ const onChangeOpenStatus = (secondCategoryIndex, isOpen) => () => {
+ const _list = _.cloneDeep(secondCategoryList)
+ _.set(_list, [secondCategoryIndex, 'isOpen'], !isOpen)
+ setSecondCategoryList(_list)
+ }
+
+ /**
+ * 展开/收起
+ */
+ const onChangePutAway = () => {
+ setIsPutAway(!isPutAway)
+ }
+
+ /**
+ * 二级分类模块
+ * @returns
+ */
+ const renderSecondContainer = () => {
+ return (
+
+
+ {secondCategoryList.map((secondCategoryItem, secondCategoryIndex) => {
+ return (
+
= categoryShowCount && isPutAway ? 'none' : 'flex'
+ }}
+ className='second-category-item'
+ key={`second_category_${secondCategoryItem.id}`}
+ >
+
+ {secondCategoryItem.categoryName}:
+
+ {secondCategoryItem?.children?.length > 0 && (
+
+
+ {secondCategoryItem.children.map((thirdCategoryItem, thirdCategoryIndex) => {
+ return (
+
+ {thirdCategoryItem.labelName}
+
+ )
+ })}
+
+ {secondCategoryItem.children.length > 5 ? (
+
+
+ {secondCategoryItem.isOpen ? '收起' : '展开'}
+
+
+ {secondCategoryItem.isOpen ? : }
+
+
+ ) : null}
+
+ )}
+
+ )
+ })}
+ {secondCategoryList?.length >= categoryShowCount && (
+
+ {isPutAway ? '展开' : '收起'}
+ {isPutAway ? (
+
+ ) : (
+
+ )}
+
+ )}
+
+
+ )
+ }
+
+ return (
+
+ {categoryList?.length && renderFirstContainer()}
+ {secondCategoryList?.length > 0 && renderSecondContainer()}
+ {/* {!this.props.isHideSec && (
{secondCategoryList?.length > 0 && this.renderSecondContainer()}
)} */}
- setOpenMoreFlag(false)}>
- {renderMoreBox()}
-
-
- )
+
setOpenMoreFlag(false)}
+ >
+ {renderMoreBox()}
+
+
+ )
}
export default CategoryList
-
-
diff --git a/src/constants/index.ts b/src/constants/index.ts
index 8371d10..2f1b4de 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -3,86 +3,60 @@ const host = import.meta.env.VITE_IMG_HOST
* 难度筛选
*/
export const filterDifficulty = [
- {
- id: 0,
- title: '全部',
- },
- {
- id: 1,
- title: '初级',
- },
- {
- id: 2,
- title: '中级',
- },
- {
- id: 3,
- title: '高级',
- },
- {
- id: 4,
- title: '资深',
- },
- {
- id: 5,
- title: '专家',
- },
-];
+ {
+ id: 0,
+ title: '全部'
+ },
+ {
+ id: 1,
+ title: '初级'
+ },
+ {
+ id: 2,
+ title: '中级'
+ },
+ {
+ id: 3,
+ title: '高级'
+ },
+ {
+ id: 4,
+ title: '资深'
+ },
+ {
+ id: 5,
+ title: '专家'
+ }
+]
/**
* 难度等级
*/
export const gradeObject = {
- 1: {
- color: 'rgba(60, 110, 238, 0.5)',
- title: '初级',
- },
- 2: {
- color: 'rgba(60, 110, 238, 0.6)',
- title: '中级',
- },
- 3: {
- color: 'rgba(60, 110, 238, 0.7)',
- title: '高级',
- },
- 4: {
- color: 'rgba(60, 110, 238, 0.8)',
- title: '资深',
- },
- 5: {
- color: 'rgba(60, 110, 238, 0.9)',
- title: '专家',
- },
-};
+ 1: {
+ color: 'rgba(60, 110, 238, 0.5)',
+ title: '初级'
+ },
+ 2: {
+ color: 'rgba(60, 110, 238, 0.6)',
+ title: '中级'
+ },
+ 3: {
+ color: 'rgba(60, 110, 238, 0.7)',
+ title: '高级'
+ },
+ 4: {
+ color: 'rgba(60, 110, 238, 0.8)',
+ title: '资深'
+ },
+ 5: {
+ color: 'rgba(60, 110, 238, 0.9)',
+ 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',
-};
\ No newline at end of file
+ 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'
+}
diff --git a/src/imgs/ranking1Img.png b/src/imgs/ranking1Img.png
new file mode 100644
index 0000000..0ec2a1d
Binary files /dev/null and b/src/imgs/ranking1Img.png differ
diff --git a/src/imgs/ranking2Img.png b/src/imgs/ranking2Img.png
new file mode 100644
index 0000000..367aae0
Binary files /dev/null and b/src/imgs/ranking2Img.png differ
diff --git a/src/imgs/ranking3Img.png b/src/imgs/ranking3Img.png
new file mode 100644
index 0000000..aaeb2f1
Binary files /dev/null and b/src/imgs/ranking3Img.png differ
diff --git a/src/imgs/rankingImg.png b/src/imgs/rankingImg.png
new file mode 100644
index 0000000..bfd4c2d
Binary files /dev/null and b/src/imgs/rankingImg.png differ
diff --git a/src/utils/request.ts b/src/utils/request.ts
index f689f5f..ea1e690 100644
--- a/src/utils/request.ts
+++ b/src/utils/request.ts
@@ -1,66 +1,71 @@
-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",
- timeout: 5 * 60 * 1000, // request timeout
- withCredentials: true, // send cookies when cross-domain requests
- headers: {
- 'Content-Type': 'application/json; charset=utf-8',
- },
- });
+ const http = axios.create({
+ baseURL: '/subject',
+ timeout: 5 * 60 * 1000, // request timeout
+ withCredentials: true, // send cookies when cross-domain requests
+ headers: {
+ 'Content-Type': 'application/json; charset=utf-8'
+ }
+ })
- return http;
-};
+ return http
+}
export default function request(config, url) {
- // const navigate = useNavigate()
+ console.log(config, url, 'config url')
+ // const navigate = useNavigate()
+ const userInfoStorage = localStorage.getItem('userInfo')
+ const userInfo = userInfoStorage ? JSON.parse(userInfoStorage) : {}
+ const baseURL = url || '/subject/subject'
+ // 1.创建axios的实例
+ const instance = axios.create({
+ baseURL,
+ timeout: 5 * 60 * 1000, // request timeout
+ withCredentials: true, // send cookies when cross-domain requests
+ headers: {
+ 'Content-Type': 'application/json; charset=utf-8',
+ [userInfo.tokenName]: 'jichi ' + userInfo.tokenValue
+ }
+ })
- const baseURL = url || '/subject';
- // 1.创建axios的实例
- const instance = axios.create({
- baseURL,
- timeout: 5 * 60 * 1000, // request timeout
- withCredentials: true, // send cookies when cross-domain requests
- headers: {
- 'Content-Type': 'application/json; charset=utf-8',
- },
- });
+ // 2.axios的拦截器
+ // 2.1.请求拦截的作用
+ instance.interceptors.request.use(
+ config => {
+ return config
+ },
+ err => {
+ console.log(err)
+ }
+ )
- // 2.axios的拦截器
- // 2.1.请求拦截的作用
- instance.interceptors.request.use(
- (config) => {
- return config;
- },
- (err) => {
- console.log(err);
- }
- );
+ // 2.2.响应拦截
+ instance.interceptors.response.use(
+ res => {
+ let { code } = res.data
+ if (code === 500) {
+ message.error(res.data.message)
+ }
+ if (code === 401) {
+ window.location.replace('/login')
+ }
+ return res.data
+ },
+ err => {
+ let { status } = err?.response ?? {}
+ if (status === 401 || !status) {
+ message.info('页面异常')
+ window.location.replace('/login')
+ } else if (status === 500 || status === 503) {
+ message.error('服务器错误')
+ }
+ return Promise.reject(err)
+ }
+ )
- // 2.2.响应拦截
- instance.interceptors.response.use(
- (res) => {
- let { code } = res.data;
- if (code === 500) {
- message.error(res.data.message);
- }
- return res.data;
- },
- (err) => {
- let { status } = err?.response ?? {};
- if (status === 401 || !status) {
- message.info('页面异常')
- window.location.replace('/login')
- } else if (status === 500 || status === 503) {
- message.error('服务器错误');
- }
- return Promise.reject(err);
- }
- );
-
- // 3.发送真正的网络请求
- return instance(config);
+ // 3.发送真正的网络请求
+ return instance(config)
}
diff --git a/src/views/login/index.less b/src/views/login/index.less
index 4423abd..7be6d1f 100644
--- a/src/views/login/index.less
+++ b/src/views/login/index.less
@@ -1,35 +1,39 @@
-.login-box{
+.login-box {
+ width: 100%;
+ height: calc(100% - 100px);
+ background: url(../../imgs/login_bg.jpg) no-repeat 50%;
+ background-size: cover;
+ min-height: 600px;
+ position: relative;
+ .login-container-inner {
+ background: transparent;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ height: 534px;
+ transform: translate(-50%, -50%);
+ clear: both;
+ max-width: 1520px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
width: 100%;
- height: calc(100% - 100px);
- background: url(../../imgs/login_bg.jpg) no-repeat 50%;
- background-size: cover;
- min-height: 600px;
- position: relative;
- .login-container-inner{
- background: transparent;
- position: absolute;
- top: 50%;
- left: 50%;
- height: 534px;
- transform: translate(-50%,-50%);
- clear: both;
- max-width: 1520px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- width: 100%;
- .notes{
- color: white;
- max-width: 400px;
- line-height: 30px;
- }
- .qrcode-box{
- width: 400px;
- height: 500px;
- background: white;
- border-radius: 10px;
- text-align: center;
- padding: 20px;
- }
+ .notes {
+ color: white;
+ max-width: 400px;
+ line-height: 30px;
}
-}
\ No newline at end of file
+ .qrcode-box {
+ width: 400px;
+ height: 500px;
+ background: white;
+ border-radius: 10px;
+ text-align: center;
+ padding: 20px;
+ .qrcode-desc {
+ padding: 20px 0;
+ line-height: 30px;
+ }
+ }
+ }
+}
diff --git a/src/views/login/index.tsx b/src/views/login/index.tsx
index e4a398f..fed0a22 100644
--- a/src/views/login/index.tsx
+++ b/src/views/login/index.tsx
@@ -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 [validCode, setValidCode] = useState('')
- const changeCode = e => {
- setValidCode(e.target.value)
- }
+ const changeCode = e => {
+ setValidCode(e.target.value)
+ }
- const doLogin = () => {
- if (!validCode) return
- req({
- method: 'get',
- url: loginApiName,
- data: { validCode }
- })
- }
+ const doLogin = () => {
+ console.log(validCode)
+ if (!validCode) return
+ req(
+ {
+ method: 'get',
+ url: loginApiName,
+ 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 (
-
-
LeNet-5 诞生
- 1998 年 11 月,早期经典卷积神经网络 LeNet-5 诞生。杨立昆、莱昂·伯托等发表经典论文“Gradient-Based Learning Applied to Document Recognition”,文章总结了应用于手写字符识别的各种模型并进行了比对,结果显示卷积神经网络表现超群。
-
-
-

-
-
-
-
-
-
-
-
+ return (
+
+
+
+ LeNet-5 诞生 1998 年 11 月,早期经典卷积神经网络 LeNet-5
+ 诞生。杨立昆、莱昂·伯托等发表经典论文“Gradient-Based Learning Applied to Document
+ Recognition”,文章总结了应用于手写字符识别的各种模型并进行了比对,结果显示卷积神经网络表现超群。
-
)
+
+
+
+

+
+
+
+
+
+
+
+
+
+
+ )
}
-export default Login
\ No newline at end of file
+export default Login
diff --git a/src/views/question-bank/components/ranking-box/index.jsx b/src/views/question-bank/components/ranking-box/index.jsx
index 1094e54..a255149 100644
--- a/src/views/question-bank/components/ranking-box/index.jsx
+++ b/src/views/question-bank/components/ranking-box/index.jsx
@@ -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 (
-
-
-
{RankingTypeText[rankingType]}
-
+
+
+
{RankingTypeText[rankingType]}
+
{tabList.length > 0 &&
tabList.map((item, index) => {
return (
{item.tab}
@@ -55,56 +60,52 @@ export default function RankingBox(props) {
-
+
{rankingList?.length > 0 &&
rankingList.map((item, index) => {
return (
-
-
+
+
{index > 2 && index + 1}
-
-

+
+
- {item.name}
-
- }
+ title={
{item.name}
}
content={
-
+
{item.name}
{/*
{item.organizationFullName}
*/}
}
>
-
-
{item.name}
+
+
{item.name}
{/*
{item.organizationName}
*/}
-
🔥 {item.count}
+
🔥 {item.count}
)
})}
-
+
-
{RankingTypeBtnText[rankingType]}
+
{RankingTypeBtnText[rankingType]}
)
diff --git a/src/views/user-info/index.tsx b/src/views/user-info/index.tsx
index 92105c1..93473ce 100644
--- a/src/views/user-info/index.tsx
+++ b/src/views/user-info/index.tsx
@@ -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 = () => {
{editFlag ? (
-
+
男
女
@@ -65,6 +100,17 @@ const UserInfo = () => {
)}
+
+ {editFlag ? (
+
+
+
+ ) : (
+
+ <>暂无>
+
+ )}
+
{editFlag ? (
{
{editFlag ? (
<>
-