From 31eefcde578b689955b6ce3bcdc45160302b379f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8C=BF=E5=B0=8F=E5=A4=A9?= <1638245306@qq.com>
Date: Sun, 14 Aug 2022 19:11:21 +0800
Subject: [PATCH 1/4] =?UTF-8?q?=E6=96=B0=E5=8A=9F=E8=83=BD:=20=E5=8A=A0?=
=?UTF-8?q?=E5=85=A5=E6=B6=88=E6=81=AF=E4=B8=AD=E5=BF=83?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/application/asgi.py | 12 +-
backend/application/websocketConfig.py | 114 +++++++
backend/conf/env.example.py | 3 +
backend/dvadmin/system/models.py | 9 +-
.../dvadmin/system/views/message_center.py | 105 ++++++
web/src/api/websocket.js | 69 ++++
web/src/layout/header-aside/layout.vue | 7 +
web/src/views/dashboard/workbench/index.vue | 2 +-
web/src/views/system/messageCenter/api.js | 56 ++++
web/src/views/system/messageCenter/crud.js | 304 ++++++++++++++++++
web/src/views/system/messageCenter/index.vue | 94 ++++++
11 files changed, 768 insertions(+), 7 deletions(-)
create mode 100644 backend/application/websocketConfig.py
create mode 100644 backend/dvadmin/system/views/message_center.py
create mode 100644 web/src/api/websocket.js
create mode 100644 web/src/views/system/messageCenter/api.js
create mode 100644 web/src/views/system/messageCenter/crud.js
create mode 100644 web/src/views/system/messageCenter/index.vue
diff --git a/backend/application/asgi.py b/backend/application/asgi.py
index 2321ae8..c38d873 100644
--- a/backend/application/asgi.py
+++ b/backend/application/asgi.py
@@ -14,4 +14,14 @@ from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
-application = get_asgi_application()
+from application.websocketConfig import websocket_application
+
+http_application = get_asgi_application()
+
+async def application(scope,receive,send):
+ if scope['type'] == 'http':
+ await http_application(scope, receive, send)
+ elif scope['type'] == 'websocket':
+ await websocket_application(scope, receive, send)
+ else:
+ raise Exception("未知的scope类型,"+ scope['type'])
\ No newline at end of file
diff --git a/backend/application/websocketConfig.py b/backend/application/websocketConfig.py
new file mode 100644
index 0000000..eb96d6f
--- /dev/null
+++ b/backend/application/websocketConfig.py
@@ -0,0 +1,114 @@
+# -*- coding: utf-8 -*-
+import django
+
+django.setup()
+import json
+import urllib
+
+#处理websocket传参
+from jwt import InvalidSignatureError
+
+from application import settings
+from dvadmin.system.models import MessageCenter
+
+
+def request_data(scope):
+ query_string = scope.get('query_string', b'').decode('utf-8')
+ qs = urllib.parse.parse_qs(query_string)
+ return qs
+
+
+# 全部的websocket sender
+CONNECTIONS = {}
+
+
+# 判断用户是否已经连接
+def check_connection(key):
+ return key in CONNECTIONS
+
+
+# 发送消息结构体
+def message(sender, msg_type, msg):
+ text = json.dumps({
+ 'sender': sender,
+ 'contentType': msg_type,
+ 'content': msg,
+ })
+ return {
+ 'type': 'websocket.send',
+ 'text': text
+ }
+
+
+async def websocket_application(scope, receive, send):
+ while True:
+ event = await receive()
+ # print('[event] ', event)
+ qs = request_data(scope)
+ print(1,qs)
+ auth = qs.get('auth', [''])[0]
+ user_id = None
+ # 收到建立WebSocket连接的消息
+ if event['type'] == 'websocket.connect':
+ # 昵称验证
+ if not auth:
+ break
+ else:
+ try:
+ import jwt
+ decoded_result = jwt.decode(auth, settings.SECRET_KEY, algorithms=["HS256"])
+ if decoded_result:
+ user_id = decoded_result.get('user_id')
+ # 记录
+ CONNECTIONS[user_id] = send
+ except InvalidSignatureError:
+ break
+ if auth in CONNECTIONS:
+ break
+
+ await send({'type': 'websocket.accept'})
+ await send(message('system', 'INFO', '连接成功'))
+ # # 发送好友列表
+ # friends_list = list(CONNECTIONS.keys())
+ # await send(message('system', 'INFO', friends_list))
+ #
+ # # 向其他人群发消息, 有人登录了
+ # for other in CONNECTIONS.values():
+ # await other(message('system', 'addFriend', auth))
+
+
+ # 收到中断WebSocket连接的消息
+ elif event['type'] == 'websocket.disconnect':
+ # 移除记录
+ if user_id in CONNECTIONS:
+ CONNECTIONS.pop(user_id)
+
+ # # 向其他人群发消息, 有人离线了
+ # for other in CONNECTIONS.values():
+ # await other(message('system', 'removeFriend', user_id))
+
+ # 其他情况,正常的WebSocket消息
+ elif event['type'] == 'websocket.receive':
+ print(11,event)
+ if event['text'] == 'ping':
+ await send(message('system', 'text', 'pong!'))
+ else:
+ receive_msg = json.loads(event['text'])
+ message_id = receive_msg.get('message_id', None)
+ _MessageCenter = MessageCenter.objects.filter(id=message_id).first()
+ if _MessageCenter:
+ user_list = _MessageCenter.target_user.values_list('id',flat=True)
+ for send_user in user_list:
+ if send_user in CONNECTIONS:
+ content_type = receive_msg.get('contentType', 'TEXT')
+ content = receive_msg.get('content', '')
+ msg = message(user_id, content_type, content)
+ await CONNECTIONS[send_user](msg)
+ else:
+ msg = message('system', 'text', '对方已下线或不存在')
+ await send(msg)
+ else:
+ print('a1a1a1')
+ pass
+
+ print('[disconnect]')
\ No newline at end of file
diff --git a/backend/conf/env.example.py b/backend/conf/env.example.py
index 2ea54f7..829b73a 100644
--- a/backend/conf/env.example.py
+++ b/backend/conf/env.example.py
@@ -44,3 +44,6 @@ LOGIN_NO_CAPTCHA_AUTH = True
# ================================================= #
ALLOWED_HOSTS = ["*"]
+
+# daphne启动命令
+#daphne application.asgi:application -b 0.0.0.0 -p 8000
diff --git a/backend/dvadmin/system/models.py b/backend/dvadmin/system/models.py
index 77f530d..1bc6273 100644
--- a/backend/dvadmin/system/models.py
+++ b/backend/dvadmin/system/models.py
@@ -416,10 +416,10 @@ class MessageCenter(CoreModel):
title = models.CharField(max_length=100,verbose_name="标题",help_text="标题")
content = models.TextField(verbose_name="内容",help_text="内容")
target_type=models.IntegerField(default=0,verbose_name="目标类型",help_text="目标类型")
- target_user = models.ForeignKey(to=Users,related_name="target_user",null=True,blank=True,db_constraint=False,on_delete=models.CASCADE,verbose_name="目标用户",help_text="目标用户")
- target_dept = models.ForeignKey(to=Dept, null=True, blank=True, db_constraint=False, on_delete=models.CASCADE,
+ target_user = models.ManyToManyField(to=Users,related_name="target_user",blank=True,db_constraint=False,verbose_name="目标用户",help_text="目标用户")
+ target_dept = models.ManyToManyField(to=Dept, null=True, blank=True, db_constraint=False,
verbose_name="目标部门", help_text="目标部门")
- target_role = models.ForeignKey(to=Role, null=True, blank=True, db_constraint=False, on_delete=models.CASCADE,
+ target_role = models.ManyToManyField(to=Role, blank=True, db_constraint=False,
verbose_name="目标角色", help_text="目标角色")
is_read=models.BooleanField(default=False,blank=True,verbose_name="是否已读",help_text="是否已读")
@@ -427,5 +427,4 @@ class MessageCenter(CoreModel):
db_table = table_prefix + "message_center"
verbose_name = "消息中心"
verbose_name_plural = verbose_name
- ordering = ("-create_datetime",)
-
+ ordering = ("-create_datetime",)
\ No newline at end of file
diff --git a/backend/dvadmin/system/views/message_center.py b/backend/dvadmin/system/views/message_center.py
new file mode 100644
index 0000000..3571e9c
--- /dev/null
+++ b/backend/dvadmin/system/views/message_center.py
@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+from itertools import chain
+
+from django_restql.fields import DynamicSerializerMethodField
+from rest_framework.decorators import action, permission_classes
+from rest_framework.permissions import IsAuthenticated, AllowAny
+
+from dvadmin.system.models import MessageCenter, Users
+from dvadmin.system.views.role import RoleSerializer
+from dvadmin.system.views.user import UserSerializer
+from dvadmin.utils.json_response import SuccessResponse
+from dvadmin.utils.serializers import CustomModelSerializer
+from dvadmin.utils.viewset import CustomModelViewSet
+
+
+class MessageCenterSerializer(CustomModelSerializer):
+ """
+ 消息中心-序列化器
+ """
+ role_info = DynamicSerializerMethodField()
+ user_info = DynamicSerializerMethodField()
+ def get_role_info(self, instance, parsed_query):
+ roles =instance.target_role.all()
+ # You can do what ever you want in here
+ # `parsed_query` param is passed to BookSerializer to allow further querying
+ serializer = RoleSerializer(
+ roles,
+ many=True,
+ parsed_query=parsed_query
+ )
+ return serializer.data
+
+ def get_user_info(self, instance, parsed_query):
+ users = instance.target_user.all()
+ # You can do what ever you want in here
+ # `parsed_query` param is passed to BookSerializer to allow further querying
+ serializer = UserSerializer(
+ users,
+ many=True,
+ parsed_query=parsed_query
+ )
+ return serializer.data
+
+ class Meta:
+ model = MessageCenter
+ fields = "__all__"
+ read_only_fields = ["id"]
+
+
+class MessageCenterCreateSerializer(CustomModelSerializer):
+ """
+ 消息中心-新增-序列化器
+ """
+
+ def save(self, **kwargs):
+ data = super().save(**kwargs)
+ initial_data = self.initial_data
+ target_type = initial_data.get('target_type')
+ # 在保存之前,根据目标类型,把目标用户查询出来并保存
+ users = initial_data.get('target_user',[])
+ if target_type in [1]:
+ target_role = initial_data.get('target_role')
+ users = Users.objects.exclude(is_deleted=True).filter(role__id__in=target_role).values_list('id',flat=True)
+ if target_type in [2]:
+ target_dept = initial_data.get('target_dept')
+ users = Users.objects.exclude(is_deleted=True).filter(dept__id__in=target_dept).values_list('id',flat=True)
+ data.save()
+ data.target_user.set(users)
+ return data
+
+ class Meta:
+ model = MessageCenter
+ fields = "__all__"
+ read_only_fields = ["id"]
+
+
+
+
+class MessageCenterViewSet(CustomModelViewSet):
+ """
+ 消息中心接口
+ list:查询
+ create:新增
+ update:修改
+ retrieve:单例
+ destroy:删除
+ """
+ queryset = MessageCenter.objects.all()
+ serializer_class = MessageCenterSerializer
+ create_serializer_class = MessageCenterCreateSerializer
+ extra_filter_backends = []
+
+ @action(methods=['GET'],detail=False,permission_classes=[IsAuthenticated])
+ def get_self_receive(self,request):
+ """
+ 获取接收到的消息
+ """
+ self_user_id = self.request.user.id
+ queryset = MessageCenter.objects.filter(target_user__id=self_user_id)
+ page = self.paginate_queryset(queryset)
+ if page is not None:
+ serializer = self.get_serializer(page, many=True, request=request)
+ return self.get_paginated_response(serializer.data)
+ serializer = self.get_serializer(queryset, many=True, request=request)
+ return SuccessResponse(data=serializer.data, msg="获取成功")
\ No newline at end of file
diff --git a/web/src/api/websocket.js b/web/src/api/websocket.js
new file mode 100644
index 0000000..e6e52cc
--- /dev/null
+++ b/web/src/api/websocket.js
@@ -0,0 +1,69 @@
+import ElementUI from 'element-ui'
+import util from '@/libs/util'
+function initWebSocket (e) {
+ const token = util.cookies.get('token')
+ if (token) {
+ const wsUri = 'ws://127.0.0.1:8000/?auth=' + token
+ this.socket = new WebSocket(wsUri)// 这里面的this都指向vue
+ this.socket.onerror = webSocketOnError
+ this.socket.onmessage = webSocketOnMessage
+ this.socket.onclose = closeWebsocket
+ }
+}
+
+function webSocketOnError (e) {
+ ElementUI.Notification({
+ title: '',
+ message: 'WebSocket连接发生错误' + JSON.stringify(e),
+ type: 'error',
+ duration: 0
+ })
+}
+function webSocketOnMessage (e) {
+ const data = JSON.parse(e.data)
+ if (data.contentType === 'INFO') {
+ ElementUI.Notification({
+ title: 'websocket',
+ message: data.content,
+ type: 'success',
+ position: 'bottom-right',
+ duration: 3000
+ })
+ } else if (data.contentType === 'ERROR') {
+ ElementUI.Notification({
+ title: '',
+ message: data.content,
+ type: 'error',
+ position: 'bottom-right',
+ duration: 0
+ })
+ } else if (data.contentType === 'TEXT') {
+ ElementUI.Notification({
+ title: '温馨提示',
+ message: data.content,
+ type: 'success',
+ position: 'bottom-right',
+ duration: 0
+ })
+ } else {
+ console.log(data.content)
+ }
+}
+// 关闭websiocket
+function closeWebsocket () {
+ console.log('连接已关闭...')
+ close()
+}
+function close () {
+ this.socket.close() // 关闭 websocket
+ this.socket.onclose = function (e) {
+ console.log(e)// 监听关闭事件
+ console.log('关闭')
+ }
+}
+function webSocketSend (message) {
+ this.socket.send(JSON.stringify(message))
+}
+export default {
+ initWebSocket, close,webSocketSend
+}
diff --git a/web/src/layout/header-aside/layout.vue b/web/src/layout/header-aside/layout.vue
index 5370c16..4d7d312 100644
--- a/web/src/layout/header-aside/layout.vue
+++ b/web/src/layout/header-aside/layout.vue
@@ -191,6 +191,13 @@ export default {
this.showView = true // DOM更新后再通过v-if添加router-view节点
})
}
+ },
+ mounted () {
+ this.$websocket.initWebSocket()
+ },
+ destroyed () {
+ // 离开路由之后断开websocket连接
+ this.$websocket.close()
}
}
diff --git a/web/src/views/dashboard/workbench/index.vue b/web/src/views/dashboard/workbench/index.vue
index 9c15a8d..4719057 100644
--- a/web/src/views/dashboard/workbench/index.vue
+++ b/web/src/views/dashboard/workbench/index.vue
@@ -217,7 +217,7 @@ export default {
gotoRoute (route) {
this.$router.push(route)
}
- }
+ },
}
diff --git a/web/src/views/system/messageCenter/api.js b/web/src/views/system/messageCenter/api.js
new file mode 100644
index 0000000..7d108b8
--- /dev/null
+++ b/web/src/views/system/messageCenter/api.js
@@ -0,0 +1,56 @@
+import { request } from '@/api/service'
+export const urlPrefix = '/api/system/message_center/'
+export function GetList (query) {
+ return request({
+ url: urlPrefix,
+ method: 'get',
+ params: query
+ })
+}
+
+/**
+ * 获取自己接收的消息
+ * @param query
+ * @returns {*}
+ * @constructor
+ */
+export function GetSelfReceive (query) {
+ return request({
+ url: urlPrefix + 'get_self_receive/',
+ method: 'get',
+ params: query
+ })
+}
+
+
+
+export function GetObj (obj) {
+ return request({
+ url: urlPrefix + obj.id + '/',
+ method: 'get',
+ params: {}
+ })
+}
+
+export function AddObj (obj) {
+ return request({
+ url: urlPrefix,
+ method: 'post',
+ data: obj
+ })
+}
+
+export function UpdateObj (obj) {
+ return request({
+ url: urlPrefix + obj.id + '/',
+ method: 'put',
+ data: obj
+ })
+}
+export function DelObj (id) {
+ return request({
+ url: urlPrefix + id + '/',
+ method: 'delete',
+ data: { id }
+ })
+}
diff --git a/web/src/views/system/messageCenter/crud.js b/web/src/views/system/messageCenter/crud.js
new file mode 100644
index 0000000..5789209
--- /dev/null
+++ b/web/src/views/system/messageCenter/crud.js
@@ -0,0 +1,304 @@
+import { request } from '@/api/service'
+
+export const crudOptions = (vm) => {
+ return {
+ indexRow: { // 或者直接传true,不显示title,不居中
+ title: '序号',
+ align: 'center'
+ },
+ options: {
+ height: '100%' // 表格高度100%, 使用toolbar必须设置
+ },
+ viewOptions: {
+ },
+ columns: [
+ {
+ title: 'id',
+ key: 'id',
+ sortable: true,
+ width: 100,
+ form: { disabled: true }
+ },
+ {
+ title: '标题',
+ key: 'title',
+ search: {
+ disabled: false
+ },
+ width: 400,
+ form: {
+ rules: [ // 表单校验规则
+ {
+ required: true,
+ message: '必填项'
+ }
+ ],
+ component: { span: 24 }
+ }
+ },
+ {
+ title: '目标类型',
+ key: 'target_type',
+ type: 'radio',
+ dict: { data: [{ value: 0, label: '按用户' }, { value: 1, label: '按角色' }, { value: 2, label: '按部门' }] },
+ form: {
+ itemProps: {
+ class: { yxtInput: true }
+ },
+ rules: [
+ {
+ required: true,
+ message: '必选项',
+ trigger: ['blur', 'change']
+ }
+ ]
+ }
+ },
+ {
+ title: '目标用户',
+ key: 'target_user',
+ search: {
+ disabled: true
+ },
+ minWidth: 130,
+ type: 'table-selector',
+ dict: {
+ cache: false,
+ url: '/api/system/user/',
+ value: 'id', // 数据字典中value字段的属性名
+ label: 'name', // 数据字典中label字段的属性名
+ getData: (url, dict, {
+ form,
+ component
+ }) => {
+ return request({
+ url: url,
+ params: {
+ page: 1,
+ limit: 10
+ }
+ }).then(ret => {
+ component._elProps.page = ret.data.page
+ component._elProps.limit = ret.data.limit
+ component._elProps.total = ret.data.total
+ return ret.data.data
+ })
+ }
+ },
+ form: {
+ rules: [ // 表单校验规则
+ {
+ required: true,
+ message: '必填项'
+ }
+ ],
+ itemProps: {
+ class: { yxtInput: true }
+ },
+ component: {
+ span: 24,
+ show (context) {
+ return context.form.target_type === 0
+ },
+ pagination: true,
+ props: { multiple: true },
+ elProps: {
+ columns: [
+ {
+ field: 'name',
+ title: '用户名称'
+ },
+ {
+ field: 'phone',
+ title: '用户电话'
+ }
+ ]
+ }
+ }
+ },
+ component: {
+ name: 'manyToMany',
+ valueBinding: 'user_info',
+ children: 'name'
+ }
+ },
+ {
+ title: '目标角色',
+ key: 'target_role',
+ search: {
+ disabled: true
+ },
+
+ minWidth: 130,
+ type: 'table-selector',
+ dict: {
+ cache: false,
+ url: '/api/system/role/',
+ value: 'id', // 数据字典中value字段的属性名
+ label: 'name', // 数据字典中label字段的属性名
+ getData: (url, dict, {
+ form,
+ component
+ }) => {
+ return request({
+ url: url,
+ params: {
+ page: 1,
+ limit: 10
+ }
+ }).then(ret => {
+ component._elProps.page = ret.data.page
+ component._elProps.limit = ret.data.limit
+ component._elProps.total = ret.data.total
+ return ret.data.data
+ })
+ }
+ },
+ form: {
+ rules: [ // 表单校验规则
+ {
+ required: true,
+ message: '必填项'
+ }
+ ],
+ itemProps: {
+ class: { yxtInput: true }
+ },
+ component: {
+ span: 24,
+ show (context) {
+ return context.form.target_type === 1
+ },
+ pagination: true,
+ props: { multiple: true },
+ elProps: {
+ columns: [
+ {
+ field: 'name',
+ title: '角色名称'
+ },
+ {
+ field: 'key',
+ title: '权限标识'
+ }
+ ]
+ }
+ }
+ },
+ component: {
+ name: 'manyToMany',
+ valueBinding: 'role_info',
+ children: 'name'
+ }
+ },
+ {
+ title: '目标部门',
+ key: 'target_dept',
+ search: {
+ disabled: true
+ },
+ minWidth: 130,
+ type: 'table-selector',
+ dict: {
+ cache: false,
+ url: '/api/system/dept/',
+ isTree: true,
+ value: 'id', // 数据字典中value字段的属性名
+ label: 'name', // 数据字典中label字段的属性名
+ children: 'children', // 数据字典中children字段的属性名
+ getData: (url, dict, {
+ form,
+ component
+ }) => {
+ return request({
+ url: url,
+ params: {
+ page: 1,
+ limit: 999
+ }
+ }).then(ret => {
+ return ret.data.data
+ })
+ }
+ },
+ form: {
+ rules: [ // 表单校验规则
+ {
+ required: true,
+ message: '必填项'
+ }
+ ],
+ itemProps: {
+ class: { yxtInput: true }
+ },
+ component: {
+ span: 24,
+ show (context) {
+ return context.form.target_type === 2
+ },
+ props: {
+ multiple: true,
+ elProps: {
+ treeConfig: {
+ transform: true,
+ rowField: 'id',
+ parentField: 'parent',
+ expandAll: true
+ },
+ columns: [
+ {
+ field: 'name',
+ title: '部门名称',
+ treeNode: true
+ },
+ {
+ field: 'status_label',
+ title: '状态'
+ },
+ {
+ field: 'parent_name',
+ title: '父级部门'
+ }
+ ]
+ }
+ }
+ }
+ },
+ component: {
+ name: 'manyToMany',
+ valueBinding: 'dept_info',
+ children: 'name'
+ }
+ },
+ {
+ title: '内容',
+ key: 'content',
+ width: 300,
+ type: 'editor-quill', // 富文本图片上传依赖file-uploader,请先配置好file-uploader
+ form: {
+ rules: [ // 表单校验规则
+ {
+ required: true,
+ message: '必填项'
+ }
+ ],
+ component: {
+ disabled: () => {
+ return vm.getEditForm().disable
+ },
+ props: {
+ uploader: {
+ type: 'form' // 上传后端类型【cos,aliyun,oss,form】
+ }
+ },
+ events: {
+ 'text-change': (event) => {
+ console.log('text-change:', event)
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/web/src/views/system/messageCenter/index.vue b/web/src/views/system/messageCenter/index.vue
new file mode 100644
index 0000000..46960a5
--- /dev/null
+++ b/web/src/views/system/messageCenter/index.vue
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+ 新增
+
+
+
+
+
+
+
+
+
+
+
+
From 63c6188591b91f10f345c7a59aff5c0d32e9b6fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8C=BF=E5=B0=8F=E5=A4=A9?= <1638245306@qq.com>
Date: Sun, 14 Aug 2022 19:19:17 +0800
Subject: [PATCH 2/4] =?UTF-8?q?=E6=96=B0=E5=8A=9F=E8=83=BD:=20=E5=8A=A0?=
=?UTF-8?q?=E5=85=A5=E6=B6=88=E6=81=AF=E4=B8=AD=E5=BF=83?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../dvadmin/system/fixtures/init_menu.json | 49 ++++++++++++++++++-
web/src/views/system/messageCenter/crud.js | 3 --
2 files changed, 48 insertions(+), 4 deletions(-)
diff --git a/backend/dvadmin/system/fixtures/init_menu.json b/backend/dvadmin/system/fixtures/init_menu.json
index 0eeedd2..2ecd57d 100644
--- a/backend/dvadmin/system/fixtures/init_menu.json
+++ b/backend/dvadmin/system/fixtures/init_menu.json
@@ -272,10 +272,57 @@
}
]
},
+ {
+ "name": "消息中心",
+ "icon": "bullhorn",
+ "sort": 7,
+ "is_link": false,
+ "is_catalog": false,
+ "web_path": "/messageCenter",
+ "component": "system/messageCenter/index",
+ "component_name": "messageCenter",
+ "status": true,
+ "cache": false,
+ "visible": true,
+ "parent": 277,
+ "children": [],
+ "menu_button": [
+ {
+ "name": "查询",
+ "value": "Search",
+ "api": "/api/system/message_center/",
+ "method": 0
+ },
+ {
+ "name": "详情",
+ "value": "Retrieve",
+ "api": "/api/system/message_center/{id}/",
+ "method": 0
+ },
+ {
+ "name": "新增",
+ "value": "Create",
+ "api": "/api/system/message_center/",
+ "method": 1
+ },
+ {
+ "name": "编辑",
+ "value": "Update",
+ "api": "/api/system/message_center/{id}/",
+ "method": 2
+ },
+ {
+ "name": "删除",
+ "value": "Delete",
+ "api": "/api/system/menu/{id}/",
+ "method": 3
+ }
+ ]
+ },
{
"name": "接口白名单",
"icon": "compass",
- "sort": 7,
+ "sort": 8,
"is_link": false,
"is_catalog": false,
"web_path": "/apiWhiteList",
diff --git a/web/src/views/system/messageCenter/crud.js b/web/src/views/system/messageCenter/crud.js
index 5789209..abed551 100644
--- a/web/src/views/system/messageCenter/crud.js
+++ b/web/src/views/system/messageCenter/crud.js
@@ -42,9 +42,6 @@ export const crudOptions = (vm) => {
type: 'radio',
dict: { data: [{ value: 0, label: '按用户' }, { value: 1, label: '按角色' }, { value: 2, label: '按部门' }] },
form: {
- itemProps: {
- class: { yxtInput: true }
- },
rules: [
{
required: true,
From 888a3b73e84ccd1076c04704b4406c6a9b12fcde Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8C=BF=E5=B0=8F=E5=A4=A9?= <1638245306@qq.com>
Date: Sun, 14 Aug 2022 19:21:35 +0800
Subject: [PATCH 3/4] =?UTF-8?q?=E6=96=B0=E5=8A=9F=E8=83=BD:=20=E5=8A=A0?=
=?UTF-8?q?=E5=85=A5=E6=B6=88=E6=81=AF=E4=B8=AD=E5=BF=83?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/dvadmin/system/models.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/backend/dvadmin/system/models.py b/backend/dvadmin/system/models.py
index 1bc6273..734a468 100644
--- a/backend/dvadmin/system/models.py
+++ b/backend/dvadmin/system/models.py
@@ -34,8 +34,8 @@ class Users(CoreModel,AbstractUser):
user_type = models.IntegerField(
choices=USER_TYPE, default=0, verbose_name="用户类型", null=True, blank=True, help_text="用户类型"
)
- post = models.ManyToManyField(to="Post", verbose_name="关联岗位", db_constraint=False, help_text="关联岗位")
- role = models.ManyToManyField(to="Role", verbose_name="关联角色", db_constraint=False, help_text="关联角色")
+ post = models.ManyToManyField(to="Post",blank=True, verbose_name="关联岗位", db_constraint=False, help_text="关联岗位")
+ role = models.ManyToManyField(to="Role", blank=True,verbose_name="关联角色", db_constraint=False, help_text="关联角色")
dept = models.ForeignKey(
to="Dept",
verbose_name="所属部门",
From ef2025f157343e739fb06719af58ae67c979bf78 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8C=BF=E5=B0=8F=E5=A4=A9?= <1638245306@qq.com>
Date: Sun, 14 Aug 2022 19:34:25 +0800
Subject: [PATCH 4/4] =?UTF-8?q?=E6=96=B0=E5=8A=9F=E8=83=BD:=20=E5=8A=A0?=
=?UTF-8?q?=E5=85=A5=E6=B6=88=E6=81=AF=E4=B8=AD=E5=BF=83?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
web/src/api/websocket.js | 2 +-
web/src/views/dashboard/workbench/index.vue | 2 +-
web/src/views/system/messageCenter/api.js | 2 --
web/src/views/system/messageCenter/index.vue | 6 +++---
4 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/web/src/api/websocket.js b/web/src/api/websocket.js
index e6e52cc..e324f12 100644
--- a/web/src/api/websocket.js
+++ b/web/src/api/websocket.js
@@ -65,5 +65,5 @@ function webSocketSend (message) {
this.socket.send(JSON.stringify(message))
}
export default {
- initWebSocket, close,webSocketSend
+ initWebSocket, close, webSocketSend
}
diff --git a/web/src/views/dashboard/workbench/index.vue b/web/src/views/dashboard/workbench/index.vue
index 4719057..9c15a8d 100644
--- a/web/src/views/dashboard/workbench/index.vue
+++ b/web/src/views/dashboard/workbench/index.vue
@@ -217,7 +217,7 @@ export default {
gotoRoute (route) {
this.$router.push(route)
}
- },
+ }
}
diff --git a/web/src/views/system/messageCenter/api.js b/web/src/views/system/messageCenter/api.js
index 7d108b8..384a787 100644
--- a/web/src/views/system/messageCenter/api.js
+++ b/web/src/views/system/messageCenter/api.js
@@ -22,8 +22,6 @@ export function GetSelfReceive (query) {
})
}
-
-
export function GetObj (obj) {
return request({
url: urlPrefix + obj.id + '/',
diff --git a/web/src/views/system/messageCenter/index.vue b/web/src/views/system/messageCenter/index.vue
index 46960a5..d0f84fe 100644
--- a/web/src/views/system/messageCenter/index.vue
+++ b/web/src/views/system/messageCenter/index.vue
@@ -26,7 +26,7 @@