version: v5.0.3

This commit is contained in:
XiaoDaiGua-Ray 2024-10-27 17:01:53 +08:00
parent 7783872ef6
commit 8f3969268a
18 changed files with 843 additions and 347 deletions

View File

@ -1,5 +1,13 @@
# CHANGE LOG
## 5.0.3
个性化配置能力再次提升。
## Feats
- `SettingDrawer` 组件重构
## 5.0.2
## Feats

View File

@ -1,7 +1,7 @@
{
"name": "ray-template",
"private": false,
"version": "5.0.2",
"version": "5.0.3",
"type": "module",
"engines": {
"node": "^18.0.0 || >=20.0.0",

View File

@ -26,7 +26,7 @@ export default defineComponent({
const { getWatermarkConfig, getWatermarkSwitch } = this
return getWatermarkSwitch ? (
<NWatermark cross fullscreen {...getWatermarkConfig} />
<NWatermark {...getWatermarkConfig} fullscreen />
) : null
},
})

View File

@ -11,7 +11,6 @@ export const APP_THEME: AppTheme = {
'#3f9eff',
'#ff42bc',
'#ee4f12',
'#a6e4f7',
'#dbcb02',
'#18A058',
],

View File

@ -79,7 +79,8 @@ export default defineComponent({
collapseMode={getMenuConfig.value.collapsedMode}
collapsedWidth={getMenuConfig.value.collapsedWidth}
onUpdateCollapsed={collapsedMenu.bind(this)}
nativeScrollbar={false}
width={getMenuConfig.value.menuWidth}
nativeScrollbar={getMenuConfig.value.nativeScrollbar}
ref={LAYOUT_SIDER_REF}
collapsed={getCollapsed.value}
onExpand={() => {
@ -88,6 +89,7 @@ export default defineComponent({
onCollapse={() => {
updateMenuState('collapsed', true)
}}
inverted={getMenuConfig.value.inverted}
>
{getMenuConfig.value.menuSiderBarLogo ? (
<SiderBarLogo collapsed={getCollapsed.value} />
@ -107,6 +109,7 @@ export default defineComponent({
}}
accordion={getMenuConfig.value.accordion}
iconSize={getMenuConfig.value.iconSize}
inverted={getMenuConfig.value.inverted}
/>
</NLayoutSider>
)

View File

@ -1,11 +1,30 @@
import type { SettingState } from '@/store/modules/setting/types'
import type { InjectionKey, Reactive } from 'vue'
import type { DebouncedFunc } from 'lodash-es'
export const defaultSettingConfig: Partial<SettingState> = {
type OmitKeys =
| 'contentTransition'
| 'watermarkSwitch'
| 'keepAliveConfig'
| 'menuConfig'
| 'menuTagSwitch'
| 'breadcrumbSwitch'
| 'copyrightSwitch'
| 'drawerPlacement'
| 'colorWeakness'
| 'watermarkConfig'
| 'dynamicDocumentTitle'
interface Config extends Pick<SettingState, OmitKeys> {}
// SettingDrawer 默认配置系统配置项
const defaultSettingConfig: Readonly<Partial<Config>> = {
contentTransition: 'scale',
watermarkSwitch: false,
keepAliveConfig: {
maxKeepAliveLength: 10,
setupKeepAlive: true,
keepAliveExclude: [],
},
menuConfig: {
collapsedWidth: 64,
@ -15,9 +34,55 @@ export const defaultSettingConfig: Partial<SettingState> = {
accordion: false,
menuSiderBarLogo: true,
iconSize: 16,
menuWidth: 272,
inverted: false,
nativeScrollbar: false,
},
menuTagSwitch: true,
breadcrumbSwitch: true,
copyrightSwitch: true,
drawerPlacement: 'right',
colorWeakness: false,
watermarkConfig: {
content: 'Trying be better~',
fontSize: 16,
lineHeight: 16,
width: 384,
height: 384,
xOffset: 12,
yOffset: 60,
rotate: -15,
xGap: 0,
yGap: 0,
cross: true,
},
dynamicDocumentTitle: true,
}
/**
*
* @description
*
*/
export const getDefaultSettingConfig = (): Partial<Config> => {
return defaultSettingConfig
}
/**
*
* @param config
*
* @description
*
*/
export const updateDefaultSettingConfig = (config: Partial<SettingState>) => {
Object.assign(defaultSettingConfig, config)
}
interface SettingDrawerInjectKey extends SettingState {
throttleSetupAppMenu: DebouncedFunc<() => Promise<void>>
}
export const SETTING_DRAWER_INJECT_KEY: Reactive<
InjectionKey<Partial<SettingDrawerInjectKey>>
> = Symbol('segmentDrawer')

View File

@ -1,8 +1,3 @@
.setting-drawer__space {
width: 100%;
& .n-descriptions-table-content {
display: flex !important;
justify-content: space-between;
}
.n-form.setting-drawer__overrides-form .n-form-item .n-form-item-blank {
justify-content: flex-end;
}

View File

@ -3,50 +3,30 @@ import './index.scss'
import {
NDrawer,
NDrawerContent,
NDivider,
NFlex,
NSwitch,
NColorPicker,
NDescriptions,
NDescriptionsItem,
NSelect,
NInputNumber,
NFormItem,
NForm,
NButton,
NText,
NTooltip,
NTabs,
NTabPane,
} from 'naive-ui'
import ThemeSegment from './components/ThemeSegment'
import { RIcon } from '@/components'
import SegmentViewsAppearance from './segment-views/Appearance'
import SegmentViewsCommon from './segment-views/Common'
import SegmentViewsWatermark from './segment-views/Watermark'
import SegmentViewsCustomMenu from './segment-views/CustomMenu'
import { APP_THEME, CONTENT_TRANSITION_OPTIONS } from '@/app-config'
import { useSettingGetters, useSettingActions, useMenuActions } from '@/store'
import { defaultSettingConfig } from './constant'
import { getDefaultSettingConfig, SETTING_DRAWER_INJECT_KEY } from './constant'
import { forIn, throttle } from 'lodash-es'
import { drawerProps } from 'naive-ui'
import { useModal } from '@/components'
import type { PropType } from 'vue'
import type { Placement } from '@/types'
import type { SettingState } from '@/store/modules/setting/types'
export default defineComponent({
name: 'SettingDrawer',
props: {
show: {
type: Boolean,
default: false,
},
placement: {
type: String as PropType<Placement>,
default: 'right',
},
width: {
type: Number,
default: 280,
},
},
emits: ['update:show'],
setup(props, { emit }) {
props: drawerProps,
setup() {
const { create: createModal } = useModal()
const { changePrimaryColor, updateSettingState } = useSettingActions()
const {
getAppTheme,
@ -59,296 +39,94 @@ export default defineComponent({
getKeepAliveConfig,
getMenuConfig,
getDrawerPlacement,
getColorWeakness,
getWatermarkConfig,
getDynamicDocumentTitle,
} = useSettingGetters()
const { setupAppMenu } = useMenuActions()
const modelShow = computed({
get: () => props.show,
set: (bool) => {
emit('update:show', bool)
},
})
// 为了方便管理多个 computed因为 computed 不能被逆向修改
const modelReactive = computed({
get: () => {
return {
getMenuTagSwitch: getMenuTagSwitch.value,
getBreadcrumbSwitch: getBreadcrumbSwitch.value,
getCopyrightSwitch: getCopyrightSwitch.value,
getContentTransition: getContentTransition.value,
getWatermarkSwitch: getWatermarkSwitch.value,
getKeepAliveConfig: getKeepAliveConfig.value,
getMenuConfig: getMenuConfig.value,
getDrawerPlacement: getDrawerPlacement.value,
}
},
set: (value) => {},
})
const throttleSetupAppMenu = throttle(setupAppMenu, 300)
const modelReactive = reactive({
menuTagSwitch: getMenuTagSwitch.value,
breadcrumbSwitch: getBreadcrumbSwitch.value,
copyrightSwitch: getCopyrightSwitch.value,
contentTransition: getContentTransition.value,
watermarkSwitch: getWatermarkSwitch.value,
keepAliveConfig: getKeepAliveConfig.value,
menuConfig: getMenuConfig.value,
drawerPlacement: getDrawerPlacement.value,
colorWeakness: getColorWeakness.value,
primaryColorOverride: getPrimaryColorOverride.value,
watermarkConfig: getWatermarkConfig.value,
dynamicDocumentTitle: getDynamicDocumentTitle.value,
throttleSetupAppMenu,
})
const defaultSettingBtnClick = () => {
forIn(defaultSettingConfig, (value, key) => {
updateSettingState(key as keyof SettingState, value)
})
createModal({
preset: 'dialog',
title: '恢复默认配置',
type: 'warning',
content: '点击【确认初始化】按钮会恢复默认系统配置,是否继续?',
positiveText: '确认初始化',
negativeText: '取消',
onPositiveClick: () => {
forIn(getDefaultSettingConfig(), (value, key) => {
modelReactive[key] = value
throttleSetupAppMenu()
updateSettingState(key as keyof SettingState, value)
})
throttleSetupAppMenu()
},
})
}
provide(SETTING_DRAWER_INJECT_KEY, modelReactive)
return {
modelShow,
changePrimaryColor,
getAppTheme,
getPrimaryColorOverride,
updateSettingState,
modelReactive,
defaultSettingBtnClick,
throttleSetupAppMenu,
}
},
render() {
const {
$t,
changePrimaryColor,
updateSettingState,
defaultSettingBtnClick,
throttleSetupAppMenu,
} = this
const { defaultSettingBtnClick, $props } = this
const { trapFocus, autoFocus, nativeScrollbar, ...restProps } = $props
return (
<NDrawer
v-model:show={this.modelShow}
placement={this.placement}
width={this.width}
trapFocus={false}
autoFocus={false}
>
<NDrawerContent title="系统配置">
<NFlex class="setting-drawer__space" vertical>
<NDivider titlePlacement="center">
{$t('headerSettingOptions.ThemeOptions.Title')}
</NDivider>
<ThemeSegment />
<NDivider titlePlacement="center">
{$t('headerSettingOptions.ThemeOptions.PrimaryColorConfig')}
</NDivider>
<NColorPicker
swatches={APP_THEME.appThemeColors}
v-model:value={this.getPrimaryColorOverride.common!.primaryColor}
onUpdateValue={changePrimaryColor.bind(this)}
/>
<NDivider titlePlacement="center">
{$t('headerSettingOptions.ContentTransition')}
</NDivider>
<NSelect
v-model:value={this.modelReactive.getContentTransition}
options={CONTENT_TRANSITION_OPTIONS}
onUpdateValue={(value) => {
updateSettingState('contentTransition', value)
}}
/>
<NDivider titlePlacement="center"></NDivider>
<NSelect
v-model:value={this.modelReactive.getDrawerPlacement}
options={[
{
label: '右边',
value: 'right',
},
{
label: '左边',
value: 'left',
},
]}
onUpdateValue={(value) => {
updateSettingState('drawerPlacement', value)
}}
/>
<NDivider titlePlacement="center"></NDivider>
<NDescriptions labelPlacement="left" column={1}>
<NDescriptionsItem label="菜单页头">
<NSwitch
v-model:value={
this.modelReactive.getMenuConfig.menuSiderBarLogo
}
onUpdateValue={(bool: boolean) =>
updateSettingState('menuConfig', {
menuSiderBarLogo: bool,
})
}
/>
</NDescriptionsItem>
<NDescriptionsItem label="菜单手风琴">
<NSwitch
v-model:value={this.modelReactive.getMenuConfig.accordion}
onUpdateValue={(bool: boolean) =>
updateSettingState('menuConfig', {
accordion: bool,
})
}
/>
</NDescriptionsItem>
<NDescriptionsItem label="页面缓存">
<NSwitch
v-model:value={
this.modelReactive.getKeepAliveConfig.setupKeepAlive
}
onUpdateValue={(bool: boolean) =>
updateSettingState('keepAliveConfig', {
setupKeepAlive: bool,
})
}
/>
</NDescriptionsItem>
<NDescriptionsItem label="多标签">
<NSwitch
v-model:value={this.modelReactive.getMenuTagSwitch}
onUpdateValue={(bool: boolean) =>
updateSettingState('menuTagSwitch', bool)
}
/>
</NDescriptionsItem>
<NDescriptionsItem label="面包屑">
<NSwitch
v-model:value={this.modelReactive.getBreadcrumbSwitch}
onUpdateValue={(bool: boolean) =>
updateSettingState('breadcrumbSwitch', bool)
}
/>
</NDescriptionsItem>
<NDescriptionsItem label="水印">
<NSwitch
v-model:value={this.modelReactive.getWatermarkSwitch}
onUpdateValue={(bool: boolean) =>
updateSettingState('watermarkSwitch', bool)
}
/>
</NDescriptionsItem>
<NDescriptionsItem label="页底信息">
<NSwitch
v-model:value={this.modelReactive.getCopyrightSwitch}
onUpdateValue={(bool: boolean) =>
updateSettingState('copyrightSwitch', bool)
}
/>
</NDescriptionsItem>
</NDescriptions>
<NDivider titlePlacement="center">
<NFlex wrap={false} align="center" size={[4, 0]}>
<NTooltip placement="top" showArrow={false}>
<NDrawer {...restProps} trapFocus={false} autoFocus={false} width={320}>
<NDrawerContent title="个性化配置" closable>
{{
default: () => (
<NTabs type="bar" animated defaultValue="appearance">
<NTabPane name="appearance" tab="外观">
<SegmentViewsAppearance />
</NTabPane>
<NTabPane name="menu" tab="菜单">
<SegmentViewsCustomMenu />
</NTabPane>
<NTabPane name="watermark" tab="水印">
<SegmentViewsWatermark />
</NTabPane>
<NTabPane name="common" tab="通用">
<SegmentViewsCommon />
</NTabPane>
</NTabs>
),
footer: () => (
<NFlex justify="flex-start">
<NButton type="warning" onClick={defaultSettingBtnClick}>
{{
trigger: () => <RIcon name="question" size="16" />,
default: () => '菜单渲染是一个复杂、耗时的操作,请手动更新',
}}
</NTooltip>
<NText></NText>
</NFlex>
</NDivider>
<NForm showFeedback={true} showRequireMark={false}>
<NFormItem label="每级菜单缩进">
<NInputNumber
v-model:value={
this.modelReactive.getMenuConfig.collapsedIndent
}
min={0}
precision={0}
onUpdateValue={(value) => {
if (value !== null) {
updateSettingState('menuConfig', {
collapsedIndent: value,
})
}
}}
/>
</NFormItem>
<NFormItem label="菜单图标尺寸">
<NInputNumber
v-model:value={this.modelReactive.getMenuConfig.iconSize}
min={0}
precision={0}
onUpdateValue={(value) => {
if (value !== null) {
updateSettingState('menuConfig', {
iconSize: value,
})
}
}}
/>
</NFormItem>
<NFormItem label="折叠菜单图标尺寸">
<NInputNumber
v-model:value={
this.modelReactive.getMenuConfig.collapsedIconSize
}
min={0}
precision={0}
onUpdateValue={(value) => {
if (value !== null) {
updateSettingState('menuConfig', {
collapsedIconSize: value,
})
}
}}
/>
</NFormItem>
<NFormItem label="折叠菜单宽度">
<NInputNumber
v-model:value={
this.modelReactive.getMenuConfig.collapsedWidth
}
min={0}
precision={0}
onUpdateValue={(value) => {
if (value !== null) {
updateSettingState('menuConfig', {
collapsedWidth: value,
})
}
}}
/>
</NFormItem>
<NFormItem showFeedback={false} showLabel={false}>
<NButton
onClick={throttleSetupAppMenu}
block
type="info"
secondary
>
{{
icon: () => <RIcon name="question" size="16" />,
default: () => '点击刷新',
icon: () => <RIcon name="reload" />,
default: () => '初始化配置',
}}
</NButton>
</NFormItem>
</NForm>
<NDivider titlePlacement="center">
<NFlex wrap={false} align="center" size={[4, 0]}>
<NTooltip placement="top" showArrow={false}>
{{
trigger: () => <RIcon name="question" size="16" />,
default: () => '当设置为【0】时缓存将会失效',
}}
</NTooltip>
<NText></NText>
</NFlex>
</NDivider>
<NInputNumber
v-model:value={
this.modelReactive.getKeepAliveConfig.maxKeepAliveLength
}
showButton={true}
min={0}
max={100}
precision={0}
disabled={!this.modelReactive.getKeepAliveConfig.setupKeepAlive}
/>
<NDivider titlePlacement="center"></NDivider>
<NFlex>
<NButton type="primary" block onClick={defaultSettingBtnClick}>
</NButton>
</NFlex>
</NFlex>
),
}}
</NDrawerContent>
</NDrawer>
)

View File

@ -0,0 +1,117 @@
import {
NFlex,
NColorPicker,
NFormItem,
NDivider,
NSelect,
NSwitch,
NForm,
} from 'naive-ui'
import ThemeSegment from '../components/ThemeSegment'
import { SETTING_DRAWER_INJECT_KEY } from '../constant'
import { APP_THEME, CONTENT_TRANSITION_OPTIONS } from '@/app-config'
import { useSettingActions } from '@/store'
export default defineComponent({
name: 'SegmentViewsAppearance',
setup() {
const model = inject(SETTING_DRAWER_INJECT_KEY, {})
const { changePrimaryColor, updateSettingState, toggleColorWeakness } =
useSettingActions()
return {
toggleColorWeakness,
model,
changePrimaryColor,
updateSettingState,
}
},
render() {
const {
toggleColorWeakness,
model,
changePrimaryColor,
updateSettingState,
} = this
return (
<NFlex vertical style="width: 100%;" size={[0, 0]}>
<NDivider></NDivider>
<ThemeSegment />
<NDivider></NDivider>
<NColorPicker
showPreview
swatches={APP_THEME.appThemeColors}
v-model:value={model.primaryColorOverride!.common!.primaryColor}
onUpdateValue={changePrimaryColor.bind(this)}
/>
<NDivider></NDivider>
<NSelect
v-model:value={model.contentTransition}
options={CONTENT_TRANSITION_OPTIONS}
onUpdateValue={(value) => {
updateSettingState('contentTransition', value)
}}
/>
<NDivider></NDivider>
<NSelect
v-model:value={model.drawerPlacement}
options={[
{
label: '右边',
value: 'right',
},
{
label: '左边',
value: 'left',
},
]}
onUpdateValue={(value) => {
updateSettingState('drawerPlacement', value)
}}
/>
<NDivider></NDivider>
<NForm
labelPlacement="left"
class="setting-drawer__overrides-form"
showFeedback={false}
>
<NFormItem label="面包屑">
<NSwitch
v-model:value={model.breadcrumbSwitch}
onUpdateValue={(bool) =>
updateSettingState('breadcrumbSwitch', bool)
}
/>
</NFormItem>
<NFormItem label="标签页">
<NSwitch
v-model:value={model.menuTagSwitch}
onUpdateValue={(bool) =>
updateSettingState('menuTagSwitch', bool)
}
/>
</NFormItem>
<NFormItem label="页底信息">
<NSwitch
v-model:value={model.copyrightSwitch}
onUpdateValue={(bool) =>
updateSettingState('copyrightSwitch', bool)
}
/>
</NFormItem>
<NFormItem label="色弱模式">
<NSwitch
v-model:value={model.colorWeakness}
onUpdateValue={(bool) => {
updateSettingState('colorWeakness', bool)
toggleColorWeakness(bool)
}}
/>
</NFormItem>
</NForm>
</NFlex>
)
},
})

View File

@ -0,0 +1,98 @@
import {
NFlex,
NFormItem,
NDivider,
NSwitch,
NForm,
NInputNumber,
NDynamicTags,
} from 'naive-ui'
import { RIcon } from '@/components'
import { SETTING_DRAWER_INJECT_KEY } from '../constant'
import { useSettingActions } from '@/store'
export default defineComponent({
name: 'SegmentViewsCommon',
setup() {
const model = inject(SETTING_DRAWER_INJECT_KEY, {})
const { updateSettingState } = useSettingActions()
return {
model,
updateSettingState,
}
},
render() {
const { model, updateSettingState } = this
return (
<NFlex vertical style="width: 100%;" size={[0, 0]}>
<NDivider></NDivider>
<NForm
labelPlacement="left"
class="setting-drawer__overrides-form"
showFeedback={false}
>
<NFormItem label="页面缓存">
<NSwitch
v-model:value={model.keepAliveConfig!.setupKeepAlive}
onUpdateValue={(bool) =>
updateSettingState('keepAliveConfig', {
setupKeepAlive: bool,
})
}
/>
</NFormItem>
<NFormItem label="动态浏览器标题">
<NSwitch
v-model:value={model.dynamicDocumentTitle}
onUpdateValue={(bool) =>
updateSettingState('dynamicDocumentTitle', bool)
}
/>
</NFormItem>
</NForm>
<NDivider></NDivider>
<NForm
labelPlacement="top"
showFeedback={true}
showRequireMark={false}
model={model.keepAliveConfig}
>
<NFormItem
label="最大缓存数"
feedback={
computed(() => {
if (model.keepAliveConfig!.maxKeepAliveLength <= 0) {
return '设置为【0】时缓存将会失效'
}
return ''
}).value
}
>
<NInputNumber
disabled={!model.keepAliveConfig!.setupKeepAlive}
v-model:value={model.keepAliveConfig!.maxKeepAliveLength}
min={0}
precision={0}
showButton={false}
onUpdateValue={(val) =>
updateSettingState('keepAliveConfig', {
maxKeepAliveLength: val!,
})
}
/>
</NFormItem>
<NFormItem label="排除缓存">
<NDynamicTags
type="success"
v-model:value={model.keepAliveConfig!.keepAliveExclude}
/>
</NFormItem>
</NForm>
</NFlex>
)
},
})

View File

@ -0,0 +1,167 @@
import {
NFlex,
NFormItem,
NDivider,
NSwitch,
NForm,
NTooltip,
NText,
NInputNumber,
NButton,
} from 'naive-ui'
import { RIcon } from '@/components'
import { SETTING_DRAWER_INJECT_KEY } from '../constant'
import { useSettingActions } from '@/store'
export default defineComponent({
name: 'SegmentViewsCustomMenu',
setup() {
const model = inject(SETTING_DRAWER_INJECT_KEY, {})
const { updateSettingState } = useSettingActions()
return {
model,
updateSettingState,
}
},
render() {
const { model, updateSettingState } = this
return (
<NFlex vertical style="width: 100%;" size={[0, 0]}>
<NDivider titlePlacement="center">
<NFlex wrap={false} align="center" size={[4, 0]}>
<NTooltip placement="top" showArrow={false}>
{{
trigger: () => <RIcon name="question" size="16" />,
default: () =>
'菜单更新是一个复杂、耗时的操作,请手动点击【更新菜单】按钮更新设置',
}}
</NTooltip>
<NText></NText>
</NFlex>
</NDivider>
<NForm
showFeedback={true}
showRequireMark={false}
class="setting-drawer__overrides-form"
>
<NFormItem label="每级菜单缩进">
<NInputNumber
v-model:value={model.menuConfig!.collapsedIndent}
min={0}
precision={0}
onUpdateValue={(value) =>
updateSettingState('menuConfig', {
collapsedIndent: value!,
})
}
/>
</NFormItem>
<NFormItem label="菜单图标尺寸">
<NInputNumber
v-model:value={model.menuConfig!.iconSize}
min={0}
precision={0}
onUpdateValue={(value) =>
updateSettingState('menuConfig', {
iconSize: value!,
})
}
/>
</NFormItem>
<NFormItem label="折叠菜单图标尺寸">
<NInputNumber
v-model:value={model.menuConfig!.collapsedIconSize}
min={0}
precision={0}
onUpdateValue={(value) =>
updateSettingState('menuConfig', {
collapsedIconSize: value!,
})
}
/>
</NFormItem>
<NFormItem label="菜单宽度">
<NInputNumber
v-model:value={model.menuConfig!.menuWidth}
min={0}
precision={0}
onUpdateValue={(value) =>
updateSettingState('menuConfig', {
menuWidth: value!,
})
}
/>
</NFormItem>
<NFormItem label="折叠菜单宽度">
<NInputNumber
v-model:value={model.menuConfig!.collapsedWidth}
min={0}
precision={0}
onUpdateValue={(value) =>
updateSettingState('menuConfig', {
collapsedWidth: value!,
})
}
/>
</NFormItem>
<NFormItem showFeedback={false} showLabel={false}>
<NButton onClick={model.throttleSetupAppMenu} block type="primary">
</NButton>
</NFormItem>
</NForm>
<NDivider></NDivider>
<NForm
showFeedback={false}
showRequireMark={false}
class="setting-drawer__overrides-form"
labelPlacement="left"
>
<NFormItem label="反转色菜单">
<NSwitch
v-model:value={model.menuConfig!.inverted}
onUpdateValue={(bool) =>
updateSettingState('menuConfig', {
inverted: bool,
})
}
/>
</NFormItem>
<NFormItem label="菜单标题">
<NSwitch
v-model:value={model.menuConfig!.menuSiderBarLogo}
onUpdateValue={(bool) =>
updateSettingState('menuConfig', {
menuSiderBarLogo: bool,
})
}
/>
</NFormItem>
<NFormItem label="手风琴菜单">
<NSwitch
v-model:value={model.menuConfig!.accordion}
onUpdateValue={(bool) =>
updateSettingState('menuConfig', {
accordion: bool,
})
}
/>
</NFormItem>
<NFormItem label="原生滚动条">
<NSwitch
v-model:value={model.menuConfig!.nativeScrollbar}
onUpdateValue={(bool) =>
updateSettingState('menuConfig', {
nativeScrollbar: bool,
})
}
/>
</NFormItem>
</NForm>
</NFlex>
)
},
})

View File

@ -0,0 +1,184 @@
import {
NFlex,
NFormItem,
NDivider,
NSwitch,
NForm,
NInputNumber,
NInput,
} from 'naive-ui'
import { SETTING_DRAWER_INJECT_KEY } from '../constant'
import { useSettingActions } from '@/store'
export default defineComponent({
name: 'SegmentViewsWatermark',
setup() {
const model = inject(SETTING_DRAWER_INJECT_KEY, {})
const { updateSettingState } = useSettingActions()
return {
model,
updateSettingState,
}
},
render() {
const { model, updateSettingState } = this
return (
<NFlex vertical style="width: 100%;" size={[0, 0]}>
<NDivider></NDivider>
<NForm
showFeedback={false}
showRequireMark={false}
class="setting-drawer__overrides-form"
labelPlacement="left"
>
<NFormItem label="全屏水印">
<NSwitch
v-model:value={model.watermarkSwitch}
onUpdateValue={(bool) =>
updateSettingState('watermarkSwitch', bool)
}
/>
</NFormItem>
<NFormItem label="跨边界显示">
<NSwitch
v-model:value={model.watermarkConfig!.cross}
onUpdateValue={(val) =>
updateSettingState('watermarkConfig', {
cross: val,
})
}
/>
</NFormItem>
</NForm>
<NDivider></NDivider>
<NForm
showFeedback={true}
showRequireMark={false}
class="setting-drawer__overrides-form"
>
<NFormItem label="水印内容">
<NInput
v-model:value={model.watermarkConfig!.content}
onUpdateValue={(val) =>
updateSettingState('watermarkConfig', {
content: val,
})
}
/>
</NFormItem>
<NFormItem label="字体尺寸">
<NInputNumber
precision={0}
showButton={false}
v-model:value={model.watermarkConfig!.fontSize}
onUpdateValue={(val) =>
updateSettingState('watermarkConfig', {
fontSize: val!,
})
}
/>
</NFormItem>
<NFormItem label="字体行高">
<NInputNumber
precision={0}
showButton={false}
v-model:value={model.watermarkConfig!.lineHeight}
onUpdateValue={(val) =>
updateSettingState('watermarkConfig', {
lineHeight: val!,
})
}
/>
</NFormItem>
<NFormItem label="字体宽度">
<NInputNumber
precision={0}
showButton={false}
v-model:value={model.watermarkConfig!.width}
onUpdateValue={(val) =>
updateSettingState('watermarkConfig', {
width: val!,
})
}
/>
</NFormItem>
<NFormItem label="字体高度">
<NInputNumber
precision={0}
showButton={false}
v-model:value={model.watermarkConfig!.height}
onUpdateValue={(val) =>
updateSettingState('watermarkConfig', {
height: val!,
})
}
/>
</NFormItem>
<NFormItem label="x轴偏移">
<NInputNumber
precision={0}
showButton={false}
v-model:value={model.watermarkConfig!.xOffset}
onUpdateValue={(val) =>
updateSettingState('watermarkConfig', {
xOffset: val!,
})
}
/>
</NFormItem>
<NFormItem label="x轴间隙">
<NInputNumber
precision={0}
showButton={false}
v-model:value={model.watermarkConfig!.xGap}
onUpdateValue={(val) =>
updateSettingState('watermarkConfig', {
xGap: val!,
})
}
/>
</NFormItem>
<NFormItem label="y轴偏移">
<NInputNumber
precision={0}
showButton={false}
v-model:value={model.watermarkConfig!.yOffset}
onUpdateValue={(val) =>
updateSettingState('watermarkConfig', {
yOffset: val!,
})
}
/>
</NFormItem>
<NFormItem label="y轴间隙">
<NInputNumber
precision={0}
showButton={false}
v-model:value={model.watermarkConfig!.yGap}
onUpdateValue={(val) =>
updateSettingState('watermarkConfig', {
yGap: val!,
})
}
/>
</NFormItem>
<NFormItem label="旋转角度">
<NInputNumber
precision={0}
showButton={false}
v-model:value={model.watermarkConfig!.rotate}
onUpdateValue={(val) =>
updateSettingState('watermarkConfig', {
rotate: val!,
})
}
/>
</NFormItem>
</NForm>
</NFlex>
)
},
})

View File

@ -105,6 +105,20 @@ export const useSettingGetters = () => {
*/
const getMenuConfig = computed(() => variable.menuConfig)
/**
*
* @description
*
*/
const getColorWeakness = computed(() => variable.colorWeakness)
/**
*
* @description
*
*/
const getDynamicDocumentTitle = computed(() => variable.dynamicDocumentTitle)
return {
getDrawerPlacement,
getPrimaryColorOverride,
@ -122,16 +136,23 @@ export const useSettingGetters = () => {
getKeepAliveConfig,
getMenuConfig,
getAppThemeStr,
getColorWeakness,
getDynamicDocumentTitle,
}
}
export const useSettingActions = () => {
const { updateLocale, changePrimaryColor, updateSettingState } =
piniaSettingStore()
const {
updateLocale,
changePrimaryColor,
updateSettingState,
toggleColorWeakness,
} = piniaSettingStore()
return {
updateLocale,
changePrimaryColor,
updateSettingState,
toggleColorWeakness,
}
}

View File

@ -109,6 +109,12 @@ export const parseAndFindMatchingNodes = (
* sideBarLogo.title
*/
export const updateDocumentTitle = (option: AppMenuOption) => {
const { dynamicDocumentTitle } = piniaSettingStore()
if (!dynamicDocumentTitle) {
return
}
const { breadcrumbLabel } = option
if (!breadcrumbLabel) {

View File

@ -1,5 +1,5 @@
import { getAppDefaultLanguage } from '@/locales/utils'
import { colorToRgba, setStorage, updateObjectValue } from '@/utils'
import { colorToRgba, setStorage, updateObjectValue, setStyle } from '@/utils'
import { useI18n, useDayjs } from '@/hooks'
import { APP_CATCH_KEY, APP_THEME } from '@/app-config'
@ -52,8 +52,11 @@ export const piniaSettingStore = defineStore(
width: 384,
height: 384,
xOffset: 12,
xGap: 0,
yGap: 0,
yOffset: 60,
rotate: -15,
cross: true,
},
// 根路由信息
appRootRoute: {
@ -82,7 +85,14 @@ export const piniaSettingStore = defineStore(
accordion: false,
menuSiderBarLogo: true,
iconSize: 16,
menuWidth: 272,
inverted: false,
nativeScrollbar: false,
},
// 色弱模式
colorWeakness: false,
// 动态标题
dynamicDocumentTitle: true,
})
// 修改当前语言
@ -125,7 +135,6 @@ export const piniaSettingStore = defineStore(
*
* @description
* settingState key settingState
*
*
* @example
* updateSettingState('drawerPlacement', 'left')
@ -143,39 +152,49 @@ export const piniaSettingStore = defineStore(
updateObjectValue(settingState, key, value, cb)
}
const toggleColorWeakness = (bool: boolean) => {
const html = document.documentElement
updateSettingState('colorWeakness', bool)
setStyle(html, {
filter: bool ? 'invert(100%)' : '',
})
}
/**
*
*
*
* @description
*
*
*/
watch(
() => settingState.appTheme,
(ndata) => {
ndata
? (settingState.primaryColorOverride = Object.assign(
{},
settingState.primaryColorOverride,
APP_THEME.appNaiveUIThemeOverrides.dark,
APP_THEME.appNaiveUIThemeOverridesCommon.dark,
))
: (settingState.primaryColorOverride = Object.assign(
{},
settingState.primaryColorOverride,
APP_THEME.appNaiveUIThemeOverrides.light,
APP_THEME.appNaiveUIThemeOverridesCommon.light,
))
},
{
immediate: true,
once: true,
},
)
watchEffect(() => {
settingState.appTheme
? (settingState.primaryColorOverride = Object.assign(
{},
settingState.primaryColorOverride,
APP_THEME.appNaiveUIThemeOverrides.dark,
APP_THEME.appNaiveUIThemeOverridesCommon.dark,
))
: (settingState.primaryColorOverride = Object.assign(
{},
settingState.primaryColorOverride,
APP_THEME.appNaiveUIThemeOverrides.light,
APP_THEME.appNaiveUIThemeOverridesCommon.light,
))
toggleColorWeakness(settingState.colorWeakness)
if (!settingState.dynamicDocumentTitle) {
document.title = settingState.sideBarLogo?.title || 'Ray Template'
}
})
return {
...toRefs(settingState),
updateLocale,
changePrimaryColor,
updateSettingState,
toggleColorWeakness,
}
},
{

View File

@ -14,7 +14,10 @@ export interface WatermarkConfig {
height: number
xOffset: number
yOffset: number
xGap: number
yGap: number
rotate: number
cross: boolean
}
export interface AppRootRoute {
@ -70,4 +73,12 @@ export interface SettingState {
* accordion
*/
menuConfig: AppMenuConfig
colorWeakness: boolean
/**
*
* @description
*
* true
*/
dynamicDocumentTitle: boolean
}

View File

@ -10,11 +10,14 @@ export interface AppMenuConfig {
accordion: boolean
menuSiderBarLogo: boolean
iconSize: number
menuWidth: number
inverted: boolean
nativeScrollbar: boolean
}
export interface AppKeepAlive {
setupKeepAlive: boolean
keepAliveExclude?: string[]
keepAliveExclude: string[]
maxKeepAliveLength: number
}

View File

@ -2,7 +2,8 @@
/**
*
*
* @description
*
*
* @example
* ConditionalKeys<{ a: string, b: number }, string> // 'a'
@ -15,7 +16,8 @@ export type ConditionalKeys<Base, Condition> = NonNullable<
/**
*
*
* @description
*
*
* @example
* ConditionalExclude<{ a: string, b: number }, string> // { b: number }
@ -27,7 +29,8 @@ export type ConditionalExclude<Base, Condition> = Omit<
/**
*
*
* @description
*
*
* @example
* ConditionalPick<{ a: string, b: number }, string> // { a: string }
@ -39,7 +42,8 @@ export type ConditionalPick<Base, Condition> = Pick<
/**
*
*
* @description
*
*
* @example
* const A: Recordable = { a: 1, b: [] }
@ -48,7 +52,8 @@ export type Recordable<T = any> = Record<string, T>
/**
*
*
* @description
*
*
* @example
* ValueOf<{ a: string, b: number }> // string | number
@ -57,7 +62,8 @@ export type ValueOf<T extends object> = T[keyof T]
/**
*
*
* @description
*
*
* @example
* Mutable<{ readonly a: string }> // { a: string }
@ -68,7 +74,8 @@ export type Mutable<T> = {
/**
*
*
* @description
*
*
* @example
* DeepMutable<{ readonly a: { readonly b: { readonly c: string } } }> // { a: { b: { c: string } } }
@ -83,7 +90,8 @@ export type DeepMutable<T> = {
/**
*
* Promise
* @description
* Promise
*
* @example
* ReturnPromiseType<Promise<string>> // string
@ -91,3 +99,17 @@ export type DeepMutable<T> = {
*/
export type ReturnPromiseType<T extends Promise<any>> =
T extends Promise<infer U> ? U : never
/**
*
* @description
*
*
* @example
* DeepReadonly<{ a: { b: string } }> // { readonly a: { readonly b: string } }
*/
export type DeepReadonly<T> = T extends object
? {
readonly [P in keyof T]: DeepReadonly<T[P]>
}
: T