迁移UI框架至naive-ui,重构组件和样式,添加Gallery和Mask组件
This commit is contained in:
4
auto-imports.d.ts
vendored
4
auto-imports.d.ts
vendored
@ -68,9 +68,13 @@ declare global {
|
|||||||
const useAttrs: typeof import('vue')['useAttrs']
|
const useAttrs: typeof import('vue')['useAttrs']
|
||||||
const useCssModule: typeof import('vue')['useCssModule']
|
const useCssModule: typeof import('vue')['useCssModule']
|
||||||
const useCssVars: typeof import('vue')['useCssVars']
|
const useCssVars: typeof import('vue')['useCssVars']
|
||||||
|
const useDialog: typeof import('naive-ui')['useDialog']
|
||||||
const useId: typeof import('vue')['useId']
|
const useId: typeof import('vue')['useId']
|
||||||
const useLink: typeof import('vue-router')['useLink']
|
const useLink: typeof import('vue-router')['useLink']
|
||||||
|
const useLoadingBar: typeof import('naive-ui')['useLoadingBar']
|
||||||
|
const useMessage: typeof import('naive-ui')['useMessage']
|
||||||
const useModel: typeof import('vue')['useModel']
|
const useModel: typeof import('vue')['useModel']
|
||||||
|
const useNotification: typeof import('naive-ui')['useNotification']
|
||||||
const useRoute: typeof import('vue-router')['useRoute']
|
const useRoute: typeof import('vue-router')['useRoute']
|
||||||
const useRouter: typeof import('vue-router')['useRouter']
|
const useRouter: typeof import('vue-router')['useRouter']
|
||||||
const useSlots: typeof import('vue')['useSlots']
|
const useSlots: typeof import('vue')['useSlots']
|
||||||
|
|||||||
51
components.d.ts
vendored
51
components.d.ts
vendored
@ -10,35 +10,36 @@ declare module 'vue' {
|
|||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
Aplayer: typeof import('./src/components/aplayer.vue')['default']
|
Aplayer: typeof import('./src/components/aplayer.vue')['default']
|
||||||
ContextMenu: typeof import('./src/components/contextMenu.vue')['default']
|
ContextMenu: typeof import('./src/components/contextMenu.vue')['default']
|
||||||
DAside: typeof import('vue-devui/layout/index.es.js')['Aside']
|
Gallery: typeof import('./src/components/Gallery.vue')['default']
|
||||||
DAvatar: typeof import('vue-devui/avatar/index.es.js')['Avatar']
|
|
||||||
DButton: typeof import('vue-devui/button/index.es.js')['Button']
|
|
||||||
DCard: typeof import('vue-devui/card/index.es.js')['Card']
|
|
||||||
DContent: typeof import('vue-devui/layout/index.es.js')['Content']
|
|
||||||
DDropdown: typeof import('vue-devui/dropdown/index.es.js')['Dropdown']
|
|
||||||
DFooter: typeof import('vue-devui/layout/index.es.js')['Footer']
|
|
||||||
DForm: typeof import('vue-devui/form/index.es.js')['Form']
|
|
||||||
DFormItem: typeof import('vue-devui/form/index.es.js')['FormItem']
|
|
||||||
DHeader: typeof import('vue-devui/layout/index.es.js')['Header']
|
|
||||||
DIcon: typeof import('vue-devui/icon/index.es.js')['Icon']
|
|
||||||
DInput: typeof import('vue-devui/input/index.es.js')['Input']
|
|
||||||
DLayout: typeof import('vue-devui/layout/index.es.js')['Layout']
|
|
||||||
DMenu: typeof import('vue-devui/menu/index.es.js')['Menu']
|
|
||||||
DMenuItem: typeof import('vue-devui/menu/index.es.js')['MenuItem']
|
|
||||||
DModal: typeof import('vue-devui/modal/index.es.js')['Modal']
|
|
||||||
DPopover: typeof import('vue-devui/popover/index.es.js')['Popover']
|
|
||||||
DSearch: typeof import('vue-devui/search/index.es.js')['Search']
|
|
||||||
DSelect: typeof import('vue-devui/select/index.es.js')['Select']
|
|
||||||
DTab: typeof import('vue-devui/tabs/index.es.js')['Tab']
|
|
||||||
DTabs: typeof import('vue-devui/tabs/index.es.js')['Tabs']
|
|
||||||
DTag: typeof import('vue-devui/tag/index.es.js')['Tag']
|
|
||||||
HomeSide: typeof import('./src/components/homeSide.vue')['default']
|
HomeSide: typeof import('./src/components/homeSide.vue')['default']
|
||||||
Login: typeof import('./src/components/Login.vue')['default']
|
Login: typeof import('./src/components/Login.vue')['default']
|
||||||
|
Mask: typeof import('./src/components/mask.vue')['default']
|
||||||
MenuH: typeof import('./src/components/menuH.vue')['default']
|
MenuH: typeof import('./src/components/menuH.vue')['default']
|
||||||
|
NAvatar: typeof import('naive-ui')['NAvatar']
|
||||||
|
NButton: typeof import('naive-ui')['NButton']
|
||||||
|
NCard: typeof import('naive-ui')['NCard']
|
||||||
|
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
||||||
|
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
|
||||||
|
NDropdown: typeof import('naive-ui')['NDropdown']
|
||||||
|
NForm: typeof import('naive-ui')['NForm']
|
||||||
|
NFormItem: typeof import('naive-ui')['NFormItem']
|
||||||
|
NIcon: typeof import('naive-ui')['NIcon']
|
||||||
|
NInput: typeof import('naive-ui')['NInput']
|
||||||
|
NInputGroup: typeof import('naive-ui')['NInputGroup']
|
||||||
|
NLayout: typeof import('naive-ui')['NLayout']
|
||||||
|
NLayoutContent: typeof import('naive-ui')['NLayoutContent']
|
||||||
|
NLayoutFooter: typeof import('naive-ui')['NLayoutFooter']
|
||||||
|
NLayoutHeader: typeof import('naive-ui')['NLayoutHeader']
|
||||||
|
NLayoutSider: typeof import('naive-ui')['NLayoutSider']
|
||||||
|
NMenu: typeof import('naive-ui')['NMenu']
|
||||||
|
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
|
||||||
|
NModal: typeof import('naive-ui')['NModal']
|
||||||
|
NModalProvider: typeof import('naive-ui')['NModalProvider']
|
||||||
|
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||||
|
NSelect: typeof import('naive-ui')['NSelect']
|
||||||
|
NTabPane: typeof import('naive-ui')['NTabPane']
|
||||||
|
NTabs: typeof import('naive-ui')['NTabs']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
}
|
}
|
||||||
export interface GlobalDirectives {
|
|
||||||
vImagePreview: typeof import('vue-devui/image-preview/index.es.js')['ImagePreviewDirective']
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
26
dist/assets/Article-Cll2DzoB.css
vendored
26
dist/assets/Article-Cll2DzoB.css
vendored
File diff suppressed because one or more lines are too long
1
dist/assets/Gallery-BWGJDDfX.css
vendored
1
dist/assets/Gallery-BWGJDDfX.css
vendored
File diff suppressed because one or more lines are too long
BIN
dist/assets/codicon-SZR-f31-.ttf
vendored
BIN
dist/assets/codicon-SZR-f31-.ttf
vendored
Binary file not shown.
BIN
dist/assets/devui-icomoon-BHLqMzSu.woff
vendored
BIN
dist/assets/devui-icomoon-BHLqMzSu.woff
vendored
Binary file not shown.
BIN
dist/assets/devui-icomoon-BeYkSg23.eot
vendored
BIN
dist/assets/devui-icomoon-BeYkSg23.eot
vendored
Binary file not shown.
BIN
dist/assets/devui-icomoon-C-SlqI79.ttf
vendored
BIN
dist/assets/devui-icomoon-C-SlqI79.ttf
vendored
Binary file not shown.
2196
dist/assets/devui-icomoon-NjuehwAK.svg
vendored
2196
dist/assets/devui-icomoon-NjuehwAK.svg
vendored
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 1.8 MiB |
4
dist/index.html
vendored
4
dist/index.html
vendored
@ -7,8 +7,8 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="description" content="这是柚子的网站,做一些分享类的功能"/>
|
<meta name="description" content="这是柚子的网站,做一些分享类的功能"/>
|
||||||
<title>柚子の网站</title>
|
<title>柚子の网站</title>
|
||||||
<script type="module" crossorigin src="/blog/assets/index-CIE_IpA5.js"></script>
|
<script type="module" crossorigin src="/blog/assets/index-C1l6Y9EA.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/blog/assets/index-DYCSKHr7.css">
|
<link rel="stylesheet" crossorigin href="/blog/assets/index-Cpzn2D0V.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
3
extra.d.ts
vendored
3
extra.d.ts
vendored
@ -1,2 +1,3 @@
|
|||||||
declare module "aplayer";
|
declare module "aplayer";
|
||||||
declare module 'vue3-video-play';
|
declare module "vue3-video-play";
|
||||||
|
declare module "vue3-masonry-plus";
|
||||||
10
package.json
10
package.json
@ -14,29 +14,28 @@
|
|||||||
"type-check": "vue-tsc --build"
|
"type-check": "vue-tsc --build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@devui-design/icons": "^1.4.0",
|
|
||||||
"@imengyu/vue3-context-menu": "^1.5.2",
|
"@imengyu/vue3-context-menu": "^1.5.2",
|
||||||
"@meting/core": "^1.5.13",
|
"@meting/core": "^1.5.13",
|
||||||
"@unocss/reset": "^66.3.3",
|
"@unocss/reset": "^66.3.3",
|
||||||
"aplayer": "^1.10.1",
|
"aplayer": "^1.10.1",
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"devui-theme": "^0.0.7",
|
|
||||||
"es-toolkit": "^1.39.8",
|
"es-toolkit": "^1.39.8",
|
||||||
"less": "^4.4.0",
|
"less": "^4.4.0",
|
||||||
"ng-devui": "^18.0.0",
|
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"qweather-icons": "^1.7.0",
|
"qweather-icons": "^1.7.0",
|
||||||
"unocss": "^66.3.3",
|
"unocss": "^66.3.3",
|
||||||
"unplugin-auto-import": "^19.3.0",
|
"unplugin-auto-import": "^19.3.0",
|
||||||
"unplugin-vue-components": "^28.8.0",
|
"unplugin-vue-components": "^28.8.0",
|
||||||
"unplugin-vue-router": "^0.15.0",
|
"unplugin-vue-router": "^0.15.0",
|
||||||
|
"v-infinite-scroll": "^1.0.4",
|
||||||
"vditor": "^3.11.2",
|
"vditor": "^3.11.2",
|
||||||
"vite-svg-loader": "^5.1.0",
|
"vite-svg-loader": "^5.1.0",
|
||||||
"vue": "^3.6.0-alpha.2",
|
"vue": "^3.6.0-alpha.2",
|
||||||
"vue-devui": "^1.6.33",
|
"vue-masonry": "^0.16.0",
|
||||||
"vue-router": "^4.5.1",
|
"vue-router": "^4.5.1",
|
||||||
"vue3-cookies": "^1.0.6",
|
"vue3-cookies": "^1.0.6",
|
||||||
|
"vue3-masonry-plus": "^1.2.5",
|
||||||
"vue3-perfect-scrollbar": "^2.0.0",
|
"vue3-perfect-scrollbar": "^2.0.0",
|
||||||
"vue3-video-play": "^1.3.2"
|
"vue3-video-play": "^1.3.2"
|
||||||
},
|
},
|
||||||
@ -45,10 +44,13 @@
|
|||||||
"@types/node": "^22.16.5",
|
"@types/node": "^22.16.5",
|
||||||
"@vitejs/plugin-vue": "^6.0.1",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"@vue/tsconfig": "^0.7.0",
|
"@vue/tsconfig": "^0.7.0",
|
||||||
|
"naive-ui": "^2.43.2",
|
||||||
"npm-run-all2": "^8.0.4",
|
"npm-run-all2": "^8.0.4",
|
||||||
"typescript": "~5.8.0",
|
"typescript": "~5.8.0",
|
||||||
|
"vfonts": "^0.0.3",
|
||||||
"vite": "^7.0.6",
|
"vite": "^7.0.6",
|
||||||
"vite-plugin-vue-devtools": "^8.0.0",
|
"vite-plugin-vue-devtools": "^8.0.0",
|
||||||
|
"vue-devui": "^1.6.35",
|
||||||
"vue-tsc": "^3.0.4"
|
"vue-tsc": "^3.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
72
src/App.vue
72
src/App.vue
@ -1,71 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<n-config-provider :theme-overrides="themeOverrides">
|
||||||
<PerfectScrollbar>
|
<n-message-provider>
|
||||||
<lay-index></lay-index>
|
<n-dialog-provider>
|
||||||
</PerfectScrollbar>
|
<n-modal-provider>
|
||||||
</div>
|
<n-scrollbar style="max-height: 100vh">
|
||||||
|
<lay-index></lay-index>
|
||||||
<d-modal class="!w-80" v-model="modal.visible" :title="modal.title">
|
</n-scrollbar>
|
||||||
{{ modal.content }}
|
</n-modal-provider>
|
||||||
<div class="mt-4 w-full flex justify-between">
|
</n-dialog-provider>
|
||||||
<!-- <d-button @click="modal.handdleCancel" variant="text"
|
</n-message-provider>
|
||||||
class="w-[49%] hover:bg-[#8a6684] hover:!text-white">{{modal.cancelText}}</d-button>
|
</n-config-provider>
|
||||||
<span class="text-[20px]"> | </span>
|
|
||||||
<d-button @click="modal.handdleSubmit" variant="text" class="w-[49%] hover:bg-[#5c866a] hover:!text-white"
|
|
||||||
color="primary">{{modal.submitText}}</d-button> -->
|
|
||||||
|
|
||||||
<d-button class="w-[48%]" variant="solid" color="secondary" @click="modal.handdleCancel">{{modal.cancelText}}</d-button>
|
|
||||||
<d-button class="w-[48%]" variant="solid" color="primary" @click="modal.handdleSubmit">{{modal.submitText}}</d-button>
|
|
||||||
</div>
|
|
||||||
</d-modal>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import layIndex from './Index.vue'
|
import themeOverrides from '@/util/theme.ts';
|
||||||
|
import layIndex from './Index.vue';
|
||||||
// 空白项目入口
|
// 空白项目入口
|
||||||
const route = useRoute()
|
|
||||||
const logStatus = $store.log.useLogStore()
|
const logStatus = $store.log.useLogStore()
|
||||||
const modal = reactive<any>({
|
|
||||||
visible: false,
|
|
||||||
title: "",
|
|
||||||
content: "",
|
|
||||||
handdleCancel: () => { modal.visible = false },
|
|
||||||
handdleSubmit: () => { },
|
|
||||||
})
|
|
||||||
|
|
||||||
function comemodal(mv: any) {
|
|
||||||
if (!mv) return
|
|
||||||
modal.visible = true
|
|
||||||
modal.title = mv.title
|
|
||||||
modal.content = mv.content
|
|
||||||
modal.cancelText = mv.cancelText || "取消"
|
|
||||||
modal.submitText = mv.submitText || "确定"
|
|
||||||
if (mv.handdleCancel) modal.handdleCancel = () => {
|
|
||||||
mv.handdleCancel()
|
|
||||||
modal.visible = false
|
|
||||||
}
|
|
||||||
modal.handdleSubmit = () => {
|
|
||||||
mv.handdleSubmit()
|
|
||||||
modal.visible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.$modal = comemodal
|
|
||||||
|
|
||||||
// 全局禁用右键菜单
|
// 全局禁用右键菜单
|
||||||
document.oncontextmenu = function () {
|
document.oncontextmenu = function () {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if($cookies.get('userinfo')) logStatus.setIsLogin(true)
|
if ($cookies.get('userinfo')) logStatus.setIsLogin(true)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less"></style>
|
||||||
.ps {
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
padding-inline-start: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,38 +1,112 @@
|
|||||||
<template>
|
<template>
|
||||||
<d-layout>
|
<n-layout>
|
||||||
<d-header class="dheader-1">
|
<n-layout-header class="dheader-1">
|
||||||
<menu-h />
|
<menu-h />
|
||||||
</d-header>
|
</n-layout-header>
|
||||||
<d-content class="dcontent-1">
|
<n-layout-content class="dcontent-1">
|
||||||
<router-view />
|
<router-view />
|
||||||
</d-content>
|
</n-layout-content>
|
||||||
<d-footer v-show="route.path == '/home'" class="dfooter-1">
|
<n-layout-footer v-show="route.path == '/home'" class="flex justify-center dfooter-1">
|
||||||
<div class="beian" ref="footer">
|
<div class="beian" ref="footer">
|
||||||
<a class="text-primary" href="https://beian.miit.gov.cn" target="_blank">皖ICP备2021017362号-1</a>
|
<a class="text-primary" href="https://beian.miit.gov.cn" target="_blank">皖ICP备2021017362号-1</a>
|
||||||
<a class="swag text-primary" target="_blank" href="https://www.hxyouzi.com/swag">api文档</a>
|
<a class="swag text-primary" target="_blank" href="https://www.hxyouzi.com/swag">api文档</a>
|
||||||
</div>
|
</div>
|
||||||
</d-footer>
|
</n-layout-footer>
|
||||||
</d-layout>
|
</n-layout>
|
||||||
|
|
||||||
|
|
||||||
|
<n-modal v-model:show="modal.visible" preset="dialog" title="Dialog">
|
||||||
|
<template #header>
|
||||||
|
<div>{{ modal.title }}</div>
|
||||||
|
</template>
|
||||||
|
<div>
|
||||||
|
<div class="my-2">{{ modal.content }}</div>
|
||||||
|
<div v-if="modal.contType == 'input'">
|
||||||
|
<n-input @change="modal.handdleInputChange($event)" :placeholder="modal.placeholder"></n-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #action>
|
||||||
|
<n-button @click="modal.handdleCancel">{{ modal.cancelText }}</n-button>
|
||||||
|
<n-button type="primary" @click="modal.handdleSubmit">{{ modal.submitText }}</n-button>
|
||||||
|
</template>
|
||||||
|
</n-modal>
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const footer = ref<HTMLElement | null>(null)
|
const footer = ref<HTMLElement | null>(null)
|
||||||
|
window.$msg = useMessage()
|
||||||
|
const modal: NmodalItem = reactive({
|
||||||
|
visible: false,
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
contType: 'text',
|
||||||
|
cancelText: '取消',
|
||||||
|
submitText: '确定',
|
||||||
|
placeholder: '请输入内容',
|
||||||
|
handdleCancel: () => { },
|
||||||
|
handdleSubmit: () => { },
|
||||||
|
handdleInputChange: (e: any) => { }
|
||||||
|
})
|
||||||
|
interface NmodalItem {
|
||||||
|
visible: boolean
|
||||||
|
title: string
|
||||||
|
content: string
|
||||||
|
contType?: string
|
||||||
|
placeholder?: string
|
||||||
|
cancelText?: string
|
||||||
|
submitText?: string
|
||||||
|
handdleCancel?: () => void
|
||||||
|
handdleSubmit?: () => void
|
||||||
|
handdleInputChange: (e: any) => void
|
||||||
|
}
|
||||||
|
//mark method
|
||||||
|
function comemodal(mv: NmodalItem) {
|
||||||
|
if (!mv) return
|
||||||
|
modal.visible = true
|
||||||
|
modal.title = mv.title
|
||||||
|
modal.content = mv.content
|
||||||
|
modal.contType = mv.contType || "text"
|
||||||
|
modal.placeholder = mv.placeholder || "请输入内容"
|
||||||
|
modal.cancelText = mv.cancelText || "取消"
|
||||||
|
modal.submitText = mv.submitText || "确定"
|
||||||
|
modal.handdleCancel = (): void => {
|
||||||
|
if (mv.handdleCancel) {
|
||||||
|
mv.handdleCancel()
|
||||||
|
}
|
||||||
|
modal.visible = false
|
||||||
|
}
|
||||||
|
modal.handdleSubmit = () => {
|
||||||
|
if (mv.handdleSubmit) {
|
||||||
|
mv.handdleSubmit()
|
||||||
|
}
|
||||||
|
modal.visible = false
|
||||||
|
}
|
||||||
|
modal.handdleInputChange = (e) => {
|
||||||
|
if (mv.handdleInputChange) {
|
||||||
|
mv.handdleInputChange(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.$modal = comemodal
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 计算footer的高度
|
// 计算footer的高度
|
||||||
|
|
||||||
const footerHeight = footer.value?.clientHeight || 0;
|
const footerHeight = footer.value?.clientHeight || 0;
|
||||||
|
|
||||||
console.log('footerHeight', footerHeight);
|
console.log('footerHeight', footerHeight);
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped lang="less">
|
||||||
.dcontent-1 {
|
.dcontent-1 {
|
||||||
|
|
||||||
background-color: #fbfbfb;
|
background-color: #fbfbfb;
|
||||||
}
|
}
|
||||||
|
|
||||||
.beian {
|
.beian {
|
||||||
|
width: 100%;
|
||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@ -1,6 +1,3 @@
|
|||||||
@import "./base.less";
|
@import "./base.less";
|
||||||
@import "@devui-design/icons/icomoon/devui-icon.css";
|
|
||||||
@import "qweather-icons/font/qweather-icons.css";
|
@import "qweather-icons/font/qweather-icons.css";
|
||||||
@import "@devui-design/icons/icomoon/devui-icon.css";
|
|
||||||
@import "vue-devui/style.css";
|
|
||||||
@import "vue3-perfect-scrollbar/style.css";
|
@import "vue3-perfect-scrollbar/style.css";
|
||||||
|
|||||||
281
src/components/Gallery.vue
Normal file
281
src/components/Gallery.vue
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
<template>
|
||||||
|
<PerfectScrollbar ref="scrollbar" @ps-scroll-y="handleScroll">
|
||||||
|
<div ref="myCon" class="gallery-page py-5 px-[10%]">
|
||||||
|
<d-search class="mt-0 mb-8 w-2/3 mx-auto rounded-full" v-model="kw" is-keyup-search :delay="1000"
|
||||||
|
@search="onSearch"></d-search>
|
||||||
|
<div class="gallery-container w-full box-border">
|
||||||
|
<!-- 瀑布流容器 -->
|
||||||
|
<div ref="waterfallContainer" v-image-preview
|
||||||
|
class="waterfall-container flex justify-between flex-nowrap w-full overflow-hidden">
|
||||||
|
<!-- 动态生成的列 -->
|
||||||
|
<div v-for="(column, index) in columns" :key="index" class="waterfall-column flex flex-col w-[240px]">
|
||||||
|
<div v-for="item in column" :key="item.id"
|
||||||
|
class="gallery-item group relative my-[10px] rounded-lg overflow-hidden transition-transform duration-300 box-border hover:-translate-y-1.5">
|
||||||
|
<div
|
||||||
|
class="absolute px-2 truncate hidden group-hover:block top-0 text-center w-full bg-[#00000070] text-white">
|
||||||
|
{{ item.filename }}</div>
|
||||||
|
<img :src="item.filepath" alt="" class="gallery-image block w-full h-auto object-cover rounded-md">
|
||||||
|
<div class="px-2 absolute bottom-0 flex justify-between w-full bg-[#00000060]">
|
||||||
|
<div class="text-white ">由 <span class="text-[#f1d9db] font-600">{{ item.nickname }}</span> 上传</div>
|
||||||
|
<d-popover content="下载" trigger="hover" class="!bg-primary" style="color: #fff">
|
||||||
|
<icon-download @click="downloadFile(item.filepath)"
|
||||||
|
class="w-5 h-5 text-white hover-text-primary"></icon-download>
|
||||||
|
</d-popover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 加载中指示器 -->
|
||||||
|
<div v-if="loading" class="loading-indicator text-center p-5 text-gray-600">加载中...</div>
|
||||||
|
<div v-else class="loading-indicator text-center p-5 text-gray-600">已全部加载完成</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PerfectScrollbar>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { throttle } from 'es-toolkit';
|
||||||
|
|
||||||
|
definePage({
|
||||||
|
name: 'gallery',
|
||||||
|
meta: {
|
||||||
|
title: '画廊',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// 画廊页逻辑
|
||||||
|
const fileList = ref<any[]>([]);
|
||||||
|
const pn = ref(1);
|
||||||
|
const ps = ref(40);
|
||||||
|
const loading = ref(false);
|
||||||
|
const waterfallContainer = ref<HTMLDivElement | null>(null);
|
||||||
|
const columns = ref<Array<Array<any>>>([]);
|
||||||
|
const columnHeights = ref<number[]>([]);
|
||||||
|
const columnCount = ref(4); // 默认列数
|
||||||
|
const itemWidth = ref(240); // 图片宽度固定为240px
|
||||||
|
const kw = ref<string>('');
|
||||||
|
|
||||||
|
// const uploadOptions = ref({
|
||||||
|
// uri: 'https://www.hxyouzi.com/api/files/upload',
|
||||||
|
// method: 'POST',
|
||||||
|
// maximumSize: 5 * 1024 * 1024,
|
||||||
|
// headers: {
|
||||||
|
// 'Authorization': 'Bearer ' + $cookies.get('token'),
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// 计算列数 based on 屏幕宽度
|
||||||
|
function calculateColumnCount() {
|
||||||
|
if (!waterfallContainer.value) return;
|
||||||
|
const containerWidth = waterfallContainer.value.clientWidth;
|
||||||
|
const newColumnCount = Math.max(1, Math.floor(containerWidth / itemWidth.value));
|
||||||
|
if (newColumnCount !== columnCount.value) {
|
||||||
|
columnCount.value = newColumnCount;
|
||||||
|
resetWaterfall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置瀑布流
|
||||||
|
function resetWaterfall() {
|
||||||
|
columns.value = Array(columnCount.value).fill(0).map(() => []);
|
||||||
|
columnHeights.value = Array(columnCount.value).fill(0);
|
||||||
|
// 重新分配图片
|
||||||
|
fileList.value.forEach(async (item:any) =>await addToWaterfall(item));
|
||||||
|
console.log('>>> --> resetWaterfall --> fileList:', fileList.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加图片到瀑布流
|
||||||
|
async function addToWaterfall(item: any) {
|
||||||
|
if (columns.value.length === 0) return;
|
||||||
|
const { height, width } =await getImageSizeByCheck(item.filepath)
|
||||||
|
|
||||||
|
// 找到高度最小的列
|
||||||
|
let minHeight = Math.min(...columnHeights.value);
|
||||||
|
let minIndex = columnHeights.value.indexOf(minHeight);
|
||||||
|
console.log('>>> --> addToWaterfall --> item:', item)
|
||||||
|
console.log('>>> --> addToWaterfall --> minIndex:', minIndex)
|
||||||
|
// 添加到该列
|
||||||
|
columns.value[minIndex].push(item);
|
||||||
|
// 估算列高 - 实际高度会在图片加载后更新
|
||||||
|
const estimatedHeight = itemWidth.value * height / width
|
||||||
|
columnHeights.value[minIndex] += estimatedHeight + 20; // 加上padding和margin
|
||||||
|
}
|
||||||
|
|
||||||
|
function getImageSizeByCheck(url: string): any {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
let image = new Image();
|
||||||
|
image.src = url;
|
||||||
|
let height = 0
|
||||||
|
let width = 0
|
||||||
|
// let timer = setTimeout(() => {
|
||||||
|
image.onload = () => {
|
||||||
|
if (image.width > 0 && image.height > 0) {
|
||||||
|
height = image.height
|
||||||
|
width = image.width
|
||||||
|
resolve({ height, width })
|
||||||
|
// clearTimeout(timer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// }, 100)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件列表
|
||||||
|
async function getFileList() {
|
||||||
|
if (loading.value) return;
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const res = await $http.file.getFileList({
|
||||||
|
keyword: kw.value,
|
||||||
|
page_num: pn.value,
|
||||||
|
page_size: ps.value,
|
||||||
|
});
|
||||||
|
// console.log('>>> --> getFileList --> res:', res);
|
||||||
|
|
||||||
|
if (pn.value === 1) {
|
||||||
|
fileList.value = res.data;
|
||||||
|
resetWaterfall();
|
||||||
|
} else {
|
||||||
|
// 追加新数据
|
||||||
|
res.data.forEach((item: any) => {
|
||||||
|
fileList.value.push(item);
|
||||||
|
addToWaterfall(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取文件列表失败:', error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 获取我的文件列表
|
||||||
|
// async function getMyList() {
|
||||||
|
// if (loading.value) return;
|
||||||
|
// loading.value = true;
|
||||||
|
// try {
|
||||||
|
// const res = await $http.file.getMyList({
|
||||||
|
// page_num: pn.value,
|
||||||
|
// page_size: ps.value,
|
||||||
|
// });
|
||||||
|
// // console.log('>>> --> getFileList --> res:', res);
|
||||||
|
|
||||||
|
// if (pn.value === 1) {
|
||||||
|
// fileList.value = res.data;
|
||||||
|
// resetWaterfall();
|
||||||
|
// } else {
|
||||||
|
// // 追加新数据
|
||||||
|
// res.data.forEach((item: any) => {
|
||||||
|
// fileList.value.push(item);
|
||||||
|
// addToWaterfall(item);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error('获取文件列表失败:', error);
|
||||||
|
// } finally {
|
||||||
|
// loading.value = false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 监听滚动事件
|
||||||
|
const handleScroll: any = throttle((e: any) => {
|
||||||
|
console.log('>>> --> handleScroll --> loading:', e)
|
||||||
|
if (loading.value) return;
|
||||||
|
const scrollTop = e.target.scrollTop
|
||||||
|
console.log('>>> --> handleScroll --> scrollTop:', scrollTop)
|
||||||
|
const scrollHeight = e.target.scrollHeight
|
||||||
|
// console.log('>>> --> handleScroll --> scrollHeight:', scrollHeight)
|
||||||
|
const clientHeight = e.target.offsetHeight;
|
||||||
|
|
||||||
|
// 当滚动到距离底部20%时加载更多
|
||||||
|
// console.log('>>> --> clientHeight --> clientHeight:', clientHeight)
|
||||||
|
if (scrollTop + clientHeight >= scrollHeight * 0.8) {
|
||||||
|
console.log('>>> --> handleScroll --> 加载更多')
|
||||||
|
pn.value++;
|
||||||
|
getFileList();
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
function onSearch() {
|
||||||
|
pn.value = 1;
|
||||||
|
getFileList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadFile(url: string) {
|
||||||
|
console.log('>>> --> downloadFile --> url:', url)
|
||||||
|
// 创建临时a标签
|
||||||
|
const link = document.createElement('a');
|
||||||
|
// 设置下载链接
|
||||||
|
link.href = url;
|
||||||
|
// 提取文件名
|
||||||
|
const fileName = url.split('/').pop() || 'downloaded-file';
|
||||||
|
// 设置下载属性和文件名
|
||||||
|
link.download = fileName;
|
||||||
|
// 设置为隐藏元素
|
||||||
|
link.style.display = 'none';
|
||||||
|
// 添加到文档
|
||||||
|
document.body.appendChild(link);
|
||||||
|
// 触发点击事件
|
||||||
|
link.click();
|
||||||
|
// 移除临时元素
|
||||||
|
document.body.removeChild(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getFileList();
|
||||||
|
// 计算初始列数
|
||||||
|
calculateColumnCount();
|
||||||
|
// 添加窗口大小变化监听
|
||||||
|
window.addEventListener('resize', calculateColumnCount);
|
||||||
|
// 添加滚动监听
|
||||||
|
window.addEventListener('scroll', handleScroll);
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
pn.value = 1;
|
||||||
|
kw.value = '';
|
||||||
|
fileList.value = [];
|
||||||
|
resetWaterfall();
|
||||||
|
|
||||||
|
// 移除监听
|
||||||
|
window.removeEventListener('resize', calculateColumnCount);
|
||||||
|
window.removeEventListener('scroll', handleScroll);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
/* 画廊页样式 */
|
||||||
|
:deep(.devui-tabs__nav) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100% !important;
|
||||||
|
// padding: 0 10%;
|
||||||
|
|
||||||
|
li {
|
||||||
|
width: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
li a span {
|
||||||
|
font-size: 18px !important;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ps {
|
||||||
|
height: calc(100vh - 65px);
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.devui-upload) {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&>div {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,44 +1,47 @@
|
|||||||
<template>
|
<template>
|
||||||
<d-card class="mt-10 bg-[#ffffff60] rounded-[10px]" shadow="never">
|
<n-card class="mt-10 rounden-[10px] w-[500px]" shadow="never">
|
||||||
<d-tabs v-model="tid" type="pills">
|
<n-tabs v-model:value="tid" justify-content="space-evenly" animated>
|
||||||
<d-tab id="tab1" title="登录">
|
<n-tab-pane name="tab1" tab="登录">
|
||||||
<d-form ref="formLogin" layout="vertical" :data="loginData" :rules="rules">
|
<n-form ref="formLogin" layout="vertical" :data="loginData" :rules="rules">
|
||||||
<d-form-item field="username">
|
<n-form-item field="username">
|
||||||
<d-input v-model="loginData.username" placeholder="请输入用户名" />
|
<n-input v-model:value="loginData.username" placeholder="请输入用户名" />
|
||||||
</d-form-item>
|
</n-form-item>
|
||||||
<d-form-item field="password">
|
<n-form-item field="password">
|
||||||
<d-input v-model="loginData.password" show-password placeholder="请输入密码" />
|
<n-input v-model:value="loginData.password" type="password" show-password-on="click" placeholder="请输入密码" />
|
||||||
</d-form-item>
|
</n-form-item>
|
||||||
<d-form-item class="form-operation-wrap">
|
<n-form-item class="form-operation-wrap">
|
||||||
<d-button class="w-full" variant="solid" @click="login">登 录</d-button>
|
<n-button class="w-full" type="primary" @click="login">登 录</n-button>
|
||||||
</d-form-item>
|
</n-form-item>
|
||||||
</d-form>
|
</n-form>
|
||||||
</d-tab>
|
</n-tab-pane>
|
||||||
<d-tab id="tab2" title="注册">
|
<n-tab-pane name="tab2" tab="注册">
|
||||||
<d-form ref="formReg" layout="vertical" :data="regData" :rules="rrules">
|
<n-form ref="formReg" layout="vertical" :data="regData" :rules="rrules">
|
||||||
<d-form-item field="username">
|
<n-form-item field="username">
|
||||||
<d-input v-model="regData.username" placeholder="请输入用户名" />
|
<n-input v-model:value="regData.username" placeholder="请输入用户名" />
|
||||||
</d-form-item>
|
</n-form-item>
|
||||||
<d-form-item field="password">
|
<n-form-item field="password">
|
||||||
<d-input v-model="regData.password" show-password placeholder="请输入用密码" />
|
<n-input v-model:value="regData.password" type="password" show-password-on="click" placeholder="请输入用密码" />
|
||||||
</d-form-item>
|
</n-form-item>
|
||||||
<d-form-item field="nickname">
|
<n-form-item field="nickname">
|
||||||
<d-input v-model="regData.nickname" placeholder="请输入昵称" />
|
<n-input v-model:value="regData.nickname" placeholder="请输入昵称" />
|
||||||
</d-form-item>
|
</n-form-item>
|
||||||
<d-form-item class="form-operation-wrap">
|
<n-form-item class="form-operation-wrap">
|
||||||
<d-button class="w-full" variant="solid" @click="register">注册</d-button>
|
<n-button class="w-full" type="primary" @click="register">注册</n-button>
|
||||||
</d-form-item>
|
</n-form-item>
|
||||||
</d-form>
|
</n-form>
|
||||||
</d-tab>
|
</n-tab-pane>
|
||||||
</d-tabs>
|
</n-tabs>
|
||||||
</d-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const emit = defineEmits<{
|
const props = defineProps({
|
||||||
(e: 'update:visible', value: boolean): void
|
setVisible: {
|
||||||
}>()
|
type: Function,
|
||||||
|
default: () => { },
|
||||||
|
}
|
||||||
|
})
|
||||||
// 登录注册逻辑
|
// 登录注册逻辑
|
||||||
const tid = ref("tab1");
|
const tid = ref("tab1");
|
||||||
const formLogin: any = ref(null);
|
const formLogin: any = ref(null);
|
||||||
@ -77,8 +80,8 @@ const rrules: any = reactive({
|
|||||||
})
|
})
|
||||||
function login() {
|
function login() {
|
||||||
console.log('>>> --> login --> formLogin.value:', usrLog.isLogin)
|
console.log('>>> --> login --> formLogin.value:', usrLog.isLogin)
|
||||||
formLogin.value.validate(async (is: boolean, b: any) => {
|
formLogin.value?.validate(async (is: boolean) => {
|
||||||
if (!is) {
|
if (is) {
|
||||||
$msg.error('信息填写不正确,请检查后再提交')
|
$msg.error('信息填写不正确,请检查后再提交')
|
||||||
} else {
|
} else {
|
||||||
const res = await $http.user.login(loginData)
|
const res = await $http.user.login(loginData)
|
||||||
@ -90,15 +93,14 @@ function login() {
|
|||||||
$cookies.set('userinfo', res.data.userinfo, '1d')
|
$cookies.set('userinfo', res.data.userinfo, '1d')
|
||||||
$msg.success(res.msg)
|
$msg.success(res.msg)
|
||||||
usrLog.setIsLogin(true)
|
usrLog.setIsLogin(true)
|
||||||
// router.push({ path: "/" })
|
props.setVisible(false)
|
||||||
emit("update:visible",false)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
function register() {
|
function register() {
|
||||||
formReg.value.validate(async (is: boolean, b: any) => {
|
formReg.value.validate(async (is: boolean) => {
|
||||||
if (!is) {
|
if (is) {
|
||||||
$msg.error('信息填写不正确,请检查后再提交')
|
$msg.error('信息填写不正确,请检查后再提交')
|
||||||
} else {
|
} else {
|
||||||
const res = await $http.user.register(regData)
|
const res = await $http.user.register(regData)
|
||||||
@ -108,8 +110,10 @@ function register() {
|
|||||||
}
|
}
|
||||||
$msg.success(res.msg)
|
$msg.success(res.msg)
|
||||||
tid.value = 'tab1'
|
tid.value = 'tab1'
|
||||||
formReg.value.resetForm()
|
|
||||||
loginData.username = regData.username
|
loginData.username = regData.username
|
||||||
|
regData.username = ''
|
||||||
|
regData.nickname = ''
|
||||||
|
regData.password = ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pr-8">
|
<div class="pr-8">
|
||||||
<d-card shadow="never" class="mt-4 bg-white">
|
<n-card embedded class="mt-4 shadow">
|
||||||
<!-- <div class="dt-card mt-10 bg-white"> -->
|
<!-- <div class="dt-card mt-10 bg-white"> -->
|
||||||
<template #title>
|
<template #header>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<icon-time class="w-5 mr-2"></icon-time>
|
<icon-time class="w-5 mr-2"></icon-time>
|
||||||
时间日期
|
时间日期
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #default>
|
||||||
<div class="w-full pr-20 text-center text-[#ec66ab] font-500 text-4xl font-[yj]">{{ t }}</div>
|
<div class="w-full pr-20 text-center text-[#ec66ab] font-500 text-4xl font-[yj]">{{ t }}</div>
|
||||||
<div class="mt-3 flex justify-between">
|
<div class="mt-3 flex justify-between">
|
||||||
<span>今年已过了{{ jq.dayOfYear }}天</span>
|
<span>今年已过了{{ jq.dayOfYear }}天</span>
|
||||||
@ -18,19 +18,20 @@
|
|||||||
<img v-else class="absolute top-0 right-4" width="120" src="@/assets/images/onwork.png" alt="">
|
<img v-else class="absolute top-0 right-4" width="120" src="@/assets/images/onwork.png" alt="">
|
||||||
</template>
|
</template>
|
||||||
<!-- </div> -->
|
<!-- </div> -->
|
||||||
</d-card>
|
</n-card>
|
||||||
|
|
||||||
|
|
||||||
<d-card shadow="never" class="mt-4 bg-white">
|
<n-card embedded class="mt-4 shadow">
|
||||||
<template #title>
|
<template #header>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<icon-news class="w-5 mr-2"></icon-news>
|
<icon-news class="w-5 mr-2"></icon-news>
|
||||||
百度新闻
|
百度新闻
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #default>
|
||||||
<div class="py-1" v-for="i in bdNews" :key="i.id">
|
<div class="py-1" v-for="i in bdNews" :key="i.id">
|
||||||
<a class="devui-link flex justify-between truncate" :href="i.url" target="_blank">
|
<!-- 淡蓝色 -->
|
||||||
|
<a class="text-[#526ecc] no-underline hover:text-primary hover:underline flex justify-between truncate" :href="i.url" target="_blank">
|
||||||
<span class="flex items-center">{{ i.index }}. {{ i.title }}
|
<span class="flex items-center">{{ i.index }}. {{ i.title }}
|
||||||
<icon-hot v-show="i.index < 4" class="ml-2 w-4 text-[red] inline-block"></icon-hot>
|
<icon-hot v-show="i.index < 4" class="ml-2 w-4 text-[red] inline-block"></icon-hot>
|
||||||
</span>
|
</span>
|
||||||
@ -39,7 +40,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mt-2 justify-between flex items-center">
|
<div class="mt-2 justify-between flex items-center">
|
||||||
<div class="w-2/5 h-px bg-[#ec66ab]"></div>
|
<div class="w-2/5 h-px bg-[#ec66ab]"></div>
|
||||||
<a class="devui-link text-[#ec66ab] flex items-center" href="https://www.baidu.com/s?ie=utf-8&wd=百度新闻"
|
<a class="text-[#526ecc] no-underline text-[#ec66ab] flex items-center" href="https://www.baidu.com/s?ie=utf-8&wd=百度新闻"
|
||||||
target="_blank">
|
target="_blank">
|
||||||
更多
|
更多
|
||||||
<icon-right class="ml-1 w-4 text-primary inline-block"></icon-right>
|
<icon-right class="ml-1 w-4 text-primary inline-block"></icon-right>
|
||||||
@ -47,18 +48,18 @@
|
|||||||
<div class="w-2/5 h-px bg-[#ec66ab]"></div>
|
<div class="w-2/5 h-px bg-[#ec66ab]"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</d-card>
|
</n-card>
|
||||||
|
|
||||||
|
|
||||||
<d-card shadow="never" class="mt-4 bg-white">
|
<n-card embedded class="mt-4 shadow">
|
||||||
<template #title>
|
<template #header>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<icon-date class="w-5 mr-2"></icon-date>
|
<icon-date class="w-5 mr-2"></icon-date>
|
||||||
农历节气
|
农历节气
|
||||||
<div class="ml-12 text-[#ec66ab] font-500">{{ jq.yearTips }}年 {{ jq.lunarCalendar }}</div>
|
<div class="ml-12 text-[#ec66ab] font-500">{{ jq.yearTips }}年 {{ jq.lunarCalendar }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #default>
|
||||||
<div class="truncate text-sm mx-[5%]">
|
<div class="truncate text-sm mx-[5%]">
|
||||||
宜:{{ jq.suit }}
|
宜:{{ jq.suit }}
|
||||||
</div>
|
</div>
|
||||||
@ -70,7 +71,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mt-2 text-center">{{ jq.solarTerms }}</div>
|
<div class="mt-2 text-center">{{ jq.solarTerms }}</div>
|
||||||
</template>
|
</template>
|
||||||
</d-card>
|
</n-card>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -132,8 +133,14 @@ onUnmounted(() => {
|
|||||||
src: url('@/assets/font/LCDML.woff2');
|
src: url('@/assets/font/LCDML.woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
:deep(.n-card > .n-card__content, .n-card > .n-card__footer){
|
||||||
|
padding: 8px 25px !important;
|
||||||
|
}
|
||||||
|
|
||||||
// .dt-card {
|
// .dt-card {
|
||||||
// background-image: url('@/assets/images/中秋节中国风边框34.png');
|
// background-image: url('@/assets/images/中秋节中国风边框34.png');
|
||||||
// background-size: 100% 100%;
|
// background-size: 100% 100%;
|
||||||
// padding: 20px 40px;
|
// padding: 20px 40px;
|
||||||
// }</style>
|
// }
|
||||||
|
</style>
|
||||||
35
src/components/mask.vue
Normal file
35
src/components/mask.vue
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<template>
|
||||||
|
<Teleport to="body">
|
||||||
|
<div v-if="visible"
|
||||||
|
class="fixed top-0 left-0 z-[1000] w-[100vw] h-[100vh] flex items-center justify-center bg-[rgba(0,0,0,0.5)]">
|
||||||
|
<slot></slot>
|
||||||
|
<div @click.prevent="handdleClose" class="absolute w-8 h-8 top-4 right-4 rounded-full bg-white flex items-center justify-center text-[#ec66ab] cursor-pointer">X</div>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
//mark import
|
||||||
|
|
||||||
|
//mark data
|
||||||
|
const props = defineProps({
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
setVisible: {
|
||||||
|
type: Function,
|
||||||
|
default: () => { },
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//mark method
|
||||||
|
function handdleClose() {
|
||||||
|
props.setVisible(false)
|
||||||
|
}
|
||||||
|
//mark 周期、内置函数等
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
@ -5,36 +5,15 @@
|
|||||||
<img :src="logo" alt="柚子的网站" class="h-9 align-middle" />
|
<img :src="logo" alt="柚子的网站" class="h-9 align-middle" />
|
||||||
</div>
|
</div>
|
||||||
<!-- 主导航菜单 -->
|
<!-- 主导航菜单 -->
|
||||||
<d-menu mode="horizontal" router class="ml-5 h-14 text-[16px] " :default-select-keys="[key]">
|
<div>
|
||||||
<d-menu-item key="home">
|
<n-menu :icon-size="12" v-model:value="activeKey" class="" mode="horizontal" :options="menuOptions" />
|
||||||
<d-icon :component="homeSvg" class="w-5 mr-1"></d-icon>
|
</div>
|
||||||
首页
|
|
||||||
</d-menu-item>
|
|
||||||
<d-menu-item key="gallery">
|
|
||||||
<d-icon :component="picSvg" class="w-5 mr-1"></d-icon>
|
|
||||||
画廊
|
|
||||||
</d-menu-item>
|
|
||||||
<d-menu-item key="article">
|
|
||||||
<d-icon :component="artiSvg" class="w-5 mr-1 "></d-icon>
|
|
||||||
文章
|
|
||||||
</d-menu-item>
|
|
||||||
<d-menu-item key="widget">
|
|
||||||
<d-icon :component="settingSvg" class="w-5 mr-1 "></d-icon>
|
|
||||||
工具
|
|
||||||
</d-menu-item>
|
|
||||||
<d-menu-item key="appshare">
|
|
||||||
<d-icon :component="downSvg" class="w-5 mr-1 "></d-icon>
|
|
||||||
软件分享
|
|
||||||
</d-menu-item>
|
|
||||||
<d-menu-item key="plink">
|
|
||||||
<d-icon :component="linkSvg" class="w-5 mr-1 "></d-icon>
|
|
||||||
友链
|
|
||||||
</d-menu-item>
|
|
||||||
</d-menu>
|
|
||||||
<!-- 用户区域 -->
|
<!-- 用户区域 -->
|
||||||
<div class="!text-[#ec66ab] flex items-center" @click="gotoHf">
|
<div class="!text-[#ec66ab] flex items-center" @click="gotoHf">
|
||||||
<span class="flex items-center location-info truncate">
|
<span class="flex items-center location-info truncate">
|
||||||
<d-icon color="#ec66ab" class="mr-1" name="location-new"></d-icon>
|
<n-icon class="mr-1">
|
||||||
|
<icon-loc class="w-[26px] h-[26px]"></icon-loc>
|
||||||
|
</n-icon>
|
||||||
{{ locationInfo }}
|
{{ locationInfo }}
|
||||||
</span>
|
</span>
|
||||||
<span class="mx-3 text-gray-300">|</span>
|
<span class="mx-3 text-gray-300">|</span>
|
||||||
@ -44,47 +23,35 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center mr-8">
|
<div class="flex items-center mr-8">
|
||||||
<d-dropdown class="cursor-pointer w-[100px]" v-if="userinfo" trigger="hover">
|
<n-dropdown class="cursor-pointer w-[100px]" v-if="userinfo" :options="oprOp" @select="handleSelect"
|
||||||
|
trigger="hover">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<d-avatar :img-src="userinfo.ava_url" class="cursor-pointer" alt="用户的头" />
|
<n-avatar round :src="userinfo.ava_url" class="cursor-pointer" alt="用户的头" />
|
||||||
<div class="cursor-pointer ml-2 text-gray text-sm">{{ userinfo.nickname }}</div>
|
<div class="cursor-pointer ml-2 text-gray text-sm">{{ userinfo.nickname }}</div>
|
||||||
</div>
|
</div>
|
||||||
<template #menu>
|
</n-dropdown>
|
||||||
<ul class="list-menu">
|
<div v-else class="flex items-center" @click="toLogin">
|
||||||
<!-- hover为淡粉色 -->
|
<n-avatar round class="cursor-pointer"></n-avatar>
|
||||||
<li class="w-full p-2 text-center hover:text-primary hover:bg-[#f5f0f0] cursor-pointer" @click="logout">
|
<div class="cursor-pointer ml-2 text-gray text-sm" >登录</div>
|
||||||
登出
|
|
||||||
</li>
|
|
||||||
<li class="w-full p-2 text-center hover:text-primary hover:bg-[#f5f0f0] cursor-pointer" @click="">
|
|
||||||
控制台
|
|
||||||
</li>
|
|
||||||
<li class="w-full p-2 text-center hover:text-primary hover:bg-[#f5f0f0] cursor-pointer" @click="">
|
|
||||||
设置
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</template>
|
|
||||||
</d-dropdown>
|
|
||||||
<div v-else class="flex items-center">
|
|
||||||
<d-avatar class="cursor-pointer" @click="toLogin"></d-avatar>
|
|
||||||
<div class="cursor-pointer ml-2 text-gray text-sm" @click="toLogin">登录</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 登录弹窗 -->
|
<!-- 登录弹窗 -->
|
||||||
<d-modal class="!w-120" v-model="visible">
|
<masked :visible="visible" :setVisible="setVisible">
|
||||||
<login-modal v-model:visible="visible"></login-modal>
|
<loginModal :setVisible="setVisible" />
|
||||||
</d-modal>
|
</masked>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between bg-white lg:hidden">
|
<div class="flex justify-between bg-white lg:hidden">
|
||||||
<div class="pl-2 items-centerflex" slot="brand" @click="">
|
<div class="pl-2 items-centerflex" slot="brand" @click="">
|
||||||
<img :src="logo" alt="柚子的网站" class="h-9 align-middle" />
|
<img :src="logo" alt="柚子的网站" class="h-9 align-middle" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center mr-2">
|
<div class="flex items-center mr-2">
|
||||||
<div v-if="userinfo" class="flex items-center">
|
<div v-if="userinfo" class="flex items-center">
|
||||||
<d-avatar :img-src="userinfo.ava_url" class="cursor-pointer" alt="用户的头" />
|
<n-avatar :src="userinfo.ava_url" round class="cursor-pointer" alt="用户的头" />
|
||||||
<div class="cursor-pointer ml-2 text-gray text-sm">{{ userinfo.nickname }}</div>
|
<div class="cursor-pointer ml-2 text-gray text-sm">{{ userinfo.nickname }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="flex items-center">
|
<div v-else class="flex items-center">
|
||||||
<d-avatar class="cursor-pointer" @click="toLogin"></d-avatar>
|
<n-avatar round class="cursor-pointer" @click="toLogin"></n-avatar>
|
||||||
<div class="cursor-pointer ml-2 text-gray text-sm" @click="toLogin">登录</div>
|
<div class="cursor-pointer ml-2 text-gray text-sm" @click="toLogin">登录</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -101,16 +68,16 @@ import linkSvg from '@/icon/menu/link.svg';
|
|||||||
import picSvg from '@/icon/menu/pic.svg';
|
import picSvg from '@/icon/menu/pic.svg';
|
||||||
import settingSvg from '@/icon/menu/setting.svg';
|
import settingSvg from '@/icon/menu/setting.svg';
|
||||||
import loginModal from '@/components/Login.vue'
|
import loginModal from '@/components/Login.vue'
|
||||||
|
import masked from '@/components/mask.vue'
|
||||||
|
|
||||||
|
|
||||||
import { onMounted, ref, watch } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter, RouterLink } from 'vue-router';
|
||||||
|
|
||||||
|
|
||||||
|
const activeKey = ref('home')
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const key = ref("home");
|
|
||||||
const locationInfo = ref("获取位置中...");
|
const locationInfo = ref("获取位置中...");
|
||||||
const latitude = ref<number | null>(null);
|
const latitude = ref<number | null>(null);
|
||||||
const longitude = ref<number | null>(null);
|
const longitude = ref<number | null>(null);
|
||||||
@ -122,7 +89,69 @@ const userinfo: any = ref(null)
|
|||||||
const nav: any = useTemplateRef('nav')
|
const nav: any = useTemplateRef('nav')
|
||||||
const navx = $store.nav.useNavStore()
|
const navx = $store.nav.useNavStore()
|
||||||
const usrLog = $store.log.useLogStore()
|
const usrLog = $store.log.useLogStore()
|
||||||
console.log('>>> --> route:', route)
|
const menuOptions = ref([
|
||||||
|
{
|
||||||
|
label: () => h(RouterLink, { to: '/home', class: 'flex items-center justify-center' }, { default: () => '首页' }),
|
||||||
|
key: "home",
|
||||||
|
icon: () => h(homeSvg)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () => h(RouterLink, { to: '/gallery', class: 'flex items-center justify-center' }, { default: () => '画廊管理' }),
|
||||||
|
key: "gallery",
|
||||||
|
icon: () => h(picSvg)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () => h(RouterLink, { to: '/blog', class: 'flex items-center justify-center' }, { default: () => '文章管理' }),
|
||||||
|
key: "blog",
|
||||||
|
icon: () => h(artiSvg)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () => h(RouterLink, { to: '/widget', class: 'flex items-center justify-center' }, { default: () => '工具管理' }),
|
||||||
|
key: "widget",
|
||||||
|
icon: () => h(downSvg)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () => h(RouterLink, { to: '/apps', class: 'flex items-center justify-center' }, { default: () => '软件管理' }),
|
||||||
|
key: "apps",
|
||||||
|
icon: () => h(settingSvg)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () => h(RouterLink, { to: '/plink', class: 'flex items-center justify-center' }, { default: () => '友链管理' }),
|
||||||
|
key: "plink",
|
||||||
|
icon: () => h(linkSvg)
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const oprOp = ref([
|
||||||
|
{
|
||||||
|
key: 'logout',
|
||||||
|
label: '退出登录',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'console',
|
||||||
|
label: '控制台',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'setting',
|
||||||
|
label: '设置',
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
function setVisible(v: any) {
|
||||||
|
visible.value = v
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSelect(key: string) {
|
||||||
|
console.log('>>> --> handleSelect --> key:', key)
|
||||||
|
if (key == 'logout') {
|
||||||
|
logout()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (key == 'console') {
|
||||||
|
router.push('/console')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 获取地理位置
|
// 获取地理位置
|
||||||
const getLocation = () => {
|
const getLocation = () => {
|
||||||
if (!navigator.geolocation) {
|
if (!navigator.geolocation) {
|
||||||
@ -198,7 +227,7 @@ async function handdleJw(jw: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
watch(() => route.name, (newVal) => {
|
watch(() => route.name, (newVal) => {
|
||||||
key.value = newVal as string
|
activeKey.value = newVal as string
|
||||||
})
|
})
|
||||||
|
|
||||||
function goHome() {
|
function goHome() {
|
||||||
@ -220,6 +249,9 @@ function logout() {
|
|||||||
usrLog.setIsLogin(false)
|
usrLog.setIsLogin(false)
|
||||||
userinfo.value = null;
|
userinfo.value = null;
|
||||||
}
|
}
|
||||||
|
function gotoConsole() {
|
||||||
|
window.open("https://www.hxyouzi.com/console/home", "_BLACK")
|
||||||
|
}
|
||||||
|
|
||||||
function gotoHf() {
|
function gotoHf() {
|
||||||
console.log('>>> --> gotoHf --> fxlink:', fxlink)
|
console.log('>>> --> gotoHf --> fxlink:', fxlink)
|
||||||
@ -230,7 +262,10 @@ onMounted(() => {
|
|||||||
|
|
||||||
userinfo.value = $cookies.get('userinfo');
|
userinfo.value = $cookies.get('userinfo');
|
||||||
console.log('>>>>>>>>>>', userinfo.value);
|
console.log('>>>>>>>>>>', userinfo.value);
|
||||||
key.value = route.name as string;
|
setTimeout(() => {
|
||||||
|
console.log('>>>>>>>>>>', route)
|
||||||
|
activeKey.value = route.name as string;
|
||||||
|
}, 20);
|
||||||
console.log('>>> --> route.name:', route.name)
|
console.log('>>> --> route.name:', route.name)
|
||||||
getLocation(); // 组件挂载时获取位置
|
getLocation(); // 组件挂载时获取位置
|
||||||
|
|
||||||
@ -242,7 +277,7 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
onBeforeUpdate(() => {
|
onBeforeUpdate(() => {
|
||||||
userinfo.value = $cookies.get('userinfo');
|
userinfo.value = $cookies.get('userinfo');
|
||||||
key.value = route.name as string;
|
activeKey.value = route.name as string;
|
||||||
const h: number = nav.value.clientHeight
|
const h: number = nav.value.clientHeight
|
||||||
// console.log('******>>> --> nav.value:', nav.value)
|
// console.log('******>>> --> nav.value:', nav.value)
|
||||||
// console.log('()()()()()>>> --> h:', h)
|
// console.log('()()()()()>>> --> h:', h)
|
||||||
@ -257,32 +292,10 @@ onBeforeUpdate(() => {
|
|||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.devui-menu-horizontal .devui-menu-item:hover span .icon) {
|
:deep(.n-menu-item-content__icon) {
|
||||||
color: var(--devui-brand, #5e7ce0) !important;
|
width: 16px !important;
|
||||||
fill: var(--devui-brand, #5e7ce0) !important;
|
height: 16px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.devui-menu-item-select span svg) {
|
|
||||||
color: var(--devui-brand, #5e7ce0) !important;
|
|
||||||
fill: var(--devui-brand, #5e7ce0) !important;
|
|
||||||
line-height: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.devui-menu-item-select span) {
|
|
||||||
color: var(--devui-brand, #5e7ce0) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.devui-menu-horizontal) {
|
|
||||||
padding: 14px 20px 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.devui-menu-item span) {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.devui-icon__container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
@ -1,5 +0,0 @@
|
|||||||
import { Message } from 'vue-devui';
|
|
||||||
|
|
||||||
const msg:any = Message;
|
|
||||||
|
|
||||||
export default msg;
|
|
||||||
1
src/icon/loc.svg
Normal file
1
src/icon/loc.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1766884807799" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10346" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M774.826667 365.226667c0 117.76-194.56 392.533333-245.76 464.213333-6.826667 8.533333-18.773333 8.533333-25.6 0C450.56 757.76 256 482.986667 256 365.226667 256 230.4 372.053333 119.466667 515.413333 119.466667s259.413333 110.933333 259.413334 245.76z" fill="#ec66ab" p-id="10347"></path><path d="M208.213333 841.386667a307.2 76.8 0 1 0 614.4 0 307.2 76.8 0 1 0-614.4 0Z" fill="#ec66ab" opacity=".5" p-id="10348"></path></svg>
|
||||||
|
After Width: | Height: | Size: 759 B |
1
src/icon/search.svg
Normal file
1
src/icon/search.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1766900628434" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11570" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M0 512a512 512 0 1 0 1024 0 512 512 0 1 0-1024 0Z" fill="#F2ECFF" p-id="11571"></path><path d="M801.723733 695.330133l-273.066666-238.933333a51.2 51.2 0 1 0-67.447467 77.073067l273.066667 238.933333a51.2 51.2 0 0 0 67.447466-77.073067z" fill="#DBBBFF" p-id="11572"></path><path d="M238.933333 494.933333a256 256 0 1 0 512 0 256 256 0 1 0-512 0Z" fill="#BC86F9" p-id="11573"></path><path d="M494.933333 315.733333q74.24 0 126.702934 52.497067 52.497067 52.462933 52.497066 126.702933 0 2.525867-0.477866 4.983467-0.512 2.491733-1.467734 4.8128-0.955733 2.321067-2.389333 4.437333-1.365333 2.082133-3.1744 3.857067-1.774933 1.809067-3.857067 3.208533-2.116267 1.365333-4.437333 2.3552-2.321067 0.955733-4.778667 1.467734-2.491733 0.477867-5.0176 0.477866t-4.983466-0.477866q-2.491733-0.512-4.8128-1.467734-2.321067-0.955733-4.437334-2.389333-2.082133-1.365333-3.857066-3.1744-1.809067-1.774933-3.208534-3.857067-1.365333-2.116267-2.3552-4.437333-0.955733-2.321067-1.467733-4.778667-0.477867-2.491733-0.477867-5.0176 0-53.009067-37.4784-90.5216-37.512533-37.4784-90.5216-37.4784-2.525867 0-4.983466-0.477866-2.491733-0.512-4.8128-1.467734-2.321067-0.955733-4.437334-2.389333-2.082133-1.365333-3.857066-3.1744-1.809067-1.774933-3.208534-3.857067-1.365333-2.116267-2.3552-4.437333-0.955733-2.321067-1.467733-4.778667-0.477867-2.491733-0.477867-5.0176t0.477867-4.983466q0.512-2.491733 1.467733-4.8128 0.955733-2.321067 2.389334-4.437334 1.365333-2.082133 3.1744-3.857066 1.774933-1.809067 3.857066-3.208534 2.116267-1.365333 4.437334-2.3552 2.321067-0.955733 4.778666-1.467733 2.491733-0.477867 5.0176-0.477867z" fill="#FFFFFF" p-id="11574"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
BIN
src/lib/assets/loadError.png
Normal file
BIN
src/lib/assets/loadError.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 680 B |
BIN
src/lib/assets/loading.gif
Normal file
BIN
src/lib/assets/loading.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 284 KiB |
183
src/lib/components/LazyImg.vue
Normal file
183
src/lib/components/LazyImg.vue
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
<template>
|
||||||
|
<div class="lazy__box">
|
||||||
|
<div class="lazy__resource">
|
||||||
|
<div class="image-container">
|
||||||
|
<el-image
|
||||||
|
ref="lazyRef"
|
||||||
|
class="lazy__img"
|
||||||
|
:src="url"
|
||||||
|
:preview-src-list="previewSrcList.length > 0 ? previewSrcList : []"
|
||||||
|
fit="contain"
|
||||||
|
:preview-teleported="true"
|
||||||
|
:initial-index="0"
|
||||||
|
:hide-on-click-modal="hideOnClickModal"
|
||||||
|
@load="handleLoad"
|
||||||
|
@error="handleError"
|
||||||
|
>
|
||||||
|
<template #placeholder>
|
||||||
|
<img :src="loading" alt="loading" />
|
||||||
|
</template>
|
||||||
|
<template #error>
|
||||||
|
<img :src="errorImg" alt="error" />
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
<div
|
||||||
|
class="overlay"
|
||||||
|
v-if="previewSrcList.length > 0 && previewIcon"
|
||||||
|
@click="hanldeShowPreview"
|
||||||
|
>
|
||||||
|
<div class="preview-icon">
|
||||||
|
<img :src="previewIcon" alt="preview" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ElImage } from "element-plus";
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import { inject, onMounted, ref, toRefs } from "vue";
|
||||||
|
import loadError from "../assets/loadError.png";
|
||||||
|
import loadingImg from "../assets/loading.gif";
|
||||||
|
import type { Nullable } from "../types/util";
|
||||||
|
const props = defineProps({
|
||||||
|
previewIcon: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: String,
|
||||||
|
default: loadingImg,
|
||||||
|
},
|
||||||
|
errorImg: {
|
||||||
|
type: String,
|
||||||
|
default: loadError,
|
||||||
|
},
|
||||||
|
previewSrcList: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
hideOnClickModal: {
|
||||||
|
// 是否可以通过点击遮罩层关闭预览
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const { url, loading, errorImg, previewSrcList } = toRefs(props);
|
||||||
|
|
||||||
|
const imgLoaded = inject("imgLoaded") as () => void;
|
||||||
|
const lazyRef = ref<Nullable<InstanceType<typeof ElImage>>>(null);
|
||||||
|
|
||||||
|
const handleLoad = () => {
|
||||||
|
imgLoaded();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleError = () => {
|
||||||
|
// 可以在这里添加错误处理逻辑
|
||||||
|
};
|
||||||
|
// 显示预览
|
||||||
|
const hanldeShowPreview = () => {
|
||||||
|
if (lazyRef.value) {
|
||||||
|
lazyRef.value.showPreview();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
onMounted(() => {
|
||||||
|
if (lazyRef.value) {
|
||||||
|
imgLoaded();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.lazy__box {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lazy__resource {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lazy__img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-image) {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-image__inner) {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lazy__img img[alt="loading"],
|
||||||
|
.lazy__img img[alt="error"] {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
padding: 1em;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container:hover .overlay {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-icon {
|
||||||
|
color: white;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-image__placeholder),
|
||||||
|
:deep(.el-image__error) {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-image__placeholder) img,
|
||||||
|
:deep(.el-image__error) img {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
208
src/lib/components/Waterfall.vue
Normal file
208
src/lib/components/Waterfall.vue
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
ref="waterfallWrapper"
|
||||||
|
class="waterfall-list"
|
||||||
|
:style="{ height: `${wrapperHeight}px` }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in list"
|
||||||
|
:key="getKey(item, index)"
|
||||||
|
class="waterfall-item"
|
||||||
|
>
|
||||||
|
<div class="waterfall-card">
|
||||||
|
<slot
|
||||||
|
name="item"
|
||||||
|
:item="item"
|
||||||
|
:index="index"
|
||||||
|
:url="getRenderURL(item)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import { provide, ref, watch } from "vue";
|
||||||
|
import { useDebounceFn } from "@vueuse/core";
|
||||||
|
import { useCalculateCols, useLayout } from "../use";
|
||||||
|
import Lazy from "../utils/Lazy";
|
||||||
|
import { getValue } from "../utils/util";
|
||||||
|
import type { ViewCard } from "../types/waterfall";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
list: {
|
||||||
|
type: Array as PropType<any[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
rowKey: {
|
||||||
|
type: String,
|
||||||
|
default: "id",
|
||||||
|
},
|
||||||
|
imgSelector: {
|
||||||
|
type: String,
|
||||||
|
default: "src",
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 200,
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
type: Number,
|
||||||
|
default: 3,
|
||||||
|
},
|
||||||
|
gutter: {
|
||||||
|
type: Number,
|
||||||
|
default: 10,
|
||||||
|
},
|
||||||
|
hasAroundGutter: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
animationPrefix: {
|
||||||
|
type: String,
|
||||||
|
default: "animate__animated",
|
||||||
|
},
|
||||||
|
animationEffect: {
|
||||||
|
type: String,
|
||||||
|
default: "fadeIn",
|
||||||
|
},
|
||||||
|
animationDuration: {
|
||||||
|
type: Number,
|
||||||
|
default: 1000,
|
||||||
|
},
|
||||||
|
animationDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: 300,
|
||||||
|
},
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: "#fff",
|
||||||
|
},
|
||||||
|
lazyload: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
loadProps: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
crossOrigin: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
delay: {
|
||||||
|
type: Number,
|
||||||
|
default: 300,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const lazy = new Lazy(props.lazyload, props.loadProps, props.crossOrigin);
|
||||||
|
provide("lazy", lazy);
|
||||||
|
|
||||||
|
// 容器块信息
|
||||||
|
const { waterfallWrapper, wrapperWidth, colWidth, cols, offsetX } =
|
||||||
|
useCalculateCols(props);
|
||||||
|
|
||||||
|
// 容器高度,块定位
|
||||||
|
const { wrapperHeight, layoutHandle } = useLayout(
|
||||||
|
props,
|
||||||
|
colWidth,
|
||||||
|
cols,
|
||||||
|
offsetX,
|
||||||
|
waterfallWrapper
|
||||||
|
);
|
||||||
|
|
||||||
|
// 1s内最多执行一次排版,减少性能开销
|
||||||
|
const renderer = useDebounceFn(() => {
|
||||||
|
layoutHandle();
|
||||||
|
// console.log("强制更新排版");
|
||||||
|
}, props.delay);
|
||||||
|
|
||||||
|
// 列表发生变化直接触发排版
|
||||||
|
watch(
|
||||||
|
() => [wrapperWidth, colWidth, props.list],
|
||||||
|
() => {
|
||||||
|
renderer();
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
// 尺寸宽度变化防抖触发
|
||||||
|
const sizeChangeTime = ref(0);
|
||||||
|
|
||||||
|
provide("sizeChangeTime", sizeChangeTime);
|
||||||
|
|
||||||
|
// 图片加载完成
|
||||||
|
provide("imgLoaded", renderer);
|
||||||
|
|
||||||
|
// 根据选择器获取图片地址
|
||||||
|
const getRenderURL = (item: ViewCard): string => {
|
||||||
|
return getValue(item, props.imgSelector)[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取唯一值
|
||||||
|
const getKey = (item: ViewCard, index: number): string => {
|
||||||
|
return item[props.rowKey] || index;
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearAndReload = () => {
|
||||||
|
const originalList = [...props.list];
|
||||||
|
props.list.length = 0;
|
||||||
|
setTimeout(() => {
|
||||||
|
props.list.push(...originalList);
|
||||||
|
renderer();
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
waterfallWrapper,
|
||||||
|
wrapperHeight,
|
||||||
|
getRenderURL,
|
||||||
|
getKey,
|
||||||
|
list: props.list,
|
||||||
|
backgroundColor: props.backgroundColor,
|
||||||
|
renderer,
|
||||||
|
clearAndReload,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.waterfall-list {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: v-bind(backgroundColor);
|
||||||
|
}
|
||||||
|
.waterfall-item {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
/* transition: .3s; */
|
||||||
|
/* 初始位置设置到屏幕以外,避免懒加载失败 */
|
||||||
|
transform: translate3d(0, 3000px, 0);
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 初始的入场效果 */
|
||||||
|
@-webkit-keyframes fadeIn {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes fadeIn {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.fadeIn {
|
||||||
|
-webkit-animation-name: fadeIn;
|
||||||
|
animation-name: fadeIn;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
3
src/lib/index.ts
Normal file
3
src/lib/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import Waterfall from './components/Waterfall.vue'
|
||||||
|
import LazyImg from './components/LazyImg.vue'
|
||||||
|
export { Waterfall, LazyImg }
|
||||||
4
src/lib/types/images.d.ts
vendored
Normal file
4
src/lib/types/images.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
declare module "*.gif" {
|
||||||
|
const value: string;
|
||||||
|
export default value;
|
||||||
|
}
|
||||||
13
src/lib/types/jsx.d.ts
vendored
Normal file
13
src/lib/types/jsx.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { VNode } from "vue";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace JSX {
|
||||||
|
interface Element extends VNode {}
|
||||||
|
interface ElementClass {
|
||||||
|
$props: {};
|
||||||
|
}
|
||||||
|
interface IntrinsicElements {
|
||||||
|
[elem: string]: any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
77
src/lib/types/lazy.d.ts
vendored
Normal file
77
src/lib/types/lazy.d.ts
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
export interface LazyOptions {
|
||||||
|
error?: string;
|
||||||
|
loading?: string;
|
||||||
|
observerOptions?: IntersectionObserverInit;
|
||||||
|
log?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ValueFormatterObject {
|
||||||
|
src: string;
|
||||||
|
error?: string;
|
||||||
|
loading?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Lazy {
|
||||||
|
lazyActive: boolean;
|
||||||
|
options: LazyOptions;
|
||||||
|
|
||||||
|
_images = new WeakMap();
|
||||||
|
|
||||||
|
constructor(flag = true, options: LazyOptions);
|
||||||
|
|
||||||
|
config(options = {}): void;
|
||||||
|
|
||||||
|
// mount
|
||||||
|
mount(
|
||||||
|
el: HTMLImageElement,
|
||||||
|
binding: string | ValueFormatterObject,
|
||||||
|
callback: () => void
|
||||||
|
): void;
|
||||||
|
|
||||||
|
// unmount
|
||||||
|
unmount(el: HTMLElement): void;
|
||||||
|
|
||||||
|
resize(el: HTMLElement, callback: () => void): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置img的src
|
||||||
|
* @param {*} el - img
|
||||||
|
* @param {*} src - 原图
|
||||||
|
* @param {*} error - 错误图片
|
||||||
|
* @param {*} callback - 完成的回调函数,通知组件刷新布局
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
_setImageSrc(
|
||||||
|
el: HTMLImageElement,
|
||||||
|
src: string,
|
||||||
|
callback: () => void,
|
||||||
|
error?: string
|
||||||
|
): void;
|
||||||
|
|
||||||
|
_isOpenLazy(): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加img和对应的observer到weakMap中
|
||||||
|
* 开启监听
|
||||||
|
* 当出现在可视区域后取消监听
|
||||||
|
* @param {*} el - img
|
||||||
|
* @param {*} src - 图片
|
||||||
|
* @param {*} error - 错误图片
|
||||||
|
* @param {*} callback - 完成的回调函数,通知组件刷新布局
|
||||||
|
*/
|
||||||
|
_initIntersectionObserver(
|
||||||
|
el: HTMLImageElement,
|
||||||
|
src: string,
|
||||||
|
callback: () => void,
|
||||||
|
error?: string
|
||||||
|
): void;
|
||||||
|
|
||||||
|
// 格式化参数
|
||||||
|
_valueFormatter(value: ValueFormatterObject | string): ValueFormatterObject;
|
||||||
|
|
||||||
|
// 日志
|
||||||
|
_log(callback: () => void): void;
|
||||||
|
|
||||||
|
// 在map中获取对应img的observer事件
|
||||||
|
_realObserver(el: HTMLElement): IntersectionObserver | undefined;
|
||||||
|
}
|
||||||
4
src/lib/types/shims-vue.d.ts
vendored
Normal file
4
src/lib/types/shims-vue.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
declare module "*.png" {
|
||||||
|
const src: string;
|
||||||
|
export default src;
|
||||||
|
}
|
||||||
3
src/lib/types/util.d.ts
vendored
Normal file
3
src/lib/types/util.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export type Nullable<T> = T | null
|
||||||
|
|
||||||
|
export type CssStyleObject = Partial<CSSStyleDeclaration> & Record<string, string | null>
|
||||||
34
src/lib/types/waterfall.d.ts
vendored
Normal file
34
src/lib/types/waterfall.d.ts
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
export interface ViewCard {
|
||||||
|
src?: any;
|
||||||
|
id?: string;
|
||||||
|
name?: string;
|
||||||
|
star?: boolean;
|
||||||
|
backgroundColor?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WaterfallProps {
|
||||||
|
columns: number;
|
||||||
|
width: number;
|
||||||
|
animationDuration: number;
|
||||||
|
animationDelay: number;
|
||||||
|
animationEffect: string;
|
||||||
|
hasAroundGutter: boolean;
|
||||||
|
gutter: number;
|
||||||
|
list: ViewCard[];
|
||||||
|
animationPrefix: string;
|
||||||
|
backgroundColor: string;
|
||||||
|
lazyload: boolean;
|
||||||
|
loadProps: Record<string, any>;
|
||||||
|
crossOrigin: boolean;
|
||||||
|
delay: number;
|
||||||
|
rowKey: string;
|
||||||
|
imgSelector: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ItemWidthProps {
|
||||||
|
wrapperWidth: number;
|
||||||
|
gutter: number;
|
||||||
|
hasAroundGutter: boolean;
|
||||||
|
columns: number;
|
||||||
|
}
|
||||||
3
src/lib/use/index.ts
Normal file
3
src/lib/use/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
export { useCalculateCols } from './useCalculateCols'
|
||||||
|
export { useLayout } from './useLayout'
|
||||||
46
src/lib/use/useCalculateCols.ts
Normal file
46
src/lib/use/useCalculateCols.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { computed, ref } from "vue";
|
||||||
|
import { useResizeObserver } from "@vueuse/core";
|
||||||
|
import { getItemWidth } from "../utils/itemWidth";
|
||||||
|
import type { WaterfallProps } from "../types/waterfall";
|
||||||
|
import type { Nullable } from "../types/util";
|
||||||
|
|
||||||
|
export function useCalculateCols(props: WaterfallProps) {
|
||||||
|
const wrapperWidth = ref<number>(0);
|
||||||
|
const waterfallWrapper = ref<Nullable<HTMLElement>>(null);
|
||||||
|
|
||||||
|
useResizeObserver(waterfallWrapper, (entries) => {
|
||||||
|
const entry = entries[0];
|
||||||
|
const { width } = entry.contentRect;
|
||||||
|
if (width === 0) return;
|
||||||
|
wrapperWidth.value = width;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 列实际宽度
|
||||||
|
const colWidth = computed(() => {
|
||||||
|
return getItemWidth({
|
||||||
|
wrapperWidth: wrapperWidth.value,
|
||||||
|
gutter: props.gutter,
|
||||||
|
hasAroundGutter: props.hasAroundGutter,
|
||||||
|
columns: props.columns,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 列
|
||||||
|
const cols = computed(() => props.columns);
|
||||||
|
|
||||||
|
// 偏移
|
||||||
|
const offsetX = computed(() => {
|
||||||
|
const offset = props.hasAroundGutter ? props.gutter : -props.gutter;
|
||||||
|
const contextWidth =
|
||||||
|
cols.value * (colWidth.value + props.gutter) + offset;
|
||||||
|
return (wrapperWidth.value - contextWidth) / 2;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
waterfallWrapper,
|
||||||
|
wrapperWidth,
|
||||||
|
colWidth,
|
||||||
|
cols,
|
||||||
|
offsetX,
|
||||||
|
};
|
||||||
|
}
|
||||||
118
src/lib/use/useLayout.ts
Normal file
118
src/lib/use/useLayout.ts
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import type { Ref } from "vue";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { addClass, hasClass, prefixStyle } from "../utils/dom";
|
||||||
|
import type { WaterfallProps } from "../types/waterfall";
|
||||||
|
import type { CssStyleObject, Nullable } from "../types/util";
|
||||||
|
|
||||||
|
const transform = prefixStyle("transform");
|
||||||
|
const duration = prefixStyle("animation-duration");
|
||||||
|
const delay = prefixStyle("animation-delay");
|
||||||
|
const transition = prefixStyle("transition");
|
||||||
|
const fillMode = prefixStyle("animation-fill-mode");
|
||||||
|
|
||||||
|
export function useLayout(
|
||||||
|
props: WaterfallProps,
|
||||||
|
colWidth: Ref<number>,
|
||||||
|
cols: Ref<number>,
|
||||||
|
offsetX: Ref<number>,
|
||||||
|
waterfallWrapper: Ref<Nullable<HTMLElement>>
|
||||||
|
) {
|
||||||
|
const posY = ref<number[]>([]);
|
||||||
|
const wrapperHeight = ref(0);
|
||||||
|
|
||||||
|
// 获取对应y下标的x的值
|
||||||
|
const getX = (index: number): number => {
|
||||||
|
const count = props.hasAroundGutter ? index + 1 : index;
|
||||||
|
return props.gutter * count + colWidth.value * index + offsetX.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始y
|
||||||
|
const initY = (): void => {
|
||||||
|
posY.value = new Array(cols.value).fill(
|
||||||
|
props.hasAroundGutter ? props.gutter : 0
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加入场动画
|
||||||
|
const animation = addAnimation(props);
|
||||||
|
|
||||||
|
// 排版
|
||||||
|
const layoutHandle = async () => {
|
||||||
|
// 初始化y集合
|
||||||
|
initY();
|
||||||
|
|
||||||
|
// 构造列表
|
||||||
|
const items: HTMLElement[] = [];
|
||||||
|
if (waterfallWrapper && waterfallWrapper.value) {
|
||||||
|
waterfallWrapper.value.childNodes.forEach((el: any) => {
|
||||||
|
if (el!.className === "waterfall-item") items.push(el);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取节点
|
||||||
|
if (items.length === 0) return false;
|
||||||
|
|
||||||
|
// 遍历节点
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
const curItem = items[i] as HTMLElement;
|
||||||
|
// 最小的y值
|
||||||
|
const minY = Math.min.apply(null, posY.value);
|
||||||
|
// 最小y的下标
|
||||||
|
const minYIndex = posY.value.indexOf(minY);
|
||||||
|
// 当前下标对应的x
|
||||||
|
const curX = getX(minYIndex);
|
||||||
|
|
||||||
|
// 设置x,y,width
|
||||||
|
const style = curItem.style as CssStyleObject;
|
||||||
|
|
||||||
|
// 设置偏移
|
||||||
|
if (transform) style[transform] = `translate3d(${curX}px,${minY}px, 0)`;
|
||||||
|
style.width = `${colWidth.value}px`;
|
||||||
|
|
||||||
|
// 更新当前index的y值
|
||||||
|
const { height } = curItem.getBoundingClientRect();
|
||||||
|
posY.value[minYIndex] += height + props.gutter;
|
||||||
|
|
||||||
|
// 添加入场动画
|
||||||
|
animation(curItem, () => {
|
||||||
|
// 添加动画时间
|
||||||
|
if (transition) style[transition] = "transform .3s";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapperHeight.value = Math.max.apply(null, posY.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
wrapperHeight,
|
||||||
|
layoutHandle,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动画
|
||||||
|
function addAnimation(props: WaterfallProps) {
|
||||||
|
return (item: HTMLElement, callback?: () => void) => {
|
||||||
|
const content = item!.firstChild as HTMLElement;
|
||||||
|
if (content && !hasClass(content, props.animationPrefix)) {
|
||||||
|
const durationSec = `${props.animationDuration / 1000}s`;
|
||||||
|
const delaySec = `${props.animationDelay / 1000}s`;
|
||||||
|
const style = content.style as CssStyleObject;
|
||||||
|
style.visibility = "visible";
|
||||||
|
if (duration) style[duration] = durationSec;
|
||||||
|
|
||||||
|
if (delay) style[delay] = delaySec;
|
||||||
|
|
||||||
|
if (fillMode) style[fillMode] = "both";
|
||||||
|
|
||||||
|
addClass(content, props.animationPrefix);
|
||||||
|
addClass(content, props.animationEffect);
|
||||||
|
|
||||||
|
// 确保动画完成后item可见
|
||||||
|
setTimeout(() => {
|
||||||
|
const itemStyle = item.style as CssStyleObject;
|
||||||
|
itemStyle.visibility = "visible";
|
||||||
|
if (callback) callback();
|
||||||
|
}, props.animationDuration + props.animationDelay);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
188
src/lib/utils/Lazy.ts
Normal file
188
src/lib/utils/Lazy.ts
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
import type { LazyOptions, ValueFormatterObject } from '../types/lazy'
|
||||||
|
import type { CssStyleObject } from '../types/util'
|
||||||
|
import { loadImage } from './loader'
|
||||||
|
import { assign, hasIntersectionObserver, isObject } from './util'
|
||||||
|
|
||||||
|
enum LifecycleEnum {
|
||||||
|
LOADING = 'loading',
|
||||||
|
LOADED = 'loaded',
|
||||||
|
ERROR = 'error',
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_OBSERVER_OPTIONS = {
|
||||||
|
rootMargin: '0px',
|
||||||
|
threshold: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_LOADING = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
|
||||||
|
const DEFAULT_ERROR = ''
|
||||||
|
|
||||||
|
export default class Lazy {
|
||||||
|
lazyActive = true // 是否开启懒加载
|
||||||
|
crossOrigin = true // 开启跨域
|
||||||
|
options: LazyOptions = {
|
||||||
|
loading: DEFAULT_LOADING,
|
||||||
|
error: DEFAULT_ERROR,
|
||||||
|
observerOptions: DEFAULT_OBSERVER_OPTIONS,
|
||||||
|
log: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
_images = new WeakMap()
|
||||||
|
|
||||||
|
constructor(flag = true, options: LazyOptions, crossOrigin = true) {
|
||||||
|
this.lazyActive = flag
|
||||||
|
this.crossOrigin = crossOrigin
|
||||||
|
this.config(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
config(options = {}) {
|
||||||
|
assign(this.options, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mount
|
||||||
|
mount(el: HTMLImageElement, binding: string | ValueFormatterObject, callback: () => void): void {
|
||||||
|
const { src, loading, error } = this._valueFormatter(binding)
|
||||||
|
el.setAttribute('lazy', LifecycleEnum.LOADING)
|
||||||
|
el.setAttribute('src', loading || DEFAULT_LOADING)
|
||||||
|
if (!this.lazyActive) {
|
||||||
|
this._setImageSrc(el, src, callback, error)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!hasIntersectionObserver) {
|
||||||
|
this._setImageSrc(el, src, callback, error)
|
||||||
|
this._log(() => {
|
||||||
|
throw new Error('Not support IntersectionObserver!')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this._initIntersectionObserver(el, src, callback, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// resize
|
||||||
|
resize(el: HTMLImageElement, callback: () => void) {
|
||||||
|
const lazy = el.getAttribute('lazy')
|
||||||
|
const src = el.getAttribute('src')
|
||||||
|
if (lazy && lazy === LifecycleEnum.LOADED && src) {
|
||||||
|
loadImage(src, this.crossOrigin).then((image) => {
|
||||||
|
const { width, height } = image
|
||||||
|
const curHeight = (el.width / width) * height
|
||||||
|
el.height = curHeight
|
||||||
|
const style = el.style as CssStyleObject
|
||||||
|
style.height = `${curHeight}px`
|
||||||
|
callback()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmount
|
||||||
|
unmount(el: HTMLElement): void {
|
||||||
|
const imgItem = this._realObserver(el)
|
||||||
|
imgItem && imgItem.unobserve(el)
|
||||||
|
this._images.delete(el)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置img的src
|
||||||
|
* @param {*} el - img
|
||||||
|
* @param {*} src - 原图
|
||||||
|
* @param {*} error - 错误图片
|
||||||
|
* @param {*} callback - 完成的回调函数,通知组件刷新布局
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
_setImageSrc(el: HTMLImageElement, src: string, callback: () => void, error?: string): void {
|
||||||
|
if (!src)
|
||||||
|
return
|
||||||
|
|
||||||
|
const preSrc = el.getAttribute('src')
|
||||||
|
if (preSrc === src)
|
||||||
|
return
|
||||||
|
|
||||||
|
loadImage(src, this.crossOrigin)
|
||||||
|
.then((image) => {
|
||||||
|
// 修改容器
|
||||||
|
const { width, height } = image
|
||||||
|
const ratio = height / width
|
||||||
|
const lazyBox = el.parentNode!.parentNode as HTMLElement
|
||||||
|
lazyBox.style.paddingBottom = `${ratio * 100}%`
|
||||||
|
|
||||||
|
// 设置图片
|
||||||
|
el.setAttribute('lazy', LifecycleEnum.LOADED)
|
||||||
|
el.removeAttribute('src')
|
||||||
|
el.setAttribute('src', src)
|
||||||
|
|
||||||
|
callback()
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
const imgItem = this._realObserver(el)
|
||||||
|
imgItem && imgItem.disconnect()
|
||||||
|
if (error) {
|
||||||
|
el.setAttribute('lazy', LifecycleEnum.ERROR)
|
||||||
|
el.setAttribute('src', error)
|
||||||
|
}
|
||||||
|
this._log(() => {
|
||||||
|
throw new Error(`Image failed to load!And failed src was: ${src} `)
|
||||||
|
})
|
||||||
|
callback()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
_isOpenLazy(): boolean {
|
||||||
|
return hasIntersectionObserver && this.lazyActive
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加img和对应的observer到weakMap中
|
||||||
|
* 开启监听
|
||||||
|
* 当出现在可视区域后取消监听
|
||||||
|
* @param {*} el - img
|
||||||
|
* @param {*} src - 图片
|
||||||
|
* @param {*} error - 错误图片
|
||||||
|
* @param {*} callback - 完成的回调函数,通知组件刷新布局
|
||||||
|
*/
|
||||||
|
_initIntersectionObserver(el: HTMLImageElement, src: string, callback: () => void, error?: string): void {
|
||||||
|
const observerOptions = this.options.observerOptions
|
||||||
|
this._images.set(
|
||||||
|
el,
|
||||||
|
new IntersectionObserver((entries) => {
|
||||||
|
Array.prototype.forEach.call(entries, (entry) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
const imgItem = this._realObserver(el)
|
||||||
|
imgItem && imgItem.unobserve(entry.target)
|
||||||
|
this._setImageSrc(el, src, callback, error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, observerOptions),
|
||||||
|
)
|
||||||
|
|
||||||
|
const imgItem = this._realObserver(el)
|
||||||
|
imgItem && imgItem.observe(el)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化参数
|
||||||
|
_valueFormatter(value: ValueFormatterObject | string): ValueFormatterObject {
|
||||||
|
let src = value as string
|
||||||
|
let loading = this.options.loading
|
||||||
|
let error = this.options.error
|
||||||
|
if (isObject(value)) {
|
||||||
|
src = (value as ValueFormatterObject).src
|
||||||
|
loading = (value as ValueFormatterObject).loading || this.options.loading
|
||||||
|
error = (value as ValueFormatterObject).error || this.options.error
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
src,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 日志
|
||||||
|
_log(callback: () => void): void {
|
||||||
|
if (this.options.log)
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在map中获取对应img的observer事件
|
||||||
|
_realObserver(el: HTMLElement): IntersectionObserver | undefined {
|
||||||
|
return this._images.get(el)
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/lib/utils/dom.ts
Normal file
53
src/lib/utils/dom.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import type { CssStyleObject } from '../types/util'
|
||||||
|
|
||||||
|
|
||||||
|
export function hasClass(el: HTMLElement, className: string) {
|
||||||
|
const reg = new RegExp(`(^|\\s)${className}(\\s|$)`)
|
||||||
|
return reg.test(el.className)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addClass(el: HTMLElement, className: string) {
|
||||||
|
if (hasClass(el, className))
|
||||||
|
return
|
||||||
|
|
||||||
|
const newClass = el.className.split(/\s+/)
|
||||||
|
newClass.push(className)
|
||||||
|
el.className = newClass.join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeClass(el: HTMLElement, className: string) {
|
||||||
|
if (hasClass(el, className)) {
|
||||||
|
const newClass = el.className.split(/\s+/).filter(name => name !== className)
|
||||||
|
el.className = newClass.join(' ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const elementStyle = document.createElement('div').style as CssStyleObject
|
||||||
|
|
||||||
|
const vendor = (() => {
|
||||||
|
const transformNames: Record<string, string> = {
|
||||||
|
webkit: 'webkitTransform',
|
||||||
|
Moz: 'MozTransform',
|
||||||
|
O: 'OTransform',
|
||||||
|
ms: 'msTransform',
|
||||||
|
standard: 'transform',
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key in transformNames) {
|
||||||
|
const val = transformNames[key]
|
||||||
|
if (elementStyle[val] !== undefined)
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
})()
|
||||||
|
|
||||||
|
export function prefixStyle(style: string) {
|
||||||
|
if (vendor === false)
|
||||||
|
return false
|
||||||
|
|
||||||
|
if (vendor === 'standard')
|
||||||
|
return style
|
||||||
|
|
||||||
|
return vendor + style.charAt(0).toUpperCase() + style.substr(1)
|
||||||
|
}
|
||||||
19
src/lib/utils/itemWidth.ts
Normal file
19
src/lib/utils/itemWidth.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import type { ItemWidthProps } from "../types/waterfall";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 获取当前窗口尺寸下格子的宽度
|
||||||
|
* @param {ItemWidthProps} param1
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
export const getItemWidth = ({
|
||||||
|
wrapperWidth,
|
||||||
|
gutter,
|
||||||
|
hasAroundGutter,
|
||||||
|
columns,
|
||||||
|
}: ItemWidthProps) => {
|
||||||
|
if (hasAroundGutter) {
|
||||||
|
return (wrapperWidth - gutter) / columns - gutter;
|
||||||
|
} else {
|
||||||
|
return (wrapperWidth - (columns - 1) * gutter) / columns;
|
||||||
|
}
|
||||||
|
};
|
||||||
20
src/lib/utils/loader.ts
Normal file
20
src/lib/utils/loader.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* load images
|
||||||
|
* @param {Array[String]} images - 图片链接数组
|
||||||
|
*/
|
||||||
|
export function loadImage(url: string, crossOrigin: Boolean): Promise<HTMLImageElement> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const image = new Image()
|
||||||
|
image.onload = () => {
|
||||||
|
resolve(image)
|
||||||
|
}
|
||||||
|
image.onerror = () => {
|
||||||
|
reject(new Error('Image load error'))
|
||||||
|
}
|
||||||
|
if (crossOrigin)
|
||||||
|
image.crossOrigin = 'Anonymous' // 支持跨域图片
|
||||||
|
|
||||||
|
image.src = url
|
||||||
|
})
|
||||||
|
}
|
||||||
156
src/lib/utils/util.ts
Normal file
156
src/lib/utils/util.ts
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
export const inBrowser = typeof window !== 'undefined' && window !== null
|
||||||
|
|
||||||
|
export const hasIntersectionObserver = checkIntersectionObserver()
|
||||||
|
const isEnumerable = Object.prototype.propertyIsEnumerable
|
||||||
|
const getSymbols = Object.getOwnPropertySymbols
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取值
|
||||||
|
* @param {Object | Array} form
|
||||||
|
* @param {...any} selectors
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function getValue(form: any, ...selectors: string[]) {
|
||||||
|
const res = selectors.map((s) => {
|
||||||
|
return s
|
||||||
|
.replace(/\[(\w+)\]/g, '.$1')
|
||||||
|
.split('.')
|
||||||
|
.reduce((prev, cur) => {
|
||||||
|
return prev && prev[cur]
|
||||||
|
}, form)
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 防抖
|
||||||
|
* @param {*} fn
|
||||||
|
* @param {*} delay
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function debounce(fn: (args?: any) => void, delay: number) {
|
||||||
|
let timer: any
|
||||||
|
return function(this: any, ...args: any) {
|
||||||
|
timer && clearTimeout(timer)
|
||||||
|
timer = null
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
fn.apply(this, args)
|
||||||
|
}, delay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否支持IntersectionObserver
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function checkIntersectionObserver(): boolean {
|
||||||
|
if (
|
||||||
|
inBrowser
|
||||||
|
&& 'IntersectionObserver' in window
|
||||||
|
&& 'IntersectionObserverEntry' in window
|
||||||
|
&& 'intersectionRatio' in window.IntersectionObserverEntry.prototype
|
||||||
|
) {
|
||||||
|
// Minimal polyfill for Edge 15's lack of `isIntersecting`
|
||||||
|
// See: https://github.com/w3c/IntersectionObserver/issues/211
|
||||||
|
if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) {
|
||||||
|
Object.defineProperty(window.IntersectionObserverEntry.prototype, 'isIntersecting', {
|
||||||
|
get() {
|
||||||
|
return this.intersectionRatio > 0
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is object
|
||||||
|
*
|
||||||
|
* @param {*} val
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isObject(val: any): boolean {
|
||||||
|
return typeof val === 'function' || toString.call(val) === '[object Object]'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is primitive
|
||||||
|
*
|
||||||
|
* @param {*} val
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isPrimitive(val: any): boolean {
|
||||||
|
return typeof val === 'object' ? val === null : typeof val !== 'function'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check private key
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {*} key
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isValidKey(key: any): boolean {
|
||||||
|
return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign the enumerable es6 Symbol properties from one
|
||||||
|
* or more objects to the first object passed on the arguments.
|
||||||
|
* Can be used as a supplement to other extend, assign or
|
||||||
|
* merge methods as a polyfill for the Symbols part of
|
||||||
|
* the es6 Object.assign method.
|
||||||
|
* https://github.com/jonschlinkert/assign-symbols
|
||||||
|
*
|
||||||
|
* @param {*} target
|
||||||
|
* @param {Array} args
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function assignSymbols(target: any, ...args: any[]) {
|
||||||
|
if (!isObject(target))
|
||||||
|
throw new TypeError('expected the first argument to be an object')
|
||||||
|
|
||||||
|
if (args.length === 0 || typeof Symbol !== 'function' || typeof getSymbols !== 'function')
|
||||||
|
return target
|
||||||
|
|
||||||
|
for (const arg of args) {
|
||||||
|
const names = getSymbols(arg)
|
||||||
|
|
||||||
|
for (const key of names) {
|
||||||
|
if (isEnumerable.call(arg, key))
|
||||||
|
target[key] = arg[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deeply assign the values of all enumerable-own-properties and symbols
|
||||||
|
* from one or more source objects to a target object. Returns the target object.
|
||||||
|
* https://github.com/jonschlinkert/assign-deep
|
||||||
|
*
|
||||||
|
* @param {*} target
|
||||||
|
* @param {Array} args
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function assign(target: any, ...args: any[]): void {
|
||||||
|
let i = 0
|
||||||
|
if (isPrimitive(target)) target = args[i++]
|
||||||
|
if (!target) target = {}
|
||||||
|
for (; i < args.length; i++) {
|
||||||
|
if (isObject(args[i])) {
|
||||||
|
for (const key of Object.keys(args[i])) {
|
||||||
|
if (isValidKey(key)) {
|
||||||
|
if (isObject(target[key]) && isObject(args[i][key]))
|
||||||
|
assign(target[key], args[i][key])
|
||||||
|
|
||||||
|
else
|
||||||
|
target[key] = args[i][key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assignSymbols(target, args[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target
|
||||||
|
}
|
||||||
18
src/main.ts
18
src/main.ts
@ -3,23 +3,16 @@ import { useConfig } from "@/config";
|
|||||||
import icon from "@/icon/index.ts";
|
import icon from "@/icon/index.ts";
|
||||||
import { createPinia } from "pinia";
|
import { createPinia } from "pinia";
|
||||||
import "virtual:uno.css";
|
import "virtual:uno.css";
|
||||||
import { createApp, vaporInteropPlugin } from "vue";
|
import 'vue-devui/tag/style.css';
|
||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
// 自定义主题配置 - 设置主色和二级色
|
// 自定义主题配置 - 设置主色和二级色\
|
||||||
import { ThemeServiceInit, infinityTheme, sweetTheme } from "devui-theme";
|
import "vfonts/FiraCode.css";
|
||||||
|
import Tag from 'vue-devui/tag';
|
||||||
import { PerfectScrollbarPlugin } from "vue3-perfect-scrollbar";
|
import { PerfectScrollbarPlugin } from "vue3-perfect-scrollbar";
|
||||||
// import vue3videoPlay from "vue3-video-play";
|
|
||||||
// import "vue3-video-play/dist/style.css";
|
|
||||||
//main.js
|
|
||||||
|
|
||||||
// ThemeServiceInit({ customTheme }, "customTheme");
|
|
||||||
const themeService = ThemeServiceInit({ infinityTheme }, "infinityTheme");
|
|
||||||
themeService?.applyTheme(sweetTheme);
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
app.use(vaporInteropPlugin)
|
app.use(Tag)
|
||||||
app.use(createPinia());
|
app.use(createPinia());
|
||||||
app.use(router);
|
app.use(router);
|
||||||
|
|
||||||
@ -30,4 +23,3 @@ for (const key in icon) {
|
|||||||
}
|
}
|
||||||
app.use(PerfectScrollbarPlugin);
|
app.use(PerfectScrollbarPlugin);
|
||||||
app.mount("#app");
|
app.mount("#app");
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import router from "@/router";
|
|
||||||
import type { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from "axios";
|
import type { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from "axios";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useCookies } from "vue3-cookies";
|
import { useCookies } from "vue3-cookies";
|
||||||
@ -45,16 +44,16 @@ request.interceptors.response.use(
|
|||||||
console.log("Response error", error);
|
console.log("Response error", error);
|
||||||
|
|
||||||
if (error.response?.status === 401) {
|
if (error.response?.status === 401) {
|
||||||
// window.$msg.warning("无效的token");
|
window.$msg.warning("无效的token");
|
||||||
cookies.remove("token");
|
cookies.remove("token");
|
||||||
cookies.remove("userinfo");
|
cookies.remove("userinfo");
|
||||||
window.$modal({
|
// window.$modal({
|
||||||
title: "无效的token",
|
// title: "无效的token",
|
||||||
content: "token已失效,需要登录,请登录 =>",
|
// content: "token已失效,需要登录,请登录 =>",
|
||||||
handdleSubmit: () => {
|
// handdleSubmit: () => {
|
||||||
router.replace("/login");
|
// router.replace("/login");
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
|
||||||
// router.replace("/login");
|
// router.replace("/login");
|
||||||
return "Unauthorized";
|
return "Unauthorized";
|
||||||
|
|||||||
15
src/util/theme.ts
Normal file
15
src/util/theme.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* js 文件下使用这个做类型提示
|
||||||
|
* @type import('naive-ui').GlobalThemeOverrides
|
||||||
|
*/
|
||||||
|
const themeOverrides = {
|
||||||
|
common: {
|
||||||
|
primaryColor: '#ec66ab',
|
||||||
|
primaryColorHover: '#ec66ab',
|
||||||
|
primaryColorPressed: '#ec66ab',
|
||||||
|
primaryColorSuppl: '#ec66ab',
|
||||||
|
},
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
export default themeOverrides;
|
||||||
@ -1,30 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="article-page">
|
|
||||||
<div id="vditor"></div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import Vditor from 'vditor';
|
|
||||||
import 'vditor/dist/index.css';
|
|
||||||
import { onMounted, ref } from 'vue';
|
|
||||||
definePage({
|
|
||||||
name: 'article',
|
|
||||||
meta: {
|
|
||||||
title: '文章',
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 文章页逻辑
|
|
||||||
const vditor:any = ref(null);
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
vditor.value = new Vditor('vditor', {
|
|
||||||
height: '100vh',
|
|
||||||
width: '100vw'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
/* 文章页样式 */
|
|
||||||
</style>
|
|
||||||
18
src/views/Blog.vue
Normal file
18
src/views/Blog.vue
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<div class="article-page">
|
||||||
|
<h1>文章页</h1>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
definePage({
|
||||||
|
name: 'blog',
|
||||||
|
meta: {
|
||||||
|
title: '文章',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 文章页样式 */
|
||||||
|
</style>
|
||||||
@ -1,126 +1,75 @@
|
|||||||
<template>
|
<template>
|
||||||
<PerfectScrollbar ref="scrollbar" @ps-scroll-y="handleScroll">
|
<!-- <PerfectScrollbar ref="scrollbar" @ps-scroll-y="handleScroll"> -->
|
||||||
<div ref="myCon" class="gallery-page py-5 px-[10%]">
|
<div ref="myCon" class="gallery-page py-5 px-[10%]">
|
||||||
<d-search class="mt-0 mb-8 w-2/3 mx-auto rounded-full" v-model="kw" is-keyup-search :delay="1000"
|
<!-- <d-search class="mt-0 mb-8 w-2/3 mx-auto rounded-full" v-model="kw" is-keyup-search :delay="1000"
|
||||||
@search="onSearch"></d-search>
|
@search="onSearch"></d-search> -->
|
||||||
<div class="gallery-container w-full box-border">
|
<n-input class="mb-8 !w-[90%] ml-[5%]" size="large" v-model:value="kw" @keyup.enter="onSearch" placeholder="请输入">
|
||||||
<!-- 瀑布流容器 -->
|
<template #suffix>
|
||||||
<div ref="waterfallContainer" v-image-preview
|
<n-icon size="large">
|
||||||
class="waterfall-container flex justify-between flex-nowrap w-full overflow-hidden">
|
<icon-search />
|
||||||
<!-- 动态生成的列 -->
|
</n-icon>
|
||||||
<div v-for="(column, index) in columns" :key="index" class="waterfall-column flex flex-col w-[240px]">
|
</template>
|
||||||
<div v-for="item in column" :key="item.id"
|
</n-input>
|
||||||
class="gallery-item group relative my-[10px] rounded-lg overflow-hidden transition-transform duration-300 box-border hover:-translate-y-1.5">
|
|
||||||
<div
|
<!-- <div v-infinite-scroll="loadMore"> -->
|
||||||
class="absolute px-2 truncate hidden group-hover:block top-0 text-center w-full bg-[#00000070] text-white">
|
<Waterfall ref="waterfall" :list="fileList" :width="cwidth" :gutter="gutter" :columns="column" img-selector="url"
|
||||||
{{ item.filename }}</div>
|
animation-effect="fadeIn" :animation-duration="1000" :animation-delay="300" backgroundColor="transparent"> >
|
||||||
<img :src="item.filepath" alt="" class="gallery-image block w-full h-auto object-cover rounded-md">
|
<template #item="{ item }">
|
||||||
<div class="px-2 absolute bottom-0 flex justify-between w-full bg-[#00000060]">
|
<div
|
||||||
<div class="text-white ">由 <span class="text-[#f1d9db] font-600">{{ item.nickname }}</span> 上传</div>
|
class="card rounded-md overflow-hidden group shadow-md transition-transform duration-300 box-border hover:-translate-y-1.5">
|
||||||
<d-popover content="下载" trigger="hover" class="!bg-primary" style="color: #fff">
|
<!-- <div class="image-wrapper"> -->
|
||||||
<icon-download @click="downloadFile(item.filepath)"
|
<LazyImg class="rounded-md overflow-hidden" :url="item.filepath" />
|
||||||
class="w-5 h-5 text-white hover-text-primary"></icon-download>
|
<!-- </div> -->
|
||||||
</d-popover>
|
<div
|
||||||
</div>
|
class="hidden truncate group-hover:block absolute rounded-md z-10 truncate top-0 text-center w-full bg-[#00000070] text-white">
|
||||||
|
{{ item.filename }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="absolute rounded-md flex z-10 truncate bottom-0 w-full bg-[#00000070] text-white justify-between items-center">
|
||||||
|
<div>由 <span class="text-[#f1d9db] font-600">{{ item.nickname }}</span> 分享</div>
|
||||||
|
<icon-download class="cursor-pointer w-4 h-4" @click="downloadFile(item.filepath)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
<!-- 加载中指示器 -->
|
</Waterfall>
|
||||||
<div v-if="loading" class="loading-indicator text-center p-5 text-gray-600">加载中...</div>
|
|
||||||
<div v-else class="loading-indicator text-center p-5 text-gray-600">已全部加载完成</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</PerfectScrollbar>
|
<!-- </div> -->
|
||||||
|
<!-- </PerfectScrollbar> -->
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { throttle } from 'es-toolkit';
|
import { throttle } from 'es-toolkit';
|
||||||
import { onMounted, onUnmounted, ref } from 'vue';
|
import { LazyImg, Waterfall } from '../lib';
|
||||||
|
|
||||||
definePage({
|
definePage({
|
||||||
name: 'gallery',
|
name: 'gallery',
|
||||||
meta: {
|
meta: {
|
||||||
title: '画廊',
|
title: '画廊',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
declare module "vue" {
|
||||||
|
interface HTMLAttributes {
|
||||||
|
"v-infinite-scroll"?: () => void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const waterfall = ref<any>(null);
|
||||||
|
|
||||||
// 画廊页逻辑
|
// 画廊页逻辑
|
||||||
const fileList = ref<any[]>([]);
|
const fileList = ref<any[]>([]);
|
||||||
const pn = ref(1);
|
const pn = ref(1);
|
||||||
const ps = ref(40);
|
const ps = ref(40);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const waterfallContainer = ref<HTMLDivElement | null>(null);
|
|
||||||
const columns = ref<Array<Array<any>>>([]);
|
|
||||||
const columnHeights = ref<number[]>([]);
|
|
||||||
const columnCount = ref(4); // 默认列数
|
|
||||||
const itemWidth = ref(240); // 图片宽度固定为240px
|
|
||||||
const kw = ref<string>('');
|
const kw = ref<string>('');
|
||||||
|
const cwidth = ref<number>(220);
|
||||||
|
const column = ref<number>(5);
|
||||||
|
const gutter = ref<number>(20);
|
||||||
|
|
||||||
// const uploadOptions = ref({
|
// 计算列数
|
||||||
// uri: 'https://www.hxyouzi.com/api/files/upload',
|
function calculateColumns() {
|
||||||
// method: 'POST',
|
const totalWidth = window.innerWidth * 0.8; // 画廊宽度为视口宽度的80%
|
||||||
// maximumSize: 5 * 1024 * 1024,
|
const col = Math.floor(totalWidth / (cwidth.value + gutter.value));
|
||||||
// headers: {
|
column.value = col > 0 ? col : 1;
|
||||||
// 'Authorization': 'Bearer ' + $cookies.get('token'),
|
waterfall.value?.renderer()
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// 计算列数 based on 屏幕宽度
|
|
||||||
function calculateColumnCount() {
|
|
||||||
if (!waterfallContainer.value) return;
|
|
||||||
const containerWidth = waterfallContainer.value.clientWidth;
|
|
||||||
const newColumnCount = Math.max(1, Math.floor(containerWidth / itemWidth.value));
|
|
||||||
if (newColumnCount !== columnCount.value) {
|
|
||||||
columnCount.value = newColumnCount;
|
|
||||||
resetWaterfall();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置瀑布流
|
|
||||||
function resetWaterfall() {
|
|
||||||
columns.value = Array(columnCount.value).fill(0).map(() => []);
|
|
||||||
columnHeights.value = Array(columnCount.value).fill(0);
|
|
||||||
// 重新分配图片
|
|
||||||
fileList.value.forEach(async item =>await addToWaterfall(item));
|
|
||||||
console.log('>>> --> resetWaterfall --> fileList:', fileList.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加图片到瀑布流
|
|
||||||
async function addToWaterfall(item: any) {
|
|
||||||
if (columns.value.length === 0) return;
|
|
||||||
const { height, width } =await getImageSizeByCheck(item.filepath)
|
|
||||||
|
|
||||||
// 找到高度最小的列
|
|
||||||
let minHeight = Math.min(...columnHeights.value);
|
|
||||||
let minIndex = columnHeights.value.indexOf(minHeight);
|
|
||||||
console.log('>>> --> addToWaterfall --> item:', item)
|
|
||||||
console.log('>>> --> addToWaterfall --> minIndex:', minIndex)
|
|
||||||
// 添加到该列
|
|
||||||
columns.value[minIndex].push(item);
|
|
||||||
// 估算列高 - 实际高度会在图片加载后更新
|
|
||||||
const estimatedHeight = itemWidth.value * height / width
|
|
||||||
columnHeights.value[minIndex] += estimatedHeight + 20; // 加上padding和margin
|
|
||||||
}
|
|
||||||
|
|
||||||
function getImageSizeByCheck(url: string): any {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
let image = new Image();
|
|
||||||
image.src = url;
|
|
||||||
let height = 0
|
|
||||||
let width = 0
|
|
||||||
// let timer = setTimeout(() => {
|
|
||||||
image.onload = () => {
|
|
||||||
if (image.width > 0 && image.height > 0) {
|
|
||||||
height = image.height
|
|
||||||
width = image.width
|
|
||||||
resolve({ height, width })
|
|
||||||
// clearTimeout(timer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// }, 100)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取文件列表
|
// 获取文件列表
|
||||||
@ -137,55 +86,27 @@ async function getFileList() {
|
|||||||
|
|
||||||
if (pn.value === 1) {
|
if (pn.value === 1) {
|
||||||
fileList.value = res.data;
|
fileList.value = res.data;
|
||||||
resetWaterfall();
|
|
||||||
} else {
|
} else {
|
||||||
// 追加新数据
|
// 追加新数据
|
||||||
res.data.forEach((item: any) => {
|
res.data.forEach((item: any) => {
|
||||||
fileList.value.push(item);
|
fileList.value.push(item);
|
||||||
addToWaterfall(item);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取文件列表失败:', error);
|
console.error('获取文件列表失败:', error);
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
waterfall.value?.renderer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 获取我的文件列表
|
|
||||||
// async function getMyList() {
|
|
||||||
// if (loading.value) return;
|
|
||||||
// loading.value = true;
|
|
||||||
// try {
|
|
||||||
// const res = await $http.file.getMyList({
|
|
||||||
// page_num: pn.value,
|
|
||||||
// page_size: ps.value,
|
|
||||||
// });
|
|
||||||
// // console.log('>>> --> getFileList --> res:', res);
|
|
||||||
|
|
||||||
// if (pn.value === 1) {
|
|
||||||
// fileList.value = res.data;
|
|
||||||
// resetWaterfall();
|
|
||||||
// } else {
|
|
||||||
// // 追加新数据
|
|
||||||
// res.data.forEach((item: any) => {
|
|
||||||
// fileList.value.push(item);
|
|
||||||
// addToWaterfall(item);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error('获取文件列表失败:', error);
|
|
||||||
// } finally {
|
|
||||||
// loading.value = false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 监听滚动事件
|
// 监听滚动事件
|
||||||
const handleScroll: any = throttle((e: any) => {
|
const handleScroll: any = throttle((e: any) => {
|
||||||
console.log('>>> --> handleScroll --> loading:', e)
|
// console.log('>>> --> handleScroll --> loading:', e)
|
||||||
if (loading.value) return;
|
if (loading.value) return;
|
||||||
const scrollTop = e.target.scrollTop
|
const scrollTop = e.target.scrollTop
|
||||||
console.log('>>> --> handleScroll --> scrollTop:', scrollTop)
|
// console.log('>>> --> handleScroll --> scrollTop:', scrollTop)
|
||||||
const scrollHeight = e.target.scrollHeight
|
const scrollHeight = e.target.scrollHeight
|
||||||
// console.log('>>> --> handleScroll --> scrollHeight:', scrollHeight)
|
// console.log('>>> --> handleScroll --> scrollHeight:', scrollHeight)
|
||||||
const clientHeight = e.target.offsetHeight;
|
const clientHeight = e.target.offsetHeight;
|
||||||
@ -224,12 +145,10 @@ function downloadFile(url: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
calculateColumns()
|
||||||
getFileList();
|
getFileList();
|
||||||
// 计算初始列数
|
|
||||||
calculateColumnCount();
|
|
||||||
// 添加窗口大小变化监听
|
|
||||||
window.addEventListener('resize', calculateColumnCount);
|
|
||||||
// 添加滚动监听
|
// 添加滚动监听
|
||||||
|
window.addEventListener('resize', calculateColumns);
|
||||||
window.addEventListener('scroll', handleScroll);
|
window.addEventListener('scroll', handleScroll);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -237,10 +156,7 @@ onUnmounted(() => {
|
|||||||
pn.value = 1;
|
pn.value = 1;
|
||||||
kw.value = '';
|
kw.value = '';
|
||||||
fileList.value = [];
|
fileList.value = [];
|
||||||
resetWaterfall();
|
|
||||||
|
|
||||||
// 移除监听
|
// 移除监听
|
||||||
window.removeEventListener('resize', calculateColumnCount);
|
|
||||||
window.removeEventListener('scroll', handleScroll);
|
window.removeEventListener('scroll', handleScroll);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,97 +1,99 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="home-page" :style="contentStyle">
|
<div class="home-page" :content-style="contentStyle">
|
||||||
<d-layout>
|
<n-layout has-sider>
|
||||||
<d-content class="main-content">
|
<n-layout-content class="main-content">
|
||||||
<div class="pt-8 px-12 relative hidden lg:block">
|
<div class="pt-8 px-12 relative hidden lg:block">
|
||||||
<d-input class="devui-input-demo__mt" size="lg" v-model="searchWord" @blur="cancelSbox" placeholder="请输入">
|
<n-input-group class="shadow ">
|
||||||
<template #prepend>
|
<n-select class="w-24" size="large" v-model:value="broswer" :options="options"
|
||||||
<d-select class="w-48" size="lg" v-model="broswer" :options="options" @click="cancelSbox"></d-select>
|
@click="cancelSbox"></n-select>
|
||||||
</template>
|
<n-input class="flex-1" size="large" v-model:value="searchWord" @blur="cancelSbox" placeholder="请输入">
|
||||||
<template #append>
|
<template #suffix>
|
||||||
<d-icon name="search" style="font-size: inherit;" @click="search" />
|
<n-icon size="large">
|
||||||
</template>
|
<icon-search />
|
||||||
</d-input>
|
</n-icon>
|
||||||
<div v-if="searchBox" class="absolute left-34 mt-2 z-10 bg-white text-sm text-gray-500 max-h-40 rounded-md shadow-md px-4 py-2 max-w-80">
|
</template>
|
||||||
|
</n-input>
|
||||||
|
</n-input-group>
|
||||||
|
<div v-if="searchBox"
|
||||||
|
class="absolute left-34 mt-2 z-10 bg-white text-sm text-gray-500 rounded-md shadow-md px-4 py-2 max-w-80">
|
||||||
<div class="flex p-2 pr-20 truncate rounded-md items-center hover:text-primary cursor-pointer"
|
<div class="flex p-2 pr-20 truncate rounded-md items-center hover:text-primary cursor-pointer"
|
||||||
:class="selecedIdx === idx ? 'text-white bg-primary' : ''" v-for="(i, idx) in searchItems"
|
:class="selecedIdx === idx ? 'text-white bg-primary' : ''" v-for="(i, idx) in searchItems" :key="idx"
|
||||||
:key="idx" @click="goExtra(i.menu_link)" @keyup.enter ="goExtra(i.menu_link)"
|
@click="goExtra(i.menu_link)" @keyup.enter="goExtra(i.menu_link)"><span v-if="idx">导航:</span>
|
||||||
><span v-if="idx">导航:</span> {{i.menu_name }}</div>
|
{{ i.menu_name }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 标签组 -->
|
<!-- 标签组 -->
|
||||||
<!-- <PerfectScrollbar class="w-full overflow-x-auto"> -->
|
<!-- <PerfectScrollbar class="w-full overflow-x-auto"> -->
|
||||||
<div v-if="navlist.length" class="flex gap-6 px-2 mt-6 mb-3 flex-wrap lg:px-12">
|
<n-scrollbar class="w-full overflow-x-auto" :style="navStyle">
|
||||||
<d-tag class="cursor-pointer truncate" hideBeyondTags v-for="tag in tagList" :checked="tag.checked"
|
<div v-if="navlist.length" class="flex gap-6 px-2 mt-6 mb-3 flex-wrap lg:px-12">
|
||||||
:color="tag.color" @click="handdleTagClick(tag)">{{ tag.name }}</d-tag>
|
<d-tag class="cursor-pointer truncate" hideBeyondTags v-for="tag in tagList" :checked="tag.checked"
|
||||||
</div>
|
:color="tag.color" @click="handdleTagClick(tag)">{{ tag.name }}</d-tag>
|
||||||
<!-- </PerfectScrollbar> -->
|
</div>
|
||||||
<!-- 图片网格展示区域 -->
|
<!-- </PerfectScrollbar> -->
|
||||||
<PerfectScrollbar class="" :style="navStyle">
|
<!-- 图片网格展示区域 -->
|
||||||
<div ref="navcards"
|
<div ref="navcards"
|
||||||
class="navcard grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-6 gap-5 pt-3 pb-6 px-2 lg:px-12">
|
class="navcard grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-6 gap-5 pt-3 pb-6 px-2 lg:px-12">
|
||||||
<d-card class="bg-[#ffffff80] h-24" v-for="(item, index) in navlist" :key="index"
|
<n-card embedded
|
||||||
@click="goExtra(item.menu_link)" @contextmenu.prevent="handdleContextMenu($event, item)">
|
class="bg-[#ffffff80] h-24 shadow-md transition-transform duration-300 box-border hover:-translate-y-1.5"
|
||||||
<template #content>
|
v-for="(item, index) in navlist" :key="index" @click="goExtra(item.menu_link)"
|
||||||
<div class="mt-1 w-full flex flex-col items-center cursor-pointer hover:!text-primary">
|
@contextmenu.prevent="handdleContextMenu($event, item)">
|
||||||
<div :style="{ background: item.color }"
|
<div class="mt-1 w-full flex flex-col items-center cursor-pointer hover:!text-primary">
|
||||||
class="w-8 h-8 rounded-full text-white flex items-center justify-center" v-if="item.icon_error">
|
<div :style="{ background: item.color }"
|
||||||
{{ item.first }}</div>
|
class="w-8 h-8 rounded-full text-white flex items-center justify-center" v-if="item.icon_error">
|
||||||
<img class="grid-image w-8 h-8 rounded-full" v-else :src="item.menu_icon"
|
{{ item.first }}</div>
|
||||||
@error="imgErr(index as number)" />
|
<img class="grid-image w-8 h-8 rounded-full" v-else :src="item.menu_icon"
|
||||||
<div class="mt-2 w-full text-center text-lg truncate">{{ item.menu_name || "" }}</div>
|
@error="imgErr(index as number)" />
|
||||||
<em class="absolute rounded-md top-0 left-0 px-2 text-white text-center text-sm"
|
<div class="mt-2 w-full text-center text-lg truncate">{{ item.menu_name || "" }}</div>
|
||||||
:style="{ background: getItemColor(item) }">{{ item.tag }}</em>
|
<em class="absolute rounded-md top-0 left-0 px-2 text-white text-center text-sm"
|
||||||
</div>
|
:style="{ background: getItemColor(item) }">{{ item.tag }}</em>
|
||||||
</template>
|
</div>
|
||||||
</d-card>
|
</n-card>
|
||||||
<d-card class="bg-[#ffffff80] h-25">
|
<n-card embedded
|
||||||
|
class="bg-[#ffffff80] h-24 shadow-md transition-transform duration-300 box-border hover:-translate-y-1.5">
|
||||||
<div @click="addNav" class="w-full h-full flex flex-col items-center justify-center cursor-pointer">
|
<div @click="addNav" class="w-full h-full flex flex-col items-center justify-center cursor-pointer">
|
||||||
<div :style="{ background: getRandomDarkColor() }"
|
<div :style="{ background: getRandomDarkColor() }"
|
||||||
class="w-12 h-12 rounded-full text-2xl text-white flex items-center justify-center">
|
class="w-8 h-8 rounded-full text-2xl text-white flex items-center justify-center">
|
||||||
+
|
+
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mt-2 w-full text-center text-lg truncate text-primary">新增导航</div>
|
||||||
</div>
|
</div>
|
||||||
</d-card>
|
</n-card>
|
||||||
</div>
|
</div>
|
||||||
</PerfectScrollbar>
|
</n-scrollbar>
|
||||||
|
</n-layout-content>
|
||||||
</d-content>
|
<n-layout-sider width="30rem">
|
||||||
<d-aside class="daside hidden w-120 lg:block">
|
|
||||||
<homeSide></homeSide>
|
<homeSide></homeSide>
|
||||||
</d-aside>
|
</n-layout-sider>
|
||||||
</d-layout>
|
</n-layout>
|
||||||
|
|
||||||
<!-- 新增导航弹窗 -->
|
<!-- 新增导航弹窗 -->
|
||||||
<d-modal class="!w-120" v-model="visible" title="新增导航">
|
<maskX :visible="visible" :setVisible="navCancel">
|
||||||
<d-form ref="formNav" layout="vertical" :data="navData">
|
<n-form class="w-[500px] bg-white rounded-md p-8 shadow-md" ref="formNav" layout="vertical" :data="navData">
|
||||||
<d-form-item class="h-8" field="username">
|
<div class="text-center text-lg">新增导航</div>
|
||||||
<d-input @blur="getIcon" v-model="navData.menu_link" placeholder="请输入单行链接(必填)" />
|
<n-form-item class="h-8" path="menu_link">
|
||||||
</d-form-item>
|
<n-input @blur="getIcon" v-model:value="navData.menu_link" placeholder="请输入单行链接(必填)" />
|
||||||
<d-form-item class="h-8" field="password">
|
</n-form-item>
|
||||||
<d-input v-model="navData.menu_name" placeholder="请输入导航名称(必填)" />
|
<n-form-item class="h-8 mt-4" path="menu_name">
|
||||||
</d-form-item>
|
<n-input v-model:value="navData.menu_name" placeholder="请输入导航名称(必填)" />
|
||||||
<d-form-item class="h-8" field="tag">
|
</n-form-item>
|
||||||
<d-input v-model="navData.tag" placeholder="请自定义一个标签(必填,只取前四字)" />
|
<n-form-item class="h-8 mt-4" path="tag">
|
||||||
</d-form-item>
|
<n-input v-model:value="navData.tag" placeholder="请自定义一个标签(必填,只取前四字)" />
|
||||||
<d-form-item class="h-8 form-operation-wrap">
|
</n-form-item>
|
||||||
<div class="flex">
|
<n-form-item class="h-8 mt-4 form-operation-wrap">
|
||||||
<d-input v-model="navData.menu_icon" placeholder="请输入图标链接" />
|
<!-- <div class="flex"> -->
|
||||||
<img class="ml-5" v-if="navData.menu_icon" width="30" height="30" :src="navData.menu_icon" alt="">
|
<n-input v-model:value="navData.menu_icon" placeholder="请输入图标链接" />
|
||||||
<div v-else class="ml-5 w-[30px] h-[30px]"></div>
|
<img class="ml-5" v-if="navData.menu_icon" width="30" height="30" :src="navData.menu_icon" alt="">
|
||||||
</div>
|
<div v-else class="ml-5 w-[30px] h-[30px]"></div>
|
||||||
</d-form-item>
|
<!-- </div> -->
|
||||||
</d-form>
|
</n-form-item>
|
||||||
<!-- <div class="mt-14 w-full flex justify-between">
|
<div class="mt-14 flex justify-between">
|
||||||
<d-button @click="navCancel" variant="text" class="w-[49%] hover:bg-[#8a6684] hover:!text-white">取消</d-button>
|
<n-button class="w-[48%]" secondary variant="solid" @click="navCancel">取消</n-button>
|
||||||
<span class="text-[20px]"> | </span>
|
<n-button class="w-[48%]" type="primary" variant="solid" @click="navSubmit">确定</n-button>
|
||||||
<d-button @click="navSubmit" variant="text" class="w-[49%] hover:bg-[#5c866a] hover:!text-white"
|
</div>
|
||||||
color="primary">确定</d-button>
|
</n-form>
|
||||||
</div> -->
|
|
||||||
<div class="mt-14 flex justify-between">
|
|
||||||
<d-button class="w-[48%]" variant="solid" color="secondary" @click="navCancel">取消</d-button>
|
</maskX>
|
||||||
<d-button class="w-[48%]" variant="solid" color="primary" @click="navSubmit">确定</d-button>
|
|
||||||
</div>
|
|
||||||
</d-modal>
|
|
||||||
|
|
||||||
<!-- 音乐插件 -->
|
<!-- 音乐插件 -->
|
||||||
<aplayer></aplayer>
|
<aplayer></aplayer>
|
||||||
@ -116,25 +118,29 @@
|
|||||||
</contextMenu>
|
</contextMenu>
|
||||||
|
|
||||||
<!-- 编辑弹窗 -->
|
<!-- 编辑弹窗 -->
|
||||||
<d-modal class="!w-120" v-model="editModal" title="导航修改">
|
<maskX :visible="editModal" :setVisible="navCancel">
|
||||||
<div class="mb-2">
|
<div class="w-[500px] bg-white p-8 rounded-md">
|
||||||
原
|
<div class="text-center text-lg mb-8">修改导航内容</div>
|
||||||
<span class="text-primary" v-if="currentClickedItem === 1">导航名称:{{ currentItem.menu_name }}</span>
|
<div class="mb-4">
|
||||||
<span class="text-primary" v-if="currentClickedItem === 2">导航链接:{{ currentItem.menu_link }}</span>
|
原
|
||||||
<span class="text-primary" v-if="currentClickedItem === 3">导航标签:{{ currentItem.tag }}</span>
|
<span class="text-primary" v-if="currentClickedItem === 1">导航名称:{{ currentItem?.menu_name }}</span>
|
||||||
|
<span class="text-primary" v-if="currentClickedItem === 2">导航链接:{{ currentItem?.menu_link }}</span>
|
||||||
|
<span class="text-primary" v-if="currentClickedItem === 3">导航标签:{{ currentItem?.tag }}</span>
|
||||||
|
</div>
|
||||||
|
<n-input v-model:value="editInput" placeholder="请输入修改内容"></n-input>
|
||||||
|
<div class="mt-8 flex justify-between">
|
||||||
|
<n-button class="w-[48%]" secondary @click="handdleItemCancel">取消</n-button>
|
||||||
|
<n-button class="w-[48%]" type="primary" @click="handdleItemSubmit">确定</n-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<d-input v-model="editInput" placeholder="请输入修改内容"></d-input>
|
</maskX>
|
||||||
<div class="mt-8 flex justify-between">
|
|
||||||
<d-button class="w-[48%]" variant="solid" color="secondary" @click="handdleItemCancel">取消</d-button>
|
|
||||||
<d-button class="w-[48%]" variant="solid" color="primary" @click="handdleItemSubmit">确定</d-button>
|
|
||||||
</div>
|
|
||||||
</d-modal>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import contextMenu from '@/components/contextMenu.vue';
|
import contextMenu from '@/components/contextMenu.vue';
|
||||||
|
import maskX from '@/components/mask.vue';
|
||||||
import { deepclone, getDictValue } from '@/util/index.ts';
|
import { deepclone, getDictValue } from '@/util/index.ts';
|
||||||
definePage({
|
definePage({
|
||||||
name: 'home',
|
name: 'home',
|
||||||
@ -144,24 +150,48 @@ definePage({
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// 定义接口类型
|
||||||
|
interface NavItem {
|
||||||
|
nid?: number
|
||||||
|
menu_link: string
|
||||||
|
menu_name: string
|
||||||
|
tag: string
|
||||||
|
menu_icon: string
|
||||||
|
icon_error?: boolean
|
||||||
|
first?: string
|
||||||
|
color?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MenuItem {
|
||||||
|
menu_name: string
|
||||||
|
menu_link: string
|
||||||
|
tag: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TagItem {
|
||||||
|
name: string
|
||||||
|
color: string
|
||||||
|
checked: boolean
|
||||||
|
}
|
||||||
|
|
||||||
// 右键菜单
|
// 右键菜单
|
||||||
const menuShow = ref(false)
|
const menuShow = ref(false)
|
||||||
const MenuOptions: any = reactive({});
|
const MenuOptions = reactive({ x: 0, y: 0 })
|
||||||
const currentItem = ref<any>(null);
|
const currentItem = ref<NavItem | null>(null)
|
||||||
const menuS = '!m-0 py-3 px-6 text-sm text-gray-700 w-full flex items-center justify-center hover:bg-[#f5f0f0] hover:text-primary';
|
const menuS = '!m-0 py-3 px-6 text-sm text-gray-700 w-full flex items-center justify-center hover:bg-[#f5f0f0] hover:text-primary'
|
||||||
const currentClickedItem = ref<number>(0);
|
const currentClickedItem = ref<number>(0)
|
||||||
const editModal = ref<boolean>(false);
|
const editModal = ref<boolean>(false)
|
||||||
const editInput = ref<string>('');
|
const editInput = ref<string>('')
|
||||||
// 新增导航弹窗
|
// 新增导航弹窗
|
||||||
const visible: any = ref<boolean>(false)
|
const visible = ref<boolean>(false)
|
||||||
const navData: any = reactive({
|
const navData = reactive<NavItem>({
|
||||||
menu_link: '',
|
menu_link: '',
|
||||||
menu_name: '',
|
menu_name: '',
|
||||||
tag: '',
|
tag: '',
|
||||||
menu_icon: ''
|
menu_icon: ''
|
||||||
})
|
})
|
||||||
const formNav: any = ref(null)
|
const formNav = ref<any>(null)
|
||||||
const navcards: any = ref(null)
|
const navcards = ref<any>(null)
|
||||||
|
|
||||||
// 首页逻辑
|
// 首页逻辑
|
||||||
const nav: any = $store.nav.useNavStore()
|
const nav: any = $store.nav.useNavStore()
|
||||||
@ -174,22 +204,22 @@ const selecedIdx = ref(0)
|
|||||||
const searchBox = ref(false)
|
const searchBox = ref(false)
|
||||||
const options = ref([
|
const options = ref([
|
||||||
{
|
{
|
||||||
name: '必应',
|
label: '必应',
|
||||||
value: 'bing',
|
value: 'bing',
|
||||||
url: 'https://cn.bing.com/search?q='
|
url: 'https://cn.bing.com/search?q='
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '百度',
|
label: '百度',
|
||||||
value: 'baidu',
|
value: 'baidu',
|
||||||
url: 'https://www.baidu.com/s?wd='
|
url: 'https://www.baidu.com/s?wd='
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '谷歌',
|
label: '谷歌',
|
||||||
value: 'google',
|
value: 'google',
|
||||||
url: 'https://www.google.com/search?q='
|
url: 'https://www.google.com/search?q='
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '翻译',
|
label: '翻译',
|
||||||
value: 'trans',
|
value: 'trans',
|
||||||
url: 'https://translate.volcengine.com?text='
|
url: 'https://translate.volcengine.com?text='
|
||||||
},
|
},
|
||||||
@ -197,9 +227,9 @@ const options = ref([
|
|||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
const navlist: any = ref([])
|
const navlist = ref<NavItem[]>([])
|
||||||
let cloneNavlist: any = []
|
let cloneNavlist: NavItem[] = []
|
||||||
const tagList: any = ref([
|
const tagList = ref<TagItem[]>([
|
||||||
{
|
{
|
||||||
name: '全部',
|
name: '全部',
|
||||||
color: '',
|
color: '',
|
||||||
@ -209,11 +239,11 @@ const tagList: any = ref([
|
|||||||
|
|
||||||
|
|
||||||
const usrLog = $store.log.useLogStore()
|
const usrLog = $store.log.useLogStore()
|
||||||
let timer: any = null;
|
let timer: any = null
|
||||||
|
|
||||||
// 输入搜索内容时监听searchWord在navlist中模糊搜索
|
// 输入搜索内容时监听searchWord在navlist中模糊搜索
|
||||||
watch(searchWord, () => {
|
watch(searchWord, () => {
|
||||||
handdleInput()
|
handleInput()
|
||||||
})
|
})
|
||||||
|
|
||||||
function cancelSbox() {
|
function cancelSbox() {
|
||||||
@ -224,7 +254,7 @@ function cancelSbox() {
|
|||||||
}, 200)
|
}, 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handdleInput() {
|
function handleInput() {
|
||||||
if (!searchWord.value) {
|
if (!searchWord.value) {
|
||||||
searchItems.value = []
|
searchItems.value = []
|
||||||
searchBox.value = false
|
searchBox.value = false
|
||||||
@ -234,24 +264,23 @@ function handdleInput() {
|
|||||||
searchBox.value = true
|
searchBox.value = true
|
||||||
selecedIdx.value = 0
|
selecedIdx.value = 0
|
||||||
const keyword = searchWord.value.toLowerCase()
|
const keyword = searchWord.value.toLowerCase()
|
||||||
searchItems.value = navlist.value.filter((item: any) =>
|
searchItems.value = navlist.value.filter((item) =>
|
||||||
item.menu_name.toLowerCase().includes(keyword) ||
|
item.menu_name.toLowerCase().includes(keyword) ||
|
||||||
item.menu_link.toLowerCase().includes(keyword) ||
|
item.menu_link.toLowerCase().includes(keyword) ||
|
||||||
item.tag.toLowerCase().includes(keyword)
|
item.tag.toLowerCase().includes(keyword)
|
||||||
)
|
)
|
||||||
// 在searchItems第一个位置插入一条原本搜索
|
// 在searchItems第一个位置插入一条原本搜索
|
||||||
searchItems.value.unshift({
|
searchItems.value.unshift({
|
||||||
menu_name: `在${getDictValue(options.value, "value", broswer.value, "name")}中搜索"${searchWord.value}"`,
|
menu_name: `在${getDictValue(options.value, "value", broswer.value, "label")}中搜索"${searchWord.value}"`,
|
||||||
menu_link: getDictValue(options.value, "value", broswer.value, "url") + searchWord.value,
|
menu_link: getDictValue(options.value, "value", broswer.value, "url") + searchWord.value,
|
||||||
tag: ''
|
tag: ''
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function handdleKeyup(e: any) {
|
function handleKeyup(e: KeyboardEvent) {
|
||||||
if (!searchBox.value) return
|
if (!searchBox.value) return
|
||||||
// console.log('>>> --> haddleDown --> idx:', e.keyCode)
|
|
||||||
// 向下箭头
|
// 向下箭头
|
||||||
if (e.keyCode == 40) {
|
if (e.keyCode === 40) {
|
||||||
if (selecedIdx.value < searchItems.value.length - 1) {
|
if (selecedIdx.value < searchItems.value.length - 1) {
|
||||||
selecedIdx.value += 1
|
selecedIdx.value += 1
|
||||||
} else {
|
} else {
|
||||||
@ -259,7 +288,7 @@ function handdleKeyup(e: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 向上箭头
|
// 向上箭头
|
||||||
else if (e.keyCode == 38) {
|
else if (e.keyCode === 38) {
|
||||||
if (selecedIdx.value > 0) {
|
if (selecedIdx.value > 0) {
|
||||||
selecedIdx.value -= 1
|
selecedIdx.value -= 1
|
||||||
} else {
|
} else {
|
||||||
@ -267,7 +296,7 @@ function handdleKeyup(e: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 回车键
|
// 回车键
|
||||||
else if (e.keyCode == 13) {
|
else if (e.keyCode === 13) {
|
||||||
if (searchItems.value.length > 0) {
|
if (searchItems.value.length > 0) {
|
||||||
const selectedItem = searchItems.value[selecedIdx.value]
|
const selectedItem = searchItems.value[selecedIdx.value]
|
||||||
window.open(selectedItem.menu_link, "_BLANK")
|
window.open(selectedItem.menu_link, "_BLANK")
|
||||||
@ -281,19 +310,23 @@ function handdleKeyup(e: any) {
|
|||||||
|
|
||||||
// 2秒后自动隐藏菜单
|
// 2秒后自动隐藏菜单
|
||||||
const hideMenu = () => {
|
const hideMenu = () => {
|
||||||
|
if (timer) clearTimeout(timer)
|
||||||
timer = setTimeout(() => {
|
timer = setTimeout(() => {
|
||||||
menuShow.value = false
|
menuShow.value = false
|
||||||
}, 2000)
|
}, 2000)
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeTimer = () => {
|
const removeTimer = () => {
|
||||||
clearTimeout(timer)
|
if (timer) {
|
||||||
|
clearTimeout(timer)
|
||||||
|
timer = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handdleMenuItem(type: number) {
|
function handleMenuItem(type: number) {
|
||||||
menuShow.value = false
|
menuShow.value = false
|
||||||
currentClickedItem.value = type
|
currentClickedItem.value = type
|
||||||
if (type == 4) {
|
if (type === 4) {
|
||||||
// 删除导航
|
// 删除导航
|
||||||
if (!currentItem.value) return
|
if (!currentItem.value) return
|
||||||
$modal({
|
$modal({
|
||||||
@ -302,9 +335,8 @@ function handdleMenuItem(type: number) {
|
|||||||
cancelText: '取消',
|
cancelText: '取消',
|
||||||
submitText: '删除',
|
submitText: '删除',
|
||||||
handdleSubmit: async () => {
|
handdleSubmit: async () => {
|
||||||
const res = await $http.nav.deleteNav(currentItem.value.nid)
|
const res = await $http.nav.deleteNav(currentItem.value?.nid)
|
||||||
console.log('>>> --> handdleMenuItem --> res:', res)
|
if (res.code === 200) {
|
||||||
if (res.code == 200) {
|
|
||||||
$msg.success('删除成功')
|
$msg.success('删除成功')
|
||||||
getNavList()
|
getNavList()
|
||||||
}
|
}
|
||||||
@ -315,27 +347,26 @@ function handdleMenuItem(type: number) {
|
|||||||
editModal.value = true
|
editModal.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function handdleItemCancel() {
|
function handleItemCancel() {
|
||||||
editModal.value = false
|
editModal.value = false
|
||||||
editInput.value = ''
|
editInput.value = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handdleItemSubmit() {
|
async function handleItemSubmit() {
|
||||||
if (!editInput.value) {
|
if (!editInput.value) {
|
||||||
$msg.error('请输入修改内容')
|
$msg.error('请输入修改内容')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let updateData: any = {}
|
let updateData: Partial<NavItem> = {}
|
||||||
if (currentClickedItem.value == 1) {
|
if (currentClickedItem.value === 1) {
|
||||||
updateData.menu_name = editInput.value
|
updateData.menu_name = editInput.value
|
||||||
} else if (currentClickedItem.value == 2) {
|
} else if (currentClickedItem.value === 2) {
|
||||||
updateData.menu_link = editInput.value
|
updateData.menu_link = editInput.value
|
||||||
} else if (currentClickedItem.value == 3) {
|
} else if (currentClickedItem.value === 3) {
|
||||||
updateData.tag = editInput.value.slice(0, 4)
|
updateData.tag = editInput.value.slice(0, 4)
|
||||||
}
|
}
|
||||||
const res = await $http.nav.editNav(currentItem.value.nid, updateData)
|
const res = await $http.nav.editNav(currentItem.value!.nid!, updateData)
|
||||||
console.log('>>> --> handdleItemSubmit --> res:', res)
|
if (res.code === 200) {
|
||||||
if (res.code == 200) {
|
|
||||||
$msg.success('修改成功')
|
$msg.success('修改成功')
|
||||||
editModal.value = false
|
editModal.value = false
|
||||||
editInput.value = ''
|
editInput.value = ''
|
||||||
@ -350,23 +381,30 @@ async function getNavList() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const res = await $http.nav.getNavList()
|
const res = await $http.nav.getNavList()
|
||||||
res.data?.forEach((i: any) => {
|
if (!res.data) return
|
||||||
i.icon_error = false
|
|
||||||
i.first = i.menu_name.at(0)
|
|
||||||
i.color = getRandomDarkColor()
|
|
||||||
});
|
|
||||||
navlist.value = res.data
|
|
||||||
|
|
||||||
console.log("&&&&&&&&&&&&&&", navlist.value);
|
// 合并两个循环,提高性能
|
||||||
res.data.forEach((i: any) => {
|
res.data.forEach((i: any) => {
|
||||||
if (!tagList.value.find((t: any) => t.name == i.tag))
|
i.icon_error = false
|
||||||
tagList.value.push({ name: i.tag.substring(0, 4), color: getRandomDarkColor(30, 128), checked: false })
|
i.first = i.menu_name?.at(0) || ''
|
||||||
})
|
i.color = getRandomDarkColor()
|
||||||
|
|
||||||
|
// 同时处理标签列表
|
||||||
|
if (!tagList.value.find((t) => t.name === i.tag)) {
|
||||||
|
tagList.value.push({
|
||||||
|
name: i.tag.substring(0, 4),
|
||||||
|
color: getRandomDarkColor(30, 128),
|
||||||
|
checked: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
navlist.value = res.data
|
||||||
cloneNavlist = deepclone(res.data)
|
cloneNavlist = deepclone(res.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getItemColor(item: any) {
|
function getItemColor(item: NavItem) {
|
||||||
const tag = tagList.value.find((t: any) => t.name == item.tag)
|
const tag = tagList.value.find((t) => t.name === item.tag)
|
||||||
return tag ? tag.color : getRandomDarkColor(30, 128)
|
return tag ? tag.color : getRandomDarkColor(30, 128)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,6 +491,8 @@ function addNav() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getIcon() {
|
async function getIcon() {
|
||||||
|
console.log(11111);
|
||||||
|
|
||||||
if (!navData.menu_link) return
|
if (!navData.menu_link) return
|
||||||
const res = await $http.mix.getIcon({
|
const res = await $http.mix.getIcon({
|
||||||
url: navData.menu_link
|
url: navData.menu_link
|
||||||
@ -463,9 +503,15 @@ async function getIcon() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resetNav() {
|
||||||
|
navData.menu_link = ''
|
||||||
|
navData.menu_name = ''
|
||||||
|
navData.tag = ''
|
||||||
|
navData.menu_icon = ''
|
||||||
|
}
|
||||||
function navCancel() {
|
function navCancel() {
|
||||||
visible.value = false
|
visible.value = false
|
||||||
formNav.value.resetFields()
|
resetNav()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function navSubmit() {
|
async function navSubmit() {
|
||||||
@ -481,14 +527,10 @@ async function navSubmit() {
|
|||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
$msg.success('添加成功')
|
$msg.success('添加成功')
|
||||||
visible.value = false
|
visible.value = false
|
||||||
formNav.value.resetFields()
|
|
||||||
getNavList()
|
getNavList()
|
||||||
}
|
}
|
||||||
// 清空navData
|
// 清空navData
|
||||||
navData.menu_link = ''
|
resetNav()
|
||||||
navData.menu_name = ''
|
|
||||||
navData.tag = ''
|
|
||||||
navData.menu_icon = ''
|
|
||||||
}
|
}
|
||||||
// 处理右键菜单
|
// 处理右键菜单
|
||||||
function handdleContextMenu(event: MouseEvent, item: any) {
|
function handdleContextMenu(event: MouseEvent, item: any) {
|
||||||
@ -503,7 +545,7 @@ function handdleContextMenu(event: MouseEvent, item: any) {
|
|||||||
|
|
||||||
|
|
||||||
// 监听store的登录状态
|
// 监听store的登录状态
|
||||||
watch(() => usrLog.isLogin, (newVal) => {
|
watch(() => usrLog.isLogin, (newVal: any) => {
|
||||||
console.log('********** --> watch --> newVal:', newVal)
|
console.log('********** --> watch --> newVal:', newVal)
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
getNavList()
|
getNavList()
|
||||||
@ -511,17 +553,97 @@ watch(() => usrLog.isLogin, (newVal) => {
|
|||||||
navlist.value = []
|
navlist.value = []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
function handdleKeyup(e: any) {
|
||||||
|
if (!searchBox.value) return
|
||||||
|
// console.log('>>> --> haddleDown --> idx:', e.keyCode)
|
||||||
|
// 向下箭头
|
||||||
|
if (e.keyCode == 40) {
|
||||||
|
if (selecedIdx.value < searchItems.value.length - 1) {
|
||||||
|
selecedIdx.value += 1
|
||||||
|
} else {
|
||||||
|
selecedIdx.value = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 向上箭头
|
||||||
|
else if (e.keyCode == 38) {
|
||||||
|
if (selecedIdx.value > 0) {
|
||||||
|
selecedIdx.value -= 1
|
||||||
|
} else {
|
||||||
|
selecedIdx.value = searchItems.value.length - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 回车键
|
||||||
|
else if (e.keyCode == 13) {
|
||||||
|
if (searchItems.value.length > 0) {
|
||||||
|
const selectedItem = searchItems.value[selecedIdx.value]
|
||||||
|
window.open(selectedItem.menu_link, "_BLANK")
|
||||||
|
searchBox.value = false
|
||||||
|
selecedIdx.value = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handdleItemCancel() {
|
||||||
|
editModal.value = false
|
||||||
|
editInput.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handdleItemSubmit() {
|
||||||
|
if (!editInput.value) {
|
||||||
|
$msg.error('请输入修改内容')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let updateData: any = {}
|
||||||
|
if (currentClickedItem.value == 1) {
|
||||||
|
updateData.menu_name = editInput.value
|
||||||
|
} else if (currentClickedItem.value == 2) {
|
||||||
|
updateData.menu_link = editInput.value
|
||||||
|
} else if (currentClickedItem.value == 3) {
|
||||||
|
updateData.tag = editInput.value.slice(0, 4)
|
||||||
|
}
|
||||||
|
const res = await $http.nav.editNav(currentItem.value?.nid, updateData)
|
||||||
|
console.log('>>> --> handdleItemSubmit --> res:', res)
|
||||||
|
if (res.code == 200) {
|
||||||
|
$msg.success('修改成功')
|
||||||
|
editModal.value = false
|
||||||
|
editInput.value = ''
|
||||||
|
getNavList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handdleMenuItem(type: number) {
|
||||||
|
menuShow.value = false
|
||||||
|
currentClickedItem.value = type
|
||||||
|
if (type == 4) {
|
||||||
|
// 删除导航
|
||||||
|
if (!currentItem.value) return
|
||||||
|
$modal({
|
||||||
|
title: '删除导航',
|
||||||
|
content: `确定要删除【${currentItem.value.menu_name}】吗?删除后不可恢复哦~`,
|
||||||
|
cancelText: '取消',
|
||||||
|
submitText: '删除',
|
||||||
|
handdleSubmit: async () => {
|
||||||
|
const res = await $http.nav.deleteNav(currentItem.value?.nid)
|
||||||
|
console.log('>>> --> handdleMenuItem --> res:', res)
|
||||||
|
if (res.code == 200) {
|
||||||
|
$msg.success('删除成功')
|
||||||
|
getNavList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
editModal.value = true
|
||||||
|
}
|
||||||
|
const navHeight: any = ref(0)
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
console.log("&&&&&&&&&&&&&&", nav.navH);
|
console.log("&&&&&&&&&&&&&&", nav.navH);
|
||||||
contentStyle.value = {
|
contentStyle.value = {
|
||||||
height: `${window.innerHeight - nav.navH}px)`
|
height: `${window.innerHeight - nav.navH}px)`
|
||||||
}
|
}
|
||||||
|
console.log('>>> --> onMounted --> navcards.value.getBoundingClientRect().y:', navcards.value.getBoundingClientRect().y)
|
||||||
|
navHeight.value = window.innerHeight - navcards.value.getBoundingClientRect().y
|
||||||
navStyle.value = {
|
navStyle.value = {
|
||||||
// height: `calc(100vh - ${navcards.value.getBoundingClientRect().y}px - ${nav.navH}px)`,
|
// height: `calc(100vh - ${navcards.value.getBoundingClientRect().y}px - ${nav.navH}px)`,
|
||||||
height: `${window.innerHeight - navcards.value.getBoundingClientRect().y - 20}px`
|
height: `${window.innerHeight - navcards.value.getBoundingClientRect().y}px`
|
||||||
}
|
}
|
||||||
tagList.value = [
|
tagList.value = [
|
||||||
{
|
{
|
||||||
@ -536,7 +658,7 @@ onMounted(() => {
|
|||||||
height: `calc(100vh - ${nav.navH}px)`
|
height: `calc(100vh - ${nav.navH}px)`
|
||||||
}
|
}
|
||||||
navStyle.value = {
|
navStyle.value = {
|
||||||
height: `${window.innerHeight - navcards.value.getBoundingClientRect().top - 20}px`
|
height: `${navHeight.value}px`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
window.addEventListener('keyup', (e: Event) => {
|
window.addEventListener('keyup', (e: Event) => {
|
||||||
|
|||||||
@ -1,22 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="widget-page">
|
<div class="widget-page">
|
||||||
<h1>工具页</h1>
|
<h1>工具页</h1>
|
||||||
|
|
||||||
<d-card class="w-1/3 bg-[#ffffff60] rounded-[10px]" shadow="hover">
|
|
||||||
<template #title>
|
|
||||||
<div class="flex items-center">
|
|
||||||
<icon-widget class="w-5 mr-2"></icon-widget>
|
|
||||||
视频工具
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #content>
|
|
||||||
<div class="p-4">
|
|
||||||
<vue3VideoPlay class="w-full" title="钢铁侠" src="https://cdn.jsdelivr.net/gh/xdlumia/files/video-play/IronMan.mp4" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</d-card>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -1,21 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
这里是控制台首页
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
//mark import
|
|
||||||
|
|
||||||
//mark data
|
|
||||||
|
|
||||||
//mark method
|
|
||||||
|
|
||||||
//mark 周期、内置函数等
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
|
|
||||||
</style>
|
|
||||||
11
typed-router.d.ts
vendored
11
typed-router.d.ts
vendored
@ -19,8 +19,7 @@ declare module 'vue-router/auto-routes' {
|
|||||||
*/
|
*/
|
||||||
export interface RouteNamedMap {
|
export interface RouteNamedMap {
|
||||||
'appshare': RouteRecordInfo<'appshare', '/AppShare', Record<never, never>, Record<never, never>>,
|
'appshare': RouteRecordInfo<'appshare', '/AppShare', Record<never, never>, Record<never, never>>,
|
||||||
'article': RouteRecordInfo<'article', '/Article', Record<never, never>, Record<never, never>>,
|
'blog': RouteRecordInfo<'blog', '/Blog', Record<never, never>, Record<never, never>>,
|
||||||
'/console/home': RouteRecordInfo<'/console/home', '/console/home', Record<never, never>, Record<never, never>>,
|
|
||||||
'gallery': RouteRecordInfo<'gallery', '/Gallery', Record<never, never>, Record<never, never>>,
|
'gallery': RouteRecordInfo<'gallery', '/Gallery', Record<never, never>, Record<never, never>>,
|
||||||
'home': RouteRecordInfo<'home', '/Home', Record<never, never>, Record<never, never>>,
|
'home': RouteRecordInfo<'home', '/Home', Record<never, never>, Record<never, never>>,
|
||||||
'404': RouteRecordInfo<'404', '/NotFound', Record<never, never>, Record<never, never>>,
|
'404': RouteRecordInfo<'404', '/NotFound', Record<never, never>, Record<never, never>>,
|
||||||
@ -43,12 +42,8 @@ declare module 'vue-router/auto-routes' {
|
|||||||
routes: 'appshare'
|
routes: 'appshare'
|
||||||
views: never
|
views: never
|
||||||
}
|
}
|
||||||
'src/views/Article.vue': {
|
'src/views/Blog.vue': {
|
||||||
routes: 'article'
|
routes: 'blog'
|
||||||
views: never
|
|
||||||
}
|
|
||||||
'src/views/console/home.vue': {
|
|
||||||
routes: '/console/home'
|
|
||||||
views: never
|
views: never
|
||||||
}
|
}
|
||||||
'src/views/Gallery.vue': {
|
'src/views/Gallery.vue': {
|
||||||
|
|||||||
@ -3,10 +3,10 @@ import { fileURLToPath, URL } from "node:url";
|
|||||||
import { resolve } from "path";
|
import { resolve } from "path";
|
||||||
import UnoCSS from "unocss/vite";
|
import UnoCSS from "unocss/vite";
|
||||||
import AutoImport from "unplugin-auto-import/vite";
|
import AutoImport from "unplugin-auto-import/vite";
|
||||||
import { DevUiResolver } from "unplugin-vue-components/resolvers";
|
import { NaiveUiResolver } from "unplugin-vue-components/resolvers";
|
||||||
import Components from "unplugin-vue-components/vite";
|
import Components from "unplugin-vue-components/vite";
|
||||||
import { VueRouterAutoImports } from 'unplugin-vue-router';
|
import { VueRouterAutoImports } from "unplugin-vue-router";
|
||||||
import VueRouter from 'unplugin-vue-router/vite';
|
import VueRouter from "unplugin-vue-router/vite";
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
// import vueDevTools from "vite-plugin-vue-devtools";
|
// import vueDevTools from "vite-plugin-vue-devtools";
|
||||||
import svgLoader from "vite-svg-loader";
|
import svgLoader from "vite-svg-loader";
|
||||||
@ -20,11 +20,18 @@ export default defineConfig({
|
|||||||
}),
|
}),
|
||||||
AutoImport({
|
AutoImport({
|
||||||
include: [/\.[tj]sx?$/, /\.vue$/, /\.vue\?vue/, /\.md$/],
|
include: [/\.[tj]sx?$/, /\.vue$/, /\.vue\?vue/, /\.md$/],
|
||||||
imports: ["vue", "pinia", VueRouterAutoImports],
|
imports: [
|
||||||
|
"vue",
|
||||||
|
"pinia",
|
||||||
|
VueRouterAutoImports,
|
||||||
|
{
|
||||||
|
"naive-ui": ["useDialog", "useMessage", "useNotification", "useLoadingBar"],
|
||||||
|
},
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Components({
|
Components({
|
||||||
resolvers: [DevUiResolver()],
|
resolvers: [NaiveUiResolver()],
|
||||||
dirs: ["src/components"],
|
dirs: ["src/components"],
|
||||||
}),
|
}),
|
||||||
UnoCSS(),
|
UnoCSS(),
|
||||||
@ -39,7 +46,7 @@ export default defineConfig({
|
|||||||
base: "/blog/",
|
base: "/blog/",
|
||||||
server: {
|
server: {
|
||||||
host: "0.0.0.0",
|
host: "0.0.0.0",
|
||||||
port: 8080,
|
port: 8989,
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
|||||||
439
yarn.lock
439
yarn.lock
@ -10,15 +10,6 @@
|
|||||||
"@jridgewell/gen-mapping" "^0.3.5"
|
"@jridgewell/gen-mapping" "^0.3.5"
|
||||||
"@jridgewell/trace-mapping" "^0.3.24"
|
"@jridgewell/trace-mapping" "^0.3.24"
|
||||||
|
|
||||||
"@angular/cdk@^18.0.0":
|
|
||||||
version "18.2.14"
|
|
||||||
resolved "https://registry.npmmirror.com/@angular/cdk/-/cdk-18.2.14.tgz#6114f37a77f2f182de482da2273c70f74a6cc52d"
|
|
||||||
integrity sha512-vDyOh1lwjfVk9OqoroZAP8pf3xxKUvyl+TVR8nJxL4c5fOfUFkD7l94HaanqKSRwJcI2xiztuu92IVoHn8T33Q==
|
|
||||||
dependencies:
|
|
||||||
tslib "^2.3.0"
|
|
||||||
optionalDependencies:
|
|
||||||
parse5 "^7.1.2"
|
|
||||||
|
|
||||||
"@antfu/install-pkg@^1.0.0":
|
"@antfu/install-pkg@^1.0.0":
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.npmmirror.com/@antfu/install-pkg/-/install-pkg-1.1.0.tgz#78fa036be1a6081b5a77a5cf59f50c7752b6ba26"
|
resolved "https://registry.npmmirror.com/@antfu/install-pkg/-/install-pkg-1.1.0.tgz#78fa036be1a6081b5a77a5cf59f50c7752b6ba26"
|
||||||
@ -279,11 +270,6 @@
|
|||||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.27.1"
|
"@babel/helper-skip-transparent-expression-wrappers" "^7.27.1"
|
||||||
"@babel/plugin-syntax-typescript" "^7.27.1"
|
"@babel/plugin-syntax-typescript" "^7.27.1"
|
||||||
|
|
||||||
"@babel/runtime@^7.21.0":
|
|
||||||
version "7.28.2"
|
|
||||||
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.28.2.tgz#2ae5a9d51cc583bd1f5673b3bb70d6d819682473"
|
|
||||||
integrity sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==
|
|
||||||
|
|
||||||
"@babel/template@^7.26.9", "@babel/template@^7.27.2":
|
"@babel/template@^7.26.9", "@babel/template@^7.27.2":
|
||||||
version "7.27.2"
|
version "7.27.2"
|
||||||
resolved "https://registry.npmmirror.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d"
|
resolved "https://registry.npmmirror.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d"
|
||||||
@ -306,15 +292,7 @@
|
|||||||
"@babel/types" "^7.28.0"
|
"@babel/types" "^7.28.0"
|
||||||
debug "^4.3.1"
|
debug "^4.3.1"
|
||||||
|
|
||||||
"@babel/types@^7.24.7", "@babel/types@^7.26.9", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.0", "@babel/types@^7.28.2":
|
"@babel/types@^7.24.7", "@babel/types@^7.28.5":
|
||||||
version "7.28.2"
|
|
||||||
resolved "https://registry.npmmirror.com/@babel/types/-/types-7.28.2.tgz#da9db0856a9a88e0a13b019881d7513588cf712b"
|
|
||||||
integrity sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==
|
|
||||||
dependencies:
|
|
||||||
"@babel/helper-string-parser" "^7.27.1"
|
|
||||||
"@babel/helper-validator-identifier" "^7.27.1"
|
|
||||||
|
|
||||||
"@babel/types@^7.28.5":
|
|
||||||
version "7.28.5"
|
version "7.28.5"
|
||||||
resolved "https://registry.npmmirror.com/@babel/types/-/types-7.28.5.tgz#10fc405f60897c35f07e85493c932c7b5ca0592b"
|
resolved "https://registry.npmmirror.com/@babel/types/-/types-7.28.5.tgz#10fc405f60897c35f07e85493c932c7b5ca0592b"
|
||||||
integrity sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==
|
integrity sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==
|
||||||
@ -322,16 +300,49 @@
|
|||||||
"@babel/helper-string-parser" "^7.27.1"
|
"@babel/helper-string-parser" "^7.27.1"
|
||||||
"@babel/helper-validator-identifier" "^7.28.5"
|
"@babel/helper-validator-identifier" "^7.28.5"
|
||||||
|
|
||||||
|
"@babel/types@^7.26.9", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.0", "@babel/types@^7.28.2":
|
||||||
|
version "7.28.2"
|
||||||
|
resolved "https://registry.npmmirror.com/@babel/types/-/types-7.28.2.tgz#da9db0856a9a88e0a13b019881d7513588cf712b"
|
||||||
|
integrity sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-string-parser" "^7.27.1"
|
||||||
|
"@babel/helper-validator-identifier" "^7.27.1"
|
||||||
|
|
||||||
"@braintree/sanitize-url@^6.0.0":
|
"@braintree/sanitize-url@^6.0.0":
|
||||||
version "6.0.4"
|
version "6.0.4"
|
||||||
resolved "https://registry.npmmirror.com/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz#923ca57e173c6b232bbbb07347b1be982f03e783"
|
resolved "https://registry.npmmirror.com/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz#923ca57e173c6b232bbbb07347b1be982f03e783"
|
||||||
integrity sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==
|
integrity sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==
|
||||||
|
|
||||||
"@devui-design/icons@^1.3.0", "@devui-design/icons@^1.4.0":
|
"@css-render/plugin-bem@^0.15.14":
|
||||||
|
version "0.15.14"
|
||||||
|
resolved "https://registry.npmmirror.com/@css-render/plugin-bem/-/plugin-bem-0.15.14.tgz#de13fc9f59299c2b646119851763dfa08929b3c1"
|
||||||
|
integrity sha512-QK513CJ7yEQxm/P3EwsI+d+ha8kSOcjGvD6SevM41neEMxdULE+18iuQK6tEChAWMOQNQPLG/Rw3Khb69r5neg==
|
||||||
|
|
||||||
|
"@css-render/vue3-ssr@^0.15.10", "@css-render/vue3-ssr@^0.15.14":
|
||||||
|
version "0.15.14"
|
||||||
|
resolved "https://registry.npmmirror.com/@css-render/vue3-ssr/-/vue3-ssr-0.15.14.tgz#a2f4dedc3e86211a3ce1445555265095b7736491"
|
||||||
|
integrity sha512-//8027GSbxE9n3QlD73xFY6z4ZbHbvrOVB7AO6hsmrEzGbg+h2A09HboUyDgu+xsmj7JnvJD39Irt+2D0+iV8g==
|
||||||
|
|
||||||
|
"@ctrl/tinycolor@^3.4.1":
|
||||||
|
version "3.6.1"
|
||||||
|
resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz#b6c75a56a1947cc916ea058772d666a2c8932f31"
|
||||||
|
integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==
|
||||||
|
|
||||||
|
"@devui-design/icons@^1.3.0":
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.npmmirror.com/@devui-design/icons/-/icons-1.4.0.tgz#41fe1ce82e1aa6b111ca30c6a553cfc4a073fd47"
|
resolved "https://registry.npmmirror.com/@devui-design/icons/-/icons-1.4.0.tgz#41fe1ce82e1aa6b111ca30c6a553cfc4a073fd47"
|
||||||
integrity sha512-taAX1RNW0QHUqQTRPqLTYTB2PZIqUplhWeF4hcmWkSTjpWlDNI40DssG/WRb3sISkfBk/4BMUxxC5XeTL3jo7A==
|
integrity sha512-taAX1RNW0QHUqQTRPqLTYTB2PZIqUplhWeF4hcmWkSTjpWlDNI40DssG/WRb3sISkfBk/4BMUxxC5XeTL3jo7A==
|
||||||
|
|
||||||
|
"@element-plus/icons-vue@^2.3.2":
|
||||||
|
version "2.3.2"
|
||||||
|
resolved "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz#7e9cb231fb738b2056f33e22c3a29e214b538dcf"
|
||||||
|
integrity sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==
|
||||||
|
|
||||||
|
"@emotion/hash@~0.8.0":
|
||||||
|
version "0.8.0"
|
||||||
|
resolved "https://registry.npmmirror.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
|
||||||
|
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
|
||||||
|
|
||||||
"@esbuild/aix-ppc64@0.25.8":
|
"@esbuild/aix-ppc64@0.25.8":
|
||||||
version "0.25.8"
|
version "0.25.8"
|
||||||
resolved "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz#a1414903bb38027382f85f03dda6065056757727"
|
resolved "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz#a1414903bb38027382f85f03dda6065056757727"
|
||||||
@ -462,10 +473,10 @@
|
|||||||
resolved "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz#610d7ea539d2fcdbe39237b5cc175eb2c4451f9c"
|
resolved "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz#610d7ea539d2fcdbe39237b5cc175eb2c4451f9c"
|
||||||
integrity sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==
|
integrity sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==
|
||||||
|
|
||||||
"@floating-ui/core@^1.2.4":
|
"@floating-ui/core@^1.2.4", "@floating-ui/core@^1.7.3":
|
||||||
version "1.7.2"
|
version "1.7.3"
|
||||||
resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.2.tgz#3d1c35263950b314b6d5a72c8bfb9e3c1551aefd"
|
resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.3.tgz#462d722f001e23e46d86fd2bd0d21b7693ccb8b7"
|
||||||
integrity sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==
|
integrity sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@floating-ui/utils" "^0.2.10"
|
"@floating-ui/utils" "^0.2.10"
|
||||||
|
|
||||||
@ -476,6 +487,14 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@floating-ui/core" "^1.2.4"
|
"@floating-ui/core" "^1.2.4"
|
||||||
|
|
||||||
|
"@floating-ui/dom@^1.0.1":
|
||||||
|
version "1.7.4"
|
||||||
|
resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.4.tgz#ee667549998745c9c3e3e84683b909c31d6c9a77"
|
||||||
|
integrity sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==
|
||||||
|
dependencies:
|
||||||
|
"@floating-ui/core" "^1.7.3"
|
||||||
|
"@floating-ui/utils" "^0.2.10"
|
||||||
|
|
||||||
"@floating-ui/utils@^0.2.10":
|
"@floating-ui/utils@^0.2.10":
|
||||||
version "0.2.10"
|
version "0.2.10"
|
||||||
resolved "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.10.tgz#a2a1e3812d14525f725d011a73eceb41fef5bc1c"
|
resolved "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.10.tgz#a2a1e3812d14525f725d011a73eceb41fef5bc1c"
|
||||||
@ -550,6 +569,11 @@
|
|||||||
"@jridgewell/resolve-uri" "^3.1.0"
|
"@jridgewell/resolve-uri" "^3.1.0"
|
||||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||||
|
|
||||||
|
"@juggle/resize-observer@^3.3.1":
|
||||||
|
version "3.4.0"
|
||||||
|
resolved "https://registry.npmmirror.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
|
||||||
|
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
|
||||||
|
|
||||||
"@meting/core@^1.5.13":
|
"@meting/core@^1.5.13":
|
||||||
version "1.5.13"
|
version "1.5.13"
|
||||||
resolved "https://registry.npmmirror.com/@meting/core/-/core-1.5.13.tgz#d5178b99124e5ba8e5cef36ca70d6e63d7426339"
|
resolved "https://registry.npmmirror.com/@meting/core/-/core-1.5.13.tgz#d5178b99124e5ba8e5cef36ca70d6e63d7426339"
|
||||||
@ -560,10 +584,10 @@
|
|||||||
resolved "https://registry.npmmirror.com/@polka/url/-/url-1.0.0-next.29.tgz#5a40109a1ab5f84d6fd8fc928b19f367cbe7e7b1"
|
resolved "https://registry.npmmirror.com/@polka/url/-/url-1.0.0-next.29.tgz#5a40109a1ab5f84d6fd8fc928b19f367cbe7e7b1"
|
||||||
integrity sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==
|
integrity sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==
|
||||||
|
|
||||||
"@popperjs/core@^2.5.4":
|
"@popperjs/core@npm:@sxzz/popperjs-es@^2.11.7":
|
||||||
version "2.11.8"
|
version "2.11.7"
|
||||||
resolved "https://registry.npmmirror.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
|
resolved "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz#a7f69e3665d3da9b115f9e71671dae1b97e13671"
|
||||||
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
|
integrity sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==
|
||||||
|
|
||||||
"@quansync/fs@^0.1.1":
|
"@quansync/fs@^0.1.1":
|
||||||
version "0.1.3"
|
version "0.1.3"
|
||||||
@ -709,7 +733,12 @@
|
|||||||
resolved "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e"
|
resolved "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e"
|
||||||
integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==
|
integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==
|
||||||
|
|
||||||
"@types/lodash-es@^4.17.4":
|
"@types/katex@^0.16.2":
|
||||||
|
version "0.16.7"
|
||||||
|
resolved "https://registry.npmmirror.com/@types/katex/-/katex-0.16.7.tgz#03ab680ab4fa4fbc6cb46ecf987ecad5d8019868"
|
||||||
|
integrity sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==
|
||||||
|
|
||||||
|
"@types/lodash-es@^4.17.12", "@types/lodash-es@^4.17.4":
|
||||||
version "4.17.12"
|
version "4.17.12"
|
||||||
resolved "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz#65f6d1e5f80539aa7cfbfc962de5def0cf4f341b"
|
resolved "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz#65f6d1e5f80539aa7cfbfc962de5def0cf4f341b"
|
||||||
integrity sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==
|
integrity sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==
|
||||||
@ -721,6 +750,11 @@
|
|||||||
resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.20.tgz#1ca77361d7363432d29f5e55950d9ec1e1c6ea93"
|
resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.20.tgz#1ca77361d7363432d29f5e55950d9ec1e1c6ea93"
|
||||||
integrity sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==
|
integrity sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==
|
||||||
|
|
||||||
|
"@types/lodash@^4.17.20":
|
||||||
|
version "4.17.21"
|
||||||
|
resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.21.tgz#b806831543d696b14f8112db600ea9d3a1df6ea4"
|
||||||
|
integrity sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==
|
||||||
|
|
||||||
"@types/node@^22.16.5":
|
"@types/node@^22.16.5":
|
||||||
version "22.16.5"
|
version "22.16.5"
|
||||||
resolved "https://registry.npmmirror.com/@types/node/-/node-22.16.5.tgz#cc46ac3994cd957000d0c11095a0b1dae2ea2368"
|
resolved "https://registry.npmmirror.com/@types/node/-/node-22.16.5.tgz#cc46ac3994cd957000d0c11095a0b1dae2ea2368"
|
||||||
@ -740,6 +774,11 @@
|
|||||||
resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz#94e175b53623384bff1f354cdb3197a8d63cdbe5"
|
resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz#94e175b53623384bff1f354cdb3197a8d63cdbe5"
|
||||||
integrity sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A==
|
integrity sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A==
|
||||||
|
|
||||||
|
"@types/web-bluetooth@^0.0.20":
|
||||||
|
version "0.0.20"
|
||||||
|
resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz#f066abfcd1cbe66267cdbbf0de010d8a41b41597"
|
||||||
|
integrity sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==
|
||||||
|
|
||||||
"@unocss/astro@66.3.3":
|
"@unocss/astro@66.3.3":
|
||||||
version "66.3.3"
|
version "66.3.3"
|
||||||
resolved "https://registry.npmmirror.com/@unocss/astro/-/astro-66.3.3.tgz#707d1df627158540bb91bde2b5f8452c073599f9"
|
resolved "https://registry.npmmirror.com/@unocss/astro/-/astro-66.3.3.tgz#707d1df627158540bb91bde2b5f8452c073599f9"
|
||||||
@ -1380,12 +1419,12 @@
|
|||||||
"@vue/compiler-ssr" "3.6.0-alpha.2"
|
"@vue/compiler-ssr" "3.6.0-alpha.2"
|
||||||
"@vue/shared" "3.6.0-alpha.2"
|
"@vue/shared" "3.6.0-alpha.2"
|
||||||
|
|
||||||
"@vue/shared@3.5.18", "@vue/shared@^3.2.33", "@vue/shared@^3.5.0", "@vue/shared@^3.5.13":
|
"@vue/shared@3.5.18", "@vue/shared@^3.5.0", "@vue/shared@^3.5.13":
|
||||||
version "3.5.18"
|
version "3.5.18"
|
||||||
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.18.tgz#529f24a88d3ed678d50fd5c07455841fbe8ac95e"
|
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.18.tgz#529f24a88d3ed678d50fd5c07455841fbe8ac95e"
|
||||||
integrity sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==
|
integrity sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==
|
||||||
|
|
||||||
"@vue/shared@3.5.26":
|
"@vue/shared@3.5.26", "@vue/shared@^3.2.33":
|
||||||
version "3.5.26"
|
version "3.5.26"
|
||||||
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.26.tgz#1e02ef2d64aced818cd31d81ce5175711dc90a9f"
|
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.26.tgz#1e02ef2d64aced818cd31d81ce5175711dc90a9f"
|
||||||
integrity sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==
|
integrity sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==
|
||||||
@ -1410,11 +1449,33 @@
|
|||||||
"@vueuse/shared" "8.9.4"
|
"@vueuse/shared" "8.9.4"
|
||||||
vue-demi "*"
|
vue-demi "*"
|
||||||
|
|
||||||
|
"@vueuse/core@^10.11.0":
|
||||||
|
version "10.11.1"
|
||||||
|
resolved "https://registry.npmmirror.com/@vueuse/core/-/core-10.11.1.tgz#15d2c0b6448d2212235b23a7ba29c27173e0c2c6"
|
||||||
|
integrity sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==
|
||||||
|
dependencies:
|
||||||
|
"@types/web-bluetooth" "^0.0.20"
|
||||||
|
"@vueuse/metadata" "10.11.1"
|
||||||
|
"@vueuse/shared" "10.11.1"
|
||||||
|
vue-demi ">=0.14.8"
|
||||||
|
|
||||||
|
"@vueuse/metadata@10.11.1":
|
||||||
|
version "10.11.1"
|
||||||
|
resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-10.11.1.tgz#209db7bb5915aa172a87510b6de2ca01cadbd2a7"
|
||||||
|
integrity sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==
|
||||||
|
|
||||||
"@vueuse/metadata@8.9.4":
|
"@vueuse/metadata@8.9.4":
|
||||||
version "8.9.4"
|
version "8.9.4"
|
||||||
resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-8.9.4.tgz#a4132db33e4c1b1023636acfa20aa7b37ab3d978"
|
resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-8.9.4.tgz#a4132db33e4c1b1023636acfa20aa7b37ab3d978"
|
||||||
integrity sha512-IwSfzH80bnJMzqhaapqJl9JRIiyQU0zsRGEgnxN6jhq7992cPUJIRfV+JHRIZXjYqbwt07E1gTEp0R0zPJ1aqw==
|
integrity sha512-IwSfzH80bnJMzqhaapqJl9JRIiyQU0zsRGEgnxN6jhq7992cPUJIRfV+JHRIZXjYqbwt07E1gTEp0R0zPJ1aqw==
|
||||||
|
|
||||||
|
"@vueuse/shared@10.11.1":
|
||||||
|
version "10.11.1"
|
||||||
|
resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-10.11.1.tgz#62b84e3118ae6e1f3ff38f4fbe71b0c5d0f10938"
|
||||||
|
integrity sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==
|
||||||
|
dependencies:
|
||||||
|
vue-demi ">=0.14.8"
|
||||||
|
|
||||||
"@vueuse/shared@8.9.4":
|
"@vueuse/shared@8.9.4":
|
||||||
version "8.9.4"
|
version "8.9.4"
|
||||||
resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-8.9.4.tgz#c9741c30ffb666b50d62f0dd80b76119fd47573e"
|
resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-8.9.4.tgz#c9741c30ffb666b50d62f0dd80b76119fd47573e"
|
||||||
@ -1437,6 +1498,11 @@ alien-signals@^2.0.5:
|
|||||||
resolved "https://registry.npmmirror.com/alien-signals/-/alien-signals-2.0.5.tgz#7528fc28de7cd76ccb6aad1d46d5b5635ce10805"
|
resolved "https://registry.npmmirror.com/alien-signals/-/alien-signals-2.0.5.tgz#7528fc28de7cd76ccb6aad1d46d5b5635ce10805"
|
||||||
integrity sha512-PdJB6+06nUNAClInE3Dweq7/2xVAYM64vvvS1IHVHSJmgeOtEdrAGyp7Z2oJtYm0B342/Exd2NT0uMJaThcjLQ==
|
integrity sha512-PdJB6+06nUNAClInE3Dweq7/2xVAYM64vvvS1IHVHSJmgeOtEdrAGyp7Z2oJtYm0B342/Exd2NT0uMJaThcjLQ==
|
||||||
|
|
||||||
|
animate.css@^4.1.1:
|
||||||
|
version "4.1.1"
|
||||||
|
resolved "https://registry.npmmirror.com/animate.css/-/animate.css-4.1.1.tgz#614ec5a81131d7e4dc362a58143f7406abd68075"
|
||||||
|
integrity sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ==
|
||||||
|
|
||||||
ansi-styles@^6.2.1:
|
ansi-styles@^6.2.1:
|
||||||
version "6.2.1"
|
version "6.2.1"
|
||||||
resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
|
resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
|
||||||
@ -1485,7 +1551,7 @@ ast-walker-scope@^0.8.1:
|
|||||||
"@babel/parser" "^7.28.3"
|
"@babel/parser" "^7.28.3"
|
||||||
ast-kit "^2.1.2"
|
ast-kit "^2.1.2"
|
||||||
|
|
||||||
async-validator@^4.0.7:
|
async-validator@^4.0.7, async-validator@^4.2.5:
|
||||||
version "4.2.5"
|
version "4.2.5"
|
||||||
resolved "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339"
|
resolved "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339"
|
||||||
integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
|
integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
|
||||||
@ -1504,11 +1570,6 @@ axios@^1.11.0:
|
|||||||
form-data "^4.0.4"
|
form-data "^4.0.4"
|
||||||
proxy-from-env "^1.1.0"
|
proxy-from-env "^1.1.0"
|
||||||
|
|
||||||
balanced-match@^1.0.2:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
|
||||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
|
||||||
|
|
||||||
balloon-css@^0.5.0:
|
balloon-css@^0.5.0:
|
||||||
version "0.5.2"
|
version "0.5.2"
|
||||||
resolved "https://registry.npmmirror.com/balloon-css/-/balloon-css-0.5.2.tgz#9e2163565a136c9d4aa20e8400772ce3b738d3ff"
|
resolved "https://registry.npmmirror.com/balloon-css/-/balloon-css-0.5.2.tgz#9e2163565a136c9d4aa20e8400772ce3b738d3ff"
|
||||||
@ -1682,6 +1743,14 @@ crypto-js@^4.2.0:
|
|||||||
resolved "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
|
resolved "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
|
||||||
integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
|
integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
|
||||||
|
|
||||||
|
css-render@^0.15.10, css-render@^0.15.14:
|
||||||
|
version "0.15.14"
|
||||||
|
resolved "https://registry.npmmirror.com/css-render/-/css-render-0.15.14.tgz#c23d8c8b9c0b44cd20b426f5e9de7ef7bade69b8"
|
||||||
|
integrity sha512-9nF4PdUle+5ta4W5SyZdLCCmFd37uVimSjg1evcTqKJCyvCEEj12WKzOSBNak6r4im4J4iYXKH1OWpUV5LBYFg==
|
||||||
|
dependencies:
|
||||||
|
"@emotion/hash" "~0.8.0"
|
||||||
|
csstype "~3.0.5"
|
||||||
|
|
||||||
css-select@^5.1.0:
|
css-select@^5.1.0:
|
||||||
version "5.2.2"
|
version "5.2.2"
|
||||||
resolved "https://registry.npmmirror.com/css-select/-/css-select-5.2.2.tgz#01b6e8d163637bb2dd6c982ca4ed65863682786e"
|
resolved "https://registry.npmmirror.com/css-select/-/css-select-5.2.2.tgz#01b6e8d163637bb2dd6c982ca4ed65863682786e"
|
||||||
@ -1717,14 +1786,6 @@ css-tree@~2.2.0:
|
|||||||
mdn-data "2.0.28"
|
mdn-data "2.0.28"
|
||||||
source-map-js "^1.0.1"
|
source-map-js "^1.0.1"
|
||||||
|
|
||||||
css-vars-ponyfill@^2.3.2:
|
|
||||||
version "2.4.9"
|
|
||||||
resolved "https://registry.npmmirror.com/css-vars-ponyfill/-/css-vars-ponyfill-2.4.9.tgz#ad04f0ee5937f816616b7fae3cfa945a33e7bfd1"
|
|
||||||
integrity sha512-aZyLue5bdiGVNCiCclNjo123D8I7kyoYNUaAvz+H1JalX1ye4Ilz7jNRRH5YbM+dYD6ucejiydGwk7lol/GCXQ==
|
|
||||||
dependencies:
|
|
||||||
balanced-match "^1.0.2"
|
|
||||||
get-css-data "^2.0.2"
|
|
||||||
|
|
||||||
css-what@^6.1.0:
|
css-what@^6.1.0:
|
||||||
version "6.2.2"
|
version "6.2.2"
|
||||||
resolved "https://registry.npmmirror.com/css-what/-/css-what-6.2.2.tgz#cdcc8f9b6977719fdfbd1de7aec24abf756b9dea"
|
resolved "https://registry.npmmirror.com/css-what/-/css-what-6.2.2.tgz#cdcc8f9b6977719fdfbd1de7aec24abf756b9dea"
|
||||||
@ -1752,6 +1813,11 @@ csstype@^3.2.3:
|
|||||||
resolved "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a"
|
resolved "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a"
|
||||||
integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==
|
integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==
|
||||||
|
|
||||||
|
csstype@~3.0.5:
|
||||||
|
version "3.0.11"
|
||||||
|
resolved "https://registry.npmmirror.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33"
|
||||||
|
integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==
|
||||||
|
|
||||||
d3-array@1, d3-array@^1.1.1, d3-array@^1.2.0:
|
d3-array@1, d3-array@^1.1.1, d3-array@^1.2.0:
|
||||||
version "1.2.4"
|
version "1.2.4"
|
||||||
resolved "https://registry.npmmirror.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f"
|
resolved "https://registry.npmmirror.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f"
|
||||||
@ -2262,17 +2328,20 @@ dagre@^0.8.5:
|
|||||||
graphlib "^2.1.8"
|
graphlib "^2.1.8"
|
||||||
lodash "^4.17.15"
|
lodash "^4.17.15"
|
||||||
|
|
||||||
date-fns@^2.20.0:
|
date-fns-tz@^3.2.0:
|
||||||
version "2.30.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.npmmirror.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
|
resolved "https://registry.npmmirror.com/date-fns-tz/-/date-fns-tz-3.2.0.tgz#647dc56d38ac33a3e37b65e9d5c4cda5af5e58e6"
|
||||||
integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
|
integrity sha512-sg8HqoTEulcbbbVXeg84u5UnlsQa8GS5QXMqjjYIhS4abEVVKIUwe0/l/UhrZdKaL/W5eWZNlbTeEIiOXTcsBQ==
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.21.0"
|
|
||||||
|
|
||||||
dayjs@^1.11.3:
|
date-fns@^4.1.0:
|
||||||
version "1.11.13"
|
version "4.1.0"
|
||||||
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c"
|
resolved "https://registry.npmmirror.com/date-fns/-/date-fns-4.1.0.tgz#64b3d83fff5aa80438f5b1a633c2e83b8a1c2d14"
|
||||||
integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
|
integrity sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==
|
||||||
|
|
||||||
|
dayjs@^1.11.19, dayjs@^1.11.3:
|
||||||
|
version "1.11.19"
|
||||||
|
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.19.tgz#15dc98e854bb43917f12021806af897c58ae2938"
|
||||||
|
integrity sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==
|
||||||
|
|
||||||
de-indent@^1.0.2:
|
de-indent@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
@ -2326,6 +2395,11 @@ delegate@^3.1.2:
|
|||||||
resolved "https://registry.npmmirror.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
|
resolved "https://registry.npmmirror.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
|
||||||
integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==
|
integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==
|
||||||
|
|
||||||
|
desandro-matches-selector@^2.0.0:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.npmmirror.com/desandro-matches-selector/-/desandro-matches-selector-2.0.2.tgz#717beed4dc13e7d8f3762f707a6d58a6774218e1"
|
||||||
|
integrity sha512-+1q0nXhdzg1IpIJdMKalUwvvskeKnYyEe3shPRwedNcWtnhEKT3ZxvFjzywHDeGcKViIxTCAoOYQWP1qD7VNyg==
|
||||||
|
|
||||||
destr@^2.0.3:
|
destr@^2.0.3:
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.npmmirror.com/destr/-/destr-2.0.5.tgz#7d112ff1b925fb8d2079fac5bdb4a90973b51fdb"
|
resolved "https://registry.npmmirror.com/destr/-/destr-2.0.5.tgz#7d112ff1b925fb8d2079fac5bdb4a90973b51fdb"
|
||||||
@ -2336,11 +2410,6 @@ devui-theme@^0.0.1:
|
|||||||
resolved "https://registry.npmmirror.com/devui-theme/-/devui-theme-0.0.1.tgz#9539023f0fdc1c90202bcfa00b0e945fd6bf1f78"
|
resolved "https://registry.npmmirror.com/devui-theme/-/devui-theme-0.0.1.tgz#9539023f0fdc1c90202bcfa00b0e945fd6bf1f78"
|
||||||
integrity sha512-5nF6fChlsXKeAtvkaAF4bZ0NMiEAbzwqQ9XZQiNuM0RRFz5lW29nnbhfDCNPkmnw5ZyCVyXqYwVRBIZrwZHXrA==
|
integrity sha512-5nF6fChlsXKeAtvkaAF4bZ0NMiEAbzwqQ9XZQiNuM0RRFz5lW29nnbhfDCNPkmnw5ZyCVyXqYwVRBIZrwZHXrA==
|
||||||
|
|
||||||
devui-theme@^0.0.7:
|
|
||||||
version "0.0.7"
|
|
||||||
resolved "https://registry.npmmirror.com/devui-theme/-/devui-theme-0.0.7.tgz#978a8a32aa7c097430350c586f0ba819e63e6a9f"
|
|
||||||
integrity sha512-sJWnkqOvqqVyvqaqyXn3/F+SIlNuoPUGdxG6TyDXuzZSAigWMuQsz8v8JJYTKL2Ash1q8kAKfRT01SqZmvlByA==
|
|
||||||
|
|
||||||
diff-match-patch@^1.0.5:
|
diff-match-patch@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.npmmirror.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37"
|
resolved "https://registry.npmmirror.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37"
|
||||||
@ -2423,16 +2492,31 @@ electron-to-chromium@^1.5.173:
|
|||||||
resolved "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.192.tgz#6dfc57a41846a57b18f9c0121821a6df1e165cc1"
|
resolved "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.192.tgz#6dfc57a41846a57b18f9c0121821a6df1e165cc1"
|
||||||
integrity sha512-rP8Ez0w7UNw/9j5eSXCe10o1g/8B1P5SM90PCCMVkIRQn2R0LEHWz4Eh9RnxkniuDe1W0cTSOB3MLlkTGDcuCg==
|
integrity sha512-rP8Ez0w7UNw/9j5eSXCe10o1g/8B1P5SM90PCCMVkIRQn2R0LEHWz4Eh9RnxkniuDe1W0cTSOB3MLlkTGDcuCg==
|
||||||
|
|
||||||
|
element-plus@^2.7.4:
|
||||||
|
version "2.13.0"
|
||||||
|
resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.13.0.tgz#e2ae817c1ed4fa9e94456af69a0f88cd824ee0c7"
|
||||||
|
integrity sha512-qjxS+SBChvqCl6lU6ShiliLMN6WqFHiXQENYbAY3GKNflG+FS3jqn8JmQq0CBZq4koFqsi95NT1M6SL4whZfrA==
|
||||||
|
dependencies:
|
||||||
|
"@ctrl/tinycolor" "^3.4.1"
|
||||||
|
"@element-plus/icons-vue" "^2.3.2"
|
||||||
|
"@floating-ui/dom" "^1.0.1"
|
||||||
|
"@popperjs/core" "npm:@sxzz/popperjs-es@^2.11.7"
|
||||||
|
"@types/lodash" "^4.17.20"
|
||||||
|
"@types/lodash-es" "^4.17.12"
|
||||||
|
"@vueuse/core" "^10.11.0"
|
||||||
|
async-validator "^4.2.5"
|
||||||
|
dayjs "^1.11.19"
|
||||||
|
lodash "^4.17.21"
|
||||||
|
lodash-es "^4.17.21"
|
||||||
|
lodash-unified "^1.0.3"
|
||||||
|
memoize-one "^6.0.0"
|
||||||
|
normalize-wheel-es "^1.2.0"
|
||||||
|
|
||||||
entities@^4.2.0, entities@^4.5.0:
|
entities@^4.2.0, entities@^4.5.0:
|
||||||
version "4.5.0"
|
version "4.5.0"
|
||||||
resolved "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
|
resolved "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
|
||||||
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
|
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
|
||||||
|
|
||||||
entities@^6.0.0:
|
|
||||||
version "6.0.1"
|
|
||||||
resolved "https://registry.npmmirror.com/entities/-/entities-6.0.1.tgz#c28c34a43379ca7f61d074130b2f5f7020a30694"
|
|
||||||
integrity sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==
|
|
||||||
|
|
||||||
entities@^7.0.0:
|
entities@^7.0.0:
|
||||||
version "7.0.0"
|
version "7.0.0"
|
||||||
resolved "https://registry.npmmirror.com/entities/-/entities-7.0.0.tgz#2ae4e443f3f17d152d3f5b0f79b932c1e59deb7a"
|
resolved "https://registry.npmmirror.com/entities/-/entities-7.0.0.tgz#2ae4e443f3f17d152d3f5b0f79b932c1e59deb7a"
|
||||||
@ -2541,6 +2625,16 @@ estree-walker@^3.0.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/estree" "^1.0.0"
|
"@types/estree" "^1.0.0"
|
||||||
|
|
||||||
|
ev-emitter@^1.0.0:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.npmmirror.com/ev-emitter/-/ev-emitter-1.1.1.tgz#8f18b0ce5c76a5d18017f71c0a795c65b9138f2a"
|
||||||
|
integrity sha512-ipiDYhdQSCZ4hSbX4rMW+XzNKMD1prg/sTvoVmSLkuQ1MVlwjJQQA+sW8tMYR3BLUr9KjodFV4pvzunvRhd33Q==
|
||||||
|
|
||||||
|
evtd@^0.2.2, evtd@^0.2.4:
|
||||||
|
version "0.2.4"
|
||||||
|
resolved "https://registry.npmmirror.com/evtd/-/evtd-0.2.4.tgz#0aac39ba44d6926e6668948ac27618e0795b9d07"
|
||||||
|
integrity sha512-qaeGN5bx63s/AXgQo8gj6fBkxge+OoLddLniox5qtLAEY5HSnuSlISXVPxnSae1dWblvTh4/HoMIB+mbMsvZzw==
|
||||||
|
|
||||||
execa@^9.6.0:
|
execa@^9.6.0:
|
||||||
version "9.6.0"
|
version "9.6.0"
|
||||||
resolved "https://registry.npmmirror.com/execa/-/execa-9.6.0.tgz#38665530e54e2e018384108322f37f35ae74f3bc"
|
resolved "https://registry.npmmirror.com/execa/-/execa-9.6.0.tgz#38665530e54e2e018384108322f37f35ae74f3bc"
|
||||||
@ -2583,6 +2677,13 @@ fill-range@^7.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range "^5.0.1"
|
to-regex-range "^5.0.1"
|
||||||
|
|
||||||
|
fizzy-ui-utils@^2.0.0:
|
||||||
|
version "2.0.7"
|
||||||
|
resolved "https://registry.npmmirror.com/fizzy-ui-utils/-/fizzy-ui-utils-2.0.7.tgz#7df45dcc4eb374a08b65d39bb9a4beedf7330505"
|
||||||
|
integrity sha512-CZXDVXQ1If3/r8s0T+v+qVeMshhfcuq0rqIFgJnrtd+Bu8GmDmqMjntjUePypVtjHXKJ6V4sw9zeyox34n9aCg==
|
||||||
|
dependencies:
|
||||||
|
desandro-matches-selector "^2.0.0"
|
||||||
|
|
||||||
follow-redirects@^1.15.6:
|
follow-redirects@^1.15.6:
|
||||||
version "1.15.9"
|
version "1.15.9"
|
||||||
resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1"
|
resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1"
|
||||||
@ -2623,11 +2724,6 @@ gensync@^1.0.0-beta.2:
|
|||||||
resolved "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
resolved "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
||||||
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
|
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
|
||||||
|
|
||||||
get-css-data@^2.0.2:
|
|
||||||
version "2.1.1"
|
|
||||||
resolved "https://registry.npmmirror.com/get-css-data/-/get-css-data-2.1.1.tgz#be1ef413f5a0854b75967f3b694a6ce164557070"
|
|
||||||
integrity sha512-JpMa/f5P4mDXKg6l5/2cHL5xNY77Jap7tHyduMa6BF0E2a7bQ6Tvaz2BIMjeVYZYLcmOZ5w2Ro0yVJEI41tMbw==
|
|
||||||
|
|
||||||
get-intrinsic@^1.2.6:
|
get-intrinsic@^1.2.6:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
|
resolved "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
|
||||||
@ -2652,6 +2748,11 @@ get-proto@^1.0.1:
|
|||||||
dunder-proto "^1.0.1"
|
dunder-proto "^1.0.1"
|
||||||
es-object-atoms "^1.0.0"
|
es-object-atoms "^1.0.0"
|
||||||
|
|
||||||
|
get-size@^2.0.2:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.npmmirror.com/get-size/-/get-size-2.0.3.tgz#54a1d0256b20ea7ac646516756202769941ad2ef"
|
||||||
|
integrity sha512-lXNzT/h/dTjTxRbm9BXb+SGxxzkm97h/PCIKtlN/CBCxxmkkIVV21udumMS93MuVTDX583gqc94v3RjuHmI+2Q==
|
||||||
|
|
||||||
get-stream@^9.0.0:
|
get-stream@^9.0.0:
|
||||||
version "9.0.1"
|
version "9.0.1"
|
||||||
resolved "https://registry.npmmirror.com/get-stream/-/get-stream-9.0.1.tgz#95157d21df8eb90d1647102b63039b1df60ebd27"
|
resolved "https://registry.npmmirror.com/get-stream/-/get-stream-9.0.1.tgz#95157d21df8eb90d1647102b63039b1df60ebd27"
|
||||||
@ -2732,7 +2833,7 @@ highlight.js@11.9.0:
|
|||||||
resolved "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.9.0.tgz#04ab9ee43b52a41a047432c8103e2158a1b8b5b0"
|
resolved "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.9.0.tgz#04ab9ee43b52a41a047432c8103e2158a1b8b5b0"
|
||||||
integrity sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==
|
integrity sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==
|
||||||
|
|
||||||
highlight.js@^11.6.0:
|
highlight.js@^11.6.0, highlight.js@^11.8.0:
|
||||||
version "11.11.1"
|
version "11.11.1"
|
||||||
resolved "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.11.1.tgz#fca06fa0e5aeecf6c4d437239135fabc15213585"
|
resolved "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.11.1.tgz#fca06fa0e5aeecf6c4d437239135fabc15213585"
|
||||||
integrity sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==
|
integrity sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==
|
||||||
@ -2779,6 +2880,13 @@ image-size@~0.5.0:
|
|||||||
resolved "https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
|
resolved "https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
|
||||||
integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==
|
integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==
|
||||||
|
|
||||||
|
imagesloaded@4.1.4:
|
||||||
|
version "4.1.4"
|
||||||
|
resolved "https://registry.npmmirror.com/imagesloaded/-/imagesloaded-4.1.4.tgz#1376efcd162bb768c34c3727ac89cc04051f3cc7"
|
||||||
|
integrity sha512-ltiBVcYpc/TYTF5nolkMNsnREHW+ICvfQ3Yla2Sgr71YFwQ86bDwV9hgpFhFtrGPuwEx5+LqOHIrdXBdoWwwsA==
|
||||||
|
dependencies:
|
||||||
|
ev-emitter "^1.0.0"
|
||||||
|
|
||||||
"internmap@1 - 2":
|
"internmap@1 - 2":
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.npmmirror.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009"
|
resolved "https://registry.npmmirror.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009"
|
||||||
@ -2893,9 +3001,9 @@ json5@^2.2.3:
|
|||||||
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
|
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
|
||||||
|
|
||||||
jsonfile@^6.0.1:
|
jsonfile@^6.0.1:
|
||||||
version "6.1.0"
|
version "6.2.0"
|
||||||
resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
|
resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.0.tgz#7c265bd1b65de6977478300087c99f1c84383f62"
|
||||||
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
|
integrity sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==
|
||||||
dependencies:
|
dependencies:
|
||||||
universalify "^2.0.0"
|
universalify "^2.0.0"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
@ -2951,10 +3059,15 @@ local-pkg@^1.0.0, local-pkg@^1.1.1:
|
|||||||
pkg-types "^2.0.1"
|
pkg-types "^2.0.1"
|
||||||
quansync "^0.2.8"
|
quansync "^0.2.8"
|
||||||
|
|
||||||
lodash-es@^4.17.15, lodash-es@^4.17.20:
|
lodash-es@^4.17.20, lodash-es@^4.17.21:
|
||||||
version "4.17.21"
|
version "4.17.22"
|
||||||
resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
|
resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.22.tgz#eb7d123ec2470d69b911abe34f85cb694849b346"
|
||||||
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
|
integrity sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==
|
||||||
|
|
||||||
|
lodash-unified@^1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz#80b1eac10ed2eb02ed189f08614a29c27d07c894"
|
||||||
|
integrity sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==
|
||||||
|
|
||||||
lodash@^4.17.15, lodash@^4.17.21:
|
lodash@^4.17.15, lodash@^4.17.21:
|
||||||
version "4.17.21"
|
version "4.17.21"
|
||||||
@ -3018,6 +3131,14 @@ markdown-it@12.2.0:
|
|||||||
mdurl "^1.0.1"
|
mdurl "^1.0.1"
|
||||||
uc.micro "^1.0.5"
|
uc.micro "^1.0.5"
|
||||||
|
|
||||||
|
masonry-layout@^4.2.2:
|
||||||
|
version "4.2.2"
|
||||||
|
resolved "https://registry.npmmirror.com/masonry-layout/-/masonry-layout-4.2.2.tgz#d57b44af13e601bfcdc423f1dd8348b5524de348"
|
||||||
|
integrity sha512-iGtAlrpHNyxaR19CvKC3npnEcAwszXoyJiI8ARV2ePi7fmYhIud25MHK8Zx4P0LCC4d3TNO9+rFa1KoK1OEOaA==
|
||||||
|
dependencies:
|
||||||
|
get-size "^2.0.2"
|
||||||
|
outlayer "^2.1.0"
|
||||||
|
|
||||||
math-intrinsics@^1.1.0:
|
math-intrinsics@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
|
resolved "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
|
||||||
@ -3043,6 +3164,11 @@ mdurl@^1.0.1:
|
|||||||
resolved "https://registry.npmmirror.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
|
resolved "https://registry.npmmirror.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
|
||||||
integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==
|
integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==
|
||||||
|
|
||||||
|
memoize-one@^6.0.0:
|
||||||
|
version "6.0.0"
|
||||||
|
resolved "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
|
||||||
|
integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
|
||||||
|
|
||||||
memorystream@^0.3.1:
|
memorystream@^0.3.1:
|
||||||
version "0.3.1"
|
version "0.3.1"
|
||||||
resolved "https://registry.npmmirror.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
|
resolved "https://registry.npmmirror.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
|
||||||
@ -3125,6 +3251,31 @@ muggle-string@^0.4.1:
|
|||||||
resolved "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz#3b366bd43b32f809dc20659534dd30e7c8a0d328"
|
resolved "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz#3b366bd43b32f809dc20659534dd30e7c8a0d328"
|
||||||
integrity sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==
|
integrity sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==
|
||||||
|
|
||||||
|
naive-ui@^2.43.2:
|
||||||
|
version "2.43.2"
|
||||||
|
resolved "https://registry.npmmirror.com/naive-ui/-/naive-ui-2.43.2.tgz#101ded965257119090d4f9e6f4479a5a09fbafa1"
|
||||||
|
integrity sha512-YlLMnGrwGTOc+zMj90sG3ubaH5/7czsgLgGcjTLA981IUaz8r6t4WIujNt8r9PNr+dqv6XNEr0vxkARgPPjfBQ==
|
||||||
|
dependencies:
|
||||||
|
"@css-render/plugin-bem" "^0.15.14"
|
||||||
|
"@css-render/vue3-ssr" "^0.15.14"
|
||||||
|
"@types/katex" "^0.16.2"
|
||||||
|
"@types/lodash" "^4.17.20"
|
||||||
|
"@types/lodash-es" "^4.17.12"
|
||||||
|
async-validator "^4.2.5"
|
||||||
|
css-render "^0.15.14"
|
||||||
|
csstype "^3.1.3"
|
||||||
|
date-fns "^4.1.0"
|
||||||
|
date-fns-tz "^3.2.0"
|
||||||
|
evtd "^0.2.4"
|
||||||
|
highlight.js "^11.8.0"
|
||||||
|
lodash "^4.17.21"
|
||||||
|
lodash-es "^4.17.21"
|
||||||
|
seemly "^0.3.10"
|
||||||
|
treemate "^0.3.11"
|
||||||
|
vdirs "^0.1.8"
|
||||||
|
vooks "^0.2.12"
|
||||||
|
vueuc "^0.4.65"
|
||||||
|
|
||||||
nanoid@^3.3.11:
|
nanoid@^3.3.11:
|
||||||
version "3.3.11"
|
version "3.3.11"
|
||||||
resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b"
|
resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b"
|
||||||
@ -3143,18 +3294,6 @@ needle@^3.1.0:
|
|||||||
iconv-lite "^0.6.3"
|
iconv-lite "^0.6.3"
|
||||||
sax "^1.2.4"
|
sax "^1.2.4"
|
||||||
|
|
||||||
ng-devui@^18.0.0:
|
|
||||||
version "18.0.0"
|
|
||||||
resolved "https://registry.npmmirror.com/ng-devui/-/ng-devui-18.0.0.tgz#48cf945f0da4dbf1fc69b9131b64194efbf3e4ef"
|
|
||||||
integrity sha512-QZzDqZ2cUF8w5VF65QASLIeE/2vpDr4iw9FCIbbFaQc4eLMb4lHRwRQFPyVatCpxe05k8qT2larICJbfJA6NJA==
|
|
||||||
dependencies:
|
|
||||||
"@angular/cdk" "^18.0.0"
|
|
||||||
"@popperjs/core" "^2.5.4"
|
|
||||||
css-vars-ponyfill "^2.3.2"
|
|
||||||
date-fns "^2.20.0"
|
|
||||||
lodash-es "^4.17.15"
|
|
||||||
tslib "^2.0.0"
|
|
||||||
|
|
||||||
node-fetch-native@^1.6.4:
|
node-fetch-native@^1.6.4:
|
||||||
version "1.6.6"
|
version "1.6.6"
|
||||||
resolved "https://registry.npmmirror.com/node-fetch-native/-/node-fetch-native-1.6.6.tgz#ae1d0e537af35c2c0b0de81cbff37eedd410aa37"
|
resolved "https://registry.npmmirror.com/node-fetch-native/-/node-fetch-native-1.6.6.tgz#ae1d0e537af35c2c0b0de81cbff37eedd410aa37"
|
||||||
@ -3177,6 +3316,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
|
|||||||
resolved "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
resolved "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||||
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
||||||
|
|
||||||
|
normalize-wheel-es@^1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz#0fa2593d619f7245a541652619105ab076acf09e"
|
||||||
|
integrity sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==
|
||||||
|
|
||||||
npm-normalize-package-bin@^4.0.0:
|
npm-normalize-package-bin@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.npmmirror.com/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz#df79e70cd0a113b77c02d1fe243c96b8e618acb1"
|
resolved "https://registry.npmmirror.com/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz#df79e70cd0a113b77c02d1fe243c96b8e618acb1"
|
||||||
@ -3235,6 +3379,15 @@ open@^10.2.0:
|
|||||||
is-inside-container "^1.0.0"
|
is-inside-container "^1.0.0"
|
||||||
wsl-utils "^0.1.0"
|
wsl-utils "^0.1.0"
|
||||||
|
|
||||||
|
outlayer@^2.1.0:
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "https://registry.npmmirror.com/outlayer/-/outlayer-2.1.1.tgz#29863b6de10ea5dadfffcadfa0d728907387e9a2"
|
||||||
|
integrity sha512-+GplXsCQ3VrbGujAeHEzP9SXsBmJxzn/YdDSQZL0xqBmAWBmortu2Y9Gwdp9J0bgDQ8/YNIPMoBM13nTwZfAhw==
|
||||||
|
dependencies:
|
||||||
|
ev-emitter "^1.0.0"
|
||||||
|
fizzy-ui-utils "^2.0.0"
|
||||||
|
get-size "^2.0.2"
|
||||||
|
|
||||||
package-manager-detector@^1.3.0:
|
package-manager-detector@^1.3.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.npmmirror.com/package-manager-detector/-/package-manager-detector-1.3.0.tgz#b42d641c448826e03c2b354272456a771ce453c0"
|
resolved "https://registry.npmmirror.com/package-manager-detector/-/package-manager-detector-1.3.0.tgz#b42d641c448826e03c2b354272456a771ce453c0"
|
||||||
@ -3250,13 +3403,6 @@ parse-node-version@^1.0.1:
|
|||||||
resolved "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
|
resolved "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
|
||||||
integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==
|
integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==
|
||||||
|
|
||||||
parse5@^7.1.2:
|
|
||||||
version "7.3.0"
|
|
||||||
resolved "https://registry.npmmirror.com/parse5/-/parse5-7.3.0.tgz#d7e224fa72399c7a175099f45fc2ad024b05ec05"
|
|
||||||
integrity sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==
|
|
||||||
dependencies:
|
|
||||||
entities "^6.0.0"
|
|
||||||
|
|
||||||
path-browserify@^1.0.1:
|
path-browserify@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
|
resolved "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
|
||||||
@ -3469,6 +3615,11 @@ scule@^1.3.0:
|
|||||||
resolved "https://registry.npmmirror.com/scule/-/scule-1.3.0.tgz#6efbd22fd0bb801bdcc585c89266a7d2daa8fbd3"
|
resolved "https://registry.npmmirror.com/scule/-/scule-1.3.0.tgz#6efbd22fd0bb801bdcc585c89266a7d2daa8fbd3"
|
||||||
integrity sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==
|
integrity sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==
|
||||||
|
|
||||||
|
seemly@^0.3.10, seemly@^0.3.6:
|
||||||
|
version "0.3.10"
|
||||||
|
resolved "https://registry.npmmirror.com/seemly/-/seemly-0.3.10.tgz#acf5d22c85ce855bf3715bbb740d18f544e59746"
|
||||||
|
integrity sha512-2+SMxtG1PcsL0uyhkumlOU6Qo9TAQ/WyH7tthnPIOQB05/12jz9naq6GZ6iZ6ApVsO3rr2gsnTf3++OV63kE1Q==
|
||||||
|
|
||||||
select@^1.1.2:
|
select@^1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.npmmirror.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
|
resolved "https://registry.npmmirror.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
|
||||||
@ -3607,12 +3758,17 @@ totalist@^3.0.0:
|
|||||||
resolved "https://registry.npmmirror.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8"
|
resolved "https://registry.npmmirror.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8"
|
||||||
integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==
|
integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==
|
||||||
|
|
||||||
|
treemate@^0.3.11:
|
||||||
|
version "0.3.11"
|
||||||
|
resolved "https://registry.npmmirror.com/treemate/-/treemate-0.3.11.tgz#7d52f8f69ab9ce326f8d139e0a3d1ffb25e48222"
|
||||||
|
integrity sha512-M8RGFoKtZ8dF+iwJfAJTOH/SM4KluKOKRJpjCMhI8bG3qB74zrFoArKZ62ll0Fr3mqkMJiQOmWYkdYgDeITYQg==
|
||||||
|
|
||||||
tslib@2.3.0:
|
tslib@2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
|
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
|
||||||
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
|
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
|
||||||
|
|
||||||
tslib@^2.0.0, tslib@^2.1.0, tslib@^2.3.0:
|
tslib@^2.1.0, tslib@^2.3.0:
|
||||||
version "2.8.1"
|
version "2.8.1"
|
||||||
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
||||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||||
@ -3780,6 +3936,18 @@ uuid@^9.0.1:
|
|||||||
resolved "https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
|
resolved "https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
|
||||||
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
|
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
|
||||||
|
|
||||||
|
v-infinite-scroll@^1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.npmmirror.com/v-infinite-scroll/-/v-infinite-scroll-1.0.4.tgz#56aad33b3d89759abd23702d7960763aeb8e0fc7"
|
||||||
|
integrity sha512-o2PeC0LNh3nSpsak+tcJEPRj9ENWWZTFvp1JdsraOom/d7lEbj7QfsJuF56AyrkqdSszaAwiVq2h4xTayl3RtQ==
|
||||||
|
|
||||||
|
vdirs@^0.1.4, vdirs@^0.1.8:
|
||||||
|
version "0.1.8"
|
||||||
|
resolved "https://registry.npmmirror.com/vdirs/-/vdirs-0.1.8.tgz#a103bc43baca738f8dea912a7e9737154a19dbc2"
|
||||||
|
integrity sha512-H9V1zGRLQZg9b+GdMk8MXDN2Lva0zx72MPahDKc30v+DtwKjfyOSXWRIX4t2mhDubM1H09gPhWeth/BJWPHGUw==
|
||||||
|
dependencies:
|
||||||
|
evtd "^0.2.2"
|
||||||
|
|
||||||
vditor@^3.11.2:
|
vditor@^3.11.2:
|
||||||
version "3.11.2"
|
version "3.11.2"
|
||||||
resolved "https://registry.npmmirror.com/vditor/-/vditor-3.11.2.tgz#612a405c74b71278a4eea188db3c7d93c0884c11"
|
resolved "https://registry.npmmirror.com/vditor/-/vditor-3.11.2.tgz#612a405c74b71278a4eea188db3c7d93c0884c11"
|
||||||
@ -3787,6 +3955,11 @@ vditor@^3.11.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
diff-match-patch "^1.0.5"
|
diff-match-patch "^1.0.5"
|
||||||
|
|
||||||
|
vfonts@^0.0.3:
|
||||||
|
version "0.0.3"
|
||||||
|
resolved "https://registry.npmmirror.com/vfonts/-/vfonts-0.0.3.tgz#999d66fecea18efee3f2b966c81101ae8ce01a29"
|
||||||
|
integrity sha512-nguyw8L6Un8eelg1vQ31vIU2ESxqid7EYmy8V+MDeMaHBqaRSkg3dTBToC1PR00D89UzS/SLkfYPnx0Wf23IQQ==
|
||||||
|
|
||||||
vite-dev-rpc@^1.1.0:
|
vite-dev-rpc@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.npmmirror.com/vite-dev-rpc/-/vite-dev-rpc-1.1.0.tgz#a54be63cc4dbb127bce1360e4b12d9038087c204"
|
resolved "https://registry.npmmirror.com/vite-dev-rpc/-/vite-dev-rpc-1.1.0.tgz#a54be63cc4dbb127bce1360e4b12d9038087c204"
|
||||||
@ -3864,20 +4037,32 @@ vite@^7.0.6:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.3"
|
fsevents "~2.3.3"
|
||||||
|
|
||||||
|
vooks@^0.2.12, vooks@^0.2.4:
|
||||||
|
version "0.2.12"
|
||||||
|
resolved "https://registry.npmmirror.com/vooks/-/vooks-0.2.12.tgz#2b6e23330b77bac81c7f7a344c4ca3e9f4f6c373"
|
||||||
|
integrity sha512-iox0I3RZzxtKlcgYaStQYKEzWWGAduMmq+jS7OrNdQo1FgGfPMubGL3uGHOU9n97NIvfFDBGnpSvkWyb/NSn/Q==
|
||||||
|
dependencies:
|
||||||
|
evtd "^0.2.2"
|
||||||
|
|
||||||
vscode-uri@^3.0.8:
|
vscode-uri@^3.0.8:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz#dd09ec5a66a38b5c3fffc774015713496d14e09c"
|
resolved "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz#dd09ec5a66a38b5c3fffc774015713496d14e09c"
|
||||||
integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==
|
integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==
|
||||||
|
|
||||||
vue-demi@*:
|
vue-demi@*, vue-demi@>=0.14.8:
|
||||||
version "0.14.10"
|
version "0.14.10"
|
||||||
resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04"
|
resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04"
|
||||||
integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==
|
integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==
|
||||||
|
|
||||||
vue-devui@^1.6.33:
|
vue-demi@^0.13.2:
|
||||||
version "1.6.33"
|
version "0.13.11"
|
||||||
resolved "https://registry.npmmirror.com/vue-devui/-/vue-devui-1.6.33.tgz#7fb3638a9da78c75c5584379b832bb26fbf8fa5f"
|
resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99"
|
||||||
integrity sha512-HQI1OAPyqEKa1BX8jlcsGq1pL99mUYJmzQxAZ7sWy19wR+sSvvl2OWcMDwr24ngVCx5uEQA1cSvM8TYum5249A==
|
integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==
|
||||||
|
|
||||||
|
vue-devui@^1.6.35:
|
||||||
|
version "1.6.35"
|
||||||
|
resolved "https://registry.npmmirror.com/vue-devui/-/vue-devui-1.6.35.tgz#9d3602957c0fd4d4368b8920083ee7938b952272"
|
||||||
|
integrity sha512-vjyR7fny+j5PoX0gC/JobTZW9kxcILHUfkibgAj1LwU/LPWnV/1xFkbrCYiKt+OlE1ONT5nv0WlYaNqZzbMHIA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-hoist-variables" "^7.22.5"
|
"@babel/helper-hoist-variables" "^7.22.5"
|
||||||
"@devui-design/icons" "^1.3.0"
|
"@devui-design/icons" "^1.3.0"
|
||||||
@ -3916,7 +4101,24 @@ vue-flow-layout@^0.1.1:
|
|||||||
resolved "https://registry.npmmirror.com/vue-flow-layout/-/vue-flow-layout-0.1.1.tgz#4095d9e79b80e845f110d4d015de6faf2c71f735"
|
resolved "https://registry.npmmirror.com/vue-flow-layout/-/vue-flow-layout-0.1.1.tgz#4095d9e79b80e845f110d4d015de6faf2c71f735"
|
||||||
integrity sha512-JdgRRUVrN0Y2GosA0M68DEbKlXMqJ7FQgsK8CjQD2vxvNSqAU6PZEpi4cfcTVtfM2GVOMjHo7GKKLbXxOBqDqA==
|
integrity sha512-JdgRRUVrN0Y2GosA0M68DEbKlXMqJ7FQgsK8CjQD2vxvNSqAU6PZEpi4cfcTVtfM2GVOMjHo7GKKLbXxOBqDqA==
|
||||||
|
|
||||||
vue-router@^4.0.3, vue-router@^4.5.1:
|
vue-masonry@^0.16.0:
|
||||||
|
version "0.16.0"
|
||||||
|
resolved "https://registry.npmmirror.com/vue-masonry/-/vue-masonry-0.16.0.tgz#e374fa34024cee664f6983bf672f417aa8cad2d1"
|
||||||
|
integrity sha512-0Wi/BH4iYYRrAAFY/wokczz0lWWPg1vmOvFW4aC2nKybKf6kVqUvFfR9/+izDfzG657/vY+Om0gqOB5YPxPxuQ==
|
||||||
|
dependencies:
|
||||||
|
imagesloaded "4.1.4"
|
||||||
|
masonry-layout "^4.2.2"
|
||||||
|
mitt "^3.0.0"
|
||||||
|
vue-demi "^0.13.2"
|
||||||
|
|
||||||
|
vue-router@^4.0.3:
|
||||||
|
version "4.6.4"
|
||||||
|
resolved "https://registry.npmmirror.com/vue-router/-/vue-router-4.6.4.tgz#a0a9cb9ef811a106d249e4bb9313d286718020d8"
|
||||||
|
integrity sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==
|
||||||
|
dependencies:
|
||||||
|
"@vue/devtools-api" "^6.6.4"
|
||||||
|
|
||||||
|
vue-router@^4.5.1:
|
||||||
version "4.5.1"
|
version "4.5.1"
|
||||||
resolved "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.1.tgz#47bffe2d3a5479d2886a9a244547a853aa0abf69"
|
resolved "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.1.tgz#47bffe2d3a5479d2886a9a244547a853aa0abf69"
|
||||||
integrity sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==
|
integrity sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==
|
||||||
@ -3938,6 +4140,14 @@ vue3-cookies@^1.0.6:
|
|||||||
dependencies:
|
dependencies:
|
||||||
vue "^3.0.0"
|
vue "^3.0.0"
|
||||||
|
|
||||||
|
vue3-masonry-plus@^1.2.5:
|
||||||
|
version "1.2.5"
|
||||||
|
resolved "https://registry.npmmirror.com/vue3-masonry-plus/-/vue3-masonry-plus-1.2.5.tgz#72d2af86471746921ee3b497d2ba073d91825d2a"
|
||||||
|
integrity sha512-MU6zVeGsD8H1RIS+LWGjd9Yd7W68UwjJksO71p3Se+owTuj5zt08FkbkYH5chbd51FuVmdDpAh1nO1/F9Aop8A==
|
||||||
|
dependencies:
|
||||||
|
animate.css "^4.1.1"
|
||||||
|
element-plus "^2.7.4"
|
||||||
|
|
||||||
vue3-perfect-scrollbar@^2.0.0:
|
vue3-perfect-scrollbar@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmmirror.com/vue3-perfect-scrollbar/-/vue3-perfect-scrollbar-2.0.0.tgz#51cedf1090d731ec7cc8163067e348867de0aa69"
|
resolved "https://registry.npmmirror.com/vue3-perfect-scrollbar/-/vue3-perfect-scrollbar-2.0.0.tgz#51cedf1090d731ec7cc8163067e348867de0aa69"
|
||||||
@ -3988,6 +4198,19 @@ vue@^3.6.0-alpha.2:
|
|||||||
"@vue/server-renderer" "3.6.0-alpha.2"
|
"@vue/server-renderer" "3.6.0-alpha.2"
|
||||||
"@vue/shared" "3.6.0-alpha.2"
|
"@vue/shared" "3.6.0-alpha.2"
|
||||||
|
|
||||||
|
vueuc@^0.4.65:
|
||||||
|
version "0.4.65"
|
||||||
|
resolved "https://registry.npmmirror.com/vueuc/-/vueuc-0.4.65.tgz#12c53aa9c92c307f26f6291ab40cab84cdfbe004"
|
||||||
|
integrity sha512-lXuMl+8gsBmruudfxnMF9HW4be8rFziylXFu1VHVNbLVhRTXXV4njvpRuJapD/8q+oFEMSfQMH16E/85VoWRyQ==
|
||||||
|
dependencies:
|
||||||
|
"@css-render/vue3-ssr" "^0.15.10"
|
||||||
|
"@juggle/resize-observer" "^3.3.1"
|
||||||
|
css-render "^0.15.10"
|
||||||
|
evtd "^0.2.4"
|
||||||
|
seemly "^0.3.6"
|
||||||
|
vdirs "^0.1.4"
|
||||||
|
vooks "^0.2.4"
|
||||||
|
|
||||||
webpack-virtual-modules@^0.6.2:
|
webpack-virtual-modules@^0.6.2:
|
||||||
version "0.6.2"
|
version "0.6.2"
|
||||||
resolved "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz#057faa9065c8acf48f24cb57ac0e77739ab9a7e8"
|
resolved "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz#057faa9065c8acf48f24cb57ac0e77739ab9a7e8"
|
||||||
|
|||||||
Reference in New Issue
Block a user