refactor: 完成全局 emoji 到 SVG 图标迁移
- IconLibrary 新增 6 个图标: star, lightbulb, pin, clipboard, microphone, bookmark - 迁移 12 个组件中的 emoji 为 IconLibrary 组件 - 更新 paradigms.js 中的 icon 字段为图标名称 - 修复深度模式开关点击无效的问题 (改用 Vue 动态类绑定) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -60,7 +60,8 @@
|
||||
>
|
||||
<div class="paradigm-card-header">
|
||||
<h4 class="paradigm-card-title">
|
||||
{{ paradigm.icon }} {{ paradigm.name }}
|
||||
<IconLibrary :name="paradigm.icon" :size="16" class="shrink-0" />
|
||||
{{ paradigm.name }}
|
||||
<span v-if="paradigm.isNew" class="badge-new animate-pulse">NEW</span>
|
||||
<span v-if="isCustomParadigm(paradigm)" class="badge-custom">自定义</span>
|
||||
<span v-if="paradigm.createdAt" class="text-[10px] text-muted ml-auto opacity-70">
|
||||
@@ -202,7 +203,7 @@ const activeTab = ref('paradigms') // 'paradigms' or 'tools'
|
||||
|
||||
// 编辑表单
|
||||
const editForm = reactive({
|
||||
icon: '📝',
|
||||
icon: 'edit',
|
||||
name: '',
|
||||
description: '',
|
||||
tagsInput: '',
|
||||
@@ -211,8 +212,8 @@ const editForm = reactive({
|
||||
specializedPrompt: ''
|
||||
})
|
||||
|
||||
// 图标选项 (保留 emoji 用于用户自定义范式图标选择器,TODO: 后续优化为 IconLibrary 选择器)
|
||||
const iconOptions = ['📝', '💻', '📊', '🚀', '📚', '🏛️', '🔥', '🏢', '💡', '🎯', '📋', '✨']
|
||||
// 图标选项 (使用 IconLibrary 图标名称)
|
||||
const iconOptions = ['edit', 'document', 'chart', 'sparkles', 'folder', 'article', 'star', 'lightbulb', 'clipboard', 'bookmark']
|
||||
|
||||
// 颜色选项
|
||||
const colorOptions = [
|
||||
@@ -259,7 +260,7 @@ const openAddModal = () => {
|
||||
|
||||
// 重置表单
|
||||
const form = appStore.paradigmEditState.editForm
|
||||
form.icon = '📝'
|
||||
form.icon = 'edit'
|
||||
form.name = ''
|
||||
form.description = ''
|
||||
form.tagsInput = ''
|
||||
@@ -293,7 +294,7 @@ const openEditModal = (paradigm) => {
|
||||
|
||||
// 填充表单数据
|
||||
const form = appStore.paradigmEditState.editForm
|
||||
form.icon = paradigm.icon || '📝'
|
||||
form.icon = paradigm.icon || 'edit'
|
||||
form.name = paradigm.name || ''
|
||||
form.description = paradigm.description || ''
|
||||
form.tagsInput = (paradigm.tags || []).join(', ')
|
||||
@@ -310,7 +311,7 @@ const closeEditModal = () => {
|
||||
|
||||
// 重置表单
|
||||
const resetEditForm = () => {
|
||||
editForm.icon = '📝'
|
||||
editForm.icon = 'edit'
|
||||
editForm.name = ''
|
||||
editForm.description = ''
|
||||
editForm.tagsInput = ''
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<header class="p-3 border-b border-slate-700 bg-slate-800 flex items-center justify-between shrink-0">
|
||||
<div class="flex items-center gap-3">
|
||||
<h1 class="font-bold text-white flex items-center gap-2">
|
||||
<span class="text-xl">🔍</span> 对照检查
|
||||
<IconLibrary name="search" :size="20" /> 对照检查
|
||||
</h1>
|
||||
<span class="text-xs text-slate-500">选中左右两侧对应段落进行检查</span>
|
||||
</div>
|
||||
@@ -13,7 +13,9 @@
|
||||
<!-- 范式上下文提示条 -->
|
||||
<div v-if="hasParadigmRules" class="px-4 py-2 bg-indigo-900/30 border-b border-indigo-700/50 flex items-center justify-between shrink-0">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-indigo-400 text-sm">📚 当前写作范式:</span>
|
||||
<span class="text-indigo-400 text-sm flex items-center gap-1">
|
||||
<IconLibrary name="folder" :size="14" /> 当前写作范式:
|
||||
</span>
|
||||
<span class="text-white text-sm font-medium">{{ activeParadigmName }}</span>
|
||||
<!-- 检查模式切换 -->
|
||||
<div class="flex bg-slate-900/50 rounded p-0.5 border border-indigo-700/50">
|
||||
@@ -61,7 +63,7 @@
|
||||
<div :class="['w-4 h-4 rounded border flex items-center justify-center shrink-0 mt-0.5 transition',
|
||||
enabledRuleIdxs.has(rule.idx) ? 'bg-indigo-600 border-indigo-500' : 'bg-slate-800 border-slate-600'
|
||||
]">
|
||||
<span v-if="enabledRuleIdxs.has(rule.idx)" class="text-white text-[10px]">✓</span>
|
||||
<IconLibrary v-if="enabledRuleIdxs.has(rule.idx)" name="check" :size="10" class="text-white" />
|
||||
</div>
|
||||
<!-- 规则标签和文本 -->
|
||||
<div class="flex-1 min-w-0">
|
||||
@@ -80,7 +82,7 @@
|
||||
<div class="w-[40%] flex flex-col border-r border-slate-700 min-w-0">
|
||||
<div class="p-3 bg-slate-800 border-b border-slate-700 flex items-center justify-between">
|
||||
<h2 class="text-sm font-medium text-amber-400 flex items-center gap-2">
|
||||
📋 要求原文
|
||||
<IconLibrary name="clipboard" :size="14" /> 要求原文
|
||||
</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs text-slate-500">{{ leftParagraphs.length }} 段</span>
|
||||
@@ -95,11 +97,11 @@
|
||||
: 'bg-slate-700 text-slate-400 cursor-not-allowed'"
|
||||
>
|
||||
<span v-if="isLeftSaving" class="animate-spin">↻</span>
|
||||
<span v-else>💾</span>
|
||||
<IconLibrary v-else name="save" :size="12" />
|
||||
{{ isLeftSaving ? '保存中...' : (hasLeftContentChanged ? '保存版本' : '已保存') }}
|
||||
</button>
|
||||
<span v-if="leftSourceType === 'document' && leftSourceDocTitle" class="text-xs text-amber-400">
|
||||
📄 {{ leftSourceDocTitle }}
|
||||
<span v-if="leftSourceType === 'document' && leftSourceDocTitle" class="text-xs text-amber-400 flex items-center gap-1">
|
||||
<IconLibrary name="document" :size="12" /> {{ leftSourceDocTitle }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -132,7 +134,9 @@
|
||||
<div class="flex-1 overflow-y-auto p-4 space-y-3 min-h-0">
|
||||
<div v-if="!leftContent" class="h-full flex items-center justify-center">
|
||||
<div class="text-center">
|
||||
<span class="text-4xl opacity-20 block mb-2">📝</span>
|
||||
<div class="w-12 h-12 flex items-center justify-center mx-auto mb-2 opacity-20">
|
||||
<IconLibrary name="edit" :size="32" />
|
||||
</div>
|
||||
<p class="text-slate-600 text-sm">请在下方粘贴写作要求的原文</p>
|
||||
<p class="text-slate-700 text-xs mt-1">(如:红头文件、通知要求等)</p>
|
||||
</div>
|
||||
@@ -151,7 +155,8 @@
|
||||
<div class="flex items-start gap-2">
|
||||
<span :class="['text-xs shrink-0 mt-0.5 w-5 h-5 rounded flex items-center justify-center',
|
||||
selectedLeftIdxs.includes(idx) ? 'bg-amber-500 text-white' : 'text-amber-500/70']">
|
||||
{{ selectedLeftIdxs.includes(idx) ? '✓' : (idx + 1) }}
|
||||
<span v-if="selectedLeftIdxs.includes(idx)"><IconLibrary name="check" :size="10" /></span>
|
||||
<span v-else>{{ idx + 1 }}</span>
|
||||
</span>
|
||||
<p class="text-sm text-slate-300 whitespace-pre-wrap">{{ para }}</p>
|
||||
</div>
|
||||
@@ -186,7 +191,7 @@
|
||||
<div class="flex-1 flex flex-col min-w-0">
|
||||
<div class="p-3 bg-slate-800 border-b border-slate-700 flex items-center justify-between">
|
||||
<h2 class="text-sm font-medium text-blue-400 flex items-center gap-2">
|
||||
✍️ 写作内容
|
||||
<IconLibrary name="edit" :size="14" /> 写作内容
|
||||
</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs text-slate-500">{{ rightParagraphs.length }} 段</span>
|
||||
@@ -201,11 +206,11 @@
|
||||
: 'bg-slate-700 text-slate-400 cursor-not-allowed'"
|
||||
>
|
||||
<span v-if="isSaving" class="animate-spin">↻</span>
|
||||
<span v-else>💾</span>
|
||||
<IconLibrary v-else name="save" :size="12" />
|
||||
{{ isSaving ? '保存中...' : (hasContentChanged ? '保存版本' : '已保存') }}
|
||||
</button>
|
||||
<span v-if="rightSourceType === 'document' && rightSourceDocTitle" class="text-xs text-blue-400">
|
||||
📄 {{ rightSourceDocTitle }}
|
||||
<span v-if="rightSourceType === 'document' && rightSourceDocTitle" class="text-xs text-blue-400 flex items-center gap-1">
|
||||
<IconLibrary name="document" :size="12" /> {{ rightSourceDocTitle }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -228,7 +233,9 @@
|
||||
<div class="flex-1 overflow-y-auto p-4 space-y-3 min-h-0">
|
||||
<div v-if="!rightContent" class="h-full flex items-center justify-center">
|
||||
<div class="text-center">
|
||||
<span class="text-4xl opacity-20 block mb-2">📄</span>
|
||||
<div class="w-12 h-12 flex items-center justify-center mx-auto mb-2 opacity-20">
|
||||
<IconLibrary name="document" :size="32" />
|
||||
</div>
|
||||
<p class="text-slate-600 text-sm">请在下方输入写作内容</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -246,7 +253,8 @@
|
||||
<div class="flex items-start gap-2">
|
||||
<span :class="['text-xs shrink-0 mt-0.5 w-5 h-5 rounded flex items-center justify-center',
|
||||
selectedRightIdxs.includes(idx) ? 'bg-blue-500 text-white' : 'text-blue-500/70']">
|
||||
{{ selectedRightIdxs.includes(idx) ? '✓' : (idx + 1) }}
|
||||
<span v-if="selectedRightIdxs.includes(idx)"><IconLibrary name="check" :size="10" /></span>
|
||||
<span v-else>{{ idx + 1 }}</span>
|
||||
</span>
|
||||
<p class="text-sm text-slate-300 whitespace-pre-wrap">{{ para }}</p>
|
||||
</div>
|
||||
@@ -287,7 +295,9 @@
|
||||
checkResults[idx].status === 'warning' ? 'bg-yellow-900/30 text-yellow-400' :
|
||||
'bg-red-900/30 text-red-400'
|
||||
]">
|
||||
<span>{{ checkResults[idx].status === 'pass' ? '✅' : checkResults[idx].status === 'warning' ? '⚠️' : '❌' }}</span>
|
||||
<IconLibrary v-if="checkResults[idx].status === 'pass'" name="success" :size="14" />
|
||||
<IconLibrary v-else-if="checkResults[idx].status === 'warning'" name="warning" :size="14" />
|
||||
<IconLibrary v-else name="error" :size="14" />
|
||||
{{ checkResults[idx].message }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -316,7 +326,9 @@
|
||||
]">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<span class="text-lg">
|
||||
{{ lastCheckResult.overall === 'pass' ? '✅' : lastCheckResult.overall === 'warning' ? '⚠️' : '❌' }}
|
||||
<IconLibrary v-if="lastCheckResult.overall === 'pass'" name="success" :size="18" />
|
||||
<IconLibrary v-else-if="lastCheckResult.overall === 'warning'" name="warning" :size="18" />
|
||||
<IconLibrary v-else name="error" :size="18" />
|
||||
</span>
|
||||
<span :class="[
|
||||
'font-medium',
|
||||
@@ -340,7 +352,7 @@
|
||||
<div v-if="showDetailedSuggestions && lastCheckResult.suggestions?.length"
|
||||
class="mt-3 p-3 bg-slate-800/50 rounded-lg border border-slate-700">
|
||||
<h4 class="text-xs text-slate-400 mb-2 flex items-center gap-1">
|
||||
<span>💡</span> 改进建议
|
||||
<IconLibrary name="lightbulb" :size="12" /> 改进建议
|
||||
</h4>
|
||||
<div class="space-y-2">
|
||||
<div v-for="(suggestion, idx) in lastCheckResult.suggestions" :key="idx"
|
||||
@@ -353,7 +365,7 @@
|
||||
hover:bg-indigo-500 transition flex items-center gap-1
|
||||
disabled:opacity-50 disabled:cursor-not-allowed ml-2 shrink-0">
|
||||
<span v-if="rewritingSuggestionIdx === idx" class="animate-spin">↻</span>
|
||||
<span v-else>🔄</span>
|
||||
<IconLibrary v-else name="refresh" :size="12" />
|
||||
{{ rewritingSuggestionIdx === idx ? '重写中...' : '一键重写' }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -384,7 +396,7 @@
|
||||
<span v-if="isDetectingTypes" class="flex items-center gap-2">
|
||||
<span class="animate-spin">↻</span> 识别中...
|
||||
</span>
|
||||
<span v-else>🧠 智能识别</span>
|
||||
<span v-else><IconLibrary name="sparkles" :size="14" /> 智能识别</span>
|
||||
</button>
|
||||
<button
|
||||
@click="runCompare"
|
||||
@@ -395,7 +407,7 @@
|
||||
<span v-if="isComparing" class="flex items-center gap-2">
|
||||
<span class="animate-spin">↻</span> 检查中...
|
||||
</span>
|
||||
<span v-else>🔍 对照检查</span>
|
||||
<span v-else><IconLibrary name="search" :size="14" /> 对照检查</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -438,18 +450,20 @@
|
||||
<!-- 浮窗头部 -->
|
||||
<div class="p-4 border-b border-slate-700 flex items-center justify-between">
|
||||
<h3 class="text-lg font-medium text-white flex items-center gap-2">
|
||||
<span>🔄</span> AI 重写预览
|
||||
<IconLibrary name="refresh" :size="18" /> AI 重写预览
|
||||
</h3>
|
||||
<button
|
||||
@click="resetRewriteModal"
|
||||
class="text-slate-400 hover:text-white text-xl"
|
||||
>✕</button>
|
||||
><IconLibrary name="close" :size="20" /></button>
|
||||
</div>
|
||||
|
||||
<!-- 建议信息 + 视图切换 -->
|
||||
<div class="px-4 py-2 bg-indigo-900/30 border-b border-indigo-700/50 flex items-center justify-between">
|
||||
<div>
|
||||
<span class="text-xs text-indigo-300">📋 根据建议:</span>
|
||||
<span class="text-xs text-indigo-300 flex items-center gap-1">
|
||||
<IconLibrary name="clipboard" :size="12" /> 根据建议:
|
||||
</span>
|
||||
<span class="text-xs text-white ml-1">{{ currentSuggestion }}</span>
|
||||
</div>
|
||||
<!-- 视图切换按钮 -->
|
||||
@@ -512,7 +526,9 @@
|
||||
<div class="flex gap-4">
|
||||
<!-- 左边:原文 -->
|
||||
<div class="flex-1">
|
||||
<div class="text-xs text-amber-400 mb-2 font-medium">📄 原文(点击选中需要替换的部分)</div>
|
||||
<div class="text-xs text-amber-400 mb-2 font-medium flex items-center gap-1">
|
||||
<IconLibrary name="document" :size="12" /> 原文(点击选中需要替换的部分)
|
||||
</div>
|
||||
<div class="bg-slate-900 rounded-lg p-3 border border-slate-700">
|
||||
<template v-for="segment in diffSegments" :key="'orig-' + segment.idx">
|
||||
<span
|
||||
@@ -535,7 +551,9 @@
|
||||
</div>
|
||||
<!-- 右边:重写后 -->
|
||||
<div class="flex-1">
|
||||
<div class="text-xs text-blue-400 mb-2 font-medium">✨ 重写后(选中部分将替换为此内容)</div>
|
||||
<div class="text-xs text-blue-400 mb-2 font-medium flex items-center gap-1">
|
||||
<IconLibrary name="sparkles" :size="12" /> 重写后(选中部分将替换为此内容)
|
||||
</div>
|
||||
<div class="bg-slate-900 rounded-lg p-3 border border-slate-700">
|
||||
<template v-for="segment in diffSegments" :key="'new-' + segment.idx">
|
||||
<span
|
||||
@@ -607,7 +625,7 @@
|
||||
: 'bg-slate-700 text-slate-300 hover:bg-slate-600'
|
||||
]"
|
||||
>
|
||||
{{ acceptedChanges.has(currentReviewItem.idx) ? '✓ 已接受' : '接受修改' }}
|
||||
{{ acceptedChanges.has(currentReviewItem.idx) ? '' : '' }}<IconLibrary v-if="acceptedChanges.has(currentReviewItem.idx)" name="check" :size="12" class="inline mr-1" />{{ acceptedChanges.has(currentReviewItem.idx) ? '已接受' : '接受修改' }}
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
@@ -628,7 +646,7 @@
|
||||
<!-- 左边:原文句子 -->
|
||||
<div class="flex-1">
|
||||
<div class="text-xs text-amber-400 mb-2 font-medium flex items-center justify-between">
|
||||
<span>📄 原文(点击选中要被替换的句子)</span>
|
||||
<span class="flex items-center gap-1"><IconLibrary name="document" :size="12" /> 原文(点击选中要被替换的句子)</span>
|
||||
<span class="text-slate-500">已选 {{ partialLeftSelected.size }} 句</span>
|
||||
</div>
|
||||
<div class="bg-slate-900 rounded-lg p-3 border border-slate-700 max-h-[400px] overflow-y-auto">
|
||||
@@ -648,7 +666,7 @@
|
||||
<!-- 右边:重写后句子 -->
|
||||
<div class="flex-1">
|
||||
<div class="text-xs text-blue-400 mb-2 font-medium flex items-center justify-between">
|
||||
<span>✨ 重写后(点击选中用于替换的句子)</span>
|
||||
<span class="flex items-center gap-1"><IconLibrary name="sparkles" :size="12" /> 重写后(点击选中用于替换的句子)</span>
|
||||
<span class="text-slate-500">已选 {{ partialRightSelected.size }} 句</span>
|
||||
</div>
|
||||
<div class="bg-slate-900 rounded-lg p-3 border border-slate-700 max-h-[400px] overflow-y-auto">
|
||||
@@ -749,6 +767,7 @@ import { storeToRefs } from 'pinia'
|
||||
import { useAppStore } from '../stores/app'
|
||||
import { useDatabaseStore } from '../stores/database'
|
||||
import { updateDocument, saveDocumentVersion, getDocumentById } from '../db/index.js'
|
||||
import IconLibrary from './icons/IconLibrary.vue'
|
||||
import { SECTION_TYPES, getSectionTypeById, getSectionTypeClasses } from '../config/sectionTypes'
|
||||
import { getLogicParadigmById, buildLogicPrompt } from '../config/logicParadigms'
|
||||
import { computeDiff, applySelectedChanges as applyDiffChanges, getDiffStats, splitIntoSentencesWithPosition } from '../utils/textDiff'
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<header class="h-14 border-b border-slate-800 flex items-center justify-between px-6 bg-slate-950 shrink-0">
|
||||
<div class="flex items-center gap-4">
|
||||
<h1 class="text-lg font-bold text-white flex items-center gap-2">
|
||||
📊 文稿差异标注
|
||||
<IconLibrary name="chart" :size="20" /> 文稿差异标注
|
||||
</h1>
|
||||
<button
|
||||
@click="goBack"
|
||||
@@ -32,7 +32,7 @@
|
||||
:disabled="!leftContent || !rightContent"
|
||||
class="text-sm px-4 py-2 rounded bg-blue-600 text-white hover:bg-blue-500 disabled:opacity-50 disabled:cursor-not-allowed transition flex items-center gap-2"
|
||||
>
|
||||
📥 导出 Word
|
||||
<IconLibrary name="download" :size="14" /> 导出 Word
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
@@ -43,7 +43,7 @@
|
||||
<div class="flex-1 flex flex-col border-r border-slate-700 min-w-0">
|
||||
<div class="p-3 bg-slate-800 border-b border-slate-700 flex items-center justify-between shrink-0">
|
||||
<h2 class="text-sm font-medium text-amber-400 flex items-center gap-2">
|
||||
📄 原文
|
||||
<IconLibrary name="document" :size="14" /> 原文
|
||||
</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs text-slate-500">来源:</span>
|
||||
@@ -81,7 +81,9 @@
|
||||
</template>
|
||||
</div>
|
||||
<div v-else class="h-full flex flex-col items-center justify-center text-slate-500">
|
||||
<span class="text-5xl block mb-3 opacity-30">📝</span>
|
||||
<div class="w-16 h-16 flex items-center justify-center mb-3 opacity-30">
|
||||
<IconLibrary name="edit" :size="40" />
|
||||
</div>
|
||||
<p class="text-sm">在下方输入原文内容</p>
|
||||
<p class="text-xs text-slate-600 mt-1">或从文稿库选择</p>
|
||||
</div>
|
||||
@@ -109,7 +111,7 @@
|
||||
<div class="flex-1 flex flex-col min-w-0">
|
||||
<div class="p-3 bg-slate-800 border-b border-slate-700 flex items-center justify-between shrink-0">
|
||||
<h2 class="text-sm font-medium text-blue-400 flex items-center gap-2">
|
||||
✏️ 修改文
|
||||
<IconLibrary name="edit" :size="14" /> 修改文
|
||||
</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs text-slate-500">来源:</span>
|
||||
@@ -147,7 +149,9 @@
|
||||
</template>
|
||||
</div>
|
||||
<div v-else class="h-full flex flex-col items-center justify-center text-slate-500">
|
||||
<span class="text-5xl block mb-3 opacity-30">✏️</span>
|
||||
<div class="w-16 h-16 flex items-center justify-center mb-3 opacity-30">
|
||||
<IconLibrary name="edit" :size="40" />
|
||||
</div>
|
||||
<p class="text-sm">在下方输入修改后的内容</p>
|
||||
<p class="text-xs text-slate-600 mt-1">或从文稿库选择</p>
|
||||
</div>
|
||||
@@ -192,6 +196,7 @@
|
||||
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
|
||||
import { useAppStore } from '../stores/app'
|
||||
import { computePreciseDiff, getPreciseDiffStats } from '../utils/preciseDiff.js'
|
||||
import IconLibrary from './icons/IconLibrary.vue'
|
||||
import { Document, Packer, Paragraph, TextRun } from 'docx'
|
||||
import { saveAs } from 'file-saver'
|
||||
import DocumentSelectorModal from './DocumentSelectorModal.vue'
|
||||
|
||||
@@ -3,8 +3,12 @@
|
||||
<div class="bg-slate-800 rounded-lg w-[500px] max-h-[70vh] overflow-hidden border border-slate-600 flex flex-col">
|
||||
<!-- 头部 -->
|
||||
<div class="p-4 border-b border-slate-700 flex items-center justify-between shrink-0">
|
||||
<h3 class="text-lg font-bold text-white">📂 选择文稿</h3>
|
||||
<button @click="$emit('close')" class="text-slate-400 hover:text-white">✕</button>
|
||||
<h3 class="text-lg font-bold text-white flex items-center gap-2">
|
||||
<IconLibrary name="folder" :size="18" /> 选择文稿
|
||||
</h3>
|
||||
<button @click="$emit('close')" class="text-slate-400 hover:text-white">
|
||||
<IconLibrary name="close" :size="18" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 筛选 -->
|
||||
@@ -25,7 +29,9 @@
|
||||
<!-- 文稿列表 -->
|
||||
<div class="flex-1 overflow-y-auto p-4 space-y-2 min-h-0">
|
||||
<div v-if="filteredDocuments.length === 0" class="text-center text-slate-500 py-8">
|
||||
<span class="text-4xl block mb-2">📄</span>
|
||||
<div class="w-12 h-12 flex items-center justify-center mx-auto mb-2">
|
||||
<IconLibrary name="document" :size="32" />
|
||||
</div>
|
||||
<p class="text-sm">暂无文稿</p>
|
||||
</div>
|
||||
|
||||
@@ -76,6 +82,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import IconLibrary from './icons/IconLibrary.vue'
|
||||
|
||||
const props = defineProps({
|
||||
visible: Boolean
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
<!-- 头部 -->
|
||||
<header class="p-4 border-b border-slate-700 flex items-center justify-between">
|
||||
<h2 class="font-bold text-white flex items-center gap-2">
|
||||
<span class="text-xl">🕐</span> 版本历史
|
||||
<IconLibrary name="clock" :size="18" /> 版本历史
|
||||
</h2>
|
||||
<button
|
||||
<button
|
||||
@click="$emit('close')"
|
||||
class="text-slate-400 hover:text-white transition"
|
||||
>
|
||||
✕
|
||||
<IconLibrary name="close" :size="18" />
|
||||
</button>
|
||||
</header>
|
||||
|
||||
@@ -69,7 +69,9 @@
|
||||
|
||||
<!-- 无版本记录 -->
|
||||
<div v-else class="flex-1 flex flex-col items-center justify-center text-slate-500">
|
||||
<span class="text-4xl mb-2">📋</span>
|
||||
<div class="w-12 h-12 flex items-center justify-center mb-2">
|
||||
<IconLibrary name="clipboard" :size="32" />
|
||||
</div>
|
||||
<p class="text-sm">暂无版本记录</p>
|
||||
<p class="text-xs text-slate-600 mt-1">保存文稿后将自动记录版本</p>
|
||||
</div>
|
||||
@@ -92,10 +94,10 @@
|
||||
<span><span class="inline-block w-3 h-3 rounded bg-amber-500/50 mr-1"></span>修改</span>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
<button
|
||||
@click="showCompareModal = false"
|
||||
class="text-slate-400 hover:text-white"
|
||||
>✕</button>
|
||||
><IconLibrary name="close" :size="18" /></button>
|
||||
</header>
|
||||
<div class="flex-1 overflow-y-auto p-4">
|
||||
<div class="flex gap-4">
|
||||
@@ -170,6 +172,7 @@
|
||||
import { ref, watch, computed, defineProps, defineEmits } from 'vue'
|
||||
import { getDocumentVersions, getDocumentById, saveDocumentVersion, updateDocument } from '../db/index.js'
|
||||
import { computeDiff, getDiffStats } from '../utils/textDiff.js'
|
||||
import IconLibrary from './icons/IconLibrary.vue'
|
||||
|
||||
const props = defineProps({
|
||||
visible: Boolean,
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<div v-if="currentPage === 'writer'">
|
||||
<div v-if="!generatedContent && !isGenerating" class="h-full flex flex-col items-center justify-center text-slate-700 mt-20">
|
||||
<div class="w-20 h-20 flex items-center justify-center rounded-2xl bg-slate-800/50 border border-slate-700 mb-4 opacity-40">
|
||||
<IconLibrary name="keyboard" :size="48" />
|
||||
<IconLibrary name="edit" :size="48" />
|
||||
</div>
|
||||
<p>在左侧配置参数,点击生成开始写作</p>
|
||||
</div>
|
||||
@@ -297,12 +297,12 @@
|
||||
v-for="icon in iconOptions"
|
||||
:key="icon"
|
||||
@click="paradigmEditState.editForm.icon = icon"
|
||||
:class="['w-10 h-10 text-xl rounded border transition',
|
||||
paradigmEditState.editForm.icon === icon
|
||||
? 'border-blue-500 bg-blue-500/20'
|
||||
:class="['w-10 h-10 rounded border transition flex items-center justify-center',
|
||||
paradigmEditState.editForm.icon === icon
|
||||
? 'border-blue-500 bg-blue-500/20'
|
||||
: 'border-slate-600 hover:border-slate-500']"
|
||||
>
|
||||
{{ icon }}
|
||||
<IconLibrary :name="icon" :size="20" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -584,8 +584,8 @@ const exportParadigmToWord = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 图标选项 (TODO: 后续优化为 IconLibrary 图标网格选择器)
|
||||
const iconOptions = ['📝', '📄', '📊', '📈', '📉', '🏛️', '🍂', '💻', '📌', '💡']
|
||||
// 图标选项 (使用 IconLibrary 图标名称)
|
||||
const iconOptions = ['edit', 'document', 'chart', 'sparkles', 'folder', 'article', 'star', 'lightbulb', 'pin', 'clipboard']
|
||||
|
||||
// 颜色选项
|
||||
const colorOptions = [
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<button
|
||||
@click="$emit('close')"
|
||||
class="text-slate-400 hover:text-white"
|
||||
>✕</button>
|
||||
><IconLibrary name="close" :size="18" /></button>
|
||||
</div>
|
||||
|
||||
<!-- 筛选器 -->
|
||||
@@ -71,6 +71,7 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { useDatabaseStore } from '../stores/database'
|
||||
import IconLibrary from './icons/IconLibrary.vue'
|
||||
|
||||
const props = defineProps({
|
||||
visible: Boolean
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
<!-- 头部 -->
|
||||
<div class="p-4 border-b border-slate-700 flex items-center justify-between shrink-0">
|
||||
<h3 class="text-lg font-bold text-white flex items-center gap-2">
|
||||
<span>📚</span> 选择写作范式
|
||||
<IconLibrary name="folder" :size="18" /> 选择写作范式
|
||||
</h3>
|
||||
<button @click="$emit('close')" class="text-slate-400 hover:text-white transition">✕</button>
|
||||
<button @click="$emit('close')" class="text-slate-400 hover:text-white transition">
|
||||
<IconLibrary name="close" :size="18" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 搜索/过滤 -->
|
||||
@@ -22,7 +24,9 @@
|
||||
<!-- 范式列表 -->
|
||||
<div class="flex-1 overflow-y-auto p-4 space-y-3 min-h-0 bg-slate-900/20">
|
||||
<div v-if="filteredParadigms.length === 0" class="text-center text-slate-500 py-12">
|
||||
<span class="text-4xl block mb-2">🔍</span>
|
||||
<div class="w-12 h-12 flex items-center justify-center mx-auto mb-2">
|
||||
<IconLibrary name="search" :size="32" />
|
||||
</div>
|
||||
<p class="text-sm">未找到相关范式</p>
|
||||
</div>
|
||||
|
||||
@@ -70,7 +74,7 @@
|
||||
<!-- 勾选指示 -->
|
||||
<div class="w-6 h-6 rounded-full border-2 flex items-center justify-center shrink-0 mt-1 transition-colors"
|
||||
:class="selectedId === paradigm.id ? 'border-blue-500 bg-blue-600' : 'border-slate-600'">
|
||||
<span v-if="selectedId === paradigm.id" class="text-white text-xs">✓</span>
|
||||
<IconLibrary v-if="selectedId === paradigm.id" name="check" :size="12" class="text-white" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -83,7 +87,7 @@
|
||||
class="py-2.5 px-4 rounded-lg bg-purple-600 text-white hover:bg-purple-500 transition font-medium shadow-lg shadow-purple-900/20 flex items-center gap-2"
|
||||
title="从需求文档创建自定义范式"
|
||||
>
|
||||
<span>🎯</span>
|
||||
<IconLibrary name="sparkles" :size="14" />
|
||||
<span>新建范式</span>
|
||||
</button>
|
||||
<div class="flex-1 flex gap-3">
|
||||
@@ -109,6 +113,7 @@
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { getParadigmList } from '../config/paradigms.js'
|
||||
import IconLibrary from './icons/IconLibrary.vue'
|
||||
|
||||
const props = defineProps({
|
||||
visible: Boolean
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
<!-- 头部 -->
|
||||
<header class="writer-header">
|
||||
<h1 class="writer-header-title">
|
||||
<span style="font-size: var(--text-xl)">📝</span> 范式分段写作
|
||||
<IconLibrary name="edit" :size="20" />
|
||||
<span>范式分段写作</span>
|
||||
</h1>
|
||||
<span class="badge badge-primary">新功能</span>
|
||||
</header>
|
||||
@@ -61,23 +62,25 @@
|
||||
<div v-if="currentSectionIndex === index" class="section-card-body mt-2 space-y-3">
|
||||
<!-- 输入类型选择 -->
|
||||
<div class="flex gap-2 mb-2">
|
||||
<button
|
||||
<button
|
||||
@click.stop="section.inputType = 'material'"
|
||||
:class="['input-type-btn', section.inputType === 'material' ? 'active' : '']"
|
||||
>
|
||||
📊 素材型
|
||||
<IconLibrary name="chart" :size="12" /> 素材型
|
||||
</button>
|
||||
<button
|
||||
<button
|
||||
@click.stop="section.inputType = 'idea'"
|
||||
:class="['input-type-btn', section.inputType === 'idea' || !section.inputType ? 'active' : '']"
|
||||
>
|
||||
💡 思路型
|
||||
<IconLibrary name="lightbulb" :size="12" /> 思路型
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 结构化输入:核心论点 -->
|
||||
<div>
|
||||
<label class="text-[10px] text-muted block mb-1">📌 核心论点(必填)</label>
|
||||
<label class="text-[10px] text-muted block mb-1 flex items-center gap-1">
|
||||
<IconLibrary name="pin" :size="10" /> 核心论点(必填)
|
||||
</label>
|
||||
<textarea
|
||||
v-model="section.corePoint"
|
||||
class="writer-textarea min-h-[50px]"
|
||||
@@ -88,8 +91,8 @@
|
||||
|
||||
<!-- 结构化输入:数据/案例 -->
|
||||
<div>
|
||||
<label class="text-[10px] text-muted block mb-1">
|
||||
📊 数据/案例
|
||||
<label class="text-[10px] text-muted block mb-1 flex items-center gap-1">
|
||||
<IconLibrary name="chart" :size="10" /> 数据/案例
|
||||
<span class="text-warning">({{ section.inputType === 'material' ? '严格引用' : '可润色' }})</span>
|
||||
</label>
|
||||
<textarea
|
||||
@@ -102,7 +105,9 @@
|
||||
|
||||
<!-- 结构化输入:补充说明 -->
|
||||
<div>
|
||||
<label class="text-[10px] text-muted block mb-1">💡 补充说明(可自由发挥)</label>
|
||||
<label class="text-[10px] text-muted block mb-1 flex items-center gap-1">
|
||||
<IconLibrary name="lightbulb" :size="10" /> 补充说明(可自由发挥)
|
||||
</label>
|
||||
<textarea
|
||||
v-model="section.supplementNote"
|
||||
class="writer-textarea min-h-[40px]"
|
||||
@@ -119,13 +124,13 @@
|
||||
>
|
||||
{{ section.isGenerating ? '正在生成...' : (section.generatedContent ? '重新生成本节' : '生成本节') }}
|
||||
</button>
|
||||
<button
|
||||
<button
|
||||
v-if="section.generatedContent"
|
||||
@click.stop="copySectionContent(section)"
|
||||
class="btn btn-secondary text-[10px] py-1.5"
|
||||
title="复制内容"
|
||||
>
|
||||
📋
|
||||
<IconLibrary name="clipboard" :size="12" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -135,7 +140,9 @@
|
||||
|
||||
<!-- 提示:未选择范式 -->
|
||||
<div v-else class="empty-state">
|
||||
<div class="empty-icon text-center">📂</div>
|
||||
<div class="empty-icon text-center">
|
||||
<IconLibrary name="folder" :size="32" />
|
||||
</div>
|
||||
<p class="text-sm text-muted text-center">请先选择一个写作范式以加载大纲</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -170,6 +177,7 @@
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useAppStore } from '../stores/app'
|
||||
import IconLibrary from './icons/IconLibrary.vue'
|
||||
import { getParadigmList } from '../config/paradigms.js'
|
||||
import { marked } from 'marked'
|
||||
import { Document, Packer, Paragraph, TextRun, HeadingLevel } from 'docx'
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<!-- 头部 -->
|
||||
<header class="p-4 border-b border-slate-700 flex items-center justify-between shrink-0">
|
||||
<h2 class="font-bold text-lg text-white flex items-center gap-2">
|
||||
<span class="text-2xl">🎯</span> 需求文档解析
|
||||
<IconLibrary name="sparkles" :size="20" /> 需求文档解析
|
||||
</h2>
|
||||
<button
|
||||
@click="$emit('close')"
|
||||
@@ -54,8 +54,8 @@
|
||||
></textarea>
|
||||
<div class="flex items-center justify-between mt-2 text-xs text-slate-500">
|
||||
<span>{{ requirementText.length }} 字符</span>
|
||||
<span v-if="requirementText.length > 10000" class="text-amber-500">
|
||||
⚠️ 文档过长可能影响解析质量,建议控制在10000字符以内
|
||||
<span v-if="requirementText.length > 10000" class="text-amber-500 flex items-center gap-1">
|
||||
<IconLibrary name="warning" :size="12" /> 文档过长可能影响解析质量,建议控制在10000字符以内
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -73,7 +73,7 @@
|
||||
@click="$refs.fileInput.click()"
|
||||
class="w-full p-6 border-2 border-dashed border-slate-700 rounded-lg hover:border-indigo-500 transition text-slate-400 hover:text-indigo-400 flex flex-col items-center gap-2"
|
||||
>
|
||||
<span class="text-3xl">📄</span>
|
||||
<IconLibrary name="document" :size="24" />
|
||||
<span class="text-sm">点击选择文件(支持 .txt, .md)</span>
|
||||
<span v-if="selectedFileName" class="text-xs text-indigo-400 mt-2">
|
||||
已选择:{{ selectedFileName }}
|
||||
@@ -246,7 +246,7 @@
|
||||
@click="saveParadigm"
|
||||
class="px-4 py-2 text-sm rounded bg-green-600 text-white hover:bg-green-500 transition flex items-center gap-2"
|
||||
>
|
||||
<span>✓</span>
|
||||
<IconLibrary name="check" :size="14" />
|
||||
<span>保存并使用</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -255,7 +255,9 @@
|
||||
<!-- 解析失败 -->
|
||||
<section v-if="step === 'error'" class="space-y-4">
|
||||
<div class="bg-red-900/20 border border-red-700 rounded-lg p-6 text-center">
|
||||
<span class="text-4xl block mb-3">⚠️</span>
|
||||
<div class="w-12 h-12 flex items-center justify-center mx-auto mb-3">
|
||||
<IconLibrary name="warning" :size="32" />
|
||||
</div>
|
||||
<p class="text-red-400 mb-2">解析失败</p>
|
||||
<p class="text-xs text-slate-500">{{ errorMessage }}</p>
|
||||
<button
|
||||
@@ -275,6 +277,7 @@
|
||||
import { ref } from 'vue'
|
||||
import { useParadigmStore } from '../stores/paradigm'
|
||||
import DeepSeekAPI from '../api/deepseek'
|
||||
import IconLibrary from './icons/IconLibrary.vue'
|
||||
import { config } from '../utils/config'
|
||||
import {
|
||||
buildRequirementParserPrompt,
|
||||
|
||||
@@ -43,8 +43,10 @@
|
||||
</div>
|
||||
<div class="status-row">
|
||||
<span class="status-label">API Key</span>
|
||||
<span :class="['status-value', currentProvider?.apiKey ? 'configured' : 'not-configured']">
|
||||
{{ currentProvider?.apiKey ? '✓ 已配置' : '✗ 未配置' }}
|
||||
<span :class="['status-value flex items-center gap-1', currentProvider?.apiKey ? 'configured' : 'not-configured']">
|
||||
<IconLibrary v-if="currentProvider?.apiKey" name="check" :size="12" />
|
||||
<IconLibrary v-else name="close" :size="12" />
|
||||
{{ currentProvider?.apiKey ? '已配置' : '未配置' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="status-row" v-if="currentProvider?.model">
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
<!-- 头部 -->
|
||||
<header class="writer-header">
|
||||
<h1 class="writer-header-title">
|
||||
<span style="font-size: var(--text-xl)">✍️</span> AI 写作工坊
|
||||
<IconLibrary name="edit" :size="20" />
|
||||
<span>AI 写作工坊</span>
|
||||
</h1>
|
||||
<span class="badge badge-default">Pro版</span>
|
||||
</header>
|
||||
@@ -63,7 +64,7 @@
|
||||
<div v-for="(ref, index) in references" :key="index" class="ref-card">
|
||||
<div class="ref-card-header">
|
||||
<div class="ref-card-title">
|
||||
<span style="font-size: var(--text-base)">📄</span>
|
||||
<IconLibrary name="document" :size="14" />
|
||||
<span class="ref-card-title-text">{{ ref.title }}</span>
|
||||
</div>
|
||||
<button @click="removeReference(index)" class="ref-remove-btn px-2">×</button>
|
||||
@@ -94,8 +95,9 @@
|
||||
<!-- 专家指令(范式预设时显示) -->
|
||||
<section v-if="activeParadigm" class="writer-section">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<label class="writer-label writer-label-alt">
|
||||
⭐ 专家指令 (Expert Guidelines)
|
||||
<label class="writer-label writer-label-alt flex items-center gap-1.5">
|
||||
<IconLibrary name="star" :size="14" />
|
||||
<span>专家指令 (Expert Guidelines)</span>
|
||||
</label>
|
||||
<button
|
||||
@click="clearParadigm"
|
||||
@@ -149,14 +151,15 @@
|
||||
<div class="deep-mode-toggle mt-4">
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-bold flex items-center gap-1" style="color: var(--accent-primary)">
|
||||
🧠 深度模式 (Deep Mode)
|
||||
<IconLibrary name="sparkles" :size="14" />
|
||||
深度模式 (Deep Mode)
|
||||
</span>
|
||||
<span class="text-[10px] text-muted">模拟人类"初稿-反思-润色"的思维链</span>
|
||||
</div>
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input type="checkbox" v-model="isDeepMode" class="hidden peer">
|
||||
<div style="width: 36px; height: 20px; background: var(--bg-elevated); border-radius: 9999px; position: relative; transition: all var(--transition-normal);" class="peer-checked:bg-indigo-600">
|
||||
<div style="width: 16px; height: 16px; background: white; border-radius: 50%; position: absolute; top: 2px; left: 2px; transition: all var(--transition-normal);" class="peer-checked:translate-x-4"></div>
|
||||
<input type="checkbox" v-model="isDeepMode" class="hidden">
|
||||
<div class="toggle-switch" :class="{'active': isDeepMode}">
|
||||
<div class="toggle-thumb" :class="{'active': isDeepMode}"></div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
@@ -193,6 +196,7 @@
|
||||
import { computed } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useAppStore } from '../stores/app'
|
||||
import IconLibrary from './icons/IconLibrary.vue'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const {
|
||||
|
||||
@@ -200,6 +200,32 @@ const icons = {
|
||||
'loading': {
|
||||
paths: ['M12 4V2A10 10 0 0 0 2 12h2a8 8 0 0 1 8-8z'],
|
||||
viewBox: '0 0 24 24'
|
||||
},
|
||||
|
||||
// 新增图标
|
||||
'star': {
|
||||
paths: ['M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z'],
|
||||
viewBox: '0 0 24 24'
|
||||
},
|
||||
'lightbulb': {
|
||||
paths: ['M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7z'],
|
||||
viewBox: '0 0 24 24'
|
||||
},
|
||||
'pin': {
|
||||
paths: ['M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z'],
|
||||
viewBox: '0 0 24 24'
|
||||
},
|
||||
'clipboard': {
|
||||
paths: ['M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z'],
|
||||
viewBox: '0 0 24 24'
|
||||
},
|
||||
'microphone': {
|
||||
paths: ['M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z'],
|
||||
viewBox: '0 0 24 24'
|
||||
},
|
||||
'bookmark': {
|
||||
paths: ['M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2z'],
|
||||
viewBox: '0 0 24 24'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ export const PARADIGMS = {
|
||||
'tech': {
|
||||
id: 'tech',
|
||||
name: '技术博客范式',
|
||||
icon: '💻',
|
||||
icon: 'document',
|
||||
description: '适用于技术分享、教程类文章',
|
||||
tags: ['问题引入', '解决方案', '代码示例', '总结'],
|
||||
tagClass: 'bg-blue-900/30 text-blue-300',
|
||||
@@ -63,7 +63,7 @@ export const PARADIGMS = {
|
||||
'business': {
|
||||
id: 'business',
|
||||
name: '商业分析范式',
|
||||
icon: '📊',
|
||||
icon: 'chart',
|
||||
description: '适用于行业分析、市场报告',
|
||||
tags: ['背景介绍', '数据支撑', '趋势分析', '建议'],
|
||||
tagClass: 'bg-green-900/30 text-green-300',
|
||||
@@ -107,7 +107,7 @@ export const PARADIGMS = {
|
||||
'marketing': {
|
||||
id: 'marketing',
|
||||
name: '产品文案范式',
|
||||
icon: '🚀',
|
||||
icon: 'sparkles',
|
||||
description: '适用于产品介绍、营销文案',
|
||||
tags: ['痛点切入', '价值主张', '功能亮点', '行动号召'],
|
||||
tagClass: 'bg-purple-900/30 text-purple-300',
|
||||
@@ -151,7 +151,7 @@ export const PARADIGMS = {
|
||||
'academic': {
|
||||
id: 'academic',
|
||||
name: '学术论文范式',
|
||||
icon: '📚',
|
||||
icon: 'folder',
|
||||
description: '适用于学术写作、研究报告',
|
||||
tags: ['摘要', '引言', '文献综述', '方法论', '结果'],
|
||||
tagClass: 'bg-orange-900/30 text-orange-300',
|
||||
@@ -195,7 +195,7 @@ export const PARADIGMS = {
|
||||
'gov-report': {
|
||||
id: 'gov-report',
|
||||
name: '政府工作报告',
|
||||
icon: '🏢',
|
||||
icon: 'article',
|
||||
description: '适用于政府工作总结、述职报告',
|
||||
tags: ['工作回顾', '成绩总结', '问题分析', '下步计划'],
|
||||
tagClass: 'bg-cyan-900/30 text-cyan-300',
|
||||
@@ -242,7 +242,7 @@ export const PARADIGMS = {
|
||||
'deputy-secretary-2025': {
|
||||
id: 'deputy-secretary-2025',
|
||||
name: '2025党委副书记对照检查',
|
||||
icon: '🎖️',
|
||||
icon: 'star',
|
||||
description: '适用于党委副书记2025年组织生活会个人对照检查,强调政治敏感性与深度剖析',
|
||||
tags: ['五个带头', '思想根源', '行为习惯', '典型案例'],
|
||||
tagClass: 'bg-indigo-900/30 text-indigo-300',
|
||||
|
||||
Reference in New Issue
Block a user