试卷库分类等

master
yujialong 4 months ago
parent b6f3b1f3d6
commit 479aba93eb
  1. 2
      public/static/ueditor/ueditor.all.js
  2. 4
      public/static/ueditor/ueditor.config.js
  3. 20
      src/api/index.js
  4. 1
      src/assets/images/knowledge.svg
  5. 482
      src/pages/knowledge/index.vue
  6. 26
      src/pages/ques/index.vue
  7. 4
      src/pages/quesBank/index.vue
  8. 332
      src/pages/testPaper/detail/index.vue
  9. 189
      src/pages/testPaper/detail/template.vue
  10. 498
      src/pages/testPaper/list/index.vue
  11. 363
      src/pages/testPaperLibrary/index.vue
  12. 292
      src/pages/testPaperLibraryType/index.vue
  13. 16
      src/plugins/requests/index.js
  14. 16
      src/router/modules/knowledge.js
  15. 2
      src/router/modules/ques.js
  16. 2
      src/router/modules/quesBank.js
  17. 2
      src/router/modules/quesBankType.js
  18. 24
      src/router/modules/testPaper.js
  19. 16
      src/router/modules/testPaperLibrary.js
  20. 16
      src/router/modules/testPaperLibraryType.js

File diff suppressed because one or more lines are too long

@ -1,6 +1,6 @@
!function () { !function () {
window.UEDITOR_HOME_URL = "./static/ueditor/"; var s = window.UEDITOR_HOME_URL || l(); function l (s, l) { return function (s, l) { var t = l; /^(\/|\\\\)/.test(l) ? t = /^.+?\w(\/|\\\\)/.exec(s)[0] + l.replace(/^(\/|\\\\)/, "") : /^[a-z]+:/i.test(l) || (s = s.split("#")[0].split("?")[0].replace(/[^\\\/]+$/, ""), t = s + "" + l); return function (s) { var l = /^[a-z]+:\/\//.exec(s)[0], t = null, e = []; (s = (s = s.replace(l, "").split("?")[0].split("#")[0]).replace(/\\/g, "/").split(/\//))[s.length - 1] = ""; for (; s.length;)".." === (t = s.shift()) ? e.pop() : "." !== t && e.push(t); return l + e.join("/") }(t) }(s || self.document.URL || self.location.href, l || (t = document.getElementsByTagName("script"))[t.length - 1].src); var t } window.UEDITOR_CONFIG = { window.UEDITOR_HOME_URL = "./static/ueditor/"; var s = window.UEDITOR_HOME_URL || l(); function l (s, l) { return function (s, l) { var t = l; /^(\/|\\\\)/.test(l) ? t = /^.+?\w(\/|\\\\)/.exec(s)[0] + l.replace(/^(\/|\\\\)/, "") : /^[a-z]+:/i.test(l) || (s = s.split("#")[0].split("?")[0].replace(/[^\\\/]+$/, ""), t = s + "" + l); return function (s) { var l = /^[a-z]+:\/\//.exec(s)[0], t = null, e = []; (s = (s = s.replace(l, "").split("?")[0].split("#")[0]).replace(/\\/g, "/").split(/\//))[s.length - 1] = ""; for (; s.length;)".." === (t = s.shift()) ? e.pop() : "." !== t && e.push(t); return l + e.join("/") }(t) }(s || self.document.URL || self.location.href, l || (t = document.getElementsByTagName("script"))[t.length - 1].src); var t } window.UEDITOR_CONFIG = {
UEDITOR_HOME_URL: s, serverHeaders: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, Authorization', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS' }, serverUrl: "http://192.168.31.51:9950/exam/exam/upload/configAndUpload", toolbars: [[ UEDITOR_HOME_URL: s, serverHeaders: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, Authorization', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS' }, serverUrl: "http://192.168.31.51:9000/exam/exam/upload/configAndUpload", toolbars: [[
"fullscreen", "fullscreen",
"source", "source",
"|", "|",
@ -73,6 +73,6 @@
"background", "background",
"|", "|",
"gapfilling", "gapfilling",
]], labelMap: { anchor: "", undo: "" }, enableAutoSave: !1, saveInterval: 0, elementPathEnabled: !1, wordCount: !1, maximumWords: 1e5, xssFilterRules: !0, inputXssFilter: !0, outputXssFilter: !0, whitList: { a: ["target", "href", "title", "class", "style"], abbr: ["title", "class", "style"], address: ["class", "style"], area: ["shape", "coords", "href", "alt"], article: [], aside: [], audio: ["autoplay", "controls", "loop", "preload", "src", "class", "style"], b: ["class", "style"], bdi: ["dir"], bdo: ["dir"], big: [], blockquote: ["cite", "class", "style"], br: [], caption: ["class", "style"], center: [], cite: [], code: ["class", "style"], col: ["align", "valign", "span", "width", "class", "style"], colgroup: ["align", "valign", "span", "width", "class", "style"], dd: ["class", "style"], del: ["datetime"], details: ["open"], div: ["class", "style"], dl: ["class", "style"], dt: ["class", "style"], em: ["class", "style"], font: ["color", "size", "face"], footer: [], h1: ["class", "style"], h2: ["class", "style"], h3: ["class", "style"], h4: ["class", "style"], h5: ["class", "style"], h6: ["class", "style"], header: [], hr: [], i: ["class", "style"], img: ["src", "alt", "title", "width", "height", "id", "_src", "loadingclass", "class", "data-latex"], ins: ["datetime"], li: ["class", "style"], mark: [], nav: [], ol: ["class", "style"], p: ["class", "style"], pre: ["class", "style"], s: [], section: [], small: [], span: ["class", "style"], sub: ["class", "style"], sup: ["class", "style"], strong: ["class", "style"], table: ["width", "border", "align", "valign", "class", "style"], tbody: ["align", "valign", "class", "style"], td: ["width", "rowspan", "colspan", "align", "valign", "class", "style"], tfoot: ["align", "valign", "class", "style"], th: ["width", "rowspan", "colspan", "align", "valign", "class", "style"], thead: ["align", "valign", "class", "style"], tr: ["rowspan", "align", "valign", "class", "style"], tt: [], u: [], ul: ["class", "style"], video: ["autoplay", "controls", "loop", "preload", "src", "height", "width", "class", "style"], initialFrameHeight: 400 } ]], labelMap: { anchor: "", undo: "" }, enableAutoSave: !1, saveInterval: 0, elementPathEnabled: !1, wordCount: !1, maximumWords: 1e5, xssFilterRules: !0, inputXssFilter: !0, outputXssFilter: !0, whitList: { a: ["target", "href", "title", "class", "style"], abbr: ["title", "class", "style"], address: ["class", "style"], area: ["shape", "coords", "href", "alt"], article: [], aside: [], audio: ["autoplay", "controls", "loop", "preload", "src", "class", "style"], b: ["class", "style"], bdi: ["dir"], bdo: ["dir"], big: [], blockquote: ["cite", "class", "style"], br: [], caption: ["class", "style"], center: [], cite: [], code: ["class", "style"], col: ["align", "valign", "span", "width", "class", "style"], colgroup: ["align", "valign", "span", "width", "class", "style"], dd: ["class", "style"], del: ["datetime"], details: ["open"], div: ["class", "style"], dl: ["class", "style"], dt: ["class", "style"], em: ["class", "style"], font: ["color", "size", "face"], footer: [], h1: ["class", "style"], h2: ["class", "style"], h3: ["class", "style"], h4: ["class", "style"], h5: ["class", "style"], h6: ["class", "style"], header: [], hr: [], i: ["class", "style"], img: ["src", "alt", "title", "width", "height", "id", "_src", "loadingclass", "class", "data-latex"], ins: ["datetime"], li: ["class", "style"], mark: [], nav: [], ol: ["class", "style"], p: ["class", "style"], pre: ["class", "style"], s: [], section: [], small: [], span: ["class", "style"], sub: ["class", "style"], sup: ["class", "style"], strong: ["class", "style"], table: ["width", "border", "align", "valign", "class", "style"], tbody: ["align", "valign", "class", "style"], td: ["width", "rowspan", "colspan", "align", "valign", "class", "style"], tfoot: ["align", "valign", "class", "style"], th: ["width", "rowspan", "colspan", "align", "valign", "class", "style"], thead: ["align", "valign", "class", "style"], tr: ["rowspan", "align", "valign", "class", "style"], tt: [], u: [], ul: ["class", "style"], video: ["autoplay", "controls", "loop", "preload", "src", "height", "width", "class", "style"], initialFrameHeight: 400, zIndex: 100, }
}, window.UE = { getUEBasePath: l } }, window.UE = { getUEBasePath: l }
}(); }();

