增加省管理员和本单位管理员

This commit is contained in:
caoqianming 2021-04-05 21:31:53 +08:00
parent 0827bd6f95
commit 45265db72a
23 changed files with 315 additions and 152 deletions

View File

@ -3451,8 +3451,8 @@
},
"china-area-data": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/china-area-data/-/china-area-data-5.0.1.tgz",
"integrity": "sha512-BQDPpiv5Nn+018ekcJK2oSD9PAD+E1bvXB0wgabc//dFVS/KvRqCgg0QOEUt3vBkx9XzB5a9BmkJCEZDBxVjVw=="
"resolved": "https://registry.npm.taobao.org/china-area-data/download/china-area-data-5.0.1.tgz",
"integrity": "sha1-eUO4OgYZ8DO7WJPagMtG5S5EvmY="
},
"chokidar": {
"version": "2.1.8",
@ -5035,8 +5035,8 @@
},
"element-china-area-data": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/element-china-area-data/-/element-china-area-data-5.0.2.tgz",
"integrity": "sha512-vLQuvOKJy/uiX7MRHEk3x/j09hipuIl6DJ/C4XFUG7D7Pj3O47sy+Y6aAArM6k9v8cD9UX6e+yz2S4J+IPnZ8g==",
"resolved": "https://registry.npm.taobao.org/element-china-area-data/download/element-china-area-data-5.0.2.tgz",
"integrity": "sha1-AGwmWUuIZcthmZQGPHMlYuRYPTA=",
"requires": {
"china-area-data": "^5.0.1",
"lodash-es": "^4.17.15"
@ -9900,8 +9900,8 @@
},
"lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
"resolved": "https://registry.npm.taobao.org/lodash-es/download/lodash-es-4.17.21.tgz?cache=0&sync_timestamp=1613836280924&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash-es%2Fdownload%2Flodash-es-4.17.21.tgz",
"integrity": "sha1-Q+YmxG5lkbd1C+srUBFzkMYJ4+4="
},
"lodash.defaultsdeep": {
"version": "4.6.1",

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

View File

@ -5,6 +5,9 @@
<breadcrumb class="breadcrumb-container" />
<div class="right-menu">
<div class="right-menu-item" >
{{name}}
</div>
<el-dropdown class="avatar-container" trigger="click">
<div class="avatar-wrapper">
<img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar">
@ -49,7 +52,8 @@ export default {
computed: {
...mapGetters([
'sidebar',
'avatar'
'avatar',
'name'
])
},
methods: {

View File

@ -2,11 +2,11 @@
<div class="sidebar-logo-container" :class="{'collapse':collapse}">
<transition name="sidebarLogoFade">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo">
<h1 v-else class="sidebar-title">{{ title }} </h1>
<!-- <img v-if="logo" :src="logo" class="sidebar-logo"> -->
<h1 class="sidebar-title">{{ title }} </h1>
</router-link>
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo">
<!-- <img v-if="logo" :src="logo" class="sidebar-logo"> -->
<h1 class="sidebar-title">{{ title }} </h1>
</router-link>
</transition>

View File

@ -120,7 +120,7 @@ export const asyncRoutes = [
path: 'claim',
name: 'Claim',
component: () => import('@/views/crm/claim.vue'),
meta: { title: '认领学员', icon: '', perms: ['consumer_view'] }
meta: { title: '认领学员', icon: '', perms: ['consumer_claim'] }
},
{
path: 'candidate',

View File

@ -6,11 +6,11 @@ module.exports = {
* @type {boolean} true | false
* @description Whether fix the header
*/
fixedHeader: false,
fixedHeader: true,
/**
* @type {boolean} true | false
* @description Whether show the logo in sidebar
*/
sidebarLogo: false
sidebarLogo: true
}

View File

@ -69,7 +69,7 @@
type="primary"
size="small"
@click="handleClaim(scope)"
:disabled="!checkPermission(['consumer_claim'])"
v-if="checkPermission(['consumer_claim'])"
>认领</el-button>
</el-button-group>
</template>

View File

@ -62,7 +62,7 @@
<span>{{ scope.row.create_time }}</span>
</template>
</el-table-column>
<el-table-column label="所属">
<el-table-column label="创建管理员">
<template slot-scope="scope">
<span>{{ scope.row.create_admin_name }}</span>
</template>
@ -75,14 +75,14 @@
size="small"
@click="handleEdit(scope)"
icon="el-icon-edit"
:disabled="!checkPermission(['company_update'])"
v-if="checkPermission(['company_update'])"
></el-button>
<el-button
type="danger"
size="small"
@click="handleDelete(scope)"
icon="el-icon-delete"
:disabled="!checkPermission(['company_delete'])"
v-if="checkPermission(['company_delete'])"
></el-button>
<el-button
v-if="checkPermission(['company_transfer'])"

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-card>
<el-card v-if="checkPermission(['company_view'])">
<div slot="header" class="clearfix">
<span>单位</span>
</div>
@ -122,7 +122,7 @@
type="primary"
icon="el-icon-refresh-left"
@click="resetFilter"
>刷新</el-button>
>重置</el-button>
</div>
<div style="margin-top:10px">
@ -239,23 +239,20 @@
size="small"
@click="handleEdit(scope)"
icon="el-icon-edit"
:disabled="!checkPermission(['consumer_update'])"
v-if="!scope.row.is_superconsumer"
v-if="checkPermission(['consumer_update'])"
></el-button>
<el-button
type="danger"
size="small"
@click="handleDelete(scope)"
icon="el-icon-delete"
:disabled="!checkPermission(['consumer_delete'])"
v-if="!scope.row.is_superconsumer"
v-if="checkPermission(['consumer_delete'])"
></el-button>
<el-button
type="primary"
size="small"
@click="handleUnbind(scope)"
:disabled="!checkPermission(['consumer_unbind'])"
v-if="scope.row.username&&scope.row.openid"
v-if="scope.row.username&&scope.row.openid&&checkPermission(['consumer_unbind'])"
>解微</el-button>
</el-button-group>
</template>
@ -299,25 +296,6 @@
<el-input placeholder="单位" v-model="consumer.company_.name" readonly>
<el-button slot="append" icon="el-icon-search" @click="choose()"></el-button>
</el-input>
<!-- <el-select
v-model="consumer.company"
placeholder="单位"
style="width:100%"
clearable
filterable
remote
:loading="treeLoding"
:remote-method="searchCompany"
loading-text
no-match-text
>
<el-option
v-for="item in companyData"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>-->
</el-form-item>
<el-form-item label="缴费学科" prop="subjects">
<el-select v-model="consumer.subjects" placeholder="缴费学科" style="width:100%" multiple>

View File

@ -1,11 +1,19 @@
<template>
<div class="login-container">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
<el-form
ref="loginForm"
:model="loginForm"
:rules="loginRules"
class="login-form"
auto-complete="on"
label-position="left"
>
<div style="text-align:center;margin-bottom:8px">
<!-- <img class="logo" src="../../assets/logo.png" /> -->
</div>
<div class="title-container">
<h3 class="title">辐射学堂后台管理</h3>
</div>
<el-form-item prop="username">
<span class="svg-container">
<svg-icon icon-class="user" />
@ -37,17 +45,24 @@
@keyup.enter.native="handleLogin"
/>
<span class="show-pwd" @click="showPwd">
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
<svg-icon
:icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"
/>
</span>
</el-form-item>
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">登陆</el-button>
<el-button
:loading="loading"
type="primary"
style="width: 100%; margin-bottom: 30px"
@click.native.prevent="handleLogin"
>登陆</el-button
>
<!-- <div class="tips">
<span style="margin-right:20px;">username: admin</span>
<span> password: any</span>
</div> -->
</el-form>
</div>
</template>
@ -56,7 +71,7 @@
// import { validUsername } from '@/utils/validate'
export default {
name: 'Login',
name: "Login",
data() {
// const validateUsername = (rule, value, callback) => {
// if (!validUsername(value)) {
@ -67,78 +82,82 @@ export default {
// }
const validatePassword = (rule, value, callback) => {
if (value.length < 4) {
callback(new Error('密码长度小于4位!'))
callback(new Error("密码长度小于4位!"));
} else {
callback()
callback();
}
}
};
return {
loginForm: {
username: '',
password: ''
username: "",
password: "",
},
loginRules: {
username: [{ required: true, trigger: 'blur', message: "请输入账户" }],
password: [{ required: true, trigger: 'blur', validator: validatePassword, message: "请输入密码" }]
username: [{ required: true, trigger: "blur", message: "请输入账户" }],
password: [
{
required: true,
trigger: "blur",
validator: validatePassword,
message: "请输入密码",
},
],
},
loading: false,
passwordType: 'password',
redirect: undefined
}
passwordType: "password",
redirect: undefined,
};
},
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect
handler: function (route) {
this.redirect = route.query && route.query.redirect;
},
immediate: true
}
immediate: true,
},
},
methods: {
showPwd() {
if (this.passwordType === 'password') {
this.passwordType = ''
if (this.passwordType === "password") {
this.passwordType = "";
} else {
this.passwordType = 'password'
this.passwordType = "password";
}
this.$nextTick(() => {
this.$refs.password.focus()
})
this.$refs.password.focus();
});
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
this.$refs.loginForm.validate((valid) => {
if (valid) {
this.loading = true
this.$store.dispatch('user/login', this.loginForm).then(() => {
this.$router.push({ path: this.redirect || '/crm/consumer' })
this.loading = false
}).catch(() => {
this.loading = false
})
this.loading = true;
this.$store
.dispatch("user/login", this.loginForm)
.then(() => {
this.$router.push({ path: this.redirect || "/crm/consumer" });
this.loading = false;
})
.catch(() => {
this.loading = false;
});
} else {
console.log('error submit!!')
return false
console.log("error submit!!");
return false;
}
})
}
}
}
});
},
},
};
</script>
<style lang="scss">
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
$bg:#283443;
$light_gray:#fff;
$bg: #283443;
$light_gray: #fff;
$cursor: #fff;
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
.login-container .el-input input {
color: $cursor;
}
}
/* reset element-ui css */
.login-container {
.el-input {
@ -152,20 +171,18 @@ $cursor: #fff;
-webkit-appearance: none;
border-radius: 0px;
padding: 12px 5px 12px 15px;
color: $light_gray;
// color: $light_gray;
height: 47px;
caret-color: $cursor;
// caret-color: $cursor;
&:-webkit-autofill {
box-shadow: 0 0 0px 1000px $bg inset !important;
-webkit-text-fill-color: $cursor !important;
}
// &:-webkit-autofill {
// box-shadow: 0 0 0px 1000px inset !important;
// }
}
}
.el-form-item {
border: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(0, 0, 0, 0.1);
border: 1px solid;
border-radius: 5px;
color: #454545;
}
@ -173,23 +190,26 @@ $cursor: #fff;
</style>
<style lang="scss" scoped>
$bg:#2d3a4b;
$dark_gray:#889aa4;
$light_gray:#eee;
$bg: #2d3a4b;
$dark_gray: #889aa4;
$light_gray: #eee;
.login-container {
min-height: 100%;
width: 100%;
background-color: $bg;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../../assets/background.jpg");
background-size: cover;
.login-form {
position: relative;
width: 520px;
max-width: 100%;
padding: 160px 35px 0;
margin: 0 auto;
overflow: hidden;
border-radius: 6px;
background: #ffffff;
padding: 25px 25px 5px 25px;
width: 400px;
.logo {
width: 350px;
height: 140px;
}
}
.tips {
@ -206,7 +226,7 @@ $light_gray:#eee;
.svg-container {
padding: 6px 5px 6px 15px;
color: $dark_gray;
// color: $dark_gray;
vertical-align: middle;
width: 30px;
display: inline-block;
@ -217,8 +237,8 @@ $light_gray:#eee;
.title {
font-size: 26px;
color: $light_gray;
margin: 0px auto 40px auto;
color: #0174d7;
margin: 0px auto 20px auto;
text-align: center;
font-weight: bold;
}
@ -229,7 +249,7 @@ $light_gray:#eee;
right: 10px;
top: 7px;
font-size: 16px;
color: $dark_gray;
// color: $dark_gray;
cursor: pointer;
user-select: none;
}

View File

@ -11,18 +11,31 @@
max-height="600"
>
<el-table-column type="index" width="50"></el-table-column>
<el-table-column align="header-center" label="账户">
<el-table-column label="账户">
<template slot-scope="scope">{{ scope.row.username }}</template>
</el-table-column>
<el-table-column align="header-center" label="姓名">
<el-table-column label="姓名">
<template slot-scope="scope">{{ scope.row.name }}</template>
</el-table-column>
<el-table-column label="角色">
<template slot-scope="scope">
<el-tag v-for="item in scope.row.roles_" v-bind:key="item" effect="plain">
{{item}}
</el-tag>
</template>
</el-table-column>
<el-table-column label="所属省份">
<template slot-scope="scope">{{ scope.row.pname }}</template>
</el-table-column>
<el-table-column label="所属单位">
<template slot-scope="scope">{{ scope.row.bcompany_name }}</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="操作">
<el-table-column label="操作">
<template slot-scope="scope">
<el-button
type="primary"
@ -76,12 +89,38 @@
/>
</el-select>
</el-form-item>
<el-form-item label="省份" prop="pname">
<el-select placeholder="请选择" clearable v-model="user.pname" style="width:100%">
<el-option
v-for="item in poptions"
:key="item.label"
:label="item.label"
:value="item.label"
style="width:100%"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="单位" prop="bcompany">
<el-input placeholder="单位" v-model="user.bcompany_name" readonly>
<el-button slot="append" icon="el-icon-search" @click="dgcVisiable=true"></el-button>
</el-input>
</el-form-item>
</el-form>
<div style="text-align:right;">
<el-button type="danger" @click="dialogVisible=false">取消</el-button>
<el-button type="primary" @click="confirmUser('userForm')">确认</el-button>
</div>
</el-dialog>
<el-dialog
title="选择企业"
:visible.sync="dgcVisiable"
:close-on-click-modal="false"
width="80%"
:append-to-body="true"
>
<Companychose ref="Companychose" @handleChose="chooseComplete"></Companychose>
</el-dialog>
</div>
</template>
<script>
@ -89,6 +128,8 @@ import { getUserList, createUser, deleteUser, updateUser} from "@/api/user";
import { getRoles } from "@/api/role"
import checkPermission from "@/utils/permission";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
import { provinceAndCityData } from 'element-china-area-data'
import Companychose from "@/views/crm/companychose";
const defaultUser = {
id: "",
@ -97,7 +138,7 @@ const defaultUser = {
is_superuser:false
};
export default {
components: { Pagination },
components: { Pagination, Companychose },
data() {
return {
user: defaultUser,
@ -117,7 +158,9 @@ export default {
treeLoding: false,
orgData: [],
dialogType:'create',
dialogVisible:false
dialogVisible:false,
poptions: provinceAndCityData,
dgcVisiable:false
};
},
computed: {},
@ -154,6 +197,13 @@ export default {
this.dialogType = 'update'
} ,
chooseComplete(val){
this.dgcVisiable = false;
if (val) {
this.user.bcompany_name = val.name;
this.user.bcompany = val.id;
}
},
handleDelete(scope) {
this.$confirm("确认删除?", "警告", {
confirmButtonText: "确认",

View File

@ -52,7 +52,11 @@
show-checkbox
node-key="id"
class="permission-tree"
/>
>
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}-{{ data.method }}</span>
</span>
</el-tree>
</el-form-item>
</el-form>
<div style="text-align:right;">

View File

@ -217,6 +217,7 @@ import { upUrl } from "@/api/file";
import { getToken } from "@/utils/auth";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
const defaultUser = {
id: "",
name: "",
@ -364,6 +365,7 @@ export default {
console.error(err);
});
},
async confirmUser(form) {
this.$refs[form].validate(valid => {
if (valid) {

View File

@ -167,10 +167,18 @@ class CompanyViewSet(ModelViewSet):
def get_queryset(self):
queryset = self.queryset
if self.request.query_params.get('perm', None):
if self.request.user.is_superuser:
return queryset
if not self.request.user.is_superuser:
queryset = queryset.filter(create_admin = self.request.user)
roles = self.request.user.roles.values_list('name', flat=True)
if '普通管理' in roles:
queryset = queryset.filter(create_admin = self.request.user)
elif '省管理' in roles:
if self.request.user.pname:
queryset = queryset.filter(geo__pname = self.request.user.pname)
else:
return Company.objects.none()
else:
return queryset.none()
return queryset
@action(methods=['put'], detail=True, url_name='company_transfer',perms_map=[{'*':'company_transfer'}])
@ -243,10 +251,25 @@ class ConsumerViewSet(ModelViewSet):
def get_queryset(self):
queryset = self.queryset
queryset = self.get_serializer_class().setup_eager_loading(queryset)
if self.request.user.is_superuser:
return queryset
roles = self.request.user.roles.values_list('name', flat=True)
if '普通管理' in roles:
queryset = queryset.filter(create_admin = self.request.user)
elif '省管理' in roles:
if self.request.user.pname:
queryset = queryset.filter(company__geo__pname = self.request.user.pname)
else:
return Consumer.objects.none()
elif '本单位管理' in roles:
if self.request.user.bcompany:
queryset = queryset.filter(company = self.request.user.bcompany)
else:
return Consumer.objects.none()
else:
return queryset.none()
if self.request.query_params.get('adminoff', None):
return queryset.filter(create_admin=None)
if not self.request.user.is_superuser:
queryset = queryset.filter(create_admin = self.request.user)
return queryset
def create(self, request, *args, **kwargs):

View File

@ -48,10 +48,26 @@ class ExamViewSet(ModelViewSet):
def get_queryset(self):
queryset = Exam.objects.all()
if not self.request.user.is_superuser:
queryset = queryset.filter(create_admin = self.request.user)
if hasattr(self.get_serializer_class(), 'setup_eager_loading'):
queryset = self.get_serializer_class().setup_eager_loading(queryset) # 性能优化
if self.request.user.is_superuser:
return queryset
roles = self.request.user.roles.values_list('name', flat=True)
if '普通管理' in roles:
queryset = queryset.filter(create_admin = self.request.user)
elif '省管理' in roles:
if self.request.user.pname:
queryset = queryset.filter(examtest_exam__consumer__company__geo__pname = self.request.user.pname)
else:
return queryset.objects.none()
elif '本单位管理' in roles:
if self.request.user.bcompany:
queryset = queryset.filter(examtest_exam__consumer__company = self.request.user.bcompany)
else:
return queryset.objects.none()
else:
return queryset.none()
return queryset
def get_serializer_class(self):
@ -353,24 +369,39 @@ class ExamTestViewSet(ModelViewSet):
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_fields = ['type','is_pass', 'exam']
def get_queryset(self):
assert self.queryset is not None, (
"'%s' should either include a `queryset` attribute, "
"or override the `get_queryset()` method."
% self.__class__.__name__
)
queryset = self.queryset
if isinstance(queryset, QuerySet):
# Ensure queryset is re-evaluated on each request.
queryset = queryset.all()
if self.request.query_params.get('start'):
queryset = queryset.filter(start_time__gte=self.request.query_params['start'] )
if self.request.query_params.get('end'):
queryset = queryset.filter(start_time__lte=self.request.query_params['end'])
if not self.request.user.is_superuser:
queryset = queryset.filter(Q(consumer__create_admin = self.request.user)|Q(exam__create_admin=self.request.user))
def filter_queryset(self, queryset):
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(self.request, queryset, self)
if self.request.query_params.get('start'):
queryset = queryset.filter(start_time__gte=self.request.query_params['start'] )
if self.request.query_params.get('end'):
queryset = queryset.filter(start_time__lte=self.request.query_params['end'])
return queryset
def get_queryset(self):
queryset = self.queryset
if hasattr(self.get_serializer_class(), 'setup_eager_loading'):
queryset = self.get_serializer_class().setup_eager_loading(queryset)
if self.request.user.is_superuser:
return queryset
roles = self.request.user.roles.values_list('name', flat=True)
if '普通管理' in roles:
queryset = queryset.filter(Q(consumer__create_admin = self.request.user)|Q(exam__create_admin=self.request.user))
elif '省管理' in roles:
if self.request.user.pname:
queryset = queryset.filter(consumer__company__geo__pname = self.request.user.pname)
else:
return queryset.objects.none()
elif '本单位管理' in roles:
if self.request.user.bcompany:
queryset = queryset.filter(consumer__company = self.request.user.bcompany)
else:
return queryset.objects.none()
else:
return queryset.none()
return queryset
@action(methods=['get'], detail=False,url_path='self', url_name='selftest', perms_map = [{'*':'my_examtest'}])
def selftest(self, request, pk=None):
'''

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,18 @@
# Generated by Django 3.0.4 on 2021-04-05 10:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rbac', '0003_auto_20200402_1157'),
]
operations = [
migrations.AddField(
model_name='userprofile',
name='pname',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='所属省份'),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 3.0.4 on 2021-04-05 13:01
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('crm', '0027_consumer_deptname'),
('rbac', '0004_userprofile_pname'),
]
operations = [
migrations.AddField(
model_name='userprofile',
name='bcompany',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='crm.Company', verbose_name='所属公司'),
),
]

View File

@ -109,7 +109,6 @@ class Role(SoftCommonModel):
name = models.CharField(max_length=32, unique=True, verbose_name="角色")
menus = models.ManyToManyField("Menu", blank=True, verbose_name="功能权限")
desc = models.CharField(max_length=50, blank=True, null=True, verbose_name="描述")
class Meta:
verbose_name = "角色"
verbose_name_plural = verbose_name
@ -151,6 +150,9 @@ class UserProfile(AbstractUser):
roles = models.ManyToManyField("Role", verbose_name="角色", blank=True)
is_delete = models.BooleanField(default=False, verbose_name='删除标记', help_text='删除标记')
pname = models.CharField('所属省份', max_length=100, null=True, blank=True)
bcompany = models.ForeignKey('crm.company', verbose_name='所属公司', null=True, blank=True, on_delete=models.SET_NULL)
class Meta:
verbose_name = "用户信息"
verbose_name_plural = verbose_name

View File

View File

@ -10,6 +10,8 @@ class UserListSerializer(serializers.ModelSerializer):
# roles = serializers.SerializerMethodField()
date_joined = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
department_name = serializers.StringRelatedField(source='department')
roles_ = serializers.StringRelatedField(source='roles', many=True)
bcompany_name = serializers.StringRelatedField(source='bcompany')
# def get_roles(self, obj):
# return obj.roles.values()
@ -17,9 +19,16 @@ class UserListSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ['id', 'username', 'name', 'department', 'position',
'is_active', 'roles', 'date_joined', 'is_superuser','department_name', 'avatar']
'is_active', 'roles', 'date_joined', 'is_superuser','department_name', 'avatar', 'roles_', 'pname', 'bcompany_name']
# depth = 1
@staticmethod
def setup_eager_loading(queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.select_related('superior','department', 'bcompany')
queryset = queryset.prefetch_related('roles',)
return queryset
class UserModifySerializer(serializers.ModelSerializer):
"""
@ -30,7 +39,7 @@ class UserModifySerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ['id', 'username', 'name', 'mobile', 'email', 'avatar', 'department', 'position', 'superior',
'is_active', 'roles']
'is_active', 'roles', 'pname', 'bcompany']
def validate_mobile(self, mobile):
REGEX_MOBILE = "^1[358]\d{9}$|^147\d{8}$|^176\d{8}$"
@ -49,7 +58,7 @@ class UserCreateSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ['id', 'username', 'name', 'mobile', 'email', 'department', 'position', 'is_active', 'roles',
'password','is_superuser']
'password','is_superuser', 'pname', 'bcompany']
def validate_username(self, username):
if UserProfile.objects.filter(username=username):

View File

@ -77,6 +77,8 @@ class UserViewSet(PageOrNot, ModelViewSet):
def get_queryset(self):
queryset = self.queryset
if hasattr(self.get_serializer_class(), 'setup_eager_loading'):
queryset = self.get_serializer_class().setup_eager_loading(queryset) # 性能优化
department = self.request.query_params.get('department', None) # 该部门及其子部门所有员工
name = self.request.query_params.get('name',None)
if name is not None: