优化: 知识检索同项目加权与拒绝池

This commit is contained in:
lxy
2026-10-05 23:41:27 +08:00
parent 0f3c3ce1aa
commit 9e81182b4f
9 changed files with 387 additions and 22 deletions
+65 -6
View File
@@ -28,6 +28,16 @@
{{ $t('knowledge.tab.inbox') }}
<span v-if="store.candidates.length" class="inbox-badge">{{ store.candidates.length }}</span>
</button>
<!-- 归档箱(2026-10-05 归档功能尾巴):低频可见可恢复,与回收站/正式库分池 -->
<button class="top-tab" :class="{ active: topTab === 'archived' }" @click="switchTopTab('archived')">
🗄️ {{ $t('knowledge.tab.archived') }}
<span v-if="store.archived.length" class="inbox-badge">{{ store.archived.length }}</span>
</button>
<!-- 拒绝池(2026-10-05 分池):审核否决独立可见,与归档分池 -->
<button class="top-tab" :class="{ active: topTab === 'rejected' }" @click="switchTopTab('rejected')">
🚫 {{ $t('knowledge.tab.rejected') }}
<span v-if="store.rejected.length" class="inbox-badge">{{ store.rejected.length }}</span>
</button>
</div>
<!-- 左右分栏: 列表 + 详情 -->
@@ -83,7 +93,7 @@
</div>
<div v-if="listItems.length === 0" class="list-empty">
<div>{{ topTab === 'inbox' ? $t('knowledge.emptyInbox') : $t('knowledge.emptyLibrary') }}</div>
<div>{{ topTab === 'inbox' ? $t('knowledge.emptyInbox') : topTab === 'rejected' ? $t('knowledge.emptyRejected') : topTab === 'archived' ? $t('knowledge.emptyArchived') : $t('knowledge.emptyLibrary') }}</div>
</div>
</div>
</div>
@@ -99,6 +109,8 @@
@publish="publishCurrent"
@reject="rejectCurrent"
@archive="archiveCurrent"
@restore="restoreCurrent"
@resubmit="resubmitCurrent"
/>
<div v-else class="detail-empty">
@@ -174,7 +186,7 @@ const { toast, showToast } = useToast()
// topTab/activeKind/searchQuery 持久化 localStorage(跨刷新保留用户视图态)
// 仅持久化视图态:不持久化详情选中(id 跨刷新可能已失效)。usePersistedRef 无类型校验,
// 解析失败/无效值回退 default,与 Tasks/Ideas 一致。
const topTab = usePersistedRef<'library' | 'inbox'>('knowledge.topTab', 'library')
const topTab = usePersistedRef<'library' | 'inbox' | 'rejected' | 'archived'>('knowledge.topTab', 'library')
const categories = [
{ key: 'all', icon: '📦' },
@@ -208,12 +220,16 @@ onUnmounted(() => {
}
})
function switchTopTab(tab: 'library' | 'inbox') {
function switchTopTab(tab: 'library' | 'inbox' | 'rejected' | 'archived') {
topTab.value = tab
selectedId.value = null
detail.value = null
if (tab === 'inbox') {
store.loadCandidates()
} else if (tab === 'rejected') {
store.loadRejected()
} else if (tab === 'archived') {
store.loadArchived()
} else {
store.loadList()
}
@@ -226,7 +242,10 @@ function clearError() {
// 左侧列表(随 Tab 切换数据源 + 知识库的分类过滤)
const listItems = computed(() => {
const src = topTab.value === 'inbox' ? store.candidates : store.items
const src = topTab.value === 'inbox' ? store.candidates
: topTab.value === 'rejected' ? store.rejected
: topTab.value === 'archived' ? store.archived
: store.items
if (topTab.value === 'library' && activeKind.value !== 'all') {
return src.filter(i => i.kind === activeKind.value)
}
@@ -312,9 +331,10 @@ async function rejectCurrent() {
const idx = store.candidates.findIndex(c => c.id === currentId)
submitting.value = true
try {
const ok = await store.archive(currentId)
// 分池(2026-10-05):审核否决走 rejected 独立池,与 archived 分开
const ok = await store.reject(currentId)
if (!ok) {
showToast(t('knowledge.err.archiveFailed'), 'error')
showToast(t('knowledge.err.rejectFailed'), 'error')
return
}
await selectNextCandidate(idx)
@@ -348,6 +368,44 @@ async function archiveCurrent() {
}
}
// ===== 归档箱恢复(2026-10-05 归档功能尾巴) =====
async function restoreCurrent() {
if (!detail.value) return
const currentId = detail.value.knowledge.id
submitting.value = true
try {
const ok = await store.restore(currentId)
if (!ok) {
showToast(t('knowledge.err.restoreFailed'), 'error')
return
}
selectedId.value = null
detail.value = null
showToast(t('knowledge.restoredToast'), 'success')
} finally {
submitting.value = false
}
}
// ===== 拒绝池恢复(2026-10-05 分池):rejected → candidate 重新送审 =====
async function resubmitCurrent() {
if (!detail.value) return
const currentId = detail.value.knowledge.id
submitting.value = true
try {
const ok = await store.resubmit(currentId)
if (!ok) {
showToast(t('knowledge.err.resubmitFailed'), 'error')
return
}
selectedId.value = null
detail.value = null
showToast(t('knowledge.resubmittedToast'), 'success')
} finally {
submitting.value = false
}
}
// 当前条目从 candidates 移除后,选中同位置后续条目;末尾则清空详情
// 实现策略:操作前记下 currentId 在原列表中的 index,移除后从剩余列表的同
// index 取(若无则取前一条),保证「下一条」语义而非跳回开头
@@ -510,6 +568,7 @@ onMounted(() => {
.st-pending_review { background: rgba(108,159,255,0.15); color: var(--df-info); }
.st-published { background: rgba(100,255,218,0.15); color: var(--df-success); }
.st-archived { background: rgba(90,99,128,0.2); color: var(--df-text-dim); }
.st-rejected { background: rgba(240,84,110,0.15); color: var(--df-danger); }
.conf-high { background: rgba(100,255,218,0.15); color: var(--df-success); padding: 1px 6px; border-radius: var(--df-radius-xs); }
.conf-medium { background: rgba(255,217,61,0.15); color: var(--df-warning); padding: 1px 6px; border-radius: var(--df-radius-xs); }
.conf-low { background: rgba(255,107,107,0.15); color: var(--df-danger); padding: 1px 6px; border-radius: var(--df-radius-xs); }