修复: 设置页和分离窗口渲染崩溃(TDZ + 窗口权限通配符)

- AdvancedSection clampApprovalTimeout 常量移到 reactive 之前(打包后 const 初始化顺序 TDZ)
- @/i18n 去掉对 @/stores/appSettings 的 import,改直读 localStorage
- Tauri capability 加 ai-detached-* / fe-detached-* 通配符(分离窗口 listen 权限)
This commit is contained in:
2026-07-01 00:48:07 +08:00
parent 3758bea0b5
commit bce2fea4e5
4 changed files with 20 additions and 19 deletions

View File

@@ -1,7 +1,7 @@
{ {
"identifier": "default", "identifier": "default",
"description": "DevFlow default permissions", "description": "DevFlow default permissions",
"windows": ["main", "ai-detached"], "windows": ["main", "ai-detached", "ai-detached-*", "fe-detached-*"],
"permissions": [ "permissions": [
"core:default", "core:default",
"core:event:default", "core:event:default",

View File

@@ -86,8 +86,14 @@ onMounted(async () => {
// 字段。此处用 msg 拼标题+内容,dangerLabel 作确认按钮文案,自渲染独立弹层(上方模板)。 // 字段。此处用 msg 拼标题+内容,dangerLabel 作确认按钮文案,自渲染独立弹层(上方模板)。
const { confirmState, confirmDialog, answerConfirm } = useConfirm() const { confirmState, confirmDialog, answerConfirm } = useConfirm()
// 三档合法值 + 脏值白名单兜底:KV 被外部改库为非法值(空串/非三档)时回退 low, // 审批超时合法选项白名单(对齐 <select> option);脏值回退默认 15min。
// 防 <select v-model> 无匹配 option 致控件空白(后端 audit 脏值 fail-safe 降级审批,前端需对齐可视) // 必须在 settings reactive 之前定义,防打包后初始化顺序导致 TDZ
const VALID_APPROVAL_TIMEOUTS = [0, 300_000, 900_000, 1_800_000, 3_600_000]
function clampApprovalTimeout(raw: number): number {
return VALID_APPROVAL_TIMEOUTS.includes(raw) ? raw : 900_000
}
// 三档合法值 + 脏值白名单兜底
const VALID_MODES = ['low', 'medium', 'all'] as const const VALID_MODES = ['low', 'medium', 'all'] as const
type AutoMode = (typeof VALID_MODES)[number] type AutoMode = (typeof VALID_MODES)[number]
function clampMode(raw: string): AutoMode { function clampMode(raw: string): AutoMode {
@@ -145,14 +151,6 @@ function markSaved() {
rowLogLevel.value?.markSaved() rowLogLevel.value?.markSaved()
} }
// 审批超时合法选项白名单(对齐 <select> option);脏值(外部改库为非法数字)回退默认 15min,
// 防 <select v-model> 无匹配 option 致控件空白。允许的取值:0/5/15/30/60 分钟对应毫秒数。
const VALID_APPROVAL_TIMEOUTS = [0, 300_000, 900_000, 1_800_000, 3_600_000]
function clampApprovalTimeout(raw: number): number {
return VALID_APPROVAL_TIMEOUTS.includes(raw) ? raw : 900_000
}
// 审批超时下拉变更:落 KV(df-approval-timeout,ms)+ 显「已保存」反馈。
// 下一笔发起的审批即生效(aiShared.startApprovalTimer 每次实时读),已在跑的计时器沿用旧值。 // 下一笔发起的审批即生效(aiShared.startApprovalTimer 每次实时读),已在跑的计时器沿用旧值。
function onApprovalTimeoutChange() { function onApprovalTimeoutChange() {
appSettings.set('df-approval-timeout', settings.approvalTimeout) appSettings.set('df-approval-timeout', settings.approvalTimeout)

View File

@@ -43,8 +43,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, watch, onMounted, useTemplateRef } from 'vue' import { reactive, watch, onMounted, useTemplateRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { useAppSettingsStore } from '@/stores/appSettings' import { useAppSettingsStore } from '@/stores/appSettings'
import i18n from '@/i18n'
import SettingRow from './SettingRow.vue' import SettingRow from './SettingRow.vue'
// ============================================================ // ============================================================
@@ -53,6 +53,7 @@ import SettingRow from './SettingRow.vue'
// 阶段5:SettingRow 封装行布局,控件变更后调 markSaved 显"已保存" // 阶段5:SettingRow 封装行布局,控件变更后调 markSaved 显"已保存"
// ============================================================ // ============================================================
const appSettings = useAppSettingsStore() const appSettings = useAppSettingsStore()
const { locale } = useI18n()
const settings = reactive({ const settings = reactive({
theme: appSettings.get<string>('df-theme', 'dark'), theme: appSettings.get<string>('df-theme', 'dark'),
@@ -107,7 +108,7 @@ watch(() => settings.streamingMd, (val) => {
watch(() => settings.language, (val) => { watch(() => settings.language, (val) => {
void appSettings.set('df-language', val) void appSettings.set('df-language', val)
// 同步 i18n 实例,让界面立即跟随语言切换 // 同步 i18n 实例,让界面立即跟随语言切换
i18n.global.locale.value = val as 'zh-CN' | 'en' locale.value = val as 'zh-CN' | 'en'
}) })
onMounted(() => { onMounted(() => {

View File

@@ -1,14 +1,16 @@
import { createI18n } from 'vue-i18n' import { createI18n } from 'vue-i18n'
import zhCN from './zh-CN' import zhCN from './zh-CN'
import en from './en' import en from './en'
import { useAppSettingsStore } from '@/stores/appSettings'
// 界面语言:模块加载时 appSettings 缓存尚未填充(loadAll 在 App.vue onMounted 异步执行), // 界面语言:直接读 localStorage(避免 import @/stores/appSettings 形成循环依赖 TDZ)。
// 故这里 get() 拿到默认 'zh-CN';真实用户偏好由 App.vue 在 loadAll 完成后回填到 // appSettings.loadAll 也会从 SQLite 写入 localStorage,此处直读与 store 行为一致。
// i18n.global.locale.value,初帧渲染短暂 zh-CN 不影响功能。 const getInitialLocale = (): string => {
const getInitialLocale = () => {
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
return useAppSettingsStore().get<string>('df-language', 'zh-CN') try {
return localStorage.getItem('df-language') || 'zh-CN'
} catch {
return 'zh-CN'
}
} }
return 'zh-CN' return 'zh-CN'
} }