Spaces:
Sleeping
Sleeping
Enhance Step4Report component with individual selection reason parsing and display
Browse files- Introduced a new function to parse individual selection reasons from interview text, accommodating multiple formats for better accuracy.
- Updated the interview object to include a selection reason property, ensuring each interview displays the corresponding rationale.
- Enhanced the InterviewDisplay component to render selection reasons with improved styling for better visibility and user experience.
frontend/src/components/Step4Report.vue
CHANGED
|
@@ -661,6 +661,72 @@ const parseInterview = (text) => {
|
|
| 661 |
result.selectionReason = reasonMatch[1].trim()
|
| 662 |
}
|
| 663 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 664 |
// 提取每个采访记录
|
| 665 |
const interviewBlocks = text.split(/#### 采访 #\d+:/).slice(1)
|
| 666 |
|
|
@@ -671,6 +737,7 @@ const parseInterview = (text) => {
|
|
| 671 |
name: '',
|
| 672 |
role: '',
|
| 673 |
bio: '',
|
|
|
|
| 674 |
questions: [],
|
| 675 |
twitterAnswer: '',
|
| 676 |
redditAnswer: '',
|
|
@@ -686,6 +753,8 @@ const parseInterview = (text) => {
|
|
| 686 |
if (nameRoleMatch) {
|
| 687 |
interview.name = nameRoleMatch[1].trim()
|
| 688 |
interview.role = nameRoleMatch[2].trim()
|
|
|
|
|
|
|
| 689 |
}
|
| 690 |
|
| 691 |
// 提取简介
|
|
@@ -1079,6 +1148,12 @@ const InterviewDisplay = {
|
|
| 1079 |
])
|
| 1080 |
]),
|
| 1081 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1082 |
// Q&A Conversation Thread - 一问一答样式
|
| 1083 |
h('div', { class: 'qa-thread' },
|
| 1084 |
(props.result.interviews[activeIndex.value]?.questions?.length > 0
|
|
@@ -3368,6 +3443,30 @@ watch(() => props.reportId, (newId) => {
|
|
| 3368 |
overflow: hidden;
|
| 3369 |
}
|
| 3370 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3371 |
/* Q&A Thread - Clean list */
|
| 3372 |
:deep(.interview-display .qa-thread) {
|
| 3373 |
display: flex;
|
|
|
|
| 661 |
result.selectionReason = reasonMatch[1].trim()
|
| 662 |
}
|
| 663 |
|
| 664 |
+
// 解析每个人的选择理由
|
| 665 |
+
const parseIndividualReasons = (reasonText) => {
|
| 666 |
+
const reasons = {}
|
| 667 |
+
if (!reasonText) return reasons
|
| 668 |
+
|
| 669 |
+
const lines = reasonText.split(/\n+/)
|
| 670 |
+
let currentName = null
|
| 671 |
+
let currentReason = []
|
| 672 |
+
|
| 673 |
+
for (const line of lines) {
|
| 674 |
+
let headerMatch = null
|
| 675 |
+
let name = null
|
| 676 |
+
let reasonStart = null
|
| 677 |
+
|
| 678 |
+
// 格式1: 数字. **名字(index=X)**:理由
|
| 679 |
+
// 例如: 1. **校友_345(index=1)**:作为武大校友...
|
| 680 |
+
headerMatch = line.match(/^\d+\.\s*\*\*([^*((]+)(?:[((]index\s*=?\s*\d+[))])?\*\*[::]\s*(.*)/)
|
| 681 |
+
if (headerMatch) {
|
| 682 |
+
name = headerMatch[1].trim()
|
| 683 |
+
reasonStart = headerMatch[2]
|
| 684 |
+
}
|
| 685 |
+
|
| 686 |
+
// 格式2: - 选择名字(index X):理由
|
| 687 |
+
// 例如: - 选择家长_601(index 0):作为家长群体代表...
|
| 688 |
+
if (!headerMatch) {
|
| 689 |
+
headerMatch = line.match(/^-\s*选择([^((]+)(?:[((]index\s*=?\s*\d+[))])?[::]\s*(.*)/)
|
| 690 |
+
if (headerMatch) {
|
| 691 |
+
name = headerMatch[1].trim()
|
| 692 |
+
reasonStart = headerMatch[2]
|
| 693 |
+
}
|
| 694 |
+
}
|
| 695 |
+
|
| 696 |
+
// 格式3: - **名字(index X)**:理由
|
| 697 |
+
// 例如: - **家长_601(index 0)**:作为家长群体代表...
|
| 698 |
+
if (!headerMatch) {
|
| 699 |
+
headerMatch = line.match(/^-\s*\*\*([^*((]+)(?:[((]index\s*=?\s*\d+[))])?\*\*[::]\s*(.*)/)
|
| 700 |
+
if (headerMatch) {
|
| 701 |
+
name = headerMatch[1].trim()
|
| 702 |
+
reasonStart = headerMatch[2]
|
| 703 |
+
}
|
| 704 |
+
}
|
| 705 |
+
|
| 706 |
+
if (name) {
|
| 707 |
+
// 保存上一个人的理由
|
| 708 |
+
if (currentName && currentReason.length > 0) {
|
| 709 |
+
reasons[currentName] = currentReason.join(' ').trim()
|
| 710 |
+
}
|
| 711 |
+
// 开始新的人
|
| 712 |
+
currentName = name
|
| 713 |
+
currentReason = reasonStart ? [reasonStart.trim()] : []
|
| 714 |
+
} else if (currentName && line.trim() && !line.match(/^未选|^综上|^最终选择/)) {
|
| 715 |
+
// 理由的续行(排除结尾总结段落)
|
| 716 |
+
currentReason.push(line.trim())
|
| 717 |
+
}
|
| 718 |
+
}
|
| 719 |
+
|
| 720 |
+
// 保存最后一个人的理由
|
| 721 |
+
if (currentName && currentReason.length > 0) {
|
| 722 |
+
reasons[currentName] = currentReason.join(' ').trim()
|
| 723 |
+
}
|
| 724 |
+
|
| 725 |
+
return reasons
|
| 726 |
+
}
|
| 727 |
+
|
| 728 |
+
const individualReasons = parseIndividualReasons(result.selectionReason)
|
| 729 |
+
|
| 730 |
// 提取每个采访记录
|
| 731 |
const interviewBlocks = text.split(/#### 采访 #\d+:/).slice(1)
|
| 732 |
|
|
|
|
| 737 |
name: '',
|
| 738 |
role: '',
|
| 739 |
bio: '',
|
| 740 |
+
selectionReason: '',
|
| 741 |
questions: [],
|
| 742 |
twitterAnswer: '',
|
| 743 |
redditAnswer: '',
|
|
|
|
| 753 |
if (nameRoleMatch) {
|
| 754 |
interview.name = nameRoleMatch[1].trim()
|
| 755 |
interview.role = nameRoleMatch[2].trim()
|
| 756 |
+
// 设置该人的选择理由
|
| 757 |
+
interview.selectionReason = individualReasons[interview.name] || ''
|
| 758 |
}
|
| 759 |
|
| 760 |
// 提取简介
|
|
|
|
| 1148 |
])
|
| 1149 |
]),
|
| 1150 |
|
| 1151 |
+
// Selection Reason - 选择理由
|
| 1152 |
+
props.result.interviews[activeIndex.value]?.selectionReason && h('div', { class: 'selection-reason' }, [
|
| 1153 |
+
h('div', { class: 'reason-label' }, '选择理由'),
|
| 1154 |
+
h('div', { class: 'reason-content' }, props.result.interviews[activeIndex.value].selectionReason)
|
| 1155 |
+
]),
|
| 1156 |
+
|
| 1157 |
// Q&A Conversation Thread - 一问一答样式
|
| 1158 |
h('div', { class: 'qa-thread' },
|
| 1159 |
(props.result.interviews[activeIndex.value]?.questions?.length > 0
|
|
|
|
| 3443 |
overflow: hidden;
|
| 3444 |
}
|
| 3445 |
|
| 3446 |
+
/* Selection Reason - 选择理由 */
|
| 3447 |
+
:deep(.interview-display .selection-reason) {
|
| 3448 |
+
background: #F8FAFC;
|
| 3449 |
+
border: 1px solid #E2E8F0;
|
| 3450 |
+
border-radius: 8px;
|
| 3451 |
+
padding: 12px 14px;
|
| 3452 |
+
margin-bottom: 16px;
|
| 3453 |
+
}
|
| 3454 |
+
|
| 3455 |
+
:deep(.interview-display .reason-label) {
|
| 3456 |
+
font-size: 11px;
|
| 3457 |
+
font-weight: 600;
|
| 3458 |
+
color: #64748B;
|
| 3459 |
+
text-transform: uppercase;
|
| 3460 |
+
letter-spacing: 0.03em;
|
| 3461 |
+
margin-bottom: 6px;
|
| 3462 |
+
}
|
| 3463 |
+
|
| 3464 |
+
:deep(.interview-display .reason-content) {
|
| 3465 |
+
font-size: 12px;
|
| 3466 |
+
color: #475569;
|
| 3467 |
+
line-height: 1.6;
|
| 3468 |
+
}
|
| 3469 |
+
|
| 3470 |
/* Q&A Thread - Clean list */
|
| 3471 |
:deep(.interview-display .qa-thread) {
|
| 3472 |
display: flex;
|