diff --git a/CHANGELOG.md b/CHANGELOG.md index b292e9b5..988b6a33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # CHANGE LOG +## 4.2.1 + +经过综合考虑,还是给模板增加 `cdn` 的配置。基于 `vite-plugin-cdn2` 插件实现。 + +### Feats + +- 指令相关 + - `v-copy` 指令将使用 `String` 强制转换传入的值 + - 统一暴露节流、防抖指令的配置项类型 `import type { DebounceBindingOptions, ThrottleBindingOptions } from '@/directives/type'` + - 现在 `v-disabled` 指令生效时会降低一点元素的亮度 +- `changeMenuModelValue` 方法添加节流锁,避免重复刷新 url 导致的一些问题 +- 新增 `cdn`,缩减构建体积。如果不需要该配置,搜索 `viteCDNPlugin` 注释即可 + ## 4.2.0 针对分包,做了全局的重新设计、调整。让包的名称更加语义化;最重要的是,重新抽离了一些全局可能常用的方法,例如:useI18n、useDayjs 等,在以前这些方法存放于对应的包中,其实这样很不合理,所以现在统一存放于 `src/hooks` 包中。并且该包以后统一存放 `hooks` 方法,并不是 `utils` 方法,做了一个本质的区分,所以 `xxxCopilot.ts` 文件中的方法并不会移动,维持存放在原有的模块下。 diff --git a/cfg.ts b/cfg.ts index 83526643..abe2b43f 100644 --- a/cfg.ts +++ b/cfg.ts @@ -47,7 +47,7 @@ import type { BuildOptions } from 'vite' const config: AppConfigExport = { /** 公共基础路径配置, 如果为空则会默认以 '/' 填充 */ - base: '/ray-template/', + // base: '/ray-template/', /** 配置首屏加载信息 */ preloadingConfig: PRE_LOADING_CONFIG, /** 默认主题色(不可省略, 必填), 也用于 ejs 注入 */ diff --git a/package.json b/package.json index 5a243e6e..f8ee6042 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "pinia": "^2.1.4", "pinia-plugin-persistedstate": "^3.1.0", "print-js": "^1.6.0", - "sass": "^1.54.3", "screenfull": "^6.0.2", "vue": "^3.3.4", "vue-hooks-plus": "1.8.2", @@ -81,11 +80,13 @@ "postcss-px-to-viewport-8-plugin": "1.2.2", "prettier": "^2.7.1", "rollup-plugin-visualizer": "^5.8.3", + "sass": "1.54.3", "svg-sprite-loader": "^6.0.11", "typescript": "^5.0.2", "unplugin-auto-import": "^0.15.0", "unplugin-vue-components": "^0.25.1", "vite": "^4.4.9", + "vite-plugin-cdn2": "0.12.4", "vite-plugin-compression": "^0.5.1", "vite-plugin-ejs": "^1.6.4", "vite-plugin-eslint": "1.8.1", diff --git a/src/app-components/app/RayLink/index.tsx b/src/app-components/app/RayLink/index.tsx index 67459166..fe7c62eb 100644 --- a/src/app-components/app/RayLink/index.tsx +++ b/src/app-components/app/RayLink/index.tsx @@ -27,25 +27,25 @@ const RayLink = defineComponent({ key: 'ray-js-note', src: 'https://note.youdao.com/s/ObWEe2BB', tooltip: 'Ray的前端学习笔记', - icon: 'https://usc1.contabostorage.com/c2e495d7890844d392e8ec0c6e5d77eb:image/longmao.jpeg', + icon: 'https://usc1.contabostorage.com/c2e495d7890844d392e8ec0c6e5d77eb:image/longmao.navigator.png', }, { key: 'ray-js-cover', src: 'https://note.youdao.com/s/IC8xKPdB', tooltip: 'Ray的面试题总结', - icon: 'https://usc1.contabostorage.com/c2e495d7890844d392e8ec0c6e5d77eb:image/longmao.jpeg', + icon: 'https://usc1.contabostorage.com/c2e495d7890844d392e8ec0c6e5d77eb:image/longmao.navigator.png', }, { key: 'ray-template-doc', src: 'https://xiaodaigua-ray.github.io/ray-template-doc/', tooltip: 'Ray Template Doc', - icon: 'https://usc1.contabostorage.com/c2e495d7890844d392e8ec0c6e5d77eb:image/longmao.jpeg', + icon: 'https://usc1.contabostorage.com/c2e495d7890844d392e8ec0c6e5d77eb:image/longmao.navigator.png', }, { key: 'ray-template-doc-out', src: 'https://ray-template.yunkuangao.com/', tooltip: 'Ray Template Doc (国内地址)', - icon: 'https://usc1.contabostorage.com/c2e495d7890844d392e8ec0c6e5d77eb:image/longmao.jpeg', + icon: 'https://usc1.contabostorage.com/c2e495d7890844d392e8ec0c6e5d77eb:image/longmao.navigator.png', }, ] diff --git a/src/components/RQRCode/src/index.tsx b/src/components/RQRCode/src/index.tsx index fcaad2dc..ce3d3245 100644 --- a/src/components/RQRCode/src/index.tsx +++ b/src/components/RQRCode/src/index.tsx @@ -114,7 +114,10 @@ export default defineComponent({ const downloadQRCode = (fileName?: string) => { if (qrcodeURL.value && isValueType(qrcodeURL.value, 'String')) { - downloadBase64File(qrcodeURL.value, fileName) + downloadBase64File( + qrcodeURL.value, + fileName || new Date().getTime() + '.png', + ) } } diff --git a/src/directives/index.ts b/src/directives/index.ts index c7a97d17..6fc8e1ba 100644 --- a/src/directives/index.ts +++ b/src/directives/index.ts @@ -11,7 +11,6 @@ import { combineDirective } from './helper/combine' import { forIn } from 'lodash-es' -import { isValueType } from '@/utils/hook' import type { App } from 'vue' import type { DirectiveModules } from '@/directives/type' @@ -40,10 +39,7 @@ export const setupDirectives = (app: App) => { forIn(directivesModules, (value, key) => { const dname = key.match(regexExtractDirectiveName)?.[0] - if ( - isValueType(dname, 'String') && - regexDirectiveName.test(dname) - ) { + if (typeof dname === 'string' && regexDirectiveName.test(dname)) { app.directive(dname, value?.()) } else { console.error(`[setupDirectives] ${dname} is not a valid directive name`) diff --git a/src/directives/modules/copy/index.ts b/src/directives/modules/copy/index.ts index c089ad65..ce2e52b0 100644 --- a/src/directives/modules/copy/index.ts +++ b/src/directives/modules/copy/index.ts @@ -23,7 +23,7 @@ const copyDirective: CustomDirectiveFC = () => { return { mounted: (el, { value }) => { const clipboard = new ClipboardJS(el, { - text: () => value, + text: () => String(value), }) clipboard.on('success', () => { @@ -40,7 +40,7 @@ const copyDirective: CustomDirectiveFC = () => { el.$$clipboard?.destroy() el.$$clipboard = new ClipboardJS(el, { - text: () => value, + text: () => String(value), }) } }, diff --git a/src/directives/modules/debounce/index.ts b/src/directives/modules/debounce/index.ts index 2dcd14a2..144fc9d6 100644 --- a/src/directives/modules/debounce/index.ts +++ b/src/directives/modules/debounce/index.ts @@ -33,7 +33,7 @@ const debounceDirective: CustomDirectiveFC< const { func, trigger = 'click', wait = 500, options } = value if (typeof func !== 'function') { - throw new Error('debounce directive value must be a function') + throw new TypeError('debounce directive value must be a function') } debounceFunction = debounce(func, wait, Object.assign({}, options)) diff --git a/src/directives/modules/debounce/type.ts b/src/directives/modules/debounce/type.ts index ea46a569..40a214c6 100644 --- a/src/directives/modules/debounce/type.ts +++ b/src/directives/modules/debounce/type.ts @@ -3,7 +3,7 @@ import type { AnyFC } from '@/types/modules/utils' export interface DebounceBindingOptions { func: AnyFC - trigger: string - wait: number - options: DebounceSettings + trigger?: string + wait?: number + options?: DebounceSettings } diff --git a/src/directives/modules/throttle/index.ts b/src/directives/modules/throttle/index.ts index 69c5fab6..6f58d124 100644 --- a/src/directives/modules/throttle/index.ts +++ b/src/directives/modules/throttle/index.ts @@ -33,7 +33,7 @@ const throttleDirective: CustomDirectiveFC< const { func, trigger = 'click', wait = 500, options } = value if (typeof func !== 'function') { - throw new Error('throttle directive value must be a function') + throw new TypeError('throttle directive value must be a function') } throttleFunction = throttle(func, wait, Object.assign({}, options)) diff --git a/src/directives/modules/throttle/type.ts b/src/directives/modules/throttle/type.ts index 74883475..77487d0d 100644 --- a/src/directives/modules/throttle/type.ts +++ b/src/directives/modules/throttle/type.ts @@ -3,7 +3,7 @@ import type { AnyFC } from '@/types/modules/utils' export interface ThrottleBindingOptions { func: AnyFC - trigger: string - wait: number - options: ThrottleSettings + trigger?: string + wait?: number + options?: ThrottleSettings } diff --git a/src/directives/type.ts b/src/directives/type.ts index 1bc15324..1cfa0563 100644 --- a/src/directives/type.ts +++ b/src/directives/type.ts @@ -1,6 +1,9 @@ import type { Directive } from 'vue' import type { App } from 'vue' +export type { DebounceBindingOptions } from './modules/debounce/type' +export type { ThrottleBindingOptions } from './modules/throttle/type' + export type CustomDirectiveFC = () => Directive export interface DirectiveModules extends Object { diff --git a/src/layout/default/ContentWrapper/index.tsx b/src/layout/default/ContentWrapper/index.tsx index d9fa1ef1..b245b82b 100644 --- a/src/layout/default/ContentWrapper/index.tsx +++ b/src/layout/default/ContentWrapper/index.tsx @@ -70,9 +70,7 @@ const ContentWrapper = defineComponent({ class="content-wrapper" transitionPropName={this.contentTransition + '-transform'} /> - ) : ( - '' - )} + ) : null} ) }, diff --git a/src/store/modules/menu/index.ts b/src/store/modules/menu/index.ts index 248a42a2..62478eeb 100644 --- a/src/store/modules/menu/index.ts +++ b/src/store/modules/menu/index.ts @@ -36,6 +36,7 @@ import { useI18n } from '@/hooks/web/index' import { getAppRawRoutes } from '@/router/appRouteModules' import { useKeepAlive } from '@/store' import { useVueRouter } from '@/hooks/web/index' +import { throttle } from 'lodash-es' import type { AppRouteMeta, AppRouteRecordRaw } from '@/router/type' import type { @@ -354,7 +355,7 @@ export const useMenu = defineStore( return { ...toRefs(menuState), - changeMenuModelValue, + changeMenuModelValue: throttle(changeMenuModelValue, 500), setupAppMenu, collapsedMenu, spliceMenTagOptions, diff --git a/src/store/modules/signin/index.ts b/src/store/modules/signin/index.ts index 134646b9..2a7bbedd 100644 --- a/src/store/modules/signin/index.ts +++ b/src/store/modules/signin/index.ts @@ -54,7 +54,7 @@ export const useSignin = defineStore( role: 'admin', name: signinForm.name, avatar: - 'https://usc1.contabostorage.com/c2e495d7890844d392e8ec0c6e5d77eb:image/longmao.jpeg', + 'https://usc1.contabostorage.com/c2e495d7890844d392e8ec0c6e5d77eb:image/longmao.navigator.png', } resolve({ diff --git a/src/styles/base.scss b/src/styles/base.scss index 623162c6..87788813 100644 --- a/src/styles/base.scss +++ b/src/styles/base.scss @@ -95,4 +95,5 @@ body .ray-template__directive--disabled { opacity: 0.3 !important; pointer-events: none !important; cursor: not-allowed !important; + filter: brightness(0.88); } diff --git a/src/utils/hook.ts b/src/utils/hook.ts index 00d3b11a..f330c5ef 100644 --- a/src/utils/hook.ts +++ b/src/utils/hook.ts @@ -40,11 +40,11 @@ export const arrayBufferToBase64Image = (data: ArrayBuffer): string | null => { * * @remark 下载 base64 文件 */ -export const downloadBase64File = (base64: string, fileName?: string) => { +export const downloadBase64File = (base64: string, fileName: string) => { const link = document.createElement('a') link.href = base64 - link.download = fileName || new Date().getTime() + '.png' + link.download = fileName link.click() } diff --git a/src/views/demo/directive/index.tsx b/src/views/demo/directive/index.tsx index 620bfc03..6ac7460a 100644 --- a/src/views/demo/directive/index.tsx +++ b/src/views/demo/directive/index.tsx @@ -21,6 +21,10 @@ import { } from 'naive-ui' import type { ConditionalPick } from '@/types/modules/helper' +import type { + DebounceBindingOptions, + ThrottleBindingOptions, +} from '@/directives/type' const RDirective = defineComponent({ name: 'RDirective', diff --git a/vite.pliugin.config.ts b/vite.pliugin.config.ts index 764146ba..88ba02b3 100644 --- a/vite.pliugin.config.ts +++ b/vite.pliugin.config.ts @@ -26,13 +26,16 @@ import mockDevServerPlugin from 'vite-plugin-mock-dev-server' import vueI18nPlugin from '@intlify/unplugin-vue-i18n/vite' import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' import unpluginViteComponents from 'unplugin-vue-components/vite' +import { cdn as viteCDNPlugin } from 'vite-plugin-cdn2' import { NaiveUiResolver } from 'unplugin-vue-components/resolvers' import { VueHooksPlusResolver } from '@vue-hooks-plus/resolvers' import config from './cfg' -export default function (mode: string) { +import type { PluginOption } from 'vite' + +export default function (mode: string): PluginOption[] { const { title, appPrimaryColor, preloadingConfig } = config return [ @@ -161,5 +164,24 @@ export default function (mode: string) { inject: 'body-last', customDomId: '__svg__icons__dom__', }), + viteCDNPlugin({ + modules: [ + 'vue', + 'vue-demi', + 'pinia', + 'naive-ui', + 'vue-router', + 'vue-i18n', + 'dayjs', + 'echarts', + 'vuedraggable', + 'xlsx', + 'axios', + 'screenfull', + 'print-js', + 'clipboard', + 'lodash-es', + ], + }), ] }