fix: 修复对照检查页面多项问题
1. 修复「导入范式要求」按钮不显示 - activeParadigm 是对象而非 ID 2. 左右两侧支持多选段落 - 点击切换选中状态 3. 中间指示器显示选中段落数量 4. 多选段落合并后一起发送给 AI 分析
This commit is contained in:
@@ -55,13 +55,16 @@
|
|||||||
@click="selectLeftParagraph(idx)"
|
@click="selectLeftParagraph(idx)"
|
||||||
:class="[
|
:class="[
|
||||||
'p-3 rounded-lg border cursor-pointer transition-all',
|
'p-3 rounded-lg border cursor-pointer transition-all',
|
||||||
selectedLeftIdx === idx
|
selectedLeftIdxs.includes(idx)
|
||||||
? 'bg-amber-900/30 border-amber-500 ring-2 ring-amber-500/30'
|
? 'bg-amber-900/30 border-amber-500 ring-2 ring-amber-500/30'
|
||||||
: 'bg-slate-800/50 border-slate-700 hover:border-amber-500/50'
|
: 'bg-slate-800/50 border-slate-700 hover:border-amber-500/50'
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<div class="flex items-start gap-2">
|
<div class="flex items-start gap-2">
|
||||||
<span class="text-xs text-amber-500/70 shrink-0 mt-0.5">{{ idx + 1 }}.</span>
|
<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>
|
||||||
<p class="text-sm text-slate-300 whitespace-pre-wrap">{{ para }}</p>
|
<p class="text-sm text-slate-300 whitespace-pre-wrap">{{ para }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -76,16 +79,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 中间:对应关系指示器 -->
|
<!-- 中间:对应关系指示器 -->
|
||||||
<div class="w-16 flex flex-col items-center justify-center bg-slate-800/50 shrink-0">
|
<div class="w-20 flex flex-col items-center justify-center bg-slate-800/50 shrink-0">
|
||||||
<div v-if="selectedLeftIdx !== null && selectedRightIdx !== null" class="flex flex-col items-center gap-2">
|
<div v-if="selectedLeftIdxs.length > 0 && selectedRightIdxs.length > 0" class="flex flex-col items-center gap-2">
|
||||||
|
<div class="text-xs text-amber-400 font-medium">{{ selectedLeftIdxs.length }} 段</div>
|
||||||
<div class="w-3 h-3 rounded-full bg-amber-500"></div>
|
<div class="w-3 h-3 rounded-full bg-amber-500"></div>
|
||||||
<div class="w-0.5 h-8 bg-gradient-to-b from-amber-500 to-blue-500"></div>
|
<div class="w-0.5 h-6 bg-gradient-to-b from-amber-500 to-blue-500"></div>
|
||||||
<span class="text-xs text-slate-500 writing-mode-vertical">对应</span>
|
<span class="text-xs text-slate-400 px-1 py-0.5 bg-slate-700 rounded">对照</span>
|
||||||
<div class="w-0.5 h-8 bg-gradient-to-b from-blue-500 to-blue-500"></div>
|
<div class="w-0.5 h-6 bg-gradient-to-b from-blue-500 to-blue-500"></div>
|
||||||
<div class="w-3 h-3 rounded-full bg-blue-500"></div>
|
<div class="w-3 h-3 rounded-full bg-blue-500"></div>
|
||||||
|
<div class="text-xs text-blue-400 font-medium">{{ selectedRightIdxs.length }} 段</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="text-center px-2">
|
<div v-else class="text-center px-2">
|
||||||
<span class="text-xs text-slate-600">请选中<br/>两侧段落</span>
|
<span class="text-xs text-slate-600">点击选中<br/>多个段落</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -110,13 +115,16 @@
|
|||||||
@click="selectRightParagraph(idx)"
|
@click="selectRightParagraph(idx)"
|
||||||
:class="[
|
:class="[
|
||||||
'p-3 rounded-lg border cursor-pointer transition-all',
|
'p-3 rounded-lg border cursor-pointer transition-all',
|
||||||
selectedRightIdx === idx
|
selectedRightIdxs.includes(idx)
|
||||||
? 'bg-blue-900/30 border-blue-500 ring-2 ring-blue-500/30'
|
? 'bg-blue-900/30 border-blue-500 ring-2 ring-blue-500/30'
|
||||||
: 'bg-slate-800/50 border-slate-700 hover:border-blue-500/50'
|
: 'bg-slate-800/50 border-slate-700 hover:border-blue-500/50'
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<div class="flex items-start gap-2">
|
<div class="flex items-start gap-2">
|
||||||
<span class="text-xs text-blue-500/70 shrink-0 mt-0.5">{{ idx + 1 }}.</span>
|
<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>
|
||||||
<p class="text-sm text-slate-300 whitespace-pre-wrap">{{ para }}</p>
|
<p class="text-sm text-slate-300 whitespace-pre-wrap">{{ para }}</p>
|
||||||
</div>
|
</div>
|
||||||
<!-- 检查结果标记 -->
|
<!-- 检查结果标记 -->
|
||||||
@@ -202,7 +210,6 @@
|
|||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { useAppStore } from '../stores/app'
|
import { useAppStore } from '../stores/app'
|
||||||
import { PARADIGMS } from '../config/paradigms'
|
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const { activeParadigm } = storeToRefs(appStore)
|
const { activeParadigm } = storeToRefs(appStore)
|
||||||
@@ -211,32 +218,28 @@ const { activeParadigm } = storeToRefs(appStore)
|
|||||||
const leftContent = ref('')
|
const leftContent = ref('')
|
||||||
const rightContent = ref('')
|
const rightContent = ref('')
|
||||||
|
|
||||||
// 选中状态
|
// 选中状态(改为数组支持多选)
|
||||||
const selectedLeftIdx = ref(null)
|
const selectedLeftIdxs = ref([])
|
||||||
const selectedRightIdx = ref(null)
|
const selectedRightIdxs = ref([])
|
||||||
|
|
||||||
// 检查状态
|
// 检查状态
|
||||||
const isComparing = ref(false)
|
const isComparing = ref(false)
|
||||||
const lastCheckResult = ref(null)
|
const lastCheckResult = ref(null)
|
||||||
const checkResults = ref({})
|
const checkResults = ref({})
|
||||||
|
|
||||||
// 范式相关
|
// 范式相关(activeParadigm 是对象,不是 ID)
|
||||||
const hasParadigmRules = computed(() => {
|
const hasParadigmRules = computed(() => {
|
||||||
if (!activeParadigm.value) return false
|
const p = activeParadigm.value
|
||||||
const paradigm = PARADIGMS[activeParadigm.value]
|
return p && (p.expertGuidelines || p.systemConstraints || p.validationRules)
|
||||||
return paradigm && (paradigm.expertGuidelines || paradigm.systemConstraints)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const activeParadigmName = computed(() => {
|
const activeParadigmName = computed(() => {
|
||||||
if (!activeParadigm.value) return ''
|
return activeParadigm.value?.name || ''
|
||||||
const paradigm = PARADIGMS[activeParadigm.value]
|
|
||||||
return paradigm?.name || ''
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 导入范式写作要求
|
// 导入范式写作要求
|
||||||
const importParadigmRules = () => {
|
const importParadigmRules = () => {
|
||||||
if (!activeParadigm.value) return
|
const paradigm = activeParadigm.value
|
||||||
const paradigm = PARADIGMS[activeParadigm.value]
|
|
||||||
if (!paradigm) return
|
if (!paradigm) return
|
||||||
|
|
||||||
const rules = []
|
const rules = []
|
||||||
@@ -282,24 +285,49 @@ const rightParagraphs = computed(() => {
|
|||||||
.filter(p => p.length > 0)
|
.filter(p => p.length > 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 是否可以检查
|
// 是否可以检查(两侧都至少选中一段)
|
||||||
const canCompare = computed(() => {
|
const canCompare = computed(() => {
|
||||||
return selectedLeftIdx.value !== null && selectedRightIdx.value !== null
|
return selectedLeftIdxs.value.length > 0 && selectedRightIdxs.value.length > 0
|
||||||
})
|
})
|
||||||
|
|
||||||
// 选择段落
|
// 选择段落(多选切换)
|
||||||
const selectLeftParagraph = (idx) => {
|
const selectLeftParagraph = (idx) => {
|
||||||
selectedLeftIdx.value = selectedLeftIdx.value === idx ? null : idx
|
const i = selectedLeftIdxs.value.indexOf(idx)
|
||||||
|
if (i === -1) {
|
||||||
|
selectedLeftIdxs.value.push(idx)
|
||||||
|
} else {
|
||||||
|
selectedLeftIdxs.value.splice(i, 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectRightParagraph = (idx) => {
|
const selectRightParagraph = (idx) => {
|
||||||
selectedRightIdx.value = selectedRightIdx.value === idx ? null : idx
|
const i = selectedRightIdxs.value.indexOf(idx)
|
||||||
|
if (i === -1) {
|
||||||
|
selectedRightIdxs.value.push(idx)
|
||||||
|
} else {
|
||||||
|
selectedRightIdxs.value.splice(i, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取选中的段落文本(多选合并)
|
||||||
|
const getSelectedLeftText = () => {
|
||||||
|
return selectedLeftIdxs.value
|
||||||
|
.sort((a, b) => a - b)
|
||||||
|
.map(i => leftParagraphs.value[i])
|
||||||
|
.join('\n\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSelectedRightText = () => {
|
||||||
|
return selectedRightIdxs.value
|
||||||
|
.sort((a, b) => a - b)
|
||||||
|
.map(i => rightParagraphs.value[i])
|
||||||
|
.join('\n\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清除选择
|
// 清除选择
|
||||||
const clearSelection = () => {
|
const clearSelection = () => {
|
||||||
selectedLeftIdx.value = null
|
selectedLeftIdxs.value = []
|
||||||
selectedRightIdx.value = null
|
selectedRightIdxs.value = []
|
||||||
lastCheckResult.value = null
|
lastCheckResult.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,8 +340,8 @@ const goBack = () => {
|
|||||||
const runCompare = async () => {
|
const runCompare = async () => {
|
||||||
if (!canCompare.value) return
|
if (!canCompare.value) return
|
||||||
|
|
||||||
const requirement = leftParagraphs.value[selectedLeftIdx.value]
|
const requirement = getSelectedLeftText()
|
||||||
const content = rightParagraphs.value[selectedRightIdx.value]
|
const content = getSelectedRightText()
|
||||||
|
|
||||||
isComparing.value = true
|
isComparing.value = true
|
||||||
lastCheckResult.value = null
|
lastCheckResult.value = null
|
||||||
@@ -321,10 +349,10 @@ const runCompare = async () => {
|
|||||||
try {
|
try {
|
||||||
const prompt = `你是一个严格的写作质检专家。请对比以下"写作要求"和"写作内容",判断内容是否符合要求。
|
const prompt = `你是一个严格的写作质检专家。请对比以下"写作要求"和"写作内容",判断内容是否符合要求。
|
||||||
|
|
||||||
# 写作要求
|
# 写作要求(共 ${selectedLeftIdxs.value.length} 段)
|
||||||
${requirement}
|
${requirement}
|
||||||
|
|
||||||
# 写作内容
|
# 写作内容(共 ${selectedRightIdxs.value.length} 段)
|
||||||
${content}
|
${content}
|
||||||
|
|
||||||
# 输出要求
|
# 输出要求
|
||||||
|
|||||||
Reference in New Issue
Block a user