feat: 统一管理端弹窗与内容区交互样式
- 收敛管理端公共 Modal 链路,新增表单弹窗与普通内容弹窗包装\n- 迁移 Bot、知识库、插件、工作流、资源、MCP、数据中枢与系统管理页面级弹窗\n- 统一内容区工具栏、列表容器、导航与顶部按钮的视觉密度和交互节奏
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, useAttrs, watch } from 'vue';
|
||||
|
||||
import { $t } from '@easyflow/locales';
|
||||
|
||||
import { useEasyFlowModal } from '@easyflow-core/popup-ui';
|
||||
import { EasyFlowButton } from '@easyflow-core/shadcn-ui';
|
||||
import { cn } from '@easyflow-core/shared/utils';
|
||||
|
||||
type BeforeClose = () => boolean | Promise<boolean | void> | void;
|
||||
|
||||
interface Props {
|
||||
alignCenter?: boolean;
|
||||
beforeClose?: BeforeClose;
|
||||
cancelText?: string;
|
||||
centered?: boolean;
|
||||
closable?: boolean;
|
||||
closeOnClickModal?: boolean;
|
||||
confirmLoading?: boolean;
|
||||
confirmText?: string;
|
||||
description?: string;
|
||||
destroyOnClose?: boolean;
|
||||
draggable?: boolean;
|
||||
modelValue?: boolean;
|
||||
open?: boolean;
|
||||
showCancelButton?: boolean;
|
||||
showConfirmButton?: boolean;
|
||||
showFooter?: boolean;
|
||||
submitting?: boolean;
|
||||
title: string;
|
||||
width?: 'lg' | 'md' | 'xl' | number | string;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: 'EasyFlowPanelModal',
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
alignCenter: false,
|
||||
beforeClose: undefined,
|
||||
cancelText: '',
|
||||
centered: false,
|
||||
closable: true,
|
||||
closeOnClickModal: false,
|
||||
confirmLoading: false,
|
||||
confirmText: '',
|
||||
description: '',
|
||||
destroyOnClose: true,
|
||||
draggable: false,
|
||||
modelValue: undefined,
|
||||
open: undefined,
|
||||
showCancelButton: true,
|
||||
showConfirmButton: true,
|
||||
showFooter: true,
|
||||
submitting: false,
|
||||
width: 'lg',
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
cancel: [];
|
||||
confirm: [];
|
||||
'update:modelValue': [boolean];
|
||||
'update:open': [boolean];
|
||||
}>();
|
||||
|
||||
const attrs = useAttrs();
|
||||
|
||||
const [Modal, modalApi] = useEasyFlowModal({
|
||||
async onBeforeClose() {
|
||||
const result = await props.beforeClose?.();
|
||||
return result !== false;
|
||||
},
|
||||
onOpenChange(isOpen) {
|
||||
emit('update:modelValue', isOpen);
|
||||
emit('update:open', isOpen);
|
||||
},
|
||||
});
|
||||
|
||||
const widthClassMap: Record<string, string> = {
|
||||
'482': 'sm:w-[482px]',
|
||||
'482px': 'sm:w-[482px]',
|
||||
'50%': 'sm:w-[min(50vw,720px)]',
|
||||
'500px': 'sm:w-[500px]',
|
||||
'520px': 'sm:w-[520px]',
|
||||
'550px': 'sm:w-[550px]',
|
||||
'600px': 'sm:w-[600px]',
|
||||
'762': 'sm:w-[762px]',
|
||||
'762px': 'sm:w-[762px]',
|
||||
'800px': 'sm:w-[800px]',
|
||||
'80%': 'sm:w-[min(80vw,1120px)]',
|
||||
'min(920px, 92vw)': 'sm:w-[min(92vw,920px)]',
|
||||
'min(980px, 92vw)': 'sm:w-[min(92vw,980px)]',
|
||||
md: 'sm:w-[560px]',
|
||||
lg: 'sm:w-[720px]',
|
||||
xl: 'sm:w-[960px]',
|
||||
};
|
||||
|
||||
const modalClass = computed(() => {
|
||||
const widthKey = String(props.width);
|
||||
return cn(
|
||||
'w-[calc(100vw-24px)] max-w-[calc(100vw-24px)] sm:max-w-[min(calc(100vw-48px),1120px)]',
|
||||
widthClassMap[widthKey] || widthClassMap.lg,
|
||||
attrs.class,
|
||||
);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.open ?? props.modelValue ?? false,
|
||||
(value) => {
|
||||
modalApi.setState({ isOpen: value });
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
function handleCancel() {
|
||||
emit('cancel');
|
||||
modalApi.close();
|
||||
}
|
||||
|
||||
function handleConfirm() {
|
||||
emit('confirm');
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
:class="modalClass"
|
||||
:centered="centered || alignCenter"
|
||||
:closable="closable"
|
||||
:close-on-click-modal="closeOnClickModal"
|
||||
:confirm-loading="confirmLoading"
|
||||
:description="description"
|
||||
:destroy-on-close="destroyOnClose"
|
||||
:draggable="draggable"
|
||||
:footer="showFooter"
|
||||
:fullscreen-button="false"
|
||||
:show-cancel-button="false"
|
||||
:show-confirm-button="false"
|
||||
:submitting="submitting"
|
||||
:title="title"
|
||||
>
|
||||
<slot></slot>
|
||||
|
||||
<template v-if="showFooter" #footer>
|
||||
<slot name="footer">
|
||||
<div class="flex w-full items-center justify-between gap-3">
|
||||
<div class="min-w-0 flex-1">
|
||||
<slot name="footer-extra"></slot>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<EasyFlowButton
|
||||
v-if="showCancelButton"
|
||||
variant="ghost"
|
||||
:disabled="submitting"
|
||||
@click="handleCancel"
|
||||
>
|
||||
{{ cancelText || $t('button.cancel') }}
|
||||
</EasyFlowButton>
|
||||
<EasyFlowButton
|
||||
v-if="showConfirmButton"
|
||||
:disabled="submitting"
|
||||
:loading="confirmLoading || submitting"
|
||||
@click="handleConfirm"
|
||||
>
|
||||
{{ confirmText || $t('button.confirm') }}
|
||||
</EasyFlowButton>
|
||||
</div>
|
||||
</div>
|
||||
</slot>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
Reference in New Issue
Block a user