Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
猿小天
2023-11-24 15:13:23 +08:00
16 changed files with 379 additions and 280 deletions

View File

@@ -73,7 +73,7 @@ class DvadminWebSocket(AsyncJsonWebsocketConsumer):
unread_count = await _get_message_unread(self.user_id) unread_count = await _get_message_unread(self.user_id)
if unread_count == 0: if unread_count == 0:
# 发送连接成功 # 发送连接成功
await self.send_json(set_message('system', 'SYSTEM', '连接成功')) await self.send_json(set_message('system', 'SYSTEM', '您已上线'))
else: else:
await self.send_json( await self.send_json(
set_message('system', 'SYSTEM', "请查看您的未读消息~", set_message('system', 'SYSTEM', "请查看您的未读消息~",

View File

@@ -28,6 +28,6 @@ server {
proxy_send_timeout 600s; proxy_send_timeout 600s;
real_ip_header X-Forwarded-For; real_ip_header X-Forwarded-For;
rewrite ^/api/(.*)$ /$1 break; #重写 rewrite ^/api/(.*)$ /$1 break; #重写
proxy_pass http://177.8.0.12:8000/; # 设置代理服务器的协议和地址 proxy_pass http://177.10.0.12:8000/; # 设置代理服务器的协议和地址
} }
} }

View File

@@ -1,7 +1,7 @@
FROM registry.cn-zhangjiakou.aliyuncs.com/dvadmin-pro/dvadmin3-base-web:16.19-alpine FROM registry.cn-zhangjiakou.aliyuncs.com/dvadmin-pro/dvadmin3-base-web:16.19-alpine
WORKDIR /web/ WORKDIR /web/
COPY web/. . COPY web/. .
RUN yarn install RUN yarn install --registry=https://registry.npm.taobao.org
RUN yarn build RUN yarn build
FROM nginx:alpine FROM nginx:alpine

View File

@@ -62,7 +62,7 @@
"@typescript-eslint/parser": "^5.46.0", "@typescript-eslint/parser": "^5.46.0",
"@vitejs/plugin-vue": "^4.0.0", "@vitejs/plugin-vue": "^4.0.0",
"@vue/compiler-sfc": "^3.2.45", "@vue/compiler-sfc": "^3.2.45",
"eslint": "^8.29.0", "eslint": "^8.54.0",
"eslint-plugin-vue": "^9.8.0", "eslint-plugin-vue": "^9.8.0",
"prettier": "^2.8.1", "prettier": "^2.8.1",
"sass": "^1.56.2", "sass": "^1.56.2",

View File

@@ -59,12 +59,6 @@ onBeforeMount(() => {
setIntroduction.cssCdn(); setIntroduction.cssCdn();
// 设置批量第三方 js // 设置批量第三方 js
setIntroduction.jsCdn(); setIntroduction.jsCdn();
//websockt 模块
try {
//websocket.init(wsReceive)
} catch (e) {
console.log('websocket错误');
}
}); });
// 页面加载时 // 页面加载时
onMounted(() => { onMounted(() => {
@@ -93,6 +87,14 @@ watch(
() => route.path, () => route.path,
() => { () => {
other.useTitle(); other.useTitle();
if (!websocket.websocket) {
//websockt 模块
try {
websocket.init(wsReceive)
} catch (e) {
console.log('websocket错误');
}
}
}, },
{ {
deep: true, deep: true,

View File

@@ -1,123 +1,131 @@
// 定义内容 // 定义内容
export default { export default {
router: { router: {
home: 'home', home: 'home',
system: 'system', system: 'system',
systemMenu: 'systemMenu', systemMenu: 'systemMenu',
systemRole: 'systemRole', systemRole: 'systemRole',
systemUser: 'systemUser', systemUser: 'systemUser',
systemDept: 'systemDept', systemDept: 'systemDept',
systemDic: 'systemDic', systemDic: 'systemDic',
limits: 'limits', limits: 'limits',
limitsFrontEnd: 'FrontEnd', limitsFrontEnd: 'FrontEnd',
limitsFrontEndPage: 'FrontEndPage', limitsFrontEndPage: 'FrontEndPage',
limitsFrontEndBtn: 'FrontEndBtn', limitsFrontEndBtn: 'FrontEndBtn',
limitsBackEnd: 'BackEnd', limitsBackEnd: 'BackEnd',
limitsBackEndEndPage: 'BackEndEndPage', limitsBackEndEndPage: 'BackEndEndPage',
personal: 'personal', personal: 'personal',
}, },
staticRoutes: { staticRoutes: {
signIn: 'signIn', signIn: 'signIn',
notFound: 'notFound', notFound: 'notFound',
noPower: 'noPower', noPower: 'noPower',
}, },
user: { user: {
title0: 'Component size', title0: 'Component size',
title1: 'Language switching', title1: 'Language switching',
title2: 'Menu search', title2: 'Menu search',
title3: 'Layout configuration', title3: 'Layout configuration',
title4: 'news', title4: 'news',
title5: 'Full screen on', title5: 'Full screen on',
title6: 'Full screen off', title6: 'Full screen off',
dropdownLarge: 'large', dropdownLarge: 'large',
dropdownDefault: 'default', dropdownDefault: 'default',
dropdownSmall: 'small', dropdownSmall: 'small',
dropdown1: 'home page', dropdown1: 'home page',
dropdown2: 'Personal Center', dropdown2: 'Personal Center',
dropdown3: '404', dropdown3: '404',
dropdown4: '401', dropdown4: '401',
dropdown5: 'Log out', dropdown5: 'Log out',
dropdown6: 'Code warehouse', dropdown6: 'Code warehouse',
searchPlaceholder: 'Menu search: support Chinese, routing path', searchPlaceholder: 'Menu search: support Chinese, routing path',
newTitle: 'notice', newTitle: 'notice',
newBtn: 'All read', newBtn: 'All read',
newGo: 'Go to the notification center', newGo: 'Go to the notification center',
newDesc: 'No notice', newDesc: 'No notice',
logOutTitle: 'Tips', logOutTitle: 'Tips',
logOutMessage: 'This operation will log out. Do you want to continue?', logOutMessage: 'This operation will log out. Do you want to continue?',
logOutConfirm: 'determine', logOutConfirm: 'determine',
logOutCancel: 'cancel', logOutCancel: 'cancel',
logOutExit: 'Exiting', logOutExit: 'Exiting',
}, },
tagsView: { tagsView: {
refresh: 'refresh', refresh: 'refresh',
close: 'close', close: 'close',
closeOther: 'closeOther', closeOther: 'closeOther',
closeAll: 'closeAll', closeAll: 'closeAll',
fullscreen: 'fullscreen', fullscreen: 'fullscreen',
closeFullscreen: 'closeFullscreen', closeFullscreen: 'closeFullscreen',
}, },
notFound: { notFound: {
foundTitle: 'Wrong address input, please re-enter the address~', foundTitle: 'Wrong address input, please re-enter the address~',
foundMsg: 'You can check the web address first, and then re-enter or give us feedback.', foundMsg: 'You can check the web address first, and then re-enter or give us feedback.',
foundBtn: 'Back to home page', foundBtn: 'Back to home page',
}, },
noAccess: { noAccess: {
accessTitle: 'You are not authorized to operate~', accessTitle: 'You are not authorized to operate~',
accessMsg: 'Contact information: add QQ group discussion 665452019', accessMsg: 'Contact information: add QQ group discussion 665452019',
accessBtn: 'Reauthorization', accessBtn: 'Reauthorization',
}, },
layout: { layout: {
configTitle: 'Layout configuration', configTitle: 'Layout configuration',
oneTitle: 'Global Themes', oneTitle: 'Global Themes',
twoTopTitle: 'top bar set up', twoTopTitle: 'top bar set up',
twoMenuTitle: 'Menu set up', twoMenuTitle: 'Menu set up',
twoColumnsTitle: 'Columns set up', twoColumnsTitle: 'Columns set up',
twoTopBar: 'Top bar background', twoTopBar: 'Top bar background',
twoTopBarColor: 'Top bar default font color', twoTopBarColor: 'Top bar default font color',
twoIsTopBarColorGradual: 'Top bar gradient', twoIsTopBarColorGradual: 'Top bar gradient',
twoMenuBar: 'Menu background', twoMenuBar: 'Menu background',
twoMenuBarColor: 'Menu default font color', twoMenuBarColor: 'Menu default font color',
twoIsMenuBarColorGradual: 'Menu gradient', twoIsMenuBarColorGradual: 'Menu gradient',
twoColumnsMenuBar: 'Column menu background', twoColumnsMenuBar: 'Column menu background',
twoColumnsMenuBarColor: 'Default font color bar menu', twoColumnsMenuBarColor: 'Default font color bar menu',
twoIsColumnsMenuBarColorGradual: 'Column gradient', twoIsColumnsMenuBarColorGradual: 'Column gradient',
threeTitle: 'Interface settings', threeTitle: 'Interface settings',
threeIsCollapse: 'Menu horizontal collapse', threeIsCollapse: 'Menu horizontal collapse',
threeIsUniqueOpened: 'Menu accordion', threeIsUniqueOpened: 'Menu accordion',
threeIsFixedHeader: 'Fixed header', threeIsFixedHeader: 'Fixed header',
threeIsClassicSplitMenu: 'Classic layout split menu', threeIsClassicSplitMenu: 'Classic layout split menu',
threeIsLockScreen: 'Open the lock screen', threeIsLockScreen: 'Open the lock screen',
threeLockScreenTime: 'screen locking(s/s)', threeLockScreenTime: 'screen locking(s/s)',
fourTitle: 'Interface display', fourTitle: 'Interface display',
fourIsShowLogo: 'Sidebar logo', fourIsShowLogo: 'Sidebar logo',
fourIsBreadcrumb: 'Open breadcrumb', fourIsBreadcrumb: 'Open breadcrumb',
fourIsBreadcrumbIcon: 'Open breadcrumb icon', fourIsBreadcrumbIcon: 'Open breadcrumb icon',
fourIsTagsview: 'Open tagsview', fourIsTagsview: 'Open tagsview',
fourIsTagsviewIcon: 'Open tagsview Icon', fourIsTagsviewIcon: 'Open tagsview Icon',
fourIsCacheTagsView: 'Enable tagsview cache', fourIsCacheTagsView: 'Enable tagsview cache',
fourIsSortableTagsView: 'Enable tagsview drag', fourIsSortableTagsView: 'Enable tagsview drag',
fourIsShareTagsView: 'Enable tagsview sharing', fourIsShareTagsView: 'Enable tagsview sharing',
fourIsFooter: 'Open footer', fourIsFooter: 'Open footer',
fourIsGrayscale: 'Grey model', fourIsGrayscale: 'Grey model',
fourIsInvert: 'Color weak mode', fourIsInvert: 'Color weak mode',
fourIsDark: 'Dark Mode', fourIsDark: 'Dark Mode',
fourIsWartermark: 'Turn on watermark', fourIsWartermark: 'Turn on watermark',
fourWartermarkText: 'Watermark copy', fourWartermarkText: 'Watermark copy',
fiveTitle: 'Other settings', fiveTitle: 'Other settings',
fiveTagsStyle: 'Tagsview style', fiveTagsStyle: 'Tagsview style',
fiveAnimation: 'page animation', fiveAnimation: 'page animation',
fiveColumnsAsideStyle: 'Column style', fiveColumnsAsideStyle: 'Column style',
fiveColumnsAsideLayout: 'Column layout', fiveColumnsAsideLayout: 'Column layout',
sixTitle: 'Layout switch', sixTitle: 'Layout switch',
sixDefaults: 'One', sixDefaults: 'One',
sixClassic: 'Two', sixClassic: 'Two',
sixTransverse: 'Three', sixTransverse: 'Three',
sixColumns: 'Four', sixColumns: 'Four',
tipText: 'Click the button below to copy the layout configuration to `/src/stores/themeConfig.ts` It has been modified in.', tipText: 'Click the button below to copy the layout configuration to `/src/stores/themeConfig.ts` It has been modified in.',
copyText: 'replication configuration', copyText: 'replication configuration',
resetText: 'restore default', resetText: 'restore default',
copyTextSuccess: 'Copy succeeded!', copyTextSuccess: 'Copy succeeded!',
copyTextError: 'Copy failed!', copyTextError: 'Copy failed!',
}, },
upgrade: {
title: 'New version upgrade',
msg: 'It\'s a new version. Update it nowDon\'t worry, update quickly oh!',
desc: 'Tip: The update restores the default configuration',
btnOne: 'Cruel refusal',
btnTwo: 'Update now',
btnTwoLoading: 'updating',
},
}; };

View File

@@ -1,134 +1,146 @@
// 定义内容 // 定义内容
export default { export default {
router: { router: {
home: '首页', home: '首页',
system: '系统管理', system: '系统管理',
config: '常规配置', config: '常规配置',
log: '日志管理', log: '日志管理',
/* 常规配置 */ /* 常规配置 */
configSystem: '系统配置', configSystem: '系统配置',
configDict: '字典管理', configDict: '字典管理',
configArea: '地区管理', configArea: '地区管理',
configFile: '附件管理', configFile: '附件管理',
/* 系统管理 */ /* 系统管理 */
systemMenu: '菜单管理', systemMenu: '菜单管理',
systemRole: '角色管理', systemRole: '角色管理',
systemUser: '用户管理', systemUser: '用户管理',
systemDept: '部门管理', systemDept: '部门管理',
/* 日志管理 */ /* 日志管理 */
loginLog: '登录日志', loginLog: '登录日志',
operationLog: '操作日志', operationLog: '操作日志',
systemApiWhiteList: '接口白名单', systemApiWhiteList: '接口白名单',
limits: '权限管理', limits: '权限管理',
limitsFrontEnd: '前端控制', limitsFrontEnd: '前端控制',
limitsFrontEndPage: '页面权限', limitsFrontEndPage: '页面权限',
limitsFrontEndBtn: '按钮权限', limitsFrontEndBtn: '按钮权限',
limitsBackEnd: '后端控制', limitsBackEnd: '后端控制',
limitsBackEndEndPage: '页面权限', limitsBackEndEndPage: '页面权限',
personal: '个人中心', personal: '个人中心',
}, },
staticRoutes: { staticRoutes: {
signIn: '登录', signIn: '登录',
notFound: '找不到此页面', notFound: '找不到此页面',
noPower: '没有权限', noPower: '没有权限',
}, },
user: { user: {
title0: '组件大小', title0: '组件大小',
title1: '语言切换', title1: '语言切换',
title2: '菜单搜索', title2: '菜单搜索',
title3: '布局配置', title3: '布局配置',
title4: '消息', title4: '消息',
title5: '开全屏', title5: '开全屏',
title6: '关全屏', title6: '关全屏',
dropdownLarge: '大型', retry: '重试上线',
dropdownDefault: '默认', onlinePrompt: '当前离线状态,是否重试上线?',
dropdownSmall: '型', dropdownLarge: '型',
dropdown1: '首页', dropdownDefault: '默认',
dropdown2: '个人中心', dropdownSmall: '小型',
dropdown3: '404', dropdown1: '首页',
dropdown4: '401', dropdown2: '个人中心',
dropdown5: '退出登录', dropdown3: '404',
dropdown6: '代码仓库', dropdown4: '401',
searchPlaceholder: '菜单搜索:支持中文、路由路径', dropdown5: '退出登录',
newTitle: '通知', dropdown6: '代码仓库',
newBtn: '全部已读', searchPlaceholder: '菜单搜索:支持中文、路由路径',
newGo: '前往通知中心', newTitle: '通知',
newDesc: '暂无通知', newBtn: '全部已读',
logOutTitle: '提示', newGo: '前往通知中心',
logOutMessage: '此操作将退出登录, 是否继续?', newDesc: '暂无通知',
logOutConfirm: '确定', logOutTitle: '提示',
logOutCancel: '取消', logOutMessage: '此操作将退出登录, 是否继续?',
logOutExit: '退出中', logOutConfirm: '确定',
}, logOutCancel: '取消',
tagsView: { logOutExit: '退出中',
refresh: '刷新', },
close: '关闭', tagsView: {
closeOther: '关闭其它', refresh: '刷新',
closeAll: '全部关闭', close: '关闭',
fullscreen: '当前页全屏', closeOther: '关闭其它',
closeFullscreen: '关闭全屏', closeAll: '全部关闭',
}, fullscreen: '当前页全屏',
notFound: { closeFullscreen: '关闭全屏',
foundTitle: '地址输入错误,请重新输入地址~', },
foundMsg: '您可以先检查网址,然后重新输入或给我们反馈问题。', notFound: {
foundBtn: '返回首页', foundTitle: '地址输入错误,请重新输入地址~',
}, foundMsg: '您可以先检查网址,然后重新输入或给我们反馈问题。',
noAccess: { foundBtn: '返回首页',
accessTitle: '您未被授权,没有操作权限~', },
accessMsg: '联系方式加QQ群探讨 665452019', noAccess: {
accessBtn: '重新授权', accessTitle: '您未被授权,没有操作权限~',
}, accessMsg: '请联系管理员',
layout: { accessBtn: '重新授权',
configTitle: '布局配置', },
oneTitle: '全局主题', layout: {
twoTopTitle: '顶栏设置', configTitle: '布局配置',
twoMenuTitle: '菜单设置', oneTitle: '全局主题',
twoColumnsTitle: '栏设置', twoTopTitle: '栏设置',
twoTopBar: '顶栏背景', twoMenuTitle: '菜单设置',
twoTopBarColor: '顶栏默认字体颜色', twoColumnsTitle: '分栏设置',
twoIsTopBarColorGradual: '顶栏背景渐变', twoTopBar: '顶栏背景',
twoMenuBar: '菜单背景', twoTopBarColor: '顶栏默认字体颜色',
twoMenuBarColor: '菜单默认字体颜色', twoIsTopBarColorGradual: '顶栏背景渐变',
twoIsMenuBarColorGradual: '菜单背景渐变', twoMenuBar: '菜单背景',
twoColumnsMenuBar: '分栏菜单背景', twoMenuBarColor: '菜单默认字体颜色',
twoColumnsMenuBarColor: '分栏菜单默认字体颜色', twoMenuBarActiveColor: '菜单高亮背景色',
twoIsColumnsMenuBarColorGradual: '分栏菜单背景渐变', twoIsMenuBarColorGradual: '菜单背景渐变',
threeTitle: '界面设置', twoColumnsMenuBar: '分栏菜单背景',
threeIsCollapse: '菜单水平折叠', twoColumnsMenuBarColor: '分栏菜单默认字体颜色',
threeIsUniqueOpened: '菜单手风琴', twoIsColumnsMenuBarColorGradual: '分栏菜单背景渐变',
threeIsFixedHeader: '固定 Header', twoIsColumnsMenuHoverPreload: '分栏菜单滑鼠悬停预加载',
threeIsClassicSplitMenu: '经典布局分割菜单', threeTitle: '界面设置',
threeIsLockScreen: '开启锁屏', threeIsCollapse: '菜单水平折叠',
threeLockScreenTime: '自动锁屏(s/秒)', threeIsUniqueOpened: '菜单手风琴',
fourTitle: '界面显示', threeIsFixedHeader: '固定 Header',
fourIsShowLogo: '侧边栏 Logo', threeIsClassicSplitMenu: '经典布局分割菜单',
fourIsBreadcrumb: '开启 Breadcrumb', threeIsLockScreen: '开启锁屏',
fourIsBreadcrumbIcon: '开启 Breadcrumb 图标', threeLockScreenTime: '自动锁屏(s/秒)',
fourIsTagsview: '开启 Tagsview', fourTitle: '界面显示',
fourIsTagsviewIcon: '开启 Tagsview 图标', fourIsShowLogo: '侧边栏 Logo',
fourIsCacheTagsView: '开启 TagsView 缓存', fourIsBreadcrumb: '开启 Breadcrumb',
fourIsSortableTagsView: '开启 TagsView 拖拽', fourIsBreadcrumbIcon: '开启 Breadcrumb 图标',
fourIsShareTagsView: '开启 TagsView 共用', fourIsTagsview: '开启 Tagsview',
fourIsFooter: '开启 Footer', fourIsTagsviewIcon: '开启 Tagsview 图标',
fourIsGrayscale: '灰色模式', fourIsCacheTagsView: '开启 TagsView 缓存',
fourIsInvert: '色弱模式', fourIsSortableTagsView: '开启 TagsView 拖拽',
fourIsDark: '深色模式', fourIsShareTagsView: '开启 TagsView 共用',
fourIsWartermark: '开启水印', fourIsFooter: '开启 Footer',
fourWartermarkText: '水印文案', fourIsGrayscale: '灰色模式',
fiveTitle: '其它设置', fourIsInvert: '色弱模式',
fiveTagsStyle: 'Tagsview 风格', fourIsDark: '深色模式',
fiveAnimation: '主页面切换动画', fourIsWartermark: '开启水印',
fiveColumnsAsideStyle: '分栏高亮风格', fourWartermarkText: '水印文案',
fiveColumnsAsideLayout: '分栏布局风格', fiveTitle: '其它设置',
sixTitle: '布局切换', fiveTagsStyle: 'Tagsview 风格',
sixDefaults: '默认', fiveAnimation: '主页面切换动画',
sixClassic: '经典', fiveColumnsAsideStyle: '分栏高亮风格',
sixTransverse: '横向', fiveColumnsAsideLayout: '分栏布局风格',
sixColumns: '分栏', sixTitle: '布局切换',
tipText: '点击下方按钮,复制布局配置去 `src/stores/themeConfig.ts` 中修改。', sixDefaults: '默认',
copyText: '一键复制配置', sixClassic: '经典',
resetText: '一键恢复默认', sixTransverse: '横向',
copyTextSuccess: '复制成功!', sixColumns: '分栏',
copyTextError: '复制失败!', tipText: '点击下方按钮,复制布局配置去 `src/stores/themeConfig.ts` 中修改。',
}, copyText: '一键复制配置',
resetText: '一键恢复默认',
copyTextSuccess: '复制成功!',
copyTextError: '复制失败!',
},
upgrade: {
title: '新版本升级',
msg: '新版本来啦,马上更新尝鲜吧!不用担心,更新很快的哦!',
desc: '提示:更新会还原默认配寘',
btnOne: '残忍拒绝',
btnTwo: '马上更新',
btnTwoLoading: '更新中',
},
}; };

View File

@@ -123,7 +123,7 @@ export default {
}, },
noAccess: { noAccess: {
accessTitle: '您未被授權,沒有操作許可權~', accessTitle: '您未被授權,沒有操作許可權~',
accessMsg: '聯繫方式加QQ群探討665452019', accessMsg: '請聯系管理員',
accessBtn: '重新授權', accessBtn: '重新授權',
}, },
layout: { layout: {

View File

@@ -1,7 +1,7 @@
// 定义内容 // 定义内容
export default { export default {
label: { label: {
one1: '用户名登录', one1: '账号密码登录',
two2: '手机号登录', two2: '手机号登录',
}, },
link: { link: {

View File

@@ -4,7 +4,7 @@
<el-scrollbar ref="layoutMainScrollbarRef" class="layout-main-scroll layout-backtop-header-fixed" <el-scrollbar ref="layoutMainScrollbarRef" class="layout-main-scroll layout-backtop-header-fixed"
wrap-class="layout-main-scroll" view-class="layout-main-scroll"> wrap-class="layout-main-scroll" view-class="layout-main-scroll">
<LayoutParentView /> <LayoutParentView />
<!-- <LayoutFooter v-if="isFooter" /> --> <LayoutFooter v-if="isFooter" />
</el-scrollbar> </el-scrollbar>
<el-backtop :target="setBacktopClass" /> <el-backtop :target="setBacktopClass" />
</el-main> </el-main>

View File

@@ -1,8 +1,7 @@
<template> <template>
<div class="layout-footer pb15"> <div class="layout-footer pb5 pt2">
<div class="layout-footer-warp"> <div class="layout-footer-warp">
<div> Powered by Django-Vue3-Admin </div> <div> Powered by Django-Vue3-Admin Copyright © DVAdmin团队 </div>
<div class="mt5">Copyright DVAdmin团队</div>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -57,9 +57,33 @@
:class="!state.isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'" :class="!state.isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'"
></i> ></i>
</div> </div>
<div>
<span v-if="!isSocketOpen">
<el-popconfirm
width="250"
ref="onlinePopoverRef"
:confirm-button-text="$t('message.user.retry')"
:icon="InfoFilled"
trigger="hover"
icon-color="#626AEF"
:title="$t('message.user.onlinePrompt')"
@confirm="onlineConfirmEvent"
>
<template #reference>
<el-badge is-dot class="item" :class="{'online-status': isSocketOpen,'online-down':!isSocketOpen}">
<img :src="userInfos.avatar || headerImage" class="layout-navbars-breadcrumb-user-link-photo mr5" />
</el-badge>
</template>
</el-popconfirm>
</span>
</div>
<el-dropdown :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick"> <el-dropdown :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick">
<span class="layout-navbars-breadcrumb-user-link"> <span class="layout-navbars-breadcrumb-user-link">
<img :src="userInfos.avatar || headerImage" class="layout-navbars-breadcrumb-user-link-photo mr5" /> <span v-if="isSocketOpen">
<el-badge is-dot class="item" :class="{'online-status': isSocketOpen,'online-down':!isSocketOpen}">
<img :src="userInfos.avatar || headerImage" class="layout-navbars-breadcrumb-user-link-photo mr5" />
</el-badge>
</span>
{{ userInfos.username === '' ? 'common' : userInfos.username }} {{ userInfos.username === '' ? 'common' : userInfos.username }}
<el-icon class="el-icon--right"> <el-icon class="el-icon--right">
<ele-ArrowDown /> <ele-ArrowDown />
@@ -79,7 +103,7 @@
</template> </template>
<script setup lang="ts" name="layoutBreadcrumbUser"> <script setup lang="ts" name="layoutBreadcrumbUser">
import { defineAsyncComponent, ref, computed, reactive, onMounted } from 'vue'; import { defineAsyncComponent, ref, computed, reactive, onMounted, unref, watch } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { ElMessageBox, ElMessage } from 'element-plus'; import { ElMessageBox, ElMessage } from 'element-plus';
import screenfull from 'screenfull'; import screenfull from 'screenfull';
@@ -91,6 +115,8 @@ import other from '/@/utils/other';
import mittBus from '/@/utils/mitt'; import mittBus from '/@/utils/mitt';
import { Session, Local } from '/@/utils/storage'; import { Session, Local } from '/@/utils/storage';
import headerImage from '/@/assets/img/headerImage.png'; import headerImage from '/@/assets/img/headerImage.png';
import websocket from '/@/utils/websocket';
import { InfoFilled } from '@element-plus/icons-vue'
// 引入组件 // 引入组件
const UserNews = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/userNews.vue')); const UserNews = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/userNews.vue'));
const Search = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/search.vue')); const Search = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/search.vue'));
@@ -118,6 +144,21 @@ const layoutUserFlexNum = computed(() => {
else num = ''; else num = '';
return num; return num;
}); });
// 定义变量内容
const { isSocketOpen } = storeToRefs(useUserInfo());
// websocket状态
const onlinePopoverRef = ref()
const onlineConfirmEvent = () => {
if (!isSocketOpen.value) {
websocket.is_reonnect = true
websocket.reconnect_current = 1
websocket.reconnect()
}
// 手动隐藏弹出
unref(onlinePopoverRef).popperRef?.delayHide?.()
}
// 全屏点击时 // 全屏点击时
const onScreenfullClick = () => { const onScreenfullClick = () => {
if (!screenfull.isEnabled) { if (!screenfull.isEnabled) {
@@ -256,5 +297,29 @@ const messageCenter = messageCenterStore();
:deep(.el-badge__content.is-fixed) { :deep(.el-badge__content.is-fixed) {
top: 12px; top: 12px;
} }
.online-status{
cursor: pointer;
:deep .el-badge__content.is-fixed {
top: 30px;
font-size: 14px;
left: 5px;
height: 12px;
width: 12px;
padding: 0;
background-color: #18bc9c;
}
}
.online-down{
cursor: pointer;
:deep .el-badge__content.is-fixed {
top: 30px;
font-size: 14px;
left: 5px;
height: 12px;
width: 12px;
padding: 0;
background-color: #979b9c;
}
}
} }
</style> </style>

View File

@@ -17,7 +17,7 @@
<div class="upgrade-content"> <div class="upgrade-content">
{{ getThemeConfig.globalTitle }} {{ $t('message.upgrade.msg') }} {{ getThemeConfig.globalTitle }} {{ $t('message.upgrade.msg') }}
<div class="mt5"> <div class="mt5">
<el-link type="primary" class="font12" href="https://gitee.com/lyt-top/vue-next-admin/blob/master/CHANGELOG.md" target="_black"> <el-link type="primary" class="font12" href=https://gitee.com/huge-dream/django-vue3-admin/blob/master/CHANGELOG.md" target="_black">
CHANGELOG.md CHANGELOG.md
</el-link> </el-link>
</div> </div>
@@ -76,10 +76,10 @@ const delayShow = () => {
}; };
// 页面加载时 // 页面加载时
onMounted(() => { onMounted(() => {
// delayShow(); delayShow();
// setTimeout(() => { setTimeout(() => {
// state.btnTxt = t('message.upgrade.btnTwo'); state.btnTxt = t('message.upgrade.btnTwo');
// }, 200); }, 200);
}); });
</script> </script>

View File

@@ -19,6 +19,7 @@ export interface UserInfosState {
} }
export interface UserInfosStates { export interface UserInfosStates {
userInfos: UserInfosState; userInfos: UserInfosState;
isSocketOpen: boolean
} }
// 路由缓存列表 // 路由缓存列表

View File

@@ -26,6 +26,7 @@ export const useUserInfo = defineStore('userInfo', {
}, },
], ],
}, },
isSocketOpen: false
}), }),
actions: { actions: {
async updateUserInfos() { async updateUserInfos() {
@@ -57,6 +58,9 @@ export const useUserInfo = defineStore('userInfo', {
Session.set('userInfo', this.userInfos); Session.set('userInfo', this.userInfos);
} }
}, },
async setWebSocketState(socketState: boolean) {
this.isSocketOpen = socketState;
},
async getApiUserInfo() { async getApiUserInfo() {
return request({ return request({
url: '/api/system/user/user_info/', url: '/api/system/user/user_info/',

View File

@@ -3,7 +3,7 @@ import {Session} from "/@/utils/storage";
import {getWsBaseURL} from "/@/utils/baseUrl"; import {getWsBaseURL} from "/@/utils/baseUrl";
// @ts-ignore // @ts-ignore
import socket from '@/types/api/socket' import socket from '@/types/api/socket'
import {useUserInfo} from "/@/stores/userInfo";
const websocket: socket = { const websocket: socket = {
websocket: null, websocket: null,
connectURL: getWsBaseURL(), connectURL: getWsBaseURL(),
@@ -42,6 +42,7 @@ const websocket: socket = {
} }
websocket.websocket.onclose = (e: any) => { websocket.websocket.onclose = (e: any) => {
websocket.socket_open = false websocket.socket_open = false
useUserInfo().setWebSocketState(websocket.socket_open);
// 需要重新连接 // 需要重新连接
if (websocket.is_reonnect) { if (websocket.is_reonnect) {
websocket.reconnect_timer = setTimeout(() => { websocket.reconnect_timer = setTimeout(() => {
@@ -49,6 +50,8 @@ const websocket: socket = {
if (websocket.reconnect_current > websocket.reconnect_count) { if (websocket.reconnect_current > websocket.reconnect_count) {
clearTimeout(websocket.reconnect_timer) clearTimeout(websocket.reconnect_timer)
websocket.is_reonnect = false websocket.is_reonnect = false
websocket.socket_open = false
useUserInfo().setWebSocketState(websocket.socket_open);
return return
} }
// 记录重连次数 // 记录重连次数
@@ -60,6 +63,7 @@ const websocket: socket = {
// 连接成功 // 连接成功
websocket.websocket.onopen = function () { websocket.websocket.onopen = function () {
websocket.socket_open = true websocket.socket_open = true
useUserInfo().setWebSocketState(websocket.socket_open);
websocket.is_reonnect = true websocket.is_reonnect = true
// 开启心跳 // 开启心跳
websocket.heartbeat() websocket.heartbeat()
@@ -85,17 +89,21 @@ const websocket: socket = {
callback && callback() callback && callback()
} else { } else {
clearInterval(websocket.hearbeat_timer) clearInterval(websocket.hearbeat_timer)
message({ // message({
type: 'warning', // type: 'warning',
message: 'socket链接已断开', // message: 'socket链接已断开',
duration: 1000, // duration: 1000,
}) // })
websocket.socket_open = false
useUserInfo().setWebSocketState(websocket.socket_open);
} }
}, },
close: () => { close: () => {
websocket.is_reonnect = false websocket.is_reonnect = false
websocket.websocket.close() websocket.websocket.close()
websocket.websocket = null; websocket.websocket = null;
websocket.socket_open = false
useUserInfo().setWebSocketState(websocket.socket_open);
}, },
/** /**
* 重新连接 * 重新连接