提交 769dfe68 authored 作者: 张伊明's avatar 张伊明

bug修复

上级 88a85d8a
流水线 #392 已通过 于阶段
in 1 分 42 秒
...@@ -16,7 +16,7 @@ export function getBillIndustry(params) { ...@@ -16,7 +16,7 @@ export function getBillIndustry(params) {
return request({ return request({
method: 'GET', method: 'GET',
url: `/api/BillOverview/billIndustry/${params.year}`, url: `/api/BillOverview/billIndustry/${params.year}`,
params: { status: params.status } params: { stageName: params.stageName }
}) })
} }
......
<template> <template>
<p class="p-regular-rereg"> <p class="p-regular-rereg">
<span class="text-regular" v-for="(segment, index) in processedText" :key="index"> <span class="text-regular" v-for="(segment, index) in processedText" :key="index">
<span v-if="segment.isEntity" @click="$emit('onEntityClick', segment.entity)" class="entity-link"> <span
v-if="segment.isEntity"
@click="$emit('onEntityClick', segment.entity)"
:class="['entity-link', { 'keyword-highlight': segment.isKeywordHit }]"
>
{{ segment.entity?.text_span }} {{ segment.entity?.text_span }}
<img :src="SearchIcon" :width="10" :height="10" alt="search" /> <img :src="SearchIcon" :width="10" :height="10" alt="search" />
</span> </span>
<span v-else> <span v-else>
{{ segment.text }} <span :class="{ 'keyword-highlight': segment.isKeywordHit }">{{ segment.text }}</span>
</span> </span>
</span> </span>
</p> </p>
...@@ -20,6 +24,7 @@ export interface ProcessedTextSegment { ...@@ -20,6 +24,7 @@ export interface ProcessedTextSegment {
text: string; text: string;
isEntity: boolean; isEntity: boolean;
entity?: TextEntity; entity?: TextEntity;
isKeywordHit?: boolean;
} }
const props = defineProps({ const props = defineProps({
text: { text: {
...@@ -29,15 +34,42 @@ const props = defineProps({ ...@@ -29,15 +34,42 @@ const props = defineProps({
entities: { entities: {
type: Array<TextEntity>, type: Array<TextEntity>,
default: () => [] default: () => []
},
highlight: {
type: String,
default: ""
} }
}); });
const emit = defineEmits(["onEntityClick"]); const emit = defineEmits(["onEntityClick"]);
// 处理后的文本段 // 处理后的文本段
const processedText = ref<ProcessedTextSegment[]>([]); const processedText = ref<ProcessedTextSegment[]>([]);
const normalizeKeyword = (value: unknown) => String(value ?? "").trim();
const getKeywordMatches = (text: string, keyword: string) => {
if (!keyword) return [{ text, isKeywordHit: false }];
const lowerText = text.toLowerCase();
const lowerKeyword = keyword.toLowerCase();
if (!lowerKeyword) return [{ text, isKeywordHit: false }];
const parts: Array<{ text: string; isKeywordHit: boolean }> = [];
let start = 0;
while (start < text.length) {
const index = lowerText.indexOf(lowerKeyword, start);
if (index === -1) {
parts.push({ text: text.slice(start), isKeywordHit: false });
break;
}
if (index > start) {
parts.push({ text: text.slice(start, index), isKeywordHit: false });
}
parts.push({ text: text.slice(index, index + keyword.length), isKeywordHit: true });
start = index + keyword.length;
}
return parts.filter(part => part.text);
};
// 处理文本,识别并替换实体 // 处理文本,识别并替换实体
const processText = () => { const processText = () => {
console.log("props.entities.length", props.entities.length);
if (!props.text || !props.entities) { if (!props.text || !props.entities) {
// console.log('props.text', props.entities.length) // console.log('props.text', props.entities.length)
processedText.value = [{ text: "", isEntity: false }]; processedText.value = [{ text: "", isEntity: false }];
...@@ -46,6 +78,7 @@ const processText = () => { ...@@ -46,6 +78,7 @@ const processText = () => {
const result = []; const result = [];
let currentPosition = 0; let currentPosition = 0;
const keyword = normalizeKeyword(props.highlight);
// 按实体文本长度排序,优先匹配长文本 // 按实体文本长度排序,优先匹配长文本
const sortedEntities = [...props.entities].sort((a, b) => b.text_span.length - a.text_span.length); const sortedEntities = [...props.entities].sort((a, b) => b.text_span.length - a.text_span.length);
...@@ -61,7 +94,8 @@ const processText = () => { ...@@ -61,7 +94,8 @@ const processText = () => {
// 如果当前位置是实体,添加到结果 // 如果当前位置是实体,添加到结果
result.push({ result.push({
isEntity: true, isEntity: true,
entity: { ...entity } entity: { ...entity },
isKeywordHit: keyword ? entityText.toLowerCase().includes(keyword.toLowerCase()) : false
}); });
currentPosition = endPosition; currentPosition = endPosition;
matched = true; matched = true;
...@@ -82,18 +116,26 @@ const processText = () => { ...@@ -82,18 +116,26 @@ const processText = () => {
if (nextEntityStart > currentPosition) { if (nextEntityStart > currentPosition) {
const plainText = props.text.substring(currentPosition, nextEntityStart); const plainText = props.text.substring(currentPosition, nextEntityStart);
result.push({ const parts = getKeywordMatches(plainText, keyword);
text: plainText, parts.forEach(part => {
isEntity: false result.push({
text: part.text,
isEntity: false,
isKeywordHit: part.isKeywordHit
});
}); });
currentPosition = nextEntityStart; currentPosition = nextEntityStart;
} else { } else {
// 没有更多实体,添加剩余文本 // 没有更多实体,添加剩余文本
const remainingText = props.text.substring(currentPosition); const remainingText = props.text.substring(currentPosition);
if (remainingText) { if (remainingText) {
result.push({ const parts = getKeywordMatches(remainingText, keyword);
text: remainingText, parts.forEach(part => {
isEntity: false result.push({
text: part.text,
isEntity: false,
isKeywordHit: part.isKeywordHit
});
}); });
} }
currentPosition = props.text.length; currentPosition = props.text.length;
...@@ -106,6 +148,7 @@ const processText = () => { ...@@ -106,6 +148,7 @@ const processText = () => {
// 监听文本和实体变化 // 监听文本和实体变化
watch(() => props.text, processText); watch(() => props.text, processText);
watch(() => props.entities, processText, { deep: true }); watch(() => props.entities, processText, { deep: true });
watch(() => props.highlight, processText);
// 初始化处理 // 初始化处理
onMounted(processText); onMounted(processText);
...@@ -113,6 +156,11 @@ onMounted(processText); ...@@ -113,6 +156,11 @@ onMounted(processText);
<style lang="scss" scoped> <style lang="scss" scoped>
@use "@/styles/common.scss"; @use "@/styles/common.scss";
.keyword-highlight {
background: rgba(255, 199, 0, 0.35);
border-radius: 2px;
}
.entity-link { .entity-link {
color: var(--color-primary-100); color: var(--color-primary-100);
&:hover { &:hover {
......
...@@ -1030,14 +1030,15 @@ const handleBox6 = async () => { ...@@ -1030,14 +1030,15 @@ const handleBox6 = async () => {
// 涉华领域分布 // 涉华领域分布
const box9ChartData = ref([]); const box9ChartData = ref([]);
const box9selectetedTime = ref("2025"); const box9selectetedTime = ref("2025");
// 立法状态下拉:提出法案、众议院通过、参议院通过、解决分歧、完成立法 // 立法状态下拉:提出法案、众议院通过、参议院通过、解决分歧、呈交总统、完成立法
// v-model 存储的是接口需要的 status 值 // v-model 存储的是接口需要的 status 值(直接作为接口参数)
const box9LegislativeStatus = ref("提案"); const box9LegislativeStatus = ref("提出法案");
const box9LegislativeStatusList = ref([ const box9LegislativeStatusList = ref([
{ label: "提出法案", value: "提案" }, { label: "提出法案", value: "提出法案" },
{ label: "众议院通过", value: "众议院通过" }, { label: "众议院通过", value: "众议院通过" },
{ label: "参议院通过", value: "参议院通过" }, { label: "参议院通过", value: "参议院通过" },
{ label: "解决分歧", value: "分歧已解决" }, { label: "解决分歧", value: "解决分歧" },
{ label: "呈交总统", value: "呈交总统" },
{ label: "完成立法", value: "完成立法" } { label: "完成立法", value: "完成立法" }
]); ]);
const box9YearList = ref([ const box9YearList = ref([
...@@ -1089,7 +1090,7 @@ const getBox9Data = async () => { ...@@ -1089,7 +1090,7 @@ const getBox9Data = async () => {
chartLoading.value = { ...chartLoading.value, box6: true }; chartLoading.value = { ...chartLoading.value, box6: true };
const params = { const params = {
year: box9selectetedTime.value, year: box9selectetedTime.value,
status: box9LegislativeStatus.value stageName: box9LegislativeStatus.value
}; };
try { try {
const res = await getBillIndustry(params); const res = await getBillIndustry(params);
...@@ -1126,16 +1127,9 @@ const handleBox9Data = async () => { ...@@ -1126,16 +1127,9 @@ const handleBox9Data = async () => {
const selectedIndex = box9LegislativeStatusList.value.findIndex( const selectedIndex = box9LegislativeStatusList.value.findIndex(
item => item.value === box9LegislativeStatus.value item => item.value === box9LegislativeStatus.value
); );
const arr = [ // 当前选中的立法状态中文名(直接等于接口传参值)
{ label: "提出法案", value: "提案" }, const statusItem = box9LegislativeStatusList.value[selectedIndex];
{ label: "众议院通过", value: "众议院通过" }, const status = statusItem ? statusItem.label : "";
{ label: "参议院通过", value: "参议院通过" },
{ label: "解决分歧", value: "分歧已解决" },
{ label: "完成立法", value: "完成立法" }
]
const status = arr.filter(item => {
return item.value === box9LegislativeStatus.value
})[0].label
const selectParam = { const selectParam = {
moduleType: '国会法案', moduleType: '国会法案',
key: 2, key: 2,
...@@ -1294,13 +1288,14 @@ const getBox8ChartOption = stageList => { ...@@ -1294,13 +1288,14 @@ const getBox8ChartOption = stageList => {
const handleBox8Data = async () => { const handleBox8Data = async () => {
chartLoading.value = { ...chartLoading.value, box8: true }; chartLoading.value = { ...chartLoading.value, box8: true };
// 进展分布显示顺序:提出法案(对应进度“提案”)、众议院通过、参议院通过、分歧已解决(解决分歧)、完成立法 // 进展分布显示顺序:提出法案(对应进度“提案”)、众议院通过、参议院通过、解决分歧(对应进度“分歧已解决”)、呈交总统、完成立法
const stageOrder = ["提案", "众议院通过", "参议院通过", "分歧已解决", "完成立法"]; const stageOrder = ["提案", "众议院通过", "参议院通过", "分歧已解决", "呈交总统", "完成立法"];
const stageNameMap = { const stageNameMap = {
提案: "提出法案", 提案: "提出法案",
众议院通过: "众议院通过", 众议院通过: "众议院通过",
参议院通过: "参议院通过", 参议院通过: "参议院通过",
分歧已解决: "解决分歧", 分歧已解决: "解决分歧",
呈交总统: "呈交总统",
完成立法: "完成立法" 完成立法: "完成立法"
}; };
......
...@@ -1169,6 +1169,10 @@ onMounted(async () => { ...@@ -1169,6 +1169,10 @@ onMounted(async () => {
<style lang="scss" scoped> <style lang="scss" scoped>
.wrap { .wrap {
display: flex; display: flex;
flex-direction: row;
flex-wrap: nowrap;
direction: ltr;
justify-content: flex-start;
margin-bottom: 30px; margin-bottom: 30px;
...@@ -1254,6 +1258,8 @@ onMounted(async () => { ...@@ -1254,6 +1258,8 @@ onMounted(async () => {
.left { .left {
margin-top: 16px; margin-top: 16px;
width: 792px;
flex: 0 0 792px;
.box1 { .box1 {
width: 792px; width: 792px;
...@@ -1651,6 +1657,7 @@ onMounted(async () => { ...@@ -1651,6 +1657,7 @@ onMounted(async () => {
margin-left: 16px; margin-left: 16px;
margin-top: 16px; margin-top: 16px;
width: 792px; width: 792px;
flex: 0 0 792px;
height: 847px; height: 847px;
.box3 { .box3 {
......
...@@ -131,6 +131,7 @@ ...@@ -131,6 +131,7 @@
<IntelligentEntityText <IntelligentEntityText
:text="term?.fynr || ''" :text="term?.fynr || ''"
:entities="termsHighlight ? getTermEntities(term, 'cn') : []" :entities="termsHighlight ? getTermEntities(term, 'cn') : []"
:highlight="searchKeyword"
@on-entity-click="e => gotoSearchResults(e.text_span, '')" @on-entity-click="e => gotoSearchResults(e.text_span, '')"
/> />
</div> </div>
...@@ -141,6 +142,7 @@ ...@@ -141,6 +142,7 @@
<IntelligentEntityText <IntelligentEntityText
:text="term?.ywnr || ''" :text="term?.ywnr || ''"
:entities="termsHighlight ? getTermEntities(term, 'en') : []" :entities="termsHighlight ? getTermEntities(term, 'en') : []"
:highlight="searchKeyword"
@on-entity-click="e => gotoSearchResults(e.text_span, '')" @on-entity-click="e => gotoSearchResults(e.text_span, '')"
/> />
</div> </div>
......
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论