@ -2,6 +2,8 @@ import Setting from '@/setting'
const host = 'http://192.168.31.51:9000' const host = 'http://192.168.31.51:9000'
export default { export default {
queryProfessional: `/exam/exam/professional/queryProfessional`,
categoriesDel: `/exam/question/bank/categories/batchDeletion`, categoriesDel: `/exam/question/bank/categories/batchDeletion`,
categoriesFind: `/exam/question/bank/categories/findById`, categoriesFind: `/exam/question/bank/categories/findById`,
getAllQuestionBankCategories: `/exam/question/bank/categories/getAllQuestionBankCategories`, getAllQuestionBankCategories: `/exam/question/bank/categories/getAllQuestionBankCategories`,
@ -16,15 +18,11 @@ export default {
copyQuestionBank: `/exam/questionBank/copyQuestionBank`, copyQuestionBank: `/exam/questionBank/copyQuestionBank`,
TreeStructure: `/exam/knowledgeHierarchy/TreeStructure`, TreeStructure: `/exam/knowledgeHierarchy/TreeStructure`,
classificationTreeStructure: `/exam/knowledgeHierarchy/classificationTreeStructure`,
knowledgeHierarchyDel: `/exam/knowledgeHierarchy/batchDeletion`, knowledgeHierarchyDel: `/exam/knowledgeHierarchy/batchDeletion`,
knowledgeHierarchyFind: `/exam/knowledgeHierarchy/findById`, knowledgeHierarchyFind: `/exam/knowledgeHierarchy/findById`,
knowledgeHierarchySave: `/exam/knowledgeHierarchy/saveOrUpdate`, knowledgeHierarchySave: `/exam/knowledgeHierarchy/saveOrUpdate`,
knowledgeHierarchyList: `/exam/knowledgeHierarchy/pagingQuery`,
knowledgePointsDel: `/exam/knowledgePoints/batchDeletion`,
knowledgePointsFind: `/exam/knowledgePoints/findById`,
knowledgePointsList: `/exam/knowledgePoints/pagingQuery`,
knowledgePointsSave: `/exam/knowledgePoints/saveOrUpdate`,
knowledgePointsDisable: `/exam/knowledgePoints/updateStatus`,
libraryClassificationDel: `/exam/exam/libraryClassification/delete`, libraryClassificationDel: `/exam/exam/libraryClassification/delete`,
libraryClassificationSave: `/exam/exam/libraryClassification/save`, libraryClassificationSave: `/exam/exam/libraryClassification/save`,
@ -43,4 +41,14 @@ export default {
examClassificationSave: `/exam/exam/classification/save`, examClassificationSave: `/exam/exam/classification/save`,
examClassificationList: `/exam/exam/classification/treeList`, examClassificationList: `/exam/exam/classification/treeList`,
examClassificationUpdate: `/exam/exam/classification/update`, examClassificationUpdate: `/exam/exam/classification/update`,
examClassificationFind: `/exam/exam/classification/details`,
paperDel: `/exam/exam/paper/delete`,
examPaperList: `/exam/exam/paper/examPaperList`,
saveExamPaper: `/exam/exam/paper/saveExamPaper`,
paperDisable: `/exam/exam/paper/updateStatus`,
deleteTemplate: `/exam/exam/paperTemplate/deleteTemplate`,
examPaperTemplateList: `/exam/exam/paperTemplate/examPaperTemplateList`,
saveExamPaperTemplate: `/exam/exam/paperTemplate/saveExamPaperTemplate`,
} }

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1721902228999" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4555" width="22" height="22" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M249.8 280.2h145v51.2h-145zM249.8 380.6h96v51.2h-96z" fill="#2962ff" p-id="4556"></path><path d="M894.2 157.4H608c-38.1 0-72.3 16.8-95.8 43.2-23.4-26.5-57.7-43.2-95.8-43.2H162.3l-33.2 1.2V782l1.2 33.2h286.2c19 0 36.8 8.4 49 23 11.6 13.9 28.6 21.8 46.7 21.8 18.2 0 35.2-7.9 46.8-21.8 12.1-14.6 30-23 49-23h254.2l33.2-1.2V190.6l-1.2-33.2z m-62.9 593.8H608c-36.8 0-71.5 15.7-95.8 43.2-24.3-27.5-59-43.2-95.8-43.2H193.2V221.4h223.3c33.5 0 60.7 26 63.2 58.8v441.9h64V285.2h0.5c0-35.2 28.6-63.7 63.7-63.7h223.3v529.7z" fill="#2962ff" p-id="4557"></path></svg>

After

Width:  |  Height:  |  Size: 884 B

@ -0,0 +1,482 @@
<template>
<div>
<Breadcrumb :data="crumbs" />
<div class="page">
<div class="side">
<div class="m-b-20">
<el-radio-group v-model="isNotJoin" @change="changeType">
<div class="m-b-20">
<el-radio :label="0">所有知识点</el-radio>
</div>
<div>
<el-radio :label="1">未加入分类的知识点</el-radio>
</div>
</el-radio-group>
</div>
<el-divider></el-divider>
<div>
<div class="flex-between m-b-10">
<h6 class="page-name" style="margin-bottom: 0">知识点分类</h6>
<el-button type="text" @click="addType">添加</el-button>
</div>
<el-input class="m-b-10" placeholder="请输入知识点分类" prefix-icon="el-icon-search" size="small" clearable
v-model="keyword"></el-input>
<div style="overflow: auto">
<el-tree v-loading="loading" :data="types" default-expand-all ref="typeTree" node-key="id" highlight-current
:expand-on-click-node="false" @node-click="handleNodeClick" :props="{ label: 'name', isLeaf: 'leaf' }">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span class="org-name">{{ data.name }}</span>
<span>
<el-button type="text" icon="el-icon-circle-plus-outline" @click="() => addType(node, data)">
</el-button>
<el-button type="text" icon="el-icon-edit-outline" @click="() => editType(node, data)">
</el-button>
<el-button type="text" icon="el-icon-delete" @click="() => delType(data)">
</el-button>
</span>
</span>
</el-tree>
</div>
</div>
<el-dialog :title="typeForm.id ? '编辑' : '新增' + '知识点分类'" :visible.sync="typeVisible"
:close-on-click-modal="false" width="400px">
<el-form v-if="typeVisible" ref="typeForm" :model="typeForm" :rules="typeRules" label-width="130px">
<el-form-item label="知识点分类名称" prop="name">
<el-input v-model.trim="typeForm.name" placeholder="请输入知识点分类" maxlength="20"></el-input>
</el-form-item>
<el-form-item label="设置上一级">
<el-cascader :options="types" v-model="cascaderValue" :props="cascaderProps" clearable
style="width: 100%">
</el-cascader>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="closeType"> </el-button>
<el-button type="primary" @click="typeSubmit"> </el-button>
</span>
</el-dialog>
</div>
<div class="right">
<h6 class="page-name">筛选</h6>
<div class="tool">
<ul class="filter">
<li>
<el-input style="width: 250px;" placeholder="请输入知识点名称" prefix-icon="el-icon-search" v-model="filter.name"
clearable></el-input>
</li>
</ul>
<div>
<el-button type="primary" @click="add">新增知识点</el-button>
<el-button type="primary" @click="delAllSelection">批量删除</el-button>
</div>
</div>
<el-table :data="list" v-loading="listLoading" class="table" ref="table" stripe header-align="center"
@selection-change="handleSelectionChange" row-key="id" @sort-change="sortChange">
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column>
<el-table-column prop="name" label="知识点名称" align="center" min-width="120"></el-table-column>
<el-table-column prop="knowledgePointsClassification" label="知识点分类" align="center" min-width="120"
show-overflow-tooltip></el-table-column>
<el-table-column prop="relatedQuestionsNum" label="已关联试题" align="center" width="90"></el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center" width="160"
sortable="custom"></el-table-column>
<el-table-column prop="createUserName" label="创建人" align="center" width="100"></el-table-column>
<el-table-column label="操作" align="center" width="100">
<template slot-scope="scope">
<el-button type="text" @click="edit(scope.row)">编辑</el-button>
<!-- <el-button type="text" v-auth="'/system:后台账号:重置密码'" @click="resetPassword(scope.row)">转移</el-button> -->
<el-button type="text" @click="del(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="currentChange" :current-page="page"
layout="total, prev, pager, next" :total="total"></el-pagination>
</div>
<el-dialog :title="!form.id ? '添加知识点' : '编辑知识点'" :visible.sync="knowledgeVisible" width="400px"
:close-on-click-modal="false">
<el-form :model="form" :rules="rules" label-width="100px">
<el-form-item prop="parentId" label="知识点分类">
<el-cascader placeholder="请选择题库分类" v-model="form.parentId" :options="types"
:props="{ value: 'id', label: 'name', checkStrictly: true }" clearable></el-cascader>
</el-form-item>
<el-form-item prop="name" label="知识点名称">
<el-input placeholder="请输入知识点名称" v-model="form.name" maxlength="20"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="knowledgeVisible = false"> </el-button>
<el-button type="primary" @click="knowledgeSubmit"> </el-button>
</span>
</el-dialog>
</div>
</div>
<el-dialog title="提示" :visible.sync="delVisible" width="400px" :close-on-click-modal="false" custom-class="del-dia">
<div class="del-wrap">
<div class="icon el-icon-warning"></div>
<div>
<p>确认要删除{{ curName }}</p>
<p class="tips">删除后其子级分类与知识点也将被删除</p>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="delVisible = false">取消</el-button>
<el-button type="primary" @click="delTypeSubmit">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Util from '@/libs/util'
import _ from 'lodash'
import Breadcrumb from '@/components/breadcrumb'
export default {
components: { Breadcrumb },
data () {
return {
typeId: this.$route.query.id,
createSource: 1,
loading: false,
keyword: '',
types: [],
isNotJoin: 0,
typeVisible: false, //
typeForm: {
id: '',
name: ''
},
cascaderValue: [],
cascaderProps: {
checkStrictly: true,
label: "name",
value: "id"
},
treeVisible: true,
isDetail: false,
name: '',
form: {
name: '',
parentId: []
},
typeRules: {
name: [
{ required: true, message: '请输入知识点分类名称', trigger: 'blur' }
]
},
rules: {
name: [
{ required: true, message: '请输入知识点名称', trigger: 'blur' }
],
},
filter: {
timeOrderBy: '',
name: '',
},
listLoading: false,
list: [],
page: 1,
pageSize: 10,
total: 0,
multipleSelection: [],
knowledgeVisible: false,
submiting: false, //
delVisible: false,
deleteQuestions: false,
curName: '',
curId: [],
};
},
watch: {
keyword: function () {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(this.getType, 500)
},
'filter.name': function () {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(this.getList, 500)
},
},
mounted () {
this.crumbs = [
{
name: this.$route.query.name || '题库管理',
route: '/quesBank'
},
{
name: '试题列表',
route: '/ques',
query: {
id: this.typeId
}
},
{
name: '知识点列表'
},
],
this.getType()
},
methods: {
//
async getType () {
try {
this.loading = true
const { data } = await this.$post(this.api.classificationTreeStructure, {
createSource: this.createSource,
keyword: this.keyword,
questionBankId: this.typeId,
})
this.handleType(data)
this.types = data
this.getList()
} finally {
this.loading = false
}
},
//
changeType () {
this.$refs.typeTree.setCurrentKey(null)
this.initData()
},
//
addType (node, data) {
this.typeForm = {
id: '',
parentId: data ? data.id : '',
name: '',
}
this.typeVisible = true
this.cascaderValue = data.path.split('/').map(e => +e)
},
//
editType (node, data) {
this.typeForm = {
id: data.id,
name: data.name
}
this.typeVisible = true
const path = data.path.split('/').map(e => +e)
this.cascaderValue = path.length > 1 ? path.slice(0, path.length - 1) : []
},
//
handleType (list) {
list.map(e => {
if (e.children && e.children.length) {
this.handleType(e.children)
} else {
delete e.children
}
})
},
//
async delType (row) {
try {
await this.$confirm(`<p>确认要删除【${row.name}】吗?</p><p style="color: #f56c6c;">删除后,其子级分类与知识点都将被删除!</p>`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
dangerouslyUseHTMLString: true,
})
await this.$post(this.api.knowledgeHierarchyDel, [row.id])
Util.successMsg('删除成功')
this.getType()
} catch (e) { }
},
//
async delTypeSubmit () {
await this.$post(this.api.knowledgeHierarchyDel, this.curId)
Util.successMsg('删除成功')
this.delVisible = false
this.getType()
},
// /
typeSubmit () {
this.$refs.typeForm.validate(async (valid) => {
if (valid) {
const form = this.typeForm
const cas = this.cascaderValue
const len = cas.length
if (cas && len) {
this.typeForm.parentId = cas[len - 1]
}
form.createSource = this.createSource
form.questionBankId = this.typeId
form.type = 0
await this.$post(this.api.knowledgeHierarchySave, form)
Util.successMsg('保存成功')
this.closeType()
}
});
},
//
handleNodeClick (data) {
this.$refs.table.clearSelection()
this.isNotJoin = ''
this.getList()
},
//
closeType () {
this.typeVisible = false
this.cascaderValue = []
this.getType()
},
//
async getList () {
try {
this.listLoading = true
const res = await this.$post(this.api.knowledgeHierarchyList, {
...this.filter,
isNotJoin: this.isNotJoin || '',
pageNum: this.page,
pageSize: this.pageSize,
questionBankId: this.typeId,
knowledgePointCategoryId: this.$refs.typeTree.getCurrentKey() || '',
})
this.list = res.message.records
this.total = res.message.total
} finally {
this.listLoading = false
}
},
//
currentChange (val) {
this.page = val
this.getList()
},
handleSelectionChange (val) { //
this.multipleSelection = val
},
initData () {
this.$refs.table.clearSelection()
this.page = 1
this.getList()
},
//
sortChange (column) {
if (column.prop === 'createTime') this.filter.timeOrderBy = column.order ? column.order === 'ascending' ? 'asc' : 'desc' : ''
this.getList()
},
//
async del (row) {
try {
await this.$confirm(`<p>确认要删除【${row.name}】吗?</p><p style="color: #f56c6c;">删除后,关联此知识点的试题将自动移除此知识点!</p>`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
dangerouslyUseHTMLString: true,
})
await this.$post(this.api.knowledgeHierarchyDel, [row.id])
Util.successMsg('删除成功')
this.getList()
} catch (e) { }
},
//
add () {
const type = this.$refs.typeTree.getCurrentNode()
this.form = {
name: '',
parentId: type ? type.path.split('/').map(e => +e) : [],
}
this.knowledgeVisible = true
},
//
async edit (row) {
const { data } = await this.$post(`${this.api.knowledgeHierarchyFind}?id=${row.id}`)
this.knowledgeVisible = true
const path = data.path.split('/').map(e => +e)
this.form = {
id: row.id,
name: row.name,
parentId: path.slice(0, path.length - 1),
}
console.log(11, this.form)
},
//
async knowledgeSubmit () {
if (this.submiting) return false
const form = _.cloneDeep(this.form)
if (!form.name) return Util.warningMsg('请输入题库名称')
this.submiting = true
form.parentId = form.parentId.length ? form.parentId[form.parentId.length - 1] : 0
form.createSource = 1
form.questionBankId = this.typeId
form.type = 1
try {
await this.$post(this.api.knowledgeHierarchySave, form)
Util.successMsg('保存成功')
this.knowledgeVisible = false
this.submiting = false
this.getList()
} catch (e) {
this.submiting = false
}
},
async delAllSelection () {
const list = this.multipleSelection
if (list.length) {
try {
await this.$confirm(`<p style="margin-bottom: 10px;">确认要删除已选定的${list.length}个知识点吗?</p><p style="color: #f56c6c;">删除后,关联这些知识点的试题将自动移除这些知识点!</p>`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
dangerouslyUseHTMLString: true,
})
await this.$post(this.api.knowledgeHierarchyDel, list.map(e => e.id))
Util.successMsg('删除成功')
this.multipleSelection = []
this.$refs.table.clearSelection()
this.getList()
} catch (e) { }
} else {
Util.warningMsg('请选择数据')
}
},
}
};
</script>
<style lang="scss" scoped>
.m-b-20 {
margin-bottom: 20px;
}
.org-name {
margin-right: 20px;
}
.w-100 {
width: 100%;
}
.page {
display: flex;
min-height: 100%;
margin-top: 20px;
padding: 0 24px;
.side {
width: 300px;
padding: 24px 10px 24px 0;
margin-right: 24px;
border-right: 1px solid rgba(0, 0, 0, 0.06);
}
.right {
width: calc(100% - 324px);
padding: 24px 0;
}
}
</style>

