mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-30 15:16:42 +08:00
feat(projects): 增加useModal hooks,并添加lodash-es依赖
This commit is contained in:
parent
c9c5ca9989
commit
d9ccce69df
@ -58,6 +58,7 @@
|
||||
"@iconify/vue": "^3.1.1",
|
||||
"@types/bmapgl": "^0.0.5",
|
||||
"@types/chroma-js": "^2.1.3",
|
||||
"@types/lodash-es": "^4.17.5",
|
||||
"@types/qs": "^6.9.7",
|
||||
"@typescript-eslint/eslint-plugin": "^5.8.0",
|
||||
"@typescript-eslint/parser": "^5.8.0",
|
||||
@ -77,6 +78,7 @@
|
||||
"eslint-plugin-vue": "^8.2.0",
|
||||
"husky": "^7.0.4",
|
||||
"lint-staged": "^12.1.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"patch-package": "^6.4.7",
|
||||
"postinstall-postinstall": "^2.1.0",
|
||||
"prettier": "^2.5.1",
|
||||
@ -85,7 +87,7 @@
|
||||
"typescript": "^4.5.4",
|
||||
"unplugin-icons": "^0.12.23",
|
||||
"unplugin-vue-components": "^0.17.9",
|
||||
"vite": "~2.5.10",
|
||||
"vite": "~2.5.10",
|
||||
"vite-plugin-html": "^2.1.1",
|
||||
"vite-plugin-windicss": "^1.6.1",
|
||||
"vue-tsc": "^0.30.0",
|
||||
|
@ -10,6 +10,7 @@ specifiers:
|
||||
'@iconify/vue': ^3.1.1
|
||||
'@types/bmapgl': ^0.0.5
|
||||
'@types/chroma-js': ^2.1.3
|
||||
'@types/lodash-es': ^4.17.5
|
||||
'@types/qs': ^6.9.7
|
||||
'@typescript-eslint/eslint-plugin': ^5.8.0
|
||||
'@typescript-eslint/parser': ^5.8.0
|
||||
@ -35,6 +36,7 @@ specifiers:
|
||||
form-data: ^4.0.0
|
||||
husky: ^7.0.4
|
||||
lint-staged: ^12.1.3
|
||||
lodash-es: ^4.17.21
|
||||
naive-ui: ^2.23.1
|
||||
patch-package: ^6.4.7
|
||||
pinia: ^2.0.8
|
||||
@ -88,6 +90,7 @@ devDependencies:
|
||||
'@iconify/vue': registry.npmmirror.com/@iconify/vue/3.1.1_vue@3.2.26
|
||||
'@types/bmapgl': registry.npmmirror.com/@types/bmapgl/0.0.5
|
||||
'@types/chroma-js': registry.npmmirror.com/@types/chroma-js/2.1.3
|
||||
'@types/lodash-es': registry.npmmirror.com/@types/lodash-es/4.17.5
|
||||
'@types/qs': registry.npmmirror.com/@types/qs/6.9.7
|
||||
'@typescript-eslint/eslint-plugin': registry.npmmirror.com/@typescript-eslint/eslint-plugin/5.8.0_836011a006f4f5d67178564baf2b6d34
|
||||
'@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser/5.8.0_eslint@8.5.0+typescript@4.5.4
|
||||
@ -107,6 +110,7 @@ devDependencies:
|
||||
eslint-plugin-vue: registry.npmmirror.com/eslint-plugin-vue/8.2.0_eslint@8.5.0
|
||||
husky: registry.npmmirror.com/husky/7.0.4
|
||||
lint-staged: registry.npmmirror.com/lint-staged/12.1.3
|
||||
lodash-es: registry.nlark.com/lodash-es/4.17.21
|
||||
patch-package: registry.npmmirror.com/patch-package/6.4.7
|
||||
postinstall-postinstall: registry.npmmirror.com/postinstall-postinstall/2.1.0
|
||||
prettier: registry.npmmirror.com/prettier/2.5.1
|
||||
@ -2073,7 +2077,6 @@ packages:
|
||||
resolution: {integrity: sha1-Q+YmxG5lkbd1C+srUBFzkMYJ4+4=, registry: https://registry.npm.taobao.org/, tarball: https://registry.nlark.com/lodash-es/download/lodash-es-4.17.21.tgz}
|
||||
name: lodash-es
|
||||
version: 4.17.21
|
||||
dev: false
|
||||
|
||||
registry.nlark.com/lodash.get/4.4.2:
|
||||
resolution: {integrity: sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/lodash.get/download/lodash.get-4.4.2.tgz}
|
||||
@ -3877,7 +3880,7 @@ packages:
|
||||
dev: true
|
||||
|
||||
registry.npmmirror.com/@commitlint/load/15.0.0:
|
||||
resolution: {integrity: sha512-Ak1YPeOhvxmY3ioe0o6m1yLGvUAYb4BdfGgShU8jiTCmU3Mnmms0Xh/kfQz8AybhezCC3AmVTyBLaBZxOHR8kg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@commitlint/load/download/@commitlint/load-15.0.0.tgz?cache=0&sync_timestamp=1637131952207&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40commitlint%2Fload%2Fdownload%2F%40commitlint%2Fload-15.0.0.tgz}
|
||||
resolution: {integrity: sha512-Ak1YPeOhvxmY3ioe0o6m1yLGvUAYb4BdfGgShU8jiTCmU3Mnmms0Xh/kfQz8AybhezCC3AmVTyBLaBZxOHR8kg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@commitlint/load/download/@commitlint/load-15.0.0.tgz}
|
||||
name: '@commitlint/load'
|
||||
version: 15.0.0
|
||||
engines: {node: '>=v12'}
|
||||
@ -4122,13 +4125,11 @@ packages:
|
||||
version: 4.17.5
|
||||
dependencies:
|
||||
'@types/lodash': registry.npmmirror.com/@types/lodash/4.14.178
|
||||
dev: false
|
||||
|
||||
registry.npmmirror.com/@types/lodash/4.14.178:
|
||||
resolution: {integrity: sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/lodash/download/@types/lodash-4.14.178.tgz}
|
||||
name: '@types/lodash'
|
||||
version: 4.14.178
|
||||
dev: false
|
||||
|
||||
registry.npmmirror.com/@types/minimist/1.2.2:
|
||||
resolution: {integrity: sha1-7nceK6Sz3Fs3KTXVSf2WF780W4w=, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/minimist/download/@types/minimist-1.2.2.tgz}
|
||||
|
@ -1,7 +1,11 @@
|
||||
<template>
|
||||
<div v-if="reloadFlag" class="relative">
|
||||
<slot></slot>
|
||||
<div v-show="showPlaceholder" class="absolute-lt w-full h-full" :class="placeholderClass">
|
||||
<div
|
||||
v-show="showPlaceholder"
|
||||
class="absolute-lt w-full h-full border-[var(--border-color)] border-1px dark:bg-dark"
|
||||
:class="placeholderClass"
|
||||
>
|
||||
<div v-show="loading" class="absolute-center">
|
||||
<n-spin :show="true" :size="loadingSize" />
|
||||
</div>
|
||||
|
58
src/components/common/Modal/index.vue
Normal file
58
src/components/common/Modal/index.vue
Normal file
@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<NModal
|
||||
v-model:show="show"
|
||||
v-bind="getModalProps"
|
||||
:loading="loading"
|
||||
@positive-click="positiveClick"
|
||||
@negative-click="negativeClick"
|
||||
>
|
||||
{{ isFunction(props.content) ? props.content() : props.content }}
|
||||
</NModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { NModal } from 'naive-ui';
|
||||
import type { ModalProps } from 'naive-ui';
|
||||
import { omit, isFunction } from 'lodash-es';
|
||||
|
||||
export interface HookModalProps extends Partial<ModalProps> {
|
||||
closeModal?: () => void;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<HookModalProps>(), {
|
||||
closeModal: () => {}
|
||||
});
|
||||
|
||||
/** 重组NModal的props */
|
||||
const getModalProps = computed(() => omit(props, ['onPositiveClick', 'onNegativeClick']));
|
||||
|
||||
const loading = ref(false);
|
||||
const show = computed({
|
||||
get() {
|
||||
return props.show ?? false;
|
||||
},
|
||||
set(val: boolean) {
|
||||
if (Object.is(val, false)) {
|
||||
props.closeModal?.();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function positiveClick() {
|
||||
loading.value = true;
|
||||
try {
|
||||
await props?.onPositiveClick?.();
|
||||
show.value = false;
|
||||
} catch (error) {
|
||||
loading.value = false;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function negativeClick() {
|
||||
await props?.onNegativeClick?.();
|
||||
show.value = false;
|
||||
}
|
||||
</script>
|
@ -5,5 +5,6 @@ import BannerSvg from './BannerSvg/index.vue';
|
||||
import HoverContainer from './HoverContainer/index.vue';
|
||||
import LoadingEmptyWrapper from './LoadingEmptyWrapper/index.vue';
|
||||
import IconSelect from './IconSelect/index.vue';
|
||||
import Modal from './Modal/index.vue';
|
||||
|
||||
export { NaiveProvider, SystemLogo, LoginBg, BannerSvg, HoverContainer, LoadingEmptyWrapper, IconSelect };
|
||||
export { NaiveProvider, SystemLogo, LoginBg, BannerSvg, HoverContainer, LoadingEmptyWrapper, IconSelect, Modal };
|
||||
|
@ -2,5 +2,6 @@ import useContext from './useContext';
|
||||
import useBoolean from './useBoolean';
|
||||
import useLoading from './useLoading';
|
||||
import useLoadingEmpty from './useLoadingEmpty';
|
||||
import useModal from './useModal';
|
||||
|
||||
export { useContext, useBoolean, useLoading, useLoadingEmpty };
|
||||
export { useContext, useBoolean, useLoading, useLoadingEmpty, useModal };
|
||||
|
45
src/hooks/common/useModal.ts
Normal file
45
src/hooks/common/useModal.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { createVNode, render, getCurrentInstance, nextTick } from 'vue';
|
||||
import type { AppContext, ComponentInternalInstance } from 'vue';
|
||||
import { Modal } from '@/components';
|
||||
import type { HookModalProps } from '@/components/common/Modal/index.vue';
|
||||
|
||||
export default function useModal() {
|
||||
let modalInstance: ComponentInternalInstance;
|
||||
const appContext = getCurrentInstance()?.appContext as AppContext;
|
||||
|
||||
function getModalInstance() {
|
||||
if (modalInstance) {
|
||||
return modalInstance;
|
||||
}
|
||||
const container = document.createElement('template');
|
||||
const VNode = createVNode(Modal);
|
||||
VNode.appContext = appContext;
|
||||
render(VNode, container);
|
||||
modalInstance = VNode.component!;
|
||||
modalInstance.props.closeModal = hideModal;
|
||||
|
||||
return modalInstance;
|
||||
}
|
||||
|
||||
async function showModal(props: HookModalProps) {
|
||||
const modalInstance = getModalInstance();
|
||||
|
||||
Object.assign<any, HookModalProps>(modalInstance?.props, {
|
||||
...props,
|
||||
show: true
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
}
|
||||
|
||||
function hideModal() {
|
||||
Object.assign<any, HookModalProps>(modalInstance?.props, { show: false });
|
||||
}
|
||||
|
||||
return {
|
||||
showModal,
|
||||
hideModal
|
||||
};
|
||||
}
|
||||
|
||||
export type ModalInstance = ReturnType<typeof useModal>;
|
@ -32,6 +32,7 @@ export type RouteKey =
|
||||
| 'component'
|
||||
| 'component_button'
|
||||
| 'component_card'
|
||||
| 'component_modal'
|
||||
| 'component_table'
|
||||
| 'multi-menu'
|
||||
| 'multi-menu_first'
|
||||
|
@ -219,6 +219,14 @@ const routeConstMap = new Map<RouteKey, RouteConst>([
|
||||
title: '卡片'
|
||||
}
|
||||
],
|
||||
[
|
||||
'component_modal',
|
||||
{
|
||||
name: 'component_modal',
|
||||
path: '/component/modal',
|
||||
title: '弹窗'
|
||||
}
|
||||
],
|
||||
[
|
||||
'component_table',
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import { BasicLayout } from '@/layouts';
|
||||
import { ComponentButton, ComponentCard, ComponentTable } from '@/views';
|
||||
import { ComponentButton, ComponentCard, ComponentModal, ComponentTable } from '@/views';
|
||||
import { routeName, routePath, routeTitle } from '../constant';
|
||||
|
||||
const component: RouteRecordRaw = {
|
||||
@ -34,6 +34,16 @@ const component: RouteRecordRaw = {
|
||||
keepAlive: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: routeName('component_modal'),
|
||||
path: routePath('component_modal'),
|
||||
component: ComponentModal,
|
||||
meta: {
|
||||
title: routeTitle('component_modal'),
|
||||
requiresAuth: true,
|
||||
keepAlive: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: routeName('component_table'),
|
||||
path: routePath('component_table'),
|
||||
|
@ -1,5 +1,6 @@
|
||||
import ComponentButton from './button/index.vue';
|
||||
import ComponentCard from './card/index.vue';
|
||||
import ComponentModal from './modal/index.vue';
|
||||
import ComponentTable from './table/index.vue';
|
||||
|
||||
export { ComponentButton, ComponentCard, ComponentTable };
|
||||
export { ComponentButton, ComponentCard, ComponentModal, ComponentTable };
|
||||
|
53
src/views/component/modal/index.vue
Normal file
53
src/views/component/modal/index.vue
Normal file
@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<n-card title="弹窗" class="h-full shadow-sm rounded-16px">
|
||||
<n-grid cols="s:1 m:2" responsive="screen" :x-gap="16" :y-gap="16">
|
||||
<n-grid-item>
|
||||
<n-card title="普通弹窗" class="min-h-180px">
|
||||
<n-button @click="visible = true">来吧</n-button>
|
||||
<n-modal v-model:show="visible">
|
||||
<n-card style="width: 600px" title="模态框" :bordered="false" size="huge">
|
||||
<template #header-extra>噢!</template>
|
||||
内容
|
||||
<template #footer>尾部</template>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
<n-card title="Hook弹窗" class="min-h-180px">
|
||||
<n-button @click="handleShow">来吧</n-button>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</n-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { NCard, NGrid, NGridItem, NModal, NButton } from 'naive-ui';
|
||||
import { useModal } from '@/hooks';
|
||||
|
||||
const visible = ref(false);
|
||||
const { showModal } = useModal();
|
||||
|
||||
function handleShow() {
|
||||
showModal({
|
||||
title: '确认',
|
||||
content: () => '111',
|
||||
maskClosable: true,
|
||||
preset: 'dialog',
|
||||
positiveText: '确认',
|
||||
bordered: false,
|
||||
onPositiveClick: () => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve(111);
|
||||
}, 3000);
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {},
|
||||
negativeText: '算了'
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
Loading…
Reference in New Issue
Block a user