提交 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) {
return request200(
request({
method: "GET",
url: "/api/entitiesDataCount/compareCountSan",
// url: "/api/entitiesDataCount/compareCountSan",
url: "/api/entitiesDataInfo/getSanCountInfo",
params: {
startTime
sanctionDate: startTime || "2025-11-11"
}
})
);
......@@ -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'
......@@ -416,7 +441,7 @@ export function getEntitiesDomainCount() {
return request200(
request({
method: "GET",
url: "/api/entitiesDataCount/entitiesDomainCount"
url: "/api/entitiesDataInfo/getPreviousDomian"
})
);
}
......@@ -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 @@
<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from "vue";
import * as echarts from "echarts";
import Center from "./assets/埃隆·马斯克.png";
import P1 from "./assets/唐纳德·特朗普.png";
import P2 from "./assets/詹姆斯・默多克.png";
import P3 from "./assets/格温・肖特韦尔.png";
import P4 from "./assets/金博尔・马斯克.png";
import P5 from "./assets/拉里・埃里森.png";
import P6 from "./assets/斯科特·贝森特.png";
import P7 from "./assets/杰弗里·凯斯勒.png";
import P8 from "./assets/马尔科·卢比奥.png";
import P9 from "./assets/道格·伯格姆.png";
import P10 from "./assets/艾拉・埃伦普里斯.png";
import P11 from "./assets/贾斯汀・马斯克.png";
import PS from "./assets/史蒂夫・尤尔韦松.png";
import Center from "./assets/img1.png";
import P1 from "./assets/img2.png";
import P2 from "./assets/img3.png";
import P3 from "./assets/img4.png";
import P4 from "./assets/img5.png";
import P5 from "./assets/img6.png";
import P6 from "./assets/img7.png";
import P7 from "./assets/img8.png";
import P8 from "./assets/img9.png";
import P9 from "./assets/img10.png";
import P10 from "./assets/img11.png";
import P11 from "./assets/img12.png";
import PS from "./assets/img13.png";
const list = ref(["圆形布局", "力导向布局", "树形布局"]);
const activeIndex = ref("圆形布局");
......
......@@ -42,7 +42,7 @@ const getBarChart = (nameList, valueList) => {
label: {
show: true,
position: 'top',
color: 'var(--color-main-active)',
color: 'rgba(5, 95, 194, 1)',
fontWeight: 'bold', // 文字加粗
fontSize: 14,
formatter: function (params) {
......@@ -59,7 +59,7 @@ const getBarChart = (nameList, valueList) => {
},
{
offset: 1,
color: 'var(--color-main-active)'
color: 'rgba(5, 95, 194, 1)'
}
]);
},
......
......@@ -2,16 +2,16 @@
{
"id": null,
"name": "2025-10-09",
"count": 41
"count": 10
},
{
"id": null,
"name": "2025-10-08",
"count": 398
"count": 8
},
{
"id": null,
"name": "2025-09-16",
"count": 138
"count": 16
}
]
\ No newline at end of file
......@@ -47,10 +47,10 @@
<div class="item" v-for="(item, index) in subPanel4" :key="index">
<div class="name">{{ item.name }}</div>
<div class="infoWrap">
<div class="shizhi">市值:{{ item.shizhi }}</div>
<div class="address">地址:{{ item.address }}</div>
<div class="hangye">行业:{{ item.hangye }}</div>
<div class="type">类型:{{ item.type }}</div>
<div class="shizhi">{{ item.shizhi }}</div>
<div class="address">{{ item.address }}</div>
<div class="hangye">{{ item.hangye }}</div>
<div class="type">{{ item.type }}</div>
<div class="detail">查看详情</div>
</div>
</div>
......@@ -65,13 +65,16 @@
</template>
<script setup>
import { ref, shallowRef, onMounted } from "vue";
import { ref, shallowRef, onMounted, watch } from "vue";
import CardCustom from "../../components/CardCustom.vue";
import { Search } from "@element-plus/icons-vue";
import Echarts from "@/components/Chart/index.vue";
import { getBarChart, getLineChart } from "../../utils/charts";
import _ from "lodash";
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 = [
{
value: "1",
......@@ -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 () => {
try {
......@@ -121,9 +193,11 @@ const fetchEntityFinancing = async () => {
// 数据结构示例: [{name: "2025-10-09", count: 41}, ...]
// 按日期排序
const sortedData = data.sort((a, b) => {
return new Date(a.name) - new Date(b.name);
});
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);
......@@ -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(() => {
bar1Option.value = getBarChart(
["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
[219, 228, 129, 159, 152, 157, 78, 34, 56, 78],
["rgba(22, 119, 255, 1)", "rgba(22, 119, 255, 0)"],
"制裁强度"
);
bar2Option.value = getBarChart(
["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
[39, 28, 49, 19, 22, 25, 78, 34, 56, 28],
["rgba(19, 188, 196, 1)", "rgba(19, 188, 196, 0)"],
"市值变化"
);
// bar1Option.value = getBarChart(
// ["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
// [219, 228, 129, 159, 152, 157, 78, 34, 56, 78],
// ["rgba(22, 119, 255, 1)", "rgba(22, 119, 255, 0)"],
// "制裁强度"
// );
// bar2Option.value = getBarChart(
// ["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
// [39, 28, 49, 19, 22, 25, 78, 34, 56, 28],
// ["rgba(19, 188, 196, 1)", "rgba(19, 188, 196, 0)"],
// "市值变化"
// );
// line1Option.value = getLineChart({
// xAxisData: [2013, 2023, 2024, 2015],
// seriesData: [434, 24, 453, 322],
......@@ -165,7 +297,19 @@ onMounted(() => {
// });
// 获取上市企业融资变化数据
fetchEntityFinancing();
fetchEntityMarketValue();
fetchKeyListedEntityList();
fetchSanStrength();
});
// 监听搜索关键词变化,重新获取数据
watch(
value3,
_.debounce(async newVal => {
console.log("关键词变化:", newVal);
await fetchKeyListedEntityList(newVal);
}, 300)
);
</script>
<style lang="scss" scoped>
......
......@@ -55,15 +55,41 @@ const bar2Option = shallowRef({});
const line1Option = 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 () => {
try {
const [entitiesAreaCountByYearData, countThisDomainData4, entitiesDomainCountData, countThisDomainData10] =
await Promise.all([
getEntitiesAreaCountByYear(route.query.startTime),
getCountThisDomain("4"),
getEntitiesDomainCount(),
getCountThisDomain("10")
]);
const [entitiesAreaCountByYearData, countThisDomainData4, countThisDomainData10] = await Promise.all([
getEntitiesAreaCountByYear(route.query.startTime),
getCountThisDomain("4"),
// getEntitiesDomainCount(),
getCountThisDomain("10")
]);
pie1Option.value = getPieOption1(entitiesAreaCountByYearData ?? []);
const list4 = _.reverse(countThisDomainData4 ?? []);
......@@ -74,12 +100,12 @@ onMounted(async () => {
color: "rgba(255, 149, 77, 1)"
});
bar2Option.value = getBarChart(
_.reverse(entitiesDomainCountData?.xAxis ?? []),
_.reverse(entitiesDomainCountData?.series ?? []),
["rgba(19, 188, 196, 1)", "rgba(19, 188, 196, 0)"],
"领域数"
);
// bar2Option.value = getBarChart(
// _.reverse(entitiesDomainCountData?.xAxis ?? []),
// _.reverse(entitiesDomainCountData?.series ?? []),
// ["rgba(19, 188, 196, 1)", "rgba(19, 188, 196, 0)"],
// "领域数"
// );
const list10 = _.reverse(countThisDomainData10 ?? []);
line2Option.value = getLineChart({
......@@ -88,6 +114,7 @@ onMounted(async () => {
name: "航空航天领域",
color: "rgba(146, 84, 222, 1)"
});
await fetchEntitiesDomainCount();
} catch (err) {
console.log(err);
}
......
......@@ -66,37 +66,39 @@ const activePanelId = ref(null);
onMounted(async () => {
try {
const [compareCountSanData] = await Promise.all([getCompareCountSan(route.query.startTime)]);
const { countSanNow, countSanLast, countDomainNow, countDomainLast, countTypeNow, countTypeLast } =
compareCountSanData ?? {};
// const { countSanNow, countSanLast, countDomainNow, countDomainLast, countTypeNow, countTypeLast } =
// compareCountSanData ?? {};
const { entityNum, entityChange, listedCompanyNum, listedCompanyChange, domainNum, domainChange, typeNum, typeChange } =
compareCountSanData ?? {};
compareCountSan.value = [
{
id: 1,
name: "新增实体数量",
number: countSanNow,
isUp: countSanNow - countSanLast >= 0,
ComparisonNumber: Math.abs(countSanNow - countSanLast)
number: entityNum,
isUp: entityChange >= 0,
ComparisonNumber: Math.abs(entityChange)
},
{
id: 2,
name: "上市企业数量",
number: "--",
isUp: true,
ComparisonNumber: "--"
number: listedCompanyNum,
isUp: listedCompanyChange >= 0,
ComparisonNumber: Math.abs(listedCompanyChange)
},
{
id: 3,
name: "涉及领域数量",
number: countDomainNow,
isUp: countDomainNow - countDomainLast >= 0,
ComparisonNumber: Math.abs(countDomainNow - countDomainLast)
number: domainNum,
isUp: domainChange >= 0,
ComparisonNumber: Math.abs(domainChange)
},
{
id: 4,
name: "实体类别数量",
number: countTypeNow,
isUp: countTypeNow - countTypeLast >= 0,
ComparisonNumber: Math.abs(countTypeNow - countTypeLast)
number: typeNum,
isUp: typeChange >= 0,
ComparisonNumber: Math.abs(typeChange)
}
];
activePanelId.value = compareCountSan.value[0].id;
......
......@@ -449,7 +449,7 @@
<el-col :span="16">
<custom-container title="制裁实体清单" :titleIcon="entityIcon" height="845px">
<template #header-right>
<div class="box5-header-right">1329家实体</div>
<div class="box5-header-right">{{ total }}家实体</div>
</template>
<template #default>
<div class="box5">
......@@ -470,7 +470,22 @@
<el-table-column prop="name" label="实体名称" min-width="200">
<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>
</el-table-column>
......@@ -480,7 +495,9 @@
<el-tag
v-for="tag in scope.row.domains"
:key="tag"
:type="tag === '通信网络' ? 'primary' : 'danger'"
:type="
tag === '通信网络' ? 'primary' : tagsType[Math.floor(Math.random() * 5)]
"
>{{ tag }}</el-tag
>
</div>
......@@ -521,7 +538,6 @@
'revenue-cell',
scope.row.revenue === '无营收数据' ? 'no-revenue' : ''
]"
>
{{ scope.row.name }}...等
</div>
......@@ -622,12 +638,15 @@ import {
getCountDomainByYear,
getSanctionsInfoCount,
getEntitiesList,
getSanctionProcess
getSanctionProcess,
getSanDomainCount
} from "@/api/exportControl";
import { getMultipleBarChart_m } from "./utils/charts";
import { formatAnyDateToChinese } from "./utils";
import _ from "lodash";
const tagsType = ["primary", "success", "info", "warning", "danger"];
//数据定义
const entitiesDataInfoReactive = shallowRef({
chNum: undefined,
......@@ -693,6 +712,8 @@ onMounted(async () => {
// });
await fetchEntitiesList(currentPage.value, pageSize.value);
await fetchSanctionProcess(1, pageSize.value);
// 获取雷达图数据
await fetchRadarData();
// console.log("entitiesList entitiesList", entityBody);
// entitiesList.value = _.map(entityBody.content, item => {
// return {
......@@ -872,7 +893,7 @@ const radarOption = ref({
},
series: [
{
name: "Budget vs spending",
name: "",
type: "radar",
data: [
{
......@@ -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 percent = _percent * 100;
......@@ -2464,12 +2547,27 @@ onMounted(async () => {
line-height: 30px;
letter-spacing: 0px;
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 {
width: 280px;
display: flex;
.name-item{
.name-item {
width: 215px;
overflow: hidden;
text-overflow: ellipsis;
......
......@@ -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 params = {
......@@ -1376,7 +1365,6 @@ const handleGetBillsByType = async () => {
onMounted(async () => {
handleGetHylyList();
await handleGetHotBills();
curBill.value = billList.value[0];
handleGetBillsByType();
let chart1 = getMultiLineChart(chart1Data.value.title, chart1Data.value.data[0].value, chart1Data.value.data[1].value);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论