<!-- 代码已包含 CSS:使用 TailwindCSS , 安装 TailwindCSS 后方可看到布局样式效果 -->
<template>
<div class="min-h-screen bg-gradient-to-b from-blue-50 to-white">
<!-- 顶部导航 -->
<header class="bg-blue-600 text-white">
<div class="container mx-auto px-4 flex items-center justify-between h-16">
<div class="flex items-center space-x-2">
<img src="https://ai-public.mastergo.com/ai/img_res/d6eeef870ba388fea0d6f3a9f2d03ae2.jpg"
class="h-8 w-8"
alt="logo"/>
<span class="text-lg font-medium">广东省招投标在线监管平台</span>
</div>
<div class="flex items-center">
<div class="relative">
<el-input
v-model="searchText"
placeholder="请输入关键词进行搜索"
class="!w-64"
>
<template #suffix>
<el-icon><Search /></el-icon>
</template>
</el-input>
</div>
<div class="flex items-center ml-4 space-x-4 text-sm">
<span>操作指南</span>
<span>法律法规</span>
<span>系统管理</span>
<span class="flex items-center">
<el-icon class="mr-1"><User /></el-icon>
登录用户
</span>
</div>
</div>
</div>
</header>
<!-- 二级导航 -->
<nav class="bg-blue-700 text-white">
<div class="container mx-auto px-4">
<div class="flex items-center h-12 space-x-8">
<router-link v-for="(item, index) in navItems"
:key="index"
:to="item.path"
class="flex items-center space-x-1 px-4 h-full hover:bg-blue-600">
<el-icon><component :is="item.icon" /></el-icon>
<span>{{ item.name }}</span>
</router-link>
</div>
</div>
</nav>
<!-- 主体内容 -->
<main class="container mx-auto px-4 py-6">
<!-- 筛选栏 -->
<div class="bg-white rounded-lg p-4 mb-6 flex items-center space-x-8">
<div class="flex items-center space-x-4">
<span>智能筛选</span>
<span>行业分类</span>
<span>地市分布</span>
<span>项目阶段</span>
<span>风险监管</span>
<span>规则监管</span>
<span>数据环比</span>
</div>
<div class="flex items-center space-x-2">
<el-date-picker
v-model="dateRange"
type="month"
range-separator="至"
start-placeholder="开始月份"
end-placeholder="结束月份"
size="small"
/>
</div>
</div>
<!-- 数据卡片 -->
<div class="grid grid-cols-5 gap-4 mb-6">
<div class="bg-indigo-100 rounded-lg p-4 flex items-center justify-between">
<div>
<div class="text-2xl font-bold text-indigo-600">93.50%</div>
<div class="text-sm text-gray-600">招标计划提前发布占比</div>
</div>
<el-icon class="text-3xl text-indigo-500"><Document /></el-icon>
</div>
<div class="bg-blue-100 rounded-lg p-4 flex items-center justify-between">
<div>
<div class="text-2xl font-bold text-blue-600">17天</div>
<div class="text-sm text-gray-600">开标至中标结果公告平均时长</div>
</div>
<el-icon class="text-3xl text-blue-500"><Timer /></el-icon>
</div>
<div class="bg-orange-100 rounded-lg p-4 flex items-center justify-between">
<div>
<div class="text-2xl font-bold text-orange-600">68.10%</div>
<div class="text-sm text-gray-600">签订合同信息公开率</div>
</div>
<el-icon class="text-3xl text-orange-500"><Files /></el-icon>
</div>
<div class="bg-cyan-100 rounded-lg p-4 flex items-center justify-between">
<div>
<div class="text-2xl font-bold text-cyan-600">94.65%</div>
<div class="text-sm text-gray-600">全流程信息公开率</div>
</div>
<el-icon class="text-3xl text-cyan-500"><DataLine /></el-icon>
</div>
<div class="bg-teal-100 rounded-lg p-4 flex items-center justify-between">
<div>
<div class="text-2xl font-bold text-teal-600">88.70%</div>
<div class="text-sm text-gray-600">项目实施不见面开标率</div>
</div>
<el-icon class="text-3xl text-teal-500"><TrendCharts /></el-icon>
</div>
</div>
<!-- 图表区域 -->
<div class="space-y-6">
<div class="bg-white rounded-lg p-6">
<h3 class="text-lg font-medium mb-4">招标计划提前发布占比</h3>
<div ref="chart1" class="h-80"></div>
</div>
<div class="bg-white rounded-lg p-6">
<h3 class="text-lg font-medium mb-4">各市开标至中标结果公告平均时长(自然天)</h3>
<div ref="chart2" class="h-80"></div>
</div>
<div class="bg-white rounded-lg p-6">
<h3 class="text-lg font-medium mb-4">各市签订合同信息公开率(%)</h3>
<div ref="chart3" class="h-80"></div>
</div>
<div class="bg-white rounded-lg p-6">
<h3 class="text-lg font-medium mb-4">各市招标标段全流程信息公开率(%)</h3>
<div ref="chart4" class="h-80"></div>
</div>
<div class="bg-white rounded-lg p-6">
<h3 class="text-lg font-medium mb-4">实施不见面开标的项目比例</h3>
<div ref="chart5" class="h-80"></div>
</div>
</div>
</main>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import * as echarts from 'echarts';
import { Search, User, Document, Timer, Files, DataLine, TrendCharts } from '@element-plus/icons-vue';
const searchText = ref('');
const dateRange = ref([]);
const navItems = [
{ name: '工作台', path: '/dashboard', icon: 'HomeFilled' },
{ name: '专项工作', path: '/special', icon: 'Menu' },
{ name: '数据汇', path: '/data', icon: 'DataLine' },
{ name: '智慧监管', path: '/monitor', icon: 'Monitor' },
{ name: '协同办公', path: '/collaboration', icon: 'Connection' },
{ name: '招标代理库', path: '/agency', icon: 'Collection' },
{ name: '全程监管', path: '/fullprocess', icon: 'View' },
{ name: '智能问答', path: '/qa', icon: 'ChatDotRound' }
];
// 图表实例
const chart1 = ref<HTMLElement | null>(null);
const chart2 = ref<HTMLElement | null>(null);
const chart3 = ref<HTMLElement | null>(null);
const chart4 = ref<HTMLElement | null>(null);
const chart5 = ref<HTMLElement | null>(null);
onMounted(() => {
const cities = ['广州市', '深圳市', '珠海市', '汕头市', '佛山市', '韶关市', '河源市', '梅州市', '惠州市', '汕尾市',
'东莞市', '中山市', '江门市', '阳江市', '湛江市', '茂名市', '肇庆市', '清远市', '潮州市', '揭阳市', '云浮市'];
// 图表1配置
const chart1Instance = echarts.init(chart1.value as HTMLElement);
chart1Instance.setOption({
animation: false,
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: cities,
axisLabel: {
interval: 0,
rotate: 45
}
},
yAxis: {
type: 'value',
min: 0,
max: 100,
axisLabel: {
formatter: '{value}%'
}
},
series: [{
data: [88.99, 91.56, 90.34, 90.37, 91.47, 95.14, 84.91, 95.38, 92.89, 93.43,
91.13, 94.17, 92.41, 100, 90.70, 91.26, 95.42, 91.17, 91.42, 91.04],
type: 'line',
smooth: true,
lineStyle: {
color: '#6366f1'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(99, 102, 241, 0.3)' },
{ offset: 1, color: 'rgba(99, 102, 241, 0.1)' }
])
}
}]
});
// 图表2配置
const chart2Instance = echarts.init(chart2.value as HTMLElement);
chart2Instance.setOption({
animation: false,
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: cities,
axisLabel: {
interval: 0,
rotate: 45
}
},
yAxis: {
type: 'value',
name: '天数'
},
series: [{
data: [33.5, 20.5, 32.7, 15.5, 20.6, 15.8, 10.5, 19.6, 15.3, 24.8,
24.5, 17.3, 32.5, 19.5, 23.2, 14.5, 16.6, 16.6, 13.8, 18.8],
type: 'line',
smooth: true,
lineStyle: {
color: '#0ea5e9'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(14, 165, 233, 0.3)' },
{ offset: 1, color: 'rgba(14, 165, 233, 0.1)' }
])
}
}]
});
// 图表3配置
const chart3Instance = echarts.init(chart3.value as HTMLElement);
chart3Instance.setOption({
animation: false,
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: cities,
axisLabel: {
interval: 0,
rotate: 45
}
},
yAxis: {
type: 'value',
min: 0,
max: 100,
axisLabel: {
formatter: '{value}%'
}
},
series: [{
data: [54.03, 42.11, 34.31, 77.01, 85.43, 22.59, 60.53, 43.33, 40.39, 33.33,
75.00, 68.83, 44.17, 38.55, 42.35, 65.73, 90.48, 23.47, 0, 0],
type: 'line',
smooth: true,
lineStyle: {
color: '#f97316'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(249, 115, 22, 0.3)' },
{ offset: 1, color: 'rgba(249, 115, 22, 0.1)' }
])
}
}]
});
// 图表4配置
const chart4Instance = echarts.init(chart4.value as HTMLElement);
chart4Instance.setOption({
animation: false,
tooltip: {
trigger: 'axis'
},
legend: {
data: ['招标公告', '资格预审', '中标公告', '中标候选人公示', '合同公告']
},
xAxis: {
type: 'category',
data: cities,
axisLabel: {
interval: 0,
rotate: 45
}
},
yAxis: {
type: 'value',
min: 0,
max: 100,
axisLabel: {
formatter: '{value}%'
}
},
series: [
{
name: '招标公告',
type: 'line',
stack: 'Total',
data: Array(20).fill(0).map(() => Math.random() * 30 + 70),
smooth: true
},
{
name: '资格预审',
type: 'line',
stack: 'Total',
data: Array(20).fill(0).map(() => Math.random() * 30 + 70),
smooth: true
},
{
name: '中标公告',
type: 'line',
stack: 'Total',
data: Array(20).fill(0).map(() => Math.random() * 30 + 70),
smooth: true
},
{
name: '中标候选人公示',
type: 'line',
stack: 'Total',
data: Array(20).fill(0).map(() => Math.random() * 30 + 70),
smooth: true
},
{
name: '合同公告',
type: 'line',
stack: 'Total',
data: Array(20).fill(0).map(() => Math.random() * 30 + 70),
smooth: true
}
]
});
// 图表5配置
const chart5Instance = echarts.init(chart5.value as HTMLElement);
chart5Instance.setOption({
animation: false,
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: cities,
axisLabel: {
interval: 0,
rotate: 45
}
},
yAxis: {
type: 'value',
min: 0,
max: 100,
axisLabel: {
formatter: '{value}%'
}
},
series: [{
data: [94.87, 100, 91.67, 87.15, 74.61, 92.23, 95.24, 76.54, 96.96, 100,
28.57, 94.02, 91.43, 42.86, 95.29, 85.22, 89.67, 100, 100],
type: 'line',
smooth: true,
lineStyle: {
color: '#14b8a6'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(20, 184, 166, 0.3)' },
{ offset: 1, color: 'rgba(20, 184, 166, 0.1)' }
])
}
}]
});
// 监听窗口大小变化
window.addEventListener('resize', () => {
chart1Instance.resize();
chart2Instance.resize();
chart3Instance.resize();
chart4Instance.resize();
chart5Instance.resize();
});
});
</script>
<style scoped>
.el-input :deep(.el-input__wrapper) {
background-color: rgba(255, 255, 255, 0.1);
box-shadow: none;
border: 1px solid rgba(255, 255, 255, 0.2);
}
.el-input :deep(.el-input__inner) {
color: white;
}
.el-input :deep(.el-input__inner::placeholder) {
color: rgba(255, 255, 255, 0.7);
}
.el-input :deep(.el-input__suffix) {
color: rgba(255, 255, 255, 0.7);
}
</style>
帮我这里的ts改为js