提交 85d882e0 authored 作者: huhuiqing's avatar huhuiqing

企业主页

上级 8d8de43f
<template>
<div class="sanction-content">
<div class="sanction-header">
<div class="section-header">
<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 style=" height: 34%;">
<Timeline :data="sanctionTimeData" text-key="title" id-key="seq" type="inline" />
</div>
<div style=" height: calc(60% - 120px);">
<process />
</div>
<div class="chart-text">
<img src="@/assets/icons/model.png" style="width: 19px;height: 20px;">
<div>
近年来,华为遭遇了严峻的外部技术封锁,其核心源于某些国家的持续制裁。这主要包括被列入“实体清单”,禁止其未经许可从美国公司获取芯片等关键技术;以及遭受更严格的“外国直接产品规则”打击,旨在切断其利用美国工具、软件和技术设计或制造先进芯片的渠道。这些措施不仅限制了华为自身产品的设计与生产,也影响了其全球供应链,使其在获取先进半导体、移动操作系统生态(如GMS)及基础软件工具等方面面临巨大挑战,意图从根本上遏制其技术发展。
</div>
<div class="arrow-2">
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import Timeline from './Timeline.vue';
import process from './process.vue';
const sanctionTimeData = ref([
{
"title": "初步限制与“实体清单”",
"content": "美国开始游说盟友禁止使用华为5G设备。2019年5月,美国商务部将华为及其70家关联公司列入“实体清单”,禁止关联公司在未获许可证的情况下向华为出售技术和产品。",
"time": "2025年10月"
},
{
"title": "“外国直接产品规则”升级",
"content": "制裁全面升级。任何公司,只要使用美国的技术或设备为华为生产芯片,都必须先获得美国许可。此举措旨在切断华为与全球顶级芯片制造商(如台积电)的联系。",
"time": "2025年10月"
},
{
"title": "进一步封堵漏洞",
"content": "将华为在21个国家的38家子公司列入实体清单,封堵华为通过第三方子公司获取受控物项的可能性。",
"time": "2025年10月"
},
{
"title": "5G设备禁令",
"content": "美国联邦通信委员会将华为、中兴等中国公司列为“国家安全威胁”,禁止美国运营商使用联邦补贴资金购买其设备。",
"time": "2025年10月"
},
{
"title": "全面切断与制裁加码",
"content": "美国政府吊销了英特尔、高通等公司向华为出口4G、Wi-Fi等芯片的许可证。据报道,美国已完全停止向华为发放所有产品的出口许可证。持续将更多与华为相关的公司列入实体清单。",
"time": "2025年10月"
}
])
</script>
<style scoped>
.sanction-content {
width: calc(100% - 320px);
height: calc(100vh - 220px);
overflow: auto;
border-radius: 4px;
margin: 16px 160px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 1);
justify-content: space-between;
}
.sanction-header {
width: 100%;
height: 60px;
display: flex;
padding: 16px 0;
}
.section-header {
display: flex;
align-items: center;
}
.action-icons {
display: flex;
gap: 15px;
margin-left: auto;
}
.action-icon {
/* 收藏按钮 */
width: 28px;
height: 28px;
cursor: pointer;
}
.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: 15px;
color: #1d2129;
margin: 0;
color: rgba(5, 95, 194, 1);
font-family: Microsoft YaHei;
font-size: 18px;
font-weight: 700;
line-height: 24px;
letter-spacing: 1px;
text-align: left;
}
.chart-text {
/* 大模型对话结果 */
height: 80px;
margin: 12px 20px;
/* 自动布局 */
display: flex;
flex-direction: row;
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
......@@ -4,8 +4,13 @@
&lt;
</button> -->
<div class="timeline-box">
<div class="line"></div>
<div class="timeline-box" :style="{
height: '100%'
// height: type === 'normal' ? '100%' : '50vh'
}">
<div class="line"
:style="{ '--i': type === 'normal' ? ' 50%' : '100%', '--translateY': type === 'normal' ? ' -50%' : '-100%', }">
</div>
<div v-for="(item, i) in showList" :key="item[idKey]" class="node" :style="leftOffset(i)">
<div class="node" :style="leftOffset(i)">
<!-- 圆环 -->
......@@ -15,14 +20,19 @@
<div class="time" :style="{
marginTop: linePos(i, flip) === 'down' ? '10px' : '-40px'
}">
}" v-if="type === 'normal'">
{{ item.time }}
</div>
<!-- 卡片:放到线右侧 -->
<div class="card" :class="[cardPos(i, flip), 'right-side']" @click="$emit('click-card', item)" :style="{
marginTop: linePos(i, flip) === 'down' ? '100px' : '-40px'
marginTop: linePos(i, flip) === 'down' ? '100px' : '-40px',
marginLeft: type === 'normal' ? '150px' : '0px'
}">
<div class="time" :style="{
marginLeft: 0
}" v-if="type !== 'normal'">
{{ item.time }}
</div>
<div class="title">
{{ item.title }}
<!-- <img class="item-header-icon" src="@/assets/images/icon/copy.png" style="cursor: pointer;"></img> -->
......@@ -56,7 +66,11 @@ export default {
idKey: { // 唯一标识字段
type: String,
default: 'id'
}
},
type: { // 父组件传入的数组
type: String,
default: 'normal'
},
},
data() {
return { index: 0 };
......@@ -72,17 +86,17 @@ export default {
},
methods: {
leftOffset(i) {
return { left: `${(i * 100) / 5}%` };
return this.type === 'normal' ? { left: `${(i * 100) / 5}%`, top: '50%' } : { left: `${(i * 100) / 5}%`, top: '100%' }
},
/* 上下层翻转(保留上次逻辑) */
cardPos(i, flip = false) {
return (i % 2) ^ flip ? 'down' : 'up';
return this.type === 'normal' ? ((i % 2) ^ flip ? 'down' : 'up') : ('up')
},
/* 线延伸方向 = 卡片出现方向 */
linePos(i, flip = false) {
return this.cardPos(i, flip); // up / down
return this.type === 'normal' ? this.cardPos(i, flip) : this.cardPos(i, flip) // up / down
}
}
};
......@@ -96,6 +110,7 @@ export default {
width: 100%;
position: relative;
padding: 0 40px;
height: 100%;
}
.arrow {
......@@ -131,7 +146,7 @@ export default {
.timeline-box {
flex: 1;
height: 100%;
/* height: 100%; */
position: relative;
}
......@@ -139,12 +154,10 @@ export default {
position: absolute;
left: 0;
right: 0;
top: 50%;
top: var(--i);
height: 6px;
background-image: url("@/assets/images/bg/timeLine-bg.jpg");
transform: translateY(-50%);
transform: translateY(var(--translateY));
background-size: auto 100%;
}
......@@ -152,7 +165,7 @@ export default {
.node {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
z-index: 2;
}
......@@ -242,7 +255,7 @@ export default {
}
.card.up {
bottom: 20px;
bottom: 50px;
}
.card.down {
......
<template>
<div class="chart-container">
<div v-for="(item, index) in chartData" :key="index" class="chart-card">
<!-- 研发投入 -->
<div class="metric-section">
<div class="metric-header">
<span class="title">研发投入</span>
<span class="growth-badge">+13.2%</span>
</div>
<!-- 制裁后 -->
<div class="bar-row">
<div class="year-label">{{ item.year }}</div>
<div style="width: calc(100% - 66px);">
<div class="bar after" :style="{ width: getInvestmentWidth(item.investmentAfter) + '%' }">
<div class="value-label">{{ formatInvestment(item.investmentAfter) }}</div>
</div>
</div>
</div>
<!-- 制裁前 -->
<div class="bar-row">
<div class="year-label">{{ item.year }}</div>
<div style="width: calc(100% - 66px);">
<div class="bar before" :style="{ width: getInvestmentWidth(item.investmentBefore) + '%' }">
<div class="value-label">{{ formatInvestment(item.investmentBefore) }}</div>
</div>
</div>
</div>
</div>
<!-- 研发人员 -->
<div class="metric-section">
<div class="metric-header">
<span class="title">研发人员</span>
<span class="growth-badge">+13.2%</span>
</div>
<!-- 制裁后 -->
<div class="bar-row">
<div class="year-label">{{ item.year }}</div>
<div style="width: calc(100% - 66px);">
<div class="bar after" :style="{ width: getStaffWidth(item.staffAfter) + '%' }">
<div class="value-label">{{ formatStaff(item.staffAfter) }}</div>
</div>
</div>
</div>
<!-- 制裁前 -->
<div class="bar-row">
<div class="year-label">{{ item.year }}</div>
<div style="width: calc(100% - 66px);">
<div class="bar before" :style="{ width: getStaffWidth(item.staffBefore) + '%' }">
<div class="value-label">{{ formatStaff(item.staffBefore) }}</div>
</div>
</div>
</div>
</div>
<!-- 图例 -->
<div class="legend">
<div class="legend-item">
<div class="color-box after"></div>
<span>制裁后</span>
</div>
<div class="legend-item">
<div class="color-box before"></div>
<span>制裁前</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
// 模拟从 JSON 导入(实际可替换为 import data from './rdData.json')
const rawData = [
{ year: "2019", investmentBefore: 1.01, investmentAfter: 1.37, staffBefore: 80000, staffAfter: 96000 },
{ year: "2020", investmentBefore: 1.15, investmentAfter: 1.52, staffBefore: 85000, staffAfter: 102000 },
{ year: "2021", investmentBefore: 1.20, investmentAfter: 1.68, staffBefore: 90000, staffAfter: 110000 },
{ year: "2022", investmentBefore: 1.25, investmentAfter: 1.75, staffBefore: 92000, staffAfter: 115000 },
{ year: "2023", investmentBefore: 1.30, investmentAfter: 1.85, staffBefore: 95000, staffAfter: 120000 }
];
const chartData = ref(rawData);
// === 投入相关计算 ===
const maxInvestment = computed(() => {
return Math.max(...chartData.value.flatMap(d => [d.investmentBefore, d.investmentAfter]));
});
function getInvestmentWidth(value) {
return Math.min(100, (value / maxInvestment.value) * 100);
}
function formatInvestment(value) {
return value.toFixed(2) + '亿元';
}
// === 人员相关计算 ===
const maxStaff = computed(() => {
return Math.max(...chartData.value.flatMap(d => [d.staffBefore, d.staffAfter]));
});
function getStaffWidth(value) {
return Math.min(100, (value / maxStaff.value) * 100);
}
function formatStaff(value) {
return Math.round(value / 1000) + 'k+';
}
</script>
<style scoped>
.chart-container {
display: flex;
flex-wrap: wrap;
gap: 24px;
padding: 24px;
}
.chart-card {
flex: 1;
min-width: 260px;
max-width: 320px;
background: rgba(240, 249, 255, 1);
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
padding: 20px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.metric-section {
margin-bottom: 24px;
}
.metric-header {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.title {
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 30px;
letter-spacing: 0px;
text-align: justify;
}
.growth-badge {
height: 30px;
line-height: 30px;
box-sizing: border-box;
border: 1px solid rgba(166, 227, 111, 0.5);
border-radius: 4px;
background: rgba(166, 227, 111, 0.2);
color: rgba(33, 129, 57, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
text-align: center;
padding: 0 4px;
margin-left: 8px;
}
.bar-row {
display: flex;
align-items: center;
height: 28px;
margin-bottom: 8px;
}
.year-label {
width: 66px;
font-size: 13px;
color: #64748b;
text-align: left;
}
.bar {
flex: 0 0 auto;
height: 24px;
border-radius: 0 12px 12px 0px;
min-width: 20px;
position: relative;
/* 👈 关键:为内部绝对定位提供参照 */
display: flex;
align-items: center;
justify-content: flex-end;
/* 数值靠右 */
padding-right: 8px;
/* 避免贴边 */
box-sizing: border-box;
}
/* 更精准的渐变色(匹配设计图质感) */
.after {
background: linear-gradient(90deg, #EEEBF0, #CE4F51);
}
.before {
background: linear-gradient(90deg, #DDEEFF, #1677FF);
}
.value-label {
width: auto !important;
/* 覆盖外部 width */
margin-left: 0 !important;
font-size: 12px;
color: white;
/* 白色文字更清晰 */
text-shadow: 0 0 2px rgba(0, 0, 0, 0.3);
/* 增强可读性 */
white-space: nowrap;
overflow: hidden;
}
.legend {
display: flex;
gap: 16px;
font-size: 12px;
color: #64748b;
margin-top: 12px;
padding-top: 12px;
}
.legend-item {
display: flex;
align-items: center;
gap: 6px;
}
.color-box {
width: 14px;
height: 14px;
}
.color-box.after {
background: linear-gradient(90deg, #EEEBF0, #CE4F51);
}
.color-box.before {
background: linear-gradient(90deg, #DDEEFF, #1677FF);
}
</style>
\ No newline at end of file
[
{
"year": "2019",
"investmentBefore": "1.01亿元",
"investmentAfter": "1.37亿元",
"staffBefore": "80000+",
"staffAfter": "96000+"
},
{
"year": "2020",
"investmentBefore": "1.01亿元",
"investmentAfter": "1.37亿元",
"staffBefore": "80000+",
"staffAfter": "96000+"
},
{
"year": "2021",
"investmentBefore": "1.01亿元",
"investmentAfter": "1.37亿元",
"staffBefore": "80000+",
"staffAfter": "96000+"
},
{
"year": "2022",
"investmentBefore": "1.01亿元",
"investmentAfter": "1.37亿元",
"staffBefore": "80000+",
"staffAfter": "96000+"
},
{
"year": "2023",
"investmentBefore": "1.01亿元",
"investmentAfter": "1.37亿元",
"staffBefore": "80000+",
"staffAfter": "96000+"
}
]
{
"openapi": "3.0.1",
"info": { "title": "刷课", "description": "", "version": "1.0.0" },
"tags": [],
"paths": {
"https://www.casmooc.cn/server/api/study/submit": {
"post": {
"summary": "刷课",
"deprecated": false,
"description": "",
"tags": [],
"parameters": [
{
"name": "x-access-origin",
"in": "header",
"description": "",
"required": false,
"example": "aHR0cHM6Ly93d3cuY2FzbW9vYy5jbg==",
"schema": { "type": "string" }
},
{
"name": "x-access-token",
"in": "header",
"description": "",
"required": false,
"example": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MzQ1NzY0MjksIm9wZXJhdG9ySWQiOiIxOTI0MzI2NDYwIn0.wZRjm7v4wMtYAEw3tpuGy879Ci3gY-fq7qaIedyJBZU",
"schema": { "type": "string" }
}
],
"requestBody": {
"content": {
"application/json": {
"schema": { "type": "object", "properties": {} },
"example": {
"belongCourseId": "",
"courseId": "1471492433195",
"isRecordAudio": 0,
"lastLearnTime": 1,
"recordDuration": "14400",
"studyLockUUID": "070885784AC74CE5BD7E104E2564CF7E"
}
}
}
},
"responses": {
"200": {
"description": "",
"content": { "application/json": { "schema": { "type": "object", "properties": {} } } },
"headers": {}
}
},
"security": []
}
}
},
"components": { "schemas": {}, "responses": {}, "securitySchemes": {} },
"servers": [],
"security": []
}
......@@ -138,6 +138,8 @@
<div class="main-content" v-if="activeTab === '研发实力'">
<Capability />
</div>
<SanctionsSituation v-if="activeTab === '被制裁情况'" />
<SupplyChain v-if="activeTab === '供应链情况'" />
</div>
</template>
......@@ -147,7 +149,8 @@ import data from './data/huaweiData.json'
import movementData from './data/movement.json'
import Timeline from "./component/Timeline.vue";
import Capability from './component/Capability.vue';
import SanctionsSituation from './component/SanctionsSituation‌.vue'
import SupplyChain from './component/SupplyChain.vue';
const tabList = ref(['基础信息', '研发实力', '被制裁情况', '供应链情况'])
const activeTab = ref('基础信息')
const tabListSmall = ref(['企业概况', '企业动态'])
......
......@@ -43,7 +43,7 @@ const getDonutChart = (nameList, valueList, isPercent = false) => {
radius: ['45%', '70%'], // 内环 / 外环
center: ['40%', '50%'],
avoidLabelOverlap: false,
itemStyle: { borderRadius: 0, borderColor: '#fff', borderWidth: 2 },
itemStyle: { borderRadius: 0, borderColor: '#fff', borderWidth: 0 },
label: {
show: false,
position: 'inside',
......
const getGraphChart = (nodes, links) => {
const option = {
legend: {
// data: categories.map(c => c.name),
show: false,
top: 40,
textStyle: {
fontSize: 12
}
},
animation: true,
animationDuration: 1000,
animationEasing: 'cubicOut',
series: [{
type: 'graph',
itemStyle: {
color: '#73C0DE'
},
layout: 'force',
data: nodes,
links: links,
// categories: categories,
roam: true,
label: {
show: true,
position: 'bottom',
formatter: '{b}',
fontSize: 12,
fontWeight: 'bold',
// backgroundColor: 'rgba(255,255,255,0.8)',
padding: [4, 6],
borderRadius: 4
},
lineStyle: {
color: 'source',
curveness: 0,
width: 1,
color: '#AED6FF'
},
edgeSymbol: ['none', 'arrow'],
edgeSymbolSize: [0, 5],
emphasis: {
focus: 'adjacency',
lineStyle: {
width: 4
},
label: {
show: true,
fontSize: 14
}
},
force: {
repulsion: 300,
gravity: 0,
edgeLength: 300
}
}],
// color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de']
};
return option
}
export default getGraphChart
\ No newline at end of file
......@@ -3,28 +3,18 @@ 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%'], // 可选:再往下挪一点,避免图例挤在一起
center: ['50%', '50%'], // 可选:再往下挪一点,避免图例挤在一起
indicator: [
{ name: '能源', max: 6500 },
{ name: '集成电路', max: 16000 },
{ name: '5G通信', max: 6500 },
{ name: '生物科技', max: 16000 },
{ name: '人工智能', max: 30000 },
{ name: '通信网络', max: 38000 },
{ name: '物联网', max: 38000 },
{ name: '量子科技', max: 52000 },
{ name: '生物科技', max: 25000 }
{ name: '智能汽车', max: 25000 }
],
axisName: {
formatter: '{value}',
......@@ -38,37 +28,18 @@ const getBarChart = (nameList, valueList, isPer) => {
name: 'Budget vs spending',
type: 'radar',
symbol: 'none',
// 添加或修改 lineStyle 属性来控制线条粗细
lineStyle: {
width: 1, // 调整这个值可以改变线条的粗细,数值越大线条越粗
color: '#69B1FF'
},
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)' }
areaStyle: { color: 'rgba(105, 177, 255, 0.1)' }
},
{
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)' }
}
]
}
]
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论