From 3b2bba391e5dd31f2e9cdd4e5f6dfefd1c06cf9f Mon Sep 17 00:00:00 2001 From: XiaoDaiGua-Ray <443547225@qq.com> Date: Fri, 20 Dec 2024 18:23:55 +0800 Subject: [PATCH] version: v5.0.8 --- CHANGELOG.md | 14 + package.json | 4 +- pnpm-lock.yaml | 52 ++-- .../provider/AppStyleProvider/index.tsx | 2 +- src/app-config/app-config.ts | 2 + src/app-config/design-config.ts | 4 +- .../base/RDraggableCard/DraggableCard.tsx | 264 ++++++++++++++++++ src/components/base/RDraggableCard/index.scss | 25 ++ .../base/RForm/src/hooks/useForm.ts | 5 +- src/components/base/RTable/src/Table.tsx | 25 +- src/components/index.ts | 3 +- src/layout/components/MenuTag/index.scss | 2 +- .../components/SettingDrawer/index.tsx | 6 +- src/locales/lang/en-US/menu.json | 3 +- src/locales/lang/zh-CN/menu.json | 3 +- src/router/modules/demo/draggable-card.ts | 19 ++ src/store/hooks/useMenuStore.ts | 21 +- src/store/modules/menu/index.ts | 40 ++- src/store/modules/menu/utils.ts | 14 + src/store/modules/setting/index.ts | 15 +- src/utils/update-object-value.ts | 4 +- src/views/demo/draggable-card.tsx | 46 +++ 22 files changed, 490 insertions(+), 83 deletions(-) create mode 100644 src/components/base/RDraggableCard/DraggableCard.tsx create mode 100644 src/components/base/RDraggableCard/index.scss create mode 100644 src/router/modules/demo/draggable-card.ts create mode 100644 src/views/demo/draggable-card.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index b3458cc5..76eb9a1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # CHANGE LOG +## 5.0.8 + +## Feats + +- 修改 `menuTagOptions` 的缓存方式,现在会缓存至 `sessionStorage` 中,兼容可能多系统版本部署与多开系统页面标签页冲突的问题 +- 新增 `RDraggableCard` 组件 +- 更新 `vite` 版本至 `6.0.4` + +## Fixes + +- 修复 `updateObjectValue` 方法对于对象值判断不准确的问题 +- 修复 `SettingDrawer` 组件初始化时,没有正确初始化 `settingStore` 的问题 +- 修复 `RTable` 组件在未设置 `title` 与 `tool` 为 `false` 时,导致 `headerStyle` 样式会高一些的问题 + ## 5.0.7 ## Feats diff --git a/package.json b/package.json index 52dd962a..4f47531d 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ray-template", "private": false, - "version": "5.0.7", + "version": "5.0.8", "type": "module", "engines": { "node": "^18.0.0 || ^20.0.0 || >=22.0.0", @@ -95,7 +95,7 @@ "typescript": "^5.6.3", "unplugin-auto-import": "^0.18.2", "unplugin-vue-components": "^0.27.4", - "vite": "^6.0.3", + "vite": "^6.0.4", "vite-bundle-analyzer": "0.9.4", "vite-plugin-cdn2": "1.1.0", "vite-plugin-ejs": "^1.7.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c984a6dc..0ec0dcec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -116,10 +116,10 @@ importers: version: 8.16.0(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.3) '@vitejs/plugin-vue': specifier: ^5.1.0 - version: 5.1.0(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1))(vue@3.5.13(typescript@5.6.3)) + version: 5.1.0(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1))(vue@3.5.13(typescript@5.6.3)) '@vitejs/plugin-vue-jsx': specifier: ^4.1.1 - version: 4.1.1(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1))(vue@3.5.13(typescript@5.6.3)) + version: 4.1.1(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1))(vue@3.5.13(typescript@5.6.3)) '@vitest/ui': specifier: 1.5.2 version: 1.5.2(vitest@2.0.5) @@ -190,8 +190,8 @@ importers: specifier: ^0.27.4 version: 0.27.4(@babel/parser@7.26.2)(@nuxt/kit@3.13.2(rollup@4.27.4)(webpack-sources@3.2.3))(rollup@4.27.4)(vue@3.5.13(typescript@5.6.3))(webpack-sources@3.2.3) vite: - specifier: ^6.0.3 - version: 6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) + specifier: ^6.0.4 + version: 6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) vite-bundle-analyzer: specifier: 0.9.4 version: 0.9.4 @@ -200,19 +200,19 @@ importers: version: 1.1.0(rollup@4.27.4) vite-plugin-ejs: specifier: ^1.7.0 - version: 1.7.0(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)) + version: 1.7.0(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)) vite-plugin-eslint: specifier: 1.8.1 - version: 1.8.1(eslint@9.11.0(jiti@1.21.6))(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)) + version: 1.8.1(eslint@9.11.0(jiti@1.21.6))(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)) vite-plugin-inspect: specifier: ^0.8.4 - version: 0.8.4(@nuxt/kit@3.13.2(rollup@4.27.4)(webpack-sources@3.2.3))(rollup@4.27.4)(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)) + version: 0.8.4(@nuxt/kit@3.13.2(rollup@4.27.4)(webpack-sources@3.2.3))(rollup@4.27.4)(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)) vite-plugin-mock-dev-server: specifier: 1.8.0 - version: 1.8.0(esbuild@0.24.0)(rollup@4.27.4)(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)) + version: 1.8.0(esbuild@0.24.0)(rollup@4.27.4)(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)) vite-plugin-svg-icons: specifier: ^2.0.1 - version: 2.0.1(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)) + version: 2.0.1(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)) vite-svg-loader: specifier: ^5.1.0 version: 5.1.0(vue@3.5.13(typescript@5.6.3)) @@ -4183,8 +4183,8 @@ packages: terser: optional: true - vite@6.0.3: - resolution: {integrity: sha512-Cmuo5P0ENTN6HxLSo6IHsjCLn/81Vgrp81oaiFFMRa8gGDj5xEjIcEpf2ZymZtZR8oU0P2JX5WuUp/rlXcHkAw==} + vite@6.0.4: + resolution: {integrity: sha512-zwlH6ar+6o6b4Wp+ydhtIKLrGM/LoqZzcdVmkGAFun0KHTzIzjh+h0kungEx7KJg/PYnC80I4TII9WkjciSR6Q==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -5461,19 +5461,19 @@ snapshots: '@typescript-eslint/types': 8.16.0 eslint-visitor-keys: 4.2.0 - '@vitejs/plugin-vue-jsx@4.1.1(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1))(vue@3.5.13(typescript@5.6.3))': + '@vitejs/plugin-vue-jsx@4.1.1(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1))(vue@3.5.13(typescript@5.6.3))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-transform-typescript': 7.25.9(@babel/core@7.26.0) '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.26.0) - vite: 6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) + vite: 6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) vue: 3.5.13(typescript@5.6.3) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@5.1.0(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1))(vue@3.5.13(typescript@5.6.3))': + '@vitejs/plugin-vue@5.1.0(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1))(vue@3.5.13(typescript@5.6.3))': dependencies: - vite: 6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) + vite: 6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) vue: 3.5.13(typescript@5.6.3) '@vitest/expect@2.0.5': @@ -8582,20 +8582,20 @@ snapshots: - rollup - supports-color - vite-plugin-ejs@1.7.0(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)): + vite-plugin-ejs@1.7.0(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)): dependencies: ejs: 3.1.9 - vite: 6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) + vite: 6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) - vite-plugin-eslint@1.8.1(eslint@9.11.0(jiti@1.21.6))(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)): + vite-plugin-eslint@1.8.1(eslint@9.11.0(jiti@1.21.6))(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)): dependencies: '@rollup/pluginutils': 4.2.1 '@types/eslint': 8.56.6 eslint: 9.11.0(jiti@1.21.6) rollup: 2.79.1 - vite: 6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) + vite: 6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) - vite-plugin-inspect@0.8.4(@nuxt/kit@3.13.2(rollup@4.27.4)(webpack-sources@3.2.3))(rollup@4.27.4)(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)): + vite-plugin-inspect@0.8.4(@nuxt/kit@3.13.2(rollup@4.27.4)(webpack-sources@3.2.3))(rollup@4.27.4)(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)): dependencies: '@antfu/utils': 0.7.10 '@rollup/pluginutils': 5.1.2(rollup@4.27.4) @@ -8606,14 +8606,14 @@ snapshots: perfect-debounce: 1.0.0 picocolors: 1.1.1 sirv: 2.0.4 - vite: 6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) + vite: 6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) optionalDependencies: '@nuxt/kit': 3.13.2(rollup@4.27.4)(webpack-sources@3.2.3) transitivePeerDependencies: - rollup - supports-color - vite-plugin-mock-dev-server@1.8.0(esbuild@0.24.0)(rollup@4.27.4)(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)): + vite-plugin-mock-dev-server@1.8.0(esbuild@0.24.0)(rollup@4.27.4)(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)): dependencies: '@pengzhanbo/utils': 1.1.2 '@rollup/pluginutils': 5.1.2(rollup@4.27.4) @@ -8630,7 +8630,7 @@ snapshots: mime-types: 2.1.35 path-to-regexp: 6.2.2 picocolors: 1.1.1 - vite: 6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) + vite: 6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) ws: 8.18.0 optionalDependencies: esbuild: 0.24.0 @@ -8640,7 +8640,7 @@ snapshots: - supports-color - utf-8-validate - vite-plugin-svg-icons@2.0.1(vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)): + vite-plugin-svg-icons@2.0.1(vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1)): dependencies: '@types/svgo': 2.6.4 cors: 2.8.5 @@ -8650,7 +8650,7 @@ snapshots: pathe: 0.2.0 svg-baker: 1.7.0 svgo: 2.8.0 - vite: 6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) + vite: 6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1) transitivePeerDependencies: - supports-color @@ -8669,7 +8669,7 @@ snapshots: fsevents: 2.3.3 sass: 1.77.1 - vite@6.0.3(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1): + vite@6.0.4(@types/node@22.5.5)(jiti@1.21.6)(sass@1.77.1): dependencies: esbuild: 0.24.0 postcss: 8.4.49 diff --git a/src/app-components/provider/AppStyleProvider/index.tsx b/src/app-components/provider/AppStyleProvider/index.tsx index 9a83df76..8f224bcf 100644 --- a/src/app-components/provider/AppStyleProvider/index.tsx +++ b/src/app-components/provider/AppStyleProvider/index.tsx @@ -44,7 +44,7 @@ export default defineComponent({ primaryColor, ) // 将主色调任意颜色转换为 rgba 格式 - const fp = colorToRgba(p, 0.8) + const fp = colorToRgba(p, 0.85) // 设置全局主题色 css 变量 html.style.setProperty(rayTemplateThemePrimaryColor, p) // 主色调 diff --git a/src/app-config/app-config.ts b/src/app-config/app-config.ts index 19d4efd8..2ac7ab73 100644 --- a/src/app-config/app-config.ts +++ b/src/app-config/app-config.ts @@ -93,6 +93,7 @@ export const APP_CATCH_KEY_PREFIX = '' * - appPiniaMenuStore: pinia menu store key * - appPiniaSigningStore: pinia signing store key * - appVersionProvider: 版本信息缓存 key + * - appMenuTagOptions: 标签页菜单列表 */ export const APP_CATCH_KEY = { signing: 'signing', @@ -106,6 +107,7 @@ export const APP_CATCH_KEY = { appVersionProvider: 'appVersionProvider', isAppLockScreen: 'isAppLockScreen', appGlobalSearchOptions: 'appGlobalSearchOptions', + appMenuTagOptions: 'appMenuTagOptions', } as const /** diff --git a/src/app-config/design-config.ts b/src/app-config/design-config.ts index c022475f..37143d13 100644 --- a/src/app-config/design-config.ts +++ b/src/app-config/design-config.ts @@ -20,7 +20,7 @@ export const APP_THEME: AppTheme = { // 主题色 primaryColor: '#2d8cf0', // 主题辅助色(用于整体 hover、active 等之类颜色) - primaryFadeColor: 'rgba(45, 140, 240, 0.8)', + primaryFadeColor: 'rgba(45, 140, 240, 0.85)', }, /** * @@ -52,14 +52,12 @@ export const APP_THEME: AppTheme = { common: { borderRadius: '4px', baseColor: 'rgb(18, 18, 18)', - textColorBase: 'rgb(255, 255, 255)', }, }, light: { common: { borderRadius: '4px', baseColor: 'rgb(255, 255, 255)', - textColorBase: 'rgb(31, 31, 31)', }, }, }, diff --git a/src/components/base/RDraggableCard/DraggableCard.tsx b/src/components/base/RDraggableCard/DraggableCard.tsx new file mode 100644 index 00000000..f23b4452 --- /dev/null +++ b/src/components/base/RDraggableCard/DraggableCard.tsx @@ -0,0 +1,264 @@ +import './index.scss' + +import { NCard } from 'naive-ui' +import { Teleport, Transition } from 'vue' + +import interact from 'interactjs' +import { cardProps } from 'naive-ui' +import { unrefElement, completeSize, queryElements } from '@/utils' +import { useTemplateRef } from 'vue' + +import type { VNode } from 'vue' + +type RestrictRectOptions = Parameters[0] + +type Position = { + x: number + y: number +} + +const props = { + ...cardProps, + /** + * + * @description + * 需要限制的区域位置。 + * + * @default body + */ + restrictionElement: { + type: [String, HTMLElement, Function] as PropType< + string | HTMLElement | (() => VNode) + >, + default: 'body', + }, + /** + * + * @description + * 是否启用拖拽。 + * + * @default true + */ + dad: { + type: Boolean, + default: true, + }, + /** + * + * @description + * 自定义限制拖拽范围。 + * + * @default undefined + */ + restrictRectOptions: { + type: Object as PropType, + default: void 0, + }, + /** + * + * @description + * 默认位置。 + * + * @default { x: 0, y: 0 } + */ + defaultPosition: { + type: Object as PropType, + default: () => ({ + x: 0, + y: 0, + }), + }, + /** + * + * @description + * 拖拽卡片宽度。 + * + * @default 600 + */ + width: { + type: [String, Number] as PropType, + default: 600, + }, + /** + * + * @description + * 拖拽卡片 z-index。 + * + * @default undefined + */ + zIndex: { + type: Number, + default: void 0, + }, + /** + * + * @description + * 是否启用动画。 + * + * @default false + */ + animation: { + type: Boolean, + default: false, + }, +} + +export default defineComponent({ + name: 'RDraggableCard', + props, + setup(props, { expose }) { + const cardRef = useTemplateRef('cardRef') + let interactInst: ReturnType | null = null + const position = { + ...props.defaultPosition, + } + const CONTAINER_ID = 'draggable-card-container' + const cssVars = computed(() => { + return { + '--r-draggable-card-width': completeSize(props.width), + '--r-draggable-card-z-index': props.zIndex, + } + }) + let isSetup = false + + const createDraggableCardContainer = () => { + if (!document.getElementById(CONTAINER_ID)) { + const container = document.createElement('div') + + container.id = CONTAINER_ID + document.documentElement.appendChild(container) + } + } + + createDraggableCardContainer() + + const getDom = () => { + const card = unrefElement(cardRef) + const re = + typeof props.restrictionElement === 'string' + ? queryElements(props.restrictionElement) + : props.restrictionElement + let restrictionElement: HTMLElement | null = null + + if (Array.isArray(re)) { + restrictionElement = re[0] + } else if (typeof re === 'function') { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + restrictionElement = unrefElement(re as any) as HTMLElement + } else { + restrictionElement = re + } + + return { + card, + restrictionElement, + } + } + + const setupDraggable = () => { + const { card, restrictionElement } = getDom() + + if (!card || !props.dad) { + return + } + + const restrictionRect = restrictionElement?.getBoundingClientRect() + const cardHeader = card.querySelector('.n-card-header') + const restrictRectOptions = Object.assign( + {}, + { + restriction: restrictionElement, + endOnly: true, + }, + props.restrictRectOptions, + ) + + if (restrictionRect && !isSetup) { + // 计算偏移位置 + const offsetX = restrictionRect.x + position.x + const offsetY = restrictionRect.y + position.y + + // 设置初始位置 + card.style.transform = `translate(${offsetX}px, ${offsetY}px)` + position.x = offsetX + position.y = offsetY + } + + interactInst = interact(card) + .draggable({ + inertia: true, + autoScroll: true, + allowFrom: cardHeader ? '.n-card-header' : '.n-card__content', + modifiers: [interact.modifiers.restrictRect(restrictRectOptions)], + listeners: { + move: (event) => { + card.setAttribute('can-drag', 'true') + + position.x += event.dx + position.y += event.dy + + card.style.transform = `translate(${position.x}px, ${position.y}px)` + }, + }, + }) + .resizable(false) + + isSetup = true + } + + expose() + + watchEffect(() => { + if (props.dad) { + setupDraggable() + } else { + interactInst?.unset() + + interactInst = null + } + }) + + onMounted(() => { + nextTick(() => { + setupDraggable() + }) + }) + + return { + cardRef, + CONTAINER_ID, + cssVars, + } + }, + render() { + const { $attrs, $slots, $props, CONTAINER_ID, cssVars, animation } = this + + return ( + + {animation ? ( + + + {{ ...$slots }} + + + ) : ( + + {{ ...$slots }} + + )} + + ) + }, +}) diff --git a/src/components/base/RDraggableCard/index.scss b/src/components/base/RDraggableCard/index.scss new file mode 100644 index 00000000..b1aac478 --- /dev/null +++ b/src/components/base/RDraggableCard/index.scss @@ -0,0 +1,25 @@ +.n-card.r-draggable-card { + transform-origin: 0 0; + position: absolute; + width: var(--r-draggable-card-width); + z-index: var(--r-draggable-card-z-index); +} + +#draggable-card-container { + position: fixed; + top: 0; + left: 0; + width: 0; + height: 0; +} + +// draggable-card 的 Transition 样式 +.draggable-card-enter-active, +.draggable-card-leave-active { + transition: opacity 0.3s var(--r-bezier); +} + +.draggable-card-enter-from, +.draggable-card-leave-to { + opacity: 0; +} diff --git a/src/components/base/RForm/src/hooks/useForm.ts b/src/components/base/RForm/src/hooks/useForm.ts index 3b928040..c9d2cb01 100644 --- a/src/components/base/RForm/src/hooks/useForm.ts +++ b/src/components/base/RForm/src/hooks/useForm.ts @@ -36,7 +36,10 @@ import type { Recordable } from '@/types' * }, * }) */ -const useForm = ( +const useForm = < + T extends Recordable = Recordable, + R extends RFormRules = RFormRules, +>( model?: T, rules?: R, ) => { diff --git a/src/components/base/RTable/src/Table.tsx b/src/components/base/RTable/src/Table.tsx index f70bc3ce..1f72d6be 100644 --- a/src/components/base/RTable/src/Table.tsx +++ b/src/components/base/RTable/src/Table.tsx @@ -61,6 +61,23 @@ export default defineComponent({ pick(props, 'striped', 'bordered'), ), ) + // 默认设置 card header style + const cardHeaderStyle = computed(() => { + const { title, tool, cardProps } = props + const { headerStyle = {} } = cardProps ?? {} + + if (!title && !tool) { + return Object.assign( + {}, + { + paddingTop: '0px', + }, + headerStyle, + ) + } + + return headerStyle + }) /** * @@ -231,6 +248,7 @@ export default defineComponent({ tool, wrapperRef, propsPopselectValue, + cardHeaderStyle, } }, render() { @@ -243,6 +261,7 @@ export default defineComponent({ uuidWrapper, privateReactive, propsPopselectValue, + cardHeaderStyle, } = this const { class: className, ...restAttrs } = $attrs const { tool, combineRowProps, contextMenuSelect } = this @@ -255,11 +274,12 @@ export default defineComponent({ tableFlexHeight, cardProps, ...restProps - } = $props as ExtractPublicPropTypes + } = $props + const { headerStyle, ...restCardProps } = cardProps ?? {} return ( {{ default: () => ( diff --git a/src/components/index.ts b/src/components/index.ts index a63c2a50..4a28a97e 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,4 +1,5 @@ import RCollapse from '../components/pro/RCollapse/Collapse' +import RDraggableCard from '../components/base/RDraggableCard/DraggableCard' // 导出所有自定义组件 export * from './base/RChart' @@ -14,7 +15,7 @@ export * from './base/RSegment' export * from './base/RBarcode' export * from '../components/pro/RTablePro' export * from './base/RFlow' -export { RCollapse } +export { RCollapse, RDraggableCard } // 导出自定义组件类型 export type * from './base/RChart/src/types' diff --git a/src/layout/components/MenuTag/index.scss b/src/layout/components/MenuTag/index.scss index 47e50aca..8dad0aef 100644 --- a/src/layout/components/MenuTag/index.scss +++ b/src/layout/components/MenuTag/index.scss @@ -53,7 +53,7 @@ $menuTagWrapperWidth: 76px; .ray-template--light { .menu-tag__btn-icon:hover { - filter: brightness(2); + filter: brightness(1.2); } } diff --git a/src/layout/components/SiderBar/components/SettingDrawer/index.tsx b/src/layout/components/SiderBar/components/SettingDrawer/index.tsx index 4dae28a7..a266907c 100644 --- a/src/layout/components/SiderBar/components/SettingDrawer/index.tsx +++ b/src/layout/components/SiderBar/components/SettingDrawer/index.tsx @@ -16,7 +16,7 @@ import SegmentViewsCustomMenu from './segment-views/CustomMenu' import { useSettingGetters, useSettingActions, useMenuActions } from '@/store' import { SETTING_DRAWER_INJECT_KEY } from './constant' -import { forIn, throttle } from 'lodash-es' +import { cloneDeep, forIn, throttle } from 'lodash-es' import { drawerProps } from 'naive-ui' import { useModal } from '@/components' import { getDefaultSettingConfig } from '@/store/modules/setting/constant' @@ -71,11 +71,13 @@ export default defineComponent({ positiveText: '确认初始化', negativeText: '取消', onPositiveClick: () => { - forIn(getDefaultSettingConfig(), (value, key) => { + forIn(cloneDeep(getDefaultSettingConfig()), (value, key) => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore modelReactive[key] = value + console.log(value, key) + updateSettingState(key as keyof SettingState, value) }) diff --git a/src/locales/lang/en-US/menu.json b/src/locales/lang/en-US/menu.json index 76be895d..79a47f48 100644 --- a/src/locales/lang/en-US/menu.json +++ b/src/locales/lang/en-US/menu.json @@ -29,5 +29,6 @@ "TemplateHooks": "Template Api", "scrollReveal": "Scroll Reveal", "TablePro": "Table Pro", - "Flow": "Flow" + "Flow": "Flow", + "DraggableCard": "Draggable Card" } diff --git a/src/locales/lang/zh-CN/menu.json b/src/locales/lang/zh-CN/menu.json index f5be40be..7d5538f1 100644 --- a/src/locales/lang/zh-CN/menu.json +++ b/src/locales/lang/zh-CN/menu.json @@ -29,5 +29,6 @@ "TemplateHooks": "模板内置 Api", "scrollReveal": "滚动动画", "TablePro": "高级表格", - "Flow": "流程图" + "Flow": "流程图", + "DraggableCard": "拖拽卡片" } diff --git a/src/router/modules/demo/draggable-card.ts b/src/router/modules/demo/draggable-card.ts new file mode 100644 index 00000000..982d1fe6 --- /dev/null +++ b/src/router/modules/demo/draggable-card.ts @@ -0,0 +1,19 @@ +import { t } from '@/hooks/web/useI18n' +import { LAYOUT } from '@/router/constant' + +import type { AppRouteRecordRaw } from '@/router/types' + +const r: AppRouteRecordRaw = { + path: '/draggable-card', + component: () => import('@/views/demo/draggable-card'), + meta: { + i18nKey: t('menu.DraggableCard'), + icon: 'other', + order: 2, + extra: { + label: 'drag', + }, + }, +} + +export default r diff --git a/src/store/hooks/useMenuStore.ts b/src/store/hooks/useMenuStore.ts index 8a69b530..88d80721 100644 --- a/src/store/hooks/useMenuStore.ts +++ b/src/store/hooks/useMenuStore.ts @@ -1,5 +1,4 @@ import { piniaMenuStore } from '../modules/menu' -import { useAppRoot } from '@/hooks' export const useMenuGetters = () => { const variable = piniaMenuStore() @@ -31,25 +30,7 @@ export const useMenuGetters = () => { * 获取菜单标签列表。 */ const getMenuTagOptions = computed(() => { - const { getRootPath } = useAppRoot() - - return variable.menuTagOptions.map((curr, _idx, currentArray) => { - if (curr.key === getMenuKey.value && curr.key !== getRootPath.value) { - curr.closeable = true - } else { - curr.closeable = false - } - - if (curr.key === getRootPath.value) { - curr.closeable = false - } - - if (currentArray.length <= 1) { - curr.closeable = false - } - - return curr - }) + return variable.menuTagOptions }) /** diff --git a/src/store/modules/menu/index.ts b/src/store/modules/menu/index.ts index ead108f5..988a658c 100644 --- a/src/store/modules/menu/index.ts +++ b/src/store/modules/menu/index.ts @@ -8,6 +8,7 @@ import { createMenuIcon, getCatchMenuKey, createMenuExtra, + getCatchMenuTagOptions, } from './utils' import { useI18n } from '@/hooks' import { getAppRawRoutes } from '@/router/app-route-modules' @@ -73,7 +74,7 @@ export const piniaMenuStore = defineStore( menuKey: getCatchMenuKey(), // 当前菜单 `key` options: [], // 菜单列表 collapsed: false, // 是否折叠菜单 - menuTagOptions: [], // tag 标签菜单 + menuTagOptions: getCatchMenuTagOptions(), // tag 标签菜单 breadcrumbOptions: [], // 面包屑菜单 currentMenuOption: null, // 当前激活菜单项 }) @@ -117,11 +118,7 @@ export const piniaMenuStore = defineStore( // 设置 label, i18nKey 优先级最高 const label = computed(() => (i18nKey ? t(`${i18nKey}`) : noLocalTitle)) - /** - * - * 拼装菜单项 - * 容错处理,兼容以前版本 key 选取为 path 的情况 - */ + // 拼装菜单项,容错处理,兼容以前版本 key 选取为 path 的情况 const route = { ...option, key: option.fullPath, @@ -137,10 +134,12 @@ export const piniaMenuStore = defineStore( extra: createMenuExtra(option), }) + // 如果当前菜单项与缓存菜单项相同,则更新当前菜单项 if (option.fullPath === getCatchMenuKey()) { menuState.currentMenuOption = attr } + // 验证菜单项是否显示 attr.show = validMenuItemShow(attr) return attr @@ -163,12 +162,13 @@ export const piniaMenuStore = defineStore( /** * - * @param options menu tag options - * @param isAppend is append + * @param options menu tag option(s) + * @param isAppend true: 追加操作(push), false: 覆盖操作 * * @description - * 设置标签菜单。 - * true: 追加操作(push),false: 覆盖操作。 + * 设置标签页。 + * 如果传递的 options 为数组,则进行追加操作。 + * 如果传递的 options 为单个对象,则进行覆盖操作。 */ const setMenuTagOptions = ( options: MenuTagOptions | MenuTagOptions[], @@ -180,6 +180,8 @@ export const piniaMenuStore = defineStore( isAppend ? menuState.menuTagOptions.push(...arr) : (menuState.menuTagOptions = arr) + + setStorage(APP_CATCH_KEY.appMenuTagOptions, menuState.menuTagOptions) } /** @@ -199,6 +201,13 @@ export const piniaMenuStore = defineStore( if (!tag) { menuState.menuTagOptions.push(option as MenuTagOptions) } + + // 清理所有非根路径的标签页 + menuState.menuTagOptions = menuState.menuTagOptions.filter((curr) => + curr.fullPath?.startsWith('/'), + ) + + setStorage(APP_CATCH_KEY.appMenuTagOptions, menuState.menuTagOptions) } /** @@ -402,8 +411,13 @@ export const piniaMenuStore = defineStore( * @description * 关闭 menu tag 标签。 */ - const spliceMenTagOptions = (idx: number, length = 1) => - menuState.menuTagOptions.splice(idx, length) + const spliceMenTagOptions = (idx: number, length = 1) => { + const r = menuState.menuTagOptions.splice(idx, length) + + setStorage(APP_CATCH_KEY.appMenuTagOptions, menuState.menuTagOptions) + + return r + } /** * @@ -451,7 +465,7 @@ export const piniaMenuStore = defineStore( persist: { key: APP_CATCH_KEY.appPiniaMenuStore, storage: window.localStorage, - pick: ['breadcrumbOptions', 'menuKey', 'menuTagOptions', 'collapsed'], + pick: ['breadcrumbOptions', 'menuKey', 'collapsed'], }, }, ) diff --git a/src/store/modules/menu/utils.ts b/src/store/modules/menu/utils.ts index 3cf325dc..25a101eb 100644 --- a/src/store/modules/menu/utils.ts +++ b/src/store/modules/menu/utils.ts @@ -264,3 +264,17 @@ export const getCatchMenuKey = () => { return cacheMenuKey } + +/** + * + * @returns 获取缓存的菜单标签页 + */ +export const getCatchMenuTagOptions = () => { + return getStorage( + APP_CATCH_KEY.appMenuTagOptions, + 'sessionStorage', + { + defaultValue: [], + }, + ) +} diff --git a/src/store/modules/setting/index.ts b/src/store/modules/setting/index.ts index 8795b970..5b7c4b40 100644 --- a/src/store/modules/setting/index.ts +++ b/src/store/modules/setting/index.ts @@ -3,7 +3,7 @@ import { colorToRgba, setStorage, updateObjectValue, setStyle } from '@/utils' import { useI18n, useDayjs } from '@/hooks' import { APP_CATCH_KEY, APP_THEME, GLOBAL_CLASS_NAMES } from '@/app-config' import { getDefaultSettingConfig } from './constant' -import { merge } from 'lodash-es' +import { cloneDeep, merge } from 'lodash-es' import type { SettingState } from '@/store/modules/setting/types' import type { LocalKey } from '@/hooks' @@ -24,8 +24,8 @@ export const piniaSettingStore = defineStore( common: { primaryColor: primaryColor, primaryColorHover: primaryFadeColor, - primaryColorPressed: primaryFadeColor, - primaryColorSuppl: colorToRgba(primaryColor, 0.9), + primaryColorPressed: primaryColor, + primaryColorSuppl: primaryFadeColor, }, }, // 内部使用,用于判断是否为黑夜主题(为了兼容历史遗留版本);true 为黑夜主题,false 为明亮主题 @@ -48,7 +48,7 @@ export const piniaSettingStore = defineStore( url: '/dashboard', jumpType: 'station', }, - ...getDefaultSettingConfig(), + ...cloneDeep(getDefaultSettingConfig()), }) // 修改当前语言 @@ -65,14 +65,13 @@ export const piniaSettingStore = defineStore( * @description * 切换主题色,传递对应颜色即可更新 naive-ui 的主题色。 */ - const changePrimaryColor = (value: string, alpha = 0.8) => { + const changePrimaryColor = (value: string, alpha = 0.85) => { const alphaColor1 = colorToRgba(value, alpha) - const alphaColor2 = colorToRgba(value, 0.9) const themeOverrides = { primaryColor: value, primaryColorHover: alphaColor1, - primaryColorPressed: alphaColor1, - primaryColorSuppl: alphaColor2, + primaryColorPressed: value, + primaryColorSuppl: alphaColor1, } const { rayTemplateThemePrimaryColor, rayTemplateThemePrimaryFadeColor } = GLOBAL_CLASS_NAMES diff --git a/src/utils/update-object-value.ts b/src/utils/update-object-value.ts index ee2e2a87..6d0818a1 100644 --- a/src/utils/update-object-value.ts +++ b/src/utils/update-object-value.ts @@ -1,3 +1,5 @@ +import { isValueType } from '@/utils' + import type { Recordable, AnyFC } from '@/types' /** @@ -42,7 +44,7 @@ export const updateObjectValue = < return } - if (typeof value === 'object' && value !== null) { + if (isValueType(value, 'Object')) { targetObject[key] = { ...targetObject[key], ...value, diff --git a/src/views/demo/draggable-card.tsx b/src/views/demo/draggable-card.tsx new file mode 100644 index 00000000..f916149f --- /dev/null +++ b/src/views/demo/draggable-card.tsx @@ -0,0 +1,46 @@ +import { RDraggableCard } from '@/components' +import { NButton, NCard, NFlex } from 'naive-ui' + +export default defineComponent({ + name: 'DraggableCardDemo', + setup() { + const card3 = ref(false) + + return { + card3, + } + }, + render() { + const { card3 } = this + + return ( +
+ + 我被限制在 body 中。 + + {card3 ? ( + (this.card3 = false)} + > + {{ + default: () => + '我被限制在 Layout Container 中。并且我支持 NCard 的所有配置与插槽。', + 'header-extra': () => '其实我就是 NCard 封装的', + footer: () => '我支持 footer 插槽', + action: () => '我支持 action 插槽', + }} + + ) : null} + + (this.card3 = !this.card3)}> + 点一下试试 + + +
+ ) + }, +})