- 新增范式选择模态框 (ParadigmSelectorModal) - 新增差异标注面板 (DiffAnnotationPanel) - 新增精确差异处理工具 (preciseDiff.js) - 更新各面板组件支持范式润色功能 - 更新范式配置文件 (paradigms.js) - 更新依赖配置 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
595 lines
21 KiB
Vue
595 lines
21 KiB
Vue
<template>
|
||
<aside class="w-[400px] flex flex-col border-r border-slate-700 bg-slate-800 shrink-0 h-screen">
|
||
<!-- 头部 -->
|
||
<header class="p-4 border-b border-slate-700 flex items-center justify-between shrink-0">
|
||
<h1 class="font-bold text-lg text-white flex items-center gap-2">
|
||
<span class="text-2xl">🎯</span> 写作范式分析
|
||
</h1>
|
||
<span class="text-xs px-2 py-1 rounded bg-blue-900 text-blue-300 border border-blue-700">Pro版</span>
|
||
</header>
|
||
|
||
<!-- 内容区 - 添加 min-h-0 确保滚动正常 -->
|
||
<div class="flex-1 overflow-y-auto p-4 space-y-6 min-h-0">
|
||
<!-- 写作范式库 -->
|
||
<section>
|
||
<div class="flex items-center justify-between mb-4">
|
||
<h3 class="text-sm font-medium text-slate-400">📚 写作范式库</h3>
|
||
<button
|
||
@click="openAddModal"
|
||
class="text-xs px-2 py-1 bg-green-600 text-white rounded hover:bg-green-500 transition flex items-center gap-1"
|
||
>
|
||
<span>+</span> 新增范式
|
||
</button>
|
||
</div>
|
||
|
||
<div class="space-y-3">
|
||
<div
|
||
v-for="paradigm in paradigms"
|
||
:key="paradigm.id"
|
||
@click="selectParadigm(paradigm)"
|
||
:class="['bg-slate-700/50 rounded-lg p-4 border transition cursor-pointer',
|
||
selectedParadigm?.id === paradigm.id
|
||
? 'border-blue-500 bg-blue-900/20'
|
||
: 'border-slate-600 hover:border-blue-500']"
|
||
>
|
||
<div class="flex justify-between items-start mb-2">
|
||
<h4 class="font-medium text-white flex items-center gap-2">
|
||
{{ paradigm.icon }} {{ paradigm.name }}
|
||
<span v-if="paradigm.isNew" class="text-[10px] px-1.5 py-0.5 rounded bg-orange-500 text-white font-bold animate-pulse">
|
||
NEW
|
||
</span>
|
||
<span v-if="paradigm.isCustom" class="text-[10px] px-1.5 py-0.5 rounded bg-purple-500 text-white font-bold">
|
||
自定义
|
||
</span>
|
||
</h4>
|
||
<div class="flex items-center gap-1">
|
||
<button
|
||
@click.stop="openEditModal(paradigm)"
|
||
class="text-xs px-2 py-1 bg-slate-600 text-white rounded hover:bg-slate-500 transition"
|
||
title="编辑范式"
|
||
>
|
||
✏️
|
||
</button>
|
||
<button
|
||
v-if="paradigm.isCustom"
|
||
@click.stop="deleteParadigm(paradigm)"
|
||
class="text-xs px-2 py-1 bg-red-600 text-white rounded hover:bg-red-500 transition"
|
||
title="删除范式"
|
||
>
|
||
🗑️
|
||
</button>
|
||
<button
|
||
v-if="selectedParadigm?.id === paradigm.id"
|
||
@click.stop="applyParadigm(paradigm)"
|
||
class="text-xs px-2 py-1 bg-blue-600 text-white rounded hover:bg-blue-500 transition"
|
||
>
|
||
应用到写作
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<p class="text-xs text-slate-400 mb-2">{{ paradigm.description }}</p>
|
||
<div class="flex flex-wrap gap-1">
|
||
<span
|
||
v-for="tag in paradigm.tags"
|
||
:key="tag"
|
||
:class="['text-xs px-2 py-1 rounded', paradigm.tagClass]"
|
||
>
|
||
{{ tag }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 范式分析工具 -->
|
||
<section>
|
||
<h3 class="text-sm font-medium text-slate-400 mb-4">🔍 范式分析工具</h3>
|
||
<textarea
|
||
v-model="analysisText"
|
||
class="w-full h-32 bg-slate-900 border border-slate-700 rounded-lg p-3 text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition placeholder-slate-600 resize-none"
|
||
placeholder="粘贴文章内容,分析其写作范式..."
|
||
></textarea>
|
||
<div class="mt-2 flex gap-2">
|
||
<button
|
||
@click="analyzeArticle"
|
||
:disabled="isAnalyzing || !analysisText"
|
||
class="flex-1 bg-blue-600 hover:bg-blue-500 text-white py-2 rounded-lg text-sm font-medium transition disabled:opacity-50 disabled:cursor-not-allowed"
|
||
>
|
||
{{ isAnalyzing ? '正在分析...' : '分析文章范式' }}
|
||
</button>
|
||
<button
|
||
@click="clearAnalysis"
|
||
class="px-4 py-2 bg-slate-700 hover:bg-slate-600 text-white rounded-lg text-sm font-medium transition"
|
||
>
|
||
清空
|
||
</button>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 分析历史 -->
|
||
<section v-if="analysisHistory.length > 0">
|
||
<h3 class="text-sm font-medium text-slate-400 mb-4">📝 分析历史</h3>
|
||
<div class="space-y-2">
|
||
<div
|
||
v-for="(item, index) in analysisHistory"
|
||
:key="index"
|
||
@click="loadHistoryItem(item)"
|
||
class="bg-slate-700/30 rounded p-3 cursor-pointer hover:bg-slate-700/50 transition text-xs"
|
||
>
|
||
<div class="flex justify-between items-center">
|
||
<span class="text-slate-300">{{ item.paradigm }}</span>
|
||
<span class="text-slate-500">{{ formatDate(item.timestamp) }}</span>
|
||
</div>
|
||
<p class="text-slate-500 mt-1 truncate">{{ item.preview }}</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
|
||
<!-- 编辑/新增范式弹窗 -->
|
||
<div
|
||
v-if="showEditModal"
|
||
class="fixed inset-0 bg-black/60 flex items-center justify-center z-50"
|
||
@click.self="closeEditModal"
|
||
>
|
||
<div class="bg-slate-800 rounded-lg w-[500px] max-h-[80vh] overflow-y-auto border border-slate-600 shadow-xl">
|
||
<div class="p-4 border-b border-slate-700 flex items-center justify-between">
|
||
<h3 class="font-medium text-white">{{ isAddMode ? '新增写作范式' : '编辑写作范式' }}</h3>
|
||
<button @click="closeEditModal" class="text-slate-400 hover:text-white transition">✕</button>
|
||
</div>
|
||
|
||
<div class="p-4 space-y-4">
|
||
<!-- 图标选择 -->
|
||
<div>
|
||
<label class="block text-sm text-slate-400 mb-2">图标</label>
|
||
<div class="flex gap-2 flex-wrap">
|
||
<button
|
||
v-for="icon in iconOptions"
|
||
:key="icon"
|
||
@click="editForm.icon = icon"
|
||
:class="['w-10 h-10 rounded-lg text-xl flex items-center justify-center transition',
|
||
editForm.icon === icon ? 'bg-blue-600' : 'bg-slate-700 hover:bg-slate-600']"
|
||
>
|
||
{{ icon }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 名称 -->
|
||
<div>
|
||
<label class="block text-sm text-slate-400 mb-2">范式名称</label>
|
||
<input
|
||
v-model="editForm.name"
|
||
class="w-full bg-slate-900 border border-slate-700 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition"
|
||
placeholder="如:技术博客范式"
|
||
/>
|
||
</div>
|
||
|
||
<!-- 描述 -->
|
||
<div>
|
||
<label class="block text-sm text-slate-400 mb-2">描述</label>
|
||
<textarea
|
||
v-model="editForm.description"
|
||
rows="2"
|
||
class="w-full bg-slate-900 border border-slate-700 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition resize-none"
|
||
placeholder="简要描述此范式的适用场景"
|
||
></textarea>
|
||
</div>
|
||
|
||
<!-- 标签 -->
|
||
<div>
|
||
<label class="block text-sm text-slate-400 mb-2">标签(逗号分隔)</label>
|
||
<input
|
||
v-model="editForm.tagsInput"
|
||
class="w-full bg-slate-900 border border-slate-700 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition"
|
||
placeholder="如:问题引入,解决方案,代码示例"
|
||
/>
|
||
<div class="flex flex-wrap gap-1 mt-2" v-if="editForm.tagsInput">
|
||
<span
|
||
v-for="tag in editForm.tagsInput.split(',').map(t => t.trim()).filter(t => t)"
|
||
:key="tag"
|
||
:class="['text-xs px-2 py-1 rounded', editForm.tagClass]"
|
||
>
|
||
{{ tag }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 标签颜色 -->
|
||
<div>
|
||
<label class="block text-sm text-slate-400 mb-2">标签颜色</label>
|
||
<div class="flex gap-2 flex-wrap">
|
||
<button
|
||
v-for="color in colorOptions"
|
||
:key="color.class"
|
||
@click="editForm.tagClass = color.class"
|
||
:class="['px-3 py-1 rounded text-xs transition', color.class,
|
||
editForm.tagClass === color.class ? 'ring-2 ring-white' : '']"
|
||
>
|
||
{{ color.label }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ⭐ 核心字段:完整 Prompt -->
|
||
<div class="border-t border-slate-700 pt-4 mt-4">
|
||
<label class="block text-sm text-slate-400 mb-2 flex items-center gap-2">
|
||
<span>✨</span> 完整 Prompt(核心字段)
|
||
<span class="text-xs text-slate-500 font-normal">粘贴您的完整提示词</span>
|
||
</label>
|
||
<textarea
|
||
v-model="editForm.specializedPrompt"
|
||
rows="12"
|
||
class="w-full bg-slate-900 border border-slate-700 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition resize-y font-mono leading-relaxed"
|
||
placeholder="在此粘贴您的完整 Prompt...
|
||
|
||
示例:
|
||
# Role
|
||
你是一个具有较高政治敏感性的AI助手...
|
||
|
||
# 任务目标
|
||
你需要逐一分析文章中的每一条问题...
|
||
|
||
# 检查步骤
|
||
1. 检查问题表述的清晰度
|
||
2. 深度分析思想根源
|
||
..."
|
||
></textarea>
|
||
<p class="text-xs text-slate-500 mt-2">
|
||
💡 提示:这是 AI 调用时的核心指令。完整的 Prompt 应包含角色、目标、步骤和输出格式。
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="p-4 border-t border-slate-700 flex justify-end gap-2">
|
||
<button
|
||
@click="closeEditModal"
|
||
class="px-4 py-2 bg-slate-700 text-white rounded-lg text-sm hover:bg-slate-600 transition"
|
||
>
|
||
取消
|
||
</button>
|
||
<button
|
||
@click="saveParadigm"
|
||
:disabled="!editForm.name"
|
||
class="px-4 py-2 bg-blue-600 text-white rounded-lg text-sm hover:bg-blue-500 transition disabled:opacity-50 disabled:cursor-not-allowed"
|
||
>
|
||
{{ isAddMode ? '添加' : '保存' }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, onMounted, computed, watch } from 'vue'
|
||
import { storeToRefs } from 'pinia'
|
||
import { useAppStore } from '../stores/app'
|
||
import { useDatabaseStore } from '../stores/database.js'
|
||
import DeepSeekAPI from '../api/deepseek.js'
|
||
import { getParadigmList } from '../config/paradigms.js'
|
||
|
||
const appStore = useAppStore()
|
||
const { analysisText, isAnalyzing } = storeToRefs(appStore)
|
||
|
||
// 数据库 Store
|
||
const dbStore = useDatabaseStore()
|
||
const { isInitialized: dbInitialized } = storeToRefs(dbStore)
|
||
|
||
// 选中的范式
|
||
const selectedParadigm = ref(null)
|
||
|
||
// 分析历史
|
||
const analysisHistory = ref([])
|
||
|
||
// 范式列表(响应式,支持编辑)
|
||
const paradigms = ref([])
|
||
|
||
// 编辑弹窗状态
|
||
const showEditModal = ref(false)
|
||
const isAddMode = ref(false)
|
||
const editingParadigmId = ref(null)
|
||
|
||
// 编辑表单
|
||
const editForm = reactive({
|
||
icon: '📝',
|
||
name: '',
|
||
description: '',
|
||
tagsInput: '',
|
||
tagClass: 'bg-blue-900/30 text-blue-300',
|
||
// ⭐ 核心字段:完整 Prompt
|
||
specializedPrompt: ''
|
||
})
|
||
|
||
// 图标选项
|
||
const iconOptions = ['📝', '💻', '📊', '🚀', '📚', '🏛️', '🔥', '🏢', '💡', '🎯', '📋', '✨']
|
||
|
||
// 颜色选项
|
||
const colorOptions = [
|
||
{ label: '蓝色', class: 'bg-blue-900/30 text-blue-300' },
|
||
{ label: '绿色', class: 'bg-green-900/30 text-green-300' },
|
||
{ label: '红色', class: 'bg-red-900/30 text-red-300' },
|
||
{ label: '紫色', class: 'bg-purple-900/30 text-purple-300' },
|
||
{ label: '橙色', class: 'bg-orange-900/30 text-orange-300' },
|
||
{ label: '青色', class: 'bg-cyan-900/30 text-cyan-300' }
|
||
]
|
||
|
||
|
||
// 初始化范式列表
|
||
const initParadigms = () => {
|
||
// 先加载默认范式
|
||
const defaultParadigms = getParadigmList()
|
||
|
||
// 从本地存储加载自定义修改
|
||
const savedCustomizations = localStorage.getItem('paradigmCustomizations')
|
||
const customizations = savedCustomizations ? JSON.parse(savedCustomizations) : {}
|
||
|
||
// 从本地存储加载自定义范式
|
||
const savedCustomParadigms = localStorage.getItem('customParadigms')
|
||
const customParadigms = savedCustomParadigms ? JSON.parse(savedCustomParadigms) : []
|
||
|
||
// 合并默认范式和自定义修改
|
||
const mergedParadigms = defaultParadigms.map(p => {
|
||
if (customizations[p.id]) {
|
||
return { ...p, ...customizations[p.id] }
|
||
}
|
||
return p
|
||
})
|
||
|
||
// 添加自定义范式
|
||
paradigms.value = [...mergedParadigms, ...customParadigms]
|
||
}
|
||
|
||
// 打开新增弹窗
|
||
const openAddModal = () => {
|
||
isAddMode.value = true
|
||
editingParadigmId.value = null
|
||
resetEditForm()
|
||
showEditModal.value = true
|
||
}
|
||
|
||
// 打开编辑弹窗
|
||
const openEditModal = (paradigm) => {
|
||
isAddMode.value = false
|
||
editingParadigmId.value = paradigm.id
|
||
|
||
editForm.icon = paradigm.icon || '📝'
|
||
editForm.name = paradigm.name || ''
|
||
editForm.description = paradigm.description || ''
|
||
editForm.tagsInput = (paradigm.tags || []).join(', ')
|
||
editForm.tagClass = paradigm.tagClass || 'bg-blue-900/30 text-blue-300'
|
||
// ⭐ 核心字段:加载完整 Prompt
|
||
editForm.specializedPrompt = paradigm.specializedPrompt || ''
|
||
|
||
showEditModal.value = true
|
||
}
|
||
|
||
|
||
// 关闭弹窗
|
||
const closeEditModal = () => {
|
||
showEditModal.value = false
|
||
resetEditForm()
|
||
}
|
||
|
||
// 重置表单
|
||
const resetEditForm = () => {
|
||
editForm.icon = '📝'
|
||
editForm.name = ''
|
||
editForm.description = ''
|
||
editForm.tagsInput = ''
|
||
editForm.tagClass = 'bg-blue-900/30 text-blue-300'
|
||
// ⭐ 核心字段重置
|
||
editForm.specializedPrompt = ''
|
||
}
|
||
|
||
|
||
|
||
// 保存范式
|
||
const saveParadigm = () => {
|
||
const tags = editForm.tagsInput.split(',').map(t => t.trim()).filter(t => t)
|
||
|
||
if (isAddMode.value) {
|
||
// 新增自定义范式
|
||
const newParadigm = {
|
||
id: `custom-${Date.now()}`,
|
||
icon: editForm.icon,
|
||
name: editForm.name,
|
||
description: editForm.description || editForm.specializedPrompt.substring(0, 100) + '...',
|
||
tags,
|
||
tagClass: editForm.tagClass,
|
||
isCustom: true,
|
||
// ⭐ 核心字段:完整 Prompt
|
||
specializedPrompt: editForm.specializedPrompt
|
||
}
|
||
|
||
paradigms.value.push(newParadigm)
|
||
|
||
// 保存到本地存储
|
||
const savedCustomParadigms = localStorage.getItem('customParadigms')
|
||
const customParadigms = savedCustomParadigms ? JSON.parse(savedCustomParadigms) : []
|
||
customParadigms.push(newParadigm)
|
||
localStorage.setItem('customParadigms', JSON.stringify(customParadigms))
|
||
} else {
|
||
// 编辑现有范式
|
||
const index = paradigms.value.findIndex(p => p.id === editingParadigmId.value)
|
||
if (index !== -1) {
|
||
const updatedParadigm = {
|
||
...paradigms.value[index],
|
||
icon: editForm.icon,
|
||
name: editForm.name,
|
||
description: editForm.description,
|
||
tags,
|
||
tagClass: editForm.tagClass,
|
||
// ⭐ 核心字段:完整 Prompt
|
||
specializedPrompt: editForm.specializedPrompt
|
||
}
|
||
|
||
paradigms.value[index] = updatedParadigm
|
||
|
||
// 根据是否是自定义范式决定存储位置
|
||
if (updatedParadigm.isCustom) {
|
||
// 更新自定义范式
|
||
const savedCustomParadigms = localStorage.getItem('customParadigms')
|
||
const customParadigms = savedCustomParadigms ? JSON.parse(savedCustomParadigms) : []
|
||
const customIndex = customParadigms.findIndex(p => p.id === editingParadigmId.value)
|
||
if (customIndex !== -1) {
|
||
customParadigms[customIndex] = updatedParadigm
|
||
localStorage.setItem('customParadigms', JSON.stringify(customParadigms))
|
||
}
|
||
} else {
|
||
// 保存对默认范式的自定义修改
|
||
const savedCustomizations = localStorage.getItem('paradigmCustomizations')
|
||
const customizations = savedCustomizations ? JSON.parse(savedCustomizations) : {}
|
||
customizations[editingParadigmId.value] = {
|
||
icon: editForm.icon,
|
||
name: editForm.name,
|
||
description: editForm.description,
|
||
tags,
|
||
tagClass: editForm.tagClass,
|
||
specializedPrompt: editForm.specializedPrompt
|
||
}
|
||
localStorage.setItem('paradigmCustomizations', JSON.stringify(customizations))
|
||
}
|
||
}
|
||
}
|
||
|
||
closeEditModal()
|
||
}
|
||
|
||
|
||
// 删除自定义范式
|
||
const deleteParadigm = (paradigm) => {
|
||
if (!paradigm.isCustom) return
|
||
|
||
if (!confirm(`确定要删除"${paradigm.name}"吗?`)) return
|
||
|
||
// 从列表中移除
|
||
paradigms.value = paradigms.value.filter(p => p.id !== paradigm.id)
|
||
|
||
// 从本地存储中移除
|
||
const savedCustomParadigms = localStorage.getItem('customParadigms')
|
||
const customParadigms = savedCustomParadigms ? JSON.parse(savedCustomParadigms) : []
|
||
const filtered = customParadigms.filter(p => p.id !== paradigm.id)
|
||
localStorage.setItem('customParadigms', JSON.stringify(filtered))
|
||
|
||
// 如果正在选中该范式,清除选中状态
|
||
if (selectedParadigm.value?.id === paradigm.id) {
|
||
selectedParadigm.value = null
|
||
}
|
||
}
|
||
|
||
// 选择范式
|
||
const selectParadigm = (paradigm) => {
|
||
selectedParadigm.value = paradigm
|
||
}
|
||
|
||
// 应用范式到写作(使用新的 loadParadigmPreset 方法)
|
||
const applyParadigm = (paradigm) => {
|
||
appStore.loadParadigmPreset(paradigm.id)
|
||
|
||
// 显示提示
|
||
alert(`已应用"${paradigm.name}"到写作任务`)
|
||
}
|
||
|
||
// 分析文章
|
||
const analyzeArticle = async () => {
|
||
try {
|
||
const result = await appStore.analyzeArticleAction(analysisText.value, detectParadigm)
|
||
// 添加到历史记录
|
||
addToHistory(result.paradigm, analysisText.value, result.content)
|
||
} catch (error) {
|
||
alert(error.message)
|
||
}
|
||
}
|
||
|
||
// 检测文章范式
|
||
const detectParadigm = (analysis) => {
|
||
const text = analysis.toLowerCase()
|
||
const list = paradigms.value
|
||
|
||
// 根据 id 查找范式
|
||
const findById = (id) => list.find(p => p.id === id)
|
||
|
||
if (text.includes('民主生活会') || text.includes('对照检查') || text.includes('整改') || text.includes('党性')) {
|
||
return findById('party-review') || list[0]
|
||
} else if (text.includes('政府') || text.includes('工作报告') || text.includes('述职')) {
|
||
return findById('gov-report') || list[0]
|
||
} else if (text.includes('技术') || text.includes('代码') || text.includes('编程')) {
|
||
return findById('tech') || list[0]
|
||
} else if (text.includes('商业') || text.includes('市场') || text.includes('数据分析')) {
|
||
return findById('business') || list[0]
|
||
} else if (text.includes('产品') || text.includes('营销') || text.includes('用户')) {
|
||
return findById('marketing') || list[0]
|
||
} else if (text.includes('学术') || text.includes('研究') || text.includes('文献')) {
|
||
return findById('academic') || list[0]
|
||
}
|
||
|
||
return list[0] // 默认第一个范式
|
||
}
|
||
|
||
// 添加到历史记录
|
||
const addToHistory = (paradigm, text, analysis) => {
|
||
const historyItem = {
|
||
paradigm,
|
||
text,
|
||
analysis,
|
||
preview: text.substring(0, 50) + '...',
|
||
timestamp: new Date()
|
||
}
|
||
|
||
// 限制历史记录数量
|
||
analysisHistory.value.unshift(historyItem)
|
||
if (analysisHistory.value.length > 10) {
|
||
analysisHistory.value = analysisHistory.value.slice(0, 10)
|
||
}
|
||
|
||
// 保存到本地存储
|
||
localStorage.setItem('analysisHistory', JSON.stringify(analysisHistory.value))
|
||
}
|
||
|
||
// 加载历史记录项
|
||
const loadHistoryItem = (item) => {
|
||
analysisText.value = item.text
|
||
appStore.analysisResult = {
|
||
paradigm: item.paradigm,
|
||
analysis: item.analysis,
|
||
timestamp: item.timestamp
|
||
}
|
||
}
|
||
|
||
// 清空分析
|
||
const clearAnalysis = () => {
|
||
analysisText.value = ''
|
||
appStore.analysisResult = null
|
||
selectedParadigm.value = null
|
||
}
|
||
|
||
// 格式化日期
|
||
const formatDate = (date) => {
|
||
const now = new Date()
|
||
const diff = now - new Date(date)
|
||
const minutes = Math.floor(diff / 60000)
|
||
const hours = Math.floor(diff / 3600000)
|
||
const days = Math.floor(diff / 86400000)
|
||
|
||
if (minutes < 1) return '刚刚'
|
||
if (minutes < 60) return `${minutes}分钟前`
|
||
if (hours < 24) return `${hours}小时前`
|
||
if (days < 7) return `${days}天前`
|
||
|
||
return new Date(date).toLocaleDateString()
|
||
}
|
||
|
||
// 组件挂载时加载历史记录和范式列表
|
||
onMounted(() => {
|
||
// 初始化范式列表
|
||
initParadigms()
|
||
|
||
// 加载分析历史
|
||
const saved = localStorage.getItem('analysisHistory')
|
||
if (saved) {
|
||
analysisHistory.value = JSON.parse(saved)
|
||
}
|
||
})
|
||
</script>
|