Files
ai-write/src/components/AnalysisPanel.vue
empty d2c42e68c8 feat: 新增【2025党委组织生活会】范式(基于二十届四中全会精神)
- 全新大纲结构:七大板块(会前准备→八项规定→典型案例→五个方面→原因剖析→意识形态→整改措施)
- 时政知识库注入:十五五规划、中办发〔2025〕57号文、四中全会精神
- 典型案例四维剖析:以案说德、以案说纪、以案说法、以案说责
- 增强质检规则:60%篇幅比例检查、必查项校验
- UI:NEW 标签闪烁提示最新范式
2026-01-08 12:12:24 +08:00

236 lines
8.1 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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">
<div class="flex items-center gap-4">
<h1 class="font-bold text-lg text-white flex items-center gap-2">
<span class="text-2xl"></span> 写作范式分析
</h1>
<button
@click="switchPage('writer')"
class="text-xs px-2 py-1 rounded bg-slate-700 text-slate-300 hover:bg-slate-600 transition"
>
返回写作
</button>
</div>
<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>
<h3 class="text-sm font-medium text-slate-400 mb-4">📚 写作范式库</h3>
<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>
</h4>
<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>
<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>
</aside>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import { useAppStore } from '../stores/app'
import DeepSeekAPI from '../api/deepseek.js'
import { getParadigmList } from '../config/paradigms.js'
const appStore = useAppStore()
const { analysisText, isAnalyzing } = storeToRefs(appStore)
// 选中的范式
const selectedParadigm = ref(null)
// 分析历史
const analysisHistory = ref([])
// 从配置文件获取范式列表
const paradigms = getParadigmList()
// 选择范式
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()
if (text.includes('民主生活会') || text.includes('对照检查') || text.includes('整改') || text.includes('党性')) {
return paradigms[4] // 民主生活会对照检查
} else if (text.includes('政府') || text.includes('工作报告') || text.includes('述职')) {
return paradigms[5] // 政府工作报告
} else if (text.includes('技术') || text.includes('代码') || text.includes('编程')) {
return paradigms[0] // 技术博客
} else if (text.includes('商业') || text.includes('市场') || text.includes('数据分析')) {
return paradigms[1] // 商业分析
} else if (text.includes('产品') || text.includes('营销') || text.includes('用户')) {
return paradigms[2] // 产品文案
} else if (text.includes('学术') || text.includes('研究') || text.includes('文献')) {
return paradigms[3] // 学术论文
}
return paradigms[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(() => {
const saved = localStorage.getItem('analysisHistory')
if (saved) {
analysisHistory.value = JSON.parse(saved)
}
})
</script>