chore: 基线提交(重构前代码快照)
- git 初始化 + .gitignore 补全(根 .env / logs / instance / __pycache__ 等) - 修复 utils/.gitignore 误将整个 utils/ 源码层忽略的问题,补入全部工具源码(含 ip2region.xdb) - 含后端全部代码:application / extensions / utils / config / migrations - 含前端 ui/(后续整体迁走) - 不含根 .env(含密钥,本地保留) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
export { default as basicModal } from './src/basicModal.vue';
|
||||
export { default as FooterAction } from './src/components/FooterAction.vue';
|
||||
export { useModal } from './src/hooks/useModal';
|
||||
export * from './src/type';
|
||||
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:showClose="getProps.showClose"
|
||||
:width="getProps.width"
|
||||
:draggable="getProps.draggable"
|
||||
:fullscreen="getFullscreen"
|
||||
v-bind="attrs"
|
||||
v-model="isModal"
|
||||
@close="onCloseModal"
|
||||
>
|
||||
<template #header>
|
||||
<div class="dialog-header">
|
||||
<div class="dialog-header-title">{{ getProps.title }}</div>
|
||||
<div class="dialog-header-action">
|
||||
<el-tooltip content="还原" placement="bottom" v-if="fullscreen">
|
||||
<el-link :underline="false" class="mr-4"
|
||||
><el-icon class="el-input__icon" :size="18">
|
||||
<FullscreenExitOutlined role="full" @click="handleFullScreen" /> </el-icon
|
||||
></el-link>
|
||||
>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-else content="最大化" placement="bottom">
|
||||
<el-link :underline="false" class="mr-4"
|
||||
><el-icon class="el-input__icon" :size="18"
|
||||
><FullscreenOutlined role="close" @click="handleFullScreen" /></el-icon
|
||||
></el-link>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="关闭" placement="bottom">
|
||||
<el-link :underline="false" @click="onCloseModal"
|
||||
><el-icon class="el-input__icon" :size="18"><CloseOutlined /></el-icon
|
||||
></el-link>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<slot name="default"></slot>
|
||||
</template>
|
||||
<template v-if="!getProps.hideFooter && !$slots.footer" #footer>
|
||||
<el-space>
|
||||
<slot name="prefixFooter"></slot>
|
||||
<el-button @click="closeModal" v-bind="getProps.cancelButProps">取消</el-button>
|
||||
<slot name="centerFooter"></slot>
|
||||
<el-button
|
||||
v-bind="getProps.confirmButProps"
|
||||
:loading="subLoading"
|
||||
type="primary"
|
||||
@click="handleSubmit"
|
||||
>{{ getProps.confirmButText }}
|
||||
</el-button>
|
||||
<slot name="suffixFooter"></slot>
|
||||
</el-space>
|
||||
</template>
|
||||
<template v-else #footer>
|
||||
<slot name="action"></slot>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { getCurrentInstance, ref, unref, computed, useAttrs, provide } from 'vue';
|
||||
import { basicProps } from './props';
|
||||
import { deepMerge } from '@/utils';
|
||||
import { ModalProps, ModalMethods } from './type';
|
||||
import { FullscreenExitOutlined, FullscreenOutlined, CloseOutlined } from '@vicons/antd';
|
||||
|
||||
const attrs = useAttrs();
|
||||
const props = defineProps({ ...basicProps });
|
||||
|
||||
const emit = defineEmits(['close', 'ok', 'register']);
|
||||
|
||||
const propsRef = ref(null);
|
||||
|
||||
const isModal = ref(false);
|
||||
const subLoading = ref(false);
|
||||
const fullscreen = ref(false);
|
||||
|
||||
const getProps = computed(() => {
|
||||
return { ...props, ...(unref(propsRef) as any) };
|
||||
});
|
||||
|
||||
async function setProps(modalProps: Partial<ModalProps>): Promise<void> {
|
||||
propsRef.value = deepMerge(unref(propsRef) || ({} as any), modalProps);
|
||||
}
|
||||
|
||||
const getFullscreen = computed(() => {
|
||||
return fullscreen.value;
|
||||
});
|
||||
|
||||
function setSubLoading(status: boolean) {
|
||||
subLoading.value = status;
|
||||
}
|
||||
|
||||
function openModal() {
|
||||
isModal.value = true;
|
||||
}
|
||||
|
||||
//切换全屏
|
||||
function handleFullScreen() {
|
||||
fullscreen.value = !fullscreen.value;
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
isModal.value = false;
|
||||
subLoading.value = false;
|
||||
emit('close');
|
||||
}
|
||||
|
||||
function onCloseModal() {
|
||||
isModal.value = false;
|
||||
emit('close');
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
subLoading.value = true;
|
||||
emit('ok');
|
||||
}
|
||||
|
||||
const modalMethods: ModalMethods = {
|
||||
setProps,
|
||||
openModal,
|
||||
closeModal,
|
||||
setSubLoading,
|
||||
};
|
||||
|
||||
const instance = getCurrentInstance();
|
||||
if (instance) {
|
||||
emit('register', modalMethods);
|
||||
}
|
||||
|
||||
provide('handleSubmit', handleSubmit);
|
||||
provide('closeModal', closeModal);
|
||||
provide('subLoading', subLoading.value);
|
||||
|
||||
defineExpose({
|
||||
openModal,
|
||||
closeModal,
|
||||
setProps,
|
||||
setSubLoading,
|
||||
handleSubmit,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dialog-header {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
&-title {
|
||||
flex: 1;
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
}
|
||||
&-action {
|
||||
color: var(--el-color-info);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div class="flex justify-end">
|
||||
<el-button @click="closeModal" v-bind="props.cancelButProps">{{
|
||||
props.cancelButText
|
||||
}}</el-button>
|
||||
<el-button
|
||||
:loading="subLoading"
|
||||
type="primary"
|
||||
v-bind="props.confirmButProps"
|
||||
@click="handleSubmit"
|
||||
>{{ props.confirmButText }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { inject } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
confirmButProps: {
|
||||
type: Object,
|
||||
},
|
||||
cancelButProps: {
|
||||
type: Object,
|
||||
},
|
||||
// 确认按钮文字
|
||||
confirmButText: {
|
||||
type: String,
|
||||
default: '确认',
|
||||
},
|
||||
// 取消按钮文字
|
||||
cancelButText: {
|
||||
type: String,
|
||||
default: '取消',
|
||||
},
|
||||
});
|
||||
|
||||
const handleSubmit: any = inject('handleSubmit');
|
||||
const closeModal: any = inject('closeModal');
|
||||
const subLoading = inject('subLoading');
|
||||
</script>
|
||||
@@ -0,0 +1,54 @@
|
||||
import { ref, unref, getCurrentInstance, watch } from 'vue';
|
||||
import { isProdMode } from '@/utils/env';
|
||||
import { ModalMethods, UseModalReturnType } from '../type';
|
||||
import { getDynamicProps } from '@/utils';
|
||||
import { tryOnUnmounted } from '@vueuse/core';
|
||||
export function useModal(props): UseModalReturnType {
|
||||
const modalRef = ref<Nullable<ModalMethods>>(null);
|
||||
const currentInstance = getCurrentInstance();
|
||||
|
||||
const getInstance = () => {
|
||||
const instance = unref(modalRef.value);
|
||||
if (!instance) {
|
||||
console.error('useModal instance is undefined!');
|
||||
}
|
||||
return instance;
|
||||
};
|
||||
|
||||
const register = (modalInstance: ModalMethods) => {
|
||||
isProdMode() &&
|
||||
tryOnUnmounted(() => {
|
||||
modalRef.value = null;
|
||||
});
|
||||
modalRef.value = modalInstance;
|
||||
currentInstance?.emit('register', modalInstance);
|
||||
|
||||
watch(
|
||||
() => props,
|
||||
() => {
|
||||
props && modalInstance.setProps(getDynamicProps(props));
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
const methods: ModalMethods = {
|
||||
setProps: (props): void => {
|
||||
getInstance()?.setProps(props);
|
||||
},
|
||||
openModal: () => {
|
||||
getInstance()?.openModal();
|
||||
},
|
||||
closeModal: () => {
|
||||
getInstance()?.closeModal();
|
||||
},
|
||||
setSubLoading: (status) => {
|
||||
getInstance()?.setSubLoading(status);
|
||||
},
|
||||
};
|
||||
|
||||
return [register, methods];
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
export const basicProps = {
|
||||
/** ********************** 原组件属性 ********************** **/
|
||||
width: {
|
||||
type: Number,
|
||||
default: 446,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
draggable: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
//不建议打开
|
||||
showClose: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/** ********************** 自定义属性 ********************** **/
|
||||
//隐藏底部
|
||||
hideFooter: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
//确认按钮定制
|
||||
confirmButProps: {
|
||||
type: Object,
|
||||
},
|
||||
//取消按钮定制
|
||||
cancelButProps: {
|
||||
type: Object,
|
||||
},
|
||||
// 确认按钮文字
|
||||
confirmButText: {
|
||||
type: String,
|
||||
default: '确认',
|
||||
},
|
||||
// 取消按钮文字
|
||||
cancelButText: {
|
||||
type: String,
|
||||
default: '取消',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import type { ElDialog } from 'element-plus/es/components/dialog';
|
||||
|
||||
/**
|
||||
* @description: 弹窗对外暴露的方法
|
||||
*/
|
||||
export interface ModalMethods {
|
||||
setProps: (props) => void;
|
||||
openModal: () => void;
|
||||
closeModal: () => void;
|
||||
setSubLoading: (status?) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 支持修改,ElDialog 參數
|
||||
*/
|
||||
export type ModalProps = ElDialog;
|
||||
|
||||
export type RegisterFn = (ModalInstance: ModalMethods) => void;
|
||||
|
||||
export type UseModalReturnType = [RegisterFn, ModalMethods];
|
||||
Reference in New Issue
Block a user