提交 057e9eb4 authored 作者: 王鹏飞's avatar 王鹏飞

chore: 新增权限控制

上级 09919e27
VITE_LOGIN_URL=https://login.ezijing.com/auth/login/index VITE_LOGIN_URL=https://login.ezijing.com/auth/login/index
VITE_SECRET_ID=ezijing_9e887612acba9afb8ebf137969cc55bb
VITE_SECRET_KEY=26cb02e8fc2c9a2a173498bb60d78fcf
\ No newline at end of file
VITE_LOGIN_URL=https://login.ezijing.com/auth/login/index VITE_LOGIN_URL=https://login.ezijing.com/auth/login/index
VITE_SECRET_ID=ezijing_9e887612acba9afb8ebf137969cc55bb
VITE_SECRET_KEY=26cb02e8fc2c9a2a173498bb60d78fcf
\ No newline at end of file
VITE_LOGIN_URL=https://login2.ezijing.com/auth/login/index VITE_LOGIN_URL=https://login2.ezijing.com/auth/login/index
VITE_SECRET_ID=ezijing_9e887612acba9afb8ebf137969cc55bb
VITE_SECRET_KEY=26cb02e8fc2c9a2a173498bb60d78fcf
\ No newline at end of file
{ {
"name": "qbs", "name": "center-qa",
"version": "0.0.0", "version": "0.0.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
......
...@@ -28,6 +28,13 @@ export function uploadFile(data) { ...@@ -28,6 +28,13 @@ export function uploadFile(data) {
}) })
} }
/**
* 获取权限列表
*/
export function getPermissions(params) {
return httpRequest.get('/api/permissions/api/v1/user/permissions', { params })
}
// 获取可访问的所有项目 // 获取可访问的所有项目
export function getAllProjects() { export function getAllProjects() {
return httpRequest.get('/api/qbs/admin/v1/projects') return httpRequest.get('/api/qbs/admin/v1/projects')
......
...@@ -243,7 +243,14 @@ export default { ...@@ -243,7 +243,14 @@ export default {
padding: 10px 0; padding: 10px 0;
text-align: right; text-align: right;
} }
.el-table-column--selection .cell { .el-table__cell {
padding: 0 14px !important; .el-button + .el-button,
.el-button + a {
margin-left: 10px;
}
a + a,
a + .el-button {
margin-left: 10px;
}
} }
</style> </style>
...@@ -3,13 +3,18 @@ ...@@ -3,13 +3,18 @@
<nav class="nav"> <nav class="nav">
<el-menu :default-active="defaultActive" :router="true"> <el-menu :default-active="defaultActive" :router="true">
<template v-for="item in menuList"> <template v-for="item in menuList">
<el-submenu :index="item.path" :key="item.path" v-if="item.children"> <el-submenu :index="item.path" :key="item.path" v-permission="item.tag" v-if="item.children">
<template #title><i :class="item.icon"></i>{{ item.name }}</template> <template #title><i :class="item.icon"></i>{{ item.name }}</template>
<el-menu-item :index="subitem.path" v-for="subitem in item.children" :key="subitem.path"> <el-menu-item
:index="subitem.path"
v-for="subitem in item.children"
:key="subitem.path"
v-permission="subitem.tag"
>
{{ subitem.name }} {{ subitem.name }}
</el-menu-item> </el-menu-item>
</el-submenu> </el-submenu>
<el-menu-item :index="item.path" :key="item.path" v-else> <el-menu-item :index="item.path" :key="item.path" v-permission="item.tag" v-else>
<i :class="item.icon"></i>{{ item.name }} <i :class="item.icon"></i>{{ item.name }}
</el-menu-item> </el-menu-item>
</template> </template>
...@@ -28,23 +33,26 @@ export default { ...@@ -28,23 +33,26 @@ export default {
name: '试题中心', name: '试题中心',
path: '/question', path: '/question',
icon: 'el-icon-collection', icon: 'el-icon-collection',
tag: 'admin_v1_question',
children: [ children: [
{ name: '新建试题', path: '/question/create' }, { name: '新建试题', path: '/question/create', tag: 'admin_v1_question_create' },
{ name: '我的题库', path: '/question/list' }, { name: '我的题库', path: '/question', tag: 'admin_v1_question_list' },
{ name: '题库分类', path: '/question/classify' } { name: '题库分类', path: '/question/classify', tag: 'admin_v1_question_category' }
] ]
}, },
{ {
name: '试卷中心', name: '试卷中心',
path: '/paper', path: '/paper',
icon: 'el-icon-toilet-paper', icon: 'el-icon-toilet-paper',
children: [{ name: '我的试卷库', path: '/paper' }] tag: 'admin_v1_paper',
children: [{ name: '我的试卷库', path: '/paper', tag: 'admin_v1_paper_list' }]
}, },
{ {
name: '考试中心', name: '考试中心',
path: '/exam', path: '/exam',
icon: 'el-icon-folder-opened', icon: 'el-icon-folder-opened',
children: [{ name: '我的考试', path: '/exam/list' }] tag: 'admin_exam',
children: [{ name: '我的考试', path: '/exam', tag: 'admin_exam_exam_index' }]
} }
] ]
} }
...@@ -59,9 +67,9 @@ export default { ...@@ -59,9 +67,9 @@ export default {
} }
return result return result
}, []) }, [])
const found = flatMenuList.reverse().find(item => { const found =
return this.$route.path.includes(item.path) flatMenuList.find(item => item.path === this.$route.path) ||
}) flatMenuList.find(item => this.$route.path.includes(item.path))
return found ? found.path : '/' return found ? found.path : '/'
} }
} }
......
...@@ -3,6 +3,7 @@ import App from './App.vue' ...@@ -3,6 +3,7 @@ import App from './App.vue'
import router from './router' import router from './router'
import store from './store' import store from './store'
import modules from './modules' import modules from './modules'
import directives from '@/utils/directives'
// 公共css // 公共css
import './assets/css/base.css' import './assets/css/base.css'
...@@ -20,6 +21,9 @@ Vue.use(ElementUI, { size: 'small' }) ...@@ -20,6 +21,9 @@ Vue.use(ElementUI, { size: 'small' })
Vue.component('AppCard', AppCard) Vue.component('AppCard', AppCard)
Vue.component('AppList', AppList) Vue.component('AppList', AppList)
// 注册指令
Vue.use(directives)
// 注册模块 // 注册模块
modules({ router, store }) modules({ router, store })
......
...@@ -18,7 +18,14 @@ ...@@ -18,7 +18,14 @@
<template v-if="questionType === 3"> <template v-if="questionType === 3">
<div class="SAQ">{{ questionData.user_answer[0] || '' }}</div> <div class="SAQ">{{ questionData.user_answer[0] || '' }}</div>
<div style="text-align: right"> <div style="text-align: right">
<el-button type="primary" size="mini" plain @click="showComment = !showComment">点击评分</el-button> <el-button
type="primary"
size="mini"
plain
@click="showComment = !showComment"
v-permission="'admin_exam_exam_submit_sheet'"
>点击评分</el-button
>
</div> </div>
<div class="comment" v-show="showComment"> <div class="comment" v-show="showComment">
<div class="comment-top"> <div class="comment-top">
......
...@@ -5,20 +5,43 @@ ...@@ -5,20 +5,43 @@
<el-dropdown split-button size="small" style="margin-left: 10px; margin-right: 10px; float: right"> <el-dropdown split-button size="small" style="margin-left: 10px; margin-right: 10px; float: right">
操作 操作
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="editExamInfo">考试信息编辑</el-dropdown-item> <el-dropdown-item @click.native="editExamInfo" v-permission="'admin_exam_exam_update'"
<el-dropdown-item @click.native="editExam">考试试卷编辑</el-dropdown-item> >考试信息编辑</el-dropdown-item
<el-dropdown-item @click.native="editInfo">信息采集编辑</el-dropdown-item> >
<el-dropdown-item @click.native="editExamSetting">考试配置编辑</el-dropdown-item> <el-dropdown-item @click.native="editExam" v-permission="'admin_exam_exam_update'"
<el-dropdown-item @click.native="copyExamUrl">复制考试地址</el-dropdown-item> >考试试卷编辑</el-dropdown-item
<el-dropdown-item @click.native="dialogVisible = true" :disabled="this.multipleSelection.length === 0" >
<el-dropdown-item @click.native="editInfo" v-permission="'admin_exam_exam_update'"
>信息采集编辑</el-dropdown-item
>
<el-dropdown-item @click.native="editExamSetting" v-permission="'admin_exam_exam_update'"
>考试配置编辑</el-dropdown-item
>
<el-dropdown-item @click.native="copyExamUrl" v-permission="'admin_exam_exam_update'"
>复制考试地址</el-dropdown-item
>
<el-dropdown-item
@click.native="dialogVisible = true"
:disabled="this.multipleSelection.length === 0"
v-permission="'admin_exam_exam_transfer_student'"
>转移考生</el-dropdown-item >转移考生</el-dropdown-item
> >
<el-dropdown-item @click.native="exportDetail">导出明细</el-dropdown-item> <el-dropdown-item @click.native="exportDetail" v-permission="'admin_exam_exam_download_details'"
<el-dropdown-item @click.native="delStudent" :disabled="this.multipleSelection.length === 0" >导出明细</el-dropdown-item
>
<el-dropdown-item
@click.native="delStudent"
:disabled="this.multipleSelection.length === 0"
v-permission="'admin_exam_student_delete'"
>删除考生</el-dropdown-item >删除考生</el-dropdown-item
> >
<el-dropdown-item @click.native="handleAddStudent">添加考生</el-dropdown-item> <el-dropdown-item @click.native="handleAddStudent" v-permission="'admin_exam_exam_add_student'"
<el-dropdown-item @click.native="sendMessage" :disabled="this.multipleSelection.length === 0" >添加考生</el-dropdown-item
>
<el-dropdown-item
@click.native="sendMessage"
:disabled="this.multipleSelection.length === 0"
v-permission="'admin_exam_exam_send_msg'"
>发送成绩信息</el-dropdown-item >发送成绩信息</el-dropdown-item
> >
</el-dropdown-menu> </el-dropdown-menu>
...@@ -26,11 +49,9 @@ ...@@ -26,11 +49,9 @@
</div> </div>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<router-link <router-link
:to="{ :to="{ path: 'markingPaper', query: { eid: exam_id, sid: row.student_id } }"
path: 'markingPaper',
query: { eid: exam_id, sid: row.student_id }
}"
target="_blank" target="_blank"
v-permission="'admin_exam_exam_sheet_detail'"
> >
<el-button type="text">查看详情</el-button> <el-button type="text">查看详情</el-button>
</router-link> </router-link>
...@@ -142,7 +163,7 @@ export default { ...@@ -142,7 +163,7 @@ export default {
{ label: '参考时间', prop: 'exam_begin_time' }, { label: '参考时间', prop: 'exam_begin_time' },
{ label: '考中异常', prop: 'exam_error' }, { label: '考中异常', prop: 'exam_error' },
{ label: '成绩', prop: 'sheet.score' }, { label: '成绩', prop: 'sheet.score' },
{ label: '操作', slots: 'table-x', align: 'right', width: 150 } { label: '操作', slots: 'table-x', align: 'right', width: 100 }
], ],
limit: 20 limit: 20
} }
...@@ -168,17 +189,11 @@ export default { ...@@ -168,17 +189,11 @@ export default {
copyDom.value = 'https://x-exam.ezijing.com/' + 'login/' + this.exam_id copyDom.value = 'https://x-exam.ezijing.com/' + 'login/' + this.exam_id
copyDom.select() // 选择对象 copyDom.select() // 选择对象
document.execCommand('Copy') document.execCommand('Copy')
this.$message({ this.$message({ message: '复制成功!', type: 'success' })
message: '复制成功!',
type: 'success'
})
}, },
// 添加考生 // 添加考生
handleAddStudent() { handleAddStudent() {
this.$router.push({ this.$router.push({ path: 'createStudent', query: { id: this.exam_id } })
path: 'createStudent',
query: { id: this.exam_id }
})
}, },
// 考试信息编辑 // 考试信息编辑
editExamInfo() { editExamInfo() {
...@@ -195,20 +210,14 @@ export default { ...@@ -195,20 +210,14 @@ export default {
editInfo() { editInfo() {
this.$router.push({ this.$router.push({
path: 'personalInfo', path: 'personalInfo',
query: { query: { exam_id: this.exam_id, isEdit: '2' }
exam_id: this.exam_id,
isEdit: '2'
}
}) })
}, },
// 考试配置编辑 // 考试配置编辑
editExamSetting() { editExamSetting() {
this.$router.push({ this.$router.push({
path: 'examSetting', path: 'examSetting',
query: { query: { exam_id: this.exam_id, isEdit: '2' }
exam_id: this.exam_id,
isEdit: '2'
}
}) })
}, },
// 删除考生 // 删除考生
......
...@@ -2,13 +2,15 @@ ...@@ -2,13 +2,15 @@
<app-card> <app-card>
<app-list v-bind="tableOptions" ref="list"> <app-list v-bind="tableOptions" ref="list">
<template #header-aside> <template #header-aside>
<el-button type="primary" icon="el-icon-plus" @click="handleCreatePaper">新建试卷</el-button> <el-button type="primary" icon="el-icon-plus" @click="handleCreatePaper" v-permission="'admin_exam_exam_create'"
>新建考试</el-button
>
</template> </template>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<router-link :to="{ path: 'examDetail', query: { exam_id: row.exam_id } }" target="_blank"> <router-link :to="{ path: 'examDetail', query: { exam_id: row.exam_id } }" target="_blank">
<el-button type="text">查看详情</el-button> <el-button type="text" v-permission="'admin_exam_exam_view'">查看详情</el-button>
</router-link> </router-link>
<el-button type="text" @click="handleDelete(row)">删除</el-button> <el-button type="text" @click="handleDelete(row)" v-permission="'admin_exam_exam_delete'">删除</el-button>
</template> </template>
</app-list> </app-list>
</app-card> </app-card>
...@@ -93,7 +95,7 @@ export default { ...@@ -93,7 +95,7 @@ export default {
} }
}, },
methods: { methods: {
// 新建试卷 // 新建考试
handleCreatePaper() { handleCreatePaper() {
this.$router.push({ this.$router.push({
path: 'newExam', path: 'newExam',
......
...@@ -16,7 +16,11 @@ export default { ...@@ -16,7 +16,11 @@ export default {
methods: { methods: {
handleClick(item) { handleClick(item) {
this.$store.commit('setActiveProjedct', item) this.$store.commit('setActiveProjedct', item)
this.$router.push({ path: '/', query: { project_tag: item.tag } }) // 重新获取权限
this.$store.dispatch('getPermissions').then(() => {
// 跳转到首页
this.$router.push({ path: '/', query: { project_tag: item.tag } })
})
} }
} }
} }
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
<!-- 组卷题库 --> <!-- 组卷题库 -->
<el-form-item label="组卷题库:"> <el-form-item label="组卷题库:">
<el-radio-group v-model="form.permission"> <el-radio-group v-model="form.permission">
<el-radio label="1">我的题库</el-radio> <el-radio label="1" v-permission="'button_question_permission_my'">我的题库</el-radio>
<el-radio label="2">公共题库</el-radio> <el-radio label="2" v-permission="'button_question_permission_public'">公共题库</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<!-- 自动组卷规则 --> <!-- 自动组卷规则 -->
......
...@@ -6,13 +6,17 @@ ...@@ -6,13 +6,17 @@
<app-card title="试题列表"> <app-card title="试题列表">
<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">添加试题</el-button> <el-button type="primary" @click="showSelectQuestion" v-permission="'admin_v1_question_paper_rules'"
>添加试题</el-button
>
<el-button type="primary" :disabled="!multipleSelection.length" @click="handleRemove" <el-button type="primary" :disabled="!multipleSelection.length" @click="handleRemove"
>删除选中试题</el-button >删除选中试题</el-button
> >
</template> </template>
<template v-if="data.paper_type === 2"> <template v-if="data.paper_type === 2">
<el-button type="primary" @click="handleAutoPaper">自动组卷</el-button> <el-button type="primary" @click="handleAutoPaper" v-permission="'admin_v1_question_paper_rules'"
>自动组卷</el-button
>
</template> </template>
</template> </template>
<question-list <question-list
...@@ -47,7 +51,9 @@ ...@@ -47,7 +51,9 @@
</template> </template>
<template #footer> <template #footer>
<template v-if="data.paper_type === 1"> <template v-if="data.paper_type === 1">
<el-button type="primary" @click="handleSubmit">保存试卷</el-button> <el-button type="primary" @click="handleSubmit" v-permission="'admin_v1_question_paper_rules'"
>保存试卷</el-button
>
</template> </template>
</template> </template>
</question-num> </question-num>
......
...@@ -2,12 +2,20 @@ ...@@ -2,12 +2,20 @@
<div> <div>
<div style="margin-bottom: 25px"> <div style="margin-bottom: 25px">
<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">我的题库</el-radio> <el-radio @change="refetchList" v-model="permission" :label="1" v-permission="'button_question_permission_my'"
<el-radio @change="refetchList" v-model="permission" :label="2">公共题库</el-radio> >我的题库</el-radio
>
<el-radio @change="refetchList" v-model="permission" :label="2" v-permission="'button_question_permission_public'"
>公共题库</el-radio
>
</div> </div>
<app-list v-bind="tableOptions" ref="list" v-on="$listeners"> <app-list v-bind="tableOptions" ref="list" v-on="$listeners">
<template v-slot:filter-category="{ params }"> <template v-slot:filter-category="{ params }">
<question-type-treeselect v-model="params.question_category" @change="refetchList"></question-type-treeselect> <question-type-treeselect
multiple
v-model="params.question_categories"
@change="refetchList"
></question-type-treeselect>
</template> </template>
</app-list> </app-list>
</div> </div>
...@@ -36,7 +44,7 @@ export default { ...@@ -36,7 +44,7 @@ export default {
question_type: '', question_type: '',
question_title: '', question_title: '',
question_difficulty: '', question_difficulty: '',
question_category: '' question_categories: []
} }
}, },
filters: [ filters: [
...@@ -73,7 +81,7 @@ export default { ...@@ -73,7 +81,7 @@ export default {
label: '难度等级' label: '难度等级'
}, },
{ {
prop: 'question_category', prop: 'question_categories',
label: '试题分类', label: '试题分类',
slots: 'filter-category' slots: 'filter-category'
}, },
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<!-- 试卷描述 --> <!-- 试卷描述 -->
<app-card title="试卷信息"> <app-card title="试卷信息">
<template #header-aside> <template #header-aside>
<el-button type="primary" @click="handleUpdate">编辑试卷</el-button> <el-button type="primary" @click="handleUpdate" v-permission="'admin_v1_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>
......
...@@ -2,20 +2,41 @@ ...@@ -2,20 +2,41 @@
<app-card> <app-card>
<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">新建试卷</el-button> <el-button type="primary" icon="el-icon-plus" @click="handleCreate" v-permission="'admin_v1_paper_create'"
<el-button type="primary" icon="el-icon-delete" :disabled="!multipleSelection.length" @click="handleBatchDelete" >新建试卷</el-button
>
<el-button
type="primary"
icon="el-icon-delete"
:disabled="!multipleSelection.length"
@click="handleBatchDelete"
v-permission="'admin_v1_paper_batch_delete'"
>批量删除</el-button >批量删除</el-button
> >
</div> </div>
<template v-slot:filter-category="{ params }"> <template v-slot:filter-category="{ params }">
<question-type-treeselect v-model="params.paper_category" @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 }">
<el-button type="text" @click="handleUpdate(row)">编辑</el-button> <router-link
<router-link :to="{ name: 'viewPaper', params: { id: row.id } }" target="_blank"> :to="{ name: 'editPaper', params: { id: row.id } }"
target="_blank"
v-permission="'admin_v1_paper_update'"
>
<el-button type="text">编辑</el-button>
</router-link>
<router-link
:to="{ name: 'viewPaper', params: { id: row.id } }"
target="_blank"
v-permission="'admin_v1_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)">删除</el-button> <el-button type="text" @click="handleDelete(row)" v-permission="'admin_v1_paper_batch_delete'">删除</el-button>
</template> </template>
</app-list> </app-list>
</app-card> </app-card>
...@@ -51,7 +72,7 @@ export default { ...@@ -51,7 +72,7 @@ export default {
paper_title: '', paper_title: '',
paper_type: '', paper_type: '',
paper_labels: '', paper_labels: '',
paper_category: '' paper_categories: []
} }
}, },
filters: [ filters: [
...@@ -77,7 +98,7 @@ export default { ...@@ -77,7 +98,7 @@ export default {
label: '标签:' label: '标签:'
}, },
{ {
prop: 'paper_category', prop: 'paper_categories',
label: '试卷分类:', label: '试卷分类:',
slots: 'filter-category' slots: 'filter-category'
} }
......
...@@ -10,8 +10,12 @@ ...@@ -10,8 +10,12 @@
class="demo-ruleForm" class="demo-ruleForm"
> >
<el-form-item label="题库范围" prop="permission"> <el-form-item label="题库范围" prop="permission">
<el-radio v-model="ruleForm.permission" label="1">我的题库</el-radio> <el-radio v-model="ruleForm.permission" label="1" v-permission="'button_question_permission_my'"
<el-radio v-model="ruleForm.permission" label="2">公共题库</el-radio> >我的题库</el-radio
>
<el-radio v-model="ruleForm.permission" label="2" v-permission="'button_question_permission_public'"
>公共题库</el-radio
>
</el-form-item> </el-form-item>
<el-form-item label="题目类型" prop="question_type"> <el-form-item label="题目类型" prop="question_type">
<el-select <el-select
......
...@@ -13,8 +13,12 @@ ...@@ -13,8 +13,12 @@
class="demo-ruleForm" class="demo-ruleForm"
> >
<el-form-item label="题库范围" prop="permission"> <el-form-item label="题库范围" prop="permission">
<el-radio v-model="ruleForm.permission" label="1">我的题库</el-radio> <el-radio v-model="ruleForm.permission" label="1" v-permission="'button_question_permission_my'"
<el-radio v-model="ruleForm.permission" label="2">公共题库</el-radio> >我的题库</el-radio
>
<el-radio v-model="ruleForm.permission" label="2" v-permission="'button_question_permission_public'"
>公共题库</el-radio
>
</el-form-item> </el-form-item>
<el-form-item label="题目类型" prop="question_type"> <el-form-item label="题目类型" prop="question_type">
<el-select <el-select
......
...@@ -75,9 +75,7 @@ export default { ...@@ -75,9 +75,7 @@ export default {
this.$refs.upload.submit() this.$refs.upload.submit()
}, },
cancel() { cancel() {
this.$router.push({ this.$emit('update:visible', false)
name: 'teacher'
})
} }
} }
} }
......
...@@ -6,8 +6,20 @@ ...@@ -6,8 +6,20 @@
<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 type="text" size="mini" @click="() => append(data)"> 添加子项 </el-button> <el-button
<el-button type="text" size="mini" @click="() => edit(data)"> 修改名称 </el-button> type="text"
size="mini"
@click="() => append(data)"
v-permission="'admin_v1_qustion_category_add'"
>添加子项</el-button
>
<el-button
type="text"
size="mini"
@click="() => edit(data)"
v-permission="'admin_v1_question_category_update'"
>修改名称</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> -->
</span> </span>
</span> </span>
......
...@@ -2,35 +2,64 @@ ...@@ -2,35 +2,64 @@
<app-card> <app-card>
<div style="margin-bottom: 25px"> <div style="margin-bottom: 25px">
<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">我的题库</el-radio> <el-radio @change="refetchList" v-model="permission" :label="1" v-permission="'button_question_permission_my'"
<el-radio @change="refetchList" v-model="permission" :label="2">公共题库</el-radio> >我的题库</el-radio
>
<el-radio @change="refetchList" v-model="permission" :label="2" v-permission="'button_question_permission_public'"
>公共题库</el-radio
>
</div> </div>
<app-list v-bind="tableOptions" ref="list" @selection-change="handleSelectionChange"> <app-list v-bind="tableOptions" ref="list" @selection-change="handleSelectionChange">
<template v-slot:filter-category="{ params }"> <template v-slot:filter-category="{ params }">
<question-type-cascader v-model="params.question_category" @change="refetchList"></question-type-cascader> <question-type-cascader
multiple
v-model="params.question_categories"
@change="refetchList"
></question-type-cascader>
</template> </template>
<div class="operate-btn"> <div class="operate-btn">
<el-button type="primary" icon="el-icon-plus" @click="$router.push({ path: '/question/create' })" <el-button
type="primary"
icon="el-icon-plus"
@click="$router.push({ path: '/question/create' })"
v-permission="'admin_v1_question_create'"
>新建试题</el-button >新建试题</el-button
> >
<el-button type="primary" icon="el-icon-plus" @click="importDialogVisible = true">批量导入试题</el-button> <el-button
type="primary"
icon="el-icon-plus"
@click="importDialogVisible = true"
v-permission="'admin_v1_question_import'"
>批量导入试题</el-button
>
<el-button <el-button
type="primary" type="primary"
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'"
>批量删除</el-button >批量删除</el-button
> >
</div> </div>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<router-link :to="{ path: '/question/editQuestion', query: { id: row.id, type: 'edit' } }" target="_blank"> <router-link
:to="{ path: '/question/editQuestion', query: { id: row.id, type: 'edit' } }"
target="_blank"
v-permission="'admin_v1_question_update'"
>
<el-button type="text">编辑</el-button> <el-button type="text">编辑</el-button>
</router-link> </router-link>
<router-link :to="{ path: '/question/questionDetail', query: { id: row.id, type: 'view' } }" target="_blank"> <router-link
:to="{ path: '/question/questionDetail', query: { id: row.id, type: 'view' } }"
target="_blank"
v-permission="'admin_v1_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)">删除</el-button> <el-button type="text" @click="handleDelete(row.id)" v-permission="'admin_v1_question_batch_delete'"
>删除</el-button
>
</template> </template>
</app-list> </app-list>
<import-question :visible.sync="importDialogVisible" /> <import-question :visible.sync="importDialogVisible" />
...@@ -99,7 +128,7 @@ export default { ...@@ -99,7 +128,7 @@ export default {
}, },
{ {
slots: 'filter-category', slots: 'filter-category',
prop: 'question_category', prop: 'question_categories',
type: 'input', type: 'input',
label: '试题分类:' label: '试题分类:'
}, },
...@@ -117,7 +146,7 @@ export default { ...@@ -117,7 +146,7 @@ export default {
question_content: '', question_content: '',
permission: this.permission, permission: this.permission,
project_prefix: this.activeProject.tag, project_prefix: this.activeProject.tag,
question_category: '' question_categories: []
}, },
callback(data) { callback(data) {
const questionType = { const questionType = {
......
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import { getUser, logout, getAllProjects, getQuestionCategory } from '@/api/base' import { getUser, logout, getPermissions, getAllProjects, getQuestionCategory } from '@/api/base'
Vue.use(Vuex) Vue.use(Vuex)
const store = new Vuex.Store({ const store = new Vuex.Store({
state: { state: {
user: {}, user: {},
permissions: [], // 权限列表
projects: [], // 项目列表 projects: [], // 项目列表
activeProject: {}, // 当前激活的项目 activeProject: {}, // 当前激活的项目
questionCategory: [] // 试题分类 questionCategory: [] // 试题分类
...@@ -15,6 +16,9 @@ const store = new Vuex.Store({ ...@@ -15,6 +16,9 @@ const store = new Vuex.Store({
setUser(state, user) { setUser(state, user) {
state.user = user state.user = user
}, },
setPermissions(state, permissions) {
state.permissions = permissions
},
setProject(state, projects) { setProject(state, projects) {
state.projects = projects state.projects = projects
}, },
...@@ -57,7 +61,7 @@ const store = new Vuex.Store({ ...@@ -57,7 +61,7 @@ const store = new Vuex.Store({
return response return response
}) })
}, },
async checkLogin({ commit }) { async checkLogin({ commit, dispatch }) {
const isLogin = await getUser() const isLogin = await getUser()
.then(response => { .then(response => {
if (response.code === 0) { if (response.code === 0) {
...@@ -72,8 +76,17 @@ const store = new Vuex.Store({ ...@@ -72,8 +76,17 @@ const store = new Vuex.Store({
commit('setUser', {}) commit('setUser', {})
return false return false
}) })
await dispatch('getPermissions')
return isLogin return isLogin
}, },
// 获取所有权限列表
async getPermissions({ commit }) {
await getPermissions().then(res => {
if (res.data && res.data.items) {
commit('setPermissions', res.data.items)
}
})
},
getQuestionCategory({ commit }, params) { getQuestionCategory({ commit }, params) {
return getQuestionCategory(params).then(res => { return getQuestionCategory(params).then(res => {
commit('setQuestionCategory', res.data) commit('setQuestionCategory', res.data)
......
...@@ -18,15 +18,19 @@ httpRequest.interceptors.request.use( ...@@ -18,15 +18,19 @@ httpRequest.interceptors.request.use(
config.params = Object.assign({ project_prefix: store.state.activeProject?.tag }, config.params) config.params = Object.assign({ project_prefix: store.state.activeProject?.tag }, config.params)
config.data = Object.assign({ project_prefix: store.state.activeProject?.tag }, config.data) config.data = Object.assign({ project_prefix: store.state.activeProject?.tag }, config.data)
// 默认参数 // 权限接口单独签名
const defaultHeaders = { // https://gitlab.ezijing.com/root/api-documents/-/blob/master/ezijing_permissions/%E7%AD%BE%E5%90%8D%E9%AA%8C%E8%AF%81.md
timestamp: parseInt(Date.now() / 1000), if (/^\/api\/permissions/.test(config.url)) {
nonce: Math.random().toString(36).slice(-8), // 默认参数
'secret-id': 'ezijing_20200410', const defaultHeaders = {
'secret-key': 'THIxz9hfbMDD5pil', timestamp: parseInt(Date.now() / 1000),
signature: 'UG7wBenexQhiuD2wpCwuxkU0jqcj006d' nonce: Math.random().toString(36).slice(-8),
'secret-id': import.meta.env.VITE_SECRET_ID,
'secret-key': import.meta.env.VITE_SECRET_KEY,
signature: 'UG7wBenexQhiuD2wpCwuxkU0jqcj006d'
}
config.headers = Object.assign(config.headers, defaultHeaders)
} }
config.headers = Object.assign(config.headers, 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)
......
import store from '@/store'
function checkPermission(el, binding) {
const { value } = binding
if (!value) return
const permissions = store.state.permissions || []
let hasPermission = false
if (Array.isArray(value)) {
hasPermission = permissions.some(item => value.includes(item.tag))
} else {
hasPermission = !!permissions.find(item => item.tag === value)
}
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el)
}
}
// 判断是否有权限
export default Vue => {
Vue.directive('permission', { inserted: checkPermission, update: checkPermission })
}
...@@ -23,18 +23,17 @@ export default defineConfig(({ mode }) => { ...@@ -23,18 +23,17 @@ 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/qbs': {
target: 'https://question-api.ezijing.com', // target: 'https://question-api.ezijing.com',
changeOrigin: true, // changeOrigin: true,
rewrite: path => path.replace(/^\/api\/qbs/, '') // 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',
changeOrigin: true, // rewrite: path => path.replace(/^\/api\/exam/, '')
rewrite: path => path.replace(/^\/api\/exam/, '') // },
}, '/api': 'https://qa-center.ezijing.com'
'/api': 'https://app.ezijing.com'
} }
}, },
resolve: { resolve: {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论