mirror of
https://github.com/fjykTec/ModernWMS.git
synced 2024-09-20 06:56:08 +08:00
feat(全局): 增加hook组件, 用于对话框、消息提示; 修改系统标题
This commit is contained in:
parent
1e51acbcc7
commit
e596df5305
|
@ -1,4 +1,4 @@
|
|||
# 开发环境
|
||||
Vue: 3.2.45
|
||||
# 系统环境
|
||||
Vue + TS: 3.2.45
|
||||
Vite: 4.0.0
|
||||
Node: 16.13.1
|
|
@ -5,7 +5,7 @@
|
|||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Vue + TS</title>
|
||||
<title>ModernWMS</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
8
frontend/src/assets/css/hookComponent.css
Normal file
8
frontend/src/assets/css/hookComponent.css
Normal file
|
@ -0,0 +1,8 @@
|
|||
.messageItems {
|
||||
position: fixed;
|
||||
/* top: 10px; */
|
||||
left: 50%;
|
||||
max-width: 90%;
|
||||
transform: translate(-50%, 0);
|
||||
transition: all 0.2s;
|
||||
}
|
21
frontend/src/components/common/function/index.ts
Normal file
21
frontend/src/components/common/function/index.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import '@/assets/css/hookComponent.css' // import hookComponent style
|
||||
|
||||
// Use import.meta.globEager to read the files in the components folder, distinguished by the suffix ts
|
||||
const componentsList: any = import.meta.globEager('../hookComponent/**')
|
||||
|
||||
const List: any = {}
|
||||
export default function (app: any) {
|
||||
Object.keys(componentsList).forEach((key) => {
|
||||
// Filter out ts suffix
|
||||
if (key.includes('.ts')) {
|
||||
// Assignment function component, thrown later, imported for use
|
||||
List[`$${ componentsList[key].default.name }`] = componentsList[key].default
|
||||
|
||||
// Define function components into global variables, and use them in script in vue through proxy
|
||||
app.config.globalProperties[`$${ componentsList[key].default.name }`] = componentsList[key].default
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Export function components for import
|
||||
export const funComponentList = List
|
20
frontend/src/components/common/hookComponent/dialog.ts
Normal file
20
frontend/src/components/common/hookComponent/dialog.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { createApp } from 'vue'
|
||||
import DialogComponent from './dialog.vue'
|
||||
import { DialogOptions } from '@/types/system/hookComponent'
|
||||
// Use vuetify
|
||||
import { vuetify } from '@/plugins/vuetify/index'
|
||||
|
||||
// Use the createApp of vue3 and the mount and unmount methods to create a mounted instance
|
||||
export default function dialog(options: DialogOptions) {
|
||||
const mountNode = document.createElement('div')
|
||||
document.body.appendChild(mountNode)
|
||||
const app = createApp(DialogComponent, {
|
||||
...options,
|
||||
visible: true,
|
||||
removeComponent: () => {
|
||||
app.unmount()
|
||||
document.body.removeChild(mountNode)
|
||||
}
|
||||
}).use(vuetify)
|
||||
return app.mount(mountNode)
|
||||
}
|
86
frontend/src/components/common/hookComponent/dialog.vue
Normal file
86
frontend/src/components/common/hookComponent/dialog.vue
Normal file
|
@ -0,0 +1,86 @@
|
|||
<template>
|
||||
<v-dialog v-model="data.dialogVisible" persistent :width="dialogWidth">
|
||||
<v-card>
|
||||
<v-card-title class="text-h5"> {{ title }} </v-card-title>
|
||||
<v-card-text>{{ content }}</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="green-darken-1" variant="text" @click="data.dialogVisible = false">
|
||||
{{ cancleText }}
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="typeof dialogProps.handleConfirm === 'function'"
|
||||
color="green-darken-1"
|
||||
variant="text"
|
||||
@click="method._sure()"
|
||||
>
|
||||
{{ confirmText }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch, reactive } from 'vue'
|
||||
import i18n from '@/languages/i18n'
|
||||
|
||||
const dialogProps = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
confirmText: {
|
||||
type: String,
|
||||
default: i18n.global.t('system.hookComponent.dialog.defaultConfirm')
|
||||
},
|
||||
cancleText: {
|
||||
type: String,
|
||||
default: i18n.global.t('system.hookComponent.dialog.defaultClose')
|
||||
},
|
||||
handleConfirm: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
// Remove dom function
|
||||
removeComponent: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: i18n.global.t('system.hookComponent.dialog.defaultTitle')
|
||||
},
|
||||
dialogWidth: {
|
||||
type: [String, Number],
|
||||
default: 700
|
||||
}
|
||||
})
|
||||
|
||||
const data = reactive({
|
||||
dialogVisible: false,
|
||||
dialogText: ''
|
||||
})
|
||||
|
||||
// Init dialog visible
|
||||
data.dialogVisible = Boolean(dialogProps.visible) // Avoid shallow copies
|
||||
|
||||
const method = reactive({
|
||||
_sure: async () => {
|
||||
await dialogProps.handleConfirm()
|
||||
data.dialogVisible = false
|
||||
}
|
||||
})
|
||||
|
||||
// Shut dialog run remove function
|
||||
watch(
|
||||
() => data.dialogVisible,
|
||||
(val) => {
|
||||
!val && dialogProps.removeComponent()
|
||||
}
|
||||
)
|
||||
</script>
|
55
frontend/src/components/common/hookComponent/message.ts
Normal file
55
frontend/src/components/common/hookComponent/message.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { createApp } from 'vue'
|
||||
import MessageComponent from './message.vue'
|
||||
import { MessageOptions } from '@/types/system/hookComponent'
|
||||
// Use vuetify
|
||||
import { vuetify } from '@/plugins/vuetify/index'
|
||||
|
||||
// Use the createApp of vue3 and the mount and unmount methods to create a mounted instance
|
||||
export default function message(options: MessageOptions) {
|
||||
const mountNode = document.createElement('div')
|
||||
mountNode.className = 'messageItems'
|
||||
mountNode.style.top = `${ getNewMsgTop() }px`
|
||||
document.body.appendChild(mountNode)
|
||||
const app = createApp(MessageComponent, {
|
||||
...options,
|
||||
removeComponent: () => {
|
||||
setTimeout(() => {
|
||||
mountNode.style.opacity = '0'
|
||||
setTimeout(() => {
|
||||
app.unmount()
|
||||
document.body.removeChild(mountNode)
|
||||
resetMsgTop()
|
||||
}, 200)
|
||||
}, options.shutDelay ? options.shutDelay - 200 : 1300)
|
||||
}
|
||||
}).use(vuetify)
|
||||
return app.mount(mountNode)
|
||||
}
|
||||
|
||||
// Reset message top
|
||||
function resetMsgTop() {
|
||||
const messageDomList: any = document.body.getElementsByClassName('messageItems')
|
||||
for (let i = 0; i < messageDomList.length; i++) {
|
||||
messageDomList[i].style.top = `${ getNewMsgTop(i) }px`
|
||||
}
|
||||
}
|
||||
|
||||
// Get message top
|
||||
function getNewMsgTop(index = -1) {
|
||||
const messageDomList = document.body.querySelectorAll('.messageItems')
|
||||
let top = 10
|
||||
if (index < 0) {
|
||||
for (let i = 0; i < messageDomList.length; i++) {
|
||||
top += messageDomList[i].clientHeight + 10
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < messageDomList.length; i++) {
|
||||
if (i < index) {
|
||||
top += messageDomList[i].clientHeight + 10
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return top
|
||||
}
|
33
frontend/src/components/common/hookComponent/message.vue
Normal file
33
frontend/src/components/common/hookComponent/message.vue
Normal file
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<v-alert
|
||||
:type="type || 'info'"
|
||||
:variant="variant || 'flat'"
|
||||
:border="border || false"
|
||||
:color="color || undefined"
|
||||
:width="messageWidth"
|
||||
:min-width="250"
|
||||
>
|
||||
<!-- :max-height="60" -->
|
||||
{{ content }}
|
||||
</v-alert>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onBeforeMount } from 'vue'
|
||||
|
||||
// Vue3 does not support external interfaces
|
||||
const messageProps = defineProps<{
|
||||
type?: 'success' | 'info' | 'warning' | 'error'
|
||||
variant?: 'flat' | 'elevated' | 'tonal' | 'outlined' | 'text' | 'plain'
|
||||
content: string
|
||||
border?: boolean | 'top' | 'end' | 'bottom' | 'start'
|
||||
color?: string
|
||||
messageWidth?: string | number // message width pixel or percentage
|
||||
removeComponent(): void
|
||||
}>()
|
||||
|
||||
onBeforeMount(() => {
|
||||
messageProps.removeComponent()
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped></style>
|
|
@ -25,7 +25,6 @@
|
|||
></v-text-field>
|
||||
<v-checkbox v-model="data.remember" :label="$t('login.rememberTips')"></v-checkbox>
|
||||
<v-btn color="purple" @click="method.login()">{{ $t('login.mainButtonLabel') }}</v-btn>
|
||||
<!-- <v-btn color="purple" @click="method.testApi()">{{ '测试接口' }}</v-btn> -->
|
||||
</v-form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -38,6 +37,7 @@ import i18n from '@/languages/i18n'
|
|||
import { login } from '@/api/sys/login'
|
||||
// import { getNotify } from '@/api/sys/test'
|
||||
import { store } from '@/store'
|
||||
// import { funComponentList } from '@/components/common/function/index'
|
||||
|
||||
// Get v-form ref
|
||||
const VFormRef = ref()
|
||||
|
@ -77,16 +77,6 @@ const method = reactive({
|
|||
store.commit('user/setEffectiveMinutes', loginRes.data.expire)
|
||||
}
|
||||
}
|
||||
// testApi: async () => {
|
||||
// const { data: res } = await getNotify({
|
||||
// ifall: true,
|
||||
// iftodo: true
|
||||
// })
|
||||
|
||||
// if (res.isSuccess) {
|
||||
// console.log('成功!', res)
|
||||
// }
|
||||
// }
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
export default {
|
||||
system: {
|
||||
hookComponent: {
|
||||
dialog: {
|
||||
defaultClose: '关闭',
|
||||
defaultConfirm: '确认',
|
||||
defaultTitle: '提示'
|
||||
}
|
||||
}
|
||||
},
|
||||
login: {
|
||||
welcomeTitle: '欢迎来到ModernWMS!👋🏻',
|
||||
userNameMustInput: '请填写用户名!',
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
export default {
|
||||
system: {
|
||||
hookComponent: {
|
||||
dialog: {
|
||||
defaultClose: 'Close',
|
||||
defaultConfirm: 'Agree',
|
||||
defaultTitle: 'Tips'
|
||||
}
|
||||
}
|
||||
},
|
||||
login: {
|
||||
welcomeTitle: 'Welcome to ModernWMS!👋🏻',
|
||||
userNameMustInput: 'Please fill in the userName!',
|
||||
|
|
|
@ -8,6 +8,7 @@ import App from './App.vue'
|
|||
// import router
|
||||
import { router } from './router'
|
||||
import { store } from './store/index'
|
||||
import hookComponent from '@/components/common/function/index'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
|
@ -15,5 +16,6 @@ app.use(router)
|
|||
app.use(store)
|
||||
app.use(vuetify)
|
||||
app.use(i18n)
|
||||
app.use(hookComponent)
|
||||
|
||||
app.mount('#app')
|
||||
|
|
20
frontend/src/types/system/hookComponent.ts
Normal file
20
frontend/src/types/system/hookComponent.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
// Dialog modal options
|
||||
export interface DialogOptions {
|
||||
confirmText?: string // confirm btn text
|
||||
cancleText?: string // cancle btn text
|
||||
handleConfirm?(): void // confirm trigger method
|
||||
content: string // dialog content text
|
||||
title?: string // dialog title text
|
||||
dialogWidth?: string | number // dialog width pixel or percentage
|
||||
}
|
||||
|
||||
// System message options
|
||||
export interface MessageOptions {
|
||||
type?: 'success' | 'info' | 'warning' | 'error'
|
||||
variant?: 'flat' | 'elevated' | 'tonal' | 'outlined' | 'text' | 'plain'
|
||||
content: string
|
||||
border?: boolean | 'top' | 'end' | 'bottom' | 'start'
|
||||
shutDelay?: number
|
||||
color?: string
|
||||
messageWidth?: string | number // message width pixel or percentage
|
||||
}
|
Loading…
Reference in a new issue