|
@@ -85,12 +85,20 @@
|
|
|
<el-row :gutter="16">
|
|
<el-row :gutter="16">
|
|
|
<el-col :span="8" v-for="tpl in recommendTemplates" :key="tpl.id">
|
|
<el-col :span="8" v-for="tpl in recommendTemplates" :key="tpl.id">
|
|
|
<div class="tpl-card card" @click="useTemplate(tpl)">
|
|
<div class="tpl-card card" @click="useTemplate(tpl)">
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ class="tpl-delete-btn"
|
|
|
|
|
+ type="danger"
|
|
|
|
|
+ :icon="Delete"
|
|
|
|
|
+ circle
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ @click.stop="handleDeleteTemplate(tpl)"
|
|
|
|
|
+ />
|
|
|
<div class="tpl-preview">{{ tpl.icon }}</div>
|
|
<div class="tpl-preview">{{ tpl.icon }}</div>
|
|
|
<div class="tpl-info">
|
|
<div class="tpl-info">
|
|
|
<div class="tpl-name">{{ tpl.name }}</div>
|
|
<div class="tpl-name">{{ tpl.name }}</div>
|
|
|
<div class="tpl-meta">
|
|
<div class="tpl-meta">
|
|
|
<span>📊 {{ tpl.useCount }}次</span>
|
|
<span>📊 {{ tpl.useCount }}次</span>
|
|
|
- <span>⭐ {{ tpl.rating }}</span>
|
|
|
|
|
|
|
+ <span>⭐ {{ tpl.rating.toFixed(1) }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="tpl-tags">
|
|
<div class="tpl-tags">
|
|
|
<span class="tpl-tag" v-if="tpl.isOfficial">官方</span>
|
|
<span class="tpl-tag" v-if="tpl.isOfficial">官方</span>
|
|
@@ -206,8 +214,8 @@
|
|
|
<script setup>
|
|
<script setup>
|
|
|
import { ref, reactive, computed, onMounted } from 'vue'
|
|
import { ref, reactive, computed, onMounted } from 'vue'
|
|
|
import { useRouter } from 'vue-router'
|
|
import { useRouter } from 'vue-router'
|
|
|
-import { Promotion, UploadFilled, CircleCheckFilled } from '@element-plus/icons-vue'
|
|
|
|
|
-import { ElMessage } from 'element-plus'
|
|
|
|
|
|
|
+import { Promotion, UploadFilled, CircleCheckFilled, Delete } from '@element-plus/icons-vue'
|
|
|
|
|
+import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
import { useTemplateStore } from '@/stores/template'
|
|
import { useTemplateStore } from '@/stores/template'
|
|
|
import { useTaskCenterStore } from '@/stores/taskCenter'
|
|
import { useTaskCenterStore } from '@/stores/taskCenter'
|
|
|
import { templateApi, parseApi } from '@/api'
|
|
import { templateApi, parseApi } from '@/api'
|
|
@@ -303,6 +311,33 @@ function useTemplate(tpl) {
|
|
|
router.push(`/editor/${tpl.id}`)
|
|
router.push(`/editor/${tpl.id}`)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+async function handleDeleteTemplate(tpl) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ await ElMessageBox.confirm(
|
|
|
|
|
+ `确定要删除模板「${tpl.name}」吗?此操作不可恢复。`,
|
|
|
|
|
+ '删除确认',
|
|
|
|
|
+ {
|
|
|
|
|
+ type: 'warning',
|
|
|
|
|
+ confirmButtonText: '删除',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ confirmButtonClass: 'el-button--danger'
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ await templateStore.deleteTemplate(tpl.id)
|
|
|
|
|
+ // 从推荐列表中移除
|
|
|
|
|
+ recommendTemplates.value = recommendTemplates.value.filter(t => t.id !== tpl.id)
|
|
|
|
|
+ // 更新统计
|
|
|
|
|
+ stats.templateCount = Math.max(0, stats.templateCount - 1)
|
|
|
|
|
+ ElMessage.success('删除成功')
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ if (error !== 'cancel') {
|
|
|
|
|
+ console.error('删除模板失败:', error)
|
|
|
|
|
+ ElMessage.error('删除失败')
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
async function handleCreateTemplate() {
|
|
async function handleCreateTemplate() {
|
|
|
if (!newTemplate.name) {
|
|
if (!newTemplate.name) {
|
|
|
ElMessage.warning('请输入模板名称')
|
|
ElMessage.warning('请输入模板名称')
|
|
@@ -526,6 +561,23 @@ async function handleUploadTemplate() {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+.tpl-card {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+
|
|
|
|
|
+ .tpl-delete-btn {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 8px;
|
|
|
|
|
+ right: 8px;
|
|
|
|
|
+ opacity: 0;
|
|
|
|
|
+ transition: opacity 0.2s;
|
|
|
|
|
+ z-index: 10;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &:hover .tpl-delete-btn {
|
|
|
|
|
+ opacity: 1;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
.quick-actions {
|
|
.quick-actions {
|
|
|
.quick-action {
|
|
.quick-action {
|
|
|
display: flex;
|
|
display: flex;
|