feat: 刷题页面
This commit is contained in:
26
index.html
26
index.html
@@ -1,13 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
12
package.json
12
package.json
@@ -21,9 +21,15 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.2.6",
|
||||
"antd": "^5.9.4",
|
||||
"axios": "^1.5.1",
|
||||
"lodash": "^4.17.21",
|
||||
"pubsub-js": "^1.9.4",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"react-router-dom": "^6.16.0"
|
||||
"react-router-dom": "^6.16.0",
|
||||
"wangeditor": "^4.7.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.0.1",
|
||||
@@ -38,6 +44,10 @@
|
||||
"eslint-plugin-react": "^7.30.0",
|
||||
"eslint-plugin-react-hooks": "^4.5.0",
|
||||
"husky": "^8.0.1",
|
||||
"less": "^4.2.0",
|
||||
"less-loader": "^11.1.3",
|
||||
"postcss": "^8.4.31",
|
||||
"postcss-preset-env": "^9.1.4",
|
||||
"prettier": "^3.0.3",
|
||||
"stylelint": "^14.9.0",
|
||||
"stylelint-config-prettier": "^9.0.3",
|
||||
|
3087
pnpm-lock.yaml
generated
3087
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
5
postcss.config.js
Normal file
5
postcss.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('postcss-preset-env')
|
||||
]
|
||||
}
|
43
src/App.css
43
src/App.css
@@ -1,43 +0,0 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: app-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
background-color: #282c34;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
@keyframes app-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
font-size: calc(10px + 2vmin);
|
||||
}
|
155
src/App.less
Normal file
155
src/App.less
Normal file
@@ -0,0 +1,155 @@
|
||||
@import '@assets/base.less';
|
||||
|
||||
.app-main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
border-radius: 4px;
|
||||
margin: 0 auto;
|
||||
position: absolute;
|
||||
min-width: 1439px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #f3f4f6;
|
||||
padding: 66px 16px 32px;
|
||||
overflow: hidden;
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||
-khtml-user-select: none; /* Konqueror */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||
user-select: none; /* Non-prefixed version, currently not supported by any browser */
|
||||
}
|
||||
|
||||
.header-navigator {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 50px;
|
||||
min-width: 1439px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
width: 1407px;
|
||||
margin: 0 auto;
|
||||
line-height: 50px;
|
||||
color: #1890ff;
|
||||
font-size: 24px;
|
||||
// font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", 微软雅黑,
|
||||
// Arial, sans-serif;
|
||||
}
|
||||
|
||||
.header-navigator .user {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
float: right;
|
||||
/* background: #1890ff; */
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
margin-top: 7px;
|
||||
line-height: 36px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.jump-box {
|
||||
font-size: 14px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.info-time-box {
|
||||
display: flex;
|
||||
}
|
||||
.time-box {
|
||||
margin-top: 8px;
|
||||
margin-right: 120px;
|
||||
}
|
||||
.head-navigator-box {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 50px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.head-navigator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 0 auto;
|
||||
width: 1435px;
|
||||
}
|
||||
.head-navigator-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.head-navigator-logo {
|
||||
margin-right: 20px;
|
||||
// line-height: 50px;
|
||||
cursor: pointer;
|
||||
color: #1890ff;
|
||||
font-size: 24px;
|
||||
// font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, 微软雅黑,
|
||||
// Arial, sans-serif;
|
||||
}
|
||||
.head-navigator-select-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.head-navigator-menu-box {
|
||||
display: flex;
|
||||
}
|
||||
.head-navigator-menu-box .ant-menu-horizontal {
|
||||
border-bottom: 0;
|
||||
}
|
||||
.ant-menu-horizontal > .ant-menu-item,
|
||||
.ant-menu-horizontal > .ant-menu-submenu {
|
||||
padding: 0px;
|
||||
margin: 0 12px;
|
||||
}
|
||||
.head-navigator-input-box {
|
||||
margin-right: 24px;
|
||||
}
|
||||
.head-navigator-input-box .ant-input {
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.head-navigator-user-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.head-navigator-bell {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 24px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
.head-navigator-bell:hover {
|
||||
background-color: rgba(0, 10, 32, 0.03);
|
||||
}
|
||||
.head-navigator-user-img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
|
||||
}
|
125
src/App.tsx
125
src/App.tsx
@@ -1,22 +1,113 @@
|
||||
import './App.css'
|
||||
import { BrowserRouter as Router, Route, Outlet, Routes } from 'react-router-dom'
|
||||
import React, { Component } from 'react';
|
||||
import './App.less';
|
||||
import { Routes, Route, Link } from "react-router-dom"
|
||||
import req from '@utils/request.ts';
|
||||
import PubSub from 'pubsub-js';
|
||||
import { Input } from 'antd';
|
||||
import QuestionBank from './views/question-bank';
|
||||
import UploadQuestions from './views/upload-questions';
|
||||
import Logo from '@views/imgs/logo.jpg'
|
||||
import Head from '@views/imgs/head.jpg'
|
||||
import TopMenu from '@components/top-menu'
|
||||
|
||||
import Home from './views/home'
|
||||
import UploadExam from './views/upload-exam'
|
||||
const { Search } = Input;
|
||||
class NavTop extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
userName: '',
|
||||
intervieweEamil: '',
|
||||
headImg: '',
|
||||
isShowTimer: false,
|
||||
};
|
||||
}
|
||||
|
||||
function App() {
|
||||
timerRef = React.createRef();
|
||||
|
||||
return (
|
||||
<div className='App'>
|
||||
<Router >
|
||||
<Routes>
|
||||
<Route path='/' Component={Home}></Route>
|
||||
<Route path='/home' Component={Home}></Route>
|
||||
<Route path='/upload-exam' Component={UploadExam}></Route>
|
||||
</Routes>
|
||||
</Router>
|
||||
</div>
|
||||
)
|
||||
componentDidMount() {
|
||||
// req({
|
||||
// method: 'post',
|
||||
// url: 'admin/interview/peo/getDirectorInfo',
|
||||
// }).then((re) => {
|
||||
// this.setState(
|
||||
// {
|
||||
// userName: re.data?.name ?? '',
|
||||
// intervieweEamil: re.data?.email ?? '',
|
||||
// headImg: '',
|
||||
// },
|
||||
// () => {
|
||||
// window.localStorage.setItem('interviewerName', re.data?.name ?? 'XXX');
|
||||
// window.localStorage.setItem('intervieweEamil', re.data?.email ?? 'XXX');
|
||||
// }
|
||||
// );
|
||||
// });
|
||||
PubSub.subscribe('handleToRender', () => {
|
||||
this.setState({});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let { headImg, isShowTimer } = this.state;
|
||||
const { pathname } = window.location;
|
||||
return (
|
||||
<div className="head-navigator-box">
|
||||
<div className="head-navigator">
|
||||
<div className="head-navigator-left">
|
||||
<div
|
||||
className="head-navigator-logo"
|
||||
onClick={() =>
|
||||
(window.location.href = '/question-bank')
|
||||
}>
|
||||
<img src={Logo} style={{ height: 50 }} />
|
||||
</div>
|
||||
<TopMenu />
|
||||
</div>
|
||||
<div className="head-navigator-user-box">
|
||||
<div className="time-box"></div>
|
||||
{'/question-bank' == pathname && (
|
||||
<div className="head-navigator-input-box">
|
||||
<Search
|
||||
placeholder="请输入感兴趣的内容~"
|
||||
onSearch={(value) => console.log(value)}
|
||||
style={{ width: 300, borderRadius: '10px' }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="head-navigator-bell">
|
||||
{/* <Icon type="bell" /> */}
|
||||
</div>
|
||||
<div className="head-navigator-user-img">
|
||||
<img
|
||||
src={Head}
|
||||
style={{ width: 36, height: 36 }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
class RouteExample extends Component {
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<NavTop />
|
||||
<Routes>
|
||||
<Route path="/question-bank" element={<QuestionBank />}></Route>
|
||||
<Route path="/upload-questions" element={<UploadQuestions />}></Route>
|
||||
</Routes>
|
||||
</>
|
||||
|
||||
export default App
|
||||
);
|
||||
}
|
||||
}
|
||||
export default class App extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="app-main">
|
||||
<RouteExample />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
61
src/assets/base.less
Normal file
61
src/assets/base.less
Normal file
@@ -0,0 +1,61 @@
|
||||
@import "normalize.less";
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
font-family: -apple-system, "宋体","微软雅黑";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #666666;
|
||||
background: #ffffff;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.clear-fix:after {
|
||||
font-size: 0;
|
||||
display: block;
|
||||
clear: both;
|
||||
height: 0;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.arrow-right {
|
||||
display: inline-block;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
margin-left: 0.1rem;
|
||||
transform: rotate(135deg);
|
||||
border-top: 1px solid #999999;
|
||||
border-left: 1px solid #999999;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
//修改input高亮的问题
|
||||
.ant-input-affix-wrapper {
|
||||
&:hover {
|
||||
border-color: none!important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.ant-input:focus, .ant-input:hover {
|
||||
border-color: #d9d9d9;
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled) {
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
|
349
src/assets/normalize.less
vendored
Normal file
349
src/assets/normalize.less
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
|
||||
|
||||
/* Document
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Correct the line height in all browsers.
|
||||
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
||||
*/
|
||||
|
||||
html {
|
||||
line-height: 1.15; /* 1 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/* Sections
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the margin in all browsers.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the `main` element consistently in IE.
|
||||
*/
|
||||
|
||||
main {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the font size and margin on `h1` elements within `section` and
|
||||
* `article` contexts in Chrome, Firefox, and Safari.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in Firefox.
|
||||
* 2. Show the overflow in Edge and IE.
|
||||
*/
|
||||
|
||||
hr {
|
||||
box-sizing: content-box; /* 1 */
|
||||
height: 0; /* 1 */
|
||||
overflow: visible; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the gray background on active links in IE 10.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Remove the bottom border in Chrome 57-
|
||||
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none; /* 1 */
|
||||
text-decoration: underline; /* 2 */
|
||||
text-decoration: underline dotted; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||
* all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the border on images inside links in IE 10.
|
||||
*/
|
||||
|
||||
img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Change the font styles in all browsers.
|
||||
* 2. Remove the margin in Firefox and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit; /* 1 */
|
||||
font-size: 100%; /* 1 */
|
||||
line-height: 1.15; /* 1 */
|
||||
margin: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the overflow in IE.
|
||||
* 1. Show the overflow in Edge.
|
||||
*/
|
||||
|
||||
button,
|
||||
input { /* 1 */
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||
* 1. Remove the inheritance of text transform in Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select { /* 1 */
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the inability to style clickable types in iOS and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
[type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner border and padding in Firefox.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the focus styles unset by the previous rule.
|
||||
*/
|
||||
|
||||
button:-moz-focusring,
|
||||
[type="button"]:-moz-focusring,
|
||||
[type="reset"]:-moz-focusring,
|
||||
[type="submit"]:-moz-focusring {
|
||||
outline: 1px dotted ButtonText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the padding in Firefox.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
padding: 0.35em 0.75em 0.625em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the text wrapping in Edge and IE.
|
||||
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||
* 3. Remove the padding so developers are not caught out when they zero out
|
||||
* `fieldset` elements in all browsers.
|
||||
*/
|
||||
|
||||
legend {
|
||||
box-sizing: border-box; /* 1 */
|
||||
color: inherit; /* 2 */
|
||||
display: table; /* 1 */
|
||||
max-width: 100%; /* 1 */
|
||||
padding: 0; /* 3 */
|
||||
white-space: normal; /* 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the default vertical scrollbar in IE 10+.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in IE 10.
|
||||
* 2. Remove the padding in IE 10.
|
||||
*/
|
||||
|
||||
[type="checkbox"],
|
||||
[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||
*/
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the odd appearance in Chrome and Safari.
|
||||
* 2. Correct the outline style in Safari.
|
||||
*/
|
||||
|
||||
[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
outline-offset: -2px; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner padding in Chrome and Safari on macOS.
|
||||
*/
|
||||
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||
* 2. Change font properties to `inherit` in Safari.
|
||||
*/
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
}
|
||||
|
||||
/* Interactive
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Add the correct display in Edge, IE 10+, and Firefox.
|
||||
*/
|
||||
|
||||
details {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the correct display in all browsers.
|
||||
*/
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/* Misc
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10+.
|
||||
*/
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10.
|
||||
*/
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
67
src/components/category-list/constant.js
Normal file
67
src/components/category-list/constant.js
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* 难度筛选
|
||||
*/
|
||||
export const filterDifficulty = [
|
||||
{
|
||||
id: 0,
|
||||
title: '全部',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: 'T4',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'T5',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'T6',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: 'T7',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: 'T8',
|
||||
},
|
||||
];
|
||||
|
||||
export const apiName = {
|
||||
/**
|
||||
* 获取二级和三级标签
|
||||
*/
|
||||
getCategoryLabelInfo: '/admin/question/category/getCategoryLabelInfo',
|
||||
};
|
||||
|
||||
export const imgObject = {
|
||||
clickImg:
|
||||
'../../views/imgs/clickImg.png',
|
||||
ranking1Img:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/206730/39/7751/986/617f4fbaE4e23097a/aa94ca31a9c132b2.png',
|
||||
ranking2Img:
|
||||
'https://img10.360buyimg.com/imagetools/jfs/t1/156125/21/27968/948/617f4fbaEcf1da9a9/722ad0917497697a.png',
|
||||
ranking3Img:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/213197/17/2682/958/617f4fbbE06c277a9/03ef4c389c52ab8d.png',
|
||||
timeline:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/210387/35/7564/555/617f4fbbE0cb305c1/728913d21e650794.png',
|
||||
backAllImg:
|
||||
'https://img11.360buyimg.com/imagetools/jfs/t1/206213/24/13307/2603/617f4fc4E676d448d/622d5287fbf5a919.png',
|
||||
dataImg:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/207558/34/7606/3672/617f4fc4E1ca685fc/3953a92a6072fba4.png',
|
||||
javaImg:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/213752/24/2703/4803/617f4fc4E037da291/5f8050641d4d73d2.png',
|
||||
npmImg: 'https://img11.360buyimg.com/imagetools/jfs/t1/200551/24/15367/3145/617f4fc4Ea153dc2e/b4bbf2de8807f42d.png',
|
||||
parallelComputingImg:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/207198/23/7638/3037/617f4fc4E0e20ab9d/40197a6c79c5a33f.png',
|
||||
springbootImg:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/171775/10/24915/4127/617f4fc4Eeb3d356e/cfbfe8d7c3155047.png',
|
||||
sqlImg: 'https://img13.360buyimg.com/imagetools/jfs/t1/208027/11/7347/3074/617f4fc4Ef11e9495/1093903301db1d1d.png',
|
||||
systemDesignImg:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/206967/24/7622/3629/617f4fc4E60a188b3/cb659847c5d4232a.png',
|
||||
algorithmImg:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/215758/34/2633/4128/617f4fc4E5dcdab66/727be155858a06a5.png',
|
||||
defaultImg:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/155957/24/22934/2028/617a147cE8bcbb57a/7a4885e4ae99a895.png',
|
||||
};
|
362
src/components/category-list/index.jsx
Normal file
362
src/components/category-list/index.jsx
Normal file
@@ -0,0 +1,362 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
|
||||
import {
|
||||
RightOutlined,
|
||||
UpOutlined,
|
||||
DownOutlined,
|
||||
CaretDownOutlined,
|
||||
CaretUpOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import req from '@utils/request';
|
||||
import { Divider } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import './index.less';
|
||||
import { apiName, imgObject } from './constant';
|
||||
|
||||
/**
|
||||
* 大分类中的背景图
|
||||
*/
|
||||
export const categoryBackImg = {
|
||||
0: imgObject.backAllImg,
|
||||
1: imgObject.dataImg,
|
||||
2: imgObject.javaImg,
|
||||
3: imgObject.npmImg,
|
||||
4: imgObject.parallelComputingImg,
|
||||
5: imgObject.springbootImg,
|
||||
6: imgObject.sqlImg,
|
||||
7: imgObject.systemDesignImg,
|
||||
8: imgObject.algorithmImg,
|
||||
};
|
||||
|
||||
const categoryShowCount = 4;
|
||||
|
||||
export default class CategoryList extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
secondCategoryList: [],
|
||||
currentActive: '',
|
||||
isPutAway: true, // 是否收起 默认收起状态
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// this.initCategoryList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化数据,默认选择第一个
|
||||
*/
|
||||
initCategoryList() {
|
||||
const { categoryList, primaryCategoryId } = this.props;
|
||||
let currentActive = primaryCategoryId ?? categoryList[0].primaryCategoryId;
|
||||
this.props.onChangeCategory(currentActive);
|
||||
this.getSecondCategoryList(currentActive);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得二级三级分类数据
|
||||
*/
|
||||
getSecondCategoryList(currentActive) {
|
||||
const { categoryListMap } = this.props;
|
||||
// 调用接口返回二级三级数据
|
||||
let params = {
|
||||
primaryCategoryId: currentActive,
|
||||
subjectTypeList: [4],
|
||||
};
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.getCategoryLabelInfo,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
let secondCategoryList = res.data;
|
||||
let listLen =
|
||||
categoryListMap &&
|
||||
categoryListMap[currentActive] &&
|
||||
categoryListMap[currentActive].length;
|
||||
let objActive = {};
|
||||
listLen > 0 &&
|
||||
categoryListMap &&
|
||||
categoryListMap[currentActive] &&
|
||||
categoryListMap[currentActive].forEach((item) => {
|
||||
objActive[item] = item;
|
||||
});
|
||||
secondCategoryList.forEach((categoryItem) => {
|
||||
categoryItem.labelInfoList.forEach((item) => {
|
||||
if (listLen > 0 && objActive[item.assembleId]) {
|
||||
item.active = true;
|
||||
} else {
|
||||
item.active = false;
|
||||
}
|
||||
});
|
||||
categoryItem.isOpen = false;
|
||||
});
|
||||
this.setState(
|
||||
{
|
||||
secondCategoryList,
|
||||
currentActive,
|
||||
},
|
||||
() => {
|
||||
let activeList = [];
|
||||
secondCategoryList.forEach((categoryItem) => {
|
||||
categoryItem.labelInfoList.forEach((item) => {
|
||||
if (item.active) {
|
||||
activeList.push(item.assembleId);
|
||||
}
|
||||
});
|
||||
});
|
||||
secondCategoryList.forEach((item, index) => {
|
||||
let height = document.getElementById('id_' + index)?.scrollHeight;
|
||||
let displayHeight = height > 43 ? 'flex' : 'none';
|
||||
!this.props.isHideSec &&
|
||||
(document.getElementById('second_id_' + index).style.display =
|
||||
displayHeight);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((err) => console.log(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换一级分类
|
||||
* @param {*} item
|
||||
* @returns
|
||||
*/
|
||||
onChangeCategory = (primaryCategoryId) => () => {
|
||||
let { currentActive } = this.state;
|
||||
if (currentActive === primaryCategoryId) {
|
||||
return;
|
||||
}
|
||||
this.props.isHideSec &&
|
||||
this.setState({
|
||||
currentActive: primaryCategoryId,
|
||||
});
|
||||
this.props.onChangeCategory(primaryCategoryId);
|
||||
!this.props.isHideSec && this.getSecondCategoryList(primaryCategoryId);
|
||||
};
|
||||
|
||||
/**
|
||||
* 选择标签-支持单选(多选)
|
||||
* @param {*} categoryId 一级分类id
|
||||
* @param {*} childrenLevelList 二级分类对象的标签列表
|
||||
* @param {*} secondCategoryIndex 二级分类对象index
|
||||
* @param {*} thirdCategoryIndex 三级标签index
|
||||
* @param {*} active 三级标签当前的选中状态
|
||||
* @returns
|
||||
*/
|
||||
onChangeLabel = (childrenLevelList, secondCategoryIndex, thirdCategoryIndex, active) => () => {
|
||||
let { secondCategoryList, currentActive } = this.state;
|
||||
const { isMultipleChoice } = this.props;
|
||||
if (isMultipleChoice) {
|
||||
// 三级标签支持多选
|
||||
_.set(childrenLevelList, [thirdCategoryIndex, 'active'], !active);
|
||||
_.set(secondCategoryList, [secondCategoryIndex, 'labelInfoList'], childrenLevelList);
|
||||
} else {
|
||||
// 三级标签支持单选
|
||||
let formatLabelList = childrenLevelList.map((item, index) => {
|
||||
let flag = false;
|
||||
if (index === thirdCategoryIndex) {
|
||||
flag = !active; // 将三级标签设置选中/未选中
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
active: flag,
|
||||
};
|
||||
});
|
||||
_.set(secondCategoryList, [secondCategoryIndex, 'labelInfoList'], formatLabelList);
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
secondCategoryList,
|
||||
},
|
||||
() => {
|
||||
let activeList = [];
|
||||
secondCategoryList.forEach((categoryItem) => {
|
||||
categoryItem.labelInfoList.forEach((item) => {
|
||||
if (item.active) {
|
||||
activeList.push(item.assembleId);
|
||||
}
|
||||
});
|
||||
});
|
||||
this.props.onChangeLabel(currentActive, activeList);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 展开/收起
|
||||
* @param {*} secondCategoryIndex
|
||||
* @returns
|
||||
*/
|
||||
onChangeOpenStatus = (secondCategoryIndex, isOpen) => () => {
|
||||
let { secondCategoryList } = this.state;
|
||||
_.set(secondCategoryList, [secondCategoryIndex, 'isOpen'], !isOpen);
|
||||
this.setState({
|
||||
secondCategoryList,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 展开/收起
|
||||
*/
|
||||
onChangePutAway = () => {
|
||||
let { isPutAway } = this.state;
|
||||
this.setState({
|
||||
isPutAway: !isPutAway,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { categoryList } = this.props;
|
||||
const { secondCategoryList } = this.state;
|
||||
return (
|
||||
<div className="category-box">
|
||||
<Fragment>{categoryList?.length > 0 && this.renderFirstContainer()}</Fragment>
|
||||
{!this.props.isHideSec && (
|
||||
<Fragment>
|
||||
{secondCategoryList?.length > 0 && this.renderSecondContainer()}
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一级分类模块
|
||||
* @returns
|
||||
*/
|
||||
renderFirstContainer = () => {
|
||||
const { categoryList } = this.props;
|
||||
const { currentActive } = this.state;
|
||||
return (
|
||||
<div className="first-category-list">
|
||||
{categoryList.slice(0, 7).map((categoryModuleItem, categoryModuleIndex) => {
|
||||
return (
|
||||
<div
|
||||
className={`first-category-item ${categoryModuleItem.primaryCategoryId === currentActive &&
|
||||
'first-category-item-active'
|
||||
}`}
|
||||
key={`first_category_${categoryModuleItem.primaryCategoryId}`}
|
||||
style={{
|
||||
backgroundImage: `url(${categoryBackImg[categoryModuleIndex]})`,
|
||||
}}
|
||||
onClick={this.onChangeCategory(categoryModuleItem.primaryCategoryId)}>
|
||||
<div className="first-category-item-title">
|
||||
{categoryModuleItem.levelName}
|
||||
</div>
|
||||
<div className="first-category-item-count">
|
||||
{categoryModuleItem.count}道题
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{categoryList.length > 7 && (
|
||||
<div className="first-category-more">
|
||||
更多
|
||||
<RightOutlined />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 二级分类模块
|
||||
* @returns
|
||||
*/
|
||||
renderSecondContainer = () => {
|
||||
const { secondCategoryList, isPutAway } = this.state;
|
||||
return (
|
||||
<div className="second-category-list">
|
||||
{secondCategoryList.map((secondCategoryItem, secondCategoryIndex) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display:
|
||||
secondCategoryIndex >= categoryShowCount && isPutAway
|
||||
? 'none'
|
||||
: 'flex',
|
||||
}}
|
||||
className="second-category-item"
|
||||
key={`second_category_${secondCategoryItem.categoryId}`}>
|
||||
<div className="second-category-item-title">
|
||||
{secondCategoryItem.categoryName}:
|
||||
</div>
|
||||
{secondCategoryItem?.labelInfoList?.length > 0 && (
|
||||
<div className="second-category-item-box">
|
||||
<div
|
||||
style={{
|
||||
height: secondCategoryItem.isOpen ? 'auto' : 43,
|
||||
}}
|
||||
className="second-category-item-list"
|
||||
id={`id_${secondCategoryIndex}`}>
|
||||
{secondCategoryItem.labelInfoList.map(
|
||||
(thirdCategoryItem, thirdCategoryIndex) => {
|
||||
return (
|
||||
<div
|
||||
className={`third-category-item ${thirdCategoryItem.active
|
||||
? 'third-category-item-active'
|
||||
: ''
|
||||
}`}
|
||||
key={`third_category_${thirdCategoryItem.id}`}
|
||||
onClick={this.onChangeLabel(
|
||||
secondCategoryItem.labelInfoList,
|
||||
secondCategoryIndex,
|
||||
thirdCategoryIndex,
|
||||
thirdCategoryItem.active
|
||||
)}>
|
||||
{thirdCategoryItem.labelName}·
|
||||
{thirdCategoryItem.subjectCount}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
id={`second_id_${secondCategoryIndex}`}
|
||||
className="second-category-item-status"
|
||||
onClick={this.onChangeOpenStatus(
|
||||
secondCategoryIndex,
|
||||
secondCategoryItem.isOpen
|
||||
)}>
|
||||
<div className="second-category-item-type" style={{ fontSize: 12 }}>
|
||||
{secondCategoryItem.isOpen ? '收起' : '展开'}
|
||||
</div>
|
||||
<div className="second-category-item-icon" style={{ fontSize: 12 }}>
|
||||
{secondCategoryItem.isOpen ? (
|
||||
<UpOutlined />
|
||||
) : (
|
||||
<DownOutlined />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{secondCategoryList?.length >= categoryShowCount && (
|
||||
<Divider
|
||||
onClick={this.onChangePutAway}
|
||||
dashed
|
||||
style={{
|
||||
marginTop: 10,
|
||||
fontSize: 13,
|
||||
}}>
|
||||
{isPutAway ? '展开' : '收起'}
|
||||
{isPutAway ? (
|
||||
<CaretDownOutlined style={{ marginLeft: 4 }} />
|
||||
) : (
|
||||
<CaretUpOutlined style={{ marginLeft: 4 }} />
|
||||
)}
|
||||
</Divider>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
128
src/components/category-list/index.less
Normal file
128
src/components/category-list/index.less
Normal file
@@ -0,0 +1,128 @@
|
||||
.category-box {
|
||||
.first-category-list {
|
||||
display: flex;
|
||||
.first-category-item {
|
||||
flex-shrink: 1;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
margin-right: 18px;
|
||||
padding: 10px 12px;
|
||||
width: 120px;
|
||||
height: 76px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
background-size: 100% 100%;
|
||||
background-color: rgba(0, 0, 0, 0.04);
|
||||
font-weight: 400;
|
||||
transition: all 0.5s;
|
||||
.first-category-item-title {
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 1;
|
||||
overflow: hidden;
|
||||
/* autoprefixer: off */
|
||||
-webkit-box-orient: vertical;
|
||||
display: -webkit-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
.first-category-item-count {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.65);
|
||||
line-height: 16px;
|
||||
}
|
||||
&:hover {
|
||||
transition: all 0.5s;
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
}
|
||||
.first-category-item-active {
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
.first-category-more {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 88px;
|
||||
height: 76px;
|
||||
font-size: 16px;
|
||||
color: #13b4ff;
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
background-color: rgba(19, 180, 255, 0.08);
|
||||
}
|
||||
}
|
||||
.second-category-list {
|
||||
padding-top: 15px;
|
||||
border-radius: 4px;
|
||||
.second-category-item {
|
||||
display: flex;
|
||||
.second-category-item-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 16px;
|
||||
min-width: 60px;
|
||||
height: 40px;
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
font-weight: bold;
|
||||
}
|
||||
.second-category-item-box {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
.second-category-item-list {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
height: 43px;
|
||||
overflow: hidden;
|
||||
.third-category-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 2px 8px;
|
||||
margin: 8px 15px 8px 0;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||
border-radius: 4px;
|
||||
&:hover {
|
||||
@include box-backgroundColor(0.1);
|
||||
@include box-border();
|
||||
@include font-color();
|
||||
}
|
||||
}
|
||||
.third-category-item-active {
|
||||
@include box-backgroundColor(0.1);
|
||||
@include box-border();
|
||||
@include font-color();
|
||||
}
|
||||
}
|
||||
.second-category-item-status {
|
||||
display: flex;
|
||||
margin-top: 8px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 4px 4px 4px 8px;
|
||||
width: 54px;
|
||||
height: 28px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-divider-horizontal.ant-divider-with-text-center {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
0
src/components/layout/index.less
Normal file
0
src/components/layout/index.less
Normal file
0
src/components/layout/index.tsx
Normal file
0
src/components/layout/index.tsx
Normal file
82
src/components/question-list/constant.js
Normal file
82
src/components/question-list/constant.js
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 难度等级
|
||||
*/
|
||||
export const gradeObject = {
|
||||
1: {
|
||||
color: 'rgba(60, 110, 238, 0.5)',
|
||||
title: '初级',
|
||||
},
|
||||
2: {
|
||||
color: 'rgba(60, 110, 238, 0.6)',
|
||||
title: '中级',
|
||||
},
|
||||
3: {
|
||||
color: 'rgba(60, 110, 238, 0.7)',
|
||||
title: '高级',
|
||||
},
|
||||
4: {
|
||||
color: 'rgba(60, 110, 238, 0.8)',
|
||||
title: '资深',
|
||||
},
|
||||
5: {
|
||||
color: 'rgba(60, 110, 238, 0.9)',
|
||||
title: '专家',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 难度筛选
|
||||
*/
|
||||
export const filterDifficulty = [
|
||||
{
|
||||
id: 0,
|
||||
title: '全部',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '初级',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '中级',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '高级',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: '资深',
|
||||
},
|
||||
];
|
||||
|
||||
export const imgObject = {
|
||||
clickImg:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/222669/25/807/6590/617f4f06Eb2094586/64c39ce3769b8a16.png',
|
||||
ranking1Img:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/206730/39/7751/986/617f4fbaE4e23097a/aa94ca31a9c132b2.png',
|
||||
ranking2Img:
|
||||
'https://img10.360buyimg.com/imagetools/jfs/t1/156125/21/27968/948/617f4fbaEcf1da9a9/722ad0917497697a.png',
|
||||
ranking3Img:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/213197/17/2682/958/617f4fbbE06c277a9/03ef4c389c52ab8d.png',
|
||||
timeline:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/210387/35/7564/555/617f4fbbE0cb305c1/728913d21e650794.png',
|
||||
backAllImg:
|
||||
'https://img11.360buyimg.com/imagetools/jfs/t1/206213/24/13307/2603/617f4fc4E676d448d/622d5287fbf5a919.png',
|
||||
dataImg:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/207558/34/7606/3672/617f4fc4E1ca685fc/3953a92a6072fba4.png',
|
||||
javaImg:
|
||||
'../../views/imgs/javaImg.png',
|
||||
npmImg: 'https://img11.360buyimg.com/imagetools/jfs/t1/200551/24/15367/3145/617f4fc4Ea153dc2e/b4bbf2de8807f42d.png',
|
||||
parallelComputingImg:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/207198/23/7638/3037/617f4fc4E0e20ab9d/40197a6c79c5a33f.png',
|
||||
springbootImg:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/171775/10/24915/4127/617f4fc4Eeb3d356e/cfbfe8d7c3155047.png',
|
||||
sqlImg: 'https://img13.360buyimg.com/imagetools/jfs/t1/208027/11/7347/3074/617f4fc4Ef11e9495/1093903301db1d1d.png',
|
||||
systemDesignImg:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/206967/24/7622/3629/617f4fc4E60a188b3/cb659847c5d4232a.png',
|
||||
algorithmImg:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/215758/34/2633/4128/617f4fc4E5dcdab66/727be155858a06a5.png',
|
||||
defaultImg:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/155957/24/22934/2028/617a147cE8bcbb57a/7a4885e4ae99a895.png',
|
||||
};
|
229
src/components/question-list/index.jsx
Normal file
229
src/components/question-list/index.jsx
Normal file
@@ -0,0 +1,229 @@
|
||||
import React, { Component, Fragment } from "react";
|
||||
|
||||
import { Tag, Table, Pagination, Input } from "antd";
|
||||
import { filterDifficulty, gradeObject, imgObject } from "./constant";
|
||||
import { splicingQuery } from "@utils";
|
||||
import "./index.less";
|
||||
const { Search } = Input;
|
||||
|
||||
const colors = ['#ffffb8', '#f4ffb8', '#b5f5ec', '#bae0ff', '#d9f7be', '#efdbff', ' #ffd6e7', '#d6e4ff']
|
||||
|
||||
class QuestionList extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selectValue: "难度",
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() { }
|
||||
|
||||
|
||||
RandomNumBoth = (Min, Max) => {
|
||||
//差值
|
||||
const Range = Max - Min;
|
||||
// 随机数
|
||||
const Rand = Math.random();
|
||||
return Min + Math.round(Rand * Range); //四舍五入
|
||||
}
|
||||
|
||||
/**
|
||||
* 题目列表
|
||||
*/
|
||||
questionColumns = [
|
||||
{
|
||||
title: <div style={{ display: 'flex' }}>题目 <div className="question-count-box" style={{ marginLeft: '10px', color: 'rgba(0, 0, 0, 0.5)' }}>
|
||||
(当前
|
||||
<span style={{ color: "rgba(0, 0, 0, 0.65)" }}> {100} </span>
|
||||
道题)
|
||||
</div></div>,
|
||||
key: "questionNo",
|
||||
align: "centlefter",
|
||||
render: (item) => {
|
||||
return (
|
||||
<div className="question-info-container">
|
||||
<div className="question-info-desc">
|
||||
{item.questionTitle}
|
||||
|
||||
</div>
|
||||
<div className="question-info-tags">
|
||||
{item?.tags?.length > 0 &&
|
||||
item.tags.map((tagsItem, index) => {
|
||||
return (
|
||||
<div className="question-info-tag" key={index} style={{ backgroundColor: colors[this.RandomNumBoth(0, 7)] }}>
|
||||
{tagsItem.name}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "难度",
|
||||
dataIndex: "grade",
|
||||
key: "grade",
|
||||
align: "center",
|
||||
filters: [
|
||||
{
|
||||
value: 0,
|
||||
text: '全部',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
text: '初级',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
text: '中级',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
text: '高级',
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
text: '资深',
|
||||
},
|
||||
],
|
||||
onFilter: (value, record) => {
|
||||
return value === 0 ? record : record.grade === value
|
||||
},
|
||||
width: 90,
|
||||
render: (key) => {
|
||||
return (
|
||||
<Tag color={gradeObject?.[key]?.color}>{gradeObject?.[key]?.title}</Tag>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 选择标签
|
||||
* @param {*} id
|
||||
*/
|
||||
handleChangeSelect = (id) => {
|
||||
console.log(id);
|
||||
let selectValue = "难度";
|
||||
if (id != 0) {
|
||||
filterDifficulty.forEach((item) => {
|
||||
if (item.id == id) {
|
||||
selectValue = item.id;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
selectValue,
|
||||
},
|
||||
() => {
|
||||
this.props.handleChangeSelect(id);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 进入详情
|
||||
* @param {*} item
|
||||
* @param {*} type
|
||||
* @returns
|
||||
*/
|
||||
onChangeAction = (item, index) => () => {
|
||||
let { isNotToDetail, difficulty, primaryCategoryId, labelList, pageIndex } =
|
||||
this.props;
|
||||
!isNotToDetail &&
|
||||
this.props.history.push(
|
||||
splicingQuery("/brush-questions", {
|
||||
id: item?.id,
|
||||
index: index + (pageIndex - 1) * 10 + 1,
|
||||
difficulty,
|
||||
primaryCategoryId,
|
||||
labelList,
|
||||
})
|
||||
);
|
||||
if (!isNotToDetail) return;
|
||||
this.toChangeSelectRows(item);
|
||||
};
|
||||
|
||||
toChangeSelectRows = (record) => {
|
||||
let newSelectedRows = [...this.props.selectRows];
|
||||
const isHas = newSelectedRows.some((rowItem) => rowItem.id === record.id);
|
||||
if (isHas) {
|
||||
newSelectedRows = newSelectedRows.filter(
|
||||
(rowItem) => rowItem.id !== record.id
|
||||
);
|
||||
} else {
|
||||
newSelectedRows.push(record);
|
||||
}
|
||||
this.props.setSelectRows(newSelectedRows);
|
||||
};
|
||||
|
||||
onChangePagination = (e) => {
|
||||
this.props.onChangePagination(e);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { questionList, total, pageIndex, isHideSelect, isMultiple } =
|
||||
this.props;
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="question-list-filter">
|
||||
{!isHideSelect && this.renderFilterContainer()}
|
||||
<div className="question-list-container">
|
||||
<Table
|
||||
onRow={(record, index) => {
|
||||
return {
|
||||
onClick: this.onChangeAction(record, index), // 点击行
|
||||
};
|
||||
}}
|
||||
columns={this.questionColumns}
|
||||
dataSource={questionList}
|
||||
rowKey={(record) => record.id}
|
||||
// bordered={false}
|
||||
pagination={false}
|
||||
rowClassName="question-table-row"
|
||||
/>
|
||||
{total > 10 && (
|
||||
<Pagination
|
||||
style={{
|
||||
padding: "24px 0",
|
||||
textAlign: "center",
|
||||
}}
|
||||
showQuickJumper
|
||||
defaultCurrent={pageIndex}
|
||||
total={total}
|
||||
onChange={this.onChangePagination}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤框-搜索框-模块
|
||||
* @returns
|
||||
*/
|
||||
renderFilterContainer = () => {
|
||||
const { selectValue } = this.state;
|
||||
const { total, isShowSearch, setSearchStr } = this.props;
|
||||
return (
|
||||
<div className="question-filter-container">
|
||||
{isShowSearch && (
|
||||
<Search
|
||||
placeholder="请输入感兴趣的内容~"
|
||||
onSearch={(value) => setSearchStr(value)}
|
||||
style={{ width: 240 }}
|
||||
allowClear
|
||||
size="small"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export default QuestionList;
|
82
src/components/question-list/index.less
Normal file
82
src/components/question-list/index.less
Normal file
@@ -0,0 +1,82 @@
|
||||
.question-list-filter {
|
||||
padding: 0px 6px 20px 9px;
|
||||
background-color: #ffffff;
|
||||
.question-filter-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
padding-right: 18px;
|
||||
padding-left: 5px;
|
||||
.question-filter-box {
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
.question-filter-select {
|
||||
margin-right: 4px;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
border: 0;
|
||||
.ant-select-selection {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.question-count-box {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
.ant-btn {
|
||||
margin-left: 16px;
|
||||
width: 150px;
|
||||
height: 34px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
background-color: #13b4ff;
|
||||
border-color: #13b4ff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
|
||||
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
.question-list-container {
|
||||
.ant-table-tbody > tr > td {
|
||||
// border-bottom: 0;
|
||||
padding: 10px 4px 0 14px;
|
||||
}
|
||||
.ant-table-thead > tr > th {
|
||||
background-color: #ffffff;
|
||||
// border-bottom: 0;
|
||||
}
|
||||
.ant-table-row:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
.ant-table-thead > tr > th .ant-table-header-column .ant-table-column-sorters:hover:before {
|
||||
// background-color: #fff;
|
||||
}
|
||||
.question-info-container {
|
||||
.question-info-desc {
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.question-info-tags {
|
||||
display: flex;
|
||||
margin-top: 8px;
|
||||
padding-bottom: 10px;
|
||||
.question-info-tag {
|
||||
margin-right: 10px;
|
||||
padding: 0px 6px;
|
||||
font-size: 10px !important;
|
||||
border-radius: 4px;
|
||||
// @include font-color();
|
||||
// border: 1px solid rgba(60, 110, 238, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.question-type-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
30
src/components/tags-editor/constant.js
Normal file
30
src/components/tags-editor/constant.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* API名称
|
||||
*/
|
||||
export const apiName = {
|
||||
/**
|
||||
* 新增二级分类
|
||||
*/
|
||||
addInterviewCategory: '/admin/question/category/add',
|
||||
/**
|
||||
* 删除二级分类
|
||||
*/
|
||||
deleteInterviewCategory: '/admin/question/category/delete',
|
||||
/**
|
||||
* 新增三级标签
|
||||
*/
|
||||
addInterviewLabel: '/admin/question/label/add',
|
||||
/**
|
||||
* 删除三级标签
|
||||
*/
|
||||
deleteInterviewLabel: '/admin/question/label/delete',
|
||||
};
|
||||
|
||||
/**
|
||||
* 模块类型
|
||||
*/
|
||||
export const ModuleType = {
|
||||
default: 'default',
|
||||
second: 'second',
|
||||
third: 'third',
|
||||
};
|
302
src/components/tags-editor/index.jsx
Normal file
302
src/components/tags-editor/index.jsx
Normal file
@@ -0,0 +1,302 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import req from '@utils/request';
|
||||
import { Input, Tag, Tooltip, message } from 'antd';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { apiName, ModuleType } from './constant';
|
||||
import './index.less';
|
||||
|
||||
const apiNameModule = {
|
||||
[ModuleType.second]: [apiName.addInterviewCategory, apiName.deleteInterviewCategory],
|
||||
[ModuleType.third]: [apiName.addInterviewLabel, apiName.deleteInterviewLabel],
|
||||
};
|
||||
|
||||
export default class TagsEditor extends Component {
|
||||
saveInputRef = (input) => (this.input = input);
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
inputVisible: false,
|
||||
inputValue: '',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击X号
|
||||
* @param {*} index 当前index
|
||||
* @param {*} categoryId 当前id
|
||||
*/
|
||||
handleClose = (index, categoryId) => {
|
||||
const { moduleType, categoryList } = this.props;
|
||||
let params = {
|
||||
id: categoryId,
|
||||
};
|
||||
let url = apiNameModule[moduleType][1];
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: url,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
let list = categoryList.filter((item) => {
|
||||
return item.categoryId !== categoryId;
|
||||
});
|
||||
this.props.onChangeLabel(list, this.formatList(list));
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 展示输入框
|
||||
*/
|
||||
showInput = () => {
|
||||
this.setState({ inputVisible: true }, () => this.input.focus());
|
||||
};
|
||||
|
||||
/**
|
||||
* 输入框改变内容
|
||||
* @param {*} e
|
||||
*/
|
||||
handleInputChange = (e) => {
|
||||
this.setState({ inputValue: e.target.value });
|
||||
};
|
||||
|
||||
/**
|
||||
* 增加标签
|
||||
*/
|
||||
handleInputConfirm = () => {
|
||||
let { categoryList } = this.props;
|
||||
let { inputValue } = this.state;
|
||||
let equalList = [],
|
||||
formatInputValue = inputValue.trim();
|
||||
if (!formatInputValue) {
|
||||
this.setState({
|
||||
inputValue: '',
|
||||
inputVisible: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (categoryList.length > 0) {
|
||||
equalList = categoryList.filter((item) => {
|
||||
return item.categoryName.toLowerCase() === formatInputValue.toLowerCase();
|
||||
});
|
||||
}
|
||||
if (equalList.length <= 0) {
|
||||
this.postAddInterviewCategory(formatInputValue);
|
||||
} else {
|
||||
message.info('所增内容已存在', 0.3);
|
||||
this.setState({
|
||||
inputValue: '',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 增加标签
|
||||
* @param {*} inputValue 当前的值
|
||||
*/
|
||||
postAddInterviewCategory = (inputValue) => {
|
||||
const { parentCategoryValue, moduleType, categoryList } = this.props;
|
||||
let params_2 = {
|
||||
categoryName: inputValue,
|
||||
categoryType: 2,
|
||||
parentId: parentCategoryValue[0],
|
||||
};
|
||||
let params_3 = {
|
||||
labelName: inputValue,
|
||||
primaryCategoryId: parentCategoryValue[0],
|
||||
};
|
||||
let params = moduleType == ModuleType.third ? params_3 : params_2;
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiNameModule[moduleType][0],
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
let id = res.data;
|
||||
let list = [
|
||||
...categoryList,
|
||||
{
|
||||
categoryName: inputValue,
|
||||
categoryId: id,
|
||||
isShowClose: true,
|
||||
},
|
||||
];
|
||||
let formatList = this.onHandleLabelSelectState(list, list.length - 1, false);
|
||||
this.setState(
|
||||
{
|
||||
inputVisible: false,
|
||||
inputValue: '',
|
||||
},
|
||||
() => {
|
||||
this.props.onChangeLabel(formatList, this.formatList(formatList));
|
||||
}
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 选中/未选中-标签
|
||||
* @param {*} tagIndex 选择的标签
|
||||
* @param {*} active 选择的标签的当前状态
|
||||
* @returns
|
||||
*/
|
||||
onChangeLabel = (tagIndex, active) => () => {
|
||||
let { categoryList, isDisabledReverseSelection } = this.props;
|
||||
if (active && isDisabledReverseSelection) {
|
||||
return;
|
||||
}
|
||||
let formatLabelList = this.onHandleLabelSelectState(categoryList, tagIndex, active);
|
||||
this.props.onChangeLabel(formatLabelList, this.formatList(formatLabelList));
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理数据选中/未选中(单选/多选)
|
||||
* @param {*} list 分类列表
|
||||
* @param {*} tagIndex 当前索引
|
||||
* @param {*} active 当前选中状态
|
||||
* @returns
|
||||
*/
|
||||
onHandleLabelSelectState = (list, tagIndex, active) => {
|
||||
const { isSingleChoice } = this.props;
|
||||
let formatLabelList = [];
|
||||
// 单选
|
||||
if (isSingleChoice) {
|
||||
formatLabelList = list.map((item, index) => {
|
||||
let flag = false;
|
||||
if (index == tagIndex) {
|
||||
flag = !active; // 将三级标签设置选中/未选中
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
active: flag,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
// 多选
|
||||
formatLabelList = list.map((item, index) => {
|
||||
let flag = item.active;
|
||||
if (index == tagIndex) {
|
||||
flag = !active; // 将三级标签设置选中/未选中
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
active: flag,
|
||||
};
|
||||
});
|
||||
}
|
||||
return formatLabelList;
|
||||
};
|
||||
|
||||
/**
|
||||
* 格式化数据-获得选中项id列表
|
||||
* @param {*} list
|
||||
* @returns
|
||||
*/
|
||||
formatList = (list) => {
|
||||
let labelList = [];
|
||||
list.forEach((item) => {
|
||||
if (item.active) {
|
||||
labelList.push(item.categoryId);
|
||||
}
|
||||
});
|
||||
return labelList;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { moduleType, categoryList, isAddTag, isDeleteTag } = this.props;
|
||||
const { inputVisible, inputValue } = this.state;
|
||||
let labelList = categoryList;
|
||||
// 数组中存在 -9999 表示暂无数据,需要支持新增
|
||||
if (
|
||||
categoryList.filter((item) => {
|
||||
return item.categoryId === -9999;
|
||||
}).length > 0
|
||||
) {
|
||||
labelList = categoryList.slice(1, categoryList.length);
|
||||
}
|
||||
return (
|
||||
<div className="tags-editor-box">
|
||||
{labelList?.length > 0 &&
|
||||
labelList.map((item, index) => {
|
||||
const isLongTag = item.categoryName.length > 20;
|
||||
const tagElem = (
|
||||
<Tag
|
||||
style={{
|
||||
margin: '4px',
|
||||
height: '40px',
|
||||
lineHeight: '40px',
|
||||
fontSize: '13px',
|
||||
padding: '0px 16px',
|
||||
border: '1px solid #d9d9d9',
|
||||
backgroundColor: '#fff',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
key={item.categoryId}
|
||||
// 支持删除标签
|
||||
closable={item.isShowClose && isDeleteTag}
|
||||
className={`tags-editor-item ${item.active && 'tag-active'}`}
|
||||
onClick={this.onChangeLabel(index, item.active)}
|
||||
onClose={() => this.handleClose(index, item.categoryId)}>
|
||||
{isLongTag
|
||||
? `${item.categoryName.slice(0, 20)}...`
|
||||
: item.categoryName}
|
||||
</Tag>
|
||||
);
|
||||
return isLongTag ? (
|
||||
<Tooltip title={item.categoryName} key={item.categoryId}>
|
||||
{tagElem}
|
||||
</Tooltip>
|
||||
) : (
|
||||
tagElem
|
||||
);
|
||||
})}
|
||||
{inputVisible && (
|
||||
<Input
|
||||
ref={this.saveInputRef}
|
||||
type="text"
|
||||
size="small"
|
||||
style={{ width: 78, height: 40, marginTop: '4px' }}
|
||||
max={10}
|
||||
value={inputValue}
|
||||
onChange={this.handleInputChange}
|
||||
onBlur={this.handleInputConfirm}
|
||||
onPressEnter={this.handleInputConfirm}
|
||||
/>
|
||||
)}
|
||||
{/* 支持手动增加标签 */}
|
||||
{!inputVisible && isAddTag && (
|
||||
<Tag
|
||||
onClick={this.showInput}
|
||||
style={{
|
||||
background: '#fff',
|
||||
borderColor: 'rgba(60, 110, 238, 1)',
|
||||
borderStyle: 'dashed',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: '14px',
|
||||
height: '40px',
|
||||
padding: '0px 16px',
|
||||
marginTop: '4px',
|
||||
}}>
|
||||
<PlusOutlined />
|
||||
新增{moduleType == ModuleType.third ? '标签' : '分类'}
|
||||
</Tag>
|
||||
)}
|
||||
{!isAddTag && labelList.length === 0 && (
|
||||
<div className="tag-empty-tip">暂无数据呦~</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
21
src/components/tags-editor/index.less
Normal file
21
src/components/tags-editor/index.less
Normal file
@@ -0,0 +1,21 @@
|
||||
.tags-editor-box {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.tag-active {
|
||||
@include box-backgroundColor(0.1);
|
||||
@include box-border();
|
||||
@include font-color();
|
||||
}
|
||||
.ant-tag .anticon-close {
|
||||
font-size: 11px;
|
||||
margin-right: -4px;
|
||||
border: 1px solid;
|
||||
border-radius: 50%;
|
||||
padding: 4px;
|
||||
}
|
||||
.tag-empty-tip {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
}
|
91
src/components/top-menu/index.jsx
Normal file
91
src/components/top-menu/index.jsx
Normal file
@@ -0,0 +1,91 @@
|
||||
import React, { Component } from 'react'
|
||||
import './index.less'
|
||||
// 顶部tab
|
||||
const MENULIST = [
|
||||
{
|
||||
key: 'shareIndex',
|
||||
title: '刷题',
|
||||
route: '/share-index',
|
||||
},
|
||||
{
|
||||
key: 'questionBank',
|
||||
title: '练题',
|
||||
route: '/question-bank',
|
||||
},
|
||||
{
|
||||
key: 'practiceQuestions',
|
||||
title: '鸡圈',
|
||||
route: '/practice-questions',
|
||||
},
|
||||
{
|
||||
key: 'interList',
|
||||
title: '模拟面试',
|
||||
route: '/inter-list',
|
||||
// isOpenNewWindow: true,
|
||||
},
|
||||
]
|
||||
|
||||
// 顶部tab映射
|
||||
const mapMenu = {
|
||||
'/cms-supplier/share-index': 'shareIndex',
|
||||
'/cms-supplier/inter-list': 'interList',
|
||||
'/cms-supplier/question-bank': 'questionBank',
|
||||
'/cms-supplier/practice-questions': 'practiceQuestions',
|
||||
}
|
||||
class TopMenu extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
currentKey: 'shareIndex',
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// this.setState({
|
||||
// currentKey: mapMenu[this.props.currentRoute] || '',
|
||||
// })
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换item
|
||||
* @param {*} item
|
||||
* @returns
|
||||
*/
|
||||
changeMenu = (item) => () => {
|
||||
// 打开新窗口
|
||||
if (item.isOpenNewWindow) {
|
||||
window.open('/cms-supplier' + item.route)
|
||||
return
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
currentKey: item.key,
|
||||
},
|
||||
() => {
|
||||
this.props.history.push(item.route)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { currentKey } = this.state
|
||||
return (
|
||||
<div className="top-menu-list">
|
||||
{MENULIST.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
className={`top-menu-item ${currentKey === item.key ? 'top-menu-item-active' : ''}`}
|
||||
key={item.key + index}
|
||||
onClick={this.changeMenu(item)}
|
||||
>
|
||||
<div className="top-menu-text">{item.title}</div>
|
||||
<div className={`top-menu-line ${currentKey === item.key ? 'top-menu-line-active' : ''}`}></div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default TopMenu
|
35
src/components/top-menu/index.less
Normal file
35
src/components/top-menu/index.less
Normal file
@@ -0,0 +1,35 @@
|
||||
.top-menu-list {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
.top-menu-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0 28px;
|
||||
font-size: 16px;
|
||||
font-size: 500;
|
||||
color: rgba(24, 24, 29, 1);
|
||||
cursor: pointer;
|
||||
&-active {
|
||||
color: rgba(60, 110, 238, 1);
|
||||
}
|
||||
&:hover {
|
||||
color: rgba(60, 110, 238, 1);
|
||||
}
|
||||
|
||||
.top-menu-line {
|
||||
position: absolute;
|
||||
bottom: -12px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
&-active {
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background: rgba(60, 110, 238, 1);
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Fira Sans', 'Droid Sans',
|
||||
'Helvetica Neue', sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||
}
|
0
src/main.less
Normal file
0
src/main.less
Normal file
@@ -1,10 +1,14 @@
|
||||
import './main.less'
|
||||
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App'
|
||||
import './index.css'
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
<BrowserRouter basename='/'>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</React.StrictMode>
|
||||
)
|
||||
|
16
src/router/index.ts
Normal file
16
src/router/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
import QuestionBank from '@views/question-bank';
|
||||
import UploadQuestions from '@views/upload-questions';
|
||||
|
||||
export default [
|
||||
{
|
||||
path: '/question-bank',
|
||||
exact: true,
|
||||
component: QuestionBank,
|
||||
},
|
||||
{
|
||||
path: '/upload-questions',
|
||||
exact: true,
|
||||
component: UploadQuestions,
|
||||
},
|
||||
];
|
129
src/utils/index.ts
Normal file
129
src/utils/index.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
//解析查询字符串
|
||||
export function queryParse(str) {
|
||||
if (!str) return {};
|
||||
let strParams = decodeURIComponent(str).split('?')[1];
|
||||
let paramsObj = {};
|
||||
strParams.split('&').forEach((item) => {
|
||||
let arrParams = item.split('=');
|
||||
paramsObj[arrParams[0]] = arrParams[1];
|
||||
});
|
||||
return paramsObj;
|
||||
}
|
||||
|
||||
//拼接查询字符串
|
||||
export function splicingQuery(path, paramsObj = {}) {
|
||||
let paramsArr = Object.keys(paramsObj);
|
||||
if (paramsArr.length === 0) return path;
|
||||
let splicingPath = '';
|
||||
for (let i = 0; i < paramsArr.length; i++) {
|
||||
splicingPath +=
|
||||
paramsArr[i] +
|
||||
'=' +
|
||||
(paramsObj[paramsArr[i]] ?? '') +
|
||||
(i !== paramsArr.length - 1 ? '&' : '');
|
||||
}
|
||||
return path + '?' + encodeURIComponent(splicingPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 防抖函数
|
||||
* @param {function} method 回调函数
|
||||
* @param {number} wait 表示时间窗口的间隔
|
||||
* @param {boolean} immediate 是否立即执行
|
||||
* @return {function} 返回客户调用函数
|
||||
*/
|
||||
export function debounce(method, wait = 300, immediate = false) {
|
||||
let timer, context, args;
|
||||
const later = () =>
|
||||
setTimeout(() => {
|
||||
timer = null;
|
||||
if (!immediate) {
|
||||
method.apply(context, args);
|
||||
context = args = null;
|
||||
}
|
||||
}, wait);
|
||||
return function (...params) {
|
||||
if (!timer) {
|
||||
timer = later();
|
||||
if (immediate) {
|
||||
method.apply(this, params);
|
||||
} else {
|
||||
context = this;
|
||||
args = params;
|
||||
}
|
||||
} else {
|
||||
clearTimeout(timer);
|
||||
timer = later();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 节流函数
|
||||
* @param method
|
||||
* @param delay 延迟执行,只执行最后一次
|
||||
* @param duration 间隔时间
|
||||
* @param context
|
||||
*/
|
||||
export function throttle(method, delay, duration = 0, context = '') {
|
||||
let timer;
|
||||
let begin = new Date().getTime();
|
||||
return function (...args) {
|
||||
const current = new Date().getTime();
|
||||
clearTimeout(timer);
|
||||
if (duration) {
|
||||
if (current - begin > duration) {
|
||||
method.apply(context || this, args);
|
||||
begin = current;
|
||||
return;
|
||||
}
|
||||
}
|
||||
timer = setTimeout(function () {
|
||||
method.apply(context || this, args);
|
||||
}, delay);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得当前年月日时分秒
|
||||
* @returns
|
||||
*/
|
||||
export function getCurrentTime() {
|
||||
var date = new Date();
|
||||
var seperator1 = '-';
|
||||
var month = date.getMonth() + 1;
|
||||
var strDate = date.getDate();
|
||||
var hour = date.getHours();
|
||||
var minute = date.getMinutes();
|
||||
var second = date.getSeconds();
|
||||
|
||||
if (month >= 1 && month <= 9) {
|
||||
month = '0' + month;
|
||||
}
|
||||
if (strDate >= 0 && strDate <= 9) {
|
||||
strDate = '0' + strDate;
|
||||
}
|
||||
if (hour >= 0 && hour <= 9) {
|
||||
hour = '0' + hour;
|
||||
}
|
||||
if (minute >= 0 && minute <= 9) {
|
||||
minute = '0' + minute;
|
||||
}
|
||||
if (second >= 0 && second <= 9) {
|
||||
second = '0' + second;
|
||||
}
|
||||
var currentdate =
|
||||
'' +
|
||||
date.getFullYear() +
|
||||
seperator1 +
|
||||
month +
|
||||
seperator1 +
|
||||
strDate +
|
||||
' ' +
|
||||
hour +
|
||||
':' +
|
||||
minute +
|
||||
':' +
|
||||
second;
|
||||
return currentdate;
|
||||
}
|
62
src/utils/request.ts
Normal file
62
src/utils/request.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import axios from 'axios';
|
||||
import { message } from 'antd';
|
||||
|
||||
export const baseHttp = () => {
|
||||
const http = axios.create({
|
||||
// baseURL: "/flow",
|
||||
timeout: 5 * 60 * 1000, // request timeout
|
||||
withCredentials: true, // send cookies when cross-domain requests
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
},
|
||||
});
|
||||
|
||||
return http;
|
||||
};
|
||||
|
||||
export default function request(config, url) {
|
||||
const baseURL = url || '/api';
|
||||
// 1.创建axios的实例
|
||||
const instance = axios.create({
|
||||
baseURL,
|
||||
timeout: 5 * 60 * 1000, // request timeout
|
||||
withCredentials: true, // send cookies when cross-domain requests
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
},
|
||||
});
|
||||
|
||||
// 2.axios的拦截器
|
||||
// 2.1.请求拦截的作用
|
||||
instance.interceptors.request.use(
|
||||
(config) => {
|
||||
return config;
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
}
|
||||
);
|
||||
|
||||
// 2.2.响应拦截
|
||||
instance.interceptors.response.use(
|
||||
(res) => {
|
||||
let { code } = res.data;
|
||||
if (code === 500) {
|
||||
message.error(res.data.message);
|
||||
}
|
||||
return res.data;
|
||||
},
|
||||
(err) => {
|
||||
let { status } = err?.response ?? {};
|
||||
if (status === 401 || !status) {
|
||||
message.info('页面异常')
|
||||
} else if (status === 500 || status === 503) {
|
||||
message.error('服务器错误');
|
||||
}
|
||||
return Promise.reject(err);
|
||||
}
|
||||
);
|
||||
|
||||
// 3.发送真正的网络请求
|
||||
return instance(config);
|
||||
}
|
@@ -1,10 +0,0 @@
|
||||
const Home = () => {
|
||||
return (
|
||||
<div>
|
||||
home
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export default Home
|
BIN
src/views/imgs/clickImg.png
Normal file
BIN
src/views/imgs/clickImg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
BIN
src/views/imgs/head.jpg
Normal file
BIN
src/views/imgs/head.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
BIN
src/views/imgs/javaImg.png
Normal file
BIN
src/views/imgs/javaImg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
BIN
src/views/imgs/logo.jpg
Normal file
BIN
src/views/imgs/logo.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
@@ -0,0 +1,99 @@
|
||||
import React, { Fragment, Component } from 'react';
|
||||
import req from '@utils/request';
|
||||
import RankingBox from '../ranking-box';
|
||||
import { imgObject, apiName, RankingType } from '../../constant';
|
||||
import { mockRankingModuleList } from '../../mock';
|
||||
|
||||
const rankingBackImg = {
|
||||
0: imgObject.ranking1Img,
|
||||
1: imgObject.ranking2Img,
|
||||
2: imgObject.ranking3Img,
|
||||
};
|
||||
|
||||
class ContributionList extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
contributionList: mockRankingModuleList[1].rankingList || [],
|
||||
contributeType: 1,
|
||||
isLoading: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// this.getContributeList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得贡献榜
|
||||
*/
|
||||
getContributeList() {
|
||||
const { contributeType } = this.state;
|
||||
let params = {
|
||||
contributeType: contributeType,
|
||||
};
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.getContributeList,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
this.setState({
|
||||
contributionList: res.data,
|
||||
isLoading: false,
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
contributionList: [],
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => console.log(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换排行榜
|
||||
* @param {*} type
|
||||
* @returns
|
||||
*/
|
||||
onChangeRanking = (type) => {
|
||||
this.setState(
|
||||
{
|
||||
contributeType: type,
|
||||
isLoading: true,
|
||||
},
|
||||
() => {
|
||||
this.getContributeList();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 去录题
|
||||
*/
|
||||
onChangeJump = () => {
|
||||
this.props.history.push('/upload-questions');
|
||||
};
|
||||
|
||||
render() {
|
||||
const { contributionList, isLoading, contributeType } = this.state;
|
||||
return (
|
||||
<Fragment>
|
||||
{contributionList?.length > 0 && (
|
||||
<RankingBox
|
||||
isLoading={isLoading}
|
||||
rankingList={contributionList}
|
||||
currentActive={contributeType}
|
||||
rankingType={RankingType.contribution}
|
||||
onHandleRanking={this.onChangeRanking}
|
||||
onHandleJump={this.onChangeJump}
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ContributionList;
|
151
src/views/question-bank/components/contribution-list/index.less
Normal file
151
src/views/question-bank/components/contribution-list/index.less
Normal file
@@ -0,0 +1,151 @@
|
||||
.ranking-list-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
padding: 0px 16px 0px;
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
|
||||
.ranking-list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
font-size: 16px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
border-bottom: 1px solid #f3f3f6;
|
||||
.ranking-list-title {
|
||||
}
|
||||
|
||||
.ranking-list-btns {
|
||||
display: flex;
|
||||
.ranking-list-btn {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 4px;
|
||||
width: 48px;
|
||||
height: 30px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.5s;
|
||||
&:last-child {
|
||||
margin-right: 0px;
|
||||
}
|
||||
&:hover {
|
||||
@include font-color();
|
||||
}
|
||||
}
|
||||
.ranking-list-btn-active {
|
||||
font-weight: 600;
|
||||
@include font-color();
|
||||
border-bottom: 1px solid rgba(60, 110, 238, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.ranking-list {
|
||||
// height: 326px;
|
||||
// overflow-y: scroll;
|
||||
font-size: 14px;
|
||||
.ranking-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 12px 10px 6px;
|
||||
color: #999999;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
.ranking-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.ranking-icon {
|
||||
margin-right: 10px;
|
||||
// margin-top: 14px;
|
||||
width: 20px;
|
||||
height: 26px;
|
||||
line-height: 17px;
|
||||
text-align: center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.ranking-head-img {
|
||||
margin-right: 4px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
|
||||
.ranking-head-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.ranking-info {
|
||||
.ranking-name {
|
||||
margin-bottom: 2px;
|
||||
color: #666666;
|
||||
}
|
||||
.ranking-department {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ranking-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #c3c3c6;
|
||||
}
|
||||
&:hover {
|
||||
@include box-backgroundColor(0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
.ranking-btn-go {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
cursor: pointer;
|
||||
width: 230px;
|
||||
height: 36px;
|
||||
border-radius: 30px;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
|
||||
@include box-backgroundColor(0.9);
|
||||
.ranking-btn-go-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
background-size: 100% 100%;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.ranking-btn-text {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
&:hover {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
color: transparent;
|
||||
}
|
||||
.tooltip-info {
|
||||
font-size: 12px;
|
||||
}
|
||||
.popover-img {
|
||||
margin-left: 4px;
|
||||
cursor: pointer;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
96
src/views/question-bank/components/ranking-box/index.jsx
Normal file
96
src/views/question-bank/components/ranking-box/index.jsx
Normal file
@@ -0,0 +1,96 @@
|
||||
import React from 'react';
|
||||
import { Popover, Spin } from 'antd';
|
||||
import { debounce } from '@utils';
|
||||
import { imgObject, RankingTypeText, RankingTypeBtnText } from '../../constant';
|
||||
import './index.less';
|
||||
|
||||
const rankingBackImg = {
|
||||
0: imgObject.ranking1Img,
|
||||
1: imgObject.ranking2Img,
|
||||
2: imgObject.ranking3Img,
|
||||
};
|
||||
|
||||
export default function RankingBox(props) {
|
||||
const { isLoading, currentActive, rankingList, rankingType } = props;
|
||||
const onChangeRanking = (type) =>
|
||||
debounce(() => {
|
||||
props.onHandleRanking && props.onHandleRanking(type);
|
||||
});
|
||||
const onJump = debounce(() => {
|
||||
props.onHandleJump && props.onHandleJump();
|
||||
});
|
||||
return (
|
||||
<div className="ranking-list-box">
|
||||
<div className="ranking-list-header">
|
||||
<div className="ranking-list-title">{RankingTypeText[rankingType]}</div>
|
||||
<div className="ranking-list-btns">
|
||||
<div
|
||||
onClick={onChangeRanking(1)}
|
||||
className={`ranking-list-btn ${currentActive === undefined || currentActive === 1
|
||||
? 'ranking-list-btn-active'
|
||||
: ''
|
||||
}`}>
|
||||
本月排行
|
||||
</div>
|
||||
<div
|
||||
onClick={onChangeRanking(2)}
|
||||
className={`ranking-list-btn ${currentActive === 2 ? 'ranking-list-btn-active' : ''
|
||||
}`}>
|
||||
总排行
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Spin spinning={isLoading}>
|
||||
<div className="ranking-list">
|
||||
{rankingList?.length > 0 &&
|
||||
rankingList.map((item, index) => {
|
||||
return (
|
||||
<div className="ranking-item" key={item.id}>
|
||||
<div className="ranking-left">
|
||||
<div
|
||||
className="ranking-icon"
|
||||
style={{
|
||||
backgroundImage: `url(${rankingBackImg[index]})`,
|
||||
}}>
|
||||
{index + 1}
|
||||
</div>
|
||||
<div className="ranking-head-img">
|
||||
<img src={item.headImg} className="ranking-head-icon" />
|
||||
</div>
|
||||
<Popover
|
||||
title={
|
||||
<div>
|
||||
{item.name}
|
||||
</div>
|
||||
}
|
||||
content={
|
||||
<div className="tooltip-info">
|
||||
<div>{item.erp}</div>
|
||||
<div>{item.organizationFullName}</div>
|
||||
</div>
|
||||
}>
|
||||
<div className="ranking-info">
|
||||
<div className="ranking-name">{item.name}</div>
|
||||
<div className="ranking-department">
|
||||
{item.organizationName}
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
<div className="ranking-right">🔥 {item.count}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Spin>
|
||||
<div className="ranking-btn-go" onClick={onJump}>
|
||||
<div
|
||||
className="ranking-btn-go-icon"
|
||||
style={{
|
||||
backgroundImage: `url(${imgObject.clickImg})`,
|
||||
}}></div>
|
||||
<div className="ranking-btn-text">{RankingTypeBtnText[rankingType]}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
149
src/views/question-bank/components/ranking-box/index.less
Normal file
149
src/views/question-bank/components/ranking-box/index.less
Normal file
@@ -0,0 +1,149 @@
|
||||
.ranking-list-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
padding: 0px 16px 0px;
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
|
||||
.ranking-list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
font-size: 16px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
border-bottom: 1px solid #f3f3f6;
|
||||
|
||||
.ranking-list-btns {
|
||||
display: flex;
|
||||
.ranking-list-btn {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 4px;
|
||||
width: 48px;
|
||||
height: 30px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.5s;
|
||||
&:last-child {
|
||||
margin-right: 0px;
|
||||
}
|
||||
&:hover {
|
||||
@include font-color();
|
||||
}
|
||||
}
|
||||
.ranking-list-btn-active {
|
||||
font-weight: 600;
|
||||
// @include font-color();
|
||||
border-bottom: 1px solid rgba(60, 110, 238, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.ranking-list {
|
||||
// height: 326px;
|
||||
// overflow-y: scroll;
|
||||
font-size: 14px;
|
||||
.ranking-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 12px 10px 6px;
|
||||
color: #999999;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
.ranking-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.ranking-icon {
|
||||
margin-right: 10px;
|
||||
// margin-top: 14px;
|
||||
width: 20px;
|
||||
height: 26px;
|
||||
line-height: 17px;
|
||||
text-align: center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.ranking-head-img {
|
||||
margin-right: 4px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
|
||||
.ranking-head-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.ranking-info {
|
||||
.ranking-name {
|
||||
margin-bottom: 2px;
|
||||
color: #666666;
|
||||
}
|
||||
.ranking-department {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ranking-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #c3c3c6;
|
||||
}
|
||||
&:hover {
|
||||
@include box-backgroundColor(0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
.ranking-btn-go {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
cursor: pointer;
|
||||
width: 230px;
|
||||
height: 36px;
|
||||
border-radius: 30px;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
|
||||
background-color: rgba(60, 110, 238, 0.9);
|
||||
.ranking-btn-go-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
background-size: 100% 100%;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.ranking-btn-text {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
&:hover {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
color: transparent;
|
||||
}
|
||||
.tooltip-info {
|
||||
font-size: 12px;
|
||||
}
|
||||
.popover-img {
|
||||
margin-left: 4px;
|
||||
cursor: pointer;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
109
src/views/question-bank/components/ranking-list/index.jsx
Normal file
109
src/views/question-bank/components/ranking-list/index.jsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import React, { Fragment, Component } from 'react';
|
||||
|
||||
import req from '@utils/request';
|
||||
import { mockRankingModuleList } from '../../mock';
|
||||
import { imgObject, apiName, RankingType } from '../../constant';
|
||||
import RankingBox from '../ranking-box';
|
||||
|
||||
const rankingBackImg = {
|
||||
0: imgObject.ranking1Img,
|
||||
1: imgObject.ranking2Img,
|
||||
2: imgObject.ranking3Img,
|
||||
};
|
||||
class RankingList extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
moduleList: [],
|
||||
contributeType: 2,
|
||||
isLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getContributeList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得贡献榜
|
||||
*/
|
||||
getContributeList() {
|
||||
// let params = {
|
||||
// contributeType: this.contributeType,
|
||||
// };
|
||||
// req({
|
||||
// method: 'post',
|
||||
// data: params,
|
||||
// url: apiName.getContributeList,
|
||||
// })
|
||||
// .then((res) => {
|
||||
// if (res.data && res.data.length > 0) {
|
||||
// this.setState(
|
||||
// {
|
||||
// firstCategoryList: res.data,
|
||||
// isShowSpin: false,
|
||||
// },
|
||||
// () => {
|
||||
// this.getInterviewSubjectList();
|
||||
// }
|
||||
// );
|
||||
// } else {
|
||||
// this.primaryCategoryId = '';
|
||||
// this.setState({
|
||||
// isShowSpin: false,
|
||||
// });
|
||||
// }
|
||||
// })
|
||||
// .catch((err) => console.log(err));
|
||||
|
||||
this.setState({
|
||||
moduleList: mockRankingModuleList[0].rankingList,
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换排行榜
|
||||
* @param {*} type
|
||||
* @returns
|
||||
*/
|
||||
onChangeRanking = (type, index) => () => {
|
||||
let { moduleList } = this.state;
|
||||
moduleList[index].currentActive = type;
|
||||
this.setState(
|
||||
{
|
||||
moduleList,
|
||||
isLoading: true,
|
||||
},
|
||||
() => {
|
||||
this.getData();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
onJump = (e) => () => {
|
||||
if (e === 2) {
|
||||
this.props.history.push('/upload-questions');
|
||||
} else {
|
||||
this.props.history.push('/practice-questions');
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { moduleList, isLoading, contributeType } = this.state;
|
||||
return (
|
||||
<Fragment>
|
||||
<RankingBox
|
||||
isLoading={isLoading}
|
||||
rankingList={moduleList}
|
||||
currentActive={contributeType}
|
||||
rankingType={RankingType.practice}
|
||||
onHandleRanking={this.onChangeRanking}
|
||||
onHandleJump={this.onChangeJump}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RankingList;
|
151
src/views/question-bank/components/ranking-list/index.less
Normal file
151
src/views/question-bank/components/ranking-list/index.less
Normal file
@@ -0,0 +1,151 @@
|
||||
.ranking-list-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
padding: 0px 16px 0px;
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
|
||||
.ranking-list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
font-size: 16px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
border-bottom: 1px solid #f3f3f6;
|
||||
.ranking-list-title {
|
||||
}
|
||||
|
||||
.ranking-list-btns {
|
||||
display: flex;
|
||||
.ranking-list-btn {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 4px;
|
||||
width: 48px;
|
||||
height: 30px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.5s;
|
||||
&:last-child {
|
||||
margin-right: 0px;
|
||||
}
|
||||
&:hover {
|
||||
@include font-color();
|
||||
}
|
||||
}
|
||||
.ranking-list-btn-active {
|
||||
font-weight: 600;
|
||||
@include font-color();
|
||||
border-bottom: 1px solid rgba(60, 110, 238, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.ranking-list {
|
||||
// height: 326px;
|
||||
// overflow-y: scroll;
|
||||
font-size: 14px;
|
||||
.ranking-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 12px 10px 6px;
|
||||
color: #999999;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
.ranking-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.ranking-icon {
|
||||
margin-right: 10px;
|
||||
// margin-top: 14px;
|
||||
width: 20px;
|
||||
height: 26px;
|
||||
line-height: 17px;
|
||||
text-align: center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.ranking-head-img {
|
||||
margin-right: 4px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08);
|
||||
.ranking-head-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.ranking-info {
|
||||
.ranking-name {
|
||||
margin-bottom: 2px;
|
||||
color: #666666;
|
||||
}
|
||||
.ranking-department {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ranking-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #c3c3c6;
|
||||
}
|
||||
&:hover {
|
||||
@include box-backgroundColor(0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
.ranking-btn-go {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
cursor: pointer;
|
||||
width: 230px;
|
||||
height: 36px;
|
||||
border-radius: 30px;
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
|
||||
@include box-backgroundColor(0.9);
|
||||
.ranking-btn-go-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
background-size: 100% 100%;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.ranking-btn-text {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
&:hover {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
color: transparent;
|
||||
}
|
||||
.tooltip-info {
|
||||
font-size: 12px;
|
||||
}
|
||||
.popover-img {
|
||||
margin-left: 4px;
|
||||
cursor: pointer;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
133
src/views/question-bank/constant.js
Normal file
133
src/views/question-bank/constant.js
Normal file
@@ -0,0 +1,133 @@
|
||||
import JavaImg from '@views/imgs/javaImg.png'
|
||||
/**
|
||||
* 难度等级
|
||||
*/
|
||||
export const gradeObject = {
|
||||
1: {
|
||||
color: 'rgba(60, 110, 238, 0.7)',
|
||||
title: '初级',
|
||||
},
|
||||
2: {
|
||||
color: 'rgba(60, 110, 238, 0.7)',
|
||||
title: '中级',
|
||||
},
|
||||
3: {
|
||||
color: 'rgba(60, 110, 238, 0.7)',
|
||||
title: '高级',
|
||||
},
|
||||
4: {
|
||||
color: 'rgba(60, 110, 238, 0.7)',
|
||||
title: '资深',
|
||||
},
|
||||
5: {
|
||||
color: 'rgba(60, 110, 238, 0.7)',
|
||||
title: '专家',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 难度筛选
|
||||
*/
|
||||
export const filterDifficulty = [
|
||||
{
|
||||
id: 0,
|
||||
title: '全部',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: '初级',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '中级',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '高级',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '资深',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: '专家',
|
||||
},
|
||||
];
|
||||
|
||||
export const apiName = {
|
||||
/**
|
||||
* 获取一级分类
|
||||
*/
|
||||
getPrimaryCategoryInfo: '/admin/question/category/getPrimaryCategoryInfo',
|
||||
|
||||
/**
|
||||
* 获取题目列表
|
||||
*/
|
||||
getInterviewSubjectList: '/admin/question/subject/getSubjectList',
|
||||
|
||||
/**
|
||||
* 获得贡献榜
|
||||
*/
|
||||
getContributeList: '/admin/question/subject/getContributeList',
|
||||
};
|
||||
|
||||
export const imgObject = {
|
||||
clickImg:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/222669/25/807/6590/617f4f06Eb2094586/64c39ce3769b8a16.png',
|
||||
ranking1Img:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/206730/39/7751/986/617f4fbaE4e23097a/aa94ca31a9c132b2.png',
|
||||
ranking2Img:
|
||||
'https://img10.360buyimg.com/imagetools/jfs/t1/156125/21/27968/948/617f4fbaEcf1da9a9/722ad0917497697a.png',
|
||||
ranking3Img:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/213197/17/2682/958/617f4fbbE06c277a9/03ef4c389c52ab8d.png',
|
||||
timeline:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/210387/35/7564/555/617f4fbbE0cb305c1/728913d21e650794.png',
|
||||
backAllImg:
|
||||
'https://img11.360buyimg.com/imagetools/jfs/t1/206213/24/13307/2603/617f4fc4E676d448d/622d5287fbf5a919.png',
|
||||
dataImg:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/207558/34/7606/3672/617f4fc4E1ca685fc/3953a92a6072fba4.png',
|
||||
javaImg: JavaImg,
|
||||
npmImg: 'https://img11.360buyimg.com/imagetools/jfs/t1/200551/24/15367/3145/617f4fc4Ea153dc2e/b4bbf2de8807f42d.png',
|
||||
parallelComputingImg:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/207198/23/7638/3037/617f4fc4E0e20ab9d/40197a6c79c5a33f.png',
|
||||
springbootImg:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/171775/10/24915/4127/617f4fc4Eeb3d356e/cfbfe8d7c3155047.png',
|
||||
sqlImg: 'https://img13.360buyimg.com/imagetools/jfs/t1/208027/11/7347/3074/617f4fc4Ef11e9495/1093903301db1d1d.png',
|
||||
systemDesignImg:
|
||||
'https://img12.360buyimg.com/imagetools/jfs/t1/206967/24/7622/3629/617f4fc4E60a188b3/cb659847c5d4232a.png',
|
||||
algorithmImg:
|
||||
'https://img14.360buyimg.com/imagetools/jfs/t1/215758/34/2633/4128/617f4fc4E5dcdab66/727be155858a06a5.png',
|
||||
defaultImg:
|
||||
'https://img13.360buyimg.com/imagetools/jfs/t1/155957/24/22934/2028/617a147cE8bcbb57a/7a4885e4ae99a895.png',
|
||||
};
|
||||
|
||||
/**
|
||||
* 模块类型
|
||||
*/
|
||||
export const RankingType = {
|
||||
/**
|
||||
* 贡献榜
|
||||
*/
|
||||
contribution: 1,
|
||||
/**
|
||||
* 排行榜
|
||||
*/
|
||||
practice: 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* 模块名称
|
||||
*/
|
||||
export const RankingTypeText = {
|
||||
[RankingType.contribution]: '贡献榜',
|
||||
[RankingType.practice]: '综合练习榜',
|
||||
};
|
||||
|
||||
/**
|
||||
* 对应按钮名字
|
||||
*/
|
||||
export const RankingTypeBtnText = {
|
||||
[RankingType.contribution]: '去出题',
|
||||
[RankingType.practice]: '去练习',
|
||||
};
|
35
src/views/question-bank/index.less
Normal file
35
src/views/question-bank/index.less
Normal file
@@ -0,0 +1,35 @@
|
||||
.question-bank-box {
|
||||
display: flex;
|
||||
width: 1439px;
|
||||
margin: 0 auto;
|
||||
background-color: #f3f4f6;
|
||||
border-radius: 5px;
|
||||
.ant-spin-nested-loading {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
border-radius: 8px;
|
||||
.question-box {
|
||||
// flex: 1;
|
||||
// overflow-y: auto;
|
||||
// border-radius: 8px;
|
||||
.category-list-box {
|
||||
padding: 24px 24px 6px;
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.question-list-box {
|
||||
margin-top: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ranking-box {
|
||||
margin-left: 16px;
|
||||
overflow-y: auto;
|
||||
width: 310px;
|
||||
}
|
||||
.ant-spin-nested-loading {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
177
src/views/question-bank/index.tsx
Normal file
177
src/views/question-bank/index.tsx
Normal file
@@ -0,0 +1,177 @@
|
||||
import { Component } from 'react';
|
||||
import QuestionList from '@components/question-list';
|
||||
import CategoryList from '@components/category-list';
|
||||
import ContributionList from './components/contribution-list';
|
||||
import RankingList from './components/ranking-list'
|
||||
import { apiName } from './constant';
|
||||
import req from '@utils/request';
|
||||
import { Spin } from 'antd';
|
||||
import { mockTabList, mockDataList } from './mock'
|
||||
import './index.less';
|
||||
|
||||
export default class QuestionBank extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
firstCategoryList: mockTabList || [],
|
||||
questionList: mockDataList || [],
|
||||
isShowSpin: false,
|
||||
};
|
||||
}
|
||||
labelList = []; // 选中的标签列表
|
||||
difficulty = 0; //困难度(全部)
|
||||
total = 0; // 总条数
|
||||
pageIndex = 1;
|
||||
primaryCategoryId = ''; //第一个大类id
|
||||
|
||||
componentDidMount() {
|
||||
// this.getPrimaryCategoryInfo();
|
||||
// console.log(this.props.route);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一级分类数据
|
||||
*/
|
||||
getPrimaryCategoryInfo() {
|
||||
req({
|
||||
method: 'post',
|
||||
data: { subjectTypeList: [4] },
|
||||
url: apiName.getPrimaryCategoryInfo,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
this.primaryCategoryId = res.data[0].primaryCategoryId;
|
||||
this.setState(
|
||||
{
|
||||
firstCategoryList: res.data,
|
||||
isShowSpin: false,
|
||||
},
|
||||
() => {
|
||||
this.getInterviewSubjectList();
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.primaryCategoryId = '';
|
||||
this.setState({
|
||||
isShowSpin: false,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => console.log(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取题目列表
|
||||
*/
|
||||
getInterviewSubjectList() {
|
||||
let params = {
|
||||
pageInfo: {
|
||||
pageIndex: this.pageIndex,
|
||||
pageSize: 10,
|
||||
},
|
||||
difficulty: this.difficulty,
|
||||
primaryCategoryId: this.primaryCategoryId,
|
||||
assembleIds: this.labelList,
|
||||
};
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.getInterviewSubjectList,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data && res.data?.pageList?.length > 0) {
|
||||
this.total = res.data.pageInfo.total;
|
||||
this.setState({
|
||||
questionList: res.data.pageList,
|
||||
isShowSpin: false,
|
||||
});
|
||||
} else {
|
||||
this.total = 0;
|
||||
this.setState({
|
||||
questionList: [],
|
||||
isShowSpin: false,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => console.log(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择标签时,请求列表数据
|
||||
* @param {*} primaryCategoryId 一级分类id
|
||||
* @param {*} assembleIds 三级标签 assembleIds
|
||||
*/
|
||||
onChangeLabel = (primaryCategoryId, assembleIds) => {
|
||||
this.labelList = assembleIds;
|
||||
this.primaryCategoryId = primaryCategoryId;
|
||||
this.pageIndex = 1;
|
||||
this.getInterviewSubjectList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 切换一级分类
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeCategory = (e) => {
|
||||
this.labelList = [];
|
||||
this.primaryCategoryId = e;
|
||||
this.pageIndex = 1;
|
||||
this.getInterviewSubjectList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 筛选列表数据
|
||||
* @param {*} id
|
||||
*/
|
||||
handleChangeSelect = (id) => {
|
||||
this.difficulty = id;
|
||||
this.pageIndex = 1;
|
||||
this.getInterviewSubjectList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 分页功能
|
||||
* @param {*} pageIndex 当前页码
|
||||
*/
|
||||
onChangePagination = (pageIndex) => {
|
||||
this.pageIndex = pageIndex;
|
||||
this.getInterviewSubjectList();
|
||||
};
|
||||
|
||||
render() {
|
||||
const { firstCategoryList, questionList, isShowSpin } = this.state;
|
||||
return (
|
||||
<div className="question-bank-box">
|
||||
<Spin spinning={isShowSpin}>
|
||||
<div className="question-box">
|
||||
<div className="category-list-box">
|
||||
{firstCategoryList?.length > 0 && (
|
||||
<CategoryList
|
||||
onChangeCategory={this.onChangeCategory}
|
||||
categoryList={firstCategoryList}
|
||||
onChangeLabel={this.onChangeLabel}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="question-list-box">
|
||||
<QuestionList
|
||||
pageIndex={this.pageIndex}
|
||||
total={this.total}
|
||||
questionList={questionList}
|
||||
handleChangeSelect={this.handleChangeSelect}
|
||||
onChangePagination={this.onChangePagination}
|
||||
difficulty={this.difficulty}
|
||||
primaryCategoryId={this.primaryCategoryId}
|
||||
labelList={this.labelList}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
<div className="ranking-box">
|
||||
<ContributionList />
|
||||
<RankingList />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
580
src/views/question-bank/mock.ts
Normal file
580
src/views/question-bank/mock.ts
Normal file
@@ -0,0 +1,580 @@
|
||||
export const mockRankingModuleList = [
|
||||
{
|
||||
id: 1,
|
||||
title: '综合练习榜',
|
||||
rankingList: [
|
||||
{
|
||||
id: 1,
|
||||
wechatName: 'jcdw',
|
||||
headImg:
|
||||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg1.doubanio.com%2Fview%2Fnote%2Flarge%2Fpublic%2Fp37015927.jpg&refer=http%3A%2F%2Fimg1.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1699286185&t=00db8ff5a1e11783f6c8eba954a5891f',
|
||||
name: '鸡翅大王1',
|
||||
count: 160,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
wechatName: 'jcdw1',
|
||||
headImg:
|
||||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg1.doubanio.com%2Fview%2Fnote%2Flarge%2Fpublic%2Fp37015927.jpg&refer=http%3A%2F%2Fimg1.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1699286185&t=00db8ff5a1e11783f6c8eba954a5891f',
|
||||
name: '鸡翅大王2',
|
||||
count: 140,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
wechatName: 'jcdw2',
|
||||
headImg:
|
||||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg1.doubanio.com%2Fview%2Fnote%2Flarge%2Fpublic%2Fp37015927.jpg&refer=http%3A%2F%2Fimg1.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1699286185&t=00db8ff5a1e11783f6c8eba954a5891f',
|
||||
name: '鸡翅大王',
|
||||
count: 101,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
wechatName: 'jcdw3',
|
||||
headImg:
|
||||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg1.doubanio.com%2Fview%2Fnote%2Flarge%2Fpublic%2Fp37015927.jpg&refer=http%3A%2F%2Fimg1.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1699286185&t=00db8ff5a1e11783f6c8eba954a5891f',
|
||||
name: '鸡翅小王',
|
||||
count: 100,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
wechatName: 'jcdw4',
|
||||
headImg:
|
||||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg1.doubanio.com%2Fview%2Fnote%2Flarge%2Fpublic%2Fp37015927.jpg&refer=http%3A%2F%2Fimg1.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1699286185&t=00db8ff5a1e11783f6c8eba954a5891f',
|
||||
name: '鸡翅大王5',
|
||||
count: 99,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '贡献榜',
|
||||
rankingList: [
|
||||
{
|
||||
id: 1,
|
||||
wechatName: 'jcdw5',
|
||||
headImg:
|
||||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg1.doubanio.com%2Fview%2Fnote%2Flarge%2Fpublic%2Fp37015927.jpg&refer=http%3A%2F%2Fimg1.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1699286185&t=00db8ff5a1e11783f6c8eba954a5891f',
|
||||
name: '鸡翅小王',
|
||||
count: 160,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
wechatName: 'jcdw6',
|
||||
headImg:
|
||||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg1.doubanio.com%2Fview%2Fnote%2Flarge%2Fpublic%2Fp37015927.jpg&refer=http%3A%2F%2Fimg1.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1699286185&t=00db8ff5a1e11783f6c8eba954a5891f',
|
||||
name: '鸡翅大王2',
|
||||
count: 150,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
wechatName: 'jcdw7',
|
||||
headImg:
|
||||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg1.doubanio.com%2Fview%2Fnote%2Flarge%2Fpublic%2Fp37015927.jpg&refer=http%3A%2F%2Fimg1.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1699286185&t=00db8ff5a1e11783f6c8eba954a5891f',
|
||||
name: '鸡翅大王',
|
||||
count: 101,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
wechatName: 'jcdw8',
|
||||
headImg:
|
||||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg1.doubanio.com%2Fview%2Fnote%2Flarge%2Fpublic%2Fp37015927.jpg&refer=http%3A%2F%2Fimg1.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1699286185&t=00db8ff5a1e11783f6c8eba954a5891f',
|
||||
name: '鸡翅大王4',
|
||||
count: 100,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
wechatName: 'jcdw9',
|
||||
headImg:
|
||||
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg1.doubanio.com%2Fview%2Fnote%2Flarge%2Fpublic%2Fp37015927.jpg&refer=http%3A%2F%2Fimg1.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1699286185&t=00db8ff5a1e11783f6c8eba954a5891f',
|
||||
name: '鸡翅大王5',
|
||||
count: 99,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const mockDataList = [
|
||||
{
|
||||
questionTitle: '什么是防抖和节流?有什么区别?如何实现',
|
||||
tags: [
|
||||
{ name: '排序', id: 590 },
|
||||
{ name: '数学', id: 5050 },
|
||||
{ name: '穷举', id: 596 },
|
||||
{ name: '贪心', id: 592 },
|
||||
{ name: '二分', id: 5058 },
|
||||
],
|
||||
id: 0,
|
||||
grade: 1,
|
||||
questionType: 6,
|
||||
difficulty: 1
|
||||
},
|
||||
{
|
||||
questionTitle: '非空数组,某元素只出现1次,其余出现2次,找到出现1次的元素',
|
||||
tags: [
|
||||
{ name: '数学', id: 5050 },
|
||||
{ name: '穷举', id: 596 },
|
||||
],
|
||||
id: 1,
|
||||
grade: 2,
|
||||
questionType: 6,
|
||||
difficulty: 1
|
||||
},
|
||||
{
|
||||
questionTitle: 'Proxy、Observable的区别',
|
||||
tags: [
|
||||
{ name: '贪心', id: 592 },
|
||||
{ name: '二分', id: 5058 },
|
||||
],
|
||||
id: 2,
|
||||
grade: 3,
|
||||
questionType: 3,
|
||||
},
|
||||
{
|
||||
questionTitle: '谈谈浏览器的回流与重绘,如何优化dom渲染呢',
|
||||
tags: [
|
||||
{ name: '字符串', id: 579 },
|
||||
{ name: '模拟', id: 595 },
|
||||
],
|
||||
id: 3,
|
||||
grade: 1,
|
||||
questionType: 1,
|
||||
},
|
||||
{
|
||||
questionTitle: 'API指标有哪些,为什么有白屏现象,考虑哪些方向优化',
|
||||
tags: [
|
||||
{ name: '字符串', id: 579 },
|
||||
{ name: '模拟', id: 595 },
|
||||
],
|
||||
id: 4,
|
||||
grade: 2,
|
||||
questionType: 4,
|
||||
},
|
||||
{
|
||||
questionTitle: '将两个升序链表合并为一个新的升序链表并返回',
|
||||
tags: [{ name: '数学', id: 5050 }],
|
||||
id: 5,
|
||||
grade: 1,
|
||||
questionType: 2,
|
||||
},
|
||||
{
|
||||
questionTitle: '对MVP架构的理解',
|
||||
tags: [
|
||||
{ name: '递归', id: 591 },
|
||||
{ name: '动态规划', id: 593 },
|
||||
],
|
||||
id: 6,
|
||||
grade: 3,
|
||||
questionType: 5,
|
||||
},
|
||||
{
|
||||
questionTitle: 'SPA页面的前端路由实现方案',
|
||||
tags: [
|
||||
{ name: '排序', id: 590 },
|
||||
{ name: '数组', id: 578 },
|
||||
],
|
||||
id: 7,
|
||||
grade: 2,
|
||||
questionType: 1,
|
||||
},
|
||||
{
|
||||
questionTitle: '怎么看 nodejs 可支持高并发',
|
||||
tags: [
|
||||
{ name: '数学', id: 5050 },
|
||||
{ name: '模拟', id: 595 },
|
||||
],
|
||||
id: 8,
|
||||
grade: 2,
|
||||
questionType: 2,
|
||||
},
|
||||
{
|
||||
questionTitle: '二叉树遍历',
|
||||
tags: [
|
||||
{ name: '树', id: 583 },
|
||||
{ name: '搜索', id: 3381 },
|
||||
],
|
||||
id: 9,
|
||||
grade: 3,
|
||||
questionType: 4,
|
||||
},
|
||||
{
|
||||
questionTitle: '玛雅人的密码',
|
||||
tags: [
|
||||
{ name: '图', id: 584 },
|
||||
{ name: '搜索', id: 3381 },
|
||||
],
|
||||
id: 10,
|
||||
grade: 1,
|
||||
questionType: 3,
|
||||
},
|
||||
{ questionTitle: '求最大最小数', tags: [], id: 11, grade: 1, questionType: 1 },
|
||||
{
|
||||
questionTitle: '最小邮票数',
|
||||
tags: [{ name: '动态规划', id: 593 }],
|
||||
id: 12,
|
||||
grade: 1,
|
||||
questionType: 1,
|
||||
},
|
||||
{ questionTitle: 'abc', tags: [{ name: '穷举', id: 596 }], id: 13, grade: 1, questionType: 5 },
|
||||
{
|
||||
questionTitle: '求root(N, k)',
|
||||
tags: [
|
||||
{ name: '递归', id: 591 },
|
||||
{ name: '数学', id: 5050 },
|
||||
{ name: '二分', id: 5058 },
|
||||
],
|
||||
id: 14,
|
||||
grade: 1,
|
||||
questionType: 3,
|
||||
},
|
||||
{
|
||||
questionTitle: 'n的阶乘',
|
||||
tags: [{ name: '数学', id: 5050 }],
|
||||
id: 15,
|
||||
grade: 1,
|
||||
questionType: 3,
|
||||
},
|
||||
{
|
||||
questionTitle: '特殊乘法',
|
||||
tags: [
|
||||
{ name: '模拟', id: 595 },
|
||||
{ name: '数组', id: 578 },
|
||||
{ name: '数学', id: 5050 },
|
||||
],
|
||||
id: 16,
|
||||
grade: 1,
|
||||
questionType: 3,
|
||||
},
|
||||
{
|
||||
questionTitle: '今年的第几天?',
|
||||
tags: [
|
||||
{ name: '递归', id: 591 },
|
||||
{ name: '数学', id: 5050 },
|
||||
{ name: '穷举', id: 596 },
|
||||
],
|
||||
id: 17,
|
||||
grade: 1,
|
||||
questionType: 2,
|
||||
},
|
||||
{
|
||||
questionTitle: '完数VS盈数',
|
||||
tags: [{ name: '数学', id: 5050 }],
|
||||
id: 18,
|
||||
grade: 1,
|
||||
questionType: 3,
|
||||
},
|
||||
{
|
||||
questionTitle: '递推数列',
|
||||
tags: [
|
||||
{ name: '动态规划', id: 593 },
|
||||
{ name: '数学', id: 5050 },
|
||||
],
|
||||
id: 19,
|
||||
grade: 1,
|
||||
questionType: 1,
|
||||
},
|
||||
{ questionTitle: '最大序列和', tags: [{ name: '动态规划', id: 593 }], id: 20, grade: 1 },
|
||||
{
|
||||
questionTitle: '最小花费',
|
||||
tags: [
|
||||
{ name: '动态规划', id: 593 },
|
||||
{ name: '图', id: 584 },
|
||||
],
|
||||
id: 21,
|
||||
grade: 1,
|
||||
questionType: 2,
|
||||
},
|
||||
{ questionTitle: 'N的阶乘', tags: [{ name: '数学', id: 5050 }], id: 22, grade: 1 },
|
||||
{
|
||||
questionTitle: '剩下的树',
|
||||
tags: [
|
||||
{ name: '数组', id: 578 },
|
||||
{ name: '数学', id: 5050 },
|
||||
{ name: '哈希', id: 585 },
|
||||
{ name: '栈', id: 581 },
|
||||
],
|
||||
id: 23,
|
||||
grade: 1,
|
||||
questionType: 5,
|
||||
},
|
||||
{
|
||||
questionTitle: '10进制 VS 2进制',
|
||||
tags: [
|
||||
{ name: '数学', id: 5050 },
|
||||
{ name: '位运算', id: 5074 },
|
||||
],
|
||||
id: 24,
|
||||
grade: 1,
|
||||
questionType: 3,
|
||||
},
|
||||
{
|
||||
questionTitle: '查找学生信息',
|
||||
tags: [
|
||||
{ name: '数组', id: 578 },
|
||||
{ name: '模拟', id: 595 },
|
||||
],
|
||||
id: 25,
|
||||
grade: 1,
|
||||
questionType: 2,
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 一级分类
|
||||
*/
|
||||
export const mockTabList = [
|
||||
{ id: 1, levelName: '全部', count: 100 },
|
||||
{ id: 2, levelName: '前端', count: 1001 },
|
||||
{ id: 3, levelName: '后端', count: 1005 },
|
||||
{ id: 4, levelName: '测试', count: 1100 },
|
||||
{ id: 5, levelName: '人工智能', count: 1200 },
|
||||
{ id: 6, levelName: '产品', count: 1 },
|
||||
{ id: 7, levelName: '视觉', count: 100 },
|
||||
{ id: 8, levelName: '产品', count: 1 },
|
||||
{ id: 9, levelName: '视觉', count: 100 },
|
||||
{ id: 10, levelName: '产品', count: 1 },
|
||||
{ id: 11, levelName: '视觉', count: 100 },
|
||||
];
|
||||
|
||||
// 二级数据
|
||||
export const mockCategoryList = {
|
||||
// 全部
|
||||
1: [
|
||||
{
|
||||
id: 1,
|
||||
levelName: '算法',
|
||||
childrenLevelList: [
|
||||
{ id: 1, levelName: '双指针', count: 107 },
|
||||
{ id: 2, levelName: '同向双指针', count: 57 },
|
||||
{ id: 3, levelName: '相向双指针', count: 31 },
|
||||
{ id: 4, levelName: '二分法', count: 95 },
|
||||
{ id: 5, levelName: '二分答案', count: 28 },
|
||||
{ id: 6, levelName: '分治法', count: 77 },
|
||||
{ id: 7, levelName: '宽度优先搜索', count: 135 },
|
||||
{ id: 8, levelName: '深度优先搜索/回溯法', count: 10 },
|
||||
{ id: 9, levelName: '背包型动态规划', count: 224 },
|
||||
{ id: 10, levelName: '状态压缩动态规划', count: 240 },
|
||||
{ id: 11, levelName: '拓扑排序', count: 28 },
|
||||
{ id: 12, levelName: '坐标型动态规划', count: 40 },
|
||||
{ id: 13, levelName: '划分型动态规划', count: 15 },
|
||||
{ id: 14, levelName: '记忆化搜索', count: 23 },
|
||||
{ id: 15, levelName: '区间型动态规划', count: 22 },
|
||||
{ id: 16, levelName: '动态规划', count: 3 },
|
||||
{ id: 17, levelName: '博弈型动态规划', count: 4 },
|
||||
{ id: 18, levelName: '匹配型动态规划', count: 15 },
|
||||
{ id: 19, levelName: '树型动态规划', count: 4 },
|
||||
{ id: 20, levelName: '排序算法', count: 83 },
|
||||
{ id: 21, levelName: '外排序算法', count: 2 },
|
||||
{ id: 22, levelName: '快速选择算法', count: 12 },
|
||||
{ id: 23, levelName: '欧拉路径', count: 1 },
|
||||
{ id: 24, levelName: '模拟法', count: 282 },
|
||||
{ id: 25, levelName: '扫描线算法', count: 19 },
|
||||
{ id: 26, levelName: '枚举法', count: 109 },
|
||||
{ id: 27, levelName: '最短路', count: 6 },
|
||||
{ id: 28, levelName: '贪心法', count: 85 },
|
||||
{ id: 29, levelName: '最小生成树', count: 3 },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
levelName: '数据结构',
|
||||
childrenLevelList: [
|
||||
{ id: 1, levelName: '数组', count: 179 },
|
||||
{ id: 2, levelName: '前缀和数组', count: 41 },
|
||||
{ id: 3, levelName: '字符串', count: 257 },
|
||||
{ id: 4, levelName: '链表', count: 52 },
|
||||
{ id: 5, levelName: '双向链表', count: 1 },
|
||||
{ id: 6, levelName: '队列', count: 18 },
|
||||
{ id: 7, levelName: '单调队列', count: 3 },
|
||||
{ id: 8, levelName: '双向队列', count: 3 },
|
||||
{ id: 9, levelName: '栈', count: 74 },
|
||||
{ id: 10, levelName: '单调栈', count: 27 },
|
||||
{ id: 11, levelName: '二叉树', count: 120 },
|
||||
{ id: 12, levelName: '树', count: 5 },
|
||||
{ id: 13, levelName: '二叉搜索树', count: 30 },
|
||||
{ id: 14, levelName: '迭代器', count: 6 },
|
||||
{ id: 15, levelName: '堆', count: 45 },
|
||||
{ id: 16, levelName: '图', count: 17 },
|
||||
{ id: 17, levelName: '二分图', count: 5 },
|
||||
{ id: 18, levelName: '哈希表', count: 156 },
|
||||
{ id: 19, levelName: '字典树', count: 19 },
|
||||
{ id: 20, levelName: '并查集', count: 36 },
|
||||
{ id: 21, levelName: '树状数组', count: 7 },
|
||||
{ id: 22, levelName: '线段树', count: 21 },
|
||||
{ id: 23, levelName: '平衡树', count: 7 },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
levelName: 'SQL 基础语法',
|
||||
childrenLevelList: [
|
||||
{ id: 1, levelName: '比较运算符', count: 52 },
|
||||
{ id: 2, levelName: '嵌套查询', count: 35 },
|
||||
{ id: 3, levelName: '基础语法', count: 27 },
|
||||
{ id: 4, levelName: '逻辑运算符', count: 25 },
|
||||
{ id: 5, levelName: 'GROUP BY', count: 18 },
|
||||
{ id: 6, levelName: '算术运算符', count: 17 },
|
||||
{ id: 7, levelName: 'IN', count: 17 },
|
||||
{ id: 8, levelName: 'ORDER BY', count: 16 },
|
||||
{ id: 9, levelName: 'AS', count: 15 },
|
||||
{ id: 10, levelName: 'HAVING', count: 8 },
|
||||
{ id: 11, levelName: 'SELECT', count: 7 },
|
||||
{ id: 12, levelName: 'DISTINCT', count: 6 },
|
||||
{ id: 13, levelName: 'LIKE', count: 5 },
|
||||
{ id: 14, levelName: 'LIMIT', count: 4 },
|
||||
{ id: 15, levelName: 'IS NULL', count: 4 },
|
||||
{ id: 16, levelName: 'UNION', count: 3 },
|
||||
{ id: 17, levelName: '约束', count: 3 },
|
||||
{ id: 18, levelName: 'IFNULL/COLLAPSE', count: 2 },
|
||||
{ id: 19, levelName: 'ANY', count: 2 },
|
||||
{ id: 20, levelName: 'ALL', count: 2 },
|
||||
],
|
||||
},
|
||||
],
|
||||
// 前端
|
||||
2: [
|
||||
{
|
||||
id: 1,
|
||||
levelName: '移动端',
|
||||
childrenLevelList: [
|
||||
{
|
||||
id: 1,
|
||||
levelName: 'IOSIOSIOSIOS',
|
||||
count: 13,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
levelName: '安卓',
|
||||
count: 130,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
levelName: '鸿蒙',
|
||||
count: 134,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
levelName: '框架',
|
||||
childrenLevelList: [
|
||||
{
|
||||
id: 1,
|
||||
levelName: 'Vue.js',
|
||||
count: 13,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
levelName: 'React.js',
|
||||
count: 13,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
levelName: 'Bootstrap',
|
||||
count: 13,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
levelName: '小程序',
|
||||
childrenLevelList: [
|
||||
{ id: 1, levelName: '微信小程序', count: 13 },
|
||||
{ id: 2, levelName: '京东小程序', count: 13 },
|
||||
{ id: 3, levelName: '支付宝小程序', count: 13 },
|
||||
{ id: 4, levelName: '百度小程序', count: 13 },
|
||||
{ id: 5, levelName: 'QQ小程序', count: 13 },
|
||||
],
|
||||
},
|
||||
],
|
||||
// 后端
|
||||
3: [
|
||||
{
|
||||
id: 1,
|
||||
levelName: '框架',
|
||||
childrenLevelList: [
|
||||
{
|
||||
id: 1,
|
||||
levelName: 'Spring框架',
|
||||
count: 17,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
levelName: 'Struts框架',
|
||||
count: 127,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
levelName: 'Hibernate框架',
|
||||
count: 170,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
levelName: 'SSM框架组合',
|
||||
childrenLevelList: [
|
||||
{
|
||||
id: 1,
|
||||
levelName: 'SpringMVC框架',
|
||||
count: 170,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
levelName: 'Mybatis框架',
|
||||
count: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
// 测试
|
||||
4: [
|
||||
{
|
||||
id: 1,
|
||||
levelName: '自动化测试',
|
||||
childrenLevelList: [
|
||||
{
|
||||
id: 1,
|
||||
levelName: '管理工具',
|
||||
count: 16,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
levelName: 'UI自动化',
|
||||
count: 16,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
levelName: '接口自动化',
|
||||
count: 16,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
// 人工智能
|
||||
5: [
|
||||
{
|
||||
id: 1,
|
||||
levelName: '数据处理',
|
||||
childrenLevelList: [
|
||||
{ id: 1, levelName: '工具库', count: 107 },
|
||||
{ id: 2, levelName: '数据预处理', count: 127 },
|
||||
{ id: 3, levelName: 'Numpy', count: 170 },
|
||||
{ id: 4, levelName: 'Matplotlib', count: 170 },
|
||||
{ id: 5, levelName: 'Pandas', count: 170 },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
levelName: '机器学习',
|
||||
childrenLevelList: [
|
||||
{ id: 1, levelName: '工具库', count: 170 },
|
||||
{ id: 2, levelName: '分类', count: 1 },
|
||||
{ id: 3, levelName: '模型', count: 170 },
|
||||
{ id: 4, levelName: '决策树', count: 170 },
|
||||
],
|
||||
},
|
||||
],
|
||||
// 产品
|
||||
6: [],
|
||||
// 视觉
|
||||
7: [],
|
||||
};
|
@@ -1,10 +0,0 @@
|
||||
const UploadExam = () => {
|
||||
return (
|
||||
<div>
|
||||
upload exam
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export default UploadExam
|
360
src/views/upload-questions/components/brief-questions/index.jsx
Normal file
360
src/views/upload-questions/components/brief-questions/index.jsx
Normal file
@@ -0,0 +1,360 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { Input, Modal, message, Spin } from 'antd';
|
||||
|
||||
import req from '@utils/request';
|
||||
import { debounce } from '@utils';
|
||||
import KindEditor from '../kind-editor';
|
||||
import RankLabelBox from '../rank-label-box';
|
||||
import RepeatContentBox from '../repeat-content-box';
|
||||
import { apiName } from '../../constant';
|
||||
import './index.less';
|
||||
|
||||
export default class BriefQuestions extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
subjectName: '', // 题目
|
||||
isDisabledSubmit: true, //是否禁止输入
|
||||
isShowModalBox: false, // 是否展示重复率弹框
|
||||
isSubmit: true, // 是否支持提交
|
||||
};
|
||||
}
|
||||
kindEditor = KindEditor | null;
|
||||
rankLabelBox = RankLabelBox | null;
|
||||
rankId = 1; //职级
|
||||
subjectAnswer = ''; // 答案
|
||||
firstCategoryValue = ''; // 一级分类的值
|
||||
secondCategoryValue = []; // 二级分类的值
|
||||
thirdCategoryValue = []; // 三级标签的值
|
||||
repeatInfo = {}; // 重复率
|
||||
|
||||
/**
|
||||
* 输入题目
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectName = (e) => {
|
||||
let str = e.target.value.trim();
|
||||
this.setState(
|
||||
{
|
||||
subjectName: str,
|
||||
},
|
||||
() => {
|
||||
this.rankLabelBox.getThirdCategoryList();
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 富文本编辑器
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeEditor = (e) => {
|
||||
this.subjectAnswer = e;
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 一次确认录入
|
||||
*/
|
||||
onSubmit = debounce(() => {
|
||||
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,
|
||||
difficulty: this.rankId,
|
||||
subjectType: 4,
|
||||
subjectScore: 1,
|
||||
subjectAnswer: this.subjectAnswer,
|
||||
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, // 重复率
|
||||
repeatSubjectName: res.data.subjectName, // 重复题目
|
||||
repeatSubjectAnswe: res.data.subjectAnswer, // 重复答案
|
||||
repeatSetterErp: res.data.subjectSetterErp, // 出题人erp
|
||||
repeatSetterName: res.data.subjectSetterName, // 出题人姓名
|
||||
};
|
||||
this.setState({
|
||||
isShowModalBox: true,
|
||||
isSubmit: true,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
isSubmit: true,
|
||||
});
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
checkData = () => {
|
||||
const { subjectName } = this.state;
|
||||
let isDisabledSubmit = false;
|
||||
if (
|
||||
!!!subjectName ||
|
||||
!!!this.subjectAnswer ||
|
||||
!!!this.firstCategoryValue ||
|
||||
this.secondCategoryValue.length <= 0 ||
|
||||
this.thirdCategoryValue.length <= 0
|
||||
) {
|
||||
isDisabledSubmit = true;
|
||||
}
|
||||
return isDisabledSubmit;
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
onCancel = () => {
|
||||
this.subjectAnswer = ''; // 答案
|
||||
this.rankId = 1;
|
||||
this.firstCategoryValue = '';
|
||||
this.secondCategoryValue = [];
|
||||
this.thirdCategoryValue = [];
|
||||
this.repeatInfo = {};
|
||||
this.kindEditor.onClear();
|
||||
this.rankLabelBox.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 = '/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,
|
||||
});
|
||||
};
|
||||
|
||||
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
|
||||
ref={(ref) => {
|
||||
this.rankLabelBox = ref;
|
||||
}}
|
||||
subjectName={subjectName}
|
||||
onChangeRankLabel={this.onChangeRankLabel}
|
||||
handleChangeRank={this.handleChangeRank}
|
||||
/>
|
||||
<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">
|
||||
<KindEditor
|
||||
onChange={this.onChangeEditor}
|
||||
ref={(ref) => {
|
||||
this.kindEditor = ref;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
@@ -0,0 +1,58 @@
|
||||
.brief-questions-container {
|
||||
width: 1000px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
padding-top: 36px;
|
||||
.brief-questions-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: 140px;
|
||||
line-height: 40px;
|
||||
font-size: 16px;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
&:before {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
margin-top: 1px;
|
||||
color: #f5222d;
|
||||
font-size: 16px;
|
||||
content: '*';
|
||||
}
|
||||
}
|
||||
.brief-questions-main {
|
||||
width: 100%;
|
||||
// 题目输入框
|
||||
.brief-questions-input {
|
||||
height: 48px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.brief-questions-btns-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin: 20px auto;
|
||||
width: 952px;
|
||||
.brief-questions-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.brief-questions-submit {
|
||||
margin-left: 40px;
|
||||
background-color: #4390f7;
|
||||
color: #fff;
|
||||
border: 1px solid #4390f7;
|
||||
}
|
||||
.brief-questions-disabled-submit {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
327
src/views/upload-questions/components/judge-questions/index.jsx
Normal file
327
src/views/upload-questions/components/judge-questions/index.jsx
Normal file
@@ -0,0 +1,327 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { Input, Modal, message, Spin } from 'antd';
|
||||
import req from '@utils/request';
|
||||
import { debounce } from '@utils';
|
||||
import RankLabelBox from '../rank-label-box';
|
||||
import OptionInputBox from '../option-input-box';
|
||||
import RepeatContentBox from '../repeat-content-box';
|
||||
import { apiName } from '../../constant';
|
||||
import './index.less';
|
||||
export default class JudgeQuestions extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
subjectName: '', // 题目
|
||||
isDisabledSubmit: true, //是否禁止输入
|
||||
isShowModalBox: false, // 是否展示重复率弹框
|
||||
isSubmit: true, // 是否支持提交
|
||||
};
|
||||
}
|
||||
rankLabelBox = RankLabelBox | null;
|
||||
optionInputBox = OptionInputBox | null;
|
||||
currentActive = []; // 当前选中的项
|
||||
scoreValue = ''; // 分数
|
||||
subjectAnalysis = ''; //试题解析
|
||||
rankId = 1; //职级
|
||||
firstCategoryValue = ''; // 一级分类的值
|
||||
secondCategoryValue = []; // 二级分类的值
|
||||
thirdCategoryValue = []; // 三级标签的值
|
||||
repeatInfo = {}; // 重复率
|
||||
|
||||
/**
|
||||
* 输入题目
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectName = (e) => {
|
||||
let str = e.target.value.trim();
|
||||
this.setState(
|
||||
{
|
||||
subjectName: str,
|
||||
},
|
||||
() => {
|
||||
this.rankLabelBox.getThirdCategoryList();
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 一次确认录入
|
||||
*/
|
||||
onSubmit = debounce(() => {
|
||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state;
|
||||
if (isDisabledSubmit || !isSubmit) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
isSubmit: false,
|
||||
});
|
||||
let params = {
|
||||
subjectName: subjectName,
|
||||
difficulty: this.rankId,
|
||||
subjectType: 3,
|
||||
subjectScore: this.scoreValue,
|
||||
subjectParse: this.subjectAnalysis,
|
||||
isCorrect: this.currentActive[0],
|
||||
categoryIds: this.secondCategoryValue,
|
||||
labelIds: this.thirdCategoryValue,
|
||||
};
|
||||
console.log('判断录入 ----', params);
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addInterviewSubject,
|
||||
})
|
||||
.then((res) => {
|
||||
this.repeatInfo = {};
|
||||
if (res.data && res.data.insertStatus) {
|
||||
this.setState(
|
||||
{
|
||||
isSubmit: true,
|
||||
},
|
||||
() => {
|
||||
this.successModalConfirm();
|
||||
}
|
||||
);
|
||||
} else if (!res.data.insertStatus) {
|
||||
this.repeatInfo = {
|
||||
repeatDocId: res.data.docId, // 重复题目id
|
||||
repeatRate: res.data.repeatRate, // 重复率
|
||||
repeatIsCorrect: res.data.isCorrect, // 答案
|
||||
repeatSubjectName: res.data.subjectName, // 重复题目
|
||||
repeatSetterErp: res.data.subjectSetterErp, // 出题人erp
|
||||
repeatSetterName: res.data.subjectSetterName, // 出题人姓名
|
||||
};
|
||||
this.setState({
|
||||
isShowModalBox: true,
|
||||
isSubmit: true,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
isSubmit: true,
|
||||
});
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
checkData = () => {
|
||||
const { subjectName } = this.state;
|
||||
let isDisabledSubmit = false;
|
||||
if (
|
||||
!!!subjectName ||
|
||||
this.currentActive?.length <= 0 ||
|
||||
!!!this.firstCategoryValue ||
|
||||
this.secondCategoryValue.length <= 0 ||
|
||||
this.thirdCategoryValue.length <= 0 ||
|
||||
!!!this.scoreValue
|
||||
) {
|
||||
isDisabledSubmit = true;
|
||||
}
|
||||
return isDisabledSubmit;
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
onCancel = () => {
|
||||
this.currentActive = []; // 选项列表
|
||||
this.scoreValue = ''; // 分数
|
||||
this.subjectAnalysis = ''; //试题解析
|
||||
this.rankId = 1;
|
||||
this.firstCategoryValue = ''; // 一级分类的值
|
||||
this.secondCategoryValue = []; // 二级分类的值
|
||||
this.thirdCategoryValue = []; // 三级标签的值
|
||||
this.repeatInfo = {};
|
||||
this.rankLabelBox.initRankLabel();
|
||||
this.optionInputBox.handleClearOption();
|
||||
this.setState({
|
||||
subjectName: '',
|
||||
isShowModalBox: false,
|
||||
isSubmit: true, // 是否支持提交
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 重复率弹框-确认录入
|
||||
*/
|
||||
onSubmitRepeatModal = debounce(
|
||||
() => {
|
||||
let params = {
|
||||
docId: this.repeatInfo.repeatDocId,
|
||||
};
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addRepeatInterviewSubject,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
this.successModalConfirm();
|
||||
} else {
|
||||
message.info('请再次确认');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
message.error('请再次确认');
|
||||
});
|
||||
},
|
||||
300,
|
||||
true
|
||||
);
|
||||
|
||||
/**
|
||||
* 重复率弹框-取消录入
|
||||
*/
|
||||
onCancelRepeatModal = () => {
|
||||
this.repeatInfo = {};
|
||||
this.setState({
|
||||
isShowModalBox: false,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功的弹框
|
||||
*/
|
||||
successModalConfirm = () => {
|
||||
Modal.confirm({
|
||||
title: (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: 'rgba(60, 110, 238, 1)',
|
||||
fontSize: 16,
|
||||
}}>
|
||||
录入成功!贡献榜火力值 + 1
|
||||
</div>
|
||||
),
|
||||
closable: false,
|
||||
maskClosable: false,
|
||||
icon: ' ',
|
||||
onOk: this.onAgainSuccessModal,
|
||||
onCancel: this.onGoHomeSuccessModal,
|
||||
okText: '再录一题',
|
||||
cancelText: '去首页',
|
||||
className: 'questions-success-modal-confirm',
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-再来一题
|
||||
*/
|
||||
onAgainSuccessModal = () => {
|
||||
this.onCancel();
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-去首页
|
||||
*/
|
||||
onGoHomeSuccessModal = () => {
|
||||
// this.onCancel();
|
||||
window.location.href = '/cms-supplier/question-bank';
|
||||
};
|
||||
|
||||
/**
|
||||
* 分类选择
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeRankLabel = (firstCategoryValue, secondCategoryValue, thirdCategoryValue) => {
|
||||
this.firstCategoryValue = firstCategoryValue; // 一级分类的值
|
||||
this.secondCategoryValue = secondCategoryValue; // 二级分类的值
|
||||
this.thirdCategoryValue = thirdCategoryValue; // 三级标签的值
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 职级选择
|
||||
* @param {*} list
|
||||
*/
|
||||
handleChangeRank = (list) => {
|
||||
this.rankId = list[0];
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 选项操作
|
||||
* @param {*} currentActive 选项列表
|
||||
* @param {*} scoreValue 分值
|
||||
* @param {*} subjectAnalysis 解析
|
||||
*/
|
||||
handleChangeOption = (currentActive, scoreValue, subjectAnalysis) => {
|
||||
this.currentActive = currentActive;
|
||||
this.scoreValue = scoreValue;
|
||||
this.subjectAnalysis = subjectAnalysis;
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { subjectName, isDisabledSubmit, isSubmit, isShowModalBox } = this.state;
|
||||
const { questionsType } = this.props;
|
||||
return (
|
||||
<Spin spinning={!isSubmit}>
|
||||
<Fragment>
|
||||
<div className="judge-questions-container">
|
||||
<div className="judge-questions-title">题目名称:</div>
|
||||
<Input
|
||||
placeholder="输入题目"
|
||||
style={{ height: 48, width: '100%' }}
|
||||
value={subjectName}
|
||||
maxLength={64}
|
||||
onChange={(e) => this.onChangeSubjectName(e)}
|
||||
/>
|
||||
</div>
|
||||
<OptionInputBox
|
||||
ref={(ref) => {
|
||||
this.optionInputBox = ref;
|
||||
}}
|
||||
isJudge={true}
|
||||
handleChangeOption={this.handleChangeOption}
|
||||
/>
|
||||
<RankLabelBox
|
||||
ref={(ref) => {
|
||||
this.rankLabelBox = ref;
|
||||
}}
|
||||
subjectName={subjectName}
|
||||
onChangeRankLabel={this.onChangeRankLabel}
|
||||
handleChangeRank={this.handleChangeRank}
|
||||
/>
|
||||
<div className="judge-questions-btns-container">
|
||||
<div className="judge-questions-btn" onClick={this.onCancel}>
|
||||
清空
|
||||
</div>
|
||||
<div
|
||||
className={`judge-questions-btn judge-questions-submit ${isDisabledSubmit && 'judge-questions-disabled-submit'
|
||||
}`}
|
||||
onClick={this.onSubmit}>
|
||||
提交
|
||||
</div>
|
||||
</div>
|
||||
<RepeatContentBox
|
||||
isShowModalBox={isShowModalBox}
|
||||
repeatQuestionsType={questionsType}
|
||||
repeatInfo={this.repeatInfo}
|
||||
handleSubmitRepeatModal={this.onSubmitRepeatModal}
|
||||
handleCancelRepeatModal={this.onCancelRepeatModal}
|
||||
/>
|
||||
</Fragment>
|
||||
</Spin>
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
.judge-questions-container {
|
||||
width: 1000px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
padding-top: 36px;
|
||||
// label名字title
|
||||
.judge-questions-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: 140px;
|
||||
line-height: 40px;
|
||||
font-size: 16px;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
&:before {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
margin-top: 1px;
|
||||
color: #f5222d;
|
||||
font-size: 16px;
|
||||
content: '*';
|
||||
}
|
||||
}
|
||||
}
|
||||
.judge-questions-btns-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin: 20px auto;
|
||||
width: 952px;
|
||||
.judge-questions-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.judge-questions-submit {
|
||||
margin-left: 40px;
|
||||
background-color: #4390f7;
|
||||
color: #fff;
|
||||
border: 1px solid #4390f7;
|
||||
}
|
||||
.judge-questions-disabled-submit {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
153
src/views/upload-questions/components/kind-editor/index.jsx
Normal file
153
src/views/upload-questions/components/kind-editor/index.jsx
Normal file
@@ -0,0 +1,153 @@
|
||||
import React, { Component } from 'react';
|
||||
import './index.less';
|
||||
|
||||
import Editor from 'wangeditor';
|
||||
|
||||
export default class KindEditor extends Component {
|
||||
defaultValueHead = `<div style='font-size:14px !important;line-height:22px !important;margin-bottom: -15px !important;word-break: break-word !important;'>`;
|
||||
defaultValueFoot = '</div>';
|
||||
editor = Editor;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { editorContent: '', isActive: false };
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空内容
|
||||
*/
|
||||
onClear = () => {
|
||||
this.editor.txt.clear();
|
||||
this.editor.config.focus = false;
|
||||
this.setState({
|
||||
isActive: false,
|
||||
editorContent: '',
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 回现代码
|
||||
*/
|
||||
onCashBack = () => {
|
||||
let { cashBackText } = this.props;
|
||||
if (!!!cashBackText) {
|
||||
return;
|
||||
}
|
||||
this.editor.txt.html(`${cashBackText}`);
|
||||
this.editor.config.focus = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获得焦点
|
||||
*/
|
||||
onFocus = () => {
|
||||
this.editor.config.focus = true;
|
||||
this.setState({
|
||||
isActive: true,
|
||||
});
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const elemMenu = this.refs.editorElemMenu;
|
||||
const elemBody = this.refs.editorElemBody;
|
||||
this.editor = new Editor(elemMenu, elemBody);
|
||||
// // 使用 onchange 函数监听内容的变化,并实时更新到 state 中
|
||||
this.editor.config.onchange = (html) => {
|
||||
let htmlStr = this.editor.txt.html();
|
||||
// console.log('htmlStr ---', htmlStr);
|
||||
if (htmlStr?.indexOf('<div style=') < 0) {
|
||||
htmlStr = this.defaultValueHead + htmlStr + this.defaultValueFoot;
|
||||
}
|
||||
let isActive = false;
|
||||
if (this.state.editorContent) {
|
||||
isActive = true;
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
// editorContent: editor.txt.text()
|
||||
editorContent: htmlStr,
|
||||
isActive: isActive,
|
||||
},
|
||||
() => {
|
||||
this.props.onChange(htmlStr);
|
||||
}
|
||||
);
|
||||
};
|
||||
this.editor.config.onfocus = () => {
|
||||
this.setState({
|
||||
isActive: true,
|
||||
});
|
||||
};
|
||||
this.editor.config.onblur = () => {
|
||||
this.setState({
|
||||
isActive: false,
|
||||
});
|
||||
};
|
||||
|
||||
this.editor.config.menus = [
|
||||
// 'head', // 标题
|
||||
// 'bold', // 粗体
|
||||
// 'fontSize', // 字号
|
||||
// 'fontName', // 字体
|
||||
// 'italic', // 斜体
|
||||
// 'underline', // 下划线
|
||||
// 'strikeThrough', // 删除线
|
||||
'foreColor', // 文字颜色
|
||||
// 'backColor', // 背景颜色
|
||||
// 'link', // 插入链接
|
||||
'list', // 列表
|
||||
// 'justify', // 对齐方式
|
||||
// 'quote', // 引用
|
||||
// 'emoticon', // 表情
|
||||
// 'image', // 插入图片
|
||||
// 'table', // 表格
|
||||
// 'video', // 插入视频
|
||||
'code', // 插入代码
|
||||
'undo', // 撤销
|
||||
// 'redo', // 重复
|
||||
];
|
||||
// this.editor.customConfig.uploadImgShowBase64 = true;
|
||||
// 取消自动 focus
|
||||
this.editor.config.focus = false;
|
||||
this.editor.config.pasteFilterStyle = true; // 样式过滤
|
||||
this.editor.config.pasteIgnoreImg = true; // 如果复制的内容有图片又有文字,则只粘贴文字,不粘贴图片
|
||||
this.editor.config.placeholder = '请输入';
|
||||
this.editor.create();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isActive } = this.state;
|
||||
const { bodyHeight, bodyWidth, borderRadius } = this.props;
|
||||
return (
|
||||
<div
|
||||
className={`text-area ${isActive && 'kind-editor-active-box'}`}
|
||||
style={{
|
||||
borderRadius: borderRadius,
|
||||
}}>
|
||||
<div
|
||||
ref="editorElemMenu"
|
||||
className="editorelem-menu"
|
||||
style={{
|
||||
width: bodyWidth,
|
||||
borderTopLeftRadius: borderRadius,
|
||||
borderTopRightRadius: borderRadius,
|
||||
}}></div>
|
||||
<div
|
||||
ref="editorElemBody"
|
||||
className="editorelem-body"
|
||||
style={{
|
||||
height: bodyHeight,
|
||||
width: bodyWidth,
|
||||
borderBottomLeftRadius: borderRadius,
|
||||
borderBottomRightRadius: borderRadius,
|
||||
}}></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
KindEditor.defaultProps = {
|
||||
bodyHeight: 320,
|
||||
bodyWidth: '100%',
|
||||
borderRadius: '4px',
|
||||
};
|
32
src/views/upload-questions/components/kind-editor/index.less
Normal file
32
src/views/upload-questions/components/kind-editor/index.less
Normal file
@@ -0,0 +1,32 @@
|
||||
.text-area {
|
||||
background-color: #fff;
|
||||
font-size: 14px;
|
||||
.editorelem-menu {
|
||||
border: 1px solid #d9d9d9;
|
||||
.w-e-menu-tooltip {
|
||||
padding: 0px 6px;
|
||||
line-height: 28px;
|
||||
}
|
||||
.w-e-toolbar {
|
||||
z-index: 2 !important;
|
||||
border-radius: 12px;
|
||||
}
|
||||
}
|
||||
.editorelem-body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 10px 10px;
|
||||
overflow-y: scroll;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-top: none;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
}
|
||||
.w-e-text-container {
|
||||
z-index: 1 !important;
|
||||
}
|
||||
.kind-editor-active-box {
|
||||
border: 1px solid #40a9ff;
|
||||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||||
}
|
@@ -0,0 +1,343 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { Input, Modal, message, Spin } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import req from '@utils/request';
|
||||
import { debounce } from '@utils';
|
||||
import KindEditor from '../kind-editor';
|
||||
import RankLabelBox from '../rank-label-box';
|
||||
import OptionInputBox from '../option-input-box';
|
||||
import RepeatContentBox from '../repeat-content-box';
|
||||
import { apiName } from '../../constant';
|
||||
import './index.less';
|
||||
|
||||
const defalutLabel = '请使用富文本编辑器输入选项内容';
|
||||
export default class MultipleQuestions extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
subjectName: '', // 题目
|
||||
isDisabledSubmit: true, //是否禁止输入
|
||||
isShowModalBox: false, // 是否展示重复率弹框
|
||||
isSubmit: true, // 是否支持提交
|
||||
};
|
||||
}
|
||||
kindEditor = KindEditor | null;
|
||||
rankLabelBox = RankLabelBox | null;
|
||||
optionInputBox = OptionInputBox | null;
|
||||
currentActive = []; // 选项列表
|
||||
scoreValue = ''; // 分数
|
||||
subjectAnalysis = ''; //试题解析
|
||||
rankId = 1; //职级
|
||||
subjectAnswer = ''; // 选项内容
|
||||
firstCategoryValue = ''; // 一级分类的值
|
||||
secondCategoryValue = []; // 二级分类的值
|
||||
thirdCategoryValue = []; // 三级标签的值
|
||||
repeatInfo = {}; // 重复率
|
||||
|
||||
/**
|
||||
* 输入题目
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectName = (e) => {
|
||||
let str = e.target.value.trim();
|
||||
this.setState(
|
||||
{
|
||||
subjectName: str,
|
||||
},
|
||||
() => {
|
||||
this.rankLabelBox.getThirdCategoryList();
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 一次确认录入
|
||||
*/
|
||||
onSubmit = debounce(() => {
|
||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state;
|
||||
if (isDisabledSubmit || !isSubmit) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
isSubmit: false,
|
||||
});
|
||||
let params = {
|
||||
subjectName: subjectName,
|
||||
difficulty: this.rankId,
|
||||
subjectType: 2,
|
||||
subjectScore: this.scoreValue,
|
||||
subjectParse: this.subjectAnalysis,
|
||||
categoryIds: this.secondCategoryValue,
|
||||
labelIds: this.thirdCategoryValue,
|
||||
optionList: this.currentActive,
|
||||
};
|
||||
console.log('多选录入 ----', params);
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addInterviewSubject,
|
||||
})
|
||||
.then((res) => {
|
||||
this.repeatInfo = {};
|
||||
if (res.data && res.data.insertStatus) {
|
||||
this.setState(
|
||||
{
|
||||
isSubmit: true,
|
||||
},
|
||||
() => {
|
||||
this.successModalConfirm();
|
||||
}
|
||||
);
|
||||
} else if (!res.data.insertStatus) {
|
||||
this.repeatInfo = {
|
||||
repeatDocId: res.data.docId, // 重复题目id
|
||||
repeatRate: res.data.repeatRate, // 重复率
|
||||
repeatSubjectName: res.data.subjectName, // 重复题目
|
||||
repeatOptionList: res.data.optionList, // 重复列表项
|
||||
repeatSetterErp: res.data.subjectSetterErp, // 出题人erp
|
||||
repeatSetterName: res.data.subjectSetterName, // 出题人姓名
|
||||
};
|
||||
this.setState({
|
||||
isShowModalBox: true,
|
||||
isSubmit: true,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
isSubmit: true,
|
||||
});
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
checkData = () => {
|
||||
const { subjectName } = this.state;
|
||||
let list = this.currentActive.filter((item) => item.optionContent === defalutLabel);
|
||||
let isDisabledSubmit = false;
|
||||
if (
|
||||
!!!subjectName ||
|
||||
list.length > 0 ||
|
||||
!!!this.firstCategoryValue ||
|
||||
this.secondCategoryValue.length <= 0 ||
|
||||
this.thirdCategoryValue.length <= 0 ||
|
||||
!!!this.scoreValue
|
||||
) {
|
||||
isDisabledSubmit = true;
|
||||
}
|
||||
return isDisabledSubmit;
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
onCancel = () => {
|
||||
this.currentActive = []; // 选项列表
|
||||
this.scoreValue = ''; // 分数
|
||||
this.subjectAnalysis = ''; //试题解析
|
||||
this.rankId = 1;
|
||||
this.subjectAnswer = ''; // 选项内容
|
||||
this.firstCategoryValue = ''; // 一级分类的值
|
||||
this.secondCategoryValue = []; // 二级分类的值
|
||||
this.thirdCategoryValue = []; // 三级标签的值
|
||||
this.repeatInfo = {};
|
||||
this.kindEditor && this.kindEditor.onClear();
|
||||
this.rankLabelBox.initRankLabel();
|
||||
this.optionInputBox.handleClearOption();
|
||||
this.setState({
|
||||
subjectName: '',
|
||||
isShowModalBox: false,
|
||||
isSubmit: true, // 是否支持提交
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 重复率弹框-确认录入
|
||||
*/
|
||||
onSubmitRepeatModal = debounce(
|
||||
() => {
|
||||
let params = {
|
||||
docId: this.repeatInfo.repeatDocId,
|
||||
};
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addRepeatInterviewSubject,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
this.successModalConfirm();
|
||||
} else {
|
||||
message.info('请再次确认');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
message.error('请再次确认');
|
||||
});
|
||||
},
|
||||
300,
|
||||
true
|
||||
);
|
||||
|
||||
/**
|
||||
* 重复率弹框-取消录入
|
||||
*/
|
||||
onCancelRepeatModal = () => {
|
||||
this.repeatInfo = {};
|
||||
this.setState({
|
||||
isShowModalBox: false,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功的弹框
|
||||
*/
|
||||
successModalConfirm = () => {
|
||||
Modal.confirm({
|
||||
title: (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: 'rgba(60, 110, 238, 1)',
|
||||
fontSize: 16,
|
||||
}}>
|
||||
录入成功!贡献榜火力值 + 1
|
||||
</div>
|
||||
),
|
||||
closable: false,
|
||||
maskClosable: false,
|
||||
icon: ' ',
|
||||
onOk: this.onAgainSuccessModal,
|
||||
onCancel: this.onGoHomeSuccessModal,
|
||||
okText: '再录一题',
|
||||
cancelText: '去首页',
|
||||
className: 'questions-success-modal-confirm',
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-再来一题
|
||||
*/
|
||||
onAgainSuccessModal = () => {
|
||||
this.onCancel();
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-去首页
|
||||
*/
|
||||
onGoHomeSuccessModal = () => {
|
||||
// this.onCancel();
|
||||
window.location.href = '/cms-supplier/question-bank';
|
||||
};
|
||||
|
||||
/**
|
||||
* 分类选择
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeRankLabel = (firstCategoryValue, secondCategoryValue, thirdCategoryValue) => {
|
||||
this.firstCategoryValue = firstCategoryValue; // 一级分类的值
|
||||
this.secondCategoryValue = secondCategoryValue; // 二级分类的值
|
||||
this.thirdCategoryValue = thirdCategoryValue; // 三级标签的值
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 职级选择
|
||||
* @param {*} list
|
||||
*/
|
||||
handleChangeRank = (list) => {
|
||||
this.rankId = list[0];
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 选项操作
|
||||
* @param {*} currentActive 选项列表
|
||||
* @param {*} scoreValue 分值
|
||||
* @param {*} subjectAnalysis 解析
|
||||
*/
|
||||
handleChangeOption = (currentActive, scoreValue, subjectAnalysis) => {
|
||||
this.currentActive = currentActive;
|
||||
this.scoreValue = scoreValue;
|
||||
this.subjectAnalysis = subjectAnalysis;
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { subjectName, isDisabledSubmit, isSubmit, isShowModalBox } = this.state;
|
||||
const { questionsType } = this.props;
|
||||
return (
|
||||
<Spin spinning={!isSubmit}>
|
||||
<Fragment>
|
||||
<div className="multiple-questions-container">
|
||||
<div className="multiple-questions-title">题目名称:</div>
|
||||
<Input
|
||||
placeholder="输入题目"
|
||||
style={{ height: 48, width: '100%' }}
|
||||
value={subjectName}
|
||||
maxLength={64}
|
||||
onChange={(e) => this.onChangeSubjectName(e)}
|
||||
/>
|
||||
</div>
|
||||
<OptionInputBox
|
||||
key="multiple-option-input"
|
||||
ref={(ref) => {
|
||||
this.optionInputBox = ref;
|
||||
}}
|
||||
isMultiple={true}
|
||||
handleChangeOption={this.handleChangeOption}
|
||||
/>
|
||||
<RankLabelBox
|
||||
ref={(ref) => {
|
||||
this.rankLabelBox = ref;
|
||||
}}
|
||||
subjectName={subjectName}
|
||||
onChangeRankLabel={this.onChangeRankLabel}
|
||||
handleChangeRank={this.handleChangeRank}
|
||||
/>
|
||||
<div className="multiple-questions-btns-container">
|
||||
<div className="multiple-questions-btn" onClick={this.onCancel}>
|
||||
清空
|
||||
</div>
|
||||
<div
|
||||
className={`multiple-questions-btn multiple-questions-submit ${isDisabledSubmit && 'multiple-questions-disabled-submit'
|
||||
}`}
|
||||
onClick={this.onSubmit}>
|
||||
提交
|
||||
</div>
|
||||
</div>
|
||||
<RepeatContentBox
|
||||
isShowModalBox={isShowModalBox}
|
||||
repeatQuestionsType={questionsType}
|
||||
repeatInfo={this.repeatInfo}
|
||||
handleSubmitRepeatModal={this.onSubmitRepeatModal}
|
||||
handleCancelRepeatModal={this.onCancelRepeatModal}
|
||||
/>
|
||||
</Fragment>
|
||||
</Spin>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,52 @@
|
||||
.multiple-questions-container {
|
||||
width: 1000px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
padding-top: 36px;
|
||||
// label名字title
|
||||
.multiple-questions-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: 140px;
|
||||
line-height: 40px;
|
||||
font-size: 16px;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
&:before {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
margin-top: 1px;
|
||||
color: #f5222d;
|
||||
font-size: 16px;
|
||||
content: '*';
|
||||
}
|
||||
}
|
||||
}
|
||||
.multiple-questions-btns-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin: 20px auto;
|
||||
width: 952px;
|
||||
.multiple-questions-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.multiple-questions-submit {
|
||||
margin-left: 40px;
|
||||
background-color: #4390f7;
|
||||
color: #fff;
|
||||
border: 1px solid #4390f7;
|
||||
}
|
||||
.multiple-questions-disabled-submit {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
438
src/views/upload-questions/components/option-input-box/index.jsx
Normal file
438
src/views/upload-questions/components/option-input-box/index.jsx
Normal file
@@ -0,0 +1,438 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { Input, message, Tooltip, Select } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { debounce } from '@utils';
|
||||
import { optionLetter } from '../../constant';
|
||||
import KindEditor from '../kind-editor';
|
||||
import './index.less';
|
||||
const { TextArea } = Input;
|
||||
const { Option } = Select;
|
||||
const defalutLabel = '请使用富文本编辑器输入选项内容';
|
||||
// 判断题
|
||||
const judgeList = [
|
||||
{
|
||||
label: '错误',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: '正确',
|
||||
value: 1,
|
||||
},
|
||||
];
|
||||
const optionLetterLength = 7; // ABCD的长度
|
||||
const showDeleteLength = 3; // 展示删除icon的最短长度
|
||||
export default class OptionInputBox extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
optionList: [
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 4,
|
||||
},
|
||||
], // 选项列表
|
||||
currentActiveList: [], // 当前选中的项
|
||||
scoreValue: '', // 分数
|
||||
subjectAnalysis: '', //试题解析
|
||||
};
|
||||
}
|
||||
|
||||
kindEditor = KindEditor | null;
|
||||
subjectAnswer = ''; // 选项内容
|
||||
|
||||
/**
|
||||
* 新增/删除
|
||||
* @param {*} len
|
||||
* @param {*} type add-新增 / del-删除
|
||||
* @returns
|
||||
*/
|
||||
onChangeAddOption = (len, type) => () => {
|
||||
let { optionList, currentActiveList } = this.state;
|
||||
let list = [];
|
||||
// 新增
|
||||
if (type === 'add') {
|
||||
if (len === optionLetterLength) {
|
||||
return;
|
||||
}
|
||||
optionList.push({ label: defalutLabel, value: optionLetter[len].value });
|
||||
} else {
|
||||
// 删除
|
||||
currentActiveList = [];
|
||||
optionList.splice(len, 1);
|
||||
// 重新初始化ABCD对应的id
|
||||
list = optionList.map((item, index) => {
|
||||
return {
|
||||
label: item.label,
|
||||
value: optionLetter[index].value,
|
||||
};
|
||||
});
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
optionList: type === 'add' ? optionList : list,
|
||||
currentActiveList,
|
||||
},
|
||||
() => {
|
||||
this.handleChangeOption();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 确认/取消 编辑框
|
||||
* @param {*} index
|
||||
* @param {*} type submit/cancel
|
||||
* @returns
|
||||
*/
|
||||
onChangeOptEditor = (index, type) => () => {
|
||||
let { optionList } = this.state;
|
||||
this.kindEditor && this.kindEditor.onClear();
|
||||
if (type === 'submit') {
|
||||
_.set(
|
||||
optionList,
|
||||
[index, 'label'],
|
||||
!!this.subjectAnswer ? this.subjectAnswer : defalutLabel
|
||||
);
|
||||
}
|
||||
_.set(optionList, [index, 'isShowEditor'], false);
|
||||
this.subjectAnswer = '';
|
||||
this.setState(
|
||||
{
|
||||
optionList,
|
||||
},
|
||||
() => {
|
||||
this.handleChangeOption();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 展开 编辑项
|
||||
* @param {*} index
|
||||
* @returns
|
||||
*/
|
||||
onChangeShowEditor = (index) =>
|
||||
debounce(() => {
|
||||
let { optionList } = this.state;
|
||||
if (optionList.filter((item) => item.isShowEditor).length > 0) {
|
||||
return message.info('请先确认正在编辑的选项内容');
|
||||
}
|
||||
_.set(optionList, [index, 'isShowEditor'], true);
|
||||
this.setState(
|
||||
{
|
||||
optionList,
|
||||
},
|
||||
() => {
|
||||
this.kindEditor && this.kindEditor.onCashBack();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* 富文本编辑器
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeEditor = (index) => (e) => {
|
||||
this.subjectAnswer = e;
|
||||
};
|
||||
|
||||
/**
|
||||
* 正确选项
|
||||
* @param {*} value
|
||||
*/
|
||||
onChangeSelect = (value) => {
|
||||
const { isMultiple } = this.props;
|
||||
let str = value;
|
||||
if (!isMultiple) {
|
||||
// 单选,格式化成数组
|
||||
str = [value];
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
currentActiveList: str,
|
||||
},
|
||||
() => {
|
||||
this.handleChangeOption();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 本题分值
|
||||
*/
|
||||
onChangeScore = (e) => {
|
||||
this.setState(
|
||||
{
|
||||
scoreValue: e.target.value.trim(),
|
||||
},
|
||||
() => {
|
||||
this.handleChangeOption();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 试题解析
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectAnalysis = (e) => {
|
||||
this.setState(
|
||||
{
|
||||
subjectAnalysis: e.target.value.trim(),
|
||||
},
|
||||
() => {
|
||||
this.handleChangeOption();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 清空
|
||||
*/
|
||||
handleClearOption = () => {
|
||||
this.subjectAnswer = ''; // 选项内容
|
||||
this.setState({
|
||||
optionList: [
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
label: defalutLabel,
|
||||
value: 4,
|
||||
},
|
||||
], // 选项列表
|
||||
currentActiveList: [], // 当前选中的项
|
||||
scoreValue: '', // 分数
|
||||
subjectAnalysis: '', //试题解析
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 向父组件传值
|
||||
*/
|
||||
handleChangeOption = () => {
|
||||
let { currentActiveList, scoreValue, subjectAnalysis, optionList } = this.state;
|
||||
const { isJudge } = this.props;
|
||||
let activeList = [];
|
||||
if (!isJudge) {
|
||||
// 单选/多选
|
||||
activeList = optionList.map((item) => {
|
||||
let flag = 0;
|
||||
if (currentActiveList.includes(item.value)) {
|
||||
flag = 1;
|
||||
}
|
||||
return {
|
||||
optionType: item.value,
|
||||
optionContent: item.label,
|
||||
isCorrect: flag,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
// 判断
|
||||
activeList = currentActiveList;
|
||||
}
|
||||
console.log('向父组件传值', activeList, scoreValue, subjectAnalysis);
|
||||
// this.props.handleChangeOption(activeList, scoreValue, subjectAnalysis);
|
||||
this.props.handleChangeOption(activeList, 1, subjectAnalysis);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { subjectAnalysis } = this.state;
|
||||
const { isJudge } = this.props;
|
||||
return (
|
||||
<Fragment>
|
||||
{!isJudge && this.renderOption()}
|
||||
{this.renderOptionBtn()}
|
||||
<div className="option-input-container">
|
||||
<div className="option-input-title">试题解析:</div>
|
||||
<TextArea
|
||||
placeholder="试题解析(非必填 限500字)"
|
||||
value={subjectAnalysis}
|
||||
style={{ height: 48, width: '100%' }}
|
||||
maxLength={500}
|
||||
autoSize={{ minRows: 3, maxRows: 4 }}
|
||||
onChange={(e) => this.onChangeSubjectAnalysis(e)}
|
||||
/>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 选项模块
|
||||
* @returns
|
||||
*/
|
||||
renderOption = () => {
|
||||
const { optionList } = this.state;
|
||||
let listLen = optionList.length;
|
||||
return (
|
||||
<Fragment>
|
||||
{optionList.length > 0 &&
|
||||
optionList.map((item, index) => {
|
||||
const isShowTip = item.label === defalutLabel;
|
||||
return (
|
||||
<div
|
||||
className="option-input-container"
|
||||
style={{ flexDirection: 'column' }}
|
||||
key={`option_input_${index}`}>
|
||||
<div className="option-input-main">
|
||||
<div className="option-input-title-option">
|
||||
{optionLetter[item.value - 1].label}
|
||||
</div>
|
||||
<div
|
||||
className="option-input-item"
|
||||
key={`option_id_${item.value}`}>
|
||||
<Tooltip
|
||||
title="点击可输入该选项内容"
|
||||
onClick={this.onChangeShowEditor(index)}>
|
||||
<div
|
||||
className="option-input-item-header"
|
||||
style={
|
||||
isShowTip
|
||||
? {
|
||||
color: 'rgba(51,51,51,0.3)',
|
||||
}
|
||||
: {
|
||||
color: 'rgba(51,51,51,0.9)',
|
||||
}
|
||||
}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item.label,
|
||||
}}></div>
|
||||
</Tooltip>
|
||||
<div className="option-input-item-delete">
|
||||
{listLen > showDeleteLength && (
|
||||
<Tooltip
|
||||
title="删除选项"
|
||||
onClick={this.onChangeAddOption(index, 'del')}>
|
||||
<img
|
||||
className="option-input-item-delete-icon"
|
||||
src="https://img14.360buyimg.com/imagetools/jfs/t1/212738/17/4123/399/618dd36bEd53475f5/38e899e92bbd5d5e.png"
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{item.isShowEditor && (
|
||||
<div
|
||||
key={`option_editor_${index}`}
|
||||
className="option-input-main"
|
||||
style={{ marginTop: 19 }}>
|
||||
<div className="option-input-editor">
|
||||
<KindEditor
|
||||
ref={(ref) => {
|
||||
this.kindEditor = ref;
|
||||
}}
|
||||
bodyHeight={145}
|
||||
borderRadius={12}
|
||||
onChange={this.onChangeEditor(index)}
|
||||
cashBackText={isShowTip ? '' : item.label}
|
||||
/>
|
||||
<div className="option-input-editor-btns">
|
||||
<Tooltip title="取消后内容将不会更新到选项框内">
|
||||
<div
|
||||
className="option-input-editor-btn"
|
||||
onClick={this.onChangeOptEditor(
|
||||
index,
|
||||
'cancel'
|
||||
)}>
|
||||
取消
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip title="确定后内容将会更新到选项框内">
|
||||
<div
|
||||
className="option-input-editor-btn option-input-editor-submit-btn"
|
||||
onClick={this.onChangeOptEditor(
|
||||
index,
|
||||
'submit'
|
||||
)}>
|
||||
确定
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 选项模块-操作按钮
|
||||
* @returns
|
||||
*/
|
||||
renderOptionBtn = () => {
|
||||
const { optionList, scoreValue, currentActiveList } = this.state;
|
||||
const { isMultiple, isJudge } = this.props;
|
||||
let listLen = optionList.length;
|
||||
return (
|
||||
<div className="option-input-container">
|
||||
<div className="option-input-title option-input-title-required">题目操作:</div>
|
||||
<div style={{ display: 'flex', width: '100%' }}>
|
||||
{!isJudge && (
|
||||
<div
|
||||
className="option-input-option-btn"
|
||||
onClick={this.onChangeAddOption(listLen, 'add')}>
|
||||
添加选项
|
||||
</div>
|
||||
)}
|
||||
<div className="option-input-option-btn option-input-option-input">
|
||||
正确选项
|
||||
<Select
|
||||
mode={isMultiple && 'multiple'}
|
||||
defaultActiveFirstOption={false}
|
||||
value={currentActiveList}
|
||||
placeholder="请选择"
|
||||
style={{ minWidth: isMultiple ? '64px' : '68px', marginLeft: 4 }}
|
||||
onChange={this.onChangeSelect}>
|
||||
{isJudge
|
||||
? judgeList.map((item, index) => {
|
||||
return (
|
||||
<Option
|
||||
key={`option_select_${item.value}`}
|
||||
value={item.value}>
|
||||
{item.label}
|
||||
</Option>
|
||||
);
|
||||
})
|
||||
: optionList.map((item, index) => {
|
||||
return (
|
||||
<Option
|
||||
key={`option_select_${item.value}`}
|
||||
value={item.value}>
|
||||
{optionLetter[index].label}
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
@@ -0,0 +1,157 @@
|
||||
.option-input-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
padding-top: 19px;
|
||||
// 选项模块
|
||||
.option-input-main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
// 选项label-abcd...
|
||||
.option-input-title-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: 140px;
|
||||
line-height: 40px;
|
||||
font-size: 16px;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
}
|
||||
.option-input-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
transition: all 0.5s;
|
||||
cursor: pointer;
|
||||
.option-input-item-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
padding: 4px 10px;
|
||||
width: 100%;
|
||||
min-height: 48px;
|
||||
background: rgba(255, 255, 255, 1);
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 7px;
|
||||
}
|
||||
.option-input-item-delete {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 19px;
|
||||
width: 19px;
|
||||
.option-input-item-delete-icon {
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 编辑器
|
||||
.option-input-editor {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-right: 38px;
|
||||
margin-left: 124px;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
transition: all 0.5s;
|
||||
.option-input-editor-btns {
|
||||
display: flex;
|
||||
margin-top: 19px;
|
||||
.option-input-editor-btn {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 115px;
|
||||
height: 43px;
|
||||
font-size: 14px;
|
||||
color: rgba(24, 24, 29, 1);
|
||||
cursor: pointer;
|
||||
background: rgba(255, 255, 255, 1);
|
||||
border: 1px solid rgba(208, 212, 222, 1);
|
||||
border-radius: 22px;
|
||||
}
|
||||
.option-input-editor-submit-btn {
|
||||
margin-left: 19px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
font-weight: 500;
|
||||
background: rgba(60, 110, 238, 1);
|
||||
border: 2px solid rgba(60, 110, 238, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 必填项
|
||||
.option-input-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: 140px;
|
||||
line-height: 40px;
|
||||
font-size: 16px;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
}
|
||||
// 非必填项
|
||||
.option-input-title-required {
|
||||
&:before {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
margin-top: 1px;
|
||||
color: #f5222d;
|
||||
font-size: 16px;
|
||||
content: '*';
|
||||
}
|
||||
}
|
||||
// 选项模块-操作按钮
|
||||
.option-input-option-btn {
|
||||
margin-right: 8px;
|
||||
padding: 0 32px;
|
||||
height: 48px;
|
||||
text-align: center;
|
||||
line-height: 48px;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
color: rgba(60, 110, 238, 1);
|
||||
cursor: pointer;
|
||||
background: rgba(255, 255, 255, 1);
|
||||
border: 1px solid rgba(240, 240, 240, 1);
|
||||
border-radius: 7px;
|
||||
}
|
||||
// 选项模块-操作按钮-输入框
|
||||
.option-input-option-input {
|
||||
padding-left: 14px;
|
||||
padding-right: 4px;
|
||||
color: #333;
|
||||
.ant-select,
|
||||
.ant-select-open,
|
||||
.ant-select-focused,
|
||||
.ant-select-enabled {
|
||||
box-shadow: none !important;
|
||||
-webkit-box-shadow: none !important;
|
||||
}
|
||||
// 正确选项:去除两边外边距
|
||||
.ant-select-selection--single .ant-select-selection__rendered {
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
// 正确选项:去除边框
|
||||
.ant-select-selection {
|
||||
border: none;
|
||||
}
|
||||
// 正确选项:值的位置优化
|
||||
.ant-select-selection-selected-value {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.ant-input {
|
||||
padding: 4px;
|
||||
}
|
||||
// 正确选项:距离右边的位置
|
||||
.ant-select-selection__rendered {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
350
src/views/upload-questions/components/rank-label-box/index.jsx
Normal file
350
src/views/upload-questions/components/rank-label-box/index.jsx
Normal file
@@ -0,0 +1,350 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import req from '@utils/request';
|
||||
import TagsEditor from '@components/tags-editor';
|
||||
import { apiName, ModuleType, starList } from '../../constant';
|
||||
import './index.less';
|
||||
export default class RankLabelBox extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
firstCategoryList: [],
|
||||
secondCategoryList: [],
|
||||
thirdCategoryList: [],
|
||||
rankList: starList,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.geFirstCategoryList();
|
||||
}
|
||||
|
||||
firstValue = ''; // 一级分类id
|
||||
|
||||
firstCategoryValue = ''; // 一级分类的值
|
||||
secondCategoryValue = []; // 二级分类的值
|
||||
thirdCategoryValue = []; // 三级标签的值
|
||||
|
||||
/**
|
||||
* 初始化数据
|
||||
*/
|
||||
initRankLabel = () => {
|
||||
this.firstCategoryValue = ''; // 一级分类的值
|
||||
this.secondCategoryValue = []; // 二级分类的值
|
||||
this.thirdCategoryValue = []; // 三级标签的值
|
||||
this.firstValue = '';
|
||||
this.setState(
|
||||
{
|
||||
firstCategoryList: [],
|
||||
secondCategoryList: [],
|
||||
thirdCategoryList: [],
|
||||
rankList: starList,
|
||||
},
|
||||
() => {
|
||||
this.geFirstCategoryList();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获得一级分类数据
|
||||
*/
|
||||
geFirstCategoryList() {
|
||||
const params = { categoryType: 1 };
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.getInterviewCategory,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
let list = res.data.map((item, index) => {
|
||||
return {
|
||||
...item,
|
||||
active: index == 0 ? true : false,
|
||||
};
|
||||
});
|
||||
this.setState(
|
||||
{
|
||||
firstCategoryList: list,
|
||||
secondCategoryList: [],
|
||||
thirdCategoryList: [],
|
||||
},
|
||||
() => {
|
||||
this.firstValue = list[0].categoryId;
|
||||
this.getSecondCategoryList(this.firstValue);
|
||||
this.getThirdCategoryList(this.firstValue);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.setState({
|
||||
firstCategoryList: [],
|
||||
secondCategoryList: [],
|
||||
thirdCategoryList: [],
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => console.log(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得二级分类数据
|
||||
* @param {*} id 一级分类id
|
||||
*/
|
||||
getSecondCategoryList(id) {
|
||||
const params = { parentId: id, categoryType: 2 };
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.getInterviewCategory,
|
||||
})
|
||||
.then((res) => {
|
||||
this.firstCategoryValue = id;
|
||||
this.secondCategoryValue = [];
|
||||
this.thirdCategoryValue = [];
|
||||
if (res.data && res.data.length > 0) {
|
||||
this.setState({
|
||||
secondCategoryList: res.data,
|
||||
});
|
||||
} else {
|
||||
// 若需要新增时,则需要将数组第一个item,重置如下
|
||||
this.setState({
|
||||
secondCategoryList: [{ categoryName: '空', categoryId: -9999 }],
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => console.log(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得三级分类数据
|
||||
* @param {*} id 二级分类id
|
||||
*/
|
||||
getThirdCategoryList(id) {
|
||||
const { subjectName } = this.props;
|
||||
const params = {
|
||||
primaryCategoryId: id || this.firstValue,
|
||||
subjectName: subjectName,
|
||||
};
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.getRecommendLabel,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
let list = res.data.map((item) => {
|
||||
return {
|
||||
categoryName: item.labelName,
|
||||
categoryId: item.labelId,
|
||||
active: item?.isRecommend === 1 ? true : false,
|
||||
};
|
||||
});
|
||||
this.thirdCategoryValue = this.formatList(list);
|
||||
if (this.thirdCategoryValue.length >= 0) {
|
||||
this.onChangeRankLabel();
|
||||
}
|
||||
this.setState({
|
||||
thirdCategoryList: list,
|
||||
});
|
||||
} else {
|
||||
// 若需要新增时,则需要将数组第一个item,重置如下
|
||||
this.setState({
|
||||
thirdCategoryList: [{ categoryName: '空', categoryId: -9999 }],
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => console.log(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择职级-单选
|
||||
* @param {*} handleStatusList
|
||||
* @param {*} selectList
|
||||
*/
|
||||
onHandleChangeRank = (handleStatusList, selectList) => {
|
||||
this.setState({ rankList: handleStatusList });
|
||||
this.props.handleChangeRank(selectList);
|
||||
};
|
||||
|
||||
/**
|
||||
* 选择一级分类-单选
|
||||
* @param {*} handleStatusList 带有是否选中状态的原数组
|
||||
* @param {*} selectList 选中id的数组
|
||||
*/
|
||||
onChangeFirst = (handleStatusList, selectList) => {
|
||||
this.setState({ firstCategoryList: handleStatusList });
|
||||
this.firstValue = selectList[0];
|
||||
// 获得二级分类
|
||||
this.getSecondCategoryList(this.firstValue);
|
||||
// 获得三级标签
|
||||
this.getThirdCategoryList(this.firstValue);
|
||||
};
|
||||
|
||||
/**
|
||||
* 选择二级分类
|
||||
* @param {*} handleStatusList 带有是否选中状态的原数组
|
||||
* @param {*} selectList 选中id的数组
|
||||
*/
|
||||
onChangeSecondTags = (handleStatusList, selectList) => {
|
||||
this.secondCategoryValue = selectList;
|
||||
this.setState({ secondCategoryList: handleStatusList });
|
||||
this.onChangeRankLabel();
|
||||
};
|
||||
|
||||
/**
|
||||
* 选择三级标签
|
||||
* @param {*} handleStatusList 带有是否选中状态的原数组
|
||||
* @param {*} selectList 选中id的数组
|
||||
*/
|
||||
onChangeThirdTags = (handleStatusList, selectList) => {
|
||||
this.thirdCategoryValue = selectList;
|
||||
this.setState({ thirdCategoryList: handleStatusList });
|
||||
this.onChangeRankLabel();
|
||||
};
|
||||
|
||||
/**
|
||||
* 格式化数据-获得选中项id列表
|
||||
* @param {*} list
|
||||
* @returns
|
||||
*/
|
||||
formatList = (list) => {
|
||||
let labelList = [];
|
||||
list.forEach((item) => {
|
||||
if (item.active) {
|
||||
labelList.push(item.categoryId);
|
||||
}
|
||||
});
|
||||
return labelList;
|
||||
};
|
||||
|
||||
/**
|
||||
* 向父组件传递
|
||||
*/
|
||||
onChangeRankLabel = () => {
|
||||
console.log(
|
||||
'问答题 -------',
|
||||
this.firstCategoryValue,
|
||||
this.secondCategoryValue,
|
||||
this.thirdCategoryValue
|
||||
);
|
||||
this.props.onChangeRankLabel(
|
||||
this.firstCategoryValue,
|
||||
this.secondCategoryValue,
|
||||
this.thirdCategoryValue
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { firstCategoryList, secondCategoryList, thirdCategoryList, rankList } = this.state;
|
||||
return (
|
||||
<Fragment>
|
||||
{this.rendeRrankModule(rankList)}
|
||||
{this.renderFirstModule(firstCategoryList)}
|
||||
{secondCategoryList?.length > 0 && (
|
||||
<Fragment>
|
||||
{this.renderSecondModule(secondCategoryList)}
|
||||
{thirdCategoryList?.length > 0 && this.renderThirdModule(thirdCategoryList)}
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 职级选择
|
||||
* @param {*} rankList
|
||||
* @returns
|
||||
*/
|
||||
rendeRrankModule = (rankList) => {
|
||||
return (
|
||||
<div className="upload-single-container">
|
||||
<div className="upload-single-title">职级选择:</div>
|
||||
<div className="upload-single-main">
|
||||
<TagsEditor
|
||||
categoryList={rankList}
|
||||
isSingleChoice={true}
|
||||
onChangeLabel={this.onHandleChangeRank}
|
||||
isDisabledReverseSelection={true}
|
||||
/>
|
||||
<span style={{ marginLeft: '8px', color: 'red' }}>
|
||||
注:所选职级应为熟练掌握该题的最低职级
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 一级分类选择
|
||||
* @param {*} firstCategoryList
|
||||
* @returns
|
||||
*/
|
||||
renderFirstModule = (firstCategoryList) => {
|
||||
return (
|
||||
<Fragment>
|
||||
{firstCategoryList?.length > 0 && (
|
||||
<div className="upload-single-container">
|
||||
<div className="upload-single-title">一级分类:</div>
|
||||
<div className="upload-single-main">
|
||||
<TagsEditor
|
||||
categoryList={firstCategoryList}
|
||||
isSingleChoice={true}
|
||||
onChangeLabel={this.onChangeFirst}
|
||||
isDisabledReverseSelection={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 二级分类选择
|
||||
* @param {*} secondCategoryList
|
||||
* @returns
|
||||
*/
|
||||
renderSecondModule = (secondCategoryList) => {
|
||||
return (
|
||||
<div className="upload-single-container">
|
||||
<div className="upload-single-title">二级分类:</div>
|
||||
<div className="upload-single-main">
|
||||
<TagsEditor
|
||||
moduleType={ModuleType.second}
|
||||
categoryList={secondCategoryList}
|
||||
isSingleChoice={false}
|
||||
onChangeLabel={this.onChangeSecondTags}
|
||||
// parentCategoryValue={[this.firstCategoryValue]}
|
||||
// isAddTag={true}
|
||||
// isDeleteTag={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 三级标签选择
|
||||
* @param {*} thirdCategoryList
|
||||
* @returns
|
||||
*/
|
||||
renderThirdModule = (thirdCategoryList) => {
|
||||
return (
|
||||
<div className="upload-single-container">
|
||||
<div className="upload-single-title">三级标签:</div>
|
||||
<div className="upload-single-main">
|
||||
<TagsEditor
|
||||
moduleType={ModuleType.third}
|
||||
categoryList={thirdCategoryList}
|
||||
isSingleChoice={false}
|
||||
onChangeLabel={this.onChangeThirdTags}
|
||||
// parentCategoryValue={[this.firstCategoryValue]}
|
||||
// isAddTag={true}
|
||||
// isDeleteTag={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
@@ -0,0 +1,44 @@
|
||||
.upload-single-container {
|
||||
width: 1000px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 0 24px;
|
||||
padding-top: 36px;
|
||||
.upload-single-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: 140px;
|
||||
line-height: 40px;
|
||||
font-size: 16px;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
&:before {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
margin-top: 1px;
|
||||
color: #f5222d;
|
||||
font-size: 16px;
|
||||
content: '*';
|
||||
}
|
||||
}
|
||||
.upload-single-main {
|
||||
width: 100%;
|
||||
// 题目输入框
|
||||
.upload-single-input {
|
||||
height: 40px;
|
||||
}
|
||||
// 一级大类
|
||||
.ant-radio-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
flex-wrap: wrap;
|
||||
height: 40px;
|
||||
}
|
||||
.tag-active {
|
||||
@include box-backgroundColor(0.1);
|
||||
@include box-border();
|
||||
@include font-color();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,234 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { Modal, Tooltip } from 'antd';
|
||||
import { letterList, judgeList } from '../../constant';
|
||||
import './index.less';
|
||||
export default function RepeatContentBox(props) {
|
||||
const { isShowModalBox, repeatInfo, repeatQuestionsType } = props;
|
||||
// const { isShowModalBox, repeatQuestionsType } = props;
|
||||
// const repeatInfo = {
|
||||
// repeatSubjectName:
|
||||
// 'Chrome如Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?何支持小于12px的字?',
|
||||
// repeatSubjectAnswe:
|
||||
// 'Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?',
|
||||
// repeatSetterErp: 'suchunping3',
|
||||
// repeatSetterName: '苏春萍',
|
||||
// };
|
||||
|
||||
// const repeatInfo = {
|
||||
// repeatSubjectName:
|
||||
// 'Chrome如Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?Chrome如何支持小于12px的字?何支持小于12px的字?',
|
||||
// repeatOptionList: [
|
||||
// {
|
||||
// isCorrect: '',
|
||||
// optionContent: 'Chrome如何支持小于12px的字?Chrome如何支持小于12px的',
|
||||
// optionType: 1,
|
||||
// },
|
||||
// {
|
||||
// isCorrect: '',
|
||||
// optionContent: 'Chrome如何支持小于12px的字?Chrome如何支持小于12px的',
|
||||
// optionType: 2,
|
||||
// },
|
||||
// {
|
||||
// isCorrect: 1,
|
||||
// optionContent: 'Chrome如何支持小于12px的字?Chrome如何支持小于12px的',
|
||||
// optionType: 3,
|
||||
// },
|
||||
// ],
|
||||
// repeatSetterErp: 'suchunping3',
|
||||
// repeatSetterName: '苏春萍',
|
||||
// };
|
||||
/**
|
||||
* 确认录入
|
||||
*/
|
||||
const onSubmitRepeatModal = (e) => {
|
||||
props.handleSubmitRepeatModal && props.handleSubmitRepeatModal();
|
||||
};
|
||||
/**
|
||||
* 取消录入
|
||||
*/
|
||||
const onCancelRepeatModal = () => {
|
||||
props.handleCancelRepeatModal && props.handleCancelRepeatModal();
|
||||
};
|
||||
|
||||
const renderRepeat = (type, repeatInfo) => {
|
||||
switch (type) {
|
||||
case 1:
|
||||
return renderBriefQuestions(repeatInfo);
|
||||
case 2:
|
||||
case 3:
|
||||
return renderSelectQuestions(type, repeatInfo);
|
||||
case 4:
|
||||
return renderJudgeQuestions(repeatInfo);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 展示重复内容-问答型
|
||||
* @returns
|
||||
*/
|
||||
const renderBriefQuestions = (repeatInfo) => {
|
||||
return (
|
||||
<div className="repeat-content-box">
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">问答题</div>
|
||||
<div className="repeat-subject-text">{repeatInfo.repeatSubjectName}</div>
|
||||
</div>
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">参考答案</div>
|
||||
<div
|
||||
className="repeat-subject-text"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: repeatInfo.repeatSubjectAnswe,
|
||||
}}></div>
|
||||
</div>
|
||||
<div className="repeat-subject-box repeat-subject-info-box">
|
||||
<div className="repeat-subject-title">来自</div>
|
||||
<Tooltip
|
||||
title={repeatInfo.repeatSetterErp}
|
||||
placement="right"
|
||||
style={{ fontSize: 14 }}>
|
||||
{repeatInfo.repeatSetterName}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 展示重复内容-单选/多选
|
||||
* @returns
|
||||
*/
|
||||
const renderSelectQuestions = (type, repeatInfo) => {
|
||||
// 过滤获得正确选项
|
||||
let repeatRightKey = repeatInfo?.repeatOptionList?.filter((item) => item.isCorrect === 1);
|
||||
return (
|
||||
<div className="repeat-content-box">
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">{type === 2 ? '单选题' : '多选题'}</div>
|
||||
<div className="repeat-subject-text">{repeatInfo.repeatSubjectName}</div>
|
||||
</div>
|
||||
{repeatInfo?.repeatOptionList?.length > 0 && (
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">选项内容</div>
|
||||
<div className="repeat-subject-list">
|
||||
{repeatInfo.repeatOptionList.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
className="repeat-subject-item"
|
||||
key={`repeat_option_${index}`}>
|
||||
{/* <div className="repeat-subject-label">
|
||||
{letterList[item.optionType]}
|
||||
</div> */}
|
||||
<div
|
||||
className="repeat-subject-text"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: item.optionContent,
|
||||
}}></div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{repeatRightKey?.length > 0 && (
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">答案</div>
|
||||
<div className="repeat-subject-list">
|
||||
{repeatRightKey.map((item, index) => {
|
||||
return (
|
||||
<span key={`repeat_answe_${index}`}>
|
||||
{letterList[item.optionType]}{' '}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!!repeatInfo.repeatSubjectAnswe && (
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">题目解析</div>
|
||||
<div
|
||||
className="repeat-subject-text"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: repeatInfo.repeatSubjectAnswe,
|
||||
}}></div>
|
||||
</div>
|
||||
)}
|
||||
<div className="repeat-subject-box repeat-subject-info-box">
|
||||
<div className="repeat-subject-title">来自</div>
|
||||
<Tooltip
|
||||
title={repeatInfo.repeatSetterErp}
|
||||
placement="right"
|
||||
style={{ fontSize: 14 }}>
|
||||
{repeatInfo.repeatSetterName}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 展示重复内容-判断
|
||||
* @returns
|
||||
*/
|
||||
const renderJudgeQuestions = (repeatInfo) => {
|
||||
return (
|
||||
<div className="repeat-content-box">
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">判断题</div>
|
||||
<div className="repeat-subject-text">{repeatInfo.repeatSubjectName}</div>
|
||||
</div>
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">答案</div>
|
||||
<div className="repeat-subject-list">
|
||||
{judgeList[repeatInfo.repeatIsCorrect]}
|
||||
</div>
|
||||
</div>
|
||||
{!!repeatInfo.repeatSubjectAnswe && (
|
||||
<div className="repeat-subject-box">
|
||||
<div className="repeat-subject-title">题目解析</div>
|
||||
<div
|
||||
className="repeat-subject-text"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: repeatInfo.repeatSubjectAnswe,
|
||||
}}></div>
|
||||
</div>
|
||||
)}
|
||||
<div className="repeat-subject-box repeat-subject-info-box">
|
||||
<div className="repeat-subject-title">来自</div>
|
||||
<Tooltip
|
||||
title={repeatInfo.repeatSetterErp}
|
||||
placement="right"
|
||||
style={{ fontSize: 14 }}>
|
||||
{repeatInfo.repeatSetterName}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="repeat-content-repeat-box"
|
||||
visible={isShowModalBox}
|
||||
title={
|
||||
<Fragment>
|
||||
<span
|
||||
style={{
|
||||
color: 'rgba(60, 110, 238, 0.8)',
|
||||
fontSize: 50,
|
||||
marginRight: 10,
|
||||
}}>
|
||||
{repeatInfo.repeatRate || '10%'}
|
||||
</span>
|
||||
重复率
|
||||
</Fragment>
|
||||
}
|
||||
onOk={onSubmitRepeatModal}
|
||||
onCancel={onCancelRepeatModal}
|
||||
okText="确认录入"
|
||||
cancelText="取消录入">
|
||||
{renderRepeat(repeatQuestionsType, repeatInfo)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
.repeat-content-box {
|
||||
font-size: 14px;
|
||||
.repeat-subject-box {
|
||||
padding-bottom: 14px;
|
||||
margin-bottom: 14px;
|
||||
line-height: 22px;
|
||||
border-bottom: 1px dotted #e4e4e4;
|
||||
.repeat-subject-title {
|
||||
margin-right: 8px;
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #3c6eee;
|
||||
line-height: 22px;
|
||||
}
|
||||
.repeat-subject-text {
|
||||
flex: 1;
|
||||
line-height: 18px;
|
||||
font-size: 14px;
|
||||
color: rgba(51, 51, 51, 0.8);
|
||||
}
|
||||
.repeat-subject-list {
|
||||
.repeat-subject-item {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
padding: 12px 10px 13px;
|
||||
background: #fff;
|
||||
border: 1px solid #d4d4d4;
|
||||
border-radius: 4px;
|
||||
// .repeat-subject-label {
|
||||
// margin-right: 4px;
|
||||
// width: 20px;
|
||||
// height: 20px;
|
||||
// line-height: 20px;
|
||||
// text-align: center;
|
||||
// color: rgba(51, 51, 51, 0.8);
|
||||
// border-radius: 50%;
|
||||
// @include box-backgroundColor(0.3);
|
||||
// }
|
||||
.repeat-subject-text {
|
||||
line-height: 22px;
|
||||
font-size: 14px;
|
||||
color: rgba(51, 51, 51, 0.8);
|
||||
}
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.repeat-subject-info-box {
|
||||
display: flex;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.repeat-content-repeat-box {
|
||||
// 弹框宽度
|
||||
.ant-modal-content {
|
||||
width: 630px;
|
||||
// 提示框-头部title位置
|
||||
.ant-modal-header {
|
||||
border-bottom: none;
|
||||
.ant-modal-title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: baseline;
|
||||
margin-top: 10px;
|
||||
font-size: 13px;
|
||||
line-height: 40px;
|
||||
color: rgba(51, 51, 51, 0.8);
|
||||
}
|
||||
}
|
||||
// 提示框-两个按钮
|
||||
.ant-modal-footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 14px 0;
|
||||
border-top: none;
|
||||
.ant-btn {
|
||||
border-radius: 18px;
|
||||
}
|
||||
.ant-btn-primary {
|
||||
background: rgba(60, 110, 238, 1);
|
||||
margin-left: 60px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
338
src/views/upload-questions/components/single-questions/index.jsx
Normal file
338
src/views/upload-questions/components/single-questions/index.jsx
Normal file
@@ -0,0 +1,338 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { Input, Modal, message, Spin } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import req from '@utils/request';
|
||||
import { debounce } from '@utils';
|
||||
import KindEditor from '../kind-editor';
|
||||
import RankLabelBox from '../rank-label-box';
|
||||
import OptionInputBox from '../option-input-box';
|
||||
import RepeatContentBox from '../repeat-content-box';
|
||||
import { apiName } from '../../constant';
|
||||
import './index.less';
|
||||
const defalutLabel = '请使用富文本编辑器输入选项内容';
|
||||
export default class SingleQuestions extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
subjectName: '', // 题目
|
||||
isDisabledSubmit: true, //是否禁止输入
|
||||
isShowModalBox: false, // 是否展示重复率弹框
|
||||
isSubmit: true, // 是否支持提交
|
||||
};
|
||||
}
|
||||
kindEditor = KindEditor | null;
|
||||
rankLabelBox = RankLabelBox | null;
|
||||
optionInputBox = OptionInputBox | null;
|
||||
|
||||
currentActive = []; // 选项列表
|
||||
scoreValue = ''; // 分数
|
||||
subjectAnalysis = ''; //试题解析
|
||||
rankId = 1; //职级
|
||||
subjectAnswer = ''; // 选项内容
|
||||
|
||||
firstCategoryValue = ''; // 一级分类的值
|
||||
secondCategoryValue = []; // 二级分类的值
|
||||
thirdCategoryValue = []; // 三级标签的值
|
||||
repeatInfo = {}; // 重复率
|
||||
|
||||
/**
|
||||
* 输入题目
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeSubjectName = (e) => {
|
||||
let str = e.target.value.trim();
|
||||
this.setState(
|
||||
{
|
||||
subjectName: str,
|
||||
},
|
||||
() => {
|
||||
this.rankLabelBox.getThirdCategoryList();
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 一次确认录入
|
||||
*/
|
||||
onSubmit = debounce(() => {
|
||||
const { subjectName, isDisabledSubmit, isSubmit } = this.state;
|
||||
if (isDisabledSubmit || !isSubmit) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
isSubmit: false,
|
||||
});
|
||||
let params = {
|
||||
subjectName: subjectName,
|
||||
difficulty: this.rankId,
|
||||
subjectType: 1,
|
||||
subjectScore: this.scoreValue,
|
||||
subjectParse: this.subjectAnalysis,
|
||||
categoryIds: this.secondCategoryValue,
|
||||
labelIds: this.thirdCategoryValue,
|
||||
optionList: this.currentActive,
|
||||
};
|
||||
console.log('单选题录入 ----', params);
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addInterviewSubject,
|
||||
})
|
||||
.then((res) => {
|
||||
this.repeatInfo = {};
|
||||
if (res.data && res.data.insertStatus) {
|
||||
this.setState(
|
||||
{
|
||||
isSubmit: true,
|
||||
},
|
||||
() => {
|
||||
this.successModalConfirm();
|
||||
}
|
||||
);
|
||||
} else if (!res.data.insertStatus) {
|
||||
this.repeatInfo = {
|
||||
repeatDocId: res.data.docId, // 重复题目id
|
||||
repeatRate: res.data.repeatRate, // 重复率
|
||||
repeatSubjectName: res.data.subjectName, // 重复题目
|
||||
repeatOptionList: res.data.optionList, // 重复列表项
|
||||
repeatSetterErp: res.data.subjectSetterErp, // 出题人erp
|
||||
repeatSetterName: res.data.subjectSetterName, // 出题人姓名
|
||||
};
|
||||
this.setState({
|
||||
isShowModalBox: true,
|
||||
isSubmit: true,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
isSubmit: true,
|
||||
});
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 校验是否支持点击按钮
|
||||
* @returns
|
||||
*/
|
||||
checkData = () => {
|
||||
const { subjectName } = this.state;
|
||||
let list = this.currentActive.filter((item) => item.optionContent === defalutLabel);
|
||||
let isDisabledSubmit = false;
|
||||
if (
|
||||
!!!subjectName ||
|
||||
list.length > 0 ||
|
||||
!!!this.firstCategoryValue ||
|
||||
this.secondCategoryValue.length <= 0 ||
|
||||
this.thirdCategoryValue.length <= 0 ||
|
||||
!!!this.scoreValue
|
||||
) {
|
||||
isDisabledSubmit = true;
|
||||
}
|
||||
return isDisabledSubmit;
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
onCancel = () => {
|
||||
this.currentActive = []; // 选项列表
|
||||
this.scoreValue = ''; // 分数
|
||||
this.subjectAnalysis = ''; //试题解析
|
||||
this.rankId = 1;
|
||||
this.subjectAnswer = ''; // 选项内容
|
||||
this.firstCategoryValue = ''; // 一级分类的值
|
||||
this.secondCategoryValue = []; // 二级分类的值
|
||||
this.thirdCategoryValue = []; // 三级标签的值
|
||||
this.kindEditor && this.kindEditor.onClear();
|
||||
this.rankLabelBox.initRankLabel();
|
||||
this.optionInputBox.handleClearOption();
|
||||
this.repeatInfo = {};
|
||||
this.setState({
|
||||
subjectName: '',
|
||||
isShowModalBox: false,
|
||||
isSubmit: true, // 是否支持提交
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 重复率弹框-确认录入
|
||||
*/
|
||||
onSubmitRepeatModal = debounce(
|
||||
() => {
|
||||
let params = {
|
||||
docId: this.repeatInfo.repeatDocId,
|
||||
};
|
||||
req({
|
||||
method: 'post',
|
||||
data: params,
|
||||
url: apiName.addRepeatInterviewSubject,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data) {
|
||||
this.successModalConfirm();
|
||||
} else {
|
||||
message.info('请再次确认');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
message.error('请再次确认');
|
||||
});
|
||||
},
|
||||
300,
|
||||
true
|
||||
);
|
||||
|
||||
/**
|
||||
* 重复率弹框-取消录入
|
||||
*/
|
||||
onCancelRepeatModal = () => {
|
||||
this.repeatInfo = {};
|
||||
this.setState({
|
||||
isShowModalBox: false,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功的弹框
|
||||
*/
|
||||
successModalConfirm = () => {
|
||||
Modal.confirm({
|
||||
title: (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: 'rgba(60, 110, 238, 1)',
|
||||
fontSize: 16,
|
||||
}}>
|
||||
录入成功!贡献榜火力值 + 1
|
||||
</div>
|
||||
),
|
||||
closable: false,
|
||||
maskClosable: false,
|
||||
icon: ' ',
|
||||
onOk: this.onAgainSuccessModal,
|
||||
onCancel: this.onGoHomeSuccessModal,
|
||||
okText: '再录一题',
|
||||
cancelText: '去首页',
|
||||
className: 'questions-success-modal-confirm',
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-再来一题
|
||||
*/
|
||||
onAgainSuccessModal = () => {
|
||||
this.onCancel();
|
||||
};
|
||||
|
||||
/**
|
||||
* 录入成功弹框-去首页
|
||||
*/
|
||||
onGoHomeSuccessModal = () => {
|
||||
window.location.href = '/cms-supplier/question-bank';
|
||||
};
|
||||
|
||||
/**
|
||||
* 分类选择
|
||||
* @param {*} e
|
||||
*/
|
||||
onChangeRankLabel = (firstCategoryValue, secondCategoryValue, thirdCategoryValue) => {
|
||||
this.firstCategoryValue = firstCategoryValue; // 一级分类的值
|
||||
this.secondCategoryValue = secondCategoryValue; // 二级分类的值
|
||||
this.thirdCategoryValue = thirdCategoryValue; // 三级标签的值
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 职级选择
|
||||
* @param {*} list
|
||||
*/
|
||||
handleChangeRank = (list) => {
|
||||
this.rankId = list[0];
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 选项操作
|
||||
* @param {*} currentActive 选项列表
|
||||
* @param {*} scoreValue 分值
|
||||
* @param {*} subjectAnalysis 解析
|
||||
*/
|
||||
handleChangeOption = (currentActive, scoreValue, subjectAnalysis) => {
|
||||
this.currentActive = currentActive;
|
||||
this.scoreValue = scoreValue;
|
||||
this.subjectAnalysis = subjectAnalysis;
|
||||
let isDisabledSubmit = this.checkData();
|
||||
this.setState({
|
||||
isDisabledSubmit,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { subjectName, isDisabledSubmit, isSubmit, isShowModalBox } = this.state;
|
||||
const { questionsType } = this.props;
|
||||
return (
|
||||
<Spin spinning={!isSubmit}>
|
||||
<Fragment>
|
||||
<div className="single-questions-container">
|
||||
<div className="single-questions-title">题目名称:</div>
|
||||
<Input
|
||||
placeholder="输入题目"
|
||||
style={{ height: 48, width: '100%' }}
|
||||
value={subjectName}
|
||||
maxLength={64}
|
||||
onChange={(e) => this.onChangeSubjectName(e)}
|
||||
/>
|
||||
</div>
|
||||
<OptionInputBox
|
||||
key="single-option-input"
|
||||
ref={(ref) => {
|
||||
this.optionInputBox = ref;
|
||||
}}
|
||||
handleChangeOption={this.handleChangeOption}
|
||||
/>
|
||||
<RankLabelBox
|
||||
ref={(ref) => {
|
||||
this.rankLabelBox = ref;
|
||||
}}
|
||||
subjectName={subjectName}
|
||||
onChangeRankLabel={this.onChangeRankLabel}
|
||||
handleChangeRank={this.handleChangeRank}
|
||||
/>
|
||||
<div className="single-questions-btns-container">
|
||||
<div className="single-questions-btn" onClick={this.onCancel}>
|
||||
清空
|
||||
</div>
|
||||
<div
|
||||
className={`single-questions-btn single-questions-submit ${isDisabledSubmit && 'single-questions-disabled-submit'
|
||||
}`}
|
||||
onClick={this.onSubmit}>
|
||||
提交
|
||||
</div>
|
||||
</div>
|
||||
<RepeatContentBox
|
||||
isShowModalBox={isShowModalBox}
|
||||
repeatQuestionsType={questionsType}
|
||||
repeatInfo={this.repeatInfo}
|
||||
handleSubmitRepeatModal={this.onSubmitRepeatModal}
|
||||
handleCancelRepeatModal={this.onCancelRepeatModal}
|
||||
/>
|
||||
</Fragment>
|
||||
</Spin>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,53 @@
|
||||
.single-questions-container {
|
||||
width: 1000px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
padding-top: 36px;
|
||||
// label名字title
|
||||
.single-questions-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: 140px;
|
||||
line-height: 40px;
|
||||
font-size: 16px;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
&:before {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
margin-top: 1px;
|
||||
color: #f5222d;
|
||||
font-size: 16px;
|
||||
content: '*';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.single-questions-btns-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin: 20px auto;
|
||||
width: 952px;
|
||||
.single-questions-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.single-questions-submit {
|
||||
margin-left: 40px;
|
||||
background-color: #4390f7;
|
||||
color: #fff;
|
||||
border: 1px solid #4390f7;
|
||||
}
|
||||
.single-questions-disabled-submit {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import { Affix } from 'antd';
|
||||
import { RightOutlined } from '@ant-design/icons';
|
||||
import './index.less';
|
||||
|
||||
export default function UploadLeftLayout(props) {
|
||||
return (
|
||||
<Affix offsetTop={150}>
|
||||
<div className="upload-left-layout">
|
||||
{props.layoutList.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
className={`upload-left-layout-item ${item.active ? 'upload-left-layout-item-active' : ''
|
||||
}`}
|
||||
onClick={() => {
|
||||
props.onChange(index);
|
||||
}}
|
||||
key={`upload_left_layout_${item.id}`}>
|
||||
{item.title}
|
||||
<RightOutlined style={{ marginLeft: 54 }} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Affix>
|
||||
);
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
.upload-left-layout {
|
||||
width: 233px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-left: 26px;
|
||||
|
||||
.upload-left-layout-item {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding-right: 10px;
|
||||
margin-bottom: 20px;
|
||||
width: 207px;
|
||||
height: 48px;
|
||||
font-size: 16px;
|
||||
color: rgba(57, 60, 76, 1);
|
||||
transition: all 0.3s;
|
||||
background: rgba(255, 255, 255, 1);
|
||||
border: 1px solid rgba(208, 212, 222, 1);
|
||||
border-radius: 12px;
|
||||
&:hover {
|
||||
@include font-color(0.9);
|
||||
@include box-backgroundColor(0.3);
|
||||
}
|
||||
}
|
||||
.upload-left-layout-item-active {
|
||||
color: rgba(60, 110, 238, 1);
|
||||
font-weight: bold;
|
||||
background: rgba(60, 110, 238, 0.1);
|
||||
border: 1px solid rgba(60, 110, 238, 1);
|
||||
}
|
||||
}
|
139
src/views/upload-questions/constant.js
Normal file
139
src/views/upload-questions/constant.js
Normal file
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* API名称
|
||||
*/
|
||||
export const apiName = {
|
||||
/**
|
||||
* 获取一级/二级分类
|
||||
*/
|
||||
getInterviewCategory: '/admin/question/category/getCategory',
|
||||
|
||||
/**
|
||||
* 获取三级分类标签
|
||||
*/
|
||||
getRecommendLabel: '/admin/question/label/getRecommendLabel',
|
||||
/**
|
||||
* 新增题目
|
||||
*/
|
||||
addInterviewSubject: '/admin/question/subject/add',
|
||||
/**
|
||||
* 新增重复题目
|
||||
*/
|
||||
addRepeatInterviewSubject: '/admin/question/subject/addRepeatSubject',
|
||||
};
|
||||
|
||||
/**
|
||||
* 模块类型
|
||||
*/
|
||||
export const ModuleType = {
|
||||
default: 'default',
|
||||
second: 'second',
|
||||
third: 'third',
|
||||
};
|
||||
|
||||
/**
|
||||
* 导入职级对应的星
|
||||
*/
|
||||
export const starList = [
|
||||
{
|
||||
categoryId: 1,
|
||||
categoryName: 'T4',
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
categoryId: 2,
|
||||
categoryName: 'T5',
|
||||
},
|
||||
{
|
||||
categoryId: 3,
|
||||
categoryName: 'T6',
|
||||
},
|
||||
{
|
||||
categoryId: 4,
|
||||
categoryName: 'T7',
|
||||
},
|
||||
{
|
||||
categoryId: 5,
|
||||
categoryName: 'T8',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 模块类型
|
||||
*/
|
||||
export const uploadLayout = [
|
||||
{
|
||||
id: 1,
|
||||
title: '问答题',
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '单选题',
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '多选题',
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '判断题',
|
||||
active: false,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 数组索引对应字母
|
||||
*/
|
||||
export const optionLetter = {
|
||||
0: {
|
||||
label: 'A',
|
||||
value: 1,
|
||||
},
|
||||
1: {
|
||||
label: 'B',
|
||||
value: 2,
|
||||
},
|
||||
2: {
|
||||
label: 'C',
|
||||
value: 3,
|
||||
},
|
||||
3: {
|
||||
label: 'D',
|
||||
value: 4,
|
||||
},
|
||||
4: {
|
||||
label: 'E',
|
||||
value: 5,
|
||||
},
|
||||
5: {
|
||||
label: 'F',
|
||||
value: 6,
|
||||
},
|
||||
6: {
|
||||
label: 'G',
|
||||
value: 7,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 字母id对应字母
|
||||
*/
|
||||
export const letterList = {
|
||||
1: 'A',
|
||||
2: 'B',
|
||||
3: 'C',
|
||||
4: 'D',
|
||||
5: 'E',
|
||||
6: 'F',
|
||||
7: 'G',
|
||||
};
|
||||
|
||||
/**
|
||||
* 正确/错误
|
||||
*/
|
||||
export const judgeList = {
|
||||
0: '错误',
|
||||
1: '正确',
|
||||
};
|
19
src/views/upload-questions/index.less
Normal file
19
src/views/upload-questions/index.less
Normal file
@@ -0,0 +1,19 @@
|
||||
.upload-questions-box {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
width: 1439px;
|
||||
overflow-y: auto;
|
||||
border-radius: 5px;
|
||||
.ant-card-head {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 0 48px;
|
||||
z-index: 10;
|
||||
background-color: #fff;
|
||||
}
|
||||
.ant-card-body {
|
||||
display: flex;
|
||||
}
|
||||
}
|
49
src/views/upload-questions/index.tsx
Normal file
49
src/views/upload-questions/index.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Card } from 'antd';
|
||||
import SingleBox from './pages/single-box';
|
||||
import BatchleBox from './pages/batch-box';
|
||||
import './index.less';
|
||||
const tabList = [
|
||||
{
|
||||
key: 'singleBox',
|
||||
tab: '单题录入',
|
||||
},
|
||||
// {
|
||||
// key: 'batchBox',
|
||||
// tab: '批量导入',
|
||||
// },
|
||||
];
|
||||
export default class UploadQuestions extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { currentKey: 'singleBox' };
|
||||
}
|
||||
|
||||
contentList = {
|
||||
singleBox: <SingleBox />,
|
||||
batchBox: <BatchleBox />,
|
||||
};
|
||||
|
||||
onTabChange = (e) => {
|
||||
this.setState({
|
||||
currentKey: e,
|
||||
});
|
||||
};
|
||||
render() {
|
||||
const { currentKey } = this.state;
|
||||
return (
|
||||
<div className="upload-questions-box">
|
||||
<Card
|
||||
style={{ width: '100%' }}
|
||||
tabList={tabList}
|
||||
bordered={false}
|
||||
activeTabKey={currentKey}
|
||||
onTabChange={(key) => {
|
||||
this.onTabChange(key, 'key');
|
||||
}}>
|
||||
{this.contentList[currentKey]}
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
12
src/views/upload-questions/pages/batch-box/index.jsx
Normal file
12
src/views/upload-questions/pages/batch-box/index.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
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>;
|
||||
}
|
||||
}
|
7
src/views/upload-questions/pages/batch-box/index.less
Normal file
7
src/views/upload-questions/pages/batch-box/index.less
Normal file
@@ -0,0 +1,7 @@
|
||||
.upload-batch-questions-box {
|
||||
margin: 0 auto;
|
||||
width: 1000px;
|
||||
display: flex;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #3d3d3d;
|
||||
}
|
64
src/views/upload-questions/pages/single-box/index.jsx
Normal file
64
src/views/upload-questions/pages/single-box/index.jsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import React, { Component } from 'react';
|
||||
import UploadLeftLayout from '../../components/upload-left-layout';
|
||||
import BriefQuestions from '../../components/brief-questions';
|
||||
import SingleQuestions from '../../components/single-questions';
|
||||
import MultipleQuestions from '../../components/multiple-questions';
|
||||
import JudgeQuestions from '../../components/judge-questions';
|
||||
import { uploadLayout } from '../../constant';
|
||||
import './index.less';
|
||||
export default class SingleBox extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
layoutList: uploadLayout,
|
||||
currentIndex: 0,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 切换题型
|
||||
* @param {*} id
|
||||
*/
|
||||
onChangeQuestionsType = (layoutIndex) => {
|
||||
let { layoutList, currentIndex } = this.state;
|
||||
if (currentIndex === layoutIndex) {
|
||||
return;
|
||||
}
|
||||
let list = layoutList.map((item, index) => {
|
||||
let flag = false;
|
||||
if (layoutIndex === index) {
|
||||
flag = true;
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
active: flag,
|
||||
};
|
||||
});
|
||||
this.setState({
|
||||
layoutList: list,
|
||||
currentIndex: layoutIndex,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { currentIndex, layoutList } = this.state;
|
||||
return (
|
||||
<div style={{ display: 'flex' }}>
|
||||
<UploadLeftLayout layoutList={layoutList} onChange={this.onChangeQuestionsType} />
|
||||
<div className="upload-questions-modular">{this.changeReander(currentIndex)}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
changeReander = (i) => {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return <BriefQuestions questionsType={i + 1} key={`question_${i}`} />;
|
||||
case 1:
|
||||
return <SingleQuestions questionsType={i + 1} key={`question_${i}`} />;
|
||||
case 2:
|
||||
return <MultipleQuestions questionsType={i + 1} key={`question_${i}`} />;
|
||||
case 3:
|
||||
return <JudgeQuestions questionsType={i + 1} key={`question_${i}`} />;
|
||||
}
|
||||
};
|
||||
}
|
29
src/views/upload-questions/pages/single-box/index.less
Normal file
29
src/views/upload-questions/pages/single-box/index.less
Normal file
@@ -0,0 +1,29 @@
|
||||
.ant-modal-body {
|
||||
padding: 12px 24px 0;
|
||||
}
|
||||
.upload-questions-modular {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 auto;
|
||||
margin-left: 35px;
|
||||
background: rgba(249, 250, 252, 1);
|
||||
border: 2px solid rgba(240, 240, 240, 1);
|
||||
border-radius: 12px;
|
||||
}
|
||||
.questions-success-modal-confirm {
|
||||
width: 300px;
|
||||
// 录入成功弹框
|
||||
.ant-modal-confirm-btns {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
.ant-btn {
|
||||
width: 100px;
|
||||
border-radius: 18px;
|
||||
}
|
||||
.ant-btn-primary {
|
||||
background: rgba(60, 110, 238, 1);
|
||||
margin-left: 60px;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,7 +1,17 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
const path = require('path')
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, 'src'),
|
||||
'@assets': path.resolve(__dirname, 'src/assets'),
|
||||
'@views': path.resolve(__dirname, 'src/views'),
|
||||
'@utils': path.resolve(__dirname, 'src/utils'),
|
||||
'@components': path.resolve(__dirname, 'src/components')
|
||||
}
|
||||
},
|
||||
plugins: [react()]
|
||||
})
|
||||
|
Reference in New Issue
Block a user