Commit f48a2dd4 by yuananting

feat:题库代码优化

parent 3935654b
......@@ -2,8 +2,8 @@
* @Author: yuananting
* @Date: 2021-02-23 18:28:50
* @LastEditors: yuananting
* @LastEditTime: 2021-03-27 13:49:14
* @Description: 助学工具-题库-课程分类管理
* @LastEditTime: 2021-03-29 19:50:28
* @Description: 助学工具-课程分类
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
......@@ -32,8 +32,9 @@ class CourseCategoryManage extends Component {
this.state = {
NewEditCourseCategoryModal: null, //新增或编辑分类模态框
treeData: [],
originTreeData: [],
treeMap: {},
selectedKeys: ["0"],
selectedKeys: ["null"],
autoExpandParent: true,
};
}
......@@ -42,8 +43,34 @@ class CourseCategoryManage extends Component {
this.queryCategoryTree("search");
}
getWholeTree = () => {
let query = {
source: 0,
userId: User.getStoreUserId(),
tenantId: User.getStoreId(),
};
QuestionBankService.queryCategoryTree(query).then((res) => {
const { result } = res;
this.setState({ originTreeData: result }, () => {
let map = {};
let topItem = [];
result.forEach((item) => {
topItem.push(item);
});
this.setState({
treeMap: Object.assign(this.getTreeMap(result, map), {
0: {
sonCategoryList: topItem,
},
}),
});
});
});
};
// 查询分类树
queryCategoryTree = (operateType, categoryName) => {
this.getWholeTree();
this.setState({ categoryName });
let query = {
source: 0,
......@@ -67,7 +94,7 @@ class CourseCategoryManage extends Component {
this.setState({ expandedKeys: nodeId });
} else {
const defaultNode = {
id: "0",
id: "null",
categoryName: "未分类",
categoryCount: 0,
parentId: "0",
......@@ -88,16 +115,14 @@ class CourseCategoryManage extends Component {
} else {
this.setState({ autoExpandParent: false });
const defaultNode = {
id: "0",
id: "null",
categoryName: "未分类",
categoryCount: 0,
parentId: "0",
categoryLevel: 0,
};
result.unshift(defaultNode);
this.setState({
treeData: this.renderTreeNodes(result, categoryName),
});
this.setState({ treeData: this.renderTreeNodes(result, categoryName) });
if (operateType === "search") {
this.setState({ expandedKeys: [] });
}
......@@ -105,32 +130,144 @@ class CourseCategoryManage extends Component {
});
};
// 删除分类
delCategory = (item) => {
return confirm({
title: "确认删除该分类吗?",
content: "删除后,分类下的所有内容将自动转入“未分类”中。",
icon: (
<span className="icon iconfont default-confirm-icon">&#xe839; </span>
),
okText: "删除",
okType: "danger",
cancelText: "取消",
onOk: () => {
let params = {
categoryId: item.id,
source: 0,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
};
QuestionBankService.delCategory(params).then((res) => {
if (res.success) {
message.success("删除分类成功");
this.queryCategoryTree("change");
// 树节点渲染-内容处理
renderTreeNodes = (data, value) => {
let newTreeData = data.map((item) => {
item.title = item.categoryName;
item.key = item.id;
item.title = (
<div
style={{
opacity:
!value || (value && item.categoryName.indexOf(value) > -1)
? 1
: 0.5,
}}
className="node-title-div"
onMouseOver={(e) => {
let mouseNodeOpts = e.currentTarget.getElementsByTagName("div")[0];
if (mouseNodeOpts) {
mouseNodeOpts.style.visibility = "visible";
}
}}
onMouseOut={(e) => {
let mouseNodeOpts = e.currentTarget.getElementsByTagName("div")[0];
if (mouseNodeOpts) {
mouseNodeOpts.style.visibility = "hidden";
}
}}
>
<span>{item.categoryName}</span>
{item.categoryName !== "未分类" && (
<Space className="title-opts" size={16}>
<span
onClick={() => {
let nodesCount = 0;
const { originTreeData } = this.state;
console.log("orororo", originTreeData);
if (
(item.categoryLevel === 0 && originTreeData.length >= 29) ||
(item.categoryLevel > 0 &&
this.getRelatedNodes(item.parentId).length >= 30)
) {
return message.info("最多只能添加30个分类");
}
this.newEditCourseCategory(
"newEqualLevelCategory",
"equal",
"new",
item
);
}}
>
<span className="icon iconfont" style={{ color: "#BFBFBF" }}>
&#xe7f5;{" "}
</span>
<span>同级</span>
</span>
{item.categoryLevel < 4 && (
<span
onClick={() => {
if (
this.getRelatedNodes(item.id) &&
this.getRelatedNodes(item.id).length >= 30
) {
message.info("最多只能添加30个子分类");
return;
}
this.newEditCourseCategory(
"newChildLevelCategory",
"child",
"new",
item
);
}}
>
<span className="icon iconfont" style={{ color: "#BFBFBF" }}>
&#xe7f8;{" "}
</span>
<span>子级</span>
</span>
)}
<Dropdown overlay={this.initDropMenu(item)}>
<span>
<span className="icon iconfont" style={{ color: "#BFBFBF" }}>
&#xe7f7;{" "}
</span>
<span>更多</span>
</span>
</Dropdown>
</Space>
)}
</div>
);
item.icon =
item.categoryName === "未分类" ? (
<img
style={{
width: "24px",
height: "24px",
opacity:
!value || (value && item.categoryName.indexOf(value) > -1)
? 1
: 0.5,
}}
src="https://image.xiaomaiketang.com/xm/defaultCategory.png"
alt=""
/>
) : (
<img
style={{
width: "24px",
height: "24px",
opacity:
!value || (value && item.categoryName.indexOf(value) > -1)
? 1
: 0.5,
}}
src="https://image.xiaomaiketang.com/xm/hasCategory.png"
alt=""
/>
);
if (item.sonCategoryList) {
item.children = this.renderTreeNodes(item.sonCategoryList, value);
}
return item;
});
},
return newTreeData;
};
// 树结构平铺
getTreeMap = (data, map) => {
data.forEach((item) => {
map[item.id] = item;
if (item.sonCategoryList && item.sonCategoryList.length > 0) {
this.getTreeMap(item.sonCategoryList, map);
}
});
return map;
};
// 新增或编辑分类
......@@ -160,11 +297,10 @@ class CourseCategoryManage extends Component {
node={node}
addLevelType={addLevelType}
type={type}
treeData={this.state.treeData}
title={title}
label={label}
close={() => {
this.queryCategoryTree("change");
this.queryCategoryTree("change", this.state.categoryName);
this.setState({
NewEditCourseCategoryModal: null,
});
......@@ -174,6 +310,35 @@ class CourseCategoryManage extends Component {
this.setState({ NewEditCourseCategoryModal: m });
};
// 删除分类
delCategory = (item) => {
return confirm({
title: "确认删除该分类吗?",
content: "删除后,分类下的所有内容将自动转入“未分类”中。",
icon: (
<span className="icon iconfont default-confirm-icon">&#xe839; </span>
),
okText: "删除",
okType: "danger",
cancelText: "取消",
onOk: () => {
let params = {
categoryId: item.id,
source: 0,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
};
QuestionBankService.delCategory(params).then((res) => {
if (res.success) {
message.success("删除分类成功");
this.queryCategoryTree("change", this.state.categoryName);
}
});
},
});
};
// 更多操作-【重命名 删除】
initDropMenu = (item) => {
return (
<Menu>
......@@ -203,12 +368,14 @@ class CourseCategoryManage extends Component {
);
};
// 获取相关节点
getRelatedNodes = (parentId) => {
return this.state.treeMap[parentId]
? this.state.treeMap[parentId].sonCategoryList
: [];
};
// 获取拖拽目标父节点层级
getParentDragNodesLevel = (dragNode) => {
if (!dragNode) {
return [];
......@@ -224,6 +391,7 @@ class CourseCategoryManage extends Component {
return dragNodes;
};
// 获取拖拽节点层级
getDragNodesLevel = (dragNode) => {
let dragNodes = [];
if (dragNode.sonCategoryList && dragNode.sonCategoryList.length > 0) {
......@@ -237,6 +405,7 @@ class CourseCategoryManage extends Component {
return [...new Set(dragNodes)];
};
// 拖拽
onDrop = (info) => {
if (this.state.categoryName) {
return;
......@@ -257,6 +426,13 @@ class CourseCategoryManage extends Component {
return;
let targetParentId = info.dropToGap ? info.node.parentId : info.node.id;
let relatedNodes = this.getRelatedNodes(targetParentId);
if (
!(
(info.dropToGap && info.node.parentId === info.dragNode.parentId) ||
(!info.dropToGap && info.node.id === info.dragNode.parentId)
)
) {
if (this.state.treeMap[targetParentId].categoryLevel === 4) {
return message.info("最多支持5级分类");
} else {
......@@ -267,13 +443,13 @@ class CourseCategoryManage extends Component {
this.state.treeMap[targetParentId]
);
if (nodesArr.length + parentArr.length > 4) {
console.log(nodesArr.length, parentArr.length);
return message.info("最多支持5级分类");
}
}
let relatedNodes = this.getRelatedNodes(targetParentId);
if (relatedNodes && relatedNodes.length === 30) {
return message.info("最多只能添加30个子分类");
if (relatedNodes && relatedNodes.length >= 30) {
return message.info("最多只能添加30个分类");
}
}
const dropKey = info.node.key;
const dragKey = info.dragNode.key;
......@@ -389,186 +565,12 @@ class CourseCategoryManage extends Component {
return data;
};
/** 获取树状第一级key 设置默认展开第一项 */
getFirstLevelKeys = (data) => {
let firstLevelKeys = [];
data.forEach((item) => {
if (item.categoryLevel === 0) {
firstLevelKeys.push(item.key);
}
});
return firstLevelKeys;
};
/** 树状展开事件 */
// 树状展开事件
onExpand = (expandedKeys) => {
this.setState({ expandedKeys });
};
renderTreeNodes = (data, value) => {
let newTreeData = data.map((item) => {
item.title = item.categoryName;
item.key = item.id;
item.title = (
<div
style={{
opacity:
!value || (value && item.categoryName.indexOf(value) > -1)
? 1
: 0.5,
}}
className="node-title-div"
onMouseOver={(e) => {
let mouseNodeOpts = e.currentTarget.getElementsByTagName("div")[0];
if (mouseNodeOpts) {
mouseNodeOpts.style.visibility = "visible";
}
}}
onMouseOut={(e) => {
let mouseNodeOpts = e.currentTarget.getElementsByTagName("div")[0];
if (mouseNodeOpts) {
mouseNodeOpts.style.visibility = "hidden";
}
}}
>
<span>{item.categoryName}</span>
{item.categoryName !== "未分类" && (
<Space className="title-opts" size={16}>
<span
onClick={() => {
let nodesCount = 0;
const { treeData } = this.state;
if (item.categoryLevel === 0) {
// 第一层级
nodesCount = treeData.length;
} else {
let parentNodes = this.getRelatedNodes(item.parentId);
if (
parentNodes.length > 0 &&
parentNodes[0].sonCategoryList
) {
nodesCount = parentNodes[0].sonCategoryList.length;
} else {
nodesCount = 0;
}
}
if (nodesCount >= 30) {
message.info("最多只能添加30个分类");
return;
}
this.newEditCourseCategory(
"newEqualLevelCategory",
"equal",
"new",
item
);
}}
>
<span className="icon iconfont" style={{ color: "#BFBFBF" }}>
&#xe7f5;{" "}
</span>
<span>同级</span>
</span>
{item.categoryLevel < 4 && (
<span
onClick={() => {
if (
item.sonCategoryList &&
item.sonCategoryList.length >= 30
) {
message.info("最多只能添加30个子分类");
return;
}
this.newEditCourseCategory(
"newChildLevelCategory",
"child",
"new",
item
);
}}
>
<span className="icon iconfont" style={{ color: "#BFBFBF" }}>
&#xe7f8;{" "}
</span>
<span>子级</span>
</span>
)}
<Dropdown overlay={this.initDropMenu(item)}>
<span>
<span className="icon iconfont" style={{ color: "#BFBFBF" }}>
&#xe7f7;{" "}
</span>
<span>更多</span>
</span>
</Dropdown>
</Space>
)}
</div>
);
item.icon =
item.categoryName === "未分类" ? (
<img
style={{
width: "24px",
height: "24px",
opacity:
!value || (value && item.categoryName.indexOf(value) > -1)
? 1
: 0.5,
}}
src="https://image.xiaomaiketang.com/xm/defaultCategory.png"
alt=""
/>
) : (
<img
style={{
width: "24px",
height: "24px",
opacity:
!value || (value && item.categoryName.indexOf(value) > -1)
? 1
: 0.5,
}}
src="https://image.xiaomaiketang.com/xm/hasCategory.png"
alt=""
/>
);
if (item.sonCategoryList) {
item.children = this.renderTreeNodes(item.sonCategoryList, value);
}
return item;
});
let map = {};
let topItem = [];
data.forEach((item) => {
topItem.push(item);
});
this.setState({
treeMap: Object.assign(this.getTreeMap(data, map), {
0: {
sonCategoryList: topItem,
},
}),
});
return newTreeData;
};
getTreeMap = (data, map) => {
data.forEach((item) => {
map[item.id] = item;
if (item.sonCategoryList && item.sonCategoryList.length > 0) {
this.getTreeMap(item.sonCategoryList, map);
}
});
return map;
};
/** 树状选中事件 */
// 树状选中事件
onSelect = (selectedKeys) => {
this.setState({ selectedKeys });
};
......@@ -576,9 +578,11 @@ class CourseCategoryManage extends Component {
render() {
const {
treeData,
originTreeData,
expandedKeys,
selectedKeys,
autoExpandParent,
NewEditCourseCategoryModal,
} = this.state;
return (
<div className="page course-category-manage">
......@@ -608,7 +612,7 @@ class CourseCategoryManage extends Component {
<Button
type="primary"
onClick={() => {
if (treeData.length >= 30) {
if (originTreeData.length >= 29) {
message.info("最多只能添加30个分类");
return;
}
......@@ -641,7 +645,7 @@ class CourseCategoryManage extends Component {
></DirectoryTree>
</div>
</div>
{this.state.NewEditCourseCategoryModal}
{NewEditCourseCategoryModal}
</div>
);
}
......
/*
* @Author: yuananting
* @Date: 2021-02-23 19:41:42
* @LastEditors: yuananting
* @LastEditTime: 2021-03-27 13:49:00
* @Description: 助学工具-题库-课程分类管理样式
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
.course-category-manage {
.course-category-manage {
position: relative;
.search-condition {
width: 30%;
......@@ -22,7 +14,7 @@
position: relative;
margin-top: 16px;
width: 900px;
border: 1px solid #E8E8E8;
border: 1px solid #e8e8e8;
.ant-tree.ant-tree-directory {
font-size: 14px;
font-weight: 400;
......@@ -75,6 +67,6 @@
}
.ant-tree.ant-tree-directory .ant-tree-treenode:hover::before {
background-color: #F3F6FA;
background-color: #f3f6fa;
}
}
......@@ -2,8 +2,8 @@
* @Author: yuananting
* @Date: 2021-02-22 10:59:43
* @LastEditors: yuananting
* @LastEditTime: 2021-03-27 13:51:43
* @Description: 助学工具-题库-课程分类侧边栏
* @LastEditTime: 2021-03-29 16:17:53
* @Description: 助学工具-课程分类侧边栏
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
......@@ -18,14 +18,8 @@ const { DirectoryTree } = Tree;
class CourseCategorySiderTree extends Component {
constructor(props) {
super(props);
const categoryId = getParameterByName("categoryId");
this.state = {
selectedKeys: categoryId
? categoryId === "null"
? ["0"]
: [categoryId]
: ["0"],
searchValue: null,
selectedKeys: [getParameterByName("categoryId") || "null"],
treeData: this.props.treeData || [],
autoExpandParent: false,
};
......@@ -33,11 +27,9 @@ class CourseCategorySiderTree extends Component {
componentDidMount() {
this.queryCategoryTree("change");
this.props.getSelectedCategoryId(
getParameterByName("categoryId")
? [getParameterByName("categoryId")]
: ["0"]
);
this.props.getSelectedCategoryId([
getParameterByName("categoryId") || "null",
]);
}
shouldComponentUpdate(nextProps, nextState) {
......@@ -51,28 +43,6 @@ class CourseCategorySiderTree extends Component {
return true;
}
/** 获取树状第一级key 设置默认展开第一项 */
getFirstLevelKeys = (data) => {
let firstLevelKeys = [];
data.forEach((item) => {
if (item.categoryLevel === 0) {
firstLevelKeys.push(item.key);
}
});
return firstLevelKeys;
};
/** 树状展开事件 */
onExpand = (expandedKeys) => {
this.setState({ expandedKeys });
};
/** 树状选中事件 */
onSelect = (selectedKeys) => {
this.setState({ selectedKeys });
this.props.getSelectedCategoryId(selectedKeys);
};
// 查询分类树
queryCategoryTree = (type, categoryName) => {
let query = {
......@@ -99,7 +69,7 @@ class CourseCategorySiderTree extends Component {
}
} else {
const defaultNode = {
id: "0",
id: "null",
categoryName: "未分类",
categoryCount: noCategoryCnt,
parentId: "0",
......@@ -120,7 +90,7 @@ class CourseCategorySiderTree extends Component {
} else {
this.setState({ autoExpandParent: false });
const defaultNode = {
id: "0",
id: "null",
categoryName: "未分类",
categoryCount: noCategoryCnt,
parentId: "0",
......@@ -137,6 +107,7 @@ class CourseCategorySiderTree extends Component {
});
};
// 树结构平铺
getTreeMap = (data, map) => {
data.forEach((item) => {
map[item.id] = item;
......@@ -147,6 +118,18 @@ class CourseCategorySiderTree extends Component {
return map;
};
// 树状展开事件
onExpand = (expandedKeys) => {
this.setState({ expandedKeys });
};
// 树状选中事件
onSelect = (selectedKeys) => {
this.setState({ selectedKeys });
this.props.getSelectedCategoryId(selectedKeys);
};
// 树节点渲染-内容处理
renderTreeNodes = (data, value) => {
let newTreeData = data.map((item) => {
item.title = item.categoryName;
......@@ -164,13 +147,27 @@ class CourseCategorySiderTree extends Component {
item.icon =
item.categoryName === "未分类" ? (
<img
style={{ width: "24px", height: "24px", opacity: !value || (value && item.categoryName.indexOf(value) > -1) ? 1 : 0.5 }}
style={{
width: "24px",
height: "24px",
opacity:
!value || (value && item.categoryName.indexOf(value) > -1)
? 1
: 0.5,
}}
src="https://image.xiaomaiketang.com/xm/defaultCategory.png"
alt=""
/>
) : (
<img
style={{ width: "24px", height: "24px", opacity: !value || (value && item.categoryName.indexOf(value) > -1) ? 1 : 0.5 }}
style={{
width: "24px",
height: "24px",
opacity:
!value || (value && item.categoryName.indexOf(value) > -1)
? 1
: 0.5,
}}
src="https://image.xiaomaiketang.com/xm/hasCategory.png"
alt=""
/>
......
/*
* @Author: yuananting
* @Date: 2021-02-22 12:02:34
* @LastEditors: yuananting
* @LastEditTime: 2021-03-27 13:52:19
* @Description: 助学工具-题库-课程分类侧边栏样式
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
.category-tree-sider {
.category-tree-sider {
position: relative;
.sider-title {
height: 22px;
......@@ -68,6 +60,6 @@
}
.ant-tree.ant-tree-directory .ant-tree-treenode:hover::before {
background-color: #F3F6FA;
background-color: #f3f6fa;
}
}
......@@ -2,18 +2,29 @@
* @Author: yuananting
* @Date: 2021-03-27 16:15:13
* @LastEditors: yuananting
* @LastEditTime: 2021-03-27 18:19:13
* @LastEditTime: 2021-03-29 10:54:49
* @Description: 助学工具-新建试卷
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
import { Form, Button, Select, Input, Space, Table } from "antd";
import {
Form,
Button,
Select,
Input,
Space,
Table,
InputNumber,
ConfigProvider,
Empty,
} from "antd";
import { PlusOutlined } from "@ant-design/icons";
import ShowTips from "@/components/ShowTips";
import Breadcrumbs from "@/components/Breadcrumbs";
import { PageControl } from "@/components";
import "./NewExaminationPaper.less";
import SelectQuestionModal from "./modal/SelectQuestionModal";
const { TextArea } = Input;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
......@@ -25,6 +36,42 @@ const formItemLayout = {
},
};
class NewExaminationPaper extends Component {
constructor(props) {
super(props);
this.state = {
current: 1,
size: 10,
total: 20,
};
}
// 自定义表格空状态
customizeRenderEmpty = () => {
return (
<Empty
image="https://image.xiaomaiketang.com/xm/emptyTable.png"
imageStyle={{
height: 100,
}}
description={"请在右上角选择出题方式添加题"}
></Empty>
);
};
// 选择题目
chooseQuestion = () => {
const m = (
<SelectQuestionModal
close={() => {
this.setState({
SelectQuestionModal: null,
});
}}
/>
);
this.setState({ SelectQuestionModal: m });
}
render() {
const columns = [
{
......@@ -36,12 +83,24 @@ class NewExaminationPaper extends Component {
dataIndex: "questionType",
filters: [
{
text: "London",
value: "London",
text: "单选题",
value: "SINGLE_CHOICE",
},
{
text: "多选题",
value: "MULTI_CHOICE",
},
{
text: "判断题",
value: "JUDGE",
},
{
text: "填空题",
value: "GAP_FILLING",
},
{
text: "New York",
value: "New York",
text: "不定项选择题",
value: "INDEFINITE_CHOICE",
},
],
filterMultiple: false,
......@@ -50,37 +109,35 @@ class NewExaminationPaper extends Component {
{
title: "题目",
dataIndex: "questionContent",
},
];
const data = [
{
key: "1",
name: "John Brown",
age: 32,
address: "New York No. 1 Lake Park",
title: "分值",
dataIndex: "score",
render: (val) => {
return <InputNumber min={1} max={100} defaultValue={2} />;
},
{
key: "2",
name: "Jim Green",
age: 42,
address: "London No. 1 Lake Park",
},
{
key: "3",
name: "Joe Black",
age: 32,
address: "Sidney No. 1 Lake Park",
dataIndex: "extraScore",
render: (val) => {
return (
<div>
漏选得
<InputNumber defaultValue={0} />
</div>
);
},
},
{
key: "4",
name: "Jim Red",
age: 32,
address: "London No. 2 Lake Park",
title: "操作",
dataIndex: "operate",
render: (val, record) => <span>移除</span>,
},
];
const data = [];
const { current, size, total, SelectQuestionModal } = this.state;
return (
<div className="page new-examination-paper">
<Breadcrumbs navList={"新建试卷"} goBack={() => this.handleGoBack()} />
......@@ -105,13 +162,42 @@ class NewExaminationPaper extends Component {
>
<h1 style={{ fontSize: 16 }}>题目管理</h1>
<Space>
<Button icon={<PlusOutlined />}>自选题目</Button>
<Button icon={<PlusOutlined />} onClick={this.chooseQuestion}>自选题目</Button>
<Button icon={<PlusOutlined />}>系统抽题</Button>
<Button icon={<PlusOutlined />}>一人一卷</Button>
</Space>
</div>
<Form.Item>
<Table columns={columns} dataSource={data} />
<div>
总计40分,共20题。
单选题5题,共10分;多选题2题,共4分;判断题3题,共6分,填空题5题,共10分,不定项选择题5题,共10分
</div>
<ConfigProvider renderEmpty={this.customizeRenderEmpty}>
<Table columns={columns} dataSource={data} pagination={false} />
</ConfigProvider>
<div className="box-footer">
<PageControl
current={current - 1}
pageSize={size}
total={total}
toPage={(page) => {
const _query = { ...query, current: page + 1 };
this.setState({ query: _query }, () =>
this.queryQuestionPageList()
);
}}
showSizeChanger={true}
onShowSizeChange={this.onShowSizeChange}
/>
</div>
</Form.Item>
<Form.Item label="及格线:">
<div>
<InputNumber min={1} defaultValue={60} /> %
<span style={{ marginLeft: 20 }}>
总分(0)*及格线(60%)=及格分数(0)
</span>
</div>
</Form.Item>
</Form>
</div>
......@@ -120,6 +206,7 @@ class NewExaminationPaper extends Component {
<Button>预览</Button>
<Button type="primary">保存</Button>
</div>
{SelectQuestionModal}
</div>
);
}
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-02-25 11:23:47
* @LastEditors: yuananting
* @LastEditTime: 2021-03-27 16:54:25
* @LastEditTime: 2021-03-29 13:57:20
* @Description: 助学工具-题库-题目管理主页面列表数据
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -335,8 +335,6 @@ class ExaminationPaperContent extends Component {
/>
</div>
)}
{/* {this.state.QuestionPreviewModal} */}
{/* {this.state.ImportQuestionModal} */}
</div>
</div>
);
......
/*
* @Author: yuananting
* @Date: 2021-02-25 11:23:47
* @LastEditors: yuananting
* @LastEditTime: 2021-03-29 14:23:42
* @Description: 助学工具-新建试卷-选择题目列表
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
import {
Table,
ConfigProvider,
Empty,
Row,
Input,
Select,
Tooltip,
Space,
Button,
Modal,
message,
} from "antd";
import { PageControl } from "@/components";
import "./SelectQuestionContent.less";
import User from "@/common/js/user";
import QuestionBankService from "@/domains/question-bank-domain/QuestionBankService";
import _ from "underscore";
import ShowTips from "@/components/ShowTips";
const { Search } = Input;
const questionTypeEnum = {
SINGLE_CHOICE: "单选题",
MULTI_CHOICE: "多选题",
JUDGE: "判断题",
GAP_FILLING: "填空题",
INDEFINITE_CHOICE: "不定项选择题",
};
const questionTypeList = [
{
label: "单选题",
value: "SINGLE_CHOICE",
},
{
label: "多选题",
value: "MULTI_CHOICE",
},
{
label: "判断题",
value: "JUDGE",
},
{
label: "填空题",
value: "GAP_FILLING",
},
{
label: "不定项选择题",
value: "INDEFINITE_CHOICE",
},
];
class QuestionListContent extends Component {
constructor(props) {
super(props);
this.state = {
query: {
current: 1,
size: 10,
order: "UPDATED_DESC", // 排序规则[ ACCURACY_DESC, ACCURACY_ASC, CREATED_DESC, CREATED_ASC, UPDATED_DESC, UPDATED_ASC ]
categoryId: null, // 当前题库分类Id
questionName: null, // 题目名称
questionType: null, // 题目类型
source: 0,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
},
questionTypeList: [], // 题型列表
dataSource: [],
totalCount: 0,
selectedRowKeys: [],
};
}
componentDidMount() {}
shouldComponentUpdate(nextProps, nextState) {
let { selectedCategoryId } = nextProps;
const _query = this.state.query;
if (this.props.selectedCategoryId !== selectedCategoryId) {
if (selectedCategoryId === "null") {
selectedCategoryId = null;
}
_query.categoryId = selectedCategoryId;
_query.questionName = null;
_query.questionType = null;
_query.current = 1;
this.setState({ query: _query }, () => this.queryQuestionPageList());
}
return true;
}
queryQuestionPageList = (remain) => {
const _query = this.state.query;
if (_query.categoryId === "0") _query.categoryId = null;
QuestionBankService.queryQuestionPageList(_query).then((res) => {
const { records = [], total = 0 } = res.result;
this.setState({ dataSource: records });
this.setState({ total }, () =>
this.props.updatedSiderTree(total, this.props.selectedCategoryId)
);
});
};
handleCreateQuestionBank = () => {
window.RCHistory.push({
pathname: `/create-new-question?categoryId=${this.state.query.categoryId}`,
});
};
delQuestionConfirm(record) {
return Modal.confirm({
title: "提示",
content: "确定要删除此题目吗?",
icon: (
<span className="icon iconfont default-confirm-icon">&#xe839; </span>
),
okText: "删除",
cancelText: "取消",
onOk: () => {
this.deleteQuestion(record);
},
});
}
deleteQuestion = (record) => {
let params = {
id: record.id,
source: 0,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
};
QuestionBankService.deleteQuestion(params).then((res) => {
if (res.success) {
message.success("删除成功");
const { query, total } = this.state;
const { size, current } = query;
const _query = query;
if (total / size < current) {
if (total % size === 1) {
_query.current = 1;
}
}
this.setState({ query: _query }, () => this.queryQuestionPageList());
}
});
};
// 排序
handleChangeTable = (pagination, filters, sorter) => {
const { columnKey, order } = sorter;
let sort = null;
if (columnKey === "accuracy" && order === "ascend") {
sort = "ACCURACY_ASC";
}
if (columnKey === "accuracy" && order === "descend") {
sort = "ACCURACY_DESC";
}
if (columnKey === "updateTime" && order === "ascend") {
sort = "UPDATED_ASC";
}
if (columnKey === "updateTime" && order === "descend") {
sort = "UPDATED_DESC";
}
const _query = this.state.query;
_query.order = sort || "UPDATED_DESC";
_query.current = 1;
this.setState({ query: _query }, () => this.queryQuestionPageList());
};
// 清空搜索条件
handleReset = () => {
const _query = {
...this.state.query,
current: 1,
order: "ACCURACY_DESC", // 排序规则
questionName: null, // 题目名称
questionType: null, // 题目类型
};
this.setState({ query: _query }, () => {
this.queryQuestionPageList();
});
};
toEditQuestion = (id, type) => {
const { categoryId } = this.state.query;
if (categoryId) {
window.RCHistory.push({
pathname: `/create-new-question?id=${id}&type=${type}&categoryId=${categoryId}`,
});
} else {
window.RCHistory.push({
pathname: `/create-new-question?id=${id}&type=${type}`,
});
}
};
// 表头设置
parseColumns = () => {
const isPermiss = ["CloudManager", "StoreManager"].includes(
User.getUserRole()
);
const columns = [
{
title: "题目",
key: "questionStem",
dataIndex: "questionStem",
ellipsis: {
showTitle: false,
},
render: (val, record) => {
var handleVal = val;
handleVal = handleVal.replace(/<(?!img|input).*?>/g, "");
handleVal = handleVal.replace(/<\s?input[^>]*>/gi, "_、");
handleVal = handleVal.replace(/<\s?img[^>]*>/gi, "【图片】");
handleVal = handleVal.replace(/\&nbsp\;/gi, " ");
return (
<Tooltip
overlayClassName="tool-list"
title={
<div style={{ maxWidth: 700, width: "auto" }}>{handleVal}</div>
}
placement="topLeft"
overlayStyle={{ maxWidth: 700 }}
>
{handleVal}
</Tooltip>
);
},
},
{
title: "题型",
key: "questionTypeEnum",
dataIndex: "questionTypeEnum",
render: (val) => {
return questionTypeEnum[val];
},
},
{
title: "正确率",
key: "accuracy",
dataIndex: "accuracy",
sorter: true,
showSorterTooltip: false,
render: (val) => {
return val + "%";
},
},
];
return columns;
};
// 自定义表格空状态
customizeRenderEmpty = () => {
const { categoryId } = this.state.query;
return (
<Empty
image="https://image.xiaomaiketang.com/xm/emptyTable.png"
imageStyle={{
height: 100,
}}
description={
<div>
<span>还没有题目</span>
{["CloudManager", "StoreManager"].includes(User.getUserRole()) &&
!["0", null].includes(categoryId) && (
<span>
,快去
<span
className="empty-list-tip"
onClick={() => {
this.handleCreateQuestionBank();
}}
>
新建一个
</span>
吧!
</span>
)}
</div>
}
></Empty>
);
};
onShowSizeChange = (current, size) => {
if (current == size) {
return;
}
let _query = this.state.query;
_query.size = size;
this.setState({ query: _query }, () => this.queryQuestionPageList());
};
// 改变搜索条件
handleChangeQuery = (searchType, value) => {
this.setState(
{
query: {
...this.state.query,
[searchType]: value || null,
current: 1,
},
},
() => {
if (searchType === "questionName") return;
this.queryQuestionPageList();
}
);
};
render() {
const { dataSource = [], total, query, selectedRowKeys } = this.state;
const { current, size, categoryId, questionName, questionType } = query;
const rowSelection = {
selectedRowKeys,
columnWidth: "48px",
};
return (
<div className="select-question-content">
<div className="select-question-filter">
<Row type="flex" justify="space-between" align="top">
<div className="search-condition">
<div className="search-condition__item">
<span className="search-label">题目:</span>
<Search
placeholder="搜索题目名称"
value={questionName}
style={{ width: "calc(100% - 84px)" }}
onChange={(e) => {
this.handleChangeQuery("questionName", e.target.value);
}}
onSearch={() => {
this.queryQuestionPageList();
}}
enterButton={<span className="icon iconfont">&#xe832;</span>}
/>
</div>
<div className="search-condition__item">
<span className="search-label">题型:</span>
<Select
placeholder="请选择题目类型"
value={questionType}
style={{ width: "calc(100% - 70px)" }}
showSearch
allowClear
enterButton={<span className="icon iconfont">&#xe832;</span>}
filterOption={(inputVal, option) =>
option.props.children.includes(inputVal)
}
onChange={(value) => {
if (_.isEmpty(value)) {
this.handleChangeQuery("questionType", value);
}
}}
onSelect={(value) => {
this.handleChangeQuery("questionType", value);
}}
>
{_.map(questionTypeList, (item, index) => {
return (
<Select.Option value={item.value} key={item.key}>
{item.label}
</Select.Option>
);
})}
</Select>
</div>
</div>
<div className="reset-fold-area">
<Tooltip title="清空筛选">
<span
className="resetBtn iconfont icon"
onClick={this.handleReset}
>
&#xe61b;{" "}
</span>
</Tooltip>
</div>
</Row>
</div>
<ShowTips
message={
<div>
<span>
已选{200}题(单选题{1}题、多选题{2}题、判断题{3}
题、填空题{4}题、不定项选择题{5}题)
</span>
<span style={{marginLeft: 20}}>清空</span>
</div>
}
/>
<div className="question-manage-list">
<ConfigProvider renderEmpty={this.customizeRenderEmpty}>
<Table
rowSelection={rowSelection}
rowKey={(record) => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
pagination={false}
bordered
onChange={this.handleChangeTable}
/>
</ConfigProvider>
<div className="box-footer">
<PageControl
current={current - 1}
pageSize={size}
total={total}
toPage={(page) => {
const _query = { ...query, current: page + 1 };
this.setState({ query: _query }, () =>
this.queryQuestionPageList()
);
}}
showSizeChanger={true}
onShowSizeChange={this.onShowSizeChange}
/>
</div>
</div>
</div>
);
}
}
export default QuestionListContent;
/*
* @Author: yuananting
* @Date: 2021-02-25 11:26:28
* @LastEditors: yuananting
* @LastEditTime: 2021-03-29 13:39:28
* @Description: 助学工具-题库-题目管理右侧内容样式
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
.select-question-content {
.select-question-filter {
position: relative;
.search-condition {
width: calc(100% - 80px);
display: flex;
align-items: center;
flex-wrap: wrap;
&__item {
width: 30%;
margin-right: 3%;
margin-bottom: 16px;
.search-label {
vertical-align: middle;
display: inline-block;
height: 32px;
line-height: 32px;
}
}
}
.reset-fold-area {
position: absolute;
right: 12px;
.resetBtn {
color: #999999;
font-size: 18px;
margin-right: 8px;
}
.fold-btn {
font-size: 14px;
color: #666666;
line-height: 20px;
.fold-icon {
font-size: 12px;
margin-left: 4px;
}
}
}
}
.data-icon {
cursor: pointer;
}
.question-manage-list {
position: relative;
margin-top: 16px;
.empty-list-tip {
color: #ffb714;
cursor: pointer;
}
.record-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.record-operate {
display: flex;
&__item {
color: #5289fa;
cursor: pointer;
&.split {
margin: 0 8px;
color: #bfbfbf;
}
}
}
}
}
.tool-list {
.ant-tooltip-inner {
max-width: 700px !important;
}
}
/*
* @Author: yuananting
* @Date: 2021-03-29 10:52:26
* @LastEditors: yuananting
* @LastEditTime: 2021-03-29 14:09:08
* @Description: 助学工具-新建试卷-选择题目弹窗
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
import { Modal } from "antd";
import CourseCategorySiderTree from "../../components/CourseCategorySiderTree";
import SelectQuestionContent from "../components/SelectQuestionContent";
import "./SelectQuestionModal.less"
class SelectQuestionModal extends Component {
constructor(props) {
super(props);
this.state = {
updatedCategoryId: null,
selectedCategoryId: null,
};
}
getCategoryIdFromSider = (selectedCategoryId) => {
if (selectedCategoryId && selectedCategoryId.length > 0) {
this.setState({ selectedCategoryId: selectedCategoryId[0] });
}
};
updatedSiderTreeFromList = (updatedCategoryId) => {
this.setState({ updatedCategoryId });
};
render() {
const { updatedCategoryId, selectedCategoryId } = this.state;
return (
<Modal
title="选择题目"
visible={true}
width={1200}
// onOk={handleOk}
onCancel={this.props.close}
className="select-question-modal"
>
<div className="box content-body">
<div
style={{ borderRight: "0.5px solid #EEEEEE", paddingRight: "4px" }}
>
<div className="sider">
<CourseCategorySiderTree
getSelectedCategoryId={this.getCategoryIdFromSider.bind(this)}
updatedCategoryId
/>
</div>
</div>
<div className="content">
<SelectQuestionContent
updatedSiderTree={this.updatedSiderTreeFromList.bind(this)}
selectedCategoryId
/>
</div>
</div>
</Modal>
);
}
}
export default SelectQuestionModal;
.select-question-modal {
.content-body {
display: flex;
.site-layout-background {
background: #fff;
}
.sider {
min-width: 244px;
}
.content {
width: 100%;
margin-left: 24px;
height: calc(100vh - 160px);
}
}
}
\ No newline at end of file
......@@ -2,12 +2,12 @@
* @Author: yuananting
* @Date: 2021-02-22 17:51:28
* @LastEditors: yuananting
* @LastEditTime: 2021-03-27 14:08:47
* @Description: 助学工具-题库-新建编辑课程分类模态框
* @LastEditTime: 2021-03-29 19:37:03
* @Description: 助学工具-新建编辑课程分类模态框
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
import { Modal, Form, Input, message } from "antd";
import { Modal, Form, Input } from "antd";
import User from "@/common/js/user";
import QuestionBankService from "@/domains/question-bank-domain/QuestionBankService";
class NewEditCourseCategoryModal extends Component {
......@@ -51,7 +51,7 @@ class NewEditCourseCategoryModal extends Component {
//新增
params.categoryName = categoryName;
if (addLevelType === "equal") {
params.parentId = node ? node.parentId : 0
params.parentId = node ? node.parentId : 0;
params.categoryLevel = node ? node.categoryLevel : 0;
} else {
params.parentId = node.id;
......@@ -86,29 +86,51 @@ class NewEditCourseCategoryModal extends Component {
}
};
// 校验是否重名
checkExist = (sameLevelNodes, categoryName) => {
if (sameLevelNodes.length > 0 && sameLevelNodes[0].parentId === "0") {
if (categoryName === "未分类") {
return true;
}
}
var result = null;
sameLevelNodes.forEach((item) => {
if (result != null) {
return result;
}
if (item.categoryName === categoryName) {
result = item;
}
});
return result;
};
// 查询同级节点
getEqualLevelNodes = (data, parentId) => {
let nodes = [];
data.forEach((item) => {
if (item.parentId === parentId) {
nodes.push(item);
}
if (item.children) {
nodes.push(...this.getEqualLevelNodes(item.children, parentId));
if (item.sonCategoryList) {
nodes.push(...this.getEqualLevelNodes(item.sonCategoryList, parentId));
}
});
return nodes;
};
// 查询子级节点
getChildLevelNodes = (data, id) => {
let nodes = [];
data.forEach((item) => {
if (item.id === id && item.children) {
nodes.push(...item.children);
if (item.id === id && item.sonCategoryList) {
nodes.push(...item.sonCategoryList);
}
if (item.children) {
nodes.push(...this.getChildLevelNodes(item.children, id));
if (item.sonCategoryList) {
nodes.push(...this.getChildLevelNodes(item.sonCategoryList, id));
}
});
console.log(nodes)
return nodes;
};
......@@ -123,28 +145,9 @@ class NewEditCourseCategoryModal extends Component {
return sameLevelNodes;
};
// 查询是否重名
checkExist = (sameLevelNodes, categoryName) => {
if ((sameLevelNodes.length > 0 && sameLevelNodes[0].parentId === "0")) {
if (categoryName === "未分类") {
return true;
}
}
var result = null;
sameLevelNodes.forEach((item) => {
if (result != null) {
return result;
}
if (item.categoryName === categoryName) {
result = item;
}
});
return result;
};
render() {
const { title, label, treeData, addLevelType } = this.props;
const { categoryName } = this.state;
const { title, label, addLevelType } = this.props;
const { categoryName, treeData } = this.state;
const _that = this;
return (
<Modal
......
......@@ -2,8 +2,8 @@
* @Author: yuananting
* @Date: 2021-02-25 13:46:35
* @LastEditors: yuananting
* @LastEditTime: 2021-03-27 14:42:23
* @Description: 助学工具-题库-题目管理-新增题目
* @LastEditTime: 2021-03-29 20:24:01
* @Description: 助学工具-题库-新建题目
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
......@@ -59,6 +59,7 @@ class AddNewQuestion extends Component {
return p;
};
// 编辑题目时获取相应题目详情
queryQuestionDetails = () => {
let query = {
id: getParameterByName("id"),
......@@ -104,6 +105,7 @@ class AddNewQuestion extends Component {
});
};
// 保存并继续添加时重新构建题目结构
handleRest = (type) => {
this.setState({ currentOperate: "add" });
switch (type) {
......@@ -147,6 +149,67 @@ class AddNewQuestion extends Component {
chooseOptions.push(defineJudgeOptionInfo(content));
};
// 取消编辑并返回上一级路由
handleGoBack = () => {
Modal.confirm({
title: "确定要返回吗?",
content: "返回后,本次编辑的内容将不被保存",
okText: "确认返回",
cancelText: "留在本页",
icon: (
<span className="icon iconfont default-confirm-icon">&#xe6f4;</span>
),
onOk: () => {
window.RCHistory.push({
pathname: `/question-bank-index?categoryId=${getParameterByName("categoryId")}`,
});
},
});
};
// 校验保存题目
confirmSaveQuestion = (next) => {
const {
singleChoiceContent,
multiChoiceContent,
judgeContent,
gapFillingContent,
indefiniteChoiceContent,
} = this.state;
switch (this.state.activeKey) {
case "SINGLE_CHOICE":
if (this.singleChoiceRef.checkInput() === 0) {
this.saveCurrentQuestion(singleChoiceContent, "SINGLE_CHOICE", next);
}
break;
case "MULTI_CHOICE":
if (this.multiChoiceRef.checkInput() === 0) {
this.saveCurrentQuestion(multiChoiceContent, "MULTI_CHOICE", next);
}
break;
case "JUDGE":
if (this.judgeRef.checkInput() === 0) {
this.saveCurrentQuestion(judgeContent, "JUDGE", next);
}
break;
case "GAP_FILLING":
if (this.gapRef.checkInput() === 0) {
this.saveCurrentQuestion(gapFillingContent, "GAP_FILLING", next);
}
break;
case "INDEFINITE_CHOICE":
if (this.indefiniteRef.checkInput() === 0) {
this.saveCurrentQuestion(
indefiniteChoiceContent,
"INDEFINITE_CHOICE",
next
);
}
break;
}
};
// 确认保存题目
saveCurrentQuestion = (content, type, next) => {
content.questionStemList.map((item, index) => {
item.sort = index;
......@@ -169,7 +232,7 @@ class AddNewQuestion extends Component {
params = {
...content,
id: getParameterByName("id"),
categoryId: categoryId || null,
categoryId: categoryId === "null" ? null : categoryId,
source: 0,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
......@@ -183,7 +246,7 @@ class AddNewQuestion extends Component {
}
if (next === "close") {
window.RCHistory.push({
pathname: `/question-bank-index?categoryId=${params.categoryId}`,
pathname: `/question-bank-index?categoryId=${categoryId}`,
});
}
}
......@@ -191,7 +254,7 @@ class AddNewQuestion extends Component {
} else {
params = {
...content,
categoryId: getParameterByName("categoryId"),
categoryId,
source: 0,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
......@@ -204,7 +267,7 @@ class AddNewQuestion extends Component {
}
if (next === "close") {
window.RCHistory.push({
pathname: `/question-bank-index?categoryId=${params.categoryId}`,
pathname: `/question-bank-index?categoryId=${categoryId}`,
});
}
}
......@@ -212,63 +275,6 @@ class AddNewQuestion extends Component {
}
};
// 取消编辑并返回上一级路由
handleGoBack = () => {
Modal.confirm({
title: "确定要返回吗?",
content: "返回后,本次编辑的内容将不被保存",
okText: "确认返回",
cancelText: "留在本页",
icon: (
<span className="icon iconfont default-confirm-icon">&#xe6f4;</span>
),
onOk: () => {
window.RCHistory.goBack();
},
});
};
confirmSaveQuestion = (next) => {
const {
singleChoiceContent,
multiChoiceContent,
judgeContent,
gapFillingContent,
indefiniteChoiceContent,
} = this.state;
switch (this.state.activeKey) {
case "SINGLE_CHOICE":
if (this.singleChoiceRef.checkInput() === 0) {
this.saveCurrentQuestion(singleChoiceContent, "SINGLE_CHOICE", next);
}
break;
case "MULTI_CHOICE":
if (this.multiChoiceRef.checkInput() === 0) {
this.saveCurrentQuestion(multiChoiceContent, "MULTI_CHOICE", next);
}
break;
case "JUDGE":
if (this.judgeRef.checkInput() === 0) {
this.saveCurrentQuestion(judgeContent, "JUDGE", next);
}
break;
case "GAP_FILLING":
if (this.gapRef.checkInput() === 0) {
this.saveCurrentQuestion(gapFillingContent, "GAP_FILLING", next);
}
break;
case "INDEFINITE_CHOICE":
if (this.indefiniteRef.checkInput() === 0) {
this.saveCurrentQuestion(
indefiniteChoiceContent,
"INDEFINITE_CHOICE",
next
);
}
break;
}
};
handleLogger = (en, cn) => {
const { onLogger } = this.props;
onLogger && onLogger(en, cn);
......@@ -308,7 +314,13 @@ class AddNewQuestion extends Component {
<TabPane
tab={
<span>
<span className="icon iconfont" style={{ color: activeKey === "SINGLE_CHOICE" ? "#ffb714" : "#CCCCCC" }}>
<span
className="icon iconfont"
style={{
color:
activeKey === "SINGLE_CHOICE" ? "#ffb714" : "#CCCCCC",
}}
>
&#xe7fa;{" "}
</span>
<span>单选题</span>
......@@ -331,7 +343,13 @@ class AddNewQuestion extends Component {
<TabPane
tab={
<span>
<span className="icon iconfont" style={{ color: activeKey === "MULTI_CHOICE" ? "#ffb714" : "#CCCCCC" }}>
<span
className="icon iconfont"
style={{
color:
activeKey === "MULTI_CHOICE" ? "#ffb714" : "#CCCCCC",
}}
>
&#xe7fb;{" "}
</span>
<span>多选题</span>
......@@ -354,7 +372,12 @@ class AddNewQuestion extends Component {
<TabPane
tab={
<span>
<span className="icon iconfont" style={{ color: activeKey === "JUDGE" ? "#ffb714" : "#CCCCCC" }}>
<span
className="icon iconfont"
style={{
color: activeKey === "JUDGE" ? "#ffb714" : "#CCCCCC",
}}
>
&#xe7fc;{" "}
</span>
<span>判断题</span>
......@@ -376,7 +399,13 @@ class AddNewQuestion extends Component {
<TabPane
tab={
<span>
<span className="icon iconfont" style={{ color: activeKey === "GAP_FILLING" ? "#ffb714" : "#CCCCCC" }}>
<span
className="icon iconfont"
style={{
color:
activeKey === "GAP_FILLING" ? "#ffb714" : "#CCCCCC",
}}
>
&#xe7fd;{" "}
</span>
<span>填空题</span>
......@@ -398,12 +427,25 @@ class AddNewQuestion extends Component {
<TabPane
tab={
<span>
<span className="icon iconfont" style={{ color: activeKey === "INDEFINITE_CHOICE" ? "#ffb714" : "#CCCCCC" }}>
<span
className="icon iconfont"
style={{
color:
activeKey === "INDEFINITE_CHOICE"
? "#ffb714"
: "#CCCCCC",
}}
>
&#xe7fe;{" "}
</span>
<span>不定项选择题 </span>
<Tooltip title="至少有一项正确,至多不限的选择题,多项选择题的一种特殊形式">
<span className="icon iconfont" style={{ color: "#BFBFBF" }}>&#xe7c4;</span>
<span
className="icon iconfont"
style={{ color: "#BFBFBF" }}
>
&#xe7c4;
</span>
</Tooltip>
</span>
}
......
/*
* @Author: yuananting
* @Date: 2021-02-25 13:52:01
* @LastEditors: yuananting
* @LastEditTime: 2021-03-18 09:32:11
* @Description: 助学工具-题库-题目管理-新增题目样式
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
.add-new-question {
.add-new-question {
position: relative !important;
.box {
margin-bottom: 66px !important;
......
......@@ -2,11 +2,10 @@
* @Author: yuananting
* @Date: 2021-02-21 17:51:01
* @LastEditors: yuananting
* @LastEditTime: 2021-03-27 14:58:13
* @LastEditTime: 2021-03-29 16:11:41
* @Description: 助学工具-题库-题库主页面
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
import "./QuestionBankIndex.less";
import CourseCategorySiderTree from "../components/CourseCategorySiderTree";
......@@ -15,13 +14,9 @@ import QuestionManageContent from "./components/QuestionManageContent";
class QuestionBankIndex extends Component {
constructor(props) {
super(props);
this.state = {
selectedCategoryId: "",
};
this.state = {};
}
componentDidMount() {}
getCategoryIdFromSider = (selectedCategoryId) => {
if (selectedCategoryId && selectedCategoryId.length > 0) {
this.setState({ selectedCategoryId: selectedCategoryId[0] });
......
/*
* @Author: yuananting
* @Date: 2021-02-21 18:27:43
* @LastEditors: yuananting
* @LastEditTime: 2021-03-24 16:15:03
* @Description: 助学工具-题库-题库主页面样式
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
.question-bank-index {
.question-bank-index {
.content-body {
display: flex;
.site-layout-background {
......
......@@ -2,8 +2,8 @@
* @Author: yuananting
* @Date: 2021-02-25 14:34:29
* @LastEditors: yuananting
* @LastEditTime: 2021-03-27 14:45:03
* @Description: 助学工具-题库-题目管理-新建题目Tab
* @LastEditTime: 2021-03-29 16:22:15
* @Description: 助学工具-题库-新建题目Tab
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
......@@ -24,7 +24,10 @@ import {
NUM_TO_WORD_MAP,
MEDIA_FILE_ACCEPT,
} from "@/common/constants/punchClock/punchClock";
import { defineOptionInfo, defineJudgeOptionInfo } from "../../components/model";
import {
defineOptionInfo,
defineJudgeOptionInfo,
} from "../../components/model";
import XMAudio from "../../components/XMAudio";
import XMRecord from "../../components/XMRecord";
import ScanFileModal from "@/modules/resource-disk/modal/ScanFileModal";
......@@ -151,162 +154,7 @@ class NewQuestionTab extends Component {
});
};
transferStemDocument = (txt) => {
const template = `<div class='stem'>${txt}</div>`;
let doc = new DOMParser().parseFromString(template, "text/html");
let div = doc.querySelector(".stem");
return div;
};
// 保存校验
checkInput = () => {
let validateError = 0;
// 题干校验
let stemContent = _.find(
this.state.stemContent,
(contentItem) => contentItem.type === "RICH_TEXT"
);
let stem = stemContent.content.replace(/<[^>]+>/g, "");
stem = stem.replace(/\&nbsp\;/gi, "");
stem = stem.replace(/\s+/g, "");
if (this.props.questionTypeKey === "GAP_FILLING") {
if (this.state.blanksList.length === 0 || stem.length === 0) {
this.setState({
stemValidate: "error",
stemText: (
<div style={{ marginTop: 8, minWidth: "523px" }}>
请输入正确格式,示例:党章规定,凡事有
<span style={{ padding: "0 10px", borderBottom: "1px solid" }}>
填空1
</span>
人以上的
<span style={{ padding: "0 10px", borderBottom: "1px solid" }}>
填空2
</span>
,都应该成立党的基层组织
</div>
),
});
validateError++;
} else {
this.setState({ stemValidate: "success", stemText: "" });
}
} else {
if (stem.length === 0) {
this.setState({ stemValidate: "error", stemText: "请输入题干" });
validateError++;
} else {
this.setState({ stemValidate: "success", stemText: "" });
}
}
// 选项校验
let optionUnChecked = 0;
const { chooseOptions } = this.state;
if (this.props.questionTypeKey === "GAP_FILLING") {
this.state.gapFillingAnswer.forEach((item, index) => {
if (item.correctAnswerList.length === 0) {
this.setState({
[`optionsValidate_${index}`]: "error",
[`optionsText_${index}`]: "请输入答案",
});
validateError++;
} else {
this.setState({
[`optionsValidate_${index}`]: "success",
[`optionsText_${index}`]: "",
});
}
});
} else {
chooseOptions.forEach((item, index) => {
const optionContent = item.questionOptionContentList;
optionUnChecked = item.isCorrectAnswer
? optionUnChecked
: optionUnChecked + 1;
let optionInput = optionContent[0].content.replace(/<[^>]+>/g, "");
optionInput = optionInput.replace(/\&nbsp\;/gi, "");
optionInput = optionInput.replace(/\s+/g, "");
if (
optionContent.length === 1 &&
optionContent[0].type === "RICH_TEXT" &&
optionInput.length === 0
) {
this.setState({
[`optionsValidate_${index}`]: "error",
[`optionsText_${index}`]: "请输入选项",
});
validateError++;
} else {
this.setState({
[`optionsValidate_${index}`]: "success",
[`optionsText_${index}`]: "",
});
}
});
var chooseIcon = [];
if (["SINGLE_CHOICE", "JUDGE"].includes(this.props.questionTypeKey)) {
chooseIcon = document.getElementsByClassName("ant-radio-inner");
} else if (
["MULTI_CHOICE", "INDEFINITE_CHOICE"].includes(
this.props.questionTypeKey
)
) {
chooseIcon = document.getElementsByClassName("ant-checkbox-inner");
}
if (optionUnChecked === chooseOptions.length) {
this.setState({
radioValidate: "error",
radioText: (
<span>
正确答案
<br />
不能为空
</span>
),
});
chooseIcon.forEach((item) => {
item.setAttribute("style", "border:1px solid #ff4d4f;");
});
validateError++;
} else {
this.setState({ radioValidate: "success", radioText: "" });
chooseIcon.forEach((item) => {
item.removeAttribute("style");
});
}
if (
this.props.questionTypeKey === "MULTI_CHOICE" &&
this.state.chooseOptions.length - optionUnChecked === 1
) {
this.setState({ radioValidate: "error", radioText: "最少选两个" });
chooseIcon.forEach((item) => {
item.setAttribute("style", "border:1px solid #ff4d4f;");
});
validateError++;
}
}
return validateError;
};
/**
* 预览
*
* @memberof QuestionInputItem
*/
handleScanFile = (scanFileType, scanFileAddress) => {
this.setState({
showScanFile: true,
scanFileAddress,
scanFileType,
});
};
/**
* 添加选项
*
* @memberof QuestionInputItem
*/
// 添加选项
handleAddOption = (content) => {
const { chooseOptions } = this.state;
if (chooseOptions.length >= 20) {
......@@ -317,22 +165,7 @@ class NewQuestionTab extends Component {
}
};
/**
* 初始化判断选项
*
* @memberof QuestionInputItem
*/
initJudgeOption = (content) => {
const { chooseOptions } = this.state;
chooseOptions.push(defineJudgeOptionInfo(content));
this._onSetState();
};
/**
* 删除选项
*
* @memberof QuestionInputItem
*/
// 删除选项
handleDelOption = (optionIndex) => {
const { chooseOptions } = this.state;
this.handleLogger("delete_option", "删除选项");
......@@ -344,11 +177,7 @@ class NewQuestionTab extends Component {
}
};
/**
* 移动选项
*
* @memberof QuestionInputItem
*/
// 移动选项
handleMoveOption = (optionIndex, moveLength) => {
const { chooseOptions } = this.state;
const optionItem = chooseOptions.splice(optionIndex + moveLength, 1);
......@@ -356,11 +185,8 @@ class NewQuestionTab extends Component {
chooseOptions.splice(optionIndex, 0, optionItem[0]);
this._onSetState();
};
/**
* 选择上传文件类型
*
* @memberof QuestionInputItem
*/
// 选择上传文件类型
handleChangeMedia = (key, uploadItemTarget, contentType) => {
const pictureMediaArr = _.filter(uploadItemTarget, (mediaItem) => {
return mediaItem.type === "PICTURE";
......@@ -577,6 +403,38 @@ class NewQuestionTab extends Component {
});
}
// 完成语音录制
handleFinishRecord = (mp3URL, duration) => {
const originArr = mp3URL.split(".");
const originType = originArr[originArr.length - 1];
this.state.onAudioFinish();
const { uploadItemTarget, contentType } = this.state;
uploadItemTarget.push({
contentType,
type: "AUDIO",
contentName: `${window.random_string(16)}.${originType}`, // 文件名
fileType: originType, // 文件后缀
content: mp3URL,
size: duration,
});
this._onSetState({ showRecord: false });
};
// 取消录制
handleCancelRecord = () => {
this.setState({ showRecord: false });
};
// 云盘文件筛选
handleSelectMedia = (file) => {
this.uploadFile(file);
this.setState({
showSelectFileModal: false,
});
};
// 填空内容改变-联动答案
changeBlankCount = (data, idx) => {
let _gap = this.state.gapFillingAnswer;
if (data.length === 0) {
......@@ -615,6 +473,7 @@ class NewQuestionTab extends Component {
);
};
// 填空-tag新增答案
addAnswerTag = (optionItem) => {
const _blanksList = this.state.blanksList;
_blanksList.forEach((item) => {
......@@ -625,7 +484,7 @@ class NewQuestionTab extends Component {
this.setState({ blanksList: _blanksList });
};
// 填空选项
// 确认输入填空选项
handleInputConfirm = (optionItem, val) => {
var tagContent = val.replace(/\&nbsp\;/gi, "");
tagContent = val.replace(/\s+/g, "");
......@@ -651,6 +510,7 @@ class NewQuestionTab extends Component {
);
};
// 填空-删除已填答案tag
handleTagClose = (optionItem, removedTag, removedIndex) => {
const _blanksList = this.state.blanksList;
const { gapFillingAnswer } = this.state;
......@@ -670,7 +530,7 @@ class NewQuestionTab extends Component {
);
};
// 输入框关闭
// 填空-输入框关闭
handleInputClose = (optionItem) => {
const _blanksList = this.state.blanksList;
_blanksList.forEach((item) => {
......@@ -682,16 +542,15 @@ class NewQuestionTab extends Component {
this.setState({ blanksList: _blanksList });
};
handleInputEdit = (optionItem, index) => {
const _blanksList = this.state.blanksList;
_blanksList.forEach((item) => {
if (item.id === optionItem.id) {
item.correctAnswerList.map();
}
});
this.setState({ blanksList: _blanksList });
// 填空-字符串转html
transferStemDocument = (txt) => {
const template = `<div class='stem'>${txt}</div>`;
let doc = new DOMParser().parseFromString(template, "text/html");
let div = doc.querySelector(".stem");
return div;
};
// 填空答案渲染
renderGapFillingAnswer = (optionItem, optionIndex) => {
const { gapFillingAnswer } = this.state;
const list =
......@@ -753,16 +612,161 @@ class NewQuestionTab extends Component {
);
};
// 初始化判断选项
initJudgeOption = (content) => {
const { chooseOptions } = this.state;
chooseOptions.push(defineJudgeOptionInfo(content));
this._onSetState();
};
// 判断题选项渲染
renderJudgeOption = (judgeOptions) => {
return (
<div dangerouslySetInnerHTML={{ __html: judgeOptions[0].content }} />
);
};
/**
* 渲染输入内容
*
* @memberof QuestionInputItem
*/
// 保存校验
checkInput = () => {
let validateError = 0;
// 题干校验
let stemContent = _.find(
this.state.stemContent,
(contentItem) => contentItem.type === "RICH_TEXT"
);
let stem = stemContent.content.replace(/<[^>]+>/g, "");
stem = stem.replace(/\&nbsp\;/gi, "");
stem = stem.replace(/\s+/g, "");
if (this.props.questionTypeKey === "GAP_FILLING") {
if (this.state.blanksList.length === 0 || stem.length === 0) {
this.setState({
stemValidate: "error",
stemText: (
<div style={{ marginTop: 8, minWidth: "523px" }}>
请输入正确格式,示例:党章规定,凡事有
<span style={{ padding: "0 10px", borderBottom: "1px solid" }}>
填空1
</span>
人以上的
<span style={{ padding: "0 10px", borderBottom: "1px solid" }}>
填空2
</span>
,都应该成立党的基层组织
</div>
),
});
validateError++;
} else {
this.setState({ stemValidate: "success", stemText: "" });
}
} else {
if (stem.length === 0) {
this.setState({ stemValidate: "error", stemText: "请输入题干" });
validateError++;
} else {
this.setState({ stemValidate: "success", stemText: "" });
}
}
// 选项校验
let optionUnChecked = 0;
const { chooseOptions } = this.state;
if (this.props.questionTypeKey === "GAP_FILLING") {
this.state.gapFillingAnswer.forEach((item, index) => {
if (item.correctAnswerList.length === 0) {
this.setState({
[`optionsValidate_${index}`]: "error",
[`optionsText_${index}`]: "请输入答案",
});
validateError++;
} else {
this.setState({
[`optionsValidate_${index}`]: "success",
[`optionsText_${index}`]: "",
});
}
});
} else {
chooseOptions.forEach((item, index) => {
const optionContent = item.questionOptionContentList;
optionUnChecked = item.isCorrectAnswer
? optionUnChecked
: optionUnChecked + 1;
let optionInput = optionContent[0].content.replace(/<[^>]+>/g, "");
optionInput = optionInput.replace(/\&nbsp\;/gi, "");
optionInput = optionInput.replace(/\s+/g, "");
if (
optionContent.length === 1 &&
optionContent[0].type === "RICH_TEXT" &&
optionInput.length === 0
) {
this.setState({
[`optionsValidate_${index}`]: "error",
[`optionsText_${index}`]: "请输入选项",
});
validateError++;
} else {
this.setState({
[`optionsValidate_${index}`]: "success",
[`optionsText_${index}`]: "",
});
}
});
var chooseIcon = [];
if (["SINGLE_CHOICE", "JUDGE"].includes(this.props.questionTypeKey)) {
chooseIcon = document.getElementsByClassName("ant-radio-inner");
} else if (
["MULTI_CHOICE", "INDEFINITE_CHOICE"].includes(
this.props.questionTypeKey
)
) {
chooseIcon = document.getElementsByClassName("ant-checkbox-inner");
}
if (optionUnChecked === chooseOptions.length) {
this.setState({
radioValidate: "error",
radioText: (
<span>
正确答案
<br />
不能为空
</span>
),
});
chooseIcon.forEach((item) => {
item.setAttribute("style", "border:1px solid #ff4d4f;");
});
validateError++;
} else {
this.setState({ radioValidate: "success", radioText: "" });
chooseIcon.forEach((item) => {
item.removeAttribute("style");
});
}
if (
this.props.questionTypeKey === "MULTI_CHOICE" &&
this.state.chooseOptions.length - optionUnChecked === 1
) {
this.setState({ radioValidate: "error", radioText: "最少选两个" });
chooseIcon.forEach((item) => {
item.setAttribute("style", "border:1px solid #ff4d4f;");
});
validateError++;
}
}
return validateError;
};
// 预览
handleScanFile = (scanFileType, scanFileAddress) => {
this.setState({
showScanFile: true,
scanFileAddress,
scanFileType,
});
};
// 渲染输入内容
renderContent = (
contentList,
placehold,
......@@ -1060,57 +1064,6 @@ class NewQuestionTab extends Component {
);
};
/**
* 取消上传
*
* @memberof QuestionInputItem
*/
handleAbort = (uploadItem, index) => {
const { uploadItemTarget } = this.state;
const { xhr } = uploadItem;
xhr && xhr.abort && xhr.abort();
uploadItemTarget.splice(index, 1);
this._onSetState();
};
/**
* 完成语音录制
*
* @memberof QuestionInputItem
*/
handleFinishRecord = (mp3URL, duration) => {
const originArr = mp3URL.split(".");
const originType = originArr[originArr.length - 1];
this.state.onAudioFinish();
const { uploadItemTarget, contentType } = this.state;
uploadItemTarget.push({
contentType,
type: "AUDIO",
contentName: `${window.random_string(16)}.${originType}`, // 文件名
fileType: originType, // 文件后缀
content: mp3URL,
size: duration,
});
this._onSetState({ showRecord: false });
};
/**
* 取消录制
*
* @memberof QuestionInputItem
*/
handleCancelRecord = () => {
this.setState({ showRecord: false });
};
handleSelectMedia = (file) => {
this.uploadFile(file);
this.setState({
showSelectFileModal: false,
});
};
render() {
const {
stemContent,
......
......@@ -175,12 +175,6 @@
margin-right: 187px;
}
// .question-item_options {
// display: flex;
// align-items: center;
// padding-bottom: 15px;
// }
.question-item_options__list {
flex: 1;
position: relative;
......@@ -440,38 +434,3 @@
}
}
}
.question_skeleton {
background: linear-gradient(90deg, #f2f2f2 25%, #e6e6e6 37%, #f2f2f2 63%);
background-size: 400% 100%;
animation: question-editor_skeleton__loading 1.4s ease infinite;
}
.question_skeleton__editor {
min-height: 33px;
max-height: 140px;
overflow: hidden;
}
.question_skeleton__img {
width: 88px;
height: 88px;
}
.question_skeleton__voice {
height: 48px;
width: 280px;
}
.question_skeleton__video {
width: 100%;
height: 100%;
}
@keyframes question-editor_skeleton__loading {
0% {
background-position: 100% 50%;
}
100% {
background-position: 0 50%;
}
}
......@@ -2,8 +2,8 @@
* @Author: yuananting
* @Date: 2021-02-25 11:23:47
* @LastEditors: yuananting
* @LastEditTime: 2021-03-27 15:30:34
* @Description: 助学工具-题库-题目管理主页面列表数据
* @LastEditTime: 2021-03-29 16:21:50
* @Description: 助学工具-题库-列表数据
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
......@@ -76,15 +76,12 @@ class QuestionManageContent extends Component {
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
},
questionTypeList: [], // 题型列表
dataSource: [],
totalCount: 0,
dataSource: [], // 题库列表
QuestionPreviewModal: null, // 题目预览模态框
BatchImportQuestionModal: null, // 批量导入模态框
};
}
componentDidMount() {}
shouldComponentUpdate(nextProps, nextState) {
let { selectedCategoryId } = nextProps;
const _query = this.state.query;
......@@ -101,9 +98,40 @@ class QuestionManageContent extends Component {
return true;
}
queryQuestionPageList = (remain) => {
// 改变搜索条件
handleChangeQuery = (searchType, value) => {
this.setState(
{
query: {
...this.state.query,
[searchType]: value || null,
current: 1,
},
},
() => {
if (searchType === "questionName") return;
this.queryQuestionPageList();
}
);
};
// 清空搜索条件
handleReset = () => {
const _query = {
...this.state.query,
current: 1,
order: "ACCURACY_DESC", // 排序规则
questionName: null, // 题目名称
questionType: null, // 题目类型
};
this.setState({ query: _query }, () => {
this.queryQuestionPageList();
});
};
// 题库列表查询
queryQuestionPageList = () => {
const _query = this.state.query;
if (_query.categoryId === "0") _query.categoryId = null;
QuestionBankService.queryQuestionPageList(_query).then((res) => {
const { records = [], total = 0 } = res.result;
this.setState({ dataSource: records });
......@@ -113,48 +141,37 @@ class QuestionManageContent extends Component {
});
};
handleCreateQuestionBank = () => {
window.RCHistory.push({
pathname: `/create-new-question?categoryId=${this.state.query.categoryId}`,
});
};
delQuestionConfirm(record) {
return Modal.confirm({
title: "提示",
content: "确定要删除此题目吗?",
icon: (
<span className="icon iconfont default-confirm-icon">&#xe839; </span>
),
okText: "删除",
cancelText: "取消",
onOk: () => {
this.deleteQuestion(record);
},
});
}
deleteQuestion = (record) => {
let params = {
id: record.id,
source: 0,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
};
QuestionBankService.deleteQuestion(params).then((res) => {
if (res.success) {
message.success("删除成功");
const { query, total } = this.state;
const { size, current } = query;
const _query = query;
if (total / size < current) {
if (total % size === 1) {
_query.current = 1;
}
}
this.setState({ query: _query }, () => this.queryQuestionPageList());
// 自定义表格空状态
customizeRenderEmpty = () => {
const { categoryId } = this.state.query;
return (
<Empty
image="https://image.xiaomaiketang.com/xm/emptyTable.png"
imageStyle={{
height: 100,
}}
description={
<div>
<span>还没有题目</span>
{["CloudManager", "StoreManager"].includes(User.getUserRole()) &&
categoryId && (
<span>
,快去
<span
className="empty-list-tip"
onClick={() => {
this.handleCreateQuestionBank();
}}
>
新建一个
</span>
吧!
</span>
)}
</div>
}
});
></Empty>
);
};
// 排序
......@@ -179,49 +196,9 @@ class QuestionManageContent extends Component {
this.setState({ query: _query }, () => this.queryQuestionPageList());
};
// 清空搜索条件
handleReset = () => {
const _query = {
...this.state.query,
current: 1,
order: "ACCURACY_DESC", // 排序规则
questionName: null, // 题目名称
questionType: null, // 题目类型
};
this.setState({ query: _query }, () => {
this.queryQuestionPageList();
});
};
previewQuestion = (id) => {
const m = (
<QuestionPreviewModal
id={id}
close={() => {
this.setState({
QuestionPreviewModal: null,
});
}}
/>
);
this.setState({ QuestionPreviewModal: m });
};
toEditQuestion = (id, type) => {
const { categoryId } = this.state.query;
if (categoryId) {
window.RCHistory.push({
pathname: `/create-new-question?id=${id}&type=${type}&categoryId=${categoryId}`,
});
} else {
window.RCHistory.push({
pathname: `/create-new-question?id=${id}&type=${type}`,
});
}
};
// 表头设置
parseColumns = () => {
// 权限判断
const isPermiss = ["CloudManager", "StoreManager"].includes(
User.getUserRole()
);
......@@ -233,7 +210,7 @@ class QuestionManageContent extends Component {
ellipsis: {
showTitle: false,
},
render: (val, record) => {
render: (val) => {
var handleVal = val;
handleVal = handleVal.replace(/<(?!img|input).*?>/g, "");
handleVal = handleVal.replace(/<\s?input[^>]*>/gi, "_、");
......@@ -305,7 +282,7 @@ class QuestionManageContent extends Component {
<div
className="record-operate__item"
onClick={() =>
this.toEditQuestion(record.id, record.questionTypeEnum)
this.editQuestion(record.id, record.questionTypeEnum)
}
>
编辑
......@@ -330,39 +307,7 @@ class QuestionManageContent extends Component {
return columns;
};
// 自定义表格空状态
customizeRenderEmpty = () => {
const { categoryId } = this.state.query;
return (
<Empty
image="https://image.xiaomaiketang.com/xm/emptyTable.png"
imageStyle={{
height: 100,
}}
description={
<div>
<span>还没有题目</span>
{["CloudManager", "StoreManager"].includes(User.getUserRole()) &&
!["0", null].includes(categoryId) && (
<span>
,快去
<span
className="empty-list-tip"
onClick={() => {
this.handleCreateQuestionBank();
}}
>
新建一个
</span>
吧!
</span>
)}
</div>
}
></Empty>
);
};
// 设置表格每页展示条数
onShowSizeChange = (current, size) => {
if (current == size) {
return;
......@@ -372,40 +317,100 @@ class QuestionManageContent extends Component {
this.setState({ query: _query }, () => this.queryQuestionPageList());
};
// 改变搜索条件
handleChangeQuery = (searchType, value) => {
this.setState(
{
query: {
...this.state.query,
[searchType]: value || null,
current: 1,
},
// 预览题目
previewQuestion = (id) => {
const m = (
<QuestionPreviewModal
id={id}
close={() => {
this.setState({
QuestionPreviewModal: null,
});
}}
/>
);
this.setState({ QuestionPreviewModal: m });
};
// 编辑题目
editQuestion = (id, type) => {
const { categoryId } = this.state.query;
window.RCHistory.push({
pathname: `/create-new-question?id=${id}&type=${type}&categoryId=${categoryId}`,
});
};
// 删除题目确认弹窗
delQuestionConfirm(record) {
return Modal.confirm({
title: "提示",
content: "确定要删除此题目吗?",
icon: (
<span className="icon iconfont default-confirm-icon">&#xe839; </span>
),
okText: "删除",
cancelText: "取消",
onOk: () => {
this.deleteQuestion(record);
},
() => {
if (searchType === "questionName") return;
this.queryQuestionPageList();
});
}
);
// 删除题目
deleteQuestion = (record) => {
let params = {
id: record.id,
source: 0,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
};
QuestionBankService.deleteQuestion(params).then((res) => {
if (res.success) {
message.success("删除成功");
const { query, total } = this.state;
const { size, current } = query;
const _query = query;
if (total / size < current) {
if (total % size === 1) {
_query.current = 1;
}
}
this.setState({ query: _query }, () => this.queryQuestionPageList());
}
});
};
// 创建题目-跳转新建页
handleCreateQuestionBank = () => {
window.RCHistory.push({
pathname: `/create-new-question?categoryId=${this.state.query.categoryId}`,
});
};
// 批量导入弹窗
batchImportQuestion = () => {
const { categoryId } = this.state.query;
const ImportQuestionModal = (
const m = (
<BatchImportQuestionModal
close={() => {
this.setState({ ImportQuestionModal: null }, () => {
this.setState({ BatchImportQuestionModal: null }, () => {
this.queryQuestionPageList();
});
}}
categoryId={categoryId}
/>
);
this.setState({ ImportQuestionModal });
this.setState({ BatchImportQuestionModal: m });
};
render() {
const { dataSource = [], total, query } = this.state;
const {
dataSource = [],
total,
query,
QuestionPreviewModal,
BatchImportQuestionModal,
} = this.state;
const { current, size, categoryId, questionName, questionType } = query;
return (
<div className="question-manage-content">
......@@ -473,7 +478,7 @@ class QuestionManageContent extends Component {
</Row>
</div>
{["CloudManager", "StoreManager"].includes(User.getUserRole()) &&
!["0", null].includes(categoryId) && (
categoryId && (
<Space size={16}>
<Button type="primary" onClick={this.handleCreateQuestionBank}>
新建题目
......@@ -509,8 +514,8 @@ class QuestionManageContent extends Component {
/>
</div>
)}
{this.state.QuestionPreviewModal}
{this.state.ImportQuestionModal}
{QuestionPreviewModal}
{BatchImportQuestionModal}
</div>
</div>
);
......
/*
* @Author: yuananting
* @Date: 2021-02-25 11:26:28
* @LastEditors: yuananting
* @LastEditTime: 2021-03-25 14:32:01
* @Description: 助学工具-题库-题目管理右侧内容样式
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
.question-manage-content {
.question-manage-filter {
position: relative;
......@@ -81,8 +73,3 @@
max-width: 700px !important;
}
}
.fill-line {
padding: 0 10px;
border-bottom: 1px solid;
}
/*
* @Author: zhangyi
* @Date: 2019-12-09 10:29:55
* @Last Modified by: mikey.wanghaofeng
* @Last Modified time: 2020-09-25 11:03:47
* @Author: yuananting
* @Date: 2021-03-27 11:15:03
* @LastEditors: yuananting
* @LastEditTime: 2021-03-29 16:22:28
* @Description: 助学工具-题库-批量导入题目
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
import { Modal, Button, message, Spin } from "antd";
import "./BatchImportQuestionModal.less";
......
@import '@/core/mixins.less';
@import "@/core/mixins.less";
.import-score-modal {
.step-section {
margin-bottom: 24px;
......@@ -48,7 +48,7 @@
}
}
.file-box :hover {
background-color: #FFF8E8;
background-color: #fff8e8;
.del-img {
visibility: visible !important;
}
......@@ -63,7 +63,7 @@
}
.down-btn {
text-align: left;
color: #5289FA;
color: #5289fa;
font-size: 12px;
display: block;
margin-top: 8px;
......@@ -73,18 +73,18 @@
width: 200px;
.ant-upload-list-item-name {
.text-overflow-ellipsis();
width:70%;
width: 70%;
}
}
}
.import-status-box {
height:430px;
height: 430px;
overflow: hidden;
.status-content {
margin:auto;
margin: auto;
text-align: center;
margin-top:100px;
>img {
margin-top: 100px;
> img {
width: 76px;
}
.status {
......@@ -97,7 +97,7 @@
color: #666666;
margin-bottom: 16px;
.num {
color: #FC9C6B;
color: #fc9c6b;
}
}
}
......
/*
* @Author: yuananting
* @Date: 2021-03-27 11:15:03
* @LastEditors: yuananting
* @LastEditTime: 2021-03-29 16:19:35
* @Description: 助学工具-题库-预览题目
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
import { Modal } from "antd";
import User from "@/common/js/user";
......@@ -42,6 +50,7 @@ class QuestionPreviewModal extends Component {
});
};
// 查看图片或视频
handleScanFile = (scanFileType, scanFileAddress) => {
this.setState({
showScanFile: true,
......@@ -50,13 +59,6 @@ class QuestionPreviewModal extends Component {
});
};
transferStemDocument = (txt) => {
const template = `<p class='content'>${txt}</p>`;
let doc = new DOMParser().parseFromString(template, "text/html");
let p = doc.querySelector(".content");
return p;
};
render() {
const {
showScanFile,
......@@ -225,7 +227,10 @@ class QuestionPreviewModal extends Component {
)}
{["JUDGE"].includes(questionTypeEnum) &&
_.map(questionOptionContentList, (item, index) => {
item.content = item.content.replace(/<\/?[^>]*>/g, "");
item.content = item.content.replace(
/<\/?[^>]*>/g,
""
);
return <span key={index}>{item.content}</span>;
})}
</div>
......
......@@ -17,7 +17,7 @@
}
.question-stem {
margin-bottom: 16px;
border-bottom: 1px solid #E8E8E8;
border-bottom: 1px solid #e8e8e8;
padding-bottom: 16px;
&__title {
height: 22px;
......@@ -140,7 +140,7 @@
}
.question-answer {
margin-bottom: 16px;
border-bottom: 1px solid #E8E8E8;
border-bottom: 1px solid #e8e8e8;
padding-bottom: 16px;
img {
max-width: 88px;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment