feat: init
This commit is contained in:
68
src/components/global-setting/block.vue
Normal file
68
src/components/global-setting/block.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="block">
|
||||
<h5 class="title">{{ title }}</h5>
|
||||
<div v-for="option in options" :key="option.name" class="switch-wrapper">
|
||||
<span>{{ $t(option.name) }}</span>
|
||||
<form-wrapper :type="option.type || 'switch'" :name="option.key" :default-value="option.defaultVal" @input-change="handleChange" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useAppStore } from '@/store'
|
||||
import { PropType } from 'vue'
|
||||
import FormWrapper from './form-wrapper.vue'
|
||||
|
||||
interface OptionsProps {
|
||||
name: string
|
||||
key: string
|
||||
type?: string
|
||||
defaultVal?: boolean | string | number
|
||||
}
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
options: {
|
||||
type: Array as PropType<OptionsProps[]>,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
})
|
||||
const appStore = useAppStore()
|
||||
const handleChange = async ({ key, value }: { key: string; value: unknown }) => {
|
||||
if (key === 'colorWeak') {
|
||||
document.body.style.filter = value ? 'invert(80%)' : 'none'
|
||||
}
|
||||
if (key === 'menuFromServer' && value) {
|
||||
await appStore.fetchServerMenuConfig()
|
||||
}
|
||||
if (key === 'topMenu') {
|
||||
appStore.updateSettings({
|
||||
menuCollapse: false,
|
||||
})
|
||||
}
|
||||
appStore.updateSettings({ [key]: value })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.block {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 10px 0;
|
||||
padding: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.switch-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 32px;
|
||||
}
|
||||
</style>
|
||||
34
src/components/global-setting/form-wrapper.vue
Normal file
34
src/components/global-setting/form-wrapper.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<a-input-number
|
||||
v-if="type === 'number'"
|
||||
:style="{ width: '80px' }"
|
||||
size="small"
|
||||
:default-value="defaultValue as number"
|
||||
@change="handleChange"
|
||||
/>
|
||||
<a-switch v-else :default-checked="defaultValue as boolean" size="small" @change="handleChange" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
defaultValue: {
|
||||
type: [String, Boolean, Number],
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['inputChange'])
|
||||
const handleChange = (value: unknown) => {
|
||||
emit('inputChange', {
|
||||
value,
|
||||
key: props.name,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
98
src/components/global-setting/index.vue
Normal file
98
src/components/global-setting/index.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<div v-if="!appStore.navbar" class="fixed-settings" @click="setVisible">
|
||||
<a-button type="primary">
|
||||
<template #icon>
|
||||
<icon-settings />
|
||||
</template>
|
||||
</a-button>
|
||||
</div>
|
||||
<a-drawer
|
||||
:width="300"
|
||||
unmount-on-close
|
||||
:visible="visible"
|
||||
:cancel-text="$t('settings.close')"
|
||||
:ok-text="$t('settings.copySettings')"
|
||||
@ok="copySettings"
|
||||
@cancel="cancel"
|
||||
>
|
||||
<template #title>{{ $t('settings.title') }}</template>
|
||||
<Block :options="contentOpts" :title="$t('settings.content')" />
|
||||
<Block :options="othersOpts" :title="$t('settings.otherSettings')" />
|
||||
<a-alert>{{ $t('settings.alertContent') }}</a-alert>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useAppStore } from '@/store'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import Block from './block.vue'
|
||||
|
||||
const emit = defineEmits(['cancel'])
|
||||
|
||||
const appStore = useAppStore()
|
||||
const { t } = useI18n()
|
||||
const { copy } = useClipboard()
|
||||
const visible = computed(() => appStore.globalSettings)
|
||||
const contentOpts = computed(() => [
|
||||
{ name: 'settings.navbar', key: 'navbar', defaultVal: appStore.navbar },
|
||||
// {
|
||||
// name: 'settings.menu',
|
||||
// key: 'menu',
|
||||
// defaultVal: appStore.menu,
|
||||
// },
|
||||
// {
|
||||
// name: 'settings.topMenu',
|
||||
// key: 'topMenu',
|
||||
// defaultVal: appStore.topMenu,
|
||||
// },
|
||||
{ name: 'settings.footer', key: 'footer', defaultVal: appStore.footer },
|
||||
{ name: 'settings.tabBar', key: 'tabBar', defaultVal: appStore.tabBar },
|
||||
{
|
||||
name: 'settings.menuFromServer',
|
||||
key: 'menuFromServer',
|
||||
defaultVal: appStore.menuFromServer,
|
||||
},
|
||||
{
|
||||
name: 'settings.menuWidth',
|
||||
key: 'menuWidth',
|
||||
defaultVal: appStore.menuWidth,
|
||||
type: 'number',
|
||||
},
|
||||
])
|
||||
const othersOpts = computed(() => [
|
||||
{
|
||||
name: 'settings.colorWeak',
|
||||
key: 'colorWeak',
|
||||
defaultVal: appStore.colorWeak,
|
||||
},
|
||||
])
|
||||
|
||||
const cancel = () => {
|
||||
appStore.updateSettings({ globalSettings: false })
|
||||
emit('cancel')
|
||||
}
|
||||
const copySettings = async () => {
|
||||
const text = JSON.stringify(appStore.$state, null, 2)
|
||||
await copy(text)
|
||||
Message.success(t('settings.copySettings.message'))
|
||||
}
|
||||
const setVisible = () => {
|
||||
appStore.updateSettings({ globalSettings: true })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.fixed-settings {
|
||||
position: fixed;
|
||||
top: 280px;
|
||||
right: 0;
|
||||
|
||||
svg {
|
||||
font-size: 18px;
|
||||
vertical-align: -4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user