提交 2fecb118 authored 作者: yanpeng's avatar yanpeng

update

上级 12a9f4b2
......@@ -23,7 +23,8 @@ export function getEntitiesDataCount() {
return request200(
request({
method: "GET",
url: "/api/entitiesDataCount/countData"
// url: "/api/entitiesDataCount/countData",
url: "/api/sanctionList/export/getTotalInfo"
})
);
}
......@@ -62,12 +63,15 @@ export function getEntitiesDataInfo() {
* maxCount: number
* }[]>}
*/
export function getIndustryCountByYear() {
export function getIndustryCountByYear(sanTypeId) {
return request200(
request({
method: "GET",
// url: "/api/entitiesDataCount/industryCountByYear"
url: "/api/entitiesDataCount/getAnnualCount"
url: "/api/entitiesDataCount/getAnnualCount",
params: {
sanTypeId
}
})
);
}
......@@ -84,11 +88,16 @@ export function getIndustryCountByYear() {
* domains: string[]
* }>}
*/
export function getCountDomainByYear() {
export function getCountDomainByYear(isRule, startYear = "2020", endYear = new Date().getFullYear()) {
return request200(
request({
method: "GET",
url: "/api/entitiesDataCount/countDomainByYear"
method: "POST",
url: "/api/entitiesDataCount/getAnnualSanDomain",
data: {
isRule,
startYear,
endYear
}
})
);
}
......@@ -187,6 +196,21 @@ export function getKeyEntityList(date, keyword = "") {
);
}
/**
* 区域分布查询
*/
export function getAreaDistribution(date) {
return request200(
request({
method: "GET",
url: "/api/entitiesDataInfo/getRegionDistribution",
params: {
sanctionDate: date || "2025-11-11"
}
})
);
}
/**
* 不同领域实体统计
* @param {string} startTime - 统计开始时间,格式为 'YYYY-MM-DD'
......@@ -292,7 +316,7 @@ export function getDomainDistribution(sanctionDate = "2025-11-11") {
* startTime: string
* }[]>}
*/
export function getEntitiesList(typeName = "实体清单", pageNum = 1, pageSize = 10) {
export function getEntitiesList(typeName = "实体清单", pageNum = 1, pageSize = 10, sanctionDate = "", rule = false) {
return request200(
request({
method: "POST",
......@@ -300,7 +324,9 @@ export function getEntitiesList(typeName = "实体清单", pageNum = 1, pageSize
data: {
typeName,
pageNum,
pageSize
pageSize,
sanctionDate,
rule
}
})
);
......@@ -340,15 +366,16 @@ export function getCompareCountSan(startTime) {
* count:number
* }[]>}
*/
export function getEntitiesChangeCount(domain, type) {
export function getEntitiesChangeCount(domianId, typeId) {
return request200(
request({
method: "GET",
// url: '/api/entitiesDataCount/entitiesChangeCount',
url: "/api/entitiesDataCount/sanCountByYear",
// url: "/api/entitiesDataCount/sanCountByYear",
url: "/api/entitiesDataInfo/getCountByDomianAndType",
params: {
domain,
type
domianId,
typeId
}
})
);
......@@ -377,11 +404,14 @@ export function getEntitiesGrowthTrend() {
* xAxis: string[]
* }>}
*/
export function getEntitiesUpdateCount() {
export function getEntitiesUpdateCount(sanTypeId = 1) {
return request200(
request({
method: "GET",
url: "/api/entitiesDataCount/entitiesUpdateCount"
url: "/api/entitiesDataCount/getAnnualCount",
params: {
sanTypeId
}
})
);
}
......@@ -389,11 +419,14 @@ export function getEntitiesUpdateCount() {
/**
* 制裁领域分析
*/
export function getSanDomainCount() {
export function getSanDomainCount(rule) {
return request200(
request({
method: "GET",
url: "/api/entitiesDataCount/getSanDomainCount"
url: "/api/entitiesDataCount/getSanDomainCount",
params: {
rule
}
})
);
}
......
......@@ -32,6 +32,7 @@ const emit = defineEmits(["click"]);
cursor: pointer;
padding-left: 8px;
padding-right: 8px;
flex-shrink: 0;
}
.activeButton {
border: 1px solid rgb(10, 87, 166);
......
......@@ -61,5 +61,6 @@ function setActiveIndex(item) {
.buttonList {
display: flex;
gap: 8px;
overflow-x: auto;
}
</style>
......@@ -25,7 +25,7 @@
<div class="chartsWrap">
<div class="right-main-content">
<div class="right-main-content-main">
<Fishbone />
<Fishbone :chainId="activeButtonId" />
</div>
<div class="right-main-content-footer">
<div class="footer-item1">
......@@ -76,30 +76,12 @@ import Echarts from "@/components/Chart/index.vue";
import Hint from "./hint.vue";
import ButtonList from "@/components/buttonList/buttonList.vue";
import Fishbone from "./fishbone.vue";
import college1 from "../../assets/images/college1.png";
import college2 from "../../assets/images/college2.png";
import college3 from "../../assets/images/college3.png";
import college4 from "../../assets/images/college4.png";
import college5 from "../../assets/images/college5.png";
import college6 from "../../assets/images/college6.png";
import college7 from "../../assets/images/college7.png";
import college8 from "../../assets/images/college8.png";
import college9 from "../../assets/images/college9.png";
import college10 from "../../assets/images/college10.png";
import college11 from "../../assets/images/college11.png";
import { getHorizontalBarChart2 } from "../../utils/charts";
import { getDomainDistribution, getChainEntities } from "@/api/exportControl";
import { useRoute } from "vue-router";
const route = useRoute();
const buttonList = ref([
{ id: 1, text: "新能源" },
{ id: 2, text: "半导体" },
{ id: 3, text: "跨境电商" },
{ id: 4, text: "金融业" },
{ id: 5, text: "军工" },
{ id: 6, text: "贸易" }
]);
const activeButtonId = ref(buttonList.value[0].id);
const buttonList = ref([]);
const activeButtonId = ref(buttonList.value[0]?.id || 1);
const setActiveButtonId = id => {
activeButtonId.value = id;
};
......@@ -178,10 +160,12 @@ const fetchDomainDistribution = async () => {
horizontalBarOptions.value = getHorizontalBarChart2(yAxisData, seriesData, false);
// 更新buttonList
buttonList.value = sortedData.map(item => ({
id: item.id,
text: item.name
}));
buttonList.value = sortedData
.map(item => ({
id: item.id,
text: item.name
}))
.sort((a, b) => a.id - b.id);
console.log("buttonList.value", buttonList.value);
setActiveButtonId(buttonList.value[0].id);
}
......
......@@ -8,9 +8,23 @@
import Echarts from "@/components/Chart/index.vue";
import { getMapOption } from "../../utils/charts";
import { ref, onMounted, shallowRef } from "vue";
import { getAreaDistribution } from "@/api/exportControl";
// 这儿接收父组件传递过来的date参数
const props = defineProps({
date: {
type: String,
default: ""
}
});
const mapOption = shallowRef({});
onMounted(() => {
mapOption.value = getMapOption();
// 区域分布查询
getAreaDistribution(props.date).then(res => {
console.log("res", res);
});
});
</script>
......
......@@ -8,6 +8,7 @@
size="mini"
v-model="domainValue"
placeholder="领域选择"
@change="handleDomainChange"
>
<el-option v-for="item in domainOptions" :key="item.value" :label="item.label" :value="item.value">
</el-option>
......@@ -24,7 +25,8 @@
</template>
<div class="subPanel1">
<div class="chartsWrap" :style="{ paddingBottom: '10px' }">
<Echarts :option="bar1Option" height="100%"></Echarts>
<Echarts v-if="!bar1DataIsEmpty" :option="bar1Option" height="100%"></Echarts>
<el-empty v-else description="暂无数据" />
</div>
<Hint text="近几次新增受制裁实体中,中国实体占比提高,美方针对中国的出口管制风险显著增加。"></Hint>
</div>
......@@ -123,7 +125,7 @@ onMounted(async () => {
try {
const [entitiesGrowthTrendData, entitiesUpdateCountData] = await Promise.all([
getEntitiesGrowthTrend(),
getEntitiesUpdateCount()
getEntitiesUpdateCount(1)
]);
const list = _.reverse(entitiesGrowthTrendData);
......@@ -133,12 +135,25 @@ onMounted(async () => {
});
line1Option.value = getLineChart({ xAxisData, seriesData, name: "增长趋势", color: "rgba(146, 84, 222, 1)" }, true);
bar2Option.value = getBarChart(
_.reverse(entitiesUpdateCountData.xAxis),
_.reverse(entitiesUpdateCountData.series),
["rgba(22, 119, 255, 1)", "rgba(22, 119, 255, 0)"],
"更新频率"
);
if (entitiesUpdateCountData && Array.isArray(entitiesUpdateCountData)) {
const sortedData = _.sortBy(entitiesUpdateCountData, "year");
// 提取 x 轴数据(年份)
const xAxisData = sortedData.map(item => item.year.toString());
// 提取 y 轴数据(数量)
const seriesData = sortedData.map(item => item.count);
bar2Option.value = getBarChart(xAxisData, seriesData, ["rgba(22, 119, 255, 1)", "rgba(22, 119, 255, 0)"], "更新频率");
} else {
// 保持原有逻辑以防数据格式不符合预期
bar2Option.value = getBarChart(
_.reverse(entitiesUpdateCountData.xAxis),
_.reverse(entitiesUpdateCountData.series),
["rgba(22, 119, 255, 1)", "rgba(22, 119, 255, 0)"],
"更新频率"
);
}
// 获取重点实体列表数据
await fetchKeyEntityList(route.query.startTime);
} catch (err) {
......@@ -248,11 +263,13 @@ const typeOptions = [
const domainValue = ref(domainOptions[0].value);
const typeValue = ref(typeOptions[0].value);
const bar1Option = shallowRef({});
const bar1DataIsEmpty = ref(false);
watch(
[domainValue, typeValue],
async ([domain, type]) => {
let EntitiesChangeCount = await getEntitiesChangeCount(domain, type);
EntitiesChangeCount = _.reverse(EntitiesChangeCount);
bar1DataIsEmpty.value = EntitiesChangeCount.length === 0;
bar1Option.value = getBarChart(
_.map(EntitiesChangeCount, "year"),
_.map(EntitiesChangeCount, "count"),
......@@ -317,6 +334,10 @@ watch(
await fetchKeyEntityList(route.query.startTime, newVal);
}, 300)
);
const handleDomainChange = async domain => {
await fetchKeyEntityList(route.query.startTime, value3.value, domain);
};
</script>
<style lang="scss" scoped>
......
......@@ -19,7 +19,7 @@
</CardCustom>
</div>
<div class="row">
<CardCustom title="历制裁涉及领域数" :style="{ width: '798px', height: '422px' }">
<CardCustom title="历制裁涉及领域数" :style="{ width: '798px', height: '422px' }">
<div class="subPanel3">
<div class="chartsWrap" :style="{ paddingBottom: '10px' }">
<Echarts :option="bar2Option" height="100%"></Echarts>
......@@ -46,7 +46,12 @@ import { Search } from "@element-plus/icons-vue";
import Echarts from "@/components/Chart/index.vue";
import { getBarChart, getLineChart, getPieOption1 } from "../../utils/charts";
import Hint from "./hint.vue";
import { getEntitiesAreaCountByYear, getEntitiesDomainCount, getCountThisDomain } from "@/api/exportControl";
import {
getEntitiesAreaCountByYear,
getEntitiesDomainCount,
getCountThisDomain,
getDomainDistribution
} from "@/api/exportControl";
import _ from "lodash";
import { useRoute } from "vue-router";
const route = useRoute();
......@@ -85,13 +90,18 @@ const fetchEntitiesDomainCount = async () => {
onMounted(async () => {
try {
const [entitiesAreaCountByYearData, countThisDomainData4, countThisDomainData10] = await Promise.all([
getEntitiesAreaCountByYear(route.query.startTime),
getDomainDistribution(route.query.startTime),
getCountThisDomain("4"),
// getEntitiesDomainCount(),
getCountThisDomain("10")
]);
pie1Option.value = getPieOption1(entitiesAreaCountByYearData ?? []);
pie1Option.value = getPieOption1(
entitiesAreaCountByYearData.map(item => ({
name: item.name,
value: item.count
})) ?? []
);
const list4 = _.reverse(countThisDomainData4 ?? []);
line1Option.value = getLineChart({
xAxisData: _.map(list4, "year"),
......
......@@ -42,7 +42,7 @@ onMounted(async () => {
.filter(item => item.count > 0)
.map(item => {
return {
name: item?.type,
name: item?.name,
value: item?.count
};
})
......
......@@ -57,7 +57,7 @@
<div class="panel3">
<div class="chartWrap">
<PieCharts v-if="panel3ActiveIndex === 1"></PieCharts>
<MapCharts v-if="panel3ActiveIndex === 2"></MapCharts>
<MapCharts v-if="panel3ActiveIndex === 2" :date="route.query.startTime"></MapCharts>
</div>
<Hint text="本次制裁共新增83个实体,其中53个中国大陆实体、1个中国台湾实体。"></Hint>
</div>
......@@ -94,7 +94,7 @@
</div>
</div>
<div class="tableWrap">
<div class="tableWrap" ref="tableWrapRef" @scroll="handleScroll">
<el-table
:data="selectEntitiesList"
class="sanction-table"
......@@ -115,7 +115,7 @@
</template>
</el-table-column>
<el-table-column prop="domains" label="涉及领域" width="100">
<el-table-column prop="domains" label="涉及领域" width="180">
<template #default="{ row }">
<div class="domain-tags">
<el-tag v-for="tag in row.domains" :key="tag" :type="panel5TypeMap[tag]">{{
......@@ -125,11 +125,11 @@
</template>
</el-table-column>
<el-table-column prop="address" label="上市地点" width="90" align="center">
<!-- <el-table-column prop="address" label="上市地点" width="90" align="center">
<template #default="{ row }">
{{ row.address }}
</template>
</el-table-column>
</el-table-column> -->
<el-table-column prop="time" label="制裁时间" width="120" align="center">
<template #default="{ row }">
......@@ -137,11 +137,11 @@
</template>
</el-table-column>
<el-table-column prop="revenue" label="营收(亿元)" width="100" align="center">
<!-- <el-table-column prop="revenue" label="营收(亿元)" width="100" align="center">
<template #default="{ row }">
{{ row.revenue }}
</template>
</el-table-column>
</el-table-column> -->
<el-table-column prop="subCompany" label="50%规则子企业" min-width="140" align="left">
<template #default="{ row }">
......@@ -183,7 +183,7 @@ import PieCharts from "../components/pieCharts.vue";
import MapCharts from "../components/mapCharts.vue";
import ButtonList from "@/components/buttonList/buttonList.vue";
import Hint from "../components/hint.vue";
import { onMounted, reactive, ref, shallowRef } from "vue";
import { onMounted, reactive, ref, shallowRef, watch } from "vue";
import panel1_1 from "../../assets/images/panel1_1.png";
import panel2_1 from "../../assets/images/panel2_1.png";
import panel2_2 from "../../assets/images/panel2_2.png";
......@@ -197,7 +197,14 @@ import panel5_5 from "../../assets/images/panel5_5.png";
import panel5_6 from "../../assets/images/panel5_6.png";
import panel5_7 from "../../assets/images/panel5_7.png";
import panel5_8 from "../../assets/images/panel5_8.png";
import { getOrganizationInfo, getPersonList, getSanReasonSelect, getSelectEntitiesList } from "@/api/exportControl";
import {
getOrganizationInfo,
getPersonList,
getSanReasonSelect,
getSelectEntitiesList,
getEntitiesList
} from "@/api/exportControl";
import _ from "lodash";
import { useRoute } from "vue-router";
import { formatAnyDateToChinese } from "../../utils";
......@@ -246,15 +253,26 @@ const sanReasonSelect = shallowRef([
text: "将中国定位为“通过强制技术转让获取先进制程的威胁”"
}
]);
const panel5IsChecked = ref(true);
const selectEntitiesList = shallowRef([]);
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(0);
const loading = ref(false);
const tableWrapRef = ref(null);
const noMoreData = ref(false);
onMounted(async () => {
try {
const [organizationInfoData, personListData, sanReasonSelectData, selectEntitiesListData] = await Promise.all([
const [organizationInfoData, sanReasonSelectData] = await Promise.all([
getOrganizationInfo(),
getPersonList(),
getSanReasonSelect(route.query.startTime),
getSelectEntitiesList(route.query.startTime)
// getPersonList(),
getSanReasonSelect(route.query.startTime)
// getSelectEntitiesList(route.query.startTime)
]);
console.log("organizationInfoData", organizationInfoData);
organizationInfo.value = {
img: panel1_1,
mingcheng: organizationInfoData?.orgNameZh,
......@@ -274,22 +292,103 @@ onMounted(async () => {
return { text: item };
});
selectEntitiesList.value = _.map(selectEntitiesListData, item => {
return {
name: item?.entityNameZh,
domains: item.techDomainList,
// selectEntitiesList.value = _.map(selectEntitiesListData, item => {
// return {
// name: item?.entityNameZh,
// domains: item.techDomainList,
// address: "--",
// time: formatAnyDateToChinese(item?.startTime),
// isUp: true,
// revenue: "--",
// subCompany: "--",
// img: ""
// };
// });
// 初始化加载第一页数据
await fetchEntitiesList(currentPage.value, pageSize.value);
} catch (err) {
console.log(err);
}
});
// 获取实体清单数据
const fetchEntitiesList = async (page = 1, size = 10) => {
if (loading.value || noMoreData.value) return;
loading.value = true;
try {
const res = await getEntitiesList("实体清单", page, size, route.query.startTime, panel5IsChecked.value);
if (res) {
const newData = res.content.map(item => ({
...item,
name: item.entityNameZh,
enName: item.entityName,
domains: item.techDomains,
time: formatAnyDateToChinese(item.startTime),
address: "--",
time: formatAnyDateToChinese(item?.startTime),
isUp: true,
revenue: "--",
subCompany: "--",
img: ""
};
});
}));
// 如果是第一页,替换数据;否则追加数据
if (page === 1) {
selectEntitiesList.value = newData;
} else {
selectEntitiesList.value = [...selectEntitiesList.value, ...newData];
}
total.value = res.totalElements;
currentPage.value = res.number + 1;
// 检查是否还有更多数据
if (selectEntitiesList.value.length >= total.value) {
noMoreData.value = true;
}
}
} catch (err) {
console.log(err);
console.error(err);
if (currentPage.value > 1) {
currentPage.value--;
}
} finally {
loading.value = false;
}
});
};
watch(
() => panel5IsChecked.value,
newVal => {
fetchEntitiesList(1, 10);
}
);
// 处理滚动事件
const debounceFlag = ref(false);
const handleScroll = () => {
if (!tableWrapRef.value || debounceFlag.value) return;
const { scrollTop, scrollHeight, clientHeight } = tableWrapRef.value;
// 当距离底部小于50px时加载更多
if (scrollHeight - scrollTop - clientHeight < 50) {
// 设置防抖标志
debounceFlag.value = true;
loadMore();
// 延迟重置防抖标志,防止连续触发
setTimeout(() => {
debounceFlag.value = false;
}, 300);
}
};
// 加载更多数据
const loadMore = () => {
if (!loading.value && !noMoreData.value) {
currentPage.value++;
fetchEntitiesList(currentPage.value, pageSize.value);
}
};
const panel3ActiveIndex = ref(1);
const setPanel3ActiveIndex = index => {
......@@ -304,7 +403,7 @@ const panel5ButtonAcitveID = ref(panel5ButtonList[0].id);
const panel5SetButtonAcitveID = id => {
panel5ButtonAcitveID.value = id;
};
const panel5IsChecked = ref(true);
const panel5TypeMap = {
人工智能: "danger",
通信网络: "warning",
......@@ -662,6 +761,10 @@ const panel6 = ref([
margin-top: 14px;
min-height: 0;
overflow: auto;
.domain-tags {
display: flex;
gap: 4px;
}
}
.name {
display: flex;
......
......@@ -35,14 +35,19 @@
</div>
<div class="layout-main-header-right-box">
<div class="right-box-top">
<div class="time">{{ "2025年7月" }}</div>
<div class="time">{{ route.query.startTime }}</div>
<div class="name">{{ "美国商务部工业与安全局" }}</div>
</div>
<div class="right-box-bottom">
<el-button type="plain" size="large" icon="Search" @click="handleSwitchActiveName('实体清单原文')"
<el-button
type="plain"
size="large"
disabled
icon="Search"
@click="handleSwitchActiveName('实体清单原文')"
>实体清单原文</el-button
>
<el-button type="primary" size="large" icon="EditPen">分析报告</el-button>
<el-button type="primary" size="large" disabled icon="EditPen">分析报告</el-button>
</div>
</div>
</div>
......
......@@ -7,7 +7,7 @@
<div class="sub-title">{{ subtitle }}</div>
</div>
<div class="description">{{ description }}</div>
<div v-if="quantity > 0" class="quantity" :style="{ color: color }">{{ quantity }}</div>
<div v-if="quantity > 0" class="quantity" :style="{ color: color }">{{ quantity }}{{ unit || "个" }}</div>
</div>
</div>
</template>
......@@ -30,6 +30,10 @@ defineProps({
type: [Number, String],
default: 0
},
unit: {
type: String,
default: ""
},
color: {
type: String,
default: "#409EFF"
......
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论