试卷库分类等联调

master
yujialong 4 months ago
parent 15897f24e5
commit b6f3b1f3d6
  1. 2
      public/static/ueditor/ueditor.config.js
  2. 17
      src/App.vue
  3. 33
      src/api/index.js
  4. 47
      src/components/breadcrumb/index.vue
  5. 12
      src/layouts/navbar/index.vue
  6. 290
      src/pages/ques/index.vue
  7. 59
      src/pages/quesBank/index.vue
  8. 42
      src/pages/quesBankType/index.vue
  9. 487
      src/pages/theoryExam/knowledge.vue
  10. 16
      src/plugins/requests/index.js
  11. 4
      src/setting.js
  12. 25
      src/styles/common.scss

@ -1,6 +1,6 @@
!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 = {
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: [[
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: [[
"fullscreen",
"source",
"|",

@ -1,5 +1,10 @@
<template>
<div id="app">
<el-radio-group v-if="Setting.isDev" v-model="ip" @change="ipChange">
<el-radio :label="0">刘榕ip</el-radio>
<el-radio :label="1">陈赓ip</el-radio>
<el-radio :label="2">测试服ip</el-radio>
</el-radio-group>
<router-view></router-view>
</div>
</template>
@ -10,6 +15,12 @@ import util from '@/libs/util'
export default {
name: "App",
data () {
return {
Setting,
ip: localStorage.getItem('ip') ? +localStorage.getItem('ip') : 0,
};
},
created () {
//localStorage
if (util.local.get(Setting.storeKey)) {
@ -20,6 +31,12 @@ export default {
window.addEventListener("beforeunload", () => {
util.local.get(Setting.tokenKey) && util.local.set(Setting.storeKey, this.$store.state);
});
},
methods: {
ipChange (val) {
localStorage.setItem('ip', val)
location.reload()
},
}
};
</script>

@ -1,6 +1,5 @@
import Setting from '@/setting'
const { apiBaseURL: host } = Setting
// const host = 'http://192.168.31.217:9000/'
const host = 'http://192.168.31.51:9000'
export default {
categoriesDel: `/exam/question/bank/categories/batchDeletion`,
@ -14,4 +13,34 @@ export default {
questionBankList: `/exam/questionBank/pagingQuery`,
questionBankSave: `/exam/questionBank/saveOrUpdate`,
questionBankDisable: `/exam/questionBank/updateStatus`,
copyQuestionBank: `/exam/questionBank/copyQuestionBank`,
TreeStructure: `/exam/knowledgeHierarchy/TreeStructure`,
knowledgeHierarchyDel: `/exam/knowledgeHierarchy/batchDeletion`,
knowledgeHierarchyFind: `/exam/knowledgeHierarchy/findById`,
knowledgeHierarchySave: `/exam/knowledgeHierarchy/saveOrUpdate`,
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`,
libraryClassificationSave: `/exam/exam/libraryClassification/save`,
libraryClassificationList: `/exam/exam/libraryClassification/treeList`,
libraryClassificationUpdate: `/exam/exam/libraryClassification/update`,
libraryClassificationDisable: `/exam/exam/libraryClassification/updateStatus`,
libraryClassificationFind: `/exam/exam/libraryClassification/details`,
paperLibraryDel: `/exam/exam/paperLibrary/delete`,
libraryList: `/exam/exam/paperLibrary/libraryList`,
paperLibrarySave: `/exam/exam/paperLibrary/save`,
paperLibraryUpdate: `/exam/exam/paperLibrary/update`,
paperLibraryDisable: `/exam/exam/paperLibrary/updateStatus`,
examClassificationDel: `/exam/exam/classification/delete`,
examClassificationSave: `/exam/exam/classification/save`,
examClassificationList: `/exam/exam/classification/treeList`,
examClassificationUpdate: `/exam/exam/classification/update`,
}

@ -3,15 +3,10 @@
<div class="breadcrumb">
<el-breadcrumb separator="/">
<template v-for="(item, index) in data">
<el-breadcrumb-item
v-if="index != data.length - 1"
:key="index"
:to="{ path: item.route, query: item.query }">
<el-breadcrumb-item v-if="index != data.length - 1" :key="index" :to="{ path: item.route, query: item.query }">
{{ item.name }}
</el-breadcrumb-item>
<el-breadcrumb-item
v-else
:key="index">
<el-breadcrumb-item v-else :key="index">
{{ item.name }}
</el-breadcrumb-item>
</template>
@ -21,36 +16,40 @@
<script>
export default {
props: {
data: {
type: Array,
required: true
}
},
data() {
return {
// pages: this.data.split('/')
};
},
methods: {
update(data){
// this.pages = data.split('/')
}
props: {
data: {
type: Array,
required: true
}
},
data () {
return {
// pages: this.data.split('/')
};
},
methods: {
update (data) {
// this.pages = data.split('/')
}
}
};
</script>
<style lang="scss" scoped>
.breadcrumb {
margin-left: 12px;
margin-bottom: 20px;
/deep/.el-breadcrumb__item {
.el-breadcrumb__inner, .el-breadcrumb__separator {
.el-breadcrumb__inner,
.el-breadcrumb__separator {
font-weight: 400;
color: #333;
}
&:last-child:not(:first-child) {
.el-breadcrumb__inner {
color: #666;
}
.is-link {
color: #0B1D30;
}

@ -70,7 +70,17 @@ export default {
{
icon: 'annex',
index: '/annex/list',
title: '试卷管理'
title: '试卷管理',
subs: [
{
index: '/testPaperLibraryType',
title: '中台试卷库分类'
},
{
index: '/testPaperLibrary',
title: '中台试卷库'
},
]
}
],
};

@ -1,117 +1,121 @@
<template>
<div class="page">
<div class="side">
<div class="m-b-20">
<el-radio-group v-model="type" @change="typeChange">
<div class="m-b-20">
<el-radio :label="1">所有试题</el-radio>
<div>
<Breadcrumb :data="crumbs" />
<div class="page">
<div class="side">
<div class="m-b-20">
<el-radio-group v-model="type" @change="typeChange">
<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="toSet">设置</el-button>
</div>
<div>
<el-radio :label="2">未分配知识点的试题</el-radio>
<el-input class="m-b-10" placeholder="请输入知识点名称" prefix-icon="el-icon-search" size="small"
clearable></el-input>
<div style="height: 504px; max-height: 504px; overflow: auto">
<el-tree :data="types" default-expand-all ref="orgTree" node-key="id" highlight-current
:expand-on-click-node="false" @node-click="handleNodeClick"
:props="{ label: 'name', isLeaf: 'leaf' }"></el-tree>
</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="toSet">设置</el-button>
</div>
<el-input class="m-b-10" placeholder="请输入知识点名称" prefix-icon="el-icon-search" size="small" clearable></el-input>
<div style="height: 504px; max-height: 504px; overflow: auto">
<el-tree :data="orgList" default-expand-all ref="orgTree" node-key="id" highlight-current
:expand-on-click-node="false" @node-click="handleNodeClick"
:props="{ children: 'children', label: 'partnerClassificationName', 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.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: 80px;" placeholder="请输入" v-model="filter.keyWord" clearable />
<span style="margin: 0 10px;">% -- </span>
<el-input style="width: 80px;" placeholder="请输入" v-model="filter.keyWord" clearable />
<span style="margin-left: 10px;">%</span>
</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="batchImport">批量导入</el-button>
<!-- <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>
<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-input style="width: 80px;" placeholder="请输入" v-model="filter.keyWord" clearable />
<span style="margin: 0 10px;">% -- </span>
<el-input style="width: 80px;" placeholder="请输入" v-model="filter.keyWord" clearable />
<span style="margin-left: 10px;">%</span>
</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="batchImport">批量导入</el-button>
<!-- <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" class="table" ref="table" stripe header-align="center"
@selection-change="handleSelectionChange" row-key="id">
<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="userName" label="题干" align="center" min-width="100"></el-table-column>
<el-table-column prop="account" label="题型" align="center" min-width="100"></el-table-column>
<el-table-column prop="phone" label="专业" align="center" min-width="120"></el-table-column>
<el-table-column prop="invitationAccount" label="知识点" align="center" min-width="120"></el-table-column>
<el-table-column prop="invitationAccount" label="年份" align="center" min-width="120"></el-table-column>
<el-table-column prop="invitationAccount" label="难度" align="center" min-width="120"></el-table-column>
<el-table-column prop="invitationAccount" label="正确率" align="center" min-width="120"></el-table-column>
<el-table-column prop="loginNumber" label="更新时间" align="center" width="120"></el-table-column>
<el-table-column prop="lastLoginTime" label="最近编辑人" align="center" width="120"></el-table-column>
<el-table-column prop="lastLoginTime" label="已引用试卷(套)" align="center" width="120"></el-table-column>
<el-table-column label="操作" align="center" width="300">
<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>
<el-button type="text" @click="del(scope.row)">删除</el-button>
<el-switch v-model="scope.row.ztOpen" :active-value="0" :inactive-value="1" style="margin: 0 10px 0 5px"
:active-text="scope.row.ztOpen ? '关' : '开'"
@change="switchOff($event, scope.row, scope.$index)"></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>
<el-table :data="list" class="table" ref="table" stripe header-align="center"
@selection-change="handleSelectionChange" row-key="id">
<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="userName" label="题干" align="center" min-width="100"></el-table-column>
<el-table-column prop="account" label="题型" align="center" min-width="100"></el-table-column>
<el-table-column prop="phone" label="专业" align="center" min-width="120"></el-table-column>
<el-table-column prop="invitationAccount" label="知识点" align="center" min-width="120"></el-table-column>
<el-table-column prop="invitationAccount" label="年份" align="center" min-width="120"></el-table-column>
<el-table-column prop="invitationAccount" label="难度" align="center" min-width="120"></el-table-column>
<el-table-column prop="invitationAccount" label="正确率" align="center" min-width="120"></el-table-column>
<el-table-column prop="loginNumber" label="更新时间" align="center" width="120"></el-table-column>
<el-table-column prop="lastLoginTime" label="最近编辑人" align="center" width="120"></el-table-column>
<el-table-column prop="lastLoginTime" label="已引用试卷(套)" align="center" width="120"></el-table-column>
<el-table-column label="操作" align="center" width="300">
<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>
<el-button type="text" @click="del(scope.row)">删除</el-button>
<el-switch v-model="scope.row.ztOpen" :active-value="0" :inactive-value="1" style="margin: 0 10px 0 5px"
:active-text="scope.row.ztOpen ? '关' : '开'"
@change="switchOff($event, scope.row, scope.$index)"></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>
</div>
</div>
@ -164,6 +168,21 @@
<el-form-item prop="userName" label="解析">
<Ueditor ref="title1" @ready="editorReady" />
</el-form-item>
<el-form-item prop="userName" label="上传题干文件">
<el-input placeholder="请输入题库名称" v-model="form.name"></el-input>
</el-form-item>
<el-form-item prop="userName" label="支持学生上传附件">
<el-radio-group v-model="radio">
<el-radio :label="3"></el-radio>
<el-radio :label="6"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="userName" label="判分标准">
<el-select style="width: 100%" v-model="form.provinceId" placeholder="请选择判分标准">
<el-option v-for="(item, i) in types" :key="i" :label="item.provinceName"
:value="item.provinceId"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="quesSubmit(0)">保存</el-button>
@ -228,13 +247,26 @@
import Util from '@/libs/util'
import Setting from '@/setting'
import Ueditor from '@/components/ueditor'
import Breadcrumb from '@/components/breadcrumb'
export default {
components: { Ueditor },
components: { Ueditor, Breadcrumb },
data () {
return {
crumbs: [
{
name: this.$route.query.name || '题库管理',
route: '/quesBank'
},
{
name: '试题管理'
},
],
typeId: this.$route.query.id,
loading: false,
createSource: 1,
radio: '',
type: 1,
orgList: [],
types: [],
status: [
{
id: 1,
@ -255,7 +287,6 @@ export default {
total: 0,
multipleSelection: [],
types: [],
form: {
userName: '',
provinceId: '',
@ -314,39 +345,26 @@ export default {
}
},
mounted () {
this.getOrg()
// this.getType()
},
methods: {
//
async getOrg () {
const res = await this.$post(this.api.listParner)
const list = res.treeList
// children
const handleLeaf = (list, ids) => {
list.map(e => {
e.ids = ids ? [...ids, e.id] : [e.id]
if (e.children.length) {
if (e.isTeam) {
delete e.children
} else {
handleLeaf(e.children, e.ids)
}
} else {
delete e.children
}
//
async getType () {
try {
this.loading = true
const { data } = await this.$post(this.api.getAllKnowledgePointsCategories, {
createSource: 1,
questionCategoryId: this.typeId,
})
this.types = data
this.getList()
} finally {
this.loading = false
}
handleLeaf(list)
this.orgList = list
//
this.setKey && this.$nextTick(() => {
this.$refs.orgTree.setCurrentKey(this.setKey)
})
this.getList()
},
//
toSet () {
this.$router.push('knowledge')
this.$router.push(`/knowledge?id=${this.typeId}`)
},
//
typeChange () {

@ -14,11 +14,10 @@
</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="id" highlight-current
<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="{ children: 'children', label: 'name', isLeaf: 'leaf' }"></el-tree>
</div>
@ -46,7 +45,7 @@
</div>
</div>
<el-table :data="list" class="table" ref="table" stripe header-align="center"
<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>
@ -60,7 +59,7 @@
<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="edit(scope.row)">试题管理</el-button>
<el-button type="text" @click="toQues(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>
@ -102,6 +101,7 @@
<script>
import Util from "@/libs/util";
import Setting from "@/setting";
import _ from 'lodash'
export default {
data () {
return {
@ -125,6 +125,7 @@ export default {
status: '',
name: '',
},
listLoading: false,
list: [],
page: 1,
pageSize: 10,
@ -171,10 +172,6 @@ export default {
})
this.handleList(data)
this.types = data
//
this.setKey && this.$nextTick(() => {
this.$refs.typeTree.setCurrentKey(this.setKey)
})
this.getList()
} finally {
this.loading = false
@ -204,15 +201,20 @@ export default {
},
//
async getList () {
const res = await this.$post(this.api.questionBankList, {
...this.filter,
isNotJoin: this.isNotJoin || '',
pageNum: this.page,
pageSize: this.pageSize,
questionCategoryId: this.$refs.typeTree.getCurrentKey() || '',
})
this.list = res.message.records
this.total = res.message.total
try {
this.listLoading = true
const res = await this.$post(this.api.questionBankList, {
...this.filter,
isNotJoin: this.isNotJoin || '',
pageNum: this.page,
pageSize: this.pageSize,
questionCategoryId: this.$refs.typeTree.getCurrentKey() || '',
})
this.list = res.message.records
this.total = res.message.total
} finally {
this.listLoading = false
}
},
//
currentChange (val) {
@ -230,7 +232,6 @@ export default {
},
//
sortChange (column) {
// 12
if (column.prop === 'questionNumOrderBy') this.filter.questionNumOrderBy = column.order ? column.order === 'ascending' ? 'asc' : 'desc' : ''
if (column.prop === 'createTime') this.filter.timeOrderBy = column.order ? column.order === 'ascending' ? 'asc' : 'desc' : ''
this.getList()
@ -267,6 +268,10 @@ export default {
}
this.quesBankVisible = true
},
//
toQues (row) {
this.$router.push(`/ques?id=${row.id}&name=${row.questionBankName}`)
},
// /
async edit (row, isCopy) {
this.getEnableType()
@ -297,18 +302,22 @@ export default {
//
async quesBankSubmit () {
if (this.submiting) return false
const { form } = this
if (!form.categoryIds.length) return Util.warningMsg('请选择分类')
const form = _.cloneDeep(this.form)
// if (!form.categoryIds.length) return Util.warningMsg('')
if (!form.questionBankName) return Util.warningMsg('请输入题库名称')
this.submiting = true
if (form.categoryIds.length) form.categoryIds = [form.categoryIds[form.categoryIds.length - 1]]
// form.systemId = this.systemId
form.createSource = 1
await this.$post(this.api.questionBankSave, form)
Util.successMsg('保存成功')
this.quesBankVisible = false
this.submiting = false
this.getList()
try {
await this.$post(this.api[this.isCopy ? 'copyQuestionBank' : 'questionBankSave'], form)
Util.successMsg(this.isCopy ? '复制成功' : '保存成功')
this.quesBankVisible = false
this.submiting = false
this.getList()
} catch (e) {
this.submiting = false
}
},
}
};

@ -63,7 +63,7 @@
<div class="icon el-icon-warning"></div>
<div>
<p>确认要删除{{ curName }}</p>
<p class="tips">删除后此题库分类及其子分类将被删除关联题库将无分类</p>
<p class="tips">删除后此题库分类及其子分类将被删除关联题库将无分类</p>
<el-checkbox v-model="deleteQuestions">同时删除此分类及其子分类的题库删除后数据无法恢复请谨慎操作</el-checkbox>
</div>
</div>
@ -171,7 +171,8 @@ export default {
id: data.id,
name: data.name,
}
this.parentId = data.path.split('/').map(e => +e)
const path = data.path.split('/').map(e => +e)
this.parentId = path.length > 1 ? path.slice(0, path.length - 1) : []
},
//
async typeSubmit () {
@ -217,8 +218,8 @@ export default {
//
async switchOff (val, row) {
try {
row.status = val ? 0 : 1 //
if (!val) {
row.status = 1
await this.$confirm(`<p>确认要禁用【${row.name}】吗?</p><p style="color: #f56c6c;">禁用后,此题库分类及其子分类将被禁用</p>`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@ -226,40 +227,17 @@ export default {
closeOnClickModal: false,
dangerouslyUseHTMLString: true,
})
row.status = 0
}
await this.$post(`${this.api.categoriesDisable}?categoryId=${row.id}&status=${row.status}`)
await this.$post(`${this.api.categoriesDisable}?categoryId=${row.id}&status=${val}`)
row.status = val
Util.successMsg(val ? '启用成功' : '禁用成功')
this.getData()
} catch (e) { }
} catch (e) {
row.status = val ? 0 : 1
}
},
}
};
</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>
<style lang="scss" scoped></style>

@ -1,487 +0,0 @@
<template>
<div class="page">
<div class="side">
<div class="m-b-20">
<el-radio-group v-model="studentType" @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">
<h6 class="page-name" style="margin-bottom: 0">知识点分类</h6>
<el-button type="text" @click="addOrg">添加</el-button>
</div>
<div style="overflow: auto">
<el-tree :data="orgList" default-expand-all ref="orgTree" node-key="id" highlight-current
:expand-on-click-node="false" @node-click="handleNodeClick"
:props="{ children: 'children', label: 'organizationName', isLeaf: 'leaf' }">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span class="org-name">{{ node.label }}</span>
<span>
<el-button type="text" icon="el-icon-circle-plus-outline" @click="() => addOrg(node, data)">
</el-button>
<el-button type="text" icon="el-icon-edit-outline" @click="() => editOrg(node, data)">
</el-button>
<el-button type="text" icon="el-icon-delete" @click="() => delOrg(node, data)">
</el-button>
</span>
</span>
</el-tree>
</div>
</div>
<el-dialog :title="orgForm.id ? '编辑' : '新增' + '知识点分类'" :visible.sync="orgVisible" :close-on-click-modal="false"
width="50%">
<el-form v-if="orgVisible" ref="orgForm" :model="orgForm" :rules="orgRules" label-width="100px">
<el-form-item label="知识点分类名称" prop="organizationName">
<el-input v-model.trim="orgForm.organizationName" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="设置上一级">
<span v-if="orgForm.parentName">{{ orgForm.parentName }}</span>
<el-cascader v-else :options="orgListDia" 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="closeOrg"> </el-button>
<el-button type="primary" @click="orgSubmit"> </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="keyWord"
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" class="table" ref="table" stripe header-align="center"
@selection-change="handleSelectionChange" row-key="accountId">
<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="userName" label="知识点名称" align="center" min-width="100"></el-table-column>
<el-table-column prop="account" label="知识点分类" align="center" min-width="100"></el-table-column>
<el-table-column prop="phone" label="已关联试题" align="center" width="120"></el-table-column>
<el-table-column prop="phone" label="创建时间" align="center" width="120"></el-table-column>
<el-table-column prop="phone" label="创建人" align="center" width="120"></el-table-column>
<el-table-column label="操作" align="center" width="300">
<template slot-scope="scope">
<el-button type="text" v-auth="'/system:后台账号:编辑'" @click="queryStaff(scope.row, false)">编辑</el-button>
<el-button type="text" v-auth="'/system:后台账号:重置密码'" @click="resetPassword(scope.row)">转移</el-button>
<el-button type="text" v-auth="'/system:后台账号:删除'" @click="delStaff(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 label-width="100px">
<el-form-item prop="userName" label="知识点分类">
<el-select style="width: 100%" v-model="form.provinceId" placeholder="请选择知识点分类">
<el-option v-for="(item, i) in types" :key="i" :label="item.provinceName"
:value="item.provinceId"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="userName" 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>
</template>
<script>
import util from "@/libs/util";
import Setting from "@/setting";
import OrgTree from "@/components/org-tree/src/tree";
export default {
components: { OrgTree },
data () {
return {
orgList: [],
orgListDia: [],
studentType: 1, //:(1. 2.)
orgVisible: false, //
orgForm: {
id: '',
organizationName: ''
},
cascaderValue: [], //
cascaderProps: {
checkStrictly: true,
label: "organizationName",
value: "id"
},
treeVisible: true,
treeNode: {},
treeResolve: [],
isDetail: false,
keyWord: '',
types: [],
form: {
accountId: '',
userName: '',
phone: '',
roleList: [],
uniqueIdentification: '',
workNumber: '',
email: '',
account: '',
staffArchitectureId: []
},
orgRules: {
organizationName: [
{ required: true, message: "请输入部门名称", trigger: "blur" }
]
},
rules: {
account: [
{ required: true, message: "请输入部门名称", trigger: "blur" }
],
},
list: [],
page: 1,
pageSize: 10,
total: 0,
multipleSelection: [],
knowledgeVisible: false,
submiting: false //
};
},
watch: {
keyWord: function (val) {
clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(this.getList, 500);
}
},
mounted () {
this.getOrg()
},
methods: {
//
async getOrg () {
const res = await this.$post(this.api.treeListArch)
const list = res.treeList
this.orgList = list
this.getList()
},
//
changeType () {
this.$refs.orgTree.setCurrentKey(null)
this.initData()
},
//
addOrg (node, data) {
const list = JSON.parse(JSON.stringify(this.orgList))
this.handleOrg(list)
this.orgListDia = list
this.orgForm = {
id: '',
parentId: data ? data.id : 1,
level: data ? data.level + 1 : 1,
parentName: data ? data.organizationName : '',
organizationName: ''
}
this.orgVisible = true
},
//
editOrg (node, data) {
const list = JSON.parse(JSON.stringify(this.orgList))
this.handleOrg(list, data.id, 0)
this.orgListDia = list
this.orgForm = {
id: data.id,
organizationName: data.organizationName
}
this.orgVisible = true
const ids = data.ids
ids.splice(ids.length - 1, 1)
this.cascaderValue = ids
},
//
handleOrg (list, id, disabled) {
list.forEach(e => {
// disabled
if (disabled) {
e.disabled = true
e.children && this.handleOrg(e.children, id, 1)
} else {
if (e.id === id) {
e.disabled = true
e.children && this.handleOrg(e.children, id, 1)
} else {
e.children && this.handleOrg(e.children, id, 0)
}
}
})
},
//
delOrg (node, data) {
this.$confirm("确定要删除吗?", "提示", {
type: "warning"
}).then(() => {
this.$post(`${this.api.deleteArch}?id=${data.id}`).then(res => {
util.successMsg("删除成功")
this.getOrg()
}).catch(res => { })
}).catch(() => { })
},
// /
orgSubmit () {
this.$refs.orgForm.validate((valid) => {
if (valid) {
const form = this.orgForm
const cas = this.cascaderValue
const len = cas.length
if (cas && len) {
this.orgForm.parentId = cas[len - 1]
this.orgForm.level = len + 1
}
if (!form.id) {
//
this.$post(this.api.saveArch, form).then(res => {
util.successMsg("新增成功!")
this.closeOrg()
}).catch(err => { })
} else {
//
this.$post(this.api.updateArch, form).then(res => {
util.successMsg("编辑成功!")
this.closeOrg()
}).catch(err => { })
}
}
});
},
//
handleNodeClick (data) {
this.$refs.table.clearSelection()
this.studentType = null
this.getList()
},
//
closeOrg () {
this.orgVisible = false
this.cascaderValue = []
this.getOrg()
},
//
getList () {
this.$post(this.api.staffList, {
type: this.studentType || 1,
staffArchitectureId: this.$refs.orgTree.getCurrentKey() || '',
keyWord: this.keyWord,
pageNum: this.page,
pageSize: this.pageSize
}).then(res => {
this.list = res.page.records
this.total = res.page.total
}).catch(err => { })
},
//
currentChange (val) {
this.page = val
this.getList()
},
handleSelectionChange (val) { //
this.multipleSelection = val
},
initData () {
this.$refs.table.clearSelection()
this.page = 1
this.getList()
},
//
delStaff (row) {
this.$confirm("确定要删除吗?", "提示", {
type: "warning"
}).then(() => {
this.$post(`${this.api.delStaff}?accountIds=${row.accountId}`).then(res => {
util.successMsg("删除成功")
this.getList()
}).catch(res => { })
}).catch(() => { })
},
//
resetPassword (row) {
const newPwd = Setting.initialPassword
this.$confirm(`重置后的密码为:${newPwd},确定重置?`, "提示", { type: "warning" }).then(() => {
this.$get(`${this.api.resetPwd}?userId=${row.userId}&newPwd=${newPwd}`).then(res => {
util.successMsg("重置成功")
}).catch(res => { })
}).catch(() => { })
},
//
add () {
this.knowledgeVisible = true
this.$nextTick(() => {
this.$refs.form.clearValidate()
})
},
// /
queryStaff (row, isDetail) {
const archId = []
// id
const handleArchId = (list, ids, parentId = []) => {
list.map(e => {
// id[[1, 2], [3, 4]]idid
if (ids.includes(e.id)) {
archId.push([...parentId, e.id])
} else {
e.children && handleArchId(e.children, ids, [...parentId, e.id])
}
})
}
this.isDetail = isDetail
this.staffVisible = true
this.$get(`${this.api.staffDetail}?accountId=${row.accountId}`).then(res => {
const { data } = res
const { staffArchitectureId, roleId } = data
if (roleId) {
const roleList = roleId.split(',').map(e => Number(e))
const list = this.roleList
if (roleList.length) {
let has = false //
for (const i in roleList) {
if (list.find(n => n.id === roleList[i])) {
has = true
break
}
}
if (!has) {
util.warningMsg('角色被删请重新选择')
data.roleList = []
} else {
data.roleList = roleList
}
}
}
if (staffArchitectureId) {
handleArchId(this.orgList, staffArchitectureId.split(',').map(e => Number(e)))
data.staffArchitectureId = archId
}
this.form = data
this.originAccount = data.account
this.originWorkNumber = data.workNumber
}).catch(res => { })
},
//
knowledgeSubmit () {
this.$refs.form.validate((valid) => {
if (valid) {
if (this.submiting) return false
this.submiting = true
const form = JSON.parse(JSON.stringify(this.form))
const ids = form.staffArchitectureId
if (ids) form.staffArchitectureId = ids.map(e => e[e.length - 1])
if (form.accountId) {
this.$post(this.api.modifyStaff, form).then(res => {
util.successMsg("编辑成功!")
this.staffVisible = false
setTimeout(() => {
this.submiting = false
}, 2000)
}).catch(res => {
setTimeout(() => {
this.submiting = false
}, 2000)
})
} else {
form.uniqueIdentification = new Date().getTime()
this.$post(this.api.saveStaff, form).then(res => {
util.successMsg("新增成功!")
this.staffVisible = false
setTimeout(() => {
this.submiting = false
}, 2000)
}).catch(res => {
setTimeout(() => {
this.submiting = false
}, 2000)
})
}
}
})
},
delAllSelection () {
const list = this.multipleSelection
if (list.length) {
//
this.$confirm("确定要删除吗?", "提示", {
type: "warning"
}).then(() => {
this.$post(this.api.orderDelete, { ids: list }).then(res => {
const { orderData } = this
this.$message.success("删除成功");
this.$refs.table.clearSelection()
this.getData();
}).catch(err => {
});
}).catch(err => {
});
} else {
this.$message.error("请先选择数据 !");
}
},
}
};
</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%;
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% - 374px);
padding: 24px 0;
}
}
</style>

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

@ -4,7 +4,9 @@
const isDev = process.env.NODE_ENV === 'development' // 开发环境
let host = location.origin
if (isDev) {
host = 'http://192.168.31.217:9000'
host = 'http://192.168.31.51:9000'
const ips = ['http://192.168.31.217:9000', 'http://192.168.31.51:9000', 'http://121.37.12.51']
host = ips[+localStorage.getItem('ip')]
}
const Setting = {

@ -409,4 +409,29 @@
}
.tinymce-load {
z-index: 3000 !important;
}
.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;
}
}
Loading…
Cancel
Save