@ -19,12 +19,16 @@
<h6 class="page-name" style="margin-bottom: 0">知识点框架</h6> <h6 class="page-name" style="margin-bottom: 0">知识点框架</h6>
<el-button type="text" @click="toSet">设置</el-button> <el-button type="text" @click="toSet">设置</el-button>
</div> </div>
<el-input class="m-b-10" placeholder="请输入知识点名称" prefix-icon="el-icon-search" size="small" <el-input class="m-b-10" placeholder="请输入知识点分类、知识点名称" prefix-icon="el-icon-search" size="small"
clearable></el-input> v-model="keyword" clearable></el-input>
<div style="height: 504px; max-height: 504px; overflow: auto"> <div style="height: 504px; max-height: 504px; overflow: auto">
<el-tree :data="types" default-expand-all ref="orgTree" node-key="id" highlight-current <el-tree :data="types" default-expand-all ref="orgTree" node-key="id" highlight-current
:expand-on-click-node="false" @node-click="handleNodeClick" :expand-on-click-node="false" @node-click="handleNodeClick" :props="{ label: 'name', isLeaf: 'leaf' }">
:props="{ label: 'name', isLeaf: 'leaf' }"></el-tree> <span class="custom-tree-node" slot-scope="{ node, data }">
<img v-if="data.type" class="m-r-5" src="@/assets/images/knowledge.svg" alt="">
<span class="org-name">{{ data.name }}</span>
</span>
</el-tree>
</div> </div>
</div> </div>
</div> </div>
@ -264,6 +268,7 @@ export default {
typeId: this.$route.query.id, typeId: this.$route.query.id,
loading: false, loading: false,
createSource: 1, createSource: 1,
keyword: '',
radio: '', radio: '',
type: 1, type: 1,
types: [], types: [],
@ -339,25 +344,30 @@ export default {
}; };
}, },
watch: { watch: {
keyword: function (val) {
clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(this.getType, 500);
},
keyWord: function (val) { keyWord: function (val) {
clearTimeout(this.searchTimer); clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(this.initData, 500); this.searchTimer = setTimeout(this.initData, 500);
} }
}, },
mounted () { mounted () {
// this.getType() this.getType()
}, },
methods: { methods: {
// //
async getType () { async getType () {
try { try {
this.loading = true this.loading = true
const { data } = await this.$post(this.api.getAllKnowledgePointsCategories, { const { data } = await this.$post(this.api.TreeStructure, {
createSource: 1, createSource: 1,
questionCategoryId: this.typeId, questionBankId: this.typeId,
keyword: this.keyword,
}) })
this.types = data this.types = data
this.getList() // this.getList()
} finally { } finally {
this.loading = false this.loading = false
} }

@ -30,7 +30,7 @@
<ul class="filter"> <ul class="filter">
<li> <li>
<label>状态</label> <label>状态</label>
<el-select v-model="filter.status" clearable placeholder="请选择状态" @change="getList"> <el-select v-model="filter.status" clearable placeholder="请选择状态" @change="initData">
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option> <el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select> </el-select>
</li> </li>
@ -172,7 +172,7 @@ export default {
}) })
this.handleList(data) this.handleList(data)
this.types = data this.types = data
this.getList() this.initData()
} finally { } finally {
this.loading = false this.loading = false
} }

