c007a897cf
* feat: support multi-tag for document knowledge - Add knowledge_tag_relations join table for many-to-many tag-knowledge mapping - Migrate existing single tag_id data to the new table - Update Knowledge struct, filter, payload types (TagID -> Tags/TagIDs) - Rewrite repository layer: SetKnowledgeTags, GetKnowledgeTags, ListIDsByTagIDs - Update tag count references to query knowledge_tag_relations - Update service/handler layers for multi-tag create/list/batch-update - Frontend: multi-select tag sidebar, multi-tag chip display, tag toggle in popup - FAQ tags remain single-tag model (unchanged) * feat(knowledge): tag edit dialog with dynamic overflow and inline creation - Add TagEditDialog component with search, multi-select, and confirm - Replace inline t-popup tag selector with dialog-based editing - Tags overflow with +N badge, visible count adapts to container width via ResizeObserver - Date/card layout: fixed date width, tags flex to fill remaining space - Add persistent new-tag input bar in dialog (Enter to create, auto-select) - Tag creation emits callback to refresh parent tag list immediately - Apply same overflow + dialog trigger to both card view and list view - Add i18n keys: tagEditDialogTitle, tagEditSearch, tagSelectedCount, tagOverflowTip, tagNewPlaceholder * fix: exclude soft-deleted knowledge from tag reference counts CountReferences, BatchCountReferences, and DeleteUnusedTags now JOIN with knowledges table to filter out soft-deleted records when counting knowledge_tag_relations. Previously they queried knowledge_tag_relations directly without the deleted_at check, causing stale tag counts after knowledge deletion. * fix: refresh tag counts after async knowledge deletion completes Add a second delayed tag list refresh (2.5s) after tag deletion to capture updated reference counts for remaining tags. The original immediate refresh handles removing the deleted tag from the list, while this delayed refresh ensures other tags' counts are correct after the async deletion finishes. --------- Co-authored-by: lyingbug <xiayula2014@gmail.com>
140 lines
4.5 KiB
TypeScript
140 lines
4.5 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
|
|
export const useUIStore = defineStore('ui', {
|
|
state: () => ({
|
|
showSettingsModal: false,
|
|
showKBEditorModal: false,
|
|
kbEditorMode: 'create' as 'create' | 'edit',
|
|
currentKBId: null as string | null,
|
|
kbEditorType: 'document' as 'document' | 'faq',
|
|
// 当前选中的分类ID,用于文件上传时传递
|
|
selectedTagIds: [] as string[],
|
|
kbEditorInitialSection: null as string | null,
|
|
settingsInitialSection: null as string | null,
|
|
settingsInitialSubSection: null as string | null,
|
|
manualEditorVisible: false,
|
|
manualEditorMode: 'create' as 'create' | 'edit',
|
|
manualEditorKBId: null as string | null,
|
|
manualEditorKnowledgeId: null as string | null,
|
|
manualEditorInitialTitle: '',
|
|
manualEditorInitialContent: '',
|
|
manualEditorInitialStatus: 'draft' as 'draft' | 'publish',
|
|
manualEditorOnSuccess: null as null | ((payload: { kbId: string; knowledgeId: string; status: 'draft' | 'publish' }) => void),
|
|
sidebarCollapsed: localStorage.getItem('sidebar_collapsed') === 'true'
|
|
}),
|
|
|
|
actions: {
|
|
openSettings(section?: string, subSection?: string) {
|
|
this.settingsInitialSection = section || null
|
|
this.settingsInitialSubSection = subSection || null
|
|
this.showSettingsModal = true
|
|
},
|
|
|
|
closeSettings() {
|
|
this.showSettingsModal = false
|
|
this.settingsInitialSection = null
|
|
this.settingsInitialSubSection = null
|
|
},
|
|
|
|
toggleSettings() {
|
|
this.showSettingsModal = !this.showSettingsModal
|
|
},
|
|
|
|
openKBSettings(kbId: string, initialSection?: string) {
|
|
this.currentKBId = kbId
|
|
this.kbEditorMode = 'edit'
|
|
this.kbEditorType = 'document'
|
|
this.kbEditorInitialSection = initialSection || null
|
|
this.showKBEditorModal = true
|
|
},
|
|
|
|
openEditKB(kbId: string, initialSection?: string) {
|
|
this.openKBSettings(kbId, initialSection)
|
|
},
|
|
|
|
openCreateKB(type: 'document' | 'faq' = 'document', initialSection?: string) {
|
|
this.currentKBId = null
|
|
this.kbEditorMode = 'create'
|
|
this.kbEditorType = type
|
|
this.kbEditorInitialSection = initialSection || null
|
|
this.showKBEditorModal = true
|
|
},
|
|
|
|
closeKBEditor() {
|
|
this.showKBEditorModal = false
|
|
this.currentKBId = null
|
|
this.kbEditorInitialSection = null
|
|
this.kbEditorType = 'document'
|
|
},
|
|
|
|
openManualEditor(options: {
|
|
mode?: 'create' | 'edit'
|
|
kbId?: string | null
|
|
knowledgeId?: string | null
|
|
title?: string
|
|
content?: string
|
|
status?: 'draft' | 'publish'
|
|
onSuccess?: (payload: { kbId: string; knowledgeId: string; status: 'draft' | 'publish' }) => void
|
|
} = {}) {
|
|
this.manualEditorMode = options.mode || 'create'
|
|
this.manualEditorKBId = options.kbId ?? null
|
|
this.manualEditorKnowledgeId = options.knowledgeId ?? null
|
|
this.manualEditorInitialTitle = options.title || ''
|
|
this.manualEditorInitialContent = options.content || ''
|
|
this.manualEditorInitialStatus = options.status || 'draft'
|
|
this.manualEditorOnSuccess = options.onSuccess || null
|
|
this.manualEditorVisible = true
|
|
},
|
|
|
|
closeManualEditor() {
|
|
this.manualEditorVisible = false
|
|
this.manualEditorKnowledgeId = null
|
|
this.manualEditorInitialContent = ''
|
|
this.manualEditorInitialTitle = ''
|
|
this.manualEditorInitialStatus = 'draft'
|
|
this.manualEditorOnSuccess = null
|
|
},
|
|
|
|
notifyManualEditorSuccess(payload: { kbId: string; knowledgeId: string; status: 'draft' | 'publish' }) {
|
|
if (typeof this.manualEditorOnSuccess === 'function') {
|
|
try {
|
|
this.manualEditorOnSuccess(payload)
|
|
} catch (err) {
|
|
console.error('Manual editor success callback error:', err)
|
|
}
|
|
}
|
|
this.manualEditorOnSuccess = null
|
|
},
|
|
|
|
// 设置当前选中的分类ID
|
|
toggleSelectedTagId(tagId: string) {
|
|
const idx = this.selectedTagIds.indexOf(tagId)
|
|
if (idx >= 0) {
|
|
this.selectedTagIds.splice(idx, 1)
|
|
} else {
|
|
this.selectedTagIds.push(tagId)
|
|
}
|
|
},
|
|
|
|
clearSelectedTagIds() {
|
|
this.selectedTagIds = []
|
|
},
|
|
|
|
toggleSidebar() {
|
|
this.sidebarCollapsed = !this.sidebarCollapsed
|
|
localStorage.setItem('sidebar_collapsed', String(this.sidebarCollapsed))
|
|
},
|
|
|
|
collapseSidebar() {
|
|
this.sidebarCollapsed = true
|
|
localStorage.setItem('sidebar_collapsed', 'true')
|
|
},
|
|
|
|
expandSidebar() {
|
|
this.sidebarCollapsed = false
|
|
localStorage.setItem('sidebar_collapsed', 'false')
|
|
}
|
|
}
|
|
})
|
|
|