agent-Specialization/static/src/components/personalization/tabs/ModelTab.vue
JOJO f5bfab4056 feat(settings): 个人空间重构为紧凑窄版布局,完善移动端适配
- 卡片窄化至 648px、圆角 14px、侧栏 184px,控件行高紧凑化
- 4429 行主文件拆分为 13 个 tab 子组件 + 共享样式表
- 移动端(≤760px)改为 iOS 设置式「列表→子页」导航
- 修复内容区缺 flex:1 导致设置行无法占满
- 修复交流语气行 label 被 grid auto 列挤压成竖排
- 修复移动端弹窗顶栏被主界面顶栏(z-index 1500)遮挡
- 窄屏禁用选项 hover/active 视觉态与 tab 切换过渡动画
- 修复上下文图标 28 viewBox/1.7 描边导致的视觉偏小偏细
2026-08-29 21:58:53 +08:00

160 lines
7.3 KiB
Vue

<script setup lang="ts">
import { inject } from 'vue';
defineOptions({ name: 'ModelTab' });
/**
* 共享上下文由 PersonalizationDrawer.vue 通过 provide 注入。
* 解构出的名称与主文件 script 顶层绑定一致,模板可直接引用。
*/
const ctx = inject<Record<string, any>>('personalizationDrawer')!;
const {
personalization,
form,
activeDropdown,
defaultModelLabel,
filteredModelOptions,
floatingMenuStyle,
isEffortActive,
isRunModeActive,
reasoningEffortLabel,
runModeLabel,
selectDefaultModel,
selectDefaultReasoningEffort,
selectDefaultRunMode,
toggleDropdown,
runModeOptions,
reasoningEffortOptions,
activeTheme
} = ctx;
</script>
<template>
<section
class="settings-page"
data-tutorial="personal-page-model"
>
<div class="settings-select-row">
<span class="settings-row-copy"
><span class="settings-row-title">{{ $t('personalization.defaultModelTitle') }}</span
><span class="settings-row-desc"
>{{ $t('personalization.defaultModelDesc') }}</span
></span
>
<div
class="settings-select-wrap"
:class="{ open: activeDropdown === 'model' }"
@click.stop
>
<button
type="button"
class="settings-select-button"
@click="toggleDropdown('model')"
>
{{ defaultModelLabel }}
<span class="select-chevron" aria-hidden="true"></span>
</button>
<div
:class="['settings-floating-menu', { dark: activeTheme === 'dark' }]"
:style="activeDropdown ? floatingMenuStyle : undefined"
>
<button
v-for="option in filteredModelOptions"
:key="option.id"
type="button"
class="settings-menu-option"
:class="{
selected: form.default_model === option.value,
disabled: option.disabled
}"
:disabled="option.disabled"
@click="selectDefaultModel(option.value)"
>
<strong>{{ option.label }}</strong
><span>{{ option.disabled ? $t('personalization.modelDisabled') : option.desc }}</span
><svg viewBox="0 0 24 24"><path d="M5 12.5 9.5 17 19 7" /></svg>
</button>
</div>
</div>
</div>
<div class="settings-select-row">
<span class="settings-row-copy"
><span class="settings-row-title">{{ $t('personalization.defaultRunModeTitle') }}</span
><span class="settings-row-desc"
>{{ $t('personalization.defaultRunModeDesc') }}</span
></span
>
<div
class="settings-select-wrap"
:class="{ open: activeDropdown === 'run-mode' }"
@click.stop
>
<button
type="button"
class="settings-select-button"
@click="toggleDropdown('run-mode')"
>
{{ runModeLabel }}
<span class="select-chevron" aria-hidden="true"></span>
</button>
<div
:class="['settings-floating-menu', { dark: activeTheme === 'dark' }]"
:style="activeDropdown ? floatingMenuStyle : undefined"
>
<button
v-for="option in runModeOptions"
:key="option.id"
type="button"
class="settings-menu-option"
:class="{ selected: isRunModeActive(option.value) }"
@click="selectDefaultRunMode(option.value)"
>
<strong>{{ $t(option.labelKey) }}</strong
><span>{{ $t(option.descKey) }}</span
><svg viewBox="0 0 24 24"><path d="M5 12.5 9.5 17 19 7" /></svg>
</button>
</div>
</div>
</div>
<div class="settings-select-row">
<span class="settings-row-copy"
><span class="settings-row-title">{{ $t('personalization.reasoningEffortTitle') }}</span
><span class="settings-row-desc"
>{{ $t('personalization.reasoningEffortDesc') }}</span
></span
>
<div
class="settings-select-wrap"
:class="{ open: activeDropdown === 'reasoning-effort' }"
@click.stop
>
<button
type="button"
class="settings-select-button"
@click="toggleDropdown('reasoning-effort')"
>
{{ reasoningEffortLabel }}
<span class="select-chevron" aria-hidden="true"></span>
</button>
<div
:class="['settings-floating-menu', { dark: activeTheme === 'dark' }]"
:style="activeDropdown ? floatingMenuStyle : undefined"
>
<button
v-for="option in reasoningEffortOptions"
:key="option.id"
type="button"
class="settings-menu-option"
:class="{ selected: isEffortActive(option.value) }"
@click="selectDefaultReasoningEffort(option.value)"
>
<strong>{{ $t(option.labelKey) }}</strong
><span>{{ $t(option.descKey) }}</span
><svg viewBox="0 0 24 24"><path d="M5 12.5 9.5 17 19 7" /></svg>
</button>
</div>
</div>
</div>
</section>
</template>