feat: 增加练题
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/charts": "^1.4.3",
|
||||
"@ant-design/icons": "^5.2.6",
|
||||
"@reduxjs/toolkit": "^1.9.7",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
|
3914
pnpm-lock.yaml
generated
3914
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
10
src/App.less
10
src/App.less
@@ -2,7 +2,7 @@
|
||||
|
||||
.app-main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-direction: column;
|
||||
border-radius: 4px;
|
||||
margin: 0 auto;
|
||||
position: absolute;
|
||||
@@ -12,7 +12,7 @@
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #f3f4f6;
|
||||
padding: 66px 16px 32px;
|
||||
padding: 66px 16px 0;
|
||||
overflow: hidden;
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||
@@ -25,5 +25,11 @@
|
||||
width: 1439px;
|
||||
margin: 0 auto;
|
||||
overflow: auto;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.copyright {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
42
src/App.tsx
42
src/App.tsx
@@ -1,11 +1,46 @@
|
||||
import req from '@utils/request'
|
||||
import Header from '@views/header'
|
||||
import { Suspense, memo, useEffect } from 'react'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { Outlet, useLocation, useNavigate } from 'react-router-dom'
|
||||
// 引入对应的方法
|
||||
import './App.less'
|
||||
import { saveUserInfo } from './store/features/userInfoSlice.ts'
|
||||
|
||||
const apiName = {
|
||||
update: '/user/update',
|
||||
queryInfo: '/user/getUserInfo'
|
||||
}
|
||||
|
||||
const App = () => {
|
||||
const userInfoStorage = localStorage.getItem('userInfo')
|
||||
const { loginId = '' } = userInfoStorage ? JSON.parse(userInfoStorage) : {}
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const location = useLocation()
|
||||
const navigate = useNavigate()
|
||||
|
||||
const getUserInfo = async () => {
|
||||
req(
|
||||
{
|
||||
method: 'post',
|
||||
url: apiName.queryInfo,
|
||||
data: {
|
||||
userName: loginId
|
||||
}
|
||||
},
|
||||
'/auth'
|
||||
).then(res => {
|
||||
if (res?.success && res?.data) {
|
||||
dispatch(saveUserInfo(res.data))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getUserInfo()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (location.pathname === '/') {
|
||||
const userInfoStorage = localStorage.getItem('userInfo')
|
||||
@@ -18,7 +53,7 @@ const App = () => {
|
||||
return (
|
||||
<div
|
||||
className='app-main'
|
||||
style={{ padding: location.pathname === '/login' ? '66px 0 0' : '66px 16px 32px' }}
|
||||
style={{ padding: location.pathname === '/login' ? '66px 0 0' : '66px 16px 0' }}
|
||||
>
|
||||
<Header />
|
||||
<div
|
||||
@@ -29,6 +64,11 @@ const App = () => {
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
</div>
|
||||
<div className='copyright'>
|
||||
<a href='http://beian.miit.gov.cn/' target='_blank'>
|
||||
京ICP备2023035579号
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
71
src/components/analysis-atlas/index.jsx
Normal file
71
src/components/analysis-atlas/index.jsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import { Radar } from '@ant-design/charts'
|
||||
import React, { memo } from 'react'
|
||||
|
||||
//atlasList 列表数据 [{name:'',star:''}]
|
||||
//aliasStr 鼠标浮上去显示的框框内的别名
|
||||
//fillOpacity 填充区域的透明度
|
||||
//fill 填充区域的颜色
|
||||
//alternateColor 图形相间的颜色
|
||||
//lineColor 线的颜色
|
||||
//atlasWidth 分析图宽
|
||||
//atlasHeight 分析图长
|
||||
//atlasSpan 分析图跨度
|
||||
//atlasParag 你需要有几个圈
|
||||
|
||||
export default memo(function ({
|
||||
atlasList = [],
|
||||
aliasStr,
|
||||
fillOpacity = 0.2,
|
||||
fill = 'rgb(60, 110, 238)',
|
||||
alternateColor = 'rgba(0, 0, 0, 0.04)',
|
||||
lineColor = 'rgb(60, 110, 238)',
|
||||
atlasWidth = 250,
|
||||
atlasHeight = 250,
|
||||
atlasSpan = 25,
|
||||
atlasParag = 4,
|
||||
atlasMin = 0,
|
||||
atlasMax = 100
|
||||
}) {
|
||||
let spanList = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
|
||||
.splice(0, atlasParag + 1)
|
||||
.map(item => item * atlasSpan + '')
|
||||
|
||||
const config = {
|
||||
data: atlasList,
|
||||
xField: 'name',
|
||||
yField: 'star',
|
||||
width: atlasWidth,
|
||||
height: atlasHeight,
|
||||
appendPadding: [0, 15, 15, 15],
|
||||
meta: {
|
||||
star: {
|
||||
alias: aliasStr, //字段别名
|
||||
min: atlasMin,
|
||||
max: atlasMax,
|
||||
nice: true,
|
||||
formatter: v => v,
|
||||
values: spanList //用来控制有几个圈
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
tickLine: null
|
||||
},
|
||||
yAxis: {
|
||||
label: false,
|
||||
grid: {
|
||||
alternateColor: alternateColor
|
||||
}
|
||||
},
|
||||
// 开启辅助点
|
||||
point: {
|
||||
size: 2
|
||||
},
|
||||
lineStyle: {
|
||||
fill: fill,
|
||||
fillOpacity: fillOpacity,
|
||||
cursor: 'pointer',
|
||||
stroke: lineColor
|
||||
}
|
||||
}
|
||||
return <Radar {...config} />
|
||||
})
|
@@ -1,304 +1,303 @@
|
||||
import React, { Component } from 'react';
|
||||
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';
|
||||
import { PlusOutlined } from '@ant-design/icons'
|
||||
import req from '@utils/request'
|
||||
import { Input, Tag, Tooltip, message } from 'antd'
|
||||
import { ModuleType, apiName } from './constant'
|
||||
import './index.less'
|
||||
|
||||
const apiNameModule = {
|
||||
[ModuleType.second]: [apiName.addInterviewCategory, apiName.deleteInterviewCategory],
|
||||
[ModuleType.third]: [apiName.addInterviewLabel, apiName.deleteInterviewLabel],
|
||||
};
|
||||
[ModuleType.second]: [apiName.addInterviewCategory, apiName.deleteInterviewCategory],
|
||||
[ModuleType.third]: [apiName.addInterviewLabel, apiName.deleteInterviewLabel]
|
||||
}
|
||||
|
||||
export default class TagsEditor extends Component {
|
||||
saveInputRef = (input) => (this.input = input);
|
||||
saveInputRef = input => (this.input = input)
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
inputVisible: false,
|
||||
inputValue: '',
|
||||
};
|
||||
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.id !== 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;
|
||||
/**
|
||||
* 点击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.id !== categoryId
|
||||
})
|
||||
this.props.onChangeLabel(list, this.formatList(list))
|
||||
}
|
||||
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: '',
|
||||
});
|
||||
}
|
||||
};
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加标签
|
||||
* @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);
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 展示输入框
|
||||
*/
|
||||
showInput = () => {
|
||||
this.setState({ inputVisible: true }, () => this.input.focus())
|
||||
}
|
||||
|
||||
/**
|
||||
* 选中/未选中-标签
|
||||
* @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 {*} e
|
||||
*/
|
||||
handleInputChange = e => {
|
||||
this.setState({ inputValue: e.target.value })
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理数据选中/未选中(单选/多选)
|
||||
* @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;
|
||||
};
|
||||
/**
|
||||
* 增加标签
|
||||
*/
|
||||
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: ''
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化数据-获得选中项id列表
|
||||
* @param {*} list
|
||||
* @returns
|
||||
*/
|
||||
formatList = (list) => {
|
||||
let labelList = [];
|
||||
list.forEach((item) => {
|
||||
if (item.active) {
|
||||
labelList.push(item.id);
|
||||
/**
|
||||
* 增加标签
|
||||
* @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
|
||||
}
|
||||
});
|
||||
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.id === -9999;
|
||||
}).length > 0
|
||||
) {
|
||||
labelList = categoryList.slice(1, categoryList.length);
|
||||
]
|
||||
let formatList = this.onHandleLabelSelectState(list, list.length - 1, false)
|
||||
this.setState(
|
||||
{
|
||||
inputVisible: false,
|
||||
inputValue: ''
|
||||
},
|
||||
() => {
|
||||
this.props.onChangeLabel(formatList, this.formatList(formatList))
|
||||
}
|
||||
)
|
||||
}
|
||||
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.id}
|
||||
// 支持删除标签
|
||||
closable={item.isShowClose && isDeleteTag}
|
||||
className={`tags-editor-item ${item.active ? 'tag-active' : ''}`}
|
||||
onClick={this.onChangeLabel(index, item.active)}
|
||||
onClose={() => this.handleClose(index, item.id)}>
|
||||
{isLongTag
|
||||
? `${item.categoryName.slice(0, 20)}...`
|
||||
: item.categoryName}
|
||||
</Tag>
|
||||
);
|
||||
return isLongTag ? (
|
||||
<Tooltip title={item.categoryName} key={item.id}>
|
||||
{tagElem}
|
||||
</Tooltip>
|
||||
) : (
|
||||
<div key={item.id}>
|
||||
{tagElem}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{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>
|
||||
);
|
||||
})
|
||||
.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.id)
|
||||
}
|
||||
})
|
||||
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.id === -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.id || item.categoryId) + '_' + item.categoryName}
|
||||
// 支持删除标签
|
||||
closable={item.isShowClose && isDeleteTag}
|
||||
className={`tags-editor-item ${item.active ? 'tag-active' : ''}`}
|
||||
onClick={this.onChangeLabel(index, item.active)}
|
||||
onClose={() => this.handleClose(index, item.id)}
|
||||
>
|
||||
{isLongTag ? `${item.categoryName.slice(0, 20)}...` : item.categoryName}
|
||||
</Tag>
|
||||
)
|
||||
return isLongTag ? (
|
||||
<Tooltip
|
||||
title={item.categoryName}
|
||||
key={(item.id || item.categoryId) + '_' + item.categoryName}
|
||||
>
|
||||
{tagElem}
|
||||
</Tooltip>
|
||||
) : (
|
||||
<div key={(item.id || item.categoryId) + '_' + item.categoryName}>{tagElem}</div>
|
||||
)
|
||||
})}
|
||||
{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>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
118
src/components/timerCom/FlipClock.jsx
Normal file
118
src/components/timerCom/FlipClock.jsx
Normal file
@@ -0,0 +1,118 @@
|
||||
import React, { Component } from 'react'
|
||||
import Flipper from './Flipper'
|
||||
import './flipClock.less'
|
||||
|
||||
class FlipClock extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.timer = null
|
||||
this.flipObjs = []
|
||||
this.state = {
|
||||
hou: 0,
|
||||
second: 0,
|
||||
minutes: 0,
|
||||
strikes: 0,
|
||||
oneHour: false,
|
||||
halfHour: false
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let { oneHour, halfHour } = this.state
|
||||
return (
|
||||
<div className='FlipClock'>
|
||||
<Flipper ref='flipperHour1' oneHour={oneHour} halfHour={halfHour} />
|
||||
<Flipper ref='flipperHour2' oneHour={oneHour} halfHour={halfHour} />
|
||||
<em>:</em>
|
||||
<Flipper ref='flipperMinute1' oneHour={oneHour} halfHour={halfHour} />
|
||||
<Flipper ref='flipperMinute2' oneHour={oneHour} halfHour={halfHour} />
|
||||
<em>:</em>
|
||||
<Flipper ref='flipperSecond1' oneHour={oneHour} halfHour={halfHour} />
|
||||
<Flipper ref='flipperSecond2' oneHour={oneHour} halfHour={halfHour} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.flipObjs = [
|
||||
this.refs.flipperHour1,
|
||||
this.refs.flipperHour2,
|
||||
this.refs.flipperMinute1,
|
||||
this.refs.flipperMinute2,
|
||||
this.refs.flipperSecond1,
|
||||
this.refs.flipperSecond2
|
||||
]
|
||||
this.init()
|
||||
}
|
||||
|
||||
// 初始化数字
|
||||
init() {
|
||||
for (let i = 0; i < this.flipObjs.length; i++) {
|
||||
this.flipObjs[i].setFront(0)
|
||||
}
|
||||
}
|
||||
// 开始计时
|
||||
run = () => {
|
||||
this.timer = setInterval(() => {
|
||||
// 获取当前时间
|
||||
const nextstrikes = this.state.strikes + 1000
|
||||
const o_nextstrikes = nextstrikes + 1000
|
||||
let hou = parseInt(nextstrikes / 3600000) % 24,
|
||||
minetes = parseInt(nextstrikes / 60000) % 60,
|
||||
second = parseInt(nextstrikes / 1000) % 60
|
||||
let o_hou = parseInt(o_nextstrikes / 3600000) % 24,
|
||||
o_minetes = parseInt(o_nextstrikes / 60000) % 60,
|
||||
o_second = parseInt(o_nextstrikes / 1000) % 60
|
||||
let n_hou = o_hou <= 9 ? '0' + o_hou : o_hou,
|
||||
n_minetes = o_minetes <= 9 ? '0' + o_minetes : o_minetes,
|
||||
n_second = o_second <= 9 ? '0' + o_second : o_second
|
||||
let nextTimeStr = n_hou + n_minetes + n_second
|
||||
|
||||
this.setState(
|
||||
{
|
||||
hou: hou <= 9 ? '0' + hou : hou,
|
||||
minutes: minetes <= 9 ? '0' + minetes : minetes,
|
||||
second: second <= 9 ? '0' + second : second,
|
||||
strikes: nextstrikes,
|
||||
oneHour: 10000 <= nextTimeStr,
|
||||
halfHour: 3000 <= nextTimeStr
|
||||
},
|
||||
() => {
|
||||
let { hou, minutes, second } = this.state
|
||||
let nowTimeStr = hou + minutes + second
|
||||
|
||||
for (let i = 0; i < this.flipObjs.length; i++) {
|
||||
if (nowTimeStr[i] === nextTimeStr[i]) {
|
||||
continue
|
||||
}
|
||||
this.flipObjs[i].flipDown(nowTimeStr[i], nextTimeStr[i])
|
||||
}
|
||||
}
|
||||
)
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
end = () => {
|
||||
clearInterval(this.timer)
|
||||
}
|
||||
|
||||
stop = () => {
|
||||
clearInterval(this.timer)
|
||||
}
|
||||
|
||||
/**
|
||||
* 计时的时间段
|
||||
* @returns
|
||||
*/
|
||||
getUseTime = () => {
|
||||
const { hou, minutes, second } = this.state
|
||||
const nowTimeStr = hou + minutes + second
|
||||
return nowTimeStr
|
||||
}
|
||||
|
||||
//清除定时器
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.timer)
|
||||
}
|
||||
}
|
||||
export default FlipClock
|
106
src/components/timerCom/Flipper.jsx
Normal file
106
src/components/timerCom/Flipper.jsx
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 翻牌数字
|
||||
* @author: 兔子先生
|
||||
* @createDate: 2019-11-24
|
||||
*/
|
||||
// import PropTypes from 'prop-types'
|
||||
import React, { Component } from 'react'
|
||||
import './flipper.less'
|
||||
|
||||
class Flipper extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
isFlipping: false,
|
||||
flipType: 'down',
|
||||
frontTextFromData: 0,
|
||||
backTextFromData: 1
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isFlipping, flipType, frontTextFromData, backTextFromData } = this.state
|
||||
return (
|
||||
<div className={['M-Flipper', flipType, isFlipping ? 'go' : null].join(' ')}>
|
||||
<div
|
||||
className={`digital front ` + this._thisTimeClass() + this._textClass(frontTextFromData)}
|
||||
></div>
|
||||
<div
|
||||
className={'digital back ' + this._thisTimeClass() + this._textClass(backTextFromData)}
|
||||
></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
_textClass(number) {
|
||||
return 'number' + number
|
||||
}
|
||||
|
||||
_thisTimeClass() {
|
||||
let { oneHour, halfHour } = this.props
|
||||
return (halfHour ? 'digital30 ' : '') + (oneHour ? 'digital60 ' : ' ')
|
||||
}
|
||||
|
||||
_flip(type, front, back) {
|
||||
// 如果处于翻转中,则不执行
|
||||
if (this.isFlipping) {
|
||||
return false
|
||||
}
|
||||
this.setState({
|
||||
frontTextFromData: front,
|
||||
backTextFromData: back,
|
||||
// 根据传递过来的type设置翻转方向
|
||||
flipType: type,
|
||||
// 设置翻转状态为true
|
||||
isFlipping: true
|
||||
})
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
frontTextFromData: back,
|
||||
isFlipping: false
|
||||
})
|
||||
}, this.props.duration)
|
||||
}
|
||||
// 下翻牌
|
||||
flipDown(front, back) {
|
||||
this._flip('down', front, back)
|
||||
}
|
||||
// 上翻牌
|
||||
flipUp(front, back) {
|
||||
this._flip('up', front, back)
|
||||
}
|
||||
// 设置前牌文字
|
||||
setFront(text) {
|
||||
this.setState({
|
||||
frontTextFromData: text
|
||||
})
|
||||
}
|
||||
// 设置后牌文字
|
||||
setBack(text) {
|
||||
this.setState({
|
||||
backTextFromData: text
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// props类型校验
|
||||
// Flipper.propTypes = {
|
||||
// frontText: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
// backText: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
// duration: PropTypes.number
|
||||
// }
|
||||
|
||||
// props默认值
|
||||
Flipper.defaultProps = {
|
||||
// front paper text
|
||||
// 前牌文字
|
||||
frontText: 0,
|
||||
// back paper text
|
||||
// 后牌文字
|
||||
backText: 1,
|
||||
// flipping duration, please be consistent with the CSS animation-duration value.
|
||||
// 翻牌动画时间,与CSS中设置的animation-duration保持一致
|
||||
duration: 600
|
||||
}
|
||||
|
||||
export default Flipper
|
17
src/components/timerCom/flipClock.less
Normal file
17
src/components/timerCom/flipClock.less
Normal file
@@ -0,0 +1,17 @@
|
||||
.FlipClock {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.FlipClock .M-Flipper {
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
.FlipClock em {
|
||||
display: inline-block;
|
||||
line-height: 27px;
|
||||
font-size: 40px;
|
||||
font-style: normal;
|
||||
vertical-align: top;
|
||||
margin: 0 3px;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
}
|
196
src/components/timerCom/flipper.less
Normal file
196
src/components/timerCom/flipper.less
Normal file
@@ -0,0 +1,196 @@
|
||||
.M-Flipper {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 36px;
|
||||
height: 35px;
|
||||
line-height: 34px;
|
||||
/* border: solid 1px #000; */
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
font-size: 30px;
|
||||
color: #000;
|
||||
box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
|
||||
text-align: center;
|
||||
font-family: "Helvetica Neue";
|
||||
}
|
||||
|
||||
.M-Flipper .digital:before,
|
||||
.M-Flipper .digital:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.M-Flipper .digital30:before,
|
||||
.M-Flipper .digital30:after {
|
||||
background: #ff9e20;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.M-Flipper .digital60:before,
|
||||
.M-Flipper .digital60:after {
|
||||
background: rgb(240, 76, 76);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.M-Flipper .digital:before {
|
||||
top: 0;
|
||||
bottom: 50%;
|
||||
border-radius: 10px 10px 0 0;
|
||||
border-bottom: solid 0.5px #ccc;
|
||||
}
|
||||
|
||||
.M-Flipper .digital:after {
|
||||
top: 50%;
|
||||
bottom: 0;
|
||||
border-radius: 0 0 10px 10px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
/*向下翻*/
|
||||
.M-Flipper.down .front:before {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.M-Flipper.down .back:after {
|
||||
z-index: 2;
|
||||
transform-origin: 50% 0%;
|
||||
transform: perspective(160px) rotateX(180deg);
|
||||
}
|
||||
|
||||
.M-Flipper.down .front:after,
|
||||
.M-Flipper.down .back:before {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.M-Flipper.down.go .front:before {
|
||||
transform-origin: 50% 100%;
|
||||
animation: frontFlipDown 0.6s ease-in-out both;
|
||||
box-shadow: 0 -2px 6px rgba(255, 255, 255, 0.3);
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.M-Flipper.down.go .back:after {
|
||||
animation: backFlipDown 0.6s ease-in-out both;
|
||||
}
|
||||
|
||||
/*向上翻*/
|
||||
.M-Flipper.up .front:after {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.M-Flipper.up .back:before {
|
||||
z-index: 2;
|
||||
transform-origin: 50% 100%;
|
||||
transform: perspective(160px) rotateX(-180deg);
|
||||
}
|
||||
|
||||
.M-Flipper.up .front:before,
|
||||
.M-Flipper.up .back:after {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.M-Flipper.up.go .front:after {
|
||||
transform-origin: 50% 0;
|
||||
animation: frontFlipUp 0.6s ease-in-out both;
|
||||
/* box-shadow: 0 2px 6px rgba(255, 255, 255, 0.3); */
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.M-Flipper.up.go .back:before {
|
||||
animation: backFlipUp 0.6s ease-in-out both;
|
||||
}
|
||||
|
||||
@keyframes frontFlipDown {
|
||||
0% {
|
||||
transform: perspective(160px) rotateX(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: perspective(160px) rotateX(-180deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes backFlipDown {
|
||||
0% {
|
||||
transform: perspective(160px) rotateX(180deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: perspective(160px) rotateX(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes frontFlipUp {
|
||||
0% {
|
||||
transform: perspective(160px) rotateX(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: perspective(160px) rotateX(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes backFlipUp {
|
||||
0% {
|
||||
transform: perspective(160px) rotateX(-180deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: perspective(160px) rotateX(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
.M-Flipper .number0:before,
|
||||
.M-Flipper .number0:after {
|
||||
content: "0";
|
||||
}
|
||||
|
||||
.M-Flipper .number1:before,
|
||||
.M-Flipper .number1:after {
|
||||
content: "1";
|
||||
}
|
||||
|
||||
.M-Flipper .number2:before,
|
||||
.M-Flipper .number2:after {
|
||||
content: "2";
|
||||
}
|
||||
|
||||
.M-Flipper .number3:before,
|
||||
.M-Flipper .number3:after {
|
||||
content: "3";
|
||||
}
|
||||
|
||||
.M-Flipper .number4:before,
|
||||
.M-Flipper .number4:after {
|
||||
content: "4";
|
||||
}
|
||||
|
||||
.M-Flipper .number5:before,
|
||||
.M-Flipper .number5:after {
|
||||
content: "5";
|
||||
}
|
||||
|
||||
.M-Flipper .number6:before,
|
||||
.M-Flipper .number6:after {
|
||||
content: "6";
|
||||
}
|
||||
|
||||
.M-Flipper .number7:before,
|
||||
.M-Flipper .number7:after {
|
||||
content: "7";
|
||||
}
|
||||
|
||||
.M-Flipper .number8:before,
|
||||
.M-Flipper .number8:after {
|
||||
content: "8";
|
||||
}
|
||||
|
||||
.M-Flipper .number9:before,
|
||||
.M-Flipper .number9:after {
|
||||
content: "9";
|
||||
}
|
34
src/components/timerCom/index.jsx
Normal file
34
src/components/timerCom/index.jsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import React, { Component } from "react";
|
||||
|
||||
export default class timerCom extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
hou: 0,
|
||||
second: 0,
|
||||
minutes: 0,
|
||||
strikes: 0,
|
||||
};
|
||||
}
|
||||
timer = () => {
|
||||
const nextstrikes = this.state.strikes + 50;
|
||||
this.setState({
|
||||
hou: parseInt(nextstrikes / 3600000) % 24,
|
||||
minutes: parseInt(nextstrikes / 60000) % 60,
|
||||
second: parseInt(nextstrikes / 1000) % 60,
|
||||
strikes: this.state.strikes + 50,
|
||||
});
|
||||
}
|
||||
componentDidMount() {
|
||||
setInterval(this.timer, 50);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h1>
|
||||
{this.state.hou}:{this.state.minutes}:{this.state.second}
|
||||
</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@@ -7,22 +7,26 @@ const MENULIST = [
|
||||
{
|
||||
key: 'questionBank',
|
||||
title: '刷题',
|
||||
route: '/question-bank'
|
||||
route: '/question-bank',
|
||||
finished: true
|
||||
},
|
||||
{
|
||||
key: 'prictiseQuestion',
|
||||
title: '练题',
|
||||
route: '/brush-question'
|
||||
route: '/practice-questions',
|
||||
finished: true
|
||||
},
|
||||
{
|
||||
key: 'practiceQuestions',
|
||||
title: '鸡圈',
|
||||
route: '/practice-questions'
|
||||
route: '/jichi-club',
|
||||
finished: false
|
||||
},
|
||||
{
|
||||
key: 'interList',
|
||||
title: '模拟面试',
|
||||
route: '/inter-list'
|
||||
route: '/inter-list',
|
||||
finished: false
|
||||
}
|
||||
]
|
||||
|
||||
@@ -55,10 +59,10 @@ const TopMenu = () => {
|
||||
if (!userInfoStorage) {
|
||||
return message.info('请登录')
|
||||
}
|
||||
if (item.key === 'questionBank') {
|
||||
if (location.pathname === '/question-bank') return
|
||||
navigate('/question-bank')
|
||||
if (item.finished) {
|
||||
if (location.pathname === item.route) return
|
||||
setCurrentKey(item.key)
|
||||
navigate(item.route)
|
||||
} else {
|
||||
return message.info('敬请期待')
|
||||
}
|
||||
|
BIN
src/imgs/badcf6d37c476233.png
Normal file
BIN
src/imgs/badcf6d37c476233.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 478 KiB |
BIN
src/imgs/personal_qr_code.jpg
Normal file
BIN
src/imgs/personal_qr_code.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
@@ -36,8 +36,20 @@ const router = createBrowserRouter([
|
||||
Component: lazy(() => import('@views/search-details'))
|
||||
},
|
||||
{
|
||||
path: 'personal-center',
|
||||
path: 'personal-center/:tab',
|
||||
Component: lazy(() => import('@views/personal-center'))
|
||||
},
|
||||
{
|
||||
path: 'practice-questions',
|
||||
Component: lazy(() => import('@views/practise/practice-questions'))
|
||||
},
|
||||
{
|
||||
path: 'practice-detail/:id',
|
||||
Component: lazy(() => import('@views/practise/practice-details/index1.jsx'))
|
||||
},
|
||||
{
|
||||
path: 'practice-analytic/:id',
|
||||
Component: lazy(() => import('@views/practise/practice-analytic'))
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,23 +1,33 @@
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
export interface CounterState {
|
||||
value: number
|
||||
title: string
|
||||
export interface UserInfo {
|
||||
nickName?: string
|
||||
phone?: string
|
||||
email?: string
|
||||
sex?: string | number
|
||||
introduce?: string
|
||||
avatar?: string
|
||||
}
|
||||
const initialState: CounterState = {
|
||||
value: 0,
|
||||
title: 'redux toolkit pre'
|
||||
const initialState: UserInfo = {
|
||||
nickName: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
sex: undefined,
|
||||
introduce: '',
|
||||
avatar: ''
|
||||
}
|
||||
|
||||
// 创建一个 Slice
|
||||
export const userInfoSlice = createSlice({
|
||||
name: 'userInfo',
|
||||
initialState,
|
||||
initialState: {
|
||||
userInfo: initialState
|
||||
},
|
||||
// 定义 reducers 并生成关联的操作
|
||||
reducers: {
|
||||
// 定义一个加的方法
|
||||
saveUserInfo: (state, { payload }) => {
|
||||
state.value = payload
|
||||
state.userInfo = { ...state.userInfo, ...payload }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import Head from '@/imgs/head.jpg'
|
||||
import Logo from '@/imgs/logo.jpg'
|
||||
import { HeartOutlined, LikeOutlined, LoginOutlined, UserOutlined } from '@ant-design/icons'
|
||||
import TopMenu from '@components/top-menu'
|
||||
import LoginQrcode from '@imgs/login_qrcode.jpg'
|
||||
import LoginQrcode from '@imgs/personal_qr_code.jpg'
|
||||
import req from '@utils/request'
|
||||
import { Button, Dropdown, Input, Modal, Popover, Space, message } from 'antd'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
import './index.less'
|
||||
@@ -15,17 +15,20 @@ const menuItems = [
|
||||
{
|
||||
label: '个人中心',
|
||||
key: 1,
|
||||
icon: <UserOutlined style={{ fontSize: '16px' }} />
|
||||
icon: <UserOutlined style={{ fontSize: '16px' }} />,
|
||||
path: '/user-info'
|
||||
},
|
||||
{
|
||||
label: '我的收藏',
|
||||
key: 2,
|
||||
icon: <HeartOutlined style={{ fontSize: '16px' }} />
|
||||
icon: <HeartOutlined style={{ fontSize: '16px' }} />,
|
||||
path: '/personal-center/0'
|
||||
},
|
||||
{
|
||||
label: '我的点赞',
|
||||
key: 3,
|
||||
icon: <LikeOutlined style={{ fontSize: '16px' }} />
|
||||
icon: <LikeOutlined style={{ fontSize: '16px' }} />,
|
||||
path: '/personal-center/1'
|
||||
},
|
||||
{
|
||||
type: 'divider'
|
||||
@@ -47,19 +50,19 @@ const discoverItems = [
|
||||
title: '跟我做',
|
||||
subTitle: '从0到1做鸡翅Club项目',
|
||||
key: 'club',
|
||||
path: ''
|
||||
path: 'https://www.yuque.com/jingdianjichi/gb9bgl/zod2490hhixazf6n?singleDoc#%20%E3%80%8A%E9%B8%A1%E7%BF%85Club%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D%E3%80%8B'
|
||||
},
|
||||
{
|
||||
title: '更深入',
|
||||
subTitle: '从0到1做企业级框架项目',
|
||||
key: 'deep',
|
||||
path: ''
|
||||
path: 'https://www.yuque.com/jingdianjichi/gb9bgl/rliblb1tvthnl6k3?singleDoc#%20%E3%80%8Aape-frame%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D%E3%80%8B'
|
||||
},
|
||||
{
|
||||
title: '加星球',
|
||||
subTitle: '一键进入鸡哥的知识星球',
|
||||
key: 'star',
|
||||
path: ''
|
||||
path: 'https://www.yuque.com/jingdianjichi/gb9bgl/ko3bclqhtuu8uif0?singleDoc#%20%E3%80%8A%E7%9F%A5%E8%AF%86%E6%98%9F%E7%90%83%E5%AE%A3%E4%BC%A0%E3%80%8B'
|
||||
}
|
||||
]
|
||||
|
||||
@@ -67,48 +70,43 @@ const Header = () => {
|
||||
const { pathname } = window.location
|
||||
const navigate = useNavigate()
|
||||
|
||||
const { userInfo } = useSelector(store => store.userInfo)
|
||||
|
||||
const handleMenuClick = e => {
|
||||
const userInfoStorage = localStorage.getItem('userInfo')
|
||||
if (!userInfoStorage) {
|
||||
return message.info('请登录')
|
||||
}
|
||||
const { loginId } = JSON.parse(userInfoStorage)
|
||||
switch (e.key) {
|
||||
case '1':
|
||||
navigate('/user-info')
|
||||
break
|
||||
case '4':
|
||||
// 退出
|
||||
Modal.confirm({
|
||||
title: '退出提示',
|
||||
content: '确定退出当前用户登录吗?',
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
req(
|
||||
{
|
||||
method: 'get',
|
||||
url: '/user/logOut',
|
||||
params: {
|
||||
userName: loginId
|
||||
}
|
||||
},
|
||||
'/auth'
|
||||
).then(res => {
|
||||
if (res.success) {
|
||||
localStorage.removeItem('userInfo')
|
||||
message.info('退出成功')
|
||||
setTimeout(() => {
|
||||
navigate('/login')
|
||||
}, 500)
|
||||
if (e.key == 4) {
|
||||
Modal.confirm({
|
||||
title: '退出提示',
|
||||
content: '确定退出当前用户登录吗?',
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
req(
|
||||
{
|
||||
method: 'get',
|
||||
url: '/user/logOut',
|
||||
params: {
|
||||
userName: loginId
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
break
|
||||
default:
|
||||
message.info('敬请期待')
|
||||
break
|
||||
},
|
||||
'/auth'
|
||||
).then(res => {
|
||||
if (res.success) {
|
||||
localStorage.removeItem('userInfo')
|
||||
message.info('退出成功')
|
||||
setTimeout(() => {
|
||||
navigate('/login')
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
navigate(e.item.props.path)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +132,7 @@ const Header = () => {
|
||||
<div className='head-navigator-user-box'>
|
||||
<Dropdown
|
||||
placement='bottom'
|
||||
trigger={['click']}
|
||||
// trigger={['click']}
|
||||
destroyPopupOnHide
|
||||
dropdownRender={() => {
|
||||
return (
|
||||
@@ -174,7 +172,7 @@ const Header = () => {
|
||||
)
|
||||
}}
|
||||
>
|
||||
<Button type='link'>发现精彩</Button>
|
||||
<Button type='link'>升职加薪必看</Button>
|
||||
</Dropdown>
|
||||
{'/question-bank' == pathname && (
|
||||
<div className='head-navigator-input-box'>
|
||||
@@ -189,22 +187,29 @@ const Header = () => {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className='head-navigator-user-img'>
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: menuItems,
|
||||
onClick: handleMenuClick
|
||||
}}
|
||||
placement='bottom'
|
||||
trigger={['click']}
|
||||
destroyPopupOnHide
|
||||
overlayStyle={{
|
||||
width: '150px'
|
||||
}}
|
||||
>
|
||||
<img src={Head} style={{ width: 36, height: 36 }} />
|
||||
</Dropdown>
|
||||
</div>
|
||||
{'/login' !== pathname && (
|
||||
<div className='head-navigator-user-img'>
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: menuItems,
|
||||
onClick: handleMenuClick
|
||||
}}
|
||||
placement='bottom'
|
||||
trigger={['click']}
|
||||
destroyPopupOnHide
|
||||
overlayStyle={{
|
||||
width: '150px'
|
||||
}}
|
||||
>
|
||||
{userInfo.avatar ? (
|
||||
<img src={userInfo.avatar} style={{ width: 36, height: 36 }} />
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
{/* <img src={userInfo.avatar || Head} style={{ width: 36, height: 36 }} /> */}
|
||||
</Dropdown>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,7 +1,9 @@
|
||||
import { saveUserInfo } from '@features/userInfoSlice.ts'
|
||||
import LoginQrcode from '@imgs/login_qrcode.jpg'
|
||||
import req from '@utils/request'
|
||||
import { Button, Input, Space, message } from 'antd'
|
||||
import { useState } from 'react'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
import './index.less'
|
||||
@@ -11,13 +13,30 @@ const loginApiName = '/user/doLogin'
|
||||
const Login = () => {
|
||||
const [validCode, setValidCode] = useState('')
|
||||
const navigate = useNavigate()
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const changeCode = e => {
|
||||
setValidCode(e.target.value)
|
||||
}
|
||||
|
||||
const getUserInfo = async loginId => {
|
||||
req(
|
||||
{
|
||||
method: 'post',
|
||||
url: '/user/getUserInfo',
|
||||
data: {
|
||||
userName: loginId
|
||||
}
|
||||
},
|
||||
'/auth'
|
||||
).then(res => {
|
||||
if (res?.success && res?.data) {
|
||||
dispatch(saveUserInfo(res.data))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const doLogin = () => {
|
||||
console.log(validCode)
|
||||
if (!validCode) return
|
||||
req(
|
||||
{
|
||||
@@ -26,13 +45,14 @@ const Login = () => {
|
||||
params: { validCode }
|
||||
},
|
||||
'/auth'
|
||||
).then(res => {
|
||||
).then(async res => {
|
||||
if (res.success && res.data) {
|
||||
message.success('登录成功')
|
||||
localStorage.setItem('userInfo', JSON.stringify(res.data))
|
||||
await getUserInfo(res.data.loginId)
|
||||
setTimeout(() => {
|
||||
navigate('/question-bank')
|
||||
}, 1000)
|
||||
}, 500)
|
||||
} else {
|
||||
message.error('登录失败,请重试')
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { Card, Pagination, Spin } from 'antd'
|
||||
import React, { Component } from 'react'
|
||||
import { collectTabType } from '../../constant'
|
||||
import CollectionQuestion from '../collection-question'
|
||||
import EmptyBox from '../empty-box'
|
||||
import QuestionList from '../question-list'
|
||||
import './index.less'
|
||||
const tabList = [
|
||||
{
|
||||
@@ -21,7 +21,7 @@ export default class CollectionBag extends Component {
|
||||
this.state = {
|
||||
currentKey: collectTabType.testQuestions, // 选中的tab 默认选中第一个
|
||||
collectionList: [],
|
||||
isShowSpin: true,
|
||||
isShowSpin: false,
|
||||
isShowSkeleton: true
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,25 @@ export default class CollectionBag extends Component {
|
||||
/**
|
||||
* 获取一级分类数据
|
||||
*/
|
||||
getCollectionList() {}
|
||||
getCollectionList() {
|
||||
this.total = 3
|
||||
this.setState({
|
||||
collectionList: [
|
||||
{
|
||||
id: 100,
|
||||
subjectName: 'Redis支持哪几种数据类型?'
|
||||
},
|
||||
{
|
||||
id: 101,
|
||||
subjectName: 'Redis的高级数据类型有什么?'
|
||||
},
|
||||
{
|
||||
id: 102,
|
||||
subjectName: 'Redis的优点有什么?'
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页
|
||||
@@ -109,7 +127,7 @@ export default class CollectionBag extends Component {
|
||||
case collectTabType.testQuestions:
|
||||
return (
|
||||
<div>
|
||||
<CollectionQuestion collectionList={collectionList} collectionTotal={this.total} />
|
||||
<QuestionList list={collectionList} total={this.total} name='收藏' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@@ -1,103 +0,0 @@
|
||||
import { SnippetsTwoTone } from '@ant-design/icons'
|
||||
import { debounce, splicingQuery } from '@utils'
|
||||
import React, { Component } from 'react'
|
||||
|
||||
import './index.less'
|
||||
|
||||
class CollectionQuestion extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
isModalVisible: false //对话框默认不可见
|
||||
}
|
||||
}
|
||||
|
||||
handleCancelCollection = () => {
|
||||
console.log('取消收藏')
|
||||
this.setState({
|
||||
isModalVisible: true
|
||||
})
|
||||
}
|
||||
|
||||
handleCancel = () => {
|
||||
// console.log('点了取消');
|
||||
this.setState({
|
||||
isModalVisible: false
|
||||
})
|
||||
}
|
||||
|
||||
handleOk = () => {
|
||||
console.log('点了确认')
|
||||
this.setState({
|
||||
isModalVisible: false
|
||||
})
|
||||
}
|
||||
handleJump = id =>
|
||||
debounce(() => {
|
||||
this.props.history.push(
|
||||
splicingQuery('good-collection-question', {
|
||||
subjectType: 4,
|
||||
subjectId: id
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
render() {
|
||||
const { collectionList, collectionTotal } = this.props
|
||||
const { isModalVisible } = this.state
|
||||
return (
|
||||
<div className='collection-bag-component-tab1-body'>
|
||||
<div className='collection-bag-component-tab1-head-title'>
|
||||
<div className='collection-bag-component-tab1-head-title-icon'>
|
||||
<SnippetsTwoTone twoToneColor='#FF0000' />
|
||||
</div>
|
||||
<div>收藏的题目({collectionTotal})</div>
|
||||
</div>
|
||||
{collectionList.map(item => {
|
||||
return (
|
||||
<div
|
||||
className='collection-bag-component-tab1-body-item'
|
||||
key={`collection_question_${item.id}`}
|
||||
>
|
||||
<div className='collection-bag-component-tab1-body-item-question'>
|
||||
<span
|
||||
className='collection-bag-component-tab1-body-item-question-content'
|
||||
onClick={this.handleJump(item.id)}
|
||||
>
|
||||
{item.subjectName}
|
||||
</span>
|
||||
</div>
|
||||
{/* <div className="collection-bag-component-tab1-body-item-foot">
|
||||
<span
|
||||
className="collection-bag-component-tab1-body-item-foot-button"
|
||||
onClick={this.handleCancelCollection}
|
||||
>
|
||||
取消收藏
|
||||
</span>
|
||||
<Modal
|
||||
title="提示"
|
||||
visible={isModalVisible}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
onOk={this.handleOk}
|
||||
onCancel={this.handleCancel}
|
||||
>
|
||||
<p
|
||||
style={{
|
||||
fontSize: '17px',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
确认取消收藏吗?
|
||||
</p>
|
||||
</Modal>
|
||||
</div> */}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default CollectionQuestion
|
@@ -3,7 +3,7 @@ import './index.less'
|
||||
export default function EmptyBox() {
|
||||
return (
|
||||
<div className='empty-box'>
|
||||
<img className='empty-inco' />
|
||||
{/* <img className='empty-inco' /> */}
|
||||
<span className='empty-text'>这里什么也没有哦~</span>
|
||||
</div>
|
||||
)
|
||||
|
@@ -2,7 +2,7 @@ import { Card, Pagination, Spin } from 'antd'
|
||||
import React, { Component } from 'react'
|
||||
import { goodTabType } from '../../constant'
|
||||
import EmptyBox from '../empty-box'
|
||||
import GoodQuestion from '../good-question'
|
||||
import QuestionList from '../question-list'
|
||||
import './index.less'
|
||||
const tabList = [
|
||||
{
|
||||
@@ -21,7 +21,7 @@ export default class GoodBag extends Component {
|
||||
this.state = {
|
||||
currentKey: goodTabType.testQuestions, // 选中的tab 默认选中第一个
|
||||
goodList: [],
|
||||
isShowSpin: true
|
||||
isShowSpin: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,25 @@ export default class GoodBag extends Component {
|
||||
/**
|
||||
* 获取一级分类数据
|
||||
*/
|
||||
getGoodList() {}
|
||||
getGoodList() {
|
||||
this.total = 3
|
||||
this.setState({
|
||||
goodList: [
|
||||
{
|
||||
id: 100,
|
||||
subjectName: 'Redis支持哪几种数据类型?'
|
||||
},
|
||||
{
|
||||
id: 101,
|
||||
subjectName: 'Redis的高级数据类型有什么?'
|
||||
},
|
||||
{
|
||||
id: 102,
|
||||
subjectName: 'Redis的优点有什么?'
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页
|
||||
@@ -106,7 +124,7 @@ export default class GoodBag extends Component {
|
||||
switch (type) {
|
||||
// 收藏的试题
|
||||
case goodTabType.testQuestions:
|
||||
return <GoodQuestion goodList={goodList} goodTotal={this.total} />
|
||||
return <QuestionList list={goodList} total={this.total} name='点赞' />
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,97 +0,0 @@
|
||||
import { SnippetsTwoTone } from '@ant-design/icons'
|
||||
import { debounce, splicingQuery } from '@utils'
|
||||
import React, { Component } from 'react'
|
||||
|
||||
import './index.less'
|
||||
|
||||
class GoodQuestion extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
isModalVisible: false //对话框默认不可见
|
||||
}
|
||||
}
|
||||
|
||||
handleCancelGood = () => {
|
||||
console.log('取消点赞')
|
||||
this.setState({
|
||||
isModalVisible: true
|
||||
})
|
||||
}
|
||||
|
||||
handleCancel = () => {
|
||||
// console.log('点了取消');
|
||||
this.setState({
|
||||
isModalVisible: false
|
||||
})
|
||||
}
|
||||
|
||||
handleOk = () => {
|
||||
console.log('点了确认')
|
||||
this.setState({
|
||||
isModalVisible: false
|
||||
})
|
||||
}
|
||||
handleJump = id =>
|
||||
debounce(() => {
|
||||
this.props.history.push(
|
||||
splicingQuery('good-collection-question', {
|
||||
subjectType: 4,
|
||||
subjectId: id
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
render() {
|
||||
const { goodList, goodTotal } = this.props
|
||||
const { isModalVisible } = this.state
|
||||
return (
|
||||
<div className='good-bag-component-tab1-body'>
|
||||
<div className='good-bag-component-tab1-head-title'>
|
||||
<div className='good-bag-component-tab1-head-title-icon'>
|
||||
<SnippetsTwoTone twoToneColor='#FF0000' />
|
||||
</div>
|
||||
<div>点赞的题目({goodTotal})</div>
|
||||
</div>
|
||||
{goodList.map(item => {
|
||||
return (
|
||||
<div className='good-bag-component-tab1-body-item' key={`good_question_${item.id}`}>
|
||||
<div className='good-bag-component-tab1-body-item-question'>
|
||||
<span
|
||||
className='good-bag-component-tab1-body-item-question-content'
|
||||
onClick={this.handleJump(item.id)}
|
||||
>
|
||||
{item.subjectName}
|
||||
</span>
|
||||
</div>
|
||||
{/* <div className="good-bag-component-tab1-body-item-foot">
|
||||
<span className="good-bag-component-tab1-body-item-foot-button" onClick={this.handleCancelGood}>
|
||||
取消点赞
|
||||
</span>
|
||||
<Modal
|
||||
title="提示"
|
||||
visible={isModalVisible}
|
||||
cancelText="取消"
|
||||
okText="确认"
|
||||
onOk={this.handleOk}
|
||||
onCancel={this.handleCancel}
|
||||
>
|
||||
<p
|
||||
style={{
|
||||
fontSize: '17px',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
确认取消点赞吗?
|
||||
</p>
|
||||
</Modal>
|
||||
</div> */}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default GoodQuestion
|
@@ -1,44 +0,0 @@
|
||||
.good-bag-component-tab1-body {
|
||||
padding: 0 20px 20px 20px;
|
||||
.good-bag-component-tab1-head-title {
|
||||
display: flex;
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
.good-bag-component-tab1-head-title-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
.good-bag-component-tab1-body-item {
|
||||
margin: 10px 0;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
clear: both;
|
||||
// height: 60px;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
|
||||
.good-bag-component-tab1-body-item-question {
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
.good-bag-component-tab1-body-item-question-content {
|
||||
width: 600px;
|
||||
cursor: pointer;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
overflow: hidden;
|
||||
&:hover {
|
||||
color: #3c6eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
.good-bag-component-tab1-body-item-foot {
|
||||
margin-top: 10px;
|
||||
float: right;
|
||||
.good-bag-component-tab1-body-item-foot-button {
|
||||
cursor: pointer;
|
||||
color: #3c6eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
src/views/personal-center/components/question-list/index.jsx
Normal file
44
src/views/personal-center/components/question-list/index.jsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { SnippetsTwoTone } from '@ant-design/icons'
|
||||
import React from 'react'
|
||||
|
||||
import './index.less'
|
||||
|
||||
const CollectionQuestion = props => {
|
||||
const { total, list, name } = props
|
||||
|
||||
const handleJump = id => {
|
||||
window.open('/brush-question/' + id)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='collection-bag-component-tab1-body'>
|
||||
<div className='collection-bag-component-tab1-head-title'>
|
||||
<div className='collection-bag-component-tab1-head-title-icon'>
|
||||
<SnippetsTwoTone twoToneColor='#FF0000' />
|
||||
</div>
|
||||
<div>
|
||||
{name}的题目({total})
|
||||
</div>
|
||||
</div>
|
||||
{list.map(item => {
|
||||
return (
|
||||
<div
|
||||
className='collection-bag-component-tab1-body-item'
|
||||
key={`collection_question_${item.id}`}
|
||||
>
|
||||
<div className='collection-bag-component-tab1-body-item-question'>
|
||||
<span
|
||||
className='collection-bag-component-tab1-body-item-question-content'
|
||||
onClick={() => handleJump(item.id)}
|
||||
>
|
||||
{item.subjectName}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CollectionQuestion
|
@@ -11,9 +11,10 @@
|
||||
}
|
||||
.collection-bag-component-tab1-body-item {
|
||||
margin: 10px 0;
|
||||
padding: 10px 0;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
clear: both;
|
||||
// clear: both;
|
||||
// height: 60px;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
|
@@ -1,135 +1,97 @@
|
||||
import { IdcardOutlined, LikeTwoTone, MailOutlined, StarTwoTone } from '@ant-design/icons'
|
||||
import { LikeTwoTone, StarTwoTone } from '@ant-design/icons'
|
||||
import { Menu } from 'antd'
|
||||
import PubSub from 'pubsub-js'
|
||||
import React, { Component } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import CollectionBag from './components/collection-bag'
|
||||
import GoodBag from './components/good-bag'
|
||||
import './index.less'
|
||||
|
||||
export default class PersonalCenter extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
currentKeyMap: 0, //选中的menu
|
||||
userName: '', //姓名
|
||||
intervieweEamil: '', //邮箱
|
||||
headImg: '', //头像
|
||||
department: '', //部门
|
||||
practiceAmount: 0, //练题数
|
||||
inputAmount: 0, //录题数
|
||||
goodAmount: 0, //点赞数
|
||||
collectionAmount: 0, //收藏数
|
||||
subMenuList: []
|
||||
}
|
||||
const personList = {
|
||||
0: '收藏',
|
||||
1: '点赞'
|
||||
}
|
||||
|
||||
const PersonalCenter = props => {
|
||||
const [currentKeyMap, setCurrentKeyMap] = useState(0)
|
||||
const { userInfo } = useSelector(store => store.userInfo)
|
||||
const [selectedKeys, setSelectedKeys] = useState('0')
|
||||
|
||||
const { tab } = useParams()
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentKeyMap(+tab)
|
||||
setSelectedKeys(tab)
|
||||
}, [tab])
|
||||
|
||||
const handleClick = ({ key }) => {
|
||||
setCurrentKeyMap(Number(key))
|
||||
setSelectedKeys(key)
|
||||
}
|
||||
personList = {
|
||||
// 0: '刷题',
|
||||
0: '收藏',
|
||||
1: '点赞'
|
||||
}
|
||||
componentDidMount() {
|
||||
PubSub.subscribe('handleToRender', () => {
|
||||
this.setState({})
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 切换菜单
|
||||
* @param {*} e
|
||||
*/
|
||||
handleClick = e => {
|
||||
console.log('--------', e)
|
||||
//截取_后的字符
|
||||
let index = e.keyPath[0].lastIndexOf('_')
|
||||
let index2 = e.keyPath[0].substring(index + 1, e.keyPath[0].length)
|
||||
//
|
||||
console.log('index2>>>>', index2)
|
||||
this.setState({
|
||||
currentKeyMap: Number(index2)
|
||||
})
|
||||
}
|
||||
render() {
|
||||
let {
|
||||
headImg,
|
||||
userName,
|
||||
intervieweEamil,
|
||||
department,
|
||||
goodAmount,
|
||||
collectionAmount,
|
||||
practiceAmount,
|
||||
inputAmount
|
||||
} = this.state
|
||||
const { currentKeyMap } = this.state
|
||||
return (
|
||||
<div className='personal-center-box'>
|
||||
<div className='personal-center-introduction'>
|
||||
<div className='personal-center-introduction-detail'>
|
||||
<div className='personal-center-introduction-detail-headImg'>
|
||||
<img src={headImg} style={{ width: 60, height: 60, borderRadius: '50%' }} />
|
||||
</div>
|
||||
<div className='personal-center-introduction-detail-text'>
|
||||
<div className='personal-center-introduction-detail-name'>{userName}</div>
|
||||
<div className='personal-center-introduction-detail-information'>
|
||||
<span className='personal-center-introduction-detail-information-content'>
|
||||
<IdcardOutlined style={{ color: 'blue', marginRight: '3px' }} />
|
||||
</span>
|
||||
<span className='personal-center-introduction-detail-information-content'>
|
||||
<MailOutlined style={{ color: 'blue', marginRight: '3px' }} />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
return (
|
||||
<div className='personal-center-box'>
|
||||
<div className='personal-center-introduction'>
|
||||
<div className='personal-center-introduction-detail'>
|
||||
<div className='personal-center-introduction-detail-headImg'>
|
||||
<img src={userInfo.avatar} style={{ width: 60, height: 60, borderRadius: '50%' }} />
|
||||
</div>
|
||||
<div className='personal-center-introduction-result'>
|
||||
<div className='personal-center-introduction-result-item'>
|
||||
<div className='personal-center-introduction-result-item-number'>
|
||||
{practiceAmount}
|
||||
</div>
|
||||
<div>练题</div>
|
||||
</div>
|
||||
<div className='personal-center-introduction-result-item'>
|
||||
<div className='personal-center-introduction-result-item-number'>{inputAmount}</div>
|
||||
<div>录题</div>
|
||||
</div>
|
||||
<div className='personal-center-introduction-result-item'>
|
||||
<div className='personal-center-introduction-result-item-number'>{goodAmount}</div>
|
||||
<div>点赞</div>
|
||||
</div>
|
||||
<div className='personal-center-introduction-result-item'>
|
||||
<div className='personal-center-introduction-result-item-number'>
|
||||
{collectionAmount}
|
||||
</div>
|
||||
<div>收藏</div>
|
||||
</div>
|
||||
<div className='personal-center-introduction-detail-text'>
|
||||
<div className='personal-center-introduction-detail-name'>{userInfo.nickName}</div>
|
||||
{/* <div className='personal-center-introduction-detail-information'>
|
||||
<span className='personal-center-introduction-detail-information-content'>
|
||||
<IdcardOutlined style={{ color: 'blue', marginRight: '3px' }} />
|
||||
</span>
|
||||
<span className='personal-center-introduction-detail-information-content'>
|
||||
<MailOutlined style={{ color: 'blue', marginRight: '3px' }} />
|
||||
</span>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
<div className='personal-center-content'>
|
||||
<div className='personal-center-content-left'>
|
||||
<Menu
|
||||
mode='inline'
|
||||
onClick={this.handleClick}
|
||||
style={{ width: 256 }}
|
||||
defaultSelectedKeys={['personList_0']}
|
||||
>
|
||||
{/* <Menu.Item key={`personList_0`}>
|
||||
<MailOutlined style={{ color: 'rgb(171,214,97)' }} />
|
||||
<span>{this.personList[0]}</span>
|
||||
</Menu.Item> */}
|
||||
<Menu.Item key={`personList_0`}>
|
||||
<StarTwoTone twoToneColor='rgb(252,132,67)' />
|
||||
<span>{this.personList[0]}</span>
|
||||
</Menu.Item>
|
||||
<Menu.Item key={`personList_1`}>
|
||||
<LikeTwoTone twoToneColor='#99bbff' />
|
||||
<span>{this.personList[1]}</span>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
<div className='personal-center-introduction-result'>
|
||||
{/* <div className='personal-center-introduction-result-item'>
|
||||
<div className='personal-center-introduction-result-item-number'>{10}</div>
|
||||
<div>练题</div>
|
||||
</div> */}
|
||||
{/* <div className='personal-center-introduction-result-item'>
|
||||
<div className='personal-center-introduction-result-item-number'>{inputAmount}</div>
|
||||
<div>录题</div>
|
||||
</div> */}
|
||||
<div className='personal-center-introduction-result-item'>
|
||||
<div className='personal-center-introduction-result-item-number'>{20}</div>
|
||||
<div>点赞</div>
|
||||
</div>
|
||||
<div className='personal-center-content-right'>
|
||||
{/* {currentKeyMap === 0 && <BrushQuestion />} */}
|
||||
{currentKeyMap === 0 && <CollectionBag />}
|
||||
{currentKeyMap === 1 && <GoodBag />}
|
||||
<div className='personal-center-introduction-result-item'>
|
||||
<div className='personal-center-introduction-result-item-number'>{30}</div>
|
||||
<div>收藏</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div className='personal-center-content'>
|
||||
<div className='personal-center-content-left'>
|
||||
<Menu
|
||||
mode='inline'
|
||||
onClick={handleClick}
|
||||
style={{ width: 256 }}
|
||||
selectedKeys={[selectedKeys]}
|
||||
>
|
||||
<Menu.Item key={0}>
|
||||
<StarTwoTone twoToneColor='rgb(252,132,67)' />
|
||||
<span>{personList[0]}</span>
|
||||
</Menu.Item>
|
||||
<Menu.Item key={1}>
|
||||
<LikeTwoTone twoToneColor='#99bbff' />
|
||||
<span>{personList[1]}</span>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</div>
|
||||
<div className='personal-center-content-right'>
|
||||
{currentKeyMap === 0 && <CollectionBag />}
|
||||
{currentKeyMap === 1 && <GoodBag />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PersonalCenter
|
||||
|
@@ -1,7 +1,6 @@
|
||||
.personal-center-box {
|
||||
margin: 0 auto;
|
||||
width: 1439px;
|
||||
// padding: 20px 50px;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
.personal-center-introduction {
|
||||
@@ -11,10 +10,12 @@
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.personal-center-introduction-detail {
|
||||
margin-left: 50px;
|
||||
padding-top: 20px;
|
||||
// padding-top: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.personal-center-introduction-detail-headImg {
|
||||
margin-right: 20px;
|
||||
align-items: center;
|
||||
@@ -34,8 +35,8 @@
|
||||
}
|
||||
.personal-center-introduction-result {
|
||||
margin-right: 50px;
|
||||
padding-top: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.personal-center-introduction-result-item {
|
||||
text-align: center;
|
||||
padding-right: 10px;
|
||||
@@ -54,7 +55,7 @@
|
||||
overflow-y: auto;
|
||||
border-radius: 3px;
|
||||
width: 300px;
|
||||
height: 720px;
|
||||
min-height: 320px;
|
||||
}
|
||||
.personal-center-content-right {
|
||||
background-color: #fff;
|
||||
|
@@ -0,0 +1,216 @@
|
||||
import req from '@utils/request'
|
||||
import { Spin } from 'antd'
|
||||
import React, { Component } from 'react'
|
||||
import { ApiName, IdKeyLetterKey } from '../../constant'
|
||||
import './index.less'
|
||||
|
||||
export default class AnswerAnalysis extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
subjectList: [], // 题目列表
|
||||
subjectName: '',
|
||||
optionList: [], // 选项列表
|
||||
labelNames: '', // 标签列表
|
||||
respondAnswer: [], // 你的答案
|
||||
subjectParse: '', // 解析
|
||||
correctAnswer: [], // 正确答案
|
||||
currentIndex: 0, // 当前选中的下标
|
||||
isLoading: false
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getScoreDetail()
|
||||
}
|
||||
|
||||
/**
|
||||
* 答案解析-获得题目列表
|
||||
*/
|
||||
getScoreDetail = () => {
|
||||
const { practiceId } = this.props
|
||||
let params = {
|
||||
practiceId: practiceId
|
||||
}
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: ApiName.getScoreDetail
|
||||
})
|
||||
.then(res => {
|
||||
if (res?.data && res?.data?.length > 0) {
|
||||
this.setState(
|
||||
{
|
||||
subjectList: res.data
|
||||
},
|
||||
() => {
|
||||
this.getSubjectDetail(0, res.data[0])
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
.catch(err => console.log(err))
|
||||
}
|
||||
|
||||
/**
|
||||
* 答案解析-获得答案详情
|
||||
* @param {*} index 当前index
|
||||
* @param {*} subjectItem 当前item
|
||||
*/
|
||||
getSubjectDetail = (index, subjectItem) => {
|
||||
const { practiceId } = this.props
|
||||
let params = {
|
||||
practiceId: practiceId,
|
||||
subjectId: subjectItem.subjectId,
|
||||
subjectType: subjectItem.subjectType
|
||||
}
|
||||
JDreq({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: ApiName.getSubjectDetail
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data) {
|
||||
let respondAnswer = res.data.respondAnswer
|
||||
let optionList = []
|
||||
res.data.optionList.forEach(element => {
|
||||
let obj = {
|
||||
isCorrect: element.isCorrect,
|
||||
optionContent: element.optionContent,
|
||||
optionType: element.optionType,
|
||||
isAnswer: 0
|
||||
}
|
||||
if (respondAnswer.includes(element.optionType)) {
|
||||
obj.isAnswer = 1
|
||||
}
|
||||
optionList.push(obj)
|
||||
})
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
currentIndex: index,
|
||||
subjectName: res.data.subjectName,
|
||||
optionList: optionList, // 选项列表
|
||||
labelNames: res.data.labelNames, // 标签列表
|
||||
respondAnswer: respondAnswer, // 你的答案
|
||||
subjectParse: res.data.subjectParse, // 解析
|
||||
correctAnswer: res.data.correctAnswer // 正确答案
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(err => console.log(err))
|
||||
}
|
||||
|
||||
onChangeOption = (index, item) => () => {
|
||||
let { currentIndex } = this.state
|
||||
if (index === currentIndex) {
|
||||
return
|
||||
}
|
||||
this.getSubjectDetail(index, item)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
subjectList,
|
||||
subjectName,
|
||||
optionList,
|
||||
labelNames,
|
||||
respondAnswer,
|
||||
subjectParse,
|
||||
correctAnswer,
|
||||
currentIndex,
|
||||
isLoading
|
||||
} = this.state
|
||||
const isRight = correctAnswer.join('') !== respondAnswer.join('')
|
||||
return (
|
||||
<Spin spinning={isLoading}>
|
||||
<div className='answer-analysis-box'>
|
||||
{subjectList?.length > 0 && (
|
||||
<div className='answer-analysis-paging'>
|
||||
<div className='answer-analysis-paging-tip'>每题得分</div>
|
||||
<div className='answer-analysis-paging-list'>
|
||||
{subjectList.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
className={`answer-analysis-paging-item ${
|
||||
item.isCorrect === 1 ? 'answer-analysis-rigth' : 'answer-analysis-error'
|
||||
} ${currentIndex == index ? 'answer-analysis-paging-item-active' : ''}`}
|
||||
onClick={this.onChangeOption(index, item)}
|
||||
key={`${item.subjectId}_${index}`}
|
||||
>
|
||||
{index + 1}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className='answer-analysis-name'>
|
||||
<div className='answer-analysis-name-num'>{currentIndex + 1}</div>
|
||||
<div className='answer-analysis-name-text'>{subjectName}</div>
|
||||
</div>
|
||||
<div className='answer-analysis-answer'>
|
||||
正确答案:
|
||||
{correctAnswer?.length > 0
|
||||
? correctAnswer.map((item, index) => {
|
||||
return <span key={`correct_answer_${index}`}>{IdKeyLetterKey[item] + ' '}</span>
|
||||
})
|
||||
: '空'}
|
||||
你的答案:
|
||||
{respondAnswer?.length > 0
|
||||
? respondAnswer.map((item, index) => {
|
||||
return <span key={`respond_answer_${index}`}>{IdKeyLetterKey[item] + ' '}</span>
|
||||
})
|
||||
: '空'}
|
||||
<span style={isRight ? { color: '#ff431e' } : { color: 'rgba(60, 110, 238, 1)' }}>
|
||||
({isRight ? '错误' : '正确'})
|
||||
</span>
|
||||
</div>
|
||||
{optionList?.length > 0 && (
|
||||
<div className='answer-analysis-option-list'>
|
||||
{optionList.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
key={`option_${index}`}
|
||||
className={`answer-analysis-option-item ${
|
||||
item.isCorrect === 1
|
||||
? 'answer-analysis-option-item-rigth'
|
||||
: item.isAnswer === 1
|
||||
? 'answer-analysis-option-item-error'
|
||||
: ''
|
||||
}`}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item.optionContent
|
||||
}}
|
||||
></div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{labelNames?.length > 0 && (
|
||||
<div className='answer-analysis-points'>
|
||||
<div className='answer-analysis-points-tip'>本题知识点</div>
|
||||
<div className='answer-analysis-points-list'>
|
||||
{labelNames.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
key={`answer_analysis_points_${index}`}
|
||||
className='answer-analysis-points-item'
|
||||
>
|
||||
{item}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!!subjectParse && (
|
||||
<div className='answer-analysis-parse'>
|
||||
<div className='answer-analysis-parse-tip'>参考解析</div>
|
||||
<div className='answer-analysis-parse-text'>{subjectParse}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,146 @@
|
||||
.answer-analysis-box {
|
||||
padding-bottom: 30px;
|
||||
// 分页
|
||||
.answer-analysis-paging {
|
||||
padding: 20px 30px;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ededed;
|
||||
.answer-analysis-paging-tip {
|
||||
margin-bottom: 20px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
.answer-analysis-paging-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.answer-analysis-paging-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 4px;
|
||||
margin-bottom: 20px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
margin-top: -6px;
|
||||
margin-bottom: -6px;
|
||||
height: 44px;
|
||||
}
|
||||
}
|
||||
// 选中
|
||||
.answer-analysis-paging-item-active {
|
||||
margin-top: -6px;
|
||||
margin-bottom: -6px;
|
||||
height: 44px;
|
||||
}
|
||||
// 答错
|
||||
.answer-analysis-error {
|
||||
background-color: #ff431e;
|
||||
}
|
||||
// 答对
|
||||
.answer-analysis-rigth {
|
||||
background-color: rgba(60, 110, 238, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 题名
|
||||
.answer-analysis-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20px 30px;
|
||||
font-size: 14px;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ededed;
|
||||
.answer-analysis-name-num {
|
||||
padding: 5px 7px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-width: 30px;
|
||||
color: #fff;
|
||||
font-weight: 400;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(60, 110, 238, 1);
|
||||
}
|
||||
.answer-analysis-name-text {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
// 答案
|
||||
.answer-analysis-answer {
|
||||
padding: 20px 30px;
|
||||
}
|
||||
// 选项
|
||||
.answer-analysis-option-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 30px;
|
||||
.answer-analysis-option-item {
|
||||
padding: 10px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #d4d4d4;
|
||||
background: #fff;
|
||||
}
|
||||
// 正确
|
||||
.answer-analysis-option-item-rigth {
|
||||
border-color: rgba(60, 110, 238, 1);
|
||||
}
|
||||
// 错误
|
||||
.answer-analysis-option-item-error {
|
||||
border-color: #ff431e;
|
||||
}
|
||||
}
|
||||
// 知识点
|
||||
.answer-analysis-points {
|
||||
padding: 0 30px 20px;
|
||||
font-size: 14px;
|
||||
background-color: rgba(60, 110, 238, 0.08);
|
||||
.answer-analysis-points-tip {
|
||||
margin-bottom: 20px;
|
||||
padding-top: 20px;
|
||||
color: rgb(102, 102, 102);
|
||||
}
|
||||
.answer-analysis-points-list {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
.answer-analysis-points-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 4px;
|
||||
padding: 0 8px;
|
||||
height: 22px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 12px;
|
||||
&:hover {
|
||||
color: rgba(60, 110, 238, 1);
|
||||
border-color: rgba(60, 110, 238, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 解析
|
||||
.answer-analysis-parse {
|
||||
padding: 0 30px 20px;
|
||||
font-size: 14px;
|
||||
background-color: #fff;
|
||||
.answer-analysis-parse-tip {
|
||||
margin-bottom: 20px;
|
||||
padding-top: 20px;
|
||||
color: rgb(102, 102, 102);
|
||||
}
|
||||
.answer-analysis-parse-text {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,148 @@
|
||||
import req from '@utils/request'
|
||||
|
||||
import AnalysisAtlas from '@components/analysis-atlas'
|
||||
import { splicingQuery } from '@utils'
|
||||
import { Button, Spin } from 'antd'
|
||||
import React, { Component } from 'react'
|
||||
import { ApiName, ModuleName } from '../../constant'
|
||||
import RecommendList from '../recommend-list'
|
||||
import './index.less'
|
||||
|
||||
class AssessmentReport extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
correctSubject: '3',
|
||||
recommendSetList: [],
|
||||
skill: [],
|
||||
title: '测试试卷',
|
||||
isLoading: false
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getReport()
|
||||
}
|
||||
|
||||
/**
|
||||
* 答案解析-获得评估报告
|
||||
*/
|
||||
getReport = async () => {
|
||||
const { practiceId } = this.props
|
||||
let params = {
|
||||
practiceId: practiceId
|
||||
}
|
||||
await req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: ApiName.getReport
|
||||
})
|
||||
.then(res => {
|
||||
if (res?.data) {
|
||||
let list = res.data.skill || []
|
||||
let len = res.data.skill.length
|
||||
if (len === 1) {
|
||||
let l1 = [
|
||||
{ name: res.data.skill[0].name + ' ', star: res.data.skill[0].star },
|
||||
{
|
||||
name: ' ' + res.data.skill[0].name + ' ',
|
||||
star: res.data.skill[0].star
|
||||
}
|
||||
]
|
||||
list = list.concat(l1)
|
||||
} else if (len === 2) {
|
||||
let l1 = [{ name: res.data.skill[1].name + ' ', star: res.data.skill[1].star }]
|
||||
list = list.concat(l1)
|
||||
}
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
title: res.data.title,
|
||||
correctSubject: res.data.correctSubject,
|
||||
recommendSetList: res.data.recommendSetList,
|
||||
skill: list
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(err => console.log(err))
|
||||
}
|
||||
|
||||
/**
|
||||
* 练习其他技能
|
||||
*/
|
||||
onChangePracticeOther = () => {
|
||||
this.props.history.push('/practice-questions')
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看答案解析
|
||||
*/
|
||||
onChangeAnswerAnalysis = () => {
|
||||
this.props.onHandleAnswerAnalysis && this.props.onHandleAnswerAnalysis(ModuleName.analysis)
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击推荐套题
|
||||
* @param {*} setId
|
||||
* @returns
|
||||
*/
|
||||
onChangeSetId = setId => {
|
||||
this.props.history.push(
|
||||
splicingQuery('/practice-details', {
|
||||
setId
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { correctSubject, recommendSetList, skill, title, isLoading } = this.state
|
||||
return (
|
||||
<Spin spinning={isLoading}>
|
||||
<div className='assessment-report-box'>
|
||||
<div className='assessment-report-top'>
|
||||
<div className='assessment-report-main'>
|
||||
{/* <div className="assessment-report-defen">
|
||||
<img src={ImgObj.defen} className="assessment-report-defen-icon" />
|
||||
得分:12
|
||||
</div> */}
|
||||
<div className='assessment-report-item'>试卷:{title}</div>
|
||||
<div className='assessment-report-item'>正确题数:{correctSubject}</div>
|
||||
<Button
|
||||
className='assessment-report-submit'
|
||||
type='primary'
|
||||
onClick={this.onChangePracticeOther}
|
||||
>
|
||||
练习其他技能
|
||||
</Button>
|
||||
</div>
|
||||
<div className='assessment-report-tupu'>
|
||||
<div className='assessment-report-tupu-tip'>你的技能图谱</div>
|
||||
<div className='assessment-report-tupu-content'>
|
||||
<AnalysisAtlas
|
||||
aliasStr='正确率'
|
||||
atlasList={skill || []}
|
||||
atlasMin={-25}
|
||||
atlasWidth={200}
|
||||
atlasHeight={200}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{recommendSetList?.length > 0 && (
|
||||
<RecommendList recommendSetList={recommendSetList} onHandleSetId={this.onChangeSetId} />
|
||||
)}
|
||||
<div className='assessment-report-answer-analysis'>
|
||||
<Button
|
||||
className='assessment-report-answer-btn'
|
||||
type='primary'
|
||||
onClick={this.onChangeAnswerAnalysis}
|
||||
>
|
||||
查看答案解析
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default AssessmentReport
|
@@ -0,0 +1,63 @@
|
||||
.assessment-report-box {
|
||||
.assessment-report-top {
|
||||
display: flex;
|
||||
padding: 30px 24px;
|
||||
background-color: #fff;
|
||||
.assessment-report-main {
|
||||
flex: 1;
|
||||
padding: 20px 0 20px 16px;
|
||||
// // 得分
|
||||
// .assessment-report-defen {
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// margin-bottom: 20px;
|
||||
// color: #888;
|
||||
// .assessment-report-defen-icon {
|
||||
// margin-right: 4px;
|
||||
// width: 28px;
|
||||
// height: 28px;
|
||||
// }
|
||||
// }
|
||||
.assessment-report-item {
|
||||
margin-bottom: 20px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
// 再练一套
|
||||
.assessment-report-submit {
|
||||
height: 40px;
|
||||
border-color: rgba(60, 110, 238, 1);
|
||||
background-color: rgba(60, 110, 238, 1);
|
||||
}
|
||||
}
|
||||
// 图谱
|
||||
.assessment-report-tupu {
|
||||
flex: 1;
|
||||
padding: 20px 0 20px 30px;
|
||||
border-left: 1px solid #ddd;
|
||||
.assessment-report-tupu-tip {
|
||||
margin-bottom: 20px;
|
||||
color: #888;
|
||||
font-size: 16px;
|
||||
}
|
||||
.assessment-report-tupu-content {
|
||||
margin: 0 auto;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 查看答案解析
|
||||
.assessment-report-answer-analysis {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 30px 0;
|
||||
.assessment-report-answer-btn {
|
||||
width: 260px;
|
||||
height: 40px;
|
||||
border-color: rgba(60, 110, 238, 1);
|
||||
background-color: rgba(60, 110, 238, 1);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
import { debounce } from '@utils'
|
||||
import React from 'react'
|
||||
import { RecommendBackImg } from '../../constant'
|
||||
import './index.less'
|
||||
|
||||
export default function RecommendList(props) {
|
||||
const { recommendSetList } = props
|
||||
/**
|
||||
* 点击推荐套题
|
||||
* @param {*} setId
|
||||
* @returns
|
||||
*/
|
||||
const onChangeSetId = setId =>
|
||||
debounce(() => {
|
||||
props.onHandleSetId && props.onHandleSetId(setId)
|
||||
})
|
||||
return (
|
||||
<div className='assessment-report-recommend'>
|
||||
<div className='assessment-report-recommend-tip'>根据本次练习,为你推荐以下内容</div>
|
||||
<div className='assessment-report-recommend-list'>
|
||||
{recommendSetList.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
className='recommend-item'
|
||||
key={item.setId}
|
||||
style={{
|
||||
backgroundImage: `url(${RecommendBackImg[index % 4]})`
|
||||
}}
|
||||
onClick={onChangeSetId(item.setId)}
|
||||
>
|
||||
<div className='recommend-item-name'>{item.setName}</div>
|
||||
<div className='recommend-item-heat'>热度指数:{item.setHeat}</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
// 推荐
|
||||
.assessment-report-recommend {
|
||||
margin-top: 30px;
|
||||
padding: 30px 40px;
|
||||
background-color: #fff;
|
||||
.assessment-report-recommend-tip {
|
||||
position: relative;
|
||||
margin-bottom: 30px;
|
||||
margin-left: 16px;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -16px;
|
||||
top: 8px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: rgba(255, 158, 32, 1);
|
||||
}
|
||||
}
|
||||
// 推荐列表
|
||||
.assessment-report-recommend-list {
|
||||
display: flex;
|
||||
.recommend-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-right: 10px;
|
||||
padding: 20px;
|
||||
width: 220px;
|
||||
height: 130px;
|
||||
border-radius: 10px;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
cursor: pointer;
|
||||
transition: all 0.5s;
|
||||
&:hover {
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
.recommend-item-name {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis; //省略
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
.recommend-item-heat {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
53
src/views/practise/practice-analytic/constant.js
Normal file
53
src/views/practise/practice-analytic/constant.js
Normal file
@@ -0,0 +1,53 @@
|
||||
export const ModuleName = {
|
||||
/**
|
||||
* 评估报告
|
||||
*/
|
||||
assessment: 'assessment',
|
||||
/**
|
||||
* 答案解析
|
||||
*/
|
||||
analysis: 'analysis',
|
||||
};
|
||||
|
||||
export const ImgObj = {
|
||||
defen: 'https://img10.360buyimg.com/imagetools/jfs/t1/197806/1/18639/2369/61a095a8E09f4e860/493d753073a4a9fa.png',
|
||||
};
|
||||
|
||||
export const ApiName = {
|
||||
/**
|
||||
* 获得评价
|
||||
*/
|
||||
getReport: '/admin/practice/detail/getReport',
|
||||
/**
|
||||
* 答案详情
|
||||
*/
|
||||
getSubjectDetail: '/admin/practice/detail/getSubjectDetail',
|
||||
/**
|
||||
* 获得题号
|
||||
*/
|
||||
getScoreDetail: 'admin/practice/detail/getScoreDetail',
|
||||
};
|
||||
|
||||
/**
|
||||
* id对应字母
|
||||
*/
|
||||
export const IdKeyLetterKey = {
|
||||
1: 'A',
|
||||
2: 'B',
|
||||
3: 'C',
|
||||
4: 'D',
|
||||
5: 'E',
|
||||
6: 'F',
|
||||
7: 'G',
|
||||
8: 'H',
|
||||
};
|
||||
|
||||
/**
|
||||
* 推荐对应的背景图
|
||||
*/
|
||||
export const RecommendBackImg = {
|
||||
0: 'https://img11.360buyimg.com/imagetools/jfs/t1/202713/11/17151/312/61a5dea1E5623fea6/2922d716cae01b28.png',
|
||||
1: 'https://img10.360buyimg.com/imagetools/jfs/t1/142359/35/22866/2975/61a5dea0E3fcd563c/78ee45555dd19cda.png',
|
||||
2: 'https://img13.360buyimg.com/imagetools/jfs/t1/161380/34/26207/1078/61a5dea0E7824463e/4e18f74e8c6439ad.png',
|
||||
3: 'https://img14.360buyimg.com/imagetools/jfs/t1/160815/15/27226/880/61a5e1e6E152b08b7/fb698b8321d08246.png',
|
||||
};
|
69
src/views/practise/practice-analytic/index.jsx
Normal file
69
src/views/practise/practice-analytic/index.jsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Tabs } from 'antd'
|
||||
import React, { Component } from 'react'
|
||||
import AnswerAnalysis from './components/answer-analysis'
|
||||
import AssessmentReport from './components/assessment-report'
|
||||
import { ModuleName } from './constant'
|
||||
import './index.less'
|
||||
const { TabPane } = Tabs
|
||||
|
||||
const practiceAnalyticTabList = [
|
||||
{ tab: '评估报告', key: ModuleName.assessment },
|
||||
{ tab: '答案解析', key: ModuleName.analysis }
|
||||
]
|
||||
export default class PracticeAnalytic extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = { currentKey: ModuleName.assessment }
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换card tab
|
||||
* @param {*} key
|
||||
*/
|
||||
onTabChange = key => {
|
||||
this.setState({ currentKey: key })
|
||||
}
|
||||
|
||||
render() {
|
||||
const { currentKey } = this.state
|
||||
console.log(this.props)
|
||||
// const urlParams = queryParse(this.props.location.search)
|
||||
// if (!urlParams.practiceId) {
|
||||
// return null
|
||||
// }
|
||||
return (
|
||||
<div className='practice-analytic-box'>
|
||||
<Tabs
|
||||
size='default'
|
||||
type='card'
|
||||
style={{ width: '100%' }}
|
||||
activeKey={currentKey}
|
||||
defaultActiveKey={currentKey}
|
||||
tabBarStyle={{
|
||||
height: '41px',
|
||||
background: '#fff',
|
||||
borderBottom: '1px solid #1890ff',
|
||||
margin: 0
|
||||
}}
|
||||
onChange={key => {
|
||||
this.onTabChange(key, 'key')
|
||||
}}
|
||||
>
|
||||
{practiceAnalyticTabList.map(item => {
|
||||
return <TabPane tab={item.tab} key={item.key}></TabPane>
|
||||
})}
|
||||
</Tabs>
|
||||
{currentKey == ModuleName.assessment ? (
|
||||
<AssessmentReport
|
||||
onHandleAnswerAnalysis={key => {
|
||||
this.onTabChange(key, 'key')
|
||||
}}
|
||||
practiceId={1}
|
||||
/>
|
||||
) : (
|
||||
<AnswerAnalysis practiceId={1} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
20
src/views/practise/practice-analytic/index.less
Normal file
20
src/views/practise/practice-analytic/index.less
Normal file
@@ -0,0 +1,20 @@
|
||||
.practice-analytic-box {
|
||||
margin: 0 auto;
|
||||
width: 1430px;
|
||||
border: 1px solid #e0e0e0;
|
||||
overflow-y: auto;
|
||||
.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab {
|
||||
background-color: #fff;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
}
|
||||
.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab-active {
|
||||
color: #fff;
|
||||
background-color: #1890ff;
|
||||
}
|
||||
// 将body背景重置作为灰色
|
||||
.ant-card-body {
|
||||
background-color: #f3f4f6;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
import { debounce } from '@utils'
|
||||
import { Button } from 'antd'
|
||||
import React, { Fragment } from 'react'
|
||||
import { ImgObj, mark } from '../../constant'
|
||||
import './index.less'
|
||||
|
||||
export default function PracticeAction(props) {
|
||||
const { isLast, isMark } = props
|
||||
|
||||
/**
|
||||
* 标记一下
|
||||
* @returns
|
||||
*/
|
||||
const onChangeMark = debounce(() => {
|
||||
props.onHandleMark && props.onHandleMark()
|
||||
})
|
||||
|
||||
/**
|
||||
* 交卷
|
||||
* @returns
|
||||
*/
|
||||
const onChangeOver = debounce(() => {
|
||||
props.onHandleOver && props.onHandleOver()
|
||||
})
|
||||
|
||||
/**
|
||||
* 提前交卷
|
||||
* @returns
|
||||
*/
|
||||
const onChangeAdvanceOver = debounce(() => {
|
||||
props.onHandleAdvanceOver && props.onHandleAdvanceOver()
|
||||
})
|
||||
|
||||
/**
|
||||
* 下一题
|
||||
* @returns
|
||||
*/
|
||||
const onChangeNext = debounce(() => {
|
||||
props.onHandleNext && props.onHandleNext()
|
||||
})
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className='practice-action-box'>
|
||||
<div className='practice-action-list'>
|
||||
<div className='practice-action-item' onClick={onChangeMark}>
|
||||
<img src={ImgObj.mark} className='action-mark-icon' />
|
||||
{mark[isMark]}
|
||||
</div>
|
||||
</div>
|
||||
<div className='practice-action-list'>
|
||||
<div className='practice-action-button'>
|
||||
{isLast ? (
|
||||
<Button className='action-button-submit' type='primary' onClick={onChangeOver}>
|
||||
交卷
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
className='action-button-advance-submit'
|
||||
type='primary'
|
||||
onClick={onChangeAdvanceOver}
|
||||
>
|
||||
提前交卷
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{!isLast && (
|
||||
<div className='practice-action-button'>
|
||||
<Button type='primary' onClick={onChangeNext}>
|
||||
下一题
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='practice-action-tips'>*交卷即可查看全部答案和解析</div>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
// 标记/提前交卷/交卷/下一题
|
||||
.practice-action-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
.practice-action-list {
|
||||
display: flex;
|
||||
// 标记
|
||||
.practice-action-item {
|
||||
margin-right: 30px;
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
.action-mark-icon {
|
||||
margin-right: 4px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
// 按钮
|
||||
.practice-action-button {
|
||||
margin: 0 15px;
|
||||
.action-button-advance-submit {
|
||||
background-color: #ff6547;
|
||||
border-color: #ff6547;
|
||||
color: white;
|
||||
}
|
||||
.action-button-submit {
|
||||
background-color: rgba(60, 110, 238, 1);
|
||||
border-color: rgba(60, 110, 238, 1);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 提示
|
||||
.practice-action-tips {
|
||||
margin-top: 10px;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
text-align: right;
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
import { Modal } from 'antd'
|
||||
import React from 'react'
|
||||
import { ImgObj } from '../../constant'
|
||||
import './index.less'
|
||||
|
||||
export default function PracticeAdvance(props) {
|
||||
const { isShowModalBox } = props
|
||||
const onSubmitModal = () => {
|
||||
props.onHandleSubmitModal && props.onHandleSubmitModal()
|
||||
}
|
||||
const onCancelModal = () => {
|
||||
props.onHandleCancelModal && props.onHandleCancelModal()
|
||||
}
|
||||
return (
|
||||
<Modal
|
||||
className='practice-advance-box'
|
||||
closable={false}
|
||||
maskClosable={false}
|
||||
open={isShowModalBox}
|
||||
title='提前交卷提示'
|
||||
onOk={onSubmitModal}
|
||||
onCancel={onCancelModal}
|
||||
okText='立即交卷'
|
||||
cancelText='继续做题'
|
||||
>
|
||||
<div className='practice-advance'>
|
||||
<div className='practice-advance-img'>
|
||||
<img className='practice-advance-icon' src={ImgObj.advanceTip} />
|
||||
</div>
|
||||
<div className='practice-advance-text'>
|
||||
你还有部分题目未完成,交卷即可查看试卷全部答案及解析,是否立即交卷?
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
.practice-advance-box {
|
||||
.practice-advance {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 28px 0;
|
||||
.practice-advance-img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
.practice-advance-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.practice-advance-text {
|
||||
margin: 10px;
|
||||
padding: 0 50px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
import { AppstoreOutlined } from '@ant-design/icons'
|
||||
import { debounce } from '@utils'
|
||||
import React, { Fragment } from 'react'
|
||||
import './index.less'
|
||||
|
||||
export default function PracticePaging(props) {
|
||||
const { subjectList, singleLength, multipleLength, judgeLength } = props
|
||||
const onChangePaging = index =>
|
||||
debounce(() => {
|
||||
props.onHandlePaging && props.onHandlePaging(index)
|
||||
})
|
||||
return (
|
||||
<Fragment>
|
||||
{subjectList?.length > 0 && (
|
||||
<div className='practice-paging-box'>
|
||||
<div className='practice-paging-tips'>
|
||||
<div>答题卡</div>
|
||||
<div className='practice-paging-tip'>
|
||||
<AppstoreOutlined style={{ marginRight: 4 }} />
|
||||
单选题{singleLength}道 | 多选题{multipleLength}道 | 判断题
|
||||
{judgeLength}道
|
||||
</div>
|
||||
</div>
|
||||
<div className='practice-paging-list'>
|
||||
{subjectList.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
key={`paging_${item.subjectId}`}
|
||||
className={`practice-paging-item
|
||||
${
|
||||
item?.isMark == 1 ? 'practice-paging-item-mark' : ''
|
||||
} ${
|
||||
item?.active
|
||||
? 'practice-paging-item-active'
|
||||
: item?.activeList?.length > 0
|
||||
? 'practice-paging-item-answer'
|
||||
: 'practice-paging-item-unactive'
|
||||
} `}
|
||||
onClick={onChangePaging(index)}
|
||||
>
|
||||
{index + 1}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
.practice-paging-box {
|
||||
padding: 20px;
|
||||
border-top: 1px dashed #ddd;
|
||||
.practice-paging-tips {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
.practice-paging-tip {
|
||||
padding: 5px 10px;
|
||||
font-size: 14px;
|
||||
background: #f2f2f2;
|
||||
}
|
||||
}
|
||||
|
||||
.practice-paging-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.practice-paging-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 10px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: white;
|
||||
background-color: rgba(60, 110, 238, 1);
|
||||
}
|
||||
}
|
||||
// 未选中
|
||||
.practice-paging-item-unactive {
|
||||
color: #dce4ec;
|
||||
&:after {
|
||||
background: #aaa;
|
||||
}
|
||||
}
|
||||
// 选中
|
||||
.practice-paging-item-active {
|
||||
color: white;
|
||||
background-color: rgba(60, 110, 238, 1);
|
||||
&:after {
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
// 有答案
|
||||
.practice-paging-item-answer {
|
||||
color: rgba(60, 110, 238, 1);
|
||||
&:after {
|
||||
background: rgba(60, 110, 238, 1);
|
||||
}
|
||||
}
|
||||
// 被标记
|
||||
.practice-paging-item-mark {
|
||||
position: relative;
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 3px;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
src/views/practise/practice-details/constant.js
Normal file
43
src/views/practise/practice-details/constant.js
Normal file
@@ -0,0 +1,43 @@
|
||||
export const mark = {
|
||||
0: '标记一下',
|
||||
1: '已标记',
|
||||
};
|
||||
|
||||
export const collection = {
|
||||
0: '未收藏',
|
||||
1: '已收藏',
|
||||
};
|
||||
|
||||
export const quetionsType = {
|
||||
1: '单选题',
|
||||
2: '多选题',
|
||||
3: '判断题',
|
||||
};
|
||||
|
||||
export const ApiName = {
|
||||
/**
|
||||
* 获取练习题目
|
||||
*/
|
||||
getSubjects: '/admin/practice/set/getSubjects',
|
||||
|
||||
/**
|
||||
* 获取练习题目详情
|
||||
*/
|
||||
getPracticeSubject: '/admin/practice/set/getPracticeSubject',
|
||||
|
||||
/**
|
||||
* 交卷
|
||||
*/
|
||||
submitSubject: '/admin/practice/detail/submit',
|
||||
};
|
||||
|
||||
export const ImgObj = {
|
||||
stop: 'https://img10.360buyimg.com/imagetools/jfs/t1/206561/1/10729/2819/619f783cE77dd49ed/54eb1fc4b3144a97.png',
|
||||
run: 'https://img11.360buyimg.com/imagetools/jfs/t1/161735/6/25253/2598/619f783cEa897a673/fbf4e8c05d40feb5.png',
|
||||
info: 'https://img13.360buyimg.com/imagetools/jfs/t1/217399/4/5733/2641/619f7b91E0894649e/2f6353fe0d35fb46.png',
|
||||
questionMark:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/201809/8/16630/2674/61a04963E92475548/ede8a7f006113cae.png',
|
||||
mark: 'https://img12.360buyimg.com/imagetools/jfs/t1/207329/30/11079/2474/61a70ad0E64730d1c/ed75ee746fb33926.png',
|
||||
advanceTip:
|
||||
'https://img11.360buyimg.com/imagetools/jfs/t1/161028/16/25609/6746/61a08d83E06659dfa/e6418acdab948134.png',
|
||||
};
|
511
src/views/practise/practice-details/index.jsx
Normal file
511
src/views/practise/practice-details/index.jsx
Normal file
@@ -0,0 +1,511 @@
|
||||
import Timer from '@components/timerCom/FlipClock'
|
||||
import { getCurrentTime, splicingQuery } from '@utils'
|
||||
import req from '@utils/request'
|
||||
import { Checkbox, Modal, Radio } from 'antd'
|
||||
import _ from 'lodash'
|
||||
import React, { Component } from 'react'
|
||||
import PracticeAction from './components/practice-action'
|
||||
import PracticeAdvance from './components/practice-advance'
|
||||
import PracticePaging from './components/practice-paging'
|
||||
import { ApiName, ImgObj, quetionsType } from './constant'
|
||||
import './index.less'
|
||||
|
||||
export default class PracticeDetails extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
isMark: 0, // 是否标记
|
||||
isCollection: 0,
|
||||
currentActive: '',
|
||||
subjectList: [], // 总题目列表
|
||||
subjectObject: {}, //题目
|
||||
currentIndex: 0,
|
||||
isShowAdvanOverceBox: false,
|
||||
isShowStopBox: false
|
||||
}
|
||||
}
|
||||
|
||||
timerRef = React.createRef()
|
||||
subjectTitle = ''
|
||||
singleLength = 0
|
||||
multipleLength = 0
|
||||
judgeLength = 0
|
||||
setId = ''
|
||||
|
||||
componentDidMount() {
|
||||
// const urlParams = queryParse(this.props.location.search)
|
||||
// this.setId = urlParams.setId
|
||||
this.getSubjectList()
|
||||
this.timerRef.current.run()
|
||||
// window.addEventListener('beforeunload', this.listener);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// window.addEventListener('beforeunload', this.listener);
|
||||
}
|
||||
|
||||
//监听屏幕刷新,关闭默认事件,界面没有动,不会拦截
|
||||
listener = ev => {
|
||||
ev.preventDefault()
|
||||
ev.returnValue = ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得题目列表
|
||||
*/
|
||||
getSubjectList = () => {
|
||||
let params = {
|
||||
setId: this.setId
|
||||
}
|
||||
this.subjectTitle = '热门题目练习'
|
||||
this.singleLength = 1
|
||||
this.multipleLength = 1
|
||||
this.judgeLength = 1
|
||||
const list = [
|
||||
{
|
||||
subjectType: 1,
|
||||
subjectId: 1
|
||||
},
|
||||
{
|
||||
subjectType: 2,
|
||||
subjectId: 2
|
||||
},
|
||||
{
|
||||
subjectType: 3,
|
||||
subjectId: 3
|
||||
}
|
||||
]
|
||||
this.setState({
|
||||
subjectList: [...list]
|
||||
})
|
||||
_.set(list, [0, 'active'], true)
|
||||
this.getPracticeSubject(list[0], list, 0, [])
|
||||
// req({
|
||||
// method: 'post',
|
||||
// data: params,
|
||||
// url: ApiName.getSubjects
|
||||
// })
|
||||
// .then(res => {
|
||||
// if (res.data && res.data?.subjectList?.length > 0) {
|
||||
// let list = res.data.subjectList
|
||||
// this.singleLength =
|
||||
// list?.length > 0 ? list.filter(item => item.subjectType === 1).length : 0
|
||||
// this.multipleLength =
|
||||
// list?.length > 0 ? list.filter(item => item.subjectType === 2).length : 0
|
||||
// this.judgeLength =
|
||||
// list?.length > 0 ? list.filter(item => item.subjectType === 3).length : 0
|
||||
// this.subjectTitle = res.data?.title || '' // 总题目列表
|
||||
// this.getPracticeSubject(list[0], list, 0, [])
|
||||
// }
|
||||
// })
|
||||
// .catch(err => console.log(err))
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得题目详情
|
||||
* @param {*} item 选择的项
|
||||
* @param {*} subjectList 题目列表
|
||||
* @param {*} index 选择的下标
|
||||
* @param {*} activeList 选中的列表
|
||||
* @param {*} isMark 是否被标记
|
||||
*/
|
||||
getPracticeSubject = (item, subjectList, index, activeList, isMark = 0) => {
|
||||
let params = {
|
||||
subjectId: item.subjectId,
|
||||
subjectType: item.subjectType
|
||||
}
|
||||
|
||||
const optionList =
|
||||
item.subjectType === 3
|
||||
? [
|
||||
{
|
||||
optionContent: '正确',
|
||||
optionType: 1
|
||||
},
|
||||
{
|
||||
optionContent: '错误',
|
||||
optionType: 0
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
optionType: 1,
|
||||
optionContent: '<p>题目答案1</p>'
|
||||
},
|
||||
{
|
||||
optionType: 2,
|
||||
optionContent: '<p>题目答案2</p>'
|
||||
},
|
||||
{
|
||||
optionType: 3,
|
||||
optionContent: '<p>题目答案3</p>'
|
||||
}
|
||||
]
|
||||
|
||||
return this.setState({
|
||||
currentIndex: index,
|
||||
currentActive: item.subjectType === 2 ? activeList : activeList[0],
|
||||
subjectObject: {
|
||||
subjectName: '题干内容',
|
||||
subjectType: item.subjectType,
|
||||
optionList,
|
||||
// subjectList: subjectList,
|
||||
// currentIndex: index,
|
||||
// currentActive: item.sub??jectType === 2 ? activeList : activeList[0],
|
||||
isMark: isMark
|
||||
}
|
||||
})
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: ApiName.getPracticeSubject
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data) {
|
||||
let subjectObject = res.data
|
||||
if (item.subjectType === 3) {
|
||||
subjectObject.optionList = [
|
||||
{
|
||||
optionContent: '正确',
|
||||
optionType: 1
|
||||
},
|
||||
{
|
||||
optionContent: '错误',
|
||||
optionType: 0
|
||||
}
|
||||
]
|
||||
}
|
||||
this.setState({
|
||||
subjectObject: res.data,
|
||||
subjectList: subjectList,
|
||||
currentIndex: index,
|
||||
currentActive: item.subjectType === 2 ? activeList : activeList[0],
|
||||
isMark: isMark
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(err => console.log(err))
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择单选
|
||||
* @param {*} e
|
||||
* @returns
|
||||
*/
|
||||
onChangeRadio = e => () => {
|
||||
let { currentIndex, subjectList } = this.state
|
||||
_.set(subjectList, [currentIndex, 'activeList'], [e])
|
||||
this.setState({
|
||||
currentActive: e,
|
||||
subjectList
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择多选
|
||||
* @param {*} e
|
||||
* @returns
|
||||
*/
|
||||
onChangeCheck = e => {
|
||||
let { currentIndex, subjectList } = this.state
|
||||
_.set(subjectList, [currentIndex, 'activeList'], e)
|
||||
this.setState({
|
||||
currentActive: e,
|
||||
subjectList
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停计时
|
||||
*/
|
||||
onChangeStop = () => {
|
||||
this.setState({ isShowStopBox: true })
|
||||
this.timerRef.current.stop()
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记一下
|
||||
*/
|
||||
onChangeMark = () => {
|
||||
let { currentIndex, subjectList, subjectObject } = this.state
|
||||
let flag = 1
|
||||
if (subjectList[currentIndex]?.isMark) {
|
||||
flag = 0
|
||||
}
|
||||
_.set(subjectList, [currentIndex, 'isMark'], flag)
|
||||
this.setState({
|
||||
subjectList,
|
||||
isMark: flag,
|
||||
subjectObject
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择答题卡
|
||||
* @param {*} index
|
||||
* @param {*} item
|
||||
* @returns
|
||||
*/
|
||||
onChangePaging = index => {
|
||||
let { currentIndex } = this.state
|
||||
// 如果点击当前题目,直接return
|
||||
if (currentIndex === index) {
|
||||
return
|
||||
}
|
||||
this.changeData(index)
|
||||
}
|
||||
|
||||
/**
|
||||
* 交卷
|
||||
*/
|
||||
onChangeOver = () => {
|
||||
const { subjectList } = this.state
|
||||
let answerDetails = []
|
||||
subjectList.forEach(item => {
|
||||
let obj = {
|
||||
subjectId: item.subjectId,
|
||||
subjectType: item.subjectType,
|
||||
answerContents: []
|
||||
}
|
||||
if (item?.activeList && item?.activeList?.length > 0) {
|
||||
obj.answerContents = item.activeList
|
||||
}
|
||||
answerDetails.push(obj)
|
||||
})
|
||||
let params = {
|
||||
setId: this.setId,
|
||||
timeUse: this.timerRef.current.getUseTime(),
|
||||
submitTime: getCurrentTime(),
|
||||
answerDetails: answerDetails
|
||||
}
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: ApiName.submitSubject
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data && res.data.practiceId) {
|
||||
//关闭定时器
|
||||
this.timerRef.current.end()
|
||||
this.props.history.replace(
|
||||
splicingQuery('/practice-analytic', {
|
||||
practiceId: res.data.practiceId
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
.catch(err => console.log(err))
|
||||
}
|
||||
|
||||
/**
|
||||
* 提前交卷弹框-直接交卷
|
||||
*/
|
||||
onHandleSubmitModal = () => {
|
||||
this.onChangeOver()
|
||||
}
|
||||
|
||||
/**
|
||||
* 提前交卷弹框-继续做题
|
||||
*/
|
||||
onHandleCancelModal = () => {
|
||||
this.setState({ isShowAdvanOverceBox: false })
|
||||
}
|
||||
|
||||
/**
|
||||
* 提前交卷
|
||||
*/
|
||||
onChangeAdvanceOver = () => {
|
||||
this.setState({
|
||||
isShowAdvanOverceBox: true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 下一题
|
||||
* @returns
|
||||
*/
|
||||
onChangeNext = () => {
|
||||
let { currentIndex } = this.state
|
||||
currentIndex += 1
|
||||
this.changeData(currentIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* 改变数据
|
||||
* @param {*} index 当前点击下标
|
||||
*/
|
||||
changeData = index => {
|
||||
let { subjectList } = this.state
|
||||
let subObj = subjectList[index]
|
||||
let activeList = [] // 多选 选中的答案项
|
||||
let isMark = 0 // 是否被标记
|
||||
|
||||
// 将其他item设置为未选中
|
||||
subjectList.forEach(item => {
|
||||
item.active = false
|
||||
})
|
||||
_.set(subjectList, [index, 'active'], true)
|
||||
|
||||
// if当前选择的有选答案,则直接显示出来
|
||||
if (subObj?.activeList?.length > 0) {
|
||||
activeList = subObj?.activeList
|
||||
}
|
||||
|
||||
// if当前已被标记,则直接显示出来
|
||||
if (subObj?.isMark == 1) {
|
||||
isMark = 1
|
||||
}
|
||||
|
||||
this.getPracticeSubject(subObj, subjectList, index, activeList, isMark)
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停弹框-继续做题
|
||||
*/
|
||||
onChangeSubmitModal = () => {
|
||||
this.timerRef.current.run()
|
||||
this.setState({ isShowStopBox: false })
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停弹框-再次再做
|
||||
*/
|
||||
onChangeCancelModal = () => {
|
||||
this.props.history.goBack()
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
isMark,
|
||||
isCollection,
|
||||
currentIndex,
|
||||
currentActive,
|
||||
subjectList,
|
||||
subjectObject,
|
||||
isShowAdvanOverceBox,
|
||||
isShowStopBox
|
||||
} = this.state
|
||||
const isLast = currentIndex === subjectList?.length - 1
|
||||
// 获得已答的题目个数
|
||||
const noAnswerNum =
|
||||
subjectList.filter(item => item.activeList && item.activeList.length > 0).length || 0
|
||||
return (
|
||||
<div className='details-container'>
|
||||
<div className='container-box'>
|
||||
<div className='container-box-title'>
|
||||
<div className='title-title'>{this.subjectTitle}</div>
|
||||
<div className='title-time'>
|
||||
<div className='title-timer-img' onClick={this.onChangeStop}>
|
||||
<img src={isShowStopBox ? ImgObj.stop : ImgObj.run} className='title-timer-icon' />
|
||||
</div>
|
||||
<Timer ref={this.timerRef} />
|
||||
</div>
|
||||
</div>
|
||||
<div className='details-question-number'>
|
||||
<div className='question-number-number'>
|
||||
{currentIndex + 1}/{subjectList?.length}
|
||||
</div>
|
||||
<img src={ImgObj.questionMark} className='question-number-mark' />
|
||||
<div className='question-number-type'>[{quetionsType[subjectObject.subjectType]}]</div>
|
||||
</div>
|
||||
<div className='practice-main'>
|
||||
<div className='practice-text'>
|
||||
<div className='practice-question'>{subjectObject.subjectName}</div>
|
||||
{subjectObject.subjectType === 2 ? (
|
||||
<Checkbox.Group
|
||||
className='practice-answer-list'
|
||||
onChange={this.onChangeCheck}
|
||||
value={currentActive || []}
|
||||
key={currentIndex}
|
||||
>
|
||||
{subjectObject?.optionList?.length > 0 &&
|
||||
subjectObject?.optionList.map(item => {
|
||||
return (
|
||||
<Checkbox
|
||||
key={item.optionType}
|
||||
className={`practice-answer-item ${
|
||||
currentActive.includes(item.optionType)
|
||||
? 'practice-answer-item-active'
|
||||
: ''
|
||||
}`}
|
||||
value={item.optionType}
|
||||
>
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item.optionContent
|
||||
}}
|
||||
></div>
|
||||
</Checkbox>
|
||||
)
|
||||
})}
|
||||
</Checkbox.Group>
|
||||
) : (
|
||||
<Radio.Group
|
||||
className='practice-answer-list'
|
||||
value={currentActive}
|
||||
key={currentIndex}
|
||||
>
|
||||
{subjectObject?.optionList?.length > 0 &&
|
||||
subjectObject?.optionList.map(item => {
|
||||
return (
|
||||
<Radio
|
||||
key={item.optionType}
|
||||
onClick={this.onChangeRadio(item.optionType)}
|
||||
className={`practice-answer-item ${
|
||||
currentActive === item.optionType ? 'practice-answer-item-active' : ''
|
||||
}`}
|
||||
value={item.optionType}
|
||||
>
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item.optionContent
|
||||
}}
|
||||
></div>
|
||||
</Radio>
|
||||
)
|
||||
})}
|
||||
</Radio.Group>
|
||||
)}
|
||||
</div>
|
||||
<PracticeAction
|
||||
isLast={isLast}
|
||||
isMark={isMark}
|
||||
onHandleMark={this.onChangeMark}
|
||||
onHandleOver={this.onChangeOver}
|
||||
onHandleAdvanceOver={this.onChangeAdvanceOver}
|
||||
onHandleNext={this.onChangeNext}
|
||||
/>
|
||||
</div>
|
||||
<PracticePaging
|
||||
subjectList={subjectList}
|
||||
onHandlePaging={this.onChangePaging}
|
||||
singleLength={this.singleLength}
|
||||
multipleLength={this.multipleLength}
|
||||
judgeLength={this.judgeLength}
|
||||
/>
|
||||
</div>
|
||||
<PracticeAdvance
|
||||
isShowModalBox={isShowAdvanOverceBox}
|
||||
onHandleSubmitModal={this.onHandleSubmitModal}
|
||||
onHandleCancelModal={this.onHandleCancelModal}
|
||||
/>
|
||||
<Modal
|
||||
closable={false}
|
||||
maskClosable={false}
|
||||
style={{ padding: 20 }}
|
||||
open={isShowStopBox}
|
||||
onOk={this.onChangeSubmitModal}
|
||||
onCancel={this.onChangeCancelModal}
|
||||
okText='继续做题'
|
||||
cancelText='下次再做'
|
||||
>
|
||||
<div style={{ padding: 40 }}>
|
||||
<img src={ImgObj.info} className='details-container-box-info' />
|
||||
休息一下吧!共{subjectList?.length}道题,还剩
|
||||
{subjectList?.length - noAnswerNum}道没做哦~
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
107
src/views/practise/practice-details/index.less
Normal file
107
src/views/practise/practice-details/index.less
Normal file
@@ -0,0 +1,107 @@
|
||||
.details-container {
|
||||
width: 1439px;
|
||||
margin: 0 auto;
|
||||
overflow: auto;
|
||||
background-color: #ffffff;
|
||||
flex-direction: column;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 3px;
|
||||
.container-box {
|
||||
background-color: #ffffff;
|
||||
.container-box-title {
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.title-title {
|
||||
font-size: 20px;
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
// text-overflow: ellipsis;
|
||||
// white-space: nowrap;
|
||||
// word-wrap: normal;
|
||||
max-width: 1000px;
|
||||
}
|
||||
.title-time {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.title-timer-img {
|
||||
margin: -4px 10px 0 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
.title-timer-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.details-question-number {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
.question-number-number {
|
||||
background-color: #e5e5e5;
|
||||
padding: 0 5px;
|
||||
border-radius: 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.question-number-mark {
|
||||
margin: 0 8px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
.question-number-type {
|
||||
background-color: #fff;
|
||||
line-height: 1.5;
|
||||
font-size: 16px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
.practice-main {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
padding: 10px 20px 20px;
|
||||
.practice-text {
|
||||
margin-bottom: 20px;
|
||||
.practice-question {
|
||||
margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.practice-answer-list {
|
||||
width: 100%;
|
||||
.practice-answer-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
padding: 12px 20px 13px;
|
||||
word-break: break-all;
|
||||
border: 1px solid #d4d4d4;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: #1890ff;
|
||||
background: #f3f3f3;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
.practice-answer-item-active {
|
||||
color: #1890ff;
|
||||
text-decoration: none;
|
||||
border-color: #1890ff;
|
||||
}
|
||||
.ant-checkbox-wrapper + .ant-checkbox-wrapper {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.details-container-box-info {
|
||||
margin-right: 10px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
485
src/views/practise/practice-details/index1.jsx
Normal file
485
src/views/practise/practice-details/index1.jsx
Normal file
@@ -0,0 +1,485 @@
|
||||
import Timer from '@components/timerCom/FlipClock'
|
||||
import req from '@utils/request'
|
||||
import { Checkbox, Modal, Radio } from 'antd'
|
||||
import _ from 'lodash'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import PracticeAction from './components/practice-action'
|
||||
import PracticeAdvance from './components/practice-advance'
|
||||
import PracticePaging from './components/practice-paging'
|
||||
import { ApiName, ImgObj, quetionsType } from './constant'
|
||||
import './index.less'
|
||||
|
||||
const PracticeDetails = props => {
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [isMark, setIsMark] = useState(0) // 是否标记
|
||||
const [currentActive, setCurrentActive] = useState('')
|
||||
const [subjectList, setSubjectList] = useState([])
|
||||
const [subjectObject, setSubjectObject] = useState({})
|
||||
const [currentIndex, setCurrentIndex] = useState(0)
|
||||
const [isShowAdvanOverceBox, setIsShowAdvanOverceBox] = useState(false)
|
||||
const [isShowStopBox, setIsShowStopBox] = useState(false)
|
||||
|
||||
const timerRef = React.createRef()
|
||||
let subjectTitle = ''
|
||||
let singleLength = 0
|
||||
let multipleLength = 0
|
||||
let judgeLength = 0
|
||||
const setId = ''
|
||||
|
||||
const isLast = currentIndex === subjectList?.length - 1
|
||||
|
||||
/**
|
||||
* 获得题目列表
|
||||
*/
|
||||
const getSubjectList = () => {
|
||||
let params = {
|
||||
setId: setId
|
||||
}
|
||||
subjectTitle = '热门题目练习'
|
||||
singleLength = 1
|
||||
multipleLength = 1
|
||||
judgeLength = 1
|
||||
const list = [
|
||||
{
|
||||
subjectType: 1,
|
||||
subjectId: 1,
|
||||
active: true
|
||||
},
|
||||
{
|
||||
subjectType: 2,
|
||||
subjectId: 2
|
||||
},
|
||||
{
|
||||
subjectType: 3,
|
||||
subjectId: 3
|
||||
}
|
||||
]
|
||||
setSubjectList([...list])
|
||||
// _.set(list, [0, 'active'], true)
|
||||
getPracticeSubject(list[0], list, 0, [])
|
||||
// req({
|
||||
// method: 'post',
|
||||
// data: params,
|
||||
// url: ApiName.getSubjects
|
||||
// })
|
||||
// .then(res => {
|
||||
// if (res.data && res.data?.subjectList?.length > 0) {
|
||||
// let list = res.data.subjectList
|
||||
// singleLength =
|
||||
// list?.length > 0 ? list.filter(item => item.subjectType === 1).length : 0
|
||||
// multipleLength =
|
||||
// list?.length > 0 ? list.filter(item => item.subjectType === 2).length : 0
|
||||
// judgeLength =
|
||||
// list?.length > 0 ? list.filter(item => item.subjectType === 3).length : 0
|
||||
// subjectTitle = res.data?.title || '' // 总题目列表
|
||||
// getPracticeSubject(list[0], list, 0, [])
|
||||
// }
|
||||
// })
|
||||
// .catch(err => console.log(err))
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
timerRef.current.run()
|
||||
getSubjectList()
|
||||
}, [])
|
||||
|
||||
/**
|
||||
* 获得题目详情
|
||||
* @param {*} item 选择的项
|
||||
* @param {*} subjectList 题目列表
|
||||
* @param {*} index 选择的下标
|
||||
* @param {*} activeList 选中的列表
|
||||
* @param {*} isMark 是否被标记
|
||||
*/
|
||||
const getPracticeSubject = (item, subjectList, index, activeList, isMark = 0) => {
|
||||
let params = {
|
||||
subjectId: item.subjectId,
|
||||
subjectType: item.subjectType
|
||||
}
|
||||
|
||||
const optionList =
|
||||
item.subjectType === 3
|
||||
? [
|
||||
{
|
||||
optionContent: '正确',
|
||||
optionType: 1
|
||||
},
|
||||
{
|
||||
optionContent: '错误',
|
||||
optionType: 0
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
optionType: 1,
|
||||
optionContent: '<p>题目答案1</p>'
|
||||
},
|
||||
{
|
||||
optionType: 2,
|
||||
optionContent: '<p>题目答案2</p>'
|
||||
},
|
||||
{
|
||||
optionType: 3,
|
||||
optionContent: '<p>题目答案3</p>'
|
||||
}
|
||||
]
|
||||
setCurrentActive(item.subjectType === 2 ? activeList : activeList[0])
|
||||
setCurrentIndex(index)
|
||||
setSubjectObject({
|
||||
subjectName: '题干内容',
|
||||
subjectType: item.subjectType,
|
||||
optionList,
|
||||
// subjectList: subjectList,
|
||||
// currentIndex: index,
|
||||
// currentActive: item.sub??jectType === 2 ? activeList : activeList[0],
|
||||
isMark: isMark
|
||||
})
|
||||
|
||||
return
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: ApiName.getPracticeSubject
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data) {
|
||||
let subjectObject = res.data
|
||||
if (item.subjectType === 3) {
|
||||
subjectObject.optionList = [
|
||||
{
|
||||
optionContent: '正确',
|
||||
optionType: 1
|
||||
},
|
||||
{
|
||||
optionContent: '错误',
|
||||
optionType: 0
|
||||
}
|
||||
]
|
||||
}
|
||||
setState({
|
||||
subjectObject: res.data,
|
||||
subjectList: subjectList,
|
||||
currentIndex: index,
|
||||
currentActive: item.subjectType === 2 ? activeList : activeList[0],
|
||||
isMark: isMark
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(err => console.log(err))
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择单选
|
||||
* @param {*} e
|
||||
* @returns
|
||||
*/
|
||||
const onChangeRadio = e => () => {
|
||||
const list = [...subjectList]
|
||||
_.set(list, [currentIndex, 'activeList'], [e])
|
||||
setCurrentActive(e)
|
||||
setSubjectList([...list])
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择多选
|
||||
* @param {*} e
|
||||
* @returns
|
||||
*/
|
||||
const onChangeCheck = e => {
|
||||
// let { currentIndex, subjectList } = state
|
||||
const list = [...subjectList]
|
||||
_.set(list, [currentIndex, 'activeList'], e)
|
||||
setCurrentActive(e)
|
||||
setSubjectList([...list])
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停计时
|
||||
*/
|
||||
const onChangeStop = () => {
|
||||
// setState({ isShowStopBox: true })
|
||||
setIsShowStopBox(true)
|
||||
timerRef.current.stop()
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记一下
|
||||
*/
|
||||
const onChangeMark = () => {
|
||||
const list = [...subjectList]
|
||||
let flag = 1
|
||||
if (list[currentIndex]?.isMark) {
|
||||
flag = 0
|
||||
}
|
||||
_.set(list, [currentIndex, 'isMark'], flag)
|
||||
setSubjectList([...list])
|
||||
setIsMark(flag)
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择答题卡
|
||||
* @param {*} index
|
||||
* @param {*} item
|
||||
* @returns
|
||||
*/
|
||||
const onChangePaging = index => {
|
||||
// 如果点击当前题目,直接return
|
||||
if (currentIndex === index) {
|
||||
return
|
||||
}
|
||||
changeData(index)
|
||||
}
|
||||
|
||||
/**
|
||||
* 交卷
|
||||
*/
|
||||
const onChangeOver = () => {
|
||||
timerRef.current.end()
|
||||
navigate('/practice-analytic/1', { replace: true })
|
||||
// const list = [...subjectList]
|
||||
// let answerDetails = []
|
||||
// list.forEach(item => {
|
||||
// let obj = {
|
||||
// subjectId: item.subjectId,
|
||||
// subjectType: item.subjectType,
|
||||
// answerContents: []
|
||||
// }
|
||||
// if (item?.activeList && item?.activeList?.length > 0) {
|
||||
// obj.answerContents = item.activeList
|
||||
// }
|
||||
// answerDetails.push(obj)
|
||||
// })
|
||||
// let params = {
|
||||
// setId: setId,
|
||||
// timeUse: timerRef.current.getUseTime(),
|
||||
// submitTime: getCurrentTime(),
|
||||
// answerDetails: answerDetails
|
||||
// }
|
||||
// req({
|
||||
// method: 'post',
|
||||
// data: params,
|
||||
// url: ApiName.submitSubject
|
||||
// })
|
||||
// .then(res => {
|
||||
// if (res.data && res.data.practiceId) {
|
||||
// //关闭定时器
|
||||
// timerRef.current.end()
|
||||
// props.history.replace(
|
||||
// splicingQuery('/practice-analytic', {
|
||||
// practiceId: res.data.practiceId
|
||||
// })
|
||||
// )
|
||||
// }
|
||||
// })
|
||||
// .catch(err => console.log(err))
|
||||
}
|
||||
|
||||
/**
|
||||
* 提前交卷弹框-直接交卷
|
||||
*/
|
||||
const onHandleSubmitModal = () => {
|
||||
onChangeOver()
|
||||
}
|
||||
|
||||
/**
|
||||
* 提前交卷弹框-继续做题
|
||||
*/
|
||||
const onHandleCancelModal = () => {
|
||||
setIsShowAdvanOverceBox(false)
|
||||
|
||||
// setState({ isShowAdvanOverceBox: false })
|
||||
}
|
||||
|
||||
/**
|
||||
* 提前交卷
|
||||
*/
|
||||
const onChangeAdvanceOver = () => {
|
||||
setIsShowAdvanOverceBox(true)
|
||||
// setState({
|
||||
// isShowAdvanOverceBox: true
|
||||
// })
|
||||
}
|
||||
|
||||
/**
|
||||
* 下一题
|
||||
* @returns
|
||||
*/
|
||||
const onChangeNext = () => {
|
||||
// let { currentIndex } = state
|
||||
// currentIndex += 1
|
||||
setCurrentIndex(currentIndex + 1)
|
||||
changeData(currentIndex + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* 改变数据
|
||||
* @param {*} index 当前点击下标
|
||||
*/
|
||||
const changeData = index => {
|
||||
// let { subjectList } = state
|
||||
const list = [...subjectList]
|
||||
let subObj = list[index]
|
||||
let activeList = [] // 多选 选中的答案项
|
||||
let isMark = 0 // 是否被标记
|
||||
|
||||
// 将其他item设置为未选中
|
||||
list.forEach(item => {
|
||||
item.active = false
|
||||
})
|
||||
_.set(list, [index, 'active'], true)
|
||||
|
||||
// if当前选择的有选答案,则直接显示出来
|
||||
if (subObj?.activeList?.length > 0) {
|
||||
activeList = subObj?.activeList
|
||||
}
|
||||
|
||||
// if当前已被标记,则直接显示出来
|
||||
if (subObj?.isMark == 1) {
|
||||
isMark = 1
|
||||
}
|
||||
|
||||
getPracticeSubject(subObj, list, index, activeList, isMark)
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停弹框-继续做题
|
||||
*/
|
||||
const onChangeSubmitModal = () => {
|
||||
timerRef.current.run()
|
||||
setIsShowStopBox(false)
|
||||
// setState({ isShowStopBox: false })
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停弹框-再次再做
|
||||
*/
|
||||
const onChangeCancelModal = () => {
|
||||
// props.history.goBack()
|
||||
navigate(-1)
|
||||
}
|
||||
|
||||
const noAnswerNum =
|
||||
subjectList.filter(item => item.activeList && item.activeList.length > 0).length || 0
|
||||
|
||||
return (
|
||||
<div className='details-container'>
|
||||
<div className='container-box'>
|
||||
<div className='container-box-title'>
|
||||
<div className='title-title'>{subjectTitle}</div>
|
||||
<div className='title-time'>
|
||||
<div className='title-timer-img' onClick={onChangeStop}>
|
||||
<img src={isShowStopBox ? ImgObj.stop : ImgObj.run} className='title-timer-icon' />
|
||||
</div>
|
||||
<Timer ref={timerRef} />
|
||||
</div>
|
||||
</div>
|
||||
<div className='details-question-number'>
|
||||
<div className='question-number-number'>
|
||||
{currentIndex + 1}/{subjectList?.length}
|
||||
</div>
|
||||
<img src={ImgObj.questionMark} className='question-number-mark' />
|
||||
<div className='question-number-type'>[{quetionsType[subjectObject.subjectType]}]</div>
|
||||
</div>
|
||||
<div className='practice-main'>
|
||||
<div className='practice-text'>
|
||||
<div className='practice-question'>{subjectObject.subjectName}</div>
|
||||
{subjectObject.subjectType === 2 ? (
|
||||
<Checkbox.Group
|
||||
className='practice-answer-list'
|
||||
onChange={onChangeCheck}
|
||||
value={currentActive || []}
|
||||
key={currentIndex}
|
||||
>
|
||||
{subjectObject?.optionList?.length > 0 &&
|
||||
subjectObject?.optionList.map(item => {
|
||||
return (
|
||||
<Checkbox
|
||||
key={item.optionType}
|
||||
className={`practice-answer-item ${
|
||||
currentActive.includes(item.optionType)
|
||||
? 'practice-answer-item-active'
|
||||
: ''
|
||||
}`}
|
||||
value={item.optionType}
|
||||
>
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item.optionContent
|
||||
}}
|
||||
></div>
|
||||
</Checkbox>
|
||||
)
|
||||
})}
|
||||
</Checkbox.Group>
|
||||
) : (
|
||||
<Radio.Group
|
||||
className='practice-answer-list'
|
||||
value={currentActive}
|
||||
key={currentIndex}
|
||||
>
|
||||
{subjectObject?.optionList?.length > 0 &&
|
||||
subjectObject?.optionList.map(item => {
|
||||
return (
|
||||
<Radio
|
||||
key={item.optionType}
|
||||
onClick={onChangeRadio(item.optionType)}
|
||||
className={`practice-answer-item ${
|
||||
currentActive === item.optionType ? 'practice-answer-item-active' : ''
|
||||
}`}
|
||||
value={item.optionType}
|
||||
>
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item.optionContent
|
||||
}}
|
||||
></div>
|
||||
</Radio>
|
||||
)
|
||||
})}
|
||||
</Radio.Group>
|
||||
)}
|
||||
</div>
|
||||
<PracticeAction
|
||||
isLast={isLast}
|
||||
isMark={isMark}
|
||||
onHandleMark={onChangeMark}
|
||||
onHandleOver={onChangeOver}
|
||||
onHandleAdvanceOver={onChangeAdvanceOver}
|
||||
onHandleNext={onChangeNext}
|
||||
/>
|
||||
</div>
|
||||
<PracticePaging
|
||||
subjectList={subjectList}
|
||||
onHandlePaging={onChangePaging}
|
||||
singleLength={singleLength}
|
||||
multipleLength={multipleLength}
|
||||
judgeLength={judgeLength}
|
||||
/>
|
||||
</div>
|
||||
<PracticeAdvance
|
||||
isShowModalBox={isShowAdvanOverceBox}
|
||||
onHandleSubmitModal={onHandleSubmitModal}
|
||||
onHandleCancelModal={onHandleCancelModal}
|
||||
/>
|
||||
<Modal
|
||||
closable={false}
|
||||
maskClosable={false}
|
||||
style={{ padding: 20 }}
|
||||
open={isShowStopBox}
|
||||
onOk={onChangeSubmitModal}
|
||||
onCancel={onChangeCancelModal}
|
||||
okText='继续做题'
|
||||
cancelText='下次再做'
|
||||
>
|
||||
<div style={{ padding: 40 }}>
|
||||
<img src={ImgObj.info} className='details-container-box-info' />
|
||||
休息一下吧!共{subjectList?.length}道题,还剩
|
||||
{subjectList?.length - noAnswerNum}道没做哦~
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default PracticeDetails
|
@@ -0,0 +1,236 @@
|
||||
import { debounce, splicingQuery } from '@utils'
|
||||
import req from '@utils/request'
|
||||
import { Button, Card, Checkbox, Descriptions, Spin } from 'antd'
|
||||
import _ from 'lodash'
|
||||
import React, { Component, Fragment } from 'react'
|
||||
import { ApiName } from '../../constant'
|
||||
import './index.less'
|
||||
|
||||
const CheckboxGroup = Checkbox.Group
|
||||
class FrontEnd extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
tabList: [],
|
||||
secondCategoryList: [],
|
||||
isShowSpin: false,
|
||||
currentKey: '', //当前的大类id
|
||||
difficulty: 1
|
||||
}
|
||||
}
|
||||
allCategoryMap = {}
|
||||
selectList = []
|
||||
|
||||
componentDidMount() {
|
||||
this.getSpecialPracticeContent()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单对应的内容
|
||||
*/
|
||||
getSpecialPracticeContent() {
|
||||
const { menuId, menuType } = this.props
|
||||
let params = {
|
||||
menuId: menuId,
|
||||
menuType: menuType
|
||||
}
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: ApiName.getSpecialPracticeContent
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data && res.data?.length > 0) {
|
||||
let tabList = res.data.map(item => {
|
||||
return {
|
||||
tab: item.primaryCategoryName,
|
||||
key: item.primaryCategoryId
|
||||
}
|
||||
})
|
||||
res.data.forEach(item => {
|
||||
this.allCategoryMap[item.primaryCategoryId] = item.categoryList
|
||||
})
|
||||
|
||||
this.setState({
|
||||
currentKey: tabList[0].key,
|
||||
tabList: tabList,
|
||||
secondCategoryList: this.allCategoryMap[res.data[0].primaryCategoryId],
|
||||
isShowSpin: false
|
||||
})
|
||||
} else {
|
||||
this.setState({
|
||||
tabList: [],
|
||||
secondCategoryList: [],
|
||||
isShowSpin: false
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(err => console.log(err))
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成setId接口
|
||||
*/
|
||||
addPractice = debounce(() => {
|
||||
const { menuId } = this.props
|
||||
let params = {
|
||||
difficulty: menuId,
|
||||
assembleIds: this.selectList
|
||||
}
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: '/admin/practice/set/addPractice'
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data) {
|
||||
this.props.history.push(
|
||||
splicingQuery('/practice-details', {
|
||||
setId: res.data.setId
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
.catch(err => console.log(err))
|
||||
})
|
||||
|
||||
/**
|
||||
* 复选框-选中/未选中
|
||||
* @param {*} index 二级分类下标
|
||||
* @returns
|
||||
*/
|
||||
onChange = index => list => {
|
||||
let { secondCategoryList } = this.state
|
||||
_.set(secondCategoryList, [index, 'activeList'], list)
|
||||
this.setState({ secondCategoryList })
|
||||
this.getAssembleIdList(secondCategoryList)
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换一级分类
|
||||
* @param {*} key
|
||||
*/
|
||||
onTabChange = debounce(key => {
|
||||
let { secondCategoryList } = this.state
|
||||
// 切换一级大类时,将activeList全重置为空
|
||||
secondCategoryList.forEach(item => {
|
||||
item.activeList = []
|
||||
})
|
||||
this.getAssembleIdList([])
|
||||
this.setState({
|
||||
currentKey: key,
|
||||
secondCategoryList: this.allCategoryMap[key]
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取选中的assembleId列表
|
||||
* @param {*} list
|
||||
*/
|
||||
getAssembleIdList = list => {
|
||||
let activeList = []
|
||||
list.forEach(item => {
|
||||
if (item.activeList && item.activeList?.length !== 0) {
|
||||
activeList = _.concat(activeList, item.activeList)
|
||||
}
|
||||
})
|
||||
this.selectList = activeList
|
||||
}
|
||||
|
||||
/**
|
||||
* 全选
|
||||
* @param {*} index 二级分类下标
|
||||
* @returns
|
||||
*/
|
||||
onCheckAllChange = index => e => {
|
||||
let { secondCategoryList } = this.state
|
||||
let activeList = []
|
||||
if (e.target.checked) {
|
||||
activeList = secondCategoryList[index].labelList.map(item => item.assembleId)
|
||||
}
|
||||
_.set(secondCategoryList, [index, 'activeList'], activeList)
|
||||
this.setState({ secondCategoryList })
|
||||
this.getAssembleIdList(secondCategoryList)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { secondCategoryList, isShowSpin, currentKey, tabList } = this.state
|
||||
return (
|
||||
<Spin spinning={isShowSpin}>
|
||||
{tabList?.length > 0 && (
|
||||
<div className='front-box'>
|
||||
<Card
|
||||
style={{ width: '100%' }}
|
||||
tabList={tabList}
|
||||
bordered={false}
|
||||
activeTabKey={currentKey + ''}
|
||||
onTabChange={key => {
|
||||
this.onTabChange(key, 'key')
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
{secondCategoryList?.length > 0 &&
|
||||
secondCategoryList.map((secondItem, secondIndex) => {
|
||||
let labelList = secondItem.labelList.map(item => {
|
||||
return {
|
||||
label: item.labelName,
|
||||
value: item.assembleId
|
||||
}
|
||||
})
|
||||
return (
|
||||
<Descriptions
|
||||
key={`second_category_${secondIndex}`}
|
||||
size='default'
|
||||
title={
|
||||
<Fragment>
|
||||
<div className='box'>
|
||||
<div id={secondItem.categoryId} className='box1'>
|
||||
{secondItem.categoryName}
|
||||
</div>
|
||||
<div className='box2'>
|
||||
<Checkbox
|
||||
checked={
|
||||
secondItem?.activeList?.length == secondItem.labelList.length
|
||||
}
|
||||
onChange={this.onCheckAllChange(secondIndex)}
|
||||
>
|
||||
全选
|
||||
</Checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
}
|
||||
>
|
||||
<Descriptions.Item label=''>
|
||||
<CheckboxGroup
|
||||
value={secondItem.activeList}
|
||||
options={labelList}
|
||||
onChange={this.onChange(secondIndex)}
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Card>
|
||||
<div className='but'>
|
||||
<Button
|
||||
disabled={this.selectList.length === 0}
|
||||
style={{ opacity: this.selectList.length === 0 ? 0.5 : 1 }}
|
||||
className='button'
|
||||
size='large'
|
||||
onClick={() => {
|
||||
this.addPractice()
|
||||
}}
|
||||
>
|
||||
开始练习
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default FrontEnd
|
@@ -0,0 +1,24 @@
|
||||
.front-box {
|
||||
.ant-descriptions-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 18px;
|
||||
color: rgba(51, 51, 51, 0.7);
|
||||
}
|
||||
.ant-checkbox-wrapper {
|
||||
font-size: 14px;
|
||||
color: rgba(51, 51, 51, 0.5);
|
||||
}
|
||||
.box{
|
||||
display: flex;
|
||||
width: 1439px;
|
||||
.box1{
|
||||
flex: 1;
|
||||
}
|
||||
.box2{
|
||||
flex: 1;
|
||||
// float: right;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
import req from '@utils/request'
|
||||
import { Card, Checkbox, Descriptions } from 'antd'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
const apiName = {
|
||||
/**
|
||||
* 查询大类
|
||||
*/
|
||||
queryPrimaryCategory: '/category/queryPrimaryCategory',
|
||||
|
||||
// 查询分类及标签
|
||||
queryCategoryAndLabel: '/category/queryCategoryAndLabel'
|
||||
}
|
||||
|
||||
const PracticeHome = () => {
|
||||
const [primaryList, setPrimaryList] = useState<Record<string, any>[]>([])
|
||||
const [cateAndLabelList, setCateAndLabelList] = useState<Record<string, any>[]>([])
|
||||
const [currentPrimaryId, setCurrentPrimaryId] = useState()
|
||||
|
||||
const queryPrimaryList = () => {
|
||||
req({
|
||||
method: 'post',
|
||||
url: apiName.queryPrimaryCategory,
|
||||
data: { categoryType: 1 }
|
||||
})
|
||||
.then((res: Record<string, any>) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
setCurrentPrimaryId(res.data[0].id)
|
||||
setPrimaryList([...res.data].map(t => ({ tab: t.categoryName, key: t.id })))
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
queryPrimaryList()
|
||||
}, [])
|
||||
|
||||
const getCategoryAndLabel = () => {
|
||||
req({
|
||||
method: 'post',
|
||||
url: apiName.queryCategoryAndLabel,
|
||||
data: { id: currentPrimaryId }
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
res.data = res.data.map(item => {
|
||||
return {
|
||||
...item,
|
||||
children: item.labelDTOList.map(t => ({ label: t.labelName, value: t.id }))
|
||||
}
|
||||
})
|
||||
setCateAndLabelList([...res.data])
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (currentPrimaryId) {
|
||||
getCategoryAndLabel()
|
||||
}
|
||||
}, [currentPrimaryId])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Card tabList={primaryList}>
|
||||
{cateAndLabelList.map(item => {
|
||||
return (
|
||||
<Descriptions title={item.categoryName} extra={<Checkbox>全选</Checkbox>}>
|
||||
<Descriptions.Item label=''>
|
||||
<Checkbox.Group
|
||||
// value={secondItem.activeList}
|
||||
options={item.children}
|
||||
// onChange={this.onChange(secondIndex)}
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
)
|
||||
})}
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PracticeHome
|
@@ -0,0 +1,155 @@
|
||||
// import req from '@utils/request'
|
||||
import { Card, Input, Pagination, Spin, Tooltip } from 'antd'
|
||||
import React, { useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
import './index.less'
|
||||
|
||||
const { Search } = Input
|
||||
|
||||
const tabList = [
|
||||
{
|
||||
key: '0',
|
||||
tab: '默认'
|
||||
}
|
||||
// {
|
||||
// key: '1',
|
||||
// tab: '最新'
|
||||
// },
|
||||
// {
|
||||
// key: '2',
|
||||
// tab: '最热'
|
||||
// }
|
||||
]
|
||||
|
||||
const PaperView = props => {
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [spinning, setSpinning] = useState(false)
|
||||
const [paperList, setPaperList] = useState([
|
||||
{
|
||||
setId: 1,
|
||||
setName: '测试试卷',
|
||||
setHeat: 1,
|
||||
setDesc: '描述'
|
||||
}
|
||||
])
|
||||
const [orderType, setOrderType] = useState(0)
|
||||
const [setId, setSetId] = useState(0)
|
||||
const [pageInfo, setPageInfo] = useState({
|
||||
total: 0,
|
||||
pageIndex: 1
|
||||
})
|
||||
const [searchText, setSearchText] = useState('')
|
||||
const getPreSetContent = () => {
|
||||
// const { menuId, menuType } = this.props
|
||||
// const { orderType, searchText } = this.state
|
||||
// let params = {
|
||||
// menuId: menuId,
|
||||
// menuType: menuType,
|
||||
// orderType: orderType,
|
||||
// pageInfo: {
|
||||
// pageIndex: this.pageIndex,
|
||||
// pageSize: 8
|
||||
// },
|
||||
// setName: searchText
|
||||
// }
|
||||
// req({
|
||||
// method: 'post',
|
||||
// data: params,
|
||||
// url: 'admin/practice/set/getPreSetContent'
|
||||
// })
|
||||
// .then(res => {
|
||||
// if (res.data.pageList && res.data.pageList?.length > 0) {
|
||||
// this.setState({
|
||||
// paperList: res.data.pageList,
|
||||
// total: res.data.pageInfo.total,
|
||||
// isShowSpin: false,
|
||||
// setId: res.data.pageList.setId
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
// .catch(err => console.log(err))
|
||||
}
|
||||
|
||||
const onTabChange = key => {
|
||||
setOrderType(key)
|
||||
}
|
||||
|
||||
const onChangePagination = pageIndex => {
|
||||
setPageInfo({
|
||||
...pageInfo,
|
||||
pageIndex
|
||||
})
|
||||
}
|
||||
|
||||
const handleJump = setId => navigate('/practice-detail/' + setId)
|
||||
|
||||
const onSearch = value => {
|
||||
setSearchText(value)
|
||||
}
|
||||
|
||||
return (
|
||||
<Spin spinning={spinning}>
|
||||
{/* <div className='paper-box-search'>
|
||||
<Search
|
||||
placeholder='请输入试卷名'
|
||||
onSearch={onSearch}
|
||||
style={{ width: 300, borderRadius: '10px' }}
|
||||
/>
|
||||
</div> */}
|
||||
<div className='paper-box'>
|
||||
<div className='paper-box-cardlist'>
|
||||
<Card
|
||||
style={{ width: '100%' }}
|
||||
tabList={tabList}
|
||||
bordered={false}
|
||||
activeTabKey={tabList.key}
|
||||
onTabChange={onTabChange}
|
||||
>
|
||||
<div className='ant-card-body'>
|
||||
{paperList?.length > 0 &&
|
||||
paperList.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
className='paper-box-cardlist-body-item'
|
||||
onClick={() => handleJump(item.setId)}
|
||||
key={`paperList_${index}`}
|
||||
>
|
||||
<h1 className='paper-box-cardlist-body-item-title'>{item.setName}</h1>
|
||||
<div className='paper-box-cardlist-body-item-hot'>
|
||||
热度指数:{item.setHeat}
|
||||
</div>
|
||||
<div className='paper-box-cardlist-body-item-describe'>
|
||||
<Tooltip placement='topLeft' title={item.setDesc}>
|
||||
<span className='hide-3-line'>{item.setDesc}</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
<div className='paper-box-paging'>
|
||||
{pageInfo.total > 8 && (
|
||||
<Pagination
|
||||
style={{
|
||||
padding: '24px 0',
|
||||
textAlign: 'center'
|
||||
}}
|
||||
showQuickJumper
|
||||
current={pageInfo.pageIndex}
|
||||
defaultCurrent={1}
|
||||
total={pageInfo.total}
|
||||
defaultPageSize={10}
|
||||
onChange={onChangePagination}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
|
||||
export default PaperView
|
@@ -0,0 +1,76 @@
|
||||
.paper-box-search {
|
||||
margin-left: 600px;
|
||||
}
|
||||
.paper-box {
|
||||
.paper-box-cardlist {
|
||||
border-radius: 3px;
|
||||
margin-bottom: 10px;
|
||||
.ant-card-body {
|
||||
padding: 20px 10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.paper-box-cardlist-body-item {
|
||||
height: 190px;
|
||||
width: 210px;
|
||||
padding: 20px 30px;
|
||||
margin: 0 15px 10px 0px;
|
||||
border-radius: 3px;
|
||||
background-image: url(../../../../../imgs/badcf6d37c476233.png);
|
||||
background-size: 100% 100%;
|
||||
cursor: pointer;
|
||||
transition: all 0.5s;
|
||||
&:hover {
|
||||
transform: scale(1.04);
|
||||
}
|
||||
.paper-box-cardlist-body-item-title {
|
||||
max-height: 40px;
|
||||
margin-top: 15px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 10px;
|
||||
height: 100px;
|
||||
line-height: 1.4;
|
||||
font-weight: 400;
|
||||
font-weight: bolder;
|
||||
}
|
||||
.paper-box-cardlist-body-item-logo {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
text-align: center;
|
||||
line-height: 80px;
|
||||
margin: 10px auto 0;
|
||||
border-radius: 50px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.paper-box-cardlist-body-item-hot {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.paper-box-cardlist-body-item-describe {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
box-sizing: border-box;
|
||||
padding-top: 10px;
|
||||
.hide-3-line {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
src/views/practise/practice-questions/constant.js
Normal file
20
src/views/practise/practice-questions/constant.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 接口
|
||||
*/
|
||||
export const ApiName = {
|
||||
/**
|
||||
* 获取左侧菜单
|
||||
*/
|
||||
getPracticeMenu: '/admin/practice/set/getPracticeMenu',
|
||||
/**
|
||||
* 获取右侧内容
|
||||
*/
|
||||
getSpecialPracticeContent: '/admin/practice/set/getSpecialPracticeContent',
|
||||
/**
|
||||
* 查询大类
|
||||
*/
|
||||
queryPrimaryCategory: '/category/queryPrimaryCategory',
|
||||
|
||||
// 查询分类及标签
|
||||
queryCategoryAndLabel: '/category/queryCategoryAndLabel'
|
||||
}
|
159
src/views/practise/practice-questions/index.jsx
Normal file
159
src/views/practise/practice-questions/index.jsx
Normal file
@@ -0,0 +1,159 @@
|
||||
import { MailOutlined } from '@ant-design/icons'
|
||||
import req from '@utils/request'
|
||||
import { Menu } from 'antd'
|
||||
import React, { Component, Fragment } from 'react'
|
||||
import PaperEnd from './components/paper-end/index'
|
||||
import { ApiName } from './constant'
|
||||
import './index.less'
|
||||
|
||||
const { SubMenu } = Menu
|
||||
|
||||
export default class PracticeQuestions extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
currentKey: '', // 选中的menu
|
||||
subMenuList: []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前选择的二级菜单
|
||||
*/
|
||||
currentKeyMap = {}
|
||||
|
||||
/**
|
||||
* 当前选择的二级菜单对应的一级菜单
|
||||
*/
|
||||
currentKeyFirstMenuType = 1
|
||||
|
||||
componentDidMount() {
|
||||
this.getPracticeMenu()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取左侧菜单
|
||||
*/
|
||||
getPracticeMenu() {
|
||||
this.currentKeyMap = {
|
||||
menuName: '试卷',
|
||||
menuId: '10',
|
||||
menuType: 2
|
||||
}
|
||||
this.setState({
|
||||
currentKey: '10',
|
||||
subMenuList: [
|
||||
{
|
||||
title: '模拟套卷',
|
||||
detailVOS: [
|
||||
{
|
||||
menuName: '后端',
|
||||
menuId: '10',
|
||||
menuType: 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
return
|
||||
// return new Promise(resolve => {
|
||||
// resolve()
|
||||
// })
|
||||
req({
|
||||
method: 'post',
|
||||
data: {},
|
||||
url: ApiName.getPracticeMenu
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
this.currentKeyMap = res.data[0].detailVOS[0]
|
||||
this.setState({
|
||||
subMenuList: res.data,
|
||||
currentKey: this.currentKeyMap.menuId
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(err => console.log(err))
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换菜单
|
||||
* @param {*} e
|
||||
*/
|
||||
handleClick = e => {
|
||||
console.log(e)
|
||||
let { subMenuList, currentKey } = this.state
|
||||
if (currentKey === e.key) {
|
||||
return
|
||||
}
|
||||
// 获得当前选择的下标
|
||||
let index = e.keyPath[1].split('_')[2]
|
||||
// this.currentKeyFirstMenuType = subMenuList[index].id;
|
||||
this.currentKeyFirstMenuType = index // 记录一级菜单
|
||||
|
||||
subMenuList[index].detailVOS.forEach(element => {
|
||||
// 获得当前选中的菜单项
|
||||
if (element.menuId == e.key) {
|
||||
this.currentKeyMap = element
|
||||
}
|
||||
})
|
||||
this.setState({
|
||||
currentKey: e.key
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { currentKey, subMenuList } = this.state
|
||||
return (
|
||||
<Fragment>
|
||||
{subMenuList?.length > 0 && (
|
||||
<div className='practice-questions-container'>
|
||||
<div className='practice-questions-menu'>
|
||||
<Menu
|
||||
mode='inline'
|
||||
onClick={this.handleClick}
|
||||
style={{ width: 256 }}
|
||||
defaultOpenKeys={['sub_menu_0']}
|
||||
defaultSelectedKeys={[currentKey + '']}
|
||||
>
|
||||
{subMenuList.map((subMenuItem, subMenuIndex) => {
|
||||
return (
|
||||
<SubMenu
|
||||
key={`sub_menu_${subMenuIndex}`}
|
||||
title={subMenuItem.title}
|
||||
icon={<MailOutlined />}
|
||||
>
|
||||
{subMenuItem?.detailVOS?.length > 0 &&
|
||||
subMenuItem?.detailVOS?.map(menuItem => {
|
||||
return (
|
||||
<Menu.Item key={menuItem.menuId}>
|
||||
{menuItem.menuType == 1 ? 'GRADE ' : ''}
|
||||
{menuItem.menuName}
|
||||
</Menu.Item>
|
||||
)
|
||||
})}
|
||||
</SubMenu>
|
||||
)
|
||||
})}
|
||||
</Menu>
|
||||
</div>
|
||||
<div className='practice-questions-box' key={this.currentKeyMap.menuId}>
|
||||
{/* {this.currentKeyFirstMenuType == 0 ? (
|
||||
<FrontEnd
|
||||
menuId={this.currentKeyMap.menuId}
|
||||
menuType={this.currentKeyMap.menuType}
|
||||
/>
|
||||
) : (
|
||||
<PaperEnd
|
||||
menuId={this.currentKeyMap.menuId}
|
||||
menuType={this.currentKeyMap.menuType}
|
||||
/>
|
||||
)} */}
|
||||
<PaperEnd menuId={this.currentKeyMap.menuId} menuType={this.currentKeyMap.menuType} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
}
|
50
src/views/practise/practice-questions/index.less
Normal file
50
src/views/practise/practice-questions/index.less
Normal file
@@ -0,0 +1,50 @@
|
||||
.practice-questions-container {
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
width: 1439px;
|
||||
// padding: 20px 50px;
|
||||
border-radius: 5px;
|
||||
// flex-direction: column;
|
||||
overflow: auto;
|
||||
.practice-questions-menu {
|
||||
margin-right: 20px;
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
background-color: white;
|
||||
|
||||
.ant-menu-submenu > .ant-menu {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
// 右边线去掉
|
||||
.ant-menu-inline,
|
||||
.ant-menu-vertical,
|
||||
.ant-menu-vertical-left {
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
.practice-questions-box {
|
||||
flex: 1;
|
||||
margin: 0 auto;
|
||||
background-color: white;
|
||||
padding: 20px 50px;
|
||||
border-radius: 5px;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
.tab-name {
|
||||
color: rgba(60, 110, 238, 1) !important;
|
||||
}
|
||||
.but {
|
||||
margin-bottom: 50px;
|
||||
.button {
|
||||
// size: 25px;
|
||||
width: 120px;
|
||||
block-size: 40px;
|
||||
color: white;
|
||||
// background-color: rgba(60, 110, 238, 0.7) !important;
|
||||
background-color: rgba(60, 110, 238, 1);
|
||||
border-radius: 36px;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,39 +1,39 @@
|
||||
.question-bank-box {
|
||||
display: flex;
|
||||
width: 1439px;
|
||||
margin: 0 auto;
|
||||
background-color: #f3f4f6;
|
||||
border-radius: 5px;
|
||||
height: calc(100vh - 90px);
|
||||
overflow-y: scroll;
|
||||
.mask-box {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
border-radius: 8px;
|
||||
.question-box {
|
||||
.category-list-box {
|
||||
padding: 24px 24px 6px;
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.question-list-box {
|
||||
margin-top: 1px;
|
||||
}
|
||||
.loading-more{
|
||||
background-color: white;
|
||||
text-align: center;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ranking-box {
|
||||
margin-left: 16px;
|
||||
overflow-y: auto;
|
||||
width: 310px;
|
||||
}
|
||||
.ant-spin-nested-loading {
|
||||
display: flex;
|
||||
width: 1439px;
|
||||
margin: 0 auto;
|
||||
background-color: #f3f4f6;
|
||||
border-radius: 5px;
|
||||
height: calc(100vh - 90px);
|
||||
overflow-y: scroll;
|
||||
.mask-box {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
border-radius: 8px;
|
||||
.question-box {
|
||||
.category-list-box {
|
||||
padding: 24px 24px 6px;
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.question-list-box {
|
||||
margin-top: 1px;
|
||||
}
|
||||
.loading-more {
|
||||
background-color: white;
|
||||
text-align: center;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ranking-box {
|
||||
margin-left: 16px;
|
||||
overflow-y: auto;
|
||||
width: 310px;
|
||||
}
|
||||
.ant-spin-nested-loading {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
@@ -31,7 +31,6 @@ const QuestionBank = () => {
|
||||
* @param {*} assembleIds 三级标签 assembleIds
|
||||
*/
|
||||
const onChangeLabel = values => {
|
||||
console.log(values)
|
||||
setSelectedValue(values)
|
||||
setQuestionList([])
|
||||
setTotal(0)
|
||||
|
@@ -1,341 +1,341 @@
|
||||
import React, { Component, Fragment, createRef } from 'react';
|
||||
import { Input, Modal, message, Spin } from 'antd';
|
||||
import { Input, Modal, message } from 'antd'
|
||||
import React, { Component, Fragment, createRef } from 'react'
|
||||
|
||||
import req from '@utils/request';
|
||||
import { debounce } from '@utils';
|
||||
import KindEditor from '../kind-editor';
|
||||
import RankLabelBox from '../rank-label-box';
|
||||
import RepeatContentBox from '../repeat-content-box';
|
||||
import { apiName } from '../../constant';
|
||||
import { debounce } from '@utils'
|
||||
import req from '@utils/request'
|
||||
import { apiName } from '../../constant'
|
||||
import QuestionEditor from '../question-editor'
|
||||
import './index.less';
|
||||
import RankLabelBox from '../rank-label-box'
|
||||
import RepeatContentBox from '../repeat-content-box'
|
||||
import './index.less'
|
||||
|
||||
export default class BriefQuestions extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
subjectName: '', // 题目
|
||||
isDisabledSubmit: true, //是否禁止输入
|
||||
isShowModalBox: false, // 是否展示重复率弹框
|
||||
isSubmit: true, // 是否支持提交
|
||||
};
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
subjectName: '', // 题目
|
||||
isDisabledSubmit: true, //是否禁止输入
|
||||
isShowModalBox: false, // 是否展示重复率弹框
|
||||
isSubmit: true // 是否支持提交
|
||||
}
|
||||
kindEditor = createRef();
|
||||
rankLabelBox = createRef();
|
||||
rankId = 1; //职级
|
||||
subjectAnswer = ''; // 答案
|
||||
firstCategoryValue = ''; // 一级分类的值
|
||||
secondCategoryValue = []; // 二级分类的值
|
||||
thirdCategoryValue = []; // 三级标签的值
|
||||
repeatInfo = {}; // 重复率
|
||||
}
|
||||
kindEditor = createRef()
|
||||
rankLabelBox = createRef()
|
||||
rankId = 1 //职级
|
||||
subjectAnswer = '' // 答案
|
||||
firstCategoryValue = '' // 一级分类的值
|
||||
secondCategoryValue = [] // 二级分类的值
|
||||
thirdCategoryValue = [] // 三级标签的值
|
||||
repeatInfo = {} // 重复率
|
||||
|
||||
/**
|
||||
* 输入题目
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectName = (e) => {
|
||||
let str = e.target.value.trim();
|
||||
this.setState(
|
||||
{
|
||||
subjectName: str,
|
||||
},
|
||||
() => {
|
||||
// this.rankLabelBox.getThirdCategoryList();
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 富文本编辑器
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeEditor = (e) => {
|
||||
this.subjectAnswer = e;
|
||||
let isDisabledSubmit = this.checkData();
|
||||
/**
|
||||
* 输入题目
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectName = e => {
|
||||
let str = e.target.value.trim()
|
||||
this.setState(
|
||||
{
|
||||
subjectName: str
|
||||
},
|
||||
() => {
|
||||
// this.rankLabelBox.getThirdCategoryList();
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 一次确认录入
|
||||
*/
|
||||
onSubmit = debounce(() => {
|
||||
console.log(this.rankId)
|
||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state;
|
||||
if (isDisabledSubmit || !isSubmit) {
|
||||
return;
|
||||
}
|
||||
if (!isSubmit) {
|
||||
return;
|
||||
}
|
||||
if (!!!subjectName) {
|
||||
message.warning('请输入题目名称');
|
||||
return;
|
||||
}
|
||||
if (!!!this.subjectAnswer) {
|
||||
message.warning('请输入题目答案');
|
||||
return;
|
||||
}
|
||||
if (!!!this.firstCategoryValue) {
|
||||
message.warning('请选择一级分类');
|
||||
return;
|
||||
}
|
||||
if (this.secondCategoryValue.length <= 0) {
|
||||
message.warning('请选择二级分类');
|
||||
return;
|
||||
}
|
||||
if (this.thirdCategoryValue.length <= 0) {
|
||||
message.warning('请选择三级标签');
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
isSubmit: false,
|
||||
});
|
||||
let params = {
|
||||
subjectName: subjectName,
|
||||
subjectDifficult: this.rankId,
|
||||
subjectType: 4,
|
||||
subjectScore: 1,
|
||||
subjectParse: '解析什么',
|
||||
subjectAnswer: this.subjectAnswer,
|
||||
categoryIds: this.secondCategoryValue.filter(item => item.active).map(t => t.id),
|
||||
labelIds: this.thirdCategoryValue.filter(item => item.active).map(t => t.id),
|
||||
};
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.add,
|
||||
isDisabledSubmit
|
||||
})
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
isSubmit: true,
|
||||
}, () => {
|
||||
this.successModalConfirm();
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
isSubmit: true,
|
||||
});
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
checkData = () => {
|
||||
const { subjectName } = this.state;
|
||||
let isDisabledSubmit = false;
|
||||
if (
|
||||
!!!subjectName ||
|
||||
!!!this.subjectAnswer ||
|
||||
!!!this.firstCategoryValue ||
|
||||
this.secondCategoryValue.length <= 0
|
||||
// ||
|
||||
// this.thirdCategoryValue.length <= 0
|
||||
) {
|
||||
isDisabledSubmit = true;
|
||||
}
|
||||
return isDisabledSubmit;
|
||||
};
|
||||
/**
|
||||
* 富文本编辑器
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeEditor = e => {
|
||||
this.subjectAnswer = e
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isDisabledSubmit
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
onCancel = () => {
|
||||
console.log(this.kindEditor)
|
||||
this.subjectAnswer = ''; // 答案
|
||||
this.rankId = 1;
|
||||
this.firstCategoryValue = '';
|
||||
this.secondCategoryValue = [];
|
||||
this.thirdCategoryValue = [];
|
||||
this.repeatInfo = {};
|
||||
this.kindEditor.current.onClear();
|
||||
this.rankLabelBox.current.initRankLabel();
|
||||
this.setState({
|
||||
subjectName: '',
|
||||
isShowModalBox: false,
|
||||
isSubmit: true, // 是否支持提交
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 重复率弹框-确认录入
|
||||
*/
|
||||
onSubmitRepeatModal = debounce(
|
||||
() => {
|
||||
let params = {
|
||||
docId: this.repeatInfo.repeatDocId,
|
||||
};
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addRepeatInterviewSubject,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
this.successModalConfirm();
|
||||
} else {
|
||||
message.info('请再次确认');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
message.error('请再次确认');
|
||||
});
|
||||
},
|
||||
300,
|
||||
true
|
||||
);
|
||||
|
||||
/**
|
||||
* 重复率弹框-取消录入
|
||||
*/
|
||||
onCancelRepeatModal = () => {
|
||||
this.repeatInfo = {};
|
||||
this.setState({
|
||||
isShowModalBox: false,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功的弹框
|
||||
*/
|
||||
successModalConfirm = () => {
|
||||
Modal.confirm({
|
||||
title: (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: 'rgba(60, 110, 238, 1)',
|
||||
fontSize: 16,
|
||||
}}>
|
||||
录入成功!贡献榜火力值 + 1
|
||||
</div>
|
||||
),
|
||||
closable: false,
|
||||
maskClosable: false,
|
||||
icon: ' ',
|
||||
onOk: this.onAgainSuccessModal,
|
||||
onCancel: this.onGoHomeSuccessModal,
|
||||
okText: '再录一题',
|
||||
cancelText: '去首页',
|
||||
className: 'questions-success-modal-confirm',
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-再来一题
|
||||
*/
|
||||
onAgainSuccessModal = () => {
|
||||
this.onCancel();
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-去首页
|
||||
*/
|
||||
onGoHomeSuccessModal = () => {
|
||||
window.location.href = '/question-bank';
|
||||
};
|
||||
|
||||
/**
|
||||
* 分类选择
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeRankLabel = (firstCategoryValue, secondCategoryValue, thirdCategoryValue) => {
|
||||
this.firstCategoryValue = firstCategoryValue; // 一级分类的值
|
||||
this.secondCategoryValue = secondCategoryValue; // 二级分类的值
|
||||
this.thirdCategoryValue = thirdCategoryValue; // 三级标签的值
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 职级选择
|
||||
* @param {*} list
|
||||
*/
|
||||
handleChangeRank = (list) => {
|
||||
this.rankId = list[0].categoryId;
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { subjectName, isDisabledSubmit, isSubmit, isShowModalBox } = this.state;
|
||||
const { questionsType } = this.props;
|
||||
// this.successModalConfirm();
|
||||
|
||||
return (
|
||||
<Spin spinning={!isSubmit}>
|
||||
<Fragment>
|
||||
<div className="brief-questions-container">
|
||||
<div className="brief-questions-title">题目名称:</div>
|
||||
<div className="brief-questions-main">
|
||||
<Input
|
||||
placeholder="输入题目"
|
||||
className="brief-questions-input"
|
||||
value={subjectName}
|
||||
maxLength={64}
|
||||
onChange={this.onChangeSubjectName}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="brief-questions-container">
|
||||
<div className="brief-questions-title">题目答案:</div>
|
||||
{this.reanderAnser()}
|
||||
</div>
|
||||
<RankLabelBox
|
||||
subjectName={subjectName}
|
||||
onChangeRankLabel={this.onChangeRankLabel}
|
||||
handleChangeRank={this.handleChangeRank}
|
||||
ref={this.rankLabelBox}
|
||||
/>
|
||||
<div className="brief-questions-btns-container">
|
||||
<div className="brief-questions-btn" onClick={this.onCancel}>
|
||||
清空
|
||||
</div>
|
||||
<div
|
||||
className={`brief-questions-btn brief-questions-submit ${isDisabledSubmit && 'brief-questions-disabled-submit'
|
||||
}`}
|
||||
onClick={this.onSubmit}>
|
||||
提交
|
||||
</div>
|
||||
</div>
|
||||
<RepeatContentBox
|
||||
isShowModalBox={isShowModalBox}
|
||||
repeatQuestionsType={questionsType}
|
||||
repeatInfo={this.repeatInfo}
|
||||
handleSubmitRepeatModal={this.onSubmitRepeatModal}
|
||||
handleCancelRepeatModal={this.onCancelRepeatModal}
|
||||
/>
|
||||
</Fragment>
|
||||
</Spin>
|
||||
);
|
||||
/**
|
||||
* 一次确认录入
|
||||
*/
|
||||
onSubmit = debounce(() => {
|
||||
console.log(this.rankId)
|
||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state
|
||||
if (isDisabledSubmit || !isSubmit) {
|
||||
return
|
||||
}
|
||||
if (!isSubmit) {
|
||||
return
|
||||
}
|
||||
if (!!!subjectName) {
|
||||
message.warning('请输入题目名称')
|
||||
return
|
||||
}
|
||||
if (!!!this.subjectAnswer) {
|
||||
message.warning('请输入题目答案')
|
||||
return
|
||||
}
|
||||
if (!!!this.firstCategoryValue) {
|
||||
message.warning('请选择一级分类')
|
||||
return
|
||||
}
|
||||
if (this.secondCategoryValue.length <= 0) {
|
||||
message.warning('请选择二级分类')
|
||||
return
|
||||
}
|
||||
if (this.thirdCategoryValue.length <= 0) {
|
||||
message.warning('请选择三级标签')
|
||||
return
|
||||
}
|
||||
this.setState({
|
||||
isSubmit: false
|
||||
})
|
||||
let params = {
|
||||
subjectName: subjectName,
|
||||
subjectDifficult: this.rankId,
|
||||
subjectType: 4,
|
||||
subjectScore: 1,
|
||||
subjectParse: '解析什么',
|
||||
subjectAnswer: this.subjectAnswer,
|
||||
categoryIds: this.secondCategoryValue.filter(item => item.active).map(t => t.id),
|
||||
labelIds: this.thirdCategoryValue.filter(item => item.active).map(t => t.id)
|
||||
}
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.add
|
||||
})
|
||||
.then(res => {
|
||||
this.setState(
|
||||
{
|
||||
isSubmit: true
|
||||
},
|
||||
() => {
|
||||
this.successModalConfirm()
|
||||
}
|
||||
)
|
||||
})
|
||||
.catch(err => {
|
||||
this.setState({
|
||||
isSubmit: true
|
||||
})
|
||||
console.log(err)
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* 问答题-答案
|
||||
*/
|
||||
reanderAnser = () => {
|
||||
return (
|
||||
<div className="brief-questions-main">
|
||||
<QuestionEditor
|
||||
onChange={this.onChangeEditor}
|
||||
ref={this.kindEditor}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
checkData = () => {
|
||||
const { subjectName } = this.state
|
||||
let isDisabledSubmit = false
|
||||
if (
|
||||
!!!subjectName ||
|
||||
!!!this.subjectAnswer ||
|
||||
!!!this.firstCategoryValue ||
|
||||
this.secondCategoryValue.length <= 0
|
||||
// ||
|
||||
// this.thirdCategoryValue.length <= 0
|
||||
) {
|
||||
isDisabledSubmit = true
|
||||
}
|
||||
return isDisabledSubmit
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
onCancel = () => {
|
||||
this.subjectAnswer = '' // 答案
|
||||
this.rankId = 1
|
||||
this.firstCategoryValue = ''
|
||||
this.secondCategoryValue = []
|
||||
this.thirdCategoryValue = []
|
||||
this.repeatInfo = {}
|
||||
this.kindEditor.current.onClear()
|
||||
this.rankLabelBox.current.initRankLabel()
|
||||
this.setState({
|
||||
subjectName: '',
|
||||
isShowModalBox: false,
|
||||
isSubmit: true // 是否支持提交
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 重复率弹框-确认录入
|
||||
*/
|
||||
onSubmitRepeatModal = debounce(
|
||||
() => {
|
||||
let params = {
|
||||
docId: this.repeatInfo.repeatDocId
|
||||
}
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addRepeatInterviewSubject
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data) {
|
||||
this.successModalConfirm()
|
||||
} else {
|
||||
message.info('请再次确认')
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
message.error('请再次确认')
|
||||
})
|
||||
},
|
||||
300,
|
||||
true
|
||||
)
|
||||
|
||||
/**
|
||||
* 重复率弹框-取消录入
|
||||
*/
|
||||
onCancelRepeatModal = () => {
|
||||
this.repeatInfo = {}
|
||||
this.setState({
|
||||
isShowModalBox: false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 录入成功的弹框
|
||||
*/
|
||||
successModalConfirm = () => {
|
||||
Modal.confirm({
|
||||
title: (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: 'rgba(60, 110, 238, 1)',
|
||||
fontSize: 16
|
||||
}}
|
||||
>
|
||||
录入成功!贡献榜火力值 + 1
|
||||
</div>
|
||||
),
|
||||
closable: false,
|
||||
maskClosable: false,
|
||||
icon: ' ',
|
||||
onOk: this.onAgainSuccessModal,
|
||||
onCancel: this.onGoHomeSuccessModal,
|
||||
okText: '再录一题',
|
||||
cancelText: '去首页',
|
||||
className: 'questions-success-modal-confirm'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 录入成功弹框-再来一题
|
||||
*/
|
||||
onAgainSuccessModal = () => {
|
||||
this.onCancel()
|
||||
}
|
||||
|
||||
/**
|
||||
* 录入成功弹框-去首页
|
||||
*/
|
||||
onGoHomeSuccessModal = () => {
|
||||
window.location.href = '/question-bank'
|
||||
}
|
||||
|
||||
/**
|
||||
* 分类选择
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeRankLabel = (firstCategoryValue, secondCategoryValue, thirdCategoryValue) => {
|
||||
this.firstCategoryValue = firstCategoryValue // 一级分类的值
|
||||
this.secondCategoryValue = secondCategoryValue // 二级分类的值
|
||||
this.thirdCategoryValue = thirdCategoryValue // 三级标签的值
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isDisabledSubmit
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 职级选择
|
||||
* @param {*} list
|
||||
*/
|
||||
handleChangeRank = list => {
|
||||
this.rankId = list[0].categoryId
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isDisabledSubmit
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { subjectName, isDisabledSubmit, isSubmit, isShowModalBox } = this.state
|
||||
const { questionsType } = this.props
|
||||
// this.successModalConfirm();
|
||||
|
||||
return (
|
||||
// <Spin spinning={!isSubmit}>
|
||||
<Fragment>
|
||||
<div className='brief-questions-container'>
|
||||
<div className='brief-questions-title'>题目名称:</div>
|
||||
<div className='brief-questions-main'>
|
||||
<Input
|
||||
placeholder='输入题目'
|
||||
className='brief-questions-input'
|
||||
value={subjectName}
|
||||
maxLength={64}
|
||||
onChange={this.onChangeSubjectName}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='brief-questions-container'>
|
||||
<div className='brief-questions-title'>题目答案:</div>
|
||||
{this.reanderAnser()}
|
||||
</div>
|
||||
<RankLabelBox
|
||||
subjectName={subjectName}
|
||||
onChangeRankLabel={this.onChangeRankLabel}
|
||||
handleChangeRank={this.handleChangeRank}
|
||||
ref={this.rankLabelBox}
|
||||
/>
|
||||
<div className='brief-questions-btns-container'>
|
||||
<div className='brief-questions-btn' onClick={this.onCancel}>
|
||||
清空
|
||||
</div>
|
||||
<div
|
||||
className={`brief-questions-btn brief-questions-submit ${
|
||||
isDisabledSubmit && 'brief-questions-disabled-submit'
|
||||
}`}
|
||||
onClick={this.onSubmit}
|
||||
>
|
||||
提交
|
||||
</div>
|
||||
</div>
|
||||
<RepeatContentBox
|
||||
isShowModalBox={isShowModalBox}
|
||||
repeatQuestionsType={questionsType}
|
||||
repeatInfo={this.repeatInfo}
|
||||
handleSubmitRepeatModal={this.onSubmitRepeatModal}
|
||||
handleCancelRepeatModal={this.onCancelRepeatModal}
|
||||
/>
|
||||
</Fragment>
|
||||
// {/* </Spin> */}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 问答题-答案
|
||||
*/
|
||||
reanderAnser = () => {
|
||||
return (
|
||||
<div className='brief-questions-main'>
|
||||
<QuestionEditor onChange={this.onChangeEditor} ref={this.kindEditor} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,327 +1,312 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { Input, Modal, message, Spin } from 'antd';
|
||||
import req from '@utils/request';
|
||||
import { debounce } from '@utils';
|
||||
import RankLabelBox from '../rank-label-box';
|
||||
import OptionInputBox from '../option-input-box';
|
||||
import RepeatContentBox from '../repeat-content-box';
|
||||
import { apiName } from '../../constant';
|
||||
import './index.less';
|
||||
import { debounce } from '@utils'
|
||||
import req from '@utils/request'
|
||||
import { Input, Modal, Spin, message } from 'antd'
|
||||
import React, { Component, Fragment, createRef } from 'react'
|
||||
import { apiName } from '../../constant'
|
||||
import OptionInputBox from '../option-input-box'
|
||||
import RankLabelBox from '../rank-label-box'
|
||||
import RepeatContentBox from '../repeat-content-box'
|
||||
import './index.less'
|
||||
export default class JudgeQuestions extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
subjectName: '', // 题目
|
||||
isDisabledSubmit: true, //是否禁止输入
|
||||
isShowModalBox: false, // 是否展示重复率弹框
|
||||
isSubmit: true, // 是否支持提交
|
||||
};
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
subjectName: '', // 题目
|
||||
isDisabledSubmit: true, //是否禁止输入
|
||||
isShowModalBox: false, // 是否展示重复率弹框
|
||||
isSubmit: true // 是否支持提交
|
||||
}
|
||||
rankLabelBox = RankLabelBox | null;
|
||||
optionInputBox = OptionInputBox | null;
|
||||
currentActive = []; // 当前选中的项
|
||||
scoreValue = ''; // 分数
|
||||
subjectAnalysis = ''; //试题解析
|
||||
rankId = 1; //职级
|
||||
firstCategoryValue = ''; // 一级分类的值
|
||||
secondCategoryValue = []; // 二级分类的值
|
||||
thirdCategoryValue = []; // 三级标签的值
|
||||
repeatInfo = {}; // 重复率
|
||||
}
|
||||
// rankLabelBox = RankLabelBox | null
|
||||
rankLabelBox = createRef()
|
||||
optionInputBox = OptionInputBox | null
|
||||
currentActive = [] // 当前选中的项
|
||||
scoreValue = '' // 分数
|
||||
subjectAnalysis = '' //试题解析
|
||||
rankId = 1 //职级
|
||||
firstCategoryValue = '' // 一级分类的值
|
||||
secondCategoryValue = [] // 二级分类的值
|
||||
thirdCategoryValue = [] // 三级标签的值
|
||||
repeatInfo = {} // 重复率
|
||||
|
||||
/**
|
||||
* 输入题目
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectName = (e) => {
|
||||
let str = e.target.value.trim();
|
||||
this.setState(
|
||||
{
|
||||
subjectName: str,
|
||||
},
|
||||
() => {
|
||||
this.rankLabelBox.getThirdCategoryList();
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 一次确认录入
|
||||
*/
|
||||
onSubmit = debounce(() => {
|
||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state;
|
||||
if (isDisabledSubmit || !isSubmit) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* 输入题目
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectName = e => {
|
||||
let str = e.target.value.trim()
|
||||
this.setState(
|
||||
{
|
||||
subjectName: str
|
||||
},
|
||||
() => {
|
||||
// this.rankLabelBox.getThirdCategoryList();
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isSubmit: false,
|
||||
});
|
||||
let params = {
|
||||
subjectName: subjectName,
|
||||
difficulty: this.rankId,
|
||||
subjectType: 3,
|
||||
subjectScore: this.scoreValue,
|
||||
subjectParse: this.subjectAnalysis,
|
||||
isCorrect: this.currentActive[0],
|
||||
categoryIds: this.secondCategoryValue,
|
||||
labelIds: this.thirdCategoryValue,
|
||||
};
|
||||
console.log('判断录入 ----', params);
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addInterviewSubject,
|
||||
isDisabledSubmit
|
||||
})
|
||||
.then((res) => {
|
||||
this.repeatInfo = {};
|
||||
if (res.data && res.data.insertStatus) {
|
||||
this.setState(
|
||||
{
|
||||
isSubmit: true,
|
||||
},
|
||||
() => {
|
||||
this.successModalConfirm();
|
||||
}
|
||||
);
|
||||
} else if (!res.data.insertStatus) {
|
||||
this.repeatInfo = {
|
||||
repeatDocId: res.data.docId, // 重复题目id
|
||||
repeatRate: res.data.repeatRate, // 重复率
|
||||
repeatIsCorrect: res.data.isCorrect, // 答案
|
||||
repeatSubjectName: res.data.subjectName, // 重复题目
|
||||
repeatSetterErp: res.data.subjectSetterErp, // 出题人erp
|
||||
repeatSetterName: res.data.subjectSetterName, // 出题人姓名
|
||||
};
|
||||
this.setState({
|
||||
isShowModalBox: true,
|
||||
isSubmit: true,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
isSubmit: true,
|
||||
});
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
checkData = () => {
|
||||
const { subjectName } = this.state;
|
||||
let isDisabledSubmit = false;
|
||||
if (
|
||||
!!!subjectName ||
|
||||
this.currentActive?.length <= 0 ||
|
||||
!!!this.firstCategoryValue ||
|
||||
this.secondCategoryValue.length <= 0 ||
|
||||
this.thirdCategoryValue.length <= 0 ||
|
||||
!!!this.scoreValue
|
||||
) {
|
||||
isDisabledSubmit = true;
|
||||
}
|
||||
return isDisabledSubmit;
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
onCancel = () => {
|
||||
this.currentActive = []; // 选项列表
|
||||
this.scoreValue = ''; // 分数
|
||||
this.subjectAnalysis = ''; //试题解析
|
||||
this.rankId = 1;
|
||||
this.firstCategoryValue = ''; // 一级分类的值
|
||||
this.secondCategoryValue = []; // 二级分类的值
|
||||
this.thirdCategoryValue = []; // 三级标签的值
|
||||
this.repeatInfo = {};
|
||||
this.rankLabelBox.initRankLabel();
|
||||
this.optionInputBox.handleClearOption();
|
||||
this.setState({
|
||||
subjectName: '',
|
||||
isShowModalBox: false,
|
||||
isSubmit: true, // 是否支持提交
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 重复率弹框-确认录入
|
||||
*/
|
||||
onSubmitRepeatModal = debounce(
|
||||
() => {
|
||||
let params = {
|
||||
docId: this.repeatInfo.repeatDocId,
|
||||
};
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addRepeatInterviewSubject,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
this.successModalConfirm();
|
||||
} else {
|
||||
message.info('请再次确认');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
message.error('请再次确认');
|
||||
});
|
||||
},
|
||||
300,
|
||||
true
|
||||
);
|
||||
|
||||
/**
|
||||
* 重复率弹框-取消录入
|
||||
*/
|
||||
onCancelRepeatModal = () => {
|
||||
this.repeatInfo = {};
|
||||
this.setState({
|
||||
isShowModalBox: false,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功的弹框
|
||||
*/
|
||||
successModalConfirm = () => {
|
||||
Modal.confirm({
|
||||
title: (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: 'rgba(60, 110, 238, 1)',
|
||||
fontSize: 16,
|
||||
}}>
|
||||
录入成功!贡献榜火力值 + 1
|
||||
</div>
|
||||
),
|
||||
closable: false,
|
||||
maskClosable: false,
|
||||
icon: ' ',
|
||||
onOk: this.onAgainSuccessModal,
|
||||
onCancel: this.onGoHomeSuccessModal,
|
||||
okText: '再录一题',
|
||||
cancelText: '去首页',
|
||||
className: 'questions-success-modal-confirm',
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-再来一题
|
||||
*/
|
||||
onAgainSuccessModal = () => {
|
||||
this.onCancel();
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-去首页
|
||||
*/
|
||||
onGoHomeSuccessModal = () => {
|
||||
// this.onCancel();
|
||||
window.location.href = '/cms-supplier/question-bank';
|
||||
};
|
||||
|
||||
/**
|
||||
* 分类选择
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeRankLabel = (firstCategoryValue, secondCategoryValue, thirdCategoryValue) => {
|
||||
this.firstCategoryValue = firstCategoryValue; // 一级分类的值
|
||||
this.secondCategoryValue = secondCategoryValue; // 二级分类的值
|
||||
this.thirdCategoryValue = thirdCategoryValue; // 三级标签的值
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 职级选择
|
||||
* @param {*} list
|
||||
*/
|
||||
handleChangeRank = (list) => {
|
||||
this.rankId = list[0];
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 选项操作
|
||||
* @param {*} currentActive 选项列表
|
||||
* @param {*} scoreValue 分值
|
||||
* @param {*} subjectAnalysis 解析
|
||||
*/
|
||||
handleChangeOption = (currentActive, scoreValue, subjectAnalysis) => {
|
||||
this.currentActive = currentActive;
|
||||
this.scoreValue = scoreValue;
|
||||
this.subjectAnalysis = subjectAnalysis;
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { subjectName, isDisabledSubmit, isSubmit, isShowModalBox } = this.state;
|
||||
const { questionsType } = this.props;
|
||||
return (
|
||||
<Spin spinning={!isSubmit}>
|
||||
<Fragment>
|
||||
<div className="judge-questions-container">
|
||||
<div className="judge-questions-title">题目名称:</div>
|
||||
<Input
|
||||
placeholder="输入题目"
|
||||
style={{ height: 48, width: '100%' }}
|
||||
value={subjectName}
|
||||
maxLength={64}
|
||||
onChange={(e) => this.onChangeSubjectName(e)}
|
||||
/>
|
||||
</div>
|
||||
<OptionInputBox
|
||||
ref={(ref) => {
|
||||
this.optionInputBox = ref;
|
||||
}}
|
||||
isJudge={true}
|
||||
handleChangeOption={this.handleChangeOption}
|
||||
/>
|
||||
<RankLabelBox
|
||||
ref={(ref) => {
|
||||
this.rankLabelBox = ref;
|
||||
}}
|
||||
subjectName={subjectName}
|
||||
onChangeRankLabel={this.onChangeRankLabel}
|
||||
handleChangeRank={this.handleChangeRank}
|
||||
/>
|
||||
<div className="judge-questions-btns-container">
|
||||
<div className="judge-questions-btn" onClick={this.onCancel}>
|
||||
清空
|
||||
</div>
|
||||
<div
|
||||
className={`judge-questions-btn judge-questions-submit ${isDisabledSubmit && 'judge-questions-disabled-submit'
|
||||
}`}
|
||||
onClick={this.onSubmit}>
|
||||
提交
|
||||
</div>
|
||||
</div>
|
||||
<RepeatContentBox
|
||||
isShowModalBox={isShowModalBox}
|
||||
repeatQuestionsType={questionsType}
|
||||
repeatInfo={this.repeatInfo}
|
||||
handleSubmitRepeatModal={this.onSubmitRepeatModal}
|
||||
handleCancelRepeatModal={this.onCancelRepeatModal}
|
||||
/>
|
||||
</Fragment>
|
||||
</Spin>
|
||||
);
|
||||
/**
|
||||
* 一次确认录入
|
||||
*/
|
||||
onSubmit = debounce(() => {
|
||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state
|
||||
if (isDisabledSubmit || !isSubmit) {
|
||||
return
|
||||
}
|
||||
this.setState({
|
||||
isSubmit: false
|
||||
})
|
||||
let params = {
|
||||
subjectName: subjectName,
|
||||
subjectDifficult: this.rankId,
|
||||
subjectType: 3,
|
||||
subjectScore: this.scoreValue,
|
||||
subjectParse: this.subjectAnalysis,
|
||||
optionList: [{ isCorrect: this.currentActive[0] }],
|
||||
categoryIds: this.secondCategoryValue.filter(item => item.active).map(t => t.id),
|
||||
labelIds: this.thirdCategoryValue.filter(item => item.active).map(t => t.id)
|
||||
}
|
||||
console.log('判断录入 ----', params)
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.add
|
||||
})
|
||||
.then(res => {
|
||||
this.setState(
|
||||
{
|
||||
isSubmit: true
|
||||
},
|
||||
() => {
|
||||
this.successModalConfirm()
|
||||
}
|
||||
)
|
||||
})
|
||||
.catch(err => {
|
||||
this.setState({
|
||||
isSubmit: true
|
||||
})
|
||||
console.log(err)
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
checkData = () => {
|
||||
const { subjectName } = this.state
|
||||
let isDisabledSubmit = false
|
||||
if (
|
||||
!!!subjectName ||
|
||||
this.currentActive?.length <= 0 ||
|
||||
!!!this.firstCategoryValue ||
|
||||
this.secondCategoryValue.length <= 0 ||
|
||||
this.thirdCategoryValue.length <= 0 ||
|
||||
!!!this.scoreValue
|
||||
) {
|
||||
isDisabledSubmit = true
|
||||
}
|
||||
return isDisabledSubmit
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
onCancel = () => {
|
||||
this.currentActive = [] // 选项列表
|
||||
this.scoreValue = '' // 分数
|
||||
this.subjectAnalysis = '' //试题解析
|
||||
this.rankId = 1
|
||||
this.firstCategoryValue = '' // 一级分类的值
|
||||
this.secondCategoryValue = [] // 二级分类的值
|
||||
this.thirdCategoryValue = [] // 三级标签的值
|
||||
this.repeatInfo = {}
|
||||
this.rankLabelBox.current.initRankLabel()
|
||||
this.optionInputBox.handleClearOption()
|
||||
this.setState({
|
||||
subjectName: '',
|
||||
isShowModalBox: false,
|
||||
isSubmit: true // 是否支持提交
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 重复率弹框-确认录入
|
||||
*/
|
||||
onSubmitRepeatModal = debounce(
|
||||
() => {
|
||||
let params = {
|
||||
docId: this.repeatInfo.repeatDocId
|
||||
}
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addRepeatInterviewSubject
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data) {
|
||||
this.successModalConfirm()
|
||||
} else {
|
||||
message.info('请再次确认')
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
message.error('请再次确认')
|
||||
})
|
||||
},
|
||||
300,
|
||||
true
|
||||
)
|
||||
|
||||
/**
|
||||
* 重复率弹框-取消录入
|
||||
*/
|
||||
onCancelRepeatModal = () => {
|
||||
this.repeatInfo = {}
|
||||
this.setState({
|
||||
isShowModalBox: false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 录入成功的弹框
|
||||
*/
|
||||
successModalConfirm = () => {
|
||||
Modal.confirm({
|
||||
title: (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: 'rgba(60, 110, 238, 1)',
|
||||
fontSize: 16
|
||||
}}
|
||||
>
|
||||
录入成功!贡献榜火力值 + 1
|
||||
</div>
|
||||
),
|
||||
closable: false,
|
||||
maskClosable: false,
|
||||
icon: ' ',
|
||||
onOk: this.onAgainSuccessModal,
|
||||
onCancel: this.onGoHomeSuccessModal,
|
||||
okText: '再录一题',
|
||||
cancelText: '去首页',
|
||||
className: 'questions-success-modal-confirm'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 录入成功弹框-再来一题
|
||||
*/
|
||||
onAgainSuccessModal = () => {
|
||||
this.onCancel()
|
||||
}
|
||||
|
||||
/**
|
||||
* 录入成功弹框-去首页
|
||||
*/
|
||||
onGoHomeSuccessModal = () => {
|
||||
window.location.href = '/question-bank'
|
||||
}
|
||||
|
||||
/**
|
||||
* 分类选择
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeRankLabel = (firstCategoryValue, secondCategoryValue, thirdCategoryValue) => {
|
||||
this.firstCategoryValue = firstCategoryValue // 一级分类的值
|
||||
this.secondCategoryValue = secondCategoryValue // 二级分类的值
|
||||
this.thirdCategoryValue = thirdCategoryValue // 三级标签的值
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isDisabledSubmit
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 职级选择
|
||||
* @param {*} list
|
||||
*/
|
||||
handleChangeRank = list => {
|
||||
this.rankId = list[0]
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isDisabledSubmit
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 选项操作
|
||||
* @param {*} currentActive 选项列表
|
||||
* @param {*} scoreValue 分值
|
||||
* @param {*} subjectAnalysis 解析
|
||||
*/
|
||||
handleChangeOption = (currentActive, scoreValue, subjectAnalysis) => {
|
||||
this.currentActive = currentActive
|
||||
this.scoreValue = scoreValue
|
||||
this.subjectAnalysis = subjectAnalysis
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isDisabledSubmit
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { subjectName, isDisabledSubmit, isSubmit, isShowModalBox } = this.state
|
||||
const { questionsType } = this.props
|
||||
return (
|
||||
<Spin spinning={!isSubmit}>
|
||||
<Fragment>
|
||||
<div className='judge-questions-container'>
|
||||
<div className='judge-questions-title'>题目名称:</div>
|
||||
<Input
|
||||
placeholder='输入题目'
|
||||
style={{ height: 48, width: '100%' }}
|
||||
value={subjectName}
|
||||
maxLength={64}
|
||||
onChange={e => this.onChangeSubjectName(e)}
|
||||
/>
|
||||
</div>
|
||||
<OptionInputBox
|
||||
ref={ref => {
|
||||
this.optionInputBox = ref
|
||||
}}
|
||||
isJudge={true}
|
||||
handleChangeOption={this.handleChangeOption}
|
||||
/>
|
||||
<RankLabelBox
|
||||
ref={this.rankLabelBox}
|
||||
subjectName={subjectName}
|
||||
onChangeRankLabel={this.onChangeRankLabel}
|
||||
handleChangeRank={this.handleChangeRank}
|
||||
/>
|
||||
<div className='judge-questions-btns-container'>
|
||||
<div className='judge-questions-btn' onClick={this.onCancel}>
|
||||
清空
|
||||
</div>
|
||||
<div
|
||||
className={`judge-questions-btn judge-questions-submit ${
|
||||
isDisabledSubmit && 'judge-questions-disabled-submit'
|
||||
}`}
|
||||
onClick={this.onSubmit}
|
||||
>
|
||||
提交
|
||||
</div>
|
||||
</div>
|
||||
<RepeatContentBox
|
||||
isShowModalBox={isShowModalBox}
|
||||
repeatQuestionsType={questionsType}
|
||||
repeatInfo={this.repeatInfo}
|
||||
handleSubmitRepeatModal={this.onSubmitRepeatModal}
|
||||
handleCancelRepeatModal={this.onCancelRepeatModal}
|
||||
/>
|
||||
</Fragment>
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -1,52 +1,52 @@
|
||||
.judge-questions-container {
|
||||
width: 1000px;
|
||||
// width: 1000px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
padding-top: 36px;
|
||||
// label名字title
|
||||
.judge-questions-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
padding-top: 36px;
|
||||
// label名字title
|
||||
.judge-questions-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: 140px;
|
||||
line-height: 40px;
|
||||
font-size: 16px;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
&:before {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
margin-top: 1px;
|
||||
color: #f5222d;
|
||||
font-size: 16px;
|
||||
content: '*';
|
||||
}
|
||||
justify-content: flex-end;
|
||||
width: 140px;
|
||||
line-height: 40px;
|
||||
font-size: 16px;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
&:before {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
margin-top: 1px;
|
||||
color: #f5222d;
|
||||
font-size: 16px;
|
||||
content: '*';
|
||||
}
|
||||
}
|
||||
}
|
||||
.judge-questions-btns-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin: 20px auto;
|
||||
width: 952px;
|
||||
.judge-questions-btn {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin: 20px auto;
|
||||
width: 952px;
|
||||
.judge-questions-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.judge-questions-submit {
|
||||
margin-left: 40px;
|
||||
background-color: #4390f7;
|
||||
color: #fff;
|
||||
border: 1px solid #4390f7;
|
||||
}
|
||||
.judge-questions-disabled-submit {
|
||||
opacity: 0.5;
|
||||
}
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.judge-questions-submit {
|
||||
margin-left: 40px;
|
||||
background-color: #4390f7;
|
||||
color: #fff;
|
||||
border: 1px solid #4390f7;
|
||||
}
|
||||
.judge-questions-disabled-submit {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
@@ -1,343 +1,366 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { Input, Modal, message, Spin } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import req from '@utils/request';
|
||||
import { debounce } from '@utils';
|
||||
import KindEditor from '../kind-editor';
|
||||
import RankLabelBox from '../rank-label-box';
|
||||
import OptionInputBox from '../option-input-box';
|
||||
import RepeatContentBox from '../repeat-content-box';
|
||||
import { apiName } from '../../constant';
|
||||
import './index.less';
|
||||
import { debounce } from '@utils'
|
||||
import req from '@utils/request'
|
||||
import { Input, Modal, Spin, message } from 'antd'
|
||||
import React, { Component, Fragment, createRef } from 'react'
|
||||
import { apiName } from '../../constant'
|
||||
import OptionInputBox from '../option-input-box'
|
||||
import RankLabelBox from '../rank-label-box'
|
||||
import RepeatContentBox from '../repeat-content-box'
|
||||
import './index.less'
|
||||
|
||||
const defalutLabel = '请使用富文本编辑器输入选项内容';
|
||||
const defalutLabel = '请使用富文本编辑器输入选项内容'
|
||||
export default class MultipleQuestions extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
subjectName: '', // 题目
|
||||
isDisabledSubmit: true, //是否禁止输入
|
||||
isShowModalBox: false, // 是否展示重复率弹框
|
||||
isSubmit: true, // 是否支持提交
|
||||
};
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
subjectName: '', // 题目
|
||||
isDisabledSubmit: true, //是否禁止输入
|
||||
isShowModalBox: false, // 是否展示重复率弹框
|
||||
isSubmit: true // 是否支持提交
|
||||
}
|
||||
kindEditor = KindEditor | null;
|
||||
rankLabelBox = RankLabelBox | null;
|
||||
optionInputBox = OptionInputBox | null;
|
||||
currentActive = []; // 选项列表
|
||||
scoreValue = ''; // 分数
|
||||
subjectAnalysis = ''; //试题解析
|
||||
rankId = 1; //职级
|
||||
subjectAnswer = ''; // 选项内容
|
||||
firstCategoryValue = ''; // 一级分类的值
|
||||
secondCategoryValue = []; // 二级分类的值
|
||||
thirdCategoryValue = []; // 三级标签的值
|
||||
repeatInfo = {}; // 重复率
|
||||
}
|
||||
rankLabelBox = createRef()
|
||||
optionInputBox = OptionInputBox | null
|
||||
currentActive = [] // 选项列表
|
||||
scoreValue = '' // 分数
|
||||
subjectAnalysis = '' //试题解析
|
||||
rankId = 1 //职级
|
||||
subjectAnswer = '' // 选项内容
|
||||
firstCategoryValue = '' // 一级分类的值
|
||||
secondCategoryValue = [] // 二级分类的值
|
||||
thirdCategoryValue = [] // 三级标签的值
|
||||
repeatInfo = {} // 重复率
|
||||
|
||||
/**
|
||||
* 输入题目
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectName = (e) => {
|
||||
let str = e.target.value.trim();
|
||||
this.setState(
|
||||
{
|
||||
subjectName: str,
|
||||
},
|
||||
() => {
|
||||
this.rankLabelBox.getThirdCategoryList();
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 一次确认录入
|
||||
*/
|
||||
onSubmit = debounce(() => {
|
||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state;
|
||||
if (isDisabledSubmit || !isSubmit) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* 输入题目
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectName = e => {
|
||||
let str = e.target.value.trim()
|
||||
this.setState(
|
||||
{
|
||||
subjectName: str
|
||||
},
|
||||
() => {
|
||||
// this.rankLabelBox.getThirdCategoryList();
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isSubmit: false,
|
||||
});
|
||||
let params = {
|
||||
subjectName: subjectName,
|
||||
difficulty: this.rankId,
|
||||
subjectType: 2,
|
||||
subjectScore: this.scoreValue,
|
||||
subjectParse: this.subjectAnalysis,
|
||||
categoryIds: this.secondCategoryValue,
|
||||
labelIds: this.thirdCategoryValue,
|
||||
optionList: this.currentActive,
|
||||
};
|
||||
console.log('多选录入 ----', params);
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addInterviewSubject,
|
||||
isDisabledSubmit
|
||||
})
|
||||
.then((res) => {
|
||||
this.repeatInfo = {};
|
||||
if (res.data && res.data.insertStatus) {
|
||||
this.setState(
|
||||
{
|
||||
isSubmit: true,
|
||||
},
|
||||
() => {
|
||||
this.successModalConfirm();
|
||||
}
|
||||
);
|
||||
} else if (!res.data.insertStatus) {
|
||||
this.repeatInfo = {
|
||||
repeatDocId: res.data.docId, // 重复题目id
|
||||
repeatRate: res.data.repeatRate, // 重复率
|
||||
repeatSubjectName: res.data.subjectName, // 重复题目
|
||||
repeatOptionList: res.data.optionList, // 重复列表项
|
||||
repeatSetterErp: res.data.subjectSetterErp, // 出题人erp
|
||||
repeatSetterName: res.data.subjectSetterName, // 出题人姓名
|
||||
};
|
||||
this.setState({
|
||||
isShowModalBox: true,
|
||||
isSubmit: true,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
isSubmit: true,
|
||||
});
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
checkData = () => {
|
||||
const { subjectName } = this.state;
|
||||
let list = this.currentActive.filter((item) => item.optionContent === defalutLabel);
|
||||
let isDisabledSubmit = false;
|
||||
if (
|
||||
!!!subjectName ||
|
||||
list.length > 0 ||
|
||||
!!!this.firstCategoryValue ||
|
||||
this.secondCategoryValue.length <= 0 ||
|
||||
this.thirdCategoryValue.length <= 0 ||
|
||||
!!!this.scoreValue
|
||||
) {
|
||||
isDisabledSubmit = true;
|
||||
}
|
||||
return isDisabledSubmit;
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
onCancel = () => {
|
||||
this.currentActive = []; // 选项列表
|
||||
this.scoreValue = ''; // 分数
|
||||
this.subjectAnalysis = ''; //试题解析
|
||||
this.rankId = 1;
|
||||
this.subjectAnswer = ''; // 选项内容
|
||||
this.firstCategoryValue = ''; // 一级分类的值
|
||||
this.secondCategoryValue = []; // 二级分类的值
|
||||
this.thirdCategoryValue = []; // 三级标签的值
|
||||
this.repeatInfo = {};
|
||||
this.kindEditor && this.kindEditor.onClear();
|
||||
this.rankLabelBox.initRankLabel();
|
||||
this.optionInputBox.handleClearOption();
|
||||
this.setState({
|
||||
subjectName: '',
|
||||
isShowModalBox: false,
|
||||
isSubmit: true, // 是否支持提交
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 重复率弹框-确认录入
|
||||
*/
|
||||
onSubmitRepeatModal = debounce(
|
||||
() => {
|
||||
let params = {
|
||||
docId: this.repeatInfo.repeatDocId,
|
||||
};
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addRepeatInterviewSubject,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
this.successModalConfirm();
|
||||
} else {
|
||||
message.info('请再次确认');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
message.error('请再次确认');
|
||||
});
|
||||
},
|
||||
300,
|
||||
true
|
||||
);
|
||||
|
||||
/**
|
||||
* 重复率弹框-取消录入
|
||||
*/
|
||||
onCancelRepeatModal = () => {
|
||||
this.repeatInfo = {};
|
||||
this.setState({
|
||||
isShowModalBox: false,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功的弹框
|
||||
*/
|
||||
successModalConfirm = () => {
|
||||
Modal.confirm({
|
||||
title: (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: 'rgba(60, 110, 238, 1)',
|
||||
fontSize: 16,
|
||||
}}>
|
||||
录入成功!贡献榜火力值 + 1
|
||||
</div>
|
||||
),
|
||||
closable: false,
|
||||
maskClosable: false,
|
||||
icon: ' ',
|
||||
onOk: this.onAgainSuccessModal,
|
||||
onCancel: this.onGoHomeSuccessModal,
|
||||
okText: '再录一题',
|
||||
cancelText: '去首页',
|
||||
className: 'questions-success-modal-confirm',
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-再来一题
|
||||
*/
|
||||
onAgainSuccessModal = () => {
|
||||
this.onCancel();
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-去首页
|
||||
*/
|
||||
onGoHomeSuccessModal = () => {
|
||||
// this.onCancel();
|
||||
window.location.href = '/cms-supplier/question-bank';
|
||||
};
|
||||
|
||||
/**
|
||||
* 分类选择
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeRankLabel = (firstCategoryValue, secondCategoryValue, thirdCategoryValue) => {
|
||||
this.firstCategoryValue = firstCategoryValue; // 一级分类的值
|
||||
this.secondCategoryValue = secondCategoryValue; // 二级分类的值
|
||||
this.thirdCategoryValue = thirdCategoryValue; // 三级标签的值
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 职级选择
|
||||
* @param {*} list
|
||||
*/
|
||||
handleChangeRank = (list) => {
|
||||
this.rankId = list[0];
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 选项操作
|
||||
* @param {*} currentActive 选项列表
|
||||
* @param {*} scoreValue 分值
|
||||
* @param {*} subjectAnalysis 解析
|
||||
*/
|
||||
handleChangeOption = (currentActive, scoreValue, subjectAnalysis) => {
|
||||
this.currentActive = currentActive;
|
||||
this.scoreValue = scoreValue;
|
||||
this.subjectAnalysis = subjectAnalysis;
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { subjectName, isDisabledSubmit, isSubmit, isShowModalBox } = this.state;
|
||||
const { questionsType } = this.props;
|
||||
return (
|
||||
<Spin spinning={!isSubmit}>
|
||||
<Fragment>
|
||||
<div className="multiple-questions-container">
|
||||
<div className="multiple-questions-title">题目名称:</div>
|
||||
<Input
|
||||
placeholder="输入题目"
|
||||
style={{ height: 48, width: '100%' }}
|
||||
value={subjectName}
|
||||
maxLength={64}
|
||||
onChange={(e) => this.onChangeSubjectName(e)}
|
||||
/>
|
||||
</div>
|
||||
<OptionInputBox
|
||||
key="multiple-option-input"
|
||||
ref={(ref) => {
|
||||
this.optionInputBox = ref;
|
||||
}}
|
||||
isMultiple={true}
|
||||
handleChangeOption={this.handleChangeOption}
|
||||
/>
|
||||
<RankLabelBox
|
||||
ref={(ref) => {
|
||||
this.rankLabelBox = ref;
|
||||
}}
|
||||
subjectName={subjectName}
|
||||
onChangeRankLabel={this.onChangeRankLabel}
|
||||
handleChangeRank={this.handleChangeRank}
|
||||
/>
|
||||
<div className="multiple-questions-btns-container">
|
||||
<div className="multiple-questions-btn" onClick={this.onCancel}>
|
||||
清空
|
||||
</div>
|
||||
<div
|
||||
className={`multiple-questions-btn multiple-questions-submit ${isDisabledSubmit && 'multiple-questions-disabled-submit'
|
||||
}`}
|
||||
onClick={this.onSubmit}>
|
||||
提交
|
||||
</div>
|
||||
</div>
|
||||
<RepeatContentBox
|
||||
isShowModalBox={isShowModalBox}
|
||||
repeatQuestionsType={questionsType}
|
||||
repeatInfo={this.repeatInfo}
|
||||
handleSubmitRepeatModal={this.onSubmitRepeatModal}
|
||||
handleCancelRepeatModal={this.onCancelRepeatModal}
|
||||
/>
|
||||
</Fragment>
|
||||
</Spin>
|
||||
);
|
||||
/**
|
||||
* 一次确认录入
|
||||
*/
|
||||
onSubmit = debounce(() => {
|
||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state
|
||||
if (isDisabledSubmit || !isSubmit) {
|
||||
return
|
||||
}
|
||||
if (!!!subjectName) {
|
||||
message.warning('请输入题目名称')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.currentActive.length) {
|
||||
message.warning('请录入答案')
|
||||
return
|
||||
}
|
||||
if (!!!this.firstCategoryValue) {
|
||||
message.warning('请选择一级分类')
|
||||
return
|
||||
}
|
||||
if (this.secondCategoryValue.length <= 0) {
|
||||
message.warning('请选择二级分类')
|
||||
return
|
||||
}
|
||||
if (this.thirdCategoryValue.length <= 0) {
|
||||
message.warning('请选择三级标签')
|
||||
return
|
||||
}
|
||||
this.setState({
|
||||
isSubmit: false
|
||||
})
|
||||
let params = {
|
||||
subjectName: subjectName,
|
||||
subjectDifficult: this.rankId,
|
||||
subjectType: 2,
|
||||
subjectScore: this.scoreValue,
|
||||
subjectParse: this.subjectAnalysis,
|
||||
categoryIds: this.secondCategoryValue.filter(item => item.active).map(t => t.id),
|
||||
labelIds: this.thirdCategoryValue.filter(item => item.active).map(t => t.id),
|
||||
optionList: this.currentActive
|
||||
}
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.add
|
||||
})
|
||||
.then(res => {
|
||||
// this.repeatInfo = {}
|
||||
// if (res.data && res.data.insertStatus) {
|
||||
// this.setState(
|
||||
// {
|
||||
// isSubmit: true
|
||||
// },
|
||||
// () => {
|
||||
// this.successModalConfirm()
|
||||
// }
|
||||
// )
|
||||
// } else if (!res.data.insertStatus) {
|
||||
// this.repeatInfo = {
|
||||
// repeatDocId: res.data.docId, // 重复题目id
|
||||
// repeatRate: res.data.repeatRate, // 重复率
|
||||
// repeatSubjectName: res.data.subjectName, // 重复题目
|
||||
// repeatOptionList: res.data.optionList, // 重复列表项
|
||||
// repeatSetterErp: res.data.subjectSetterErp, // 出题人erp
|
||||
// repeatSetterName: res.data.subjectSetterName // 出题人姓名
|
||||
// }
|
||||
// this.setState({
|
||||
// isShowModalBox: true,
|
||||
// isSubmit: true
|
||||
// })
|
||||
// }
|
||||
this.setState(
|
||||
{
|
||||
isSubmit: true
|
||||
},
|
||||
() => {
|
||||
this.successModalConfirm()
|
||||
}
|
||||
)
|
||||
})
|
||||
.catch(err => {
|
||||
this.setState({
|
||||
isSubmit: true
|
||||
})
|
||||
console.log(err)
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
checkData = () => {
|
||||
const { subjectName } = this.state
|
||||
let list = this.currentActive.filter(item => item.optionContent === defalutLabel)
|
||||
let isDisabledSubmit = false
|
||||
if (
|
||||
!!!subjectName ||
|
||||
list.length > 0 ||
|
||||
!!!this.firstCategoryValue ||
|
||||
this.secondCategoryValue.length <= 0 ||
|
||||
this.thirdCategoryValue.length <= 0 ||
|
||||
!!!this.scoreValue
|
||||
) {
|
||||
isDisabledSubmit = true
|
||||
}
|
||||
return isDisabledSubmit
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
onCancel = () => {
|
||||
this.currentActive = [] // 选项列表
|
||||
this.scoreValue = '' // 分数
|
||||
this.subjectAnalysis = '' //试题解析
|
||||
this.rankId = 1
|
||||
this.subjectAnswer = '' // 选项内容
|
||||
this.firstCategoryValue = '' // 一级分类的值
|
||||
this.secondCategoryValue = [] // 二级分类的值
|
||||
this.thirdCategoryValue = [] // 三级标签的值
|
||||
this.repeatInfo = {}
|
||||
this.rankLabelBox.current.initRankLabel()
|
||||
this.optionInputBox.handleClearOption()
|
||||
this.setState({
|
||||
subjectName: '',
|
||||
isShowModalBox: false,
|
||||
isSubmit: true // 是否支持提交
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 重复率弹框-确认录入
|
||||
*/
|
||||
onSubmitRepeatModal = debounce(
|
||||
() => {
|
||||
let params = {
|
||||
docId: this.repeatInfo.repeatDocId
|
||||
}
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addRepeatInterviewSubject
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data) {
|
||||
this.successModalConfirm()
|
||||
} else {
|
||||
message.info('请再次确认')
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
message.error('请再次确认')
|
||||
})
|
||||
},
|
||||
300,
|
||||
true
|
||||
)
|
||||
|
||||
/**
|
||||
* 重复率弹框-取消录入
|
||||
*/
|
||||
onCancelRepeatModal = () => {
|
||||
this.repeatInfo = {}
|
||||
this.setState({
|
||||
isShowModalBox: false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 录入成功的弹框
|
||||
*/
|
||||
successModalConfirm = () => {
|
||||
Modal.confirm({
|
||||
title: (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: 'rgba(60, 110, 238, 1)',
|
||||
fontSize: 16
|
||||
}}
|
||||
>
|
||||
录入成功!贡献榜火力值 + 1
|
||||
</div>
|
||||
),
|
||||
closable: false,
|
||||
maskClosable: false,
|
||||
icon: ' ',
|
||||
onOk: this.onAgainSuccessModal,
|
||||
onCancel: this.onGoHomeSuccessModal,
|
||||
okText: '再录一题',
|
||||
cancelText: '去首页',
|
||||
className: 'questions-success-modal-confirm'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 录入成功弹框-再来一题
|
||||
*/
|
||||
onAgainSuccessModal = () => {
|
||||
this.onCancel()
|
||||
}
|
||||
|
||||
/**
|
||||
* 录入成功弹框-去首页
|
||||
*/
|
||||
onGoHomeSuccessModal = () => {
|
||||
window.location.href = '/question-bank'
|
||||
}
|
||||
|
||||
/**
|
||||
* 分类选择
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeRankLabel = (firstCategoryValue, secondCategoryValue, thirdCategoryValue) => {
|
||||
this.firstCategoryValue = firstCategoryValue // 一级分类的值
|
||||
this.secondCategoryValue = secondCategoryValue // 二级分类的值
|
||||
this.thirdCategoryValue = thirdCategoryValue // 三级标签的值
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isDisabledSubmit
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 职级选择
|
||||
* @param {*} list
|
||||
*/
|
||||
handleChangeRank = list => {
|
||||
this.rankId = list[0]
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isDisabledSubmit
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 选项操作
|
||||
* @param {*} currentActive 选项列表
|
||||
* @param {*} scoreValue 分值
|
||||
* @param {*} subjectAnalysis 解析
|
||||
*/
|
||||
handleChangeOption = (currentActive, scoreValue, subjectAnalysis) => {
|
||||
this.currentActive = currentActive
|
||||
this.scoreValue = scoreValue
|
||||
this.subjectAnalysis = subjectAnalysis
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isDisabledSubmit
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { subjectName, isDisabledSubmit, isSubmit, isShowModalBox } = this.state
|
||||
const { questionsType } = this.props
|
||||
return (
|
||||
<Spin spinning={!isSubmit}>
|
||||
<Fragment>
|
||||
<div className='multiple-questions-container'>
|
||||
<div className='multiple-questions-title'>题目名称:</div>
|
||||
<Input
|
||||
placeholder='输入题目'
|
||||
style={{ height: 48, width: '100%' }}
|
||||
value={subjectName}
|
||||
maxLength={64}
|
||||
onChange={e => this.onChangeSubjectName(e)}
|
||||
/>
|
||||
</div>
|
||||
<OptionInputBox
|
||||
key='multiple-option-input'
|
||||
ref={ref => {
|
||||
this.optionInputBox = ref
|
||||
}}
|
||||
isMultiple={true}
|
||||
handleChangeOption={this.handleChangeOption}
|
||||
/>
|
||||
<RankLabelBox
|
||||
ref={this.rankLabelBox}
|
||||
subjectName={subjectName}
|
||||
onChangeRankLabel={this.onChangeRankLabel}
|
||||
handleChangeRank={this.handleChangeRank}
|
||||
/>
|
||||
<div className='multiple-questions-btns-container'>
|
||||
<div className='multiple-questions-btn' onClick={this.onCancel}>
|
||||
清空
|
||||
</div>
|
||||
<div
|
||||
className={`multiple-questions-btn multiple-questions-submit ${
|
||||
isDisabledSubmit && 'multiple-questions-disabled-submit'
|
||||
}`}
|
||||
onClick={this.onSubmit}
|
||||
>
|
||||
提交
|
||||
</div>
|
||||
</div>
|
||||
<RepeatContentBox
|
||||
isShowModalBox={isShowModalBox}
|
||||
repeatQuestionsType={questionsType}
|
||||
repeatInfo={this.repeatInfo}
|
||||
handleSubmitRepeatModal={this.onSubmitRepeatModal}
|
||||
handleCancelRepeatModal={this.onCancelRepeatModal}
|
||||
/>
|
||||
</Fragment>
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -1,52 +1,52 @@
|
||||
.multiple-questions-container {
|
||||
width: 1000px;
|
||||
// width: 1000px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
padding-top: 36px;
|
||||
// label名字title
|
||||
.multiple-questions-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
padding-top: 36px;
|
||||
// label名字title
|
||||
.multiple-questions-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: 140px;
|
||||
line-height: 40px;
|
||||
font-size: 16px;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
&:before {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
margin-top: 1px;
|
||||
color: #f5222d;
|
||||
font-size: 16px;
|
||||
content: '*';
|
||||
}
|
||||
justify-content: flex-end;
|
||||
width: 140px;
|
||||
line-height: 40px;
|
||||
font-size: 16px;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
&:before {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
margin-top: 1px;
|
||||
color: #f5222d;
|
||||
font-size: 16px;
|
||||
content: '*';
|
||||
}
|
||||
}
|
||||
}
|
||||
.multiple-questions-btns-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin: 20px auto;
|
||||
width: 952px;
|
||||
.multiple-questions-btn {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin: 20px auto;
|
||||
width: 952px;
|
||||
.multiple-questions-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.multiple-questions-submit {
|
||||
margin-left: 40px;
|
||||
background-color: #4390f7;
|
||||
color: #fff;
|
||||
border: 1px solid #4390f7;
|
||||
}
|
||||
.multiple-questions-disabled-submit {
|
||||
opacity: 0.5;
|
||||
}
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.multiple-questions-submit {
|
||||
margin-left: 40px;
|
||||
background-color: #4390f7;
|
||||
color: #fff;
|
||||
border: 1px solid #4390f7;
|
||||
}
|
||||
.multiple-questions-disabled-submit {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,11 @@
|
||||
import { CloseCircleFilled } from '@ant-design/icons'
|
||||
import { debounce } from '@utils'
|
||||
import { Input, Select, Tooltip, message } from 'antd'
|
||||
import _ from 'lodash'
|
||||
import React, { Component, Fragment } from 'react'
|
||||
import React, { Component, Fragment, createRef } from 'react'
|
||||
import { optionLetter } from '../../constant'
|
||||
import KindEditor from '../kind-editor'
|
||||
import QuestionEditor from '../question-editor'
|
||||
|
||||
import './index.less'
|
||||
const { TextArea } = Input
|
||||
const { Option } = Select
|
||||
@@ -49,7 +51,8 @@ export default class OptionInputBox extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
kindEditor = KindEditor | null
|
||||
// kindEditor = KindEditor | null
|
||||
kindEditor = createRef()
|
||||
subjectAnswer = '' // 选项内容
|
||||
|
||||
/**
|
||||
@@ -98,10 +101,10 @@ export default class OptionInputBox extends Component {
|
||||
*/
|
||||
onChangeOptEditor = (index, type) => () => {
|
||||
let { optionList } = this.state
|
||||
this.kindEditor && this.kindEditor.onClear()
|
||||
if (type === 'submit') {
|
||||
_.set(optionList, [index, 'label'], !!this.subjectAnswer ? this.subjectAnswer : defalutLabel)
|
||||
}
|
||||
this.kindEditor && this.kindEditor.current.onClear()
|
||||
_.set(optionList, [index, 'isShowEditor'], false)
|
||||
this.subjectAnswer = ''
|
||||
this.setState(
|
||||
@@ -131,7 +134,7 @@ export default class OptionInputBox extends Component {
|
||||
optionList
|
||||
},
|
||||
() => {
|
||||
this.kindEditor && this.kindEditor.onCashBack()
|
||||
this.kindEditor && this.kindEditor.current.onCashBack()
|
||||
}
|
||||
)
|
||||
})
|
||||
@@ -140,7 +143,7 @@ export default class OptionInputBox extends Component {
|
||||
* 富文本编辑器
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeEditor = index => e => {
|
||||
onChangeEditor = e => {
|
||||
this.subjectAnswer = e
|
||||
}
|
||||
|
||||
@@ -318,7 +321,7 @@ export default class OptionInputBox extends Component {
|
||||
<div className='option-input-item-delete'>
|
||||
{listLen > showDeleteLength && (
|
||||
<Tooltip title='删除选项' onClick={this.onChangeAddOption(index, 'del')}>
|
||||
<img className='option-input-item-delete-icon' src='' />
|
||||
<CloseCircleFilled style={{ fontSize: '18px' }} />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
@@ -331,15 +334,7 @@ export default class OptionInputBox extends Component {
|
||||
style={{ marginTop: 19 }}
|
||||
>
|
||||
<div className='option-input-editor'>
|
||||
<KindEditor
|
||||
ref={ref => {
|
||||
this.kindEditor = ref
|
||||
}}
|
||||
bodyHeight={145}
|
||||
borderRadius={12}
|
||||
onChange={this.onChangeEditor(index)}
|
||||
cashBackText={isShowTip ? '' : item.label}
|
||||
/>
|
||||
<QuestionEditor onChange={this.onChangeEditor} ref={this.kindEditor} />
|
||||
<div className='option-input-editor-btns'>
|
||||
<Tooltip title='取消后内容将不会更新到选项框内'>
|
||||
<div
|
||||
@@ -395,7 +390,7 @@ export default class OptionInputBox extends Component {
|
||||
defaultActiveFirstOption={false}
|
||||
value={currentActiveList}
|
||||
placeholder='请选择'
|
||||
style={{ minWidth: isMultiple ? '64px' : '68px', marginLeft: 4 }}
|
||||
style={{ minWidth: isMultiple ? '84px' : '88px', marginLeft: 4 }}
|
||||
onChange={this.onChangeSelect}
|
||||
>
|
||||
{isJudge
|
||||
|
@@ -1,77 +1,82 @@
|
||||
import '@wangeditor/editor/dist/css/style.css' // 引入 css
|
||||
|
||||
import React, {
|
||||
useState, useEffect, forwardRef,
|
||||
useImperativeHandle,
|
||||
} from 'react'
|
||||
import { Editor, Toolbar } from '@wangeditor/editor-for-react'
|
||||
|
||||
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react'
|
||||
|
||||
// 当前菜单排序和分组
|
||||
|
||||
function MyEditor(props, ref) {
|
||||
// editor 实例
|
||||
const [editor, setEditor] = useState(null)
|
||||
// editor 实例
|
||||
const [editor, setEditor] = useState(null)
|
||||
|
||||
// 编辑器内容
|
||||
const [html, setHtml] = useState('<p></p>')
|
||||
|
||||
// 编辑器内容
|
||||
const [html, setHtml] = useState('<p></p>')
|
||||
// 工具栏配置
|
||||
const toolbarConfig = {
|
||||
excludeKeys: ['group-image', 'group-video']
|
||||
}
|
||||
|
||||
// 编辑器配置
|
||||
const editorConfig = {
|
||||
placeholder: '请输入内容...'
|
||||
}
|
||||
|
||||
// 工具栏配置
|
||||
const toolbarConfig = {
|
||||
excludeKeys: [
|
||||
'group-image', 'group-video'
|
||||
]
|
||||
const changeValue = html => {
|
||||
setHtml(html)
|
||||
props.onChange(html)
|
||||
}
|
||||
|
||||
const onClear = () => setHtml('')
|
||||
|
||||
/**
|
||||
* 回现代码
|
||||
*/
|
||||
const onCashBack = () => {
|
||||
let { cashBackText } = props
|
||||
if (!!!cashBackText) {
|
||||
return
|
||||
}
|
||||
setHtml(`${cashBackText}`)
|
||||
// editor.fo;
|
||||
}
|
||||
|
||||
// 编辑器配置
|
||||
const editorConfig = {
|
||||
placeholder: '请输入内容...',
|
||||
// 此处注意useImperativeHandle方法的的第一个参数是目标元素的ref引用
|
||||
useImperativeHandle(ref, () => ({
|
||||
// onCallback 就是暴露给父组件的方法
|
||||
onClear,
|
||||
onCashBack
|
||||
}))
|
||||
|
||||
// 及时销毁 editor ,重要!
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (editor == null) return
|
||||
editor.destroy()
|
||||
setEditor(null)
|
||||
}
|
||||
}, [editor])
|
||||
|
||||
|
||||
const changeValue = (html) => {
|
||||
setHtml(html)
|
||||
props.onChange(html)
|
||||
}
|
||||
|
||||
const onClear = () => setHtml('')
|
||||
// 此处注意useImperativeHandle方法的的第一个参数是目标元素的ref引用
|
||||
useImperativeHandle(ref, () => ({
|
||||
// onCallback 就是暴露给父组件的方法
|
||||
onClear
|
||||
}));
|
||||
|
||||
// 及时销毁 editor ,重要!
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (editor == null) return
|
||||
editor.destroy()
|
||||
setEditor(null)
|
||||
}
|
||||
}, [editor])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ border: '1px solid #ccc', zIndex: 100 }}>
|
||||
<Toolbar
|
||||
editor={editor}
|
||||
defaultConfig={toolbarConfig}
|
||||
mode="default"
|
||||
style={{ borderBottom: '1px solid #ccc' }}
|
||||
/>
|
||||
<Editor
|
||||
defaultConfig={editorConfig}
|
||||
value={html}
|
||||
onCreated={setEditor}
|
||||
onChange={editor => changeValue(editor.getHtml())}
|
||||
mode="default"
|
||||
style={{ height: '300px', overflowY: 'scroll' }}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
return (
|
||||
<>
|
||||
<div style={{ border: '1px solid #ccc', zIndex: 100 }}>
|
||||
<Toolbar
|
||||
editor={editor}
|
||||
defaultConfig={toolbarConfig}
|
||||
mode='default'
|
||||
style={{ borderBottom: '1px solid #ccc' }}
|
||||
/>
|
||||
<Editor
|
||||
defaultConfig={editorConfig}
|
||||
value={html}
|
||||
onCreated={setEditor}
|
||||
onChange={editor => changeValue(editor.getHtml())}
|
||||
mode='default'
|
||||
style={{ height: '300px', overflowY: 'scroll' }}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default forwardRef(MyEditor)
|
||||
export default forwardRef(MyEditor)
|
||||
|
@@ -1,234 +1,190 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { Modal, Tooltip } from 'antd';
|
||||
import { letterList, judgeList } from '../../constant';
|
||||
import './index.less';
|
||||
import { Modal, Tooltip } from 'antd'
|
||||
import React, { Fragment } from 'react'
|
||||
import { judgeList, letterList } from '../../constant'
|
||||
import './index.less'
|
||||
export default function RepeatContentBox(props) {
|
||||
const { isShowModalBox, repeatInfo, repeatQuestionsType } = props;
|
||||
// const { isShowModalBox, repeatQuestionsType } = props;
|
||||
// const repeatInfo = {
|
||||
// repeatSubjectName:
|
||||
// 'Chrome如Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?何支持小于12px的字?',
|
||||
// repeatSubjectAnswe:
|
||||
// 'Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?',
|
||||
// repeatSetterErp: 'suchunping3',
|
||||
// repeatSetterName: '苏春萍',
|
||||
// };
|
||||
const { isShowModalBox, repeatInfo, repeatQuestionsType } = props
|
||||
/**
|
||||
* 确认录入
|
||||
*/
|
||||
const onSubmitRepeatModal = e => {
|
||||
props.handleSubmitRepeatModal && props.handleSubmitRepeatModal()
|
||||
}
|
||||
/**
|
||||
* 取消录入
|
||||
*/
|
||||
const onCancelRepeatModal = () => {
|
||||
props.handleCancelRepeatModal && props.handleCancelRepeatModal()
|
||||
}
|
||||
|
||||
// const repeatInfo = {
|
||||
// repeatSubjectName:
|
||||
// 'Chrome如Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?何支持小于12px的字?',
|
||||
// repeatOptionList: [
|
||||
// {
|
||||
// isCorrect: '',
|
||||
// optionContent: 'Chrome如何支持小于12px的字?Chrome如何支持小于12px的',
|
||||
// optionType: 1,
|
||||
// },
|
||||
// {
|
||||
// isCorrect: '',
|
||||
// optionContent: 'Chrome如何支持小于12px的字?Chrome如何支持小于12px的',
|
||||
// optionType: 2,
|
||||
// },
|
||||
// {
|
||||
// isCorrect: 1,
|
||||
// optionContent: 'Chrome如何支持小于12px的字?Chrome如何支持小于12px的',
|
||||
// optionType: 3,
|
||||
// },
|
||||
// ],
|
||||
// repeatSetterErp: 'suchunping3',
|
||||
// repeatSetterName: '苏春萍',
|
||||
// };
|
||||
/**
|
||||
* 确认录入
|
||||
*/
|
||||
const onSubmitRepeatModal = (e) => {
|
||||
props.handleSubmitRepeatModal && props.handleSubmitRepeatModal();
|
||||
};
|
||||
/**
|
||||
* 取消录入
|
||||
*/
|
||||
const onCancelRepeatModal = () => {
|
||||
props.handleCancelRepeatModal && props.handleCancelRepeatModal();
|
||||
};
|
||||
const renderRepeat = (type, repeatInfo) => {
|
||||
switch (type) {
|
||||
case 1:
|
||||
return renderBriefQuestions(repeatInfo)
|
||||
case 2:
|
||||
case 3:
|
||||
return renderSelectQuestions(type, repeatInfo)
|
||||
case 4:
|
||||
return renderJudgeQuestions(repeatInfo)
|
||||
}
|
||||
}
|
||||
|
||||
const renderRepeat = (type, repeatInfo) => {
|
||||
switch (type) {
|
||||
case 1:
|
||||
return renderBriefQuestions(repeatInfo);
|
||||
case 2:
|
||||
case 3:
|
||||
return renderSelectQuestions(type, repeatInfo);
|
||||
case 4:
|
||||
return renderJudgeQuestions(repeatInfo);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 展示重复内容-问答型
|
||||
* @returns
|
||||
*/
|
||||
const renderBriefQuestions = repeatInfo => {
|
||||
return (
|
||||
<div className='repeat-content-box'>
|
||||
<div className='repeat-subject-box'>
|
||||
<div className='repeat-subject-title'>问答题</div>
|
||||
<div className='repeat-subject-text'>{repeatInfo.repeatSubjectName}</div>
|
||||
</div>
|
||||
<div className='repeat-subject-box'>
|
||||
<div className='repeat-subject-title'>参考答案</div>
|
||||
<div
|
||||
className='repeat-subject-text'
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: repeatInfo.repeatSubjectAnswe
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
<div className='repeat-subject-box repeat-subject-info-box'>
|
||||
<div className='repeat-subject-title'>来自</div>
|
||||
<Tooltip title={repeatInfo.repeatSetterErp} placement='right' style={{ fontSize: 14 }}>
|
||||
{repeatInfo.repeatSetterName}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 展示重复内容-问答型
|
||||
* @returns
|
||||
*/
|
||||
const renderBriefQuestions = (repeatInfo) => {
|
||||
return (
|
||||
<div className="repeat-content-box">
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">问答题</div>
|
||||
<div className="repeat-subject-text">{repeatInfo.repeatSubjectName}</div>
|
||||
</div>
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">参考答案</div>
|
||||
<div
|
||||
className="repeat-subject-text"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: repeatInfo.repeatSubjectAnswe,
|
||||
}}></div>
|
||||
</div>
|
||||
<div className="repeat-subject-box repeat-subject-info-box">
|
||||
<div className="repeat-subject-title">来自</div>
|
||||
<Tooltip
|
||||
title={repeatInfo.repeatSetterErp}
|
||||
placement="right"
|
||||
style={{ fontSize: 14 }}>
|
||||
{repeatInfo.repeatSetterName}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 展示重复内容-单选/多选
|
||||
* @returns
|
||||
*/
|
||||
const renderSelectQuestions = (type, repeatInfo) => {
|
||||
// 过滤获得正确选项
|
||||
let repeatRightKey = repeatInfo?.repeatOptionList?.filter((item) => item.isCorrect === 1);
|
||||
return (
|
||||
<div className="repeat-content-box">
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">{type === 2 ? '单选题' : '多选题'}</div>
|
||||
<div className="repeat-subject-text">{repeatInfo.repeatSubjectName}</div>
|
||||
</div>
|
||||
{repeatInfo?.repeatOptionList?.length > 0 && (
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">选项内容</div>
|
||||
<div className="repeat-subject-list">
|
||||
{repeatInfo.repeatOptionList.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
className="repeat-subject-item"
|
||||
key={`repeat_option_${index}`}>
|
||||
{/* <div className="repeat-subject-label">
|
||||
/**
|
||||
* 展示重复内容-单选/多选
|
||||
* @returns
|
||||
*/
|
||||
const renderSelectQuestions = (type, repeatInfo) => {
|
||||
// 过滤获得正确选项
|
||||
let repeatRightKey = repeatInfo?.repeatOptionList?.filter(item => item.isCorrect === 1)
|
||||
return (
|
||||
<div className='repeat-content-box'>
|
||||
<div className='repeat-subject-box'>
|
||||
<div className='repeat-subject-title'>{type === 2 ? '单选题' : '多选题'}</div>
|
||||
<div className='repeat-subject-text'>{repeatInfo.repeatSubjectName}</div>
|
||||
</div>
|
||||
{repeatInfo?.repeatOptionList?.length > 0 && (
|
||||
<div className='repeat-subject-box'>
|
||||
<div className='repeat-subject-title'>选项内容</div>
|
||||
<div className='repeat-subject-list'>
|
||||
{repeatInfo.repeatOptionList.map((item, index) => {
|
||||
return (
|
||||
<div className='repeat-subject-item' key={`repeat_option_${index}`}>
|
||||
{/* <div className="repeat-subject-label">
|
||||
{letterList[item.optionType]}
|
||||
</div> */}
|
||||
<div
|
||||
className="repeat-subject-text"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item.optionContent,
|
||||
}}></div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{repeatRightKey?.length > 0 && (
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">答案</div>
|
||||
<div className="repeat-subject-list">
|
||||
{repeatRightKey.map((item, index) => {
|
||||
return (
|
||||
<span key={`repeat_answe_${index}`}>
|
||||
{letterList[item.optionType]}{' '}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!!repeatInfo.repeatSubjectAnswe && (
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">题目解析</div>
|
||||
<div
|
||||
className="repeat-subject-text"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: repeatInfo.repeatSubjectAnswe,
|
||||
}}></div>
|
||||
</div>
|
||||
)}
|
||||
<div className="repeat-subject-box repeat-subject-info-box">
|
||||
<div className="repeat-subject-title">来自</div>
|
||||
<Tooltip
|
||||
title={repeatInfo.repeatSetterErp}
|
||||
placement="right"
|
||||
style={{ fontSize: 14 }}>
|
||||
{repeatInfo.repeatSetterName}
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div
|
||||
className='repeat-subject-text'
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item.optionContent
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 展示重复内容-判断
|
||||
* @returns
|
||||
*/
|
||||
const renderJudgeQuestions = (repeatInfo) => {
|
||||
return (
|
||||
<div className="repeat-content-box">
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">判断题</div>
|
||||
<div className="repeat-subject-text">{repeatInfo.repeatSubjectName}</div>
|
||||
</div>
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">答案</div>
|
||||
<div className="repeat-subject-list">
|
||||
{judgeList[repeatInfo.repeatIsCorrect]}
|
||||
</div>
|
||||
</div>
|
||||
{!!repeatInfo.repeatSubjectAnswe && (
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">题目解析</div>
|
||||
<div
|
||||
className="repeat-subject-text"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: repeatInfo.repeatSubjectAnswe,
|
||||
}}></div>
|
||||
</div>
|
||||
)}
|
||||
<div className="repeat-subject-box repeat-subject-info-box">
|
||||
<div className="repeat-subject-title">来自</div>
|
||||
<Tooltip
|
||||
title={repeatInfo.repeatSetterErp}
|
||||
placement="right"
|
||||
style={{ fontSize: 14 }}>
|
||||
{repeatInfo.repeatSetterName}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{repeatRightKey?.length > 0 && (
|
||||
<div className='repeat-subject-box'>
|
||||
<div className='repeat-subject-title'>答案</div>
|
||||
<div className='repeat-subject-list'>
|
||||
{repeatRightKey.map((item, index) => {
|
||||
return <span key={`repeat_answe_${index}`}>{letterList[item.optionType]} </span>
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
</div>
|
||||
)}
|
||||
{!!repeatInfo.repeatSubjectAnswe && (
|
||||
<div className='repeat-subject-box'>
|
||||
<div className='repeat-subject-title'>题目解析</div>
|
||||
<div
|
||||
className='repeat-subject-text'
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: repeatInfo.repeatSubjectAnswe
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
)}
|
||||
<div className='repeat-subject-box repeat-subject-info-box'>
|
||||
<div className='repeat-subject-title'>来自</div>
|
||||
<Tooltip title={repeatInfo.repeatSetterErp} placement='right' style={{ fontSize: 14 }}>
|
||||
{repeatInfo.repeatSetterName}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 展示重复内容-判断
|
||||
* @returns
|
||||
*/
|
||||
const renderJudgeQuestions = repeatInfo => {
|
||||
return (
|
||||
<Modal
|
||||
className="repeat-content-repeat-box"
|
||||
visible={isShowModalBox}
|
||||
title={
|
||||
<Fragment>
|
||||
<span
|
||||
style={{
|
||||
color: 'rgba(60, 110, 238, 0.8)',
|
||||
fontSize: 50,
|
||||
marginRight: 10,
|
||||
}}>
|
||||
{repeatInfo.repeatRate || '10%'}
|
||||
</span>
|
||||
重复率
|
||||
</Fragment>
|
||||
}
|
||||
onOk={onSubmitRepeatModal}
|
||||
onCancel={onCancelRepeatModal}
|
||||
okText="确认录入"
|
||||
cancelText="取消录入">
|
||||
{renderRepeat(repeatQuestionsType, repeatInfo)}
|
||||
</Modal>
|
||||
);
|
||||
<div className='repeat-content-box'>
|
||||
<div className='repeat-subject-box'>
|
||||
<div className='repeat-subject-title'>判断题</div>
|
||||
<div className='repeat-subject-text'>{repeatInfo.repeatSubjectName}</div>
|
||||
</div>
|
||||
<div className='repeat-subject-box'>
|
||||
<div className='repeat-subject-title'>答案</div>
|
||||
<div className='repeat-subject-list'>{judgeList[repeatInfo.repeatIsCorrect]}</div>
|
||||
</div>
|
||||
{!!repeatInfo.repeatSubjectAnswe && (
|
||||
<div className='repeat-subject-box'>
|
||||
<div className='repeat-subject-title'>题目解析</div>
|
||||
<div
|
||||
className='repeat-subject-text'
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: repeatInfo.repeatSubjectAnswe
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
)}
|
||||
<div className='repeat-subject-box repeat-subject-info-box'>
|
||||
<div className='repeat-subject-title'>来自</div>
|
||||
<Tooltip title={repeatInfo.repeatSetterErp} placement='right' style={{ fontSize: 14 }}>
|
||||
{repeatInfo.repeatSetterName}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className='repeat-content-repeat-box'
|
||||
open={isShowModalBox}
|
||||
title={
|
||||
<Fragment>
|
||||
<span
|
||||
style={{
|
||||
color: 'rgba(60, 110, 238, 0.8)',
|
||||
fontSize: 50,
|
||||
marginRight: 10
|
||||
}}
|
||||
>
|
||||
{repeatInfo.repeatRate || '10%'}
|
||||
</span>
|
||||
重复率
|
||||
</Fragment>
|
||||
}
|
||||
onOk={onSubmitRepeatModal}
|
||||
onCancel={onCancelRepeatModal}
|
||||
okText='确认录入'
|
||||
cancelText='取消录入'
|
||||
>
|
||||
{renderRepeat(repeatQuestionsType, repeatInfo)}
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
@@ -1,338 +1,365 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { Input, Modal, message, Spin } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import req from '@utils/request';
|
||||
import { debounce } from '@utils';
|
||||
import KindEditor from '../kind-editor';
|
||||
import RankLabelBox from '../rank-label-box';
|
||||
import OptionInputBox from '../option-input-box';
|
||||
import RepeatContentBox from '../repeat-content-box';
|
||||
import { apiName } from '../../constant';
|
||||
import './index.less';
|
||||
const defalutLabel = '请使用富文本编辑器输入选项内容';
|
||||
import { debounce } from '@utils'
|
||||
import req from '@utils/request'
|
||||
import { Input, Modal, Spin, message } from 'antd'
|
||||
import React, { Component, Fragment, createRef } from 'react'
|
||||
import { apiName } from '../../constant'
|
||||
import OptionInputBox from '../option-input-box'
|
||||
import RankLabelBox from '../rank-label-box'
|
||||
import RepeatContentBox from '../repeat-content-box'
|
||||
import './index.less'
|
||||
const defalutLabel = '请使用富文本编辑器输入选项内容'
|
||||
export default class SingleQuestions extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
subjectName: '', // 题目
|
||||
isDisabledSubmit: true, //是否禁止输入
|
||||
isShowModalBox: false, // 是否展示重复率弹框
|
||||
isSubmit: true, // 是否支持提交
|
||||
};
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
subjectName: '', // 题目
|
||||
isDisabledSubmit: true, //是否禁止输入
|
||||
isShowModalBox: false, // 是否展示重复率弹框
|
||||
isSubmit: true // 是否支持提交
|
||||
}
|
||||
kindEditor = KindEditor | null;
|
||||
rankLabelBox = RankLabelBox | null;
|
||||
optionInputBox = OptionInputBox | null;
|
||||
}
|
||||
rankLabelBox = createRef()
|
||||
|
||||
currentActive = []; // 选项列表
|
||||
scoreValue = ''; // 分数
|
||||
subjectAnalysis = ''; //试题解析
|
||||
rankId = 1; //职级
|
||||
subjectAnswer = ''; // 选项内容
|
||||
optionInputBox = OptionInputBox | null
|
||||
|
||||
firstCategoryValue = ''; // 一级分类的值
|
||||
secondCategoryValue = []; // 二级分类的值
|
||||
thirdCategoryValue = []; // 三级标签的值
|
||||
repeatInfo = {}; // 重复率
|
||||
currentActive = [] // 选项列表
|
||||
scoreValue = '' // 分数
|
||||
subjectAnalysis = '' //试题解析
|
||||
rankId = 1 //职级
|
||||
subjectAnswer = '' // 选项内容
|
||||
|
||||
/**
|
||||
* 输入题目
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectName = (e) => {
|
||||
let str = e.target.value.trim();
|
||||
this.setState(
|
||||
{
|
||||
subjectName: str,
|
||||
},
|
||||
() => {
|
||||
this.rankLabelBox.getThirdCategoryList();
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
firstCategoryValue = '' // 一级分类的值
|
||||
secondCategoryValue = [] // 二级分类的值
|
||||
thirdCategoryValue = [] // 三级标签的值
|
||||
repeatInfo = {} // 重复率
|
||||
|
||||
/**
|
||||
* 一次确认录入
|
||||
*/
|
||||
onSubmit = debounce(() => {
|
||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state;
|
||||
if (isDisabledSubmit || !isSubmit) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* 输入题目
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectName = e => {
|
||||
let str = e.target.value.trim()
|
||||
this.setState(
|
||||
{
|
||||
subjectName: str
|
||||
},
|
||||
() => {
|
||||
// this.rankLabelBox.getThirdCategoryList();
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isSubmit: false,
|
||||
});
|
||||
let params = {
|
||||
subjectName: subjectName,
|
||||
difficulty: this.rankId,
|
||||
subjectType: 1,
|
||||
subjectScore: this.scoreValue,
|
||||
subjectParse: this.subjectAnalysis,
|
||||
categoryIds: this.secondCategoryValue,
|
||||
labelIds: this.thirdCategoryValue,
|
||||
optionList: this.currentActive,
|
||||
};
|
||||
console.log('单选题录入 ----', params);
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addInterviewSubject,
|
||||
isDisabledSubmit
|
||||
})
|
||||
.then((res) => {
|
||||
this.repeatInfo = {};
|
||||
if (res.data && res.data.insertStatus) {
|
||||
this.setState(
|
||||
{
|
||||
isSubmit: true,
|
||||
},
|
||||
() => {
|
||||
this.successModalConfirm();
|
||||
}
|
||||
);
|
||||
} else if (!res.data.insertStatus) {
|
||||
this.repeatInfo = {
|
||||
repeatDocId: res.data.docId, // 重复题目id
|
||||
repeatRate: res.data.repeatRate, // 重复率
|
||||
repeatSubjectName: res.data.subjectName, // 重复题目
|
||||
repeatOptionList: res.data.optionList, // 重复列表项
|
||||
repeatSetterErp: res.data.subjectSetterErp, // 出题人erp
|
||||
repeatSetterName: res.data.subjectSetterName, // 出题人姓名
|
||||
};
|
||||
this.setState({
|
||||
isShowModalBox: true,
|
||||
isSubmit: true,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
isSubmit: true,
|
||||
});
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
checkData = () => {
|
||||
const { subjectName } = this.state;
|
||||
let list = this.currentActive.filter((item) => item.optionContent === defalutLabel);
|
||||
let isDisabledSubmit = false;
|
||||
if (
|
||||
!!!subjectName ||
|
||||
list.length > 0 ||
|
||||
!!!this.firstCategoryValue ||
|
||||
this.secondCategoryValue.length <= 0 ||
|
||||
this.thirdCategoryValue.length <= 0 ||
|
||||
!!!this.scoreValue
|
||||
) {
|
||||
isDisabledSubmit = true;
|
||||
}
|
||||
return isDisabledSubmit;
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
onCancel = () => {
|
||||
this.currentActive = []; // 选项列表
|
||||
this.scoreValue = ''; // 分数
|
||||
this.subjectAnalysis = ''; //试题解析
|
||||
this.rankId = 1;
|
||||
this.subjectAnswer = ''; // 选项内容
|
||||
this.firstCategoryValue = ''; // 一级分类的值
|
||||
this.secondCategoryValue = []; // 二级分类的值
|
||||
this.thirdCategoryValue = []; // 三级标签的值
|
||||
this.kindEditor && this.kindEditor.onClear();
|
||||
this.rankLabelBox.initRankLabel();
|
||||
this.optionInputBox.handleClearOption();
|
||||
this.repeatInfo = {};
|
||||
this.setState({
|
||||
subjectName: '',
|
||||
isShowModalBox: false,
|
||||
isSubmit: true, // 是否支持提交
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 重复率弹框-确认录入
|
||||
*/
|
||||
onSubmitRepeatModal = debounce(
|
||||
() => {
|
||||
let params = {
|
||||
docId: this.repeatInfo.repeatDocId,
|
||||
};
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addRepeatInterviewSubject,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
this.successModalConfirm();
|
||||
} else {
|
||||
message.info('请再次确认');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
message.error('请再次确认');
|
||||
});
|
||||
},
|
||||
300,
|
||||
true
|
||||
);
|
||||
|
||||
/**
|
||||
* 重复率弹框-取消录入
|
||||
*/
|
||||
onCancelRepeatModal = () => {
|
||||
this.repeatInfo = {};
|
||||
this.setState({
|
||||
isShowModalBox: false,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功的弹框
|
||||
*/
|
||||
successModalConfirm = () => {
|
||||
Modal.confirm({
|
||||
title: (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: 'rgba(60, 110, 238, 1)',
|
||||
fontSize: 16,
|
||||
}}>
|
||||
录入成功!贡献榜火力值 + 1
|
||||
</div>
|
||||
),
|
||||
closable: false,
|
||||
maskClosable: false,
|
||||
icon: ' ',
|
||||
onOk: this.onAgainSuccessModal,
|
||||
onCancel: this.onGoHomeSuccessModal,
|
||||
okText: '再录一题',
|
||||
cancelText: '去首页',
|
||||
className: 'questions-success-modal-confirm',
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-再来一题
|
||||
*/
|
||||
onAgainSuccessModal = () => {
|
||||
this.onCancel();
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-去首页
|
||||
*/
|
||||
onGoHomeSuccessModal = () => {
|
||||
window.location.href = '/cms-supplier/question-bank';
|
||||
};
|
||||
|
||||
/**
|
||||
* 分类选择
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeRankLabel = (firstCategoryValue, secondCategoryValue, thirdCategoryValue) => {
|
||||
this.firstCategoryValue = firstCategoryValue; // 一级分类的值
|
||||
this.secondCategoryValue = secondCategoryValue; // 二级分类的值
|
||||
this.thirdCategoryValue = thirdCategoryValue; // 三级标签的值
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 职级选择
|
||||
* @param {*} list
|
||||
*/
|
||||
handleChangeRank = (list) => {
|
||||
this.rankId = list[0];
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 选项操作
|
||||
* @param {*} currentActive 选项列表
|
||||
* @param {*} scoreValue 分值
|
||||
* @param {*} subjectAnalysis 解析
|
||||
*/
|
||||
handleChangeOption = (currentActive, scoreValue, subjectAnalysis) => {
|
||||
this.currentActive = currentActive;
|
||||
this.scoreValue = scoreValue;
|
||||
this.subjectAnalysis = subjectAnalysis;
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { subjectName, isDisabledSubmit, isSubmit, isShowModalBox } = this.state;
|
||||
const { questionsType } = this.props;
|
||||
return (
|
||||
<Spin spinning={!isSubmit}>
|
||||
<Fragment>
|
||||
<div className="single-questions-container">
|
||||
<div className="single-questions-title">题目名称:</div>
|
||||
<Input
|
||||
placeholder="输入题目"
|
||||
style={{ height: 48, width: '100%' }}
|
||||
value={subjectName}
|
||||
maxLength={64}
|
||||
onChange={(e) => this.onChangeSubjectName(e)}
|
||||
/>
|
||||
</div>
|
||||
<OptionInputBox
|
||||
key="single-option-input"
|
||||
ref={(ref) => {
|
||||
this.optionInputBox = ref;
|
||||
}}
|
||||
handleChangeOption={this.handleChangeOption}
|
||||
/>
|
||||
<RankLabelBox
|
||||
ref={(ref) => {
|
||||
this.rankLabelBox = ref;
|
||||
}}
|
||||
subjectName={subjectName}
|
||||
onChangeRankLabel={this.onChangeRankLabel}
|
||||
handleChangeRank={this.handleChangeRank}
|
||||
/>
|
||||
<div className="single-questions-btns-container">
|
||||
<div className="single-questions-btn" onClick={this.onCancel}>
|
||||
清空
|
||||
</div>
|
||||
<div
|
||||
className={`single-questions-btn single-questions-submit ${isDisabledSubmit && 'single-questions-disabled-submit'
|
||||
}`}
|
||||
onClick={this.onSubmit}>
|
||||
提交
|
||||
</div>
|
||||
</div>
|
||||
<RepeatContentBox
|
||||
isShowModalBox={isShowModalBox}
|
||||
repeatQuestionsType={questionsType}
|
||||
repeatInfo={this.repeatInfo}
|
||||
handleSubmitRepeatModal={this.onSubmitRepeatModal}
|
||||
handleCancelRepeatModal={this.onCancelRepeatModal}
|
||||
/>
|
||||
</Fragment>
|
||||
</Spin>
|
||||
);
|
||||
/**
|
||||
* 一次确认录入
|
||||
*/
|
||||
onSubmit = debounce(() => {
|
||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state
|
||||
if (isDisabledSubmit || !isSubmit) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if (!isSubmit) {
|
||||
return
|
||||
}
|
||||
if (!!!subjectName) {
|
||||
message.warning('请输入题目名称')
|
||||
return
|
||||
}
|
||||
if (!this.currentActive.length) {
|
||||
message.warning('请录入答案')
|
||||
return
|
||||
}
|
||||
if (!!!this.firstCategoryValue) {
|
||||
message.warning('请选择一级分类')
|
||||
return
|
||||
}
|
||||
if (this.secondCategoryValue.length <= 0) {
|
||||
message.warning('请选择二级分类')
|
||||
return
|
||||
}
|
||||
if (this.thirdCategoryValue.length <= 0) {
|
||||
message.warning('请选择三级标签')
|
||||
return
|
||||
}
|
||||
this.setState({
|
||||
isSubmit: false
|
||||
})
|
||||
let params = {
|
||||
subjectName: subjectName,
|
||||
subjectDifficult: this.rankId,
|
||||
subjectType: 1,
|
||||
subjectScore: this.scoreValue,
|
||||
subjectParse: this.subjectAnalysis,
|
||||
categoryIds: this.secondCategoryValue.filter(item => item.active).map(t => t.id),
|
||||
labelIds: this.thirdCategoryValue.filter(item => item.active).map(t => t.id),
|
||||
optionList: this.currentActive
|
||||
}
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.add
|
||||
})
|
||||
.then(res => {
|
||||
// this.repeatInfo = {}
|
||||
// if (res.data && res.data.insertStatus) {
|
||||
// this.setState(
|
||||
// {
|
||||
// isSubmit: true
|
||||
// },
|
||||
// () => {
|
||||
// this.successModalConfirm()
|
||||
// }
|
||||
// )
|
||||
// } else if (!res.data.insertStatus) {
|
||||
// this.repeatInfo = {
|
||||
// repeatDocId: res.data.docId, // 重复题目id
|
||||
// repeatRate: res.data.repeatRate, // 重复率
|
||||
// repeatSubjectName: res.data.subjectName, // 重复题目
|
||||
// repeatOptionList: res.data.optionList, // 重复列表项
|
||||
// repeatSetterErp: res.data.subjectSetterErp, // 出题人erp
|
||||
// repeatSetterName: res.data.subjectSetterName // 出题人姓名
|
||||
// }
|
||||
// this.setState({
|
||||
// isShowModalBox: true,
|
||||
// isSubmit: true
|
||||
// })
|
||||
// }
|
||||
this.setState(
|
||||
{
|
||||
isSubmit: true
|
||||
},
|
||||
() => {
|
||||
this.successModalConfirm()
|
||||
}
|
||||
)
|
||||
})
|
||||
.catch(err => {
|
||||
this.setState({
|
||||
isSubmit: true
|
||||
})
|
||||
console.log(err)
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
checkData = () => {
|
||||
const { subjectName } = this.state
|
||||
let list = this.currentActive.filter(item => item.optionContent === defalutLabel)
|
||||
let isDisabledSubmit = false
|
||||
if (
|
||||
!!!subjectName ||
|
||||
list.length > 0 ||
|
||||
!!!this.firstCategoryValue ||
|
||||
this.secondCategoryValue.length <= 0 ||
|
||||
this.thirdCategoryValue.length <= 0 ||
|
||||
!!!this.scoreValue
|
||||
) {
|
||||
isDisabledSubmit = true
|
||||
}
|
||||
return isDisabledSubmit
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
onCancel = () => {
|
||||
this.currentActive = [] // 选项列表
|
||||
this.scoreValue = '' // 分数
|
||||
this.subjectAnalysis = '' //试题解析
|
||||
this.rankId = 1
|
||||
this.subjectAnswer = '' // 选项内容
|
||||
this.firstCategoryValue = '' // 一级分类的值
|
||||
this.secondCategoryValue = [] // 二级分类的值
|
||||
this.thirdCategoryValue = [] // 三级标签的值
|
||||
this.rankLabelBox.current.initRankLabel()
|
||||
this.optionInputBox.handleClearOption()
|
||||
this.repeatInfo = {}
|
||||
this.setState({
|
||||
subjectName: '',
|
||||
isShowModalBox: false,
|
||||
isSubmit: true // 是否支持提交
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 重复率弹框-确认录入
|
||||
*/
|
||||
onSubmitRepeatModal = debounce(
|
||||
() => {
|
||||
let params = {
|
||||
docId: this.repeatInfo.repeatDocId
|
||||
}
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addRepeatInterviewSubject
|
||||
})
|
||||
.then(res => {
|
||||
if (res.data) {
|
||||
this.successModalConfirm()
|
||||
} else {
|
||||
message.info('请再次确认')
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
message.error('请再次确认')
|
||||
})
|
||||
},
|
||||
300,
|
||||
true
|
||||
)
|
||||
|
||||
/**
|
||||
* 重复率弹框-取消录入
|
||||
*/
|
||||
onCancelRepeatModal = () => {
|
||||
this.repeatInfo = {}
|
||||
this.setState({
|
||||
isShowModalBox: false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 录入成功的弹框
|
||||
*/
|
||||
successModalConfirm = () => {
|
||||
Modal.confirm({
|
||||
title: (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: 'rgba(60, 110, 238, 1)',
|
||||
fontSize: 16
|
||||
}}
|
||||
>
|
||||
录入成功!贡献榜火力值 + 1
|
||||
</div>
|
||||
),
|
||||
closable: false,
|
||||
maskClosable: false,
|
||||
icon: ' ',
|
||||
onOk: this.onAgainSuccessModal,
|
||||
onCancel: this.onGoHomeSuccessModal,
|
||||
okText: '再录一题',
|
||||
cancelText: '去首页',
|
||||
className: 'questions-success-modal-confirm'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 录入成功弹框-再来一题
|
||||
*/
|
||||
onAgainSuccessModal = () => {
|
||||
this.onCancel()
|
||||
}
|
||||
|
||||
/**
|
||||
* 录入成功弹框-去首页
|
||||
*/
|
||||
onGoHomeSuccessModal = () => {
|
||||
window.location.href = '/question-bank'
|
||||
}
|
||||
|
||||
/**
|
||||
* 分类选择
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeRankLabel = (firstCategoryValue, secondCategoryValue, thirdCategoryValue) => {
|
||||
this.firstCategoryValue = firstCategoryValue // 一级分类的值
|
||||
this.secondCategoryValue = secondCategoryValue // 二级分类的值
|
||||
this.thirdCategoryValue = thirdCategoryValue // 三级标签的值
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isDisabledSubmit
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 职级选择
|
||||
* @param {*} list
|
||||
*/
|
||||
handleChangeRank = list => {
|
||||
this.rankId = list[0]
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isDisabledSubmit
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 选项操作
|
||||
* @param {*} currentActive 选项列表
|
||||
* @param {*} scoreValue 分值
|
||||
* @param {*} subjectAnalysis 解析
|
||||
*/
|
||||
handleChangeOption = (currentActive, scoreValue, subjectAnalysis) => {
|
||||
this.currentActive = currentActive
|
||||
this.scoreValue = scoreValue
|
||||
this.subjectAnalysis = subjectAnalysis
|
||||
let isDisabledSubmit = this.checkData()
|
||||
this.setState({
|
||||
isDisabledSubmit
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { subjectName, isDisabledSubmit, isSubmit, isShowModalBox } = this.state
|
||||
const { questionsType } = this.props
|
||||
return (
|
||||
<Spin spinning={!isSubmit}>
|
||||
<Fragment>
|
||||
<div className='single-questions-container'>
|
||||
<div className='single-questions-title'>题目名称:</div>
|
||||
<Input
|
||||
placeholder='输入题目'
|
||||
style={{ height: 48, width: '100%' }}
|
||||
value={subjectName}
|
||||
maxLength={64}
|
||||
onChange={e => this.onChangeSubjectName(e)}
|
||||
/>
|
||||
</div>
|
||||
<OptionInputBox
|
||||
key='single-option-input'
|
||||
ref={ref => {
|
||||
this.optionInputBox = ref
|
||||
}}
|
||||
handleChangeOption={this.handleChangeOption}
|
||||
/>
|
||||
<RankLabelBox
|
||||
ref={this.rankLabelBox}
|
||||
subjectName={subjectName}
|
||||
onChangeRankLabel={this.onChangeRankLabel}
|
||||
handleChangeRank={this.handleChangeRank}
|
||||
/>
|
||||
<div className='single-questions-btns-container'>
|
||||
<div className='single-questions-btn' onClick={this.onCancel}>
|
||||
清空
|
||||
</div>
|
||||
<div
|
||||
className={`single-questions-btn single-questions-submit ${
|
||||
isDisabledSubmit && 'single-questions-disabled-submit'
|
||||
}`}
|
||||
onClick={this.onSubmit}
|
||||
>
|
||||
提交
|
||||
</div>
|
||||
</div>
|
||||
<RepeatContentBox
|
||||
isShowModalBox={isShowModalBox}
|
||||
repeatQuestionsType={questionsType}
|
||||
repeatInfo={this.repeatInfo}
|
||||
handleSubmitRepeatModal={this.onSubmitRepeatModal}
|
||||
handleCancelRepeatModal={this.onCancelRepeatModal}
|
||||
/>
|
||||
</Fragment>
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -1,53 +1,53 @@
|
||||
.single-questions-container {
|
||||
width: 1000px;
|
||||
// width: 1000px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
padding-top: 36px;
|
||||
// label名字title
|
||||
.single-questions-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
padding-top: 36px;
|
||||
// label名字title
|
||||
.single-questions-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: 140px;
|
||||
line-height: 40px;
|
||||
font-size: 16px;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
&:before {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
margin-top: 1px;
|
||||
color: #f5222d;
|
||||
font-size: 16px;
|
||||
content: '*';
|
||||
}
|
||||
justify-content: flex-end;
|
||||
width: 140px;
|
||||
line-height: 40px;
|
||||
font-size: 16px;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
&:before {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
margin-top: 1px;
|
||||
color: #f5222d;
|
||||
font-size: 16px;
|
||||
content: '*';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.single-questions-btns-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin: 20px auto;
|
||||
width: 952px;
|
||||
.single-questions-btn {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin: 20px auto;
|
||||
width: 952px;
|
||||
.single-questions-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.single-questions-submit {
|
||||
margin-left: 40px;
|
||||
background-color: #4390f7;
|
||||
color: #fff;
|
||||
border: 1px solid #4390f7;
|
||||
}
|
||||
.single-questions-disabled-submit {
|
||||
opacity: 0.5;
|
||||
}
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.single-questions-submit {
|
||||
margin-left: 40px;
|
||||
background-color: #4390f7;
|
||||
color: #fff;
|
||||
border: 1px solid #4390f7;
|
||||
}
|
||||
.single-questions-disabled-submit {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
@@ -1,27 +1,29 @@
|
||||
import React from 'react';
|
||||
import { Affix } from 'antd';
|
||||
import { RightOutlined } from '@ant-design/icons';
|
||||
import './index.less';
|
||||
import { RightOutlined } from '@ant-design/icons'
|
||||
import { Affix } from 'antd'
|
||||
import React from 'react'
|
||||
import './index.less'
|
||||
|
||||
export default function UploadLeftLayout(props) {
|
||||
return (
|
||||
<Affix offsetTop={150}>
|
||||
<div className="upload-left-layout">
|
||||
{props.layoutList.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
className={`upload-left-layout-item ${item.active ? 'upload-left-layout-item-active' : ''
|
||||
}`}
|
||||
onClick={() => {
|
||||
props.onChange(index);
|
||||
}}
|
||||
key={`upload_left_layout_${item.id}`}>
|
||||
{item.title}
|
||||
<RightOutlined style={{ marginLeft: 54 }} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
return (
|
||||
<Affix offsetTop={150}>
|
||||
<div className='upload-left-layout'>
|
||||
{props.layoutList.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
className={`upload-left-layout-item ${
|
||||
item.active ? 'upload-left-layout-item-active' : ''
|
||||
}`}
|
||||
onClick={() => {
|
||||
props.onChange(index)
|
||||
}}
|
||||
key={`upload_left_layout_${item.id}`}
|
||||
>
|
||||
{item.title}
|
||||
<RightOutlined style={{ marginLeft: 54 }} />
|
||||
</div>
|
||||
</Affix>
|
||||
);
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Affix>
|
||||
)
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@
|
||||
background: rgba(255, 255, 255, 1);
|
||||
border: 1px solid rgba(208, 212, 222, 1);
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.upload-left-layout-item-active {
|
||||
color: rgba(60, 110, 238, 1);
|
||||
|
@@ -2,143 +2,142 @@
|
||||
* API名称
|
||||
*/
|
||||
export const apiName = {
|
||||
/**
|
||||
* 获取一级
|
||||
*/
|
||||
queryPrimaryCategory: '/category/queryPrimaryCategory',
|
||||
/**
|
||||
* 获取一级
|
||||
*/
|
||||
queryPrimaryCategory: '/category/queryPrimaryCategory',
|
||||
|
||||
// 查询二级分类
|
||||
queryCategoryByPrimary: 'category/queryCategoryByPrimary',
|
||||
|
||||
// 查询二级分类
|
||||
queryCategoryByPrimary: 'category/queryCategoryByPrimary',
|
||||
// 根据一级分类查询标签
|
||||
queryLabelByCategoryId: '/label/queryLabelByCategoryId',
|
||||
|
||||
// 根据一级分类查询标签
|
||||
queryLabelByCategoryId: '/label/queryLabelByCategoryId',
|
||||
|
||||
// 新增简答
|
||||
add: '/add',
|
||||
/**
|
||||
* 新增题目
|
||||
*/
|
||||
addInterviewSubject: '/admin/question/subject/add',
|
||||
/**
|
||||
* 新增重复题目
|
||||
*/
|
||||
addRepeatInterviewSubject: '/admin/question/subject/addRepeatSubject',
|
||||
};
|
||||
// 新增简答
|
||||
add: '/add',
|
||||
/**
|
||||
* 新增题目
|
||||
*/
|
||||
addInterviewSubject: '/admin/question/subject/add',
|
||||
/**
|
||||
* 新增重复题目
|
||||
*/
|
||||
addRepeatInterviewSubject: '/admin/question/subject/addRepeatSubject'
|
||||
}
|
||||
|
||||
/**
|
||||
* 模块类型
|
||||
*/
|
||||
export const ModuleType = {
|
||||
default: 'default',
|
||||
second: 'second',
|
||||
third: 'third',
|
||||
};
|
||||
default: 'default',
|
||||
second: 'second',
|
||||
third: 'third'
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入职级对应的星
|
||||
*/
|
||||
export const starList = [
|
||||
{
|
||||
categoryId: 1,
|
||||
categoryName: '初级',
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
categoryId: 2,
|
||||
categoryName: '中级',
|
||||
},
|
||||
{
|
||||
categoryId: 3,
|
||||
categoryName: '高级',
|
||||
},
|
||||
{
|
||||
categoryId: 4,
|
||||
categoryName: '资深',
|
||||
},
|
||||
{
|
||||
categoryId: 5,
|
||||
categoryName: '专家',
|
||||
},
|
||||
];
|
||||
{
|
||||
categoryId: 1,
|
||||
categoryName: '初级',
|
||||
active: true
|
||||
},
|
||||
{
|
||||
categoryId: 2,
|
||||
categoryName: '中级'
|
||||
},
|
||||
{
|
||||
categoryId: 3,
|
||||
categoryName: '高级'
|
||||
},
|
||||
{
|
||||
categoryId: 4,
|
||||
categoryName: '资深'
|
||||
},
|
||||
{
|
||||
categoryId: 5,
|
||||
categoryName: '专家'
|
||||
}
|
||||
]
|
||||
|
||||
/**
|
||||
* 模块类型
|
||||
*/
|
||||
export const uploadLayout = [
|
||||
{
|
||||
id: 1,
|
||||
title: '简答题',
|
||||
active: true,
|
||||
},
|
||||
// {
|
||||
// id: 2,
|
||||
// title: '单选题',
|
||||
// active: false,
|
||||
// },
|
||||
// {
|
||||
// id: 3,
|
||||
// title: '多选题',
|
||||
// active: false,
|
||||
// },
|
||||
// {
|
||||
// id: 4,
|
||||
// title: '判断题',
|
||||
// active: false,
|
||||
// },
|
||||
];
|
||||
{
|
||||
id: 1,
|
||||
title: '简答题',
|
||||
active: true
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '单选题',
|
||||
active: false
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '多选题',
|
||||
active: false
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '判断题',
|
||||
active: false
|
||||
}
|
||||
]
|
||||
|
||||
/**
|
||||
* 数组索引对应字母
|
||||
*/
|
||||
export const optionLetter = {
|
||||
0: {
|
||||
label: 'A',
|
||||
value: 1,
|
||||
},
|
||||
1: {
|
||||
label: 'B',
|
||||
value: 2,
|
||||
},
|
||||
2: {
|
||||
label: 'C',
|
||||
value: 3,
|
||||
},
|
||||
3: {
|
||||
label: 'D',
|
||||
value: 4,
|
||||
},
|
||||
4: {
|
||||
label: 'E',
|
||||
value: 5,
|
||||
},
|
||||
5: {
|
||||
label: 'F',
|
||||
value: 6,
|
||||
},
|
||||
6: {
|
||||
label: 'G',
|
||||
value: 7,
|
||||
},
|
||||
};
|
||||
0: {
|
||||
label: 'A',
|
||||
value: 1
|
||||
},
|
||||
1: {
|
||||
label: 'B',
|
||||
value: 2
|
||||
},
|
||||
2: {
|
||||
label: 'C',
|
||||
value: 3
|
||||
},
|
||||
3: {
|
||||
label: 'D',
|
||||
value: 4
|
||||
},
|
||||
4: {
|
||||
label: 'E',
|
||||
value: 5
|
||||
},
|
||||
5: {
|
||||
label: 'F',
|
||||
value: 6
|
||||
},
|
||||
6: {
|
||||
label: 'G',
|
||||
value: 7
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字母id对应字母
|
||||
*/
|
||||
export const letterList = {
|
||||
1: 'A',
|
||||
2: 'B',
|
||||
3: 'C',
|
||||
4: 'D',
|
||||
5: 'E',
|
||||
6: 'F',
|
||||
7: 'G',
|
||||
};
|
||||
1: 'A',
|
||||
2: 'B',
|
||||
3: 'C',
|
||||
4: 'D',
|
||||
5: 'E',
|
||||
6: 'F',
|
||||
7: 'G'
|
||||
}
|
||||
|
||||
/**
|
||||
* 正确/错误
|
||||
*/
|
||||
export const judgeList = {
|
||||
0: '错误',
|
||||
1: '正确',
|
||||
};
|
||||
0: '错误',
|
||||
1: '正确'
|
||||
}
|
||||
|
@@ -2,9 +2,9 @@
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
width: 1439px;
|
||||
overflow-y: auto;
|
||||
// overflow-y: auto;
|
||||
border-radius: 5px;
|
||||
height: calc(100vh - 100px);
|
||||
// height: calc(100vh - 100px);
|
||||
.ant-card-head {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
@@ -14,7 +14,4 @@
|
||||
z-index: 10;
|
||||
background-color: #fff;
|
||||
}
|
||||
.ant-card-body {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
@@ -2,16 +2,9 @@ import req from '@utils/request'
|
||||
import { Card, message } from 'antd'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import BatchleBox from './pages/batch-box'
|
||||
import SingleBox from './pages/single-box'
|
||||
|
||||
import './index.less'
|
||||
const tabList = [
|
||||
{
|
||||
key: 'singleBox',
|
||||
tab: '单题录入'
|
||||
}
|
||||
]
|
||||
const UploadQuestions = () => {
|
||||
const [currentKey, setCurrentKey] = useState('singleBox')
|
||||
const navigate = useNavigate()
|
||||
@@ -41,23 +34,18 @@ const UploadQuestions = () => {
|
||||
})
|
||||
}, [])
|
||||
|
||||
const contentList = {
|
||||
singleBox: <SingleBox />,
|
||||
batchBox: <BatchleBox />
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='upload-questions-box'>
|
||||
<Card
|
||||
style={{ width: '100%' }}
|
||||
tabList={tabList}
|
||||
title='题目录入'
|
||||
bordered={false}
|
||||
activeTabKey={currentKey}
|
||||
onTabChange={key => {
|
||||
setCurrentKey(key)
|
||||
}}
|
||||
>
|
||||
{contentList[currentKey]}
|
||||
<SingleBox />
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
|
@@ -1,12 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import './index.less';
|
||||
export default class BatchBox extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div className="upload-batch-questions-box">批量上传</div>;
|
||||
}
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
.upload-batch-questions-box {
|
||||
margin: 0 auto;
|
||||
width: 1000px;
|
||||
display: flex;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #3d3d3d;
|
||||
}
|
@@ -1,9 +1,10 @@
|
||||
import { RightOutlined } from '@ant-design/icons'
|
||||
import { Button, Space } from 'antd'
|
||||
import React, { Component } from 'react'
|
||||
import BriefQuestions from '../../components/brief-questions'
|
||||
import JudgeQuestions from '../../components/judge-questions'
|
||||
import MultipleQuestions from '../../components/multiple-questions'
|
||||
import SingleQuestions from '../../components/single-questions'
|
||||
import UploadLeftLayout from '../../components/upload-left-layout'
|
||||
import { uploadLayout } from '../../constant'
|
||||
|
||||
import './index.less'
|
||||
@@ -40,16 +41,6 @@ export default class SingleBox extends Component {
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { currentIndex, layoutList } = this.state
|
||||
return (
|
||||
<div style={{ display: 'flex' }}>
|
||||
<UploadLeftLayout layoutList={layoutList} onChange={this.onChangeQuestionsType} />
|
||||
<div className='upload-questions-modular'>{this.changeReander(currentIndex)}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
changeReander = i => {
|
||||
switch (i) {
|
||||
case 0:
|
||||
@@ -62,4 +53,32 @@ export default class SingleBox extends Component {
|
||||
return <JudgeQuestions questionsType={i + 1} key={`question_${i}`} />
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { currentIndex, layoutList } = this.state
|
||||
return (
|
||||
<div style={{ display: 'flex' }}>
|
||||
{/* <UploadLeftLayout layoutList={layoutList} onChange={this.onChangeQuestionsType} /> */}
|
||||
<div style={{ flex: 1 }}>
|
||||
<Space direction='vertical'>
|
||||
{layoutList.map((item, index) => {
|
||||
return (
|
||||
<Button
|
||||
key={item.id}
|
||||
type={item.active ? 'primary' : 'default'}
|
||||
ghost={item.active}
|
||||
block
|
||||
onClick={() => this.onChangeQuestionsType(index)}
|
||||
>
|
||||
{item.title}
|
||||
<RightOutlined style={{ marginLeft: 54 }} />
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
</Space>
|
||||
</div>
|
||||
<div className='upload-questions-modular'>{this.changeReander(currentIndex)}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -1,29 +1,33 @@
|
||||
.ant-modal-body {
|
||||
padding: 12px 24px 0;
|
||||
padding: 12px 24px 0;
|
||||
}
|
||||
.upload-questions-modular {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 auto;
|
||||
margin-left: 35px;
|
||||
background: rgba(249, 250, 252, 1);
|
||||
border: 2px solid rgba(240, 240, 240, 1);
|
||||
border-radius: 12px;
|
||||
// display: flex;
|
||||
// flex-direction: column;
|
||||
margin: 0 auto;
|
||||
margin-left: 35px;
|
||||
background: rgba(249, 250, 252, 1);
|
||||
border: 2px solid rgba(240, 240, 240, 1);
|
||||
border-radius: 12px;
|
||||
height: calc(100vh - 220px);
|
||||
overflow-y: scroll;
|
||||
width: 100%;
|
||||
// flex: 1 0 auto;
|
||||
}
|
||||
.questions-success-modal-confirm {
|
||||
width: 300px;
|
||||
// 录入成功弹框
|
||||
.ant-modal-confirm-btns {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
.ant-btn {
|
||||
width: 100px;
|
||||
border-radius: 18px;
|
||||
}
|
||||
.ant-btn-primary {
|
||||
background: rgba(60, 110, 238, 1);
|
||||
margin-left: 60px;
|
||||
}
|
||||
width: 300px;
|
||||
// 录入成功弹框
|
||||
.ant-modal-confirm-btns {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
.ant-btn {
|
||||
width: 100px;
|
||||
border-radius: 18px;
|
||||
}
|
||||
.ant-btn-primary {
|
||||
background: rgba(60, 110, 238, 1);
|
||||
margin-left: 60px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,9 @@
|
||||
import Head from '@/imgs/head.jpg'
|
||||
import { LoadingOutlined, PlusOutlined } from '@ant-design/icons'
|
||||
import { saveUserInfo } from '@features/userInfoSlice.ts'
|
||||
import req from '@utils/request'
|
||||
import { Button, Card, Col, Form, Input, Radio, Row, Upload, message } from 'antd'
|
||||
import { memo, useEffect, useState } from 'react'
|
||||
import { useDispatch } from 'react-redux'
|
||||
|
||||
import './index.less'
|
||||
|
||||
@@ -54,6 +55,8 @@ const UserInfo = () => {
|
||||
const userInfoStorage = localStorage.getItem('userInfo')
|
||||
const { loginId = '', tokenValue = '' } = userInfoStorage ? JSON.parse(userInfoStorage) : {}
|
||||
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const [form] = Form.useForm()
|
||||
const [editFlag, setEditFlag] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
@@ -73,6 +76,7 @@ const UserInfo = () => {
|
||||
).then(res => {
|
||||
if (res?.success && res?.data) {
|
||||
setUserInfo(res.data)
|
||||
setAvatar(res.data.avatar || '')
|
||||
form.setFieldsValue(res.data)
|
||||
}
|
||||
})
|
||||
@@ -87,7 +91,6 @@ const UserInfo = () => {
|
||||
const onFinish = () => {
|
||||
setLoading(true)
|
||||
const values = form.getFieldsValue()
|
||||
// return console.log(values)
|
||||
if (!Object.values(values).filter(Boolean).length && !avatar) {
|
||||
setLoading(false)
|
||||
return
|
||||
@@ -108,10 +111,13 @@ const UserInfo = () => {
|
||||
'/auth'
|
||||
)
|
||||
.then(res => {
|
||||
dispatch(saveUserInfo(params))
|
||||
setUserInfo(params)
|
||||
setAvatar(params.avatar || '')
|
||||
if (res.success) {
|
||||
message.success('更新成功')
|
||||
setTimeout(() => {
|
||||
getUserInfo()
|
||||
// getUserInfo()
|
||||
setLoading(false)
|
||||
setEditFlag(false)
|
||||
}, 500)
|
||||
@@ -126,7 +132,6 @@ const UserInfo = () => {
|
||||
}
|
||||
|
||||
const handleChange = ({ file }) => {
|
||||
// console.log(info)
|
||||
if (file.status === 'done' && file.response.success && file.response.data) {
|
||||
setAvatar(file.response.data)
|
||||
}
|
||||
@@ -174,7 +179,12 @@ const UserInfo = () => {
|
||||
</Form.Item>
|
||||
) : (
|
||||
<Form.Item label='用户头像'>
|
||||
<img className='user-info_header' src={userInfo.avatar || Head} />
|
||||
{userInfo.avatar ? (
|
||||
<img className='user-info_header' src={userInfo.avatar} />
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
{/* <img className='user-info_header' src={userInfo.avatar || Head} /> */}
|
||||
</Form.Item>
|
||||
)}
|
||||
</Col>
|
||||
|
@@ -25,7 +25,9 @@ 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'),
|
||||
'@store': path.resolve(__dirname, 'src/store'),
|
||||
'@features': path.resolve(__dirname, 'src/store/features')
|
||||
}
|
||||
},
|
||||
plugins: [react()],
|
||||
|
Reference in New Issue
Block a user