@ -0,0 +1,332 @@
<template>
<div class="page">
<Breadcrumb :data="crumbs" />
<p class="page-name mb">试卷</p>
<el-form :model="form" :rules="rules" class="input-form model" label-width="140px">
<el-form-item prop="name" label="试卷名称">
<el-input style="width: 940px" placeholder="请输入试卷名称" v-model="form.name" clearable maxlength="100" />
</el-form-item>
<div class="item-line">
<el-form-item prop="particularYear" label="年份">
<el-date-picker v-model="form.particularYear" type="year" placeholder="请选择年份">
</el-date-picker>
</el-form-item>
<el-form-item required label="所属试卷分类">
<el-cascader placeholder="请选择所属试卷分类" :options="types" v-model="cascaderValue" :props="cascaderProps" clearable
style="width: 100%">
</el-cascader>
</el-form-item>
</div>
<div class="item-line">
<el-form-item prop="paperType" label="建议用途">
<el-select v-model="form.paperType" clearable placeholder="请选择建议用途">
<el-option v-for="(item, i) in paperTypes" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="suggestTime" label="估计用时">
<el-input placeholder="请输入估计用时" v-model="form.suggestTime">
<template slot="append">分钟</template>
</el-input>
</el-form-item>
</div>
<div class="item-line">
<el-form-item prop="columnId" label="所属专业">
<el-select v-model="form.professionalId" clearable placeholder="请选择所属专业">
<el-option v-for="(item, i) in professionals" :key="i" :label="item.professionalName"
:value="item.professionalId" filter></el-option>
</el-select>
</el-form-item>
<el-form-item prop="difficult" label="试卷难度">
<el-select v-model="form.difficult" clearable placeholder="请选择试卷难度">
<el-option v-for="(item, i) in difficults" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
</div>
<el-form-item prop="userName" label="试卷说明">
<Ueditor @ready="editorReady" />
</el-form-item>
<div class="line"></div>
<div class="flex j-between m-b-20">
<p>默认模板</p>
<p>目标总题数30目标总分100</p>
<el-button type="primary" size="small" @click="showTemplate">选择大纲模板</el-button>
</div>
<el-table :data="form.paperOutline" stripe header-align="center" row-key="id">
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column>
<el-table-column prop="outlineName" label="大题" align="center" min-width="120"></el-table-column>
<el-table-column prop="name" label="题型" align="center" min-width="120">
<template slot-scope="scope">
<el-select v-model="scope.row.questionType" placeholder="请选择题型">
<el-option v-for="(item, i) in questionTypes" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column prop="name" label="目标题数" align="center" min-width="120">
<template slot-scope="scope">
<el-input placeholder="请输入目标题数" v-model="scope.row.questionNum" type="number" />
</template>
</el-table-column>
<el-table-column prop="name" label="目标分值" align="center" min-width="120">
<template slot-scope="scope">
<el-input placeholder="请输入目标分值" v-model="scope.row.targetScore" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="120">
<template slot-scope="scope">
<i class="el-icon-circle-plus-outline action-icon" @click="addLine(scope.$index)"></i>
<i class="el-icon-remove-outline action-icon" @click="delLine(scope.$index)"></i>
</template>
</el-table-column>
</el-table>
</el-form>
<div class="btns">
<el-button @click="submit(0)">保存草稿</el-button>
<el-button type="primary" @click="submit(1)">发布</el-button>
<el-button v-if="$route.query.id" @click="preview">预览</el-button>
<el-button @click="back">取消</el-button>
</div>
<Template :visible="templateVisible" />
</div>
</template>
<script>
import Setting from '@/setting'
import Util from '@/libs/util'
import Ueditor from '@/components/ueditor'
import Breadcrumb from '@/components/breadcrumb'
import Template from './template'
export default {
components: { Ueditor, Breadcrumb, Template },
data () {
return {
crumbs: [
{
name: '试卷管理',
route: 'list'
},
{
name: '创建试卷'
},
],
libraryId: this.$route.query.libraryId,
headers: {
token: Util.local.get(Setting.tokenKey)
},
types: [],
cascaderValue: [],
cascaderProps: {
checkStrictly: true,
label: "classificationName",
value: "classificationId"
},
paperTypes: [
{
id: 0,
name: '练习'
},
{
id: 1,
name: '考核'
},
{
id: 2,
name: '竞赛'
},
],
professionals: [],
difficults: [
{
id: 1,
name: '简单'
},
{
id: 2,
name: '普通'
},
{
id: 3,
name: '较难'
},
{
id: 4,
name: '难'
},
],
questionTypes: [
{
name: '单选题'
},
{
name: '多选题'
},
{
name: '判断题'
},
{
name: '填空题'
},
{
name: '问答题'
},
],
richEditor: {
object: null,
parameterName: '',
instance: null
},
form: {
classificationId: '',
difficult: '',
libraryId: '',
name: '',
paperMethod: '',
paperType: '',
particularYear: '',
professionalId: '',
questionCount: '',
remarks: '',
score: '',
suggestTime: '',
paperOutline: [
{
examQuestions: [],
outlineName: '单选题',
questionNum: '10',
questionType: '单选题',
targetScore: '20.0',
},
{
examQuestions: [],
outlineName: '多选题',
questionNum: '5',
questionType: '多选题',
targetScore: '15.0',
},
{
examQuestions: [],
outlineName: '判断题',
questionNum: '5',
questionType: '判断题',
targetScore: '10.0',
},
{
examQuestions: [],
outlineName: '填空题',
questionNum: '5',
questionType: '填空题',
targetScore: '15.0',
},
{
examQuestions: [],
outlineName: '问答题',
questionNum: '3',
questionType: '问答题',
targetScore: '40.0',
},
],
},
rules: {
name: [
{ required: true, message: '请输入试卷名称', trigger: 'blur' }
],
particularYear: [
{ required: true, message: '请选择年份', trigger: 'change' }
],
paperType: [
{ required: true, message: '请选择建议用途', trigger: 'change' }
],
suggestTime: [
{ required: true, message: '请输入估计用时', trigger: 'blur' }
],
name: [
{ required: true, message: '请输入试卷名称', trigger: 'blur' }
],
},
templateVisible: false,
};
},
mounted () {
this.getType()
this.getProfessional()
},
methods: {
//
async getType () {
try {
const res = await this.$post(this.api.examClassificationList, {
libraryId: this.libraryId,
})
const data = res.treeList
this.handleType(data)
this.types = data
} catch (e) { }
},
//
async getProfessional () {
try {
const res = await this.$post(this.api.queryProfessional, {
pageNum: 1,
pageSize: 1000,
})
this.professionals = res.pageList.records
} catch (e) { }
},
//
handleType (list) {
list.map(e => {
if (e.children && e.children.length) {
this.handleType(e.children)
} else {
delete e.children
}
})
},
editorReady (instance) {
// this.richEditor.instance = instance
// let currentContent = this.richEditor.object[this.richEditor.parameterName]
// this.richEditor.instance.setContent(currentContent)
// // Ueditor
// this.richEditor.instance.focus(true)
},
//
showTemplate () {
this.templateVisible = true
},
//
addLine (i) {
this.form.paperOutline.splice(i + 1, 0, {
examQuestions: [],
outlineName: '',
questionNum: '',
questionType: '',
targetScore: '',
})
},
//
delLine (i) {
this.form.paperOutline.splice(i, 1)
},
//
submit () {
},
//
back () {
}
}
};
</script>
<style lang="scss" scoped>
.action-icon {
margin-right: 10px;
font-size: 18px;
color: $main-color;
cursor: pointer;
}
</style>

