:feat:新增 考试人员导出功能
This commit is contained in:
parent
9222e2ecdf
commit
8e6e0d4c93
File diff suppressed because one or more lines are too long
|
@ -27,7 +27,7 @@ export function getQi(id) {
|
||||||
|
|
||||||
export function updateQi(id, data) {
|
export function updateQi(id, data) {
|
||||||
return request({
|
return request({
|
||||||
url: `/info/faq/${id}/`,
|
url: `/info/faqch/${id}/`,
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
|
|
|
@ -14,6 +14,14 @@ export function getRoleAll() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getRoleList(params) {
|
||||||
|
return request({
|
||||||
|
url: '/system/role/',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function createRole(data) {
|
export function createRole(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/role/',
|
url: '/system/role/',
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
|
||||||
|
export function getUserList(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/userexam/',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function createUser(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/userexam/',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateUser(id, data) {
|
||||||
|
return request({
|
||||||
|
url: `/system/userexam/${id}/`,
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function deleteUserExam(id, data) {
|
||||||
|
return request({
|
||||||
|
url: `/system/userexam/${id}/`,
|
||||||
|
method: 'delete',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetUserpw(id) {
|
||||||
|
return request({
|
||||||
|
url: `/system/user/${id}/resetpw/`,
|
||||||
|
method: 'put',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changePassword(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/password/',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
|
@ -559,20 +559,20 @@ export const asyncRoutes = [
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/exam/questions',
|
redirect: '/exam/questions',
|
||||||
name: 'exam',
|
name: 'exam',
|
||||||
meta: { title: '考试', icon: 'PT', perms: ['pt_view'] },
|
meta: { title: '考试', icon: 'Exam', perms: ['Exam'] },
|
||||||
alwaysShow: true,
|
alwaysShow: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'classify',
|
path: 'classify',
|
||||||
name: '题目分类',
|
name: '题目分类',
|
||||||
component: () => import('@/views/exam/classify.vue'),
|
component: () => import('@/views/exam/classify.vue'),
|
||||||
meta: { title: '题目分类', perms: ['pt_view'] }
|
meta: { title: '题目分类', perms: ['CateQues'] }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'questions',
|
path: 'questions',
|
||||||
name: '题目列表',
|
name: '题目列表',
|
||||||
component: () => import('@/views/exam/questions.vue'),
|
component: () => import('@/views/exam/questions.vue'),
|
||||||
meta: { title: '题目列表', perms: ['pt_view'] }
|
meta: { title: '题目列表', perms: ['CateQues'] }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'questionCreate',
|
path: 'questionCreate',
|
||||||
|
@ -592,7 +592,7 @@ export const asyncRoutes = [
|
||||||
path: 'testPaper',
|
path: 'testPaper',
|
||||||
name: '考试试卷',
|
name: '考试试卷',
|
||||||
component: () => import('@/views/exam/testPaper.vue'),
|
component: () => import('@/views/exam/testPaper.vue'),
|
||||||
meta: { title: '考试试卷', perms: ['pt_view'] }
|
meta: { title: '考试试卷', perms: ['Paper'] }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'paperCreate',
|
path: 'paperCreate',
|
||||||
|
@ -612,13 +612,19 @@ export const asyncRoutes = [
|
||||||
path: 'index',
|
path: 'index',
|
||||||
name: '考试',
|
name: '考试',
|
||||||
component: () => import('@/views/exam/index.vue'),
|
component: () => import('@/views/exam/index.vue'),
|
||||||
meta: { title: '考试', perms: ['pt_view'] }
|
meta: { title: '考试', perms: ['Paper'] }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'record',
|
path: 'record',
|
||||||
name: '考试记录',
|
name: '考试记录',
|
||||||
component: () => import('@/views/exam/examRecord.vue'),
|
component: () => import('@/views/exam/examRecord.vue'),
|
||||||
meta: { title: '考试记录', perms: ['pt_view'] }
|
meta: { title: '考试记录', perms: ['RecordExam'] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'userExam',
|
||||||
|
name: '用户考试管理',
|
||||||
|
component: () => import('@/views/system/userExam.vue'),
|
||||||
|
meta: { title: '用户考试管理', perms: ['UserExam'] }
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -25,11 +25,11 @@
|
||||||
<el-table-column label="变更日期" prop="change_date"></el-table-column>
|
<el-table-column label="变更日期" prop="change_date"></el-table-column>
|
||||||
<el-table-column align="center" label="操作" width="120px" fixed="right">
|
<el-table-column align="center" label="操作" width="120px" fixed="right">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-link :disabled="!checkPermission(['infoCollect_QIN'])" type="primary" size="small"
|
<el-link type="primary" size="small"
|
||||||
@click="handleEdit(scope)">编辑</el-link>
|
@click="handleEdit(scope)">编辑</el-link>
|
||||||
<el-divider direction="vertical"
|
<el-divider direction="vertical"
|
||||||
v-if="checkPermission(['infoCollect_QIN']) && checkPermission(['infoCollect_QIN'])"></el-divider>
|
></el-divider>
|
||||||
<el-link :disabled="!checkPermission(['infoCollect_QIN'])" type="danger" size="small"
|
<el-link type="danger" size="small"
|
||||||
@click="handleDelete(scope)">删除</el-link>
|
@click="handleDelete(scope)">删除</el-link>
|
||||||
<!-- <el-link type="primary" @click="handleChange(scope)">变更记录</el-link> -->
|
<!-- <el-link type="primary" @click="handleChange(scope)">变更记录</el-link> -->
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -0,0 +1,500 @@
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<el-row :gutter="6">
|
||||||
|
<el-col :xs="24" :md="6">
|
||||||
|
<el-card >
|
||||||
|
<div slot="header" class="clearfix">
|
||||||
|
<span>部门</span>
|
||||||
|
</div>
|
||||||
|
<el-input v-model="filterOrgText" placeholder="输入部门名进行过滤" />
|
||||||
|
<el-tree
|
||||||
|
ref="tree"
|
||||||
|
v-loading="treeLoding"
|
||||||
|
class="filter-tree"
|
||||||
|
:data="orgData"
|
||||||
|
default-expand-all
|
||||||
|
highlight-current
|
||||||
|
:expand-on-click-node="false"
|
||||||
|
:filter-node-method="filterNode"
|
||||||
|
style="margin-top: 10px;max-height:650px;overflow-y: auto;"
|
||||||
|
@node-click="handleOrgClick"
|
||||||
|
/>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="24" :md="18">
|
||||||
|
<el-card>
|
||||||
|
<div slot="header" class="clearfix">
|
||||||
|
<span>用户</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-select
|
||||||
|
v-model="listQuery.is_active"
|
||||||
|
placeholder="状态"
|
||||||
|
clearable
|
||||||
|
style="width: 90px"
|
||||||
|
class="filter-item"
|
||||||
|
@change="handleFilter"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in enabledOptions"
|
||||||
|
:key="item.key"
|
||||||
|
:label="item.display_name"
|
||||||
|
:value="item.key"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<el-select
|
||||||
|
v-model="listQuery.roles"
|
||||||
|
placeholder="角色"
|
||||||
|
style="width: 90px"
|
||||||
|
class="filter-item"
|
||||||
|
@change="handleFilter"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in roles"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<el-input
|
||||||
|
v-model="listQuery.search"
|
||||||
|
placeholder="姓名/邮箱"
|
||||||
|
style="width: 200px"
|
||||||
|
class="filter-item"
|
||||||
|
@keyup.enter.native="handleFilter"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
class="filter-item"
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-search"
|
||||||
|
@click="handleFilter"
|
||||||
|
>搜索</el-button>
|
||||||
|
<el-button
|
||||||
|
class="filter-item"
|
||||||
|
style="margin-left: 10px"
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-refresh-left"
|
||||||
|
@click="resetFilter"
|
||||||
|
>重置</el-button>
|
||||||
|
<!-- <el-button
|
||||||
|
class="filter-item"
|
||||||
|
style="margin-left: 10px"
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-download"
|
||||||
|
@click="exportExcel"
|
||||||
|
:loading="listLoading"
|
||||||
|
>导出</el-button> -->
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 10px">
|
||||||
|
<el-button type="primary" icon="el-icon-plus" @click="handleAddUser"
|
||||||
|
>新增</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<el-table
|
||||||
|
v-loading="listLoading"
|
||||||
|
:data="userList.results"
|
||||||
|
style="width: 100%; margin-top: 10px"
|
||||||
|
border
|
||||||
|
fit
|
||||||
|
stripe
|
||||||
|
highlight-current-row
|
||||||
|
max-height="600"
|
||||||
|
>
|
||||||
|
<el-table-column type="index" width="50" />
|
||||||
|
<el-table-column align="center" label="姓名">
|
||||||
|
<template slot-scope="scope">{{ scope.row.name }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="header-center" label="账户">
|
||||||
|
<template slot-scope="scope">{{ scope.row.username }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="header-center" label="部门">
|
||||||
|
<template v-if="scope.row.dept_name != null" slot-scope="scope">{{
|
||||||
|
scope.row.dept_name
|
||||||
|
}}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="header-center" label="角色">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag
|
||||||
|
style="margin: 2px"
|
||||||
|
effect="plain"
|
||||||
|
v-for="(item, index) in scope.row.roles_"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="创建日期">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ scope.row.date_joined }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
align="center"
|
||||||
|
label="操作"
|
||||||
|
width="200px"
|
||||||
|
fixed="right"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button
|
||||||
|
v-if="checkPermission(['admin'])"
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
@click="handeReset(scope)"
|
||||||
|
>重置密码</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
:disabled="!checkPermission(['user_exam_create'])"
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
icon="el-icon-edit"
|
||||||
|
@click="handleEdit(scope)"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
v-if="!scope.row.is_superuser"
|
||||||
|
:disabled="!checkPermission(['user_exam_delete'])"
|
||||||
|
type="danger"
|
||||||
|
size="small"
|
||||||
|
icon="el-icon-delete"
|
||||||
|
@click="handleDelete(scope)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination
|
||||||
|
v-show="userList.count > 0"
|
||||||
|
:total="userList.count"
|
||||||
|
:page.sync="listQuery.page"
|
||||||
|
:limit.sync="listQuery.page_size"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
:visible.sync="dialogVisible"
|
||||||
|
:title="dialogType === 'edit' ? '编辑用户' : '新增用户'"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="Form"
|
||||||
|
:model="user"
|
||||||
|
label-width="80px"
|
||||||
|
label-position="right"
|
||||||
|
:rules="rule1"
|
||||||
|
>
|
||||||
|
<el-form-item label="姓名" prop="name">
|
||||||
|
<el-input v-model="user.name" placeholder="姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="账户" prop="username">
|
||||||
|
<el-input v-model="user.username" placeholder="账户" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所属部门" prop="dept">
|
||||||
|
<treeselect
|
||||||
|
v-model="user.dept"
|
||||||
|
:multiple="false"
|
||||||
|
:options="orgData"
|
||||||
|
placeholder="所属部门"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="角色" prop="roles">
|
||||||
|
<el-select
|
||||||
|
v-model="user.roles"
|
||||||
|
multiple
|
||||||
|
placeholder="请选择"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in roles"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="头像" prop="dept">
|
||||||
|
<el-upload
|
||||||
|
class="avatar-uploader"
|
||||||
|
:action="upUrl"
|
||||||
|
accept="image/jpeg, image/gif, image/png, image/bmp"
|
||||||
|
:show-file-list="false"
|
||||||
|
:on-success="handleAvatarSuccess"
|
||||||
|
:before-upload="beforeAvatarUpload"
|
||||||
|
:headers="upHeaders"
|
||||||
|
>
|
||||||
|
<img v-if="user.avatar" :src="user.avatar" class="avatar" />
|
||||||
|
<i v-else class="el-icon-plus avatar-uploader-icon" />
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div style="text-align: right">
|
||||||
|
<el-button type="danger" @click="dialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirm('Form')">确认</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style>
|
||||||
|
.avatar-uploader .el-upload {
|
||||||
|
border: 1px dashed #d9d9d9;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.avatar-uploader .el-upload:hover {
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
.avatar-uploader-icon {
|
||||||
|
font-size: 28px;
|
||||||
|
color: #8c939d;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
line-height: 100px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
getUserList,
|
||||||
|
createUser,
|
||||||
|
deleteUserExam,
|
||||||
|
updateUser,
|
||||||
|
resetUserpw,
|
||||||
|
} from "@/api/userexam";
|
||||||
|
import { getSubOrgList } from "@/api/org";
|
||||||
|
import { getRoleList } from "@/api/role";
|
||||||
|
import { genTree } from "@/utils";
|
||||||
|
import checkPermission from "@/utils/permission";
|
||||||
|
import { upUrl, upHeaders } from "@/api/file";
|
||||||
|
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
|
||||||
|
import Treeselect from "@riophae/vue-treeselect";
|
||||||
|
import {generateExcel} from "@/utils/exportExcel.js";
|
||||||
|
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
||||||
|
const defaultUser = {
|
||||||
|
id: "",
|
||||||
|
name: "",
|
||||||
|
username: "",
|
||||||
|
dept: null,
|
||||||
|
avatar: "/media/default/avatar.png",
|
||||||
|
};
|
||||||
|
export default {
|
||||||
|
components: { Pagination, Treeselect },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
user: defaultUser,
|
||||||
|
upHeaders: upHeaders(),
|
||||||
|
upUrl: upUrl(),
|
||||||
|
userList: { count: 0 },
|
||||||
|
roles: [],
|
||||||
|
listLoading: true,
|
||||||
|
listQuery: {
|
||||||
|
page: 1,
|
||||||
|
page_size: 20,
|
||||||
|
},
|
||||||
|
enabledOptions: [
|
||||||
|
{ key: "true", display_name: "激活" },
|
||||||
|
{ key: "false", display_name: "禁用" },
|
||||||
|
],
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogType: "new",
|
||||||
|
rule1: {
|
||||||
|
name: [{ required: true, message: "请输入姓名", trigger: "blur" }],
|
||||||
|
username: [
|
||||||
|
{ required: true, message: "请输入账号", trigger: "change" },
|
||||||
|
],
|
||||||
|
roles: [{ required: true, message: "请选择角色", trigger: "change" }],
|
||||||
|
// password: [
|
||||||
|
// { required: true, message: '请输入密码', trigger: 'change' }
|
||||||
|
// ],
|
||||||
|
},
|
||||||
|
filterOrgText: "",
|
||||||
|
treeLoding: false,
|
||||||
|
orgData: [],
|
||||||
|
params : {name:'考试'},
|
||||||
|
columns : [
|
||||||
|
{ header: '姓名', key: 'name', wpx: 60 },
|
||||||
|
{ header: '账户', key: 'username', wch: 32 },
|
||||||
|
{ header: '部门', key: 'dept_name', width: 30 },
|
||||||
|
{ header: '角色', key: 'roles', width: 70 }
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
watch: {
|
||||||
|
filterOrgText(val) {
|
||||||
|
this.$refs.tree.filter(val);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getList();
|
||||||
|
this.getSubOrgList();
|
||||||
|
this.getRoleAll();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
checkPermission,
|
||||||
|
handleAvatarSuccess(res, file) {
|
||||||
|
if (res.code >= 200) {
|
||||||
|
this.user.avatar = res.data.path;
|
||||||
|
} else {
|
||||||
|
this.$message.error("头像上传失败!");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeAvatarUpload(file) {
|
||||||
|
const isLt2M = file.size / 1024 / 1024 < 2;
|
||||||
|
if (!isLt2M) {
|
||||||
|
this.$message.error("上传头像图片大小不能超过 2MB!");
|
||||||
|
}
|
||||||
|
return isLt2M;
|
||||||
|
},
|
||||||
|
filterNode(value, data) {
|
||||||
|
if (!value) return true;
|
||||||
|
return data.label.indexOf(value) !== -1;
|
||||||
|
},
|
||||||
|
handleOrgClick(obj, node, vue) {
|
||||||
|
this.listQuery.page = 1;
|
||||||
|
this.listQuery.dept = obj.id;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
getList() {
|
||||||
|
this.listLoading = true;
|
||||||
|
getUserList(this.listQuery).then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
this.userList = response.data;
|
||||||
|
}
|
||||||
|
this.listLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getSubOrgList() {
|
||||||
|
this.treeLoding = true;
|
||||||
|
getSubOrgList().then((response) => {
|
||||||
|
this.orgData = genTree(response.data);
|
||||||
|
this.treeLoding = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getRoleAll() {
|
||||||
|
getRoleList(this.params).then((response) => {
|
||||||
|
this.roles = genTree(response.data);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
resetFilter() {
|
||||||
|
this.listQuery = {
|
||||||
|
page: 1,
|
||||||
|
page_size: 20,
|
||||||
|
};
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
handleFilter() {
|
||||||
|
this.listQuery.page = 1;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
handleAddUser() {
|
||||||
|
this.user = Object.assign({}, defaultUser);
|
||||||
|
this.dialogType = "new";
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs["Form"].clearValidate();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleEdit(scope) {
|
||||||
|
this.user = Object.assign({}, scope.row); // copy obj
|
||||||
|
this.dialogType = "edit";
|
||||||
|
this.dialogVisible = true;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs["Form"].clearValidate();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleDelete(scope) {
|
||||||
|
this.$confirm("确认删除?", "警告", {
|
||||||
|
confirmButtonText: "确认",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
.then(async () => {
|
||||||
|
await deleteUserExam(scope.row.id);
|
||||||
|
this.userList.splice(scope.row.index, 1);
|
||||||
|
this.$message.success("成功");
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async confirm(form) {
|
||||||
|
this.$refs[form].validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
const isEdit = this.dialogType === "edit";
|
||||||
|
if (isEdit) {
|
||||||
|
updateUser(this.user.id, this.user).then((res) => {
|
||||||
|
if (res.code >= 200) {
|
||||||
|
this.getList();
|
||||||
|
this.dialogVisible = false;
|
||||||
|
this.$message.success("成功");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
createUser(this.user).then((res) => {
|
||||||
|
if (res.code >= 200) {
|
||||||
|
this.getList();
|
||||||
|
this.dialogVisible = false;
|
||||||
|
this.$message.success("成功");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handeReset(scope) {
|
||||||
|
this.$confirm("确认重置密码为0000吗?", "警告", {
|
||||||
|
confirmButtonText: "确认",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning",
|
||||||
|
}).then(() => {
|
||||||
|
resetUserpw(scope.row.id)
|
||||||
|
.then((res) => {
|
||||||
|
this.$message.success('成功');
|
||||||
|
})
|
||||||
|
.catch((e) => {});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//导出
|
||||||
|
exportExcel(){
|
||||||
|
let that = this;
|
||||||
|
this.listLoading = true;
|
||||||
|
//获取全部人员数据
|
||||||
|
let promises = [1,2, 3, 4].map(function (page) {
|
||||||
|
return getUserList({page:page,page_size:500}).then((res)=>{return res.data.results})
|
||||||
|
});
|
||||||
|
Promise.all(promises).then(function (posts) {
|
||||||
|
let data = JSON.parse(JSON.stringify(posts))
|
||||||
|
let list = [...data[0], ...data[1],...data[2], ...data[3]];
|
||||||
|
let exportData = [];
|
||||||
|
for(let i=0;i<list.length;i++){
|
||||||
|
let obj = {};
|
||||||
|
obj.name=list[i].name;
|
||||||
|
obj.username=list[i].username;
|
||||||
|
obj.dept_name=list[i].dept_name;
|
||||||
|
let rolesList = list[i].roles_;
|
||||||
|
let roles = rolesList.map((item)=>{
|
||||||
|
return item.name;
|
||||||
|
})
|
||||||
|
obj.roles=roles.toString();
|
||||||
|
exportData.push(obj)
|
||||||
|
}
|
||||||
|
generateExcel(that.columns,exportData,'账号清单');
|
||||||
|
that.listLoading = false;
|
||||||
|
}).catch(function(reason){
|
||||||
|
console.log('出错了',reason)
|
||||||
|
that.listLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -20,6 +20,8 @@ from apps.exam.filters import ExamRecordFilter, ExamFilter
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from apps.system.mixins import CreateUpdateCustomMixin
|
from apps.system.mixins import CreateUpdateCustomMixin
|
||||||
from apps.edu.serializers import CertificateSerializer
|
from apps.edu.serializers import CertificateSerializer
|
||||||
|
from utils.queryset import get_child_queryset2
|
||||||
|
from apps.system.permission import has_permission
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
||||||
|
@ -354,7 +356,15 @@ class ExamRecordViewSet(ListModelMixin, DestroyModelMixin, RetrieveModelMixin, G
|
||||||
search_fields = ('create_by__name', 'create_by__username', 'exam__name', 'belong_dept__name')
|
search_fields = ('create_by__name', 'create_by__username', 'exam__name', 'belong_dept__name')
|
||||||
filterset_class = ExamRecordFilter
|
filterset_class = ExamRecordFilter
|
||||||
|
|
||||||
# 排序
|
def get_queryset(self):
|
||||||
|
qs = super().get_queryset()
|
||||||
|
# if self.request.method == 'GET':
|
||||||
|
# return qs
|
||||||
|
# else:
|
||||||
|
# return qs.filter(belong_dept__in=get_child_queryset2(self.request.user.dept))
|
||||||
|
if has_permission('ability_review_jygl', self.request.user):
|
||||||
|
return qs
|
||||||
|
return qs.filter(belong_dept__in=get_child_queryset2(self.request.user.dept))
|
||||||
|
|
||||||
def get_serializer_class(self):
|
def get_serializer_class(self):
|
||||||
if self.action == 'retrieve':
|
if self.action == 'retrieve':
|
||||||
|
@ -397,7 +407,6 @@ class ExamRecordViewSet(ListModelMixin, DestroyModelMixin, RetrieveModelMixin, G
|
||||||
提交答卷
|
提交答卷
|
||||||
'''
|
'''
|
||||||
er = self.get_object()
|
er = self.get_object()
|
||||||
print('er----------------', er)
|
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
if er.create_by != request.user:
|
if er.create_by != request.user:
|
||||||
raise ParseError('提交人有误')
|
raise ParseError('提交人有误')
|
||||||
|
|
|
@ -95,6 +95,7 @@ class UserListSerializer(serializers.ModelSerializer):
|
||||||
queryset = queryset.prefetch_related('roles',)
|
queryset = queryset.prefetch_related('roles',)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
class UserModifySerializer(serializers.ModelSerializer):
|
class UserModifySerializer(serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
用户编辑序列化
|
用户编辑序列化
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
|
|
||||||
from .views import CityViewSet, ProviceViewSet, UserViewSet, OrganizationViewSet, PermissionViewSet, RoleViewSet, PositionViewSet, TestView, DictTypeViewSet, DictViewSet, InitAreaView, sendMsg
|
from .views import CityViewSet, ProviceViewSet, UserExamViewset, UserViewSet, OrganizationViewSet, PermissionViewSet, RoleViewSet, PositionViewSet, TestView, DictTypeViewSet, DictViewSet, InitAreaView, sendMsg
|
||||||
from rest_framework import routers
|
from rest_framework import routers
|
||||||
|
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
router.register('user', UserViewSet, basename="user")
|
router.register('user', UserViewSet, basename="user")
|
||||||
|
router.register('userexam', UserExamViewset, basename="userexam")
|
||||||
router.register('organization', OrganizationViewSet, basename="organization")
|
router.register('organization', OrganizationViewSet, basename="organization")
|
||||||
router.register('permission', PermissionViewSet, basename="permission")
|
router.register('permission', PermissionViewSet, basename="permission")
|
||||||
router.register('role', RoleViewSet, basename="role")
|
router.register('role', RoleViewSet, basename="role")
|
||||||
|
|
|
@ -45,26 +45,84 @@ import requests
|
||||||
import json
|
import json
|
||||||
from rest_framework.exceptions import AuthenticationFailed
|
from rest_framework.exceptions import AuthenticationFailed
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
logger = logging.getLogger('log')
|
|
||||||
# logger.info('请求成功! response_code:{};response_headers:{};response_body:{}'.format(response_code, response_headers, response_body[:251]))
|
|
||||||
# logger.error('请求出错:{}'.format(error))
|
|
||||||
|
|
||||||
|
|
||||||
class LogoutView(APIView):
|
|
||||||
permission_classes = []
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs): # 可将token加入黑名单
|
|
||||||
return Response(status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
|
from rest_framework.exceptions import ParseError
|
||||||
|
from apps.system.permission import has_permission
|
||||||
|
from openpyxl import load_workbook
|
||||||
import random
|
import random
|
||||||
import smtplib
|
import smtplib
|
||||||
import string
|
import string
|
||||||
from email.header import Header
|
from email.header import Header
|
||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
from email.utils import formataddr
|
from email.utils import formataddr
|
||||||
|
|
||||||
from rest_framework_simplejwt.tokens import RefreshToken
|
from rest_framework_simplejwt.tokens import RefreshToken
|
||||||
|
|
||||||
|
logger = logging.getLogger('log')
|
||||||
|
# logger.info('请求成功! response_code:{};response_headers:{};response_body:{}'.format(response_code, response_headers, response_body[:251]))
|
||||||
|
# logger.error('请求出错:{}'.format(error))
|
||||||
|
|
||||||
|
|
||||||
|
class ImpMixin:
|
||||||
|
def get_queryset(self):
|
||||||
|
mydept = self.request.user.dept
|
||||||
|
qs = super().get_queryset()
|
||||||
|
if has_permission('task2', self.request.user):
|
||||||
|
return qs
|
||||||
|
return qs.filter(belong_dept=mydept)
|
||||||
|
|
||||||
|
def format_date(self, ind, val):
|
||||||
|
new_val = val
|
||||||
|
if isinstance(val, datetime.datetime):
|
||||||
|
new_val = val.date()
|
||||||
|
elif isinstance(val, datetime.date):
|
||||||
|
new_val = val
|
||||||
|
elif isinstance(val, str):
|
||||||
|
try:
|
||||||
|
new_val = datetime.datetime.strptime(val, '%Y-%m-%d').date()
|
||||||
|
except ValueError:
|
||||||
|
raise ParseError(f'第{ind}行, 日期时间格式错误')
|
||||||
|
elif val is None:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise ParseError(f'第{ind}行, 日期时间格式错误')
|
||||||
|
return new_val
|
||||||
|
|
||||||
|
def get_enum(self, val, atuple, ind):
|
||||||
|
for i in atuple:
|
||||||
|
if i[1] == val:
|
||||||
|
return i[0]
|
||||||
|
raise ParseError('第{}: 请选择固定选项值'.format(ind))
|
||||||
|
|
||||||
|
def F(self, data, sheet, i, etype):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def gen_imp_view(self, request, start: int, mySerializer):
|
||||||
|
if 'file' not in request.data:
|
||||||
|
raise ParseError('请提供文件')
|
||||||
|
path = request.data['file']
|
||||||
|
print(path, "---------ssss")
|
||||||
|
|
||||||
|
if not str(path).endswith('.xlsx'):
|
||||||
|
raise ParseError('请提供xlsx格式文件')
|
||||||
|
fullpath = settings.BASE_DIR + str(path)
|
||||||
|
wb = load_workbook(fullpath,data_only=True)
|
||||||
|
sheet = wb.active
|
||||||
|
# 遍历Excel文件中的数据
|
||||||
|
data_list = self.build_data(sheet, start)
|
||||||
|
serializer = mySerializer(data=data_list, many=True, context={'request': request})
|
||||||
|
if serializer.is_valid():
|
||||||
|
serializer.save(create_by=request.user, belong_dept=request.user.dept)
|
||||||
|
else:
|
||||||
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
return Response({'uploaded': 'File uploaded successfully'}, status=status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
|
||||||
|
class LogoutView(APIView):
|
||||||
|
permission_classes = []
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs): # 可将token加入黑名单
|
||||||
|
return Response(status=status.HTTP_200_OK)
|
||||||
|
|
||||||
def get_tokens_for_user(user):
|
def get_tokens_for_user(user):
|
||||||
refresh = RefreshToken.for_user(user)
|
refresh = RefreshToken.for_user(user)
|
||||||
|
@ -246,9 +304,69 @@ class RoleViewSet(ModelViewSet):
|
||||||
serializer_class = RoleSerializer
|
serializer_class = RoleSerializer
|
||||||
pagination_class = None
|
pagination_class = None
|
||||||
search_fields = ['name']
|
search_fields = ['name']
|
||||||
|
filterset_fields = []
|
||||||
ordering_fields = ['id']
|
ordering_fields = ['id']
|
||||||
ordering = 'id'
|
ordering = 'id'
|
||||||
|
|
||||||
|
class UserExamViewset(ImpMixin, ModelViewSet):
|
||||||
|
"""
|
||||||
|
用户考试:增删改查
|
||||||
|
"""
|
||||||
|
perms_map = {'get': '*', 'post': 'user_exam_create',
|
||||||
|
'put': 'user_exam_create', 'delete': 'user_exam_delete'}
|
||||||
|
queryset = User.objects.all().order_by('-id')
|
||||||
|
serializer_class = UserListSerializer
|
||||||
|
filterset_class = UserFilter
|
||||||
|
search_fields = ['username', 'name', 'phone', 'email']
|
||||||
|
ordering_fields = ['-id']
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = self.queryset
|
||||||
|
dept = self.request.user.dept.id
|
||||||
|
deptqueryset = get_child_queryset2(Organization.objects.get(pk=dept))
|
||||||
|
queryset = queryset.filter(dept__in=deptqueryset)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
# 创建用户默认添加密码
|
||||||
|
password = request.data['password'] if 'password' in request.data else None
|
||||||
|
if password:
|
||||||
|
password = make_password(password)
|
||||||
|
else:
|
||||||
|
# password = make_password(''.join(random.sample(string.ascii_letters + string.digits, 8)))
|
||||||
|
password = make_password('0000')
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
serializer.save(password=password)
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
def build_data(self, sheet, start):
|
||||||
|
data_list = []
|
||||||
|
exam_role = Role.objects.get(name='考试')
|
||||||
|
if not exam_role:
|
||||||
|
return Response({'msg': '考试角色不存在'})
|
||||||
|
for row in sheet.iter_rows(min_row=start, values_only=True): # 假设第一行是表头,从第二行开始读取数据
|
||||||
|
if row[0] is not None:
|
||||||
|
dept = Organization.objects.get(name=row[3])
|
||||||
|
if not dept:
|
||||||
|
return Response({'msg': '部门不存在'})
|
||||||
|
serializer_data = {
|
||||||
|
'name': row[1],
|
||||||
|
'username':row[2],
|
||||||
|
'dept':dept.id,
|
||||||
|
'roles':[exam_role.id],
|
||||||
|
'avatar': "/media/default/avatar.png"
|
||||||
|
}
|
||||||
|
data_list.append(serializer_data)
|
||||||
|
return data_list
|
||||||
|
@action(detail=False, methods=['post'])
|
||||||
|
@transaction.atomic
|
||||||
|
def imp(self, request, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
导入数据
|
||||||
|
"""
|
||||||
|
return self.gen_imp_view(request, 2, UserListSerializer)
|
||||||
|
|
||||||
|
|
||||||
class UserViewSet(PageOrNot, ModelViewSet):
|
class UserViewSet(PageOrNot, ModelViewSet):
|
||||||
"""
|
"""
|
||||||
|
@ -532,5 +650,6 @@ class InitAreaView(APIView):
|
||||||
for i in cs:
|
for i in cs:
|
||||||
City.objects.create(id=i['code'], name=i['name'], parent=Province.objects.get(id=i['provinceCode']))
|
City.objects.create(id=i['code'], name=i['name'], parent=Province.objects.get(id=i['provinceCode']))
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue