UI: 标签展开到下一行,全选显示数量
Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 5s
Test / build-check (push) Successful in 3s
PR Preview / test (pull_request) Successful in 4s
PR Preview / deploy-preview (pull_request) Successful in 14s
Test / e2e-test (push) Failing after 55s

- 标签点击后在下一行展开/收起
- 全选后右侧显示"共X个"
- 工具栏布局:新增 | 全选 共X个 | 标签▾ | 批量 | 导出

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-10 14:35:56 +00:00
parent 9f0c66e583
commit b6b112e9cb

View File

@@ -25,19 +25,19 @@
</template> </template>
<!-- Row 2: Add + Select + Tags + Batch + Export --> <!-- Row 2: Add + Select + Tags + Batch + Export -->
<div class="tag-filter-bar"> <div class="toolbar-row">
<button v-if="auth.canEdit" class="btn-outline btn-sm" @click="showAddOverlay = true">新增</button> <button v-if="auth.canEdit" class="btn-outline btn-sm" @click="showAddOverlay = true">新增</button>
<button <button
class="btn-sm" class="btn-sm"
:class="selectedDiaryIds.size > 0 ? 'btn-select-active' : 'btn-outline'" :class="totalSelected > 0 ? 'btn-select-active' : 'btn-outline'"
@click="toggleSelectAllDiary" @click="toggleSelectAllDiary"
>全选</button> >全选</button>
<span v-if="totalSelected > 0" class="select-count">{{ totalSelected }}</span>
<button class="tag-toggle-btn" @click="showTagFilter = !showTagFilter"> <button class="tag-toggle-btn" @click="showTagFilter = !showTagFilter">
标签 {{ showTagFilter ? '' : '' }} 标签 {{ showTagFilter ? '' : '' }}
</button> </button>
<!-- Batch (inline when selected) --> <!-- Batch -->
<template v-if="selectedIds.size > 0 || selectedDiaryIds.size > 0"> <template v-if="totalSelected > 0">
<span class="batch-count">{{ selectedIds.size + selectedDiaryIds.size }}</span>
<select v-model="batchAction" class="batch-select" @change="onBatchSelect"> <select v-model="batchAction" class="batch-select" @change="onBatchSelect">
<option value="">批量操作...</option> <option value="">批量操作...</option>
<option value="tag">打标签</option> <option value="tag">打标签</option>
@@ -47,18 +47,18 @@
<button class="btn-sm btn-outline" @click="clearSelection">取消</button> <button class="btn-sm btn-outline" @click="clearSelection">取消</button>
</template> </template>
<button v-if="auth.isAdmin" class="export-btn" @click="exportExcel" title="导出Excel">📥</button> <button v-if="auth.isAdmin" class="export-btn" @click="exportExcel" title="导出Excel">📥</button>
<div v-if="showTagFilter" class="tag-list"> </div>
<span <div v-if="showTagFilter" class="tag-list-bar">
v-for="tag in recipeStore.allTags" <span
:key="tag" v-for="tag in recipeStore.allTags"
class="tag-chip" :key="tag"
:class="{ active: selectedTags.includes(tag) }" class="tag-chip"
@click="toggleTag(tag)" :class="{ active: selectedTags.includes(tag) }"
>{{ tag }}<span v-if="auth.isAdmin" class="tag-delete" @click.stop="deleteGlobalTag(tag)">×</span></span> @click="toggleTag(tag)"
<div v-if="auth.canEdit" class="tag-add-row"> >{{ tag }}<span v-if="auth.isAdmin" class="tag-delete" @click.stop="deleteGlobalTag(tag)">×</span></span>
<input v-model="globalNewTag" class="tag-add-input" placeholder="新标签..." @keydown.enter="addGlobalTag" /> <div v-if="auth.canEdit" class="tag-add-row">
<button class="tag-add-btn" @click="addGlobalTag" :disabled="!globalNewTag.trim()">+</button> <input v-model="globalNewTag" class="tag-add-input" placeholder="新标签..." @keydown.enter="addGlobalTag" />
</div> <button class="tag-add-btn" @click="addGlobalTag" :disabled="!globalNewTag.trim()">+</button>
</div> </div>
</div> </div>
@@ -959,6 +959,7 @@ async function saveAllParsed() {
const sharedCount = ref({ adopted: 0, total: 0 }) const sharedCount = ref({ adopted: 0, total: 0 })
const previewRecipeIndex = ref(null) const previewRecipeIndex = ref(null)
const batchAction = ref('') const batchAction = ref('')
const totalSelected = computed(() => selectedIds.size + selectedDiaryIds.size)
const showMyRecipes = ref(false) const showMyRecipes = ref(false)
const showPublicRecipes = ref(false) const showPublicRecipes = ref(false)
const showReviewHistory = ref(false) const showReviewHistory = ref(false)
@@ -1588,6 +1589,13 @@ watch(() => recipeStore.recipes, () => {
.drops-sm:focus { border-color: #7ec6a4; } .drops-sm:focus { border-color: #7ec6a4; }
.select-sm { padding: 4px 6px; border: 1.5px solid #d4cfc7; border-radius: 6px; font-size: 12px; font-family: inherit; background: #fff; width: auto; } .select-sm { padding: 4px 6px; border: 1.5px solid #d4cfc7; border-radius: 6px; font-size: 12px; font-family: inherit; background: #fff; width: auto; }
.btn-select-active { background: #e8f5e9; color: #2e7d5a; border: 1.5px solid #7ec6a4; border-radius: 10px; padding: 7px 14px; font-size: 13px; cursor: pointer; font-family: inherit; font-weight: 600; } .btn-select-active { background: #e8f5e9; color: #2e7d5a; border: 1.5px solid #7ec6a4; border-radius: 10px; padding: 7px 14px; font-size: 13px; cursor: pointer; font-family: inherit; font-weight: 600; }
.toolbar-row {
display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 8px;
}
.select-count { font-size: 12px; color: #4a9d7e; font-weight: 500; white-space: nowrap; }
.tag-list-bar {
display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; padding: 8px 0;
}
.tag-delete { margin-left: 4px; cursor: pointer; font-size: 12px; color: #ccc; } .tag-delete { margin-left: 4px; cursor: pointer; font-size: 12px; color: #ccc; }
.tag-delete:hover { color: #c0392b; } .tag-delete:hover { color: #c0392b; }
.tag-add-row { display: flex; gap: 4px; align-items: center; width: 100%; margin-top: 4px; } .tag-add-row { display: flex; gap: 4px; align-items: center; width: 100%; margin-top: 4px; }