202 lines
4.4 KiB
Markdown
202 lines
4.4 KiB
Markdown
# 新建项目系列选择功能实现
|
||
|
||
## 需求分析
|
||
|
||
* 当用户点击"新建项目"卡片时,需要弹出系列选择弹窗
|
||
|
||
* 系列弹窗包含两个选项: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
|
||
|
||
```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>
|
||
```
|
||
|