refactor: 范式分段写作页面下拉框支持图标渲染
- 用自定义下拉组件替代原生 select (原生不支持渲染组件) - 添加下拉框控制逻辑和点击外部关闭功能 - 添加自定义下拉框 CSS 样式 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,20 +14,27 @@
|
||||
<!-- 1. 选择范式 -->
|
||||
<section class="writer-section">
|
||||
<label class="writer-label">1. 选择写作范式</label>
|
||||
<select
|
||||
v-model="selectedParadigmId"
|
||||
@change="handleParadigmChange"
|
||||
class="writer-select"
|
||||
>
|
||||
<option value="" disabled>请选择范式...</option>
|
||||
<option
|
||||
v-for="p in paradigmList"
|
||||
:key="p.id"
|
||||
:value="p.id"
|
||||
>
|
||||
{{ p.icon }} {{ p.name }}
|
||||
</option>
|
||||
</select>
|
||||
<div class="custom-select" @click="toggleDropdown">
|
||||
<div class="custom-select-trigger">
|
||||
<template v-if="activeParadigm">
|
||||
<IconLibrary :name="activeParadigm.icon" :size="16" />
|
||||
<span>{{ activeParadigm.name }}</span>
|
||||
</template>
|
||||
<span v-else class="text-muted">请选择范式...</span>
|
||||
<IconLibrary name="expand" :size="14" class="ml-auto" />
|
||||
</div>
|
||||
<div v-show="isDropdownOpen" class="custom-select-dropdown">
|
||||
<div
|
||||
v-for="p in paradigmList"
|
||||
:key="p.id"
|
||||
@click.stop="selectParadigm(p)"
|
||||
:class="['custom-select-option', { 'selected': selectedParadigmId === p.id }]"
|
||||
>
|
||||
<IconLibrary :name="p.icon" :size="16" />
|
||||
<span>{{ p.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="activeParadigm" class="text-xs text-muted mt-2">
|
||||
{{ activeParadigm.description }}
|
||||
</p>
|
||||
@@ -174,7 +181,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useAppStore } from '../stores/app'
|
||||
import IconLibrary from './icons/IconLibrary.vue'
|
||||
@@ -189,6 +196,33 @@ const { paradigmWriterState, activeParadigm, generatedContent } = storeToRefs(ap
|
||||
const selectedParadigmId = ref('')
|
||||
const currentSectionIndex = ref(0)
|
||||
const paradigmList = ref([])
|
||||
const isDropdownOpen = ref(false)
|
||||
|
||||
// 下拉框控制
|
||||
const toggleDropdown = () => {
|
||||
isDropdownOpen.value = !isDropdownOpen.value
|
||||
}
|
||||
|
||||
const selectParadigm = (p) => {
|
||||
selectedParadigmId.value = p.id
|
||||
isDropdownOpen.value = false
|
||||
handleParadigmChange()
|
||||
}
|
||||
|
||||
// 点击外部关闭下拉框
|
||||
const closeDropdown = (e) => {
|
||||
if (!e.target.closest('.custom-select')) {
|
||||
isDropdownOpen.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', closeDropdown)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('click', closeDropdown)
|
||||
})
|
||||
|
||||
// 加载完整的范式列表(包含自定义范式)
|
||||
const loadAllParadigms = () => {
|
||||
@@ -649,4 +683,59 @@ onMounted(() => {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* 自定义下拉框 */
|
||||
.custom-select {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.custom-select-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: var(--space-3);
|
||||
background: var(--bg-primary);
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-lg);
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.custom-select-trigger:hover {
|
||||
border-color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.custom-select-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-top: var(--space-1);
|
||||
background: var(--bg-elevated);
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-lg);
|
||||
z-index: 100;
|
||||
max-height: 240px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.custom-select-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: var(--space-3);
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.custom-select-option:hover {
|
||||
background: var(--bg-sunken);
|
||||
}
|
||||
|
||||
.custom-select-option.selected {
|
||||
background: var(--info-bg);
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user