diff --git a/backend/dvadmin/system/views/dept.py b/backend/dvadmin/system/views/dept.py index 8a736f2..31982f5 100644 --- a/backend/dvadmin/system/views/dept.py +++ b/backend/dvadmin/system/views/dept.py @@ -6,9 +6,11 @@ @Remark: 部门管理 """ from rest_framework import serializers +from rest_framework.decorators import action from dvadmin.system.models import Dept from dvadmin.utils.json_response import DetailResponse, SuccessResponse +from dvadmin.utils.permission import AnonymousUserPermission from dvadmin.utils.serializers import CustomModelSerializer from dvadmin.utils.viewset import CustomModelViewSet @@ -18,18 +20,17 @@ class DeptSerializer(CustomModelSerializer): 部门-序列化器 """ parent_name = serializers.CharField(read_only=True, source='parent.name') - has_children = serializers.SerializerMethodField() status_label = serializers.SerializerMethodField() + has_children = serializers.SerializerMethodField() + + def get_status_label(self, obj: Dept): + if obj.status: + return "启用" + return "禁用" def get_has_children(self, obj: Dept): return Dept.objects.filter(parent_id=obj.id).count() - def get_status_label(self, instance): - status = instance.status - if status: - return "启用" - return "禁用" - class Meta: model = Dept fields = '__all__' @@ -59,7 +60,7 @@ class DeptInitSerializer(CustomModelSerializer): filter_data = { "name": menu_data['name'], "parent": menu_data['parent'], - "key":menu_data['key'] + "key": menu_data['key'] } instance_obj = Dept.objects.filter(**filter_data).first() if instance_obj and not self.initial_data.get('reset'): @@ -73,7 +74,7 @@ class DeptInitSerializer(CustomModelSerializer): class Meta: model = Dept fields = ['name', 'sort', 'owner', 'phone', 'email', 'status', 'parent', 'creator', 'dept_belong_id', - 'children','key'] + 'children', 'key'] extra_kwargs = { 'creator': {'write_only': True}, 'dept_belong_id': {'write_only': True} @@ -123,7 +124,13 @@ class DeptViewSet(CustomModelViewSet): if lazy: # 如果懒加载模式,返回全部 if not parent: - if self.request.user.is_superuser: + role_list = request.user.role.filter(status=1).values("admin", "data_range") + is_admin = False + for ele in role_list: + if 3 == ele.get("data_range") or ele.get("admin") == True: + is_admin = True + break + if self.request.user.is_superuser or is_admin: queryset = queryset.filter(parent__isnull=True) else: queryset = queryset.filter(id=self.request.user.dept_id) @@ -147,3 +154,10 @@ class DeptViewSet(CustomModelViewSet): queryset = queryset.filter(id=self.request.user.dept_id) data = queryset.filter(status=True).order_by('sort').values('name', 'id', 'parent') return DetailResponse(data=data, msg="获取成功") + + @action(methods=["GET"], detail=False, permission_classes=[AnonymousUserPermission]) + def all_dept(self, request, *args, **kwargs): + self.extra_filter_backends = [] + queryset = self.filter_queryset(self.get_queryset()) + data = queryset.filter(status=True).order_by('sort').values('name', 'id', 'parent') + return DetailResponse(data=data, msg="获取成功") diff --git a/backend/dvadmin/system/views/user.py b/backend/dvadmin/system/views/user.py index c0aa72e..a0ba6bd 100644 --- a/backend/dvadmin/system/views/user.py +++ b/backend/dvadmin/system/views/user.py @@ -3,7 +3,7 @@ import hashlib from django.contrib.auth.hashers import make_password from django_restql.fields import DynamicSerializerMethodField from rest_framework import serializers -from rest_framework.decorators import action +from rest_framework.decorators import action, permission_classes from rest_framework.permissions import IsAuthenticated from application import dispatch @@ -21,6 +21,7 @@ class UserSerializer(CustomModelSerializer): """ dept_name = serializers.CharField(source='dept.name', read_only=True) role_info = DynamicSerializerMethodField() + factory_name = serializers.CharField(source='factory_info.name', read_only=True, help_text="工厂名称") class Meta: model = Users @@ -46,16 +47,6 @@ class UsersInitSerializer(CustomModelSerializer): """ 初始化获取数信息(用于生成初始化json文件) """ - def save(self, **kwargs): - instance = super().save(**kwargs) - role_key = self.initial_data.get('role_key',[]) - role_ids = Role.objects.filter(key__in=role_key).values_list('id',flat=True) - instance.role.set(role_ids) - dept_key = self.initial_data.get('dept_key',None) - dept_id = Dept.objects.filter(key=dept_key).first() - instance.dept = dept_id - instance.save() - return instance class Meta: model = Users @@ -223,17 +214,17 @@ class UserViewSet(CustomModelViewSet): } search_fields = ["username", "name", "gender", "dept__name", "role__name"] # 导出 - export_field_label = { - "username":"用户账号", - "name":"用户名称", - "email":"用户邮箱", - "mobile":"手机号码", - "gender":"用户性别", - "is_active":"帐号状态", - "last_login":"最后登录时间", - "dept_name":"部门名称", - "dept_owner":"部门负责人", - } + export_field_label = [ + "用户账号", + "用户名称", + "用户邮箱", + "手机号码", + "用户性别", + "帐号状态", + "最后登录时间", + "部门名称", + "部门负责人", + ] export_serializer_class = ExportUserProfileSerializer # 导入 import_serializer_class = UserProfileImportSerializer @@ -262,14 +253,31 @@ class UserViewSet(CustomModelViewSet): @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated]) def user_info(self, request): """获取当前用户信息""" - user = request.user + user = self.request.user result = { + "id": user.id, "name": user.name, "mobile": user.mobile, + "user_type": user.user_type, "gender": user.gender, "email": user.email, "avatar": user.avatar, + "dept": user.dept.id, + "is_superuser": user.is_superuser, + "role": user.role.values_list('id', flat=True), } + if user.user_type == 3: + result["distributor_info"] = user.distributor_info_user.all().values_list('name', flat=True) + dept = getattr(user, 'dept', None) + if dept: + result['dept_info'] = { + 'dept_id': dept.id, + 'dept_name': dept.name + } + role = getattr(user, 'role', None) + if role: + result['role_info'] = role.values('id', 'name', 'key') + return DetailResponse(data=result, msg="获取成功") @action(methods=["PUT"], detail=False, permission_classes=[IsAuthenticated]) @@ -286,7 +294,7 @@ class UserViewSet(CustomModelViewSet): old_pwd = data.get("oldPassword") new_pwd = data.get("newPassword") new_pwd2 = data.get("newPassword2") - if old_pwd or new_pwd or new_pwd2: + if old_pwd is None or new_pwd is None or new_pwd2 is None: return ErrorResponse(msg="参数不能为空") if new_pwd != new_pwd2: return ErrorResponse(msg="两次密码不匹配") diff --git a/web/src/components/dept-format/index.js b/web/src/components/dept-format/index.js new file mode 100644 index 0000000..3af55fc --- /dev/null +++ b/web/src/components/dept-format/index.js @@ -0,0 +1,7 @@ +function install (Vue) { + Vue.component('dept-format', () => import('./lib/dept-format')) +} + +export default { + install +} diff --git a/web/src/components/dept-format/lib/dept-format.vue b/web/src/components/dept-format/lib/dept-format.vue new file mode 100644 index 0000000..1d176be --- /dev/null +++ b/web/src/components/dept-format/lib/dept-format.vue @@ -0,0 +1,47 @@ + + +Footer diff --git a/web/src/components/index.js b/web/src/components/index.js index 943e6c8..6f42469 100644 --- a/web/src/components/index.js +++ b/web/src/components/index.js @@ -9,3 +9,4 @@ Vue.component('d2-icon-svg', () => import('./d2-icon-svg/index.vue')) Vue.component('importExcel', () => import('./importExcel/index.vue')) Vue.component('foreignKey', () => import('./foreign-key/index.vue')) Vue.component('manyToMany', () => import('./many-to-many/index.vue')) +Vue.component('dept-format', () => import('./dept-format/lib/dept-format.vue')) diff --git a/web/src/install.js b/web/src/install.js index fa38537..2fab2ec 100644 --- a/web/src/install.js +++ b/web/src/install.js @@ -16,7 +16,6 @@ import { request } from '@/api/service' import util from '@/libs/util' import XEUtils from 'xe-utils' import store from '@/store/index' -import { urlPrefix as deptPrefix } from '@/views/system/dept/api' import types from '@/config/d2p-extends/types' import { checkPlugins, plugins } from '@/views/plugins' @@ -243,7 +242,8 @@ Vue.prototype.commonEndColumns = function (param = {}) { }, dept_belong_id: { showForm: (param.dept_belong_id && param.dept_belong_id.showForm) !== undefined ? param.dept_belong_id.showForm : false, - showTable: (param.dept_belong_id && param.dept_belong_id.showTable) !== undefined ? param.dept_belong_id.showTable : false + showTable: (param.dept_belong_id && param.dept_belong_id.showTable) !== undefined ? param.dept_belong_id.showTable : false, + showSearch: (param.dept_belong_id && param.dept_belong_id.showSearch) !== undefined ? param.dept_belong_id.showSearch : false }, modifier_name: { showForm: (param.modifier_name && param.modifier_name.showForm) !== undefined ? param.modifier_name.showForm : false, @@ -293,61 +293,41 @@ Vue.prototype.commonEndColumns = function (param = {}) { } }, { - title: '数据归属部门', + title: '所属部门', key: 'dept_belong_id', show: showData.dept_belong_id.showTable, width: 150, search: { - disabled: true + disabled: !showData.dept_belong_id.showSearch }, - type: 'table-selector', + type: 'tree-selector', dict: { - cache: true, - url: deptPrefix, - isTree: true, + cache: false, + url: '/api/system/dept/all_dept/', + // isTree: true, + // dept: true, value: 'id', // 数据字典中value字段的属性名 label: 'name', // 数据字典中label字段的属性名 - children: 'children', // 数据字典中children字段的属性名 - getData: (url, dict, { - _, - component - }) => { - return request({ - url: url, - params: { limit: 999, status: 1 } - }).then(ret => { - return ret.data.data - }) - } + children: 'children' // 数据字典中children字段的属性名 + // getData: (url, dict, { + // _, + // component + // }) => { + // return request({ + // url: url + // }).then(ret => { + // return XEUtils.toArrayTree(ret.data, { parentKey: 'parent', strict: false }) + // }) + // } + }, + component: { + name: 'dept-format', + props: { multiple: false, clearable: true } }, form: { disabled: !showData.dept_belong_id.showForm, component: { - props: { - elProps: { - treeConfig: { - transform: true, - rowField: 'id', - parentField: 'parent', - expandAll: true - }, - columns: [ - { - field: 'name', - title: '部门名称', - treeNode: true - }, - { - field: 'status', - title: '状态' - }, - { - field: 'parent_name', - title: '父级部门' - } - ] - } - } + props: { multiple: false, clearable: true } }, helper: { render (h) { @@ -355,6 +335,12 @@ Vue.prototype.commonEndColumns = function (param = {}) { ) } } + }, + // 接收时,处理数据 + valueBuilder (row, col) { + if (row[col.key]) { + row[col.key] = Number(row[col.key]) + } } }, { diff --git a/web/src/libs/util.import.plugin.js b/web/src/libs/util.import.plugin.js index aa3794d..1f9d17c 100644 --- a/web/src/libs/util.import.plugin.js +++ b/web/src/libs/util.import.plugin.js @@ -1 +1,9 @@ -module.exports = file => () => import('@great-dream/' + file) +module.exports = file => { + var result + try { + result = require('@great-dream/' + file).default + } catch (error) { + result = require('@/views/plugins/' + file).default + } + return result +} diff --git a/web/src/libs/util.js b/web/src/libs/util.js index 9d0abd1..35dbc62 100644 --- a/web/src/libs/util.js +++ b/web/src/libs/util.js @@ -79,4 +79,30 @@ util.randomString = function (e) { return n } +util.ArrayToTree = function (rootList, parentValue, parentName, list) { + for (const item of rootList) { + if (item.parent === parentValue) { + if (parentName) { + item.name = parentName + '/' + item.name + } + list.push(item) + } + } + + for (const i of list) { + // 如果子元素里面存在children就直接递归,不存在就生成一个children + if (i.children) { + util.ArrayToTree(rootList, i.id, i.name, i.children) + } else { + i.children = [] + util.ArrayToTree(rootList, i.id, i.name, i.children) + } + + if (i.children.length === 0) { + delete i.children + } + } + return list +} + export default util diff --git a/web/src/router/index.js b/web/src/router/index.js index 6d19422..83771a9 100644 --- a/web/src/router/index.js +++ b/web/src/router/index.js @@ -17,6 +17,7 @@ import util from '@/libs/util.js' // 路由数据 import routes from './routes' import { getMenu, handleAsideMenu, handleRouter, checkRouter } from '@/menu' +import { request } from '@/api/service' // fix vue-router NavigationDuplicated const VueRouterPush = VueRouter.prototype.push @@ -55,6 +56,24 @@ router.beforeEach(async (to, from, next) => { // 请根据自身业务需要修改 const token = util.cookies.get('token') if (token && token !== 'undefined') { + if (!store.state.d2admin.user.info.name) { + var res = await request({ + url: '/api/system/user/user_info/', + method: 'get', + params: {} + }) + await store.dispatch('d2admin/user/set', { + name: res.data.name, + user_id: res.data.id, + avatar: res.data.avatar, + role_info: res.data.role_info, + dept_info: res.data.dept_info, + is_superuser: res.data.is_superuser + }, { root: true }) + await store.dispatch('d2admin/account/load') + store.dispatch('d2admin/dept/load') + store.dispatch('d2admin/settings/init') + } if (!store.state.d2admin.menu || store.state.d2admin.menu.aside.length === 0) { // 动态添加路由 getMenu().then(ret => { diff --git a/web/src/store/modules/d2admin/modules/dept.js b/web/src/store/modules/d2admin/modules/dept.js new file mode 100644 index 0000000..0b964ee --- /dev/null +++ b/web/src/store/modules/d2admin/modules/dept.js @@ -0,0 +1,38 @@ +import { request } from '@/api/service' +import util from '@/libs/util' + +export default { + namespaced: true, + state: { + // 用户信息 + data: undefined + }, + actions: { + /** + * @description 初始化部门数据 + * @param {Object} context + * @param {*} info info + */ + async getDeptName ({ state, dispatch }, { data }) { + const nameDict = {} + for (const items of data) { + if (items.children) { + const filterData = await dispatch('getDeptName', { data: items.children }) + for (var key in filterData) { + nameDict[key] = filterData[key] + } + } + nameDict[items.id] = items.name + } + return nameDict + }, + async load ({ state, dispatch }, info) { + // 持久化 + const ret = await request({ + url: '/api/system/dept/all_dept/' + }) + const data = util.ArrayToTree(ret.data.data || ret.data, null, null, []) + state.data = await dispatch('getDeptName', { data: data }) + } + } +} diff --git a/web/src/store/modules/d2admin/modules/user.js b/web/src/store/modules/d2admin/modules/user.js index 13c9fc3..5dad7b4 100644 --- a/web/src/store/modules/d2admin/modules/user.js +++ b/web/src/store/modules/d2admin/modules/user.js @@ -14,12 +14,12 @@ export default { // store 赋值 state.info = info // 持久化 - await dispatch('d2admin/db/set', { - dbName: 'sys', - path: 'user.info', - value: info, - user: true - }, { root: true }) + // await dispatch('d2admin/db/set', { + // dbName: 'sys', + // path: 'user.info', + // value: info, + // user: true + // }, { root: true }) }, /** * @description 从数据库取用户数据 @@ -27,12 +27,12 @@ export default { */ async load ({ state, dispatch }) { // store 赋值 - state.info = await dispatch('d2admin/db/get', { - dbName: 'sys', - path: 'user.info', - defaultValue: {}, - user: true - }, { root: true }) + // state.info = await dispatch('d2admin/db/get', { + // dbName: 'sys', + // path: 'user.info', + // defaultValue: {}, + // user: true + // }, { root: true }) } } } diff --git a/web/src/views/system/dept/index.vue b/web/src/views/system/dept/index.vue index a362e70..1e935e8 100644 --- a/web/src/views/system/dept/index.vue +++ b/web/src/views/system/dept/index.vue @@ -49,13 +49,17 @@ export default { }, addRequest (row) { d2CrudPlus.util.dict.clear() + this.$store.dispatch('d2admin/dept/load') return api.createObj(row) }, updateRequest (row) { d2CrudPlus.util.dict.clear() + this.$store.dispatch('d2admin/dept/load') return api.UpdateObj(row) }, delRequest (row) { + d2CrudPlus.util.dict.clear() + this.$store.dispatch('d2admin/dept/load') return api.DelObj(row.id) }, // 授权