import { ItemView, WorkspaceLeaf } from "obsidian"; import { fetchMemories, fetchDistillStatus, fetchDistillQuota, type MemoryRecord } from "./api"; export const MEMORY_VIEW_TYPE = "zhiyi-memory-view"; export class MemoryView extends ItemView { private container: HTMLElement; private memories: MemoryRecord[] = []; private currentPage = 0; private pageSize = 20; private totalMemories = 0; private status_interval: number | null = null; constructor(leaf: WorkspaceLeaf) { super(leaf); this.container = this.contentEl; } getViewType() { return MEMORY_VIEW_TYPE; } getDisplayText() { return "织忆记忆"; } async onOpen() { this.render(); this.startStatusPoll(); } async onClose() { if (this.status_interval !== null) { (window as unknown as { clearInterval: (n: number) => void }).clearInterval(this.status_interval); } } private startStatusPoll() { // 轮询蒸馏状态(每 30 秒) const id = (window as unknown as { setInterval: (fn: () => void, ms: number) => number }).setInterval( () => this.renderDistillBanner(), 30000 ); this.status_interval = id; } private async renderDistillBanner() { const banner = this.container.querySelector(".zhiyi-distill-banner") as HTMLElement; if (!banner) return; try { const [status, quota] = await Promise.all([fetchDistillStatus(), fetchDistillQuota()]); if (status.queue_len > 0) { banner.innerHTML = `⚠️ 蒸馏队列: ${status.queue_len} 条`; banner.style.display = "block"; } else { banner.style.display = "none"; } } catch (_) { // ignore } } async render() { this.container.empty(); this.container.createEl("style", { text: ` .zhiyi-memory-view { height: 100%; display: flex; flex-direction: column; font-size: 13px; } .zhiyi-header { padding: 10px 12px 6px; border-bottom: 1px solid var(--background-modifier-border); } .zhiyi-header h1 { font-size: 14px; font-weight: 600; margin: 0 0 4px; } .zhiyi-stats { color: var(--text-muted); font-size: 11px; margin: 0; } .zhiyi-distill-banner { display: none; background: #c44; color: white; padding: 4px 12px; font-size: 12px; font-weight: 600; cursor: pointer; } .zhiyi-body { flex: 1; overflow-y: auto; } .zhiyi-item { padding: 8px 12px; border-bottom: 1px solid var(--background-modifier-border); cursor: pointer; } .zhiyi-item:hover { background: var(--background-modifier-hover); } .zhiyi-item-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 2px; } .zhiyi-item-cat { font-size: 10px; color: var(--text-muted); background: var(--background-secondary); padding: 1px 4px; border-radius: 2px; } .zhiyi-item-score { font-size: 10px; color: var(--text-muted); } .zhiyi-item-content { font-size: 12px; color: var(--text-normal); line-height: 1.4; } .zhiyi-item-time { font-size: 10px; color: var(--text-muted); margin-top: 2px; } .zhiyi-item-id { font-size: 10px; color: var(--text-faint); font-family: monospace; margin-top: 2px; overflow: hidden; text-overflow: ellipsis; } .zhiyi-pagination { display: flex; gap: 6px; padding: 8px 12px; border-top: 1px solid var(--background-modifier-border); } .zhiyi-pagination button { flex: 1; padding: 4px; background: var(--background-secondary); border: 1px solid var(--background-modifier-border); border-radius: 4px; cursor: pointer; font-size: 11px; } .zhiyi-pagination button:disabled { opacity: 0.4; cursor: not-allowed; } .zhiyi-loading { padding: 20px; text-align: center; color: var(--text-muted); } .zhiyi-empty { padding: 20px; text-align: center; color: var(--text-muted); } ` }); this.container.createEl("div", { cls: "zhiyi-memory-view" }).append( this.container.createEl("div", { cls: "zhiyi-distill-banner" }), this.container.createEl("div", { cls: "zhiyi-header" }).append( this.container.createEl("h1", { text: "🧠 织忆记忆" }), this.container.createEl("p", { cls: "zhiyi-stats", text: "加载中..." }) ), this.container.createEl("div", { cls: "zhiyi-body" }), this.container.createEl("div", { cls: "zhiyi-pagination" }) ); await this.loadMemories(); await this.renderDistillBanner(); } async loadMemories() { const body = this.container.querySelector(".zhiyi-body") as HTMLElement; const stats = this.container.querySelector(".zhiyi-stats") as HTMLElement; body.innerHTML = '