deotalandAi/.trae/documents/新建项目系列选择功能实现.md

4.4 KiB
Raw Blame History

新建项目系列选择功能实现

需求分析

  • 当用户点击"新建项目"卡片时,需要弹出系列选择弹窗
  • 系列弹窗包含两个选项Done 和 Oone对应图片在 src/assets/xh 文件夹中
  • 选中后将系列名称作为 type 参数传递给 createNewProject 函数

实现计划

1. 创建 SeriesSelector 组件

  • 文件路径src/views/components/SeriesSelector.vue
  • 功能
    • 显示两个系列选项Done 和 Oone
    • 每个选项显示对应的图片
    • 支持选中状态切换
    • 提供确认和取消按钮
    • 通过 emit 事件返回选中的系列名称

2. 修改 CreationWorkspace.vue

  • 引入组件:在 CreationWorkspace.vue 中引入 SeriesSelector 组件
  • 添加状态管理
    • showSeriesSelector:控制系列选择弹窗的显示/隐藏
  • 修改新建项目逻辑
    • 点击"新建项目"卡片时,显示系列选择弹窗
    • 监听 SeriesSelector 的确认事件,获取选中的系列名称
    • 将系列名称作为 type 参数调用 createNewProject 函数

3. 样式设计

  • 系列选择弹窗采用与现有删除确认弹窗一致的设计风格
  • 系列选项卡片包含图片和名称,支持悬停和选中效果
  • 确认和取消按钮使用现有按钮样式

代码结构

SeriesSelector.vue

<template>
  <!-- 系列选择弹窗 -->
  <div v-if="show" class="modal-overlay" @click="onCancel">
    <div class="modal-content" @click.stop>
      <!-- 模态头部 -->
      <div class="modal-header">
        <h2 class="modal-title">{{ t('creationWorkspace.selectSeries') }}</h2>
      </div>
      
      <!-- 模态内容 -->
      <div class="modal-body">
        <div class="series-selector-content">
          <!-- 系列选项列表 -->
          <div class="series-list">
            <!-- Done 系列 -->
            <div 
              class="series-item" 
              :class="{ active: selectedSeries === 'Done' }"
              @click="selectedSeries = 'Done'"
            >
              <div class="series-image">
                <img src="@/assets/xh/Done.webp" alt="Done" />
              </div>
              <div class="series-name">Done</div>
            </div>
            
            <!-- Oone 系列 -->
            <div 
              class="series-item" 
              :class="{ active: selectedSeries === 'Oone' }"
              @click="selectedSeries = 'Oone'"
            >
              <div class="series-image">
                <img src="@/assets/xh/Oone.webp" alt="Oone" />
              </div>
              <div class="series-name">Oone</div>
            </div>
          </div>
          
          <!-- 操作按钮 -->
          <div class="series-actions">
            <button class="modal-action-btn cancel" @click="onCancel">
              {{ t('creationWorkspace.cancel') }}
            </button>
            <button class="modal-action-btn primary" @click="onConfirm">
              {{ t('creationWorkspace.confirm') }}
            </button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, defineProps, defineEmits } from 'vue'
import { useI18n } from 'vue-i18n'

const { t } = useI18n()

const props = defineProps({
  show: {
    type: Boolean,
    default: false
  }
})

const emit = defineEmits(['confirm', 'cancel'])

const selectedSeries = ref('')

const onConfirm = () => {
  if (selectedSeries.value) {
    emit('confirm', selectedSeries.value)
  }
}

const onCancel = () => {
  emit('cancel')
}
</script>

<style scoped>
/* 系列选择弹窗样式 */
.series-selector-content {
  text-align: center;
}

.series-list {
  display: flex;
  gap: 24px;
  justify-content: center;
  margin-bottom: 32px;
}

.series-item {
  background: #f8fafc;
  border: 2px solid #e2e8f0;
  border-radius: 12px;
  padding: 16px;
  cursor: pointer;
  transition: all 0.3s ease;
  width: 200px;
}

.series-item:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}

.series-item.active {
  border-color: #6B46C1;
  background: rgba(107, 70, 193, 0.05);
  box-shadow: 0 4px 16px rgba(107, 70, 193, 0.2);
}

.series-image {
  width: 100%;
  height: 120px;
  overflow: hidden;
  border-radius: 8px;
  margin-bottom: 12px;
}

.series-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.series-name {
  font-size: 16px;
  font-weight: 600;
  color: #1f2937;
}

.series-actions {
  display: flex;
  gap: 16px;
  justify-content: center;
}
</style>