!141 发布 vue 版本 5.2.2 与 cloud 版本 2.2.1

Merge pull request !141 from 疯狂的狮子Li/dev
This commit is contained in:
疯狂的狮子Li 2024-08-26 03:45:16 +00:00 committed by Gitee
commit 1606dbd76f
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
22 changed files with 132 additions and 280 deletions

View File

@ -28,5 +28,5 @@ VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3C
# 客户端id
VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
# websocket 开关
VITE_APP_WEBSOCKET = true
# websocket 开关 默认使用sse推送
VITE_APP_WEBSOCKET = false

View File

@ -31,5 +31,5 @@ VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3C
# 客户端id
VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
# websocket 开关
VITE_APP_WEBSOCKET = true
# websocket 开关 默认使用sse推送
VITE_APP_WEBSOCKET = false

View File

@ -1,6 +1,6 @@
{
"name": "ruoyi-vue-plus",
"version": "5.2.1",
"version": "5.2.2",
"description": "RuoYi-Vue-Plus多租户管理系统",
"author": "LionLi",
"license": "MIT",
@ -30,7 +30,7 @@
"diagram-js": "12.3.0",
"didi": "9.0.2",
"echarts": "5.5.0",
"element-plus": "2.7.5",
"element-plus": "2.7.8",
"file-saver": "2.0.5",
"fuse.js": "7.0.0",
"highlight.js": "11.9.0",
@ -40,7 +40,7 @@
"nprogress": "0.2.0",
"pinia": "2.1.7",
"screenfull": "6.0.2",
"vue": "3.4.25",
"vue": "3.4.34",
"vue-cropper": "1.1.1",
"vue-i18n": "9.10.2",
"vue-router": "4.3.2",
@ -81,7 +81,7 @@
"unplugin-icons": "0.18.5",
"unplugin-vue-components": "0.26.0",
"unplugin-vue-setup-extend-plus": "1.0.1",
"vite": "5.2.10",
"vite": "5.2.12",
"vite-plugin-compression": "0.5.1",
"vite-plugin-svg-icons": "2.0.1",
"vitest": "1.5.0",

View File

@ -51,6 +51,10 @@ export function register(data: any) {
*
*/
export function logout() {
request({
url: '/resource/sse/close',
method: 'get'
});
return request({
url: '/auth/logout',
method: 'post'

View File

@ -1,63 +0,0 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { NodeConfigVO, NodeConfigForm, NodeConfigQuery } from '@/api/workflow/nodeConfig/types';
/**
*
* @param query
* @returns {*}
*/
export const listNodeConfig = (query?: NodeConfigQuery): AxiosPromise<NodeConfigVO[]> => {
return request({
url: '/workflow/nodeConfig/list',
method: 'get',
params: query
});
};
/**
*
* @param id
*/
export const getNodeConfig = (id: string | number): AxiosPromise<NodeConfigVO> => {
return request({
url: '/workflow/nodeConfig/' + id,
method: 'get'
});
};
/**
*
* @param data
*/
export const addNodeConfig = (data: NodeConfigForm) => {
return request({
url: '/workflow/nodeConfig',
method: 'post',
data: data
});
};
/**
*
* @param data
*/
export const updateNodeConfig = (data: NodeConfigForm) => {
return request({
url: '/workflow/nodeConfig',
method: 'put',
data: data
});
};
/**
*
* @param id
*/
export const delNodeConfig = (id: string | number | Array<string | number>) => {
return request({
url: '/workflow/nodeConfig/' + id,
method: 'delete'
});
};

View File

@ -128,6 +128,7 @@ const dynamicTenantEvent = async (tenantId: string) => {
dynamic.value = true;
proxy?.$tab.closeAllPage();
proxy?.$router.push('/');
proxy?.$tab.refreshPage();
}
};
@ -136,6 +137,7 @@ const dynamicClearEvent = async () => {
dynamic.value = false;
proxy?.$tab.closeAllPage();
proxy?.$router.push('/');
proxy?.$tab.refreshPage();
};
/** 租户列表 */

View File

@ -27,6 +27,7 @@ import { AppMain, Navbar, Settings, TagsView } from './components';
import useAppStore from '@/store/modules/app';
import useSettingsStore from '@/store/modules/settings';
import { initWebSocket } from '@/utils/websocket';
import { initSSE } from "@/utils/sse";
const settingsStore = useSettingsStore();
const theme = computed(() => settingsStore.theme);
@ -71,6 +72,10 @@ onMounted(() => {
initWebSocket(protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + '/resource/websocket');
});
onMounted(() => {
initSSE(import.meta.env.VITE_APP_BASE_API + '/resource/sse')
});
const handleClickOutside = () => {
useAppStore().closeSideBar({ withoutAnimation: false });
};

View File

@ -40,6 +40,7 @@ router.beforeEach(async (to, from, next) => {
router.addRoute(route); // 动态添加可访问路由表
}
});
// @ts-ignore
next({ path: to.path, replace: true, params: to.params, query: to.query, hash: to.hash, name: to.name as string }); // hack方法 确保addRoutes已完成
}
} else {

View File

@ -1,5 +1,5 @@
import router from '@/router';
import { RouteLocationMatched, RouteLocationNormalized } from 'vue-router';
import {RouteLocationMatched, RouteLocationNormalized, RouteLocationRaw} from 'vue-router';
import useTagsViewStore from '@/store/modules/tagsView';
export default {
@ -41,7 +41,7 @@ export default {
});
},
// 关闭当前tab页签打开新页签
closeOpenPage(obj: RouteLocationNormalized): void {
closeOpenPage(obj: RouteLocationRaw): void {
useTagsViewStore().delView(router.currentRoute.value);
if (obj !== undefined) {
router.push(obj);

View File

@ -159,7 +159,7 @@ export const dynamicRoutes: RouteRecordRaw[] = [
path: 'index/:tableId(\\d+)',
component: () => import('@/views/tool/gen/editTable.vue'),
name: 'GenEdit',
meta: { title: '修改生成配置', activeMenu: '/tool/gen', icon: '' }
meta: { title: '修改生成配置', activeMenu: '/tool/gen', icon: '', noCache: true }
}
]
},

View File

@ -21,13 +21,13 @@ export const usePermissionStore = defineStore('permission', () => {
const sidebarRouters = ref<RouteRecordRaw[]>([]);
const getRoutes = (): RouteRecordRaw[] => {
return routes.value;
return routes.value as RouteRecordRaw[];
};
const getSidebarRoutes = (): RouteRecordRaw[] => {
return sidebarRouters.value;
return sidebarRouters.value as RouteRecordRaw[];
};
const getTopbarRoutes = (): RouteRecordRaw[] => {
return topbarRouters.value;
return topbarRouters.value as RouteRecordRaw[];
};
const setRoutes = (newRoutes: RouteRecordRaw[]): void => {

View File

@ -6,10 +6,10 @@ export const useTagsViewStore = defineStore('tagsView', () => {
const iframeViews = ref<RouteLocationNormalized[]>([]);
const getVisitedViews = (): RouteLocationNormalized[] => {
return visitedViews.value;
return visitedViews.value as RouteLocationNormalized[];
};
const getIframeViews = (): RouteLocationNormalized[] => {
return iframeViews.value;
return iframeViews.value as RouteLocationNormalized[];
};
const getCachedViews = (): string[] => {
return cachedViews.value;
@ -31,7 +31,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
const delIframeView = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => {
return new Promise((resolve) => {
iframeViews.value = iframeViews.value.filter((item: RouteLocationNormalized) => item.path !== view.path);
resolve([...iframeViews.value]);
resolve([...iframeViews.value as RouteLocationNormalized[]]);
});
};
const addVisitedView = (view: RouteLocationNormalized): void => {
@ -54,7 +54,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
delCachedView(view);
}
resolve({
visitedViews: [...visitedViews.value],
visitedViews: [...visitedViews.value as RouteLocationNormalized[]],
cachedViews: [...cachedViews.value]
});
});
@ -68,7 +68,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
break;
}
}
resolve([...visitedViews.value]);
resolve([...visitedViews.value as RouteLocationNormalized[]]);
});
};
const delCachedView = (view?: RouteLocationNormalized): Promise<string[]> => {
@ -92,7 +92,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
delOthersVisitedViews(view);
delOthersCachedViews(view);
resolve({
visitedViews: [...visitedViews.value],
visitedViews: [...visitedViews.value as RouteLocationNormalized[]],
cachedViews: [...cachedViews.value]
});
});
@ -103,7 +103,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
visitedViews.value = visitedViews.value.filter((v: RouteLocationNormalized) => {
return v.meta?.affix || v.path === view.path;
});
resolve([...visitedViews.value]);
resolve([...visitedViews.value as RouteLocationNormalized[]]);
});
};
const delOthersCachedViews = (view: RouteLocationNormalized): Promise<string[]> => {
@ -124,7 +124,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
delAllVisitedViews();
delAllCachedViews();
resolve({
visitedViews: [...visitedViews.value],
visitedViews: [...visitedViews.value as RouteLocationNormalized[]],
cachedViews: [...cachedViews.value]
});
});
@ -132,7 +132,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
const delAllVisitedViews = (): Promise<RouteLocationNormalized[]> => {
return new Promise((resolve) => {
visitedViews.value = visitedViews.value.filter((tag: RouteLocationNormalized) => tag.meta?.affix);
resolve([...visitedViews.value]);
resolve([...visitedViews.value as RouteLocationNormalized[]]);
});
};
@ -167,7 +167,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
}
return false;
});
resolve([...visitedViews.value]);
resolve([...visitedViews.value as RouteLocationNormalized[]]);
});
};
const delLeftTags = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => {
@ -186,7 +186,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
}
return false;
});
resolve([...visitedViews.value]);
resolve([...visitedViews.value as RouteLocationNormalized[]]);
});
};

