mirror of
https://github.com/chansee97/nova-admin.git
synced 2025-08-16 05:09:47 +08:00
fix: fix example problem
This commit is contained in:
parent
0d7d851dd6
commit
56f6415ef2
46
package.json
46
package.json
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "nova-admin",
|
||||
"type": "module",
|
||||
"version": "0.9.14",
|
||||
"version": "0.9.15",
|
||||
"private": true,
|
||||
"description": "a clean and concise back-end management template based on Vue3, Vite5, Typescript, and Naive UI.",
|
||||
"author": {
|
||||
@ -50,42 +50,42 @@
|
||||
"sizecheck": "npx vite-bundle-visualizer"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vueuse/core": "^13.1.0",
|
||||
"alova": "^3.2.10",
|
||||
"@vueuse/core": "^13.3.0",
|
||||
"alova": "^3.3.2",
|
||||
"colord": "^2.9.3",
|
||||
"echarts": "^5.6.0",
|
||||
"md-editor-v3": "^5.4.5",
|
||||
"pinia": "^3.0.2",
|
||||
"pinia-plugin-persistedstate": "^4.2.0",
|
||||
"md-editor-v3": "^5.6.1",
|
||||
"pinia": "^3.0.3",
|
||||
"pinia-plugin-persistedstate": "^4.3.0",
|
||||
"quill": "^2.0.3",
|
||||
"radash": "^12.1.0",
|
||||
"vue": "^3.5.13",
|
||||
"vue": "^3.5.16",
|
||||
"vue-draggable-plus": "^0.6.0",
|
||||
"vue-i18n": "^11.1.3",
|
||||
"vue-router": "^4.5.0"
|
||||
"vue-i18n": "^11.1.5",
|
||||
"vue-router": "^4.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^4.12.0",
|
||||
"@antfu/eslint-config": "^4.14.1",
|
||||
"@iconify-json/icon-park-outline": "^1.2.2",
|
||||
"@iconify/vue": "^4.3.0",
|
||||
"@types/node": "^22.14.1",
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.2",
|
||||
"eslint": "^9.24.0",
|
||||
"lint-staged": "^15.5.1",
|
||||
"naive-ui": "^2.41.0",
|
||||
"@types/node": "^24.0.1",
|
||||
"@vitejs/plugin-vue": "^5.2.4",
|
||||
"@vitejs/plugin-vue-jsx": "^4.2.0",
|
||||
"eslint": "^9.29.0",
|
||||
"lint-staged": "^16.1.2",
|
||||
"naive-ui": "^2.41.1",
|
||||
"sass": "^1.86.3",
|
||||
"simple-git-hooks": "^2.12.1",
|
||||
"simple-git-hooks": "^2.13.0",
|
||||
"typescript": "^5.8.3",
|
||||
"unocss": "^0.65.4",
|
||||
"unplugin-auto-import": "^19.1.2",
|
||||
"unocss": "^66.2.0",
|
||||
"unplugin-auto-import": "^19.3.0",
|
||||
"unplugin-icons": "^22.1.0",
|
||||
"unplugin-vue-components": "^28.5.0",
|
||||
"vite": "^6.2.6",
|
||||
"unplugin-vue-components": "^28.7.0",
|
||||
"vite": "^6.3.5",
|
||||
"vite-bundle-visualizer": "^1.2.1",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-vue-devtools": "7.7.2",
|
||||
"vue-tsc": "^2.2.8"
|
||||
"vite-plugin-vue-devtools": "7.7.6",
|
||||
"vue-tsc": "^2.2.10"
|
||||
},
|
||||
"simple-git-hooks": {
|
||||
"pre-commit": "pnpm lint-staged"
|
||||
|
@ -95,17 +95,22 @@ function handleSelectIconTag(icon: string) {
|
||||
|
||||
// 包含当前分类或所有图标列表
|
||||
const icons = computed(() => {
|
||||
if (!iconList.value[currentTab.value])
|
||||
return []
|
||||
const hasTag = !!currentTag.value
|
||||
if (hasTag)
|
||||
return iconList.value[currentTab.value]?.categories[currentTag.value]
|
||||
else
|
||||
return iconList.value[currentTab.value].icons
|
||||
return hasTag
|
||||
? iconList.value[currentTab.value]?.categories[currentTag.value] || []
|
||||
: iconList.value[currentTab.value].icons || []
|
||||
})
|
||||
|
||||
// 符合搜索条件的图标列表
|
||||
const filteredIcons = computed(() => {
|
||||
return icons.value?.filter(i => i.includes(searchValue.value)) || []
|
||||
})
|
||||
|
||||
// 当前页显示的图标
|
||||
const visibleIcons = computed(() => {
|
||||
return icons.value?.filter(i => i
|
||||
.includes(searchValue.value))?.slice((currentPage.value - 1) * 200, (currentPage.value) * 200)
|
||||
return filteredIcons.value.slice((currentPage.value - 1) * 200, currentPage.value * 200)
|
||||
})
|
||||
|
||||
const showModal = ref(false)
|
||||
@ -191,7 +196,7 @@ function clearIcon() {
|
||||
<n-flex justify="center">
|
||||
<n-pagination
|
||||
v-model:page="currentPage"
|
||||
:item-count="icons?.length"
|
||||
:item-count="filteredIcons.length"
|
||||
:page-size="200"
|
||||
/>
|
||||
</n-flex>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { NScrollbar } from 'naive-ui'
|
||||
import { ref, watchEffect, type Ref } from 'vue'
|
||||
import { ref, type Ref, watchEffect } from 'vue'
|
||||
import { throttle } from 'radash'
|
||||
|
||||
export function useTabScroll(currentTabPath: Ref<string>) {
|
||||
@ -9,7 +9,7 @@ export function useTabScroll(currentTabPath: Ref<string>) {
|
||||
const handleTabSwitch = (distance: number) => {
|
||||
scrollbar.value?.scrollTo({
|
||||
left: distance,
|
||||
behavior: 'smooth'
|
||||
behavior: 'smooth',
|
||||
})
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ export function useTabScroll(currentTabPath: Ref<string>) {
|
||||
const currentTabElement = document.querySelector(`[data-tab-path="${currentTabPath.value}"]`) as HTMLElement
|
||||
const tabBarScrollWrapper = document.querySelector('.tab-bar-scroller-wrapper .n-scrollbar-container')
|
||||
const tabBarScrollContent = document.querySelector('.tab-bar-scroller-content')
|
||||
|
||||
|
||||
if (currentTabElement && tabBarScrollContent && tabBarScrollWrapper) {
|
||||
const tabLeft = currentTabElement.offsetLeft
|
||||
const tabBarLeft = tabBarScrollWrapper.scrollLeft
|
||||
@ -28,7 +28,8 @@ export function useTabScroll(currentTabPath: Ref<string>) {
|
||||
|
||||
if (tabLeft + tabWidth + safeArea.value + containerPR > wrapperWidth + tabBarLeft) {
|
||||
handleTabSwitch(tabLeft + tabWidth + containerPR - wrapperWidth + safeArea.value)
|
||||
} else if (tabLeft - safeArea.value < tabBarLeft) {
|
||||
}
|
||||
else if (tabLeft - safeArea.value < tabBarLeft) {
|
||||
handleTabSwitch(tabLeft - safeArea.value)
|
||||
}
|
||||
}
|
||||
@ -38,7 +39,7 @@ export function useTabScroll(currentTabPath: Ref<string>) {
|
||||
const handleScroll = throttle({ interval: 120 }, (step: number) => {
|
||||
scrollbar.value?.scrollBy({
|
||||
left: step * 400,
|
||||
behavior: 'smooth'
|
||||
behavior: 'smooth',
|
||||
})
|
||||
})
|
||||
|
||||
@ -59,6 +60,6 @@ export function useTabScroll(currentTabPath: Ref<string>) {
|
||||
scrollbar,
|
||||
onWheel,
|
||||
safeArea,
|
||||
handleTabSwitch
|
||||
handleTabSwitch,
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { $t } from '@/utils'
|
||||
|
||||
/** 默认实例的Aixos配置 */
|
||||
export const DEFAULT_ALOVA_OPTIONS = {
|
||||
// 请求超时时间,默认15秒
|
||||
|
6
src/typings/global.d.ts
vendored
6
src/typings/global.d.ts
vendored
@ -28,12 +28,6 @@ declare namespace NaiveUI {
|
||||
type ThemeColor = 'default' | 'error' | 'primary' | 'info' | 'success' | 'warning'
|
||||
}
|
||||
|
||||
// 修复naive-ui的TabPane组件的slots类型 https://github.com/tusen-ai/naive-ui/issues/6779 ,但是直接这样会导致更多类型报错,也无法查看naive-ui的源码
|
||||
// declare module 'naive-ui' {
|
||||
// interface TabPaneSlots {
|
||||
// tab?: () => VNode[]
|
||||
// }
|
||||
// }
|
||||
declare namespace Storage {
|
||||
interface Session {
|
||||
dict: DictMap
|
||||
|
@ -2,3 +2,4 @@ export * from './storage'
|
||||
export * from './array'
|
||||
export * from './i18n'
|
||||
export * from './icon'
|
||||
export * from './normalize'
|
||||
|
22
src/utils/normalize.ts
Normal file
22
src/utils/normalize.ts
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 统一化存储单位,字节转化为英文缩写`bytes`, `KB`, `MB`, `GB`
|
||||
*
|
||||
* @param {number} bytes 需要转换的字节大小
|
||||
* @returns {string} 转化后的字节字符串
|
||||
* @example
|
||||
* ```
|
||||
* // Output: '1 MB'
|
||||
* normalizeSizeUnits(1048576)
|
||||
* ```
|
||||
*/
|
||||
export function normalizeSizeUnits(bytes: number): string {
|
||||
if (bytes === 0)
|
||||
return '0 bytes'
|
||||
|
||||
const units = ['bytes', 'KB', 'MB', 'GB']
|
||||
const index = Math.floor(Math.log(bytes) / Math.log(1024))
|
||||
const size = +(bytes / 1024 ** index).toFixed(2)
|
||||
const unit = units[index]
|
||||
|
||||
return `${size} ${unit}`
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { useEcharts } from '@/hooks'
|
||||
import type { ECOption } from '@/hooks'
|
||||
|
||||
// 折线图
|
||||
const lineOptions = ref<ECOption>({
|
||||
tooltip: {
|
||||
|
@ -3,14 +3,15 @@ import {
|
||||
downloadFile,
|
||||
} from '@/service'
|
||||
import { useRequest } from 'alova/client'
|
||||
import { normalizeSizeUnits } from '@/utils'
|
||||
|
||||
const emit = defineEmits<{
|
||||
update: [data: any]
|
||||
}>()
|
||||
|
||||
const filePath = ref('https://images.unsplash.com/photo-1663529628961-80aa6ebcd157?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80')
|
||||
const fileURL = ref('https://images.unsplash.com/photo-1663529628961-80aa6ebcd157?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80')
|
||||
|
||||
const { downloading, abort, send, data } = useRequest(downloadFile(filePath.value), {
|
||||
const { loading, downloading, abort, send, data } = useRequest(() => downloadFile(fileURL.value), {
|
||||
// 当immediate为false时,默认不发出
|
||||
immediate: false,
|
||||
})
|
||||
@ -24,7 +25,10 @@ const downloadProcess = computed(() => {
|
||||
async function handleDownloadFile() {
|
||||
await send()
|
||||
emit('update', 'fileOk')
|
||||
downloadLink(data.value, 'fileOk')
|
||||
const urlObj = new URL(fileURL.value)
|
||||
const pathname = urlObj.pathname
|
||||
const name = pathname.split('/')[1]
|
||||
downloadLink(data.value, name)
|
||||
}
|
||||
|
||||
function downloadLink(data: Blob, name: string) {
|
||||
@ -42,10 +46,10 @@ function downloadLink(data: Blob, name: string) {
|
||||
<template>
|
||||
<n-card title="带进度的下载文件" size="small">
|
||||
<n-space vertical>
|
||||
<n-input v-model:value="filePath" />
|
||||
<div>文件大小:{{ downloading.total }}B</div>
|
||||
<div>已下载:{{ downloading.loaded }}B</div>
|
||||
<n-progress type="line" indicator-placement="inside" :percentage="downloadProcess" />
|
||||
<n-input v-model:value="fileURL" />
|
||||
<div>文件大小:{{ normalizeSizeUnits(downloading.total) }}</div>
|
||||
<div>已下载:{{ normalizeSizeUnits(downloading.loaded) }}</div>
|
||||
<n-progress type="line" indicator-placement="inside" :processing="loading" :percentage="downloadProcess" />
|
||||
<n-space>
|
||||
<n-button strong secondary @click="handleDownloadFile">
|
||||
开始下载
|
||||
|
Loading…
x
Reference in New Issue
Block a user