提交 75aed367 authored 作者: 王鹏飞's avatar 王鹏飞

chore: 接口升级到V2; 支持资源管理系统;

上级 c4b016fe
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<script src="https://webapp-pub.ezijing.com/plugins/tinymce/tinymce.min.js"></script> <script src="https://webapp-pub.ezijing.com/plugins/tinymce/tinymce.min.js"></script>
<script src="https://pv.sohu.com/cityjson"></script> <script src="https://pv.sohu.com/cityjson"></script>
<script> <script>
var ip = returnCitySN['cip'] var ip = returnCitySN ? returnCitySN['cip'] : ''
window.localStorage.setItem('ip', ip) window.localStorage.setItem('ip', ip)
</script> </script>
</body> </body>
......
...@@ -32,17 +32,17 @@ export function uploadFile(data) { ...@@ -32,17 +32,17 @@ export function uploadFile(data) {
* 获取权限列表 * 获取权限列表
*/ */
export function getPermissions(params) { export function getPermissions(params) {
return httpRequest.get('/api/permissions/api/v1/user/permissions', { params }) return httpRequest.get(`/api/xedu/api/v3/org/user/${params.id}/permissions`, { params })
} }
// 获取可访问的所有项目 // 获取可访问的所有项目
export function getAllProjects() { export function getAllProjects() {
return httpRequest.get('/api/qbs/admin/v1/projects') return httpRequest.get('/api/qbs/admin/v2/projects')
} }
/** /**
* 获取试卷分类 * 获取试卷分类
*/ */
export function getQuestionCategory(params) { export function getQuestionCategory(params) {
return httpRequest.get(`/api/qbs/admin/v1/question-category/tree/${params.project_prefix}`, { params }) return httpRequest.get(`/api/qbs/admin/v2/question-category/tree/${params.project_prefix}`, { params })
} }
...@@ -14,9 +14,11 @@ ...@@ -14,9 +14,11 @@
{{ subitem.name }} {{ subitem.name }}
</el-menu-item> </el-menu-item>
</el-submenu> </el-submenu>
<el-menu-item :index="item.path" :key="item.path" v-permission="item.tag" v-else> <template v-else>
<i :class="item.icon"></i>{{ item.name }} <el-menu-item :index="item.path" :key="item.path" v-permission="item.tag">
</el-menu-item> <i :class="item.icon"></i>{{ item.name }}
</el-menu-item>
</template>
</template> </template>
</el-menu> </el-menu>
</nav> </nav>
...@@ -33,25 +35,25 @@ export default { ...@@ -33,25 +35,25 @@ export default {
name: '试题中心', name: '试题中心',
path: '/question', path: '/question',
icon: 'el-icon-collection', icon: 'el-icon-collection',
tag: 'admin_v1_question', tag: 'question_manager',
children: [ children: [
{ name: '新建试题', path: '/question/create', tag: 'admin_v1_question_create' }, { name: '新建试题', path: '/question/create', tag: 'question_create' },
{ name: '我的题库', path: '/question', tag: 'admin_v1_question_list' }, { name: '我的题库', path: '/question', tag: 'question_list' },
{ name: '题库分类', path: '/question/classify', tag: 'admin_v1_question_category' } { name: '题库分类', path: '/question/classify', tag: 'question_category_tree' }
] ]
}, },
{ {
name: '试卷中心', name: '试卷中心',
path: '/paper', path: '/paper',
icon: 'el-icon-toilet-paper', icon: 'el-icon-toilet-paper',
tag: 'admin_v1_paper', tag: 'paper',
children: [{ name: '我的试卷库', path: '/paper', tag: 'admin_v1_paper_list' }] children: [{ name: '我的试卷库', path: '/paper', tag: 'paper_list' }]
}, },
{ {
name: '考试中心', name: '考试中心',
path: '/exam', path: '/exam',
icon: 'el-icon-folder-opened', icon: 'el-icon-folder-opened',
tag: 'admin_exam', tag: 'admin_exam_exam',
children: [{ name: '我的考试', path: '/exam', tag: 'admin_exam_exam_index' }] children: [{ name: '我的考试', path: '/exam', tag: 'admin_exam_exam_index' }]
} }
] ]
......
<template> <template>
<div> <div>
<template v-for="item in questionList"> <paper-question
<paper-question :options="{ item, sheet_id: questionData.sheet_id, question_item_id: item.question_item_id }"
:options="{ item, sheet_id: questionData.sheet_id, question_item_id: item.question_item_id }" :question_item_id="item.question_item_id"
:question_item_id="item.question_item_id" :key="item.question_item_id"
:key="item.question_item_id" v-for="item in questionList"
/> />
</template>
</div> </div>
</template> </template>
......
...@@ -261,7 +261,10 @@ ...@@ -261,7 +261,10 @@
</g> </g>
</svg> </svg>
<p class="tips">很抱歉,你暂时无权限访问...</p> <p class="tips">很抱歉,你暂时无权限访问...</p>
<a :href="loginUrl"><el-button round type="primary">重新登录</el-button></a> <div>
<router-link to="/"><el-button round type="default">返回首页</el-button></router-link>
<a :href="loginUrl" style="margin-left: 20px"><el-button round type="primary">重新登录</el-button></a>
</div>
</div> </div>
</template> </template>
......
...@@ -15,13 +15,17 @@ export default { ...@@ -15,13 +15,17 @@ export default {
}, },
methods: { methods: {
handleClick(item) { handleClick(item) {
this.$store.commit('setActiveProjedct', item) this.$store.commit('setActiveProject', item)
// 重新获取权限 // 重新获取权限
this.$store.dispatch('getPermissions').then(() => { this.$store.dispatch('getPermissions').then(() => {
// 跳转到首页 // 跳转到首页
this.$router.push({ path: '/', query: { project_tag: item.tag } }) this.$router.push({ path: '/', query: { project_tag: item.tag } })
}) })
} }
},
mounted() {
// 初始化获取项目列表
this.$store.dispatch('getAllProjects')
} }
} }
</script> </script>
......
...@@ -4,49 +4,49 @@ import httpRequest from '@/utils/axios' ...@@ -4,49 +4,49 @@ import httpRequest from '@/utils/axios'
* 获取试卷列表 * 获取试卷列表
*/ */
export function getPaperList(params) { export function getPaperList(params) {
return httpRequest.get(`/api/qbs/admin/v1/question-papers/${params.project_prefix}`, { params }) return httpRequest.get(`/api/qbs/admin/v2/question-papers/${params.project_prefix}`, { params })
} }
/** /**
* 新建试卷 * 新建试卷
*/ */
export function createPaper(data) { export function createPaper(data) {
return httpRequest.post('/api/qbs/admin/v1/question-paper', data) return httpRequest.post('/api/qbs/admin/v2/question-paper', data)
} }
/** /**
* 更新试卷 * 更新试卷
*/ */
export function updatePaper(data) { export function updatePaper(data) {
return httpRequest.put(`/api/qbs/admin/v1/question-paper/${data.id}`, data) return httpRequest.put(`/api/qbs/admin/v2/question-paper/${data.id}`, data)
} }
/** /**
* 获取试卷详情 * 获取试卷详情
*/ */
export function getPaper(params) { export function getPaper(params) {
return httpRequest.get(`/api/qbs/admin/v1/question-paper/${params.id}`, { params }) return httpRequest.get(`/api/qbs/admin/v2/question-paper/${params.id}`, { params })
} }
/** /**
* 删除试卷 * 删除试卷
*/ */
export function batchDeletePaper(data) { export function batchDeletePaper(data) {
return httpRequest.post('/api/qbs/admin/v1/question-paper/batch-delete', data) return httpRequest.post('/api/qbs/admin/v2/question-paper/batch-delete', data)
} }
/** /**
* 获取试题列表 * 获取试题列表
*/ */
export function getQuestionList(params) { export function getQuestionList(params) {
return httpRequest.get('/api/qbs/admin/v1/questions', { params }) return httpRequest.get('/api/qbs/admin/v2/questions', { params })
} }
/** /**
* 批量获取试题列表 * 批量获取试题列表
*/ */
export function batchGetQuestionList(data) { export function batchGetQuestionList(data) {
return httpRequest.post('/api/qbs/admin/v1/questions/batch', data) return httpRequest.post('/api/qbs/admin/v2/questions/batch', data)
} }
/** /**
...@@ -54,39 +54,33 @@ export function batchGetQuestionList(data) { ...@@ -54,39 +54,33 @@ export function batchGetQuestionList(data) {
* 添加试题和设置试题分数 * 添加试题和设置试题分数
*/ */
export function updatePaperRules(data) { export function updatePaperRules(data) {
return httpRequest.post(`/api/qbs/admin/v1/question-paper/rules/${data.id}`, data) return httpRequest.post(`/api/qbs/admin/v2/question-paper/rules/${data.id}`, data)
} }
/** /**
* 搜索试题数量--自动组卷 * 搜索试题数量--自动组卷
*/ */
export function getQuestionCount(params) { export function getQuestionCount(params) {
return httpRequest.get('/api/qbs/admin/v1/question/search/count', { params }) return httpRequest.get('/api/qbs/admin/v2/question/search/count', { params })
} }
/** /**
* 获取试卷分类 * 获取试卷分类
*/ */
export function getPaperCategory(params) { export function getPaperCategory(params) {
return httpRequest.get(`/api/qbs/admin/v1/question-category/tree/${params.project_prefix}`, { params }) return httpRequest.get(`/api/qbs/admin/v2/question-category/tree/${params.project_prefix}`, { params })
}
/**
* 获取知识点/标签
*/
export function getKnowledge(params) {
return httpRequest.get('/api/admin/v1/knowledge-point/search/x1', { params })
} }
/** /**
* 一次性自动组卷——搜索试题数量 (通过主题目检索) * 一次性自动组卷——搜索试题数量 (通过主题目检索)
*/ */
export function getParentQuestionCount(data) { export function getParentQuestionCount(data) {
return httpRequest.post('/api/qbs/admin/v1/question/search/parent-count', data) return httpRequest.post('/api/qbs/admin/v2/question/search/parent-count', data)
} }
/** /**
* 一次性自动组卷——通过一次性自动选题规则获取题目 * 一次性自动组卷——通过一次性自动选题规则获取题目
*/ */
export function getOnceAutoQuestionList(data) { export function getOnceAutoQuestionList(data) {
return httpRequest.post('/api/qbs/admin/v1/question/search/once-auto-questions', data) return httpRequest.post('/api/qbs/admin/v2/question/search/once-auto-questions', data)
} }
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
<div class="buttons"> <div class="buttons">
<div class="buttons-inner"> <div class="buttons-inner">
<el-button type="primary" @click="prevStep">上一步</el-button> <el-button type="primary" @click="prevStep">上一步</el-button>
<el-button type="primary" style="margin-left: 20px" :disabled="loading" @click="handleSave">保存</el-button> <el-button type="primary" style="margin-left: 20px" :loading="loading" @click="handleSave">保存</el-button>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -15,7 +15,12 @@ ...@@ -15,7 +15,12 @@
<el-table-column align="center" label="题目类型" width="140"> <el-table-column align="center" label="题目类型" width="140">
<template slot-scope="{ row, $index }"> <template slot-scope="{ row, $index }">
<el-select v-model="row.question_type" @change="getQuestionMaxCount($index, row)"> <el-select v-model="row.question_type" @change="getQuestionMaxCount($index, row)">
<el-option v-for="item in questionTypeMap" :key="item.value" :label="item.label" :value="item.value"></el-option> <el-option
v-for="item in questionTypeMap"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select> </el-select>
</template> </template>
</el-table-column> </el-table-column>
...@@ -23,7 +28,12 @@ ...@@ -23,7 +28,12 @@
<el-table-column align="center" label="难度" width="140"> <el-table-column align="center" label="难度" width="140">
<template slot-scope="{ row, $index }"> <template slot-scope="{ row, $index }">
<el-select v-model="row.question_difficulty" @change="getQuestionMaxCount($index, row)"> <el-select v-model="row.question_difficulty" @change="getQuestionMaxCount($index, row)">
<el-option v-for="item in questionDifficultyMap" :key="item.value" :label="item.label" :value="item.value"></el-option> <el-option
v-for="item in questionDifficultyMap"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select> </el-select>
</template> </template>
</el-table-column> </el-table-column>
...@@ -43,19 +53,39 @@ ...@@ -43,19 +53,39 @@
<el-table-column align="center" label="数量" width="140"> <el-table-column align="center" label="数量" width="140">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<el-input-number v-model="row.question_num" :min="0" :max="row.max_question_num" step-strictly style="width: 100%"></el-input-number> <el-input-number
v-model="row.question_num"
:min="0"
:max="row.max_question_num"
step-strictly
style="width: 100%"
></el-input-number>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="每题分值" width="140"> <el-table-column align="center" label="每题分值" width="140">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<el-input-number v-model="row.question_score" :min="0" :max="30" :disabled="['7', '8'].includes(row.question_type)" style="width: 100%"></el-input-number> <el-input-number
v-model="row.question_score"
:min="0"
:max="30"
:disabled="['5', '7', '8'].includes(row.question_type)"
style="width: 100%"
></el-input-number>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="操作" width="140"> <el-table-column align="center" label="操作" width="140">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button style="margin-left: 10px" circle icon="el-icon-plus" size="mini" :plain="true" type="danger" @click="handleAdd(scope.$index, scope.row)"></el-button> <el-button
style="margin-left: 10px"
circle
icon="el-icon-plus"
size="mini"
:plain="true"
type="danger"
@click="handleAdd(scope.$index, scope.row)"
></el-button>
<el-button <el-button
style="margin-left: 10px" style="margin-left: 10px"
...@@ -82,7 +112,9 @@ ...@@ -82,7 +112,9 @@
<el-table-column align="center" label="题目类型" prop="question_type_name"></el-table-column> <el-table-column align="center" label="题目类型" prop="question_type_name"></el-table-column>
<el-table-column align="center" label="难度 / 数量 / 分值"> <el-table-column align="center" label="难度 / 数量 / 分值">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<div v-for="(item, index) in row.children" :key="index">{{ item.question_difficulty_name }} / {{ item.question_num }} / {{ item.question_score }}</div> <div v-for="(item, index) in row.children" :key="index">
{{ item.question_difficulty_name }} / {{ item.question_num }} / {{ item.question_score }}
</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column align="center" label="小计(数量 / 分值)"> <el-table-column align="center" label="小计(数量 / 分值)">
...@@ -167,14 +199,20 @@ export default { ...@@ -167,14 +199,20 @@ export default {
totalQuestionList() { totalQuestionList() {
const result = [] const result = []
this.questionList.forEach(item => { this.questionList.forEach(item => {
if (item.question_type && item.question_num && !result.find(item2 => item2.question_type === item.question_type)) { if (
item.question_type &&
item.question_num &&
!result.find(item2 => item2.question_type === item.question_type)
) {
// 当前类型的试题列表 // 当前类型的试题列表
const currentTypeQuestionList = this.questionList.filter(item2 => item2.question_type === item.question_type) const currentTypeQuestionList = this.questionList.filter(item2 => item2.question_type === item.question_type)
// 难度列表 // 难度列表
const questionDifficultyList = this.questionDifficultyMap.map(item => { const questionDifficultyList = this.questionDifficultyMap.map(item => {
// 当前难度的试题列表 // 当前难度的试题列表
const currentDifficultyQuestionList = currentTypeQuestionList.filter(item2 => item2.question_difficulty === item.value) const currentDifficultyQuestionList = currentTypeQuestionList.filter(
item2 => item2.question_difficulty === item.value
)
return { return {
question_difficulty: item.value, question_difficulty: item.value,
question_difficulty_name: item.label, question_difficulty_name: item.label,
...@@ -235,7 +273,7 @@ export default { ...@@ -235,7 +273,7 @@ export default {
}) })
for (let i = 0; i < rules.length; i++) { for (let i = 0; i < rules.length; i++) {
const item = rules[i] const item = rules[i]
if ((!['7', '8'].includes(item.question_type) && !item.question_score) || !item.question_num) { if ((!['5', '7', '8'].includes(item.question_type) && !item.question_score) || !item.question_num) {
this.$message.error(`第${i + 1}行规则配置错误,请检查后重试`) this.$message.error(`第${i + 1}行规则配置错误,请检查后重试`)
return return
} }
......
...@@ -7,21 +7,34 @@ ...@@ -7,21 +7,34 @@
<template #header-aside> <template #header-aside>
<!-- 选题组卷 --> <!-- 选题组卷 -->
<template v-if="data.paper_type === 1"> <template v-if="data.paper_type === 1">
<el-button type="primary" @click="showSelectQuestion" v-permission="'admin_v1_question_paper_rules'">添加试题</el-button> <el-button type="primary" @click="showSelectQuestion" v-permission="'paper_setu_rules'"
<el-button type="primary" :disabled="!multipleSelection.length" @click="handleRemove">删除选中试题</el-button> >添加试题</el-button
>
<el-button type="primary" :disabled="!multipleSelection.length" @click="handleRemove"
>删除选中试题</el-button
>
</template> </template>
<!-- 自动组卷 --> <!-- 自动组卷 -->
<template v-if="data.paper_type === 2"> <template v-if="data.paper_type === 2">
<el-button type="primary" @click="handleAutoPaper" v-permission="'admin_v1_question_paper_rules'">自动组卷</el-button> <el-button type="primary" @click="handleAutoPaper" v-permission="'paper_setu_rules'">自动组卷</el-button>
</template> </template>
<!-- 自由组卷 --> <!-- 自由组卷 -->
<template v-if="data.paper_type === 3"> <template v-if="data.paper_type === 3">
<el-button type="primary" @click="handleAutoPaper" v-permission="'admin_v1_question_paper_rules'">自动组卷</el-button> <el-button type="primary" @click="handleAutoPaper" v-permission="'paper_setu_rules'">自动组卷</el-button>
<el-button type="primary" @click="paperVisible = true" v-permission="'admin_v1_question_paper_rules'">添加试题</el-button> <el-button type="primary" @click="paperVisible = true" v-permission="'paper_setu_rules'"
<el-button type="primary" :disabled="!multipleSelection.length" @click="handleRemove">删除选中试题</el-button> >添加试题</el-button
>
<el-button type="primary" :disabled="!multipleSelection.length" @click="handleRemove"
>删除选中试题</el-button
>
</template> </template>
</template> </template>
<question-list :list="currentQuestions" :disableScore="data.paper_type === 2" style="margin-top: 20px" v-if="currentQuestions.length"> <question-list
:list="currentQuestions"
:disableScore="data.paper_type === 2"
style="margin-top: 20px"
v-if="currentQuestions.length"
>
<template v-slot:selection="item" v-if="hasSelection"> <template v-slot:selection="item" v-if="hasSelection">
<el-checkbox @change="handleSelectionChange(arguments[0], item)"></el-checkbox> <el-checkbox @change="handleSelectionChange(arguments[0], item)"></el-checkbox>
</template> </template>
...@@ -48,7 +61,7 @@ ...@@ -48,7 +61,7 @@
</template> </template>
<template #footer> <template #footer>
<template v-if="hasSelection"> <template v-if="hasSelection">
<el-button type="primary" @click="handleSubmit" v-permission="'admin_v1_question_paper_rules'">保存试卷</el-button> <el-button type="primary" @click="handleSubmit" v-permission="'paper_setu_rules'">保存试卷</el-button>
</template> </template>
</template> </template>
</question-num> </question-num>
...@@ -67,7 +80,13 @@ ...@@ -67,7 +80,13 @@
<!-- 自由组卷-自动组卷 --> <!-- 自由组卷-自动组卷 -->
<OnceAutomaticPaper :visible.sync="visible" :data="data" @update="handleUpdate" v-if="visible" /> <OnceAutomaticPaper :visible.sync="visible" :data="data" @update="handleUpdate" v-if="visible" />
<!-- 自由组卷-选题组卷 --> <!-- 自由组卷-选题组卷 -->
<addPaper :visible.sync="paperVisible" :data="data" :list="questions" @update="handleUpdate" v-if="paperVisible" /> <addPaper
:visible.sync="paperVisible"
:data="data"
:list="questions"
@update="handleUpdate"
v-if="paperVisible"
/>
</template> </template>
</div> </div>
</template> </template>
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
<!-- 试卷描述 --> <!-- 试卷描述 -->
<app-card title="试卷信息"> <app-card title="试卷信息">
<template #header-aside> <template #header-aside>
<el-button type="primary" @click="handleUpdate" v-permission="'admin_v1_paper_update'">编辑试卷</el-button> <el-button type="primary" @click="handleUpdate" v-permission="'paper_update'">编辑试卷</el-button>
</template> </template>
<el-descriptions :column="2" class="descriptionsCon"> <el-descriptions :column="2" class="descriptionsCon">
<el-descriptions-item label="试卷名称">{{ detail.paper_title }}</el-descriptions-item> <el-descriptions-item label="试卷名称">{{ detail.paper_title }}</el-descriptions-item>
<el-descriptions-item label="标签">{{ detail.paper_labels }}</el-descriptions-item> <el-descriptions-item label="标签">{{ detail.paper_labels }}</el-descriptions-item>
<el-descriptions-item label="试卷分类">{{ detail.paper_category.name }}</el-descriptions-item> <el-descriptions-item label="试卷分类">{{ detail.paper_category.category_name }}</el-descriptions-item>
<el-descriptions-item label="组卷模式">{{ detail.paper_type_name }}</el-descriptions-item> <el-descriptions-item label="组卷模式">{{ detail.paper_type_name }}</el-descriptions-item>
<el-descriptions-item label="试卷总分">{{ detail.paper_total_score }}</el-descriptions-item> <el-descriptions-item label="试卷总分">{{ detail.paper_total_score }}</el-descriptions-item>
<el-descriptions-item label="及格分数">{{ detail.pass_score }}</el-descriptions-item> <el-descriptions-item label="及格分数">{{ detail.pass_score }}</el-descriptions-item>
...@@ -65,7 +65,8 @@ export default { ...@@ -65,7 +65,8 @@ export default {
temp.is_multiple_exams_name = isMultipleExamsMap[data.is_multiple_exams] || data.is_multiple_exams temp.is_multiple_exams_name = isMultipleExamsMap[data.is_multiple_exams] || data.is_multiple_exams
// 多次考试成绩计算规则 // 多次考试成绩计算规则
const multipleTestScoreRuleMap = { 1: '平均计算法', 2: '最高得分法' } const multipleTestScoreRuleMap = { 1: '平均计算法', 2: '最高得分法' }
temp.multiple_test_score_rule_name = multipleTestScoreRuleMap[data.multiple_test_score_rule] || data.multiple_test_score_rule temp.multiple_test_score_rule_name =
multipleTestScoreRuleMap[data.multiple_test_score_rule] || data.multiple_test_score_rule
this.detail = Object.assign({}, this.detail, res.data, temp) this.detail = Object.assign({}, this.detail, res.data, temp)
}) })
.finally(() => { .finally(() => {
......
<template> <template>
<app-card> <app-card>
<div style="margin-bottom: 25px" v-permission="'button_paper_permission'">
<span style="font-size: 14px; color: #606266; padding-right: 12px">试卷范围:</span>
<el-radio @change="refetchList" v-model="permission" :label="1" v-permission="'button_paper_permission_my'"
>我的试卷库</el-radio
>
<el-radio @change="refetchList" v-model="permission" :label="2" v-permission="'button_paper_permission_public'"
>公共试卷库</el-radio
>
</div>
<app-list v-bind="tableOptions" ref="list" @selection-change="handleSelectionChange"> <app-list v-bind="tableOptions" ref="list" @selection-change="handleSelectionChange">
<div class="btn_operate"> <div class="btn_operate">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate" v-permission="'admin_v1_paper_create'">新建试卷</el-button> <el-button type="primary" icon="el-icon-plus" @click="handleCreate" v-permission="'paper_create'"
<el-button type="primary" icon="el-icon-delete" :disabled="!multipleSelection.length" @click="handleBatchDelete" v-permission="'admin_v1_paper_batch_delete'">批量删除</el-button> >新建试卷</el-button
>
<el-button
type="primary"
icon="el-icon-delete"
:disabled="!multipleSelection.length"
@click="handleBatchDelete"
v-permission="'paper_batch_delete'"
>批量删除</el-button
>
</div> </div>
<template v-slot:filter-category="{ params }"> <template v-slot:filter-category="{ params }">
<question-type-treeselect multiple v-model="params.paper_categories" @change="refetchList"></question-type-treeselect> <question-type-treeselect
multiple
v-model="params.paper_categories"
@change="refetchList"
></question-type-treeselect>
</template> </template>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<router-link :to="{ name: 'editPaper', params: { id: row.id } }" target="_blank" v-permission="'admin_v1_paper_update'"> <router-link :to="{ name: 'editPaper', params: { id: row.id } }" target="_blank" v-permission="'paper_update'">
<el-button type="text">编辑</el-button> <el-button type="text">编辑</el-button>
</router-link> </router-link>
<router-link :to="{ name: 'viewPaper', params: { id: row.id } }" target="_blank" v-permission="'admin_v1_paper_detail'"> <router-link :to="{ name: 'viewPaper', params: { id: row.id } }" target="_blank" v-permission="'paper_detail'">
<el-button type="text">查看详情</el-button> <el-button type="text">查看详情</el-button>
</router-link> </router-link>
<el-button type="text" @click="handleDelete(row)" v-permission="'admin_v1_paper_batch_delete'">删除</el-button> <el-button type="text" @click="handleDelete(row)" v-permission="'paper_batch_delete'">删除</el-button>
</template> </template>
</app-list> </app-list>
</app-card> </app-card>
...@@ -30,6 +52,7 @@ export default { ...@@ -30,6 +52,7 @@ export default {
components: { QuestionTypeTreeselect }, components: { QuestionTypeTreeselect },
data() { data() {
return { return {
permission: 1,
multipleSelection: [] // 选择项 multipleSelection: [] // 选择项
} }
}, },
...@@ -47,7 +70,8 @@ export default { ...@@ -47,7 +70,8 @@ export default {
paper_title: '', paper_title: '',
paper_type: '', paper_type: '',
paper_labels: '', paper_labels: '',
paper_categories: [] paper_categories: [],
permission: this.permission
} }
}, },
filters: [ filters: [
...@@ -115,7 +139,7 @@ export default { ...@@ -115,7 +139,7 @@ export default {
methods: { methods: {
// 新建试卷 // 新建试卷
handleCreate() { handleCreate() {
this.$router.push({ name: 'createPaper' }) this.$router.push({ name: 'createPaper', query: { permission: this.permission } })
}, },
// 编辑试卷 // 编辑试卷
handleUpdate(row) { handleUpdate(row) {
......
<template> <template>
<app-card> <app-card>
<el-form ref="form" :model="form" :rules="rules" label-width="160px" label-position="right"> <el-form ref="form" :model="form" :rules="rules" label-width="160px" label-position="right">
<el-row>
<el-form-item label="试卷范围" prop="permission">
<el-radio-group v-model="form.permission">
<el-radio :label="1">我的试卷库</el-radio>
<el-radio :label="2">公共试卷库</el-radio>
</el-radio-group>
</el-form-item>
</el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="试卷名称" prop="paper_title"> <el-form-item label="试卷名称" prop="paper_title">
...@@ -35,7 +43,12 @@ ...@@ -35,7 +43,12 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item label="组卷模式" prop="paper_type"> <el-form-item label="组卷模式" prop="paper_type">
<el-select v-model="form.paper_type" placeholder="请选择组卷模式" style="width: 100%"> <el-select v-model="form.paper_type" placeholder="请选择组卷模式" style="width: 100%">
<el-option v-for="item in paperTypeList" :label="item.label" :value="item.value" :key="item.value"></el-option> <el-option
v-for="item in paperTypeList"
:label="item.label"
:value="item.value"
:key="item.value"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
...@@ -51,7 +64,15 @@ ...@@ -51,7 +64,15 @@
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="试卷总分" prop="paper_total_score"> <el-form-item label="试卷总分" prop="paper_total_score">
<el-input-number :controls="false" v-model="form.paper_total_score" :min="0" :max="200" placeholder="请输入试卷总分" style="width: 100%" :precision="0"></el-input-number> <el-input-number
:controls="false"
v-model="form.paper_total_score"
:min="0"
:max="200"
placeholder="请输入试卷总分"
style="width: 100%"
:precision="0"
></el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="10">
...@@ -71,12 +92,28 @@ ...@@ -71,12 +92,28 @@
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="考试时长" prop="paper_times"> <el-form-item label="考试时长" prop="paper_times">
<el-input-number v-model="form.paper_times" :controls="false" :min="1" :max="150" placeholder="请输入考试时长" :precision="0"></el-input-number>&nbsp;分钟 <el-input-number
v-model="form.paper_times"
:controls="false"
:min="1"
:max="150"
placeholder="请输入考试时长"
:precision="0"
></el-input-number
>&nbsp;分钟
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="最短交卷时长" prop="minimum_paper_handing_time"> <el-form-item label="最短交卷时长" prop="minimum_paper_handing_time">
<el-input-number v-model="form.minimum_paper_handing_time" :controls="false" :min="1" :max="150" placeholder="请输入考试时长" :precision="0"></el-input-number>&nbsp;分钟 <el-input-number
v-model="form.minimum_paper_handing_time"
:controls="false"
:min="1"
:max="150"
placeholder="请输入考试时长"
:precision="0"
></el-input-number
>&nbsp;分钟
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
...@@ -123,9 +160,11 @@ export default { ...@@ -123,9 +160,11 @@ export default {
callback() callback()
} }
} }
const permission = parseInt(this.$route.query.permission) || 1
return { return {
paperTypeList, paperTypeList,
form: { form: {
permission,
paper_title: '', // 试卷名称 paper_title: '', // 试卷名称
paper_uses: 1, // 试卷用途 paper_uses: 1, // 试卷用途
paper_labels: '', // 标签 paper_labels: '', // 标签
...@@ -172,6 +211,7 @@ export default { ...@@ -172,6 +211,7 @@ export default {
// 取消 // 取消
handleCancel() { handleCancel() {
this.$router.back() this.$router.back()
this.$router.replace({ path: '/paper/list' })
}, },
// 保存 // 保存
handleSubmit() { handleSubmit() {
...@@ -180,6 +220,7 @@ export default { ...@@ -180,6 +220,7 @@ export default {
if (this.isEdit) { if (this.isEdit) {
this.updatePaper().then(res => { this.updatePaper().then(res => {
this.$router.back() this.$router.back()
this.$router.replace({ path: '/paper/list' })
}) })
} else { } else {
this.createPaper().then(res => { this.createPaper().then(res => {
......
...@@ -4,63 +4,63 @@ import httpRequest from '@/utils/axios' ...@@ -4,63 +4,63 @@ import httpRequest from '@/utils/axios'
* 获取应用列表 * 获取应用列表
*/ */
export function getAppList(params) { export function getAppList(params) {
return httpRequest.get('/api/qbs/admin/v1/questions', { params }) return httpRequest.get('/api/qbs/admin/v2/questions', { params })
} }
/** /**
* 获取题目分类树形结构 * 获取题目分类树形结构
*/ */
export function getQuestionCategory(params) { export function getQuestionCategory(params) {
return httpRequest.get(`/api/qbs/admin/v1/question-category/tree/${params}`) return httpRequest.get(`/api/qbs/admin/v2/question-category/tree/${params}`)
} }
/** /**
* 添加试题分类 * 添加试题分类
*/ */
export function addQuestionCategory(data) { export function addQuestionCategory(data) {
return httpRequest.post('/api/qbs/admin/v1/question-category', data) return httpRequest.post('/api/qbs/admin/v2/question-category', data)
} }
/** /**
* 更新应用 * 更新应用
*/ */
export function updateQuestionCategory(id, data) { export function updateQuestionCategory(id, data) {
return httpRequest.put(`/api/qbs/admin/v1/question-category/${id}`, data) return httpRequest.put(`/api/qbs/admin/v2/question-category/${id}`, data)
} }
/** /**
* 知识点标签搜索 * 知识点标签搜索
*/ */
export function searchTag(params) { export function searchTag(params) {
return httpRequest.get(`/api/qbs/admin/v1/knowledge-point/search/${params.project_prefix}`, { params }) return httpRequest.get(`/api/qbs/admin/v2/knowledge-point/search/${params.project_prefix}`, { params })
} }
/** /**
* 新建试题 * 新建试题
*/ */
export function addQuestion(data) { export function addQuestion(data) {
return httpRequest.post('/api/qbs/admin/v1/question', data) return httpRequest.post('/api/qbs/admin/v2/question', data)
} }
/** /**
* 删除试题 * 删除试题
*/ */
export function deleteQuestion(data) { export function deleteQuestion(data) {
return httpRequest.post('/api/qbs/admin/v1/question/batch-delete', data) return httpRequest.post('/api/qbs/admin/v2/question/batch-delete', data)
} }
/** /**
* 更新试题 * 更新试题
*/ */
export function updateQuestion(id, data) { export function updateQuestion(id, data) {
return httpRequest.put(`/api/qbs/admin/v1/question/${id}`, data) return httpRequest.put(`/api/qbs/admin/v2/question/${id}`, data)
} }
/** /**
* 试题详情 * 试题详情
*/ */
export function questionDetail(id) { export function questionDetail(id) {
return httpRequest.get(`/api/qbs/admin/v1/question/${id}`) return httpRequest.get(`/api/qbs/admin/v2/question/${id}`)
} }
/** /**
* 导入题 * 导入题
*/ */
export function importQuestion(tag, data) { export function importQuestion(tag, data) {
return httpRequest({ return httpRequest({
url: `/api/qbs/admin/v1/question/import/${tag}`, url: `/api/qbs/admin/v2/question/import/${tag}`,
method: 'post', method: 'post',
headers: { 'Content-Type': 'multipart/form-data' }, headers: { 'Content-Type': 'multipart/form-data' },
timeout: 900000, timeout: 900000,
......
<template> <template>
<div class="radio-box"> <div class="radio-box">
<template v-for="(item, index) in option"> <div class="opt" v-for="(item, index) in option" :key="index">
<div class="opt" :key="index"> <el-checkbox v-model="checkboxValue" :label="index" @change="checkboxChange">
<el-checkbox v-model="checkboxValue" :label="index" @change="checkboxChange"> <el-tag>{{ A_Z()[index] }}</el-tag>
<el-tag>{{ A_Z()[index] }}</el-tag> <el-input v-model="item.option" maxlength="80" show-word-limit></el-input>
<el-input v-model="item.option" maxlength="80" show-word-limit></el-input> </el-checkbox>
</el-checkbox> <template v-if="!isView">
<template v-if="!!!($route.query.type === 'view')"> <i class="el-icon-remove-outline icon-style" v-if="index != option.length - 1" @click="remove(index)"></i>
<i class="el-icon-remove-outline icon-style" v-if="index != option.length - 1" @click="remove(index)"></i> <i class="el-icon-circle-plus-outline icon-style" v-else @click="add"></i>
<i class="el-icon-circle-plus-outline icon-style" v-else @click="add"></i> </template>
</template> </div>
</div>
</template>
</div> </div>
</template> </template>
...@@ -22,6 +20,7 @@ export default { ...@@ -22,6 +20,7 @@ export default {
type: Array type: Array
} }
}, },
inject: ['isView', 'isEdit', 'disabled'],
data() { data() {
return { return {
checkboxValue: [] checkboxValue: []
......
<template> <template>
<div> <div>
<template v-for="(item, index) in option"> <div class="opt" v-for="(item, index) in option" :key="index">
<div class="opt" :key="index"> <el-radio v-model="radio" :label="index" @change="radioChange">
<el-radio v-model="radio" :label="index" @change="radioChange"> <el-input v-model="item.option" style="width: 80px"></el-input>
<el-input v-model="item.option" style="width: 80px"></el-input> </el-radio>
</el-radio> </div>
</div>
</template>
</div> </div>
</template> </template>
......
<template> <template>
<div class="radio-box"> <div class="radio-box">
<template v-for="(item, index) in option"> <div class="opt" v-for="(item, index) in option" :key="index">
<div class="opt" :key="index"> <el-radio v-model="radioValue" :label="index" @change="radioChange">
<el-radio v-model="radioValue" :label="index" @change="radioChange"> <el-tag>{{ A_Z()[index] }}</el-tag>
<el-tag>{{ A_Z()[index] }}</el-tag> <el-input v-model="item.option" maxlength="80" show-word-limit></el-input>
<el-input v-model="item.option" maxlength="80" show-word-limit></el-input> </el-radio>
</el-radio> <template v-if="!isView">
<template v-if="!!!($route.query.type === 'view')"> <i class="el-icon-remove-outline icon-style" v-if="index != option.length - 1" @click="remove(index)"></i>
<i class="el-icon-remove-outline icon-style" v-if="index != option.length - 1" @click="remove(index)"></i> <i class="el-icon-circle-plus-outline icon-style" v-else @click="add"></i>
<i class="el-icon-circle-plus-outline icon-style" v-else @click="add"></i> </template>
</template> </div>
</div>
</template>
</div> </div>
</template> </template>
...@@ -22,6 +20,7 @@ export default { ...@@ -22,6 +20,7 @@ export default {
type: Array type: Array
} }
}, },
inject: ['isView', 'isEdit', 'disabled'],
data() { data() {
return { return {
radioValue: 0, radioValue: 0,
......
<template>
<div>
<div class="tool-btn" v-if="!!!($route.query.type === 'view')">
<el-button type="primary" @click="drawer = true">添加子题目</el-button>
<el-button type="primary" v-if="!!!($route.query.type === 'edit')" @click="cacheQuestion">保存主题目</el-button>
</div>
<el-form
:disabled="!!($route.query.type === 'view')"
:model="ruleForm"
:rules="rules"
ref="ruleForm"
label-width="100px"
class="demo-ruleForm"
>
<el-form-item label="题库范围" prop="permission">
<el-radio v-model="ruleForm.permission" label="1" v-permission="'button_question_permission_my'"
>我的题库</el-radio
>
<el-radio v-model="ruleForm.permission" label="2" v-permission="'button_question_permission_public'"
>公共题库</el-radio
>
</el-form-item>
<el-form-item label="题目类型" prop="question_type">
<el-select
:disabled="!!$route.query.id"
@change="questionTypeChange"
v-model="ruleForm.question_type"
placeholder="请选择活题目类型"
>
<el-option v-for="(item, index) in qType" :label="item.label" :value="item.value" :key="index"></el-option>
</el-select>
</el-form-item>
<el-form-item label="难度等级" prop="question_difficulty">
<el-select v-model="ruleForm.question_difficulty" placeholder="请选择活难度等级">
<el-option label="易" value="1"></el-option>
<el-option label="中" value="2"></el-option>
<el-option label="难" value="3"></el-option>
<el-option label="无" value="0"></el-option>
</el-select>
</el-form-item>
<el-form-item label="题目标题" prop="question_title">
<el-input v-model="ruleForm.question_title"></el-input>
</el-form-item>
<el-form-item label="公共题干" prop="common_content">
<v-editor :disabled="!!($route.query.type === 'view')" v-model="ruleForm.common_content"></v-editor>
</el-form-item>
<el-form-item label="标签" prop="question_tag">
<el-input v-model="ruleForm.question_tag"></el-input>
</el-form-item>
<el-form-item label="试题分类" prop="question_category">
<question-type-cascader v-model="ruleForm.question_category"></question-type-cascader>
</el-form-item>
<el-form-item label="知识点">
<el-select
v-model="ruleForm.knowledge_point"
filterable
remote
reserve-keyword
placeholder="请输入关键词"
:remote-method="remoteMethod"
>
<el-option v-for="item in pointOptions" :key="item.id" :label="item.title" :value="item.id"> </el-option>
</el-select>
</el-form-item>
</el-form>
<questions-chidren
:chidrenList="chidrenList"
@submitForm="submitForm"
@cacheChidren="cacheQuestion"
></questions-chidren>
<div v-if="$route.query.type === 'view'" style="text-align: center">
<el-button type="primary" @click="$router.back()">关闭</el-button>
</div>
<el-drawer size="90%" title="新建试题" :visible.sync="drawer" direction="rtl" :before-close="handleCloseDrawer">
<add-chidren @haveQuestion="haveQuestion" @questionList="questionList" :dataForm="ruleForm"></add-chidren>
</el-drawer>
</div>
</template>
<script>
import QuestionsChidren from './QuestionsChidren.vue'
import VEditor from '@/components/tinymce/Index.vue'
import AddChidren from './AddChidren.vue'
import QuestionTypeCascader from '@/components/base/QuestionTypeTreeselect.vue'
import { searchTag, addQuestion, updateQuestion } from '../api'
export default {
components: { AddChidren, VEditor, QuestionsChidren, QuestionTypeCascader },
props: {
questionTypeNumber: {
type: Number,
default: 1
},
detailData: {
type: Object
}
},
data() {
return {
pointOptions: [],
chidrenList: [],
drawer: false,
ruleForm: {
permission: '1',
question_type: 1,
question_title: '',
common_content: '',
question_category: '',
question_tag: '',
knowledge_point: '',
question_difficulty: '',
children: []
},
rules: {
permission: [{ required: true, message: '请选择', trigger: 'change' }],
question_type: [{ required: true, message: '请选择', trigger: 'change' }],
question_difficulty: [{ required: true, message: '请选择难度等级', trigger: 'change' }],
question_title: [{ required: true, message: '请填写题目标题', trigger: 'blur' }],
common_content: [{ required: true, message: '请填写题干内容', trigger: 'blur' }],
question_category: [{ required: true, message: '请选择试题分类', trigger: 'blur' }],
knowledge_point: [{ required: true, message: '请输入题目知识点内容', trigger: 'blur' }]
},
qType: [
{ label: '单选题', value: 1 },
{ label: '多选题', value: 2 },
{ label: '简答题', value: 3 },
{ label: '案例题', value: 5 },
{ label: '判断题', value: 6 },
{ label: '实操题', value: 7 },
{ label: '情景题', value: 8 }
]
}
},
created() {
this.ruleForm.question_type = this.questionTypeNumber
if (this.detailData) {
this.ruleForm = this.detailData
this.ruleForm.question_category = this.detailData.question_category.id
this.pointOptions.push(this.detailData.knowledge_point)
this.ruleForm.knowledge_point = this.detailData.knowledge_point.id
this.chidrenList = this.ruleForm.children
} else {
const cacheData = window.localStorage.cacheQuestion
if (cacheData) {
this.ruleForm = JSON.parse(cacheData).form
this.pointOptions = JSON.parse(cacheData).pointOptions
this.chidrenList = JSON.parse(cacheData).children
}
}
},
computed: {
activeProject() {
return this.$store.state.activeProject || {}
}
},
methods: {
// 添加子题 drawer关闭
handleCloseDrawer() {
this.drawer = false
},
// 提交
submitForm() {
this.ruleForm.children = this.chidrenList
// 子题目排序
const params = this.ruleForm
if (params.children && params.children.length) {
params.children = params.children.map((item, index) => {
return { ...item, question_order: index }
})
}
if (this.$route.query.id) {
if (Array.isArray(params.children)) {
params.children.map(item => {
console.log(item, '123')
item.question_options.map(cItem => {
if (cItem.checked === undefined) {
cItem.checked = false
}
return cItem
})
return item
})
}
updateQuestion(this.$route.query.id, params).then(res => {
this.$router.push({
path: '/question/list'
})
})
} else {
addQuestion(params).then(res => {
this.$router.push({
path: '/question/list'
})
})
window.localStorage.removeItem('cacheQuestion')
}
},
// 暂存本地
cacheQuestion() {
const cacheData = {
form: this.ruleForm,
tree: this.treeValue,
pointOptions: this.pointOptions,
children: this.chidrenList
}
window.localStorage.cacheQuestion = JSON.stringify(cacheData)
this.$message({
message: '保存成功',
type: 'success'
})
},
// 切换题型
questionTypeChange() {
this.$emit('questionType', this.ruleForm.question_type)
},
// 知识点搜索
remoteMethod(query) {
searchTag({ project_prefix: this.activeProject.tag, title: query }).then(res => {
this.pointOptions = res.data.data
})
},
// 添加子题目
questionList(data) {
this.chidrenList.push(data)
this.drawer = false
},
haveQuestion(data) {
data.forEach(item => {
this.chidrenList.push(item)
})
this.drawer = false
}
}
}
</script>
<style lang="scss" scoped>
.tool-btn {
display: flex;
justify-content: right;
}
.divider {
margin: 20px 0;
}
</style>
<template>
<div>
<el-form
:rules="rules"
:disabled="!!($route.query.type === 'view')"
:model="data"
ref="ruleForm"
label-width="100px"
class="demo-ruleForm"
>
<div v-for="(ruleForm, index) in chidrenList" :key="index">
<el-divider content-position="center" class="divider">子题目{{ index + 1 }}</el-divider>
<el-form-item style="text-align: right" v-if="!!!($route.query.type === 'view')">
<el-button type="primary" v-if="!!!($route.query.type === 'edit')" @click="$emit('cacheChidren')"
>保存子题目</el-button
>
<el-button type="primary" @click="removeChidren(index)">删除子题目</el-button>
</el-form-item>
<el-form-item label="子题目类型" prop="child_question_type">
<el-select v-model="ruleForm.child_question_type" disabled placeholder="请选择活动区域">
<el-option label="单选题" :value="1"></el-option>
<el-option label="多选题" :value="2"></el-option>
<el-option label="判断题" :value="6"></el-option>
<el-option label="问答题" :value="3"></el-option>
</el-select>
</el-form-item>
<el-form-item label="子题目标题" prop="question_title">
<el-input v-model="ruleForm.question_title"></el-input>
</el-form-item>
<el-form-item label="子题目内容" prop="question_content">
<v-editor :disabled="!!($route.query.type === 'view')" v-model="ruleForm.question_content"></v-editor>
</el-form-item>
<el-form-item label="选项" prop="question_options" v-if="ruleForm.child_question_type != 3">
<!-- 单选题 -->
<radio ref="options" :option="ruleForm.question_options" v-if="ruleForm.child_question_type == 1"></radio>
<!-- 多选题 -->
<checkbox
ref="options"
:option="ruleForm.question_options"
v-if="ruleForm.child_question_type == 2"
></checkbox>
<!-- 判断题 -->
<judgment
ref="options"
:option="ruleForm.question_options"
v-if="ruleForm.child_question_type == 6"
></judgment>
</el-form-item>
<el-form-item label="子题目解析" prop="question_analysis">
<v-editor :disabled="!!($route.query.type === 'view')" v-model="ruleForm.question_analysis"></v-editor>
</el-form-item>
<el-form-item style="text-align: center" v-if="index + 1 == chidrenList.length">
<el-button v-if="!!!($route.query.type === 'view')" type="primary" @click="submitForm">保存</el-button>
</el-form-item>
</div>
</el-form>
</div>
</template>
<script>
import Radio from './QTypeRadio.vue'
import Checkbox from './QTypeCheckbox.vue'
import Judgment from './QTypeJudgment.vue'
import VEditor from '@/components/tinymce/Index.vue'
export default {
components: { VEditor, Radio, Checkbox, Judgment },
props: {
data: {
type: Object
},
chidrenList: {
type: Array
}
},
data() {
return {
ruleForm: {},
rules: {
child_question_type: [{ required: true, message: ' ', trigger: 'blur' }],
question_difficulty: [{ required: true, message: ' ', trigger: 'blur' }],
question_title: [{ required: true, message: ' ', trigger: 'blur' }],
question_content: [{ required: true, message: ' ', trigger: 'blur' }],
question_analysis: [{ required: false, message: ' ', trigger: 'blur' }],
question_options: [{ required: true, message: ' ', trigger: 'blur' }]
}
}
},
mounted() {
// console.log(this.chidrenListld)
},
methods: {
removeChidren(n) {
this.$confirm('确认删除该题目吗?删除后不可恢复').then(_ => {
this.chidrenList.splice(n, 1)
})
},
submitForm() {
let flag = false
this.chidrenList.forEach(item => {
if (item.child_question_type !== 3) {
const option = item.question_options.find(opt => opt.option === '')
if (option) {
flag = true
return false
}
}
})
if (flag) {
this.$message.warning('请完善选项内容')
return false
} else {
this.$emit('submitForm')
}
}
}
}
</script>
<style lang="scss" scoped></style>
<template>
<div>
<div v-for="(ruleForm, index) in children" :key="index">
<el-divider content-position="center" class="divider">子题目{{ index + 1 }}</el-divider>
<el-form-item style="text-align: right" v-if="!isView">
<el-button type="primary" v-if="!isEdit" @click="$emit('cacheChildren')">保存子题目</el-button>
<el-button type="primary" @click="removeChildren(index)">删除子题目</el-button>
</el-form-item>
<el-form-item
label="子题目类型"
:prop="'children.' + index + '.child_question_type'"
:rules="rules.child_question_type"
>
<el-select v-model="ruleForm.child_question_type" disabled>
<el-option label="单选题" :value="1"></el-option>
<el-option label="多选题" :value="2"></el-option>
<el-option label="判断题" :value="6"></el-option>
<el-option label="问答题" :value="3"></el-option>
</el-select>
</el-form-item>
<el-form-item label="子题目标题" :prop="'children.' + index + '.question_title'" :rules="rules.question_title">
<el-input v-model="ruleForm.question_title"></el-input>
</el-form-item>
<el-form-item
label="子题目内容"
:prop="'children.' + index + '.question_content'"
:rules="rules.question_content"
>
<v-editor :disabled="disabled" v-model="ruleForm.question_content"></v-editor>
</el-form-item>
<el-form-item
label="选项"
:prop="'children.' + index + '.question_options'"
:rules="rules.question_options"
v-if="ruleForm.child_question_type !== 3"
>
<!-- 单选题 -->
<radio ref="options" :option="ruleForm.question_options" v-if="ruleForm.child_question_type == 1"></radio>
<!-- 多选题 -->
<checkbox ref="options" :option="ruleForm.question_options" v-if="ruleForm.child_question_type == 2"></checkbox>
<!-- 判断题 -->
<judgment ref="options" :option="ruleForm.question_options" v-if="ruleForm.child_question_type == 6"></judgment>
</el-form-item>
<el-form-item label="子题目解析" :prop="'children.' + index + '.question_analysis'">
<v-editor :disabled="disabled" v-model="ruleForm.question_analysis"></v-editor>
</el-form-item>
</div>
</div>
</template>
<script>
import Radio from './QTypeRadio.vue'
import Checkbox from './QTypeCheckbox.vue'
import Judgment from './QTypeJudgment.vue'
import VEditor from '@/components/tinymce/Index.vue'
export default {
components: { VEditor, Radio, Checkbox, Judgment },
props: {
children: { type: Array }
},
inject: ['isView', 'isEdit', 'disabled'],
data() {
const validateOptions = (rule, list, callback) => {
for (const item of list) {
if (item.option === '') {
callback(new Error('请完善选项内容'))
return
}
}
callback()
}
return {
rules: {
child_question_type: [{ required: true, message: '请选择', trigger: 'blur' }],
question_difficulty: [{ required: true, message: '请选择', trigger: 'blur' }],
question_title: [{ required: true, message: '请输入', trigger: 'blur' }],
question_content: [{ required: true, message: '请输入', trigger: 'blur' }],
question_options: [{ required: true, validator: validateOptions, message: '请完善选项内容', trigger: 'blur' }]
}
}
},
methods: {
removeChildren(index) {
this.$confirm('确认删除该题目吗?删除后不可恢复').then(() => {
this.children.splice(index, 1)
})
}
}
}
</script>
...@@ -11,8 +11,17 @@ ...@@ -11,8 +11,17 @@
<template v-if="source == 1"> <template v-if="source == 1">
<div class="radio-box"> <div class="radio-box">
<div class="tips-tit index">请选择题库:</div> <div class="tips-tit index">请选择题库:</div>
<el-radio @change="refetchList" v-model="questionBank" label="1">我的题库</el-radio> <el-radio @change="refetchList" v-model="questionBank" label="1" v-permission="'button_question_permission_my'"
<el-radio @change="refetchList" v-model="questionBank" label="2" style="text-indent: 1.5em">公共题库</el-radio> >我的题库</el-radio
>
<el-radio
@change="refetchList"
v-model="questionBank"
label="2"
style="text-indent: 1.5em"
v-permission="'button_question_permission_public'"
>公共题库</el-radio
>
</div> </div>
<app-list v-bind="tableOptions" ref="list" class="app-list" @selection-change="handleSelectionChange"> <app-list v-bind="tableOptions" ref="list" class="app-list" @selection-change="handleSelectionChange">
<template v-slot:filter-category="{ params }"> <template v-slot:filter-category="{ params }">
...@@ -47,10 +56,9 @@ ...@@ -47,10 +56,9 @@
<script> <script>
import { getAppList } from '../api' import { getAppList } from '../api'
import QuestionTypeCascader from '@/components/base/QuestionTypeTreeselect.vue' import QuestionTypeCascader from '@/components/base/QuestionTypeTreeselect.vue'
export default { export default {
components: { components: { QuestionTypeCascader },
QuestionTypeCascader
},
data() { data() {
return { return {
filterInput: '', filterInput: '',
...@@ -182,7 +190,6 @@ export default { ...@@ -182,7 +190,6 @@ export default {
return a return a
}, []) }, [])
.sort((a, b) => a.order - b.order) .sort((a, b) => a.order - b.order)
console.log(this.checkedList, '123')
}, },
// 筛选更新列表 // 筛选更新列表
refetchList() { refetchList() {
......
...@@ -17,7 +17,7 @@ const routes = [ ...@@ -17,7 +17,7 @@ const routes = [
}, },
{ {
path: 'create', path: 'create',
component: () => import('./views/Create.vue'), component: () => import('./views/Update.vue'),
meta: { title: '新建试题' } meta: { title: '新建试题' }
}, },
{ {
...@@ -27,13 +27,15 @@ const routes = [ ...@@ -27,13 +27,15 @@ const routes = [
}, },
{ {
path: 'questionDetail', path: 'questionDetail',
component: () => import('./views/EditView.vue'), component: () => import('./views/Update.vue'),
meta: { title: '试题详情' } meta: { title: '试题详情' },
props: { isView: true }
}, },
{ {
path: 'editQuestion', path: 'editQuestion',
component: () => import('./views/EditView.vue'), component: () => import('./views/Update.vue'),
meta: { title: '编辑试题' } meta: { title: '编辑试题' },
props: { isEdit: true }
} }
] ]
} }
......
<template> <template>
<app-card> <app-card>
<el-button v-if="!treeList.length" type="primary" @click="centerDialogVisible = true">添加分类</el-button> <el-button
v-if="!treeList.length"
type="primary"
@click="centerDialogVisible = true"
v-permission="'question_category_add'"
>添加分类</el-button
>
<div class="block"> <div class="block">
<el-tree :data="treeList" node-key="id" default-expand-all :expand-on-click-node="false"> <el-tree :data="treeList" node-key="id" default-expand-all :expand-on-click-node="false">
<span class="custom-tree-node" slot-scope="{ node, data }"> <span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span> <span>{{ node.label }}</span>
<span> <span>
<el-button <el-button type="text" size="mini" @click="() => append(data)" v-permission="'question_category_add'"
type="text"
size="mini"
@click="() => append(data)"
v-permission="'admin_v1_qustion_category_add'"
>添加子项</el-button >添加子项</el-button
> >
<el-button <el-button type="text" size="mini" @click="() => edit(data)" v-permission="'question_category_update'"
type="text"
size="mini"
@click="() => edit(data)"
v-permission="'admin_v1_question_category_update'"
>修改名称</el-button >修改名称</el-button
> >
<!-- <el-button type="text" size="mini" @click="() => remove(node, data)"> Delete </el-button> --> <!-- <el-button type="text" size="mini" @click="() => remove(node, data)"> Delete </el-button> -->
......
<template>
<app-card>
<detail v-if="[1, 2, 3, 6].includes(questionTypeNum) && !cache" @questionType="questionType"></detail>
<situation-question v-else :questionTypeNumber="questionTypeNum" @questionType="questionType"></situation-question>
</app-card>
</template>
<script>
import Detail from '../components/Detail.vue'
import SituationQuestion from '../components/QTypeSituation.vue'
export default {
components: { Detail, SituationQuestion },
data() {
return {
questionTypeNum: 1,
detailData: {},
cache: window.localStorage.cacheQuestion
}
},
methods: {
questionType(n) {
this.cache = ''
this.questionTypeNum = n
}
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<app-card>
<template v-if="[1, 2, 3, 6].includes(questionTypeNum) && !cache">
<template v-if="$route.query.id">
<detail v-if="Object.keys(detailData).length" :detailData="detailData" @questionType="questionType"></detail>
</template>
<detail v-else @questionType="questionType"></detail>
</template>
<template v-else>
<template v-if="$route.query.id">
<situation-question v-if="$route.query.id && Object.keys(detailData).length" :detailData="detailData" :questionTypeNumber="questionTypeNum" @questionType="questionType"></situation-question>
</template>
<situation-question v-else :questionTypeNumber="questionTypeNum" @questionType="questionType"></situation-question>
</template>
</app-card>
</template>
<script>
import Detail from '../components/Detail.vue'
import SituationQuestion from '../components/QTypeSituation.vue'
import { questionDetail } from '../api'
export default {
components: { Detail, SituationQuestion },
data() {
return {
questionTypeNum: 1,
detailData: {},
cache: window.localStorage.cacheQuestion
}
},
mounted() {
if (this.$route.query.id) {
questionDetail(this.$route.query.id).then(res => {
this.questionTypeNum = res.data.question_type
res.data.permission = res.data.permission.toString()
res.data.question_difficulty = res.data.question_difficulty.toString()
this.detailData = res.data
})
}
},
methods: {
questionType(n) {
this.cache = ''
this.questionTypeNum = n
}
}
}
</script>
<style lang="scss" scoped>
</style>
<template> <template>
<app-card> <app-card>
<div style="margin-bottom: 25px"> <div style="margin-bottom: 25px" v-permission="'button_question_permission'">
<span style="font-size: 14px; color: #606266; padding-right: 12px">题库范围:</span> <span style="font-size: 14px; color: #606266; padding-right: 12px">题库范围:</span>
<el-radio @change="refetchList" v-model="permission" :label="1" v-permission="'button_question_permission_my'" <el-radio @change="refetchList" v-model="permission" :label="1" v-permission="'button_question_permission_my'"
>我的题库</el-radio >我的题库</el-radio
...@@ -23,14 +23,14 @@ ...@@ -23,14 +23,14 @@
type="primary" type="primary"
icon="el-icon-plus" icon="el-icon-plus"
@click="$router.push({ path: '/question/create' })" @click="$router.push({ path: '/question/create' })"
v-permission="'admin_v1_question_create'" v-permission="'question_create'"
>新建试题</el-button >新建试题</el-button
> >
<el-button <el-button
type="primary" type="primary"
icon="el-icon-plus" icon="el-icon-plus"
@click="importDialogVisible = true" @click="importDialogVisible = true"
v-permission="'admin_v1_question_import'" v-permission="'question_import'"
>批量导入试题</el-button >批量导入试题</el-button
> >
<el-button <el-button
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
icon="el-icon-plus" icon="el-icon-plus"
@click="handleDelete()" @click="handleDelete()"
:disabled="this.deleteQuestions.length === 0" :disabled="this.deleteQuestions.length === 0"
v-permission="'admin_v1_question_batch_delete'" v-permission="'question_batch_delete'"
>批量删除</el-button >批量删除</el-button
> >
</div> </div>
...@@ -46,20 +46,18 @@ ...@@ -46,20 +46,18 @@
<router-link <router-link
:to="{ path: '/question/editQuestion', query: { id: row.id, type: 'edit' } }" :to="{ path: '/question/editQuestion', query: { id: row.id, type: 'edit' } }"
target="_blank" target="_blank"
v-permission="'admin_v1_question_update'" v-permission="'question_update'"
> >
<el-button type="text">编辑</el-button> <el-button type="text">编辑</el-button>
</router-link> </router-link>
<router-link <router-link
:to="{ path: '/question/questionDetail', query: { id: row.id, type: 'view' } }" :to="{ path: '/question/questionDetail', query: { id: row.id, type: 'view' } }"
target="_blank" target="_blank"
v-permission="'admin_v1_question_detail'" v-permission="'question_detail'"
> >
<el-button type="text">查看详情</el-button> <el-button type="text">查看详情</el-button>
</router-link> </router-link>
<el-button type="text" @click="handleDelete(row.id)" v-permission="'admin_v1_question_batch_delete'" <el-button type="text" @click="handleDelete(row.id)" v-permission="'question_batch_delete'">删除</el-button>
>删除</el-button
>
</template> </template>
</app-list> </app-list>
<import-question :visible.sync="importDialogVisible" /> <import-question :visible.sync="importDialogVisible" />
......
...@@ -6,7 +6,9 @@ Vue.use(Vuex) ...@@ -6,7 +6,9 @@ Vue.use(Vuex)
const store = new Vuex.Store({ const store = new Vuex.Store({
state: { state: {
user: {}, user: {}, // 用户信息
organization: {}, // 机构信息
roles: [], // 角色列表
permissions: [], // 权限列表 permissions: [], // 权限列表
projects: [], // 项目列表 projects: [], // 项目列表
activeProject: {}, // 当前激活的项目 activeProject: {}, // 当前激活的项目
...@@ -16,16 +18,18 @@ const store = new Vuex.Store({ ...@@ -16,16 +18,18 @@ const store = new Vuex.Store({
setUser(state, user) { setUser(state, user) {
state.user = user state.user = user
}, },
setPermissions(state, permissions) { setPermissions(state, data = {}) {
state.permissions = permissions state.permissions = data.permissions || []
}, state.roles = data.roles || []
setProject(state, projects) { state.organization = data.organization || {}
state.projects = projects // 当前激活的项目
const localProjectTag = localStorage.getItem('project_tag')
state.activeProject = localProjectTag ? { tag: localProjectTag } : data.project || {}
}, },
setProjects(state, projects) { setProjects(state, projects) {
state.projects = projects state.projects = projects
}, },
setActiveProjedct(state, project = {}) { setActiveProject(state, project = {}) {
state.activeProject = project state.activeProject = project
localStorage.setItem('project_tag', project.tag || '') localStorage.setItem('project_tag', project.tag || '')
}, },
...@@ -37,13 +41,7 @@ const store = new Vuex.Store({ ...@@ -37,13 +41,7 @@ const store = new Vuex.Store({
// 获取所有项目列表 // 获取所有项目列表
getAllProjects({ commit }) { getAllProjects({ commit }) {
getAllProjects().then(res => { getAllProjects().then(res => {
const projects = res.data const projects = res.data || []
const localProjectTag = localStorage.getItem('project_tag')
// 当前激活的项目
if (localProjectTag) {
const activeProject = projects.find(item => item.tag === localProjectTag) || {}
commit('setActiveProjedct', activeProject)
}
// 所有项目列表 // 所有项目列表
commit('setProjects', projects) commit('setProjects', projects)
}) })
...@@ -80,11 +78,9 @@ const store = new Vuex.Store({ ...@@ -80,11 +78,9 @@ const store = new Vuex.Store({
return isLogin return isLogin
}, },
// 获取所有权限列表 // 获取所有权限列表
async getPermissions({ commit }) { async getPermissions({ commit, state }) {
await getPermissions().then(res => { await getPermissions({ id: state.user.id }).then(res => {
if (res.data && res.data.items) { res.data && commit('setPermissions', res.data)
commit('setPermissions', res.data.items)
}
}) })
}, },
getQuestionCategory({ commit }, params) { getQuestionCategory({ commit }, params) {
...@@ -96,13 +92,4 @@ const store = new Vuex.Store({ ...@@ -96,13 +92,4 @@ const store = new Vuex.Store({
} }
}) })
const localProjectTag = localStorage.getItem('project_tag')
// 当前激活的项目
if (localProjectTag) {
store.commit('setActiveProjedct', { tag: localProjectTag })
}
// 初始化获取项目列表
store.dispatch('getAllProjects')
export default store export default store
...@@ -20,18 +20,17 @@ httpRequest.interceptors.request.use( ...@@ -20,18 +20,17 @@ httpRequest.interceptors.request.use(
// 权限接口单独签名 // 权限接口单独签名
// https://gitlab.ezijing.com/root/api-documents/-/blob/master/ezijing_permissions/%E7%AD%BE%E5%90%8D%E9%AA%8C%E8%AF%81.md // https://gitlab.ezijing.com/root/api-documents/-/blob/master/ezijing_permissions/%E7%AD%BE%E5%90%8D%E9%AA%8C%E8%AF%81.md
if (/^\/api\/permissions/.test(config.url)) { if (/^\/api\/xedu/.test(config.url)) {
// 默认参数 // 默认参数
const defaultHeaders = { const defaultHeaders = {
timestamp: parseInt(Date.now() / 1000), timestamp: parseInt(Date.now() / 1000),
nonce: Math.random().toString(36).slice(-8), nonce: Math.random().toString(36).slice(-8),
'secret-id': import.meta.env.VITE_SECRET_ID, // 'secret-id': import.meta.env.VITE_SECRET_ID,
'secret-key': import.meta.env.VITE_SECRET_KEY, // 'secret-key': import.meta.env.VITE_SECRET_KEY,
signature: 'UG7wBenexQhiuD2wpCwuxkU0jqcj006d' signature: 'UG7wBenexQhiuD2wpCwuxkU0jqcj006d'
} }
config.headers = Object.assign(config.headers, defaultHeaders) config.params = Object.assign(config.params || {}, defaultHeaders)
} }
if (config.headers['Content-Type'] === 'application/x-www-form-urlencoded') { if (config.headers['Content-Type'] === 'application/x-www-form-urlencoded') {
config.data = queryString.stringify(config.data) config.data = queryString.stringify(config.data)
} }
...@@ -53,20 +52,16 @@ httpRequest.interceptors.request.use( ...@@ -53,20 +52,16 @@ httpRequest.interceptors.request.use(
httpRequest.interceptors.response.use( httpRequest.interceptors.response.use(
function (response) { function (response) {
const { data } = response const { data } = response
// 未登录
if (data.code === 4001) {
window.location.href = `${import.meta.env.VITE_LOGIN_URL}?rd=${encodeURIComponent(window.location.href)}`
return Promise.reject(data)
}
// 没有权限
if (data.code === 4008 || data.code === 5018 || data.code === 403) {
router.push('/401')
}
if (data.code) { if (data.code) {
// 未登录
if (data.code === 4001) {
window.location.href = `${import.meta.env.VITE_LOGIN_URL}?rd=${encodeURIComponent(window.location.href)}`
}
// 没有权限
if (data.code === 4008 || data.code === 5018) {
router.push('/401')
}
// 题库分类修改
if (data.code === 403) {
Message({ message: '没有操作权限', type: 'error' })
return data
}
Message({ message: data.message, type: 'error' }) Message({ message: data.message, type: 'error' })
return Promise.reject(data) return Promise.reject(data)
} }
......
...@@ -2,12 +2,12 @@ import store from '@/store' ...@@ -2,12 +2,12 @@ import store from '@/store'
export default async function (to, from, next) { export default async function (to, from, next) {
// 设置project_tag // 设置project_tag
const projectTag = to.query.project_tag || '' // const projectTag = to.query.project_tag || ''
if (projectTag) { // if (projectTag) {
store.commit('setActiveProjedct', { tag: projectTag }) // store.commit('setActiveProject', { tag: projectTag })
} // }
// 登录白名单 // 登录白名单
const whiteList = [] const whiteList = ['/401']
if (whiteList.includes(to.path)) { if (whiteList.includes(to.path)) {
next() next()
return return
......
...@@ -23,7 +23,7 @@ export const questionType = { ...@@ -23,7 +23,7 @@ export const questionType = {
8: '情景题' 8: '情景题'
} }
// 试题类型列表 // 试题类型列表
export const questionTypeList = json2Array(questionType, false) export const questionTypeList = json2Array(questionType)
// 试题难度 // 试题难度
export const questionDifficulty = { export const questionDifficulty = {
...@@ -33,4 +33,4 @@ export const questionDifficulty = { ...@@ -33,4 +33,4 @@ export const questionDifficulty = {
0: '无' 0: '无'
} }
// 试题难度列表 // 试题难度列表
export const questionDifficultyList = json2Array(questionDifficulty, false) export const questionDifficultyList = json2Array(questionDifficulty)
...@@ -23,11 +23,7 @@ export default defineConfig(({ mode }) => { ...@@ -23,11 +23,7 @@ export default defineConfig(({ mode }) => {
cert: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.pem')) cert: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.pem'))
}, },
proxy: { proxy: {
// '/api/qbs': { '/api/xedu': 'https://project-center.ezijing.com',
// target: 'https://question-api.ezijing.com',
// changeOrigin: true,
// rewrite: path => path.replace(/^\/api\/qbs/, '')
// },
// '/api/exam': { // '/api/exam': {
// target: 'https://x-exam-admin-api.ezijing.com', // target: 'https://x-exam-admin-api.ezijing.com',
// // target: 'http://localhost-exam-admin.ezijing.com', // // target: 'http://localhost-exam-admin.ezijing.com',
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论