Files
Situation-Awareness-Platfor…/src/views/Jyh/Home/index.vue
2025-11-28 09:05:28 +08:00

1017 lines
29 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="home-container">
<div class="home-content">
<div class="home-title">
<img src="@/assets/imgs/logo.png" alt="logo"/>
<h1>可信开源代码库</h1>
</div>
<div class="home-search" ref="homeSearch" :class="{ 'glow-border': inputGlow }">
<d-input
ref="searchInput"
placeholder="请输入搜索关键字"
@focus="inputFocus"
@blur="inputBlur"
@keyup.enter="search"
:autocomplete="'off'"
v-model="searchStr"
>
<template #prepend>
<d-dropdown @toggle="onCateToggle($event)">
<div class="flex items-center gap-1 cursor-pointer">
{{ searchType }}
<d-icon :rotate="cateRotate" name="icon-chevron-down-2"></d-icon>
</div>
<template #menu>
<ul class="list-menu">
<li class="menu-item" @click="onCategoryChange('软件')">软件</li>
<d-dropdown :position="position" :offset="0">
<li class="menu-item">
行业
<i class="icon icon-chevron-right"></i>
</li>
<template #menu>
<ul class="list-menu">
<li class="menu-item" v-for="option in industryList" @click="onCategoryChange(option)">
{{ option.name }}
</li>
</ul>
</template>
</d-dropdown>
</ul>
</template>
</d-dropdown>
</template>
<template #append>
<div id="advancedSearch close-isopen" class="advanced-search" @click="openAdvancedSearch">
<span class="close-isopen">高级筛选</span>
<!-- <d-badge :count="6" :bg-color="'#f0f0f0'" class="close-isopen"></d-badge>-->
<d-icon class="close-isopen" :rotate="rotate" name="icon-chevron-down-2"></d-icon>
</div>
</template>
</d-input>
<d-dropdown-menu v-model="isOpen" :origin="searchInput?.$el" :offset="offset" :clickOutside="closeOutside">
<div class="advanced-search-menu" :style="{ width: dropdownWidth + 'px' }">
<AdvanceSearch @submit="submit($event)" @cancel="isOpen = false" class="p-20" :layout="'vertical'">
<template #title>
<span class="title">高级筛选</span>
</template>
</AdvanceSearch>
</div>
</d-dropdown-menu>
<d-button icon="search" shape="circle" @click="search"></d-button>
</div>
<div style="width: 70%" class="from-blue-50 to-white">
<!-- 顶部功能按钮 -->
<d-row :gutter="16" class="mb-8 top-btn">
<div style="cursor: pointer" v-for="item in topButtons" :key="item.name" @click="handleButtonClick(item)">
<div style="width: 84px;height: 84px;flex-direction: column;padding: 12px;margin: 0 12px"
class="bg-white rounded-lg shadow-md flex items-center justify-center mb-2">
<div>
<img style="width: 32px;height: 32px;margin-bottom: 4px" :src="item.icon"
class="text-blue-600 text-xl"></img>
</div>
<div class="text-sm font-medium">{{ item.name }}</div>
</div>
</div>
</d-row>
<div class="dashboard-page">
<d-row :gutter="16" class="main-row">
<!-- 左侧全球威胁态势实时监控 -->
<d-col :span="14">
<div class="bg-white rounded-xl shadow-md p-4">
<div class="section-title">全球威胁态势实时监控
<a href="#" class="text-blue-600 text-sm">更多 ></a></div>
<d-row :gutter="24" class="threat-row">
<d-col :span="10">
<d-chart :option="lineOption" style="width: 400px; height: 240px"></d-chart>
</d-col>
<d-col :span="8">
<d-chart :option="pieOption" style="width: 240px; height: 240px"></d-chart>
</d-col>
<d-col :span="6">
<div class="data-card">
<div class="data-item">
<span class="data-label">今日检测量</span>
<span class="data-value">128万次</span>
<!-- <span class="data-value">128万次</span>-->
<!-- <span class="data-desc">说明0</span>-->
</div>
<div class="data-item">
<span class="data-label">高危威胁</span>
<span class="data-value danger">327</span>
<!-- <span class="data-value danger">327</span>-->
<!-- <span class="data-desc">说明0</span>-->
</div>
</div>
</d-col>
</d-row>
</div>
</d-col>
<!-- 右侧AI+安全核心能力 -->
<d-col style="height: 320px" :span="10">
<div style="height: 100%" class="bg-white rounded-xl shadow-md p-4">
<div class="section-title">AI+安全核心能力
<router-link :to="{ name: 'aihome' }" style="cursor: pointer;" class="text-blue-600 text-sm">更多 >
</router-link>
</div>
<d-row :gutter="16" class="ai-capability-row">
<d-col :span="8" v-for="(item, index) in aiCapabilities" :key="index">
<div class="capability-card">
<div class="capability-icon">
<img :src="item.icon" class="text-blue-600 text-2xl"></img>
</div>
<h2 class="capability-title">{{ item.title }}</h2>
<h4>{{ item.rate }}</h4>
<p class="capability-desc">{{ item.desc }}</p>
</div>
</d-col>
</d-row>
</div>
</d-col>
</d-row>
</div>
<!-- 团队与成果 + 最新动态 -->
<d-row style="height: 237px" :gutter="16">
<d-col style="height: 100%" :span="8">
<div style="height: 100%" class="bg-white rounded-xl shadow-md p-4 mb-4">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-bold">团队与成果</h3>
<router-link :to="{ name: 'OurTeam' }" style="cursor: pointer;" class="text-blue-600 text-sm">更多 >
</router-link>
</div>
<div class="flex flex-col items-center">
<h4 class="font-medium mb-2">顶尖安全团队</h4>
<div class="flex gap-4 mb-3">
<div class="flex flex-col items-center" v-for="member in teamMembers" :key="member.name">
<img src="https://picsum.photos/id/1001/60/60" alt="团队成员" class="w-14 h-14 rounded-full mb-1">
<span class="text-sm font-medium">{{ member.name }}</span>
<span class="text-xs text-gray-500">{{ member.title }}</span>
</div>
</div>
<div class="flex gap-2">
<button class="bg-blue-600 text-white text-xs px-3 py-1 rounded">国家级安全认证团队</button>
<button class="bg-blue-100 text-blue-600 text-xs px-3 py-1 rounded">200+专利技术</button>
<button class="bg-blue-100 text-blue-600 text-xs px-3 py-1 rounded">200+专利技术</button>
</div>
</div>
</div>
</d-col>
<d-col style="height: 100%" :span="16">
<div style="height: 100%" class="bg-white rounded-xl shadow-md p-4">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-bold">最新动态</h3>
<router-link :to="{ name: 'Insights' }" style="cursor: pointer;" class="text-blue-600 text-sm">更多 >
</router-link>
</div>
<div style="overflow: auto; height: calc(100% - 46px);">
<d-timeline direction="vertical" center>
<d-timeline-item
v-for="(news, index) in latestNews"
:key="index"
:time="news.year"
dot-color="#ff6384"
line-color="#e5e7eb"
class="timeline-item"
>
<!-- 时间线内容区域保留原有样式结构 -->
<div class="timeline-content">
<p class="font-medium">{{ news.title }}</p>
<p class="text-xs text-gray-500">{{ news.desc }}</p>
</div>
</d-timeline-item>
</d-timeline>
</div>
</div>
</d-col>
</d-row>
</div>
<!-- <d-button v-if="isLogin" @click="check" ref="origin" icon="share" class="batch-btn">批量检索</d-button>-->
<!-- <div class="home-information" v-if="infoList.length > 0">-->
<!-- <div class="info-title">-->
<!-- <div class="sub-title">-->
<!-- <img src="@/assets/imgs/home/informIcon@2x.png" />-->
<!-- <span>预警公告</span>-->
<!-- </div>-->
<!-- &lt;!&ndash; <a v-if="accountInfo.op_access_token" class="devui-link" @click="checkMore"-->
<!-- >更多 <i class="icon icon-chevron-right-2"></i>-->
<!-- </a>-->
<!-- <span v-else class="text-blue-500">查看更多请先登录</span> &ndash;&gt;-->
<!-- </div>-->
<!-- <div class="info-content">-->
<!-- <d-timeline :direction="'vertical'" :time-position="'right'" :position="'right'">-->
<!-- <d-timeline-item-->
<!-- v-for="(item, index) in infoList"-->
<!-- :key="index"-->
<!-- :dot-color="item.dotColor"-->
<!-- :line-color="'var(&#45;&#45;devui-form-control-line-hover)'"-->
<!-- >-->
<!-- <template #default>-->
<!-- <div class="flex items-center justify-between w-full">-->
<!-- <div-->
<!-- class="cursor-pointer notice-content flex gap-2 items-center"-->
<!-- @click="openWarningDetail(item, index)"-->
<!-- >-->
<!-- <span>{{ item.subject }}</span>-->
<!-- <d-tag-->
<!-- v-if="item.importance && tagMap[item.importance]"-->
<!-- :color="tagMap[item.importance].color"-->
<!-- size="sm"-->
<!-- >{{ tagMap[item.importance].text }}</d-tag-->
<!-- >-->
<!-- </div>-->
<!-- <div class="time-container">-->
<!-- <d-icon name="icon-time"></d-icon>-->
<!-- {{ item.publishTime }}-->
<!-- </div>-->
<!-- </div>-->
<!-- </template>-->
<!-- <template #time>-->
<!-- <span></span>-->
<!-- </template>-->
<!-- </d-timeline-item>-->
<!-- </d-timeline>-->
<!-- </div>-->
<!-- </div>-->
</div>
</div>
<d-modal class="warning-modal" v-model="warningModalVisable" title="" style="width: 600px">
<EarlyWarningDetail :warningData="currentWarning" :type="'user'"></EarlyWarningDetail>
</d-modal>
</template>
<script setup lang="ts">
import {ref, onMounted, onBeforeUnmount, computed} from 'vue';
import {useRoute, useRouter} from 'vue-router';
import {useAccount} from '@/utils/hooks/useAccount';
import AdvanceSearch from '@/components/AdvanceSearch/index.vue';
import {getHomeNoticeList} from '@/api/jyh';
import EarlyWarningDetail from '@/views/Jyh/PersonalCenter/Detail/EarlyWarningDetail.vue';
import {useGlobalInfoStore} from '@/stores/Global';
const {updateHeaderSearch} = useGlobalInfoStore();
const {accountInfo} = useAccount();
import {useDiscussGetUserInfo} from '@/api/discussion/hook';
import {DChart} from 'vue-devui/echarts';
import {reactive} from 'vue';
const lineOption = reactive({
tooltip: {show: true, trigger: 'axis'},
grid: {
left: '0%',
right: '3%',
bottom: '3%',
containLabel: true,
},
xAxis: {
type: 'category',
data: ['0', '30', '60', '90', '120', '150', '180', '210', '240'],
axisLine: {lineStyle: {color: '#909399'}},
axisTick: {show: false},
},
yAxis: {
type: 'value',
max: 550,
axisLine: {show: false},
axisTick: {show: false},
splitLine: {lineStyle: {color: '#eee'}},
},
series: [
{
name: '实时威胁A',
data: [0, 150, 250, 200, 350, 400, 450, 500, 550],
type: 'line',
itemStyle: {color: '#ff9f40'},
lineStyle: {color: '#ff9f40'},
symbol: 'circle',
symbolSize: 6,
},
{
name: '实时威胁B',
data: [0, 100, 200, 150, 300, 350, 400, 450, 500],
type: 'line',
itemStyle: {color: '#36a2eb'},
lineStyle: {color: '#36a2eb'},
symbol: 'circle',
symbolSize: 6,
},
],
});
const pieOption = reactive({
tooltip: {show: true, trigger: 'item'},
series: [
{
title: '态势感知',
type: 'pie',
radius: ['40%', '70%'],
data: [
{name: '态势感知', value: 34, itemStyle: {color: '#ff6384'}},
{name: '实时威胁', value: 33, itemStyle: {color: '#36a2eb'}},
{name: '其他', value: 33, itemStyle: {color: '#ffce56'}},
],
label: {
show: true,
formatter: '{b}: {d}%',
position: 'center',
},
labelLine: {show: true},
},
],
});
const route = useRoute();
const router = useRouter();
const inputGlow = ref(false);
const searchStr = ref('');
const position = ref(['right-start', 'right-end']);
const industryOptions = ref(['通信', '军工', '金融', '能源']);
const searchType = ref('软件');
const searchOptions = ref(['软件']);
const offset = ref({mainAxis: 7, crossAxis: -10});
const isKeepOpen = ref(true);
const isOpen = ref(false);
const cateRotate = ref(0);
const infoList = ref([]);
const warningModalVisable = ref(false);
const currentWarning = ref();
const {isLogin} = useDiscussGetUserInfo();
const homeSearch = ref(null);
const dropdownWidth = ref(0);
import aqts from '@/assets/imgs/jyh/menu/风险预警.png'
import aqqb from '@/assets/imgs/jyh/menu/许可证检测.png'
import aqjc from '@/assets/imgs/jyh/menu/已知漏洞检测.png'
import aqzk from '@/assets/imgs/jyh/menu/可信治理.png'
import kxrj from '@/assets/imgs/jyh/menu/可信软件.png'
// 顶部功能按钮数据
const topButtons = ref([
{name: '安全智库', icon: aqzk},
{name: '安全检测', icon: aqjc},
{name: '安全情报', icon: aqqb},
{name: '安全态势', icon: aqts},
{name: '智能引擎', icon: kxrj},
]);
// 按钮点击事件处理
const handleButtonClick = (item) => {
// 路由映射关系:按钮名称 -> 对应路由name或新页面地址
const routeMap = {
'安全智库': 'Search', // 对应name: 'Search'的路由
'安全检测': 'TestingCenter', // 对应name: 'TestingCenter'的路由
'安全情报': 'Insights', // 对应name: 'Insights'的路由
'智能引擎': 'aihome', // 对应name: 'aihome'的路由
'安全态势': 'http://222.20.126.217:10010/bigScreen/#/kxky' // 安全态势大屏地址(替换为实际地址)
};
const target = routeMap[item.name];
if (!target) return;
// 区分路由跳转和新页面打开
if (item.name === '安全态势') {
// 安全态势:打开新页面
window.open(target, '_blank');
} else {
// 其他按钮:路由跳转
router.push({name: target});
}
};
import znjc from '@/assets/imgs/jyh/menu/AI大模型能力.png'
import aiLogo1 from '@/assets/imgs/jyh/ai/aiLogo1.png'
import vulnerabilityForewarning from '@/assets/imgs/jyh/menu/vulnerabilityForewarning.png'
// AI+安全核心能力数据
const aiCapabilities = ref([
{
title: '智能检测引擎',
rate: '覆盖99.9%样本率)',
desc: '智能检测引擎具备对各类文件、恶意软件的高精度识别能力。',
icon: znjc
},
{
title: '行为分析模型',
rate: '(实时响应<1秒',
desc: '深度行为分析模型可实时识别异常行为,精准定位威胁根源。',
icon: aiLogo1
},
{
title: '自动溯源系统',
rate: '覆盖99.9%',
desc: '自动溯源系统可快速定位威胁来源,助力威胁事件全链路分析。',
icon: vulnerabilityForewarning
},
]);
// 团队成员数据
const teamMembers = ref([
{name: '主理', title: '安全专家/负责人'},
{name: '顾问', title: '企业安全专家'},
{name: '架构', title: '技术架构专家'},
]);
// 最新动态数据
const latestNews = ref([
{year: '2024', title: '中国头安全实验室等合作的智能决策模型授奖', desc: '智能决策模型在多领域安全决策中表现卓越,获行业权威奖项。', more: true},
{year: '2023', title: '智能检测引擎从一定论到再超越的与证明', desc: '2024年深度优化检测在极端场景中达99.9%准确率,性能、智能、召回率再升级。', more: false},
{year: '2023', title: '新闻网常务委员:邻区区委交换稿与证明', desc: '网络空间安全会议上,邻区、外防负责人、专家会首席等共论,包含新成果实证。', more: false},
]);
const tagMap = {
critical: {
text: '致命',
color: '#c7000b'
},
high: {
text: '高',
color: '#f66f6a'
},
medium: {
text: '中',
color: '#fac20a'
},
low: {
text: '低',
color: '#5e7ce0'
},
Critical: {
text: '致命',
color: '#c7000b'
},
High: {
text: '高',
color: '#f66f6a'
},
Medium: {
text: '中',
color: '#fac20a'
},
Low: {
text: '低',
color: '#5e7ce0'
}
};
const rotate = computed(() => {
return isOpen.value ? 180 : 0;
});
const searchInput = ref(null);
const openAdvancedSearch = () => {
isOpen.value = !isOpen.value;
inputGlow.value = isOpen.value;
};
const check = () => {
router.push({
name: 'Search',
query: {tab: 'BatchVerify'} // 通过查询参数指定 Tab
});
};
const closeOutside = () => {
return false;
};
const submit = (formData) => {
isOpen.value = false;
router.push({
name: 'Search',
query: {
softwareName: searchStr.value ? searchStr.value : '',
searchType: getIndustryValue(searchType.value),
softwareVersion: formData.softwareVersion || '',
programmingLanguage: formData.programmingLanguage || '',
interestTag: formData.interestTag || '',
industry: formData.industry || '',
licenseName: formData.licenseName || '',
dependentSoftware: formData.dependentSoftware || '',
releaseDateStart: formData.dateRange && formData.dateRange.length > 0 ? formData.dateRange[0] : '',
releaseDateEnd: formData.dateRange && formData.dateRange.length > 0 ? formData.dateRange[1] : ''
}
});
};
const inputFocus = () => {
inputGlow.value = true;
};
const inputBlur = () => {
inputGlow.value = false;
};
const updateDropdownWidth = () => {
if (homeSearch.value) {
dropdownWidth.value = homeSearch.value.offsetWidth * 0.85;
}
};
const globalInfo = useGlobalInfoStore();
const industryList = globalInfo.industryList;
const getIndustryValue = (name) => {
const industry = industryList.find((item) => item.name === name);
return industry ? industry.value : ''; // 如果找不到,返回默认值
};
const search = () => {
// updateHeaderSearch({ searchWord: searchStr.value, searchType: selectedCate.value });
router.push({
name: 'Search',
query: {
softwareName: searchStr.value ? searchStr.value : '',
searchType: getIndustryValue(searchType.value)
}
});
// window.open(`${import.meta.env.VITE_BASE_URL}repoList?softwareName=${searchStr.value ? searchStr.value : ''}&searchType=${getIndustryValue(searchType.value)}`, '_blank')
};
const onCategoryChange = (event) => {
searchType.value = event?.name || '软件';
globalInfo.updateHeaderSearch({softwareName: softwareName.value, searchType: event.value});
};
const onCateToggle = (event) => {
cateRotate.value = event ? 180 : 0;
};
const checkMore = () => {
router.push({name: 'PersonalCenter'});
};
const openWarningDetail = (event, index) => {
infoList.value.forEach((item, i) => {
if (i <= index) {
item.dotColor = 'var(--devui-info)';
} else {
item.dotColor = '';
}
});
warningModalVisable.value = true;
currentWarning.value = event;
};
let resizeObserver: ResizeObserver | null = null;
onMounted(() => {
resizeObserver = new ResizeObserver(updateDropdownWidth);
if (homeSearch.value) {
resizeObserver.observe(homeSearch.value);
}
updateDropdownWidth();
document.querySelector('body').onclick = (e) => {
const className = e.target.className;
if (
!className.includes('close-isopen') &&
!className.includes('devui-badge__content') &&
!className.includes('advanced-search')
) {
isOpen.value = false;
}
};
});
onBeforeUnmount(() => {
if (resizeObserver && homeSearch.value) {
resizeObserver.unobserve(homeSearch.value);
}
});
const getNoticeList = async () => {
const res: any = await getHomeNoticeList();
if (!res.error) {
infoList.value = res.data.data || [];
}
};
getNoticeList();
</script>
<style scoped lang="scss">
@import 'devui-theme/styles-var/devui-var.scss';
.home-container {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
position: relative;
overflow: hidden;
.home-content {
font-size: 14px;
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
justify-self: center;
align-items: center;
gap: 20px;
.home-title {
display: flex;
flex-shrink: 0;
justify-content: center;
align-items: center;
gap: 20px;
h1 {
font-size: xx-large;
font-weight: bold;
}
img {
width: 50px;
//filter: brightness(0);
}
}
.home-search {
width: 574px;
height: 46px;
border: 1px solid #dfe1e5;
box-shadow: 0px 2px 8px 0px rgba(60, 64, 67, 0.25);
border-radius: 24px;
//width: 100%;
//height: 40px;
flex-shrink: 0;
background-color: white;
//border-radius: 10px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
//box-shadow: var(--devui-shadow, 0 2px 12px 0);
input {
border: none;
outline: none;
padding: 5px;
font-size: 14px;
}
.advanced-search {
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
&::before {
content: '';
position: absolute;
left: -10px;
top: 50%;
transform: translateY(-50%);
width: 1px;
height: 20px;
background-color: var(--devui-form-control-line, #d7d8da);
}
}
.advanced-search-menu {
height: 300px;
padding: 12px;
background-color: white;
}
.form-operation {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
}
}
.batch-btn {
color: $devui-aide-text;
width: 150px;
flex-shrink: 0;
background-color: #f0f0f0;
border-color: $devui-aide-text;
}
.home-information {
width: 100%;
background-color: #f0f0f0;
//overflow: auto;
margin-bottom: 20px;
border-radius: 10px;
padding: 12px;
.info-title {
img {
width: 20px;
}
display: flex;
justify-content: space-between;
.sub-title {
display: flex;
gap: 8px;
}
margin-bottom: 20px;
margin-left: 10px;
}
:deep(.devui-timeline-item-data-left) {
display: none;
}
:deep(.devui-timeline-item-dot) {
scale: 0.7;
}
}
}
}
.home-search {
:deep(.devui-input-slot__prepend),
:deep(.devui-input-slot__append),
:deep(.devui-input__wrapper) {
border: none;
}
:deep(.devui-select__selection--glow-style),
:deep(.devui-input--glow-style) {
box-shadow: none !important;
}
}
.glow-border {
border: 1px solid var(--devui-form-control-line, #d7d8da);
border-color: var(--devui-form-control-line-active, #5e7ce0) !important;
box-shadow: 0 0 0 4px var(--devui-form-control-interactive-outline, rgba(94, 124, 224, 0.08));
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.menu-item {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
padding: 4px;
cursor: pointer;
&:hover {
background-color: var(--devui-list-item-hover-bg, #f2f5fc);
color: var(--devui-list-item-hover-text, #526ecc);
}
}
.list-menu {
padding: 8px;
margin: 0;
width: 100px;
}
.title {
font-size: 14px;
font-weight: 500;
}
.notice-content {
flex: 1;
overflow: hidden;
margin-right: 8px;
span {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: block;
}
}
.time-container {
display: flex;
align-items: center;
gap: 8px;
width: 140px;
flex-shrink: 0;
}
:deep(.devui-timeline-item-data-right) {
width: 80%;
}
// 页面容器基础样式
.bg-gradient-to-b {
background-size: cover;
background-repeat: no-repeat;
}
// 卡片通用样式
.bg-white {
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
// 文本样式
.text-lg {
font-size: 18px;
}
.text-sm {
font-size: 14px;
}
.text-xs {
font-size: 12px;
}
.font-bold {
font-weight: 600;
}
.font-medium {
font-weight: 500;
}
// 间距与布局
.mb-8 {
margin-bottom: 24px;
}
.p-4 {
padding: 16px;
}
.flex-col {
flex-direction: column;
}
.items-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.dashboard-page {
//padding: 20px;
////background: #fff;
//border-radius: 8px;
//box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
.chart-card {
padding: 20px;
//background: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
.section-title {
font-size: 18px;
font-weight: 600;
color: #303133;
margin-bottom: 16px;
display: flex;
justify-content: space-between;
align-items: center;
a {
font-weight: 400;
}
.more-link {
font-size: 14px;
color: #409eff;
text-decoration: none;
}
}
.main-row {
margin-bottom: 20px;
}
.data-card {
//background: #fff;
//border-radius: 8px;
//padding: 16px;
//box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
.data-item {
margin-bottom: 24px;
background: #f1f5fc;
border-radius: 8px;
padding: 16px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
.data-label {
font-size: 14px;
color: #606266;
display: block;
margin-bottom: 8px;
}
.data-value {
font-size: 24px;
font-weight: 600;
color: #303133;
margin-right: 16px;
}
.data-value.danger {
color: #f56c6c;
}
.data-desc {
font-size: 12px;
color: #909399;
float: right;
}
}
}
.ai-capability-row {
height: calc(100% - 46px);
.devui-col {
height: 100%;
}
.capability-card {
height: 100%;
background: #f3f7f8;
border-radius: 8px;
padding: 12px;
border: 1px solid #323a4e;
text-align: center;
.capability-icon {
text-align: center;
margin-bottom: 12px;
img {
display: inline-block;
width: 32px;
}
}
.capability-title {
font-size: 16px;
font-weight: 500;
color: #303133;
margin-bottom: 8px;
}
.capability-desc {
font-size: 14px;
color: #606266;
line-height: 1.5;
}
}
}
}
.top-btn {
display: flex;
justify-content: center;
align-items: center;
}
/* 时间线样式调整,保持与原有布局一致 */
:deep(.devui-timeline) {
--devui-timeline-item-padding: 0 0 24px 0; /* 调整项间距 */
}
:deep(.devui-timeline-item-time) {
/* 年份标签样式,与原有红色标签保持一致 */
background-color: #fee2e2; /* 浅红背景 */
color: #dc2626; /* 红色文字 */
font-size: 12px;
padding: 2px 6px;
border-radius: 4px;
min-width: 40px;
text-align: center;
}
:deep(.devui-timeline-item-data-left) {
flex: none;
}
.timeline-content {
margin-top: 4px; /* 与时间标签保持距离 */
}
.font-medium {
font-weight: 500;
margin-bottom: 4px; /* 标题与描述间距 */
}
.text-xs {
font-size: 12px;
line-height: 1.5; /* 描述文字行高 */
}
</style>