@ -0,0 +1,189 @@
<template>
<div>
<el-dialog title="选择试卷大纲模板" :visible.sync="listVisible" width="1000px" :close-on-click-modal="false">
<div class="tool">
<ul class="filter">
<li>
<label>题型</label>
<el-select v-model="form.questionType" clearable placeholder="请选择题目类型" @change="initData">
<el-option v-for="(item, i) in questionTypes" :key="i" :value="item.name"></el-option>
</el-select>
</li>
<li>
<label>搜索</label>
<el-input style="width: 250px;" placeholder="请输入模板名称" prefix-icon="el-icon-search"
v-model="form.templateName" clearable />
</li>
</ul>
<div>
<el-button type="primary" @click="add">新增模板</el-button>
</div>
</div>
<el-table :data="list" stripe header-align="center" row-key="libraryId">
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column>
<el-table-column prop="libraryName" label="模板名称" align="center" min-width="120"></el-table-column>
<el-table-column prop="题型" label="题型" align="center" min-width="120"></el-table-column>
<el-table-column prop="libraryClassificationName" label="大题数" align="center" min-width="120"></el-table-column>
<el-table-column prop="examPaperNum" label="小题总数" align="center" width="100"></el-table-column>
<el-table-column prop="examPaperNum" label="总分" align="center" width="100"></el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center" width="160" sortable="custom"></el-table-column>
<el-table-column prop="createUserName" label="创建人" align="center" width="100"></el-table-column>
<el-table-column label="操作" align="center" width="280">
<template slot-scope="scope">
<el-button type="text" @click="useTemplate(scope.row, 0)">使用模板</el-button>
<el-button type="text" @click="edit(scope.row, 1)">编辑</el-button>
<el-button type="text" @click="del(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="currentChange" :current-page="page" layout="total, prev, pager, next"
:total="total"></el-pagination>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="listVisible = false">关闭</el-button>
</span>
</el-dialog>
<el-dialog title="新增模板" :visible.sync="detailVisible" width="600px" :close-on-click-modal="false">
<el-form :model="form" :rules="rules" label-width="100px">
<el-form-item prop="userName" label="模板名称">
<el-input placeholder="请输入模板名称" prefix-icon="el-icon-search"
v-model="name" />
</el-form-item>
</el-form>
<el-table :data="list" stripe header-align="center" row-key="libraryId">
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column>
<el-table-column prop="libraryName" label="模板名称" align="center" min-width="120"></el-table-column>
<el-table-column prop="题型" label="题型" align="center" min-width="120"></el-table-column>
<el-table-column prop="libraryClassificationName" label="大题数" align="center" min-width="120"></el-table-column>
<el-table-column prop="examPaperNum" label="小题总数" align="center" width="100"></el-table-column>
<el-table-column prop="examPaperNum" label="总分" align="center" width="100"></el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center" width="160" sortable="custom"></el-table-column>
<el-table-column prop="createUserName" label="创建人" align="center" width="100"></el-table-column>
<el-table-column label="操作" align="center" width="280">
<template slot-scope="scope">
<el-button type="text" @click="useTemplate(scope.row, 0)">使用模板</el-button>
<el-button type="text" @click="edit(scope.row, 1)">编辑</el-button>
<el-button type="text" @click="del(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="detailVisible = false">取消</el-button>
<el-button type="primary" @click="submit">保存模板</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Setting from '@/setting'
import Util from '@/libs/util'
export default {
props: ['visible'],
data () {
return {
listVisible: false,
searchTimer: null,
questionTypes: [
{
name: '单选题'
},
{
name: '多选题'
},
{
name: '判断题'
},
{
name: '填空题'
},
{
name: '问答题'
},
],
form: {
templateName: '',
questionType: '',
},
list: [],
page: 1,
pageSize: 10,
total: 0,
detailVisible: false,
};
},
watch: {
'form.templateName': function (val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(this.initData, 500)
},
visible () {
this.listVisible = this.visible
}
},
mounted () {
this.getList()
},
methods: {
//
async getList () {
try {
const res = await this.$post(this.api.examPaperTemplateList, {
pageNum: this.page,
pageSize: this.pageSize,
...this.form
})
this.types = res.pageList.records
this.total = res.pageList.total
} catch (e) { }
},
//
currentChange (val) {
this.page = val
this.getList()
},
initData () {
this.page = 1
this.getList()
},
//
add () {
this.detailVisible = true
},
// 使
useTemplate (row) {
},
//
edit (row) {
},
//
del (row) {
},
//
async submit () {
},
//
back () {
}
}
};
</script>
<style lang="scss" scoped>
.action-icon {
margin-right: 10px;
font-size: 18px;
color: $main-color;
cursor: pointer;
}
</style>

