提交 88a48798 authored 作者: 张烨's avatar 张烨

代码合并

......@@ -7,6 +7,10 @@ yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
*.rar
*.zip
*.7z
# Dependencies
node_modules
.pnpm
......@@ -14,6 +18,7 @@ node_modules
# Build outputs
dist
dist.rar
dist-ssr
*.local
......
......@@ -2,85 +2,11 @@
<div id="app">
<div class="pro-wrapper">
<div class="home-page">
<!-- <div class="navbar">
<div class="nav-content">
<div class="nav-left">
<div class="icon">
<img src="@/assets/icons/overview/logo.png" alt="" />
</div>
<div class="title-box">
<div class="title" v-for="(item, index) in homeTitleList" :key="index"
@mouseenter="handleShowMenu(index, true)" @mouseleave="handleShowMenu(index, false)"
@click="handleClickTitle(item)">
<div class="text" :class="{ textActive: homeActiveTitleIndex === index }">
{{ item.name }}
</div>
<div class="bottom-line" v-if="homeActiveTitleIndex === index"></div>
</div>
</div>
</div>
<div class="nav-right">
<div class="search-box">
<div class="input"><el-input type="text" v-model="searchText" @keyup.enter="handleSearch" /></div>
<div class="icon" @click="handleSearch">
<img src="@/assets/icons/overview/search.png" alt="" />
</div>
</div>
<div class="info-box" @click="handleClickToolBox">
<div class="mail">
<img src="@/assets/icons/overview/mail.png" alt="" />
</div>
<div class="user">
<img src="@/assets/icons/overview/user.png" alt="" />
</div>
<div class="name">{{ "管理员" }}</div>
</div>
</div>
<div class="menu-box" v-if="isShowMenu" @mouseenter="handleHoverMenu(true)"
@mouseleave="handleHoverMenu(false)">
<div class="menu-content">
<div class="menu-item" v-for="(item, index) in menuList" :key="index" @click="handleToModule(item)">
<div class="icon">
<img :src="item.icon" alt="" />
</div>
<div class="title">{{ item.title }}</div>
</div>
</div>
</div>
</div>
</div> -->
<NavBarV2/>
<ModuleHeader/>
<div class="main-container">
<router-view />
</div>
</div>
<!-- <div class="content-page" v-if="!isCurrentOverview">
<div class="navbar">
<div class="nav-brand">
<div class="brand-icon">
<img src="@/assets/icons/header-logo.png" alt="" />
</div>
<div class="brand-text" @click="handleToHome">
<div class="text-ch">某方向风险监测预警系统</div>
</div>
</div>
<div class="user-info">
<div class="email">
<img src="@/assets/icons/header-icon.png" alt="" />
</div>
<div class="avator">
<img src="@/assets/icons/header-avator.png" alt="" />
</div>
<span class="user">管理员</span>
</div>
</div>
<div class="main-container">
<router-view />
</div>
</div> -->
<div class="right-btn" @click="handleClickToolBox">
<div class="item">
<div class="icon">
......@@ -127,10 +53,8 @@
<script setup>
import { ref, computed, onMounted } from "vue";
import { Monitor, House, User, Location, Document, Bell, Message, ArrowDown } from "@element-plus/icons-vue";
import { useRouter } from "vue-router";
import { useRoute } from "vue-router";
import Breadcrumb from "@/components/BreadCrumb/index.vue";
import AiBox from "./components/AiBox.vue";
import { getPersonType } from "@/api/common/index";
// import { useDraggable } from "@vueuse/core";
......
......@@ -10,7 +10,7 @@
</div>
</div>
<div class="box3-main">
<div class="box3-item" v-for="(news, index) in list.slice(0,5)" :key="index" @click="handleClickToNewsDetail(news)">
<div class="box3-item" v-for="(news, index) in list" :key="index" @click="handleClickToNewsDetail(news)">
<div class="left">
<img
:src="getProxyUrl(news.newsImage) || defaultImg"
......
差异被折叠。
......@@ -9,7 +9,8 @@
<div class="num">{{ list.length }}</div>
</div>
</div>
<div class="box2-main">
<div class="box2-main" v-infinite-scroll="loadMore" :infinite-scroll-disabled="allLoaded || loading"
:infinite-scroll-distance="10" v-loading="loading">
<div class="box2-main-item" v-for="(item, index) in list" :key="index" @click="handleItemClick(item, index)">
<div :class="{
......@@ -37,6 +38,7 @@
</template>
<script setup>
import { ref } from 'vue'
import { ElMessage } from "element-plus";
// 接收父组件传递的参数
const props = defineProps({
......@@ -72,11 +74,19 @@ const props = defineProps({
type: String,
default: "riskLevel"
},
allLoaded: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
},
});
// 定义自定义事件,把点击事件传递给父组件
const emit = defineEmits(['item-click', 'more-click']);
const emit = defineEmits(['item-click', 'more-click', 'loadMore']);
// 点击单条风险信号
const handleItemClick = (item, index) => {
......@@ -85,10 +95,84 @@ const handleItemClick = (item, index) => {
// 点击“查看更多”
const handleMoreClick = () => {
emit('more-click')
};
// const allLoaded = ref(false)
// const loading = ref(false)
// const currentPage = ref(0)
// const pageSize = ref(7)
// const loadMore = async () => {
// if (allLoaded.value || loading.value) return;
// // await fetchListData(true); // 传入 true 表示追加数据
// ElMessage.success('追加数据')
// }
// // 添加初始化函数来获取数据
// const fetchListData = async (append = false) => {
// console.log("加载状态 =>", loading.value, allLoaded.value);
// if (loading.value || allLoaded.value) return;
// try {
// loading.value = true;
// // 调用接口获取数据
// const response = await getStrategiesTopN(currentPage.value, pageSize.value, countryName.value);
// const apiData = response.data || [];
// // 转换数据格式
// const newData =
// apiData.content?.map(item => ({
// ...item,
// img: item.countryImageUrl, // 使用默认图片或根据需要调整
// title: item.titleZh,
// content: item.contentZh,
// time: formatTime(item.date), // 转换时间格式
// tagList: item.domains
// ? item.domains.slice(0, 2).map(field => ({
// name: field,
// status: Math.floor(Math.random() * 3) + 1 // 随机分配 1-3 的状态值
// }))
// : []
// })) || [];
// if (newData.length > 0) {
// if (append) {
// // 追加数据
// list.value = [...list.value, ...newData];
// } else {
// // 替换数据
// list.value = [...newData];
// }
// // 检查是否还有更多数据(根据实际 API 响应调整判断逻辑)
// if (newData.length < pageSize.value) {
// allLoaded.value = true;
// } else {
// currentPage.value++;
// }
// } else {
// allLoaded.value = true;
// }
// console.log("获取策略数据成功:", list.value);
// } catch (error) {
// console.error("获取策略数据失败:", error);
// // 错误处理,停止加载状态但不重置数据
// if (!append && list.value.length === 0) {
// list.value = [];
// }
// } finally {
// loading.value = false;
// }
// };
const loadMore = () => {
emit('loadMore')
}
</script>
......
<template>
<div class="search-container" v-show="!isShow">
<div class="search-main">
<input v-model="store.searchBillText" :placeholder="placeholder" @keyup.enter="handleSearch" class="search-input" />
<div class="search-type-tabs" v-if="enableBillTypeSwitch">
<div class="search-type-tab" :class="{ active: billSearchType === 'federal' }"
@click="handleChangeBillSearchType('federal')">
联邦议会
</div>
<div class="search-type-tab" :class="{ active: billSearchType === 'state' }"
@click="handleChangeBillSearchType('state')">
州议会
</div>
</div>
<div class="search-main" :class="{ 'search-main-with-tabs': enableBillTypeSwitch }">
<input v-model="store.searchBillText" :placeholder="placeholder" @keyup.enter="handleSearch"
class="search-input" />
<div class="search-btn" @click="handleSearch">
<img src="@/assets/icons/search-icon.png" alt />
搜索
......@@ -43,19 +54,26 @@
</template>
<script setup>
import { ref, nextTick, watchEffect, onMounted } from "vue";
import { ref, nextTick, watchEffect } from "vue";
import { useContainerScroll } from "@/hooks/useScrollShow";
import { useRouter } from "vue-router";
import { useWrittingAsstaintStore } from "@/stores/writtingAsstaintStore";
const store = useWrittingAsstaintStore();
const router = useRouter();
let { countInfo, containerRef, placeholder, areaName } = defineProps({
const {
countInfo,
containerRef,
placeholder,
areaName,
enableBillTypeSwitch,
defaultBillSearchType
} = defineProps({
countInfo: {
type: Array,
default: () => []
},
containerRef: {
type: Object,
default: {}
......@@ -67,18 +85,48 @@ let { countInfo, containerRef, placeholder, areaName } = defineProps({
areaName: {
type: String,
default: "法案"
},
// 法案页专用:是否展示“联邦议会/州议会”搜索类型切换
// 其他页面默认 false,不受影响
enableBillTypeSwitch: {
type: Boolean,
default: false
},
// 法案页专用:默认搜索类型
// 可选值:'federal'(联邦议会)| 'state'(州议会)
defaultBillSearchType: {
type: String,
default: "federal"
}
});
// 法案搜索类型状态(仅在 enableBillTypeSwitch=true 时生效)
// 维护说明:
// - federal: 联邦议会
// - state: 州议会
const billSearchType = ref(defaultBillSearchType === "state" ? "state" : "federal");
const handleChangeBillSearchType = type => {
billSearchType.value = type;
};
const handleSearch = () => {
window.sessionStorage.setItem("curTabName", `搜索-${store.searchBillText}`);
if (!areaName) return;
const query = {
searchText: store.searchBillText,
areaName: areaName
};
// 法案页附带搜索类型参数,便于搜索结果页后续按类型处理
if (enableBillTypeSwitch) {
query.billSearchType = billSearchType.value;
}
const curRoute = router.resolve({
path: "/searchResults",
query: {
searchText: store.searchBillText,
areaName: areaName
}
query
});
window.open(curRoute.href, "_blank");
};
......@@ -90,17 +138,17 @@ watchEffect(() => {
if (isShow.value) {
homeMainRef.value.classList.add("scroll-main");
homeMainRef.value.classList.add("scrollHomeMain");
} else {
homeMainRef.value.classList.remove("scroll-main");
homeMainRef.value.classList.remove("scrollHomeMain");
}
store.changeIsShowSearchBar(isShow.value);
});
store.setSearchData({ placeholder, areaName,containerRef:homeMainRef });
store.setSearchData({ placeholder, areaName, containerRef: homeMainRef });
// 锚点跳转
const handleToPosi = id => {
const element = document.getElementById(id);
......@@ -131,6 +179,43 @@ const handleToPosi = id => {
width: 960px;
height: 168px;
margin: 0 auto 68px auto;
.search-type-tabs {
display: flex;
align-items: flex-end;
height: 41px;
gap: 2px;
.search-type-tab {
width: 176px;
height: 41px;
line-height: 48px;
text-align: center;
border-radius: 10px 10px 0 0;
border: 1px solid rgb(255, 255, 255);
border-bottom: none;
background: rgba(255, 255, 255, 0.65);
color: rgb(95, 101, 108);
font-family: Microsoft YaHei;
font-size: 18px;
font-weight: 700;
line-height: 41px;
cursor: pointer;
padding: 0 16px;
box-sizing: border-box;
}
.search-type-tab.active {
background: rgba(231, 243, 255, 1);
color: rgb(5, 95, 194);
border-color: rgb(255, 255, 255);
}
}
.search-main-with-tabs {
border-top-left-radius: 0 !important;
}
.search-center {
width: 688px;
height: 48px;
......@@ -170,6 +255,7 @@ const handleToPosi = id => {
}
}
}
.search-main {
display: flex;
padding-right: 3px;
......@@ -181,9 +267,11 @@ const handleToPosi = id => {
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;
......@@ -201,6 +289,7 @@ const handleToPosi = id => {
color: #a8abb2;
}
}
.search-btn {
cursor: pointer;
display: flex;
......@@ -216,6 +305,7 @@ const handleToPosi = id => {
font-family: "Microsoft YaHei";
line-height: 22px;
color: #fff;
img {
width: 18px;
height: 18px;
......@@ -223,6 +313,7 @@ const handleToPosi = id => {
}
}
}
.search-bottom {
width: 688px;
height: 48px;
......@@ -230,6 +321,7 @@ const handleToPosi = id => {
margin-top: 36px;
display: flex;
justify-content: space-between;
// gap: 16px;
.btn {
display: flex;
......@@ -243,9 +335,11 @@ const handleToPosi = id => {
background: #e7f3ff;
cursor: pointer;
position: relative;
&:hover {
background: #cae3fc;
}
.btn-text {
width: 80px;
color: var(--color-main-active);
......@@ -256,12 +350,14 @@ const handleToPosi = id => {
margin-left: 36px;
text-align: center;
}
.btn-icon {
position: absolute;
top: 16px;
right: 19px;
width: 6px;
height: 12px;
img {
width: 100%;
height: 100%;
......
<template>
<button class="action-button" :type="type">
{{ name }}
</button>
</template>
<script setup>
defineProps({
type: {
type: String,
default: 'normal'
},
name: {
type: String,
default: ''
}
})
</script>
<style scoped>
.action-button {
height: 28px;
padding: 0 8px;
border: 1px solid rgba(230, 231, 232, 1);
border-radius: 4px;
cursor: pointer;
line-height: 26px;
font-family: Source Han Sans CN;
font-size: 16px;
font-weight: 400;
transition: all 0.3s;
}
.action-button[type="normal"] {
background-color: rgba(255, 255, 255, 1);
color: rgba(59, 65, 75, 1);
}
.action-button[type="active"] {
background-color: rgba(231, 243, 255, 1);
color: var(--color-main-active);
border: 1px solid var(--color-main-active);
}
/* 悬停效果
.action-button[type="normal"]:hover {
background-color: #d9d9d9;
}
.action-button[type="active"]:hover {
background-color: #40a9ff;
} */
</style>
\ No newline at end of file
<template>
<button class="main-button" :type="type">
</button>
</template>
<script setup>
defineProps({
type: {
type: String,
default: 'normal'
},
name: {
type: String,
default: ''
}
})
</script>
<style scoped>
.main-button {
height: 28px;
padding: 0 8px;
border: 1px solid rgba(230, 231, 232, 1);
border-radius: 4px;
cursor: pointer;
line-height: 26px;
font-family: Source Han Sans CN;
font-size: 16px;
font-weight: 400;
transition: all 0.3s;
}
.main-button[type="normal"] {
background-color: rgba(255, 255, 255, 1);
color: rgba(59, 65, 75, 1);
}
.main-button[type="active"] {
background-color: rgba(231, 243, 255, 1);
color: var(--color-main-active);
border: 1px solid var(--color-main-active);
}
/* 悬停效果
.main-button[type="normal"]:hover {
background-color: #d9d9d9;
}
.main-button[type="active"]:hover {
background-color: #40a9ff;
} */
</style>
\ No newline at end of file
<template>
<div class="source-tab-list-wrapper" :style="{ width: width }">
<div class="tab-item" :class="{ tabItemActive: activeSouceTabId === item.id }" v-for="item, index in sourceTabList"
:key="index" @click="handleClcikTab(item)">
{{ item.name }}
</div>
</div>
</template>
<script setup>
const props = defineProps({
width: {
type: String,
default: '1000px'
},
sourceTabList: {
type: Array,
default: [
]
},
activeSouceTabId: {
type: [String, Number],
default: ''
}
})
const emit = defineEmits('clickTab')
const handleClcikTab = (tab) => {
emit('clickTab', tab)
}
</script>
<style lang="scss" scoped>
.source-tab-list-wrapper {
height: 42px;
display: flex;
justify-content: flex-start;
gap: 12px;
.tab-item {
height: 42px;
line-height: 42px;
padding: 0 16px;
font-size: 20px;
font-weight: 400;
color: rgba(59, 65, 75, 1);
font-family: Source Han Sans CN;
text-align: center;
cursor: pointer;
&:hover {
color: var(--color-main-active);
}
}
.tabItemActive {
background: var(--color-main-active);
color: #fff;
font-weight: 700;
border-radius: 21px;
&:hover {
color: #fff;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="overview-main-box-wrapper"
:style="{ width: width ? width : '1064px', height: height ? height : '450px' }">
<div class="overview-main-box-header">
<div class="header-left">
<div class="header-icon">
<slot name="headerIcon"></slot>
</div>
<div class="header-title">{{ title }}</div>
</div>
<div class="header-right" @click="handleClickToDetail()">
{{ "查看详情 >" }}
</div>
</div>
<div class="wrapper-main">
<slot></slot>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const emit = defineEmits(['toDetail'])
const props = defineProps({
title: {
type: String,
default: ''
},
width: {
type: String,
default: ''
},
height: {
type: String,
default: ''
}
})
const handleClickToDetail = () => {
emit('toDetail')
}
</script>
<style lang="scss" scoped>
.overview-main-box-wrapper {
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 1);
position: relative;
.overview-main-box-header {
height: 48px;
border-bottom: 1px solid rgba(240, 242, 244, 1);
display: flex;
justify-content: space-between;
box-sizing: border-box;
.header-left {
display: flex;
.header-icon {
width: 18px;
height: 18px;
margin-top: 13.7px;
margin-left: 18.7px;
}
.header-title {
margin-left: 21px;
height: 48px;
padding: 0 16px;
background: var(--color-main-active);
color: #fff;
font-family: Source Han Sans CN;
font-size: 20px;
font-weight: 700;
line-height: 48px;
text-align: center;
}
}
.header-right {
margin-right: 27px;
margin-top: 12px;
height: 24px;
color: rgba(20, 89, 187, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
cursor: pointer;
}
}
.wrapper-main {
height: calc(100% - 48px);
overflow: hidden;
// position: relative;
}
}
</style>
<template>
<div class="overview-box-wrapper" :style="{ width: width ? width : '640px', height: height ? height : '415px' }">
<div class="wrapper-header">
<div class="header-icon"></div>
<div class="header-title">{{ title }}</div>
<div class="header-right">
<div class="header-right-btn" @click="handleSave">
<img src="@/assets/icons/box-header-icon1.png" alt="">
</div>
<div class="header-right-btn" @click="handleDownload">
<img src="@/assets/icons/box-header-icon2.png" alt="">
</div>
<div class="header-right-btn" @click="handleCollect">
<img src="@/assets/icons/box-header-icon3.png" alt="">
<div class="overview-normal-box-wrapper"
:style="{ width: width ? width : '1064px', height: height ? height : '460px' }">
<div class="overview-normal-box-header">
<div class="header-left">
<div class="header-icon">
<slot name="headerIcon"></slot>
</div>
<div class="header-title">{{ title }}</div>
</div>
<div class="header-right">
<slot name="headerRight"></slot>
</div>
</div>
<div class="wrapper-main">
......@@ -39,81 +37,54 @@ const props = defineProps({
}
})
const handleSave = () => {
alert('save')
}
const handleDownload = () => {
alert('download')
}
const handleCollect = () => {
alert('collect')
}
</script>
<style lang="scss" scoped>
.overview-box-wrapper {
.overview-normal-box-wrapper {
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 1);
position: relative;
.wrapper-header {
height: 45px;
.overview-normal-box-header {
height: 48px;
border-bottom: 1px solid rgba(240, 242, 244, 1);
display: flex;
justify-content: space-between;
box-sizing: border-box;
.header-left {
display: flex;
.header-icon {
margin-top: 18px;
width: 8px;
height: 20px;
background: var(--color-main-active);
border-radius: 0 4px 4px 0;
}
.header-icon {
width: 24px;
height: 24px;
margin-top: 12px;
margin-left: 20px;
}
.header-title {
margin-left: 14px;
margin-top: 14px;
height: 26px;
color: var(--color-main-active);
font-family: Source Han Sans CN;
font-style: Bold;
font-size: 20px;
font-weight: 700;
line-height: 26px;
letter-spacing: 0px;
.header-title {
margin-left: 16px;
height: 48px;
color: var(--color-main-active);
font-family: Source Han Sans CN;
font-size: 20px;
font-weight: 700;
line-height: 48px;
text-align: center;
}
}
.header-right {
position: absolute;
top: 14px;
right: 12px;
height: 28px;
display: flex;
justify-content: flex-end;
gap: 4px;
.header-right-btn {
width: 28px;
height: 28px;
img {
width: 100%;
height: 100%;
}
}
height: 48px;
margin-right: 28px;
}
}
.wrapper-main {
height: calc(100% - 45px);
height: calc(100% - 48px);
overflow: hidden;
overflow-y: auto;
box-sizing: border-box;
padding: 5px 10px;
}
}
</style>
<template>
<div class="navbarV2">
<div class="module-header-wrapper">
<div class="nav-content">
<div class="nav-left" :class="{ 'flex-start': isShowSearchBar }">
<div class="icon">
......@@ -222,7 +222,7 @@ onMounted(() => {
</script>
<style lang="scss" scoped>
.navbarV2 {
.module-header-wrapper {
width: 100%;
// height: 64px;
border-bottom: 1px solid rgba(234, 236, 238, 1);
......
<template>
<div class="box3">
<div class="box3-header">
<div class="box3-header-left">
<div class="box3-header-icon">
<img src="./image1.png" alt="" />
</div>
<div class="box3-header-title">{{ "新闻资讯" }}</div>
<div class="more" @click="handleToMoreNews">{{ "更多 +" }}</div>
</div>
</div>
<div class="box3-main">
<div class="box3-item" v-for="(news, index) in newsList" :key="index" @click="handleToNewsAnalysis(news)">
<div class="left">
<img :src="news[props.img] ? news[props.img] : DefaultIconNews" alt="" />
</div>
<div class="right">
<div class="right-top">
<div class="title"><span class="text-inner">{{ news[props.title] }}</span></div>
<div class="time">{{ news[props.from] }}</div>
</div>
<div class="right-footer">{{ news[props.content] }}</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import DefaultIconNews from "@/assets/icons/default-icon-news.png";
const props = defineProps({
// 新闻列表数据
newsList: {
type: Array,
default: () => []
},
img: {
type: String,
default: 'img'
},
title: {
type: String,
default: "title"
},
from: {
type: String,
default: "from"
},
content: {
type: String,
default: "content"
},
});
const emit = defineEmits(['item-click', 'more-click']);
const handleToMoreNews = () => {
emit('more-click')
};
const handleToNewsAnalysis = (item, index) => {
emit('item-click', item, index)
};
</script>
<style lang="scss" scoped>
.box3 {
width: 792px !important;
height: 450px !important;
border-radius: 10px !important;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1) !important;
background: rgba(255, 255, 255, 1) !important;
display: flex !important;
flex-direction: column;
gap: 0 !important;
overflow: hidden;
.box3-header {
height: 48px !important;
border-bottom: 1px solid rgba(234, 236, 238, 1) !important;
margin: 0 !important;
display: flex !important;
justify-content: space-between !important;
position: relative !important;
width: 100%;
box-sizing: border-box;
.box3-header-left {
display: flex !important;
.box3-header-icon {
margin-left: 19px !important;
margin-top: 14px !important;
width: 24px !important;
height: 24px !important;
img {
width: 100% !important;
height: 100% !important;
}
}
.box3-header-title {
margin-top: 11px !important;
margin-left: 17px !important;
height: 26px !important;
color: var(--color-main-active) !important;
font-family: 'Source Han Sans CN' !important;
font-size: 20px !important;
font-weight: 700 !important;
line-height: 26px !important;
}
}
.more {
width: 45px;
height: 24px;
position: absolute;
top: 12px;
right: 27px;
color: rgba(20, 89, 187, 1);
font-family: 'Source Han Sans CN';
font-size: 16px;
font-weight: 400;
line-height: 24px;
cursor: pointer;
}
}
.box3-main {
height: 401px;
overflow-y: auto;
overflow-x: hidden;
padding: 6px 0;
.box3-item {
display: flex;
height: 78px;
width: 749px;
margin-left: 21px;
border-bottom: 1px solid rgba(240, 242, 244, 1);
cursor: pointer;
&:hover {
.right-top .title {
color: rgb(5, 95, 194) !important;
font-weight: 700;
}
.right-top .text-inner {
border-bottom-color: rgb(5, 95, 194) !important;
}
}
.left {
width: 72px;
height: 48px;
margin-top: 15px;
img {
width: 100%;
height: 100%;
}
}
.right {
width: 657px;
margin-left: 20px;
.right-top {
width: 657px;
display: flex;
justify-content: space-between;
.title {
margin-top: 14px;
width: 500px;
height: 24px;
color: rgba(59, 65, 75, 1);
font-family: 'Source Han Sans CN';
font-size: 16px;
font-weight: 700;
line-height: 24px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.text-inner {
border-bottom: 1px solid transparent;
}
}
.time {
width: 157px;
text-align: right;
height: 22px;
margin-top: 14px;
color: rgba(95, 101, 108, 1);
font-family: 'Source Han Sans CN';
font-size: 14px;
font-weight: 400;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.right-footer {
width: 657px;
height: 24px;
color: rgba(59, 65, 75, 1);
font-family: 'Source Han Sans CN';
font-size: 16px;
font-weight: 400;
line-height: 24px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
}
</style>
\ No newline at end of file
<template>
<div class="box2">
<div class="box2-header">
<div class="icon">
<img src="./image1.png" alt="" />
</div>
<div class="title">
<div class="text">{{ title }}</div>
<div class="num">{{ list.length }}</div>
</div>
</div>
<div class="box2-main">
<div class="box2-main-item" v-for="(item, index) in list" :key="index" @click="handleItemClick(item, index)">
<div :class="{
itemLeftStatus1: item[props.riskLevel] === '特别重大',
itemLeftStatus2: item[props.riskLevel] === '重大风险',
itemLeftStatus3: item[props.riskLevel] === '较大风险',
itemLeftStatus4: item[props.riskLevel] === '一般风险' || !item[props.riskLevel],
itemLeftStatus5: item[props.riskLevel] === '低风险',
}">
{{ item[props.riskLevel] || "暂无数据" }}
</div>
<div class="item-right">
<div class="text"> <span class="text-inner">{{ item[props.name] }}</span></div>
<div class="time">{{ item[props.postDate] }}</div>
</div>
</div>
</div>
<div class="box2-footer" @click="handleMoreClick" v-if="showMore">
<div class="icon">
<img src="./image2.png" alt="" />
</div>
<div class="text">{{ moreText }}</div>
</div>
</div>
</template>
<script setup>
import { ElMessage } from "element-plus";
// 接收父组件传递的参数
const props = defineProps({
// 标题(默认“风险信号”)
title: {
type: String,
default: "风险信号"
},
// 风险信号列表数据
list: {
type: Array,
default: () => []
},
// “查看更多”文本(默认“查看更多”)
moreText: {
type: String,
default: "查看更多"
},
//控制“查看更多”是否显示,默认显示
showMore: {
type: Boolean,
default: true
},
name: {
type: String,
default: "name"
},
postDate: {
type: String,
default: "postDate"
},
riskLevel: {
type: String,
default: "riskLevel"
},
});
// 定义自定义事件,把点击事件传递给父组件
const emit = defineEmits(['item-click', 'more-click']);
// 点击单条风险信号
const handleItemClick = (item, index) => {
emit('item-click', item, index)
};
// 点击“查看更多”
const handleMoreClick = () => {
emit('more-click')
};
</script>
<style scoped lang="scss">
.risk-status-base {
width: 40px;
height: 40px;
border-radius: 20px;
font-size: 12px;
font-weight: 400;
line-height: 14px;
box-sizing: border-box;
padding: 6px 4px;
text-align: center;
}
.itemLeftStatus1 {
color: rgb(206, 79, 81) !important;
background: rgba(255, 241, 240, 1) !important;
@extend .risk-status-base
}
.itemLeftStatus2 {
color: rgba(250, 140, 22, 1) !important;
background: rgba(255, 247, 230, 1) !important;
@extend .risk-status-base
}
.itemLeftStatus3 {
color: rgba(212, 177, 6, 1) !important;
background: rgba(254, 255, 230, 1) !important;
@extend .risk-status-base
}
.itemLeftStatus4 {
color: rgba(82, 196, 26, 1) !important;
background: rgba(246, 255, 237, 1) !important;
@extend .risk-status-base
}
.itemLeftStatus5 {
color: rgba(22, 119, 255, 1) !important;
background: rgba(230, 244, 255, 1) !important;
@extend .risk-status-base
}
.box2 {
width: 520px;
height: 450px;
border-radius: 10px;
position: relative;
background: rgba(255, 255, 255, 1);
padding: 0;
box-shadow: 0 0 20px 0 rgba(25, 69, 130, 0.1);
border: 1px solid rgba(234, 236, 238, 1);
box-sizing: border-box;
overflow: hidden;
.box2-header {
height: 48px;
display: flex;
border-bottom: 1px solid rgba(240, 242, 244, 1);
.icon {
width: 24px;
height: 24px;
margin-left: 18px;
margin-top: 14px;
margin-bottom: 10px;
img {
width: 100%;
height: 100%;
}
}
.title {
display: flex;
width: 148px;
background: rgb(206, 79, 81);
margin-left: 18px;
.text {
margin-left: 16px;
height: 48px;
color: rgba(255, 255, 255, 1);
font-family: 'Source Han Sans CN';
font-size: 20px;
font-weight: 700;
line-height: 48px;
}
.num {
width: 24px;
height: 20px;
line-height: 20px;
text-align: center;
color: rgba(255, 255, 255, 1);
font-family: Microsoft YaHei;
font-size: 12px;
margin-left: 15px;
margin-top: 15px;
border-radius: 100px;
background: rgba(255, 255, 255, 0.3);
}
}
}
.box2-main {
box-sizing: border-box;
padding-left: 23px;
padding-right: 30px;
overflow-y: auto;
width: 520px;
height: calc(100% - 160px);
border-radius: 4px;
.box2-main-item {
width: 463px;
height: 48px;
border-radius: 2px;
position: relative;
display: flex;
align-items: center;
cursor: pointer;
&:hover {
.item-right .text {
color: rgb(5, 95, 194) !important;
font-weight: 700;
}
.item-right .text-inner {
border-bottom-color: rgb(5, 95, 194) !important;
}
}
.item-left {
margin-top: 4px;
margin-left: 0px;
margin-bottom: 4px;
width: 40px;
height: 40px;
border-radius: 20px;
color: rgba(82, 196, 26, 1);
background: rgba(246, 255, 237, 1);
font-family: Microsoft YaHei;
font-size: 12px;
font-weight: 400;
line-height: 14px;
box-sizing: border-box;
padding: 6px 4px;
text-align: center;
flex-shrink: 0;
}
.item-right {
margin-left: 12px;
height: 46px;
display: flex;
align-items: center;
flex: 1;
background: transparent;
padding: 0;
border-bottom: 1px solid #EAECEE;
box-sizing: border-box;
overflow: hidden; // 保证右侧不会溢出
.text {
padding-top: 8px;
padding-bottom: 8px;
flex: 1 1 auto;
min-width: 0;
height: 100%;
background: transparent;
font-family: "Source Han Sans CN";
font-weight: 400;
font-size: 16px;
letter-spacing: 0px;
text-align: left;
color: rgb(59, 65, 75);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
box-sizing: border-box;
flex-shrink: 1;
.text-inner {
border-bottom: 1px solid transparent;
}
}
.time {
flex: 0 0 auto;
margin-left: 12px;
padding-top: 11px;
padding-bottom: 11px;
height: 100%;
flex-shrink: 0;
background: transparent;
font-family: "Source Han Sans CN", sans-serif;
font-weight: 400;
font-size: 16px;
line-height: 24px;
letter-spacing: 0px;
text-align: right;
box-sizing: border-box;
color: rgb(132, 136, 142);
white-space: nowrap;
}
}
}
}
.box2-footer {
position: absolute;
left: 26px;
right: 20px;
bottom: 20px;
width: 460px;
height: 42px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
border-radius: 6px;
background: var(--color-main-active);
cursor: pointer;
.icon {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text {
margin-left: 8px;
color: rgba(255, 255, 255, 1);
font-family: "Source Han Sans CN";
font-size: 16px;
font-weight: 400;
line-height: 24px;
}
}
}
</style>
\ No newline at end of file
......@@ -12,11 +12,18 @@ import "./styles/main.css";
import '@/assets/fonts/font.css'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import AreaTag from '@/components/areaTag.vue'
import leftBtn from "@/components/pageBtn/leftBtn.vue";
import rightBtn from "@/components/pageBtn/rightBtn.vue";
import OverviewBox from '@/components/BoxBackground/overviewBox.vue'
import AnalysisBox from '@/components/BoxBackground/analysisBox.vue'
import AreaTag from '@/components/base/AreaTag/index.vue'
import LeftBtn from "@/components/base/PageBtn/LeftBtn.vue";
import RightBtn from "@/components/base/PageBtn/RightBtn.vue";
import OverviewMainBox from "@/components/base/BoxBackground/OverviewMainBox.vue";
import OverviewNormalBox from "@/components/base/BoxBackground/OverviewNormalBox.vue";
import AnalysisBox from '@/components/base/BoxBackground/AnalysisBox.vue'
import NewsList from '@/components/base/NewsList/index.vue'
import ModuleHeader from '@/components/base/ModuleHeader/index.vue'
import RiskSignal from "@/components/base/RiskSignal/index.vue";
import MessageBubble from "@/components/base/MessageBubble/index.vue";
import SourceTabLsit from '@/components/base/SourceTabList/index.vue'
import ActionButton from "@/components/base/ActionButton/index.vue"
// 引入 Pinia 实例
import pinia from './stores'
......@@ -36,8 +43,17 @@ app.use(ElementPlus, {
app.use(pinia) // 挂载 Pinia
app.component("CardTitle", CardTitle);
app.component('AreaTag', AreaTag) // 领域标签
app.component('leftBtn', leftBtn)
app.component('rightBtn', rightBtn)
app.component('OverviewBox', OverviewBox) // 概览页模块背景
app.component('LeftBtn', LeftBtn) // 向左按钮
app.component('RightBtn', RightBtn) // 向右按钮
app.component('OverviewMainBox', OverviewMainBox) // 概览页最新动态背景盒子
app.component('OverviewNormalBox', OverviewNormalBox) // 概览页一版模块背景盒子
app.component('AnalysisBox', AnalysisBox) // 分析页模块背景
app.component('ModuleHeader', ModuleHeader) // 模块头部
app.component('RiskSignal', RiskSignal) // 风险信号
app.component('NewsList', NewsList) // 新闻资讯
app.component('MessageBubble', MessageBubble) // 社交媒体
app.component('SourceTabLsit', SourceTabLsit) // 资源库tab列表
app.component('ActionButton', ActionButton) // 普通按钮和激活按钮
app.mount("#app");
import { defineStore } from 'pinia'
import { ElMessage } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
export const useWrittingAsstaintStore = defineStore('writtingAsstaint', {
state: () => ({
......@@ -92,11 +92,43 @@ export const useWrittingAsstaintStore = defineStore('writtingAsstaint', {
this.abortController = null;
},
backToInputAndClear() {
this.resetGenerateState();
this.reportContent = '';
this.writtingTitle = '';
this.descText = '';
this.uploadFileList = [];
this.routeQuery = {};
this._isDisableTemplate = false;
this.curTempTitle = '政令';
this.tempActiveIndex = 0;
},
updateTempActiveIndex(index, title) {
this.tempActiveIndex = index;
this.curTempTitle = title;
},
_keepStepsViewOnError() {
this.isGenerating = false;
this.isShowProcess = true;
this.isShowSteps = true;
this.abortController?.abort();
this.abortController = null;
},
async _showErrorDialog(message) {
await ElMessageBox.alert(message || '写报生成失败', '提示', {
confirmButtonText: '确认',
type: 'error'
});
},
async _handleGenerateError(message) {
this._keepStepsViewOnError();
await this._showErrorDialog(message);
},
// ========== 路由参数处理 ==========
async setRouteParams(query) {
this.routeQuery = { ...query };
......@@ -157,8 +189,7 @@ export const useWrittingAsstaintStore = defineStore('writtingAsstaint', {
}
} catch (error) {
console.error(`获取${typeName}数据异常:`, error);
ElMessage.error(`获取${typeName}数据失败: ${error.message}`);
this.resetGenerateState();
await this._handleGenerateError(`获取${typeName}数据失败: ${error.message}`);
}
},
......@@ -309,15 +340,20 @@ export const useWrittingAsstaintStore = defineStore('writtingAsstaint', {
});
}
break;
case 'error':
await this._handleGenerateError(jsonData.message);
break;
default:
console.debug('未处理的SSE事件类型', event.event);
break;
}
},
onerror: (error) => {
onerror: async (error) => {
console.error('SSE连接错误', error);
ElMessage.warning('写报生成报错!');
if (error.name !== 'AbortError') return true;
if (error.name !== 'AbortError') {
await this._handleGenerateError('写报生成报错!');
return true;
}
this.resetGenerateState();
},
onclose: () => {
......@@ -327,8 +363,9 @@ export const useWrittingAsstaintStore = defineStore('writtingAsstaint', {
});
} catch (error) {
if (error.name !== 'AbortError') {
ElMessage.error(`PDF解析请求失败:${error.message}`);
console.error('PDF SSE请求异常', error);
await this._handleGenerateError(`PDF解析请求失败:${error.message}`);
throw error;
}
this.resetGenerateState();
throw error;
......@@ -435,8 +472,7 @@ export const useWrittingAsstaintStore = defineStore('writtingAsstaint', {
} else if ((msgData.event_type || '').toLowerCase().includes('error')) {
// 优先从 data.error 获取详细错误描述
const errorMsg = msgData.data?.error || str || '生成失败';
ElMessage.error('生成失败:' + errorMsg);
this.resetGenerateState();
this._handleGenerateError('生成失败:' + errorMsg);
} else {
// 老版 --index.vue 行为:步骤栏直接追加服务端发来的完整步骤内容,不加时间戳、不强行换行
// 这样可以避免 SSE 分片导致的“步骤破碎”(一条步骤被拆成多条显示)
......@@ -446,15 +482,17 @@ export const useWrittingAsstaintStore = defineStore('writtingAsstaint', {
this.curAgentTool = msgData.tool || '无';
}
},
onerror: (error) => {
ElMessage.warning('写报生成报错!');
this.resetGenerateState();
onerror: async (error) => {
await this._handleGenerateError('写报生成报错!');
throw new Error(error);
}
});
} catch (error) {
ElMessage.warning('写报生成报错!');
this.resetGenerateState();
if (error.name !== 'AbortError') {
await this._handleGenerateError(error.message || '写报生成报错!');
} else {
this.resetGenerateState();
}
throw error;
}
},
......
......@@ -174,7 +174,6 @@ import { getAllUnionList, getDynamic, getPrediction, getUnionCount, getIndustry,
import defaultImg from "../../../../assets/images/default-icon2.png";
import mapJson from "./assets/world.json";
import { ElMessage } from "element-plus";
import AreaTag from "@/components/areaTag.vue";
const currentPage = ref(1);
const pageSize = ref(10);
......
<!--ZM博弈概览页-->
<template>
<div class="home-wrapper">
<img :src="background" alt="" class="background-img" />
<!-- <div class="home-header">
<div class="header-left">
<HeaderMenu></HeaderMenu>
......@@ -23,6 +23,7 @@
</div>
</div> -->
<div class="content-box">
<div class="home-top-bg"></div>
<!-- 导航栏 -->
<div class="content-nav">
<div class="nav-title">中美科技博弈概览</div>
......@@ -41,13 +42,8 @@
<!-- 美对华“四全”打压 -->
<div id="us-pressure" class="us-pressure-section">
<div class="data-select">
<div
v-for="item in dateList"
:key="item.type"
class="date-item"
:class="{ active: activeDate === item.type }"
@click="handleDateClick(item.type)"
>
<div v-for="item in dateList" :key="item.type" class="date-item" :class="{ active: activeDate === item.type }"
@click="handleDateClick(item.type)">
<!-- <img :src="activeDate === item.type ? item.activeIcon : item.icon" alt="" /> -->
<span>{{ item.name }}</span>
</div>
......@@ -168,6 +164,7 @@ const handleDateClick = type => {
margin: 0;
padding: 0;
}
.home-wrapper {
width: 100%;
height: 100vh;
......@@ -175,13 +172,13 @@ const handleDateClick = type => {
flex-direction: column;
overflow: hidden;
position: relative;
.background-img {
width: 100%;
height: 700px;
position: absolute;
left: 0;
z-index: -1;
}
// .background-img {
// width: 100%;
// height: 700px;
// position: absolute;
// left: 0;
// z-index: -1;
// }
// .home-header {
// height: 64px;
// flex-shrink: 0;
......@@ -268,11 +265,26 @@ const handleDateClick = type => {
.content-box {
flex: 1;
width: 100%;
height: 100%;
overflow-y: auto;
padding-top: 48px;
position: relative;
.home-top-bg {
background:
url("./assets/images/background.png"), linear-gradient(180deg, rgba(229, 241, 254, 1) 0%, rgba(246, 251, 255, 0) 30%);
background-size: 100% 100%;
position: absolute;
width: 100%;
height: 100%;
z-index: -1;
top: -64px;
}
.us-pressure-section {
position: relative;
margin-top: 64px;
.data-select {
width: 108px;
height: 192px;
......@@ -297,6 +309,7 @@ const handleDateClick = type => {
cursor: pointer;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
&:hover {
background: var(--color-bg-hover);
// span{
......@@ -320,6 +333,7 @@ const handleDateClick = type => {
&.active {
background-color: rgba(231, 243, 255, 1);
span {
font-weight: 700;
color: rgb(5, 95, 194);
......@@ -328,6 +342,7 @@ const handleDateClick = type => {
}
}
}
.content-nav {
.nav-title {
font-size: 48px;
......@@ -377,11 +392,13 @@ const handleDateClick = type => {
}
}
}
.bottom-info {
width: 100%;
height: 176px;
margin-bottom: 80px;
background-color: rgb(247, 248, 249);
.info-item {
width: 1601px;
height: 176px;
......@@ -389,14 +406,17 @@ const handleDateClick = type => {
display: flex;
justify-content: space-between;
align-items: center;
.info-item-left {
display: flex;
align-items: center;
img {
width: 134px;
height: 91px;
margin-right: 27px;
}
.info-item-left-content {
font-size: 16px;
font-weight: 400;
......@@ -405,11 +425,13 @@ const handleDateClick = type => {
font-family: Microsoft YaHei;
}
}
.info-item-right {
display: flex;
align-items: center;
position: relative;
height: 60px;
.text2 {
left: 60px;
position: absolute;
......@@ -425,6 +447,7 @@ const handleDateClick = type => {
letter-spacing: 0px;
text-align: center;
}
.text3 {
left: 385px;
top: 12px;
......@@ -441,11 +464,13 @@ const handleDateClick = type => {
letter-spacing: 0px;
text-align: center;
}
.img1 {
width: 300px;
height: 48.8px;
margin-right: 24px;
}
.img2 {
width: 300px;
height: 43.5px;
......
......@@ -314,7 +314,6 @@ import defaultNew from "../assets/images/default-icon-news.png";
import defaultA from "../assets/images/default-icon1.png";
import { getBillBackground, getBillEvent, getBillPersonAnalyze, getBillInfoEvent, getBillPersonAnalyzeDy } from "@/api/bill";
import AnalysisBox from "@/components/BoxBackground/analysisBox.vue";
// 跳转到相关新闻
const handleClickEvent = item => {
......
......@@ -267,7 +267,6 @@ import Cyy from "@/assets/icons/cyy.png";
import Zyy from "@/assets/icons/zyy.png";
import Ghd from "@/assets/icons/ghd.png";
import Mzd from "@/assets/icons/mzd.png";
import AnalysisBox from "@/components/BoxBackground/analysisBox.vue";
const activeBtnIndex = ref(0);
const itemActiveIndex = ref(0);
......
......@@ -423,7 +423,6 @@ import { getBillInfo, getBillPerson, getBillEvent, getBillDyqk } from "@/api/bil
import defaultAvatar from "../assets/images/default-icon1.png";
import defaultNew from "../assets/images/default-icon-news.png";
import defaultBill from "./assets/images/image1.png"
import AnalysisBox from "@/components/BoxBackground/analysisBox.vue";
const route = useRoute();
const router = useRouter();
......
......@@ -50,7 +50,6 @@
</template>
<script setup>
import MessageBubble from "@/components/dialog/dialog.vue";
import NewsList from "@/components/NewsList/NewsList.vue";
import { ref, onMounted } from "vue";
import router from '@/router'
......
......@@ -13,13 +13,9 @@
</div> -->
<!-- 主页面 -->
<div class="main-content" ref="homeMainRef" :class="{ 'scroll-main': isShow }">
<div class="home-top-bg"></div>
<!-- 搜索栏部分 -->
<SearchContainer
v-if="homeMainRef"
placeholder="搜索合作限制"
:containerRef="homeMainRef"
areaName=""
/>
<SearchContainer v-if="homeMainRef" placeholder="搜索合作限制" :containerRef="homeMainRef" areaName="" />
<!-- 最新动态 -->
<div class="newdata" id="position1">
......@@ -108,6 +104,7 @@ const handleToPosi = id => {
margin: 0;
padding: 0;
}
.coop-page {
width: 100%;
height: 100%;
......@@ -127,9 +124,22 @@ const handleToPosi = id => {
overflow-y: auto;
width: 100%;
height: 100%;
background: url("./assets/images/background.png");
background-size: 100% 100%;
padding: 44px 160px 30px 160px;
// background: url("./assets/images/background.png");
// background-size: 100% 100%;
padding: 44px 0 30px 0;
.home-top-bg {
background:
url("./assets/images/background.png"),
linear-gradient(180deg, rgba(229, 241, 254, 1) 0%, rgba(246, 251, 255, 0) 30%);
background-size: 100% 100%;
position: absolute;
width: 100%;
height: 100%;
z-index: -100;
top: -64px;
}
.search {
width: 960px;
height: 168px;
......@@ -146,9 +156,11 @@ const handleToPosi = id => {
background-color: rgba(255, 255, 255, 0.65);
border-radius: 10px;
border: 1px solid transparent;
&:hover {
border: 1px solid var(--color-main-active);
}
.search-input {
border: none;
outline: none;
......@@ -166,6 +178,7 @@ const handleToPosi = id => {
color: #a8abb2;
}
}
.search-btn {
margin-right: -3px;
cursor: pointer;
......@@ -181,6 +194,7 @@ const handleToPosi = id => {
font-family: "Microsoft YaHei";
line-height: 24px;
color: #fff;
img {
width: 22px;
height: 22px;
......@@ -188,6 +202,7 @@ const handleToPosi = id => {
}
}
}
.search-center {
width: 440px;
height: 57px;
......@@ -195,10 +210,12 @@ const handleToPosi = id => {
display: flex;
align-items: center;
justify-content: space-between;
.search-item {
box-sizing: border-box;
width: 120px;
height: 57px;
.search-item-num {
width: 120px;
height: 22px;
......@@ -210,6 +227,7 @@ const handleToPosi = id => {
text-align: center;
cursor: pointer;
}
.search-item-name {
width: 120px;
height: 24px;
......@@ -223,6 +241,7 @@ const handleToPosi = id => {
}
}
}
.search-bottom {
width: 688px;
height: 48px;
......@@ -230,6 +249,7 @@ const handleToPosi = id => {
margin-top: 36px;
display: flex;
justify-content: space-between;
// gap: 16px;
.btn {
display: flex;
......@@ -243,9 +263,11 @@ const handleToPosi = id => {
background: #e7f3ff;
cursor: pointer;
position: relative;
&:hover {
background: #cae3fc;
}
.btn-text {
width: 80px;
color: var(--color-main-active);
......@@ -256,12 +278,14 @@ const handleToPosi = id => {
margin-left: 36px;
text-align: center;
}
.btn-icon {
position: absolute;
top: 16px;
right: 19px;
width: 6px;
height: 12px;
img {
width: 100%;
height: 100%;
......@@ -270,40 +294,48 @@ const handleToPosi = id => {
}
}
}
.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;
......@@ -368,6 +400,7 @@ const handleToPosi = id => {
.search-icon {
width: 18px;
height: 18px;
img {
width: 100%;
height: 100%;
......@@ -426,6 +459,7 @@ const handleToPosi = id => {
right: 19px;
width: 6px;
height: 12px;
img {
width: 100%;
height: 100%;
......
......@@ -3,15 +3,6 @@
<div class="home-main" ref="containerRef">
<div class="home-top-bg"></div>
<div class="home-main-header">
<!-- <div class="home-main-header-top" v-show="!isShow">
<div class="header-left">
<HeaderMenu></HeaderMenu>
</div>
<div class="header-right">
<headerInfo curTitleName="政令"></headerInfo>
</div>
</div> -->
<div class="home-main-header-center">
<SearchContainer style="margin-bottom: 0; margin-top: 48px; height: fit-content" v-if="containerRef"
placeholder="搜索政令" :containerRef="containerRef" areaName="政令" />
......@@ -197,7 +188,8 @@
</div>
<DivideHeader id="position2" class="divide2" :titleText="'资讯要闻'"></DivideHeader>
<div class="center-center">
<NewsList :newsList="newsList" @item-click="handleToNewsAnalysis" @more-click="handleToMoreNews" />
<!-- <NewsList :newsList="newsList" @item-click="handleToNewsAnalysis" @more-click="handleToMoreNews" /> -->
<NewsList :list="newsList" />
<MessageBubble :messageList="messageList" @person-click="handleClickPerson" @info-click="handleGetMessage"
imageUrl="img" @more-click="handleToSocialDetail" />
</div>
......@@ -262,7 +254,7 @@
<template #reference>
<div class="info-content">{{ item.content ? item.content : "暂无数据" }}</div>
</template>
</el-popover> -->
</el-popover> -->
</div>
</div>
</div>
......@@ -426,11 +418,9 @@
</template>
<script setup>
import NewsList from "@/components/NewsList/NewsList.vue";
// import NewsList from "@/components/NewsList/NewsList.vue";
import { onMounted, ref, computed, watch, nextTick } from "vue";
import router from "@/router";
import HeaderMenu from "@/components/headerMenu.vue";
import headerInfo from "@/components/headerInfo.vue";
import {
getDepartmentList,
getLatestDecree,
......@@ -446,7 +436,6 @@ import {
import RiskSignal from "@/components/RiskSignal/RiskSignal.vue";
import { getPersonSummaryInfo } from "@/api/common/index";
import { getNews, getSocialMedia, getRiskSignal } from "@/api/general/index";
import MessageBubble from "@/components/dialog/dialog.vue";
import DivideHeader from "@/components/DivideHeader.vue";
import { useContainerScroll } from "@/hooks/useScrollShow";
import getMultiLineChart from "./utils/multiLineChart";
......@@ -1397,16 +1386,13 @@ onMounted(async () => {
}
.home-main {
position: relative;
width: 100%;
height: 100%;
overflow-y: auto;
// background: url("./assets/images/background.png");
// background-size: 100% 100%;
.home-top-bg {
background:
url("./assets/images/background.png"),
linear-gradient(180deg, rgba(229, 241, 254, 1) 0%, rgba(246, 251, 255, 0) 30%);
background: url("./assets/images/background.png"), linear-gradient(180deg, rgba(229, 241, 254, 1) 0%, rgba(246, 251, 255, 0) 30%);
background-size: 100% 100%;
position: absolute;
width: 100%;
......
<template>
<div class="home-wrapper">
=======
<div class="search-header" v-show="isShow">
<!-- <div class="search-header" v-show="isShow">
<div class="home-main-header-center">
<el-input v-model="searchExportControlText" @keyup.enter="handleSearch" style="width: 800px; height: 100%"
placeholder="搜索出口管制" />
......@@ -40,7 +37,7 @@
</div>
</div>
</div>
</div>
</div> -->
<!-- <div class="home-header" v-show="!isShow">
<div class="header-left">
......@@ -51,6 +48,7 @@
</div>
</div> -->
<div class="home-main" ref="homeMainRef">
<div class="home-top-bg"></div>
<div class="home-main-header">
<SearchContainer style="margin-bottom: 0; margin-top: 48px; height: fit-content" v-if="homeMainRef"
placeholder="搜索出口管制" :containerRef="homeMainRef" areaName="实体清单" />
......@@ -624,8 +622,6 @@ import CustomContainer from "@/components/Container/index.vue";
import ClickableCard from "./components/link.vue";
import InfoCard from "./components/info.vue";
import CustomTitle from "./components/title.vue";
import MessageBubble from "@/components/dialog/dialog.vue";
import CommonPrompt from "./commonPrompt/index.vue";
import RuleSubsidiaryDialog from "./components/RuleSubsidiaryDialog.vue";
import trumpAvatar from "@/assets/images/icon-trump.png";
......@@ -2165,8 +2161,18 @@ const handleMediaClick = item => {
width: 100%;
height: 100%;
overflow-y: auto;
background: url("./assets/images/background.png");
background-size: 100% 100%;
.home-top-bg {
background:
url("./assets/images/background.png"),
linear-gradient(180deg, rgba(229, 241, 254, 1) 0%, rgba(246, 251, 255, 0) 30%);
background-size: 100% 100%;
position: absolute;
width: 100%;
height: 100%;
z-index: -100;
top: -64px;
}
.home-main-header {
display: flex;
......
......@@ -204,7 +204,6 @@ import right from "./assets/right.png";
import flag from "../../assets/default-icon2.png"
import { useRouter } from "vue-router";
import { getSingleSanctionTotalCount, getSingleSanctionDomainCount, getSingleSanctionEntityTypeCount, getSingleSanctionEntityCountryCount, getSingleSanctionEntityRegionCount } from "@/api/exportControlV2.0";
import AnalysisBox from "@/components/BoxBackground/analysisBox.vue";
// 单次制裁-数据统计-制裁实体地域分布情况
const regionDistribution = ref([]);
......
......@@ -9,6 +9,7 @@
</div>
</div> -->
<div class="home-main" ref="containerRef">
<div class="home-top-bg"></div>
<div class="home-main-header">
<div class="home-main-header-center">
<SearchContainer style="margin-bottom: 0; height: fit-content" v-if="containerRef" placeholder="搜索投融资限制政策"
......@@ -479,7 +480,6 @@ import ClickableCard from "./components/link.vue";
import InfoCard from "./components/info.vue";
import CustomTitle from "./components/title.vue";
import NewsList from "@/components/NewsList/NewsList.vue";
import MessageBubble from "@/components/dialog/dialog.vue";
import trumpAvatar from "@/assets/images/icon-trump.png";
import elongAvatar from "@/assets/images/icon-elong.png";
......@@ -1714,11 +1714,24 @@ onMounted(async () => {
overflow-y: hidden;
.home-main {
position: relative;
width: 100%;
height: 100%;
overflow-y: auto;
background: url("./assets/images/background.png");
background-size: 100% 100%;
// background: url("./assets/images/background.png");
// background-size: 100% 100%;
.home-top-bg {
background:
url("./assets/images/background.png"),
linear-gradient(180deg, rgba(229, 241, 254, 1) 0%, rgba(246, 251, 255, 0) 30%);
background-size: 100% 100%;
position: absolute;
width: 100%;
height: 100%;
z-index: -100;
top: -64px;
}
.home-main-header {
margin-top: 43px;
......
......@@ -3,6 +3,7 @@
<div class="home-wrapper">
<div class="home-main" ref="containerRef">
<div class="home-top-bg"></div>
<div class="home-main-header">
<!-- <div class="home-main-header-top" v-show="!isShow">
<div class="header-left">
......@@ -372,7 +373,7 @@
</template>
<script setup>
import MessageBubble from "@/components/dialog/dialog.vue";
import RiskSignal from "@/components/RiskSignal/RiskSignal.vue";
import NewsList from "@/components/NewsList/NewsList.vue";
import { onMounted, ref, computed } from "vue";
......@@ -1179,8 +1180,21 @@ onMounted(async () => {
width: 100%;
height: 100%;
overflow-y: auto;
background: url("./assets/images/background.png");
background-size: 100% 100%;
// background: url("./assets/images/background.png");
// background-size: 100% 100%;
position: relative;
.home-top-bg {
background:
url("./assets/images/background.png"),
linear-gradient(180deg, rgba(229, 241, 254, 1) 0%, rgba(246, 251, 255, 0) 30%);
background-size: 100% 100%;
position: absolute;
width: 100%;
height: 100%;
z-index: -100;
top: -64px;
}
.home-main-header {
display: flex;
......
......@@ -27,7 +27,7 @@
<div class="header-left"></div>
<div class="title">232调查数量年度变化趋势</div>
<div class="header-btn-box">
<div
<!-- <div
class="btn"
:class="{ btnActive: btnActiveName === '发起调查' }"
@click="handleClickBox1Btn('发起调查')"
......@@ -40,7 +40,9 @@
@click="handleClickBox1Btn('结束调查')"
>
{{ "结束调查" }}
</div>
</div> -->
<ActionButton :type="btnActiveName === '发起调查' ? 'active' : 'normal'" name="发起调查" @click="handleClickBox1Btn('发起调查')"></ActionButton>
<ActionButton :type="btnActiveName === '结束调查' ? 'active' : 'normal'" name="结束调查" @click="handleClickBox1Btn('结束调查')"></ActionButton>
</div>
<div class="header-right">
<div class="icon">
......@@ -293,6 +295,7 @@ onMounted(() => {
top: 14px;
right: 120px;
display: flex;
gap: 8px;
.btn {
margin-left: 8px;
height: 28px;
......
......@@ -62,7 +62,7 @@
<script setup>
import NewsList from "@/components/NewsList/NewsList.vue";
import MessageBubble from "@/components/dialog/dialog.vue";
import { ref, onBeforeMount } from "vue";
import router from "@/router"
import image01 from './assets/image01.png'
......
<template>
<div class="coop-page">
<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="最新动态" />
......@@ -138,9 +134,11 @@ onMounted(async () => {
margin: 0;
padding: 0;
}
.coop-page {
width: 100%;
height: 100%;
// .breadcrumb {
// width: 100%;
// height: 64px;
......@@ -156,9 +154,21 @@ onMounted(async () => {
overflow-y: auto;
width: 100%;
height: 100%;
background: url("./assets/images/background.png");
background-size: 100% 100%;
padding: 44px 160px 30px 160px;
// background: url("./assets/images/background.png");
// background-size: 100% 100%;
padding: 44px 0px 30px 0px;
.home-top-bg {
background:
url("./assets/images/background.png"),
linear-gradient(180deg, rgba(229, 241, 254, 1) 0%, rgba(246, 251, 255, 0) 30%);
background-size: 100% 100%;
position: absolute;
width: 100%;
height: 100%;
z-index: -100;
top: -64px;
}
&.scroll-main {
height: calc(100% - 144px);
......@@ -168,6 +178,7 @@ onMounted(async () => {
width: 960px;
height: 168px;
margin: 0 auto 68px auto;
.search-center {
width: 688px;
height: 48px;
......@@ -207,6 +218,7 @@ onMounted(async () => {
}
}
}
.search-main {
display: flex;
padding-right: 3px;
......@@ -218,9 +230,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;
......@@ -238,6 +252,7 @@ onMounted(async () => {
color: #a8abb2;
}
}
.search-btn {
cursor: pointer;
display: flex;
......@@ -253,6 +268,7 @@ onMounted(async () => {
font-family: "Microsoft YaHei";
line-height: 22px;
color: #fff;
img {
width: 18px;
height: 18px;
......@@ -260,6 +276,7 @@ onMounted(async () => {
}
}
}
.search-bottom {
width: 688px;
height: 48px;
......@@ -267,6 +284,7 @@ onMounted(async () => {
margin-top: 36px;
display: flex;
justify-content: space-between;
// gap: 16px;
.btn {
display: flex;
......@@ -280,9 +298,11 @@ onMounted(async () => {
background: #e7f3ff;
cursor: pointer;
position: relative;
&:hover {
background: #cae3fc;
}
.btn-text {
width: 80px;
color: var(--color-main-active);
......@@ -293,12 +313,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%;
......@@ -307,40 +329,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;
......@@ -409,6 +439,7 @@ onMounted(async () => {
.search-icon {
width: 18px;
height: 18px;
img {
width: 100%;
height: 100%;
......@@ -445,9 +476,11 @@ onMounted(async () => {
background: #e7f3ff;
cursor: pointer;
position: relative;
&:hover {
background: #cae3fc;
}
.btn-text {
width: 80px;
color: var(--color-main-active);
......@@ -458,12 +491,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%;
......
......@@ -54,7 +54,7 @@
<script setup>
import NewsList from "@/components/NewsList/NewsList.vue";
import MessageBubble from "@/components/dialog/dialog.vue";
import { ref, onMounted } from "vue";
import {
getSocialMediaInfo, getNews
......
......@@ -12,18 +12,13 @@
</div> -->
<!-- 主页面 -->
<div class="main-content" ref="containerRef">
<div class="home-top-bg"></div>
<!-- 搜索栏部分 -->
<SearchContainer
style="margin-bottom: 48px;height: fit-content;"
v-if="containerRef"
:countInfo="countInfo"
placeholder="搜索科研资助实体、资助记录"
:containerRef="containerRef"
areaName=""
/>
<SearchContainer style="margin-bottom: 48px;height: fit-content;" v-if="containerRef" :countInfo="countInfo"
placeholder="搜索科研资助实体、资助记录" :containerRef="containerRef" areaName="" />
<!-- <div class="search"> -->
<!-- <div class="search-main">
<!-- <div class="search-main">
<input v-model="input" placeholder="搜索科研资助实体、资助记录" class="search-input" />
<div class="search-btn">
<img src="./assets/icons/search-icon.png" alt="" />
......@@ -148,20 +143,20 @@ import img06 from "./assets/images/img06.png";
let containerRef = ref(null);
let countInfo = ref([
{
name:'科研资助机构',
count:18
name: '科研资助机构',
count: 18
},
{
name:'科研资助动态',
count:633
name: '科研资助动态',
count: 633
},
{
name:'科研资助项目',
count:312
name: '科研资助项目',
count: 312
},
{
name:'经费总额(亿美元)',
count:'15,556'
name: '经费总额(亿美元)',
count: '15,556'
},
]);
// 搜索框
......@@ -282,9 +277,22 @@ onMounted(async () => {
overflow-y: auto;
width: 100%;
height: 100%;
background: url("./assets/images/background.png");
background-size: 100% 100%;
padding: 44px 160px 30px 160px;
// background: url("./assets/images/background.png");
// background-size: 100% 100%;
padding: 44px 0 30px 0;
position: relative;
.home-top-bg {
background:
url("./assets/images/background.png"),
linear-gradient(180deg, rgba(229, 241, 254, 1) 0%, rgba(246, 251, 255, 0) 30%);
background-size: 100% 100%;
position: absolute;
width: 100%;
height: 100%;
z-index: -100;
top: -64px;
}
.search {
width: 960px;
......@@ -459,19 +467,22 @@ onMounted(async () => {
display: flex;
align-items: center;
padding: 0px 24px;
&:hover {
transform: translateY(-3px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
.data-text-item{
display: flex;
flex-direction: column;
justify-content: center;
.data-text-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
height: 100%;
margin-left: 16px;
margin-bottom: 4px;
}
img {
width: 88px;
height: 88px;
......
<template>
<div class="home-wrapper">
<div class="home-box" :class="{ scrollHomeBox: isShow }" ref="containerRef">
<!-- <div class="home-header" v-show="!isShow">
<div class="header-item">国家科技安全</div>
......@@ -9,6 +9,7 @@
<div class="header-item">></div>
<div class="header-item">科技人物观点</div>
</div> -->
<div class="home-top-bg"></div>
<div class="home-main">
<div class="home-main-header" v-show="!isShow">
<!-- <div class="home-main-header-top">
......@@ -19,13 +20,8 @@
<div class="header-item">科技人物观点</div>
</div> -->
<div class="home-main-header-center">
<SearchContainer
style="margin-bottom: 0;margin-top: 48px; "
v-if="containerRef"
placeholder="搜索科技人物及观点"
:containerRef="containerRef"
areaName="人物"
/>
<SearchContainer style="margin-bottom: 0;margin-top: 48px; " v-if="containerRef" placeholder="搜索科技人物及观点"
:containerRef="containerRef" areaName="人物" />
<!-- <el-input v-model="input" style="width: 838px; height: 100%" placeholder="搜索科技人物及观点" />
<div class="search">
<div class="search-icon">
......@@ -1048,9 +1044,22 @@ onMounted(async () => {
.home-box {
width: 100%;
height: 100%;
background: url("./assets/images/background.png");
background-size: 100% 100%;
// background: url("./assets/images/background.png");
// background-size: 100% 100%;
overflow-y: auto;
position: relative;
.home-top-bg {
background:
url("./assets/images/background.png"),
linear-gradient(180deg, rgba(229, 241, 254, 1) 0%, rgba(246, 251, 255, 0) 30%);
background-size: 100% 100%;
position: absolute;
width: 100%;
height: 100%;
z-index: -100;
top: -64px;
}
// .home-header {
// height: 64px;
......@@ -1114,7 +1123,7 @@ onMounted(async () => {
}
}
.home-main-header-footer {
margin-top: 38px;
......
<template>
<div class="effect-analysis">
<div class="placeholder-card">
<div class="card-header">
<CardTitle title="影响分析" />
<el-icon class="expand-icon"><TrendCharts /></el-icon>
</div>
<div class="card-body">
<div class="placeholder-content">
<h3 class="placeholder-title">影响分析功能开发中</h3>
<el-empty description="暂无数据" />
</div>
</div>
</div>
</div>
</template>
<script setup>
import { TrendCharts } from '@element-plus/icons-vue'
import CardTitle from '@/components/CardTitle.vue'
</script>
<style scoped>
.effect-analysis {
/* padding: 20px 0; */
}
.placeholder-card {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
min-height: 500px;
}
.card-header {
padding: 16px 20px;
border-bottom: 1px solid #f0f0f0;
display: flex;
justify-content: space-between;
align-items: center;
}
.card-body {
padding: 40px 20px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
}
.expand-icon {
color: #999;
}
.placeholder-content {
display: flex;
flex-direction: column;
align-items: center;
max-width: 400px;
}
.placeholder-icon {
margin-bottom: 24px;
color: #d3d3d3;
}
.placeholder-title {
font-size: 20px;
color: #333;
margin: 0 0 16px 0;
}
.placeholder-description {
font-size: 14px;
color: #666;
margin-bottom: 20px;
line-height: 1.6;
}
.feature-list {
list-style: none;
padding: 0;
margin: 0 0 30px 0;
text-align: left;
}
.feature-list li {
padding: 8px 0;
color: #666;
font-size: 14px;
position: relative;
padding-left: 20px;
}
.feature-list li::before {
content: "•";
color: #409eff;
font-weight: bold;
position: absolute;
left: 0;
}
</style>
<template>
<div class="overview-container">
<el-row :gutter="20">
<!-- 左侧内容 -->
<el-col :span="8">
<!-- 内容摘要 -->
<div class="content-card">
<div class="card-header">
<CardTitle title="内容摘要" />
<el-icon class="expand-icon"><ArrowRight /></el-icon>
</div>
<div class="card-body">
<div class="summary-content">
<div v-html="props.reportSummary.summary"></div>
<el-button type="text" class="more-btn">查看更多 ></el-button>
</div>
</div>
</div>
<!-- 涉及科技领域 -->
<div class="content-card tech-fields" style="margin-top: 20px;">
<div class="card-header">
<CardTitle title="涉及科技领域" />
<el-icon class="expand-icon"><ArrowRight /></el-icon>
</div>
<div class="card-body">
<div class="tech-tags">
<el-tag type="primary" size="small" v-for="tag in props.reportSummary.researchTypes" :key="tag">{{ tag }}</el-tag>
</div>
<WordCloud :words="props.reportSummary.researchTypes" />
</div>
</div>
</el-col>
<!-- 右侧主要内容 -->
<el-col :span="16">
<div class="content-card main-content-card">
<div class="card-header">
<CardTitle title="主要内容" />
<div class="content-actions">
<el-button type="plain" size="small">核心发现</el-button>
<el-button type="plain" size="small">政策建议</el-button>
<el-icon class="expand-icon"><Paperclip /></el-icon>
</div>
</div>
<div class="card-body">
<div class="main-content-list">
<div v-for="(item, index) in mainContentList" :key="item.id" class="content-item">
<!-- 左侧:序号 -->
<div class="item-number">{{ item.serialNum }}</div>
<!-- 中间:标题和内容 -->
<div class="item-main">
<h4 class="item-title">{{ item.content }}</h4>
<p class="item-content">{{ item.econtent }}</p>
</div>
<!-- 右侧:标签 -->
<div class="item-tags">
<el-tag
v-for="tag in item.tags"
:key="tag.name"
:type="tag.type"
size="small"
class="content-tag"
>
{{ tag.name }}
</el-tag>
</div>
</div>
</div>
<!-- 分页 -->
<div class="pagination-wrapper">
<el-pagination
v-model:current-page="currentPage"
:page-size="pageSize"
:total="totalElements"
layout="prev, pager, next"
:pager-count="5"
small
/>
<span class="total-info">{{ totalElements }}</span>
</div>
</div>
</div>
</el-col>
</el-row>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Paperclip } from '@element-plus/icons-vue'
import CardTitle from '@/components/CardTitle.vue'
import { mockMainContentList } from '../mockData'
import WordCloud from './WordCloud.vue'
const props = defineProps({
reportSummary: {
type: Object,
required: true
},
content: {
type: Object,
required: true
}
})
const currentPage = ref(1)
const totalElements = ref(6)
const pageSize = ref(10)
// 标签类型映射 - 根据限制方式设置不同的标签颜色
const getTagType = (tagName) => {
const tagTypeMap = {
'出口管制': 'danger',
'资本管制': 'warning',
'技术封锁': 'danger',
'金融制裁': 'danger',
'对台军售': 'warning',
'关税贸易': 'primary',
'供应链打击': 'warning'
}
return tagTypeMap[tagName] || 'info'
}
// 处理接口数据的方法
const processApiData = (apiResponse) => {
if (!apiResponse || !apiResponse.content) return []
return apiResponse.content.map(item => ({
id: item.id,
title: item.content, // 使用content作为标题
content: item.content, // 内容
econtent: item.econtent,
serialNum: item.serialNum,
tags: item.xzfsList.map(tag => ({
name: tag,
type: getTagType(tag)
}))
}))
}
// 更新分页信息的方法
const updatePagination = (apiResponse) => {
if (apiResponse) {
totalElements.value = apiResponse.totalElements || 0
pageSize.value = apiResponse.size || 10
currentPage.value = (apiResponse.number || 0) + 1 // API返回的是0基础的页码
}
}
const mainContentList = ref(mockMainContentList)
</script>
<style scoped>
.overview-container {
padding: 0;
}
.content-card {
background: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.card-header {
padding: 16px 20px;
border-bottom: 1px solid #f0f0f0;
display: flex;
justify-content: space-between;
align-items: center;
}
.card-body {
padding: 20px;
}
.expand-icon {
color: #999;
cursor: pointer;
margin-left: 10px;
}
.summary-content {
line-height: 1.8;
color: #666;
}
.summary-content p {
margin-bottom: 16px;
text-align: justify;
}
.more-btn {
color: #409eff;
padding: 0;
}
.tech-tags {
display: flex;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 10px;
}
.tag-row {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.tech-tag {
background: #f5f7fa;
border: 1px solid #dcdfe6;
color: #606266;
border-radius: 4px;
padding: 4px 8px;
font-size: 12px;
}
.tech-tag.ai-chip {
background: #fff7e6;
border-color: #ffd591;
color: #fa8c16;
}
.content-actions {
display: flex;
align-items: center;
}
.main-content-list {
margin-bottom: 20px;
}
.content-item {
display: flex;
align-items: flex-start;
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #f0f0f0;
gap: 16px;
}
.content-item:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.item-number {
width: 28px;
height: 28px;
background: #409eff;
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
font-weight: 600;
flex-shrink: 0;
margin-top: 2px;
}
.item-main {
flex: 1;
min-width: 0;
}
.item-title {
margin: 0 0 8px 0;
font-size: 16px;
font-weight: 600;
color: #1f2937;
line-height: 1.4;
}
.item-content {
margin: 0;
line-height: 1.6;
color: #4b5563;
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.item-tags {
display: flex;
flex-direction: column;
gap: 6px;
flex-shrink: 0;
min-width: 120px;
align-items: flex-end;
}
.content-tag {
font-size: 12px;
height: 22px;
line-height: 20px;
padding: 0 8px;
white-space: nowrap;
}
.pagination-wrapper {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 20px;
border-top: 1px solid #f0f0f0;
}
.total-info {
font-size: 12px;
color: #999;
}
.pagination-wrapper :deep(.el-pagination) {
--el-pagination-font-size: 12px;
}
.pagination-wrapper :deep(.el-pagination .el-pager li) {
min-width: 28px;
height: 28px;
line-height: 28px;
}
.pagination-wrapper :deep(.el-pagination .btn-prev),
.pagination-wrapper :deep(.el-pagination .btn-next) {
height: 28px;
line-height: 28px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.content-item {
flex-direction: column;
gap: 12px;
margin-bottom: 20px;
padding-bottom: 20px;
}
.item-number {
align-self: flex-start;
}
.item-main {
order: 2;
}
.item-tags {
order: 3;
flex-direction: row;
align-items: flex-start;
flex-wrap: wrap;
min-width: auto;
}
.item-title {
font-size: 15px;
}
.item-content {
font-size: 13px;
}
}
</style>
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论