diff --git a/backend/dvadmin/system/views/file_list.py b/backend/dvadmin/system/views/file_list.py index 82fc757..ae05084 100644 --- a/backend/dvadmin/system/views/file_list.py +++ b/backend/dvadmin/system/views/file_list.py @@ -1,6 +1,9 @@ from rest_framework import serializers +from rest_framework.decorators import action +from rest_framework.parsers import FileUploadParser from dvadmin.system.models import FileList +from dvadmin.utils.json_response import SuccessResponse from dvadmin.utils.serializers import CustomModelSerializer from dvadmin.utils.viewset import CustomModelViewSet @@ -16,6 +19,7 @@ class FileSerializer(CustomModelSerializer): fields = "__all__" def create(self, validated_data): + print(self.context['request']) validated_data['name'] = str(self.initial_data.get('file')) validated_data['url'] = self.initial_data.get('file') return super().create(validated_data) @@ -34,3 +38,8 @@ class FileViewSet(CustomModelViewSet): serializer_class = FileSerializer filter_fields = ['name', ] permission_classes = [] + + @action(detail=False, methods=['post']) + def test_post_file(self, request): + + return SuccessResponse(msg='test_is_ok') diff --git a/backend/dvadmin/system/views/menu.py b/backend/dvadmin/system/views/menu.py index 527ee7e..028ed40 100644 --- a/backend/dvadmin/system/views/menu.py +++ b/backend/dvadmin/system/views/menu.py @@ -117,7 +117,6 @@ class MenuViewSet(CustomModelViewSet): """前端拖拽菜单之后重写parent""" menu_id = request.data['menu_id'] parent_id = request.data['parent_id'] - print(parent_id) menu = Menu.objects.get(id=menu_id) menu.parent_id = parent_id menu.save() diff --git a/backend/dvadmin/system/views/message_center.py b/backend/dvadmin/system/views/message_center.py index ad3c680..96b23c3 100644 --- a/backend/dvadmin/system/views/message_center.py +++ b/backend/dvadmin/system/views/message_center.py @@ -85,7 +85,7 @@ class MessageCenterTargetUserListSerializer(CustomModelSerializer): def get_is_read(self, instance): user_id = self.request.user.id message_center_id = instance.id - queryset = MessageCenterTargetUser.objects.filter(messagecenter__id=message_center_id,users_id=user_id).first() + queryset = MessageCenterTargetUser.objects.filter(messagecenter__id=message_center_id, users_id=user_id).first() if queryset: return queryset.is_read return False @@ -95,21 +95,22 @@ class MessageCenterTargetUserListSerializer(CustomModelSerializer): fields = "__all__" read_only_fields = ["id"] + def websocket_push(user_id, message): """ 主动推送消息 """ - username = "user_"+str(user_id) - print(103,message) + username = "user_" + str(user_id) channel_layer = get_channel_layer() async_to_sync(channel_layer.group_send)( - username, - { - "type": "push.message", - "json": message - } + username, + { + "type": "push.message", + "json": message + } ) + class MessageCenterCreateSerializer(CustomModelSerializer): """ 消息中心-新增-序列化器 @@ -122,10 +123,10 @@ class MessageCenterCreateSerializer(CustomModelSerializer): # 在保存之前,根据目标类型,把目标用户查询出来并保存 users = initial_data.get('target_user', []) if target_type in [1]: # 按角色 - target_role = initial_data.get('target_role',[]) + target_role = initial_data.get('target_role', []) users = Users.objects.filter(role__id__in=target_role).values_list('id', flat=True) if target_type in [2]: # 按部门 - target_dept = initial_data.get('target_dept',[]) + target_dept = initial_data.get('target_dept', []) users = Users.objects.filter(dept__id__in=target_dept).values_list('id', flat=True) if target_type in [3]: # 系统通知 users = Users.objects.values_list('id', flat=True) @@ -141,7 +142,7 @@ class MessageCenterCreateSerializer(CustomModelSerializer): for user in users: unread_count = MessageCenterTargetUser.objects.filter(users__id=user, is_read=False).count() websocket_push(user, message={"sender": 'system', "contentType": 'SYSTEM', - "content": '您有一条新消息~', "unread": unread_count}) + "content": '您有一条新消息~', "unread": unread_count}) return data class Meta: @@ -184,7 +185,7 @@ class MessageCenterViewSet(CustomModelViewSet): # 主动推送消息 unread_count = MessageCenterTargetUser.objects.filter(users__id=user_id, is_read=False).count() websocket_push(user_id, message={"sender": 'system', "contentType": 'TEXT', - "content": '您查看了一条消息~', "unread": unread_count}) + "content": '您查看了一条消息~', "unread": unread_count}) return DetailResponse(data=serializer.data, msg="获取成功") @action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated]) @@ -195,7 +196,6 @@ class MessageCenterViewSet(CustomModelViewSet): self_user_id = self.request.user.id # queryset = MessageCenterTargetUser.objects.filter(users__id=self_user_id).order_by('-create_datetime') queryset = MessageCenter.objects.filter(target_user__id=self_user_id) - print(queryset) # queryset = self.filter_queryset(queryset) page = self.paginate_queryset(queryset) if page is not None: diff --git a/web/package.json b/web/package.json index 93136e9..4349cde 100644 --- a/web/package.json +++ b/web/package.json @@ -45,6 +45,7 @@ "ts-md5": "^1.3.1", "vue": "^3.2.45", "vue-clipboard3": "^2.0.0", + "vue-cropper": "^1.0.8", "vue-grid-layout": "^3.0.0-beta1", "vue-i18n": "^9.2.2", "vue-router": "^4.1.6", diff --git a/web/src/components/avatarSelector/index.vue b/web/src/components/avatarSelector/index.vue new file mode 100644 index 0000000..cafd4d9 --- /dev/null +++ b/web/src/components/avatarSelector/index.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/web/src/stores/interface/index.ts b/web/src/stores/interface/index.ts index 794b603..e60a85f 100644 --- a/web/src/stores/interface/index.ts +++ b/web/src/stores/interface/index.ts @@ -5,11 +5,17 @@ // 用户信息 export interface UserInfosState { - authBtnList: string[]; - photo: string; - roles: string[]; - time: number; + avatar: string; userName: string; + name: string; + email: string; + mobile: string; + gender: string; + dept_info: { + dept_id: number; + dept_name: string; + }; + role_info: any[]; } export interface UserInfosStates { userInfos: UserInfosState; diff --git a/web/src/stores/userInfo.ts b/web/src/stores/userInfo.ts index 88ab8a5..1bfd307 100644 --- a/web/src/stores/userInfo.ts +++ b/web/src/stores/userInfo.ts @@ -11,11 +11,22 @@ import { request } from '../utils/service'; export const useUserInfo = defineStore('userInfo', { state: (): UserInfosStates => ({ userInfos: { + avatar: '', userName: '', - photo: '', - time: 0, - roles: [], - authBtnList: [], + name: '', + email: '', + mobile: '', + gender: '', + dept_info: { + dept_id: 0, + dept_name: '', + }, + role_info: [ + { + id: 0, + name: '', + }, + ], }, }), actions: { @@ -26,17 +37,22 @@ export const useUserInfo = defineStore('userInfo', { } else { let userInfos: any = await this.getApiUserInfo(); this.userInfos.userName = userInfos.data.name; - this.userInfos.photo = userInfos.data.avatar || 'https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500' - this.userInfos.time = new Date().getTime() - this.userInfos.roles = ['admin'] - Session.set('userInfo', this.userInfos) + this.userInfos.avatar = + userInfos.data.avatar || 'https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500'; + this.userInfos.name = userInfos.data.name; + this.userInfos.email = userInfos.data.email; + this.userInfos.mobile = userInfos.data.mobile; + this.userInfos.gender = userInfos.data.gender; + this.userInfos.dept_info = userInfos.data.dept_info; + this.userInfos.role_info = userInfos.data.role_info; + Session.set('userInfo', this.userInfos); } }, async getApiUserInfo() { return request({ url: '/api/system/user/user_info/', method: 'get', - }) - } + }); + }, }, }); diff --git a/web/src/utils/tools.ts b/web/src/utils/tools.ts index 439b927..15645ae 100644 --- a/web/src/utils/tools.ts +++ b/web/src/utils/tools.ts @@ -3,16 +3,16 @@ * @param {String} jsonString 需要解析的 json 字符串 * @param {String} defaultValue 默认值 */ -import { uiContext } from "@fast-crud/fast-crud"; +import { uiContext } from '@fast-crud/fast-crud'; -export function parse(jsonString = "{}", defaultValue = {}) { - let result = defaultValue; - try { - result = JSON.parse(jsonString); - } catch (error) { - console.log(error); - } - return result; +export function parse(jsonString = '{}', defaultValue = {}) { + let result = defaultValue; + try { + result = JSON.parse(jsonString); + } catch (error) { + console.log(error); + } + return result; } /** @@ -21,8 +21,8 @@ export function parse(jsonString = "{}", defaultValue = {}) { * @param {String} msg 状态信息 * @param {Number} code 状态码 */ -export function response(data = {}, msg = "", code = 0) { - return [200, { code, msg, data }]; +export function response(data = {}, msg = '', code = 0) { + return [200, { code, msg, data }]; } /** @@ -30,8 +30,8 @@ export function response(data = {}, msg = "", code = 0) { * @param {Any} data 返回值 * @param {String} msg 状态信息 */ -export function responseSuccess(data = {}, msg = "成功") { - return response(data, msg); +export function responseSuccess(data = {}, msg = '成功') { + return response(data, msg); } /** @@ -40,30 +40,57 @@ export function responseSuccess(data = {}, msg = "成功") { * @param {String} msg 状态信息 * @param {Number} code 状态码 */ -export function responseError(data = {}, msg = "请求失败", code = 500) { - return response(data, msg, code); +export function responseError(data = {}, msg = '请求失败', code = 500) { + return response(data, msg, code); } /** * @description 记录和显示错误 * @param {Error} error 错误对象 */ -export function errorLog(error:any,notification=true) { - // 打印到控制台 - console.error(error); - // 显示提示 - if(notification){ - uiContext.get().notification.error({ message: error.message }); - } - +export function errorLog(error: any, notification = true) { + // 打印到控制台 + console.error(error); + // 显示提示 + if (notification) { + uiContext.get().notification.error({ message: error.message }); + } } /** * @description 创建一个错误 * @param {String} msg 错误信息 */ -export function errorCreate(msg:any,notification=true) { - const error = new Error(msg); - errorLog(error,notification); - // throw error; +export function errorCreate(msg: any, notification = true) { + const error = new Error(msg); + errorLog(error, notification); + // throw error; +} + +export function base64ToFile(base64: any, fileName: string) { + // 将base64按照 , 进行分割 将前缀 与后续内容分隔开 + let data = base64.split(','); + // 利用正则表达式 从前缀中获取图片的类型信息(image/png、image/jpeg、image/webp等) + let type = data[0].match(/:(.*?);/)[1]; + // 从图片的类型信息中 获取具体的文件格式后缀(png、jpeg、webp) + let suffix = type.split('/')[1]; + // 使用atob()对base64数据进行解码 结果是一个文件数据流 以字符串的格式输出 + const bstr = window.atob(data[1]); + // 获取解码结果字符串的长度 + let n = bstr.length; + // 根据解码结果字符串的长度创建一个等长的整形数字数组 + // 但在创建时 所有元素初始值都为 0 + const u8arr = new Uint8Array(n); + // 将整形数组的每个元素填充为解码结果字符串对应位置字符的UTF-16 编码单元 + while (n--) { + // charCodeAt():获取给定索引处字符对应的 UTF-16 代码单元 + u8arr[n] = bstr.charCodeAt(n); + } + // 利用构造函数创建File文件对象 + // new File(bits, name, options) + const file = new File([u8arr], `${fileName}.${suffix}`, { + type: type, + }); + // 将File文件对象返回给方法的调用者 + return file; } diff --git a/web/src/views/system/login/component/account.vue b/web/src/views/system/login/component/account.vue index 6b92ffb..585cf4c 100644 --- a/web/src/views/system/login/component/account.vue +++ b/web/src/views/system/login/component/account.vue @@ -89,8 +89,8 @@ export default defineComponent({ const state = reactive({ isShowPassword: false, ruleForm: { - username: 'superadmin', - password: 'admin123456', + username: '', + password: '', captcha: '', captchaKey: '', captchaImgBase: '', diff --git a/web/src/views/system/personal/api.ts b/web/src/views/system/personal/api.ts index c68e5f2..f5243d8 100644 --- a/web/src/views/system/personal/api.ts +++ b/web/src/views/system/personal/api.ts @@ -1,40 +1,38 @@ import { request } from '/@/utils/service'; import { PageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud'; -import {apiPrefix} from "/@/views/system/messageCenter/api"; +import { apiPrefix } from '/@/views/system/messageCenter/api'; export function GetUserInfo(query: PageQuery) { - return request({ - url: '/api/system/user/user_info/', - method: 'get', - params: query - }); + return request({ + url: '/api/system/user/user_info/', + method: 'get', + params: query, + }); } - /** * 更新用户信息 * @param data */ export function updateUserInfo(data: AddReq) { - return request({ - url: '/api/system/user/update_user_info/', - method: 'put', - data: data - }) + return request({ + url: '/api/system/user/update_user_info/', + method: 'put', + data: data, + }); } - /** * 获取自己接收的消息 * @param query * @returns {*} * @constructor */ -export function GetSelfReceive (query:PageQuery) { - return request({ - url: '/api/system/message_center/get_self_receive/', - method: 'get', - params: query - }) +export function GetSelfReceive(query: PageQuery) { + return request({ + url: '/api/system/message_center/get_self_receive/', + method: 'get', + params: query, + }); } /*** @@ -42,9 +40,24 @@ export function GetSelfReceive (query:PageQuery) { * @param data */ export function UpdatePassword(data: EditReq) { - return request({ - url: '/api/system/user/change_password/', - method: 'put', - data: data - }) + return request({ + url: '/api/system/user/change_password/', + method: 'put', + data: data, + }); +} + +/*** + * 上传头像 + * @param data + */ +export function uploadAvatar(data: AddReq) { + return request({ + url: 'api/system/file/', + method: 'post', + data: data, + headers: { + 'Content-Type': 'multipart/form-data', + }, + }); } diff --git a/web/src/views/system/personal/index.vue b/web/src/views/system/personal/index.vue index 14f53e5..d6d295e 100644 --- a/web/src/views/system/personal/index.vue +++ b/web/src/views/system/personal/index.vue @@ -6,10 +6,9 @@
- - - - + + +
@@ -174,13 +173,18 @@