@ -0,0 +1,498 @@
<template>
<div>
<Breadcrumb :data="crumbs" />
<div class="page">
<div class="side">
<div class="m-b-20">
<el-radio-group v-model="isNotJoin" @change="changeType">
<div class="m-b-20">
<el-radio :label="1">所有试卷</el-radio>
</div>
<div>
<el-radio :label="2">未加入分类的试卷</el-radio>
</div>
</el-radio-group>
</div>
<el-divider></el-divider>
<div>
<div class="flex-between m-b-10">
<h6 class="page-name" style="margin-bottom: 0">试卷分类</h6>
<el-button type="text" @click="addType(0)">添加</el-button>
</div>
<div style="overflow: auto">
<el-tree v-loading="loading" :data="types" default-expand-all ref="typeTree" node-key="id" highlight-current
:expand-on-click-node="false" @node-click="handleNodeClick" :props="{ label: 'name', isLeaf: 'leaf' }">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span class="org-name">{{ data.classificationName }}</span>
<span>
<el-button type="text" icon="el-icon-circle-plus-outline" @click="() => addType(data)">
</el-button>
<el-button type="text" icon="el-icon-edit-outline" @click="() => editType(data)">
</el-button>
<el-button type="text" icon="el-icon-delete" @click="() => delType(node, data)">
</el-button>
</span>
</span>
</el-tree>
</div>
</div>
<el-dialog :title="typeForm.classificationId ? '编辑' : '新增' + '试卷分类'" :visible.sync="typeVisible"
:close-on-click-modal="false" width="400px">
<el-form v-if="typeVisible" ref="typeForm" :model="typeForm" :rules="typeRules" label-width="130px">
<el-form-item label="试卷分类名称" prop="classificationName">
<el-input v-model.trim="typeForm.classificationName" placeholder="请输入试卷分类" maxlength="20"></el-input>
</el-form-item>
<el-form-item label="设置上一级">
<el-cascader :options="types" v-model="cascaderValue" :props="cascaderProps" clearable
style="width: 100%">
</el-cascader>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="closeType"> </el-button>
<el-button type="primary" @click="typeSubmit"> </el-button>
</span>
</el-dialog>
</div>
<div class="right">
<h6 class="page-name">筛选</h6>
<div class="tool">
<ul class="filter">
<li>
<label>题目类型</label>
<el-select v-model="filter.status" clearable placeholder="请选择题目类型" @change="getList">
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</li>
<li>
<label>试卷难度</label>
<el-select v-model="filter.status" clearable placeholder="请选择试卷难度" @change="getList">
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</li>
<li>
<label>所属专业</label>
<el-select v-model="filter.status" clearable placeholder="请选择所属专业" @change="getList">
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</li>
<li>
<label>年份</label>
<el-select v-model="filter.status" clearable placeholder="请选择年份" @change="getList">
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</li>
<li>
<label>建议用途</label>
<el-select v-model="filter.status" clearable placeholder="请选择状态" @change="getList">
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</li>
<li>
<label>状态</label>
<el-select v-model="filter.status" clearable placeholder="请选择状态" @change="getList">
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</li>
<li>
<label>搜索</label>
<el-input style="width: 250px;" placeholder="请输入试卷名称" prefix-icon="el-icon-search"
v-model="filter.keyWord" clearable />
</li>
<div style="margin-bottom: 15px;">
<el-button type="primary" @click="add">创建试卷</el-button>
<el-button type="primary" @click="add">批量移除 </el-button>
<el-button type="primary" @click="add">批量删除</el-button>
</div>
</ul>
</div>
<el-table :data="list" v-loading="listLoading" class="table" ref="table" stripe header-align="center"
@selection-change="handleSelectionChange" row-key="id" @sort-change="sortChange">
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column>
<el-table-column prop="name" label="试卷名称" align="center" min-width="120"></el-table-column>
<el-table-column prop="name" label="试题总数" align="center" min-width="120"></el-table-column>
<el-table-column prop="name" label="总分" align="center" width="90"></el-table-column>
<el-table-column prop="name" label="中分位数" align="center" min-width="120"></el-table-column>
<el-table-column prop="name" label="题型" align="center" min-width="120"></el-table-column>
<el-table-column prop="name" label="试卷难度" align="center" min-width="120"></el-table-column>
<el-table-column prop="name" label="建议用时" align="center" min-width="120"></el-table-column>
<el-table-column prop="knowledgePointsClassification" label="试卷分类" align="center" min-width="120"
show-overflow-tooltip></el-table-column>
<el-table-column prop="relatedQuestionsNum" label="所属专业" align="center" width="90"></el-table-column>
<el-table-column prop="relatedQuestionsNum" label="年份" align="center" width="90"></el-table-column>
<el-table-column prop="relatedQuestionsNum" label="建议用途" align="center" width="90"></el-table-column>
<el-table-column prop="relatedQuestionsNum" label="状态" align="center" width="90"></el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center" width="160"
sortable="custom"></el-table-column>
<el-table-column prop="createTime" label="最近编辑时间" align="center" width="160"
sortable="custom"></el-table-column>
<el-table-column prop="createUserName" label="最近编辑人" align="center" width="100"></el-table-column>
<el-table-column label="操作" align="center" width="240">
<template slot-scope="scope">
<el-button type="text" @click="edit(scope.row)">复制</el-button>
<el-button type="text" @click="edit(scope.row)">预览</el-button>
<el-button type="text" @click="edit(scope.row)">编辑</el-button>
<el-button type="text" @click="del(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="currentChange" :current-page="page"
layout="total, prev, pager, next" :total="total"></el-pagination>
</div>
</div>
</div>
<el-dialog title="提示" :visible.sync="delVisible" width="400px" :close-on-click-modal="false" custom-class="del-dia">
<div class="del-wrap">
<div class="icon el-icon-warning"></div>
<div>
<p>确认要删除{{ curName }}</p>
<p class="tips">删除后其子级分类也将被删除</p>
<el-checkbox v-model="deleteQuestions">同时删除此分类及其子分类的试卷删除后数据无法恢复请谨慎操作</el-checkbox>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="delVisible = false">取消</el-button>
<el-button type="primary" @click="delTypeSubmit">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Util from '@/libs/util'
import _ from 'lodash'
import Breadcrumb from '@/components/breadcrumb'
export default {
components: { Breadcrumb },
data () {
return {
typeId: this.$route.query.id,
createSource: 1,
loading: false,
keyword: '',
types: [],
isNotJoin: 1,
typeVisible: false, //
typeForm: {
classificationId: '',
classificationName: ''
},
cascaderValue: [],
cascaderProps: {
checkStrictly: true,
label: "classificationName",
value: "classificationId"
},
status: [],
form: {
name: '',
parentId: []
},
typeRules: {
classificationName: [
{ required: true, message: '请输入试卷分类名称', trigger: 'blur' }
]
},
rules: {
name: [
{ required: true, message: '请输入试卷名称', trigger: 'blur' }
],
},
filter: {
difficultOrder: '',
yearOrder: '',
updateTimeOrder: '',
crateTimeOrder: '',
keyWord: '',
difficult: '',
particularYear: '',
keyWord: '',
},
listLoading: false,
list: [],
page: 1,
pageSize: 10,
total: 0,
multipleSelection: [],
submiting: false, //
delVisible: false,
deleteQuestions: false,
curName: '',
curId: [],
};
},
watch: {
keyword: function () {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(this.getType, 500)
},
'filter.keyWord': function () {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(this.getList, 500)
},
},
mounted () {
this.crumbs = [
{
name: this.$route.query.name || '中台试卷库',
route: '/testPaperLibrary'
},
{
name: '试卷管理'
},
],
this.getType()
},
methods: {
//
async getType () {
try {
this.loading = true
const res = await this.$post(this.api.examClassificationList, {
createSource: this.createSource,
libraryId: this.typeId,
})
const data = res.treeList
this.handleType(data)
this.types = data
this.getList()
} finally {
this.loading = false
}
},
//
changeType () {
this.$refs.typeTree.setCurrentKey(null)
this.initData()
},
//
async getDetail (id) {
const res = await this.$get(this.api.examClassificationFind, {
id
})
return res.examClassification
},
//
async addType (row) {
this.typeForm = {
classificationId: '',
classificationName: '',
}
this.typeVisible = true
if (row) {
const data = await this.getDetail(row.classificationId)
const path = data.classificationPath.split('/').map(e => +e)
this.cascaderValue = data.classificationPath.split('/').map(e => +e)
}
},
//
async editType (row) {
this.typeForm = {
classificationId: row.classificationId,
classificationName: row.classificationName
}
this.typeVisible = true
const data = await this.getDetail(row.classificationId)
const path = data.classificationPath.split('/').map(e => +e)
this.cascaderValue = path.slice(0, path.length - 1)
},
//
handleType (list) {
list.map(e => {
if (e.children && e.children.length) {
this.handleType(e.children)
} else {
delete e.children
}
})
},
//
delType (node, row) {
this.curName = row.classificationName
this.curId = [row.classificationId]
this.delVisible = true
},
//
async delTypeSubmit () {
await this.$post(this.api.examClassificationDel, {
delete: this.deleteQuestions,
ids: this.curId
})
Util.successMsg('删除成功')
this.delVisible = false
this.getType()
},
// /
typeSubmit () {
this.$refs.typeForm.validate(async (valid) => {
if (valid) {
const form = this.typeForm
const cas = this.cascaderValue
const len = cas.length
if (cas && len) {
form.parentId = cas[len - 1]
form.level = len + 1
} else {
form.parentId = 0
form.level = 1
}
form.createSource = this.createSource
form.libraryId = this.typeId
await this.$post(this.api[form.classificationId ? 'examClassificationUpdate' : 'examClassificationSave'], form)
Util.successMsg('保存成功')
this.closeType()
}
});
},
//
handleNodeClick (data) {
this.$refs.table.clearSelection()
this.isNotJoin = ''
this.getList()
},
//
closeType () {
this.typeVisible = false
this.cascaderValue = []
this.getType()
},
//
async getList () {
try {
this.listLoading = true
const res = await this.$post(this.api.examPaperList, {
...this.filter,
type: this.isNotJoin,
pageNum: this.page,
pageSize: this.pageSize,
classificationId: this.$refs.typeTree.getCurrentKey() || '',
})
this.list = res.pageList.records
this.total = res.pageList.total
} finally {
this.listLoading = false
}
},
//
currentChange (val) {
this.page = val
this.getList()
},
handleSelectionChange (val) { //
this.multipleSelection = val
},
initData () {
this.$refs.table.clearSelection()
this.page = 1
this.getList()
},
//
sortChange (column) {
if (column.prop === 'createTime') this.filter.timeOrderBy = column.order ? column.order === 'ascending' ? 'asc' : 'desc' : ''
this.getList()
},
//
async del (row) {
try {
await this.$confirm(`<p>确认要删除【${row.name}】吗?</p><p style="color: #f56c6c;">删除后,关联此试卷的试题将自动移除此试卷!</p>`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
dangerouslyUseHTMLString: true,
})
await this.$post(this.api.knowledgeHierarchyDel, [row.id])
Util.successMsg('删除成功')
this.getList()
} catch (e) { }
},
//
add () {
this.$router.push(`detail?libraryId=${this.typeId}`)
},
//
async edit (row) {
const { data } = await this.$post(`${this.api.knowledgeHierarchyFind}?id=${row.id}`)
this.knowledgeVisible = true
const path = data.path.split('/').map(e => +e)
this.form = {
id: row.id,
name: row.name,
parentId: path.slice(0, path.length - 1),
}
console.log(11, this.form)
},
async delAllSelection () {
const list = this.multipleSelection
if (list.length) {
try {
await this.$confirm(`<p style="margin-bottom: 10px;">确认要删除已选定的${list.length}个试卷吗?</p><p style="color: #f56c6c;">删除后,关联这些试卷的试题将自动移除这些试卷!</p>`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
dangerouslyUseHTMLString: true,
})
await this.$post(this.api.knowledgeHierarchyDel, list.map(e => e.id))
Util.successMsg('删除成功')
this.multipleSelection = []
this.$refs.table.clearSelection()
this.getList()
} catch (e) { }
} else {
Util.warningMsg('请选择数据')
}
},
}
};
</script>
<style lang="scss" scoped>
.org-name {
margin-right: 20px;
}
.page {
display: flex;
min-height: 100%;
margin-top: 20px;
padding: 0 24px;
.side {
width: 300px;
padding: 24px 10px 24px 0;
margin-right: 24px;
border-right: 1px solid rgba(0, 0, 0, 0.06);
}
.right {
width: calc(100% - 324px);
padding: 24px 0;
}
}
.tool {
margin-bottom: 0;
.filter {
flex-wrap: wrap;
justify-content: space-between;
li {
margin-bottom: 15px;
}
}
}
</style>

