Files
voidraft/frontend/src/stores/documentStore.ts
2025-09-24 21:44:42 +08:00

253 lines
7.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {defineStore} from 'pinia';
import {computed, ref} from 'vue';
import {DocumentService} from '@/../bindings/voidraft/internal/services';
import {OpenDocumentWindow} from '@/../bindings/voidraft/internal/services/windowservice';
import {Document} from '@/../bindings/voidraft/internal/models/models';
export const useDocumentStore = defineStore('document', () => {
const DEFAULT_DOCUMENT_ID = ref<number>(1); // 默认草稿文档ID
// === 核心状态 ===
const documents = ref<Record<number, Document>>({});
const recentDocumentIds = ref<number[]>([DEFAULT_DOCUMENT_ID.value]);
const currentDocumentId = ref<number | null>(null);
const currentDocument = ref<Document | null>(null);
// === UI状态 ===
const showDocumentSelector = ref(false);
const isLoading = ref(false);
// === 计算属性 ===
const documentList = computed(() =>
Object.values(documents.value).sort((a, b) => {
const aIndex = recentDocumentIds.value.indexOf(a.id);
const bIndex = recentDocumentIds.value.indexOf(b.id);
// 按最近使用排序
if (aIndex !== -1 && bIndex !== -1) {
return aIndex - bIndex;
}
if (aIndex !== -1) return -1;
if (bIndex !== -1) return 1;
// 然后按更新时间排序
return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();
})
);
// === 私有方法 ===
const addRecentDocument = (docId: number) => {
const recent = recentDocumentIds.value.filter(id => id !== docId);
recent.unshift(docId);
recentDocumentIds.value = recent.slice(0, 100); // 保留最近100个
};
const setDocuments = (docs: Document[]) => {
documents.value = {};
docs.forEach(doc => {
documents.value[doc.id] = doc;
});
};
// === 公共API ===
// 在新窗口中打开文档
const openDocumentInNewWindow = async (docId: number): Promise<boolean> => {
try {
await OpenDocumentWindow(docId);
return true;
} catch (error) {
console.error('Failed to open document in new window:', error);
return false;
}
};
// 更新文档列表
const updateDocuments = async () => {
try {
const docs = await DocumentService.ListAllDocumentsMeta();
if (docs) {
setDocuments(docs.filter((doc): doc is Document => doc !== null));
}
} catch (error) {
console.error('Failed to update documents:', error);
}
};
// 打开文档
const openDocument = async (docId: number): Promise<boolean> => {
try {
closeDialog();
// 获取完整文档数据
const doc = await DocumentService.GetDocumentByID(docId);
if (!doc) {
throw new Error(`Document ${docId} not found`);
}
currentDocumentId.value = docId;
currentDocument.value = doc;
addRecentDocument(docId);
return true;
} catch (error) {
console.error('Failed to open document:', error);
return false;
}
};
// 创建新文档
const createNewDocument = async (title: string): Promise<Document | null> => {
try {
const newDoc = await DocumentService.CreateDocument(title);
if (!newDoc) {
throw new Error('Failed to create document');
}
// 更新文档列表
documents.value[newDoc.id] = newDoc;
return newDoc;
} catch (error) {
console.error('Failed to create document:', error);
return null;
}
};
// 保存新文档
const saveNewDocument = async (title: string, content: string): Promise<boolean> => {
try {
const newDoc = await createNewDocument(title);
if (!newDoc) return false;
// 更新内容
await DocumentService.UpdateDocumentContent(newDoc.id, content);
newDoc.content = content;
return true;
} catch (error) {
console.error('Failed to save new document:', error);
return false;
}
};
// 更新文档元数据
const updateDocumentMetadata = async (docId: number, title: string): Promise<boolean> => {
try {
await DocumentService.UpdateDocumentTitle(docId, title);
// 更新本地状态
const doc = documents.value[docId];
if (doc) {
doc.title = title;
doc.updatedAt = new Date();
}
if (currentDocument.value?.id === docId) {
currentDocument.value.title = title;
currentDocument.value.updatedAt = new Date();
}
return true;
} catch (error) {
console.error('Failed to update document metadata:', error);
return false;
}
};
// 删除文档
const deleteDocument = async (docId: number): Promise<boolean> => {
try {
// 检查是否是默认文档使用ID判断
if (docId === DEFAULT_DOCUMENT_ID.value) {
return false;
}
await DocumentService.DeleteDocument(docId);
// 更新本地状态
delete documents.value[docId];
recentDocumentIds.value = recentDocumentIds.value.filter(id => id !== docId);
// 如果删除的是当前文档,切换到第一个可用文档
if (currentDocumentId.value === docId) {
const availableDocs = Object.values(documents.value);
if (availableDocs.length > 0) {
await openDocument(availableDocs[0].id);
} else {
currentDocumentId.value = null;
currentDocument.value = null;
}
}
return true;
} catch (error) {
console.error('Failed to delete document:', error);
return false;
}
};
// === UI控制 ===
const openDocumentSelector = () => {
closeDialog();
showDocumentSelector.value = true;
};
const closeDialog = () => {
showDocumentSelector.value = false;
};
// === 初始化 ===
const initialize = async (urlDocumentId?: number): Promise<void> => {
try {
await updateDocuments();
// 优先使用URL参数中的文档ID
if (urlDocumentId && documents.value[urlDocumentId]) {
await openDocument(urlDocumentId);
} else if (currentDocumentId.value && documents.value[currentDocumentId.value]) {
// 如果URL中没有指定文档ID则使用持久化的文档ID
await openDocument(currentDocumentId.value);
} else {
// 否则获取第一个文档ID并打开
const firstDocId = await DocumentService.GetFirstDocumentID();
if (firstDocId && documents.value[firstDocId]) {
await openDocument(firstDocId);
}
}
} catch (error) {
console.error('Failed to initialize document store:', error);
}
};
return {
DEFAULT_DOCUMENT_ID,
// 状态
documents,
documentList,
recentDocumentIds,
currentDocumentId,
currentDocument,
showDocumentSelector,
isLoading,
// 方法
updateDocuments,
openDocument,
openDocumentInNewWindow,
createNewDocument,
saveNewDocument,
updateDocumentMetadata,
deleteDocument,
openDocumentSelector,
closeDialog,
initialize,
};
}, {
persist: {
key: 'voidraft-document',
storage: localStorage,
pick: ['currentDocumentId']
}
});