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

Merge branch 'master' of http://8.140.26.4:10003/caijian/risk-monitor into dev_hhq

File added
...@@ -322,9 +322,10 @@ export function getCompareCountSan(startTime) { ...@@ -322,9 +322,10 @@ export function getCompareCountSan(startTime) {
return request200( return request200(
request({ request({
method: "GET", method: "GET",
url: "/api/entitiesDataCount/compareCountSan", // url: "/api/entitiesDataCount/compareCountSan",
url: "/api/entitiesDataInfo/getSanCountInfo",
params: { params: {
startTime sanctionDate: startTime || "2025-11-11"
} }
}) })
); );
...@@ -385,6 +386,30 @@ export function getEntitiesUpdateCount() { ...@@ -385,6 +386,30 @@ export function getEntitiesUpdateCount() {
); );
} }
/**
* 制裁领域分析
*/
export function getSanDomainCount() {
return request200(
request({
method: "GET",
url: "/api/entitiesDataCount/getSanDomainCount"
})
);
}
/**
* 上市企业制裁强度
*/
export function getSanStrength() {
return request200(
request({
method: "GET",
url: "/api/entitiesDataInfo/listedEntity/sanInfo"
})
);
}
/** /**
* 新增实体领域分布情况 * 新增实体领域分布情况
* @param {string} sanTime - 开始时间,格式为 'YYYY-MM-DD' * @param {string} sanTime - 开始时间,格式为 'YYYY-MM-DD'
...@@ -416,7 +441,7 @@ export function getEntitiesDomainCount() { ...@@ -416,7 +441,7 @@ export function getEntitiesDomainCount() {
return request200( return request200(
request({ request({
method: "GET", method: "GET",
url: "/api/entitiesDataCount/entitiesDomainCount" url: "/api/entitiesDataInfo/getPreviousDomian"
}) })
); );
} }
...@@ -554,3 +579,31 @@ export function getEntityFinancing() { ...@@ -554,3 +579,31 @@ export function getEntityFinancing() {
}) })
); );
} }
/**
* 上市企业市值变化情况
*/
export function getEntityMarketValue() {
return request200(
request({
method: "GET",
url: "/api/entitiesDataInfo/listedEntity/market"
})
);
}
/**
* 重点上市企业列表
*/
export function getKeyListedEntityList(date, keyword = "") {
return request200(
request({
method: "GET",
url: "/api/entitiesDataInfo/listedEntity/keyEntity",
params: {
sanctionDate: date,
searchText: keyword
}
})
);
}
...@@ -21,19 +21,19 @@ ...@@ -21,19 +21,19 @@
<script setup> <script setup>
import { ref, onMounted, onBeforeUnmount, watch } from "vue"; import { ref, onMounted, onBeforeUnmount, watch } from "vue";
import * as echarts from "echarts"; import * as echarts from "echarts";
import Center from "./assets/埃隆·马斯克.png"; import Center from "./assets/img1.png";
import P1 from "./assets/唐纳德·特朗普.png"; import P1 from "./assets/img2.png";
import P2 from "./assets/詹姆斯・默多克.png"; import P2 from "./assets/img3.png";
import P3 from "./assets/格温・肖特韦尔.png"; import P3 from "./assets/img4.png";
import P4 from "./assets/金博尔・马斯克.png"; import P4 from "./assets/img5.png";
import P5 from "./assets/拉里・埃里森.png"; import P5 from "./assets/img6.png";
import P6 from "./assets/斯科特·贝森特.png"; import P6 from "./assets/img7.png";
import P7 from "./assets/杰弗里·凯斯勒.png"; import P7 from "./assets/img8.png";
import P8 from "./assets/马尔科·卢比奥.png"; import P8 from "./assets/img9.png";
import P9 from "./assets/道格·伯格姆.png"; import P9 from "./assets/img10.png";
import P10 from "./assets/艾拉・埃伦普里斯.png"; import P10 from "./assets/img11.png";
import P11 from "./assets/贾斯汀・马斯克.png"; import P11 from "./assets/img12.png";
import PS from "./assets/史蒂夫・尤尔韦松.png"; import PS from "./assets/img13.png";
const list = ref(["圆形布局", "力导向布局", "树形布局"]); const list = ref(["圆形布局", "力导向布局", "树形布局"]);
const activeIndex = ref("圆形布局"); const activeIndex = ref("圆形布局");
......
...@@ -562,15 +562,87 @@ ...@@ -562,15 +562,87 @@
</div> </div>
</div> </div>
<div class="home-main-footer-main"> <div class="home-main-footer-main">
<div class="left">
<div class="select-box">
<div class="select-box-header">
<div class="icon"></div>
<div class="title">{{ "发布时间" }}</div>
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox
v-for="time in pubTime"
:key="time.id"
v-model="activePubTime"
:label="time.id"
class="filter-checkbox"
>
{{ time.name }}
</el-checkbox>
</div>
</div>
</div>
<div class="select-box">
<div class="select-box-header">
<div class="icon"></div>
<div class="title">{{ "涉及领域" }}</div>
</div>
<div class="select-main select-main1">
<div class="checkbox-group">
<el-checkbox
v-for="area in areaList"
:key="area.id"
v-model="activeAreaList"
:label="area.id"
class="filter-checkbox"
>
{{ area.name }}
</el-checkbox>
</div>
</div>
</div>
</div>
<div class="right">
<div class="content-header"> <div class="content-header">
<div class="icon"> <div class="icon">
<img src="./assets/images/box1-header-icon.png" alt="" /> <img src="./assets/images/footer-header-icon.png" alt="" />
</div> </div>
<div class="title">{{ "政令库" }}</div> <div class="title">{{ "政令库" }}</div>
</div> </div>
<div class="content-box"> <div class="content-box">
<div class="main-item" v-for="(decree, index) in curDecreeList" :key="index" @click="handleClickToDetail"> <div
class="main-item"
v-for="(item, index) in curDecreeList"
:key="index"
@click="handleClickToDetail"
>
<div class="main-item-left"> <div class="main-item-left">
<div class="left-left">{{ item.time }}</div>
<div class="left-right">
<div class="icon"></div>
<div class="line"></div>
</div>
</div>
<div class="main-item-center">
<div class="center-header">
<div class="title">{{ item.title }}</div>
<div
class="type-box"
:class="{
type1: item.status === 1,
type2: item.status === 2,
type3: item.status === 3
}"
>
{{ item.type }}
</div>
</div>
<div class="desc">{{ item.desc }}</div>
<div class="tag-box">
<div class="tag" v-for="(val, idx) in item.tagList" :key="idx">{{ val }}</div>
</div>
</div>
<!-- <div class="main-item-left">
<div <div
class="left-box" class="left-box"
:class="{ :class="{
...@@ -591,7 +663,7 @@ ...@@ -591,7 +663,7 @@
<div class="main-item-right-icon"> <div class="main-item-right-icon">
<img src="./assets/images/open-icon.png" alt="" /> <img src="./assets/images/open-icon.png" alt="" />
</div> </div>
</div> </div> -->
</div> </div>
</div> </div>
<div class="footer-box"> <div class="footer-box">
...@@ -613,6 +685,7 @@ ...@@ -613,6 +685,7 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</template> </template>
<script setup> <script setup>
...@@ -935,109 +1008,91 @@ const decreeList = ref([ ...@@ -935,109 +1008,91 @@ const decreeList = ref([
type: "总统政令", type: "总统政令",
status: 1, status: 1,
title: "关于进一步延长TikTok执法宽限期的行政令", title: "关于进一步延长TikTok执法宽限期的行政令",
time: "2025年9月16日" time: "2025年9月16日",
img: 1,
desc: "123",
tagList: ["生物科技"]
}, },
{ {
type: "总统政令", type: "总统政令",
status: 1, status: 1,
title: "为国家安全部署先进核反应堆技术", title: "为国家安全部署先进核反应堆技术",
time: "2025年9月16日" time: "2025年9月16日",
img: 1,
desc: "123",
tagList: ["生物科技"]
}, },
{ {
type: "总统政令", type: "总统政令",
status: 1, status: 1,
title: "修改对等关税税率以反映与中华人民共和国会谈情况的行政令", title: "修改对等关税税率以反映与中华人民共和国会谈情况的行政令",
time: "2025年9月15日" time: "2025年9月15日",
img: 1,
desc: "123",
tagList: ["生物科技"]
}, },
{ {
type: "总统政令", type: "总统政令",
status: 1, status: 1,
title: "调整互惠关税范围,并制定实施贸易和安全协议的程序", title: "调整互惠关税范围,并制定实施贸易和安全协议的程序",
time: "2025年9月15日" time: "2025年9月15日",
img: 1,
desc: "123",
tagList: ["生物科技"]
}, },
{ {
type: "总统政令", type: "总统政令",
status: 1, status: 1,
title: "持续努力加强国家网络安全,并修订第13694号行政命令和第14144号行政命令", title: "持续努力加强国家网络安全,并修订第13694号行政命令和第14144号行政命令",
time: "2025年9月14日" time: "2025年9月14日",
img: 1,
desc: "123",
tagList: ["生物科技"]
}, },
{ {
type: "总统备忘录", type: "总统备忘录",
status: 3, status: 3,
title: "通过第232条款行动确保加工关键矿物及衍生产品的国家安全与经济韧性", title: "通过第232条款行动确保加工关键矿物及衍生产品的国家安全与经济韧性",
time: "2025年9月14日" time: "2025年9月14日",
img: 1,
desc: "123",
tagList: ["生物科技"]
}, },
{ {
type: "提名与任命", type: "提名与任命",
status: 2, status: 2,
title: "终止对不可靠、非受控能源的市场扭曲补贴", title: "终止对不可靠、非受控能源的市场扭曲补贴",
time: "2025年9月11日" time: "2025年9月11日",
}, img: 1,
{ desc: "123",
type: "总统政令", tagList: ["生物科技"]
status: 1,
title: "对所有国家暂停免关税待遇",
time: "2025年9月6日"
},
{
type: "总统政令",
status: 1,
title: "对所有国家暂停免关税待遇",
time: "2025年9月6日"
},
{
type: "总统政令",
status: 1,
title: "对所有国家暂停免关税待遇",
time: "2025年9月6日"
},
{
type: "总统政令",
status: 1,
title: "对所有国家暂停免关税待遇",
time: "2025年9月6日"
},
{
type: "总统政令",
status: 1,
title: "对所有国家暂停免关税待遇",
time: "2025年9月6日"
},
{
type: "总统政令",
status: 1,
title: "对所有国家暂停免关税待遇",
time: "2025年9月6日"
},
{
type: "总统政令",
status: 1,
title: "对所有国家暂停免关税待遇",
time: "2025年9月6日"
}, },
{ {
type: "总统政令", type: "总统政令",
status: 1, status: 1,
title: "对所有国家暂停免关税待遇", title: "对所有国家暂停免关税待遇",
time: "2025年9月6日" time: "2025年9月6日",
img: 1,
desc: "123",
tagList: ["生物科技"]
}, },
{ {
type: "总统政令", type: "总统政令",
status: 1, status: 1,
title: "对所有国家暂停免关税待遇", title: "对所有国家暂停免关税待遇",
time: "2025年9月6日" time: "2025年9月6日",
img: 1,
desc: "123",
tagList: ["生物科技"]
}, },
{ {
type: "总统政令", type: "总统政令",
status: 1, status: 1,
title: "对所有国家暂停免关税待遇", title: "对所有国家暂停免关税待遇",
time: "2025年9月6日" time: "2025年9月6日",
}, img: 1,
{ desc: "123",
type: "总统政令", tagList: ["生物科技"]
status: 1,
title: "对所有国家暂停免关税待遇",
time: "2025年9月6日"
} }
]); ]);
const curDecreeList = computed(() => { const curDecreeList = computed(() => {
...@@ -1068,7 +1123,7 @@ const releaseTimeList = ref([ ...@@ -1068,7 +1123,7 @@ const releaseTimeList = ref([
value: "近五年发布" value: "近五年发布"
} }
]); ]);
const categoryList = ref(["全部分类", "总统政令", "提名与任命", "总统备忘录", "声明"]); const categoryList = ref(["全部分类", "白宫", "能源部", "商务部", "战争部", "FCC", "FDA", "NASA", "NSF", "NIH"]);
const activeCate = ref("全部分类"); const activeCate = ref("全部分类");
const handleClickCate = cate => { const handleClickCate = cate => {
...@@ -1135,6 +1190,24 @@ const handleToPosi = id => { ...@@ -1135,6 +1190,24 @@ const handleToPosi = id => {
} }
}; };
const areaList = [
{ id: "人工智能", name: "人工智能" },
{ id: "集成电路", name: "集成电路" },
{ id: "通信网络", name: "通信网络" },
{ id: "量子科技", name: "量子科技" }
];
const activeAreaList = ["人工智能"];
const pubTime = ref([
{ id: "2025年", name: "2025年" },
{ id: "2024年", name: "2024年" },
{ id: "2023年", name: "2023年" },
{ id: "2022年", name: "2022年" },
{ id: "2021年", name: "2021年" },
{ id: "更早时间", name: "更早时间" }
]);
const activePubTime = ref(["2025年"]);
onMounted(async () => { onMounted(async () => {
let chart1 = getBarChart(chart1Data.value.dataX, chart1Data.value.dataY); let chart1 = getBarChart(chart1Data.value.dataX, chart1Data.value.dataY);
setChart(chart1, "chart1"); setChart(chart1, "chart1");
...@@ -2689,7 +2762,7 @@ onMounted(async () => { ...@@ -2689,7 +2762,7 @@ onMounted(async () => {
} }
.home-main-footer { .home-main-footer {
margin-top: 34px; margin-top: 34px;
height: 1379px; height: 1860px;
background: rgba(248, 249, 250, 1); background: rgba(248, 249, 250, 1);
overflow: hidden; overflow: hidden;
.divide4 { .divide4 {
...@@ -2706,13 +2779,13 @@ onMounted(async () => { ...@@ -2706,13 +2779,13 @@ onMounted(async () => {
justify-content: space-between; justify-content: space-between;
.btn-box { .btn-box {
margin-top: 10px; margin-top: 10px;
width: 1000px; width: 1200px;
display: flex; display: flex;
.btn { .btn {
height: 42px; height: 42px;
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 16px; font-size: 20px;
font-weight: 400; font-weight: 400;
line-height: 42px; line-height: 42px;
padding: 0 24px; padding: 0 24px;
...@@ -2725,8 +2798,7 @@ onMounted(async () => { ...@@ -2725,8 +2798,7 @@ onMounted(async () => {
} }
} }
.btnActive { .btnActive {
padding: 0 24px; font-weight: 700;
border-radius: 21px;
background: rgba(20, 89, 187, 1); background: rgba(20, 89, 187, 1);
color: #fff; color: #fff;
&:hover { &:hover {
...@@ -2744,10 +2816,52 @@ onMounted(async () => { ...@@ -2744,10 +2816,52 @@ onMounted(async () => {
} }
.home-main-footer-main { .home-main-footer-main {
width: 1600px; width: 1600px;
height: 999px; margin: 0 auto;
display: flex;
gap: 16px;
.left {
width: 300px;
height: 443px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
box-sizing: border-box;
border-radius: 10px;
.select-box {
margin-top: 21px;
.select-box-header {
display: flex;
gap: 17px;
.icon {
margin-top: 4px;
width: 8px;
height: 16px;
background: var(--color-main-active);
border-radius: 0 4px 4px 0;
}
.title {
height: 24px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 24px;
letter-spacing: 1px;
text-align: left;
}
}
.select-main {
margin-left: 25px;
}
.select-main1 {
width: 100px;
}
}
}
.right {
width: 1284px;
height: 1489px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
margin: 0 auto;
box-sizing: border-box; box-sizing: border-box;
border-radius: 10px; border-radius: 10px;
.content-header { .content-header {
...@@ -2755,110 +2869,136 @@ onMounted(async () => { ...@@ -2755,110 +2869,136 @@ onMounted(async () => {
display: flex; display: flex;
border-bottom: 1px solid rgba(234, 236, 238, 1); border-bottom: 1px solid rgba(234, 236, 238, 1);
.icon { .icon {
width: 20px; width: 23px;
height: 20px; height: 18px;
margin-top: 14px; margin-top: 16px;
margin-left: 19px; margin-left: 20px;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
} }
.title { .title {
height: 48px; height: 26px;
margin-left: 21px; margin-top: 11px;
color: rgba(5, 95, 194, 1); margin-left: 17px;
color: var(--color-main-active);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 20px; font-size: 20px;
font-weight: 700; font-weight: 700;
line-height: 48px; line-height: 26px;
} }
} }
.content-box { .content-box {
height: 850px; height: 1367px;
margin: 0 30px; border-bottom: 1px solid rgba(234, 236, 238, 1);
overflow: hidden;
.main-item { .main-item {
display: flex; display: flex;
height: 84px; height: 136px;
border-bottom: 1px solid rgba(234, 236, 238, 1); box-sizing: border-box;
padding-top: 10px;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background: var(--color-bg-hover); background: var(--color-bg-hover);
} }
.main-item-left { .main-item-left {
width: 105px; display: flex;
.left-box { gap: 18px;
margin-top: 17px; justify-content: flex-end;
.left-left {
width: 84px;
height: 48px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 24px;
letter-spacing: 1px;
text-align: right;
}
.left-right {
.icon {
width: 24px;
height: 24px; height: 24px;
width: 95px; border-radius: 12px;
background: #ccc;
}
.line {
height: 112px;
width: 2px;
background: #ddd;
margin-left: 11px;
}
}
}
.main-item-center {
margin-left: 21px;
width: 1086px;
.center-header {
display: flex;
justify-content: space-between;
.title {
height: 26px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 20px;
font-weight: 700;
line-height: 26px;
letter-spacing: 0px;
text-align: left;
}
.type-box {
height: 28px;
line-height: 28px;
padding: 0 8px;
text-align: center; text-align: center;
// color: rgba(22, 119, 255, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 14px; font-size: 16px;
font-weight: 400; font-weight: 400;
line-height: 24px; letter-spacing: 0px;
box-sizing: border-box;
border-radius: 4px; border-radius: 4px;
// border: 1px solid rgba(186, 224, 255, 1);
// background: rgba(230, 244, 255, 1);
} }
.type1 { .type1 {
color: rgba(22, 119, 255, 1); color: rgba(22, 119, 255, 1);
border: 1px solid rgba(186, 224, 255, 1);
background: rgba(230, 244, 255, 1); background: rgba(230, 244, 255, 1);
} }
.type2 { .type2 {
color: rgba(19, 168, 168, 1); color: rgba(19, 168, 168, 1);
border: 1px solid rgba(135, 232, 222, 1);
background: rgba(230, 255, 251, 1); background: rgba(230, 255, 251, 1);
} }
.type3 { .type3 {
color: rgba(250, 140, 22, 1); color: rgba(250, 140, 22, 1);
border: 1px solid rgba(255, 213, 145, 1);
background: rgba(255, 247, 230, 1); background: rgba(255, 247, 230, 1);
} }
} }
.main-item-center { .desc {
width: 1300px; margin-top: 8px;
.main-item-center-box1 {
margin-top: 15px;
height: 24px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 18px;
font-weight: 700;
line-height: 24px;
}
.main-item-center-box2 {
margin-top: 4px;
height: 24px;
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
letter-spacing: 0px;
text-align: justify;
max-height: 48px;
overflow: hidden;
} }
} .tag-box {
.main-item-right { margin-top: 9px;
display: flex; display: flex;
.main-item-right-text { .tag {
margin-top: 18px; height: 28px;
width: 128px; line-height: 28px;
height: 24px; text-align: center;
padding: 0 8px;
border-radius: 4px;
background: rgba(231, 243, 255, 1);
color: var(--color-main-active); color: var(--color-main-active);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 16px; font-size: 14px;
font-weight: 400; font-weight: 400;
line-height: 24px; letter-spacing: 0px;
}
.main-item-right-icon {
margin-top: 22px;
margin-left: 9px;
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
} }
} }
} }
...@@ -2881,6 +3021,7 @@ onMounted(async () => { ...@@ -2881,6 +3021,7 @@ onMounted(async () => {
} }
} }
} }
}
} }
.divide { .divide {
......
...@@ -42,7 +42,7 @@ const getBarChart = (nameList, valueList) => { ...@@ -42,7 +42,7 @@ const getBarChart = (nameList, valueList) => {
label: { label: {
show: true, show: true,
position: 'top', position: 'top',
color: 'var(--color-main-active)', color: 'rgba(5, 95, 194, 1)',
fontWeight: 'bold', // 文字加粗 fontWeight: 'bold', // 文字加粗
fontSize: 14, fontSize: 14,
formatter: function (params) { formatter: function (params) {
...@@ -59,7 +59,7 @@ const getBarChart = (nameList, valueList) => { ...@@ -59,7 +59,7 @@ const getBarChart = (nameList, valueList) => {
}, },
{ {
offset: 1, offset: 1,
color: 'var(--color-main-active)' color: 'rgba(5, 95, 194, 1)'
} }
]); ]);
}, },
......
...@@ -2,16 +2,16 @@ ...@@ -2,16 +2,16 @@
{ {
"id": null, "id": null,
"name": "2025-10-09", "name": "2025-10-09",
"count": 41 "count": 10
}, },
{ {
"id": null, "id": null,
"name": "2025-10-08", "name": "2025-10-08",
"count": 398 "count": 8
}, },
{ {
"id": null, "id": null,
"name": "2025-09-16", "name": "2025-09-16",
"count": 138 "count": 16
} }
] ]
\ No newline at end of file
...@@ -47,10 +47,10 @@ ...@@ -47,10 +47,10 @@
<div class="item" v-for="(item, index) in subPanel4" :key="index"> <div class="item" v-for="(item, index) in subPanel4" :key="index">
<div class="name">{{ item.name }}</div> <div class="name">{{ item.name }}</div>
<div class="infoWrap"> <div class="infoWrap">
<div class="shizhi">市值:{{ item.shizhi }}</div> <div class="shizhi">{{ item.shizhi }}</div>
<div class="address">地址:{{ item.address }}</div> <div class="address">{{ item.address }}</div>
<div class="hangye">行业:{{ item.hangye }}</div> <div class="hangye">{{ item.hangye }}</div>
<div class="type">类型:{{ item.type }}</div> <div class="type">{{ item.type }}</div>
<div class="detail">查看详情</div> <div class="detail">查看详情</div>
</div> </div>
</div> </div>
...@@ -65,13 +65,16 @@ ...@@ -65,13 +65,16 @@
</template> </template>
<script setup> <script setup>
import { ref, shallowRef, onMounted } from "vue"; import { ref, shallowRef, onMounted, watch } from "vue";
import CardCustom from "../../components/CardCustom.vue"; import CardCustom from "../../components/CardCustom.vue";
import { Search } from "@element-plus/icons-vue"; import { Search } from "@element-plus/icons-vue";
import Echarts from "@/components/Chart/index.vue"; import Echarts from "@/components/Chart/index.vue";
import { getBarChart, getLineChart } from "../../utils/charts"; import { getBarChart, getLineChart } from "../../utils/charts";
import _ from "lodash";
import Hint from "./hint.vue"; import Hint from "./hint.vue";
import { getEntityFinancing } from "@/api/exportControl"; import { getEntityFinancing, getEntityMarketValue, getKeyListedEntityList, getSanStrength } from "@/api/exportControl";
import { useRoute } from "vue-router";
const route = useRoute();
const options = [ const options = [
{ {
value: "1", value: "1",
...@@ -112,6 +115,75 @@ const subPanel4 = ref([ ...@@ -112,6 +115,75 @@ const subPanel4 = ref([
} }
]); ]);
// 获取重点上市企业列表数据
const fetchKeyListedEntityList = async (keyword = "") => {
try {
const data = await getKeyListedEntityList(route.query.startTime, keyword);
if (data && Array.isArray(data)) {
// 根据 fishbone-mock.json 的数据结构处理数据
// 数据结构示例:
// [{
// orgName: "Hua Ke Logistics (HK) Limited",
// orgNameZh: "华科物流(香港)有限公司",
// marketValue: 214.34982757457735,
// address: "广州",
// industryList: ["经济", "军事", "安全"]
// }]
subPanel4.value = data.map(item => {
// 优先使用中文名称,否则使用英文名称
const name = item.orgNameZh || item.orgName || "未知企业";
// 市值处理,保留两位小数并添加单位
const marketValue = item.marketValue ? `${item.marketValue.toFixed(2)}亿` : "未知";
// 地址信息
const address = item.address || "未知";
// 行业信息,取第一个行业或者默认值
const hangye = item.industryList && item.industryList.length > 0 ? item.industryList[0] : "未知行业";
// 类型信息,默认为"企业"
const type = item.orgType || "企业";
return {
name,
shizhi: `市值:${marketValue}`,
address: `地址:${address}`,
hangye: `行业:${hangye}`,
type: `类型:${type}`
};
});
}
} catch (error) {
console.error("获取重点上市企业列表数据失败:", error);
// 出错时使用默认数据
subPanel4.value = [
{
name: "中科星图有限公司",
shizhi: "278.47亿",
address: "北京",
hangye: "半导体",
type: "上市企业"
},
{
name: "中国科学院长春光学精密机械与物理研究所",
shizhi: "278.47亿",
address: "北京",
hangye: "半导体",
type: "研究院"
},
{
name: "中芯国际集成电路制造有限公司",
shizhi: "278.47亿",
address: "北京",
hangye: "半导体",
type: "上市企业"
}
];
}
};
// 获取上市企业融资变化数据 // 获取上市企业融资变化数据
const fetchEntityFinancing = async () => { const fetchEntityFinancing = async () => {
try { try {
...@@ -121,9 +193,11 @@ const fetchEntityFinancing = async () => { ...@@ -121,9 +193,11 @@ const fetchEntityFinancing = async () => {
// 数据结构示例: [{name: "2025-10-09", count: 41}, ...] // 数据结构示例: [{name: "2025-10-09", count: 41}, ...]
// 按日期排序 // 按日期排序
const sortedData = data.sort((a, b) => { const sortedData = data
.sort((a, b) => {
return new Date(a.name) - new Date(b.name); return new Date(a.name) - new Date(b.name);
}); })
.filter((item, idx) => idx % 3 === 0);
// 提取 x 轴数据(日期) // 提取 x 轴数据(日期)
const xAxisData = sortedData.map(item => item.name); const xAxisData = sortedData.map(item => item.name);
...@@ -144,19 +218,77 @@ const fetchEntityFinancing = async () => { ...@@ -144,19 +218,77 @@ const fetchEntityFinancing = async () => {
} }
}; };
// 获取上市企业市值变化数据
const fetchEntityMarketValue = async () => {
try {
const data = await getEntityMarketValue();
if (data && Array.isArray(data)) {
// 根据 fishbone-mock.json 的数据结构处理数据
// 数据结构示例: [{name: "2025-10-09", count: 220}, ...]
// 按日期排序
const sortedData = data
.sort((a, b) => {
return new Date(a.name) - new Date(b.name);
})
.filter((item, idx) => idx % 3 === 0);
// 提取 x 轴数据(日期)
const xAxisData = sortedData.map(item => item.name);
// 提取 y 轴数据(市值数据)
const seriesData = sortedData.map(item => item.count);
// 更新图表配置,使用指定的颜色
bar2Option.value = getBarChart(xAxisData, seriesData, ["rgba(19, 188, 196, 1)", "rgba(19, 188, 196, 0)"], "市值变化");
}
} catch (error) {
console.error("获取上市企业市值变化数据失败:", error);
}
};
//
const fetchSanStrength = async () => {
try {
const data = await getSanStrength();
if (data && Array.isArray(data)) {
// 根据 fishbone-mock.json 的数据结构处理数据
// 数据结构示例: [{name: "2025-10-09", count: 220}, ...]
// 按日期排序
const sortedData = data
.sort((a, b) => {
return new Date(a.name) - new Date(b.name);
})
.filter((item, idx) => idx % 3 === 0);
// 提取 x 轴数据(日期)
const xAxisData = sortedData.map(item => item.name);
// 提取 y 轴数据(市值数据)
const seriesData = sortedData.map(item => item.count);
// 更新图表配置,使用指定的颜色
bar1Option.value = getBarChart(xAxisData, seriesData, ["rgba(22, 119, 255, 1)", "rgba(22, 119, 255, 0)"], "制裁强度");
}
} catch (error) {
console.error("获取上市企业市值变化数据失败:", error);
}
};
onMounted(() => { onMounted(() => {
bar1Option.value = getBarChart( // bar1Option.value = getBarChart(
["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"], // ["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
[219, 228, 129, 159, 152, 157, 78, 34, 56, 78], // [219, 228, 129, 159, 152, 157, 78, 34, 56, 78],
["rgba(22, 119, 255, 1)", "rgba(22, 119, 255, 0)"], // ["rgba(22, 119, 255, 1)", "rgba(22, 119, 255, 0)"],
"制裁强度" // "制裁强度"
); // );
bar2Option.value = getBarChart( // bar2Option.value = getBarChart(
["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"], // ["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
[39, 28, 49, 19, 22, 25, 78, 34, 56, 28], // [39, 28, 49, 19, 22, 25, 78, 34, 56, 28],
["rgba(19, 188, 196, 1)", "rgba(19, 188, 196, 0)"], // ["rgba(19, 188, 196, 1)", "rgba(19, 188, 196, 0)"],
"市值变化" // "市值变化"
); // );
// line1Option.value = getLineChart({ // line1Option.value = getLineChart({
// xAxisData: [2013, 2023, 2024, 2015], // xAxisData: [2013, 2023, 2024, 2015],
// seriesData: [434, 24, 453, 322], // seriesData: [434, 24, 453, 322],
...@@ -165,7 +297,19 @@ onMounted(() => { ...@@ -165,7 +297,19 @@ onMounted(() => {
// }); // });
// 获取上市企业融资变化数据 // 获取上市企业融资变化数据
fetchEntityFinancing(); fetchEntityFinancing();
fetchEntityMarketValue();
fetchKeyListedEntityList();
fetchSanStrength();
}); });
// 监听搜索关键词变化,重新获取数据
watch(
value3,
_.debounce(async newVal => {
console.log("关键词变化:", newVal);
await fetchKeyListedEntityList(newVal);
}, 300)
);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
...@@ -55,13 +55,39 @@ const bar2Option = shallowRef({}); ...@@ -55,13 +55,39 @@ const bar2Option = shallowRef({});
const line1Option = shallowRef({}); const line1Option = shallowRef({});
const line2Option = shallowRef({}); const line2Option = shallowRef({});
// 获取历次制裁涉及领域数数据
const fetchEntitiesDomainCount = async () => {
try {
const data = await getEntitiesDomainCount();
if (data && Array.isArray(data)) {
// 根据 fishbone-mock.json 的数据结构处理数据
// 数据结构示例: [{name: "2025-10-09", count: 4}, ...]
// 按日期排序
const sortedData = data.sort((a, b) => {
return new Date(a.name) - new Date(b.name);
});
// 提取 x 轴数据(日期)
const xAxisData = sortedData.map(item => item.name);
// 提取 y 轴数据(领域数)
const seriesData = sortedData.map(item => item.count);
// 更新图表配置,使用指定的颜色
bar2Option.value = getBarChart(xAxisData, seriesData, ["rgba(19, 188, 196, 1)", "rgba(19, 188, 196, 0)"], "领域数");
}
} catch (error) {
console.error("获取历次制裁涉及领域数数据失败:", error);
}
};
onMounted(async () => { onMounted(async () => {
try { try {
const [entitiesAreaCountByYearData, countThisDomainData4, entitiesDomainCountData, countThisDomainData10] = const [entitiesAreaCountByYearData, countThisDomainData4, countThisDomainData10] = await Promise.all([
await Promise.all([
getEntitiesAreaCountByYear(route.query.startTime), getEntitiesAreaCountByYear(route.query.startTime),
getCountThisDomain("4"), getCountThisDomain("4"),
getEntitiesDomainCount(), // getEntitiesDomainCount(),
getCountThisDomain("10") getCountThisDomain("10")
]); ]);
...@@ -74,12 +100,12 @@ onMounted(async () => { ...@@ -74,12 +100,12 @@ onMounted(async () => {
color: "rgba(255, 149, 77, 1)" color: "rgba(255, 149, 77, 1)"
}); });
bar2Option.value = getBarChart( // bar2Option.value = getBarChart(
_.reverse(entitiesDomainCountData?.xAxis ?? []), // _.reverse(entitiesDomainCountData?.xAxis ?? []),
_.reverse(entitiesDomainCountData?.series ?? []), // _.reverse(entitiesDomainCountData?.series ?? []),
["rgba(19, 188, 196, 1)", "rgba(19, 188, 196, 0)"], // ["rgba(19, 188, 196, 1)", "rgba(19, 188, 196, 0)"],
"领域数" // "领域数"
); // );
const list10 = _.reverse(countThisDomainData10 ?? []); const list10 = _.reverse(countThisDomainData10 ?? []);
line2Option.value = getLineChart({ line2Option.value = getLineChart({
...@@ -88,6 +114,7 @@ onMounted(async () => { ...@@ -88,6 +114,7 @@ onMounted(async () => {
name: "航空航天领域", name: "航空航天领域",
color: "rgba(146, 84, 222, 1)" color: "rgba(146, 84, 222, 1)"
}); });
await fetchEntitiesDomainCount();
} catch (err) { } catch (err) {
console.log(err); console.log(err);
} }
......
...@@ -66,37 +66,39 @@ const activePanelId = ref(null); ...@@ -66,37 +66,39 @@ const activePanelId = ref(null);
onMounted(async () => { onMounted(async () => {
try { try {
const [compareCountSanData] = await Promise.all([getCompareCountSan(route.query.startTime)]); const [compareCountSanData] = await Promise.all([getCompareCountSan(route.query.startTime)]);
const { countSanNow, countSanLast, countDomainNow, countDomainLast, countTypeNow, countTypeLast } = // const { countSanNow, countSanLast, countDomainNow, countDomainLast, countTypeNow, countTypeLast } =
compareCountSanData ?? {}; // compareCountSanData ?? {};
const { entityNum, entityChange, listedCompanyNum, listedCompanyChange, domainNum, domainChange, typeNum, typeChange } =
compareCountSanData ?? {};
compareCountSan.value = [ compareCountSan.value = [
{ {
id: 1, id: 1,
name: "新增实体数量", name: "新增实体数量",
number: countSanNow, number: entityNum,
isUp: countSanNow - countSanLast >= 0, isUp: entityChange >= 0,
ComparisonNumber: Math.abs(countSanNow - countSanLast) ComparisonNumber: Math.abs(entityChange)
}, },
{ {
id: 2, id: 2,
name: "上市企业数量", name: "上市企业数量",
number: "--", number: listedCompanyNum,
isUp: true, isUp: listedCompanyChange >= 0,
ComparisonNumber: "--" ComparisonNumber: Math.abs(listedCompanyChange)
}, },
{ {
id: 3, id: 3,
name: "涉及领域数量", name: "涉及领域数量",
number: countDomainNow, number: domainNum,
isUp: countDomainNow - countDomainLast >= 0, isUp: domainChange >= 0,
ComparisonNumber: Math.abs(countDomainNow - countDomainLast) ComparisonNumber: Math.abs(domainChange)
}, },
{ {
id: 4, id: 4,
name: "实体类别数量", name: "实体类别数量",
number: countTypeNow, number: typeNum,
isUp: countTypeNow - countTypeLast >= 0, isUp: typeChange >= 0,
ComparisonNumber: Math.abs(countTypeNow - countTypeLast) ComparisonNumber: Math.abs(typeChange)
} }
]; ];
activePanelId.value = compareCountSan.value[0].id; activePanelId.value = compareCountSan.value[0].id;
......
...@@ -449,7 +449,7 @@ ...@@ -449,7 +449,7 @@
<el-col :span="16"> <el-col :span="16">
<custom-container title="制裁实体清单" :titleIcon="entityIcon" height="845px"> <custom-container title="制裁实体清单" :titleIcon="entityIcon" height="845px">
<template #header-right> <template #header-right>
<div class="box5-header-right">1329家实体</div> <div class="box5-header-right">{{ total }}家实体</div>
</template> </template>
<template #default> <template #default>
<div class="box5"> <div class="box5">
...@@ -470,7 +470,22 @@ ...@@ -470,7 +470,22 @@
<el-table-column prop="name" label="实体名称" min-width="200"> <el-table-column prop="name" label="实体名称" min-width="200">
<template #default="scope"> <template #default="scope">
<div class="tableName">{{ scope.row.name }}</div> <div class="tableName">
<el-image
v-if="scope.row.img"
class="box1-bottom-content-item-img"
:src="scope.row.img"
alt=""
></el-image>
<div v-else class="box1-bottom-content-item-imgUndefined">
{{
(scope.row.name || scope.row.enName)?.match(
/[\u4e00-\u9fa5a-zA-Z0-9]/
)?.[0]
}}
</div>
{{ scope.row.name }}
</div>
</template> </template>
</el-table-column> </el-table-column>
...@@ -480,7 +495,9 @@ ...@@ -480,7 +495,9 @@
<el-tag <el-tag
v-for="tag in scope.row.domains" v-for="tag in scope.row.domains"
:key="tag" :key="tag"
:type="tag === '通信网络' ? 'primary' : 'danger'" :type="
tag === '通信网络' ? 'primary' : tagsType[Math.floor(Math.random() * 5)]
"
>{{ tag }}</el-tag >{{ tag }}</el-tag
> >
</div> </div>
...@@ -521,7 +538,6 @@ ...@@ -521,7 +538,6 @@
'revenue-cell', 'revenue-cell',
scope.row.revenue === '无营收数据' ? 'no-revenue' : '' scope.row.revenue === '无营收数据' ? 'no-revenue' : ''
]" ]"
> >
{{ scope.row.name }}...等 {{ scope.row.name }}...等
</div> </div>
...@@ -622,12 +638,15 @@ import { ...@@ -622,12 +638,15 @@ import {
getCountDomainByYear, getCountDomainByYear,
getSanctionsInfoCount, getSanctionsInfoCount,
getEntitiesList, getEntitiesList,
getSanctionProcess getSanctionProcess,
getSanDomainCount
} from "@/api/exportControl"; } from "@/api/exportControl";
import { getMultipleBarChart_m } from "./utils/charts"; import { getMultipleBarChart_m } from "./utils/charts";
import { formatAnyDateToChinese } from "./utils"; import { formatAnyDateToChinese } from "./utils";
import _ from "lodash"; import _ from "lodash";
const tagsType = ["primary", "success", "info", "warning", "danger"];
//数据定义 //数据定义
const entitiesDataInfoReactive = shallowRef({ const entitiesDataInfoReactive = shallowRef({
chNum: undefined, chNum: undefined,
...@@ -693,6 +712,8 @@ onMounted(async () => { ...@@ -693,6 +712,8 @@ onMounted(async () => {
// }); // });
await fetchEntitiesList(currentPage.value, pageSize.value); await fetchEntitiesList(currentPage.value, pageSize.value);
await fetchSanctionProcess(1, pageSize.value); await fetchSanctionProcess(1, pageSize.value);
// 获取雷达图数据
await fetchRadarData();
// console.log("entitiesList entitiesList", entityBody); // console.log("entitiesList entitiesList", entityBody);
// entitiesList.value = _.map(entityBody.content, item => { // entitiesList.value = _.map(entityBody.content, item => {
// return { // return {
...@@ -872,7 +893,7 @@ const radarOption = ref({ ...@@ -872,7 +893,7 @@ const radarOption = ref({
}, },
series: [ series: [
{ {
name: "Budget vs spending", name: "",
type: "radar", type: "radar",
data: [ data: [
{ {
...@@ -901,6 +922,68 @@ const radarOption = ref({ ...@@ -901,6 +922,68 @@ const radarOption = ref({
] ]
}); });
// 获取雷达图数据
const fetchRadarData = async () => {
try {
const data = await getSanDomainCount();
if (data && Array.isArray(data) && data.length > 0) {
// 收集所有可能的领域名称
const allDomains = new Set();
data.forEach(item => {
if (item.domainCountInfo) {
item.domainCountInfo.forEach(domain => {
allDomains.add(domain.name);
});
}
});
const domainNames = Array.from(allDomains);
// 为每个制裁类型准备数据
const seriesData = data.map(sanItem => {
// 创建一个映射,将领域名称映射到数量
const domainMap = {};
if (sanItem.domainCountInfo) {
sanItem.domainCountInfo.forEach(domain => {
domainMap[domain.name] = domain.count;
});
}
// 按照统一的领域顺序创建值数组
const values = domainNames.map(name => domainMap[name] || 0);
// 确定颜色
let color = "rgba(10, 87, 166, 0.2)"; // 默认实体清单颜色
if (sanItem.sanTypeName === "商业管制清单") {
color = "rgba(206, 79, 81, 0.2)";
} else if (sanItem.sanTypeName === "关键和新型技术清单") {
color = "rgba(250, 140, 22, 0.2)";
}
return {
value: values,
name: sanItem.sanTypeName,
areaStyle: { color }
};
});
// 更新雷达图指标
const maxValue = Math.max(...seriesData.flatMap(item => item.value)) * 1.2;
const indicators = domainNames.map(name => ({
name: name,
max: maxValue || 100 // 防止max为0的情况
}));
// 更新雷达图配置
radarOption.value.radar.indicator = indicators;
radarOption.value.series[0].data = seriesData;
radarOption.value.legend.data = data.map(item => item.sanTypeName);
}
} catch (error) {
console.error("获取雷达图数据失败:", error);
}
};
// 进度条状态 // 进度条状态
const getStatus = _percent => { const getStatus = _percent => {
const percent = _percent * 100; const percent = _percent * 100;
...@@ -2464,12 +2547,27 @@ onMounted(async () => { ...@@ -2464,12 +2547,27 @@ onMounted(async () => {
line-height: 30px; line-height: 30px;
letter-spacing: 0px; letter-spacing: 0px;
text-align: justify; text-align: justify;
display: flex;
align-items: center;
gap: 10px;
.box1-bottom-content-item-imgUndefined {
width: 24px;
height: 24px;
font-size: 14px;
font-weight: 700;
flex-shrink: 0;
color: rgb(5, 95, 194);
background-color: rgb(236, 245, 255);
line-height: 24px;
text-align: center;
border-radius: 12px;
}
} }
.num-item { .num-item {
width: 280px; width: 280px;
display: flex; display: flex;
.name-item{ .name-item {
width: 215px; width: 215px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
......
...@@ -1344,17 +1344,6 @@ const chart1Data = ref({ ...@@ -1344,17 +1344,6 @@ const chart1Data = ref({
] ]
}); });
// 获取热门法案
const handleGetHotBills = async () => {
try {
const res = await getHotBills();
console.log("热门法案", res);
billList.value = res.data;
} catch (error) {
console.error(error);
}
};
// 根据法案类型获取法案列表 // 根据法案类型获取法案列表
const handleGetBillsByType = async () => { const handleGetBillsByType = async () => {
const params = { const params = {
...@@ -1376,7 +1365,6 @@ const handleGetBillsByType = async () => { ...@@ -1376,7 +1365,6 @@ const handleGetBillsByType = async () => {
onMounted(async () => { onMounted(async () => {
handleGetHylyList(); handleGetHylyList();
await handleGetHotBills();
curBill.value = billList.value[0]; curBill.value = billList.value[0];
handleGetBillsByType(); handleGetBillsByType();
let chart1 = getMultiLineChart(chart1Data.value.title, chart1Data.value.data[0].value, chart1Data.value.data[1].value); let chart1 = getMultiLineChart(chart1Data.value.title, chart1Data.value.data[0].value, chart1Data.value.data[1].value);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论