提交 8980f929 authored 作者: 张烨's avatar 张烨

Merge branch 'master' into zy-dev

......@@ -83,6 +83,15 @@ export function getThinkTankReport(params) {
})
}
// 智库概览:政策建议(资源库-政策建议)
export function getThinkTankOverviewPolicy(params) {
return request({
method: 'GET',
url: `/api/thinkTankOverview/policy`,
params
})
}
/********* 智库信息 */
//智库百科:获取全局信息
export function getThinkTankSummary(params) {
......@@ -119,6 +128,13 @@ export function getThinkPolicyIndustry(params) {
url: `/api/thinkTankInfo/policyIndustry/${params.id}/${params.year}`,
})
}
//提出政策建议涉及部门分布
export function getPolicyAdviceDeptDistribution(params){
return request({
method: 'GET',
url: `/api/thinkTankInfo/policyDepartment/${params.id}/${params.year}`,
})
}
//获取相关政策领域分布
export function getThinkPolicyIndustryTotal(params) {
......@@ -201,6 +217,15 @@ export const getThinkTankReportSummary = (params) => {
}
);
}
//智库报告:获取相关报告
export const getThinkTankReportRelated = (params) => {
return request(
{
method: 'GET',
url: `/api/thinkTankReport/related/${params}`,
}
);
}
//获取报告原文
export const getThinkTankReportcontentUrl = (params) => {
......@@ -233,6 +258,21 @@ export function getThinkTankReportContent(params) {
})
}
// 获取报告核心论点(支持关键字搜索)
export function getThinkTankReportViewpoint(params) {
const { reportId, currentPage, pageSize, keyword = '', orgIds = '' } = params
return request({
method: 'GET',
url: `/api/thinkTankReport/viewpoint/${reportId}`,
params: {
currentPage,
pageSize,
keyword,
orgIds,
}
})
}
//获取涉及科技领域
export function getThinkTankReportIndustry(params) {
return request({
......
export const TAGTYPE = ["primary", "success", "warning", "danger", "info"];
// 双色图表
export const DOUBLECHARTCOLORS = [
'#055FC2',
'#CE4F51'
]
// 多色图表预设颜色列表 20种
export const MUTICHARTCOLORS = [
"#69B1FF",
"#FF7875",
"#B37FEB",
"#FFC069",
"#1677FF",
"#87E8DE",
"#ADC6FF",
"#FFBB96",
"#BAE0FF",
"#FFD591",
"#6691FF",
"#FFB2AF",
"#81D0FF",
"#D8E5FB",
"#7981F1",
"#FF9696",
"#6678A1",
"#273C57",
"#E8B8FF",
"#DF812E"
];
......@@ -41,6 +41,7 @@ const classObject = computed(() => ({
height: 24px;
padding: 0 8px;
line-height: 24px;
width: fit-content;
text-align: center;
font-family: Microsoft YaHei;
font-style: Regular;
......
<template>
<div class="wordcloud-wrapper" :style="{ width: width ? width : '520px', height: height ? height : '400px' }">
<div class="chart-box" id="wordcloud-chart">
</div>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
import setChart from '@/utils/setChart';
import getWordCloudChart from './wordCloudChart';
const props = defineProps(({
width: {
type: String,
default: ''
},
height: {
type: String,
default: ''
},
data: {
type: Array,
default: [
// { name: "与马斯克公开冲突", value: 100 },
// { name: "传统能源", value: 5 },
// { name: "共和党财政鹰派", value: 77 },
// { name: "未实现赤字控制目标", value: 35 },
// { name: "得克萨斯州", value: 88 },
// { name: "选举压力", value: 57 },
// { name: "主张财政紧缩", value: 72 },
// { name: "财政保守", value: 18 },
]
}
}))
onMounted(() => {
let chart = getWordCloudChart(props.data);
setChart(chart, "wordcloud-chart");
})
</script>
<style lang="scss">
.chart-box {
width: 100%;
height: 100%;
}
</style>
\ No newline at end of file
import 'echarts-wordcloud';
import { MUTICHARTCOLORS } from '@/common/constant';
const getWordCloudChart = (data) => {
const option = {
grid: {
left: 5,
top: 5,
right: 5,
bottom: 5,
},
series: [
{
type: "wordCloud",
shape: 'circle',
width: '100%',
height: '100%',
// 其他形状你可以使用形状路径
// shape: 'circle', // 示例
// 或者自定义路径
gridSize: 15, // 网格大小,影响词间距。
sizeRange: [16, 36], // 定义词云中文字大小的范围
rotationRange: [0, 0],
rotationStep: 0,
drawOutOfBound: false, // 是否超出画布
shrinkToFit: true, // 是否自动缩小以适应容器
// 字体
textStyle: {
// normal: {
// color: function () {
// return 'rgb(' + [
// Math.round(Math.random() * 160),
// Math.round(Math.random() * 160),
// Math.round(Math.random() * 160)
// ].join(',') + ')';
// }
// },
color: function () {
// let colors = [
// "rgba(189, 33, 33, 1)",
// "rgba(232, 151, 21, 1)",
// "rgba(220, 190, 68, 1)",
// "rgba(96, 58, 186, 1)",
// "rgba(32, 121, 69, 1)",
// "rgba(22, 119, 255, 1)",
// ];
// let colors = MUTICHARTCOLORS
return MUTICHARTCOLORS[parseInt(Math.random() * MUTICHARTCOLORS.length)];
},
emphasis: {
shadowBlur: 5,
shadowColor: "#333",
},
},
// 设置词云数据
data: data,
},
],
};
return option
}
export default getWordCloudChart
\ No newline at end of file
......@@ -323,10 +323,12 @@ onMounted(() => {
.nav-right {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 21px;
.info-box {
height: 40px;
display: flex;
justify-content: flex-end;
align-items: center;
......
<template>
<el-space alignment="flex-start" :size="10">
<img :width="64" :height="52" :src="news ?? DefaultIconNews" alt="" />
<el-space direction="vertical" alignment="flex-start" :size="0">
<common-text :line-limit="1" class="text-regular text-hover" color="var(--text-primary-80-color)">
{{ title }}
</common-text>
<common-text :line-limit="1" class="text-tip-1" color="var(--text-primary-65-color)">
{{ from }}
<img :width="97" :height="72" :src="img ?? DefaultIconNews" alt="" />
<el-space direction="vertical" alignment="flex-start" :size="0" fill>
<div class="full-width flex-display">
<common-text :line-limit="1" class="text-title-3-bold text-hover flex-fill"
color="var(--text-primary-80-color)">
{{ title }}
</common-text>
<common-text class="text-tip-2" color="var(--text-primary-65-color)">
{{ from }}
</common-text>
</div>
<common-text :line-limit="contentLineLimit" class="text-compact" color="var(--text-primary-65-color)">
{{ content }}
</common-text>
</el-space>
</el-space>
......@@ -20,7 +26,7 @@ import CommonText from "../texts/CommonText.vue";
const props = defineProps({
img: {
type: String,
default: ''
default: null,
},
title: {
type: String,
......@@ -34,14 +40,13 @@ const props = defineProps({
type: String,
default: ""
},
contentLineLimit: {
type: Number,
default: 2
}
});
const emit = defineEmits(['item-click', 'more-click']);
const handleToNewsAnalysis = (item, index) => {
emit('item-click', item, index)
};
</script>
<style lang="scss" scoped>
@use '@/styles/common.scss';
@use '@/styles/container.scss';
</style>
\ No newline at end of file
<template>
<el-space alignment="flex-start" :size="10">
<img :width="64" :height="52" :src="img ?? DefaultIconNews" alt="" />
<el-space direction="vertical" alignment="flex-start" :size="0">
<common-text :line-limit="1" class="text-regular text-hover" color="var(--text-primary-80-color)">
{{ title }}
</common-text>
<common-text :line-limit="1" class="text-tip-1" color="var(--text-primary-65-color)">
{{ from }}
</common-text>
</el-space>
</el-space>
</template>
<script setup>
import DefaultIconNews from "@/assets/icons/default-icon-news.png";
import { ElSpace } from "element-plus";
import CommonText from "../texts/CommonText.vue";
const props = defineProps({
img: {
type: String,
default: null
},
title: {
type: String,
default: ""
},
from: {
type: String,
default: ""
}
});
</script>
<style lang="scss" scoped>
@use '@/styles/common.scss';
</style>
\ No newline at end of file
<template>
<div class="news-item">
<el-space direction="vertical" class="flex-fill" alignment='flex-start'>
<common-text :lineLimit="1" class="text-bold" color="var(--text-primary-80-color)">{{
<common-text :lineLimit="1" class="text-bold text-hover" color="var(--text-primary-80-color)">{{
props.title
}}</common-text>
<common-text class="text-tip-2" color="var(--text-primary-65-color)">
......@@ -11,8 +11,7 @@
<area-tag v-for="(tag, index) in props.aeraTags" :key="index" :tagName="tag" />
</el-space>
</el-space>
<img style="width: 122px; height: 82px" :src="props.img">
<!-- <img v-else style="width: 122px; height: 82px" :src="DefaultIconNews"> -->
<img style="width: 122px; height: 82px" :src="props.img ? props.img : DefaultIconNews">
</div>
</template>
......@@ -27,7 +26,7 @@ const props = defineProps({
img: {
type: String,
default: 'img'
default: null
},
title: {
type: String,
......
......@@ -80,6 +80,7 @@ const handleToNewsAnalysis = (item, index) => {
flex-direction: column;
gap: 0 !important;
overflow: hidden;
border: 1px solid rgba(234, 236, 238, 1) !important;
.news-header {
height: 48px !important;
......@@ -149,6 +150,7 @@ const handleToNewsAnalysis = (item, index) => {
&:hover {
background: var(--color-bg-hover);
.right-top .title {
text-decoration: underline;
color: rgb(5, 95, 194) !important;
......
......@@ -12,6 +12,7 @@
.left-btn-wrapper {
width: 24px;
height: 48px;
cursor: pointer
img {
width: 100%;
......
......@@ -12,7 +12,7 @@
.right-btn-wrapper {
width: 24px;
height: 48px;
cursor: pointer
img {
width: 100%;
height: 100%;
......
......@@ -26,8 +26,8 @@ const props = defineProps({
text: {
type: String,
default: ''
}
, entities: {
},
entities: {
type: Array<TextEntity>,
default: () => []
}
......@@ -37,8 +37,9 @@ const props = defineProps({
const processedText = ref<ProcessedTextSegment[]>([])
// 处理文本,识别并替换实体
const processText = () => {
console.log('props.entities.length', props.entities.length)
if (!props.text || !props.entities) {
console.log('props.text', props.entities.length)
// console.log('props.text', props.entities.length)
processedText.value = [{ text: '', isEntity: false }]
return
}
......@@ -120,5 +121,6 @@ onMounted(processText)
.p-regular-rereg {
text-indent: 2em;
margin: 4px 0;
}
</style>
\ No newline at end of file
<template>
<div class="full-width">
<div class="flex-display" style="align-items: center;">
<common-text class="text-title-3-bold" color="var(--text-primary-80-color)">{{ isOpenTranslation
? '中文' : '原文' }}</common-text>
<div class="flex-fill" style="margin: 0 10px;">
<el-divider></el-divider>
</div>
<el-button v-if="showMoreVisible" @click="() => { showMore = !showMore; updateText() }">
{{ showMore ? '收起' : '展开' }}
<el-icon>
<arrow-up v-if="showMore" />
<arrow-down v-else />
</el-icon>
</el-button>
</div>
<el-row :gutter="32">
<el-col :span="textColSpan" v-for="(item, index) in allTexts" :key="index">
<!-- <p class="p-news-content"> {{ item }}</p> -->
<intelligent-entity-text :text="item"
:entities="isHighlightEntity ? textEntities : []"></intelligent-entity-text>
</el-col>
</el-row>
</div>
</template>
<script lang="ts" setup>
import '@/styles/container.scss';
import '@/styles/common.scss';
import { ref, watch, onMounted } from 'vue';
import { TextEntity } from '@/api/intelligent';
import IntelligentEntityText from '@/components/base/texts/IntelligentEntityText.vue';
import { ElIcon, ElButton, ElDivider, ElRow, ElCol } from 'element-plus';
import CommonText from './CommonText.vue';
const allTexts = ref([]);
const textColSpan = ref(12);
const hasTranslation = ref(false);
const showMore = ref(false);
const showMoreVisible = ref(false);
const props = defineProps({
//段落列表: 原始文本
textsRaw: {
type: Array<String>,
default: () => []
},
//段落列表: 翻译文本
textsTranslate: {
type: Array<String>,
default: () => []
},
//是否显示翻译
isOpenTranslation: {
type: Boolean,
default: true
},
//是否高亮实体
isHighlightEntity: {
type: Boolean,
default: true
},
//实体列表
textEntities: {
type: Array<TextEntity>,
default: () => []
}
})
function updateText() {
const tempTexts = []
const tempRaws = props.textsRaw ?? []
const tempTranslates = props.textsTranslate ?? []
hasTranslation.value = tempTranslates.length > 0
if (hasTranslation.value && props.isOpenTranslation) {
// 遍历原始文本和翻译文本,将它们交替添加到 tempTexts 中,并保持原始文本和翻译文本的的数量一致
const maxCount = Math.max(tempRaws.length, tempTranslates.length)
for (let i = 0; i < maxCount; i++) {
if (i < tempTranslates.length) {
tempTexts.push(tempTranslates[i]);
} else {
tempTexts.push('');
}
if (i < tempRaws.length) {
tempTexts.push(tempRaws[i]);
} else {
tempTexts.push('');
}
}
console.log(tempTexts.length)
textColSpan.value = 12;
showMoreVisible.value = tempTexts.length > 6;
allTexts.value = showMore.value ? tempTexts : tempTexts.slice(0, 6);
} else {
textColSpan.value = 24;
showMoreVisible.value = tempRaws.length > 3;
allTexts.value = showMore.value ? tempRaws : tempRaws.slice(0, 3);
}
}
watch(() => [props.textsRaw, props.textsTranslate, props.isOpenTranslation], () => {
updateText();
})
onMounted(() => {
updateText();
})
</script>
\ No newline at end of file
import { useRouter } from "vue-router";
export function useGotoPage() {
const router = useRouter();
return (path, data, isNewTabs = true) => {
console.log('path', path);
if (isNewTabs) {
// 打开新页面
const url = new URL(window.location.origin + path);
if (data) {
Object.entries(data).forEach(([key, value]) => {
url.searchParams.append(key, value);
});
}
window.open(url.toString(), '_blank');
} else {
// 当前页面打开
router.push({ path, query: data });
}
}
}
\ No newline at end of file
const router = useRouter();
return (path, data, isNewTabs = true) => {
console.log("path", path);
if (isNewTabs) {
// 打开新页面
const url = new URL(window.location.origin + path);
if (data) {
Object.entries(data).forEach(([key, value]) => {
url.searchParams.append(key, value);
});
}
window.open(url.toString(), "_blank");
} else {
// 当前页面打开
router.push({ path, query: data });
}
};
}
// 滚动到指定元素
export function scrollToElement(elementId) {
document.getElementById(elementId).scrollIntoView({
behavior: "smooth", // 平滑滚动
block: "start" // 滚动到元素顶部
});
}
......@@ -33,4 +33,15 @@ const comprehensiveSearchRoutes = [
]
import { useGotoPage } from "../common.js";
export function useGotoComprehensiveSearch() {
const gotoPage = useGotoPage();
return (isNewTabs = true) => gotoPage("/comprehensiveSearch/", {}, isNewTabs)
}
export function useGotoSearchResults() {
const gotoPage = useGotoPage();
return (isNewTabs = true) => gotoPage("/searchResults/", {searchText, areaName}, isNewTabs)
}
export default comprehensiveSearchRoutes
\ No newline at end of file
......@@ -75,6 +75,7 @@
&:hover {
color: rgb(5, 95, 194) !important;
font-weight: 700;
cursor: pointer;
}
}
......
<template>
<el-row class="wrapper layout-grid-line">
<el-col :span="span">
<pre>
{{
`
import ActionButton from '@/components/base/ActionButton/index.vue'
<ActionButton name="全部选项" type="active" />
<ActionButton name="选项A" type="normal" />
<ActionButton name="选项B" type="normal" />
<ActionButton name="选项C" type="normal" />
选项按钮
`
}}
</pre>
<div class="button-box">
<ActionButton name="全部选项" type="active" />
<ActionButton name="选项A" type="normal" />
<ActionButton name="选项B" type="normal" />
<ActionButton name="选项C" type="normal" />
</div>
</el-col>
<el-col :span="span">
<pre>
{{
`
import LeftBtn from '@/components/base/PageBtn/LeftBtn.vue'
import RightBtn from '@/components/base/PageBtn/RightBtn.vue'
<LeftBtn />
<RightBtn />
左右按钮
`
}}
</pre>
<div class="button-box1">
<LeftBtn />
<RightBtn />
</div>
</el-col>
</el-row>
</template>
<script setup>
import '@/styles/common.scss'
import LeftBtn from '@/components/base/pageBtn/leftBtn.vue'
import RightBtn from '@/components/base/pageBtn/rightBtn.vue'
const span = 12
</script>
<style lang="scss" scoped>
.button-box {
margin-left: 40px;
;
display: flex;
gap: 8px
}
.button-box1 {
width: 200px;
display: flex;
justify-content: space-between;
margin-left: 40px;
margin-bottom: 10px;
gap: 8px
}
</style>
\ No newline at end of file
<template>
<el-row class="wrapper layout-grid-line">
<el-col :span="span">
<pre>
{{
`
import AreaTag from '@/components/base/AreaTag/index.vue'
<AreaTag tagName="人工智能" />
<AreaTag tagName="生物科技" />
<AreaTag tagName="新一代通信网络" />
<AreaTag tagName="量子科技" />
<AreaTag tagName="新能源" />
`
}}
</pre>
<div class="tag-box">
<AreaTag tagName="人工智能" />
<AreaTag tagName="生物科技" />
<AreaTag tagName="新一代通信网络" />
<AreaTag tagName="量子科技" />
<AreaTag tagName="新能源" />
</div>
</el-col>
</el-row>
</template>
<script setup>
import '@/styles/common.scss'
import AreaTag from '@/components/base/AreaTag/index.vue'
const span = 12
</script>
<style lang="scss" scoped>
.tag-box{
display: flex;
gap: 8px
}
</style>
\ No newline at end of file
......@@ -38,6 +38,14 @@ const span = 12
</pre>
<div class="mouse-hover">鼠标悬停</div>
</el-col>
<el-col :span="span">
<pre>{{ `import '@/styles/common.scss';\n<template>
<div class="text-hover"></div>
</template>
`}}
</pre>
<div class="text-hover">文字悬停</div>
</el-col>
</el-row>
</template>
......
<script setup lang="ts">
import { ElRow, ElCol } from 'element-plus';
import '@/styles/common.scss'
import NewsItemMini from '@/components/base/newsList/NewsItemMini.vue'
import NewsItem from '@/components/base/newsList/NewsItem.vue'
import NewsItemWithTag from '@/components/base/newsList/NewsItemWithTag.vue'
const span = 12
const news = {
title: '新闻标题-老长了老长了老长了老长了老长了老长长了老长了',
content: '新闻内容-老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了老长了',
from: "2025.1.1 · 来源:中国",
aeraTags: ['人工智能', '深海']
}
</script>
<template>
<el-row class="wrapper layout-grid-line">
<el-col :span="span">
<pre>
{{ `import NewsItem from '@/components/base/newsList/NewsItem.vue'` }}
</pre>
<news-item class="common-padding" :title="news.title" :content="news.content" :from="news.from"></news-item>
</el-col>
<el-col :span="span">
<pre>
{{ `import NewsItemMini from '@/components/base/newsList/NewsItemMini.vue'` }}
</pre>
<news-item-mini class="common-padding" :title="news.title" :content="news.content"
:from="news.from"></news-item-mini>
</el-col>
<el-col :span="span">
<pre>
{{ `import NewsItemWithTag from '@/components/base/newsList/NewsItemWithTag.vue'` }}
</pre>
<news-item-with-tag class="common-padding" :title="news.title" :content="news.content" :from="news.from"
:aeraTags="news.aeraTags"></news-item-with-tag>
</el-col>
</el-row>
</template>
<style lang="scss" scoped></style>
\ No newline at end of file
<script setup lang="ts">
import { ElRadioGroup, ElRadioButton, ElRow, ElCol } from 'element-plus';
import { ElRadioGroup, ElRadioButton, ElRow, ElCol, ElSpace } from 'element-plus';
import { ref } from 'vue';
import '@/styles/radio.scss';
......@@ -13,16 +13,36 @@ const span = 12
<pre>
{{ `import '@/styles/radio.scss';
<template>
<el-radio-group class="radio-group-as-gap-btn">
<el-radio-group v-model="radio" class="radio-group-as-gap-btn">
<el-radio-button :value="1">选项1</el-radio-button>
<el-radio-button :value="2">选项2</el-radio-button>
<el-radio-button :value="3">选项3</el-radio-button>
</el-radio-group>
<el-radio-group v-model="radio" class="radio-group-as-gap-btn">
<el-space :size="24">
<el-radio-button :value="1">选项1</el-radio-button>
<el-radio-button :value="2">选项2</el-radio-button>
<el-radio-button :value="3">选项3</el-radio-button>
</el-space>
</el-radio-group>
</template>
`}}
</pre>
<el-radio-group v-model="radio" class="radio-group-as-gap-btn">
<el-radio-button :value="1">选项1</el-radio-button>
<el-radio-button :value="2">选项2</el-radio-button>
<el-radio-button :value="3">选项3</el-radio-button>
</el-radio-group>
<el-space direction="vertical" fill>
<el-radio-group v-model="radio" class="radio-group-as-gap-btn">
<el-radio-button :value="1">选项1</el-radio-button>
<el-radio-button :value="2">选项2</el-radio-button>
<el-radio-button :value="3">选项3</el-radio-button>
</el-radio-group>
<el-radio-group v-model="radio" class="radio-group-as-gap-btn">
<el-space :size="24">
<el-radio-button :value="1">选项1</el-radio-button>
<el-radio-button :value="2">选项2</el-radio-button>
<el-radio-button :value="3">选项3</el-radio-button>
</el-space>
</el-radio-group>
</el-space>
</el-col>
<el-col :span="span">
<pre>{{ `import '@/styles/radio.scss';\n <template>
......
<template>
<el-space direction="vertical" class="common-padding" fill alignment="flex-start">
<el-space>
<el-switch v-model="isHightLightEntity" active-text="高亮实体" @change="console.log(isHightLightEntity)" />
<el-switch v-model="isOpenTranslation" active-text="译文" />
</el-space>
<text-translate-pane :texts-raw="textEns" :texts-translate="textZns" :text-entities="textEntities"
:is-open-translation="isOpenTranslation" :is-highlight-entity="isHightLightEntity">
</text-translate-pane>
</el-space>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import TextTranslatePane from '@/components/base/texts/TextTranslatePane.vue'
import { ElSwitch, ElButton, ElSpace } from 'element-plus'
const isOpenTranslation = ref(true);
const isHightLightEntity = ref(true);
const textEntities = ref([{
text_span: '美国',
type: '国家'
},
{
text_span: 'U.S.',
type: '国家'
}]);
const textZns = ref(['华盛顿当地时间2024年7月2日,美国商务部产业与安全局(BIS)',
'发布一项最终规则,宣布修订《出口管理条例》(EAR) ,',
'以违反美国国家安全或外交政策利益为由在实体清单中增列来自四个国家的6个实体,其中包括2家中国企业。[1]',
'多余段落-测试']);
const textEns = ref(['Washington local time on July 2, 2024, the U.S. Department of Commerce, Industry and Security (BIS) released a final rule, announcing the revision of the Export Administration Regulations (EAR) ,',
'Violating the U.S. national security or diplomatic policy interests, BIS increased the list of 6 entities from four countries, including 2 Chinese companies, on the entity list. [1]',
'Your company has a large amount of money in the U.S.',
]);
</script>
<style scoped>
:deep(.el-col) {
border: 0px !important;
}
</style>
......@@ -4,6 +4,9 @@ import '@/styles/tabs.scss'
import ColorPrefixTitle from '@/components/base/texts/ColorPrefixTitle.vue';
import AiTipPane from '@/components/base/panes/AiTipPane.vue';
import CommonText from '@/components/base/texts/CommonText.vue';
import IntelligentEntityText from '@/components/base/texts/IntelligentEntityText.vue';
import TranslateExample from './TranslateExample.vue';
const span = 12
</script>
......@@ -50,6 +53,40 @@ const span = 12
</pre>
<ai-tip-pane>huidadadadadasda</ai-tip-pane>
</el-col>
<el-col :span="span">
<pre>{{ `import IntelligentEntityText from '@/components/base/texts/IntelligentEntityText.vue';\n<template>
<intelligent-entity-text
text="华盛顿当地时间2024年7月2日,美国商务部产业与安全局(BIS) 发布一项最终规则,宣布修订《出口管理条例》(EAR) ,以违反美国国家安全或外交政策利益为由在实体清单 中增列来自四个国家的6个实体,其中包括2家中国企业。[1]"
:entities="[{
text_span: '华盛顿',
type: 'location'
}, {
text_span: '美国商务部产业与安全局',
type: 'organization'
}]">
</intelligent-entity-text>
</template>
`}}
</pre>
<intelligent-entity-text
text="华盛顿当地时间2024年7月2日,美国商务部产业与安全局(BIS) 发布一项最终规则,宣布修订《出口管理条例》(EAR) ,以违反美国国家安全或外交政策利益为由在实体清单 中增列来自四个国家的6个实体,其中包括2家中国企业。[1]"
:entities="[{
text_span: '华盛顿',
type: 'location'
}, {
text_span: '美国商务部产业与安全局',
type: 'organization'
}]">
</intelligent-entity-text>
</el-col>
<el-col :span="span">
<pre>{{ `参考src/styles/components/TextPage/TranslateExample.vue` }}
</pre>
<translate-example>
</translate-example>
</el-col>
</el-row>
</template>
......
......@@ -2,7 +2,7 @@
import { ElRow, ElCol } from 'element-plus';
import '@/styles/common.scss'
import WarnningPane from '@/components/base/WarningPane/index.vue'
const span = 12
const span = 24
</script>
<template>
......@@ -12,19 +12,26 @@ const span = 12
{{
`import WarnningPane from '@/components/base/WarningPane/index.vue';
<template>
<WarnningPane warnningLevel="特别重大风险" warnningContent="我是特别重大风险内容文字我是特别重大风险内容文字">
</WarnningPane>
<WarnningPane warnningLevel="特别重大风险" warnningContent="我是特别重大风险内容文字我是特别重大风险内容文字" />
</template>
`}}
</pre>
<WarnningPane warnningLevel="特别重大风险" warnningContent="我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字">
</WarnningPane>
<div class="warnning-box">
<WarnningPane warnningLevel="特别重大风险" warnningContent="我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字我是特别重大风险内容文字" />
<WarnningPane warnningLevel="重大风险" warnningContent="我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容我是重大风险内容" />
<WarnningPane warnningLevel="较大风险" warnningContent="我是较大风险内容我是较大风险内容我是较大风险内容我是较大风险内容我是较大风险内容我是较大风险内容我是较大风险内容我是较大风险内容我是较大风险内容我是较大风险内容我是较大风险内容我是较大风险内容我是较大风险内容我是较大风险内容我是较大风险内容" />
<WarnningPane warnningLevel="一般风险" warnningContent="我是一般风险内容我是一般风险内容我是一般风险内容我是一般风险内容我是一般风险内容我是一般风险内容我是一般风险内容我是一般风险内容我是一般风险内容我是一般风险内容我是一般风险内容我是一般风险内容我是一般风险内容" />
<WarnningPane warnningLevel="低风险" warnningContent="我是低风险内容我是低风险内容我是低风险内容我是低风险内容我是低风险内容我是低风险内容我是低风险内容我是低风险内容我是低风险内容我是低风险内容我是低风险内容" />
</div>
</el-col>
</el-row>
</template>
<style lang="scss" scoped>
.person-avatar {
width: 200px;
.warnning-box{
display: flex;
flex-direction: column;
gap: 8px;
}
</style>
\ No newline at end of file
<template>
<el-row class="wrapper layout-grid-line">
<el-col :span="span">
<pre>
{{
`
import WordCloudChart from "@/components/base/WordCloundChart/index.vue"
<div class="chart-box">
<WordCloudChart :data="data" />
</div>
`
}}
</pre>
<div class="chart-box">
<WordCloudChart :data="data" />
</div>
</el-col>
</el-row>
</template>
<script setup>
import {ref} from 'vue'
import '@/styles/common.scss'
import WordCloudChart from "@/components/base/WordCloundChart/index.vue"
const span = 12
const data = ref([
{ name: "与马斯克公开冲突", value: 100 },
{ name: "传统能源", value: 5 },
{ name: "共和党财政鹰派", value: 77 },
{ name: "未实现赤字控制目标", value: 35 },
{ name: "得克萨斯州", value: 88 },
{ name: "选举压力", value: 57 },
{ name: "主张财政紧缩", value: 72 },
{ name: "财政保守", value: 18 },
{ name: "财政保守1", value: 25 },
{ name: "财政保守2", value: 46 },
{ name: "财政保守3", value: 72 },
{ name: "财政保守4", value: 69 },
{ name: "财政保守5", value: 53 },
])
</script>
<style lang="scss" scoped>
.chart-box {
width: 520px;
height: 400px;
border: 1px solid var(--bg-black-5);
}
</style>
\ No newline at end of file
.layout-grid-line {
.el-col {
.el-col:not(disinheritance) {
border: 1px double var(--bg-black-5);
}
......
......@@ -28,15 +28,27 @@
<el-tab-pane label="人物" lazy>
<people-page />
</el-tab-pane>
<el-tab-pane label="新闻" lazy>
<news-page />
</el-tab-pane>
<el-tab-pane label="预警面板" lazy>
<WarnningPane />
</el-tab-pane>
<el-tab-pane label="领域标签" lazy>
<AreaTag />
</el-tab-pane>
<el-tab-pane label="按钮" lazy>
<ActionButton />
</el-tab-pane>
<el-tab-pane label="层级关系图" lazy>
<GraphChart />
</el-tab-pane>
<el-tab-pane label="引力关系图" lazy>
<GraphTreeChart />
</el-tab-pane>
<el-tab-pane label="词云图" lazy>
<WordCloudChart />
</el-tab-pane>
</el-tabs>
</div>
</el-space>
......@@ -59,6 +71,10 @@ import PeoplePage from './People/index.vue';
import WarnningPane from './WarnningPane/index.vue'
import GraphChart from './GraphChart/index.vue'
import GraphTreeChart from './GraphTreeChart/index.vue'
import AreaTag from './AreaTag/index.vue'
import ActionButton from './ActionButton/index.vue'
import WordCloudChart from './WordCloudChart/index.vue'
import NewsPage from './News/index.vue'
</script>
<style lang="scss" scoped>
......
......@@ -16,4 +16,12 @@
.common-padding {
padding: 20px 24px;
}
.common-padding-h {
padding: 0px 24px;
}
.common-padding-v {
padding: 20px 0px;
}
\ No newline at end of file
......@@ -3,23 +3,14 @@
<div class="content-wrapper">
<div class="policy-monitoring">
<div class="header">
<div
class="section"
v-for="(section, index) in sectionTab"
:key="index"
:style="{
width: sections[index].waveBall.length === 2 ? '350px' : '503px',
background: section.background
}"
>
<div class="section" v-for="(section, index) in sectionTab" :key="index" :style="{
width: sections[index].waveBall.length === 2 ? '350px' : '503px',
background: section.background
}">
<img class="section-title" :src="section.title" />
<div class="stats">
<div
class="ball-item"
v-for="(value, idx) in sections[index].waveBall"
:key="idx"
@click="highLight(value.type)"
>
<div class="ball-item" v-for="(value, idx) in sections[index].waveBall" :key="idx"
@click="highLight(value.type)">
<WaveBall :percent="value.percent" :data="value" :color="section.waterColor" :size="128" />
<div class="text-box">
<div class="waveBall-text">
......@@ -29,16 +20,10 @@
</div>
</div>
</div>
<div
class="bottm-box"
:style="sections[index].waveBall.length === 2 ? 'width: 350px' : 'width:503px'"
@click="handleClickCardBottomInfo(cardBottomInfo[index])"
>
<div class="bottm-box" :style="sections[index].waveBall.length === 2 ? 'width: 350px' : 'width:503px'"
@click="handleClickCardBottomInfo(cardBottomInfo[index])">
<img src="./icon/title-icon-1.png" />
<div
class="bottm-box-text"
:style="sections[index].waveBall.length === 2 ? 'width: 225px' : 'width:378px'"
>
<div class="bottm-box-text" :style="sections[index].waveBall.length === 2 ? 'width: 225px' : 'width:378px'">
{{ cardBottomInfo[index]?.title || "暂无新增数据" }}
</div>
<div style="width: 115px; color: #ffffff">
......@@ -58,24 +43,16 @@
<div style="display: flex">
<!-- 风险信号列表 -->
<div class="risk-signals" ref="riskSignalsRef">
<div
class="risk-signals-item"
v-for="(item, index) in warningList"
:key="index"
@mouseenter="onMouseEnter(item, index)"
@mouseleave="onMouseLeave"
:class="['risk-signals-item', { 'risk-signals-item-hightLight': riskSignalActiveIndex === index }]"
>
<div
class="item-left"
:class="{
'item-status-1': item.signalLevel === '特别重大',
'item-status-2': item.signalLevel === '重大风险',
'item-status-3': item.signalLevel === '较大风险',
'item-status-4': item.signalLevel === '一般风险',
'item-status-5': item.signalLevel === '低风险'
}"
>
<div class="risk-signals-item" v-for="(item, index) in warningList" :key="index"
@mouseenter="onMouseEnter(item, index)" @mouseleave="onMouseLeave"
:class="['risk-signals-item', { 'risk-signals-item-hightLight': riskSignalActiveIndex === index }]">
<div class="item-left" :class="{
'item-status-1': item.signalLevel === '特别重大',
'item-status-2': item.signalLevel === '重大风险',
'item-status-3': item.signalLevel === '较大风险',
'item-status-4': item.signalLevel === '一般风险',
'item-status-5': item.signalLevel === '低风险'
}">
{{ item.signalLevel ? item.signalLevel : "一般风险" }}
</div>
<div class="item-right">
......@@ -87,31 +64,16 @@
</div>
</div>
<div class="news">
<div
class="box1-left"
@click="handleSwithCurNews('left')"
@mouseenter="handleInBtn"
@mouseleave="handleOutBtn"
>
<div class="box1-left" @click="handleSwithCurNews('left')" @mouseenter="handleInBtn"
@mouseleave="handleOutBtn">
<img :src="leftBtn" alt="" />
</div>
<div
class="box1-right"
@click="handleSwithCurNews('right')"
@mouseenter="handleInBtn"
@mouseleave="handleOutBtn"
>
<div class="box1-right" @click="handleSwithCurNews('right')" @mouseenter="handleInBtn"
@mouseleave="handleOutBtn">
<img :src="rightBtn" alt="" />
</div>
<el-carousel
ref="carouselRef"
style="height: 443px; width: 664px"
:autoplay="true"
:interval="30000"
arrow="never"
indicator-position="none"
@change="handleCarouselChange"
>
<el-carousel ref="carouselRef" style="height: 443px; width: 664px" :autoplay="true" :interval="30000"
arrow="never" indicator-position="none" @change="handleCarouselChange">
<el-carousel-item v-for="(News, NewsIndex) in filteredHotNewsList" :key="NewsIndex">
<div class="carousel-item" @click="toDetaile(News.hotspotID, News.hotspotType)">
<div class="carousel-title">
......@@ -128,9 +90,7 @@
style="width: 96px; height: 96px"
/> -->
</div>
<div
style="/* 矩形 351 */ width: 664px; height: 1px; background: rgba(234, 236, 238, 1)"
></div>
<div style="/* 矩形 351 */ width: 664px; height: 1px; background: rgba(234, 236, 238, 1)"></div>
<div class="news-carousel-content">{{ News.hotspotDesc }}</div>
<div class="carousel-bottom">
......@@ -1146,6 +1106,7 @@ onUnmounted(() => {
align-items: center;
position: relative;
position: relative;
.red-dot {
position: absolute;
right: -15px;
......@@ -1233,21 +1194,21 @@ onUnmounted(() => {
}
.item-status-2 {
color: var(--color-orange-100) !important;
background: var(--color-orange-10) !important;
color: #FA8C16 !important;
background: #FFF7E6 !important;
}
.item-status-3 {
.item-status-3 {
color: var(--color-yellow-100) !important;
background: var(--color-yellow-10) !important;
}
.item-status-4 {
color: var(--color-green-100) !important;
background: var(--color-green-10) !important;
.item-status-4 {
color: #52C41A !important;
background: #F6FFED !important;
}
.item-status-5 {
.item-status-5 {
color: var(--color-primary-100) !important;
background: var(--color-primary-10) !important;
}
......@@ -1286,6 +1247,7 @@ onUnmounted(() => {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&:hover {
color: var(--color-main-active);
font-weight: bold;
......@@ -1410,6 +1372,7 @@ onUnmounted(() => {
width: 24px;
height: 48px;
cursor: pointer;
img {
width: 100%;
height: 100%;
......@@ -1423,6 +1386,7 @@ onUnmounted(() => {
width: 24px;
height: 48px;
cursor: pointer;
img {
width: 100%;
height: 100%;
......@@ -1448,6 +1412,7 @@ onUnmounted(() => {
text-align: justify;
display: flex;
justify-content: space-between;
.title-text {
/* 美国白宫发布关于进一步延长TikTok执法宽限期的行政令 */
width: 660px;
......@@ -1513,6 +1478,7 @@ onUnmounted(() => {
display: flex;
gap: 8px;
justify-content: flex-end;
.tag {
/* 数据展示/Tag标签/亮色/绿 */
height: 24px;
......@@ -1538,6 +1504,7 @@ onUnmounted(() => {
}
}
}
.carousel-footer {
margin-top: 10px;
width: 664px;
......@@ -1551,8 +1518,10 @@ onUnmounted(() => {
align-items: center;
justify-content: space-between;
cursor: pointer;
.footer-left {
display: flex;
.type {
color: var(--color-main-active);
font-family: Source Han Sans CN;
......@@ -1563,6 +1532,7 @@ onUnmounted(() => {
letter-spacing: 0px;
text-align: left;
}
.text {
width: 500px;
color: var(--color-main-active);
......@@ -1578,9 +1548,11 @@ onUnmounted(() => {
white-space: nowrap;
}
}
.footer-right {
width: 12px;
height: 11px;
img {
width: 100%;
height: 100%;
......
......@@ -48,6 +48,48 @@ const getProxyUrl = (url) => {
return `https://images.weserv.nl/?url=${encodeURIComponent(cleanUrl)}`;
};
// ========== 创建圆形图片 ==========
const createCircularImage = (imageUrl, size, borderWidth = 2, borderColor = "rgba(174,214,255,1)") => {
return new Promise((resolve) => {
const img = new Image();
img.crossOrigin = "anonymous";
img.onload = () => {
const canvas = document.createElement("canvas");
// 增加大小以容纳边框
const totalSize = size + borderWidth * 2;
canvas.width = totalSize;
canvas.height = totalSize;
const ctx = canvas.getContext("2d");
// 清空背景
ctx.clearRect(0, 0, totalSize, totalSize);
// 绘制圆形图片
ctx.beginPath();
ctx.arc(totalSize / 2, totalSize / 2, size / 2, 0, Math.PI * 2);
ctx.closePath();
ctx.clip();
// 绘制图片到圆形区域
ctx.drawImage(img, borderWidth, borderWidth, size, size);
// 恢复上下文并绘制边框
ctx.restore();
ctx.beginPath();
ctx.arc(totalSize / 2, totalSize / 2, size / 2, 0, Math.PI * 2);
ctx.strokeStyle = borderColor;
ctx.lineWidth = borderWidth;
ctx.stroke();
resolve(canvas.toDataURL("image/png"));
};
img.onerror = () => {
resolve(imageUrl); // 失败时返回原图
};
img.src = imageUrl;
});
};
// ========== 数据 ==========
const nodes = ref([]);
const links = ref([]);
......@@ -106,13 +148,17 @@ const getCharacterRelationFn = async () => {
console.error("获取人物关系失败", error);
}
// 创建圆形头像
const centerImageUrl = getProxyUrl(characterInfo.value.imageUrl);
const centerCircularImage = await createCircularImage(centerImageUrl, 76, 3, "rgba(174,214,255,1)");
// ---------- 组装节点和连线 ----------
const centerNode = {
id: "c",
name: characterInfo.value.name || "",
category: 0,
symbolSize: 80,
symbol: `image://${getProxyUrl(characterInfo.value.imageUrl)}`,
symbol: `image://${centerCircularImage}`,
label: {
show: true,
position: "bottom",
......@@ -130,12 +176,19 @@ const getCharacterRelationFn = async () => {
};
if (CharacterRelation.value.length > 0) {
// 并行创建所有圆形头像
const circularImages = await Promise.all(
CharacterRelation.value.map((item) =>
createCircularImage(getProxyUrl(item.imageUrl), 76, 2, "rgba(174,214,255,1)")
)
);
const newNodes = CharacterRelation.value.map((item, index) => ({
id: index,
name: item.name,
category: 1,
symbolSize: 80,
symbol: `image://${getProxyUrl(item.imageUrl)}`,
symbol: `image://${circularImages[index]}`,
}));
newNodes.push(centerNode);
......@@ -308,4 +361,4 @@ onMounted(async () => {
width: 100%;
height: 100%;
}
</style>
\ No newline at end of file
</style>
......@@ -46,6 +46,35 @@ const getProxyUrl = (url) => {
return `https://images.weserv.nl/?url=${encodeURIComponent(cleanUrl)}`
}
// 创建圆形图片的函数
const createCircularImage = (imageUrl, size) => {
return new Promise((resolve) => {
const img = new Image()
img.crossOrigin = 'anonymous'
img.onload = () => {
const canvas = document.createElement('canvas')
canvas.width = size
canvas.height = size
const ctx = canvas.getContext('2d')
// 绘制圆形裁剪区域
ctx.beginPath()
ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2)
ctx.closePath()
ctx.clip()
// 绘制图片
ctx.drawImage(img, 0, 0, size, size)
resolve(canvas.toDataURL('image/png'))
}
img.onerror = () => {
resolve(imageUrl) // 失败时返回原图
}
img.src = imageUrl
})
}
const nodes = ref([])
const links = ref([])
const characterInfo = ref({})
......@@ -91,12 +120,16 @@ const getCharacterRelationFn = async () => {
}
} catch (error) {}
// 创建圆形头像
const centerImageUrl = getProxyUrl(characterInfo.value.imageUrl)
const centerCircularImage = await createCircularImage(centerImageUrl, 168)
const centerNode = {
id: 'c',
name: characterInfo.value.name || '',
category: 0,
symbolSize: 84,
symbol: `image://${getProxyUrl(characterInfo.value.imageUrl)}`,
symbol: `image://${centerCircularImage}`,
itemStyle: {
borderColor: 'rgba(174,214,255,1)',
borderWidth: 3,
......@@ -114,12 +147,19 @@ const getCharacterRelationFn = async () => {
}
if (CharacterRelation.value.length > 0) {
// 并行创建所有圆形头像
const circularImages = await Promise.all(
CharacterRelation.value.map((item) =>
createCircularImage(getProxyUrl(item.imageUrl), 108)
)
)
const newNodes = CharacterRelation.value.map((item, index) => ({
id: index,
name: item.name,
category: 1,
symbolSize: 54,
symbol: `image://${getProxyUrl(item.imageUrl)}`,
symbol: `image://${circularImages[index]}`,
itemStyle: {
borderColor: 'rgba(174,214,255,1)',
borderWidth: 2,
......@@ -322,4 +362,4 @@ onMounted(async () => {
width: 100%;
height: 100%;
}
</style>
\ No newline at end of file
</style>
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
<rect id="icon-圆形布局 1" width="16.000000" height="16.000000" x="0.000000" y="0.000000" />
<path id="矢量 423" d="M13.81 6.6C13.67 5.97 13.39 5.41 13.04 4.85C13.18 4.64 13.25 4.36 13.25 4.15C13.25 3.38 12.62 2.75 11.85 2.75C11.57 2.75 11.36 2.82 11.15 2.96C10.59 2.61 10.03 2.4 9.4 2.19C9.33 1.49 8.7 1 8 1C7.3 1 6.74 1.56 6.6 2.19C5.97 2.4 5.41 2.61 4.85 2.96C4.64 2.82 4.36 2.75 4.15 2.75C3.38 2.75 2.75 3.38 2.75 4.15C2.75 4.43 2.82 4.64 2.96 4.85C2.61 5.41 2.4 5.97 2.19 6.6C1.56 6.74 1 7.3 1 8C1 8.7 1.56 9.26 2.19 9.4C2.33 10.03 2.61 10.59 2.96 11.15C2.82 11.36 2.75 11.64 2.75 11.85C2.75 12.62 3.38 13.25 4.15 13.25C4.43 13.25 4.64 13.18 4.85 13.04C5.41 13.39 5.97 13.6 6.6 13.81C6.67 14.51 7.3 15 8 15C8.7 15 9.26 14.44 9.4 13.81C10.03 13.67 10.59 13.39 11.15 13.04C11.36 13.18 11.64 13.25 11.85 13.25C12.62 13.25 13.25 12.62 13.25 11.85C13.25 11.57 13.18 11.36 13.04 11.15C13.39 10.59 13.6 10.03 13.81 9.4C14.51 9.33 15 8.7 15 8C15 7.3 14.44 6.74 13.81 6.6L13.81 6.6ZM12.55 10.66C12.34 10.52 12.13 10.45 11.85 10.45C11.08 10.45 10.45 11.08 10.45 11.85C10.45 12.13 10.52 12.34 10.66 12.55C10.24 12.76 9.82 12.97 9.33 13.11C9.12 12.62 8.63 12.2 8 12.2C7.44 12.2 6.88 12.55 6.67 13.11C6.18 12.97 5.76 12.83 5.34 12.55C5.48 12.34 5.55 12.13 5.55 11.85C5.55 11.08 4.92 10.45 4.15 10.45C3.87 10.45 3.66 10.52 3.45 10.66C3.24 10.24 3.03 9.82 2.89 9.33C3.45 9.12 3.8 8.56 3.8 8C3.8 7.44 3.45 6.88 2.96 6.74C3.1 6.25 3.24 5.83 3.52 5.41C3.73 5.55 3.94 5.62 4.22 5.62C4.99 5.62 5.62 4.99 5.62 4.22C5.62 3.94 5.55 3.73 5.41 3.52C5.83 3.31 6.25 3.1 6.74 2.96C6.88 3.45 7.44 3.8 8 3.8C8.56 3.8 9.12 3.45 9.33 2.89C9.82 3.03 10.24 3.17 10.66 3.45C10.52 3.66 10.45 3.87 10.45 4.15C10.45 4.92 11.08 5.55 11.85 5.55C12.13 5.55 12.34 5.48 12.55 5.34C12.76 5.76 12.97 6.18 13.11 6.67C12.55 6.88 12.2 7.44 12.2 8C12.2 8.56 12.55 9.12 13.04 9.26C12.97 9.75 12.76 10.24 12.55 10.66L12.55 10.66Z" fill="rgb(59,65,75)" fill-rule="nonzero" />
</svg>
<svg viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="28.000000" height="28.000000" fill="none">
<defs>
<clipPath id="clipPath_1">
<rect width="18.000000" height="15.000000" x="5.000000" y="5.000000" fill="rgb(255,255,255)" />
</clipPath>
</defs>
<rect id="导出数据" width="28.000000" height="28.000000" x="0.000000" y="0.000000" />
<g id="容器 742" customFrame="url(#clipPath_1)">
<rect id="容器 742" width="18.000000" height="15.000000" x="5.000000" y="5.000000" />
<rect id="矩形 347" width="2.000000" height="6.000000" x="13.000000" y="5.000000" fill="rgb(132,136,142)" />
<path id="矢量 600" d="M18 11L10 11L14 16L18 11Z" fill="rgb(132,136,142)" fill-rule="evenodd" />
<path id="矢量 601" d="M22 19.9996L22.9999 15.0012L19.9999 12.0011L18.9999 12L21.0003 15.001L17.9999 15.0015L16.9998 17.9987L14 17.9996L11.0001 17.9997L9.99998 15.002L7.00017 15.0028L8.99996 12.0008L8 12.0004L5 15.0023L6.00016 20L22 19.9996Z" fill="rgb(132,136,142)" fill-rule="evenodd" />
</g>
</svg>
<svg viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="28.000000" height="28.000000" fill="none">
<defs>
<clipPath id="clipPath_0">
<rect width="20.000000" height="20.000000" x="4.000000" y="4.000000" fill="rgb(255,255,255)" />
</clipPath>
</defs>
<rect id="数据源" width="28.000000" height="28.000000" x="0.000000" y="0.000000" />
<g id="数据库 1" clip-path="url(#clipPath_0)" customFrame="url(#clipPath_0)">
<rect id="数据库 1" width="20.000000" height="20.000000" x="4.000000" y="4.000000" />
<path id="合并" d="M10.6426 6.48828C11.6719 6.28906 12.791 6.1875 14 6.1875C15.209 6.1875 16.3281 6.28906 17.3574 6.48828C18.3867 6.6875 19.2012 6.96094 19.7988 7.30469C20.3965 7.64844 20.6973 8.01953 20.6973 8.42188L20.6973 9.53906C20.6973 9.94141 20.3984 10.3125 19.7988 10.6563C19.1992 11 18.3867 11.2715 17.3574 11.4727C16.3281 11.6699 15.209 11.7695 14 11.7695C12.791 11.7695 11.6719 11.668 10.6426 11.4688C9.61328 11.2695 8.79883 10.9961 8.20117 10.6523C7.60156 10.3086 7.30273 9.9375 7.30273 9.53516L7.30273 8.41797C7.30273 8.01563 7.60156 7.64453 8.20117 7.30078C8.80078 6.96094 9.61328 6.68945 10.6426 6.48828ZM10.1387 12.5078C11.3359 12.7578 12.623 12.8828 14 12.8828C15.377 12.8828 16.6641 12.7578 17.8613 12.5078C19.0586 12.2578 20.0039 11.8887 20.6953 11.4004L20.6953 12.8828C20.6953 13.2852 20.3965 13.6563 19.7969 14C19.1973 14.3438 18.3848 14.6152 17.3555 14.8164C16.3281 15.0156 15.209 15.1152 14 15.1152C12.791 15.1152 11.6719 15.0137 10.6426 14.8145C9.61328 14.6152 8.79883 14.3418 8.20117 13.998C7.60156 13.6543 7.30273 13.2832 7.30273 12.8809L7.30273 11.3984C7.99609 11.8906 8.94141 12.2598 10.1387 12.5078ZM10.1387 15.8574C11.3359 16.1074 12.623 16.2324 14 16.2324C14.6624 16.2324 15.3041 16.2035 15.9249 16.1456C14.2088 16.4715 12.8443 17.3161 12.2805 18.3935C11.7114 18.3432 11.1654 18.2672 10.6426 18.166C9.61328 17.9668 8.80078 17.6934 8.20117 17.3496C7.60156 17.0059 7.30273 16.6348 7.30273 16.2324L7.30273 14.75C7.9961 15.2383 8.94141 15.6074 10.1387 15.8574ZM17.5 16C17.3281 16 17.1581 16.005 16.9902 16.0148C17.2857 15.9695 17.5761 15.917 17.8613 15.8574C19.0586 15.6074 20.0039 15.2383 20.6953 14.75L20.6953 16.2324C20.6953 16.3614 20.6646 16.4872 20.6031 16.6099C19.7199 16.2251 18.6512 16 17.5 16ZM13 19.5C13 18.1193 15.0147 17 17.5 17C19.9853 17 22 18.1193 22 19.5C22 20.8807 19.9853 22 17.5 22C15.0147 22 13 20.8807 13 19.5ZM17.5 18C18.3284 18 19 18.6716 19 19.5C19 20.3284 18.3284 21 17.5 21C16.6716 21 16 20.3284 16 19.5C16 18.6716 16.6716 18 17.5 18ZM12 19.5L12 19.4861C11.3572 19.4236 10.7367 19.33 10.1387 19.2051C8.94141 18.9551 7.99609 18.5859 7.30273 18.0957L7.30273 19.5781C7.30273 19.9805 7.60156 20.3516 8.20117 20.6953C8.79883 21.0391 9.61328 21.3125 10.6426 21.5117C11.4872 21.6752 12.3923 21.7729 13.3579 21.8027C12.5123 21.1873 12 20.3817 12 19.5Z" fill="rgb(132,136,142)" fill-rule="evenodd" />
</g>
</svg>
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
<rect id="拓扑 1" width="16.000000" height="16.000000" x="0.000000" y="0.000000" />
<path id="矢量 422" d="M12.7727 11.142C12.4273 11.142 12.107 11.2495 11.8433 11.4327L9.42154 9.6837C9.65586 9.26852 9.78974 8.7891 9.78974 8.27836C9.78974 8.18728 9.7853 8.09723 9.77697 8.00833L12.257 6.54325C12.6396 6.77576 13.1451 6.72689 13.4758 6.39622C13.8641 6.00791 13.8641 5.37835 13.4758 4.99004C13.0875 4.60173 12.4579 4.60173 12.0696 4.99004C11.7835 5.27612 11.7085 5.69309 11.844 6.04812L9.63655 7.35217C9.40869 6.68522 8.9416 6.12922 8.33762 5.78637L8.77881 3.58047C8.81046 3.5835 8.84253 3.58519 8.87497 3.58519C9.42413 3.58519 9.8693 3.14002 9.8693 2.59087C9.8693 2.04173 9.42413 1.59656 8.87497 1.59656C8.32582 1.59656 7.88065 2.04173 7.88065 2.59087C7.88065 2.87182 7.99736 3.12535 8.18469 3.30617L7.73951 5.53213C7.48164 5.45587 7.2087 5.41473 6.9261 5.41473C6.388 5.41473 5.88464 5.56327 5.45458 5.8214L4.08134 4.61294C4.32918 4.12086 4.24801 3.50548 3.83714 3.09461C3.32457 2.58205 2.49355 2.58205 1.98098 3.09461C1.46841 3.60717 1.46842 4.4382 1.98098 4.95078C2.43973 5.40952 3.15341 5.45735 3.66574 5.09492L4.93964 6.21596C4.39895 6.73684 4.06247 7.46826 4.06247 8.27836C4.06247 9.15881 4.45994 9.94631 5.0851 10.4716L3.95324 11.6792C3.74531 11.5408 3.49572 11.4602 3.22724 11.4602C2.50236 11.4602 1.91474 12.0478 1.91474 12.7727C1.91474 13.4975 2.50236 14.0852 3.22724 14.0852C3.95212 14.0852 4.53974 13.4975 4.53974 12.7727C4.53974 12.5477 4.48308 12.3359 4.38332 12.1508L5.62251 10.8288C6.01351 11.029 6.45662 11.142 6.9261 11.142C7.76819 11.142 8.52534 10.7785 9.04931 10.1999L11.3976 11.8958C11.2358 12.149 11.142 12.4499 11.142 12.7727C11.142 13.6733 11.8721 14.4034 12.7727 14.4034C13.6733 14.4034 14.4034 13.6733 14.4034 12.7727C14.4034 11.8721 13.6733 11.142 12.7727 11.142L12.7727 11.142Z" fill="rgb(59,65,75)" fill-rule="nonzero" />
</svg>
<svg viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="28.000000" height="28.000000" fill="none">
<rect id="收藏" width="28.000000" height="28.000000" x="0.000000" y="0.000000" />
<path id="星形 2" d="M15.9534 11.0113C15.9936 11.1349 16.1088 11.2186 16.2388 11.2186L21.6363 11.2188C21.9269 11.2188 22.0478 11.5907 21.8127 11.7615L17.446 14.9343C17.3409 15.0107 17.2969 15.1461 17.3371 15.2697L19.0048 20.4031C19.0946 20.6795 18.7783 20.9094 18.5432 20.7385L14.1763 17.5661C14.0712 17.4897 13.9288 17.4897 13.8237 17.5661L9.45683 20.7385C9.22171 20.9094 8.90539 20.6795 8.99518 20.4031L10.6629 15.2697C10.7031 15.1461 10.6591 15.0107 10.554 14.9343L6.18734 11.7615C5.95224 11.5907 6.07307 11.2188 6.36368 11.2188L11.7612 11.2186C11.8912 11.2186 12.0064 11.1349 12.0466 11.0113L13.7147 5.87799C13.8045 5.60161 14.1955 5.60161 14.2853 5.87799L15.9534 11.0113Z" fill="rgb(132,136,142)" fill-rule="evenodd" />
</svg>
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
<rect id="绿洲_拓扑图 1" width="16.000000" height="16.000000" x="0.000000" y="0.000000" />
<path id="矢量 422" d="M15.0147 9.88449L14.1867 9.88449L14.1867 8.65516C14.1867 7.53912 13.312 6.63116 12.2368 6.63116L8.37334 6.63116L8.37334 5.08449L9.2317 5.08449C9.42605 5.08449 9.58222 4.94394 9.58222 4.74957L9.58222 2.34115C9.58222 2.11642 9.40148 1.92004 9.17669 1.92004L6.76829 1.92004C6.57396 1.92004 6.41778 2.09179 6.41778 2.28616L6.41778 4.69459C6.41778 4.91931 6.59853 5.08449 6.82329 5.08449L7.62667 5.08449L7.62667 6.63116L3.59268 6.63116C2.62816 6.63116 1.81334 7.45731 1.81334 8.43519L1.81334 9.88449L0.930314 9.88449C0.735986 9.88449 0.58667 10.0572 0.58667 10.2515L0.58667 12.66C0.58667 12.8847 0.760554 13.0489 0.985319 13.0489L3.39371 13.0489C3.58806 13.0489 3.75111 12.9093 3.75111 12.7149L3.75111 10.3066C3.75111 10.0818 3.56351 9.88451 3.33874 9.88451L2.52445 9.88451L2.52445 8.43521C2.52445 7.84276 3.01364 7.34227 3.59268 7.34227L7.62667 7.34227L7.62667 9.88449L6.76829 9.88449C6.57396 9.88449 6.41778 10.0572 6.41778 10.2515L6.41778 12.66C6.41778 12.8847 6.59853 13.0489 6.82329 13.0489L9.2317 13.0489C9.42605 13.0489 9.58222 12.9093 9.58222 12.7149L9.58222 10.3066C9.58222 10.0818 9.40148 9.88451 9.1767 9.88451L8.37334 9.88451L8.37334 7.34227L12.2368 7.34227C12.9199 7.34227 13.4756 7.93123 13.4756 8.65516L13.4756 9.88449L12.6063 9.88449C12.4119 9.88449 12.2489 10.0572 12.2489 10.2515L12.2489 12.66C12.2489 12.8847 12.4365 13.0489 12.6613 13.0489L15.0697 13.0489C15.264 13.0489 15.4133 12.9093 15.4133 12.7149L15.4133 10.3066C15.4133 10.0818 15.2395 9.88449 15.0147 9.88449Z" fill="rgb(59,65,75)" fill-rule="nonzero" />
</svg>
......@@ -5,12 +5,17 @@
v-for="(item, index) in list"
:key="index"
class="headerItem"
:class="{ active: item === activeIndex }"
@click="activeIndex = item"
>{{ item }}</span
:class="{ active: item.value === activeIndex }"
@click="handleChangeLayout(item.value)"
>
<img :src="item.icon" :alt="item.label" />
</span>
</div>
<div class="headerBtnBox">
<img src="./assets/icon-expand.svg" alt="" class="btn-icon" />
<img src="./assets/icon-download.svg" alt="" class="btn-icon" />
<img src="./assets/icon-star.svg" alt="" class="btn-icon" />
</div>
<div class="headerBtnBox"><img src="./assets/下载按钮.png" alt="" /><img src="./assets/收藏按钮.png" alt="" /></div>
<!-- 主要内容,人物关系图 -->
<div class="mainBox">
<div class="graph" id="relGraph"></div>
......@@ -98,6 +103,76 @@ const getProxyUrl = (url) => {
return `https://images.weserv.nl/?url=${encodeURIComponent(cleanUrl)}`;
};
// 创建圆形图片的函数
const createCircularImage = (imageUrl, size) => {
return new Promise((resolve) => {
if (!imageUrl) {
console.log("[v0] No image URL provided");
resolve('');
return;
}
const img = new Image();
img.crossOrigin = 'anonymous';
const onLoadSuccess = () => {
try {
const canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
const ctx = canvas.getContext('2d');
// 绘制圆形裁剪区域
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2);
ctx.closePath();
ctx.clip();
// 绘制图片
ctx.drawImage(img, 0, 0, size, size);
resolve(canvas.toDataURL('image/png'));
} catch (error) {
console.log("[v0] Canvas error:", error);
resolve(imageUrl);
}
};
img.onload = onLoadSuccess;
img.onerror = () => {
console.log("[v0] Image failed to load, trying without crossOrigin:", imageUrl);
// 如果加载失败,尝试不带 crossOrigin 的方式
const img2 = new Image();
img2.onload = () => {
try {
const canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2);
ctx.closePath();
ctx.clip();
ctx.drawImage(img2, 0, 0, size, size);
resolve(canvas.toDataURL('image/png'));
} catch (error) {
console.log("[v0] Fallback canvas error:", error);
resolve(imageUrl);
}
};
img2.onerror = () => {
console.log("[v0] Image loading failed completely:", imageUrl);
resolve(imageUrl);
};
img2.src = imageUrl;
};
img.src = imageUrl;
});
};
const nodes = ref([]);
const links = ref([]);
......@@ -111,20 +186,14 @@ const getCharacterGlobalInfoFn = async () => {
personId: personId.value
};
try{
const res = await getCharacterGlobalInfo(params);
if (res.code === 200) {
console.log("人物全局信息4", res);
if (res.data) {
characterInfo.value = res.data;
}
}
}catch(error){
......@@ -132,28 +201,42 @@ const getCharacterGlobalInfoFn = async () => {
};
const getCharacterRelationFn = async () => {
const params = {
personId: personId.value
};
try{
const res = await getCharacterRelation(params);
if (res.code === 200) {
console.log("人物关系", res);
if (res.data) {
CharacterRelation.value = res.data;
try{
const res = await getCharacterRelation(params);
if (res.code === 200) {
if (res.data) {
CharacterRelation.value = res.data;
}
}
}
// 创建圆形头像
console.log("[v0] characterInfo.value:", characterInfo.value);
console.log("[v0] characterInfo.value.imageUrl:", characterInfo.value.imageUrl);
const centerImageUrl = getProxyUrl(characterInfo.value.imageUrl);
console.log("[v0] centerImageUrl:", centerImageUrl);
const centerCircularImage = await createCircularImage(centerImageUrl, 160);
console.log("[v0] centerCircularImage:", centerCircularImage?.substring(0, 50));
if(CharacterRelation.value.length > 0){
// 并行创建所有圆形头像
const circularImages = await Promise.all(
CharacterRelation.value.map((item) =>
createCircularImage(getProxyUrl(item.imageUrl), 160)
)
);
const centerNode = {
id: "c",
name: characterInfo.value.name,
category: 0,
symbolSize: 80,
symbol: `image://${characterInfo.value.imageUrl}`,
symbol: `image://${centerCircularImage}`,
label: {
show: true,
position: "bottom",
......@@ -176,7 +259,7 @@ const getCharacterRelationFn = async () => {
name: item.name,
category: 1,
symbolSize: 80,
symbol: `image://${getProxyUrl(item.imageUrl)}`
symbol: `image://${circularImages[index]}`
}
});
......@@ -199,7 +282,7 @@ const getCharacterRelationFn = async () => {
name: characterInfo.value.name,
category: 0,
symbolSize: 80,
symbol: `image://${characterInfo.value.imageUrl}`,
symbol: `image://${centerCircularImage}`,
label: {
show: true,
position: "bottom",
......@@ -284,21 +367,36 @@ const getCharacterRelationFn = async () => {
};
const list = ref(["圆形布局", "力导向布局", "树形布局"]);
const list = ref([
{
value: "圆形布局",
label: "圆形布局",
icon: new URL('./assets/icon-circle.svg', import.meta.url).href,
},
{
value: "力导向布局",
label: "力导向布局",
icon: new URL('./assets/icon-force.svg', import.meta.url).href,
},
{
value: "树形布局",
label: "树形布局",
icon: new URL('./assets/icon-tree.svg', import.meta.url).href,
},
]);
const activeIndex = ref("圆形布局");
const handleChangeLayout = (layout) => {
activeIndex.value = layout;
};
let chart;
let chart;
onMounted(() => {
getCharacterGlobalInfoFn();
onMounted(async () => {
await getCharacterGlobalInfoFn();
getCharacterRelationFn();
const el = document.getElementById("relGraph");
if (!el) return;
......@@ -359,7 +457,6 @@ onMounted(() => {
});
};
setOption();
console.log("node1", nodes);
const onResize = () => chart && chart.resize();
window.addEventListener("resize", onResize);
watch(activeIndex, () => setOption());
......@@ -386,34 +483,44 @@ onMounted(() => {
.headerBox {
position: absolute;
top: 14px;
right: 96px;
left: 12px;
display: flex;
gap: 8px;
.headerItem {
padding: 1px 8px;
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 4px;
font-size: 16px;
font-weight: 400;
line-height: 30px;
cursor: pointer;
color: rgb(59, 65, 75);
font-family: "Microsoft YaHei";
margin-right: 8px;
border: 1px solid rgb(230, 231, 232);
background-color: #fff;
transition: all 0.3s ease;
img {
width: 20px;
height: 20px;
}
}
.active {
background-color: rgba(246, 250, 255, 1);
border-color: rgb(5, 95, 194);
color: rgb(5, 95, 194);
}
}
.headerBtnBox {
position: absolute;
top: 14px;
right: 12px;
img {
display: flex;
gap: 4px;
.btn-icon {
width: 28px;
height: 28px;
margin-right: 4px;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
transform: scale(1.1);
}
}
}
.mainBox {
......
......@@ -35,7 +35,7 @@
<script setup>
// 导入组件
import AnalysisBox from '@/components/base/BoxBackground/AnalysisBox.vue';
import AnalysisBox from '@/components/base/boxBackground/analysisBox.vue';
import { ref, watch } from 'vue';
import { getEnterpriseBranch, getEnterpriseKeyPerson } from '@/api/companyPages';
import PersonAvatar from '@/components/base/people/PersonAvatar.vue';
......
......@@ -5,8 +5,9 @@
<el-divider></el-divider>
<!-- 新闻列表 -->
<el-space :size="0" direction="vertical">
<news-item class="list-item" v-for="(t, i) in newsPage.content" :key="i" :news="t"></news-item>
<el-space class="full-width" :size="0" direction="vertical" fill alignment="flex-start">
<news-item class="list-item" v-for="(t, i) in newsPage.content" :key="i.id" :title="t.title" :from="t.from"
:content="t.content" @click="gotoNewsDetail(t.id)"></news-item>
</el-space>
<!-- 底部分隔线 -->
......@@ -20,14 +21,17 @@
</template>
<script setup>
import { ref, watch } from 'vue';
// 导入API
import { getEnterpriseNewDynamicPage } from '@/api/companyPages';
// 导入组件
import AnalysisBox from '@/components/base/BoxBackground/AnalysisBox.vue';
import AnalysisBox from '@/components/base/boxBackground/analysisBox.vue';
import NewsItem from '@/components/base/newsList/NewsItem.vue';
import { useGotoNewsDetail } from '@/router/modules/news';
import { ElDivider, ElSpace, ElPagination } from 'element-plus';
const gotoNewsDetail = useGotoNewsDetail()
// 导入Vue组合式API
import { ref, watch } from 'vue';
// 响应式数据
const newsPage = ref({}) // 新闻分页数据
......@@ -78,7 +82,11 @@ const onCurrentChange = e => {
<style lang="css" scoped>
/* 新闻列表项样式 */
.list-item {
margin-bottom: 20px;
width: 100%;
padding-bottom: 25px;
margin-bottom: 25px;
margin-left: 25px;
margin-right: 25px;
/* 底部外边距 */
border-bottom: 1px solid rgba(240, 242, 244, 1);
/* 底部边框 */
......
......@@ -3,7 +3,7 @@ import { ref, onMounted, onUnmounted, watch } from 'vue';
import { ElRadioGroup, ElRadioButton, ElSpace } from 'element-plus';
import * as echarts from 'echarts';
import { getSanctionList } from '@/api/companyPages';
import AnalysisBox from '@/components/base/BoxBackground/AnalysisBox.vue';
import AnalysisBox from '@/components/base/boxBackground/analysisBox.vue';
import AiTipPane from '@/components/base/panes/AiTipPane.vue'
export interface LineDataItem {
......
......@@ -50,7 +50,7 @@
</template>
<script setup>
import NewsList from "@/components/NewsList.vue";
import NewsList from "@/components/base/newsList/index.vue";
import { ref, onMounted } from "vue";
import router from '@/router'
import { getCoopRestrictionNews, getCoopRestrictionSocial } from '@/api/coopRestriction/coopRestriction'
......
......@@ -64,8 +64,7 @@
</div>
</div> -->
<div class="home-main-header-item-box">
<div class="item" v-for="(item, index) in govInsList" :key="index"
@click="handleToInstitution(item)">
<div class="item" v-for="(item, index) in govInsList" :key="index" @click="handleToInstitution(item)">
<div class="item-left">
<img :src="item.img ? item.img : DefaultIcon2" alt="" />
</div>
......@@ -123,8 +122,7 @@
}" v-for="(tag, index) in item.industryList" :key="index">
{{ tag.industryName }}
</div> -->
<AreaTag v-for="(tag, index) in item.industryList" :key="index"
:tagName="tag.industryName">
<AreaTag v-for="(tag, index) in item.industryList" :key="index" :tagName="tag.industryName">
</AreaTag>
</div>
<div class="box1-main-right-center">
......@@ -187,17 +185,16 @@
<div class="text">{{ "查看更多" }}</div>
</div>
</div> -->
<RiskSignal :list="warningList" @item-click="handleClickToDetail"
@more-click="handleToMoreRiskSignal" riskLevel="signalLevel" postDate="signalTime"
name="signalTitle">
<RiskSignal :list="warningList" @item-click="handleClickToDetail" @more-click="handleToMoreRiskSignal"
riskLevel="signalLevel" postDate="signalTime" name="signalTitle">
</RiskSignal>
</div>
<DivideHeader id="position2" class="divide2" :titleText="'资讯要闻'"></DivideHeader>
<div class="center-center">
<NewsList :newsList="newsList" @item-click="handleToNewsAnalysis" @more-click="handleToMoreNews" />
<!-- <NewsList :newsList="newsList" /> -->
<MessageBubble :messageList="messageList" @person-click="handleClickPerson"
@info-click="handleGetMessage" imageUrl="img" @more-click="handleToSocialDetail" />
<MessageBubble :messageList="messageList" @person-click="handleClickPerson" @info-click="handleGetMessage"
imageUrl="img" @more-click="handleToSocialDetail" />
</div>
<DivideHeader id="position3" class="divide3" :titleText="'数据总览'"></DivideHeader>
<div class="center-footer">
......@@ -212,8 +209,7 @@
<div class="box5-selectbox">
<el-select @change="handleBox5YearChange" v-model="box5SelectedYear" placeholder="选择时间"
style="width: 120px">
<el-option v-for="item in box5YearList" :key="item.value" :label="item.label"
:value="item.value" />
<el-option v-for="item in box5YearList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
......@@ -231,8 +227,7 @@
<div class="box6-selectbox">
<el-select @change="handleBox6YearChange" v-model="box6SelectedYear" placeholder="选择时间"
style="width: 120px">
<el-option v-for="item in box6YearList" :key="item.value" :label="item.label"
:value="item.value" />
<el-option v-for="item in box6YearList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
......@@ -248,8 +243,7 @@
<div class="header-title">{{ "关键行政令" }}</div>
</div>
<div class="box7-main">
<div class="box7-item" v-for="(item, index) in keyDecreeList" :key="index"
@click="handleKeyDecree(item)">
<div class="box7-item" v-for="(item, index) in keyDecreeList" :key="index" @click="handleKeyDecree(item)">
<div class="icon">
<img src="./assets/images/warning.png" alt="" />
</div>
......@@ -263,7 +257,7 @@
<template #reference>
<div class="info-content">{{ item.content ? item.content : "暂无数据" }}</div>
</template>
</el-popover> -->
</el-popover> -->
</div>
</div>
</div>
......@@ -312,9 +306,9 @@
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox v-for="type in decreeTypeList" :key="type.id"
v-model="checkedDecreeType" :label="type.typeId" style="width: 180px"
class="filter-checkbox" @change="handleChangeCheckedDecreeType">
<el-checkbox v-for="type in decreeTypeList" :key="type.id" v-model="checkedDecreeType"
:label="type.typeId" style="width: 180px" class="filter-checkbox"
@change="handleChangeCheckedDecreeType">
{{ type.typeName }}
</el-checkbox>
</div>
......@@ -356,8 +350,8 @@
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox v-for="time in pubTime" :key="time.id" v-model="activePubTime"
:label="time.id" style="width: 100px" class="filter-checkbox"
<el-checkbox v-for="time in pubTime" :key="time.id" v-model="activePubTime" :label="time.id"
style="width: 100px" class="filter-checkbox"
@change="checked => handlePubTimeChange(time.id, checked)">
{{ time.name }}
</el-checkbox>
......@@ -388,8 +382,7 @@
<div class="title">{{ "政令库" }}</div>
</div>
<div class="content-box" v-show="decreeList">
<div class="main-item" v-for="(item, index) in decreeList" :key="index"
@click="handleClickDecree(item)">
<div class="main-item" v-for="(item, index) in decreeList" :key="index" @click="handleClickDecree(item)">
<div class="main-item-left">
<div class="left-left">
{{ item.time?.split("-")[0] }}<br />{{ item.time?.split("-")[1] }}月{{
......@@ -422,9 +415,8 @@
{{ `共 ${totalDecreesNum} 项` }}
</div>
<div class="footer-right">
<el-pagination @current-change="handleCurrentChange" :pageSize="10"
:current-page="currentPage" background layout="prev, pager, next"
:total="totalDecreesNum" />
<el-pagination @current-change="handleCurrentChange" :pageSize="10" :current-page="currentPage"
background layout="prev, pager, next" :total="totalDecreesNum" />
</div>
</div>
</div>
......@@ -435,7 +427,7 @@
</template>
<script setup>
import NewsList from "@/components/base/newsList/index.vue";
import NewsList from "@/components/base/NewsList/index.vue";
import { onMounted, ref, watch, nextTick } from "vue";
import router from "@/router";
import {
......@@ -633,7 +625,7 @@ const handlegetDecreeRiskSignal = async () => {
const res = await getDecreeRiskSignal(params);
console.log("风险信号", res);
if (res.code === 200 && res.data) {
warningList.value = res.data.map(item => ({...item, id:item.orderId}));
warningList.value = res.data.map(item => ({ ...item, id: item.orderId }));
}
} catch (error) {
console.error("风险信号error", error);
......@@ -3324,10 +3316,12 @@ onMounted(async () => {
letter-spacing: 0px;
border-radius: 4px;
}
.type1 {
color: rgba(232, 189, 11, 1);
background: rgba(232, 189, 11, 0.1);
}
.type2 {
color: rgba(255, 149, 77, 1);
background: rgba(255, 149, 77, 0.1);
......
......@@ -17,8 +17,8 @@ const getWordCloudChart = (data) => {
// 其他形状你可以使用形状路径
// shape: 'circle', // 示例
// 或者自定义路径
gridSize: 30, // 网格大小,影响词间距。
sizeRange: [15, 40], // 定义词云中文字大小的范围
gridSize: 35, // 网格大小,影响词间距。
sizeRange: [16, 36], // 定义词云中文字大小的范围
rotationRange: [0, 0],
rotationStep: 0,
drawOutOfBound: false, // 是否超出画布
......
......@@ -151,15 +151,12 @@ const fieldAnalysis = ref('人工智能与信息技术占据最大份额,反
const radarAnalysis = ref('研究型大学在基础科学领域(生物医学、材料科学)占据主导地位;科技企业高度集中于人工智能和信息技术领域;国家实验室在能源技术和国家安全相关领域有显著优势;国防承包商的研究高度集中于航空航天和国家安全领域。')
// 切换视图
function switchView(view: string) {
console.log('[v0] switchView 被调用, view:', view, ', currentView:', currentView.value)
function switchView(view: string) {
if (currentView.value !== view) {
currentView.value = view
if (view === 'ranking') {
console.log('[v0] 切换到排名视图,调用 handleGetOverallRanking')
if (view === 'ranking') {
handleGetOverallRanking()
} else {
console.log('[v0] 切换到研究布局视图,调用 handleGetResearchField 和 handleGetResearchFieldSubjectType')
} else {
handleGetResearchField()
handleGetResearchFieldSubjectType()
}
......@@ -174,8 +171,7 @@ const handleGetOverallRanking = async () => {
subjectTypeId: props.activeCate1,
year: releaseTime.value
}
const res = await getOverallRanking(params)
console.log('[v0] 综合排名', res)
const res = await getOverallRanking(params)
if (res.code === 200 && res.data) {
innoItemList.value = res.data
}
......@@ -192,8 +188,7 @@ const handleGetResearchField = async () => {
const params = {
year: releaseTime.value
}
const res = await getResearchField(params)
console.log('[v0] 研究领域布局情况', res)
const res = await getResearchField(params)
if (res.code === 200 && res.data) {
const names = res.data.map(item => item.areaName)
const values = res.data.map(item => item.amount)
......@@ -215,8 +210,7 @@ const handleGetResearchFieldSubjectType = async () => {
const params = {
year: releaseTime.value
}
const res = await getResearchFieldSubjectType(params)
console.log('[v0] 研究领域主体类型', res)
const res = await getResearchFieldSubjectType(params)
if (res.code === 200 && res.data) {
raderOptionData.value = res.data
}
......
......@@ -311,7 +311,7 @@
<script setup>
import RiskSignal from "@/components/RiskSignal/RiskSignal.vue";
import RiskSignal from "@/components/base/riskSignal/index.vue";
import NewsList from "@/components/base/newsList/index.vue";
import { onMounted, ref, computed } from "vue";
import * as echarts from "echarts";
......
......@@ -390,7 +390,7 @@
</template>
<script setup>
import { onMounted, ref } from "vue";
import { onMounted, ref, nextTick } from "vue";
import LeftBtn from "@/components/base/PageBtn/LeftBtn.vue";
import RightBtn from "@/components/base/PageBtn/RightBtn.vue";
......@@ -426,6 +426,29 @@ import {
import { getRiskSignal, getNews, getRemarks } from "@/api/common/index";
import { ElMessage } from "element-plus";
const handleToPosi = id => {
const element = document.getElementById(id);
if (element && containerRef.value) {
// // 1. 如果是从完整搜索框跳转,先强制切换状态稳定布局
// if (!isShow.value) {
// isShow.value = true;
// }
// 2. 使用 nextTick 等待 DOM 布局(如高度切换)完成后再进行坐标计算
nextTick(() => {
const containerRect = containerRef.value.getBoundingClientRect();
const elementRect = element.getBoundingClientRect();
// 使用 getBoundingClientRect 计算元素相对于容器顶部的绝对距离
const top = elementRect.top - containerRect.top + containerRef.value.scrollTop;
containerRef.value.scrollTo({
top: top,
behavior: "smooth"
});
});
}
};
const formatDate = (dateStr, dateType) => {
if (!dateStr) return "";
const date = new Date(dateStr);
......@@ -1052,6 +1075,7 @@ const pageSize = ref(10);
const currentPage = ref(1);
const totalDiscussNum = ref(0);
const handleCurrentChange = page => {
handleToPosi("position4")
currentPage.value = page;
handleGetSurveyList();
};
......
......@@ -118,9 +118,9 @@
</AnalysisBox>
</div>
</div>
<div class="graph-box" id="graphChart">
<!-- <div class="graph-box" id="graphChart">
</div>
</div> -->
</div>
</template>
<script setup>
......
......@@ -4,10 +4,10 @@
<back />
</el-icon> 返回</el-button>
<el-space style="width: 993px;" direction="vertical" alignment="flex-start">
<div style="margin-top: 50px; margin-bottom: 24px; margin-left: 24px;">
<div id="ref-news-list" style="margin-top: 50px; margin-bottom: 24px; margin-left: 24px;">
<common-text class="text-title-0-show" color="var(--text-primary-90-color)">{{
moduleName
}}</common-text>
}}</common-text>
<common-text class="text-regular"
color="var(--text-primary-65-color)">基于情报价值评估预测算法,掌握全球重要潜在动向</common-text>
</div>
......@@ -21,9 +21,12 @@
</el-space>
</el-radio-group>
<el-divider style="margin: 10px 0px;"></el-divider>
<div class="">
<news-list :news="NewsData" />
<div v-if="NewsData?.content?.length > 0">
<news-list :news="NewsData.content" />
</div>
<el-empty v-else></el-empty>
<el-pagination background layout="total, ->, prev, pager, next" :current-page="modulePage"
:total="NewsData?.totalElements ?? 0" v-on:current-change="onCurrentChange" />
</el-space>
</el-space>
</el-space>
......@@ -36,32 +39,44 @@ import '@/styles/container.scss';
import '@/styles/radio.scss';
import NewsList from "./NewsList.vue";
import { getAreaList, getHotNewsByArea } from "@/api/news/newsBrief";
import { ElSpace, ElDivider, ElRadioButton, ElRadioGroup, ElButton, ElIcon } from "element-plus";
import { ElSpace, ElDivider, ElRadioButton, ElRadioGroup, ElButton, ElIcon, ElEmpty, ElPagination } from "element-plus";
import CommonText from "@/components/base/texts/CommonText.vue";
import { useGotoNewsBrief } from "@/router/modules/news";
import { scrollToElement } from "@/router/common";
import { number } from "echarts";
const route = useRoute();
const gotoNewsBrief = useGotoNewsBrief();
const moduleId = ref(route.params.id);
const moduleName = ref(route.query.name ?? "");
const NewsData = ref([]);
const modulePage = ref(1);
const NewsData = ref({});
const AreaList = ref([]);
const currentAreaId = ref("");
onMounted(async () => {
console.log(route.query.name, moduleId.value, moduleName.value);
const { data: areaList } = await getAreaList();
AreaList.value = areaList ?? [];
await changeArea("")
await updateDate("")
});
async function changeArea(id) {
const onCurrentChange = async e => {
await updateDate(currentAreaId.value, e - 1)
scrollToElement("ref-news-list");
}
async function updateDate(id, page = 0) {
const { data } = await getHotNewsByArea({
moduleId: moduleId.value,
industryId: id ? id : null,
currentPage: page,
});
data?.forEach(item => {
data?.content?.forEach(item => {
item.newsImage = item.coverUrl ?? ""
})
NewsData.value = data ?? [];
modulePage.value = (data?.number ?? 0) + 1;
}
async function changeArea(id) {
await updateDate(id, 0)
}
</script>
......
......@@ -34,49 +34,34 @@
</color-prefix-title>
<div class="flex-fill"></div>
<el-switch v-model="isHightLightEntity" active-text="高亮实体" @change="handleHighlightEntity" />
<el-button v-if="hasTranslation" :type="isOpenTranslation ? 'primary' : ''" plain
<el-button v-if="textZns.length > 0" :type="isOpenTranslation ? 'primary' : ''" plain
@click="handleTranslation">
<color-svg :svg-url="TranslationSvg" color="var(--color-primary-100)" :size="18"
style="margin-right:10px"></color-svg>
译文
</el-button>
</div>
<div class="common-padding">
<div class="flex-display" style="align-items: center;">
<common-text class="text-title-3-bold" color="var(--text-primary-80-color)">{{ isOpenTranslation
? '中文' : '原文' }}</common-text>
<div class="flex-fill" style="margin: 0 10px;">
<el-divider></el-divider>
</div>
<el-button v-if="zhEnTexts.length > 6" @click="() => showMore = !showMore">
{{ showMore ? '收起' : '展开' }}
<el-icon>
<arrow-down v-if="showMore" />
<arrow-up v-else />
</el-icon>
</el-button>
</div>
<el-row :gutter="32">
<el-col :span="znEnColSpan"
v-for="(item, index) in showMore ? zhEnTexts : zhEnTexts.slice(0, 6)" :key="index">
<!-- <p class="p-news-content"> {{ item }}</p> -->
<intelligent-entity-text :text="item"
:entities="isHightLightEntity ? textEntities : []"></intelligent-entity-text>
</el-col>
</el-row>
<text-translate-pane class="common-padding-h" :texts-raw="textEns" :texts-translate="textZns"
:text-entities="textEntities" :is-open-translation="isOpenTranslation"
:is-highlight-entity="isHightLightEntity">
</text-translate-pane>
<div>
<img v-if="newsDetail.coverUrl" class="common-padding" :src="newsDetail.coverUrl" :width="320"
:height="240" />
</div>
</el-space>
<el-space direction="vertical" class="background-as-card relation-news-box" alignment="flex-start">
<el-space direction="vertical" class="background-as-card relation-news-box" fill>
<el-space style="margin-top: 10px;">
<color-prefix-title height="20px">
<div class="text-title-2-bold">相关新闻</div>
</color-prefix-title>
</el-space>
<el-space direction="vertical" fill class="common-padding">
<news-item v-for="item in relationNews" :key="item.newsId" :news="item" :img="item.newsImage"
<el-space v-if="relationNews?.length > 0" direction="vertical" fill class="common-padding">
<news-item-mini v-for="item in relationNews" :key="item.newsId" :news="item" :img="item.newsImage"
:title="item.newsTitle" :from="`${item.newsDate} · ${item.newsOrg}`"
@click="gotoNewsDetail(item.newsId)" />
</el-space>
<el-empty v-else style=""></el-empty>
</el-space>
</div>
</el-scrollbar>
......@@ -87,28 +72,26 @@ import '@/styles/container.scss';
import '@/styles/common.scss';
import { ref, onMounted } from "vue";
import { useRoute } from "vue-router";
import { ElSpace, ElImage, ElButton, ElIcon, ElScrollbar, ElRow, ElCol, ElDivider, ElSwitch } from "element-plus";
import { ElSpace, ElButton, ElScrollbar, ElSwitch, ElEmpty, ElImage } from "element-plus";
import CommonText from "@/components/base/texts/CommonText.vue";
import AreaTag from "@/components/base/AreaTag/index.vue";
import ColorPrefixTitle from '@/components/base/texts/ColorPrefixTitle.vue';
import { getRelationNews } from "@/api/news/newsDetail";
import NewsItem from "@/components/base/newsList/NewsItem.vue";
import NewsItemMini from "@/components/base/newsList/NewsItemMini.vue";
import ColorSvg from "@/components/base/images/ColorSvg.vue";
import TranslationSvg from './assets/images/翻译 1.svg';
import NewsLogo from './assets/images/组合 293.svg';
import { extractTextEntity } from "@/api/intelligent";
import { useGotoNewsDetail } from "@/router/modules/news";
import IntelligentEntityText from "@/components/base/texts/IntelligentEntityText.vue";
import TextTranslatePane from "@/components/base/texts/TextTranslatePane.vue";
const newsDetail = ref({});
const relationNews = ref([]);
const zhEnTexts = ref([]);
const znEnColSpan = ref(12);
const hasTranslation = ref(false);
const isOpenTranslation = ref(true);
const isHightLightEntity = ref(true);
const textEntities = ref([]);
const showMore = ref(false);
const textZns = ref([]);
const textEns = ref([]);
const route = useRoute();
const gotoNewsDetail = useGotoNewsDetail();
......@@ -118,50 +101,26 @@ onMounted(async () => {
}
const { data: newsDetailData } = await getNewsDetail(params);
newsDetail.value = newsDetailData ?? {};
textZns.value = newsDetail.value?.contentZh?.split('\n') ?? [];
textEns.value = newsDetail.value?.content?.split('\n') ?? [];
const { data: relationNewsData } = await getRelationNews(params);
relationNews.value = relationNewsData ?? [];
console.log(relationNews.value)
updateText();
await handleHighlightEntity();
});
async function handleHighlightEntity() {
if (textEntities.value.length > 0) return
const { result: entityDataZh } = await extractTextEntity(newsDetail.value.contentZh);
const { result: entityDataZh } = await extractTextEntity(newsDetail.value?.contentZh ?? '');
textEntities.value = [...entityDataZh ?? []]
if (newsDetail.value.contentZh !== newsDetail.value.content) {
const { result: entityData } = await extractTextEntity(newsDetail.value.content);
const { result: entityData } = await extractTextEntity(newsDetail.value?.content ?? '');
textEntities.value = [...textEntities.value, ...entityData ?? []]
}
console.log(isHightLightEntity.value)
}
function handleTranslation() {
isOpenTranslation.value = !isOpenTranslation.value;
updateText();
}
function updateText() {
const enTexts = newsDetail.value.content?.split('\n')
const zhTexts = newsDetail.value.contentZh?.split('\n')
console.log(enTexts.length, zhTexts.length)
const tempZhEnTexts = []
hasTranslation.value = enTexts.length === zhTexts.length
if (hasTranslation.value && isOpenTranslation.value) {
for (let i = 0; i < enTexts.length; i++) {
tempZhEnTexts.push(zhTexts[i]);
tempZhEnTexts.push(enTexts[i]);
}
znEnColSpan.value = 12;
} else {
for (let i = 0; i < enTexts.length; i++) {
tempZhEnTexts.push(enTexts[i]);
}
znEnColSpan.value = 24;
}
zhEnTexts.value = tempZhEnTexts;
}
</script>
......
<template>
<el-space direction="vertical" fill class="full-width mouse-hover" v-for="(item, index) in props.news" :key="index">
<news-item2 :img="item.newsImage" :title="item.newsTitle" :from="`新闻来源:${item.newsOrg} 发表时间:${item.newsDate}`"
:aeraTags="item.industryList?.map(t => t.industryName)" @click="gotoNewsDetail(item.newsId)" />
<news-item-with-tag :img="item.newsImage" :title="item.newsTitle"
:from="`新闻来源:${item.newsOrg} 发表时间:${item.newsDate}`" :aeraTags="item.industryList?.map(t => t.industryName)"
@click="gotoNewsDetail(item.newsId)" />
<div class="divider-news-list"></div>
</el-space>
</template>
<script setup>
import NewsItem2 from '@/components/base/newsList/NewsItem2.vue';
import NewsItemWithTag from '@/components/base/newsList/NewsItemWithTag.vue';
import { useGotoNewsDetail } from '@/router/modules/news';
import { ElSpace } from 'element-plus';
......
......@@ -61,7 +61,7 @@
</template>
<script setup>
import NewsList from "@/components/NewsList.vue";
import NewsList from "@/components/base/newsList/index.vue";
import { ref, onBeforeMount } from "vue";
import router from "@/router"
......
......@@ -3,13 +3,8 @@
<div class="main-content" ref="homeMainRef">
<div class="home-top-bg"></div>
<!-- 搜索栏部分 -->
<SearchContainer
v-if="homeMainRef"
:countInfo="statCountInfo"
placeholder="搜索规则限制"
:containerRef="homeMainRef"
areaName=""
/>
<SearchContainer v-if="homeMainRef" :countInfo="statCountInfo" placeholder="搜索规则限制" :containerRef="homeMainRef"
areaName="" />
<!-- 最新动态 -->
<div class="newdata" id="position1">
<com-title title="最新动态" />
......
......@@ -215,9 +215,11 @@ onMounted(async () => {
margin: 0;
padding: 0;
}
.coop-page {
width: 100%;
height: 100%;
// .breadcrumb {
// width: 100%;
// height: 64px;
......@@ -245,6 +247,7 @@ onMounted(async () => {
width: 960px;
height: 168px;
margin: 0 auto 68px auto;
.search-center {
width: 688px;
height: 48px;
......@@ -284,6 +287,7 @@ onMounted(async () => {
}
}
}
.search-main {
display: flex;
padding-right: 3px;
......@@ -295,9 +299,11 @@ onMounted(async () => {
background-color: rgba(255, 255, 255, 0.65);
border-radius: 10px;
border: 1px solid #fff;
&:hover {
border: 1px solid var(--color-main-active);
}
.search-input {
border: none;
outline: none;
......@@ -315,6 +321,7 @@ onMounted(async () => {
color: #a8abb2;
}
}
.search-btn {
cursor: pointer;
display: flex;
......@@ -330,6 +337,7 @@ onMounted(async () => {
font-family: "Microsoft YaHei";
line-height: 22px;
color: #fff;
img {
width: 18px;
height: 18px;
......@@ -337,6 +345,7 @@ onMounted(async () => {
}
}
}
.search-bottom {
width: 688px;
height: 48px;
......@@ -344,6 +353,7 @@ onMounted(async () => {
margin-top: 36px;
display: flex;
justify-content: space-between;
// gap: 16px;
.btn {
display: flex;
......@@ -357,9 +367,11 @@ onMounted(async () => {
background: #e7f3ff;
cursor: pointer;
position: relative;
&:hover {
background: #cae3fc;
}
.btn-text {
width: 80px;
color: var(--color-main-active);
......@@ -370,12 +382,14 @@ onMounted(async () => {
margin-left: 36px;
text-align: center;
}
.btn-icon {
position: absolute;
top: 16px;
right: 19px;
width: 6px;
height: 12px;
img {
width: 100%;
height: 100%;
......@@ -384,40 +398,48 @@ onMounted(async () => {
}
}
}
.newdata {
width: 1600px;
height: 538px;
margin: 36px auto 64px auto;
.newdata-main {
width: 1600px;
height: 460px;
margin-top: 36px;
}
}
.ask {
width: 1600px;
height: 528px;
margin: 0 auto 64px auto;
.ask-main {
width: 1600px;
height: 450px;
margin-top: 36px;
}
}
.datasub {
width: 1600px;
height: 538px;
margin: 0 auto 88px auto;
.datasub-main {
width: 1600px;
height: 460px;
margin-top: 36px;
}
}
.reslib {
width: 1600px;
height: 1633px;
margin: 0 auto 0px auto;
.reslib-main {
width: 1600px;
height: 1565px;
......@@ -486,6 +508,7 @@ onMounted(async () => {
.search-icon {
width: 18px;
height: 18px;
img {
width: 100%;
height: 100%;
......@@ -522,9 +545,11 @@ onMounted(async () => {
background: #e7f3ff;
cursor: pointer;
position: relative;
&:hover {
background: #cae3fc;
}
.btn-text {
width: 80px;
color: var(--color-main-active);
......@@ -535,12 +560,14 @@ onMounted(async () => {
margin-left: 36px;
text-align: center;
}
.btn-icon {
position: absolute;
top: 16px;
right: 19px;
width: 6px;
height: 12px;
img {
width: 100%;
height: 100%;
......
......@@ -53,7 +53,7 @@
</template>
<script setup>
import NewsList from "@/components/NewsList.vue";
import NewsList from "@/components/base/newsList/index.vue";
import { ref, onMounted } from "vue";
import {
......
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.000000" height="24.000000" fill="none" customFrame="#000000">
<rect id="容器 1603" width="24.000000" height="24.000000" x="0.000000" y="0.000000" />
<path id="矢量 1680" d="M18.506 13.4068L5.49373 13.4068C4.80439 13.4068 4.23005 12.8787 4.17272 12.1925L4.00237 10.1513C3.96989 9.76532 4.27512 9.43428 4.66288 9.43428L19.3372 9.43428C19.7249 9.43428 20.0298 9.76532 19.9977 10.1513L19.8273 12.1925C19.77 12.8787 19.1957 13.4068 18.506 13.4068ZM18.4003 14.0688L5.59945 14.0688L6.9251 24L17.0746 24L18.4003 14.0688ZM12.0565 4.46505C13.291 4.46505 14.2916 3.46532 14.2916 2.23253C14.2916 0.999407 13.2907 0 12.0565 0C10.8223 0 9.82148 0.999738 9.82148 2.23253C9.82115 3.46532 10.822 4.46505 12.0565 4.46505ZM17.1368 8.7722L16.6473 6.589C16.523 6.03385 16.0686 5.61277 15.5052 5.53001L13.5177 5.23803L12.5334 7.49373L12.4065 6.3821C12.4032 6.34701 12.3734 6.3202 12.3382 6.3202L11.7758 6.3202C11.74 6.3202 11.7105 6.34734 11.7072 6.38276L11.5919 7.5222L10.5953 5.23836L8.60785 5.53034C8.04445 5.6131 7.59008 6.03418 7.4658 6.58933L6.9763 8.7722L17.1368 8.7722ZM11.3688 5.32377C11.3695 5.53001 11.5399 5.80477 11.6429 5.90772C11.746 6.01068 11.919 6.01068 12.0565 6.01068C12.1941 6.01068 12.3671 6.01068 12.4701 5.90772C12.5732 5.80477 12.7435 5.53001 12.7442 5.32377C12.7452 5.08344 12.3243 5.04901 12.0565 5.04901C11.7884 5.04901 11.3679 5.0831 11.3688 5.32377Z" fill="rgb(5,95,194)" fill-rule="nonzero" />
</svg>
......@@ -19,7 +19,10 @@
</div>
</div>
<div class="header-top-right">
<div class="name">{{ thinkInfo.thinkTankName }}</div>
<div class="image-name-box">
<div class="image"> <img :src=thinkInfo.thinkTankLogoUrl alt="" /></div>
<div class="name">{{ thinkInfo.thinkTankName }}</div>
</div>
<div class="time">{{ thinkInfo.times }}</div>
</div>
</div>
......@@ -47,6 +50,12 @@
</div>
<div class="text">{{ "查看官网" }}</div>
</div> -->
<div class="btn">
<div class="icon">
<img src="./images/btn-icon2.png" alt="" />
</div>
<div class="text" @click="goToOfficialWebsite()">{{ "查看官网" }}</div>
</div>
<div class="btn">
<div class="icon">
<img src="./images/btn-icon2.png" alt="" />
......@@ -69,7 +78,7 @@
</div>
</div>
<div class="main">
<ReportAnalysis v-if="tabActiveName === '报告分析'"></ReportAnalysis>
<ReportAnalysis v-if="tabActiveName === '报告分析'" :thinkInfo="thinkInfo" :reportList="reportList"></ReportAnalysis>
<PolicyTracking v-else></PolicyTracking>
</div>
</div>
......@@ -80,12 +89,13 @@ import { ref, onMounted } from "vue";
import ReportAnalysis from "./reportAnalysis/index.vue";
import PolicyTracking from "./policyTracking/index.vue";
import { getThinkTankReportSummary } from "@/api/thinkTank/overview";
import { getThinkTankReportSummary, getThinkTankReportRelated } from "@/api/thinkTank/overview";
import { useRoute, useRouter } from "vue-router";
const router = useRouter();
const route = useRoute();
const reportUrl = ref("");
const thinkInfo = ref({});
const reportList = ref({})
// 获取报告全局信息
const handleGetThinkTankReportSummary = async () => {
......@@ -101,7 +111,20 @@ const handleGetThinkTankReportSummary = async () => {
console.error("获取报告全局信息error", error);
}
};
// 获取相关报告信息
const handleGetThinkTankReport = async () => {
try {
const res = await getThinkTankReportRelated(router.currentRoute._value.params.id);
console.log("报告全局信息", res);
if (res.code === 200 && res.data) {
reportList.value = res.data;
}
} catch (error) {
console.error("获取相关报告error", error);
}
};
const toReport = () => {
console.log(reportUrl.value, "reportUrl.valuereportUrl.value");
const route = router.resolve({
......@@ -129,7 +152,17 @@ const handleAnalysisClick = () => {
};
onMounted(async () => {
handleGetThinkTankReportSummary();
handleGetThinkTankReport();
});
const goToOfficialWebsite = () => {
const url = thinkInfo.value?.reportUrl;
if (!url) {
return;
}
// 简单校验一下,防止空字符串
window.open(url, "_blank");
};
</script>
<style lang="scss" scoped>
......@@ -199,15 +232,46 @@ onMounted(async () => {
}
.header-top-right {
.name {
display: flex;
flex-direction: column;
text-align: right;
align-items: flex-end;
.image-name-box {
width: 118px;
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
gap: 6px;
text-align: right;
display: flex;
justify-content: flex-end;
.name {
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: right;
}
.image {
width: 16px;
height: 16px;
margin-top: 5px;
img {
width: 100%;
height: 100%;
}
}
}
.time {
......
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论