@ -0,0 +1,363 @@
<template>
<div class="page">
<div class="side">
<div class="m-b-20">
<h6 class="page-name">试卷库分类</h6>
<el-radio-group v-model="isNotJoin" @change="typeChange">
<div class="m-b-10">
<el-radio :label="1">所有试卷库</el-radio>
</div>
<div>
<el-radio :label="2">未加入分类的试卷库</el-radio>
</div>
</el-radio-group>
</div>
<el-divider></el-divider>
<div>
<el-input class="m-b-10" placeholder="请输入试卷库分类" prefix-icon="el-icon-search" size="small" clearable
v-model="keyword"></el-input>
<div style="height: 504px; max-height: 504px; overflow: auto">
<el-tree :data="types" default-expand-all ref="typeTree" node-key="libraryClassificationId" highlight-current
:expand-on-click-node="false" @node-click="handleNodeClick"
:props="{ id: 'libraryClassificationId', label: 'libraryClassificationName', isLeaf: 'leaf' }"></el-tree>
</div>
</div>
</div>
<div class="right">
<h6 class="page-name">筛选</h6>
<div class="tool">
<ul class="filter">
<li>
<label>状态</label>
<el-select v-model="filter.isDisable" clearable placeholder="请选择状态" @change="getList">
<el-option v-for="(item, i) in isDisable" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</li>
<li>
<label>搜索</label>
<el-input style="width: 250px;" placeholder="请输入试卷库名称" prefix-icon="el-icon-search" v-model="filter.keyWord"
clearable></el-input>
</li>
</ul>
<div>
<el-button type="primary" @click="add">创建试卷库</el-button>
</div>
</div>
<el-table :data="list" class="table" ref="table" stripe header-align="center"
@selection-change="handleSelectionChange" row-key="libraryId" @sort-change="sortChange">
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column>
<el-table-column prop="libraryName" label="试卷库名称" align="center" min-width="120"></el-table-column>
<el-table-column prop="remarks" label="描述" align="center" min-width="120"
show-overflow-tooltip></el-table-column>
<el-table-column prop="libraryClassificationName" label="试卷库分类" align="center"
min-width="120"></el-table-column>
<el-table-column prop="examPaperNum" label="试卷数量" align="center" width="100"
sortable="custom"></el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center" width="160" sortable="custom"></el-table-column>
<el-table-column prop="createUserName" label="创建人" align="center" width="100"></el-table-column>
<el-table-column label="操作" align="center" width="280">
<template slot-scope="scope">
<el-button type="text" @click="toTestPaper(scope.row)">试题管理</el-button>
<el-button type="text" @click="edit(scope.row, 0)">编辑</el-button>
<el-button type="text" @click="edit(scope.row, 1)">复制</el-button>
<el-button type="text" @click="del(scope.row)">删除</el-button>
<el-switch v-model="scope.row.isDisable" :active-value="false" :inactive-value="true"
style="margin: 0 10px 0 5px" :active-text="scope.row.isDisable ? '关' : '开'"
@change="switchOff($event, scope.row)"></el-switch>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background @current-change="currentChange" :current-page="page" layout="total, prev, pager, next"
:total="total"></el-pagination>
</div>
<el-dialog :title="isCopy ? '复制试卷库' : !form.libraryId ? '创建试卷库' : '编辑试卷库'" :visible.sync="quesBankVisible"
width="400px" :close-on-click-modal="false">
<p v-if="isCopy" style="margin: -10px 0 20px;font-size: 12px;color: #f00;">您将复制当前试卷库中的所有题目到新试卷库请输入新试卷库名称</p>
<el-form :model="form" :rules="rules" label-width="100px">
<el-form-item prop="userName" label="分类">
<el-cascader placeholder="请选择试卷库分类" v-model="libraryClassificationId" :options="enableTypes"
:props="{ value: 'libraryClassificationId', label: 'libraryClassificationName', checkStrictly: true }"
clearable></el-cascader>
</el-form-item>
<el-form-item prop="libraryName" label="试卷库名称">
<el-input placeholder="请输入试卷库名称" v-model="form.libraryName"></el-input>
</el-form-item>
<el-form-item prop="remarks" label="试卷库描述">
<el-input placeholder="请输入试卷库描述" type="textarea" :rows="3" v-model="form.remarks"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="quesBankVisible = false"> </el-button>
<el-button type="primary" @click="quesBankSubmit"> </el-button>
</span>
</el-dialog>
</div>
</div>
</template>
<script>
import Util from "@/libs/util";
import Setting from "@/setting";
import _ from 'lodash'
export default {
data () {
return {
loading: false,
keyword: '',
isNotJoin: 1,
types: [],
isDisable: [
{
id: 0,
name: '启用'
},
{
id: 1,
name: '禁用'
},
],
filter: {
numOrder: '',
timeOrder: '',
isDisable: '',
keyWord: '',
},
list: [],
page: 1,
pageSize: 10,
total: 0,
multipleSelection: [],
form: {
remarks: '',
libraryName: '',
},
libraryClassificationId: [],
rules: {
libraryName: [
{ required: true, message: '请输入试卷库名称', trigger: 'blur' }
]
},
enableTypes: [],
quesBankVisible: false,
submiting: false,
isCopy: false,
};
},
watch: {
keyword: function (val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(this.getType, 500)
},
'filter.keyWord': function (val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(this.initData, 500)
}
},
mounted () {
this.getType()
},
methods: {
//
async getType () {
try {
this.loading = true
const res = await this.$post(this.api.libraryClassificationList, {
keyword: this.keyword,
createSource: 1,
})
const data = res.treeList
this.handleList(data)
this.types = data
this.getList()
} finally {
this.loading = false
}
},
//
handleList (list) {
list.map(e => {
if (e.children && e.children.length) {
this.handleList(e.children)
} else {
delete e.children
}
})
},
//
typeChange () {
this.$refs.typeTree.setCurrentKey(null)
this.initData()
},
//
handleNodeClick (data) {
this.isNotJoin = ''
this.initData()
this.$refs.table.clearSelection()
},
//
async getList () {
const res = await this.$post(this.api.libraryList, {
...this.filter,
type: this.isNotJoin,
pageNum: this.page,
pageSize: this.pageSize,
libraryClassificationId: this.$refs.typeTree.getCurrentKey() || '',
})
this.list = res.pageList.records
this.total = res.pageList.total
},
//
currentChange (val) {
this.page = val
this.getList()
},
//
handleSelectionChange (val) {
this.multipleSelection = val
},
initData () {
this.$refs.table.clearSelection()
this.page = 1
this.getList()
},
//
sortChange (column) {
// 12
if (column.prop === 'examPaperNum') this.filter.numOrder = column.order ? column.order === 'ascending' ? 1 : 2 : ''
if (column.prop === 'createTime') this.filter.timeOrder = column.order ? column.order === 'ascending' ? 1 : 2 : ''
this.getList()
},
//
async del (row) {
try {
await this.$confirm(`<p>确认要删除【${row.libraryName}】吗?</p><p style="color: #f56c6c;">删除后,试卷库中的试卷将会被删除,请谨慎操作!</p>`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
dangerouslyUseHTMLString: true,
})
await this.$post(this.api.paperLibraryDel, {
ids: [row.libraryId]
})
Util.successMsg('删除成功')
this.getList()
} catch (e) { }
},
async switchOff (val, row) {
await this.$post(this.api.paperLibraryDisable, {
id: row.libraryId,
isDisable: val
})
Util.successMsg(val ? '禁用成功' : '启用成功')
this.getList()
},
//
async getDetail (id) {
const res = await this.$get(this.api.libraryClassificationFind, {
id
})
return res.libraryClassification
},
//
async add () {
this.getEnableType()
this.isCopy = false
const type = this.$refs.typeTree.getCurrentNode()
this.form = {
remarks: '',
libraryName: '',
}
if (type) {
const data = await this.getDetail(type.libraryClassificationId)
this.libraryClassificationId = data.classificationPath.split('/').map(e => +e)
} else {
this.libraryClassificationId = []
}
this.quesBankVisible = true
},
//
toTestPaper (row) {
this.$router.push(`/testPaper?id=${row.libraryId}&name=${row.libraryName}`)
},
// /
async edit (row, isCopy) {
this.getEnableType()
this.isCopy = isCopy
this.quesBankVisible = true
this.form = {
libraryId: row.libraryId,
libraryName: row.libraryName,
remarks: row.remarks,
}
let type = row.libraryClassificationId
if (type) {
type = type.split('/')
const data = await this.getDetail(type[type.length - 1])
this.libraryClassificationId = data.classificationPath.split('/').map(e => +e)
} else {
this.libraryClassificationId = []
}
},
//
async getEnableType () {
if (!this.enableTypes.length) {
try {
const res = await this.$post(this.api.libraryClassificationList, {
createSource: 1,
isDisable: false,
})
const data = res.treeList
this.handleList(data)
this.enableTypes = data
} catch (e) { }
}
},
//
async quesBankSubmit () {
if (this.submiting) return false
const form = _.cloneDeep(this.form)
if (!form.libraryName) return Util.warningMsg('请输入试卷库名称')
this.submiting = true
if (this.libraryClassificationId.length) form.libraryClassificationId = this.libraryClassificationId[this.libraryClassificationId.length - 1]
// form.systemId = this.systemId
form.createSource = 1
try {
await this.$post(this.api[this.isCopy ? 'copyQuestionBank' : form.libraryId ? 'paperLibraryUpdate' : 'paperLibrarySave'], form)
Util.successMsg(this.isCopy ? '复制成功' : '保存成功')
this.quesBankVisible = false
this.submiting = false
this.getList()
} catch (e) {
this.submiting = false
}
},
}
};
</script>
<style lang="scss" scoped>
.page {
display: flex;
padding: 0 24px;
.side {
width: 300px;
padding: 24px 10px 24px 0;
margin-right: 24px;
border-right: 1px solid rgba(0, 0, 0, 0.06);
}
.right {
width: calc(100% - 324px);
padding: 24px 0;
}
}
</style>

