mirror of
https://gitee.com/dapppp/ruoyi-plus-vben5.git
synced 2026-03-07 23:31:08 +08:00
Merge branch 'main' into fix
This commit is contained in:
@@ -17,6 +17,7 @@ import type { BaseFormComponentType } from '@vben/common-ui';
|
||||
import type { Recordable } from '@vben/types';
|
||||
|
||||
import {
|
||||
computed,
|
||||
defineAsyncComponent,
|
||||
defineComponent,
|
||||
h,
|
||||
@@ -383,12 +384,17 @@ const withPreviewUpload = () => {
|
||||
attrs?.fileList || attrs?.['file-list'] || [],
|
||||
);
|
||||
|
||||
const maxSize = computed(() => attrs?.maxSize ?? attrs?.['max-size']);
|
||||
const aspectRatio = computed(
|
||||
() => attrs?.aspectRatio ?? attrs?.['aspect-ratio'],
|
||||
);
|
||||
|
||||
const handleBeforeUpload = async (
|
||||
file: UploadFile,
|
||||
originFileList: Array<File>,
|
||||
) => {
|
||||
if (attrs.maxSize && (file.size || 0) / 1024 / 1024 > attrs.maxSize) {
|
||||
message.error($t('ui.formRules.sizeLimit', [attrs.maxSize]));
|
||||
if (maxSize.value && (file.size || 0) / 1024 / 1024 > maxSize.value) {
|
||||
message.error($t('ui.formRules.sizeLimit', [maxSize.value]));
|
||||
file.status = 'removed';
|
||||
return false;
|
||||
}
|
||||
@@ -401,7 +407,7 @@ const withPreviewUpload = () => {
|
||||
) {
|
||||
file.status = 'removed';
|
||||
// antd Upload组件问题 file参数获取的是UploadFile类型对象无法取到File类型 所以通过originFileList[0]获取
|
||||
const blob = await cropImage(originFileList[0], attrs.aspectRatio);
|
||||
const blob = await cropImage(originFileList[0], aspectRatio.value);
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!blob) {
|
||||
return reject(new Error($t('ui.crop.errorTip')));
|
||||
|
||||
@@ -41,6 +41,18 @@ export function getElementVisibleRect(
|
||||
const left = Math.max(rect.left, 0);
|
||||
const right = Math.min(rect.right, viewWidth);
|
||||
|
||||
// 如果元素完全不可见,则返回一个空的矩形
|
||||
if (top >= viewHeight || bottom <= 0 || left >= viewWidth || right <= 0) {
|
||||
return {
|
||||
bottom: 0,
|
||||
height: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
width: 0,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
bottom,
|
||||
height: Math.max(0, bottom - top),
|
||||
|
||||
@@ -41,6 +41,7 @@ export function useVbenModal<TParentModalProps extends ModalProps = ModalProps>(
|
||||
// 不能用 Object.assign,会丢失 api 的原型函数
|
||||
Object.setPrototypeOf(extendedApi, api);
|
||||
},
|
||||
consumed: false,
|
||||
options,
|
||||
async reCreateModal() {
|
||||
isModalReady.value = false;
|
||||
@@ -73,7 +74,13 @@ export function useVbenModal<TParentModalProps extends ModalProps = ModalProps>(
|
||||
return [Modal, extendedApi as ExtendedModalApi] as const;
|
||||
}
|
||||
|
||||
const injectData = inject<any>(USER_MODAL_INJECT_KEY, {});
|
||||
let injectData = inject<any>(USER_MODAL_INJECT_KEY, {});
|
||||
// 这个数据已经被使用了,说明这个弹窗是嵌套的弹窗,不应该merge上层的配置
|
||||
if (injectData.consumed) {
|
||||
injectData = {};
|
||||
} else {
|
||||
injectData.consumed = true;
|
||||
}
|
||||
|
||||
const mergedOptions = {
|
||||
...DEFAULT_MODAL_PROPS,
|
||||
|
||||
@@ -32,19 +32,19 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
// const startTime = ref(0);
|
||||
const showSpinner = ref(false);
|
||||
const renderSpinner = ref(false);
|
||||
const timer = ref<ReturnType<typeof setTimeout>>();
|
||||
let timer: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
watch(
|
||||
() => props.spinning,
|
||||
(show) => {
|
||||
if (!show) {
|
||||
showSpinner.value = false;
|
||||
clearTimeout(timer.value);
|
||||
timer && clearTimeout(timer);
|
||||
return;
|
||||
}
|
||||
|
||||
// startTime.value = performance.now();
|
||||
timer.value = setTimeout(() => {
|
||||
timer = setTimeout(() => {
|
||||
// const loadingTime = performance.now() - startTime.value;
|
||||
|
||||
showSpinner.value = true;
|
||||
|
||||
@@ -92,7 +92,8 @@ function useEcharts(chartRef: Ref<EchartsUIType>) {
|
||||
return;
|
||||
}
|
||||
useTimeoutFn(() => {
|
||||
if (!chartInstance) {
|
||||
if (!chartInstance || chartInstance?.getDom() !== el) {
|
||||
chartInstance?.dispose();
|
||||
const instance = initCharts();
|
||||
if (!instance) return;
|
||||
}
|
||||
@@ -104,6 +105,36 @@ function useEcharts(chartRef: Ref<EchartsUIType>) {
|
||||
});
|
||||
};
|
||||
|
||||
const updateDate = (
|
||||
option: EChartsOption,
|
||||
notMerge = false, // false = 合并(保留动画),true = 完全替换
|
||||
lazyUpdate = false, // true 时不立即重绘,适合短时间内多次调用
|
||||
): Promise<echarts.ECharts | null> => {
|
||||
return new Promise((resolve) => {
|
||||
nextTick(() => {
|
||||
if (!chartInstance) {
|
||||
// 还没初始化 → 当作首次渲染
|
||||
renderEcharts(option).then(resolve);
|
||||
return;
|
||||
}
|
||||
|
||||
// 合并你原有的全局配置(比如 backgroundColor)
|
||||
const finalOption = {
|
||||
...option,
|
||||
...getOptions.value,
|
||||
};
|
||||
|
||||
chartInstance.setOption(finalOption, {
|
||||
notMerge,
|
||||
lazyUpdate,
|
||||
// silent: true, // 如果追求极致性能可开启(关闭所有事件)
|
||||
});
|
||||
|
||||
resolve(chartInstance);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function resize() {
|
||||
const el = getChartEl();
|
||||
if (isElHidden(el)) {
|
||||
@@ -139,6 +170,7 @@ function useEcharts(chartRef: Ref<EchartsUIType>) {
|
||||
return {
|
||||
renderEcharts,
|
||||
resize,
|
||||
updateDate,
|
||||
getChartInstance: () => chartInstance,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import type { BaseFormComponentType } from '@vben/common-ui';
|
||||
import type { Recordable } from '@vben/types';
|
||||
|
||||
import {
|
||||
computed,
|
||||
defineAsyncComponent,
|
||||
defineComponent,
|
||||
h,
|
||||
@@ -383,12 +384,17 @@ const withPreviewUpload = () => {
|
||||
attrs?.fileList || attrs?.['file-list'] || [],
|
||||
);
|
||||
|
||||
const maxSize = computed(() => attrs?.maxSize ?? attrs?.['max-size']);
|
||||
const aspectRatio = computed(
|
||||
() => attrs?.aspectRatio ?? attrs?.['aspect-ratio'],
|
||||
);
|
||||
|
||||
const handleBeforeUpload = async (
|
||||
file: UploadFile,
|
||||
originFileList: Array<File>,
|
||||
) => {
|
||||
if (attrs.maxSize && (file.size || 0) / 1024 / 1024 > attrs.maxSize) {
|
||||
message.error($t('ui.formRules.sizeLimit', [attrs.maxSize]));
|
||||
if (maxSize.value && (file.size || 0) / 1024 / 1024 > maxSize.value) {
|
||||
message.error($t('ui.formRules.sizeLimit', [maxSize.value]));
|
||||
file.status = 'removed';
|
||||
return false;
|
||||
}
|
||||
@@ -401,7 +407,7 @@ const withPreviewUpload = () => {
|
||||
) {
|
||||
file.status = 'removed';
|
||||
// antd Upload组件问题 file参数获取的是UploadFile类型对象无法取到File类型 所以通过originFileList[0]获取
|
||||
const blob = await cropImage(originFileList[0], attrs.aspectRatio);
|
||||
const blob = await cropImage(originFileList[0], aspectRatio.value);
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!blob) {
|
||||
return reject(new Error($t('ui.crop.errorTip')));
|
||||
|
||||
@@ -78,15 +78,22 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
};
|
||||
}
|
||||
|
||||
const isLoggingOut = ref(false); // 正在 logout 标识, 防止 /logout 死循环.
|
||||
|
||||
async function logout(redirect: boolean = true) {
|
||||
if (isLoggingOut.value) return; // 正在登出中, 说明已进入循环, 直接返回.
|
||||
isLoggingOut.value = true; // 设置 标识
|
||||
|
||||
try {
|
||||
await logoutApi();
|
||||
} catch {
|
||||
// 不做任何处理
|
||||
}
|
||||
} finally {
|
||||
isLoggingOut.value = false; // 重置 标识
|
||||
|
||||
resetAllStores();
|
||||
accessStore.setLoginExpired(false);
|
||||
resetAllStores();
|
||||
accessStore.setLoginExpired(false);
|
||||
}
|
||||
|
||||
// 回登录页带上当前路由地址
|
||||
await router.replace({
|
||||
|
||||
Reference in New Issue
Block a user