Merge branch 'master' of https://gitee.com/yudaocode/yudao-ui-admin-vue3
This commit is contained in:
commit
18e2c33cef
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -102,6 +102,7 @@
|
|||||||
"codemirror",
|
"codemirror",
|
||||||
"commitlint",
|
"commitlint",
|
||||||
"cropperjs",
|
"cropperjs",
|
||||||
|
"echart",
|
||||||
"echarts",
|
"echarts",
|
||||||
"esnext",
|
"esnext",
|
||||||
"esno",
|
"esno",
|
||||||
@ -116,10 +117,12 @@
|
|||||||
"sider",
|
"sider",
|
||||||
"sortablejs",
|
"sortablejs",
|
||||||
"stylelint",
|
"stylelint",
|
||||||
|
"svgs",
|
||||||
"unocss",
|
"unocss",
|
||||||
"unplugin",
|
"unplugin",
|
||||||
"unref",
|
"unref",
|
||||||
"videojs",
|
"videojs",
|
||||||
|
"VITE",
|
||||||
"vitejs",
|
"vitejs",
|
||||||
"vueuse",
|
"vueuse",
|
||||||
"wangeditor",
|
"wangeditor",
|
||||||
|
33
package.json
33
package.json
@ -36,20 +36,20 @@
|
|||||||
"@wangeditor/editor-for-vue": "^5.1.10",
|
"@wangeditor/editor-for-vue": "^5.1.10",
|
||||||
"@zxcvbn-ts/core": "^3.0.4",
|
"@zxcvbn-ts/core": "^3.0.4",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"axios": "^1.5.1",
|
"axios": "^1.6.0",
|
||||||
"benz-amr-recorder": "^1.1.5",
|
"benz-amr-recorder": "^1.1.5",
|
||||||
"bpmn-js-token-simulation": "^0.10.0",
|
"bpmn-js-token-simulation": "^0.10.0",
|
||||||
"camunda-bpmn-moddle": "^7.0.1",
|
"camunda-bpmn-moddle": "^7.0.1",
|
||||||
"cropperjs": "^1.6.1",
|
"cropperjs": "^1.6.1",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"diagram-js": "^12.5.0",
|
"diagram-js": "^12.6.0",
|
||||||
|
"driver.js": "^1.3.0",
|
||||||
"echarts": "^5.4.3",
|
"echarts": "^5.4.3",
|
||||||
"echarts-wordcloud": "^2.1.0",
|
"echarts-wordcloud": "^2.1.0",
|
||||||
"element-plus": "2.4.1",
|
"element-plus": "2.4.1",
|
||||||
"fast-xml-parser": "^4.3.2",
|
"fast-xml-parser": "^4.3.2",
|
||||||
"highlight.js": "^11.9.0",
|
"highlight.js": "^11.9.0",
|
||||||
"intro.js": "^7.2.0",
|
|
||||||
"jsencrypt": "^3.3.2",
|
"jsencrypt": "^3.3.2",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"min-dash": "^4.1.1",
|
"min-dash": "^4.1.1",
|
||||||
@ -64,7 +64,7 @@
|
|||||||
"video.js": "^7.21.5",
|
"video.js": "^7.21.5",
|
||||||
"vue": "^3.3.7",
|
"vue": "^3.3.7",
|
||||||
"vue-dompurify-html": "^4.1.4",
|
"vue-dompurify-html": "^4.1.4",
|
||||||
"vue-i18n": "^9.5.0",
|
"vue-i18n": "^9.6.2",
|
||||||
"vue-router": "^4.2.5",
|
"vue-router": "^4.2.5",
|
||||||
"vue-types": "^5.1.1",
|
"vue-types": "^5.1.1",
|
||||||
"vuedraggable": "^4.1.0",
|
"vuedraggable": "^4.1.0",
|
||||||
@ -72,20 +72,19 @@
|
|||||||
"xml-js": "^1.6.11"
|
"xml-js": "^1.6.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^18.0.0",
|
"@commitlint/cli": "^18.2.0",
|
||||||
"@commitlint/config-conventional": "^18.0.0",
|
"@commitlint/config-conventional": "^18.1.0",
|
||||||
"@iconify/json": "^2.2.132",
|
"@iconify/json": "^2.2.135",
|
||||||
"@intlify/unplugin-vue-i18n": "^1.4.0",
|
"@intlify/unplugin-vue-i18n": "^1.4.0",
|
||||||
"@purge-icons/generated": "^0.9.0",
|
"@purge-icons/generated": "^0.9.0",
|
||||||
"@types/intro.js": "^5.1.3",
|
|
||||||
"@types/lodash-es": "^4.17.10",
|
"@types/lodash-es": "^4.17.10",
|
||||||
"@types/node": "^20.8.8",
|
"@types/node": "^20.8.9",
|
||||||
"@types/nprogress": "^0.2.2",
|
"@types/nprogress": "^0.2.2",
|
||||||
"@types/qrcode": "^1.5.4",
|
"@types/qrcode": "^1.5.4",
|
||||||
"@types/qs": "^6.9.9",
|
"@types/qs": "^6.9.9",
|
||||||
"@types/sortablejs": "^1.15.4",
|
"@types/sortablejs": "^1.15.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.9.0",
|
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
||||||
"@typescript-eslint/parser": "^6.9.0",
|
"@typescript-eslint/parser": "^6.9.1",
|
||||||
"@unocss/transformer-variant-group": "^0.57.1",
|
"@unocss/transformer-variant-group": "^0.57.1",
|
||||||
"@unocss/eslint-config": "^0.57.1",
|
"@unocss/eslint-config": "^0.57.1",
|
||||||
"@vitejs/plugin-legacy": "^4.1.1",
|
"@vitejs/plugin-legacy": "^4.1.1",
|
||||||
@ -99,24 +98,24 @@
|
|||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
"eslint-define-config": "^1.24.1",
|
"eslint-define-config": "^1.24.1",
|
||||||
"eslint-plugin-prettier": "^5.0.1",
|
"eslint-plugin-prettier": "^5.0.1",
|
||||||
"eslint-plugin-vue": "^9.18.0",
|
"eslint-plugin-vue": "^9.18.1",
|
||||||
"lint-staged": "^15.0.2",
|
"lint-staged": "^15.0.2",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.31",
|
||||||
"postcss-html": "^1.5.0",
|
"postcss-html": "^1.5.0",
|
||||||
"postcss-scss": "^4.0.9",
|
"postcss-scss": "^4.0.9",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"rollup": "^4.1.4",
|
"rollup": "^4.1.5",
|
||||||
"sass": "^1.69.4",
|
"sass": "^1.69.5",
|
||||||
"stylelint": "^15.11.0",
|
"stylelint": "^15.11.0",
|
||||||
"stylelint-config-html": "^1.1.0",
|
"stylelint-config-html": "^1.1.0",
|
||||||
"stylelint-config-recommended": "^13.0.0",
|
"stylelint-config-recommended": "^13.0.0",
|
||||||
"stylelint-config-standard": "^34.0.0",
|
"stylelint-config-standard": "^34.0.0",
|
||||||
"stylelint-order": "^6.0.3",
|
"stylelint-order": "^6.0.3",
|
||||||
"terser": "^5.22.0",
|
"terser": "^5.23.0",
|
||||||
"typescript": "5.2.2",
|
"typescript": "5.2.2",
|
||||||
"unocss": "^0.57.1",
|
"unocss": "^0.57.1",
|
||||||
"unplugin-auto-import": "^0.16.6",
|
"unplugin-auto-import": "^0.16.7",
|
||||||
"unplugin-element-plus": "^0.8.0",
|
"unplugin-element-plus": "^0.8.0",
|
||||||
"unplugin-vue-components": "^0.25.2",
|
"unplugin-vue-components": "^0.25.2",
|
||||||
"vite": "4.5.0",
|
"vite": "4.5.0",
|
||||||
@ -128,7 +127,7 @@
|
|||||||
"vite-plugin-svg-icons": "^2.0.1",
|
"vite-plugin-svg-icons": "^2.0.1",
|
||||||
"vite-plugin-top-level-await": "^1.3.1",
|
"vite-plugin-top-level-await": "^1.3.1",
|
||||||
"vue-eslint-parser": "^9.3.2",
|
"vue-eslint-parser": "^9.3.2",
|
||||||
"vue-tsc": "^1.8.20"
|
"vue-tsc": "^1.8.22"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -3,7 +3,7 @@ defineComponent({
|
|||||||
name: 'CardTitle'
|
name: 'CardTitle'
|
||||||
})
|
})
|
||||||
|
|
||||||
const { title } = defineProps({
|
defineProps({
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
<script lang="ts" setup>
|
<script setup lang="ts">
|
||||||
|
import { provide, computed, watch, onMounted } from 'vue'
|
||||||
import { propTypes } from '@/utils/propTypes'
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
import { ComponentSize, ElConfigProvider } from 'element-plus'
|
||||||
import { useLocaleStore } from '@/store/modules/locale'
|
import { useLocaleStore } from '@/store/modules/locale'
|
||||||
|
import { useWindowSize } from '@vueuse/core'
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
import { setCssVar } from '@/utils'
|
import { setCssVar } from '@/utils'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
import { ElementPlusSize } from '@/types/elementPlus'
|
|
||||||
import { useWindowSize } from '@vueuse/core'
|
|
||||||
|
|
||||||
defineOptions({ name: 'ConfigGlobal' })
|
|
||||||
|
|
||||||
const { variables } = useDesign()
|
const { variables } = useDesign()
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
size: propTypes.oneOf<ElementPlusSize>(['default', 'small', 'large']).def('default')
|
size: propTypes.oneOf<ComponentSize>(['default', 'small', 'large']).def('default')
|
||||||
})
|
})
|
||||||
|
|
||||||
provide('configGlobal', props)
|
provide('configGlobal', props)
|
||||||
@ -53,9 +52,9 @@ const currentLocale = computed(() => localeStore.currentLocale)
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ElConfigProvider
|
<ElConfigProvider
|
||||||
|
:namespace="variables.elNamespace"
|
||||||
:locale="currentLocale.elLocale"
|
:locale="currentLocale.elLocale"
|
||||||
:message="{ max: 1 }"
|
:message="{ max: 1 }"
|
||||||
:namespace="variables.elNamespace"
|
|
||||||
:size="size"
|
:size="size"
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@ -27,7 +27,7 @@ import * as DateUtil from '@/utils/formatTime'
|
|||||||
defineOptions({ name: 'ShortcutDateRangePicker' })
|
defineOptions({ name: 'ShortcutDateRangePicker' })
|
||||||
|
|
||||||
const shortcutDays = ref(7) // 日期快捷天数(单选按钮组), 默认7天
|
const shortcutDays = ref(7) // 日期快捷天数(单选按钮组), 默认7天
|
||||||
const times = ref<[dayjs.ConfigType, dayjs.ConfigType]>(['', '']) // 时间范围参数
|
const times = ref<[string, string]>(['', '']) // 时间范围参数
|
||||||
defineExpose({ times }) // 暴露时间范围参数
|
defineExpose({ times }) // 暴露时间范围参数
|
||||||
/** 日期快捷选择 */
|
/** 日期快捷选择 */
|
||||||
const shortcuts = [
|
const shortcuts = [
|
||||||
|
@ -32,7 +32,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
scrollContainer.value = getScrollContainer(refSticky.value!, true)
|
scrollContainer.value = getScrollContainer(refSticky.value!, true)
|
||||||
useEventListener(scrollContainer, 'scroll', handleScroll)
|
useEventListener(scrollContainer, 'scroll', handleScroll)
|
||||||
useEventListener('resize', handleReize)
|
useEventListener('resize', handleResize)
|
||||||
handleScroll()
|
handleScroll()
|
||||||
})
|
})
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
@ -103,7 +103,7 @@ const handleScroll = () => {
|
|||||||
reset()
|
reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleReize = () => {
|
const handleResize = () => {
|
||||||
if (isSticky.value && refSticky.value) {
|
if (isSticky.value && refSticky.value) {
|
||||||
width.value = refSticky.value.getBoundingClientRect().width + 'px'
|
width.value = refSticky.value.getBoundingClientRect().width + 'px'
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,13 @@ import { propTypes } from '@/utils/propTypes'
|
|||||||
defineOptions({ name: 'Tooltip' })
|
defineOptions({ name: 'Tooltip' })
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
titel: propTypes.string.def(''),
|
title: propTypes.string.def(''),
|
||||||
message: propTypes.string.def(''),
|
message: propTypes.string.def(''),
|
||||||
icon: propTypes.string.def('ep:question-filled')
|
icon: propTypes.string.def('ep:question-filled')
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<span>{{ titel }}</span>
|
<span>{{ title }}</span>
|
||||||
<ElTooltip :content="message" placement="top">
|
<ElTooltip :content="message" placement="top">
|
||||||
<Icon :icon="icon" class="relative top-1px ml-1px" />
|
<Icon :icon="icon" class="relative top-1px ml-1px" />
|
||||||
</ElTooltip>
|
</ElTooltip>
|
||||||
|
49
src/hooks/web/useGuide.ts
Normal file
49
src/hooks/web/useGuide.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { Config, driver } from 'driver.js'
|
||||||
|
import 'driver.js/dist/driver.css'
|
||||||
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const { variables } = useDesign()
|
||||||
|
|
||||||
|
export const useGuide = (options?: Config) => {
|
||||||
|
const driverObj = driver(
|
||||||
|
options || {
|
||||||
|
showProgress: true,
|
||||||
|
nextBtnText: t('common.nextLabel'),
|
||||||
|
prevBtnText: t('common.prevLabel'),
|
||||||
|
doneBtnText: t('common.doneLabel'),
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
element: `#${variables.namespace}-menu`,
|
||||||
|
popover: {
|
||||||
|
title: t('common.menu'),
|
||||||
|
description: t('common.menuDes'),
|
||||||
|
side: 'right'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
element: `#${variables.namespace}-tool-header`,
|
||||||
|
popover: {
|
||||||
|
title: t('common.tool'),
|
||||||
|
description: t('common.toolDes'),
|
||||||
|
side: 'left'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
element: `#${variables.namespace}-tags-view`,
|
||||||
|
popover: {
|
||||||
|
title: t('common.tagsView'),
|
||||||
|
description: t('common.tagsViewDes'),
|
||||||
|
side: 'bottom'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...driverObj
|
||||||
|
}
|
||||||
|
}
|
@ -1,47 +0,0 @@
|
|||||||
import introJs from 'intro.js'
|
|
||||||
import { IntroJs, Step, Options } from 'intro.js'
|
|
||||||
import 'intro.js/introjs.css'
|
|
||||||
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
|
||||||
|
|
||||||
export const useIntro = (setps?: Step[], options?: Options) => {
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const { variables } = useDesign()
|
|
||||||
|
|
||||||
const defaultSetps: Step[] = setps || [
|
|
||||||
{
|
|
||||||
element: `#${variables.namespace}-menu`,
|
|
||||||
title: t('common.menu'),
|
|
||||||
intro: t('common.menuDes'),
|
|
||||||
position: 'right'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
element: `#${variables.namespace}-tool-header`,
|
|
||||||
title: t('common.tool'),
|
|
||||||
intro: t('common.toolDes'),
|
|
||||||
position: 'left'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
element: `#${variables.namespace}-tags-view`,
|
|
||||||
title: t('common.tagsView'),
|
|
||||||
intro: t('common.tagsViewDes'),
|
|
||||||
position: 'bottom'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const defaultOptions: Options = options || {
|
|
||||||
prevLabel: t('common.prevLabel'),
|
|
||||||
nextLabel: t('common.nextLabel'),
|
|
||||||
skipLabel: t('common.skipLabel'),
|
|
||||||
doneLabel: t('common.doneLabel')
|
|
||||||
}
|
|
||||||
|
|
||||||
const introRef: IntroJs = introJs()
|
|
||||||
|
|
||||||
introRef.addSteps(defaultSetps).setOptions(defaultOptions)
|
|
||||||
|
|
||||||
return {
|
|
||||||
introRef
|
|
||||||
}
|
|
||||||
}
|
|
21
src/hooks/web/useNetwork.ts
Normal file
21
src/hooks/web/useNetwork.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { ref, onBeforeUnmount } from 'vue'
|
||||||
|
|
||||||
|
const useNetwork = () => {
|
||||||
|
const online = ref(true)
|
||||||
|
|
||||||
|
const updateNetwork = () => {
|
||||||
|
online.value = navigator.onLine
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('online', updateNetwork)
|
||||||
|
window.addEventListener('offline', updateNetwork)
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener('online', updateNetwork)
|
||||||
|
window.removeEventListener('offline', updateNetwork)
|
||||||
|
})
|
||||||
|
|
||||||
|
return { online }
|
||||||
|
}
|
||||||
|
|
||||||
|
export { useNetwork }
|
60
src/hooks/web/useNow.ts
Normal file
60
src/hooks/web/useNow.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { dateUtil } from '@/utils/dateUtil'
|
||||||
|
import { reactive, toRefs } from 'vue'
|
||||||
|
import { tryOnMounted, tryOnUnmounted } from '@vueuse/core'
|
||||||
|
|
||||||
|
export const useNow = (immediate = true) => {
|
||||||
|
let timer: IntervalHandle
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
year: 0,
|
||||||
|
month: 0,
|
||||||
|
week: '',
|
||||||
|
day: 0,
|
||||||
|
hour: '',
|
||||||
|
minute: '',
|
||||||
|
second: 0,
|
||||||
|
meridiem: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const update = () => {
|
||||||
|
const now = dateUtil()
|
||||||
|
|
||||||
|
const h = now.format('HH')
|
||||||
|
const m = now.format('mm')
|
||||||
|
const s = now.get('s')
|
||||||
|
|
||||||
|
state.year = now.get('y')
|
||||||
|
state.month = now.get('M') + 1
|
||||||
|
state.week = '星期' + ['日', '一', '二', '三', '四', '五', '六'][now.day()]
|
||||||
|
state.day = now.get('date')
|
||||||
|
state.hour = h
|
||||||
|
state.minute = m
|
||||||
|
state.second = s
|
||||||
|
|
||||||
|
state.meridiem = now.format('A')
|
||||||
|
}
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
update()
|
||||||
|
clearInterval(timer)
|
||||||
|
timer = setInterval(() => update(), 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
function stop() {
|
||||||
|
clearInterval(timer)
|
||||||
|
}
|
||||||
|
|
||||||
|
tryOnMounted(() => {
|
||||||
|
immediate && start()
|
||||||
|
})
|
||||||
|
|
||||||
|
tryOnUnmounted(() => {
|
||||||
|
stop()
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(state),
|
||||||
|
start,
|
||||||
|
stop
|
||||||
|
}
|
||||||
|
}
|
63
src/hooks/web/useTagsView.ts
Normal file
63
src/hooks/web/useTagsView.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { useTagsViewStoreWithOut } from '@/store/modules/tagsView'
|
||||||
|
import { RouteLocationNormalizedLoaded, useRouter } from 'vue-router'
|
||||||
|
import { computed, nextTick, unref } from 'vue'
|
||||||
|
|
||||||
|
export const useTagsView = () => {
|
||||||
|
const tagsViewStore = useTagsViewStoreWithOut()
|
||||||
|
|
||||||
|
const { replace, currentRoute } = useRouter()
|
||||||
|
|
||||||
|
const selectedTag = computed(() => tagsViewStore.getSelectedTag)
|
||||||
|
|
||||||
|
const closeAll = (callback?: Fn) => {
|
||||||
|
tagsViewStore.delAllViews()
|
||||||
|
callback?.()
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeLeft = (callback?: Fn) => {
|
||||||
|
tagsViewStore.delLeftViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
||||||
|
callback?.()
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeRight = (callback?: Fn) => {
|
||||||
|
tagsViewStore.delRightViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
||||||
|
callback?.()
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeOther = (callback?: Fn) => {
|
||||||
|
tagsViewStore.delOthersViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
||||||
|
callback?.()
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeCurrent = (view?: RouteLocationNormalizedLoaded, callback?: Fn) => {
|
||||||
|
if (view?.meta?.affix) return
|
||||||
|
tagsViewStore.delView(view || unref(currentRoute))
|
||||||
|
|
||||||
|
callback?.()
|
||||||
|
}
|
||||||
|
|
||||||
|
const refreshPage = async (view?: RouteLocationNormalizedLoaded, callback?: Fn) => {
|
||||||
|
tagsViewStore.delCachedView()
|
||||||
|
const { path, query } = view || unref(currentRoute)
|
||||||
|
await nextTick()
|
||||||
|
replace({
|
||||||
|
path: '/redirect' + path,
|
||||||
|
query: query
|
||||||
|
})
|
||||||
|
callback?.()
|
||||||
|
}
|
||||||
|
|
||||||
|
const setTitle = (title: string, path?: string) => {
|
||||||
|
tagsViewStore.setTitle(title, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
closeAll,
|
||||||
|
closeLeft,
|
||||||
|
closeRight,
|
||||||
|
closeOther,
|
||||||
|
closeCurrent,
|
||||||
|
refreshPage,
|
||||||
|
setTitle
|
||||||
|
}
|
||||||
|
}
|
@ -1,54 +1,53 @@
|
|||||||
const { t } = useI18n()
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
import { FormItemRule } from 'element-plus'
|
||||||
|
|
||||||
type Callback = (error?: string | Error | undefined) => void
|
const { t } = useI18n()
|
||||||
|
|
||||||
interface LengthRange {
|
interface LengthRange {
|
||||||
min: number
|
min: number
|
||||||
max: number
|
max: number
|
||||||
message: string
|
message?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useValidator = () => {
|
export const useValidator = () => {
|
||||||
const required = (message?: string) => {
|
const required = (message?: string): FormItemRule => {
|
||||||
return {
|
return {
|
||||||
required: true,
|
required: true,
|
||||||
message: message || t('common.required')
|
message: message || t('common.required')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const lengthRange = (val: any, callback: Callback, options: LengthRange) => {
|
const lengthRange = (options: LengthRange): FormItemRule => {
|
||||||
const { min, max, message } = options
|
const { min, max, message } = options
|
||||||
if (val.length < min || val.length > max) {
|
|
||||||
callback(new Error(message))
|
return {
|
||||||
} else {
|
min,
|
||||||
callback()
|
max,
|
||||||
|
message: message || t('common.lengthRange', { min, max })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const notSpace = (val: any, callback: Callback, message: string) => {
|
const notSpace = (message?: string): FormItemRule => {
|
||||||
// 用户名不能有空格
|
return {
|
||||||
if (val.indexOf(' ') !== -1) {
|
validator: (_, val, callback) => {
|
||||||
callback(new Error(message))
|
if (val?.indexOf(' ') !== -1) {
|
||||||
} else {
|
callback(new Error(message || t('common.notSpace')))
|
||||||
callback()
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const notSpecialCharacters = (val: any, callback: Callback, message: string) => {
|
const notSpecialCharacters = (message?: string): FormItemRule => {
|
||||||
// 密码不能是特殊字符
|
return {
|
||||||
if (/[`~!@#$%^&*()_+<>?:"{},.\/;'[\]]/gi.test(val)) {
|
validator: (_, val, callback) => {
|
||||||
callback(new Error(message))
|
if (/[`~!@#$%^&*()_+<>?:"{},.\/;'[\]]/gi.test(val)) {
|
||||||
} else {
|
callback(new Error(message || t('common.notSpecialCharacters')))
|
||||||
callback()
|
} else {
|
||||||
}
|
callback()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// 两个字符串是否想等
|
|
||||||
const isEqual = (val1: string, val2: string, callback: Callback, message: string) => {
|
|
||||||
if (val1 === val2) {
|
|
||||||
callback()
|
|
||||||
} else {
|
|
||||||
callback(new Error(message))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +55,6 @@ export const useValidator = () => {
|
|||||||
required,
|
required,
|
||||||
lengthRange,
|
lengthRange,
|
||||||
notSpace,
|
notSpace,
|
||||||
notSpecialCharacters,
|
notSpecialCharacters
|
||||||
isEqual
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -334,6 +334,6 @@ export function getLast1Year(): [dayjs.ConfigType, dayjs.ConfigType] {
|
|||||||
export function getDateRange(
|
export function getDateRange(
|
||||||
beginDate: dayjs.ConfigType,
|
beginDate: dayjs.ConfigType,
|
||||||
endDate: dayjs.ConfigType
|
endDate: dayjs.ConfigType
|
||||||
): [dayjs.ConfigType, dayjs.ConfigType] {
|
): [string, string] {
|
||||||
return [dayjs(beginDate).startOf('d'), dayjs(endDate).endOf('d')]
|
return [dayjs(beginDate).startOf('d').toString(), dayjs(endDate).endOf('d').toString()]
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,13 @@ export const underlineToHump = (str: string): string => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驼峰转横杠
|
||||||
|
*/
|
||||||
|
export const humpToDash = (str: string): string => {
|
||||||
|
return str.replace(/([A-Z])/g, '-$1').toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
export const setCssVar = (prop: string, val: any, dom = document.documentElement) => {
|
export const setCssVar = (prop: string, val: any, dom = document.documentElement) => {
|
||||||
dom.style.setProperty(prop, val)
|
dom.style.setProperty(prop, val)
|
||||||
}
|
}
|
||||||
@ -67,7 +74,7 @@ export const trim = (str: string) => {
|
|||||||
* @param {Date | number | string} time 需要转换的时间
|
* @param {Date | number | string} time 需要转换的时间
|
||||||
* @param {String} fmt 需要转换的格式 如 yyyy-MM-dd、yyyy-MM-dd HH:mm:ss
|
* @param {String} fmt 需要转换的格式 如 yyyy-MM-dd、yyyy-MM-dd HH:mm:ss
|
||||||
*/
|
*/
|
||||||
export const formatTime = (time: Date | number | string, fmt: string) => {
|
export function formatTime(time: Date | number | string, fmt: string) {
|
||||||
if (!time) return ''
|
if (!time) return ''
|
||||||
else {
|
else {
|
||||||
const date = new Date(time)
|
const date = new Date(time)
|
||||||
@ -98,7 +105,7 @@ export const formatTime = (time: Date | number | string, fmt: string) => {
|
|||||||
/**
|
/**
|
||||||
* 生成随机字符串
|
* 生成随机字符串
|
||||||
*/
|
*/
|
||||||
export const toAnyString = () => {
|
export function toAnyString() {
|
||||||
const str: string = 'xxxxx-xxxxx-4xxxx-yxxxx-xxxxx'.replace(/[xy]/g, (c: string) => {
|
const str: string = 'xxxxx-xxxxx-4xxxx-yxxxx-xxxxx'.replace(/[xy]/g, (c: string) => {
|
||||||
const r: number = (Math.random() * 16) | 0
|
const r: number = (Math.random() * 16) | 0
|
||||||
const v: number = c === 'x' ? r : (r & 0x3) | 0x8
|
const v: number = c === 'x' ? r : (r & 0x3) | 0x8
|
||||||
@ -107,6 +114,13 @@ export const toAnyString = () => {
|
|||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首字母大写
|
||||||
|
*/
|
||||||
|
export function firstUpperCase(str: string) {
|
||||||
|
return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase())
|
||||||
|
}
|
||||||
|
|
||||||
export const generateUUID = () => {
|
export const generateUUID = () => {
|
||||||
if (typeof crypto === 'object') {
|
if (typeof crypto === 'object') {
|
||||||
if (typeof crypto.randomUUID === 'function') {
|
if (typeof crypto.randomUUID === 'function') {
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
message="访问的路由地址,如:`user`。如需外网地址时,则以 `http(s)://` 开头"
|
message="访问的路由地址,如:`user`。如需外网地址时,则以 `http(s)://` 开头"
|
||||||
titel="路由地址"
|
title="路由地址"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<el-input v-model="formData.path" clearable placeholder="请输入路由地址" />
|
<el-input v-model="formData.path" clearable placeholder="请输入路由地址" />
|
||||||
@ -53,7 +53,7 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
message="Controller 方法上的权限字符,如:@PreAuthorize(`@ss.hasPermission('system:user:list')`)"
|
message="Controller 方法上的权限字符,如:@PreAuthorize(`@ss.hasPermission('system:user:list')`)"
|
||||||
titel="权限标识"
|
title="权限标识"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<el-input v-model="formData.permission" clearable placeholder="请输入权限标识" />
|
<el-input v-model="formData.permission" clearable placeholder="请输入权限标识" />
|
||||||
@ -74,7 +74,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="formData.type !== 3" label="显示状态" prop="visible">
|
<el-form-item v-if="formData.type !== 3" label="显示状态" prop="visible">
|
||||||
<template #label>
|
<template #label>
|
||||||
<Tooltip message="选择隐藏时,路由将不会出现在侧边栏,但仍然可以访问" titel="显示状态" />
|
<Tooltip message="选择隐藏时,路由将不会出现在侧边栏,但仍然可以访问" title="显示状态" />
|
||||||
</template>
|
</template>
|
||||||
<el-radio-group v-model="formData.visible">
|
<el-radio-group v-model="formData.visible">
|
||||||
<el-radio key="true" :label="true" border>显示</el-radio>
|
<el-radio key="true" :label="true" border>显示</el-radio>
|
||||||
@ -85,7 +85,7 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
message="选择不是时,当该菜单只有一个子菜单时,不展示自己,直接展示子菜单"
|
message="选择不是时,当该菜单只有一个子菜单时,不展示自己,直接展示子菜单"
|
||||||
titel="总是显示"
|
title="总是显示"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<el-radio-group v-model="formData.alwaysShow">
|
<el-radio-group v-model="formData.alwaysShow">
|
||||||
@ -97,7 +97,7 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
message="选择缓存时,则会被 `keep-alive` 缓存,必须填写「组件名称」字段"
|
message="选择缓存时,则会被 `keep-alive` 缓存,必须填写「组件名称」字段"
|
||||||
titel="缓存状态"
|
title="缓存状态"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<el-radio-group v-model="formData.keepAlive">
|
<el-radio-group v-model="formData.keepAlive">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<doc-alert title="功能权限" url="https://doc.iocoder.cn/resource-permission" />
|
<doc-alert title="功能权限" url="https://doc.iocoder.cn/resource-permission" />
|
||||||
<doc-alert title="菜单路由" url="https://doc.iocoder.cn/vue2/route/" />
|
<doc-alert title="菜单路由" url="https://doc.iocoder.cn/vue3/route/" />
|
||||||
|
|
||||||
<!-- 搜索工作栏 -->
|
<!-- 搜索工作栏 -->
|
||||||
<ContentWrap>
|
<ContentWrap>
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
"@intlify/unplugin-vue-i18n/types",
|
"@intlify/unplugin-vue-i18n/types",
|
||||||
"vite/client",
|
"vite/client",
|
||||||
"element-plus/global",
|
"element-plus/global",
|
||||||
"@types/intro.js",
|
|
||||||
"@types/qrcode",
|
"@types/qrcode",
|
||||||
"vite-plugin-svg-icons/client"
|
"vite-plugin-svg-icons/client"
|
||||||
],
|
],
|
||||||
|
@ -101,5 +101,8 @@ ${selector}:after {
|
|||||||
]
|
]
|
||||||
],
|
],
|
||||||
presets: [presetUno({ dark: 'class', attributify: false })],
|
presets: [presetUno({ dark: 'class', attributify: false })],
|
||||||
transformers: [transformerVariantGroup()]
|
transformers: [transformerVariantGroup()],
|
||||||
|
shortcuts: {
|
||||||
|
'wh-full': 'w-full h-full'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user