refactor: 范式分段写作页面下拉框支持图标渲染
- 用自定义下拉组件替代原生 select (原生不支持渲染组件) - 添加下拉框控制逻辑和点击外部关闭功能 - 添加自定义下拉框 CSS 样式 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,20 +14,27 @@
|
|||||||
<!-- 1. 选择范式 -->
|
<!-- 1. 选择范式 -->
|
||||||
<section class="writer-section">
|
<section class="writer-section">
|
||||||
<label class="writer-label">1. 选择写作范式</label>
|
<label class="writer-label">1. 选择写作范式</label>
|
||||||
<select
|
<div class="custom-select" @click="toggleDropdown">
|
||||||
v-model="selectedParadigmId"
|
<div class="custom-select-trigger">
|
||||||
@change="handleParadigmChange"
|
<template v-if="activeParadigm">
|
||||||
class="writer-select"
|
<IconLibrary :name="activeParadigm.icon" :size="16" />
|
||||||
>
|
<span>{{ activeParadigm.name }}</span>
|
||||||
<option value="" disabled>请选择范式...</option>
|
</template>
|
||||||
<option
|
<span v-else class="text-muted">请选择范式...</span>
|
||||||
v-for="p in paradigmList"
|
<IconLibrary name="expand" :size="14" class="ml-auto" />
|
||||||
:key="p.id"
|
</div>
|
||||||
:value="p.id"
|
<div v-show="isDropdownOpen" class="custom-select-dropdown">
|
||||||
>
|
<div
|
||||||
{{ p.icon }} {{ p.name }}
|
v-for="p in paradigmList"
|
||||||
</option>
|
:key="p.id"
|
||||||
</select>
|
@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">
|
<p v-if="activeParadigm" class="text-xs text-muted mt-2">
|
||||||
{{ activeParadigm.description }}
|
{{ activeParadigm.description }}
|
||||||
</p>
|
</p>
|
||||||
@@ -174,7 +181,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { useAppStore } from '../stores/app'
|
import { useAppStore } from '../stores/app'
|
||||||
import IconLibrary from './icons/IconLibrary.vue'
|
import IconLibrary from './icons/IconLibrary.vue'
|
||||||
@@ -189,6 +196,33 @@ const { paradigmWriterState, activeParadigm, generatedContent } = storeToRefs(ap
|
|||||||
const selectedParadigmId = ref('')
|
const selectedParadigmId = ref('')
|
||||||
const currentSectionIndex = ref(0)
|
const currentSectionIndex = ref(0)
|
||||||
const paradigmList = ref([])
|
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 = () => {
|
const loadAllParadigms = () => {
|
||||||
@@ -649,4 +683,59 @@ onMounted(() => {
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
cursor: not-allowed;
|
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>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user