优化: miniapp 设置页支持编辑 + 移除 Ideas 批量删除功能

This commit is contained in:
lxy
2026-08-08 14:19:59 +08:00
parent 92903702e2
commit 795e05f42d
4 changed files with 135 additions and 119 deletions
-5
View File
@@ -141,10 +141,5 @@ export default {
confirmStatus: 'Change idea "{title}" status from {from} to {to}?',
promoteFailed: 'Promotion failed',
evalFailed: 'Evaluation failed',
// Batch operations
batchDelete: 'Batch delete',
confirmBatchDelete: 'Delete {n} selected ideas? This cannot be undone.',
batchDeleteSuccess: 'Deleted {n} idea(s)',
selectedCount: '{n} selected',
},
}
-5
View File
@@ -141,10 +141,5 @@ export default {
confirmStatus: '将灵感「{title}」状态从 {from} 改为 {to}?',
promoteFailed: '立项失败',
evalFailed: '评估失败',
// 批量操作
batchDelete: '批量删除',
confirmBatchDelete: '确定删除选中的 {n} 个灵感?此操作不可撤销。',
batchDeleteSuccess: '已删除 {n} 个灵感',
selectedCount: '已选 {n} 项',
},
}
+1 -97
View File
@@ -45,27 +45,6 @@
<div class="ideas-layout">
<!-- 左侧灵感列表 -->
<section class="idea-list-panel">
<div class="idea-list-header">
<label class="idea-batch-check" v-if="filteredIdeas.length > 0">
<input
type="checkbox"
:checked="selectedAll"
:indeterminate="selectedAny && !selectedAll"
@change="toggleSelectAll"
/>
<span v-if="selectedAny" class="batch-selected-note">{{ $t('ideas.selectedCount', { n: selectedIds.size }) }}</span>
</label>
<div class="idea-list-actions">
<button
v-if="selectedAny"
class="btn btn-danger btn-sm"
:disabled="batchDeleting"
@click="confirmBatchDelete"
>
{{ batchDeleting ? $t('ideas.deleting') : $t('ideas.batchDelete') }}
</button>
</div>
</div>
<div class="idea-list">
<!-- 三态:加载/错误/(对齐 Tasks.vue:43-45) -->
<div v-if="store.loading" class="empty-state">{{ $t('common.loading') }}</div>
@@ -79,14 +58,6 @@
:class="{ selected: selectedId === idea.id }"
@click="selectedId = idea.id"
>
<div class="idea-card-check">
<input
type="checkbox"
:checked="selectedIds.has(idea.id)"
@click.stop
@change="toggleSelect(idea.id)"
/>
</div>
<div class="idea-card-body">
<div class="idea-card-header">
<span class="idea-title">{{ idea.title }}</span>
@@ -180,7 +151,7 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted, watch, type Ref } from 'vue'
import { ref, computed, onMounted, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { Message } from '@arco-design/web-vue'
@@ -211,45 +182,6 @@ type FilterKey = 'all' | 'hot' | 'pending' | 'promoted'
const activeFilter = usePersistedRef<FilterKey>('ideas.activeFilter', 'all')
const selectedId = ref<string | null>(null)
const searchQuery = ref('')
// 批量选择
const selectedIds: Ref<Set<string>> = ref(new Set()) as Ref<Set<string>>
const batchDeleting = ref(false)
const selectedAll = computed(
() => filteredIdeas.value.length > 0 && selectedIds.value.size === filteredIdeas.value.length,
)
const selectedAny = computed(() => selectedIds.value.size > 0)
function toggleSelect(id: string) {
const next = new Set(selectedIds.value)
if (next.has(id)) next.delete(id); else next.add(id)
selectedIds.value = next
}
function toggleSelectAll() {
if (selectedAll.value) {
selectedIds.value = new Set()
} else {
selectedIds.value = new Set(filteredIdeas.value.map(i => i.id))
}
}
async function confirmBatchDelete() {
if (selectedIds.value.size === 0) return
if (!await confirmDialog(t('ideas.confirmBatchDelete', { n: selectedIds.value.size }), t('common.delete'))) return
batchDeleting.value = true
const ids = [...selectedIds.value]
try {
for (const id of ids) {
await store.deleteIdea(id)
}
selectedIds.value = new Set()
selectedId.value = null
Message.success(t('ideas.batchDeleteSuccess', { n: ids.length }))
await store.loadIdeas(buildIdeaQuery())
} catch (e) {
Message.error(t('ideas.deleteFailed'))
console.error('[Ideas] 批量删除失败:', e)
} finally {
batchDeleting.value = false
}
}
// 列表排序:time 新在前 / score 高分在前(默认 time,按创建时间倒序)
const sortMode = usePersistedRef<'score' | 'time'>('ideas.sortMode', 'time')
@@ -575,7 +507,6 @@ watch(() => route.params.id, (id) => {
.idea-card-body {
flex: 1;
min-width: 0;
/* 批量操作重构后 desc/footer 移入 body,须纵向堆叠(原 .idea-card 直接子元素横排 bug) */
display: flex;
flex-direction: column;
}
@@ -586,12 +517,6 @@ watch(() => route.params.id, (id) => {
gap: 8px;
margin-bottom: 6px;
}
.idea-card-check {
display: flex;
align-items: flex-start;
padding-top: 2px;
}
.idea-card-check input { cursor: pointer; }
.idea-card:hover { background: var(--df-accent-bg); }
.idea-card.selected { background: var(--df-accent-soft); border: 0.5px solid var(--df-accent); }
@@ -622,27 +547,6 @@ watch(() => route.params.id, (id) => {
}
.idea-date { font-size: 11px; color: var(--df-text-dim); }
/* ===== 批量操作头 ===== */
.idea-list-header {
display: flex;
align-items: center;
gap: 8px;
padding: 0 14px 8px;
border-bottom: 0.5px solid var(--df-border);
margin-bottom: 4px;
}
.idea-batch-check {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--df-text-dim);
cursor: pointer;
}
.idea-batch-check input { cursor: pointer; }
.batch-selected-note { font-size: 11px; color: var(--df-text-dim); white-space: nowrap; }
.idea-list-actions { margin-left: auto; }
/* ===== 状态标签已提取到 styles/components.css 全局(.status-tag 系列) ===== */
/* ===== 右侧详情(详情内容由 IdeaDetail 子组件渲染,父级仅保留未选中空态壳) ===== */