提交 d85c3e2c authored 作者: yanpeng's avatar yanpeng

出口管制相关修改

上级 3b47eb31
......@@ -393,13 +393,13 @@ export function getDomainDistribution(sanctionDate = "2025-11-11") {
* startTime: string
* }[]>}
*/
export function getEntitiesList(typeName = "实体清单", pageNum = 1, pageSize = 10, sanctionDate = "", isCn = false) {
export function getEntitiesList(sanTypeId=1, pageNum = 1, pageSize = 10, sanctionDate = "", isCn = false) {
return request200(
request({
method: "POST",
url: "/api/sanctionList/pageQuery",
data: {
typeName,
sanTypeId,
pageNum,
pageSize,
sanctionDate,
......
......@@ -392,6 +392,14 @@ export function getSingleSanctionEntitySupplyChain(params) {
});
}
// 单次制裁-深度挖掘-制裁实体信息
export function getSingleSanctionEntityInfo(id) {
return request({
method: "GET",
url: `/api/organization/sanInfo?orgId=${id}`,
});
}
// 单次制裁-深度挖掘-制裁实体股权信息
/**
* @param {Object} params
......@@ -550,10 +558,10 @@ export function getSingleSanctionEntityInternationalPaper(params) {
}
// 商业管制清单-CCL清单简介-基本信息
export function getCCLInfo() {
export function getCCLInfo(sanTypeId = 13) {
return request({
method: "GET",
url: `/api/sanctionList/baseInfo/ccl`
url: `/api/sanctionList/baseInfoById/${sanTypeId}`
});
}
......@@ -620,3 +628,11 @@ export function getCclQuery(data) {
data
});
}
// 商业管制清单-CCL清单列表-清单版本
export function getCCLVersionList() {
return request({
method: "GET",
url: `/api/ccl/version/dateList`
});
}
......@@ -120,7 +120,7 @@ const exportControlRoutes = [
name: "commercialControlList",
component: () => import("@/views/exportControl/v2.0CommercialControlList/index.vue"),
meta: {
title: "全部实体清单"
title: "商业管制清单"
}
}
]
......
......@@ -1453,7 +1453,7 @@ watch(
// 获取实体清单数据
const fetchEntitiesList = async (page = 1, size = 10) => {
try {
const res = await getEntitiesList("实体清单", page, size);
const res = await getEntitiesList(activeResourceTabItem.value.id, page, size);
if (res) {
entitiesList.value = res.content.map(item => ({
...item,
......
......@@ -407,7 +407,7 @@ const CCLInfo = ref({
});
const getCCLInfoFn = async () => {
try {
const res = await getCCLInfo();
const res = await getCCLInfo(route.query.sanTypeId || 13);
if (res && res.code === 200) {
CCLInfo.value = res.data;
console.log("getCCLInfoFn", CCLInfo.value);
......
......@@ -18,16 +18,26 @@
<div class="text">科技领域</div>
</div>
<div class="checkbox-group">
<el-checkbox v-for="(item, index) in techFields" :key="index" v-model="item.checked" :label="item.name"
@change="handleFilterChange(item, techFields, 'tech')" />
<el-checkbox
v-for="(item, index) in techFields"
:key="index"
v-model="item.checked"
:label="item.name"
@change="handleFilterChange(item, techFields, 'tech')"
/>
</div>
<div class="title">
<div class="box"></div>
<div class="text">管控原因</div>
</div>
<div class="checkbox-group">
<el-checkbox v-for="(item, index) in controlReason" :key="index" v-model="item.checked" :label="item.name"
@change="handleFilterChange(item, controlReason, 'reason')" />
<el-checkbox
v-for="(item, index) in controlReason"
:key="index"
v-model="item.checked"
:label="item.name"
@change="handleFilterChange(item, controlReason, 'reason')"
/>
</div>
</div>
<div class="right">
......@@ -41,7 +51,7 @@
</div>
<div style="width: 100%" v-if="item.isExpand">
<div style="width: 100%" v-for="element,index in item.cclChildren" :key="index">
<div style="width: 100%" v-for="(element, index) in item.cclChildren" :key="index">
<div class="list-desc">{{ element.cclCode }}. {{ element.cclTitleZh }}</div>
<div class="list-content" v-for="(ele, j) in element.cclChildren" :key="j">
......@@ -74,71 +84,80 @@ import { ref, computed, onMounted, watch } from "vue";
import { useRouter } from "vue-router";
import { Search, Select } from "@element-plus/icons-vue";
import defaultIcon from "../../../../../assets/icons/default-avatar.png";
import { getECCNCategory, getAreaType, getControlReason, getCclQuery, getExportControlList, get50PercentEntityCount } from "@/api/exportControlV2.0.js"
import {
getECCNCategory,
getAreaType,
getControlReason,
getCclQuery,
getCCLVersionList,
getExportControlList,
get50PercentEntityCount
} from "@/api/exportControlV2.0.js";
const router = useRouter();
const currentCCLType = ref('')
const CCLTypeList = ref([])
const currentCCLType = ref("");
const CCLTypeList = ref([]);
const getTypeList = async () => {
try {
const res = await getECCNCategory()
const res = await getECCNCategory();
if (res && res.code === 200) {
console.log('-----getTypeList', res.data)
CCLTypeList.value = res.data
currentCCLType.value = CCLTypeList.value[0].id
console.log("-----getTypeList", res.data);
CCLTypeList.value = res.data;
currentCCLType.value = CCLTypeList.value[0].id;
}
} catch (error) {
console.error("获取类别字典失败:", error);
}
}
};
const techFields = ref([])
const techFields = ref([]);
const getTechFields = async () => {
try {
const res = await getAreaType()
const res = await getAreaType();
if (res && res.code === 200) {
console.log('-----getTechFields', res.data)
techFields.value = res.data
console.log("-----getTechFields", res.data);
techFields.value = res.data;
// 默认选中第一个
techFields.value[0].checked = true
techFields.value[0].checked = true;
}
} catch (error) {
console.error("获取科技领域字典失败:", error);
}
}
};
const controlReason = ref([])
const controlReason = ref([]);
const getControlReasonList = async () => {
try {
const res = await getControlReason()
const res = await getControlReason();
if (res && res.code === 200) {
console.log('-----getControlReasonList', res.data)
controlReason.value = res.data
console.log("-----getControlReasonList", res.data);
controlReason.value = res.data;
// 默认选中第一个
controlReason.value[0].checked = true
controlReason.value[0].checked = true;
}
} catch (error) {
console.error("获取管控原因字典失败:", error);
}
}
};
const searchKeyword = ref('');
const searchKeyword = ref("");
const onlyChina = ref(false);
const viewNew = ref(true)
const viewNew = ref(true);
// 获取ccl清单列表
const getCclList = async () => {
let techDomains = techFields.value.filter(item => item.checked).map(item => +item.id)
let controls = controlReason.value.filter(item => item.checked).map(item => +item.id)
let techDomains = techFields.value.filter(item => item.checked).map(item => +item.id);
let controls = controlReason.value.filter(item => item.checked).map(item => +item.id);
const params = {
categoryCode: currentCCLType.value,
techDomainIds: techDomains,
keyword: searchKeyword.value || '',
keyword: searchKeyword.value || "",
controlIds: controls,
isLatest: viewNew.value
}
console.log(JSON.stringify(params))
isLatest: viewNew.value,
recordId: ""
};
console.log(JSON.stringify(params));
try {
// const res = await getCclQuery(null);
const res = await getCclQuery(params);
......@@ -207,38 +226,52 @@ const getCclList = async () => {
// })
// })
if (res && res.code === 200) {
console.log('----getCclList', res.data)
cclList.value = res.data
console.log("----getCclList", res.data);
cclList.value = res.data;
// 给数据添加isExpand字段
cclList.value.forEach((item) => {
item.isExpand = false
item.cclChildren.forEach((ele) => {
ele.cclChildren.forEach((i) => {
i.isExpand = false
})
})
})
cclList.value.forEach(item => {
item.isExpand = false;
item.cclChildren.forEach(ele => {
ele.cclChildren.forEach(i => {
i.isExpand = false;
});
});
});
}
} catch (error) {
console.error("获取ccl清单列表失败:", error);
}
};
// 商业管制清单-CCL清单列表-清单版本
const cclVersionList = ref([]);
// 获取清单版本列表
const getCCLVersionListApi = async () => {
try {
const res = await getCCLVersionList();
if (res && res.code === 200) {
console.log("----getCCLVersionList", res.data);
cclVersionList.value = res.data;
}
} catch (error) {
console.error("获取清单版本列表失败:", error);
}
}
};
// 筛选逻辑处理
const handleFilterChange = (item, list, type) => {
console.log(item, list, type)
getCclList()
console.log(item, list, type);
getCclList();
};
watch(viewNew, (newValue) => {
watch(viewNew, newValue => {
getCclList();
});
watch(currentCCLType, (newValue) => {
console.log(newValue)
getCclList()
})
watch(currentCCLType, newValue => {
console.log(newValue);
getCclList();
});
// const searchDebounceTimer = ref(null);
// watch(searchKeyword, () => {
......@@ -250,52 +283,52 @@ watch(currentCCLType, (newValue) => {
// getExportControlListApi();
// }, 300);
// });
watch(searchKeyword, (newValue) => {
console.log('-----searchKey', newValue)
getCclList()
watch(searchKeyword, newValue => {
console.log("-----searchKey", newValue);
getCclList();
});
// 模拟清单列表
const cclList = ref([
{
name: '类别 0-核材料、设施和设备、枪支、弹药[以及其他物品]',
name: "类别 0-核材料、设施和设备、枪支、弹药[以及其他物品]",
desc: 'A."最终产品"、"设备"、"附件"、"附加装置"、"零件"、"组件"和"系统"',
isExpand: true,
list: [
{
code: '0A002',
code: "0A002",
name: '发电或推进设备,"专门设计"用于与太空、海洋或移动"核反应堆"一起使用。(这些项目"受 ITAR 管辖。"参见 22 CFR 第 120 至 130 部分。)',
isExpand: false,
isDot: false
},
{
code: '0A501',
name: '枪支(不包括 0A502 霰弹枪、0A506 半自动步枪、0A507 半自动手枪和 0A508 半自动霰弹枪)及相关商品(不包括在 Eccn 0A509 中列举或以其他方式描述的与半自动相关的商品,用于 Eccn 0A506、0A507 或 0A508)如下(参见受控物品清单)',
code: "0A501",
name: "枪支(不包括 0A502 霰弹枪、0A506 半自动步枪、0A507 半自动手枪和 0A508 半自动霰弹枪)及相关商品(不包括在 Eccn 0A509 中列举或以其他方式描述的与半自动相关的商品,用于 Eccn 0A506、0A507 或 0A508)如下(参见受控物品清单)",
isExpand: true,
isDot: true
},
{
code: '0A501',
name: '枪支(不包括 0A502 霰弹枪、0A506 半自动步枪、0A507 半自动手枪和 0A508 半自动霰弹枪)及相关商品(不包括在 Eccn 0A509 中列举或以其他方式描述的与半自动相关的商品,用于 Eccn 0A506、0A507 或 0A508)如下(参见受控物品清单)',
code: "0A501",
name: "枪支(不包括 0A502 霰弹枪、0A506 半自动步枪、0A507 半自动手枪和 0A508 半自动霰弹枪)及相关商品(不包括在 Eccn 0A509 中列举或以其他方式描述的与半自动相关的商品,用于 Eccn 0A506、0A507 或 0A508)如下(参见受控物品清单)",
isExpand: false,
isDot: true
}
]
}
])
]);
onMounted(async () => {
// 获取类别字段
await getTypeList()
await getTypeList();
// 获取科技领域字典
await getTechFields()
await getTechFields();
// 获取管控原因字典
await getControlReasonList()
await getControlReasonList();
// 获取ccl清单列表
getCclList();
// 获取清单版本列表
getCCLVersionListApi();
});
</script>
<style scoped lang="scss">
......
......@@ -17,8 +17,8 @@
class="nav-item"
v-for="(item, index) in headerNavList"
:key="index"
:class="{ active: activeIndex === index }"
@click="activeIndex = index"
:class="{ active: activeIndex === index, disabled: item.disable }"
@click="!item.disable && (activeIndex = index)"
>
<img :src="activeIndex === index ? item.imgActive : item.img" alt />
<span>{{ item.title }}</span>
......@@ -81,17 +81,20 @@ const headerNavList = ref([
{
img: icon5,
imgActive: icon5Active,
title: "数据统计"
title: "数据统计",
disable: true
},
{
img: icon2,
imgActive: icon2Active,
title: "深度挖掘"
title: "深度挖掘",
disable: true
},
{
img: icon3,
imgActive: icon3Active,
title: "影响分析"
title: "影响分析",
disable: true
}
]);
</script>
......@@ -206,6 +209,11 @@ const headerNavList = ref([
font-weight: 700;
}
&.disabled {
cursor: not-allowed;
color: rgb(95, 101, 108);
}
.active-line {
position: absolute;
bottom: 0;
......
......@@ -130,7 +130,7 @@ import companyActive from "./assets/company-active.png";
import {
getSingleSanctionEntityList,
getSingleSanctionEntitySupplyChain,
getSingleSanctionEntityEquity
getSingleSanctionEntityEquity,
} from "@/api/exportControlV2.0";
import RelationGraph from "./components/RelationGraph.vue";
import AnalysisBox from "@/components/base/BoxBackground/AnalysisBox.vue";
......@@ -888,9 +888,11 @@ onMounted(async () => {
margin-left: 16px;
.toggle-btn {
width: 108px;
height: 100%;
padding: 4px 16px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: all 0.3s;
......
......@@ -90,6 +90,37 @@
<div class="right" v-loading="isLoading">
<AnalysisBox title="制裁清单" :showAllBtn="false">
<div class="right-title">
<div class="filter-row">
<div class="filter-left">
<el-select v-model="filterEntity" placeholder="受制裁实体" style="width: 184px">
<el-option label="受制裁实体" value="2" />
<el-option label="受制裁地址" value="7" />
<el-option label="受制裁个人" value="1" />
</el-select>
</div>
<div class="filter-right">
<el-checkbox v-model="onlyChina" label="只看中国实体" />
<el-select
v-model="filterField"
placeholder="全部领域"
style="width: 150px; margin: 0 12px 0 16px"
>
<el-option label="全部领域" value="" />
<el-option
v-for="item in domainOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-input
v-model="searchKeyword"
placeholder="搜索实体"
style="width: 150px"
:suffix-icon="Search"
/>
</div>
</div>
<div class="stats-row">
<div class="tabs">
<div class="tab-btn" :class="{ active: activeTab === 'add' }" @click="activeTab = 'add'">
......@@ -120,35 +151,6 @@
</div>
</div>
</div>
<div class="filter-row">
<div class="filter-left">
<!-- <el-select v-model="filterEntity" placeholder="受制裁实体" style="width: 184px">
<el-option label="受制裁实体" value="1" />
</el-select> -->
</div>
<div class="filter-right">
<el-checkbox v-model="onlyChina" label="只看中国实体" />
<el-select
v-model="filterField"
placeholder="全部领域"
style="width: 150px; margin: 0 12px 0 16px"
>
<el-option label="全部领域" value="" />
<el-option
v-for="item in domainOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-input
v-model="searchKeyword"
placeholder="搜索实体"
style="width: 150px"
:suffix-icon="Search"
/>
</div>
</div>
</div>
<div class="right-content">
<div class="sanction-group-list">
......@@ -286,7 +288,8 @@ const getSanctionOverviewList = async () => {
isOnlyCn: onlyChina.value,
domainId: filterField.value || undefined,
searchText: searchKeyword.value || undefined,
searchType: searchType.value
searchType: searchType.value,
entityTypeId: filterEntity.value || undefined
});
isLoading.value = false;
if (res.code === 200) {
......@@ -446,7 +449,7 @@ const formattedData = computed(() => {
};
});
const filterEntity = ref("");
const filterEntity = ref("2");
const onlyChina = ref(false);
const filterField = ref("");
const searchKeyword = ref("");
......@@ -454,7 +457,7 @@ const activeTab = ref("add");
const searchType = computed(() => activeTab.value);
// 监听筛选条件变化
watch([onlyChina, filterField, activeTab], () => {
watch([onlyChina, filterField, activeTab, filterEntity], () => {
getSanctionOverviewList();
});
......@@ -865,9 +868,9 @@ onMounted(() => {
.filter-row {
display: flex;
justify-content: right;
justify-content: space-between;
align-items: center;
// margin-bottom: 20px;
margin-bottom: 20px;
:deep(.el-input__inner) {
font-size: 16px;
......@@ -897,7 +900,7 @@ onMounted(() => {
.stats-row {
display: flex;
margin-bottom: 20px;
// margin-bottom: 20px;
justify-content: space-between;
align-items: center;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论