feat: 刷题页面
This commit is contained in:
67
src/components/category-list/constant.js
Normal file
67
src/components/category-list/constant.js
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* 难度筛选
|
||||
*/
|
||||
export const filterDifficulty = [
|
||||
{
|
||||
id: 0,
|
||||
title: '全部',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: 'T4',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'T5',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'T6',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: 'T7',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: 'T8',
|
||||
},
|
||||
];
|
||||
|
||||
export const apiName = {
|
||||
/**
|
||||
* 获取二级和三级标签
|
||||
*/
|
||||
getCategoryLabelInfo: '/admin/question/category/getCategoryLabelInfo',
|
||||
};
|
||||
|
||||
export const imgObject = {
|
||||
clickImg:
|
||||
'../../views/imgs/clickImg.png',
|
||||
ranking1Img:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/206730/39/7751/986/617f4fbaE4e23097a/aa94ca31a9c132b2.png',
|
||||
ranking2Img:
|
||||
'https://img10.360buyimg.com/imagetools/jfs/t1/156125/21/27968/948/617f4fbaEcf1da9a9/722ad0917497697a.png',
|
||||
ranking3Img:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/213197/17/2682/958/617f4fbbE06c277a9/03ef4c389c52ab8d.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',
|
||||
};
|
362
src/components/category-list/index.jsx
Normal file
362
src/components/category-list/index.jsx
Normal file
@@ -0,0 +1,362 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
|
||||
import {
|
||||
RightOutlined,
|
||||
UpOutlined,
|
||||
DownOutlined,
|
||||
CaretDownOutlined,
|
||||
CaretUpOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import req from '@utils/request';
|
||||
import { Divider } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import './index.less';
|
||||
import { apiName, imgObject } from './constant';
|
||||
|
||||
/**
|
||||
* 大分类中的背景图
|
||||
*/
|
||||
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 categoryShowCount = 4;
|
||||
|
||||
export default class CategoryList extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
secondCategoryList: [],
|
||||
currentActive: '',
|
||||
isPutAway: true, // 是否收起 默认收起状态
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// this.initCategoryList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化数据,默认选择第一个
|
||||
*/
|
||||
initCategoryList() {
|
||||
const { categoryList, primaryCategoryId } = this.props;
|
||||
let currentActive = primaryCategoryId ?? categoryList[0].primaryCategoryId;
|
||||
this.props.onChangeCategory(currentActive);
|
||||
this.getSecondCategoryList(currentActive);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得二级三级分类数据
|
||||
*/
|
||||
getSecondCategoryList(currentActive) {
|
||||
const { categoryListMap } = this.props;
|
||||
// 调用接口返回二级三级数据
|
||||
let params = {
|
||||
primaryCategoryId: currentActive,
|
||||
subjectTypeList: [4],
|
||||
};
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.getCategoryLabelInfo,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
let secondCategoryList = res.data;
|
||||
let listLen =
|
||||
categoryListMap &&
|
||||
categoryListMap[currentActive] &&
|
||||
categoryListMap[currentActive].length;
|
||||
let objActive = {};
|
||||
listLen > 0 &&
|
||||
categoryListMap &&
|
||||
categoryListMap[currentActive] &&
|
||||
categoryListMap[currentActive].forEach((item) => {
|
||||
objActive[item] = item;
|
||||
});
|
||||
secondCategoryList.forEach((categoryItem) => {
|
||||
categoryItem.labelInfoList.forEach((item) => {
|
||||
if (listLen > 0 && objActive[item.assembleId]) {
|
||||
item.active = true;
|
||||
} else {
|
||||
item.active = false;
|
||||
}
|
||||
});
|
||||
categoryItem.isOpen = false;
|
||||
});
|
||||
this.setState(
|
||||
{
|
||||
secondCategoryList,
|
||||
currentActive,
|
||||
},
|
||||
() => {
|
||||
let activeList = [];
|
||||
secondCategoryList.forEach((categoryItem) => {
|
||||
categoryItem.labelInfoList.forEach((item) => {
|
||||
if (item.active) {
|
||||
activeList.push(item.assembleId);
|
||||
}
|
||||
});
|
||||
});
|
||||
secondCategoryList.forEach((item, index) => {
|
||||
let height = document.getElementById('id_' + index)?.scrollHeight;
|
||||
let displayHeight = height > 43 ? 'flex' : 'none';
|
||||
!this.props.isHideSec &&
|
||||
(document.getElementById('second_id_' + index).style.display =
|
||||
displayHeight);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((err) => console.log(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换一级分类
|
||||
* @param {*} item
|
||||
* @returns
|
||||
*/
|
||||
onChangeCategory = (primaryCategoryId) => () => {
|
||||
let { currentActive } = this.state;
|
||||
if (currentActive === primaryCategoryId) {
|
||||
return;
|
||||
}
|
||||
this.props.isHideSec &&
|
||||
this.setState({
|
||||
currentActive: primaryCategoryId,
|
||||
});
|
||||
this.props.onChangeCategory(primaryCategoryId);
|
||||
!this.props.isHideSec && this.getSecondCategoryList(primaryCategoryId);
|
||||
};
|
||||
|
||||
/**
|
||||
* 选择标签-支持单选(多选)
|
||||
* @param {*} categoryId 一级分类id
|
||||
* @param {*} childrenLevelList 二级分类对象的标签列表
|
||||
* @param {*} secondCategoryIndex 二级分类对象index
|
||||
* @param {*} thirdCategoryIndex 三级标签index
|
||||
* @param {*} active 三级标签当前的选中状态
|
||||
* @returns
|
||||
*/
|
||||
onChangeLabel = (childrenLevelList, secondCategoryIndex, thirdCategoryIndex, active) => () => {
|
||||
let { secondCategoryList, currentActive } = this.state;
|
||||
const { isMultipleChoice } = this.props;
|
||||
if (isMultipleChoice) {
|
||||
// 三级标签支持多选
|
||||
_.set(childrenLevelList, [thirdCategoryIndex, 'active'], !active);
|
||||
_.set(secondCategoryList, [secondCategoryIndex, 'labelInfoList'], childrenLevelList);
|
||||
} else {
|
||||
// 三级标签支持单选
|
||||
let formatLabelList = childrenLevelList.map((item, index) => {
|
||||
let flag = false;
|
||||
if (index === thirdCategoryIndex) {
|
||||
flag = !active; // 将三级标签设置选中/未选中
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
active: flag,
|
||||
};
|
||||
});
|
||||
_.set(secondCategoryList, [secondCategoryIndex, 'labelInfoList'], formatLabelList);
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
secondCategoryList,
|
||||
},
|
||||
() => {
|
||||
let activeList = [];
|
||||
secondCategoryList.forEach((categoryItem) => {
|
||||
categoryItem.labelInfoList.forEach((item) => {
|
||||
if (item.active) {
|
||||
activeList.push(item.assembleId);
|
||||
}
|
||||
});
|
||||
});
|
||||
this.props.onChangeLabel(currentActive, activeList);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 展开/收起
|
||||
* @param {*} secondCategoryIndex
|
||||
* @returns
|
||||
*/
|
||||
onChangeOpenStatus = (secondCategoryIndex, isOpen) => () => {
|
||||
let { secondCategoryList } = this.state;
|
||||
_.set(secondCategoryList, [secondCategoryIndex, 'isOpen'], !isOpen);
|
||||
this.setState({
|
||||
secondCategoryList,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 展开/收起
|
||||
*/
|
||||
onChangePutAway = () => {
|
||||
let { isPutAway } = this.state;
|
||||
this.setState({
|
||||
isPutAway: !isPutAway,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { categoryList } = this.props;
|
||||
const { secondCategoryList } = this.state;
|
||||
return (
|
||||
<div className="category-box">
|
||||
<Fragment>{categoryList?.length > 0 && this.renderFirstContainer()}</Fragment>
|
||||
{!this.props.isHideSec && (
|
||||
<Fragment>
|
||||
{secondCategoryList?.length > 0 && this.renderSecondContainer()}
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一级分类模块
|
||||
* @returns
|
||||
*/
|
||||
renderFirstContainer = () => {
|
||||
const { categoryList } = this.props;
|
||||
const { currentActive } = this.state;
|
||||
return (
|
||||
<div className="first-category-list">
|
||||
{categoryList.slice(0, 7).map((categoryModuleItem, categoryModuleIndex) => {
|
||||
return (
|
||||
<div
|
||||
className={`first-category-item ${categoryModuleItem.primaryCategoryId === currentActive &&
|
||||
'first-category-item-active'
|
||||
}`}
|
||||
key={`first_category_${categoryModuleItem.primaryCategoryId}`}
|
||||
style={{
|
||||
backgroundImage: `url(${categoryBackImg[categoryModuleIndex]})`,
|
||||
}}
|
||||
onClick={this.onChangeCategory(categoryModuleItem.primaryCategoryId)}>
|
||||
<div className="first-category-item-title">
|
||||
{categoryModuleItem.levelName}
|
||||
</div>
|
||||
<div className="first-category-item-count">
|
||||
{categoryModuleItem.count}道题
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{categoryList.length > 7 && (
|
||||
<div className="first-category-more">
|
||||
更多
|
||||
<RightOutlined />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 二级分类模块
|
||||
* @returns
|
||||
*/
|
||||
renderSecondContainer = () => {
|
||||
const { secondCategoryList, isPutAway } = this.state;
|
||||
return (
|
||||
<div className="second-category-list">
|
||||
{secondCategoryList.map((secondCategoryItem, secondCategoryIndex) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display:
|
||||
secondCategoryIndex >= categoryShowCount && isPutAway
|
||||
? 'none'
|
||||
: 'flex',
|
||||
}}
|
||||
className="second-category-item"
|
||||
key={`second_category_${secondCategoryItem.categoryId}`}>
|
||||
<div className="second-category-item-title">
|
||||
{secondCategoryItem.categoryName}:
|
||||
</div>
|
||||
{secondCategoryItem?.labelInfoList?.length > 0 && (
|
||||
<div className="second-category-item-box">
|
||||
<div
|
||||
style={{
|
||||
height: secondCategoryItem.isOpen ? 'auto' : 43,
|
||||
}}
|
||||
className="second-category-item-list"
|
||||
id={`id_${secondCategoryIndex}`}>
|
||||
{secondCategoryItem.labelInfoList.map(
|
||||
(thirdCategoryItem, thirdCategoryIndex) => {
|
||||
return (
|
||||
<div
|
||||
className={`third-category-item ${thirdCategoryItem.active
|
||||
? 'third-category-item-active'
|
||||
: ''
|
||||
}`}
|
||||
key={`third_category_${thirdCategoryItem.id}`}
|
||||
onClick={this.onChangeLabel(
|
||||
secondCategoryItem.labelInfoList,
|
||||
secondCategoryIndex,
|
||||
thirdCategoryIndex,
|
||||
thirdCategoryItem.active
|
||||
)}>
|
||||
{thirdCategoryItem.labelName}·
|
||||
{thirdCategoryItem.subjectCount}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
id={`second_id_${secondCategoryIndex}`}
|
||||
className="second-category-item-status"
|
||||
onClick={this.onChangeOpenStatus(
|
||||
secondCategoryIndex,
|
||||
secondCategoryItem.isOpen
|
||||
)}>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{secondCategoryList?.length >= categoryShowCount && (
|
||||
<Divider
|
||||
onClick={this.onChangePutAway}
|
||||
dashed
|
||||
style={{
|
||||
marginTop: 10,
|
||||
fontSize: 13,
|
||||
}}>
|
||||
{isPutAway ? '展开' : '收起'}
|
||||
{isPutAway ? (
|
||||
<CaretDownOutlined style={{ marginLeft: 4 }} />
|
||||
) : (
|
||||
<CaretUpOutlined style={{ marginLeft: 4 }} />
|
||||
)}
|
||||
</Divider>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
128
src/components/category-list/index.less
Normal file
128
src/components/category-list/index.less
Normal file
@@ -0,0 +1,128 @@
|
||||
.category-box {
|
||||
.first-category-list {
|
||||
display: flex;
|
||||
.first-category-item {
|
||||
flex-shrink: 1;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
margin-right: 18px;
|
||||
padding: 10px 12px;
|
||||
width: 120px;
|
||||
height: 76px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
background-size: 100% 100%;
|
||||
background-color: rgba(0, 0, 0, 0.04);
|
||||
font-weight: 400;
|
||||
transition: all 0.5s;
|
||||
.first-category-item-title {
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 1;
|
||||
overflow: hidden;
|
||||
/* autoprefixer: off */
|
||||
-webkit-box-orient: vertical;
|
||||
display: -webkit-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
.first-category-item-count {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.65);
|
||||
line-height: 16px;
|
||||
}
|
||||
&:hover {
|
||||
transition: all 0.5s;
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
}
|
||||
.first-category-item-active {
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
.first-category-more {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 88px;
|
||||
height: 76px;
|
||||
font-size: 16px;
|
||||
color: #13b4ff;
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
background-color: rgba(19, 180, 255, 0.08);
|
||||
}
|
||||
}
|
||||
.second-category-list {
|
||||
padding-top: 15px;
|
||||
border-radius: 4px;
|
||||
.second-category-item {
|
||||
display: flex;
|
||||
.second-category-item-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 16px;
|
||||
min-width: 60px;
|
||||
height: 40px;
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
font-weight: bold;
|
||||
}
|
||||
.second-category-item-box {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
.second-category-item-list {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
height: 43px;
|
||||
overflow: hidden;
|
||||
.third-category-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 2px 8px;
|
||||
margin: 8px 15px 8px 0;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||
border-radius: 4px;
|
||||
&:hover {
|
||||
@include box-backgroundColor(0.1);
|
||||
@include box-border();
|
||||
@include font-color();
|
||||
}
|
||||
}
|
||||
.third-category-item-active {
|
||||
@include box-backgroundColor(0.1);
|
||||
@include box-border();
|
||||
@include font-color();
|
||||
}
|
||||
}
|
||||
.second-category-item-status {
|
||||
display: flex;
|
||||
margin-top: 8px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 4px 4px 4px 8px;
|
||||
width: 54px;
|
||||
height: 28px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-divider-horizontal.ant-divider-with-text-center {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
0
src/components/layout/index.less
Normal file
0
src/components/layout/index.less
Normal file
0
src/components/layout/index.tsx
Normal file
0
src/components/layout/index.tsx
Normal file
82
src/components/question-list/constant.js
Normal file
82
src/components/question-list/constant.js
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 难度等级
|
||||
*/
|
||||
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: '专家',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 难度筛选
|
||||
*/
|
||||
export const filterDifficulty = [
|
||||
{
|
||||
id: 0,
|
||||
title: '全部',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '初级',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '中级',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '高级',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: '资深',
|
||||
},
|
||||
];
|
||||
|
||||
export const imgObject = {
|
||||
clickImg:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/222669/25/807/6590/617f4f06Eb2094586/64c39ce3769b8a16.png',
|
||||
ranking1Img:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/206730/39/7751/986/617f4fbaE4e23097a/aa94ca31a9c132b2.png',
|
||||
ranking2Img:
|
||||
'https://img10.360buyimg.com/imagetools/jfs/t1/156125/21/27968/948/617f4fbaEcf1da9a9/722ad0917497697a.png',
|
||||
ranking3Img:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/213197/17/2682/958/617f4fbbE06c277a9/03ef4c389c52ab8d.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:
|
||||
'../../views/imgs/javaImg.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',
|
||||
};
|
229
src/components/question-list/index.jsx
Normal file
229
src/components/question-list/index.jsx
Normal file
@@ -0,0 +1,229 @@
|
||||
import React, { Component, Fragment } from "react";
|
||||
|
||||
import { Tag, Table, Pagination, Input } from "antd";
|
||||
import { filterDifficulty, gradeObject, imgObject } from "./constant";
|
||||
import { splicingQuery } from "@utils";
|
||||
import "./index.less";
|
||||
const { Search } = Input;
|
||||
|
||||
const colors = ['#ffffb8', '#f4ffb8', '#b5f5ec', '#bae0ff', '#d9f7be', '#efdbff', ' #ffd6e7', '#d6e4ff']
|
||||
|
||||
class QuestionList extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selectValue: "难度",
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() { }
|
||||
|
||||
|
||||
RandomNumBoth = (Min, Max) => {
|
||||
//差值
|
||||
const Range = Max - Min;
|
||||
// 随机数
|
||||
const Rand = Math.random();
|
||||
return Min + Math.round(Rand * Range); //四舍五入
|
||||
}
|
||||
|
||||
/**
|
||||
* 题目列表
|
||||
*/
|
||||
questionColumns = [
|
||||
{
|
||||
title: <div style={{ display: 'flex' }}>题目 <div className="question-count-box" style={{ marginLeft: '10px', color: 'rgba(0, 0, 0, 0.5)' }}>
|
||||
(当前
|
||||
<span style={{ color: "rgba(0, 0, 0, 0.65)" }}> {100} </span>
|
||||
道题)
|
||||
</div></div>,
|
||||
key: "questionNo",
|
||||
align: "centlefter",
|
||||
render: (item) => {
|
||||
return (
|
||||
<div className="question-info-container">
|
||||
<div className="question-info-desc">
|
||||
{item.questionTitle}
|
||||
|
||||
</div>
|
||||
<div className="question-info-tags">
|
||||
{item?.tags?.length > 0 &&
|
||||
item.tags.map((tagsItem, index) => {
|
||||
return (
|
||||
<div className="question-info-tag" key={index} style={{ backgroundColor: colors[this.RandomNumBoth(0, 7)] }}>
|
||||
{tagsItem.name}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "难度",
|
||||
dataIndex: "grade",
|
||||
key: "grade",
|
||||
align: "center",
|
||||
filters: [
|
||||
{
|
||||
value: 0,
|
||||
text: '全部',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
text: '初级',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
text: '中级',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
text: '高级',
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
text: '资深',
|
||||
},
|
||||
],
|
||||
onFilter: (value, record) => {
|
||||
return value === 0 ? record : record.grade === value
|
||||
},
|
||||
width: 90,
|
||||
render: (key) => {
|
||||
return (
|
||||
<Tag color={gradeObject?.[key]?.color}>{gradeObject?.[key]?.title}</Tag>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 选择标签
|
||||
* @param {*} id
|
||||
*/
|
||||
handleChangeSelect = (id) => {
|
||||
console.log(id);
|
||||
let selectValue = "难度";
|
||||
if (id != 0) {
|
||||
filterDifficulty.forEach((item) => {
|
||||
if (item.id == id) {
|
||||
selectValue = item.id;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
selectValue,
|
||||
},
|
||||
() => {
|
||||
this.props.handleChangeSelect(id);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 进入详情
|
||||
* @param {*} item
|
||||
* @param {*} type
|
||||
* @returns
|
||||
*/
|
||||
onChangeAction = (item, index) => () => {
|
||||
let { isNotToDetail, difficulty, primaryCategoryId, labelList, pageIndex } =
|
||||
this.props;
|
||||
!isNotToDetail &&
|
||||
this.props.history.push(
|
||||
splicingQuery("/brush-questions", {
|
||||
id: item?.id,
|
||||
index: index + (pageIndex - 1) * 10 + 1,
|
||||
difficulty,
|
||||
primaryCategoryId,
|
||||
labelList,
|
||||
})
|
||||
);
|
||||
if (!isNotToDetail) return;
|
||||
this.toChangeSelectRows(item);
|
||||
};
|
||||
|
||||
toChangeSelectRows = (record) => {
|
||||
let newSelectedRows = [...this.props.selectRows];
|
||||
const isHas = newSelectedRows.some((rowItem) => rowItem.id === record.id);
|
||||
if (isHas) {
|
||||
newSelectedRows = newSelectedRows.filter(
|
||||
(rowItem) => rowItem.id !== record.id
|
||||
);
|
||||
} else {
|
||||
newSelectedRows.push(record);
|
||||
}
|
||||
this.props.setSelectRows(newSelectedRows);
|
||||
};
|
||||
|
||||
onChangePagination = (e) => {
|
||||
this.props.onChangePagination(e);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { questionList, total, pageIndex, isHideSelect, isMultiple } =
|
||||
this.props;
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="question-list-filter">
|
||||
{!isHideSelect && this.renderFilterContainer()}
|
||||
<div className="question-list-container">
|
||||
<Table
|
||||
onRow={(record, index) => {
|
||||
return {
|
||||
onClick: this.onChangeAction(record, index), // 点击行
|
||||
};
|
||||
}}
|
||||
columns={this.questionColumns}
|
||||
dataSource={questionList}
|
||||
rowKey={(record) => record.id}
|
||||
// bordered={false}
|
||||
pagination={false}
|
||||
rowClassName="question-table-row"
|
||||
/>
|
||||
{total > 10 && (
|
||||
<Pagination
|
||||
style={{
|
||||
padding: "24px 0",
|
||||
textAlign: "center",
|
||||
}}
|
||||
showQuickJumper
|
||||
defaultCurrent={pageIndex}
|
||||
total={total}
|
||||
onChange={this.onChangePagination}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤框-搜索框-模块
|
||||
* @returns
|
||||
*/
|
||||
renderFilterContainer = () => {
|
||||
const { selectValue } = this.state;
|
||||
const { total, isShowSearch, setSearchStr } = this.props;
|
||||
return (
|
||||
<div className="question-filter-container">
|
||||
{isShowSearch && (
|
||||
<Search
|
||||
placeholder="请输入感兴趣的内容~"
|
||||
onSearch={(value) => setSearchStr(value)}
|
||||
style={{ width: 240 }}
|
||||
allowClear
|
||||
size="small"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export default QuestionList;
|
82
src/components/question-list/index.less
Normal file
82
src/components/question-list/index.less
Normal file
@@ -0,0 +1,82 @@
|
||||
.question-list-filter {
|
||||
padding: 0px 6px 20px 9px;
|
||||
background-color: #ffffff;
|
||||
.question-filter-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
padding-right: 18px;
|
||||
padding-left: 5px;
|
||||
.question-filter-box {
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
.question-filter-select {
|
||||
margin-right: 4px;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
border: 0;
|
||||
.ant-select-selection {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.question-count-box {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
.ant-btn {
|
||||
margin-left: 16px;
|
||||
width: 150px;
|
||||
height: 34px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
background-color: #13b4ff;
|
||||
border-color: #13b4ff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
|
||||
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
.question-list-container {
|
||||
.ant-table-tbody > tr > td {
|
||||
// border-bottom: 0;
|
||||
padding: 10px 4px 0 14px;
|
||||
}
|
||||
.ant-table-thead > tr > th {
|
||||
background-color: #ffffff;
|
||||
// border-bottom: 0;
|
||||
}
|
||||
.ant-table-row:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
.ant-table-thead > tr > th .ant-table-header-column .ant-table-column-sorters:hover:before {
|
||||
// background-color: #fff;
|
||||
}
|
||||
.question-info-container {
|
||||
.question-info-desc {
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.question-info-tags {
|
||||
display: flex;
|
||||
margin-top: 8px;
|
||||
padding-bottom: 10px;
|
||||
.question-info-tag {
|
||||
margin-right: 10px;
|
||||
padding: 0px 6px;
|
||||
font-size: 10px !important;
|
||||
border-radius: 4px;
|
||||
// @include font-color();
|
||||
// border: 1px solid rgba(60, 110, 238, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.question-type-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
30
src/components/tags-editor/constant.js
Normal file
30
src/components/tags-editor/constant.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* API名称
|
||||
*/
|
||||
export const apiName = {
|
||||
/**
|
||||
* 新增二级分类
|
||||
*/
|
||||
addInterviewCategory: '/admin/question/category/add',
|
||||
/**
|
||||
* 删除二级分类
|
||||
*/
|
||||
deleteInterviewCategory: '/admin/question/category/delete',
|
||||
/**
|
||||
* 新增三级标签
|
||||
*/
|
||||
addInterviewLabel: '/admin/question/label/add',
|
||||
/**
|
||||
* 删除三级标签
|
||||
*/
|
||||
deleteInterviewLabel: '/admin/question/label/delete',
|
||||
};
|
||||
|
||||
/**
|
||||
* 模块类型
|
||||
*/
|
||||
export const ModuleType = {
|
||||
default: 'default',
|
||||
second: 'second',
|
||||
third: 'third',
|
||||
};
|
302
src/components/tags-editor/index.jsx
Normal file
302
src/components/tags-editor/index.jsx
Normal file
@@ -0,0 +1,302 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import req from '@utils/request';
|
||||
import { Input, Tag, Tooltip, message } from 'antd';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { apiName, ModuleType } from './constant';
|
||||
import './index.less';
|
||||
|
||||
const apiNameModule = {
|
||||
[ModuleType.second]: [apiName.addInterviewCategory, apiName.deleteInterviewCategory],
|
||||
[ModuleType.third]: [apiName.addInterviewLabel, apiName.deleteInterviewLabel],
|
||||
};
|
||||
|
||||
export default class TagsEditor extends Component {
|
||||
saveInputRef = (input) => (this.input = input);
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
inputVisible: false,
|
||||
inputValue: '',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击X号
|
||||
* @param {*} index 当前index
|
||||
* @param {*} categoryId 当前id
|
||||
*/
|
||||
handleClose = (index, categoryId) => {
|
||||
const { moduleType, categoryList } = this.props;
|
||||
let params = {
|
||||
id: categoryId,
|
||||
};
|
||||
let url = apiNameModule[moduleType][1];
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: url,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
let list = categoryList.filter((item) => {
|
||||
return item.categoryId !== categoryId;
|
||||
});
|
||||
this.props.onChangeLabel(list, this.formatList(list));
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 展示输入框
|
||||
*/
|
||||
showInput = () => {
|
||||
this.setState({ inputVisible: true }, () => this.input.focus());
|
||||
};
|
||||
|
||||
/**
|
||||
* 输入框改变内容
|
||||
* @param {*} e
|
||||
*/
|
||||
handleInputChange = (e) => {
|
||||
this.setState({ inputValue: e.target.value });
|
||||
};
|
||||
|
||||
/**
|
||||
* 增加标签
|
||||
*/
|
||||
handleInputConfirm = () => {
|
||||
let { categoryList } = this.props;
|
||||
let { inputValue } = this.state;
|
||||
let equalList = [],
|
||||
formatInputValue = inputValue.trim();
|
||||
if (!formatInputValue) {
|
||||
this.setState({
|
||||
inputValue: '',
|
||||
inputVisible: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (categoryList.length > 0) {
|
||||
equalList = categoryList.filter((item) => {
|
||||
return item.categoryName.toLowerCase() === formatInputValue.toLowerCase();
|
||||
});
|
||||
}
|
||||
if (equalList.length <= 0) {
|
||||
this.postAddInterviewCategory(formatInputValue);
|
||||
} else {
|
||||
message.info('所增内容已存在', 0.3);
|
||||
this.setState({
|
||||
inputValue: '',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 增加标签
|
||||
* @param {*} inputValue 当前的值
|
||||
*/
|
||||
postAddInterviewCategory = (inputValue) => {
|
||||
const { parentCategoryValue, moduleType, categoryList } = this.props;
|
||||
let params_2 = {
|
||||
categoryName: inputValue,
|
||||
categoryType: 2,
|
||||
parentId: parentCategoryValue[0],
|
||||
};
|
||||
let params_3 = {
|
||||
labelName: inputValue,
|
||||
primaryCategoryId: parentCategoryValue[0],
|
||||
};
|
||||
let params = moduleType == ModuleType.third ? params_3 : params_2;
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiNameModule[moduleType][0],
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
let id = res.data;
|
||||
let list = [
|
||||
...categoryList,
|
||||
{
|
||||
categoryName: inputValue,
|
||||
categoryId: id,
|
||||
isShowClose: true,
|
||||
},
|
||||
];
|
||||
let formatList = this.onHandleLabelSelectState(list, list.length - 1, false);
|
||||
this.setState(
|
||||
{
|
||||
inputVisible: false,
|
||||
inputValue: '',
|
||||
},
|
||||
() => {
|
||||
this.props.onChangeLabel(formatList, this.formatList(formatList));
|
||||
}
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 选中/未选中-标签
|
||||
* @param {*} tagIndex 选择的标签
|
||||
* @param {*} active 选择的标签的当前状态
|
||||
* @returns
|
||||
*/
|
||||
onChangeLabel = (tagIndex, active) => () => {
|
||||
let { categoryList, isDisabledReverseSelection } = this.props;
|
||||
if (active && isDisabledReverseSelection) {
|
||||
return;
|
||||
}
|
||||
let formatLabelList = this.onHandleLabelSelectState(categoryList, tagIndex, active);
|
||||
this.props.onChangeLabel(formatLabelList, this.formatList(formatLabelList));
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理数据选中/未选中(单选/多选)
|
||||
* @param {*} list 分类列表
|
||||
* @param {*} tagIndex 当前索引
|
||||
* @param {*} active 当前选中状态
|
||||
* @returns
|
||||
*/
|
||||
onHandleLabelSelectState = (list, tagIndex, active) => {
|
||||
const { isSingleChoice } = this.props;
|
||||
let formatLabelList = [];
|
||||
// 单选
|
||||
if (isSingleChoice) {
|
||||
formatLabelList = list.map((item, index) => {
|
||||
let flag = false;
|
||||
if (index == tagIndex) {
|
||||
flag = !active; // 将三级标签设置选中/未选中
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
active: flag,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
// 多选
|
||||
formatLabelList = list.map((item, index) => {
|
||||
let flag = item.active;
|
||||
if (index == tagIndex) {
|
||||
flag = !active; // 将三级标签设置选中/未选中
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
active: flag,
|
||||
};
|
||||
});
|
||||
}
|
||||
return formatLabelList;
|
||||
};
|
||||
|
||||
/**
|
||||
* 格式化数据-获得选中项id列表
|
||||
* @param {*} list
|
||||
* @returns
|
||||
*/
|
||||
formatList = (list) => {
|
||||
let labelList = [];
|
||||
list.forEach((item) => {
|
||||
if (item.active) {
|
||||
labelList.push(item.categoryId);
|
||||
}
|
||||
});
|
||||
return labelList;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { moduleType, categoryList, isAddTag, isDeleteTag } = this.props;
|
||||
const { inputVisible, inputValue } = this.state;
|
||||
let labelList = categoryList;
|
||||
// 数组中存在 -9999 表示暂无数据,需要支持新增
|
||||
if (
|
||||
categoryList.filter((item) => {
|
||||
return item.categoryId === -9999;
|
||||
}).length > 0
|
||||
) {
|
||||
labelList = categoryList.slice(1, categoryList.length);
|
||||
}
|
||||
return (
|
||||
<div className="tags-editor-box">
|
||||
{labelList?.length > 0 &&
|
||||
labelList.map((item, index) => {
|
||||
const isLongTag = item.categoryName.length > 20;
|
||||
const tagElem = (
|
||||
<Tag
|
||||
style={{
|
||||
margin: '4px',
|
||||
height: '40px',
|
||||
lineHeight: '40px',
|
||||
fontSize: '13px',
|
||||
padding: '0px 16px',
|
||||
border: '1px solid #d9d9d9',
|
||||
backgroundColor: '#fff',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
key={item.categoryId}
|
||||
// 支持删除标签
|
||||
closable={item.isShowClose && isDeleteTag}
|
||||
className={`tags-editor-item ${item.active && 'tag-active'}`}
|
||||
onClick={this.onChangeLabel(index, item.active)}
|
||||
onClose={() => this.handleClose(index, item.categoryId)}>
|
||||
{isLongTag
|
||||
? `${item.categoryName.slice(0, 20)}...`
|
||||
: item.categoryName}
|
||||
</Tag>
|
||||
);
|
||||
return isLongTag ? (
|
||||
<Tooltip title={item.categoryName} key={item.categoryId}>
|
||||
{tagElem}
|
||||
</Tooltip>
|
||||
) : (
|
||||
tagElem
|
||||
);
|
||||
})}
|
||||
{inputVisible && (
|
||||
<Input
|
||||
ref={this.saveInputRef}
|
||||
type="text"
|
||||
size="small"
|
||||
style={{ width: 78, height: 40, marginTop: '4px' }}
|
||||
max={10}
|
||||
value={inputValue}
|
||||
onChange={this.handleInputChange}
|
||||
onBlur={this.handleInputConfirm}
|
||||
onPressEnter={this.handleInputConfirm}
|
||||
/>
|
||||
)}
|
||||
{/* 支持手动增加标签 */}
|
||||
{!inputVisible && isAddTag && (
|
||||
<Tag
|
||||
onClick={this.showInput}
|
||||
style={{
|
||||
background: '#fff',
|
||||
borderColor: 'rgba(60, 110, 238, 1)',
|
||||
borderStyle: 'dashed',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: '14px',
|
||||
height: '40px',
|
||||
padding: '0px 16px',
|
||||
marginTop: '4px',
|
||||
}}>
|
||||
<PlusOutlined />
|
||||
新增{moduleType == ModuleType.third ? '标签' : '分类'}
|
||||
</Tag>
|
||||
)}
|
||||
{!isAddTag && labelList.length === 0 && (
|
||||
<div className="tag-empty-tip">暂无数据呦~</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
21
src/components/tags-editor/index.less
Normal file
21
src/components/tags-editor/index.less
Normal file
@@ -0,0 +1,21 @@
|
||||
.tags-editor-box {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.tag-active {
|
||||
@include box-backgroundColor(0.1);
|
||||
@include box-border();
|
||||
@include font-color();
|
||||
}
|
||||
.ant-tag .anticon-close {
|
||||
font-size: 11px;
|
||||
margin-right: -4px;
|
||||
border: 1px solid;
|
||||
border-radius: 50%;
|
||||
padding: 4px;
|
||||
}
|
||||
.tag-empty-tip {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
}
|
91
src/components/top-menu/index.jsx
Normal file
91
src/components/top-menu/index.jsx
Normal file
@@ -0,0 +1,91 @@
|
||||
import React, { Component } from 'react'
|
||||
import './index.less'
|
||||
// 顶部tab
|
||||
const MENULIST = [
|
||||
{
|
||||
key: 'shareIndex',
|
||||
title: '刷题',
|
||||
route: '/share-index',
|
||||
},
|
||||
{
|
||||
key: 'questionBank',
|
||||
title: '练题',
|
||||
route: '/question-bank',
|
||||
},
|
||||
{
|
||||
key: 'practiceQuestions',
|
||||
title: '鸡圈',
|
||||
route: '/practice-questions',
|
||||
},
|
||||
{
|
||||
key: 'interList',
|
||||
title: '模拟面试',
|
||||
route: '/inter-list',
|
||||
// isOpenNewWindow: true,
|
||||
},
|
||||
]
|
||||
|
||||
// 顶部tab映射
|
||||
const mapMenu = {
|
||||
'/cms-supplier/share-index': 'shareIndex',
|
||||
'/cms-supplier/inter-list': 'interList',
|
||||
'/cms-supplier/question-bank': 'questionBank',
|
||||
'/cms-supplier/practice-questions': 'practiceQuestions',
|
||||
}
|
||||
class TopMenu extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
currentKey: 'shareIndex',
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// this.setState({
|
||||
// currentKey: mapMenu[this.props.currentRoute] || '',
|
||||
// })
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换item
|
||||
* @param {*} item
|
||||
* @returns
|
||||
*/
|
||||
changeMenu = (item) => () => {
|
||||
// 打开新窗口
|
||||
if (item.isOpenNewWindow) {
|
||||
window.open('/cms-supplier' + item.route)
|
||||
return
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
currentKey: item.key,
|
||||
},
|
||||
() => {
|
||||
this.props.history.push(item.route)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { currentKey } = this.state
|
||||
return (
|
||||
<div className="top-menu-list">
|
||||
{MENULIST.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
className={`top-menu-item ${currentKey === item.key ? 'top-menu-item-active' : ''}`}
|
||||
key={item.key + index}
|
||||
onClick={this.changeMenu(item)}
|
||||
>
|
||||
<div className="top-menu-text">{item.title}</div>
|
||||
<div className={`top-menu-line ${currentKey === item.key ? 'top-menu-line-active' : ''}`}></div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default TopMenu
|
35
src/components/top-menu/index.less
Normal file
35
src/components/top-menu/index.less
Normal file
@@ -0,0 +1,35 @@
|
||||
.top-menu-list {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
.top-menu-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0 28px;
|
||||
font-size: 16px;
|
||||
font-size: 500;
|
||||
color: rgba(24, 24, 29, 1);
|
||||
cursor: pointer;
|
||||
&-active {
|
||||
color: rgba(60, 110, 238, 1);
|
||||
}
|
||||
&:hover {
|
||||
color: rgba(60, 110, 238, 1);
|
||||
}
|
||||
|
||||
.top-menu-line {
|
||||
position: absolute;
|
||||
bottom: -12px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
&-active {
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background: rgba(60, 110, 238, 1);
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user