提交 efda93be authored 作者: huhuiqing's avatar huhuiqing

研发投入+研究人员+专利情况(待完善)

上级 d28bc11c
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
<div class="box-content"> <div class="box-content">
<div class="tab-box"> <div class="tab-box">
<div v-for="(tab, index) in tabList" :class="activeTab === tab ? 'tab-active' : 'tab'" @click="activeTab = tab"> <div v-for="(tab, index) in tabList" :class="activeTab === tab ? 'tab-active' : 'tab'"
@click="changeTab(tab, index)">
{{ tab }} {{ tab }}
<div class="arrow-active"> <div class="arrow-active">
...@@ -12,7 +13,7 @@ ...@@ -12,7 +13,7 @@
</div> </div>
<!--/*头部总览 */--> <!--/*头部总览 */-->
<div class="total"> <div class="total">
<div v-for="(item) in totalData" class="total-box"> <div v-for="(item) in totalData[activeIndex]" class="total-box">
<div class="line"> <div class="line">
</div> </div>
...@@ -36,15 +37,19 @@ ...@@ -36,15 +37,19 @@
<div class="section-header" style=" margin-top: 24px;"> <div class="section-header" style=" margin-top: 24px;">
<div style="display: flex;"> <div style="display: flex;">
<div class="section-icon"></div> <div class="section-icon"></div>
<h3 class="section-title">年度研发投入对比</h3> <h3 class="section-title"> {{ activeTab === '研发投入' ? '年度研发投入对比' : activeTab === '研究人员' ? '研究人员数量增长趋势' :
'专利地域分布' }}</h3>
</div> </div>
<div class="action-icons"> <div class="action-icons">
<img src="@/assets/icons/download.png" alt="下载" class="action-icon"> <img src="@/assets/icons/download.png" alt="下载" class="action-icon">
<img src="@/assets/icons/shoucang.png" alt="收藏" class="action-icon"> <img src="@/assets/icons/shoucang.png" alt="收藏" class="action-icon">
</div> </div>
</div> </div>
<div id="chart1" class="chart-box"> <div id="chart1" class="chart-box" v-show="activeTab === '研发投入'">
</div>
<div id="chart3" class="chart-box" v-show="activeTab === '研究人员'">
</div>
<div id="chart5" class="chart-box" v-show="activeTab === '专利情况'">
</div> </div>
<div class="chart-text"> <div class="chart-text">
<img src="@/assets/icons/model.png" style="width: 19px;height: 20px;"> <img src="@/assets/icons/model.png" style="width: 19px;height: 20px;">
...@@ -61,15 +66,19 @@ ...@@ -61,15 +66,19 @@
<div class="section-header" style=" margin-top: 24px;"> <div class="section-header" style=" margin-top: 24px;">
<div style="display: flex;"> <div style="display: flex;">
<div class="section-icon"></div> <div class="section-icon"></div>
<h3 class="section-title">研发投入增长对比</h3> <h3 class="section-title"> {{ activeTab === '研发投入' ? '研发投入增长对比' : activeTab === '研究人员' ? '研究人员学历分布' :
'专利技术领域分布' }}</h3>
</div> </div>
<div class="action-icons"> <div class="action-icons">
<img src="@/assets/icons/download.png" alt="下载" class="action-icon"> <img src="@/assets/icons/download.png" alt="下载" class="action-icon">
<img src="@/assets/icons/shoucang.png" alt="收藏" class="action-icon"> <img src="@/assets/icons/shoucang.png" alt="收藏" class="action-icon">
</div> </div>
</div> </div>
<div id="chart2" class="chart-box"> <div id="chart2" class="chart-box" v-show="activeTab === '研发投入'">
</div>
<div id="chart4" class="chart-box" v-show="activeTab === '研究人员'">
</div>
<div id="chart6" class="chart-box" v-show="activeTab === '专利情况'">
</div> </div>
<div class="chart-text"> <div class="chart-text">
<img src="@/assets/icons/model.png" style="width: 19px;height: 20px;"> <img src="@/assets/icons/model.png" style="width: 19px;height: 20px;">
...@@ -85,15 +94,17 @@ ...@@ -85,15 +94,17 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted, nextTick } from 'vue'
import getBarChart from "../js/barChart.js"; import getBarChart from "../js/barChart.js";
import * as echarts from "echarts"; import getDonutChart from '../js/donutChart.js';
import getLineChart from "../js/lineChart.js"; import getLineChart from "../js/lineChart.js";
import getRadarChart from '../js/radarChart.js'
import * as echarts from "echarts";
const tabList = ref(['研发投入', '研究人员', '专利情况']) const tabList = ref(['研发投入', '研究人员', '专利情况'])
const activeTab = ref('研发投入') const activeTab = ref('研发投入')
const activeIndex = ref(0)
const totalData = ref([ const totalData = ref([[
{ {
"label": "累计研发投入", "label": "累计研发投入",
"value": 9854, "value": 9854,
...@@ -114,7 +125,17 @@ const totalData = ref([ ...@@ -114,7 +125,17 @@ const totalData = ref([
"value": "Top", "value": "Top",
"unit": "" "unit": ""
} }
]) ], [
{ label: '2025年拟招聘应届生', value: 11.4, unit: '万' },
{ label: '研发人员占比', value: 55.4, unit: '%' },
{ label: '全年计划培养实习生', value: 1, unit: '万+' },
{ label: '研发人员总数', value: 5000, unit: '+' }
], [
{ label: '全球有效专利', value: 12, unit: '万+' },
{ label: 'PCT申请量排名', value: 'Top', unit: '5' },
{ label: '5G标准必要专利占比', value: 21.5, unit: '%' },
{ label: '家族专利', value: 4500, unit: '+' }
]])
//年度研发投入对比 //年度研发投入对比
const chart1Data = ref({ const chart1Data = ref({
...@@ -127,24 +148,91 @@ const chart2Data = { ...@@ -127,24 +148,91 @@ const chart2Data = {
dataY: [1.2, 1.5, 1.4, 1.8, 1.3, 1.5, 1.6, 1.4] dataY: [1.2, 1.5, 1.4, 1.8, 1.3, 1.5, 1.6, 1.4]
}; };
const chart3Data = ref({
name: ['2020', '2021', '2022', '2023', '2024', '2025'],
value: [50, 100, 150, 200, 250, 300, 350, 400]
});
// 学历分布数据(对应图片)
const chart4Data = ref({
name: ['博士', '硕士', '学士', '其他'],
value: [28, 36, 22, 8],
})
// 学历分布数据(对应图片)
const chart5Data = ref({
name: ['博士', '硕士', '学士', '其他'],
value: [28, 36, 22, 8],
})
function changeTab(tab, index) {
console.log(tab, activeTab.value)
activeTab.value = tab
activeIndex.value = index
console.log(tab, activeTab.value, activeIndex.value)
// 保证 DOM 更新完再画
nextTick(() => {
if (tab === '研发投入') {
chart1()
chart2()
} else if (tab === '研究人员') {
chart3()
char4()
} if (tab === '专利情况') {
char5()
chart6()
}
// 其它 tab 同理 …
})
}
// 绘制echarts图表 // 绘制echarts图表
const setChart = (option, chartId) => { const setChart = (option, chartId) => {
let chartDom = document.getElementById(chartId); let chartDom = document.getElementById(chartId);
console.log(chartDom, "chartDomchartDomchartDom");
chartDom.removeAttribute("_echarts_instance_"); chartDom.removeAttribute("_echarts_instance_");
let chart = echarts.init(chartDom); let chart = echarts.init(chartDom);
chart.setOption(option); chart.setOption(option);
return chart; return chart;
}; };
onMounted(() => { function chart1() {
let char1 = getBarChart(chart1Data.value.name, chart1Data.value.value, true); let char1 = getBarChart(chart1Data.value.name, chart1Data.value.value, true);
setChart(char1, "chart1"); setChart(char1, "chart1");
}
function chart2() {
let chart2 = getLineChart(chart2Data.dataX, chart2Data.dataY); let chart2 = getLineChart(chart2Data.dataX, chart2Data.dataY);
setChart(chart2, "chart2"); setChart(chart2, "chart2");
// let char2 = radarChart(); }
// setChart(char2, "char2");
function chart3() {
let char3 = getBarChart(chart3Data.value.name, chart3Data.value.value, true);
setChart(char3, "chart3");
}
function char4() {
console.log(chart4Data.value)
let char4 = getDonutChart(chart4Data.value.name, chart4Data.value.value, true);
setChart(char4, "chart4");
}
function char5() {
console.log(chart5Data.value)
let char5 = getDonutChart(chart5Data.value.name, chart5Data.value.value, true);
setChart(char5, "chart5");
}
function chart6() {
let char6 = getRadarChart();
setChart(char6, "chart6");
}
onMounted(() => {
chart1()
chart2()
}); });
</script> </script>
......
<template>
<div class="box-content">
<div class="tab-box">
<div v-for="(tab, index) in tabList" :class="activeTab === tab ? 'tab-active' : 'tab'" @click="activeTab = tab">
{{ tab }}
<div class="arrow-active">
</div>
</div>
</div>
<!--/*头部总览 */-->
<div class="total">
<div v-for="(item) in totalData" class="total-box">
<div class="line">
</div>
<div class="total-label">
{{ item.label }}
</div>
<div class="total-content">
<div class="total-value">
{{ item.value }}
</div>
<div class="total-unit">
{{ item.unit }}
</div>
</div>
</div>
</div>
<!--/*图表 */-->
<div class="chart">
<div class="chart-content">
<div class="section-header" style=" margin-top: 24px;">
<div style="display: flex;">
<div class="section-icon"></div>
<h3 class="section-title">年度研发投入对比</h3>
</div>
<div class="action-icons">
<img src="@/assets/icons/download.png" alt="下载" class="action-icon">
<img src="@/assets/icons/shoucang.png" alt="收藏" class="action-icon">
</div>
</div>
<div id="chart1" class="chart-box">
</div>
<div class="chart-text">
<img src="@/assets/icons/model.png" style="width: 19px;height: 20px;">
<div>
近五年来,华为的研发投入在绝对金额和投入强度上均持续攀升。尤其是在收入因外部制裁而经历波动时,研发投入依然保持强劲增长,使其投入强度达到了历史高位。
</div>
<div class="arrow-2">
</div>
</div>
</div>
<div class="chart-content">
<div class="section-header" style=" margin-top: 24px;">
<div style="display: flex;">
<div class="section-icon"></div>
<h3 class="section-title">研发投入增长对比</h3>
</div>
<div class="action-icons">
<img src="@/assets/icons/download.png" alt="下载" class="action-icon">
<img src="@/assets/icons/shoucang.png" alt="收藏" class="action-icon">
</div>
</div>
<div id="chart2" class="chart-box">
</div>
<div class="chart-text">
<img src="@/assets/icons/model.png" style="width: 19px;height: 20px;">
<div>
华为在巨大的外部压力下,研发投入不仅在绝对金额上持续增长,其占收入的比重更是大幅提升,特别是2021年后形成的“剪刀差”,体现了公司最高优先级的战略抉择。 </div>
<div class="arrow-2">
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import getBarChart from "../js/barChart.js";
import * as echarts from "echarts";
import getLineChart from "../js/lineChart.js";
const tabList = ref(['研发投入', '研究人员', '专利情况'])
const activeTab = ref('研发投入')
const totalData = ref([
{
"label": "累计研发投入",
"value": 9854,
"unit": "亿元"
},
{
"label": "年度研发投入",
"value": 2153.9,
"unit": "亿元"
},
{
"label": "研发强度",
"value": 22.9,
"unit": "%"
},
{
"label": "研发投入排名",
"value": "Top",
"unit": ""
}
])
//年度研发投入对比
const chart1Data = ref({
name: ['2020', '2021', '2022', '2023', '2024', '2025'],
value: [50, 100, 150, 200, 250, 300, 350, 400]
});
//研发投入增长对比
const chart2Data = {
dataX: ["2025-01", "2025-02", "2025-03", "2025-04", "2025-05", "2025-06", "2025-07", "2025-08"],
dataY: [1.2, 1.5, 1.4, 1.8, 1.3, 1.5, 1.6, 1.4]
};
// 绘制echarts图表
const setChart = (option, chartId) => {
let chartDom = document.getElementById(chartId);
console.log(chartDom, "chartDomchartDomchartDom");
chartDom.removeAttribute("_echarts_instance_");
let chart = echarts.init(chartDom);
chart.setOption(option);
return chart;
};
onMounted(() => {
let char1 = getBarChart(chart1Data.value.name, chart1Data.value.value, true);
setChart(char1, "chart1");
let chart2 = getLineChart(chart2Data.dataX, chart2Data.dataY);
setChart(chart2, "chart2");
// let char2 = radarChart();
// setChart(char2, "char2");
});
</script>
<style scoped>
.box-content {
width: 100%;
height: calc(100vh - 220px);
overflow: auto;
}
.tab-box {
/* 左侧导航 */
width: 112px;
height: 128px;
position: absolute;
left: 0;
margin: 20px;
/* 自动布局 */
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
gap: 16;
.tab {
color: rgba(59, 65, 75, 1);
height: 48px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
box-sizing: border-box;
border-bottom: 0px solid rgba(5, 95, 194, 1);
margin: 6px 30px 0 0;
}
.tab-active {
/* 容器 7 */
width: 104px;
height: 32px;
display: flex;
align-items: center;
box-sizing: border-box;
border-bottom: 2px solid rgba(5, 95, 194, 1);
margin: 6px 30px 0 0;
border-radius: 16px;
background: rgba(5, 95, 194, 1);
color: rgba(255, 255, 255, 1);
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: left;
padding: 4px 12px;
}
.arrow-active {
width: 0;
height: 0;
border-style: solid;
border-width: 4px 0 4px 6px;
margin-left: 5px;
/* 上 右 下 左 */
border-color: transparent transparent transparent #ffffff;
/* 只给左边上色 */
/* background: rgba(255, 255, 255, 1); */
}
}
/*头部总览 */
.total {
height: 80px;
display: flex;
gap: 16px;
}
.total-box {
border-radius: 4px;
background: rgba(255, 255, 255, 1);
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
.line {
/* 矩形 214 */
width: 4px;
height: 49px;
background: rgba(5, 95, 194, 1);
}
.total-label {
color: rgba(59, 65, 75, 1);
margin: 0px 30px;
font-size: 16px;
font-weight: 700;
line-height: 24px;
letter-spacing: 1px;
text-align: left;
}
.total-content {
display: flex;
margin-right: 35px;
color: rgba(5, 95, 194, 1);
font-family: Microsoft YaHei;
letter-spacing: 0px;
text-align: right;
.total-value {
font-size: 24px;
font-weight: 700;
line-height: 24px;
}
.total-unit {
font-size: 16px;
font-weight: 500;
line-height: 16px;
margin-top: 8px;
}
}
}
.chart {
margin-top: 16px;
height: calc(100vh - 320px);
display: flex;
gap: 16px;
.chart-content {
border-radius: 4px;
background: rgba(255, 255, 255, 1);
flex: 1;
justify-content: space-between;
.section-header {
display: flex;
width: 100%;
justify-content: space-between;
}
.section-icon {
width: 7px;
height: 18px;
border-radius: 0 4px 4px 0;
background: rgba(5, 95, 194, 1);
margin-right: 17px;
}
.section-title {
font-size: 18px;
color: #1d2129;
margin: 0;
color: rgba(5, 95, 194, 1);
font-family: Microsoft YaHei;
font-weight: 700;
line-height: 24px;
letter-spacing: 1px;
text-align: left;
}
}
.action-icons {
display: flex;
margin-left: auto;
}
.action-icon {
/* 收藏按钮 */
width: 28px;
height: 28px;
cursor: pointer;
margin-right: 12px;
}
.chart-box {
width: 100%;
height: calc(100% - 130px);
}
.chart-text {
/* 大模型对话结果 */
height: 52px;
margin: 12px 20px;
/* 自动布局 */
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 10;
padding: 0px 12px 0px 12px;
box-sizing: border-box;
border: 1px solid rgba(231, 243, 255, 1);
border-radius: 4px;
background: rgba(246, 251, 255, 1);
color: rgba(5, 95, 194, 1);
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: justify;
gap: 13px;
}
.arrow-2 {
border-radius: 50%;
width: 24px;
height: 24px;
font-size: 24px;
background: rgba(231, 243, 255, 1);
}
}
</style>
\ No newline at end of file
// donutChart.js
import * as echarts from 'echarts';
/**
* 环形图( donut / pie )
* @param {Array<string>} nameList 名称数组
* @param {Array<number>} valueList 数值数组
* @param {boolean} isPercent 数值是否带 % 显示
* @returns {Object} echarts option
*/
const getDonutChart = (nameList, valueList, isPercent = false) => {
console.log(nameList, valueList, isPercent = false)
// 渐变色可随主题扩展
const colorList = [
'#87E8DE',
'#69B1FF',
'#FF7875',
'#B37FEB'
];
const data = nameList.map((name, i) => ({
name,
value: valueList[i]
}));
return {
color: colorList,
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c}' + (isPercent ? '%' : '') + ' ({d}%)'
},
legend: {
orient: 'vertical',
// left: 'center',
bottom: 'bottom',
itemGap: 16,
textStyle: { fontSize: 14, color: '#666' }
},
series: [
{
name: '统计',
type: 'pie',
radius: ['45%', '70%'], // 内环 / 外环
center: ['40%', '50%'],
avoidLabelOverlap: false,
itemStyle: { borderRadius: 0, borderColor: '#fff', borderWidth: 2 },
label: {
show: false,
position: 'inside',
formatter: ({ value }) => value + (isPercent ? '%' : ''),
fontSize: 14,
color: '#fff'
},
emphasis: {
label: { show: true, fontSize: 16, fontWeight: 'bold' }
},
data
}
]
};
};
export default getDonutChart;
\ No newline at end of file
import * as echarts from "echarts";
const getBarChart = (nameList, valueList, isPer) => {
const option = {
title: { text: '' },
legend: {
icon: 'circle',
orient: 'horizontal', // 横向
top: 0, // 图上方
left: 'center', // 水平居中
textStyle: {
fontSize: 14 // 字号,按需调整
},
grid: { top: 60 },
data: ['美国', '欧盟', '英国', '日本', '韩国', '加拿大']
},
radar: {
radius: '50%', // 关键:缩小整个雷达
center: ['50%', '60%'], // 可选:再往下挪一点,避免图例挤在一起
indicator: [
{ name: '能源', max: 6500 },
{ name: '集成电路', max: 16000 },
{ name: '人工智能', max: 30000 },
{ name: '通信网络', max: 38000 },
{ name: '量子科技', max: 52000 },
{ name: '生物科技', max: 25000 }
],
axisName: {
formatter: '{value}',
color: 'rgba(59, 65, 75, 1)',
fontSize: 14,
fontWeight: 400
}
},
series: [
{
name: 'Budget vs spending',
type: 'radar',
symbol: 'none',
data: [
{
value: [4200, 3000, 20000, 35000, 50000, 18000],
name: '美国',
areaStyle: { color: 'rgba(10, 87, 166, 0.2)' }
},
{
value: [5000, 14000, 28000, 26000, 42000, 21000],
name: '欧盟',
areaStyle: { color: 'rgba(206, 79, 81, 0.2)' }
},
{
value: [4000, 14000, 18000, 21000, 32000, 10000],
name: '英国',
areaStyle: { color: 'rgba(250, 140, 22, 0.2)' }
},
{
value: [4000, 14000, 18000, 21000, 32000, 10000],
name: '日本',
areaStyle: { color: 'rgba(250, 140, 22, 0.2)' }
},
{
value: [4000, 14000, 18000, 21000, 32000, 10000],
name: '韩国',
areaStyle: { color: 'rgba(250, 140, 22, 0.2)' }
},
{
value: [4000, 14000, 18000, 21000, 32000, 10000],
name: '加拿大',
areaStyle: { color: 'rgba(250, 140, 22, 0.2)' }
}
]
}
]
}
return option
}
export default getBarChart
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论