QuestionManage.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. <template>
  2. <div class="content question-manage">
  3. <!-- 正文信息 -->
  4. <div class="part-box">
  5. <h2 class="part-box-title">题库列表</h2>
  6. <el-form class="part-filter-form" :inline="true" :model="filter">
  7. <el-form-item label="课程名称">
  8. <course-select v-model="filter.courseId" @change="courseChange">
  9. </course-select>
  10. </el-form-item>
  11. <el-form-item label="题型">
  12. <question-type-select v-model="filter.quesStructType">
  13. </question-type-select>
  14. </el-form-item>
  15. <el-form-item label="题目内容">
  16. <el-input v-model="filter.content" placeholder="题目内容"></el-input>
  17. </el-form-item>
  18. <el-form-item label="属性名">
  19. <property-select
  20. v-model="filter.coursePropertyId"
  21. :course-id="filter.courseId"
  22. ></property-select>
  23. </el-form-item>
  24. <el-form-item label="一级属性">
  25. <property-sub-select
  26. v-model="filter.firstPropertyId"
  27. :parent-id="filter.coursePropertyId"
  28. data-type="first"
  29. ></property-sub-select>
  30. </el-form-item>
  31. <el-form-item label="二级属性">
  32. <property-sub-select
  33. v-model="filter.secondPropertyId"
  34. :parent-id="filter.firstPropertyId"
  35. data-type="second"
  36. ></property-sub-select>
  37. </el-form-item>
  38. <el-form-item>
  39. <el-button type="danger" @click="toPage(1)">查询</el-button>
  40. </el-form-item>
  41. </el-form>
  42. <div class="part-box-action">
  43. <div>
  44. <el-button
  45. type="primary"
  46. plain
  47. icon="el-icon-data-analysis"
  48. @click="toStatistics"
  49. >试题统计</el-button
  50. >
  51. <el-button
  52. type="danger"
  53. plain
  54. icon="el-icon-lock"
  55. @click="toSafetySet"
  56. >安全设置</el-button
  57. >
  58. </div>
  59. <div>
  60. <el-button
  61. type="primary"
  62. plain
  63. icon="el-icon-folder-opened"
  64. @click="toAddFolder"
  65. >新建文件夹</el-button
  66. >
  67. <el-button
  68. type="primary"
  69. plain
  70. icon="el-icon-circle-plus-outline"
  71. @click="toCreateQuestion"
  72. >创建试题</el-button
  73. >
  74. <el-button
  75. type="primary"
  76. plain
  77. icon="el-icon-upload2"
  78. @click="toImportQuestion"
  79. >批量导入</el-button
  80. >
  81. </div>
  82. </div>
  83. </div>
  84. <div class="part-box">
  85. <el-table
  86. v-loading="loading"
  87. element-loading-text="加载中"
  88. :data="questionList"
  89. >
  90. <el-table-column
  91. type="selection"
  92. width="50"
  93. align="center"
  94. ></el-table-column>
  95. <el-table-column label="题干">
  96. <template slot-scope="scope">
  97. <rich-text
  98. class="row-question-body"
  99. title="点击查看试题"
  100. :text-json="scope.row.quesBody"
  101. @click="toViewQuestion(scope.row)"
  102. ></rich-text>
  103. </template>
  104. </el-table-column>
  105. <el-table-column label="课程" width="120">
  106. <template slot-scope="scope">
  107. <span>{{ scope.row.course.name }}</span>
  108. </template>
  109. </el-table-column>
  110. <el-table-column label="题型" width="100">
  111. <template slot-scope="scope">
  112. <span>{{ scope.row.questionType | questionType }}</span>
  113. </template>
  114. </el-table-column>
  115. <el-table-column label="难度" width="80"> </el-table-column>
  116. <el-table-column label="使用量" width="80"> </el-table-column>
  117. <el-table-column label="创建人" width="120">
  118. <template slot-scope="scope">
  119. <span>{{ scope.row.creator }}</span>
  120. </template>
  121. </el-table-column>
  122. <el-table-column label="创建时间" width="170" prop="creationTime">
  123. </el-table-column>
  124. <el-table-column label="操作" width="180" fixed="right">
  125. <template slot-scope="scope">
  126. <div class="operate_left">
  127. <el-button
  128. size="mini"
  129. type="primary"
  130. plain
  131. @click="toEditQuestion(scope.row)"
  132. >编辑</el-button
  133. >
  134. <el-dropdown>
  135. <el-button type="primary" size="mini" plain>
  136. 更多 <i class="el-icon-more el-icon--right"></i>
  137. </el-button>
  138. <el-dropdown-menu slot="dropdown" class="action-dropdown">
  139. <el-dropdown-item>
  140. <el-button
  141. size="mini"
  142. type="primary"
  143. plain
  144. @click="toMoveQuestion(scope.row)"
  145. >移动</el-button
  146. >
  147. </el-dropdown-item>
  148. <el-dropdown-item>
  149. <el-button
  150. size="mini"
  151. type="primary"
  152. plain
  153. @click="toCopyQuestion(scope.row)"
  154. >复制</el-button
  155. >
  156. </el-dropdown-item>
  157. <el-dropdown-item>
  158. <el-button
  159. size="mini"
  160. type="danger"
  161. plain
  162. @click="toDeleteQuestion(scope.row)"
  163. >删除</el-button
  164. >
  165. </el-dropdown-item>
  166. <el-dropdown-item>
  167. <el-button
  168. size="mini"
  169. type="primary"
  170. plain
  171. @click="toLinkQuestion(scope.row)"
  172. >关联属性</el-button
  173. >
  174. </el-dropdown-item>
  175. </el-dropdown-menu>
  176. </el-dropdown>
  177. </div>
  178. </template>
  179. </el-table-column>
  180. </el-table>
  181. <div class="part-page">
  182. <el-pagination
  183. :current-page="currentPage"
  184. :page-size="pageSize"
  185. :page-sizes="[10, 20, 50, 100, 200, 300]"
  186. layout="total, sizes, prev, pager, next, jumper"
  187. :total="total"
  188. @current-change="toPage"
  189. @size-change="handleSizeChange"
  190. >
  191. </el-pagination>
  192. </div>
  193. <el-button type="danger" @click="toRecycle">回收站</el-button>
  194. </div>
  195. <!-- QuestionEditDialog -->
  196. <question-edit-dialog
  197. ref="QuestionEditDialog"
  198. :question="curQuestion"
  199. ></question-edit-dialog>
  200. <!-- QuestionPreviewDialog -->
  201. <question-preview-dialog
  202. ref="QuestionPreviewDialog"
  203. :question="curQuestion"
  204. ></question-preview-dialog>
  205. <!-- QuestionStatisticsDialog -->
  206. <question-statistics-dialog
  207. ref="QuestionStatisticsDialog"
  208. :course-id="filter.courseId"
  209. ></question-statistics-dialog>
  210. <!-- QuestionSafetySetDialog -->
  211. <question-safety-set-dialog
  212. ref="QuestionSafetySetDialog"
  213. ></question-safety-set-dialog>
  214. <!-- QuestionFolderDialog -->
  215. <question-folder-dialog
  216. ref="QuestionFolderDialog"
  217. :is-edit="isEditFolder"
  218. @selected="folderSelected"
  219. ></question-folder-dialog>
  220. <!-- QuestionImportDialog -->
  221. <question-import-dialog
  222. ref="QuestionImportDialog"
  223. @modified="toPage(1)"
  224. ></question-import-dialog>
  225. <!-- ModifyFolder -->
  226. <modify-folder
  227. ref="ModifyFolder"
  228. :instance="curFolder"
  229. @modified="folderModified"
  230. ></modify-folder>
  231. </div>
  232. </template>
  233. <script>
  234. import {
  235. questionPageListApi,
  236. deleteQuestionApi,
  237. moveQuestionApi,
  238. moveClassifyApi,
  239. copyQuestionApi,
  240. } from "../api";
  241. import QuestionStatisticsDialog from "../components/QuestionStatisticsDialog.vue";
  242. import QuestionSafetySetDialog from "../components/QuestionSafetySetDialog.vue";
  243. import QuestionFolderDialog from "../components/QuestionFolderDialog.vue";
  244. import QuestionImportDialog from "../components/QuestionImportDialog.vue";
  245. import QuestionEditDialog from "../components/QuestionEditDialog.vue";
  246. import QuestionPreviewDialog from "../components/QuestionPreviewDialog.vue";
  247. import ModifyFolder from "../components/ModifyFolder.vue";
  248. export default {
  249. name: "QuestionMamage",
  250. components: {
  251. QuestionStatisticsDialog,
  252. QuestionSafetySetDialog,
  253. QuestionFolderDialog,
  254. QuestionImportDialog,
  255. QuestionEditDialog,
  256. QuestionPreviewDialog,
  257. ModifyFolder,
  258. },
  259. data() {
  260. return {
  261. filter: {
  262. classifyId: null,
  263. courseId: "",
  264. quesStructType: "",
  265. content: "",
  266. coursePropertyId: "",
  267. firstPropertyId: "",
  268. secondPropertyId: "",
  269. },
  270. folderList: [],
  271. questionList: [],
  272. currentPage: 1,
  273. pageSize: 10,
  274. total: 0,
  275. loading: false,
  276. isEditFolder: true,
  277. curQuestion: {},
  278. curFolder: {},
  279. curCourse: {},
  280. curMoveType: "",
  281. };
  282. },
  283. mounted() {
  284. // this.toPage(1);
  285. },
  286. methods: {
  287. // async getFolderList() {
  288. // const res = await classifyListApi(this.filter.classifyId);
  289. // this.folderList = res.data || [];
  290. // },
  291. // toFolder(classifyId) {
  292. // this.filter.classifyId = classifyId;
  293. // this.toPage(1);
  294. // },
  295. toPage(page) {
  296. this.currentPage = page;
  297. this.getList();
  298. },
  299. async getList() {
  300. this.loading = true;
  301. const res = await questionPageListApi({
  302. ...this.filter,
  303. curPage: this.currentPage,
  304. pageSize: this.pageSize,
  305. }).catch(() => {});
  306. this.loading = false;
  307. if (!res) return;
  308. this.folderList = res.data.questionClassifyResultList;
  309. this.questionList = res.data.questionPageResult.content;
  310. this.total = res.data.questionPageResult.totalElements;
  311. },
  312. handleSizeChange(val) {
  313. this.pageSize = val;
  314. this.toPage(1);
  315. },
  316. courseChange(val) {
  317. this.curCourse = val || {};
  318. },
  319. toStatistics() {
  320. if (!this.filter.courseId) {
  321. this.$message.error("请先选择课程!");
  322. return;
  323. }
  324. this.$refs.QuestionStatisticsDialog.open();
  325. },
  326. toSafetySet() {
  327. this.$refs.QuestionSafetySetDialog.open();
  328. },
  329. toCreateQuestion() {
  330. if (!this.filter.courseId) {
  331. this.$message.error("请先选择课程!");
  332. return;
  333. }
  334. this.curQuestion = {
  335. courseId: this.curCourse.id,
  336. courseCode: this.curCourse.code,
  337. courseName: this.curCourse.name,
  338. };
  339. this.$refs.QuestionEditDialog.open();
  340. },
  341. toImportQuestion() {
  342. this.$refs.QuestionImportDialog.open();
  343. },
  344. toViewQuestion(row) {
  345. console.log(row);
  346. this.curQuestion = row;
  347. this.$refs.QuestionPreviewDialog.open();
  348. },
  349. toEditQuestion(row) {
  350. console.log(row);
  351. // todo:编辑试题
  352. this.curQuestion = row;
  353. this.$refs.QuestionEditDialog.open();
  354. },
  355. toMoveQuestion(row) {
  356. this.isEditFolder = false;
  357. this.curMoveType = "question";
  358. this.curQuestion = row;
  359. this.$refs.QuestionFolderDialog.open();
  360. },
  361. async folderSelected(folder) {
  362. let res = null;
  363. if (this.curMoveType === "question") {
  364. res = await moveQuestionApi(this.curQuestion.id, folder.id).catch(
  365. () => {}
  366. );
  367. } else {
  368. res = await moveClassifyApi(this.curFolder.id, folder.id).catch(
  369. () => {}
  370. );
  371. }
  372. if (!res) return;
  373. this.$message.success("操作成功!");
  374. this.getList();
  375. },
  376. async toCopyQuestion(row) {
  377. console.log(row);
  378. const res = await copyQuestionApi(row.id).catch(() => {});
  379. if (!res) return;
  380. this.$message.success("操作成功!");
  381. this.getList();
  382. },
  383. async toDeleteQuestion(row) {
  384. const confirm = await this.$confirm("确认删除试题吗?", "提示", {
  385. type: "warning",
  386. }).catch(() => {});
  387. if (confirm !== "confirm") return;
  388. this.loading = true;
  389. const res = await deleteQuestionApi(row.id).catch((error) => {
  390. this.$notify({
  391. message: error.response.data.desc,
  392. type: "error",
  393. });
  394. });
  395. if (!res) return;
  396. this.$notify({
  397. message: "删除成功",
  398. type: "success",
  399. });
  400. this.getList();
  401. },
  402. toLinkQuestion(row) {
  403. console.log(row);
  404. },
  405. toAddFolder() {
  406. this.curFolder = { parentId: this.filter.classifyId };
  407. this.$refs.ModifyFolder.open();
  408. },
  409. // toEditFolder(row) {
  410. // this.curFolder = row;
  411. // this.$refs.ModifyFolder.open();
  412. // },
  413. // toMoveFolder(row) {
  414. // console.log(row);
  415. // this.isEditFolder = false;
  416. // this.curMoveType = "folder";
  417. // this.curFolder = row;
  418. // this.$refs.QuestionFolderDialog.open();
  419. // },
  420. // async toDeleteFolder(row) {
  421. // const confirm = await this.$confirm(`确定要删除选中的文件夹吗?`, "提示", {
  422. // type: "warning",
  423. // }).catch(() => {});
  424. // if (confirm !== "confirm") return;
  425. // if (this.loading) return;
  426. // this.loading = true;
  427. // const res = await deleteClassifyApi(row.id).catch(() => {});
  428. // this.loading = false;
  429. // if (!res) return;
  430. // this.$message.success("操作成功");
  431. // await this.getClassifyTree();
  432. // },
  433. folderModified() {
  434. this.getFolderList();
  435. },
  436. toRecycle() {
  437. this.$router.push({
  438. name: "QuestionRecycle",
  439. });
  440. },
  441. },
  442. };
  443. </script>