feat: 增加练题
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ant-design/charts": "^1.4.3",
|
||||||
"@ant-design/icons": "^5.2.6",
|
"@ant-design/icons": "^5.2.6",
|
||||||
"@reduxjs/toolkit": "^1.9.7",
|
"@reduxjs/toolkit": "^1.9.7",
|
||||||
"@wangeditor/editor": "^5.1.23",
|
"@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 {
|
.app-main {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background-color: #f3f4f6;
|
background-color: #f3f4f6;
|
||||||
padding: 66px 16px 32px;
|
padding: 66px 16px 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
-webkit-touch-callout: none; /* iOS Safari */
|
-webkit-touch-callout: none; /* iOS Safari */
|
||||||
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||||
@@ -25,5 +25,11 @@
|
|||||||
width: 1439px;
|
width: 1439px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
overflow: 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 Header from '@views/header'
|
||||||
import { Suspense, memo, useEffect } from 'react'
|
import { Suspense, memo, useEffect } from 'react'
|
||||||
|
import { useDispatch } from 'react-redux'
|
||||||
import { Outlet, useLocation, useNavigate } from 'react-router-dom'
|
import { Outlet, useLocation, useNavigate } from 'react-router-dom'
|
||||||
|
// 引入对应的方法
|
||||||
import './App.less'
|
import './App.less'
|
||||||
|
import { saveUserInfo } from './store/features/userInfoSlice.ts'
|
||||||
|
|
||||||
|
const apiName = {
|
||||||
|
update: '/user/update',
|
||||||
|
queryInfo: '/user/getUserInfo'
|
||||||
|
}
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
|
const userInfoStorage = localStorage.getItem('userInfo')
|
||||||
|
const { loginId = '' } = userInfoStorage ? JSON.parse(userInfoStorage) : {}
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const navigate = useNavigate()
|
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(() => {
|
useEffect(() => {
|
||||||
if (location.pathname === '/') {
|
if (location.pathname === '/') {
|
||||||
const userInfoStorage = localStorage.getItem('userInfo')
|
const userInfoStorage = localStorage.getItem('userInfo')
|
||||||
@@ -18,7 +53,7 @@ const App = () => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='app-main'
|
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 />
|
<Header />
|
||||||
<div
|
<div
|
||||||
@@ -29,6 +64,11 @@ const App = () => {
|
|||||||
<Outlet />
|
<Outlet />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
|
<div className='copyright'>
|
||||||
|
<a href='http://beian.miit.gov.cn/' target='_blank'>
|
||||||
|
京ICP备2023035579号
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</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 { PlusOutlined } from '@ant-design/icons'
|
||||||
import { Input, Tag, Tooltip, message } from 'antd';
|
import req from '@utils/request'
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { Input, Tag, Tooltip, message } from 'antd'
|
||||||
import { apiName, ModuleType } from './constant';
|
import { ModuleType, apiName } from './constant'
|
||||||
import './index.less';
|
import './index.less'
|
||||||
|
|
||||||
const apiNameModule = {
|
const apiNameModule = {
|
||||||
[ModuleType.second]: [apiName.addInterviewCategory, apiName.deleteInterviewCategory],
|
[ModuleType.second]: [apiName.addInterviewCategory, apiName.deleteInterviewCategory],
|
||||||
[ModuleType.third]: [apiName.addInterviewLabel, apiName.deleteInterviewLabel],
|
[ModuleType.third]: [apiName.addInterviewLabel, apiName.deleteInterviewLabel]
|
||||||
};
|
}
|
||||||
|
|
||||||
export default class TagsEditor extends Component {
|
export default class TagsEditor extends Component {
|
||||||
saveInputRef = (input) => (this.input = input);
|
saveInputRef = input => (this.input = input)
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
inputVisible: false,
|
inputVisible: false,
|
||||||
inputValue: '',
|
inputValue: ''
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 点击X号
|
* 点击X号
|
||||||
* @param {*} index 当前index
|
* @param {*} index 当前index
|
||||||
* @param {*} categoryId 当前id
|
* @param {*} categoryId 当前id
|
||||||
*/
|
*/
|
||||||
handleClose = (index, categoryId) => {
|
handleClose = (index, categoryId) => {
|
||||||
const { moduleType, categoryList } = this.props;
|
const { moduleType, categoryList } = this.props
|
||||||
let params = {
|
let params = {
|
||||||
id: categoryId,
|
id: categoryId
|
||||||
};
|
}
|
||||||
let url = apiNameModule[moduleType][1];
|
let url = apiNameModule[moduleType][1]
|
||||||
req({
|
req({
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: params,
|
data: params,
|
||||||
url: url,
|
url: url
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then(res => {
|
||||||
if (res.data) {
|
if (res.data) {
|
||||||
let list = categoryList.filter((item) => {
|
let list = categoryList.filter(item => {
|
||||||
return item.id !== categoryId;
|
return item.id !== categoryId
|
||||||
});
|
})
|
||||||
this.props.onChangeLabel(list, this.formatList(list));
|
this.props.onChangeLabel(list, this.formatList(list))
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 展示输入框
|
|
||||||
*/
|
|
||||||
showInput = () => {
|
|
||||||
this.setState({ inputVisible: true }, () => this.input.focus());
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 输入框改变内容
|
|
||||||
* @param {*} e
|
|
||||||
*/
|
|
||||||
handleInputChange = (e) => {
|
|
||||||
this.setState({ inputValue: e.target.value });
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 增加标签
|
|
||||||
*/
|
|
||||||
handleInputConfirm = () => {
|
|
||||||
let { categoryList } = this.props;
|
|
||||||
let { inputValue } = this.state;
|
|
||||||
let equalList = [],
|
|
||||||
formatInputValue = inputValue.trim();
|
|
||||||
if (!formatInputValue) {
|
|
||||||
this.setState({
|
|
||||||
inputValue: '',
|
|
||||||
inputVisible: false,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (categoryList.length > 0) {
|
})
|
||||||
equalList = categoryList.filter((item) => {
|
.catch(err => {
|
||||||
return item.categoryName.toLowerCase() === formatInputValue.toLowerCase();
|
console.log(err)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
if (equalList.length <= 0) {
|
|
||||||
this.postAddInterviewCategory(formatInputValue);
|
|
||||||
} else {
|
|
||||||
message.info('所增内容已存在', 0.3);
|
|
||||||
this.setState({
|
|
||||||
inputValue: '',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增加标签
|
* 展示输入框
|
||||||
* @param {*} inputValue 当前的值
|
*/
|
||||||
*/
|
showInput = () => {
|
||||||
postAddInterviewCategory = (inputValue) => {
|
this.setState({ inputVisible: true }, () => this.input.focus())
|
||||||
const { parentCategoryValue, moduleType, categoryList } = this.props;
|
}
|
||||||
let params_2 = {
|
|
||||||
categoryName: inputValue,
|
|
||||||
categoryType: 2,
|
|
||||||
parentId: parentCategoryValue[0],
|
|
||||||
};
|
|
||||||
let params_3 = {
|
|
||||||
labelName: inputValue,
|
|
||||||
primaryCategoryId: parentCategoryValue[0],
|
|
||||||
};
|
|
||||||
let params = moduleType == ModuleType.third ? params_3 : params_2;
|
|
||||||
req({
|
|
||||||
method: 'post',
|
|
||||||
data: params,
|
|
||||||
url: apiNameModule[moduleType][0],
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
if (res.data) {
|
|
||||||
let id = res.data;
|
|
||||||
let list = [
|
|
||||||
...categoryList,
|
|
||||||
{
|
|
||||||
categoryName: inputValue,
|
|
||||||
categoryId: id,
|
|
||||||
isShowClose: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
let formatList = this.onHandleLabelSelectState(list, list.length - 1, false);
|
|
||||||
this.setState(
|
|
||||||
{
|
|
||||||
inputVisible: false,
|
|
||||||
inputValue: '',
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
this.props.onChangeLabel(formatList, this.formatList(formatList));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 选中/未选中-标签
|
* 输入框改变内容
|
||||||
* @param {*} tagIndex 选择的标签
|
* @param {*} e
|
||||||
* @param {*} active 选择的标签的当前状态
|
*/
|
||||||
* @returns
|
handleInputChange = e => {
|
||||||
*/
|
this.setState({ inputValue: e.target.value })
|
||||||
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 当前索引
|
handleInputConfirm = () => {
|
||||||
* @param {*} active 当前选中状态
|
let { categoryList } = this.props
|
||||||
* @returns
|
let { inputValue } = this.state
|
||||||
*/
|
let equalList = [],
|
||||||
onHandleLabelSelectState = (list, tagIndex, active) => {
|
formatInputValue = inputValue.trim()
|
||||||
const { isSingleChoice } = this.props;
|
if (!formatInputValue) {
|
||||||
let formatLabelList = [];
|
this.setState({
|
||||||
// 单选
|
inputValue: '',
|
||||||
if (isSingleChoice) {
|
inputVisible: false
|
||||||
formatLabelList = list.map((item, index) => {
|
})
|
||||||
let flag = false;
|
return
|
||||||
if (index == tagIndex) {
|
}
|
||||||
flag = !active; // 将三级标签设置选中/未选中
|
if (categoryList.length > 0) {
|
||||||
}
|
equalList = categoryList.filter(item => {
|
||||||
return {
|
return item.categoryName.toLowerCase() === formatInputValue.toLowerCase()
|
||||||
...item,
|
})
|
||||||
active: flag,
|
}
|
||||||
};
|
if (equalList.length <= 0) {
|
||||||
});
|
this.postAddInterviewCategory(formatInputValue)
|
||||||
} else {
|
} else {
|
||||||
// 多选
|
message.info('所增内容已存在', 0.3)
|
||||||
formatLabelList = list.map((item, index) => {
|
this.setState({
|
||||||
let flag = item.active;
|
inputValue: ''
|
||||||
if (index == tagIndex) {
|
})
|
||||||
flag = !active; // 将三级标签设置选中/未选中
|
}
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
active: flag,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return formatLabelList;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式化数据-获得选中项id列表
|
* 增加标签
|
||||||
* @param {*} list
|
* @param {*} inputValue 当前的值
|
||||||
* @returns
|
*/
|
||||||
*/
|
postAddInterviewCategory = inputValue => {
|
||||||
formatList = (list) => {
|
const { parentCategoryValue, moduleType, categoryList } = this.props
|
||||||
let labelList = [];
|
let params_2 = {
|
||||||
list.forEach((item) => {
|
categoryName: inputValue,
|
||||||
if (item.active) {
|
categoryType: 2,
|
||||||
labelList.push(item.id);
|
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;
|
let formatList = this.onHandleLabelSelectState(list, list.length - 1, false)
|
||||||
};
|
this.setState(
|
||||||
|
{
|
||||||
render() {
|
inputVisible: false,
|
||||||
const { moduleType, categoryList, isAddTag, isDeleteTag } = this.props;
|
inputValue: ''
|
||||||
const { inputVisible, inputValue } = this.state;
|
},
|
||||||
let labelList = categoryList;
|
() => {
|
||||||
// 数组中存在 -9999 表示暂无数据,需要支持新增
|
this.props.onChangeLabel(formatList, this.formatList(formatList))
|
||||||
if (
|
}
|
||||||
categoryList.filter((item) => {
|
)
|
||||||
return item.id === -9999;
|
|
||||||
}).length > 0
|
|
||||||
) {
|
|
||||||
labelList = categoryList.slice(1, categoryList.length);
|
|
||||||
}
|
}
|
||||||
return (
|
})
|
||||||
<div className="tags-editor-box">
|
.catch(err => {
|
||||||
{labelList?.length > 0 &&
|
console.log(err)
|
||||||
labelList.map((item, index) => {
|
})
|
||||||
const isLongTag = item.categoryName?.length > 20;
|
}
|
||||||
const tagElem = (
|
|
||||||
<Tag
|
/**
|
||||||
style={{
|
* 选中/未选中-标签
|
||||||
margin: '4px',
|
* @param {*} tagIndex 选择的标签
|
||||||
height: '40px',
|
* @param {*} active 选择的标签的当前状态
|
||||||
lineHeight: '40px',
|
* @returns
|
||||||
fontSize: '13px',
|
*/
|
||||||
padding: '0px 16px',
|
onChangeLabel = (tagIndex, active) => () => {
|
||||||
border: '1px solid #d9d9d9',
|
let { categoryList, isDisabledReverseSelection } = this.props
|
||||||
backgroundColor: '#fff',
|
if (active && isDisabledReverseSelection) {
|
||||||
cursor: 'pointer',
|
return
|
||||||
}}
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
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',
|
key: 'questionBank',
|
||||||
title: '刷题',
|
title: '刷题',
|
||||||
route: '/question-bank'
|
route: '/question-bank',
|
||||||
|
finished: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'prictiseQuestion',
|
key: 'prictiseQuestion',
|
||||||
title: '练题',
|
title: '练题',
|
||||||
route: '/brush-question'
|
route: '/practice-questions',
|
||||||
|
finished: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'practiceQuestions',
|
key: 'practiceQuestions',
|
||||||
title: '鸡圈',
|
title: '鸡圈',
|
||||||
route: '/practice-questions'
|
route: '/jichi-club',
|
||||||
|
finished: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'interList',
|
key: 'interList',
|
||||||
title: '模拟面试',
|
title: '模拟面试',
|
||||||
route: '/inter-list'
|
route: '/inter-list',
|
||||||
|
finished: false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -55,10 +59,10 @@ const TopMenu = () => {
|
|||||||
if (!userInfoStorage) {
|
if (!userInfoStorage) {
|
||||||
return message.info('请登录')
|
return message.info('请登录')
|
||||||
}
|
}
|
||||||
if (item.key === 'questionBank') {
|
if (item.finished) {
|
||||||
if (location.pathname === '/question-bank') return
|
if (location.pathname === item.route) return
|
||||||
navigate('/question-bank')
|
|
||||||
setCurrentKey(item.key)
|
setCurrentKey(item.key)
|
||||||
|
navigate(item.route)
|
||||||
} else {
|
} else {
|
||||||
return message.info('敬请期待')
|
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'))
|
Component: lazy(() => import('@views/search-details'))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'personal-center',
|
path: 'personal-center/:tab',
|
||||||
Component: lazy(() => import('@views/personal-center'))
|
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'
|
import { createSlice } from '@reduxjs/toolkit'
|
||||||
|
|
||||||
export interface CounterState {
|
export interface UserInfo {
|
||||||
value: number
|
nickName?: string
|
||||||
title: string
|
phone?: string
|
||||||
|
email?: string
|
||||||
|
sex?: string | number
|
||||||
|
introduce?: string
|
||||||
|
avatar?: string
|
||||||
}
|
}
|
||||||
const initialState: CounterState = {
|
const initialState: UserInfo = {
|
||||||
value: 0,
|
nickName: '',
|
||||||
title: 'redux toolkit pre'
|
phone: '',
|
||||||
|
email: '',
|
||||||
|
sex: undefined,
|
||||||
|
introduce: '',
|
||||||
|
avatar: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建一个 Slice
|
// 创建一个 Slice
|
||||||
export const userInfoSlice = createSlice({
|
export const userInfoSlice = createSlice({
|
||||||
name: 'userInfo',
|
name: 'userInfo',
|
||||||
initialState,
|
initialState: {
|
||||||
|
userInfo: initialState
|
||||||
|
},
|
||||||
// 定义 reducers 并生成关联的操作
|
// 定义 reducers 并生成关联的操作
|
||||||
reducers: {
|
reducers: {
|
||||||
// 定义一个加的方法
|
// 定义一个加的方法
|
||||||
saveUserInfo: (state, { payload }) => {
|
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 Logo from '@/imgs/logo.jpg'
|
||||||
import { HeartOutlined, LikeOutlined, LoginOutlined, UserOutlined } from '@ant-design/icons'
|
import { HeartOutlined, LikeOutlined, LoginOutlined, UserOutlined } from '@ant-design/icons'
|
||||||
import TopMenu from '@components/top-menu'
|
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 req from '@utils/request'
|
||||||
import { Button, Dropdown, Input, Modal, Popover, Space, message } from 'antd'
|
import { Button, Dropdown, Input, Modal, Popover, Space, message } from 'antd'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
import './index.less'
|
import './index.less'
|
||||||
@@ -15,17 +15,20 @@ const menuItems = [
|
|||||||
{
|
{
|
||||||
label: '个人中心',
|
label: '个人中心',
|
||||||
key: 1,
|
key: 1,
|
||||||
icon: <UserOutlined style={{ fontSize: '16px' }} />
|
icon: <UserOutlined style={{ fontSize: '16px' }} />,
|
||||||
|
path: '/user-info'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '我的收藏',
|
label: '我的收藏',
|
||||||
key: 2,
|
key: 2,
|
||||||
icon: <HeartOutlined style={{ fontSize: '16px' }} />
|
icon: <HeartOutlined style={{ fontSize: '16px' }} />,
|
||||||
|
path: '/personal-center/0'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '我的点赞',
|
label: '我的点赞',
|
||||||
key: 3,
|
key: 3,
|
||||||
icon: <LikeOutlined style={{ fontSize: '16px' }} />
|
icon: <LikeOutlined style={{ fontSize: '16px' }} />,
|
||||||
|
path: '/personal-center/1'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'divider'
|
type: 'divider'
|
||||||
@@ -47,19 +50,19 @@ const discoverItems = [
|
|||||||
title: '跟我做',
|
title: '跟我做',
|
||||||
subTitle: '从0到1做鸡翅Club项目',
|
subTitle: '从0到1做鸡翅Club项目',
|
||||||
key: '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: '更深入',
|
title: '更深入',
|
||||||
subTitle: '从0到1做企业级框架项目',
|
subTitle: '从0到1做企业级框架项目',
|
||||||
key: 'deep',
|
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: '加星球',
|
title: '加星球',
|
||||||
subTitle: '一键进入鸡哥的知识星球',
|
subTitle: '一键进入鸡哥的知识星球',
|
||||||
key: 'star',
|
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 { pathname } = window.location
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
const { userInfo } = useSelector(store => store.userInfo)
|
||||||
|
|
||||||
const handleMenuClick = e => {
|
const handleMenuClick = e => {
|
||||||
const userInfoStorage = localStorage.getItem('userInfo')
|
const userInfoStorage = localStorage.getItem('userInfo')
|
||||||
if (!userInfoStorage) {
|
if (!userInfoStorage) {
|
||||||
return message.info('请登录')
|
return message.info('请登录')
|
||||||
}
|
}
|
||||||
const { loginId } = JSON.parse(userInfoStorage)
|
const { loginId } = JSON.parse(userInfoStorage)
|
||||||
switch (e.key) {
|
if (e.key == 4) {
|
||||||
case '1':
|
Modal.confirm({
|
||||||
navigate('/user-info')
|
title: '退出提示',
|
||||||
break
|
content: '确定退出当前用户登录吗?',
|
||||||
case '4':
|
okText: '确定',
|
||||||
// 退出
|
cancelText: '取消',
|
||||||
Modal.confirm({
|
onOk: () => {
|
||||||
title: '退出提示',
|
req(
|
||||||
content: '确定退出当前用户登录吗?',
|
{
|
||||||
okText: '确定',
|
method: 'get',
|
||||||
cancelText: '取消',
|
url: '/user/logOut',
|
||||||
onOk: () => {
|
params: {
|
||||||
req(
|
userName: loginId
|
||||||
{
|
|
||||||
method: 'get',
|
|
||||||
url: '/user/logOut',
|
|
||||||
params: {
|
|
||||||
userName: loginId
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'/auth'
|
|
||||||
).then(res => {
|
|
||||||
if (res.success) {
|
|
||||||
localStorage.removeItem('userInfo')
|
|
||||||
message.info('退出成功')
|
|
||||||
setTimeout(() => {
|
|
||||||
navigate('/login')
|
|
||||||
}, 500)
|
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
}
|
'/auth'
|
||||||
})
|
).then(res => {
|
||||||
break
|
if (res.success) {
|
||||||
default:
|
localStorage.removeItem('userInfo')
|
||||||
message.info('敬请期待')
|
message.info('退出成功')
|
||||||
break
|
setTimeout(() => {
|
||||||
|
navigate('/login')
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
navigate(e.item.props.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +132,7 @@ const Header = () => {
|
|||||||
<div className='head-navigator-user-box'>
|
<div className='head-navigator-user-box'>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
placement='bottom'
|
placement='bottom'
|
||||||
trigger={['click']}
|
// trigger={['click']}
|
||||||
destroyPopupOnHide
|
destroyPopupOnHide
|
||||||
dropdownRender={() => {
|
dropdownRender={() => {
|
||||||
return (
|
return (
|
||||||
@@ -174,7 +172,7 @@ const Header = () => {
|
|||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button type='link'>发现精彩</Button>
|
<Button type='link'>升职加薪必看</Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
{'/question-bank' == pathname && (
|
{'/question-bank' == pathname && (
|
||||||
<div className='head-navigator-input-box'>
|
<div className='head-navigator-input-box'>
|
||||||
@@ -189,22 +187,29 @@ const Header = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className='head-navigator-user-img'>
|
{'/login' !== pathname && (
|
||||||
<Dropdown
|
<div className='head-navigator-user-img'>
|
||||||
menu={{
|
<Dropdown
|
||||||
items: menuItems,
|
menu={{
|
||||||
onClick: handleMenuClick
|
items: menuItems,
|
||||||
}}
|
onClick: handleMenuClick
|
||||||
placement='bottom'
|
}}
|
||||||
trigger={['click']}
|
placement='bottom'
|
||||||
destroyPopupOnHide
|
trigger={['click']}
|
||||||
overlayStyle={{
|
destroyPopupOnHide
|
||||||
width: '150px'
|
overlayStyle={{
|
||||||
}}
|
width: '150px'
|
||||||
>
|
}}
|
||||||
<img src={Head} style={{ width: 36, height: 36 }} />
|
>
|
||||||
</Dropdown>
|
{userInfo.avatar ? (
|
||||||
</div>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
|
import { saveUserInfo } from '@features/userInfoSlice.ts'
|
||||||
import LoginQrcode from '@imgs/login_qrcode.jpg'
|
import LoginQrcode from '@imgs/login_qrcode.jpg'
|
||||||
import req from '@utils/request'
|
import req from '@utils/request'
|
||||||
import { Button, Input, Space, message } from 'antd'
|
import { Button, Input, Space, message } from 'antd'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
import { useDispatch } from 'react-redux'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
import './index.less'
|
import './index.less'
|
||||||
@@ -11,13 +13,30 @@ const loginApiName = '/user/doLogin'
|
|||||||
const Login = () => {
|
const Login = () => {
|
||||||
const [validCode, setValidCode] = useState('')
|
const [validCode, setValidCode] = useState('')
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
const changeCode = e => {
|
const changeCode = e => {
|
||||||
setValidCode(e.target.value)
|
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 = () => {
|
const doLogin = () => {
|
||||||
console.log(validCode)
|
|
||||||
if (!validCode) return
|
if (!validCode) return
|
||||||
req(
|
req(
|
||||||
{
|
{
|
||||||
@@ -26,13 +45,14 @@ const Login = () => {
|
|||||||
params: { validCode }
|
params: { validCode }
|
||||||
},
|
},
|
||||||
'/auth'
|
'/auth'
|
||||||
).then(res => {
|
).then(async res => {
|
||||||
if (res.success && res.data) {
|
if (res.success && res.data) {
|
||||||
message.success('登录成功')
|
message.success('登录成功')
|
||||||
localStorage.setItem('userInfo', JSON.stringify(res.data))
|
localStorage.setItem('userInfo', JSON.stringify(res.data))
|
||||||
|
await getUserInfo(res.data.loginId)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navigate('/question-bank')
|
navigate('/question-bank')
|
||||||
}, 1000)
|
}, 500)
|
||||||
} else {
|
} else {
|
||||||
message.error('登录失败,请重试')
|
message.error('登录失败,请重试')
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
import { Card, Pagination, Spin } from 'antd'
|
import { Card, Pagination, Spin } from 'antd'
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { collectTabType } from '../../constant'
|
import { collectTabType } from '../../constant'
|
||||||
import CollectionQuestion from '../collection-question'
|
|
||||||
import EmptyBox from '../empty-box'
|
import EmptyBox from '../empty-box'
|
||||||
|
import QuestionList from '../question-list'
|
||||||
import './index.less'
|
import './index.less'
|
||||||
const tabList = [
|
const tabList = [
|
||||||
{
|
{
|
||||||
@@ -21,7 +21,7 @@ export default class CollectionBag extends Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
currentKey: collectTabType.testQuestions, // 选中的tab 默认选中第一个
|
currentKey: collectTabType.testQuestions, // 选中的tab 默认选中第一个
|
||||||
collectionList: [],
|
collectionList: [],
|
||||||
isShowSpin: true,
|
isShowSpin: false,
|
||||||
isShowSkeleton: true
|
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:
|
case collectTabType.testQuestions:
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<CollectionQuestion collectionList={collectionList} collectionTotal={this.total} />
|
<QuestionList list={collectionList} total={this.total} name='收藏' />
|
||||||
</div>
|
</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() {
|
export default function EmptyBox() {
|
||||||
return (
|
return (
|
||||||
<div className='empty-box'>
|
<div className='empty-box'>
|
||||||
<img className='empty-inco' />
|
{/* <img className='empty-inco' /> */}
|
||||||
<span className='empty-text'>这里什么也没有哦~</span>
|
<span className='empty-text'>这里什么也没有哦~</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@@ -2,7 +2,7 @@ import { Card, Pagination, Spin } from 'antd'
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { goodTabType } from '../../constant'
|
import { goodTabType } from '../../constant'
|
||||||
import EmptyBox from '../empty-box'
|
import EmptyBox from '../empty-box'
|
||||||
import GoodQuestion from '../good-question'
|
import QuestionList from '../question-list'
|
||||||
import './index.less'
|
import './index.less'
|
||||||
const tabList = [
|
const tabList = [
|
||||||
{
|
{
|
||||||
@@ -21,7 +21,7 @@ export default class GoodBag extends Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
currentKey: goodTabType.testQuestions, // 选中的tab 默认选中第一个
|
currentKey: goodTabType.testQuestions, // 选中的tab 默认选中第一个
|
||||||
goodList: [],
|
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) {
|
switch (type) {
|
||||||
// 收藏的试题
|
// 收藏的试题
|
||||||
case goodTabType.testQuestions:
|
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 {
|
.collection-bag-component-tab1-body-item {
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
|
padding: 10px 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
clear: both;
|
// clear: both;
|
||||||
// height: 60px;
|
// height: 60px;
|
||||||
border-bottom: 1px solid #e5e5e5;
|
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 { Menu } from 'antd'
|
||||||
import PubSub from 'pubsub-js'
|
import React, { useEffect, useState } from 'react'
|
||||||
import React, { Component } from 'react'
|
import { useSelector } from 'react-redux'
|
||||||
|
import { useParams } from 'react-router-dom'
|
||||||
import CollectionBag from './components/collection-bag'
|
import CollectionBag from './components/collection-bag'
|
||||||
import GoodBag from './components/good-bag'
|
import GoodBag from './components/good-bag'
|
||||||
import './index.less'
|
import './index.less'
|
||||||
|
|
||||||
export default class PersonalCenter extends Component {
|
const personList = {
|
||||||
constructor(props) {
|
0: '收藏',
|
||||||
super(props)
|
1: '点赞'
|
||||||
this.state = {
|
}
|
||||||
currentKeyMap: 0, //选中的menu
|
|
||||||
userName: '', //姓名
|
const PersonalCenter = props => {
|
||||||
intervieweEamil: '', //邮箱
|
const [currentKeyMap, setCurrentKeyMap] = useState(0)
|
||||||
headImg: '', //头像
|
const { userInfo } = useSelector(store => store.userInfo)
|
||||||
department: '', //部门
|
const [selectedKeys, setSelectedKeys] = useState('0')
|
||||||
practiceAmount: 0, //练题数
|
|
||||||
inputAmount: 0, //录题数
|
const { tab } = useParams()
|
||||||
goodAmount: 0, //点赞数
|
|
||||||
collectionAmount: 0, //收藏数
|
useEffect(() => {
|
||||||
subMenuList: []
|
setCurrentKeyMap(+tab)
|
||||||
}
|
setSelectedKeys(tab)
|
||||||
|
}, [tab])
|
||||||
|
|
||||||
|
const handleClick = ({ key }) => {
|
||||||
|
setCurrentKeyMap(Number(key))
|
||||||
|
setSelectedKeys(key)
|
||||||
}
|
}
|
||||||
personList = {
|
|
||||||
// 0: '刷题',
|
return (
|
||||||
0: '收藏',
|
<div className='personal-center-box'>
|
||||||
1: '点赞'
|
<div className='personal-center-introduction'>
|
||||||
}
|
<div className='personal-center-introduction-detail'>
|
||||||
componentDidMount() {
|
<div className='personal-center-introduction-detail-headImg'>
|
||||||
PubSub.subscribe('handleToRender', () => {
|
<img src={userInfo.avatar} style={{ width: 60, height: 60, borderRadius: '50%' }} />
|
||||||
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>
|
|
||||||
</div>
|
</div>
|
||||||
<div className='personal-center-introduction-result'>
|
<div className='personal-center-introduction-detail-text'>
|
||||||
<div className='personal-center-introduction-result-item'>
|
<div className='personal-center-introduction-detail-name'>{userInfo.nickName}</div>
|
||||||
<div className='personal-center-introduction-result-item-number'>
|
{/* <div className='personal-center-introduction-detail-information'>
|
||||||
{practiceAmount}
|
<span className='personal-center-introduction-detail-information-content'>
|
||||||
</div>
|
<IdcardOutlined style={{ color: 'blue', marginRight: '3px' }} />
|
||||||
<div>练题</div>
|
</span>
|
||||||
</div>
|
<span className='personal-center-introduction-detail-information-content'>
|
||||||
<div className='personal-center-introduction-result-item'>
|
<MailOutlined style={{ color: 'blue', marginRight: '3px' }} />
|
||||||
<div className='personal-center-introduction-result-item-number'>{inputAmount}</div>
|
</span>
|
||||||
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='personal-center-content'>
|
<div className='personal-center-introduction-result'>
|
||||||
<div className='personal-center-content-left'>
|
{/* <div className='personal-center-introduction-result-item'>
|
||||||
<Menu
|
<div className='personal-center-introduction-result-item-number'>{10}</div>
|
||||||
mode='inline'
|
<div>练题</div>
|
||||||
onClick={this.handleClick}
|
</div> */}
|
||||||
style={{ width: 256 }}
|
{/* <div className='personal-center-introduction-result-item'>
|
||||||
defaultSelectedKeys={['personList_0']}
|
<div className='personal-center-introduction-result-item-number'>{inputAmount}</div>
|
||||||
>
|
<div>录题</div>
|
||||||
{/* <Menu.Item key={`personList_0`}>
|
</div> */}
|
||||||
<MailOutlined style={{ color: 'rgb(171,214,97)' }} />
|
<div className='personal-center-introduction-result-item'>
|
||||||
<span>{this.personList[0]}</span>
|
<div className='personal-center-introduction-result-item-number'>{20}</div>
|
||||||
</Menu.Item> */}
|
<div>点赞</div>
|
||||||
<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>
|
</div>
|
||||||
<div className='personal-center-content-right'>
|
<div className='personal-center-introduction-result-item'>
|
||||||
{/* {currentKeyMap === 0 && <BrushQuestion />} */}
|
<div className='personal-center-introduction-result-item-number'>{30}</div>
|
||||||
{currentKeyMap === 0 && <CollectionBag />}
|
<div>收藏</div>
|
||||||
{currentKeyMap === 1 && <GoodBag />}
|
|
||||||
</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 {
|
.personal-center-box {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
width: 1439px;
|
width: 1439px;
|
||||||
// padding: 20px 50px;
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
.personal-center-introduction {
|
.personal-center-introduction {
|
||||||
@@ -11,10 +10,12 @@
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
.personal-center-introduction-detail {
|
.personal-center-introduction-detail {
|
||||||
margin-left: 50px;
|
margin-left: 50px;
|
||||||
padding-top: 20px;
|
// padding-top: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
.personal-center-introduction-detail-headImg {
|
.personal-center-introduction-detail-headImg {
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -34,8 +35,8 @@
|
|||||||
}
|
}
|
||||||
.personal-center-introduction-result {
|
.personal-center-introduction-result {
|
||||||
margin-right: 50px;
|
margin-right: 50px;
|
||||||
padding-top: 30px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
.personal-center-introduction-result-item {
|
.personal-center-introduction-result-item {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
@@ -54,7 +55,7 @@
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
height: 720px;
|
min-height: 320px;
|
||||||
}
|
}
|
||||||
.personal-center-content-right {
|
.personal-center-content-right {
|
||||||
background-color: #fff;
|
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 {
|
.question-bank-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 1439px;
|
width: 1439px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
background-color: #f3f4f6;
|
background-color: #f3f4f6;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
height: calc(100vh - 90px);
|
height: calc(100vh - 90px);
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
.mask-box {
|
.mask-box {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
.question-box {
|
.question-box {
|
||||||
.category-list-box {
|
.category-list-box {
|
||||||
padding: 24px 24px 6px;
|
padding: 24px 24px 6px;
|
||||||
border-top-left-radius: 8px;
|
border-top-left-radius: 8px;
|
||||||
border-top-right-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;
|
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
|
* @param {*} assembleIds 三级标签 assembleIds
|
||||||
*/
|
*/
|
||||||
const onChangeLabel = values => {
|
const onChangeLabel = values => {
|
||||||
console.log(values)
|
|
||||||
setSelectedValue(values)
|
setSelectedValue(values)
|
||||||
setQuestionList([])
|
setQuestionList([])
|
||||||
setTotal(0)
|
setTotal(0)
|
||||||
|
@@ -1,341 +1,341 @@
|
|||||||
import React, { Component, Fragment, createRef } from 'react';
|
import { Input, Modal, message } from 'antd'
|
||||||
import { Input, Modal, message, Spin } from 'antd';
|
import React, { Component, Fragment, createRef } from 'react'
|
||||||
|
|
||||||
import req from '@utils/request';
|
import { debounce } from '@utils'
|
||||||
import { debounce } from '@utils';
|
import req from '@utils/request'
|
||||||
import KindEditor from '../kind-editor';
|
import { apiName } from '../../constant'
|
||||||
import RankLabelBox from '../rank-label-box';
|
|
||||||
import RepeatContentBox from '../repeat-content-box';
|
|
||||||
import { apiName } from '../../constant';
|
|
||||||
import QuestionEditor from '../question-editor'
|
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 {
|
export default class BriefQuestions extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
subjectName: '', // 题目
|
subjectName: '', // 题目
|
||||||
isDisabledSubmit: true, //是否禁止输入
|
isDisabledSubmit: true, //是否禁止输入
|
||||||
isShowModalBox: false, // 是否展示重复率弹框
|
isShowModalBox: false, // 是否展示重复率弹框
|
||||||
isSubmit: true, // 是否支持提交
|
isSubmit: true // 是否支持提交
|
||||||
};
|
|
||||||
}
|
}
|
||||||
kindEditor = createRef();
|
}
|
||||||
rankLabelBox = createRef();
|
kindEditor = createRef()
|
||||||
rankId = 1; //职级
|
rankLabelBox = createRef()
|
||||||
subjectAnswer = ''; // 答案
|
rankId = 1 //职级
|
||||||
firstCategoryValue = ''; // 一级分类的值
|
subjectAnswer = '' // 答案
|
||||||
secondCategoryValue = []; // 二级分类的值
|
firstCategoryValue = '' // 一级分类的值
|
||||||
thirdCategoryValue = []; // 三级标签的值
|
secondCategoryValue = [] // 二级分类的值
|
||||||
repeatInfo = {}; // 重复率
|
thirdCategoryValue = [] // 三级标签的值
|
||||||
|
repeatInfo = {} // 重复率
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输入题目
|
* 输入题目
|
||||||
* @param {*} e
|
* @param {*} e
|
||||||
*/
|
*/
|
||||||
onChangeSubjectName = (e) => {
|
onChangeSubjectName = e => {
|
||||||
let str = e.target.value.trim();
|
let str = e.target.value.trim()
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
subjectName: str,
|
subjectName: str
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
// this.rankLabelBox.getThirdCategoryList();
|
// this.rankLabelBox.getThirdCategoryList();
|
||||||
let isDisabledSubmit = this.checkData();
|
let isDisabledSubmit = this.checkData()
|
||||||
this.setState({
|
|
||||||
isDisabledSubmit,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 富文本编辑器
|
|
||||||
* @param {*} e
|
|
||||||
*/
|
|
||||||
onChangeEditor = (e) => {
|
|
||||||
this.subjectAnswer = e;
|
|
||||||
let isDisabledSubmit = this.checkData();
|
|
||||||
this.setState({
|
this.setState({
|
||||||
isDisabledSubmit,
|
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,
|
|
||||||
})
|
})
|
||||||
.then((res) => {
|
}
|
||||||
this.setState({
|
)
|
||||||
isSubmit: true,
|
}
|
||||||
}, () => {
|
|
||||||
this.successModalConfirm();
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
this.setState({
|
|
||||||
isSubmit: true,
|
|
||||||
});
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验是否支持点击按钮
|
* 富文本编辑器
|
||||||
* @returns
|
* @param {*} e
|
||||||
*/
|
*/
|
||||||
checkData = () => {
|
onChangeEditor = e => {
|
||||||
const { subjectName } = this.state;
|
this.subjectAnswer = e
|
||||||
let isDisabledSubmit = false;
|
let isDisabledSubmit = this.checkData()
|
||||||
if (
|
this.setState({
|
||||||
!!!subjectName ||
|
isDisabledSubmit
|
||||||
!!!this.subjectAnswer ||
|
})
|
||||||
!!!this.firstCategoryValue ||
|
}
|
||||||
this.secondCategoryValue.length <= 0
|
|
||||||
// ||
|
|
||||||
// this.thirdCategoryValue.length <= 0
|
|
||||||
) {
|
|
||||||
isDisabledSubmit = true;
|
|
||||||
}
|
|
||||||
return isDisabledSubmit;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消
|
* 一次确认录入
|
||||||
*/
|
*/
|
||||||
onCancel = () => {
|
onSubmit = debounce(() => {
|
||||||
console.log(this.kindEditor)
|
console.log(this.rankId)
|
||||||
this.subjectAnswer = ''; // 答案
|
const { subjectName, isDisabledSubmit, isSubmit } = this.state
|
||||||
this.rankId = 1;
|
if (isDisabledSubmit || !isSubmit) {
|
||||||
this.firstCategoryValue = '';
|
return
|
||||||
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>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 问答题-答案
|
* 校验是否支持点击按钮
|
||||||
*/
|
* @returns
|
||||||
reanderAnser = () => {
|
*/
|
||||||
return (
|
checkData = () => {
|
||||||
<div className="brief-questions-main">
|
const { subjectName } = this.state
|
||||||
<QuestionEditor
|
let isDisabledSubmit = false
|
||||||
onChange={this.onChangeEditor}
|
if (
|
||||||
ref={this.kindEditor}
|
!!!subjectName ||
|
||||||
/>
|
!!!this.subjectAnswer ||
|
||||||
</div>
|
!!!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 { debounce } from '@utils'
|
||||||
import { Input, Modal, message, Spin } from 'antd';
|
import req from '@utils/request'
|
||||||
import req from '@utils/request';
|
import { Input, Modal, Spin, message } from 'antd'
|
||||||
import { debounce } from '@utils';
|
import React, { Component, Fragment, createRef } from 'react'
|
||||||
import RankLabelBox from '../rank-label-box';
|
import { apiName } from '../../constant'
|
||||||
import OptionInputBox from '../option-input-box';
|
import OptionInputBox from '../option-input-box'
|
||||||
import RepeatContentBox from '../repeat-content-box';
|
import RankLabelBox from '../rank-label-box'
|
||||||
import { apiName } from '../../constant';
|
import RepeatContentBox from '../repeat-content-box'
|
||||||
import './index.less';
|
import './index.less'
|
||||||
export default class JudgeQuestions extends Component {
|
export default class JudgeQuestions extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
subjectName: '', // 题目
|
subjectName: '', // 题目
|
||||||
isDisabledSubmit: true, //是否禁止输入
|
isDisabledSubmit: true, //是否禁止输入
|
||||||
isShowModalBox: false, // 是否展示重复率弹框
|
isShowModalBox: false, // 是否展示重复率弹框
|
||||||
isSubmit: true, // 是否支持提交
|
isSubmit: true // 是否支持提交
|
||||||
};
|
|
||||||
}
|
}
|
||||||
rankLabelBox = RankLabelBox | null;
|
}
|
||||||
optionInputBox = OptionInputBox | null;
|
// rankLabelBox = RankLabelBox | null
|
||||||
currentActive = []; // 当前选中的项
|
rankLabelBox = createRef()
|
||||||
scoreValue = ''; // 分数
|
optionInputBox = OptionInputBox | null
|
||||||
subjectAnalysis = ''; //试题解析
|
currentActive = [] // 当前选中的项
|
||||||
rankId = 1; //职级
|
scoreValue = '' // 分数
|
||||||
firstCategoryValue = ''; // 一级分类的值
|
subjectAnalysis = '' //试题解析
|
||||||
secondCategoryValue = []; // 二级分类的值
|
rankId = 1 //职级
|
||||||
thirdCategoryValue = []; // 三级标签的值
|
firstCategoryValue = '' // 一级分类的值
|
||||||
repeatInfo = {}; // 重复率
|
secondCategoryValue = [] // 二级分类的值
|
||||||
|
thirdCategoryValue = [] // 三级标签的值
|
||||||
|
repeatInfo = {} // 重复率
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输入题目
|
* 输入题目
|
||||||
* @param {*} e
|
* @param {*} e
|
||||||
*/
|
*/
|
||||||
onChangeSubjectName = (e) => {
|
onChangeSubjectName = e => {
|
||||||
let str = e.target.value.trim();
|
let str = e.target.value.trim()
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
subjectName: str,
|
subjectName: str
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.rankLabelBox.getThirdCategoryList();
|
// this.rankLabelBox.getThirdCategoryList();
|
||||||
let isDisabledSubmit = this.checkData();
|
let isDisabledSubmit = this.checkData()
|
||||||
this.setState({
|
|
||||||
isDisabledSubmit,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一次确认录入
|
|
||||||
*/
|
|
||||||
onSubmit = debounce(() => {
|
|
||||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state;
|
|
||||||
if (isDisabledSubmit || !isSubmit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.setState({
|
this.setState({
|
||||||
isSubmit: false,
|
isDisabledSubmit
|
||||||
});
|
|
||||||
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,
|
|
||||||
})
|
})
|
||||||
.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
|
*/
|
||||||
*/
|
onSubmit = debounce(() => {
|
||||||
checkData = () => {
|
const { subjectName, isDisabledSubmit, isSubmit } = this.state
|
||||||
const { subjectName } = this.state;
|
if (isDisabledSubmit || !isSubmit) {
|
||||||
let isDisabledSubmit = false;
|
return
|
||||||
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>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
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 {
|
.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;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 24px;
|
justify-content: flex-end;
|
||||||
padding-top: 36px;
|
width: 140px;
|
||||||
// label名字title
|
line-height: 40px;
|
||||||
.judge-questions-title {
|
font-size: 16px;
|
||||||
display: flex;
|
color: rgba(51, 51, 51, 1);
|
||||||
align-items: center;
|
&:before {
|
||||||
justify-content: flex-end;
|
display: inline-block;
|
||||||
width: 140px;
|
margin-right: 4px;
|
||||||
line-height: 40px;
|
margin-top: 1px;
|
||||||
font-size: 16px;
|
color: #f5222d;
|
||||||
color: rgba(51, 51, 51, 1);
|
font-size: 16px;
|
||||||
&:before {
|
content: '*';
|
||||||
display: inline-block;
|
|
||||||
margin-right: 4px;
|
|
||||||
margin-top: 1px;
|
|
||||||
color: #f5222d;
|
|
||||||
font-size: 16px;
|
|
||||||
content: '*';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.judge-questions-btns-container {
|
.judge-questions-btns-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
margin: 20px auto;
|
||||||
|
width: 952px;
|
||||||
|
.judge-questions-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 20px auto;
|
justify-content: center;
|
||||||
width: 952px;
|
width: 150px;
|
||||||
.judge-questions-btn {
|
height: 40px;
|
||||||
display: flex;
|
font-size: 16px;
|
||||||
align-items: center;
|
cursor: pointer;
|
||||||
justify-content: center;
|
border: 1px solid #d9d9d9;
|
||||||
width: 150px;
|
border-radius: 10px;
|
||||||
height: 40px;
|
}
|
||||||
font-size: 16px;
|
.judge-questions-submit {
|
||||||
cursor: pointer;
|
margin-left: 40px;
|
||||||
border: 1px solid #d9d9d9;
|
background-color: #4390f7;
|
||||||
border-radius: 10px;
|
color: #fff;
|
||||||
}
|
border: 1px solid #4390f7;
|
||||||
.judge-questions-submit {
|
}
|
||||||
margin-left: 40px;
|
.judge-questions-disabled-submit {
|
||||||
background-color: #4390f7;
|
opacity: 0.5;
|
||||||
color: #fff;
|
}
|
||||||
border: 1px solid #4390f7;
|
|
||||||
}
|
|
||||||
.judge-questions-disabled-submit {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,343 +1,366 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import { debounce } from '@utils'
|
||||||
import { Input, Modal, message, Spin } from 'antd';
|
import req from '@utils/request'
|
||||||
import _ from 'lodash';
|
import { Input, Modal, Spin, message } from 'antd'
|
||||||
import req from '@utils/request';
|
import React, { Component, Fragment, createRef } from 'react'
|
||||||
import { debounce } from '@utils';
|
import { apiName } from '../../constant'
|
||||||
import KindEditor from '../kind-editor';
|
import OptionInputBox from '../option-input-box'
|
||||||
import RankLabelBox from '../rank-label-box';
|
import RankLabelBox from '../rank-label-box'
|
||||||
import OptionInputBox from '../option-input-box';
|
import RepeatContentBox from '../repeat-content-box'
|
||||||
import RepeatContentBox from '../repeat-content-box';
|
import './index.less'
|
||||||
import { apiName } from '../../constant';
|
|
||||||
import './index.less';
|
|
||||||
|
|
||||||
const defalutLabel = '请使用富文本编辑器输入选项内容';
|
const defalutLabel = '请使用富文本编辑器输入选项内容'
|
||||||
export default class MultipleQuestions extends Component {
|
export default class MultipleQuestions extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
subjectName: '', // 题目
|
subjectName: '', // 题目
|
||||||
isDisabledSubmit: true, //是否禁止输入
|
isDisabledSubmit: true, //是否禁止输入
|
||||||
isShowModalBox: false, // 是否展示重复率弹框
|
isShowModalBox: false, // 是否展示重复率弹框
|
||||||
isSubmit: true, // 是否支持提交
|
isSubmit: true // 是否支持提交
|
||||||
};
|
|
||||||
}
|
}
|
||||||
kindEditor = KindEditor | null;
|
}
|
||||||
rankLabelBox = RankLabelBox | null;
|
rankLabelBox = createRef()
|
||||||
optionInputBox = OptionInputBox | null;
|
optionInputBox = OptionInputBox | null
|
||||||
currentActive = []; // 选项列表
|
currentActive = [] // 选项列表
|
||||||
scoreValue = ''; // 分数
|
scoreValue = '' // 分数
|
||||||
subjectAnalysis = ''; //试题解析
|
subjectAnalysis = '' //试题解析
|
||||||
rankId = 1; //职级
|
rankId = 1 //职级
|
||||||
subjectAnswer = ''; // 选项内容
|
subjectAnswer = '' // 选项内容
|
||||||
firstCategoryValue = ''; // 一级分类的值
|
firstCategoryValue = '' // 一级分类的值
|
||||||
secondCategoryValue = []; // 二级分类的值
|
secondCategoryValue = [] // 二级分类的值
|
||||||
thirdCategoryValue = []; // 三级标签的值
|
thirdCategoryValue = [] // 三级标签的值
|
||||||
repeatInfo = {}; // 重复率
|
repeatInfo = {} // 重复率
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输入题目
|
* 输入题目
|
||||||
* @param {*} e
|
* @param {*} e
|
||||||
*/
|
*/
|
||||||
onChangeSubjectName = (e) => {
|
onChangeSubjectName = e => {
|
||||||
let str = e.target.value.trim();
|
let str = e.target.value.trim()
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
subjectName: str,
|
subjectName: str
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.rankLabelBox.getThirdCategoryList();
|
// this.rankLabelBox.getThirdCategoryList();
|
||||||
let isDisabledSubmit = this.checkData();
|
let isDisabledSubmit = this.checkData()
|
||||||
this.setState({
|
|
||||||
isDisabledSubmit,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一次确认录入
|
|
||||||
*/
|
|
||||||
onSubmit = debounce(() => {
|
|
||||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state;
|
|
||||||
if (isDisabledSubmit || !isSubmit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.setState({
|
this.setState({
|
||||||
isSubmit: false,
|
isDisabledSubmit
|
||||||
});
|
|
||||||
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,
|
|
||||||
})
|
})
|
||||||
.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
|
*/
|
||||||
*/
|
onSubmit = debounce(() => {
|
||||||
/**
|
const { subjectName, isDisabledSubmit, isSubmit } = this.state
|
||||||
* 校验是否支持点击按钮
|
if (isDisabledSubmit || !isSubmit) {
|
||||||
* @returns
|
return
|
||||||
*/
|
}
|
||||||
checkData = () => {
|
if (!!!subjectName) {
|
||||||
const { subjectName } = this.state;
|
message.warning('请输入题目名称')
|
||||||
let list = this.currentActive.filter((item) => item.optionContent === defalutLabel);
|
return
|
||||||
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>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
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 {
|
.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;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 24px;
|
justify-content: flex-end;
|
||||||
padding-top: 36px;
|
width: 140px;
|
||||||
// label名字title
|
line-height: 40px;
|
||||||
.multiple-questions-title {
|
font-size: 16px;
|
||||||
display: flex;
|
color: rgba(51, 51, 51, 1);
|
||||||
align-items: center;
|
&:before {
|
||||||
justify-content: flex-end;
|
display: inline-block;
|
||||||
width: 140px;
|
margin-right: 4px;
|
||||||
line-height: 40px;
|
margin-top: 1px;
|
||||||
font-size: 16px;
|
color: #f5222d;
|
||||||
color: rgba(51, 51, 51, 1);
|
font-size: 16px;
|
||||||
&:before {
|
content: '*';
|
||||||
display: inline-block;
|
|
||||||
margin-right: 4px;
|
|
||||||
margin-top: 1px;
|
|
||||||
color: #f5222d;
|
|
||||||
font-size: 16px;
|
|
||||||
content: '*';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.multiple-questions-btns-container {
|
.multiple-questions-btns-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
margin: 20px auto;
|
||||||
|
width: 952px;
|
||||||
|
.multiple-questions-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 20px auto;
|
justify-content: center;
|
||||||
width: 952px;
|
width: 150px;
|
||||||
.multiple-questions-btn {
|
height: 40px;
|
||||||
display: flex;
|
font-size: 16px;
|
||||||
align-items: center;
|
cursor: pointer;
|
||||||
justify-content: center;
|
border: 1px solid #d9d9d9;
|
||||||
width: 150px;
|
border-radius: 10px;
|
||||||
height: 40px;
|
}
|
||||||
font-size: 16px;
|
.multiple-questions-submit {
|
||||||
cursor: pointer;
|
margin-left: 40px;
|
||||||
border: 1px solid #d9d9d9;
|
background-color: #4390f7;
|
||||||
border-radius: 10px;
|
color: #fff;
|
||||||
}
|
border: 1px solid #4390f7;
|
||||||
.multiple-questions-submit {
|
}
|
||||||
margin-left: 40px;
|
.multiple-questions-disabled-submit {
|
||||||
background-color: #4390f7;
|
opacity: 0.5;
|
||||||
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 { debounce } from '@utils'
|
||||||
import { Input, Select, Tooltip, message } from 'antd'
|
import { Input, Select, Tooltip, message } from 'antd'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import React, { Component, Fragment } from 'react'
|
import React, { Component, Fragment, createRef } from 'react'
|
||||||
import { optionLetter } from '../../constant'
|
import { optionLetter } from '../../constant'
|
||||||
import KindEditor from '../kind-editor'
|
import QuestionEditor from '../question-editor'
|
||||||
|
|
||||||
import './index.less'
|
import './index.less'
|
||||||
const { TextArea } = Input
|
const { TextArea } = Input
|
||||||
const { Option } = Select
|
const { Option } = Select
|
||||||
@@ -49,7 +51,8 @@ export default class OptionInputBox extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kindEditor = KindEditor | null
|
// kindEditor = KindEditor | null
|
||||||
|
kindEditor = createRef()
|
||||||
subjectAnswer = '' // 选项内容
|
subjectAnswer = '' // 选项内容
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,10 +101,10 @@ export default class OptionInputBox extends Component {
|
|||||||
*/
|
*/
|
||||||
onChangeOptEditor = (index, type) => () => {
|
onChangeOptEditor = (index, type) => () => {
|
||||||
let { optionList } = this.state
|
let { optionList } = this.state
|
||||||
this.kindEditor && this.kindEditor.onClear()
|
|
||||||
if (type === 'submit') {
|
if (type === 'submit') {
|
||||||
_.set(optionList, [index, 'label'], !!this.subjectAnswer ? this.subjectAnswer : defalutLabel)
|
_.set(optionList, [index, 'label'], !!this.subjectAnswer ? this.subjectAnswer : defalutLabel)
|
||||||
}
|
}
|
||||||
|
this.kindEditor && this.kindEditor.current.onClear()
|
||||||
_.set(optionList, [index, 'isShowEditor'], false)
|
_.set(optionList, [index, 'isShowEditor'], false)
|
||||||
this.subjectAnswer = ''
|
this.subjectAnswer = ''
|
||||||
this.setState(
|
this.setState(
|
||||||
@@ -131,7 +134,7 @@ export default class OptionInputBox extends Component {
|
|||||||
optionList
|
optionList
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.kindEditor && this.kindEditor.onCashBack()
|
this.kindEditor && this.kindEditor.current.onCashBack()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -140,7 +143,7 @@ export default class OptionInputBox extends Component {
|
|||||||
* 富文本编辑器
|
* 富文本编辑器
|
||||||
* @param {*} e
|
* @param {*} e
|
||||||
*/
|
*/
|
||||||
onChangeEditor = index => e => {
|
onChangeEditor = e => {
|
||||||
this.subjectAnswer = e
|
this.subjectAnswer = e
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +321,7 @@ export default class OptionInputBox extends Component {
|
|||||||
<div className='option-input-item-delete'>
|
<div className='option-input-item-delete'>
|
||||||
{listLen > showDeleteLength && (
|
{listLen > showDeleteLength && (
|
||||||
<Tooltip title='删除选项' onClick={this.onChangeAddOption(index, 'del')}>
|
<Tooltip title='删除选项' onClick={this.onChangeAddOption(index, 'del')}>
|
||||||
<img className='option-input-item-delete-icon' src='' />
|
<CloseCircleFilled style={{ fontSize: '18px' }} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -331,15 +334,7 @@ export default class OptionInputBox extends Component {
|
|||||||
style={{ marginTop: 19 }}
|
style={{ marginTop: 19 }}
|
||||||
>
|
>
|
||||||
<div className='option-input-editor'>
|
<div className='option-input-editor'>
|
||||||
<KindEditor
|
<QuestionEditor onChange={this.onChangeEditor} ref={this.kindEditor} />
|
||||||
ref={ref => {
|
|
||||||
this.kindEditor = ref
|
|
||||||
}}
|
|
||||||
bodyHeight={145}
|
|
||||||
borderRadius={12}
|
|
||||||
onChange={this.onChangeEditor(index)}
|
|
||||||
cashBackText={isShowTip ? '' : item.label}
|
|
||||||
/>
|
|
||||||
<div className='option-input-editor-btns'>
|
<div className='option-input-editor-btns'>
|
||||||
<Tooltip title='取消后内容将不会更新到选项框内'>
|
<Tooltip title='取消后内容将不会更新到选项框内'>
|
||||||
<div
|
<div
|
||||||
@@ -395,7 +390,7 @@ export default class OptionInputBox extends Component {
|
|||||||
defaultActiveFirstOption={false}
|
defaultActiveFirstOption={false}
|
||||||
value={currentActiveList}
|
value={currentActiveList}
|
||||||
placeholder='请选择'
|
placeholder='请选择'
|
||||||
style={{ minWidth: isMultiple ? '64px' : '68px', marginLeft: 4 }}
|
style={{ minWidth: isMultiple ? '84px' : '88px', marginLeft: 4 }}
|
||||||
onChange={this.onChangeSelect}
|
onChange={this.onChangeSelect}
|
||||||
>
|
>
|
||||||
{isJudge
|
{isJudge
|
||||||
|
@@ -1,77 +1,82 @@
|
|||||||
import '@wangeditor/editor/dist/css/style.css' // 引入 css
|
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 { Editor, Toolbar } from '@wangeditor/editor-for-react'
|
||||||
|
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react'
|
||||||
|
|
||||||
// 当前菜单排序和分组
|
// 当前菜单排序和分组
|
||||||
|
|
||||||
function MyEditor(props, ref) {
|
function MyEditor(props, ref) {
|
||||||
// editor 实例
|
// editor 实例
|
||||||
const [editor, setEditor] = useState(null)
|
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 changeValue = html => {
|
||||||
const toolbarConfig = {
|
setHtml(html)
|
||||||
excludeKeys: [
|
props.onChange(html)
|
||||||
'group-image', 'group-video'
|
}
|
||||||
]
|
|
||||||
|
const onClear = () => setHtml('')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回现代码
|
||||||
|
*/
|
||||||
|
const onCashBack = () => {
|
||||||
|
let { cashBackText } = props
|
||||||
|
if (!!!cashBackText) {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
setHtml(`${cashBackText}`)
|
||||||
|
// editor.fo;
|
||||||
|
}
|
||||||
|
|
||||||
// 编辑器配置
|
// 此处注意useImperativeHandle方法的的第一个参数是目标元素的ref引用
|
||||||
const editorConfig = {
|
useImperativeHandle(ref, () => ({
|
||||||
placeholder: '请输入内容...',
|
// onCallback 就是暴露给父组件的方法
|
||||||
|
onClear,
|
||||||
|
onCashBack
|
||||||
|
}))
|
||||||
|
|
||||||
|
// 及时销毁 editor ,重要!
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (editor == null) return
|
||||||
|
editor.destroy()
|
||||||
|
setEditor(null)
|
||||||
}
|
}
|
||||||
|
}, [editor])
|
||||||
|
|
||||||
|
return (
|
||||||
const changeValue = (html) => {
|
<>
|
||||||
setHtml(html)
|
<div style={{ border: '1px solid #ccc', zIndex: 100 }}>
|
||||||
props.onChange(html)
|
<Toolbar
|
||||||
}
|
editor={editor}
|
||||||
|
defaultConfig={toolbarConfig}
|
||||||
const onClear = () => setHtml('')
|
mode='default'
|
||||||
// 此处注意useImperativeHandle方法的的第一个参数是目标元素的ref引用
|
style={{ borderBottom: '1px solid #ccc' }}
|
||||||
useImperativeHandle(ref, () => ({
|
/>
|
||||||
// onCallback 就是暴露给父组件的方法
|
<Editor
|
||||||
onClear
|
defaultConfig={editorConfig}
|
||||||
}));
|
value={html}
|
||||||
|
onCreated={setEditor}
|
||||||
// 及时销毁 editor ,重要!
|
onChange={editor => changeValue(editor.getHtml())}
|
||||||
useEffect(() => {
|
mode='default'
|
||||||
return () => {
|
style={{ height: '300px', overflowY: 'scroll' }}
|
||||||
if (editor == null) return
|
/>
|
||||||
editor.destroy()
|
</div>
|
||||||
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>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default forwardRef(MyEditor)
|
export default forwardRef(MyEditor)
|
||||||
|
@@ -1,234 +1,190 @@
|
|||||||
import React, { Fragment } from 'react';
|
import { Modal, Tooltip } from 'antd'
|
||||||
import { Modal, Tooltip } from 'antd';
|
import React, { Fragment } from 'react'
|
||||||
import { letterList, judgeList } from '../../constant';
|
import { judgeList, letterList } from '../../constant'
|
||||||
import './index.less';
|
import './index.less'
|
||||||
export default function RepeatContentBox(props) {
|
export default function RepeatContentBox(props) {
|
||||||
const { isShowModalBox, repeatInfo, repeatQuestionsType } = props;
|
const { isShowModalBox, repeatInfo, repeatQuestionsType } = props
|
||||||
// const { isShowModalBox, repeatQuestionsType } = props;
|
/**
|
||||||
// const repeatInfo = {
|
* 确认录入
|
||||||
// repeatSubjectName:
|
*/
|
||||||
// 'Chrome如Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?何支持小于12px的字?',
|
const onSubmitRepeatModal = e => {
|
||||||
// repeatSubjectAnswe:
|
props.handleSubmitRepeatModal && props.handleSubmitRepeatModal()
|
||||||
// 'Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?',
|
}
|
||||||
// repeatSetterErp: 'suchunping3',
|
/**
|
||||||
// repeatSetterName: '苏春萍',
|
* 取消录入
|
||||||
// };
|
*/
|
||||||
|
const onCancelRepeatModal = () => {
|
||||||
|
props.handleCancelRepeatModal && props.handleCancelRepeatModal()
|
||||||
|
}
|
||||||
|
|
||||||
// const repeatInfo = {
|
const renderRepeat = (type, repeatInfo) => {
|
||||||
// repeatSubjectName:
|
switch (type) {
|
||||||
// 'Chrome如Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?何支持小于12px的字?',
|
case 1:
|
||||||
// repeatOptionList: [
|
return renderBriefQuestions(repeatInfo)
|
||||||
// {
|
case 2:
|
||||||
// isCorrect: '',
|
case 3:
|
||||||
// optionContent: 'Chrome如何支持小于12px的字?Chrome如何支持小于12px的',
|
return renderSelectQuestions(type, repeatInfo)
|
||||||
// optionType: 1,
|
case 4:
|
||||||
// },
|
return renderJudgeQuestions(repeatInfo)
|
||||||
// {
|
}
|
||||||
// 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:
|
* @returns
|
||||||
return renderBriefQuestions(repeatInfo);
|
*/
|
||||||
case 2:
|
const renderBriefQuestions = repeatInfo => {
|
||||||
case 3:
|
return (
|
||||||
return renderSelectQuestions(type, repeatInfo);
|
<div className='repeat-content-box'>
|
||||||
case 4:
|
<div className='repeat-subject-box'>
|
||||||
return renderJudgeQuestions(repeatInfo);
|
<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
|
* @returns
|
||||||
*/
|
*/
|
||||||
const renderBriefQuestions = (repeatInfo) => {
|
const renderSelectQuestions = (type, repeatInfo) => {
|
||||||
return (
|
// 过滤获得正确选项
|
||||||
<div className="repeat-content-box">
|
let repeatRightKey = repeatInfo?.repeatOptionList?.filter(item => item.isCorrect === 1)
|
||||||
<div className="repeat-subject-box">
|
return (
|
||||||
<div className="repeat-subject-title">问答题</div>
|
<div className='repeat-content-box'>
|
||||||
<div className="repeat-subject-text">{repeatInfo.repeatSubjectName}</div>
|
<div className='repeat-subject-box'>
|
||||||
</div>
|
<div className='repeat-subject-title'>{type === 2 ? '单选题' : '多选题'}</div>
|
||||||
<div className="repeat-subject-box">
|
<div className='repeat-subject-text'>{repeatInfo.repeatSubjectName}</div>
|
||||||
<div className="repeat-subject-title">参考答案</div>
|
</div>
|
||||||
<div
|
{repeatInfo?.repeatOptionList?.length > 0 && (
|
||||||
className="repeat-subject-text"
|
<div className='repeat-subject-box'>
|
||||||
dangerouslySetInnerHTML={{
|
<div className='repeat-subject-title'>选项内容</div>
|
||||||
__html: repeatInfo.repeatSubjectAnswe,
|
<div className='repeat-subject-list'>
|
||||||
}}></div>
|
{repeatInfo.repeatOptionList.map((item, index) => {
|
||||||
</div>
|
return (
|
||||||
<div className="repeat-subject-box repeat-subject-info-box">
|
<div className='repeat-subject-item' key={`repeat_option_${index}`}>
|
||||||
<div className="repeat-subject-title">来自</div>
|
{/* <div className="repeat-subject-label">
|
||||||
<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">
|
|
||||||
{letterList[item.optionType]}
|
{letterList[item.optionType]}
|
||||||
</div> */}
|
</div> */}
|
||||||
<div
|
<div
|
||||||
className="repeat-subject-text"
|
className='repeat-subject-text'
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: item.optionContent,
|
__html: item.optionContent
|
||||||
}}></div>
|
}}
|
||||||
</div>
|
></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>
|
</div>
|
||||||
);
|
</div>
|
||||||
};
|
)}
|
||||||
|
{repeatRightKey?.length > 0 && (
|
||||||
/**
|
<div className='repeat-subject-box'>
|
||||||
* 展示重复内容-判断
|
<div className='repeat-subject-title'>答案</div>
|
||||||
* @returns
|
<div className='repeat-subject-list'>
|
||||||
*/
|
{repeatRightKey.map((item, index) => {
|
||||||
const renderJudgeQuestions = (repeatInfo) => {
|
return <span key={`repeat_answe_${index}`}>{letterList[item.optionType]} </span>
|
||||||
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>
|
</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 (
|
return (
|
||||||
<Modal
|
<div className='repeat-content-box'>
|
||||||
className="repeat-content-repeat-box"
|
<div className='repeat-subject-box'>
|
||||||
visible={isShowModalBox}
|
<div className='repeat-subject-title'>判断题</div>
|
||||||
title={
|
<div className='repeat-subject-text'>{repeatInfo.repeatSubjectName}</div>
|
||||||
<Fragment>
|
</div>
|
||||||
<span
|
<div className='repeat-subject-box'>
|
||||||
style={{
|
<div className='repeat-subject-title'>答案</div>
|
||||||
color: 'rgba(60, 110, 238, 0.8)',
|
<div className='repeat-subject-list'>{judgeList[repeatInfo.repeatIsCorrect]}</div>
|
||||||
fontSize: 50,
|
</div>
|
||||||
marginRight: 10,
|
{!!repeatInfo.repeatSubjectAnswe && (
|
||||||
}}>
|
<div className='repeat-subject-box'>
|
||||||
{repeatInfo.repeatRate || '10%'}
|
<div className='repeat-subject-title'>题目解析</div>
|
||||||
</span>
|
<div
|
||||||
重复率
|
className='repeat-subject-text'
|
||||||
</Fragment>
|
dangerouslySetInnerHTML={{
|
||||||
}
|
__html: repeatInfo.repeatSubjectAnswe
|
||||||
onOk={onSubmitRepeatModal}
|
}}
|
||||||
onCancel={onCancelRepeatModal}
|
></div>
|
||||||
okText="确认录入"
|
</div>
|
||||||
cancelText="取消录入">
|
)}
|
||||||
{renderRepeat(repeatQuestionsType, repeatInfo)}
|
<div className='repeat-subject-box repeat-subject-info-box'>
|
||||||
</Modal>
|
<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 { debounce } from '@utils'
|
||||||
import { Input, Modal, message, Spin } from 'antd';
|
import req from '@utils/request'
|
||||||
import _ from 'lodash';
|
import { Input, Modal, Spin, message } from 'antd'
|
||||||
import req from '@utils/request';
|
import React, { Component, Fragment, createRef } from 'react'
|
||||||
import { debounce } from '@utils';
|
import { apiName } from '../../constant'
|
||||||
import KindEditor from '../kind-editor';
|
import OptionInputBox from '../option-input-box'
|
||||||
import RankLabelBox from '../rank-label-box';
|
import RankLabelBox from '../rank-label-box'
|
||||||
import OptionInputBox from '../option-input-box';
|
import RepeatContentBox from '../repeat-content-box'
|
||||||
import RepeatContentBox from '../repeat-content-box';
|
import './index.less'
|
||||||
import { apiName } from '../../constant';
|
const defalutLabel = '请使用富文本编辑器输入选项内容'
|
||||||
import './index.less';
|
|
||||||
const defalutLabel = '请使用富文本编辑器输入选项内容';
|
|
||||||
export default class SingleQuestions extends Component {
|
export default class SingleQuestions extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
subjectName: '', // 题目
|
subjectName: '', // 题目
|
||||||
isDisabledSubmit: true, //是否禁止输入
|
isDisabledSubmit: true, //是否禁止输入
|
||||||
isShowModalBox: false, // 是否展示重复率弹框
|
isShowModalBox: false, // 是否展示重复率弹框
|
||||||
isSubmit: true, // 是否支持提交
|
isSubmit: true // 是否支持提交
|
||||||
};
|
|
||||||
}
|
}
|
||||||
kindEditor = KindEditor | null;
|
}
|
||||||
rankLabelBox = RankLabelBox | null;
|
rankLabelBox = createRef()
|
||||||
optionInputBox = OptionInputBox | null;
|
|
||||||
|
|
||||||
currentActive = []; // 选项列表
|
optionInputBox = OptionInputBox | null
|
||||||
scoreValue = ''; // 分数
|
|
||||||
subjectAnalysis = ''; //试题解析
|
|
||||||
rankId = 1; //职级
|
|
||||||
subjectAnswer = ''; // 选项内容
|
|
||||||
|
|
||||||
firstCategoryValue = ''; // 一级分类的值
|
currentActive = [] // 选项列表
|
||||||
secondCategoryValue = []; // 二级分类的值
|
scoreValue = '' // 分数
|
||||||
thirdCategoryValue = []; // 三级标签的值
|
subjectAnalysis = '' //试题解析
|
||||||
repeatInfo = {}; // 重复率
|
rankId = 1 //职级
|
||||||
|
subjectAnswer = '' // 选项内容
|
||||||
|
|
||||||
/**
|
firstCategoryValue = '' // 一级分类的值
|
||||||
* 输入题目
|
secondCategoryValue = [] // 二级分类的值
|
||||||
* @param {*} e
|
thirdCategoryValue = [] // 三级标签的值
|
||||||
*/
|
repeatInfo = {} // 重复率
|
||||||
onChangeSubjectName = (e) => {
|
|
||||||
let str = e.target.value.trim();
|
|
||||||
this.setState(
|
|
||||||
{
|
|
||||||
subjectName: str,
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
this.rankLabelBox.getThirdCategoryList();
|
|
||||||
let isDisabledSubmit = this.checkData();
|
|
||||||
this.setState({
|
|
||||||
isDisabledSubmit,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 一次确认录入
|
* 输入题目
|
||||||
*/
|
* @param {*} e
|
||||||
onSubmit = debounce(() => {
|
*/
|
||||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state;
|
onChangeSubjectName = e => {
|
||||||
if (isDisabledSubmit || !isSubmit) {
|
let str = e.target.value.trim()
|
||||||
return;
|
this.setState(
|
||||||
}
|
{
|
||||||
|
subjectName: str
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
// this.rankLabelBox.getThirdCategoryList();
|
||||||
|
let isDisabledSubmit = this.checkData()
|
||||||
this.setState({
|
this.setState({
|
||||||
isSubmit: false,
|
isDisabledSubmit
|
||||||
});
|
|
||||||
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,
|
|
||||||
})
|
})
|
||||||
.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
|
*/
|
||||||
*/
|
onSubmit = debounce(() => {
|
||||||
checkData = () => {
|
const { subjectName, isDisabledSubmit, isSubmit } = this.state
|
||||||
const { subjectName } = this.state;
|
if (isDisabledSubmit || !isSubmit) {
|
||||||
let list = this.currentActive.filter((item) => item.optionContent === defalutLabel);
|
return
|
||||||
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>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
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 {
|
.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;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 24px;
|
justify-content: flex-end;
|
||||||
padding-top: 36px;
|
width: 140px;
|
||||||
// label名字title
|
line-height: 40px;
|
||||||
.single-questions-title {
|
font-size: 16px;
|
||||||
display: flex;
|
color: rgba(51, 51, 51, 1);
|
||||||
align-items: center;
|
&:before {
|
||||||
justify-content: flex-end;
|
display: inline-block;
|
||||||
width: 140px;
|
margin-right: 4px;
|
||||||
line-height: 40px;
|
margin-top: 1px;
|
||||||
font-size: 16px;
|
color: #f5222d;
|
||||||
color: rgba(51, 51, 51, 1);
|
font-size: 16px;
|
||||||
&:before {
|
content: '*';
|
||||||
display: inline-block;
|
|
||||||
margin-right: 4px;
|
|
||||||
margin-top: 1px;
|
|
||||||
color: #f5222d;
|
|
||||||
font-size: 16px;
|
|
||||||
content: '*';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.single-questions-btns-container {
|
.single-questions-btns-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
margin: 20px auto;
|
||||||
|
width: 952px;
|
||||||
|
.single-questions-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 20px auto;
|
justify-content: center;
|
||||||
width: 952px;
|
width: 150px;
|
||||||
.single-questions-btn {
|
height: 40px;
|
||||||
display: flex;
|
font-size: 16px;
|
||||||
align-items: center;
|
cursor: pointer;
|
||||||
justify-content: center;
|
border: 1px solid #d9d9d9;
|
||||||
width: 150px;
|
border-radius: 10px;
|
||||||
height: 40px;
|
}
|
||||||
font-size: 16px;
|
.single-questions-submit {
|
||||||
cursor: pointer;
|
margin-left: 40px;
|
||||||
border: 1px solid #d9d9d9;
|
background-color: #4390f7;
|
||||||
border-radius: 10px;
|
color: #fff;
|
||||||
}
|
border: 1px solid #4390f7;
|
||||||
.single-questions-submit {
|
}
|
||||||
margin-left: 40px;
|
.single-questions-disabled-submit {
|
||||||
background-color: #4390f7;
|
opacity: 0.5;
|
||||||
color: #fff;
|
}
|
||||||
border: 1px solid #4390f7;
|
|
||||||
}
|
|
||||||
.single-questions-disabled-submit {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,27 +1,29 @@
|
|||||||
import React from 'react';
|
import { RightOutlined } from '@ant-design/icons'
|
||||||
import { Affix } from 'antd';
|
import { Affix } from 'antd'
|
||||||
import { RightOutlined } from '@ant-design/icons';
|
import React from 'react'
|
||||||
import './index.less';
|
import './index.less'
|
||||||
|
|
||||||
export default function UploadLeftLayout(props) {
|
export default function UploadLeftLayout(props) {
|
||||||
return (
|
return (
|
||||||
<Affix offsetTop={150}>
|
<Affix offsetTop={150}>
|
||||||
<div className="upload-left-layout">
|
<div className='upload-left-layout'>
|
||||||
{props.layoutList.map((item, index) => {
|
{props.layoutList.map((item, index) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`upload-left-layout-item ${item.active ? 'upload-left-layout-item-active' : ''
|
className={`upload-left-layout-item ${
|
||||||
}`}
|
item.active ? 'upload-left-layout-item-active' : ''
|
||||||
onClick={() => {
|
}`}
|
||||||
props.onChange(index);
|
onClick={() => {
|
||||||
}}
|
props.onChange(index)
|
||||||
key={`upload_left_layout_${item.id}`}>
|
}}
|
||||||
{item.title}
|
key={`upload_left_layout_${item.id}`}
|
||||||
<RightOutlined style={{ marginLeft: 54 }} />
|
>
|
||||||
</div>
|
{item.title}
|
||||||
);
|
<RightOutlined style={{ marginLeft: 54 }} />
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</Affix>
|
)
|
||||||
);
|
})}
|
||||||
|
</div>
|
||||||
|
</Affix>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
background: rgba(255, 255, 255, 1);
|
background: rgba(255, 255, 255, 1);
|
||||||
border: 1px solid rgba(208, 212, 222, 1);
|
border: 1px solid rgba(208, 212, 222, 1);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.upload-left-layout-item-active {
|
.upload-left-layout-item-active {
|
||||||
color: rgba(60, 110, 238, 1);
|
color: rgba(60, 110, 238, 1);
|
||||||
|
@@ -2,143 +2,142 @@
|
|||||||
* API名称
|
* API名称
|
||||||
*/
|
*/
|
||||||
export const apiName = {
|
export const apiName = {
|
||||||
/**
|
/**
|
||||||
* 获取一级
|
* 获取一级
|
||||||
*/
|
*/
|
||||||
queryPrimaryCategory: '/category/queryPrimaryCategory',
|
queryPrimaryCategory: '/category/queryPrimaryCategory',
|
||||||
|
|
||||||
|
// 查询二级分类
|
||||||
|
queryCategoryByPrimary: 'category/queryCategoryByPrimary',
|
||||||
|
|
||||||
// 查询二级分类
|
// 根据一级分类查询标签
|
||||||
queryCategoryByPrimary: 'category/queryCategoryByPrimary',
|
queryLabelByCategoryId: '/label/queryLabelByCategoryId',
|
||||||
|
|
||||||
// 根据一级分类查询标签
|
// 新增简答
|
||||||
queryLabelByCategoryId: '/label/queryLabelByCategoryId',
|
add: '/add',
|
||||||
|
/**
|
||||||
// 新增简答
|
* 新增题目
|
||||||
add: '/add',
|
*/
|
||||||
/**
|
addInterviewSubject: '/admin/question/subject/add',
|
||||||
* 新增题目
|
/**
|
||||||
*/
|
* 新增重复题目
|
||||||
addInterviewSubject: '/admin/question/subject/add',
|
*/
|
||||||
/**
|
addRepeatInterviewSubject: '/admin/question/subject/addRepeatSubject'
|
||||||
* 新增重复题目
|
}
|
||||||
*/
|
|
||||||
addRepeatInterviewSubject: '/admin/question/subject/addRepeatSubject',
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模块类型
|
* 模块类型
|
||||||
*/
|
*/
|
||||||
export const ModuleType = {
|
export const ModuleType = {
|
||||||
default: 'default',
|
default: 'default',
|
||||||
second: 'second',
|
second: 'second',
|
||||||
third: 'third',
|
third: 'third'
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入职级对应的星
|
* 导入职级对应的星
|
||||||
*/
|
*/
|
||||||
export const starList = [
|
export const starList = [
|
||||||
{
|
{
|
||||||
categoryId: 1,
|
categoryId: 1,
|
||||||
categoryName: '初级',
|
categoryName: '初级',
|
||||||
active: true,
|
active: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
categoryId: 2,
|
categoryId: 2,
|
||||||
categoryName: '中级',
|
categoryName: '中级'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
categoryId: 3,
|
categoryId: 3,
|
||||||
categoryName: '高级',
|
categoryName: '高级'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
categoryId: 4,
|
categoryId: 4,
|
||||||
categoryName: '资深',
|
categoryName: '资深'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
categoryId: 5,
|
categoryId: 5,
|
||||||
categoryName: '专家',
|
categoryName: '专家'
|
||||||
},
|
}
|
||||||
];
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模块类型
|
* 模块类型
|
||||||
*/
|
*/
|
||||||
export const uploadLayout = [
|
export const uploadLayout = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
title: '简答题',
|
title: '简答题',
|
||||||
active: true,
|
active: true
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// id: 2,
|
id: 2,
|
||||||
// title: '单选题',
|
title: '单选题',
|
||||||
// active: false,
|
active: false
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// id: 3,
|
id: 3,
|
||||||
// title: '多选题',
|
title: '多选题',
|
||||||
// active: false,
|
active: false
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// id: 4,
|
id: 4,
|
||||||
// title: '判断题',
|
title: '判断题',
|
||||||
// active: false,
|
active: false
|
||||||
// },
|
}
|
||||||
];
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数组索引对应字母
|
* 数组索引对应字母
|
||||||
*/
|
*/
|
||||||
export const optionLetter = {
|
export const optionLetter = {
|
||||||
0: {
|
0: {
|
||||||
label: 'A',
|
label: 'A',
|
||||||
value: 1,
|
value: 1
|
||||||
},
|
},
|
||||||
1: {
|
1: {
|
||||||
label: 'B',
|
label: 'B',
|
||||||
value: 2,
|
value: 2
|
||||||
},
|
},
|
||||||
2: {
|
2: {
|
||||||
label: 'C',
|
label: 'C',
|
||||||
value: 3,
|
value: 3
|
||||||
},
|
},
|
||||||
3: {
|
3: {
|
||||||
label: 'D',
|
label: 'D',
|
||||||
value: 4,
|
value: 4
|
||||||
},
|
},
|
||||||
4: {
|
4: {
|
||||||
label: 'E',
|
label: 'E',
|
||||||
value: 5,
|
value: 5
|
||||||
},
|
},
|
||||||
5: {
|
5: {
|
||||||
label: 'F',
|
label: 'F',
|
||||||
value: 6,
|
value: 6
|
||||||
},
|
},
|
||||||
6: {
|
6: {
|
||||||
label: 'G',
|
label: 'G',
|
||||||
value: 7,
|
value: 7
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字母id对应字母
|
* 字母id对应字母
|
||||||
*/
|
*/
|
||||||
export const letterList = {
|
export const letterList = {
|
||||||
1: 'A',
|
1: 'A',
|
||||||
2: 'B',
|
2: 'B',
|
||||||
3: 'C',
|
3: 'C',
|
||||||
4: 'D',
|
4: 'D',
|
||||||
5: 'E',
|
5: 'E',
|
||||||
6: 'F',
|
6: 'F',
|
||||||
7: 'G',
|
7: 'G'
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 正确/错误
|
* 正确/错误
|
||||||
*/
|
*/
|
||||||
export const judgeList = {
|
export const judgeList = {
|
||||||
0: '错误',
|
0: '错误',
|
||||||
1: '正确',
|
1: '正确'
|
||||||
};
|
}
|
||||||
|
@@ -2,9 +2,9 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
width: 1439px;
|
width: 1439px;
|
||||||
overflow-y: auto;
|
// overflow-y: auto;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
height: calc(100vh - 100px);
|
// height: calc(100vh - 100px);
|
||||||
.ant-card-head {
|
.ant-card-head {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -14,7 +14,4 @@
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
.ant-card-body {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -2,16 +2,9 @@ import req from '@utils/request'
|
|||||||
import { Card, message } from 'antd'
|
import { Card, message } from 'antd'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import BatchleBox from './pages/batch-box'
|
|
||||||
import SingleBox from './pages/single-box'
|
import SingleBox from './pages/single-box'
|
||||||
|
|
||||||
import './index.less'
|
import './index.less'
|
||||||
const tabList = [
|
|
||||||
{
|
|
||||||
key: 'singleBox',
|
|
||||||
tab: '单题录入'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
const UploadQuestions = () => {
|
const UploadQuestions = () => {
|
||||||
const [currentKey, setCurrentKey] = useState('singleBox')
|
const [currentKey, setCurrentKey] = useState('singleBox')
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
@@ -41,23 +34,18 @@ const UploadQuestions = () => {
|
|||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const contentList = {
|
|
||||||
singleBox: <SingleBox />,
|
|
||||||
batchBox: <BatchleBox />
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='upload-questions-box'>
|
<div className='upload-questions-box'>
|
||||||
<Card
|
<Card
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
tabList={tabList}
|
title='题目录入'
|
||||||
bordered={false}
|
bordered={false}
|
||||||
activeTabKey={currentKey}
|
activeTabKey={currentKey}
|
||||||
onTabChange={key => {
|
onTabChange={key => {
|
||||||
setCurrentKey(key)
|
setCurrentKey(key)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{contentList[currentKey]}
|
<SingleBox />
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</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 React, { Component } from 'react'
|
||||||
import BriefQuestions from '../../components/brief-questions'
|
import BriefQuestions from '../../components/brief-questions'
|
||||||
import JudgeQuestions from '../../components/judge-questions'
|
import JudgeQuestions from '../../components/judge-questions'
|
||||||
import MultipleQuestions from '../../components/multiple-questions'
|
import MultipleQuestions from '../../components/multiple-questions'
|
||||||
import SingleQuestions from '../../components/single-questions'
|
import SingleQuestions from '../../components/single-questions'
|
||||||
import UploadLeftLayout from '../../components/upload-left-layout'
|
|
||||||
import { uploadLayout } from '../../constant'
|
import { uploadLayout } from '../../constant'
|
||||||
|
|
||||||
import './index.less'
|
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 => {
|
changeReander = i => {
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -62,4 +53,32 @@ export default class SingleBox extends Component {
|
|||||||
return <JudgeQuestions questionsType={i + 1} key={`question_${i}`} />
|
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 {
|
.ant-modal-body {
|
||||||
padding: 12px 24px 0;
|
padding: 12px 24px 0;
|
||||||
}
|
}
|
||||||
.upload-questions-modular {
|
.upload-questions-modular {
|
||||||
display: flex;
|
// display: flex;
|
||||||
flex-direction: column;
|
// flex-direction: column;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
margin-left: 35px;
|
margin-left: 35px;
|
||||||
background: rgba(249, 250, 252, 1);
|
background: rgba(249, 250, 252, 1);
|
||||||
border: 2px solid rgba(240, 240, 240, 1);
|
border: 2px solid rgba(240, 240, 240, 1);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
height: calc(100vh - 220px);
|
||||||
|
overflow-y: scroll;
|
||||||
|
width: 100%;
|
||||||
|
// flex: 1 0 auto;
|
||||||
}
|
}
|
||||||
.questions-success-modal-confirm {
|
.questions-success-modal-confirm {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
// 录入成功弹框
|
// 录入成功弹框
|
||||||
.ant-modal-confirm-btns {
|
.ant-modal-confirm-btns {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.ant-btn {
|
.ant-btn {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
}
|
|
||||||
.ant-btn-primary {
|
|
||||||
background: rgba(60, 110, 238, 1);
|
|
||||||
margin-left: 60px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
.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 { LoadingOutlined, PlusOutlined } from '@ant-design/icons'
|
||||||
|
import { saveUserInfo } from '@features/userInfoSlice.ts'
|
||||||
import req from '@utils/request'
|
import req from '@utils/request'
|
||||||
import { Button, Card, Col, Form, Input, Radio, Row, Upload, message } from 'antd'
|
import { Button, Card, Col, Form, Input, Radio, Row, Upload, message } from 'antd'
|
||||||
import { memo, useEffect, useState } from 'react'
|
import { memo, useEffect, useState } from 'react'
|
||||||
|
import { useDispatch } from 'react-redux'
|
||||||
|
|
||||||
import './index.less'
|
import './index.less'
|
||||||
|
|
||||||
@@ -54,6 +55,8 @@ const UserInfo = () => {
|
|||||||
const userInfoStorage = localStorage.getItem('userInfo')
|
const userInfoStorage = localStorage.getItem('userInfo')
|
||||||
const { loginId = '', tokenValue = '' } = userInfoStorage ? JSON.parse(userInfoStorage) : {}
|
const { loginId = '', tokenValue = '' } = userInfoStorage ? JSON.parse(userInfoStorage) : {}
|
||||||
|
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
const [form] = Form.useForm()
|
const [form] = Form.useForm()
|
||||||
const [editFlag, setEditFlag] = useState(false)
|
const [editFlag, setEditFlag] = useState(false)
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
@@ -73,6 +76,7 @@ const UserInfo = () => {
|
|||||||
).then(res => {
|
).then(res => {
|
||||||
if (res?.success && res?.data) {
|
if (res?.success && res?.data) {
|
||||||
setUserInfo(res.data)
|
setUserInfo(res.data)
|
||||||
|
setAvatar(res.data.avatar || '')
|
||||||
form.setFieldsValue(res.data)
|
form.setFieldsValue(res.data)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -87,7 +91,6 @@ const UserInfo = () => {
|
|||||||
const onFinish = () => {
|
const onFinish = () => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const values = form.getFieldsValue()
|
const values = form.getFieldsValue()
|
||||||
// return console.log(values)
|
|
||||||
if (!Object.values(values).filter(Boolean).length && !avatar) {
|
if (!Object.values(values).filter(Boolean).length && !avatar) {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
return
|
return
|
||||||
@@ -108,10 +111,13 @@ const UserInfo = () => {
|
|||||||
'/auth'
|
'/auth'
|
||||||
)
|
)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
|
dispatch(saveUserInfo(params))
|
||||||
|
setUserInfo(params)
|
||||||
|
setAvatar(params.avatar || '')
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
message.success('更新成功')
|
message.success('更新成功')
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
getUserInfo()
|
// getUserInfo()
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
setEditFlag(false)
|
setEditFlag(false)
|
||||||
}, 500)
|
}, 500)
|
||||||
@@ -126,7 +132,6 @@ const UserInfo = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleChange = ({ file }) => {
|
const handleChange = ({ file }) => {
|
||||||
// console.log(info)
|
|
||||||
if (file.status === 'done' && file.response.success && file.response.data) {
|
if (file.status === 'done' && file.response.success && file.response.data) {
|
||||||
setAvatar(file.response.data)
|
setAvatar(file.response.data)
|
||||||
}
|
}
|
||||||
@@ -174,7 +179,12 @@ const UserInfo = () => {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
) : (
|
) : (
|
||||||
<Form.Item label='用户头像'>
|
<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>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
|
@@ -25,7 +25,9 @@ export default ({ mode }) => {
|
|||||||
'@utils': path.resolve(__dirname, 'src/utils'),
|
'@utils': path.resolve(__dirname, 'src/utils'),
|
||||||
'@components': path.resolve(__dirname, 'src/components'),
|
'@components': path.resolve(__dirname, 'src/components'),
|
||||||
'@imgs': path.resolve(__dirname, 'src/imgs'),
|
'@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()],
|
plugins: [react()],
|
||||||
|
Reference in New Issue
Block a user