mirror of
https://github.com/jeecgboot/jeecg-boot.git
synced 2025-09-02 10:25:56 +00:00
Merge branch 'master' of https://github.com/zhangdaiscott/jeecg-boot
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
<template>
|
||||
<Select @dropdownVisibleChange="handleFetch" v-bind="attrs_" @change="handleChange" :options="getOptions" v-model:value="state">
|
||||
<Select
|
||||
v-bind="attrs_"
|
||||
v-model:value="state"
|
||||
:options="getOptions"
|
||||
@change="handleChange"
|
||||
@dropdownVisibleChange="handleFetch"
|
||||
@popupScroll="handlePopupScroll"
|
||||
>
|
||||
<template #[item]="data" v-for="item in Object.keys($slots)">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
@@ -24,9 +31,10 @@
|
||||
import { LoadingOutlined } from '@ant-design/icons-vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { isNumber } from '/@/utils/is';
|
||||
|
||||
type OptionsItem = { label: string; value: string; disabled?: boolean };
|
||||
|
||||
//文档 https://help.jeecg.com/ui/apiSelect#pageconfig%E5%8F%82%E6%95%B0%E9%85%8D%E7%BD%AE
|
||||
export default defineComponent({
|
||||
name: 'ApiSelect',
|
||||
components: {
|
||||
@@ -35,7 +43,7 @@
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: [Array, Object, String, Number],
|
||||
value: [Array, String, Number],
|
||||
numberToString: propTypes.bool,
|
||||
api: {
|
||||
type: Function as PropType<(arg?: Recordable) => Promise<OptionsItem[]>>,
|
||||
@@ -46,6 +54,11 @@
|
||||
type: Object as PropType<Recordable>,
|
||||
default: () => ({}),
|
||||
},
|
||||
//分页配置
|
||||
pageConfig: {
|
||||
type: Object as PropType<Recordable>,
|
||||
default: () => ({ isPage: false }),
|
||||
},
|
||||
// support xxx.xxx.xx
|
||||
resultField: propTypes.string.def(''),
|
||||
labelField: propTypes.string.def('label'),
|
||||
@@ -60,7 +73,15 @@
|
||||
const emitData = ref<any[]>([]);
|
||||
const attrs = useAttrs();
|
||||
const { t } = useI18n();
|
||||
|
||||
// update-begin--author:liusq---date:20250407---for:【QQYUN-11831】ApiSelect 分页下拉方案 #7883
|
||||
const hasMore = ref(true);
|
||||
const pagination = ref({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
const defPageConfig = { isPage: false, pageField: 'pageNo', pageSizeField: 'pageSize', totalField: 'total', listField: 'records' };
|
||||
// update-end--author:liusq---date:20250407---for:【QQYUN-11831】ApiSelect 分页下拉方案 #7883
|
||||
// Embedded in the form, just use the hook binding to perform form verification
|
||||
const [state, setState] = useRuleFormItem(props, 'value', 'change', emitData);
|
||||
// update-begin--author:liaozhiyang---date:20230830---for:【QQYUN-6308】解决警告
|
||||
@@ -114,7 +135,7 @@
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
//监听数值修改,查询数据
|
||||
//监听数值修改,查询数据
|
||||
watchEffect(() => {
|
||||
props.value && handleFetch();
|
||||
});
|
||||
@@ -122,17 +143,33 @@
|
||||
async function fetch() {
|
||||
const api = props.api;
|
||||
if (!api || !isFunction(api)) return;
|
||||
options.value = [];
|
||||
// update-begin--author:liusq---date:20250407---for:【QQYUN-11831】ApiSelect 分页下拉方案 #7883
|
||||
if (!props.pageConfig.isPage || pagination.value.pageNo == 1) {
|
||||
options.value = [];
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await api(props.params);
|
||||
if (Array.isArray(res)) {
|
||||
options.value = res;
|
||||
emitChange();
|
||||
return;
|
||||
}
|
||||
if (props.resultField) {
|
||||
options.value = get(res, props.resultField) || [];
|
||||
let { isPage, pageField, pageSizeField, totalField, listField } = { ...defPageConfig, ...props.pageConfig };
|
||||
let params = isPage
|
||||
? { ...props.params, [pageField]: pagination.value.pageNo, [pageSizeField]: pagination.value.pageSize }
|
||||
: { ...props.params };
|
||||
// update-end--author:liusq---date:20250407---for:【QQYUN-11831】ApiSelect 分页下拉方案 #7883
|
||||
const res = await api(params);
|
||||
if (isPage) {
|
||||
// update-begin--author:liusq---date:20250407---for:【QQYUN-11831】ApiSelect 分页下拉方案 #7883
|
||||
options.value = [...options.value, ...res[listField]];
|
||||
pagination.value.total = res[totalField] || 0;
|
||||
hasMore.value = res[totalField] ? options.value.length < res[totalField] : res[listField] < pagination.value.pageSize;
|
||||
// update-end--author:liusq---date:20250407---for:【QQYUN-11831】ApiSelect 分页下拉方案 #7883
|
||||
} else {
|
||||
if (Array.isArray(res)) {
|
||||
options.value = res;
|
||||
emitChange();
|
||||
return;
|
||||
}
|
||||
if (props.resultField) {
|
||||
options.value = get(res, props.resultField) || [];
|
||||
}
|
||||
}
|
||||
emitChange();
|
||||
} catch (error) {
|
||||
@@ -151,9 +188,17 @@
|
||||
|
||||
function initValue() {
|
||||
let value = props.value;
|
||||
if (value && typeof value === 'string' && value != 'null' && value != 'undefined') {
|
||||
state.value = value.split(',');
|
||||
// update-begin--author:liaozhiyang---date:20250407---for:【issues/8037】初始化值单选的值被错误地写入数组值
|
||||
if (unref(attrs).mode == 'multiple') {
|
||||
if (value && typeof value === 'string' && value != 'null' && value != 'undefined') {
|
||||
state.value = value.split(',');
|
||||
} else if (isNumber(value)) {
|
||||
state.value = [value];
|
||||
}
|
||||
} else {
|
||||
state.value = value;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20250407---for:【issues/8037】初始化值单选的值被错误地写入数组值
|
||||
}
|
||||
|
||||
async function handleFetch() {
|
||||
@@ -171,8 +216,18 @@
|
||||
vModalValue && vModalValue(_);
|
||||
emitData.value = args;
|
||||
}
|
||||
|
||||
return { state, attrs_, attrs, getOptions, loading, t, handleFetch, handleChange };
|
||||
// update-begin--author:liusq---date:20250407---for:【QQYUN-11831】ApiSelect 分页下拉方案 #7883
|
||||
// 滚动加载更多
|
||||
function handlePopupScroll(e) {
|
||||
const { scrollTop, scrollHeight, clientHeight } = e.target;
|
||||
const isNearBottom = scrollHeight - scrollTop <= clientHeight + 20;
|
||||
if (props.pageConfig.isPage && isNearBottom && hasMore.value && !loading.value) {
|
||||
pagination.value.pageNo += 1;
|
||||
fetch();
|
||||
}
|
||||
}
|
||||
// update-end--author:liusq---date:20250407---for:【QQYUN-11831】ApiSelect 分页下拉方案 #7883
|
||||
return { state, attrs_, attrs, getOptions, loading, t, handleFetch, handleChange, handlePopupScroll };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@@ -209,18 +209,11 @@ export const useUserStore = defineStore({
|
||||
//update-begin---author:wangshuai ---date:20230424 for:【QQYUN-5195】登录之后直接刷新页面导致没有进入创建组织页面------------
|
||||
if (redirect && goHome) {
|
||||
//update-end---author:wangshuai ---date:20230424 for:【QQYUN-5195】登录之后直接刷新页面导致没有进入创建组织页面------------
|
||||
// update-begin--author:liaozhiyang---date:20240104---for:【QQYUN-7804】部署生产环境,登录跳转404问题
|
||||
let publicPath = import.meta.env.VITE_PUBLIC_PATH;
|
||||
if (publicPath && publicPath != '/') {
|
||||
// update-begin--author:liaozhiyang---date:20240509---for:【issues/1147】登录跳转时去掉发布路径的最后一个/以解决404问题
|
||||
if (publicPath.endsWith('/')) {
|
||||
publicPath = publicPath.slice(0, -1);
|
||||
}
|
||||
redirect = publicPath + redirect;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240509---for:【issues/1147】登录跳转时去掉发布路径的最后一个/以解决404问题
|
||||
// update-begin--author:liaozhiyang---date:20250407---for:【issues/8034】hash模式下退出重登录默认跳转地址异常
|
||||
// router.options.history.base可替代之前的publicPath
|
||||
// 当前页面打开
|
||||
window.open(redirect, '_self')
|
||||
window.open(`${router.options.history.base}${redirect}`, '_self');
|
||||
// update-end--author:liaozhiyang---date:20250407---for:【issues/8034】hash模式下退出重登录默认跳转地址异常
|
||||
return data;
|
||||
}
|
||||
// update-end-author:sunjianlei date:20230306 for: 修复登录成功后,没有正确重定向的问题
|
||||
|
@@ -4,7 +4,8 @@
|
||||
<a-tabs v-model:activeKey="activeKey" @change="tabChange">
|
||||
<a-tab-pane key="1" tab="服务器信息"></a-tab-pane>
|
||||
<a-tab-pane key="2" tab="JVM信息" force-render></a-tab-pane>
|
||||
<a-tab-pane key="3" tab="Tomcat信息"></a-tab-pane>
|
||||
<!-- <a-tab-pane key="3" tab="Tomcat信息"></a-tab-pane> -->
|
||||
<a-tab-pane key="6" tab="Undertow信息"></a-tab-pane>
|
||||
<a-tab-pane key="4" tab="磁盘监控">
|
||||
<DiskInfo v-if="activeKey == 4" style="height: 100%"></DiskInfo>
|
||||
</a-tab-pane>
|
||||
|
@@ -30,6 +30,11 @@ enum Api {
|
||||
tomcatSessionsRejected = '/actuator/metrics/tomcat.sessions.rejected',
|
||||
|
||||
memoryInfo = '/sys/actuator/memory/info',
|
||||
// undertow 监控
|
||||
undertowSessionsCreated = '/actuator/metrics/undertow.sessions.created',
|
||||
undertowSessionsExpired = '/actuator/metrics/undertow.sessions.expired',
|
||||
undertowSessionsActiveCurrent = '/actuator/metrics/undertow.sessions.active.current',
|
||||
undertowSessionsActiveMax = '/actuator/metrics/undertow.sessions.active.max',
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,6 +212,34 @@ export const getTomcatSessionsRejected = () => {
|
||||
return defHttp.get({ url: Api.tomcatSessionsRejected }, { isTransformResponse: false });
|
||||
};
|
||||
|
||||
/**
|
||||
*undertow 已创建 session 数
|
||||
*/
|
||||
export const getUndertowSessionsCreated = () => {
|
||||
return defHttp.get({ url: Api.undertowSessionsCreated }, { isTransformResponse: false });
|
||||
};
|
||||
|
||||
/**
|
||||
*undertow 已过期 session 数
|
||||
*/
|
||||
export const getUndertowSessionsExpired = () => {
|
||||
return defHttp.get({ url: Api.undertowSessionsExpired }, { isTransformResponse: false });
|
||||
};
|
||||
|
||||
/**
|
||||
*undertow 当前活跃 session 数
|
||||
*/
|
||||
export const getUndertowSessionsActiveCurrent = () => {
|
||||
return defHttp.get({ url: Api.undertowSessionsActiveCurrent }, { isTransformResponse: false });
|
||||
};
|
||||
|
||||
/**
|
||||
*undertow 活跃 session 数峰值
|
||||
*/
|
||||
export const getUndertowSessionsActiveMax = () => {
|
||||
return defHttp.get({ url: Api.undertowSessionsActiveMax }, { isTransformResponse: false });
|
||||
};
|
||||
|
||||
/**
|
||||
* 内存信息
|
||||
*/
|
||||
@@ -230,6 +263,9 @@ export const getMoreInfo = (infoType) => {
|
||||
if (infoType == '5') {
|
||||
return {};
|
||||
}
|
||||
if (infoType == '6') {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
export const getTextInfo = (infoType) => {
|
||||
@@ -293,6 +329,16 @@ export const getTextInfo = (infoType) => {
|
||||
'memory.runtime.usage': { color: 'purple', text: 'JVM内存使用率', unit: '%', valueType: 'Number' },
|
||||
};
|
||||
}
|
||||
if (infoType == '6') {
|
||||
// undertow 监控
|
||||
return {
|
||||
'undertow.sessions.created': { color: 'green', text: 'undertow 已创建 session 数', unit: '个' },
|
||||
'undertow.sessions.expired': { color: 'green', text: 'undertow 已过期 session 数', unit: '个' },
|
||||
'undertow.sessions.active.current': { color: 'green', text: 'undertow 当前活跃 session 数', unit: '个' },
|
||||
'undertow.sessions.active.max': { color: 'green', text: 'undertow 活跃 session 数峰值', unit: '个' },
|
||||
'undertow.sessions.rejected': { color: 'green', text: '超过session 最大配置后,拒绝的 session 个数', unit: '个' },
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -334,4 +380,13 @@ export const getServerInfo = (infoType) => {
|
||||
if (infoType == '5') {
|
||||
return Promise.all([getMemoryInfo()]);
|
||||
}
|
||||
// undertow监控
|
||||
if (infoType == '6') {
|
||||
return Promise.all([
|
||||
getUndertowSessionsActiveCurrent(),
|
||||
getUndertowSessionsActiveMax(),
|
||||
getUndertowSessionsCreated(),
|
||||
getUndertowSessionsExpired(),
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user