diff --git a/backend/README.md b/backend/README.md
index 71093a9..4990c28 100644
--- a/backend/README.md
+++ b/backend/README.md
@@ -21,7 +21,7 @@
4. 设置数据库不区分大小写:修改配置文件my.cnf 的[mysqld]中增加 lower_case_table_names = 1
5. 安装依赖环境
- pip install -r requirements_linux.txt -i https://mirrors.aliyun.com/pypi/simple/
+ pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
6. 数据初始化使用sql脚本直接导入(本sql脚本使用的是SQL_Front5.3工具配合mysql5.7数据库导出的)
sql脚本位置:backend/lyadmin_pro.sql
diff --git a/backend/application/settings.py b/backend/application/settings.py
index 10f037f..da63761 100644
--- a/backend/application/settings.py
+++ b/backend/application/settings.py
@@ -325,7 +325,7 @@ X_FRAME_OPTIONS = 'SAMEORIGIN'#SAMEORIGIN允许同源iframe嵌套、 DENY不允
# "accept-encoding",
# "lypage"
# )
-
+CORS_EXPOSE_HEADERS = ['Content-Disposition'] # Content-Disposition 头部添加到 Access-Control-Expose-Headers 中,允许客户端 JavaScript 访问该头部
# ================================================= #
# ********************* 日志配置 ******************* #
# ================================================= #
@@ -441,7 +441,7 @@ REST_FRAMEWORK = {
# 'user': '60/minute' #已登录用户每分钟可以请求60次
# },
'EXCEPTION_HANDLER': 'utils.exception.CustomExceptionHandler', # 自定义的异常处理
- #线上部署正式环境,关闭web接口测试页面
+ # #线上部署正式环境,关闭web接口测试页面
# 'DEFAULT_RENDERER_CLASSES':(
# 'rest_framework.renderers.JSONRenderer',
# ),
@@ -557,6 +557,7 @@ API_MODEL_MAP = {
"/api/token/": "登录模块",
"/api/super/operate/":"前端API关闭开启",
"/api/platformsettings/uploadplatformimg/":"图片上传",
+ "/api/system/fileManage/":"文件管理"
}
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
diff --git a/backend/application/urls.py b/backend/application/urls.py
index a852524..3e82941 100644
--- a/backend/application/urls.py
+++ b/backend/application/urls.py
@@ -41,6 +41,10 @@ from apps.lyTiktokUnion.views.douyinMsgWebhook import DouyinAllianceDarenOrderWe
from apps.lyTiktokUnion.views.doudianCallback import *
from apps.lyTiktokUnion.views.dySystemAccountViews import DouyinSytemDarenCodeCallbackView
+#文件管理
+
+from mysystem.views.file_manage import RYFileMediaView,RYGetFileDownloadView
+
#字典信息数据获取
from mysystem.views.dictionary import GetDictionaryInfoView,GetDictionaryAllView
#app下载页
@@ -97,6 +101,10 @@ urlpatterns = [
path('api/lyformbuilder/', include('apps.lyFormBuilder.urls')),
path('api/lytiktokunion/', include('apps.lyTiktokUnion.urls')),
path('api/workflow/', include('apps.lyworkflow.urls')),
+
+ #文件管理
+ path('api/fileMedia/', RYFileMediaView.as_view(), name='file_media'),
+ path('api/download/', RYGetFileDownloadView.as_view(), name='download'),
# ========================================================================================= #
# ********************************** 前端微服务API用户接口************************************ #
diff --git a/backend/apps/lymessages/urls.py b/backend/apps/lymessages/urls.py
index 7ab8df0..4f2819e 100644
--- a/backend/apps/lymessages/urls.py
+++ b/backend/apps/lymessages/urls.py
@@ -13,9 +13,9 @@ system_url = routers.SimpleRouter()
system_url.register(r'messagetemplate', MyMessageTemplateViewSet)
system_url.register(r'messagenotice', MyMessageViewSet)
-
-
urlpatterns = [
-
+ path('messagenotice/ownmsg/',MyMessageViewSet.as_view({'get':'get_own_receive'}), name='获取自己的消息列表'),
+ path('messagenotice/delownmsg/',MyMessageViewSet.as_view({'post':'del_own_receive'}), name='删除自己的消息'),
+ path('messagenotice/readownmsg/',MyMessageViewSet.as_view({'post':'read_own_receive'}), name='设置自己的消息已读'),
]
urlpatterns += system_url.urls
\ No newline at end of file
diff --git a/backend/apps/lymessages/views.py b/backend/apps/lymessages/views.py
index 9815c25..24e8727 100644
--- a/backend/apps/lymessages/views.py
+++ b/backend/apps/lymessages/views.py
@@ -12,6 +12,8 @@ from rest_framework.permissions import IsAuthenticated
from utils.pagination import CustomPagination
from django.db import transaction
import datetime
+from asgiref.sync import async_to_sync
+from channels.layers import get_channel_layer
# ================================================= #
# ************** 后台消息中心 view ************** #
@@ -67,6 +69,20 @@ class MyMessageSerializer(CustomModelSerializer):
fields = '__all__'
# exclude = ['password']
+def websocket_push(user_id, message):
+ """
+ 主动推送消息
+ """
+ room_group_name = "notifications_user_" + str(user_id)
+ channel_layer = get_channel_layer()
+ async_to_sync(channel_layer.group_send)(
+ room_group_name,
+ {
+ "type": "push.message",
+ "json": message
+ }
+ )
+
class MyMessageCreateUpdateSerializer(CustomModelSerializer):
"""
消息公告 -序列化器
@@ -98,6 +114,9 @@ class MyMessageCreateUpdateSerializer(CustomModelSerializer):
targetuser_instance = MyMessageUserSerializer(data=targetuser_data, many=True, request=self.request)
targetuser_instance.is_valid(raise_exception=True)
targetuser_instance.save()
+ for user in users:
+ unread_nums = MyMessageUser.objects.filter(revuserid_id=user, is_read=False,is_delete=False).count()
+ websocket_push(user, message={"sender": 'system', "msg_type": 'SYS',"content": '您有一条新消息~', "unread": unread_nums})
return data
class Meta:
@@ -106,6 +125,28 @@ class MyMessageCreateUpdateSerializer(CustomModelSerializer):
fields = '__all__'
# exclude = ['password']
+
+class MyMessageListSerializer(CustomModelSerializer):
+ """
+ 用户消息列表序列化器-序列化器
+ """
+
+ class Meta:
+ model = MyMessage
+ fields = ("id","target_type","msg_title","msg_content")
+ read_only_fields = ["id"]
+
+class MyMessageUserListSerializer(CustomModelSerializer):
+ """
+ 目标用户序列化器-序列化器
+ """
+ messageid = MyMessageListSerializer()
+
+ class Meta:
+ model = MyMessageUser
+ fields = "__all__"
+ read_only_fields = ["id"]
+
class MyMessageViewSet(CustomModelViewSet):
"""
后台消息公告 接口:
@@ -116,6 +157,39 @@ class MyMessageViewSet(CustomModelViewSet):
update_serializer_class = MyMessageCreateUpdateSerializer
filterset_fields = ('msg_title',)
search_fields = ('msg_title',)
+
+ def get_own_receive(self, request):
+ """
+ 获取自己的接收消息
+ """
+ own_id = self.request.user.id
+ queryset = MyMessageUser.objects.filter(revuserid_id=own_id)
+ page = self.paginate_queryset(queryset)
+ if page is not None:
+ serializer = MyMessageUserListSerializer(page, many=True, request=request)
+ return self.get_paginated_response(serializer.data)
+ serializer = MyMessageUserListSerializer(queryset, many=True, request=request)
+ return SuccessResponse(data=serializer.data, msg="获取成功")
+
+ def del_own_receive(self, request):
+ """
+ 删除自己的接收消息
+ """
+ reqData = get_parameter_dic(request)
+ id = reqData.get("id")
+ own_id = self.request.user.id
+ MyMessageUser.objects.filter(id=id,revuserid_id=own_id).delete()
+ return SuccessResponse(msg="删除成功")
+
+ def read_own_receive(self, request):
+ """
+ 设置自己的接收消息已读
+ """
+ reqData = get_parameter_dic(request)
+ id = reqData.get("id")
+ own_id = self.request.user.id
+ MyMessageUser.objects.filter(id=id,revuserid_id=own_id,is_read=False).update(is_read=True,read_at=datetime.datetime.now())
+ return SuccessResponse(msg="删除成功")
def send_sys_template_message(revuser,code):
"""
diff --git a/backend/apps/lymessages/wsmessage.py b/backend/apps/lymessages/wsmessage.py
new file mode 100644
index 0000000..e2bfb0e
--- /dev/null
+++ b/backend/apps/lymessages/wsmessage.py
@@ -0,0 +1,60 @@
+import json
+from asgiref.sync import sync_to_async, async_to_sync
+from channels.db import database_sync_to_async
+from channels.generic.websocket import AsyncJsonWebsocketConsumer
+
+@database_sync_to_async
+def _get_message_unread_count(user):
+ """获取用户的未读消息数量"""
+ from apps.lymessages.models import MyMessageUser
+ count = MyMessageUser.objects.filter(revuserid=user, is_read=False, is_delete=False).count()
+ return count or 0
+
+def set_message(sender, msg_type, msg, unread=0):
+ text = {
+ 'sender': sender,
+ 'msg_type': msg_type,
+ 'content': msg,
+ 'unread': unread
+ }
+ return text
+
+
+class NotificationConsumer(AsyncJsonWebsocketConsumer):
+ async def connect(self):
+ try:
+ self.user = self.scope.get('user',None)
+ room_name = "user_" + str(self.user.id)
+ self.room_group_name = f'notifications_{room_name}'
+ await self.channel_layer.group_add(
+ self.room_group_name,
+ self.channel_name
+ )
+
+ await self.accept("JWTLYADMIN")
+
+ unread_count = await _get_message_unread_count(self.user)
+ if unread_count == 0:
+ await self.send_json(set_message('system', 'SYS', f'{self.user.name},你好!消息通知已上线!'))
+ else:
+ await self.send_json(set_message('system', 'SYS', "请查看您的未读消息~",unread=unread_count))
+ except Exception as e:
+ await self.close()
+
+ async def receive(self, text_data=None, bytes_data=None, **kwargs):
+ pass
+
+ async def disconnect(self, close_code):
+ await self.channel_layer.group_discard(
+ self.room_group_name,
+ self.channel_name
+ )
+
+ try:
+ await self.close(close_code)
+ except Exception:
+ pass
+
+ async def push_message(self, event):
+ message = event['json']
+ await self.send(text_data=json.dumps(message))
\ No newline at end of file
diff --git a/backend/apps/lywebsocket/routing.py b/backend/apps/lywebsocket/routing.py
index ea40646..2c2b5ae 100644
--- a/backend/apps/lywebsocket/routing.py
+++ b/backend/apps/lywebsocket/routing.py
@@ -6,7 +6,9 @@
from django.urls import re_path,path
from . import consumers
+from apps.lymessages.wsmessage import NotificationConsumer
websocket_urlpatterns = [
re_path(r'^ws/webssh/$', consumers.TerminalConsumer.as_asgi()),
+ re_path(r'^ws/msg/$', NotificationConsumer.as_asgi()),
]
\ No newline at end of file
diff --git a/backend/frontend/download-app/index.html b/backend/frontend/download-app/index.html
new file mode 100644
index 0000000..46fc123
--- /dev/null
+++ b/backend/frontend/download-app/index.html
@@ -0,0 +1,51 @@
+
+{% load i18n static %}
+
+
+
+
+
+
+ APP下载
+
+
+
+
+
+
+

+
+
+

+
+
+
+ {% if data.logo %}
+

+ {% else %}
+

+ {% endif %}
+
+
点击下载
+
{{ data.apkurl }}
+{#
已安装?立即打开
#}
+
+ 温馨提示:请在移动端(手机)浏览器打开此页面
+
+
+
+
+
+

+
+
+
+
+
+
diff --git a/backend/frontend/download-app/static/css/index.2554488.lllxs2download-app.css b/backend/frontend/download-app/static/css/index.2554488.lllxs2download-app.css
new file mode 100644
index 0000000..096f7dd
--- /dev/null
+++ b/backend/frontend/download-app/static/css/index.2554488.lllxs2download-app.css
@@ -0,0 +1,176 @@
+@charset "utf-8";
+
+/* 动画 */
+@keyframes debounce {
+ 0%,
+ 100% {
+ transform: translateX(0);
+ }
+ 10%,
+ 30%,
+ 50%,
+ 70%,
+ 90% {
+ transform: translateX(-2px);
+ }
+ 20%,
+ 40%,
+ 60%,
+ 80% {
+ transform: translateX(2px);
+ }
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+html,
+body,
+.page {
+ height: 100%;
+}
+
+.page {
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.pattern {
+ width: 18%;
+ position: absolute;
+ top: 0;
+}
+.pattern img {
+ width: 100%;
+}
+.pattern.left {
+ left: 0;
+}
+.pattern.right {
+ right: 0;
+}
+
+.wrap {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.logo {
+ width: 100px;
+ height: 100px;
+ border-radius: 12px;
+ margin-bottom: 20px;
+}
+
+.platform {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+.platform .icon-env {
+ width: 22px;
+ height: 22px;
+ margin-right: 10px;
+ display: none;
+}
+.platform .icon-env.show {
+ display: block;
+}
+
+.platform .app-name {
+ font-size: 16px;
+ font-weight: 800;
+ line-height: 22px;
+ color: #505556;
+ letter-spacing: 1px;
+}
+
+.download-button {
+ width: 211px;
+ height: 40px;
+ background: #32b2a7;
+ margin-top: 17px;
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ border-radius: 22px;
+ color: #ffffff;
+ font-size: 14px;
+
+ cursor: pointer;
+}
+
+/* 已安装提示 */
+.open-tips {
+ margin-top: 20px;
+ font-size: 15px;
+ font-weight: bold;
+ line-height: 21px;
+ color: #fb4545;
+ display: none;
+ cursor: pointer;
+}
+
+.open-tips.show {
+ display: block;
+}
+
+.browser-tips {
+ font-size: 12px;
+ margin-top: 20px;
+ color: #999999;
+ letter-spacing: 2px;
+ display: none;
+}
+.browser-tips.show {
+ display: block;
+}
+
+/* 微信环境提示 */
+
+.tips {
+ display: none;
+ width: 160px;
+ position: absolute;
+ right: 6px;
+ top: 0;
+}
+.tips.show {
+ display: block;
+}
+.tips.ani {
+ animation: debounce 1s;
+}
+
+/* 即将开放 */
+.dialog {
+ width: 100%;
+ height: 100%;
+
+ display: none;
+ justify-content: center;
+ align-items: center;
+
+ position: fixed;
+ top: 0;
+ left: 0;
+}
+.dialog.show {
+ display: flex;
+}
+.dialog-content {
+ background: rgba(0, 0, 0, 0.7);
+ padding: 4px 15px;
+ border-radius: 3px;
+ color: #fff;
+ font-size: 12px;
+}
diff --git a/backend/frontend/download-app/static/images/download_pattern_left.2554488.lllxs2download-app.png b/backend/frontend/download-app/static/images/download_pattern_left.2554488.lllxs2download-app.png
new file mode 100644
index 0000000..8c57c8a
Binary files /dev/null and b/backend/frontend/download-app/static/images/download_pattern_left.2554488.lllxs2download-app.png differ
diff --git a/backend/frontend/download-app/static/images/download_pattern_right.2554488.lllxs2download-app.png b/backend/frontend/download-app/static/images/download_pattern_right.2554488.lllxs2download-app.png
new file mode 100644
index 0000000..16884cb
Binary files /dev/null and b/backend/frontend/download-app/static/images/download_pattern_right.2554488.lllxs2download-app.png differ
diff --git a/backend/frontend/download-app/static/images/favicon.2554488.lllxs2download-app.ico b/backend/frontend/download-app/static/images/favicon.2554488.lllxs2download-app.ico
new file mode 100644
index 0000000..e5a2934
Binary files /dev/null and b/backend/frontend/download-app/static/images/favicon.2554488.lllxs2download-app.ico differ
diff --git a/backend/frontend/download-app/static/images/icon_android.2554488.lllxs2download-app.png b/backend/frontend/download-app/static/images/icon_android.2554488.lllxs2download-app.png
new file mode 100644
index 0000000..ed43194
Binary files /dev/null and b/backend/frontend/download-app/static/images/icon_android.2554488.lllxs2download-app.png differ
diff --git a/backend/frontend/download-app/static/images/icon_android_1.2554488.lllxs2download-app.png b/backend/frontend/download-app/static/images/icon_android_1.2554488.lllxs2download-app.png
new file mode 100644
index 0000000..debd01c
Binary files /dev/null and b/backend/frontend/download-app/static/images/icon_android_1.2554488.lllxs2download-app.png differ
diff --git a/backend/frontend/download-app/static/images/icon_ios.2554488.lllxs2download-app.png b/backend/frontend/download-app/static/images/icon_ios.2554488.lllxs2download-app.png
new file mode 100644
index 0000000..ac43aa0
Binary files /dev/null and b/backend/frontend/download-app/static/images/icon_ios.2554488.lllxs2download-app.png differ
diff --git a/backend/frontend/download-app/static/images/icon_ios_1.2554488.lllxs2download-app.png b/backend/frontend/download-app/static/images/icon_ios_1.2554488.lllxs2download-app.png
new file mode 100644
index 0000000..d1e2d65
Binary files /dev/null and b/backend/frontend/download-app/static/images/icon_ios_1.2554488.lllxs2download-app.png differ
diff --git a/backend/frontend/download-app/static/images/icon_logo.2554488.lllxs2download-app.png b/backend/frontend/download-app/static/images/icon_logo.2554488.lllxs2download-app.png
new file mode 100644
index 0000000..ac17227
Binary files /dev/null and b/backend/frontend/download-app/static/images/icon_logo.2554488.lllxs2download-app.png differ
diff --git a/backend/frontend/download-app/static/images/tips.2554488.lllxs2download-app.png b/backend/frontend/download-app/static/images/tips.2554488.lllxs2download-app.png
new file mode 100644
index 0000000..0134c12
Binary files /dev/null and b/backend/frontend/download-app/static/images/tips.2554488.lllxs2download-app.png differ
diff --git a/backend/frontend/download-app/static/js/index.2554488.lllxs2download-app.js b/backend/frontend/download-app/static/js/index.2554488.lllxs2download-app.js
new file mode 100644
index 0000000..019a151
--- /dev/null
+++ b/backend/frontend/download-app/static/js/index.2554488.lllxs2download-app.js
@@ -0,0 +1,86 @@
+
+(function () {
+ // 1. 获取必要的DOM元素
+ var oTips = document.querySelector(".tips");
+ var oBrowserTips = document.querySelector(".browser-tips");
+ var oEnvImgForiOS = document.querySelector(".icon-env.ios");
+ var oEnvImgForAndroid = document.querySelector(".icon-env.android");
+ var oButtonDownload = document.querySelector(".download-button");
+ var oButtonOpenApp = document.querySelector(".open-tips");
+ var oDialog = document.querySelector(".dialog");
+ // 2. 常量值
+ var env = getEnv();
+ var isAnimating = false;
+ var SCHEME_URI = "d-point-life://www.lybbn.com/switch?index=0";
+ var downloadUrlForiOS = "https://itunes.apple.com/cn/app/id12346546xx";
+ var downloadUrlForAndroid = document.getElementById("lyandroidurl").innerText;
+ // 3. 控制默认显示
+ switch (env) {
+ // 微信环境,提示浏览器打开
+ case "weixin":
+ oTips.classList.add("show");
+ break;
+ // iOS环境,展示图标和下载按钮
+ case "ios":
+ oEnvImgForiOS.classList.add("show");
+ // oButtonOpenApp.classList.add("show");
+ break;
+ // Android环境,展示图标和下载按钮
+ case "android":
+ oEnvImgForAndroid.classList.add("show");
+ // oButtonOpenApp.classList.add("show");
+ break;
+ case "unknown":
+ oBrowserTips.classList.add("show");
+ break;
+ }
+
+ // 4. 事件 --- 唤醒APP
+ // oButtonOpenApp.addEventListener(
+ // "click",
+ // function () {
+ // if (["ios", "android"].indexOf(env) !== -1) {
+ // window.location.href = SCHEME_URI;
+ // }
+ // },
+ // false
+ // );
+ // 5. 事件 --- 下载APP
+ oButtonDownload.addEventListener(
+ "click",
+ function () {
+ switch (env) {
+ case "weixin":
+ if (isAnimating) {
+ return;
+ }
+ isAnimating = true;
+ oTips.classList.add("ani");
+ var t = setTimeout(function () {
+ isAnimating = false;
+ oTips.classList.remove("ani");
+ clearTimeout(t);
+ }, 1000);
+ break;
+ case "android":
+ window.location.href = downloadUrlForAndroid;
+ break;
+ case "ios":
+ window.location.href = downloadUrlForiOS;
+ // # 即将开放提示
+ /*
+ oDialog.classList.add("show");
+ var t = setTimeout(function () {
+ oDialog.classList.remove("show");
+ clearTimeout(t);
+ }, 1000);*/
+ break;
+ case "unknown":
+ window.location.href = downloadUrlForAndroid;
+ // alert("请在移动端(手机)浏览器打开此页面");
+ break;
+ }
+ },
+ false
+ );
+})();
diff --git a/backend/frontend/download-app/static/js/utils.2554488.lllxs2download-app.js b/backend/frontend/download-app/static/js/utils.2554488.lllxs2download-app.js
new file mode 100644
index 0000000..6df91eb
--- /dev/null
+++ b/backend/frontend/download-app/static/js/utils.2554488.lllxs2download-app.js
@@ -0,0 +1,25 @@
+
+function getEnv() {
+ var _userAgent = window.navigator.userAgent;
+ if (/MicroMessenger/i.test(_userAgent)) {
+ return "weixin";
+ } else if (/Linux|Android/i.test(_userAgent)) {
+ return "android";
+ } else if (/iPhone/i.test(_userAgent)) {
+ return "ios";
+ } else {
+ return "unknown";
+ }
+}
+
+function setEnvImg(element, env) {
+ switch (env) {
+ case "android":
+ element.src = "images/icon_android_1.2554488.lllxs2download-app.png";
+ break;
+ case "ios":
+ element.src = "images/icon_ios_1.2554488.lllxs2download-app.png";
+ break;
+ default:
+ }
+}
diff --git a/backend/frontend/h5/index.html b/backend/frontend/h5/index.html
new file mode 100644
index 0000000..1621372
--- /dev/null
+++ b/backend/frontend/h5/index.html
@@ -0,0 +1,20 @@
+
+
+
+ django-vue-lyadmin启动成功
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/backend/frontend/h5/static/favicon.ico b/backend/frontend/h5/static/favicon.ico
new file mode 100644
index 0000000..e5a2934
Binary files /dev/null and b/backend/frontend/h5/static/favicon.ico differ
diff --git a/backend/frontend/index.html b/backend/frontend/index.html
index c803385..bb56477 100644
--- a/backend/frontend/index.html
+++ b/backend/frontend/index.html
@@ -16,7 +16,7 @@
}
}