🎨 Refactor save service
This commit is contained in:
@@ -5,6 +5,7 @@ import {useLogStore} from '@/stores/logStore';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { ref } from 'vue';
|
||||
import {SUPPORTED_LOCALES, setLocale, SupportedLocaleType} from '@/i18n';
|
||||
import { EncodingType } from '@/../bindings/voidraft/internal/models/models';
|
||||
|
||||
const editorStore = useEditorStore();
|
||||
const configStore = useConfigStore();
|
||||
@@ -13,6 +14,20 @@ const { t, locale } = useI18n();
|
||||
|
||||
// 语言下拉菜单
|
||||
const showLanguageMenu = ref(false);
|
||||
// 编码下拉菜单
|
||||
const showEncodingMenu = ref(false);
|
||||
|
||||
// 支持的编码格式
|
||||
const SUPPORTED_ENCODINGS = [
|
||||
{ code: EncodingType.EncodingUTF8, name: 'UTF-8' },
|
||||
{ code: EncodingType.EncodingUTF8BOM, name: 'UTF-8 with BOM' },
|
||||
{ code: EncodingType.EncodingUTF16LE, name: 'UTF-16 LE' },
|
||||
{ code: EncodingType.EncodingUTF16BE, name: 'UTF-16 BE' },
|
||||
{ code: EncodingType.EncodingISO88591, name: 'ISO-8859-1' },
|
||||
{ code: EncodingType.EncodingGB18030, name: 'GB18030' },
|
||||
{ code: EncodingType.EncodingGBK, name: 'GBK' },
|
||||
{ code: EncodingType.EncodingBig5, name: 'Big5' }
|
||||
];
|
||||
|
||||
// 切换语言
|
||||
const changeLanguage = (localeCode: SupportedLocaleType) => {
|
||||
@@ -23,6 +38,29 @@ const changeLanguage = (localeCode: SupportedLocaleType) => {
|
||||
// 切换语言菜单显示
|
||||
const toggleLanguageMenu = () => {
|
||||
showLanguageMenu.value = !showLanguageMenu.value;
|
||||
if (showLanguageMenu.value) {
|
||||
showEncodingMenu.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 切换编码
|
||||
const changeEncoding = (encoding: EncodingType) => {
|
||||
configStore.setEncoding(encoding);
|
||||
showEncodingMenu.value = false;
|
||||
};
|
||||
|
||||
// 切换编码菜单显示
|
||||
const toggleEncodingMenu = () => {
|
||||
showEncodingMenu.value = !showEncodingMenu.value;
|
||||
if (showEncodingMenu.value) {
|
||||
showLanguageMenu.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取编码名称
|
||||
const getEncodingDisplayName = (encoding: EncodingType) => {
|
||||
const encodingItem = SUPPORTED_ENCODINGS.find(item => item.code === encoding);
|
||||
return encodingItem ? encodingItem.name : encoding;
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -61,19 +99,37 @@ const toggleLanguageMenu = () => {
|
||||
<button class="tab-btn" @click="configStore.increaseTabSize" :disabled="configStore.config.tabSize >= configStore.MAX_TAB_SIZE">+</button>
|
||||
</span>
|
||||
</span>
|
||||
<span class="encoding">{{ t('toolbar.encoding') }}</span>
|
||||
|
||||
<!-- 编码选择按钮 -->
|
||||
<div class="selector-dropdown">
|
||||
<button class="selector-btn" @click="toggleEncodingMenu">
|
||||
{{ getEncodingDisplayName(configStore.config.encoding) }}
|
||||
<span class="arrow">▲</span>
|
||||
</button>
|
||||
<div class="selector-menu" v-if="showEncodingMenu">
|
||||
<div
|
||||
v-for="encoding in SUPPORTED_ENCODINGS"
|
||||
:key="encoding.code"
|
||||
class="selector-option"
|
||||
:class="{ active: configStore.config.encoding === encoding.code }"
|
||||
@click="changeEncoding(encoding.code)"
|
||||
>
|
||||
{{ encoding.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 语言切换按钮 -->
|
||||
<div class="language-selector">
|
||||
<button class="language-btn" @click="toggleLanguageMenu">
|
||||
<div class="selector-dropdown">
|
||||
<button class="selector-btn" @click="toggleLanguageMenu">
|
||||
{{ locale }}
|
||||
<span class="arrow-up">▲</span>
|
||||
<span class="arrow">▲</span>
|
||||
</button>
|
||||
<div class="language-menu" v-if="showLanguageMenu">
|
||||
<div class="selector-menu" v-if="showLanguageMenu">
|
||||
<div
|
||||
v-for="lang in SUPPORTED_LOCALES"
|
||||
:key="lang.code"
|
||||
class="language-option"
|
||||
class="selector-option"
|
||||
:class="{ active: locale === lang.code }"
|
||||
@click="changeLanguage(lang.code)"
|
||||
>
|
||||
@@ -200,17 +256,12 @@ const toggleLanguageMenu = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.encoding {
|
||||
color: var(--text-muted);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* 语言切换样式 */
|
||||
.language-selector {
|
||||
/* 通用下拉选择器样式 */
|
||||
.selector-dropdown {
|
||||
position: relative;
|
||||
|
||||
.language-btn {
|
||||
.selector-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--text-muted);
|
||||
@@ -226,13 +277,13 @@ const toggleLanguageMenu = () => {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.arrow-up {
|
||||
.arrow {
|
||||
font-size: 8px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.language-menu {
|
||||
.selector-menu {
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
right: 0;
|
||||
@@ -240,11 +291,13 @@ const toggleLanguageMenu = () => {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 3px;
|
||||
margin-bottom: 4px;
|
||||
min-width: 100px;
|
||||
min-width: 120px;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
|
||||
.language-option {
|
||||
.selector-option {
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
|
@@ -43,14 +43,12 @@ const i18n = createI18n({
|
||||
GetLanguage().then(lang => {
|
||||
if (lang) {
|
||||
i18n.global.locale = lang as any;
|
||||
document.documentElement.setAttribute('lang', lang);
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('Failed to get language from backend:', error);
|
||||
// 如果获取失败,使用浏览器语言作为后备
|
||||
const browserLang = getBrowserLanguage();
|
||||
i18n.global.locale = browserLang as any;
|
||||
document.documentElement.setAttribute('lang', browserLang);
|
||||
});
|
||||
|
||||
// 切换语言的方法
|
||||
|
@@ -1,21 +1,11 @@
|
||||
import {createApp} from 'vue';
|
||||
import App from './App.vue';
|
||||
import '@/assets/styles/index.css';
|
||||
import PrimeVue from 'primevue/config';
|
||||
import Aura from '@primeuix/themes/aura';
|
||||
import {createPinia} from 'pinia';
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
|
||||
import i18n from './i18n';
|
||||
|
||||
const pinia = createPinia()
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
|
||||
const app = createApp(App);
|
||||
app.use(pinia)
|
||||
app.use(PrimeVue, {
|
||||
theme: {
|
||||
preset: Aura
|
||||
}
|
||||
});
|
||||
app.use(i18n);
|
||||
app.mount('#app');
|
||||
|
@@ -3,10 +3,10 @@ import {ref, watch} from 'vue';
|
||||
import {useDebounceFn} from '@vueuse/core';
|
||||
import {
|
||||
GetEditorConfig,
|
||||
ResetToDefault,
|
||||
ResetConfig,
|
||||
UpdateEditorConfig
|
||||
} from '@/../bindings/voidraft/internal/services/configservice';
|
||||
import {EditorConfig, TabType} from '@/../bindings/voidraft/internal/models/models';
|
||||
import {EditorConfig, TabType, EncodingType} from '@/../bindings/voidraft/internal/models/models';
|
||||
import {useLogStore} from './logStore';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
@@ -20,6 +20,26 @@ const DEFAULT_TAB_SIZE = 4;
|
||||
const MIN_TAB_SIZE = 2;
|
||||
const MAX_TAB_SIZE = 8;
|
||||
|
||||
// 支持的编码
|
||||
const SUPPORTED_ENCODINGS = [
|
||||
EncodingType.EncodingUTF8,
|
||||
EncodingType.EncodingUTF8BOM,
|
||||
EncodingType.EncodingUTF16LE,
|
||||
EncodingType.EncodingUTF16BE,
|
||||
EncodingType.EncodingISO88591,
|
||||
EncodingType.EncodingGB18030,
|
||||
EncodingType.EncodingGBK,
|
||||
EncodingType.EncodingBig5
|
||||
];
|
||||
|
||||
// 配置项限制定义
|
||||
const CONFIG_LIMITS = {
|
||||
fontSize: { min: MIN_FONT_SIZE, max: MAX_FONT_SIZE, default: DEFAULT_FONT_SIZE },
|
||||
tabSize: { min: MIN_TAB_SIZE, max: MAX_TAB_SIZE, default: DEFAULT_TAB_SIZE },
|
||||
tabType: { values: [TabType.TabTypeSpaces, TabType.TabTypeTab], default: TabType.TabTypeSpaces },
|
||||
encoding: { values: SUPPORTED_ENCODINGS, default: EncodingType.EncodingUTF8 }
|
||||
};
|
||||
|
||||
export const useConfigStore = defineStore('config', () => {
|
||||
// 获取日志store
|
||||
const logStore = useLogStore();
|
||||
@@ -28,7 +48,7 @@ export const useConfigStore = defineStore('config', () => {
|
||||
// 配置状态
|
||||
const config = ref<EditorConfig>(new EditorConfig({
|
||||
fontSize: DEFAULT_FONT_SIZE,
|
||||
encoding: 'UTF-8',
|
||||
encoding: EncodingType.EncodingUTF8,
|
||||
enableTabIndent: true,
|
||||
tabSize: DEFAULT_TAB_SIZE,
|
||||
tabType: TabType.TabTypeSpaces
|
||||
@@ -58,42 +78,44 @@ export const useConfigStore = defineStore('config', () => {
|
||||
let hasChanges = false;
|
||||
|
||||
// 验证字体大小
|
||||
if (config.value.fontSize < MIN_FONT_SIZE || config.value.fontSize > MAX_FONT_SIZE) {
|
||||
if (config.value.fontSize < CONFIG_LIMITS.fontSize.min || config.value.fontSize > CONFIG_LIMITS.fontSize.max) {
|
||||
const oldValue = config.value.fontSize;
|
||||
config.value.fontSize = oldValue < MIN_FONT_SIZE ? MIN_FONT_SIZE :
|
||||
oldValue > MAX_FONT_SIZE ? MAX_FONT_SIZE :
|
||||
DEFAULT_FONT_SIZE;
|
||||
config.value.fontSize = oldValue < CONFIG_LIMITS.fontSize.min ? CONFIG_LIMITS.fontSize.min :
|
||||
oldValue > CONFIG_LIMITS.fontSize.max ? CONFIG_LIMITS.fontSize.max :
|
||||
CONFIG_LIMITS.fontSize.default;
|
||||
|
||||
logStore.warning(t('config.fontSizeFixed', {
|
||||
value: oldValue,
|
||||
fixed: config.value.fontSize
|
||||
}));
|
||||
logStore.warning(t('config.fontSizeFixed'));
|
||||
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
// 验证Tab大小
|
||||
if (config.value.tabSize < MIN_TAB_SIZE || config.value.tabSize > MAX_TAB_SIZE) {
|
||||
if (config.value.tabSize < CONFIG_LIMITS.tabSize.min || config.value.tabSize > CONFIG_LIMITS.tabSize.max) {
|
||||
const oldValue = config.value.tabSize;
|
||||
config.value.tabSize = oldValue < MIN_TAB_SIZE ? MIN_TAB_SIZE :
|
||||
oldValue > MAX_TAB_SIZE ? MAX_TAB_SIZE :
|
||||
DEFAULT_TAB_SIZE;
|
||||
config.value.tabSize = oldValue < CONFIG_LIMITS.tabSize.min ? CONFIG_LIMITS.tabSize.min :
|
||||
oldValue > CONFIG_LIMITS.tabSize.max ? CONFIG_LIMITS.tabSize.max :
|
||||
CONFIG_LIMITS.tabSize.default;
|
||||
|
||||
logStore.warning(t('config.tabSizeFixed', {
|
||||
value: oldValue,
|
||||
fixed: config.value.tabSize
|
||||
}));
|
||||
logStore.warning(t('config.tabSizeFixed'));
|
||||
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
// 验证TabType是否合法
|
||||
const validTabTypes = [TabType.TabTypeSpaces, TabType.TabTypeTab];
|
||||
if (!validTabTypes.includes(config.value.tabType)) {
|
||||
if (!CONFIG_LIMITS.tabType.values.includes(config.value.tabType)) {
|
||||
const oldValue = config.value.tabType;
|
||||
config.value.tabType = TabType.TabTypeSpaces;
|
||||
config.value.tabType = CONFIG_LIMITS.tabType.default;
|
||||
|
||||
logStore.warning(t('config.tabTypeFixed', { value: oldValue }));
|
||||
logStore.warning(t('config.tabTypeFixed'));
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
// 验证编码类型是否合法
|
||||
if (!CONFIG_LIMITS.encoding.values.includes(config.value.encoding)) {
|
||||
const oldValue = config.value.encoding;
|
||||
config.value.encoding = CONFIG_LIMITS.encoding.default;
|
||||
|
||||
logStore.warning(t('config.encodingFixed'));
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
@@ -121,67 +143,69 @@ export const useConfigStore = defineStore('config', () => {
|
||||
}
|
||||
}, {deep: true});
|
||||
|
||||
// 字体缩放
|
||||
function increaseFontSize() {
|
||||
if (config.value.fontSize < MAX_FONT_SIZE) {
|
||||
config.value.fontSize += 1;
|
||||
// 更新特定配置项的类型安全方法
|
||||
function updateConfig<K extends keyof EditorConfig>(
|
||||
key: K,
|
||||
value: EditorConfig[K] | ((currentValue: EditorConfig[K]) => EditorConfig[K])
|
||||
) {
|
||||
if (typeof value === 'function') {
|
||||
const currentValue = config.value[key];
|
||||
const fn = value as (val: EditorConfig[K]) => EditorConfig[K];
|
||||
config.value[key] = fn(currentValue);
|
||||
} else {
|
||||
config.value[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// 字体缩小
|
||||
function decreaseFontSize() {
|
||||
if (config.value.fontSize > MIN_FONT_SIZE) {
|
||||
config.value.fontSize -= 1;
|
||||
}
|
||||
// 用于数字类型配置的增减方法
|
||||
function adjustFontSize(amount: number) {
|
||||
let newValue = config.value.fontSize + amount;
|
||||
|
||||
if (newValue < MIN_FONT_SIZE) newValue = MIN_FONT_SIZE;
|
||||
if (newValue > MAX_FONT_SIZE) newValue = MAX_FONT_SIZE;
|
||||
|
||||
config.value.fontSize = newValue;
|
||||
}
|
||||
|
||||
// 重置字体大小
|
||||
function resetFontSize() {
|
||||
config.value.fontSize = DEFAULT_FONT_SIZE;
|
||||
function adjustTabSize(amount: number) {
|
||||
let newValue = config.value.tabSize + amount;
|
||||
|
||||
if (newValue < MIN_TAB_SIZE) newValue = MIN_TAB_SIZE;
|
||||
if (newValue > MAX_TAB_SIZE) newValue = MAX_TAB_SIZE;
|
||||
|
||||
config.value.tabSize = newValue;
|
||||
}
|
||||
|
||||
// 设置编码
|
||||
function setEncoding(newEncoding: string) {
|
||||
config.value.encoding = newEncoding;
|
||||
}
|
||||
|
||||
// Tab相关方法
|
||||
function toggleTabIndent() {
|
||||
config.value.enableTabIndent = !config.value.enableTabIndent;
|
||||
}
|
||||
|
||||
// 增加Tab大小
|
||||
function increaseTabSize() {
|
||||
if (config.value.tabSize < MAX_TAB_SIZE) {
|
||||
config.value.tabSize += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 减少Tab大小
|
||||
function decreaseTabSize() {
|
||||
if (config.value.tabSize > MIN_TAB_SIZE) {
|
||||
config.value.tabSize -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 切换Tab类型(空格或制表符)
|
||||
// Tab相关类型安全的配置切换
|
||||
function toggleTabType() {
|
||||
config.value.tabType = config.value.tabType === TabType.TabTypeSpaces
|
||||
? TabType.TabTypeTab
|
||||
config.value.tabType = config.value.tabType === TabType.TabTypeSpaces
|
||||
? TabType.TabTypeTab
|
||||
: TabType.TabTypeSpaces;
|
||||
}
|
||||
|
||||
// 设置编码类型
|
||||
function setEncoding(encoding: string) {
|
||||
// 验证编码是否有效的EncodingType
|
||||
const encodingType = encoding as EncodingType;
|
||||
if (SUPPORTED_ENCODINGS.includes(encodingType)) {
|
||||
config.value.encoding = encodingType;
|
||||
} else {
|
||||
logStore.warning(t('config.invalidEncoding'));
|
||||
}
|
||||
}
|
||||
|
||||
// 重置为默认配置
|
||||
async function resetToDefaults() {
|
||||
try {
|
||||
await ResetToDefault();
|
||||
await loadConfigFromBackend();
|
||||
await ResetConfig();
|
||||
await loadConfigFromBackend();
|
||||
logStore.info(t('config.resetSuccess'));
|
||||
} catch (error) {
|
||||
console.error('Failed to reset configuration:', error);
|
||||
logStore.error(t('config.resetFailed'));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
// 状态
|
||||
config,
|
||||
@@ -193,18 +217,26 @@ export const useConfigStore = defineStore('config', () => {
|
||||
DEFAULT_FONT_SIZE,
|
||||
MIN_TAB_SIZE,
|
||||
MAX_TAB_SIZE,
|
||||
SUPPORTED_ENCODINGS,
|
||||
|
||||
// 方法
|
||||
// 核心方法
|
||||
loadConfigFromBackend,
|
||||
saveConfigToBackend,
|
||||
updateConfig,
|
||||
resetToDefaults,
|
||||
|
||||
// 字体大小方法
|
||||
increaseFontSize: () => adjustFontSize(1),
|
||||
decreaseFontSize: () => adjustFontSize(-1),
|
||||
resetFontSize: () => updateConfig('fontSize', DEFAULT_FONT_SIZE),
|
||||
|
||||
// 编码操作
|
||||
setEncoding,
|
||||
increaseFontSize,
|
||||
decreaseFontSize,
|
||||
resetFontSize,
|
||||
toggleTabIndent,
|
||||
increaseTabSize,
|
||||
decreaseTabSize,
|
||||
toggleTabType,
|
||||
resetToDefaults
|
||||
|
||||
// Tab操作
|
||||
toggleTabIndent: () => updateConfig('enableTabIndent', val => !val),
|
||||
increaseTabSize: () => adjustTabSize(1),
|
||||
decreaseTabSize: () => adjustTabSize(-1),
|
||||
toggleTabType
|
||||
};
|
||||
});
|
@@ -43,9 +43,6 @@ export const useEditorStore = defineStore('editor', () => {
|
||||
documentStats,
|
||||
editorView,
|
||||
|
||||
// 配置引用
|
||||
config: configStore.config,
|
||||
|
||||
// 方法
|
||||
setEditorView,
|
||||
updateDocumentStats,
|
||||
|
Reference in New Issue
Block a user