@ -0,0 +1,292 @@
<template>
<div class="page">
<div class="tool">
<ul class="filter">
<li>
<label>状态</label>
<el-select v-model="filter.isDisable" clearable placeholder="请选择状态" @change="getData">
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</li>
<li>
<label>搜索</label>
<el-input style="width: 250px;" placeholder="请输入试卷库分类名称" prefix-icon="el-icon-search"
v-model="filter.libraryClassificationName" clearable></el-input>
</li>
</ul>
<div>
<el-button type="primary" @click="add(0)">新增</el-button>
<el-button type="primary" @click="delAllSelection">批量删除</el-button>
</div>
</div>
<el-table v-loading="loading" :data="list" class="table" ref="table" stripe header-align="center"
row-key="libraryClassificationId" default-expand-all
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column>
<el-table-column type="index" width="100" label="序号" align="center"></el-table-column>
<el-table-column prop="libraryClassificationName" label="试卷库分类名称"></el-table-column>
<el-table-column prop="relatedLibraryNum" label="已关联试卷库" align="center"></el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center"></el-table-column>
<el-table-column prop="createUser" label="创建人" align="center"></el-table-column>
<el-table-column label="操作" align="center" width="300">
<template slot-scope="scope">
<el-button type="text" @click="add(scope.row)">新增下级</el-button>
<el-button type="text" @click="edit(scope.row)">编辑</el-button>
<el-button type="text" @click="del(scope.row)">删除</el-button>
<el-switch v-model="scope.row.isDisable" :active-value="false" :inactive-value="true"
style="margin: 0 10px 0 5px" :active-text="scope.row.isDisable ? '关' : '开'"
@change="switchOff($event, scope.row)"></el-switch>
</template>
</el-table-column>
</el-table>
<el-dialog :title="(!form.libraryClassificationId ? '新增' : '编辑') + '试卷库分类'" :visible.sync="typeVisible"
width="400px" :close-on-click-modal="false">
<el-form :model="form" :rules="rules" label-width="130px">
<el-form-item prop="libraryClassificationName" label="试卷库分类名称">
<el-input placeholder="请输入分类名称" v-model="form.libraryClassificationName" maxlength="20"></el-input>
</el-form-item>
<el-form-item label="设置上一级">
<el-cascader v-model="parentId" :options="list"
:props="{ value: 'libraryClassificationId', label: 'libraryClassificationName', checkStrictly: true }"
clearable></el-cascader>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="typeVisible = false">取消</el-button>
<el-button type="primary" v-loading="submiting" @click="typeSubmit">确定</el-button>
</span>
</el-dialog>
<el-dialog title="提示" :visible.sync="delVisible" width="400px" :close-on-click-modal="false" custom-class="del-dia">
<div class="del-wrap">
<div class="icon el-icon-warning"></div>
<div>
<p>确认要删除{{ curName }}</p>
<p class="tips">删除后此试卷库分类及其子分类将被删除已关联的试卷库将无分类</p>
<el-checkbox v-model="deleteQuestions">同时删除此试卷库分类及其子分类的试卷库删除后数据无法恢复请谨慎操作</el-checkbox>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="delVisible = false">取消</el-button>
<el-button type="primary" @click="delSubmit">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Util from '@/libs/util'
export default {
data () {
return {
systemId: '',
status: [
{
id: 0,
name: '启用'
},
{
id: 1,
name: '禁用'
},
],
filter: {
isDisable: '',
libraryClassificationName: '',
},
list: [],
multipleSelection: [],
parentId: [],
form: {
libraryClassificationName: '',
},
rules: {
libraryClassificationName: [
{ required: true, message: '请输入试卷库分类名称', trigger: 'blur' }
]
},
typeVisible: false,
loading: false,
searchTimer: null,
delVisible: false,
deleteQuestions: false,
curName: '',
curId: [],
submiting: false,
};
},
watch: {
'filter.libraryClassificationName': function (val) {
clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(() => {
this.getData()
}, 500)
}
},
mounted () {
this.getData()
},
methods: {
async getData () {
try {
this.loading = true
const res = await this.$post(this.api.libraryClassificationList, {
...this.filter
})
const data = res.treeList
this.handleList(data)
this.list = data
} finally {
this.loading = false
}
},
//
handleList (list) {
list.map(e => {
if (e.children && e.children.length) {
this.handleList(e.children)
} else {
delete e.children
}
})
},
handleSelectionChange (val) {
this.multipleSelection = val
},
//
async getDetail (id) {
const res = await this.$get(this.api.libraryClassificationFind, {
id
})
return res.libraryClassification
},
//
async add (row) {
this.form = {
libraryClassificationName: '',
parentId: 0,
}
this.typeVisible = true
if (row) {
const data = await this.getDetail(row.libraryClassificationId)
const path = data.classificationPath
this.parentId = path.split('/').map(e => +e).slice(0, path.length - 1)
} else {
this.parentId = []
}
},
//
async edit (row) {
this.typeVisible = true
const data = await this.getDetail(row.libraryClassificationId)
this.form = {
libraryClassificationId: data.libraryClassificationId,
libraryClassificationName: data.libraryClassificationName,
}
const path = data.classificationPath.split('/').map(e => +e)
this.parentId = path.slice(0, path.length - 1)
},
//
async typeSubmit () {
if (this.submiting) return false
const { form, parentId } = this
if (!form.libraryClassificationName) return Util.warningMsg('请输入试卷库分类名称')
this.submiting = true
if (parentId.length) form.parentId = parentId[parentId.length - 1]
// form.systemId = this.systemId
form.createSource = 1
await this.$post(this.api[form.libraryClassificationId ? 'libraryClassificationUpdate' : 'libraryClassificationSave'], form)
Util.successMsg('保存成功')
this.typeVisible = false
this.submiting = false
this.getData()
},
//
del (row) {
this.curName = row.name
this.curId = [row.libraryClassificationId]
this.delVisible = true
},
//
async delSubmit () {
await this.$post(this.api.libraryClassificationDel, {
ids: this.curId,
delete: this.deleteQuestions
})
Util.successMsg('删除成功')
this.multipleSelection = []
this.$refs.table.clearSelection()
this.delVisible = false
this.getData()
},
//
delAllSelection () {
const list = this.multipleSelection
if (list.length) {
this.curName = list.map(e => e.libraryClassificationName).join()
this.curId = list.map(e => e.libraryClassificationId)
this.delVisible = true
} else {
Util.warningMsg('请选择数据')
}
},
//
async switchOff (val, row) {
try {
row.isDisable = !val
if (val) {
await this.$confirm(`<p>确认要禁用【${row.libraryClassificationName}】吗?</p><p style="color: #f56c6c;">禁用后,此试卷库分类及其子分类将被禁用</p>`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
dangerouslyUseHTMLString: true,
})
}
const res = await this.$post(this.api.libraryClassificationDisable, {
id: row.libraryClassificationId,
isDisable: val
})
if (res.status === 200) {
Util.successMsg(val ? '禁用成功' : '启用成功')
this.getData()
}
} catch (e) {
row.isDisable = !val
}
},
}
};
</script>
<style lang="scss" scoped>
/deep/.del-dia {
.el-dialog__body {
padding: 10px 30px;
}
.del-wrap {
display: flex;
}
.icon {
margin-right: 15px;
font-size: 24px;
color: #E6A23C;
}
.tips {
margin: 5px 0 10px;
}
.el-checkbox__label {
white-space: normal;
vertical-align: top;
}
}
</style>

@ -36,14 +36,14 @@ service.interceptors.response.use(
} else if (res.code === 401) { } else if (res.code === 401) {
// 账号互踢 // 账号互踢
if (!logouted) { if (!logouted) {
// Util.local.remove(Setting.storeKey) Util.local.remove(Setting.storeKey)
// Util.local.remove(Setting.tokenKey) Util.local.remove(Setting.tokenKey)
// Util.errorMsg(res.msg.includes('顶') ? '您的账号已在其他设备登录,您已被迫下线!' : '登录过期,请重新登录!') Util.errorMsg(res.msg.includes('顶') ? '您的账号已在其他设备登录,您已被迫下线!' : '登录过期,请重新登录!')
// setTimeout(() => { setTimeout(() => {
// store.dispatch('user/logout') // store.dispatch('user/logout')
logouted = 0 logouted = 0
// }, 5000) }, 5000)
// logouted = 1 logouted = 1
} }
} else if (!res.status) { } else if (!res.status) {
return Promise.resolve(res).catch(e => { }); return Promise.resolve(res).catch(e => { });

@ -0,0 +1,16 @@
import BasicLayout from '@/layouts/home'
const meta = {}
export default {
path: '/knowledge',
meta,
component: BasicLayout,
children: [
{
path: '/knowledge',
component: () => import('@/pages/knowledge/index.vue'),
meta: { title: '知识点' }
},
]
};

@ -9,7 +9,7 @@ export default {
children: [ children: [
{ {
path: '/ques', path: '/ques',
component: () => import('@/pages/ques/index.vue'), component: () => import('@/pages/ques'),
meta: { title: '试题管理' } meta: { title: '试题管理' }
}, },
] ]

@ -9,7 +9,7 @@ export default {
children: [ children: [
{ {
path: '/quesBank', path: '/quesBank',
component: () => import('@/pages/quesBank/index.vue'), component: () => import('@/pages/quesBank'),
meta: { title: '题库管理' } meta: { title: '题库管理' }
}, },
] ]

@ -9,7 +9,7 @@ export default {
children: [ children: [
{ {
path: '/quesBankType', path: '/quesBankType',
component: () => import('@/pages/quesBankType/index.vue'), component: () => import('@/pages/quesBankType'),
meta: { title: '题库分类' } meta: { title: '题库分类' }
}, },
] ]

@ -0,0 +1,24 @@
import BasicLayout from '@/layouts/home'
const meta = {}
export default {
path: '/testPaper',
redirect: {
path: `/testPaper/list`
},
meta,
component: BasicLayout,
children: [
{
path: 'list',
component: () => import('@/pages/testPaper/list'),
meta: { title: '试卷管理' }
},
{
path: 'detail',
component: () => import('@/pages/testPaper/detail'),
meta: { title: '试卷管理' }
},
]
};

@ -0,0 +1,16 @@
import BasicLayout from '@/layouts/home'
const meta = {}
export default {
path: '/testPaperLibrary',
meta,
component: BasicLayout,
children: [
{
path: '/testPaperLibrary',
component: () => import('@/pages/testPaperLibrary'),
meta: { title: '试卷库分类' }
},
]
};

@ -0,0 +1,16 @@
import BasicLayout from '@/layouts/home'
const meta = {}
export default {
path: '/testPaperLibraryType',
meta,
component: BasicLayout,
children: [
{
path: '/testPaperLibraryType',
component: () => import('@/pages/testPaperLibraryType'),
meta: { title: '试卷库分类' }
},
]
};
Loading…
Cancel
Save