45
src/utils/sse.ts Normal file
View File

@ -0,0 +1,45 @@
import { getToken } from '@/utils/auth';
import { ElNotification } from 'element-plus';
import useNoticeStore from '@/store/modules/notice';
let message = '';
// 初始化
export const initSSE = (url: any) => {
url = url + '?Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID
const {
data,
error
} = useEventSource(url, [], {
autoReconnect: {
retries: 10,
delay: 3000,
onFailed() {
console.log('Failed to connect after 10 retries')
},
}
});
watch(error, () => {
console.log('SSE connection error:', error.value)
error.value = null;
});
watch(data, () => {
if (!data.value) return;
useNoticeStore().addNotice({
message: data.value,
read: false,
time: new Date().toLocaleString()
});
ElNotification({
title: '消息',
message: data.value,
type: 'success',
duration: 3000
});
data.value = null;
});
};

View File

@ -1,125 +1,37 @@
/**
* @module initWebSocket
* @module websocketonopen
* @module websocketonerror
* @module websocketclose
* @module resetHeart
* @module sendSocketHeart
* @module reconnect
* @module sendMsg
* @module websocketonmessage
* @module test
* @description socket
* @param {any} url socket地址
* @param {any} websocket websocket
* @param {any} heartTime
* @param {number} socketHeart
* @param {number} HeartTimeOut
* @param {number} socketError
*/
import { getToken } from '@/utils/auth';
import { ElNotification } from 'element-plus';
import useNoticeStore from '@/store/modules/notice';
let socketUrl: any = ''; // socket地址
let websocket: any = null; // websocket 实例
let heartTime: any = null; // 心跳定时器实例
let socketHeart = 0 as number; // 心跳次数
const HeartTimeOut = 10000; // 心跳超时时间 10000 = 10s
let socketError = 0 as number; // 错误次数
// 初始化socket
export const initWebSocket = (url: any) => {
if (import.meta.env.VITE_APP_WEBSOCKET === 'false') {
return;
}
socketUrl = url;
// 初始化 websocket
websocket = new WebSocket(url + '?Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID);
websocketonopen();
websocketonmessage();
websocketonerror();
websocketclose();
sendSocketHeart();
return websocket;
};
// socket 连接成功
export const websocketonopen = () => {
websocket.onopen = function () {
console.log('连接 websocket 成功');
resetHeart();
};
};
// socket 连接失败
export const websocketonerror = () => {
websocket.onerror = function (e: any) {
console.log('连接 websocket 失败', e);
};
};
// socket 断开链接
export const websocketclose = () => {
websocket.onclose = function (e: any) {
console.log('断开连接', e);
};
};
// socket 重置心跳
export const resetHeart = () => {
socketHeart = 0;
socketError = 0;
clearInterval(heartTime);
sendSocketHeart();
};
// socket心跳发送
export const sendSocketHeart = () => {
heartTime = setInterval(() => {
// 如果连接正常则发送心跳
if (websocket.readyState == 1) {
// if (socketHeart <= 30) {
websocket.send(
JSON.stringify({
type: 'ping'
})
);
socketHeart = socketHeart + 1;
} else {
// 重连
reconnect();
}
}, HeartTimeOut);
};
// socket重连
export const reconnect = () => {
if (socketError <= 2) {
clearInterval(heartTime);
initWebSocket(socketUrl);
socketError = socketError + 1;
// eslint-disable-next-line prettier/prettier
console.log('socket重连', socketError);
} else {
// eslint-disable-next-line prettier/prettier
console.log('重试次数已用完');
clearInterval(heartTime);
}
};
// socket 发送数据
export const sendMsg = (data: any) => {
websocket.send(data);
};
// socket 接收数据
export const websocketonmessage = () => {
websocket.onmessage = function (e: any) {
if (e.data.indexOf('heartbeat') > 0) {
resetHeart();
}
url = url + '?Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID
useWebSocket(url, {
autoReconnect: {
// 重连最大次数
retries: 3,
// 重连间隔
delay: 1000,
onFailed() {
console.log('websocket重连失败');
},
},
heartbeat: {
message: JSON.stringify({type: 'ping'}),
// 发送心跳的间隔
interval: 10000,
// 接收到心跳response的超时时间
pongTimeout: 2000,
},
onConnected() {
console.log('websocket已经连接');
},
onDisconnected() {
console.log('websocket已经断开');
},
onMessage: (_, e) => {
if (e.data.indexOf('ping') > 0) {
return;
}
@ -134,6 +46,6 @@ export const websocketonmessage = () => {
type: 'success',
duration: 3000
});
return e.data;
};
}
});
};

