Commit 96b7a4c4 by yuananting

feat:题目模块联调

parent 69411c9a
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: yuananting * @Author: yuananting
* @Date: 2021-03-03 15:13:12 * @Date: 2021-03-03 15:13:12
* @LastEditors: yuananting * @LastEditors: yuananting
* @LastEditTime: 2021-03-13 20:46:54 * @LastEditTime: 2021-03-15 19:44:31
* @Description: 助学工具接口 * @Description: 助学工具接口
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -43,4 +43,12 @@ export function addQuestion(params: object) { ...@@ -43,4 +43,12 @@ export function addQuestion(params: object) {
export function deleteQuestion(params: object) { export function deleteQuestion(params: object) {
return Service.Hades("anon/hades/question/deleteQuestion", params); return Service.Hades("anon/hades/question/deleteQuestion", params);
}
export function queryQuestionDetails(params: object) {
return Service.Hades("anon/hades/question/queryQuestionDetails", params);
}
export function editQuestion(params: object) {
return Service.Hades("anon/hades/question/editQuestion", params);
} }
\ No newline at end of file
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
* @Author: yuananting * @Author: yuananting
* @Date: 2021-03-11 11:34:37 * @Date: 2021-03-11 11:34:37
* @LastEditors: yuananting * @LastEditors: yuananting
* @LastEditTime: 2021-03-13 20:46:28 * @LastEditTime: 2021-03-15 19:45:10
* @Description: 描述一下咯 * @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import { queryCategoryTree, addCategory, delCategory, editCategory, editCategoryTree, queryQuestionCategoryTree, addQuestion, queryQuestionPageList, deleteQuestion } from '@/data-source/questionBank/request-apis'; import { queryCategoryTree, addCategory, delCategory, editCategory, editCategoryTree, queryQuestionCategoryTree, addQuestion, queryQuestionPageList, deleteQuestion, queryQuestionDetails, editQuestion } from '@/data-source/questionBank/request-apis';
export default class QuestionBankService { export default class QuestionBankService {
// 获取题目分类树 // 获取题目分类树
static queryCategoryTree(params: any) { static queryCategoryTree(params: any) {
...@@ -52,4 +52,14 @@ export default class QuestionBankService { ...@@ -52,4 +52,14 @@ export default class QuestionBankService {
static deleteQuestion(params: any) { static deleteQuestion(params: any) {
return deleteQuestion(params); return deleteQuestion(params);
} }
// 预览题目
static queryQuestionDetails(params: any) {
return queryQuestionDetails(params);
}
// 编辑题目
static editQuestion(params: any) {
return editQuestion(params);
}
} }
\ No newline at end of file
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
* @Author: yuananting * @Author: yuananting
* @Date: 2021-02-25 13:46:35 * @Date: 2021-02-25 13:46:35
* @LastEditors: yuananting * @LastEditors: yuananting
* @LastEditTime: 2021-03-13 20:12:14 * @LastEditTime: 2021-03-15 21:14:47
* @Description: 助学工具-题库-题目管理-新增题目 * @Description: 助学工具-题库-题目管理-新增题目
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import React, { Component } from "react"; import React, { Component } from "react";
import { Tabs, Button, Tooltip } from "antd"; import { Tabs, Button, Tooltip, message } from "antd";
import Breadcrumbs from "@/components/Breadcrumbs"; import Breadcrumbs from "@/components/Breadcrumbs";
import ShowTips from "@/components/ShowTips"; import ShowTips from "@/components/ShowTips";
import "./AddNewQuestion.less"; import "./AddNewQuestion.less";
...@@ -21,7 +21,7 @@ class AddNewQuestion extends Component { ...@@ -21,7 +21,7 @@ class AddNewQuestion extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
activeKey: "SINGLE_CHOICE", activeKey: getParameterByName("type") || "SINGLE_CHOICE",
// 构建题目基本结构 // 构建题目基本结构
singleChoiceContent: defineQuestionInfo("SINGLE_CHOICE"), // 单选题 singleChoiceContent: defineQuestionInfo("SINGLE_CHOICE"), // 单选题
multiChoiceContent: defineQuestionInfo("MULTI_CHOICE"), // 多选题 multiChoiceContent: defineQuestionInfo("MULTI_CHOICE"), // 多选题
...@@ -31,34 +31,97 @@ class AddNewQuestion extends Component { ...@@ -31,34 +31,97 @@ class AddNewQuestion extends Component {
}; };
} }
componentDidMount() {} componentDidMount() {
if (getParameterByName("id")) {
// 编辑
this.queryQuestionDetails();
}
}
queryQuestionDetails = () => {
let query = {
id: getParameterByName("id"),
source: 0,
userId: User.getStoreUserId(),
tenantId: User.getStoreId(),
};
QuestionBankService.queryQuestionDetails(query).then((res) => {
const { result = [] } = res;
const { questionTypeEnum } = result;
switch (questionTypeEnum) {
case "SINGLE_CHOICE":
this.setState({ singleChoiceContent: result });
break;
case "MULTI_CHOICE":
this.setState({ multiChoiceContent: result });
break;
case "JUDGE":
this.setState({ judgeContent: result });
break;
case "GAP_FILLING":
this.setState({ gapFillingContent: result });
break;
case "INDEFINITE_CHOICE":
this.setState({ indefiniteChoiceContent: result });
break;
}
});
};
saveCurrentQuestion = (content) => { saveCurrentQuestion = (content) => {
content.questionStemList.map((item, index)=> { content.questionStemList.map((item, index) => {
item.sort = index; item.sort = index;
return item; return item;
}) });
content.optionList.map((item)=> { content.optionList.map((item) => {
item.questionOptionContentList.map((childItem, childIndex) => { item.questionOptionContentList.map((childItem, childIndex) => {
childItem.sort = childIndex; childItem.sort = childIndex;
return childItem; return childItem;
}) });
return item; return item;
}) });
content.questionAnswerDescList.map((item, index)=> { content.questionAnswerDescList.map((item, index) => {
item.sort = index; item.sort = index;
return item; return item;
})
let params = {
...content,
categoryId: getParameterByName("categoryId"),
source: 0,
tenantId: User.getStoreId(),
userId: User.getUserId(),
};
QuestionBankService.addQuestion(params).then((res) => {
console.log(res);
}); });
let params = {};
let categoryId = getParameterByName("categoryId");
if (getParameterByName("id")) {
params = {
...content,
id: getParameterByName("id"),
categoryId: categoryId || null,
source: 0,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
};
QuestionBankService.editQuestion(params).then((res) => {
if (res.success) {
message.success("保存成功");
window.RCHistory.push({
pathname: `/question-bank-index?categoryId=${params.categoryId}`,
});
}
});
} else {
params = {
...content,
categoryId: getParameterByName("categoryId"),
source: 0,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
};
QuestionBankService.addQuestion(params).then((res) => {
if (res.success) {
message.success("保存成功");
window.RCHistory.push({
pathname: `/question-bank-index?categoryId=${params.categoryId}`,
});
}
});
}
}; };
confirmSaveQuestion = () => { confirmSaveQuestion = () => {
...@@ -71,12 +134,14 @@ class AddNewQuestion extends Component { ...@@ -71,12 +134,14 @@ class AddNewQuestion extends Component {
} = this.state; } = this.state;
switch (this.state.activeKey) { switch (this.state.activeKey) {
case "SINGLE_CHOICE": case "SINGLE_CHOICE":
if (this.singleRef.checkInput() === 0) { if (this.singleChoiceRef.checkInput() === 0) {
this.saveCurrentQuestion(singleChoiceContent); this.saveCurrentQuestion(singleChoiceContent);
} }
break; break;
case "MULTI_CHOICE": case "MULTI_CHOICE":
this.multipleRef.checkInput(); if (this.multiChoiceRef.checkInput() === 0) {
this.saveCurrentQuestion(multiChoiceContent);
}
break; break;
case "JUDGE": case "JUDGE":
this.judgeRef.checkInput(); this.judgeRef.checkInput();
...@@ -85,19 +150,21 @@ class AddNewQuestion extends Component { ...@@ -85,19 +150,21 @@ class AddNewQuestion extends Component {
this.CompletionRef.checkInput(); this.CompletionRef.checkInput();
break; break;
case "INDEFINITE_CHOICE": case "INDEFINITE_CHOICE":
this.indefiniteRef.checkInput(); if (this.indefiniteRef.checkInput() === 0) {
this.saveCurrentQuestion(indefiniteChoiceContent);
}
break; break;
} }
}; };
handleLogger = (en, cn) => {
const { onLogger } = this.props;
onLogger && onLogger(en, cn);
};
render() { render() {
const { const {
activeKey, activeKey,
singleContent,
multipleContent,
judgeContent1,
completionContent,
indefiniteContent,
singleChoiceContent, singleChoiceContent,
multiChoiceContent, multiChoiceContent,
judgeContent, judgeContent,
...@@ -106,7 +173,10 @@ class AddNewQuestion extends Component { ...@@ -106,7 +173,10 @@ class AddNewQuestion extends Component {
} = this.state; } = this.state;
return ( return (
<div className="page add-new-question"> <div className="page add-new-question">
<Breadcrumbs navList="新增题目" goBack={() => RCHistory.goBack()} /> <Breadcrumbs
navList={getParameterByName("id") ? "编辑题目" : "新增题目"}
goBack={() => RCHistory.goBack()}
/>
<div className="box"> <div className="box">
<div className="show-tips"> <div className="show-tips">
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企培保有依据国家规定及平台规则进行处理的权利" /> <ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企培保有依据国家规定及平台规则进行处理的权利" />
...@@ -125,13 +195,13 @@ class AddNewQuestion extends Component { ...@@ -125,13 +195,13 @@ class AddNewQuestion extends Component {
<NewQuestionTab <NewQuestionTab
questionTypeKey="SINGLE_CHOICE" questionTypeKey="SINGLE_CHOICE"
onRef={(ref) => { onRef={(ref) => {
this.singleRef = ref; this.singleChoiceRef = ref;
}} }}
questionInfo={singleChoiceContent} questionInfo={singleChoiceContent}
onSetState={(newContent) => { onSetState={(newContent) => {
console.log(newContent);
Object.assign(singleChoiceContent, newContent); Object.assign(singleChoiceContent, newContent);
}} }}
onLogger={this.handleLogger}
/> />
</TabPane> </TabPane>
<TabPane <TabPane
...@@ -141,12 +211,13 @@ class AddNewQuestion extends Component { ...@@ -141,12 +211,13 @@ class AddNewQuestion extends Component {
<NewQuestionTab <NewQuestionTab
questionTypeKey="MULTI_CHOICE" questionTypeKey="MULTI_CHOICE"
onRef={(ref) => { onRef={(ref) => {
this.multipleRef = ref; this.multiChoiceRef = ref;
}} }}
questionInfo={multiChoiceContent} questionInfo={multiChoiceContent}
onSetState={(newContent) => { onSetState={(newContent) => {
Object.assign(multiChoiceContent, newContent); Object.assign(multiChoiceContent, newContent);
}} }}
onLogger={this.handleLogger}
/> />
</TabPane> </TabPane>
<TabPane <TabPane
...@@ -199,6 +270,7 @@ class AddNewQuestion extends Component { ...@@ -199,6 +270,7 @@ class AddNewQuestion extends Component {
onSetState={(newContent) => { onSetState={(newContent) => {
Object.assign(indefiniteChoiceContent, newContent); Object.assign(indefiniteChoiceContent, newContent);
}} }}
onLogger={this.handleLogger}
/> />
</TabPane> </TabPane>
</Tabs> </Tabs>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: yuananting * @Author: yuananting
* @Date: 2021-02-21 17:51:01 * @Date: 2021-02-21 17:51:01
* @LastEditors: yuananting * @LastEditors: yuananting
* @LastEditTime: 2021-03-13 16:48:23 * @LastEditTime: 2021-03-15 14:46:12
* @Description: 助学工具-题库-题库主页面 * @Description: 助学工具-题库-题库主页面
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
import React, { Component } from "react"; import React, { Component } from "react";
import "./QuestionBankIndex.less"; import "./QuestionBankIndex.less";
import QuestionBankSider from "./components/QuestionBankSider"; import QuestionBankSider from "./components/QuestionBankSider";
import QuestionManageList from "./components/QuestionManageContent"; import QuestionManageContent from "./components/QuestionManageContent";
import User from "@/common/js/user"; import User from "@/common/js/user";
import QuestionBankService from "@/domains/question-bank-domain/QuestionBankService"; import QuestionBankService from "@/domains/question-bank-domain/QuestionBankService";
...@@ -25,10 +25,7 @@ class QuestionBankIndex extends Component { ...@@ -25,10 +25,7 @@ class QuestionBankIndex extends Component {
}; };
} }
componentDidMount() { componentDidMount() {}
// TODO
// 接口请求 初始化数据
}
getCategoryIdFromSider = (selectedCategoryId) => { getCategoryIdFromSider = (selectedCategoryId) => {
if (selectedCategoryId && selectedCategoryId.length > 0) { if (selectedCategoryId && selectedCategoryId.length > 0) {
...@@ -36,6 +33,10 @@ class QuestionBankIndex extends Component { ...@@ -36,6 +33,10 @@ class QuestionBankIndex extends Component {
} }
}; };
updatedSiderTreeFromList = (updatedCategoryId) => {
this.setState({updatedCategoryId});
};
render() { render() {
return ( return (
<div className="question-bank-index page"> <div className="question-bank-index page">
...@@ -44,10 +45,14 @@ class QuestionBankIndex extends Component { ...@@ -44,10 +45,14 @@ class QuestionBankIndex extends Component {
<div className="sider"> <div className="sider">
<QuestionBankSider <QuestionBankSider
getSelectedCategoryId={this.getCategoryIdFromSider.bind(this)} getSelectedCategoryId={this.getCategoryIdFromSider.bind(this)}
updatedCategoryId={this.state.updatedCategoryId}
/> />
</div> </div>
<div className="content"> <div className="content">
<QuestionManageList selectedCategoryId={this.state.selectedCategoryId} /> <QuestionManageContent
updatedSiderTree={this.updatedSiderTreeFromList.bind(this)}
selectedCategoryId={this.state.selectedCategoryId}
/>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: yuananting * @Author: yuananting
* @Date: 2021-02-23 18:28:50 * @Date: 2021-02-23 18:28:50
* @LastEditors: yuananting * @LastEditors: yuananting
* @LastEditTime: 2021-03-13 19:53:48 * @LastEditTime: 2021-03-15 15:14:10
* @Description: 助学工具-题库-主页面分类管理 * @Description: 助学工具-题库-主页面分类管理
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -23,7 +23,6 @@ import { ...@@ -23,7 +23,6 @@ import {
Modal, Modal,
} from "antd"; } from "antd";
import ShowTips from "@/components/ShowTips"; import ShowTips from "@/components/ShowTips";
import user from "@/common/js/user";
const { DirectoryTree } = Tree; const { DirectoryTree } = Tree;
const { Search } = Input; const { Search } = Input;
const { confirm } = Modal; const { confirm } = Modal;
...@@ -34,7 +33,7 @@ class QuestionCategoryManage extends Component { ...@@ -34,7 +33,7 @@ class QuestionCategoryManage extends Component {
NewEditQuestionBankCategory: null, //新增或编辑分类模态框 NewEditQuestionBankCategory: null, //新增或编辑分类模态框
treeData: [], treeData: [],
treeMap: {}, treeMap: {},
selectedKeys: ["0"] selectedKeys: ["0"],
}; };
} }
...@@ -47,12 +46,12 @@ class QuestionCategoryManage extends Component { ...@@ -47,12 +46,12 @@ class QuestionCategoryManage extends Component {
let query = { let query = {
source: 0, source: 0,
categoryName, categoryName,
userId: User.getUserId(), userId: User.getStoreUserId(),
tenantId: User.getStoreId(), tenantId: User.getStoreId(),
}; };
QuestionBankService.queryCategoryTree(query).then((res) => { QuestionBankService.queryCategoryTree(query).then((res) => {
const { result = [] } = res; const { result = [] } = res;
const defaultNode = { id: "0", categoryName:"未分类", categoryCount: 0} const defaultNode = { id: "0", categoryName: "未分类", categoryCount: 0 };
result.unshift(defaultNode); result.unshift(defaultNode);
this.setState({ treeData: this.renderTreeNodes(result, categoryName) }); this.setState({ treeData: this.renderTreeNodes(result, categoryName) });
this.setState({ this.setState({
...@@ -78,7 +77,7 @@ class QuestionCategoryManage extends Component { ...@@ -78,7 +77,7 @@ class QuestionCategoryManage extends Component {
categoryId: item.id, categoryId: item.id,
source: 0, source: 0,
tenantId: User.getStoreId(), tenantId: User.getStoreId(),
userId: User.getUserId(), userId: User.getStoreUserId(),
}; };
QuestionBankService.delCategory(params).then((res) => { QuestionBankService.delCategory(params).then((res) => {
if (res.success) { if (res.success) {
...@@ -168,7 +167,11 @@ class QuestionCategoryManage extends Component { ...@@ -168,7 +167,11 @@ class QuestionCategoryManage extends Component {
onDrop = (info) => { onDrop = (info) => {
// 未分类不可以拖拽 // 未分类不可以拖拽
if (info.dragNode.categoryName === "未分类" || info.node.categoryName === "未分类") return; if (
info.dragNode.categoryName === "未分类" ||
info.node.categoryName === "未分类"
)
return;
// 不允许其他节点拖拽到未分类之前 // 不允许其他节点拖拽到未分类之前
if ( if (
info.node.categoryName === "未分类" && info.node.categoryName === "未分类" &&
...@@ -209,7 +212,11 @@ class QuestionCategoryManage extends Component { ...@@ -209,7 +212,11 @@ class QuestionCategoryManage extends Component {
}); });
if (sameNameNodes.length > 0) { if (sameNameNodes.length > 0) {
sufIndex++; sufIndex++;
return getSuf(originCategoryName + `(${sufIndex})`, originCategoryName, sufIndex); return getSuf(
originCategoryName + `(${sufIndex})`,
originCategoryName,
sufIndex
);
} }
} }
return sufIndex; return sufIndex;
...@@ -225,9 +232,12 @@ class QuestionCategoryManage extends Component { ...@@ -225,9 +232,12 @@ class QuestionCategoryManage extends Component {
item.originCategoryName = item.categoryName; item.originCategoryName = item.categoryName;
} }
info.dragNode.categoryName = item.originCategoryName; info.dragNode.categoryName = item.originCategoryName;
let sufIndex = getSuf(info.dragNode.categoryName, item.originCategoryName, 0); let sufIndex = getSuf(
item.categoryName = info.dragNode.categoryName,
item.categoryName + (sufIndex ? `(${sufIndex})` : ""); item.originCategoryName,
0
);
item.categoryName = item.categoryName + (sufIndex ? `(${sufIndex})` : "");
item.categoryName = item.categoryName =
item.originCategoryName + (sufIndex ? `(${sufIndex})` : ""); item.originCategoryName + (sufIndex ? `(${sufIndex})` : "");
dragObj = item; dragObj = item;
...@@ -267,7 +277,7 @@ class QuestionCategoryManage extends Component { ...@@ -267,7 +277,7 @@ class QuestionCategoryManage extends Component {
categoryList: newTreeData, categoryList: newTreeData,
source: 0, source: 0,
tenantId: User.getStoreId(), tenantId: User.getStoreId(),
userId: User.getUserId(), userId: User.getStoreUserId(),
}; };
QuestionBankService.editCategoryTree(params).then((res) => { QuestionBankService.editCategoryTree(params).then((res) => {
this.queryCategoryTree(); this.queryCategoryTree();
...@@ -430,14 +440,20 @@ class QuestionCategoryManage extends Component { ...@@ -430,14 +440,20 @@ class QuestionCategoryManage extends Component {
/** 树状选中事件 */ /** 树状选中事件 */
onSelect = (selectedKeys) => { onSelect = (selectedKeys) => {
this.setState({ selectedKeys }); this.setState({ selectedKeys });
// TODO调用查询题目接口
}; };
render() { render() {
const { treeData, expandedKeys, selectedKeys } = this.state; const { treeData, expandedKeys, selectedKeys } = this.state;
return ( return (
<div className="page question-category-manage"> <div className="page question-category-manage">
<Breadcrumbs navList="课程分类" goBack={() => RCHistory.goBack()} /> <Breadcrumbs
navList="课程分类"
goBack={() =>
window.RCHistory.push({
pathname: "/question-bank-index",
})
}
/>
<div className="box"> <div className="box">
<div className="search-condition"> <div className="search-condition">
<span className="search-label">搜索名称:</span> <span className="search-label">搜索名称:</span>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: yuananting * @Author: yuananting
* @Date: 2021-02-25 14:34:29 * @Date: 2021-02-25 14:34:29
* @LastEditors: yuananting * @LastEditors: yuananting
* @LastEditTime: 2021-03-13 20:09:55 * @LastEditTime: 2021-03-15 21:12:14
* @Description: 助学工具-题库-题目管理-新建题目Tab * @Description: 助学工具-题库-题目管理-新建题目Tab
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -22,6 +22,7 @@ import UploadingProgress from "./UploadingProgress"; ...@@ -22,6 +22,7 @@ import UploadingProgress from "./UploadingProgress";
import XMAudio from "./XMAudio"; import XMAudio from "./XMAudio";
import XMRecord from "./XMRecord"; import XMRecord from "./XMRecord";
import ScanFileModal from "@/modules/resource-disk/modal/ScanFileModal"; import ScanFileModal from "@/modules/resource-disk/modal/ScanFileModal";
import _ from 'lodash';
class NewQuestionTab extends Component { class NewQuestionTab extends Component {
constructor(props) { constructor(props) {
...@@ -93,14 +94,19 @@ class NewQuestionTab extends Component { ...@@ -93,14 +94,19 @@ class NewQuestionTab extends Component {
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
return ( const { questionInfo } = nextProps;
JSON.stringify(nextProps) !== JSON.stringify(this.props) || if (this.props.questionInfo !== questionInfo) {
JSON.stringify(nextState) !== JSON.stringify(this.state) this.setState({stemContent: JSON.parse(JSON.stringify(questionInfo.questionStemList))}); // 题干内容
); this.setState({chooseOptions: JSON.parse(JSON.stringify(questionInfo.optionList))}); // 单选多选不定项-选项列表
this.setState({questionAnswerDesc: JSON.parse(JSON.stringify(questionInfo.questionAnswerDescList))}); // 答案解析
this._onSetState()
}
return true;
} }
_onSetState = (params = {}) => { _onSetState = (params = {}) => {
this.setState({ ...params, updateKey: window.random_string(16) }, () => { this.setState({ ...params, updateKey: window.random_string(16) },
() => {
this.props.onSetState({ this.props.onSetState({
questionStemList: JSON.parse(JSON.stringify(this.state.stemContent)), questionStemList: JSON.parse(JSON.stringify(this.state.stemContent)),
optionList: JSON.parse(JSON.stringify(this.state.chooseOptions)), optionList: JSON.parse(JSON.stringify(this.state.chooseOptions)),
...@@ -108,7 +114,8 @@ class NewQuestionTab extends Component { ...@@ -108,7 +114,8 @@ class NewQuestionTab extends Component {
JSON.stringify(this.state.questionAnswerDesc) JSON.stringify(this.state.questionAnswerDesc)
), ),
}); });
}); }
);
}; };
// 保存校验 // 保存校验
...@@ -218,7 +225,7 @@ class NewQuestionTab extends Component { ...@@ -218,7 +225,7 @@ class NewQuestionTab extends Component {
* *
* @memberof QuestionInputItem * @memberof QuestionInputItem
*/ */
handleDelOption = (optionIndex) => { handleDelOption = (optionIndex) => {
const { chooseOptions } = this.state; const { chooseOptions } = this.state;
this.handleLogger("delete_option", "删除选项"); this.handleLogger("delete_option", "删除选项");
if (chooseOptions.length < 3) { if (chooseOptions.length < 3) {
...@@ -246,7 +253,8 @@ class NewQuestionTab extends Component { ...@@ -246,7 +253,8 @@ class NewQuestionTab extends Component {
* *
* @memberof QuestionInputItem * @memberof QuestionInputItem
*/ */
handleChangeMedia = (key, uploadItemTarget, inputType) => { handleChangeMedia = (key, uploadItemTarget, contentType) => {
this.setState({ contentType })
const { mediaFirstType } = this.state; const { mediaFirstType } = this.state;
const mediaArr = _.filter(uploadItemTarget, (mediaItem) => { const mediaArr = _.filter(uploadItemTarget, (mediaItem) => {
return mediaItem.type !== "RICH_TEXT"; return mediaItem.type !== "RICH_TEXT";
...@@ -254,11 +262,12 @@ class NewQuestionTab extends Component { ...@@ -254,11 +262,12 @@ class NewQuestionTab extends Component {
if (mediaArr.length === 0) { if (mediaArr.length === 0) {
this.setState({ mediaFirstType: key }); this.setState({ mediaFirstType: key });
} }
if (mediaArr.length > 0 && key !== mediaFirstType) { switch (contentType) {
return message.warning("只能添加1种类型的多媒体文件"); case "QUESTION_STEM":
} case "QUESTION_OPTION":
switch (inputType) { if (mediaArr.length > 0 && key !== mediaFirstType) {
case "stem": return message.warning("只能添加1种类型的多媒体文件");
}
if (mediaFirstType === "PICTURE" && mediaArr.length > 8) { if (mediaFirstType === "PICTURE" && mediaArr.length > 8) {
return message.warning("只能添加9张图片"); return message.warning("只能添加9张图片");
} }
...@@ -269,23 +278,47 @@ class NewQuestionTab extends Component { ...@@ -269,23 +278,47 @@ class NewQuestionTab extends Component {
return message.warning("只能添加3个录音"); return message.warning("只能添加3个录音");
} }
break; break;
case "options": case "QUESTION_ANSWER_DESC":
if (mediaArr.length > 0) { var existType = [];
return message.warning("只能添加1个多媒体文件"); const pictureMediaArr = _.filter(uploadItemTarget, (mediaItem) => {
return mediaItem.type === "PICTURE";
});
const voiceMediaArr = _.filter(uploadItemTarget, (mediaItem) => {
return mediaItem.type === "VOICE";
});
const recordMediaArr = _.filter(uploadItemTarget, (mediaItem) => {
return mediaItem.type === "RECORD";
});
const videodMediaArr = _.filter(uploadItemTarget, (mediaItem) => {
return mediaItem.type === "VIDEO";
});
if (pictureMediaArr.length > 0) {
existType.push("PICTURE")
} }
break; if (voiceMediaArr.length > 0) {
case "analysis": existType.push("VOICE")
if (mediaFirstType === "PICTURE" && mediaArr.length > 8) {
return message.warning("只能添加9张图片");
} }
if (mediaFirstType === "VOICE" && mediaArr.length > 2) { if (recordMediaArr.length > 0) {
return message.warning("只能添加3个音频"); existType.push("RECORD")
} }
if (mediaFirstType === "RECORD" && mediaArr.length > 2) { if (videodMediaArr.length > 0) {
return message.warning("只能添加3个录音"); existType.push("VIDEO")
} }
if (mediaFirstType === "VIDEO" && mediaArr.length > 2) { if (existType.length > 2 && !existType.includes(key)) {
return message.warning("只能添加3个视频"); return message.warning("只能添加3种类型的多媒体文件");
} else {
if (key === "PICTURE" && pictureMediaArr.length > 8) {
return message.warning("只能添加9张图片");
}
if (key === "VOICE" && voiceMediaArr.length > 2) {
return message.warning("只能添加3个音频");
}
if (key === "RECORD" && recordMediaArr.length > 2) {
return message.warning("只能添加3个录音");
}
if (key === "VIDEO" && videodMediaArr.length > 2) {
return message.warning("只能添加3个视频");
}
} }
break; break;
default: default:
...@@ -320,7 +353,7 @@ class NewQuestionTab extends Component { ...@@ -320,7 +353,7 @@ class NewQuestionTab extends Component {
}; };
async uploadFile(event) { async uploadFile(event) {
const { fileType, uploadItemTarget } = this.state; const { fileType, uploadItemTarget, contentType } = this.state;
const mediaFile = event.target.files[0]; const mediaFile = event.target.files[0];
if (!mediaFile) return; if (!mediaFile) return;
if (fileType === "VOICE") { if (fileType === "VOICE") {
...@@ -368,7 +401,7 @@ class NewQuestionTab extends Component { ...@@ -368,7 +401,7 @@ class NewQuestionTab extends Component {
const originType = originArr[originArr.length - 1]; const originType = originArr[originArr.length - 1];
const uploadObj = { const uploadObj = {
contentType: "QUESTION_STEM", contentType,
type: fileType, type: fileType,
contentName: `${window.random_string(16)}.${originType}`, // 文件名 contentName: `${window.random_string(16)}.${originType}`, // 文件名
fileType: originType, // 文件后缀 fileType: originType, // 文件后缀
...@@ -455,7 +488,7 @@ class NewQuestionTab extends Component { ...@@ -455,7 +488,7 @@ class NewQuestionTab extends Component {
}); });
this.setState({ blanksList: _blanksList }); this.setState({ blanksList: _blanksList });
}; };
renderCompletionAnswer = (optionItem, optionIndex) => { renderCompletionAnswer = (optionItem, optionIndex) => {
return ( return (
<div className="completion-answer-box"> <div className="completion-answer-box">
...@@ -533,7 +566,7 @@ class NewQuestionTab extends Component { ...@@ -533,7 +566,7 @@ class NewQuestionTab extends Component {
contentList, contentList,
placehold, placehold,
mediaBtn, mediaBtn,
inputType, contentType,
validateStatus validateStatus
) => { ) => {
const isCompletion = this.props.questionTypeKey === "COMPLETION"; const isCompletion = this.props.questionTypeKey === "COMPLETION";
...@@ -541,10 +574,23 @@ class NewQuestionTab extends Component { ...@@ -541,10 +574,23 @@ class NewQuestionTab extends Component {
contentList, contentList,
(contentItem) => contentItem.type === "RICH_TEXT" (contentItem) => contentItem.type === "RICH_TEXT"
); );
const pictureMediaList = _.filter(contentList, (mediaItem) => {
return mediaItem.type === "PICTURE";
});
const voiceMediaList = _.filter(contentList, (mediaItem) => {
return mediaItem.type === "VOICE";
});
const recordMediaList = _.filter(contentList, (mediaItem) => {
return mediaItem.type === "RECORD";
});
const videoMediaList = _.filter(contentList, (mediaItem) => {
return mediaItem.type === "VIDEO";
});
return ( return (
<React.Fragment> <React.Fragment>
<div> <div>
{isCompletion && inputType === "stem" ? ( {isCompletion && contentType === "QUESTION_STEM" ? (
<CompletionStem <CompletionStem
placehold={placehold} placehold={placehold}
validateStatus={validateStatus} validateStatus={validateStatus}
...@@ -552,7 +598,7 @@ class NewQuestionTab extends Component { ...@@ -552,7 +598,7 @@ class NewQuestionTab extends Component {
mediaBtn={mediaBtn} mediaBtn={mediaBtn}
changeBlankCount={this.changeBlankCount.bind(this)} changeBlankCount={this.changeBlankCount.bind(this)}
onUploadMedia={(key) => { onUploadMedia={(key) => {
this.handleChangeMedia(key, contentList, inputType); this.handleChangeMedia(key, contentList, contentType);
}} }}
/> />
) : ( ) : (
...@@ -560,7 +606,7 @@ class NewQuestionTab extends Component { ...@@ -560,7 +606,7 @@ class NewQuestionTab extends Component {
markKey={this.markKey} markKey={this.markKey}
placehold={placehold} placehold={placehold}
validateStatus={validateStatus} validateStatus={validateStatus}
detailInfo={contentList} detailInfo={editorContent}
mediaBtn={mediaBtn} mediaBtn={mediaBtn}
bindChangeContent={(cb, textElemId) => { bindChangeContent={(cb, textElemId) => {
this.setState({ textElemId }); this.setState({ textElemId });
...@@ -572,99 +618,299 @@ class NewQuestionTab extends Component { ...@@ -572,99 +618,299 @@ class NewQuestionTab extends Component {
this._onSetState(); this._onSetState();
}} }}
onUploadMedia={(key) => { onUploadMedia={(key) => {
this.handleChangeMedia(key, contentList, inputType); this.handleChangeMedia(key, contentList, contentType);
}} }}
/> />
)} )}
</div> </div>
{_.map(contentList, (contentItem, index) => { {contentType === "QUESTION_ANSWER_DESC" ?
const { type, content, status } = contentItem; <div className="question-desc-box">
let dom = ""; {pictureMediaList.length > 0 && <div className="desc-picture-box">
if (["init", "fail"].includes(status)) { {_.map(pictureMediaList, (pictureItem, pictureIndex) => {
return ( let { content, status } = pictureItem;
<div className="mt12" key={index}> if (["init", "fail"].includes(status)) {
<UploadingProgress return (
fileDesc={contentItem} <div className="mt12" key={pictureIndex}>
canCancelUpload <UploadingProgress
onReupload={() => this.handleReupload(contentItem)} fileDesc={pictureItem}
onAbort={() => this.handleAbort(contentItem, index)} canCancelUpload
/> onReupload={() => this.handleReupload(pictureItem)}
</div> onAbort={() => this.handleAbort(pictureItem, pictureIndex)}
); />
} </div>
switch (type) { );
case "PICTURE": } else {
dom = ( return (
<div className="picture-box"> <div className="picture-box" key={pictureIndex}>
<img <img
className="img-box" className="img-box"
src={content} src={content}
onClick={() => this.handleScanFile("JPG", content)} onClick={() => this.handleScanFile("JPG", content)}
/> />
</div> <span
); className="icon_arrow iconfont"
break; onClick={() => {
case "VOICE": contentList.map((item, index) => {
dom = ( if (item.contentName === pictureItem.contentName) {
<div className="audio-box"> contentList.splice(index, 1);
<XMAudio return item
forbidParse }
url={contentItem.content} })
getDuration={(size) => { this._onSetState();
contentItem.size = size; }}
this.setState({}); >
}} &#xe717;
index={index} </span>
size={contentItem.size || 1000} </div>
/> )
</div> }
); })}
break; </div>}
case "VIDEO": {recordMediaList.length > 0 && <div className="desc-audio-box">
dom = ( {_.map(recordMediaList, (recordItem, recordIndex) => {
<div let { content, status, size } = recordItem;
className="video-box" if (["init", "fail"].includes(status)) {
onClick={() => this.handleScanFile("MP4", content)} return (
> <div className="mt12" key={recordIndex}>
<img <UploadingProgress
className="video-box_content" fileDesc={recordItem}
src={`${content}?x-oss-process=video/snapshot,t_0,m_fast`} canCancelUpload
/> onReupload={() => this.handleReupload(recordItem)}
<img onAbort={() => this.handleAbort(recordItem, recordIndex)}
className="video-box_btn" />
src="https://image.xiaomaiketang.com/xm/r5H8cYm4ch.png" </div>
);
} else {
return (
<div className="audio-box" key={recordIndex}>
<XMAudio
forbidParse
url={content}
getDuration={(durationSize) => {
size = durationSize;
this.setState({});
}}
index={recordIndex}
size={size || 1000}
/>
<span
className="icon_sider iconfont"
onClick={() => {
contentList.map((item, index) => {
if (item.contentName === recordItem.contentName) {
contentList.splice(index, 1);
return item
}
})
this._onSetState();
}}
>
&#xe717;
</span>
</div>
)
}
})}
</div>}
{voiceMediaList.length > 0 && <div className="desc-audio-box">
{_.map(voiceMediaList, (voiceItem, voiceIndex) => {
let { content, status, size } = voiceItem;
if (["init", "fail"].includes(status)) {
return (
<div className="mt12" key={voiceIndex}>
<UploadingProgress
fileDesc={voiceItem}
canCancelUpload
onReupload={() => this.handleReupload(voiceItem)}
onAbort={() => this.handleAbort(voiceItem, voiceIndex)}
/>
</div>
);
} else {
return (
<div className="audio-box" key={voiceIndex}>
<XMAudio
forbidParse
url={content}
getDuration={(durationSize) => {
size = durationSize;
this.setState({});
}}
index={voiceIndex}
size={size || 1000}
/>
<span
className="icon_sider iconfont"
onClick={() => {
contentList.map((item, index) => {
if (item.contentName === voiceItem.contentName) {
contentList.splice(index, 1);
return item
}
})
this._onSetState();
}}
>
&#xe717;
</span>
</div>
)
}
})}
</div>}
{videoMediaList.length > 0 && <div className="desc-video-box">
{_.map(videoMediaList, (videoItem, videoIndex) => {
let { content, status } = videoItem;
if (["init", "fail"].includes(status)) {
return (
<div className="mt12" key={videoIndex}>
<UploadingProgress
fileDesc={videoItem}
canCancelUpload
onReupload={() => this.handleReupload(videoItem)}
onAbort={() => this.handleAbort(videoItem, videoIndex)}
/>
</div>
);
} else {
return (
<div
className="video-box"
key={videoIndex}
>
<img
className="video-box_content"
src={`${content}?x-oss-process=video/snapshot,t_0,m_fast`}
/>
<img
className="video-box_btn"
src="https://image.xiaomaiketang.com/xm/r5H8cYm4ch.png"
onClick={() => this.handleScanFile("MP4", content)}
/>
<span
className="icon_arrow iconfont"
onClick={() => {
contentList.map((item, index) => {
if (item.contentName === videoItem.contentName) {
contentList.splice(index, 1);
return item
}
})
this._onSetState();
}}
>
&#xe717;
</span>
</div>
)
}
})}
</div>}
</div>
: _.map(contentList, (contentItem, index) => {
const { type, content, status } = contentItem;
let dom = "";
if (["init", "fail"].includes(status)) {
return (
<div className="mt12" key={index}>
<UploadingProgress
fileDesc={contentItem}
canCancelUpload
onReupload={() => this.handleReupload(contentItem)}
onAbort={() => this.handleAbort(contentItem, index)}
/> />
</div> </div>
); );
break; }
} switch (type) {
return dom ? ( case "PICTURE":
<div dom = (
className="question-item_question-content" <div className="picture-box">
style={{ <img
display: ["PICTURE", "VIDEO"].includes(type) className="img-box"
? "inline-flex" src={content}
: "flex", onClick={() => this.handleScanFile("JPG", content)}
}} />
key={index} </div>
> );
{dom} break;
<span case "VOICE":
className={ dom = (
["PICTURE", "VIDEO"].includes(type) <div className="audio-box">
? "icon_arrow iconfont" <XMAudio
: "icon_sider iconfont" forbidParse
} url={contentItem.content}
onClick={() => { getDuration={(size) => {
contentList.splice(index, 1); contentItem.size = size;
this._onSetState(); this.setState({});
}}
index={index}
size={contentItem.size || 1000}
/>
</div>
);
break;
case "RECORD":
dom = (
<div className="audio-box">
<XMAudio
forbidParse
url={contentItem.content}
getDuration={(size) => {
contentItem.size = size;
this.setState({});
}}
index={index}
size={contentItem.size || 1000}
/>
</div>
);
break;
case "VIDEO":
dom = (
<div
className="video-box"
onClick={() => this.handleScanFile("MP4", content)}
>
<img
className="video-box_content"
src={`${content}?x-oss-process=video/snapshot,t_0,m_fast`}
/>
<img
className="video-box_btn"
src="https://image.xiaomaiketang.com/xm/r5H8cYm4ch.png"
/>
</div>
);
break;
}
return dom ? (
<div
className="question-item_question-content"
style={{
display: ["PICTURE", "VIDEO"].includes(type)
? "inline-grid"
: "flex",
}} }}
key={index}
> >
&#xe717; {dom}
<span
className={
["PICTURE", "VIDEO"].includes(type)
? "icon_arrow iconfont"
: "icon_sider iconfont"
}
onClick={() => {
contentList.splice(index, 1);
this._onSetState();
}}
>
&#xe717;
</span> </span>
</div> </div>
) : null; ) : null;
})} })}
</React.Fragment> </React.Fragment>
); );
}; };
...@@ -723,10 +969,10 @@ class NewQuestionTab extends Component { ...@@ -723,10 +969,10 @@ class NewQuestionTab extends Component {
* @memberof QuestionInputItem * @memberof QuestionInputItem
*/ */
handleFinishRecord = (mp3URL, duration) => { handleFinishRecord = (mp3URL, duration) => {
const { uploadItemTarget } = this.state; const { uploadItemTarget, contentType } = this.state;
uploadItemTarget.push({ uploadItemTarget.push({
contentType: "VOICE", contentType,
type: "VOICE", type: "RECORD",
content: mp3URL, content: mp3URL,
size: duration, size: duration,
}); });
...@@ -784,7 +1030,7 @@ class NewQuestionTab extends Component { ...@@ -784,7 +1030,7 @@ class NewQuestionTab extends Component {
stemContent, stemContent,
placehold, placehold,
["VOICE", "RECORD", "PICTURE"], ["VOICE", "RECORD", "PICTURE"],
"stem", "QUESTION_STEM",
stemValidate stemValidate
)} )}
</Form.Item> </Form.Item>
...@@ -828,62 +1074,62 @@ class NewQuestionTab extends Component { ...@@ -828,62 +1074,62 @@ class NewQuestionTab extends Component {
> >
{isJudge {isJudge
? _.map(judgeOptions, (optionItem, optionIndex) => { ? _.map(judgeOptions, (optionItem, optionIndex) => {
return ( return (
<div className="question-item_options__content"> <div className="question-item_options__content">
<div className="question-item_options__setting"> <div className="question-item_options__setting">
<Form.Item <Form.Item
validateStatus={radioValidate} validateStatus={radioValidate}
help={ help={
optionIndex === judgeOptions.length - 1 optionIndex === judgeOptions.length - 1
? radioText ? radioText
: "" : ""
} }
> >
{/* 判断 */} {/* 判断 */}
<Radio <Radio
checked={optionItem.isCorrectAnswer === 1} checked={optionItem.isCorrectAnswer === 1}
onClick={() => { onClick={() => {
_.each(judgeOptions, (item) => { _.each(judgeOptions, (item) => {
item.isCorrectAnswer = 0; item.isCorrectAnswer = 0;
}); });
optionItem.isCorrectAnswer = 1; optionItem.isCorrectAnswer = 1;
this._onSetState(); this._onSetState();
}} }}
/> />
</Form.Item> </Form.Item>
</div> </div>
<div className="question-item_options__sort mr12"> <div className="question-item_options__sort mr12">
{NUM_TO_WORD_MAP[optionIndex]}. {NUM_TO_WORD_MAP[optionIndex]}.
</div>
<div className="question-item_options__input">
{optionItem.label}
</div>
</div> </div>
); <div className="question-item_options__input">
}) {optionItem.label}
</div>
</div>
);
})
: _.map(chooseOptions, (optionItem, optionIndex) => { : _.map(chooseOptions, (optionItem, optionIndex) => {
const { const {
questionOptionContentList, questionOptionContentList,
isCorrectAnswer, isCorrectAnswer,
} = optionItem; } = optionItem;
optionItem.optionSort = optionIndex; optionItem.optionSort = optionIndex;
const mediaBtn = ["VOICE", "RECORD", "PICTURE"]; const mediaBtn = ["VOICE", "RECORD", "PICTURE"];
const placeHold = const placeHold =
"必填(1000字以内,可粘贴小图;可以不输入文字,只添加音频或图片)"; "必填(1000字以内,可粘贴小图;可以不输入文字,只添加音频或图片)";
return ( return (
<div className="question-item_options__content" key={optionIndex}> <div className="question-item_options__content" key={optionIndex}>
<div className="question-item_options__setting"> <div className="question-item_options__setting">
<Form.Item <Form.Item
validateStatus={radioValidate} validateStatus={radioValidate}
help={ help={
optionIndex === chooseOptions.length - 1 optionIndex === chooseOptions.length - 1
? radioText ? radioText
: "" : ""
} }
> >
{/* 单选 */} {/* 单选 */}
{this.props.questionTypeKey === {this.props.questionTypeKey ===
"SINGLE_CHOICE" && ( "SINGLE_CHOICE" && (
<Radio <Radio
checked={isCorrectAnswer} checked={isCorrectAnswer}
onClick={() => { onClick={() => {
...@@ -895,10 +1141,10 @@ class NewQuestionTab extends Component { ...@@ -895,10 +1141,10 @@ class NewQuestionTab extends Component {
}} }}
/> />
)} )}
{/* 多选 or 不定项 */} {/* 多选 or 不定项 */}
{["INDEFINITE_SELECT", "MULTI_CHOICE"].includes( {["INDEFINITE_CHOICE", "MULTI_CHOICE"].includes(
this.props.questionTypeKey this.props.questionTypeKey
) && ( ) && (
<Checkbox <Checkbox
checked={isCorrectAnswer === 1} checked={isCorrectAnswer === 1}
onChange={(e) => { onChange={(e) => {
...@@ -908,66 +1154,66 @@ class NewQuestionTab extends Component { ...@@ -908,66 +1154,66 @@ class NewQuestionTab extends Component {
}} }}
/> />
)} )}
</Form.Item> </Form.Item>
</div> </div>
<div className="question-item_options__sort mr12"> <div className="question-item_options__sort mr12">
{NUM_TO_WORD_MAP[optionIndex]}. {NUM_TO_WORD_MAP[optionIndex]}.
</div> </div>
<div className="question-item_options__input"> <div className="question-item_options__input">
<Form.Item <Form.Item
validateStatus={ validateStatus={
this.state[`optionsValidate_${optionIndex}`] this.state[`optionsValidate_${optionIndex}`]
}
help={this.state[`optionsText_${optionIndex}`]}
>
{this.renderContent(
questionOptionContentList,
placeHold,
mediaBtn,
"QUESTION_OPTION",
this.state[`optionsValidate_${optionIndex}`]
)}
</Form.Item>
</div>
<div className="question-item_options__extra">
<React.Fragment>
<span
className="option-operate_item__icon icon iconfont"
onClick={() =>
this.handleDelOption(optionIndex)
} }
help={this.state[`optionsText_${optionIndex}`]}
> >
{this.renderContent( &#xe81a;
questionOptionContentList, </span>
placeHold, {optionIndex > 0 && (
mediaBtn,
"options",
this.state[`optionsValidate_${optionIndex}`]
)}
</Form.Item>
</div>
<div className="question-item_options__extra">
<React.Fragment>
<span <span
className="option-operate_item__icon icon iconfont" className="option-operate_item__icon icon iconfont"
onClick={() => onClick={() =>
this.handleDelOption(optionIndex) this.handleMoveOption(optionIndex, -1)
} }
> >
&#xe81a; &#xe74a;
</span> </span>
{optionIndex > 0 && ( )}
<span {optionIndex < chooseOptions.length - 1 && (
className="option-operate_item__icon icon iconfont" <span
onClick={() => className="option-operate_item__icon icon iconfont"
this.handleMoveOption(optionIndex, 1) style={{
} transform: "rotate(180deg)",
> display: "inline-block",
&#xe74a; }}
</span> onClick={() =>
)} this.handleMoveOption(optionIndex, 1)
{optionIndex < chooseOptions.length - 1 && ( }
<span >
className="option-operate_item__icon icon iconfont" &#xe74a;
style={{ </span>
transform: "rotate(180deg)", )}
display: "inline-block", </React.Fragment>
}}
onClick={() =>
this.handleMoveOption(optionIndex, -1)
}
>
&#xe74a;
</span>
)}
</React.Fragment>
</div>
</div> </div>
); </div>
})} );
})}
{!isJudge && ( {!isJudge && (
<div <div
className="question-item_options__add" className="question-item_options__add"
...@@ -987,7 +1233,7 @@ class NewQuestionTab extends Component { ...@@ -987,7 +1233,7 @@ class NewQuestionTab extends Component {
questionAnswerDesc, questionAnswerDesc,
"1000字以内,可粘贴小图", "1000字以内,可粘贴小图",
["VOICE", "RECORD", "PICTURE", "VIDEO"], ["VOICE", "RECORD", "PICTURE", "VIDEO"],
"analysis" "QUESTION_ANSWER_DESC"
)} )}
</div> </div>
</Form.Item> </Form.Item>
......
...@@ -284,6 +284,89 @@ ...@@ -284,6 +284,89 @@
.question-item_analysis__content { .question-item_analysis__content {
flex: 1; flex: 1;
margin-right: 187px; margin-right: 187px;
.question-desc-box {
margin-top: 12px;
.desc-picture-box {
margin-bottom: 28px;
.picture-box {
position: relative;
display: inline-block;
width: 100px;
height: 100px;
overflow: hidden;
align-items: center;
justify-content: center;
padding: 12px 12px 0 0;
img {
max-width: 88px;
max-height: 88px;
border-radius: 4px;
}
.icon_arrow {
position: absolute;
top: 0px;
right: 5px;
color: #bfbfbf;
cursor: pointer;
font-size: 16px;
}
}
}
.desc-audio-box {
margin-bottom: 28px;
.audio-box {
position: relative;
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.1);
padding: 10px 20px;
width: 320px;
margin-bottom: 12px;
.icon_sider {
color: #bfbfbf;
cursor: pointer;
font-size: 16px;
padding: 12px;
position: absolute;
top: 0px;
left: 320px;
}
}
}
.desc-video-box {
.video-box {
position: relative;
display: inline-block;
width: 208px;
// height: calc(208px * 9 / 16);
position: relative;
overflow: hidden;
// background-color: #000;
padding-top: 12px;
margin: 0px 12px 12px 0;
&_content {
max-width: 200px;
max-height: 200px;
border-radius: 4px;
}
&_btn {
width: 32px;
height: 32px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -8px;
margin-left: -16px;
}
.icon_arrow {
position: absolute;
top: 0px;
right: 0px;
color: #bfbfbf;
cursor: pointer;
font-size: 16px;
}
}
}
}
} }
.completion-answer-box { .completion-answer-box {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: yuananting * @Author: yuananting
* @Date: 2021-02-22 10:59:43 * @Date: 2021-02-22 10:59:43
* @LastEditors: yuananting * @LastEditors: yuananting
* @LastEditTime: 2021-03-13 20:29:29 * @LastEditTime: 2021-03-15 15:22:13
* @Description: 助学工具-题库-题库主页面侧边栏 * @Description: 助学工具-题库-题库主页面侧边栏
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -19,7 +19,7 @@ class QuestionBankSider extends Component { ...@@ -19,7 +19,7 @@ class QuestionBankSider extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
selectedKeys: ["0"], selectedKeys: getParameterByName("categoryId") ? [getParameterByName("categoryId")] : ["0"],
searchValue: null, searchValue: null,
NewEditQuestionBankCategory: null, //新增或编辑分类模态框 NewEditQuestionBankCategory: null, //新增或编辑分类模态框
ImportCourseCategory: null, // 引用课程分类模态框 ImportCourseCategory: null, // 引用课程分类模态框
...@@ -29,6 +29,15 @@ class QuestionBankSider extends Component { ...@@ -29,6 +29,15 @@ class QuestionBankSider extends Component {
componentDidMount() { componentDidMount() {
this.queryCategoryTree(); this.queryCategoryTree();
this.props.getSelectedCategoryId(getParameterByName("categoryId") ? [getParameterByName("categoryId")] : ["0"],)
}
shouldComponentUpdate(nextProps, nextState) {
const { updatedCategoryId } = nextProps;
if (this.props.updatedCategoryId !== updatedCategoryId) {
this.setState({ selectedKeys: [updatedCategoryId] }, () => this.queryCategoryTree());
}
return true;
} }
/** 获取树状第一级key 设置默认展开第一项 */ /** 获取树状第一级key 设置默认展开第一项 */
...@@ -58,12 +67,12 @@ class QuestionBankSider extends Component { ...@@ -58,12 +67,12 @@ class QuestionBankSider extends Component {
let query = { let query = {
source: 0, source: 0,
categoryName, categoryName,
userId: User.getUserId(), userId: User.getStoreUserId(),
tenantId: User.getStoreId(), tenantId: User.getStoreId(),
}; };
QuestionBankService.queryQuestionCategoryTree(query).then((res) => { QuestionBankService.queryQuestionCategoryTree(query).then((res) => {
const { categoryList = [] } = res.result; const { categoryList = [], noCategoryCnt = 0 } = res.result;
const defaultNode = { id: "0", categoryName:"未分类", categoryCount: 0} const defaultNode = { id: "0", categoryName:"未分类", categoryCount: noCategoryCnt}
categoryList.unshift(defaultNode); categoryList.unshift(defaultNode);
this.setState({ treeData: this.renderTreeNodes(categoryList, categoryName) }); this.setState({ treeData: this.renderTreeNodes(categoryList, categoryName) });
this.setState({ this.setState({
......
...@@ -37,6 +37,7 @@ class QuestionEditor extends Component { ...@@ -37,6 +37,7 @@ class QuestionEditor extends Component {
isShowSingleInput: true, isShowSingleInput: true,
contentLength: 0, contentLength: 0,
errorInput: false, errorInput: false,
detailInfo: props.detailInfo || {}
}; };
} }
...@@ -44,6 +45,16 @@ class QuestionEditor extends Component { ...@@ -44,6 +45,16 @@ class QuestionEditor extends Component {
this.renderEditor(); this.renderEditor();
} }
shouldComponentUpdate(nextProps, nextState) {
const { detailInfo } = nextProps;
if (this.props.detailInfo !== detailInfo) {
this.setState({detailInfo: nextProps.detailInfo}, () => {
this.renderEditor();
})
}
return true;
}
handleUploadMedia = (key) => { handleUploadMedia = (key) => {
this.props.onUploadMedia && this.props.onUploadMedia(key); this.props.onUploadMedia && this.props.onUploadMedia(key);
}; };
...@@ -72,8 +83,8 @@ class QuestionEditor extends Component { ...@@ -72,8 +83,8 @@ class QuestionEditor extends Component {
}; };
renderEditor() { renderEditor() {
const { editorId } = this.state; const { editorId, detailInfo} = this.state;
const { detail = {}, detailInfo = {}, onChange, bindChangeContent } = this.props; const { onChange, bindChangeContent } = this.props;
const editorRoot = new E( const editorRoot = new E(
`#editor${editorId}_tabbar`, `#editor${editorId}_tabbar`,
`#editor${editorId}_content` `#editor${editorId}_content`
...@@ -156,27 +167,6 @@ class QuestionEditor extends Component { ...@@ -156,27 +167,6 @@ class QuestionEditor extends Component {
editorRoot.create(); editorRoot.create();
this.editorRoot = editorRoot; this.editorRoot = editorRoot;
if (detail.content) {
const contentHtml = /^\<p/.test(detail.content)
? detail.content
: `<p>${detail.content}</p>`;
editorRoot.txt.html(detail.content);
const textLength = editorRoot.txt.text().replace(/\&nbsp\;/gi, " ")
.length;
const imgLength = contentHtml.match(/<img/g)
? contentHtml.match(/<img/g).length * 2
: 0;
const contentLength = imgLength + textLength;
this.setState(
{
contentLength,
visiblePlacehold: contentLength === 0 && !this.state.focusFlag,
},
() => {
onChange && onChange(contentHtml, this.state.contentLength);
}
);
}
if (detailInfo.content) { if (detailInfo.content) {
const contentHtml = /^\<p/.test(detailInfo.content) const contentHtml = /^\<p/.test(detailInfo.content)
? detailInfo.content ? detailInfo.content
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: yuananting * @Author: yuananting
* @Date: 2021-02-25 11:23:47 * @Date: 2021-02-25 11:23:47
* @LastEditors: yuananting * @LastEditors: yuananting
* @LastEditTime: 2021-03-13 21:04:36 * @LastEditTime: 2021-03-15 21:08:28
* @Description: 助学工具-题库-题目管理主页面列表数据 * @Description: 助学工具-题库-题目管理主页面列表数据
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -19,14 +19,24 @@ import { ...@@ -19,14 +19,24 @@ import {
Space, Space,
Button, Button,
Modal, Modal,
message,
} from "antd"; } from "antd";
import { PageControl } from "@/components"; import { PageControl } from "@/components";
import "./QuestionManageContent.less"; import "./QuestionManageContent.less";
import User from "@/common/js/user"; import User from "@/common/js/user";
import QuestionBankService from "@/domains/question-bank-domain/QuestionBankService"; import QuestionBankService from "@/domains/question-bank-domain/QuestionBankService";
import _ from "underscore"; import _ from "underscore";
import QuestionPreviewModal from "../modal/QuestionPreviewModal";
const { Search } = Input; const { Search } = Input;
const questionTypeEnum = {
SINGLE_CHOICE: "单选题",
MULTI_CHOICE: "多选题",
JUDGE: "判断题",
GAP_FILLING: "填空题",
INDEFINITE_CHOICE: "不定项选择题",
};
const questionTypeList = [ const questionTypeList = [
{ {
label: "单选题", label: "单选题",
...@@ -63,32 +73,37 @@ class QuestionManageContent extends Component { ...@@ -63,32 +73,37 @@ class QuestionManageContent extends Component {
questionType: null, // 题目类型 questionType: null, // 题目类型
source: 0, source: 0,
tenantId: User.getStoreId(), tenantId: User.getStoreId(),
userId: User.getUserId(), userId: User.getStoreUserId(),
}, },
questionTypeList: [], // 题型列表 questionTypeList: [], // 题型列表
dataSource: [], dataSource: [],
totalCount: 0, totalCount: 0,
QuestionPreviewModal: null, // 题目预览模态框
}; };
} }
componentDidMount() { componentDidMount() {}
this.queryQuestionPageList();
}
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
const { selectedCategoryId } = nextProps; const { selectedCategoryId } = nextProps;
const _query = this.state.query; const _query = this.state.query;
if (this.props.selectedCategoryId !== selectedCategoryId) { if (this.props.selectedCategoryId !== selectedCategoryId) {
_query.categoryId = selectedCategoryId; _query.categoryId = selectedCategoryId;
_query.questionName = null;
_query.questionType = null;
_query.current = 1;
this.setState({ query: _query }, () => this.queryQuestionPageList()); this.setState({ query: _query }, () => this.queryQuestionPageList());
} }
return true; return true;
} }
queryQuestionPageList = () => { queryQuestionPageList = () => {
QuestionBankService.queryQuestionPageList(this.state.query).then((res) => { const _query = this.state.query;
if (_query.categoryId === "0") _query.categoryId = null;
QuestionBankService.queryQuestionPageList(_query).then((res) => {
const { records = [], total = 0 } = res.result; const { records = [], total = 0 } = res.result;
this.setState({ dataSource: records }); this.setState({ dataSource: records });
this.setState({ total });
}); });
}; };
...@@ -116,16 +131,81 @@ class QuestionManageContent extends Component { ...@@ -116,16 +131,81 @@ class QuestionManageContent extends Component {
deleteQuestion = (record) => { deleteQuestion = (record) => {
let params = { let params = {
id: record.id, id: record.id,
categoryId: record.categoryId,
source: 0, source: 0,
tenantId: User.getStoreId(), tenantId: User.getStoreId(),
userId: User.getUserId(), userId: User.getStoreUserId(),
};
QuestionBankService.deleteQuestion(params).then((res) => {
if (res.success) {
message.success("删除成功");
this.queryQuestionPageList();
this.props.updatedSiderTree(this.props.selectedCategoryId);
}
});
};
// 排序
handleChangeTable = (pagination, filters, sorter) => {
const { columnKey, order } = sorter;
let sort = null;
if (columnKey === "accuracy" && order === "ascend") {
sort = "ACCURACY_ASC";
} }
console.log(params) if (columnKey === "accuracy" && order === "descend") {
QuestionBankService.delCategory(params).then(res=>{ sort = "ACCURACY_DESC";
console.log(res) }
}) if (columnKey === "updateTime" && order === "ascend") {
} sort = "UPDATED_ASC";
}
if (columnKey === "updateTime" && order === "descend") {
sort = "UPDATED_DESC";
}
const _query = this.state.query;
_query.order = sort;
_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();
});
};
previewQuestion = (id) => {
const m = (
<QuestionPreviewModal
id={id}
close={() => {
this.setState({
QuestionPreviewModal: null,
});
}}
/>
);
this.setState({ QuestionPreviewModal: m });
};
toEditQuetion = (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 = () => { parseColumns = () => {
...@@ -134,27 +214,44 @@ class QuestionManageContent extends Component { ...@@ -134,27 +214,44 @@ class QuestionManageContent extends Component {
title: "题目", title: "题目",
key: "questionStem", key: "questionStem",
dataIndex: "questionStem", dataIndex: "questionStem",
width: 300,
render: (val, record) => { render: (val, record) => {
return <div className="record-name">{val}</div>; var handleVal = val;
handleVal = handleVal.replace(/<(?!img).*?>/g, "");
handleVal = handleVal.replace(/<\s?img[^>]*>/gi, "【图片】");
handleVal = handleVal.replace(/\&nbsp\;/gi, " ");
return (
<Tooltip title={handleVal}>
<div className="record-name">{handleVal}</div>
</Tooltip>
);
}, },
}, },
{ {
title: "题型", title: "题型",
key: "questionTypeEnum", key: "questionTypeEnum",
dataIndex: "questionTypeEnum", dataIndex: "questionTypeEnum",
render: (val) => {
return questionTypeEnum[val];
},
}, },
{ {
title: "正确率", title: "正确率",
key: "accuracy", key: "accuracy",
dataIndex: "accuracy", dataIndex: "accuracy",
sorter: true, sorter: true,
sortDirections: ["ascend", "descend", "ascend"],
showSorterTooltip: false,
render: (val) => {
return val + "%";
},
}, },
{ {
title: "更新时间", title: "更新时间",
key: "updateTime", key: "updateTime",
dataIndex: "updateTime", dataIndex: "updateTime",
sorter: true, sorter: true,
sortDirections: ["ascend", "descend", "ascend"],
showSorterTooltip: false,
render: (val) => { render: (val) => {
return formatDate("YYYY-MM-DD H:i:s", val); return formatDate("YYYY-MM-DD H:i:s", val);
}, },
...@@ -169,14 +266,14 @@ class QuestionManageContent extends Component { ...@@ -169,14 +266,14 @@ class QuestionManageContent extends Component {
<div className="record-operate"> <div className="record-operate">
<div <div
className="record-operate__item" className="record-operate__item"
onClick={() => console.log("预览")} onClick={() => this.previewQuestion(record.id)}
> >
预览 预览
</div> </div>
<span className="record-operate__item split"> | </span> <span className="record-operate__item split"> | </span>
<div <div
className="record-operate__item" className="record-operate__item"
onClick={() => console.log("预览")} onClick={() => this.toEditQuetion(record.id, record.questionTypeEnum)}
> >
编辑 编辑
</div> </div>
...@@ -227,9 +324,9 @@ class QuestionManageContent extends Component { ...@@ -227,9 +324,9 @@ class QuestionManageContent extends Component {
if (current == size) { if (current == size) {
return; return;
} }
let _query = this.props.query; let _query = this.state.query;
_query.size = size; _query.size = size;
this.props.onChange(_query); this.setState({ query: _query }, () => this.queryQuestionPageList());
}; };
// 改变搜索条件 // 改变搜索条件
...@@ -250,8 +347,8 @@ class QuestionManageContent extends Component { ...@@ -250,8 +347,8 @@ class QuestionManageContent extends Component {
}; };
render() { render() {
const { dataSource = [], totalCount, query } = this.state; const { dataSource = [], total, query } = this.state;
const { current, size, categoryId } = query; const { current, size, categoryId, questionName, questionType } = query;
return ( return (
<div className="question-manage-content"> <div className="question-manage-content">
<div className="question-manage-filter"> <div className="question-manage-filter">
...@@ -261,6 +358,7 @@ class QuestionManageContent extends Component { ...@@ -261,6 +358,7 @@ class QuestionManageContent extends Component {
<span className="search-label">题目:</span> <span className="search-label">题目:</span>
<Search <Search
placeholder="搜索题目名称" placeholder="搜索题目名称"
value={questionName}
style={{ width: "calc(100% - 84px)" }} style={{ width: "calc(100% - 84px)" }}
onChange={(e) => { onChange={(e) => {
this.handleChangeQuery("questionName", e.target.value); this.handleChangeQuery("questionName", e.target.value);
...@@ -275,6 +373,7 @@ class QuestionManageContent extends Component { ...@@ -275,6 +373,7 @@ class QuestionManageContent extends Component {
<span className="search-label">题型:</span> <span className="search-label">题型:</span>
<Select <Select
placeholder="请选择题目类型" placeholder="请选择题目类型"
value={questionType}
style={{ width: "calc(100% - 70px)" }} style={{ width: "calc(100% - 70px)" }}
showSearch showSearch
allowClear allowClear
...@@ -282,7 +381,7 @@ class QuestionManageContent extends Component { ...@@ -282,7 +381,7 @@ class QuestionManageContent extends Component {
option.props.children.includes(inputVal) option.props.children.includes(inputVal)
} }
onChange={(value) => { onChange={(value) => {
if(_.isEmpty(value)) { if (_.isEmpty(value)) {
this.handleChangeQuery("questionType", value); this.handleChangeQuery("questionType", value);
} }
}} }}
...@@ -333,25 +432,29 @@ class QuestionManageContent extends Component { ...@@ -333,25 +432,29 @@ class QuestionManageContent extends Component {
rowKey={(record) => record.id} rowKey={(record) => record.id}
dataSource={dataSource} dataSource={dataSource}
columns={this.parseColumns()} columns={this.parseColumns()}
onChange={this.handleChangeTable}
pagination={false} pagination={false}
bordered bordered
onChange={this.handleChangeTable}
/> />
</ConfigProvider> </ConfigProvider>
{totalCount > 0 && ( {total > 0 && (
<div className="box-footer"> <div className="box-footer">
<PageControl <PageControl
current={current - 1} current={current - 1}
pageSize={size} pageSize={size}
total={totalCount} total={total}
toPage={(page) => { toPage={(page) => {
const _query = { ...query, current: page + 1 }; const _query = { ...query, current: page + 1 };
this.props.onChange(_query); this.setState({ query: _query }, () =>
this.queryQuestionPageList()
);
}} }}
showSizeChanger={true}
onShowSizeChange={this.onShowSizeChange} onShowSizeChange={this.onShowSizeChange}
/> />
</div> </div>
)} )}
{this.state.QuestionPreviewModal}
</div> </div>
</div> </div>
); );
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
* @Author: yuananting * @Author: yuananting
* @Date: 2021-02-25 11:26:28 * @Date: 2021-02-25 11:26:28
* @LastEditors: yuananting * @LastEditors: yuananting
* @LastEditTime: 2021-03-13 16:42:41 * @LastEditTime: 2021-03-15 09:42:30
* @Description: 助学工具-题库-题目管理右侧内容样式 * @Description: 助学工具-题库-题目管理右侧内容样式
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
.question-manage-content { .question-manage-content {
.question-manage-filter { .question-manage-filter {
position: relative; position: relative;
.search-condition { .search-condition {
...@@ -57,12 +57,10 @@ ...@@ -57,12 +57,10 @@
cursor: pointer; cursor: pointer;
} }
.record-name { .record-name {
word-break: break-all;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
display: -webkit-box; white-space: nowrap;
-webkit-line-clamp: 5; width: 232px;
-webkit-box-orient: vertical;
} }
.record-operate { .record-operate {
display: flex; display: flex;
......
/* /*
* @Author: chenjianyu * @Author: chenjianyu
* @Date: 2020-09-12 17:00:44 * @Date: 2020-09-12 17:00:44
* @LastEditTime: 2021-03-13 11:19:38 * @LastEditTime: 2021-03-15 13:00:10
* @LastEditors: yuananting * @LastEditors: yuananting
* @Description: 答题模式模板 * @Description: 答题模式模板
* @Copyright © 2020 杭州杰竞科技有限公司 版权所有 * @Copyright © 2020 杭州杰竞科技有限公司 版权所有
...@@ -73,7 +73,7 @@ export function defineQuestionInfo(questionType) { ...@@ -73,7 +73,7 @@ export function defineQuestionInfo(questionType) {
export function defineOptionInfo() { export function defineOptionInfo() {
return { return {
isCorrectAnswer: false, // 是否为正确答案选项 isCorrectAnswer: 0, // 是否为正确答案选项
questionOptionContentList: [ // 选项内容 questionOptionContentList: [ // 选项内容
{ {
contentType: "QUESTION_OPTION", // 内容类型(默认选项) contentType: "QUESTION_OPTION", // 内容类型(默认选项)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: yuananting * @Author: yuananting
* @Date: 2021-02-22 17:51:28 * @Date: 2021-02-22 17:51:28
* @LastEditors: yuananting * @LastEditors: yuananting
* @LastEditTime: 2021-03-13 14:26:31 * @LastEditTime: 2021-03-15 09:56:59
* @Description: 助学工具-题库-题库新建或编辑题库分类模态框 * @Description: 助学工具-题库-题库新建或编辑题库分类模态框
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -10,7 +10,6 @@ import React, { Component } from "react"; ...@@ -10,7 +10,6 @@ import React, { Component } from "react";
import { Modal, Form, Input, message } from "antd"; import { Modal, Form, Input, message } from "antd";
import User from "@/common/js/user"; import User from "@/common/js/user";
import QuestionBankService from "@/domains/question-bank-domain/QuestionBankService"; import QuestionBankService from "@/domains/question-bank-domain/QuestionBankService";
import { node } from "prop-types";
class NewEditQuestionBankCategory extends Component { class NewEditQuestionBankCategory extends Component {
formRef = React.createRef(); formRef = React.createRef();
constructor(props) { constructor(props) {
...@@ -31,7 +30,7 @@ class NewEditQuestionBankCategory extends Component { ...@@ -31,7 +30,7 @@ class NewEditQuestionBankCategory extends Component {
queryCategoryTree = () => { queryCategoryTree = () => {
let query = { let query = {
source: 0, source: 0,
userId: User.getUserId(), userId: User.getStoreUserId(),
tenantId: User.getStoreId(), tenantId: User.getStoreId(),
}; };
QuestionBankService.queryCategoryTree(query).then((res) => { QuestionBankService.queryCategoryTree(query).then((res) => {
...@@ -47,7 +46,7 @@ class NewEditQuestionBankCategory extends Component { ...@@ -47,7 +46,7 @@ class NewEditQuestionBankCategory extends Component {
let params = { let params = {
source: 0, source: 0,
tenantId: User.getStoreId(), tenantId: User.getStoreId(),
userId: User.getUserId(), userId: User.getStoreUserId(),
}; };
if (type === "new") { if (type === "new") {
//新增 //新增
......
import React, { Component } from "react";
import { Modal, Divider } from "antd";
import User from "@/common/js/user";
import QuestionBankService from "@/domains/question-bank-domain/QuestionBankService";
import "./QuestionPreviewModal.less";
import ScanFileModal from "@/modules/resource-disk/modal/ScanFileModal";
import _ from "underscore";
import XMAudio from "../components/XMAudio";
import { NUM_TO_WORD_MAP } from "@/common/constants/punchClock/punchClock";
const questionTypeList = {
SINGLE_CHOICE: "单选题",
MULTI_CHOICE: "多选题",
JUDGE: "判断题",
GAP_FILLING: "填空题",
INDEFINITE_CHOICE: "不定项选择题",
};
class QuestionPreviewModal extends Component {
formRef = React.createRef();
constructor(props) {
super(props);
this.state = {
questionInfo: {},
};
}
componentDidMount() {
this.queryQuestionDetails();
}
// 题目预览
queryQuestionDetails = () => {
let query = {
id: this.props.id,
source: 0,
userId: User.getStoreUserId(),
tenantId: User.getStoreId(),
};
QuestionBankService.queryQuestionDetails(query).then((res) => {
const { result = [] } = res;
this.setState({ questionInfo: result });
});
};
handleScanFile = (scanFileType, scanFileAddress) => {
this.setState({
showScanFile: true,
scanFileAddress,
scanFileType,
});
};
render() {
const {
showScanFile,
scanFileAddress,
scanFileType,
questionInfo,
} = this.state;
const {
questionTypeEnum,
questionStemList,
optionList,
questionAnswerDescList,
} = questionInfo;
// 查找答案选项
let rightAnswerSort = [];
_.filter(optionList, (optionItem, optionIndex) => {
if (optionItem.isCorrectAnswer === 1) {
rightAnswerSort.push(optionIndex);
}
});
const textDescList = _.filter(questionAnswerDescList, (descItem) => {
return descItem.type === "RICH_TEXT";
});
const pictureDescList = _.filter(questionAnswerDescList, (descItem) => {
return descItem.type === "PICTURE";
});
const voiceDescList = _.filter(questionAnswerDescList, (descItem) => {
return descItem.type === "VOICE";
});
const recordDescList = _.filter(questionAnswerDescList, (descItem) => {
return descItem.type === "RECORD";
});
const videoDeacList = _.filter(questionAnswerDescList, (descItem) => {
return descItem.type === "VIDEO";
});
return (
<div>
<Modal
className="question-preview-modal"
visible={true}
title="题目预览"
width={560}
footer={null}
onCancel={this.props.close}
>
<div className="question-modal-content">
<div className="question-type">
<div className="question-type__title">题型:</div>
<div className="question-type__content">
{questionTypeList[questionTypeEnum]}
</div>
</div>
<div className="question-stem">
<div className="question-stem__title">题目:</div>
<div className="question-stem__content">
{_.map(questionStemList, (item, index) => {
let dom = "";
let { type, content, size } = item;
switch (type) {
case "RICH_TEXT":
dom = (
<div
key={index}
className="input-box"
dangerouslySetInnerHTML={{
__html: content,
}}
/>
);
break;
case "PICTURE":
dom = (
<div key={index} className="picture-box">
<img
src={content}
onClick={() => this.handleScanFile("JPG", content)}
/>
</div>
);
break;
case "VOICE":
dom = (
<div key={index} className="voice-box">
<XMAudio
forbidParse
url={content}
getDuration={(durationSize) => {
size = durationSize;
this.setState({});
}}
index={index}
size={size || 1000}
/>
</div>
);
break;
}
return dom;
})}
</div>
</div>
<hr style={{ margin: "16px 0", color: "#E8E8E8", height: "1px" }} />
<div className="question-option">
<div className="question-option__title">选项:</div>
<div className="question-option__content">
{_.map(optionList, (optionItem, optionIndex) => {
const { questionOptionContentList } = optionItem;
const inputcontent = _.filter(
questionOptionContentList,
(optionItem) => {
return optionItem.type === "RICH_TEXT";
}
);
return (
<div className="option-box" key={optionIndex}>
<div className="option-box-header">
<div className="option-sort">
{NUM_TO_WORD_MAP[optionIndex]}.
</div>
<div
className="input-box"
dangerouslySetInnerHTML={{
__html: inputcontent[0].content,
}}
/>
</div>
{_.map(questionOptionContentList, (item, index) => {
let dom = "";
let { type, content, size } = item;
switch (type) {
case "PICTURE":
dom = (
<div key={index + 1} className="picture-box">
<img
src={content}
onClick={() =>
this.handleScanFile("JPG", content)
}
/>
</div>
);
break;
case "VOICE":
dom = (
<div key={index + 1} className="voice-box">
<XMAudio
forbidParse
url={content}
getDuration={(durationSize) => {
size = durationSize;
this.setState({});
}}
index={index}
size={size || 1000}
/>
</div>
);
break;
}
return dom;
})}
</div>
);
})}
</div>
</div>
<div className="question-answer">
<div className="question-answer__title">答案:</div>
<div className="question-answer__content">
{_.map(rightAnswerSort, (item, index) => {
return (
<div className="option-sort" key={index}>
{NUM_TO_WORD_MAP[item]}
</div>
);
})}
</div>
</div>
<hr style={{ margin: "16px 0", color: "#E8E8E8", height: "1px" }} />
<div className="question-desc">
<div className="question-desc__title">答案解析:</div>
<div className="question-desc__content">
<div className="question-desc-box">
{textDescList.length > 0 && (
<div
className="desc-input-box"
dangerouslySetInnerHTML={{
__html: textDescList[0].content,
}}
/>
)}
{pictureDescList.length > 0 && (
<div className="desc-picture-box">
{_.map(pictureDescList, (pictureItem, pictureIndex) => {
let { content } = pictureItem;
return (
<div className="picture-box" key={pictureIndex}>
<img
className="img-box"
src={content}
onClick={() =>
this.handleScanFile("JPG", content)
}
/>
</div>
);
})}
</div>
)}
{recordDescList.length > 0 && (
<div className="desc-audio-box">
{_.map(recordDescList, (recordItem, recordIndex) => {
let { content, size } = recordItem;
return (
<div className="audio-box" key={recordIndex}>
<XMAudio
forbidParse
url={content}
getDuration={(durationSize) => {
size = durationSize;
this.setState({});
}}
index={recordIndex}
size={size || 1000}
/>
</div>
);
})}
</div>
)}
{voiceDescList.length > 0 && (
<div className="desc-audio-box">
{_.map(voiceDescList, (voiceItem, voiceIndex) => {
let { content, size } = voiceItem;
return (
<div className="audio-box" key={voiceIndex}>
<XMAudio
forbidParse
url={content}
getDuration={(durationSize) => {
size = durationSize;
this.setState({});
}}
index={voiceIndex}
size={size || 1000}
/>
</div>
);
})}
</div>
)}
{videoDeacList.length > 0 && (
<div className="desc-video-box">
{_.map(videoDeacList, (videoItem, videoIndex) => {
let { content } = videoItem;
return (
<div className="video-box" key={videoIndex}>
<img
className="video-box_content"
src={`${content}?x-oss-process=video/snapshot,t_0,m_fast`}
/>
<img
className="video-box_btn"
src="https://image.xiaomaiketang.com/xm/r5H8cYm4ch.png"
onClick={() =>
this.handleScanFile("MP4", content)
}
/>
</div>
);
})}
</div>
)}
</div>
</div>
</div>
</div>
</Modal>
{showScanFile && (
<ScanFileModal
modalTitle={scanFileType === "MP4" ? "视频播放" : "查看大图"}
fileType={scanFileType}
item={{
ossAddress: scanFileAddress,
}}
close={() => {
this.setState({ showScanFile: false });
}}
/>
)}
</div>
);
}
}
export default QuestionPreviewModal;
.question-modal-content {
position: relative;
.question-type {
margin-bottom: 16px;
&__title {
height: 22px;
font-size: 16px;
color: #333333;
line-height: 22px;
margin-bottom: 8px;
}
&__content {
font-size: 14px;
font-weight: 400;
color: #666666;
}
}
.question-stem {
margin-bottom: 16px;
img {
max-width: 88px;
max-height: 88px;
}
&__title {
height: 22px;
font-size: 16px;
color: #333333;
line-height: 22px;
margin-bottom: 8px;
}
&__content {
font-size: 14px;
font-weight: 400;
color: #666666;
.input-box {
margin-bottom: 8px;
* {
display: inline-block;
}
}
.picture-box {
display: inline-flex;
margin: 12px 12px 0 0;
}
.voice-box {
margin-bottom: 12px;
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.1);
padding: 10px 20px;
width: 320px;
}
}
}
.question-option {
margin-bottom: 16px;
img {
max-width: 88px;
max-height: 88px;
}
&__title {
height: 22px;
font-size: 16px;
color: #333333;
line-height: 22px;
margin-bottom: 8px;
}
&__content {
font-size: 14px;
font-weight: 400;
color: #666666;
.option-box {
color: #666666;
margin-bottom: 8px;
.option-box-header {
.option-sort {
display: inline-block;
margin-right: 5px;
}
.input-box {
display: inline-block;
max-width: calc(100% - 20px);
vertical-align: top;
}
}
.picture-box {
display: inline-flex;
margin: 12px 12px 0 0;
}
.voice-box {
margin-bottom: 12px;
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.1);
padding: 10px 20px;
width: 320px;
}
}
}
}
.question-answer {
margin-bottom: 16px;
img {
max-width: 88px;
max-height: 88px;
}
&__title {
height: 22px;
font-size: 16px;
color: #333333;
line-height: 22px;
margin-bottom: 8px;
}
&__content {
font-size: 14px;
font-weight: 400;
color: #666666;
.option-sort {
display: inline-block;
margin-right: 8px;
}
}
}
.question-desc {
margin-bottom: 16px;
&__title {
height: 22px;
font-size: 16px;
color: #333333;
line-height: 22px;
margin-bottom: 8px;
}
&__content {
font-size: 14px;
font-weight: 400;
color: #666666;
.desc-input-box {
margin-bottom: 8px;
* {
display: inline-block;
}
}
.desc-picture-box {
display: inline-flex;
margin-bottom: 28px;
.picture-box {
width: 88px;
height: 88px;
border-radius: 4px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
.img-box {
max-width: 88px;
max-height: 88px;
border-radius: 4px;
}
}
}
.desc-audio-box {
margin-bottom: 28px;
.audio-box {
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.1);
padding: 10px 20px;
width: 320px;
margin-bottom: 12px;
}
}
.desc-video-box {
.video-box {
position: relative;
display: inline-block;
width: 208px;
overflow: hidden;
padding-top: 12px;
margin: 0px 12px 12px 0;
&_content {
max-width: 200px;
max-height: 200px;
border-radius: 4px;
}
&_btn {
width: 32px;
height: 32px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -8px;
margin-left: -16px;
}
}
}
}
}
}
.question-preview-modal.ant-modal {
max-height: 60% !important;
}
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