View File

@ -33,7 +33,7 @@
* 部署方式 Docker 容器编排 一键部署业务集群<br />
* 国际化 SpringMessage Spring标准国际化方案<br />
</p>
<p><b>当前版本:</b> <span>v5.2.1</span></p>
<p><b>当前版本:</b> <span>v5.2.2</span></p>
<p>
<el-tag type="danger">&yen;免费开源</el-tag>
</p>
@ -77,7 +77,7 @@
* 分布式监控 PrometheusGrafana 全方位性能监控<br />
* 其余与 Vue 版本一致<br />
</p>
<p><b>当前版本:</b> <span>v2.2.0</span></p>
<p><b>当前版本:</b> <span>v2.2.1</span></p>
<p>
<el-tag type="danger">&yen;免费开源</el-tag>
</p>

View File

@ -60,7 +60,7 @@
>
</el-col>
<el-col :span="1.5">
<el-button v-hasPermi="['system:oss:list']" type="info" plain icon="Operation" @click="handleOssConfig">配置管理</el-button>
<el-button v-hasPermi="['system:ossConfig:list']" type="info" plain icon="Operation" @click="handleOssConfig">配置管理</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar>
</el-row>

View File

@ -18,7 +18,7 @@
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"

View File

@ -321,7 +321,7 @@ const handleDelete = async (row?: TenantPkgVO) => {
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(
'system/tenantPackage/export',
'system/package/export',
{
...queryParams.value
},

View File

@ -80,8 +80,8 @@ const tableRef = ref<ElTableInstance>();
/** 单击选中行数据 */
const clickRow = (row: RoleVO) => {
// eleselected
tableRef.value?.toggleRowSelection(row, false);
row.flag = !row.flag
tableRef.value?.toggleRowSelection(row, row.flag);
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: RoleVO[]) => {

View File

@ -39,11 +39,12 @@
<el-form-item label="创建时间" style="width: 308px">
<el-date-picker
v-model="dateRange"
value-format="YYYY-MM-DD"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
></el-date-picker>
</el-form-item>
<el-form-item>

View File

@ -176,7 +176,6 @@ const handleSelectionChange = (selection: LeaveVO[]) => {
/** 新增按钮操作 */
const handleAdd = () => {
proxy.$tab.closePage(proxy.$route);
proxy.$router.push(`/workflow/leaveEdit/index/add/add`);
proxy.$router.push({
path: `/workflow/leaveEdit/index`,
query: {

View File

@ -75,61 +75,7 @@ export default defineConfig(({ mode, command }: ConfigEnv): UserConfig => {
'diagram-js/lib/draw/BaseRenderer',
'tiny-svg',
'image-conversion',
'element-plus/es/components/text/style/css',
'element-plus/es/components/collapse-item/style/css',
'element-plus/es/components/collapse/style/css',
'element-plus/es/components/space/style/css',
'element-plus/es/components/container/style/css',
'element-plus/es/components/aside/style/css',
'element-plus/es/components/main/style/css',
'element-plus/es/components/header/style/css',
'element-plus/es/components/button-group/style/css',
'element-plus/es/components/radio-button/style/css',
'element-plus/es/components/checkbox-group/style/css',
'element-plus/es/components/form/style/css',
'element-plus/es/components/form-item/style/css',
'element-plus/es/components/button/style/css',
'element-plus/es/components/input/style/css',
'element-plus/es/components/input-number/style/css',
'element-plus/es/components/switch/style/css',
'element-plus/es/components/upload/style/css',
'element-plus/es/components/menu/style/css',
'element-plus/es/components/col/style/css',
'element-plus/es/components/icon/style/css',
'element-plus/es/components/row/style/css',
'element-plus/es/components/tag/style/css',
'element-plus/es/components/dialog/style/css',
'element-plus/es/components/loading/style/css',
'element-plus/es/components/radio/style/css',
'element-plus/es/components/radio-group/style/css',
'element-plus/es/components/popover/style/css',
'element-plus/es/components/scrollbar/style/css',
'element-plus/es/components/tooltip/style/css',
'element-plus/es/components/dropdown/style/css',
'element-plus/es/components/dropdown-menu/style/css',
'element-plus/es/components/dropdown-item/style/css',
'element-plus/es/components/sub-menu/style/css',
'element-plus/es/components/menu-item/style/css',
'element-plus/es/components/divider/style/css',
'element-plus/es/components/card/style/css',
'element-plus/es/components/link/style/css',
'element-plus/es/components/breadcrumb/style/css',
'element-plus/es/components/breadcrumb-item/style/css',
'element-plus/es/components/table/style/css',
'element-plus/es/components/tree-select/style/css',
'element-plus/es/components/table-column/style/css',
'element-plus/es/components/select/style/css',
'element-plus/es/components/option/style/css',
'element-plus/es/components/pagination/style/css',
'element-plus/es/components/tree/style/css',
'element-plus/es/components/alert/style/css',
'element-plus/es/components/checkbox/style/css',
'element-plus/es/components/date-picker/style/css',
'element-plus/es/components/transfer/style/css',
'element-plus/es/components/tabs/style/css',
'element-plus/es/components/image/style/css',
'element-plus/es/components/tab-pane/style/css'
'element-plus/es/components/**/css'
]
}
};