2250 lines
64 KiB
Vue
2250 lines
64 KiB
Vue
<script lang="ts" setup>
|
||
import { useTabBarStore } from '@/store';
|
||
import { Modal, Message as $message } from '@arco-design/web-vue';
|
||
import { useI18n } from 'vue-i18n';
|
||
import { nextTick, onMounted, ref, watch, computed } from 'vue';
|
||
|
||
import {
|
||
postInterfaceSystemInterfacePaginatedList,
|
||
postInterfaceBatchDeleteSystemInterfaceByIds,
|
||
} from '@/api/InterfaceServices/systemInterface';
|
||
|
||
import CascaderPro from '@/components/CascaderPro/Cascader.vue';
|
||
import { getServiceProviderGetServiceProviderInterfaceCascadedList } from '@/api/interface-serviceProvider/serviceProvider';
|
||
import { IconClose, IconEdit, IconPlus, IconSearch, IconMore, IconMinus, IconRefresh, IconDelete } from '@arco-design/web-vue/es/icon';
|
||
|
||
import dayjs from 'dayjs';
|
||
import { useRouter, useRoute } from 'vue-router';
|
||
import {
|
||
postCreate,
|
||
postSaveParameterMaps,
|
||
} from '@/api/InterfaceMappingServices/interfaceMap';
|
||
import useModal from '@/components/ModalPro/useModal';
|
||
import { $baseMessage, $baseConfirm } from '@/utils';
|
||
import EnteredMap from './components/EnteredMap.vue';
|
||
import MapServiceProvider from './components/map-service-provider.vue';
|
||
import ApiDebugger from './components/ApiDebugger.vue';
|
||
|
||
import { systemInterfaceColumns } from './models/tableColumns';
|
||
import InterfaceConfig from './interface-config.vue';
|
||
|
||
const { t } = useI18n();
|
||
defineOptions({
|
||
name: 'SystemInterface',
|
||
});
|
||
const active = ref(0);
|
||
const activeContentTab = ref('mapping');
|
||
const apiDebuggerRef = ref<any>();
|
||
|
||
const drawerList = ref<any[]>([]);
|
||
|
||
// 左侧接口树相关数据
|
||
const searchKeyword = ref('');
|
||
const interfaceTreeData = ref<any[]>([]);
|
||
const selectedKeys = ref<string[]>([]);
|
||
const expandedKeys = ref<string[]>([]);
|
||
const selectedInterface = ref<any>(null);
|
||
const loading = ref(false);
|
||
async function ServiceProviderGetList() {
|
||
const data =
|
||
await getServiceProviderGetServiceProviderInterfaceCascadedList({
|
||
serviceProviderName: '',
|
||
interfaceId: upStreamIdRef.value || 0,
|
||
});
|
||
drawerList.value = data as any;
|
||
|
||
setTimeout(() => {
|
||
panelRef.value?.SetOptions(data);
|
||
}, 300);
|
||
}
|
||
|
||
const panelRef = ref<any>();
|
||
const drawerVisible = ref(false); // 参数弹窗
|
||
const cascaderValue = ref<number[]>([]);
|
||
const drawerFormRef = ref<any>();
|
||
const upStreamIdRef = ref<number>();
|
||
const enteredMapRef = ref<any>();
|
||
const drawerConfig = reactive({
|
||
itemList: [
|
||
{
|
||
comp: 'a-input',
|
||
field: 'serviceProviderName',
|
||
label: '',
|
||
compProps: {
|
||
placeholder: '接口名称/代码',
|
||
allowClear: true,
|
||
size: 'small',
|
||
},
|
||
span: 12,
|
||
},
|
||
],
|
||
buttonConfig: {
|
||
showBtn: true,
|
||
span: 12,
|
||
showOk: true,
|
||
okText: '查询',
|
||
},
|
||
});
|
||
|
||
const tableRef = ref<any>();
|
||
const tableProps = reactive({
|
||
isToolsExport: false,
|
||
isToolsImport: false,
|
||
api: postInterfaceSystemInterfacePaginatedList,
|
||
tableConfig: {
|
||
columns: systemInterfaceColumns,
|
||
showIndex: true,
|
||
autoHeight: true,
|
||
showCheckbox: true,
|
||
isColumnsDrag: false,
|
||
toolbarConfig: {
|
||
enabled: true,
|
||
perfect: true,
|
||
slots: {
|
||
tools: 'toolbar_right',
|
||
buttons: 'toolbar_buttons',
|
||
},
|
||
},
|
||
},
|
||
formConfig: {
|
||
itemList: [
|
||
{
|
||
comp: 'a-input',
|
||
field: 'nameOrCode',
|
||
label: '',
|
||
compProps: {
|
||
placeholder: '请输入接口名称或接口代码',
|
||
allowClear: true,
|
||
size: 'small',
|
||
},
|
||
},
|
||
],
|
||
layout: 'inline',
|
||
labelColProps: { span: 0 },
|
||
wrapperColProps: { span: 24 },
|
||
buttonConfig: {
|
||
showBtn: true,
|
||
showOk: true,
|
||
okText: '查询',
|
||
showReset: false,
|
||
className: 'flex items-center',
|
||
span: 2,
|
||
},
|
||
},
|
||
});
|
||
const router = useRouter();
|
||
|
||
// 弹窗相关
|
||
const editVisible = ref(false);
|
||
const editId = ref<number | null>(null);
|
||
function interfaceClick() {
|
||
editId.value = null;
|
||
editVisible.value = true;
|
||
}
|
||
|
||
// 重置表单
|
||
const route = useRoute();
|
||
onActivated(() => {
|
||
if (route?.query?.openId) {
|
||
mapName.value = route?.query?.openName;
|
||
mapId.value = route?.query?.openId;
|
||
mapClick({
|
||
id: route.query.openId,
|
||
name: route.query.openName,
|
||
code: route.query.openCode,
|
||
});
|
||
}
|
||
});
|
||
|
||
// 组件挂载时加载数据
|
||
onMounted(() => {
|
||
loadInterfaceTree();
|
||
});
|
||
|
||
function compileClick(row: { id: any }) {
|
||
console.log('compileClick called with:', row);
|
||
editId.value = row.id;
|
||
editVisible.value = true;
|
||
console.log('editVisible set to:', editVisible.value);
|
||
}
|
||
|
||
|
||
|
||
const [register, registerMethods] = useModal() as any;
|
||
const [registerEnter, registerEnterMethods] = useModal() as any;
|
||
const mapId = ref();
|
||
// 映射服务商
|
||
const mapName = ref();
|
||
async function mapClick(row: any) {
|
||
newmapClickROW.value = row;
|
||
mapName.value = row.name;
|
||
mapId.value = row.id;
|
||
|
||
await registerMethods.openModal();
|
||
await (unref(MapServiceProviderRef) as any)?.tableRef?.reload();
|
||
}
|
||
|
||
// 删除
|
||
async function deleteClick() {
|
||
const list = (unref(tableRef) as any)?.checkAllRows?.();
|
||
|
||
const isHasmapCount = list.some((i: any) => i.mapCount > 0) as boolean;
|
||
if (isHasmapCount) {
|
||
$baseMessage('系统接口存在映射不允许删除', 'error');
|
||
return
|
||
}
|
||
const ids = list?.map((node: any) => node.id);
|
||
|
||
if (ids) {
|
||
$baseConfirm({
|
||
title: '提示',
|
||
content: '确定是否删除该条数据',
|
||
okText: '确定',
|
||
cancelText: '取消',
|
||
async onOk() {
|
||
await postInterfaceBatchDeleteSystemInterfaceByIds(ids);
|
||
tableRef.value?.removeCheckboxRow();
|
||
$baseMessage('删除成功', 'success');
|
||
},
|
||
});
|
||
}
|
||
}
|
||
|
||
// 删除单个接口
|
||
async function deleteInterfaceClick(nodeData: any) {
|
||
if (!nodeData || !nodeData.isLeaf) {
|
||
$baseMessage('只能删除接口节点', 'warning');
|
||
return;
|
||
}
|
||
|
||
if (nodeData.mapCount > 0) {
|
||
$baseMessage('系统接口存在映射不允许删除', 'error');
|
||
return;
|
||
}
|
||
|
||
$baseConfirm({
|
||
title: '温馨提示',
|
||
content: `确定要删除接口"${nodeData.title}"吗?`,
|
||
onOk: async () => {
|
||
try {
|
||
await postInterfaceBatchDeleteSystemInterfaceByIds([nodeData.id]);
|
||
$baseMessage('删除成功', 'success');
|
||
loadInterfaceTree();
|
||
// 如果删除的是当前选中的接口,清空选中状态
|
||
if (selectedInterface.value?.id === nodeData.id) {
|
||
selectedInterface.value = null;
|
||
selectedKeys.value = [];
|
||
}
|
||
} catch (error) {
|
||
$baseMessage('删除失败', 'error');
|
||
}
|
||
},
|
||
});
|
||
}
|
||
|
||
// 新增映射
|
||
const [registerAddMap, registerAddMapMethods] = useModal() as any;
|
||
const newmapClickROW = ref();
|
||
|
||
// 级联选择器相关数据
|
||
const cascaderOptions = ref<any[]>([]);
|
||
const mappingList = ref<any[]>([{ value: [] }]);
|
||
|
||
async function newmapClick(row: any) {
|
||
console.log('newmapClick called with:', row);
|
||
drawerVisible.value = true;
|
||
mapId.value = row.id;
|
||
|
||
registerAddMapMethods.setModalProps({
|
||
title: '新增映射',
|
||
width: 1000,
|
||
});
|
||
registerAddMapMethods.openModal();
|
||
newmapClickROW.value = row;
|
||
upStreamIdRef.value = Number(row.id);
|
||
mapName.value = row.name;
|
||
console.log('新增映射弹窗已打开');
|
||
|
||
// 重置映射列表,初始化为1个空映射
|
||
mappingList.value = [{ value: [] }];
|
||
|
||
// 初始化时加载所有服务商数据
|
||
await loadInitialServiceProviderData();
|
||
}
|
||
|
||
// 初始化加载服务商数据
|
||
async function loadInitialServiceProviderData() {
|
||
try {
|
||
console.log('开始加载初始服务商数据');
|
||
const response = await getServiceProviderGetServiceProviderInterfaceCascadedList({
|
||
serviceProviderName: '',
|
||
interfaceId: upStreamIdRef.value || 0,
|
||
});
|
||
|
||
console.log('初始API返回的原始数据:', response);
|
||
console.log('response.data:', response.data);
|
||
console.log('response 本身:', response);
|
||
|
||
// 处理数据,去掉服务商类型的一级菜单,直接显示服务商和服务商接口
|
||
// API返回的数据结构可能是 response 本身就是数组,或者 response.data 是数组
|
||
const rawData = Array.isArray(response) ? response : (response.data || []);
|
||
console.log('使用的原始数据:', rawData);
|
||
|
||
const processedData = processServiceProviderData(rawData);
|
||
console.log('初始处理后的数据:', processedData);
|
||
console.log('processedData 长度:', processedData.length);
|
||
|
||
drawerList.value = processedData;
|
||
|
||
// 构建级联选择器数据 - 直接使用处理后数据的label字段
|
||
buildCascaderOptions(processedData);
|
||
|
||
await nextTick();
|
||
console.log('设置初始panelRef选项');
|
||
panelRef.value?.SetOptions(processedData);
|
||
|
||
const arr = processedData?.filter((node: { children: any; }) => {
|
||
return node.children && node.children.length > 0;
|
||
});
|
||
cascaderValue.value = filterValue(arr);
|
||
} catch (error) {
|
||
console.error('加载初始服务商数据失败:', error);
|
||
cascaderOptions.value = [];
|
||
}
|
||
}
|
||
|
||
// 构建级联选择器数据
|
||
function buildCascaderOptions(data: any[]) {
|
||
console.log('buildCascaderOptions 输入数据:', data);
|
||
|
||
if (!data || data.length === 0) {
|
||
console.log('没有数据,设置空数组');
|
||
cascaderOptions.value = [];
|
||
return;
|
||
}
|
||
|
||
// 直接使用处理后的数据,因为它已经包含了label和value字段
|
||
cascaderOptions.value = data.map((provider: any) => {
|
||
const providerData = {
|
||
value: provider.value,
|
||
label: provider.label,
|
||
isDisable: provider.isDisable || false,
|
||
children: provider.children?.map((interfaceItem: any) => ({
|
||
value: interfaceItem.value,
|
||
label: interfaceItem.label,
|
||
isDisable: interfaceItem.isDisable || false,
|
||
providerId: provider.value,
|
||
providerName: provider.label,
|
||
interfaceId: interfaceItem.value,
|
||
interfaceName: interfaceItem.label
|
||
})) || []
|
||
};
|
||
console.log('处理后的服务商数据:', providerData);
|
||
return providerData;
|
||
});
|
||
|
||
console.log('buildCascaderOptions 输出数据:', cascaderOptions.value);
|
||
}
|
||
|
||
// 级联选择器过滤函数
|
||
function filterCascaderOption(inputValue: string, option: any) {
|
||
return option.label.toLowerCase().includes(inputValue.toLowerCase());
|
||
}
|
||
|
||
|
||
// 获取第一个映射的服务商ID和接口ID
|
||
const firstMapping = computed(() => {
|
||
if (mappingList.value.length > 0 && mappingList.value[0].value) {
|
||
// 如果 value 是数组且长度为2(完全选择)
|
||
if (Array.isArray(mappingList.value[0].value) && mappingList.value[0].value.length === 2) {
|
||
return {
|
||
providerId: mappingList.value[0].value[0],
|
||
interfaceId: mappingList.value[0].value[1]
|
||
};
|
||
}
|
||
// 如果 value 是数组但长度为1(可能只选择了服务商)
|
||
if (Array.isArray(mappingList.value[0].value) && mappingList.value[0].value.length === 1) {
|
||
return {
|
||
providerId: mappingList.value[0].value[0],
|
||
interfaceId: null
|
||
};
|
||
}
|
||
// 如果 value 是数字,需要通过接口ID找到对应的服务商ID
|
||
if (typeof mappingList.value[0].value === 'number') {
|
||
// 遍历级联选项找到包含该接口ID的服务商
|
||
for (const provider of cascaderOptions.value) {
|
||
if (provider.children) {
|
||
for (const interfaceItem of provider.children) {
|
||
if (interfaceItem.value === mappingList.value[0].value) {
|
||
return {
|
||
providerId: provider.value,
|
||
interfaceId: interfaceItem.value
|
||
};
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
}
|
||
return null;
|
||
});
|
||
|
||
// 获取第一个映射的服务商ID(向后兼容)
|
||
const firstProviderId = computed(() => {
|
||
return firstMapping.value?.providerId || null;
|
||
});
|
||
|
||
// 获取已选择的接口ID列表(包括第一个映射)
|
||
const selectedInterfaceIds = computed(() => {
|
||
const selectedIds: number[] = [];
|
||
|
||
// 遍历所有映射
|
||
for (let i = 0; i < mappingList.value.length; i++) {
|
||
const mappingValue = mappingList.value[i]?.value;
|
||
|
||
// 如果 value 是数组且长度为2
|
||
if (Array.isArray(mappingValue) && mappingValue.length === 2) {
|
||
selectedIds.push(mappingValue[1]);
|
||
}
|
||
// 如果 value 是数字,可能是接口ID
|
||
else if (typeof mappingValue === 'number') {
|
||
// 通过 firstMapping 确认这是接口ID
|
||
if (firstMapping.value && firstMapping.value.interfaceId === mappingValue) {
|
||
selectedIds.push(mappingValue);
|
||
}
|
||
}
|
||
}
|
||
|
||
return selectedIds;
|
||
});
|
||
|
||
// 获取每个映射项使用的级联选项
|
||
function getCascaderOptionsForIndex(index: number) {
|
||
// 如果是第一个映射,返回所有选项,但需要处理 isDisable
|
||
if (index === 0) {
|
||
return cascaderOptions.value.map((provider: any) => {
|
||
// 如果服务商的 isDisable 是 true,整个服务商及其接口都置灰
|
||
if (provider.isDisable) {
|
||
return {
|
||
...provider,
|
||
disabled: true,
|
||
children: provider.children?.map((interfaceItem: any) => ({
|
||
...interfaceItem,
|
||
disabled: true
|
||
})) || []
|
||
};
|
||
}
|
||
return provider;
|
||
});
|
||
}
|
||
|
||
// 第二个及之后的映射:只能选择第一个映射选择的服务商
|
||
if (!firstMapping.value || !firstMapping.value.providerId) {
|
||
return cascaderOptions.value;
|
||
}
|
||
|
||
return cascaderOptions.value.map((provider: any) => {
|
||
// 如果服务商的 isDisable 是 true,整个服务商及其接口都置灰
|
||
if (provider.isDisable) {
|
||
return {
|
||
...provider,
|
||
disabled: true,
|
||
children: provider.children?.map((interfaceItem: any) => ({
|
||
...interfaceItem,
|
||
disabled: true
|
||
})) || []
|
||
};
|
||
}
|
||
|
||
// 如果不是第一个映射选择的服务商,整个服务商都置灰
|
||
if (provider.value != firstMapping.value?.providerId) {
|
||
return {
|
||
...provider,
|
||
disabled: true,
|
||
children: provider.children?.map((interfaceItem: any) => ({
|
||
...interfaceItem,
|
||
disabled: true
|
||
})) || []
|
||
};
|
||
}
|
||
|
||
// 是第一个映射选择的服务商,需要禁用已选择的接口
|
||
return {
|
||
...provider,
|
||
children: provider.children?.map((interfaceItem: any) => ({
|
||
...interfaceItem,
|
||
disabled: selectedInterfaceIds.value.includes(interfaceItem.value)
|
||
})) || []
|
||
};
|
||
});
|
||
}
|
||
|
||
// 添加映射
|
||
function addMapping() {
|
||
mappingList.value.push({ value: [] });
|
||
}
|
||
|
||
// Tab 切换事件处理
|
||
function handleTabChange(tabName: string) {
|
||
// 如果切换到API调试tab,检查是否选择了映射服务商
|
||
if (tabName === 'debugger') {
|
||
if (!MapServiceProviderROW.value) {
|
||
$baseMessage('请选择服务商进行调试', 'warning');
|
||
// 切换回映射列表tab
|
||
activeContentTab.value = 'mapping';
|
||
return;
|
||
}
|
||
}
|
||
// 如果切换到接口明细tab,检查是否选择了接口
|
||
if (tabName === 'detail') {
|
||
if (!selectedInterface.value) {
|
||
$baseMessage('请选择左侧接口', 'warning');
|
||
activeContentTab.value = 'mapping';
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 监听第一个映射的变化,如果改变了服务商,清空后续映射
|
||
watch(
|
||
() => mappingList.value[0]?.value,
|
||
(newValue, oldValue) => {
|
||
let newProviderId: any = null;
|
||
let oldProviderId: any = null;
|
||
|
||
// 获取新的服务商ID
|
||
if (Array.isArray(newValue) && newValue.length >= 1) {
|
||
newProviderId = newValue[0];
|
||
} else if (typeof newValue === 'number') {
|
||
newProviderId = newValue;
|
||
}
|
||
|
||
// 获取旧的服务商ID
|
||
if (Array.isArray(oldValue) && oldValue.length >= 1) {
|
||
oldProviderId = oldValue[0];
|
||
} else if (typeof oldValue === 'number') {
|
||
oldProviderId = oldValue;
|
||
}
|
||
|
||
// 如果服务商改变了,清空所有后续映射的选择
|
||
if (oldProviderId && newProviderId && newProviderId !== oldProviderId) {
|
||
for (let i = 1; i < mappingList.value.length; i++) {
|
||
mappingList.value[i].value = [];
|
||
}
|
||
}
|
||
},
|
||
{ deep: true }
|
||
);
|
||
|
||
// 处理映射提交
|
||
async function handleMappingSubmit() {
|
||
// 过滤掉没有选择值的映射
|
||
const validMappings = mappingList.value.filter(m => {
|
||
// 如果是数组且长度为2,或者是一个数字(接口ID)
|
||
return (Array.isArray(m.value) && m.value.length === 2) || typeof m.value === 'number';
|
||
});
|
||
|
||
if (validMappings.length === 0) {
|
||
$baseMessage('请至少选择一个接口', 'warning');
|
||
return;
|
||
}
|
||
|
||
// 提取接口ID数组(按顺序)
|
||
const interfaceIds: number[] = [];
|
||
for (const m of validMappings) {
|
||
if (Array.isArray(m.value) && m.value.length === 2) {
|
||
interfaceIds.push(m.value[1]); // 接口ID是数组的第二个元素
|
||
} else if (typeof m.value === 'number') {
|
||
interfaceIds.push(m.value); // 数字本身就是接口ID
|
||
}
|
||
}
|
||
|
||
try {
|
||
// 调用API创建映射
|
||
await postCreate({
|
||
upStreamId: upStreamIdRef.value || 0,
|
||
downStreamIds: interfaceIds
|
||
});
|
||
|
||
$baseMessage('映射创建成功', 'success');
|
||
registerAddMapMethods.closeModal();
|
||
|
||
// 刷新映射列表
|
||
(unref(MapServiceProviderRef) as any)?.tableRef?.reload();
|
||
} catch (error) {
|
||
$baseMessage('创建映射失败', 'error');
|
||
}
|
||
}
|
||
|
||
// 抽屉查询按钮
|
||
async function onDetaCasc(formValue: any) {
|
||
console.log('onDetaCasc 被调用,参数:', formValue);
|
||
cascaderValue.value = [];
|
||
|
||
const response =
|
||
await getServiceProviderGetServiceProviderInterfaceCascadedList({
|
||
serviceProviderName: formValue?.serviceProviderName,
|
||
interfaceId: upStreamIdRef.value || 0,
|
||
});
|
||
|
||
console.log('API返回的原始数据:', response);
|
||
|
||
// 处理数据,去掉服务商类型的一级菜单,直接显示服务商和服务商接口
|
||
const processedData = processServiceProviderData(response.data || []);
|
||
console.log('处理后的数据:', processedData);
|
||
|
||
drawerList.value = processedData;
|
||
await nextTick();
|
||
console.log('设置panelRef选项');
|
||
panelRef.value?.SetOptions(processedData);
|
||
|
||
const arr = processedData?.filter((node: { children: any; }) => {
|
||
return node.children && node.children.length > 0;
|
||
});
|
||
cascaderValue.value = filterValue(arr);
|
||
}
|
||
|
||
// 处理服务商数据,去掉一级分类,直接显示服务商和服务商接口
|
||
function processServiceProviderData(data: any[]) {
|
||
if (!data || !Array.isArray(data)) return [];
|
||
|
||
const result: any[] = [];
|
||
|
||
console.log('开始处理数据,原始数据结构:', data);
|
||
|
||
data.forEach((category: any) => {
|
||
console.log('处理分类:', category);
|
||
|
||
if (category && category.children && Array.isArray(category.children)) {
|
||
// 遍历每个分类下的服务商
|
||
category.children.forEach((provider: any) => {
|
||
console.log('处理服务商:', provider);
|
||
|
||
if (provider && provider.children && Array.isArray(provider.children)) {
|
||
// 创建新的服务商节点,直接包含接口
|
||
const newProvider = {
|
||
value: provider.value || provider.id,
|
||
label: provider.label || provider.name,
|
||
key: provider.key || provider.value || provider.id,
|
||
isDisable: provider.isDisable || false,
|
||
// 其他属性
|
||
...provider
|
||
};
|
||
|
||
// 将接口作为服务商的直接子项
|
||
const interfaceItems = provider.children
|
||
.filter((interfaceItem: any) => interfaceItem) // 过滤掉空值
|
||
.map((interfaceItem: any) => ({
|
||
value: interfaceItem.value || interfaceItem.id,
|
||
label: interfaceItem.label || interfaceItem.name,
|
||
key: interfaceItem.key || interfaceItem.value || interfaceItem.id,
|
||
isDisable: interfaceItem.isDisable || false,
|
||
// 其他属性
|
||
...interfaceItem
|
||
}));
|
||
|
||
// 重新构建,让服务商直接包含接口
|
||
newProvider.children = interfaceItems;
|
||
|
||
console.log('创建新的服务商节点:', newProvider);
|
||
result.push(newProvider);
|
||
}
|
||
});
|
||
}
|
||
});
|
||
|
||
console.log('最终处理结果:', result);
|
||
return result;
|
||
}
|
||
|
||
function filterValue(arr: any[], arrValue: any[] = []): number[] {
|
||
if (!arr.length) return arrValue;
|
||
arrValue.push(arr[0]?.value);
|
||
|
||
if (arr[0].children && arr[0].children?.length > 0)
|
||
return filterValue(arr[0].children, arrValue);
|
||
return arrValue;
|
||
}
|
||
|
||
// 抽屉取消按钮
|
||
async function cancelCascader() {
|
||
drawerFormRef.value?.setFormValue('serviceProviderName', '');
|
||
const { data } =
|
||
await getServiceProviderGetServiceProviderInterfaceCascadedList({
|
||
serviceProviderName: '',
|
||
interfaceId: upStreamIdRef.value || 0,
|
||
});
|
||
|
||
// 处理数据,去掉一级分类
|
||
const processedData = processServiceProviderData(data);
|
||
|
||
cascaderValue.value = [];
|
||
drawerList.value = [];
|
||
setTimeout(() => {
|
||
drawerList.value = processedData;
|
||
}, 100);
|
||
}
|
||
|
||
// 处理树形选择变化
|
||
function handleTreeSelectionChange(selectedItems: any[]) {
|
||
console.log('选中的项目:', selectedItems);
|
||
// 这里可以处理选中的项目,比如更新UI状态等
|
||
}
|
||
|
||
// 处理树形搜索
|
||
function handleTreeSearch(keyword: string) {
|
||
console.log('搜索关键词:', keyword);
|
||
// 调用原来的搜索逻辑
|
||
onDetaCasc({ serviceProviderName: keyword });
|
||
}
|
||
const InputParameterMappingList = ref<any[]>([
|
||
{
|
||
value: '创建袋子',
|
||
label: '入参映射',
|
||
data: 1,
|
||
},
|
||
{
|
||
value: '获取带牌标签',
|
||
label: '入参映射',
|
||
data: 2,
|
||
},
|
||
{
|
||
value: '袋子绑定包裹',
|
||
label: '入参映射',
|
||
data: 3,
|
||
},
|
||
{
|
||
value: '出参映射',
|
||
label: '',
|
||
data: 4,
|
||
},
|
||
]);
|
||
const confirmLoading = ref(false);
|
||
const serviceProviderId = ref(0);
|
||
// 抽屉确认按钮
|
||
async function detCascader() {
|
||
const arr: any[] = panelRef.value?.getActivaList();
|
||
serviceProviderId.value = panelRef.value?.getCheckedList().value;
|
||
serviceProviderName.value = panelRef.value?.getCheckedList().label;
|
||
|
||
if (!arr.length) return $message.warning('请选择服务商的接口');
|
||
InputParameterMappingList.value = arr
|
||
.map((t: any, i: number) => (i = { ...t, data: i }))
|
||
.concat({
|
||
value: '',
|
||
label: '出参映射',
|
||
data: arr.length,
|
||
});
|
||
|
||
const id = arr.map((item: any) => item.value);
|
||
confirmLoading.value = true;
|
||
const data = await postCreate({
|
||
upStreamId: Number(upStreamIdRef.value),
|
||
downStreamIds: id,
|
||
}).finally(() => {
|
||
confirmLoading.value = false;
|
||
});
|
||
if (!data) return;
|
||
|
||
(unref(tableRef) as any)?.reload?.();
|
||
editMapIds.value = {
|
||
id: serviceProviderId.value,
|
||
addId: Number(upStreamIdRef.value),
|
||
intId: id,
|
||
};
|
||
|
||
registerEnterMethods.openModal();
|
||
|
||
await nextTick();
|
||
registerEnterMethods.setModalProps({
|
||
title: '新增',
|
||
width: 1600,
|
||
height: 1600,
|
||
});
|
||
|
||
(unref(enteredMapRef) as any)?.initData?.({
|
||
serviceProviderId: serviceProviderId.value,
|
||
interfaceId: upStreamIdRef.value,
|
||
});
|
||
active.value = 1;
|
||
|
||
const gb = drawerList.value;
|
||
cascaderValue.value = [];
|
||
drawerList.value = [];
|
||
setTimeout(() => {
|
||
drawerList.value = gb;
|
||
}, 100);
|
||
confirmLoading.value = false;
|
||
registerAddMapMethods.closeModal();
|
||
}
|
||
const checkRowsLength = computed(() => {
|
||
return (unref(tableRef) as any)?.checkAllRows?.()?.length || 0;
|
||
});
|
||
|
||
// 映射服务商弹窗点击修改打开入参映射弹窗
|
||
const editMapIds = ref();
|
||
// 是否全屏弹框
|
||
const fullScreen = ref(false);
|
||
const serviceProviderName = ref('');
|
||
|
||
async function handlerEditMap(data: any) {
|
||
console.log(data);
|
||
|
||
editMapIds.value = data;
|
||
serviceProviderId.value = data.serviceProviderId;
|
||
serviceProviderName.value = data.serviceProviderName;
|
||
upStreamIdRef.value = data.addId;
|
||
InputParameterMappingList.value = data.inputParameterMappingList;
|
||
registerEnterMethods.setModalProps({
|
||
title: '修改',
|
||
width: 1600,
|
||
height: 1600,
|
||
});
|
||
|
||
|
||
registerEnterMethods.openModal();
|
||
|
||
await nextTick();
|
||
|
||
await (unref(enteredMapRef) as any)?.initData?.({
|
||
serviceProviderId: data.serviceProviderId,
|
||
interfaceId: data.addId,
|
||
}
|
||
);
|
||
}
|
||
const MapServiceProviderROW = ref<any>();
|
||
const MapServiceProviderRef = ref<any>();
|
||
const loadingSubmit = ref(false);
|
||
const interfaceDetailModalRef = ref<any>();
|
||
const interfaceConfigRef = ref<any>();
|
||
const detailRefreshKey = ref(0);
|
||
const selectedProvider = ref<any>();
|
||
|
||
function saveModelEnter() {
|
||
const data = (unref(enteredMapRef) as any)?.getdata?.();
|
||
// 兜底系统接口 code,避免 undefined 读属性报错
|
||
const sysCode =
|
||
(newmapClickROW?.value && newmapClickROW.value.code) ||
|
||
(MapServiceProviderROW?.value && MapServiceProviderROW.value.systemInterfaceCode) ||
|
||
(selectedInterface?.value && selectedInterface.value.code) ||
|
||
'';
|
||
|
||
MapServiceProviderROW.value = {
|
||
serviceProviderId: serviceProviderId.value,
|
||
serviceProviderName: serviceProviderName.value,
|
||
systemInterfaceCode: sysCode,
|
||
addId: upStreamIdRef.value,
|
||
inputParameterMappingList: InputParameterMappingList.value,
|
||
};
|
||
loadingSubmit.value = true;
|
||
|
||
|
||
postSaveParameterMaps(data)
|
||
.then(() => {
|
||
$baseMessage(t('保存成功'), 'success');
|
||
loadingSubmit.value = false;
|
||
(unref(enteredMapRef) as any)?.initData?.(
|
||
{
|
||
serviceProviderId: serviceProviderId.value,
|
||
interfaceId: upStreamIdRef.value,
|
||
});
|
||
|
||
$baseConfirm({
|
||
title: t('温馨提示'),
|
||
content: t('是否去发布!'),
|
||
onOk: async () => {
|
||
// 保留发布确认,但不再弹“映射服务商/发布”窗口,仅关闭并刷新
|
||
await registerEnterMethods.closeModal?.();
|
||
await (unref(MapServiceProviderRef) as any)?.tableRef?.reload?.();
|
||
await (unref(tableRef) as any)?.reload?.();
|
||
},
|
||
});
|
||
})
|
||
.catch(() => {
|
||
loadingSubmit.value = false;
|
||
});
|
||
}
|
||
|
||
function rowClick(row: any) {
|
||
console.log(row);
|
||
MapServiceProviderROW.value = row;
|
||
// 联动右侧映射明细:根据左侧选中映射行初始化 EnteredMap
|
||
serviceProviderId.value = row.serviceProviderId;
|
||
serviceProviderName.value = row.serviceProviderName;
|
||
upStreamIdRef.value = row.systemInterfaceId || upStreamIdRef.value;
|
||
nextTick(() => {
|
||
(unref(enteredMapRef) as any)?.initData?.({
|
||
serviceProviderId: serviceProviderId.value,
|
||
interfaceId: upStreamIdRef.value,
|
||
});
|
||
});
|
||
}
|
||
|
||
function handleInterfaceDetailCancel() {
|
||
// 取消编辑,重新加载接口详情
|
||
if (selectedInterface.value) {
|
||
detailRefreshKey.value++;
|
||
}
|
||
}
|
||
// 点击跳转
|
||
function goRouter(id: number | undefined, address: string, type?: string) {
|
||
router.replace({
|
||
name: address,
|
||
query: { id, type },
|
||
});
|
||
}
|
||
|
||
// 处理接口树选择
|
||
function handleInterfaceSelect(keys: string[], info: any) {
|
||
try {
|
||
if (info && info.selected && info.node && info.node.isLeaf) {
|
||
// 更新选中的keys,保持选中状态
|
||
selectedKeys.value = keys;
|
||
|
||
const nodeData = getNodeData(info.node.key);
|
||
if (nodeData) {
|
||
selectedInterface.value = nodeData;
|
||
// 将上游接口ID同步给右侧明细区域
|
||
upStreamIdRef.value = Number(nodeData.id);
|
||
console.log('选择的接口:', nodeData);
|
||
|
||
// 重置映射明细区域,确保EnteredMap组件重新渲染
|
||
serviceProviderId.value = 0;
|
||
serviceProviderName.value = '';
|
||
MapServiceProviderROW.value = null;
|
||
|
||
// 刷新右侧映射服务商列表
|
||
nextTick(() => {
|
||
if (MapServiceProviderRef.value && MapServiceProviderRef.value.tableRef) {
|
||
console.log('重新加载映射服务商列表');
|
||
MapServiceProviderRef.value.tableRef.reload();
|
||
}
|
||
});
|
||
|
||
// 选择接口后,加载右侧嵌入的"新增映射"所需的服务商数据
|
||
loadInitialServiceProviderData();
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('处理接口选择时出错:', error);
|
||
}
|
||
}
|
||
|
||
// 处理树展开
|
||
function handleTreeExpand(keys: string[]) {
|
||
try {
|
||
expandedKeys.value = keys;
|
||
} catch (error) {
|
||
console.error('处理树展开时出错:', error);
|
||
}
|
||
}
|
||
|
||
// 加载接口树数据
|
||
async function loadInterfaceTree() {
|
||
loading.value = true;
|
||
try {
|
||
console.log('开始加载接口树数据...');
|
||
|
||
// 调用获取接口列表的API
|
||
const params: any = {
|
||
pageIndex: 1,
|
||
pageSize: 1000, // 获取所有接口
|
||
};
|
||
|
||
// 如果有搜索关键词,添加到参数中
|
||
if (searchKeyword.value) {
|
||
params.nameOrCode = searchKeyword.value;
|
||
}
|
||
|
||
const response = await postInterfaceSystemInterfacePaginatedList(params);
|
||
console.log('API完整响应:', response);
|
||
|
||
// 从API响应中获取数据
|
||
const data = (response as any)?.items || (response as any)?.data || (response as any)?.list || [];
|
||
console.log('提取的接口数据:', data);
|
||
|
||
if (Array.isArray(data) && data.length > 0) {
|
||
// 将接口数据转换为树形结构
|
||
const treeData = convertToTreeData(data);
|
||
console.log('转换后的树形数据:', treeData);
|
||
interfaceTreeData.value = treeData;
|
||
|
||
// 默认展开所有分类节点
|
||
const categoryKeys = treeData.map(item => item.key);
|
||
expandedKeys.value = categoryKeys;
|
||
} else {
|
||
interfaceTreeData.value = [];
|
||
}
|
||
} catch (error) {
|
||
console.error('加载接口树数据失败:', error);
|
||
$baseMessage('加载接口列表失败', 'error');
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
}
|
||
|
||
// 将接口数据转换为树形结构
|
||
function convertToTreeData(interfaces: any[]) {
|
||
console.log('开始转换数据:', interfaces);
|
||
|
||
// 按分类分组
|
||
const categoryMap = new Map();
|
||
|
||
interfaces.forEach((item) => {
|
||
console.log('处理接口项:', item);
|
||
|
||
// 使用categoryName作为分类,如果没有则使用category
|
||
const category = item.categoryName || `分类${item.category}` || '未分类';
|
||
|
||
if (!categoryMap.has(category)) {
|
||
categoryMap.set(category, []);
|
||
}
|
||
|
||
const treeItem = {
|
||
key: `item-${item.id}`,
|
||
title: item.name,
|
||
isLeaf: true,
|
||
id: item.id,
|
||
name: item.name,
|
||
code: item.code || item.name,
|
||
category: category,
|
||
mapCount: item.mapCount || 0
|
||
};
|
||
|
||
console.log('创建的树项:', treeItem);
|
||
categoryMap.get(category).push(treeItem);
|
||
});
|
||
|
||
// 转换为树形结构
|
||
const treeData = [];
|
||
let categoryIndex = 1;
|
||
|
||
for (const [category, items] of categoryMap) {
|
||
const categoryNode = {
|
||
key: `category-${categoryIndex}`,
|
||
title: category,
|
||
children: items
|
||
};
|
||
console.log('创建分类节点:', categoryNode);
|
||
treeData.push(categoryNode);
|
||
categoryIndex++;
|
||
}
|
||
|
||
console.log('最终树形数据:', treeData);
|
||
return treeData;
|
||
}
|
||
|
||
// 处理搜索
|
||
function handleSearch() {
|
||
loadInterfaceTree();
|
||
}
|
||
|
||
// 处理下拉菜单选择
|
||
function handleActionSelect(value: string, option: any) {
|
||
try {
|
||
console.log('handleActionSelect called:', { value, option });
|
||
if (option && option.data) {
|
||
const dataRef = option.data;
|
||
console.log('dataRef:', dataRef);
|
||
if (value === 'edit') {
|
||
console.log('调用 compileClick');
|
||
compileClick(dataRef);
|
||
} else if (value === 'map') {
|
||
console.log('调用 newmapClick');
|
||
newmapClick(dataRef);
|
||
}
|
||
} else {
|
||
console.log('option 或 option.data 为空:', { option });
|
||
}
|
||
} catch (error) {
|
||
console.error('处理下拉菜单选择时出错:', error);
|
||
}
|
||
}
|
||
|
||
// 根据key获取节点数据
|
||
function getNodeData(key: string) {
|
||
if (!key || !interfaceTreeData.value.length) return null;
|
||
|
||
// 递归查找节点
|
||
function findNode(nodes: any[]): any {
|
||
for (const node of nodes) {
|
||
if (node.key === key) {
|
||
return node;
|
||
}
|
||
if (node.children && node.children.length > 0) {
|
||
const found = findNode(node.children);
|
||
if (found) return found;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
return findNode(interfaceTreeData.value);
|
||
}
|
||
|
||
// 获取节点在接口列表中的索引
|
||
function getNodeIndex(key: string) {
|
||
if (!key || !interfaceTreeData.value.length) return '';
|
||
|
||
let index = 1;
|
||
|
||
// 递归查找节点索引
|
||
function findNodeIndex(nodes: any[]): number | null {
|
||
for (const node of nodes) {
|
||
if (node.key === key) {
|
||
return index;
|
||
}
|
||
if (node.children && node.children.length > 0) {
|
||
for (const child of node.children) {
|
||
if (child.key === key) {
|
||
return index;
|
||
}
|
||
index++;
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// 遍历所有分类,计算接口索引
|
||
for (const category of interfaceTreeData.value) {
|
||
if (category.children && category.children.length > 0) {
|
||
for (const child of category.children) {
|
||
if (child.key === key) {
|
||
return index;
|
||
}
|
||
index++;
|
||
}
|
||
}
|
||
}
|
||
|
||
return '';
|
||
}
|
||
|
||
</script>
|
||
|
||
<template>
|
||
<div class="interface-layout">
|
||
<!-- 左侧上游接口列表 -->
|
||
<div class="left-sidebar">
|
||
<div class="sidebar-header">
|
||
<div class="search-box">
|
||
<a-input
|
||
v-model="searchKeyword"
|
||
placeholder="请输入接口名称"
|
||
allow-clear
|
||
size="small"
|
||
@change="handleSearch"
|
||
@clear="handleSearch"
|
||
>
|
||
<template #prefix>
|
||
<icon-search />
|
||
</template>
|
||
</a-input>
|
||
<div class="search-actions">
|
||
<a-button
|
||
type="text"
|
||
size="small"
|
||
class="action-icon-btn refresh-btn"
|
||
@click="loadInterfaceTree"
|
||
title="刷新列表"
|
||
>
|
||
↻
|
||
</a-button>
|
||
<a-button
|
||
type="text"
|
||
size="small"
|
||
class="action-icon-btn add-btn"
|
||
@click="interfaceClick"
|
||
title="新增接口"
|
||
>
|
||
+
|
||
</a-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="interface-tree">
|
||
|
||
<div v-if="loading" class="loading-state">
|
||
<a-spin />
|
||
<p>正在加载接口列表...</p>
|
||
</div>
|
||
<a-tree
|
||
v-else
|
||
:data="interfaceTreeData"
|
||
:selected-keys="selectedKeys"
|
||
:expanded-keys="expandedKeys"
|
||
@select="handleInterfaceSelect"
|
||
@expand="handleTreeExpand"
|
||
show-line
|
||
block-node
|
||
>
|
||
<template #title="{ key, title }">
|
||
<div
|
||
class="tree-node"
|
||
:class="{ selected: selectedKeys.includes(key) }"
|
||
@click="console.log('节点数据:', { key, title, nodeData: getNodeData(key) })"
|
||
>
|
||
<table class="node-table">
|
||
<tr>
|
||
<td class="node-content-cell">
|
||
<span v-if="selectedKeys.includes(key)" class="selected-dot"></span>
|
||
<span v-if="getNodeData(key)?.isLeaf" class="node-number">{{ getNodeIndex(key) }}</span>
|
||
<span v-if="getNodeData(key)?.isLeaf" class="post-method">POST</span>
|
||
<span class="node-title">{{ title }}</span>
|
||
<span v-if="getNodeData(key)?.isLeaf" class="map-count">
|
||
<span class="bracket">[</span>
|
||
<span class="count-num">{{ getNodeData(key)?.mapCount || 0 }}</span>
|
||
<span class="bracket">]</span>
|
||
</span>
|
||
<span v-if="getNodeData(key)?.isLeaf && (getNodeData(key)?.mapCount || 0) > 0" class="status-dot"></span>
|
||
</td>
|
||
<td class="node-actions-cell" v-if="getNodeData(key)?.isLeaf">
|
||
<a-dropdown trigger="click" @select="handleActionSelect">
|
||
<a-button
|
||
type="text"
|
||
size="small"
|
||
class="action-btn vertical-dots"
|
||
title="操作"
|
||
>
|
||
<div class="vertical-dots-icon">
|
||
<span></span>
|
||
<span></span>
|
||
<span></span>
|
||
</div>
|
||
</a-button>
|
||
<template #content>
|
||
<a-doption value="delete" :data="getNodeData(key)" @click="deleteInterfaceClick(getNodeData(key))">
|
||
<icon-delete />
|
||
删除
|
||
</a-doption>
|
||
</template>
|
||
</a-dropdown>
|
||
</td>
|
||
</tr>
|
||
<tr v-if="getNodeData(key)?.isLeaf && getNodeData(key)?.code">
|
||
<td class="node-code-cell">
|
||
<span class="interface-code">{{ getNodeData(key)?.code }}</span>
|
||
</td>
|
||
<td class="node-actions-cell"></td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</template>
|
||
</a-tree>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧内容区域 -->
|
||
<div class="right-content-area">
|
||
<div class="content-tabs">
|
||
<a-tabs v-model="activeContentTab" class="content-tabs-nav" @change="handleTabChange">
|
||
<a-tab-pane key="mapping" title="映射列表">
|
||
<div class="mapping-split">
|
||
<div class="mapping-split-content">
|
||
<!-- 左侧:映射的服务商列表 -->
|
||
<div class="left-content">
|
||
<div class="pane-header">
|
||
<div class="search-box">
|
||
<a-input
|
||
v-model="searchKeyword"
|
||
placeholder="请输入服务商名称"
|
||
allow-clear
|
||
size="small"
|
||
@change="() => MapServiceProviderRef?.setSearchKeyword?.(searchKeyword)"
|
||
@clear="() => MapServiceProviderRef?.setSearchKeyword?.('')"
|
||
>
|
||
<template #prefix>
|
||
<icon-search />
|
||
</template>
|
||
</a-input>
|
||
<div class="search-actions">
|
||
<a-button
|
||
type="text"
|
||
size="small"
|
||
class="action-icon-btn refresh-btn"
|
||
@click="MapServiceProviderRef?.tableRef?.reload?.()"
|
||
title="刷新列表"
|
||
>
|
||
↻
|
||
</a-button>
|
||
<a-button
|
||
type="text"
|
||
size="small"
|
||
class="action-icon-btn add-btn"
|
||
@click="() => {
|
||
if (selectedInterface) {
|
||
newmapClick(selectedInterface);
|
||
} else {
|
||
$baseMessage('请先选择接口', 'warning');
|
||
}
|
||
}"
|
||
title="新增映射"
|
||
>
|
||
+
|
||
</a-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="pane-body">
|
||
<MapServiceProvider
|
||
v-if="selectedInterface"
|
||
:id="selectedInterface.id"
|
||
ref="MapServiceProviderRef"
|
||
@edit-map="handlerEditMap"
|
||
@row-click="rowClick"
|
||
/>
|
||
<div v-else class="empty-state">
|
||
<a-empty description="请选择左侧接口查看映射服务商列表" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧:嵌入"映射明细"(原编辑弹窗内容) -->
|
||
<div class="pane-body">
|
||
<EnteredMap
|
||
v-if="selectedInterface"
|
||
:key="`entered-map-${selectedInterface?.id}-${serviceProviderId}`"
|
||
ref="enteredMapRef"
|
||
class="h-full w-full"
|
||
:service-provider-id="serviceProviderId"
|
||
:interface-id="upStreamIdRef"
|
||
:service-provider-name="serviceProviderName"
|
||
@save-model-enter="saveModelEnter"
|
||
>
|
||
<template #toolbar_right>
|
||
<a-space :size="8">
|
||
<a-button size="small" @click="handleInterfaceDetailCancel">取消</a-button>
|
||
<a-button size="small" type="primary" @click="saveModelEnter">确定</a-button>
|
||
</a-space>
|
||
</template>
|
||
</EnteredMap>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</a-tab-pane>
|
||
|
||
<a-tab-pane key="debugger" title="API调试" :disabled="!MapServiceProviderROW">
|
||
<div class="api-debugger-wrapper">
|
||
<ApiDebugger
|
||
ref="apiDebuggerRef"
|
||
:selected-interface="selectedInterface"
|
||
:selected-service-provider="MapServiceProviderROW"
|
||
/>
|
||
</div>
|
||
</a-tab-pane>
|
||
<a-tab-pane key="detail" title="接口明细" :disabled="!selectedInterface">
|
||
<div class="mapping-split">
|
||
<div class="mapping-split-content">
|
||
<div class="pane-body">
|
||
<div class="pane-header">
|
||
<div class="pane-header-actions">
|
||
<a-space :size="8">
|
||
<a-button size="small" @click="handleInterfaceDetailCancel">取消</a-button>
|
||
<a-button size="small" type="primary" @click="interfaceConfigRef?.submit?.()">确定</a-button>
|
||
</a-space>
|
||
</div>
|
||
</div>
|
||
<div class="mapping-content">
|
||
<div v-if="selectedInterface" class="h-full w-full">
|
||
<InterfaceConfig
|
||
:key="`${selectedInterface?.id}-${detailRefreshKey}`"
|
||
ref="interfaceConfigRef"
|
||
:modal-mode="true"
|
||
:modal-id="selectedInterface?.id"
|
||
@saved="() => { /* 保留在当前tab,按需刷新左侧树 */ }"
|
||
/>
|
||
</div>
|
||
<div v-else class="empty-state">
|
||
<a-empty description="请选择左侧接口查看接口明细" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</a-tab-pane>
|
||
</a-tabs>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<ModalPro
|
||
v-model:visible="editVisible"
|
||
:width="1500"
|
||
:title="editId ? '修改上游接口' : '新增上游接口'"
|
||
unmount-on-close
|
||
:footer="false"
|
||
>
|
||
<InterfaceConfig
|
||
ref="modalForm"
|
||
:modal-mode="true"
|
||
:modal-id="editId"
|
||
@close="editVisible = false"
|
||
@saved="editVisible = false; tableRef?.reload()"
|
||
/>
|
||
<div class="modal-footer">
|
||
<a-space :size="16">
|
||
<a-button @click="editVisible = false">取消</a-button>
|
||
<a-button type="primary" @click="$refs.modalForm?.submit?.()">保存</a-button>
|
||
</a-space>
|
||
</div>
|
||
</ModalPro>
|
||
<ModalPro
|
||
@register="registerAddMap"
|
||
@ok="handleMappingSubmit"
|
||
@cancel="cancelCascader"
|
||
:width="1000"
|
||
:title="`新增映射 - ${mapName || ''}`"
|
||
>
|
||
<div class="mapping-modal-content">
|
||
<!-- 映射列表 -->
|
||
<div class="mapping-selector">
|
||
<div class="selector-tip">
|
||
<span class="tip-text">需要映射多个接口的,请注意排序</span>
|
||
</div>
|
||
|
||
<div class="mapping-list">
|
||
<div
|
||
v-for="(mapping, index) in mappingList"
|
||
:key="index"
|
||
class="mapping-item"
|
||
>
|
||
<span class="mapping-label">第{{ index + 1 }}个映射</span>
|
||
<a-cascader
|
||
v-model="mapping.value"
|
||
:options="getCascaderOptionsForIndex(index)"
|
||
:field-names="{ label: 'label', value: 'value', children: 'children' }"
|
||
placeholder="请选择服务商和接口"
|
||
:show-search="true"
|
||
:filter-option="filterCascaderOption"
|
||
:change-on-select="false"
|
||
style="flex: 1"
|
||
/>
|
||
<a-button
|
||
v-if="index === mappingList.length - 1"
|
||
type="text"
|
||
size="small"
|
||
class="action-icon-btn add-btn"
|
||
@click="addMapping"
|
||
title="添加映射"
|
||
>
|
||
+
|
||
</a-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</ModalPro>
|
||
<ModalPro title="映射服务商列表" :width="1200" @register="register">
|
||
<MapServiceProvider
|
||
:id="mapId"
|
||
ref="MapServiceProviderRef"
|
||
@edit-map="handlerEditMap"
|
||
@row-click="rowClick"
|
||
/>
|
||
</ModalPro>
|
||
|
||
<ModalPro
|
||
before-close
|
||
:width="1600"
|
||
:height="1600"
|
||
class="mapping-modal"
|
||
@register="registerEnter"
|
||
@ok="saveModelEnter"
|
||
@reset="() => {}"
|
||
>
|
||
|
||
<div >
|
||
|
||
<EnteredMap
|
||
ref="enteredMapRef"
|
||
|
||
class="h-full w-full"
|
||
:service-provider-id="serviceProviderId"
|
||
:interface-id="upStreamIdRef"
|
||
:service-provider-name="serviceProviderName"
|
||
@save-model-enter="saveModelEnter"
|
||
/>
|
||
</div>
|
||
|
||
</ModalPro>
|
||
</template>
|
||
|
||
<style scoped lang="less">
|
||
.interface-layout {
|
||
display: flex;
|
||
height: 100vh;
|
||
background-color: #ffffff; /* 改为白色,便于观察是否有空白 */
|
||
/* 避免页面层级滚动条出现/消失导致整体水平抖动 */
|
||
overflow: hidden;
|
||
scrollbar-gutter: stable both-edges;
|
||
/* 移除margin-left,使用flex布局 */
|
||
}
|
||
|
||
.left-sidebar {
|
||
width: 250px; /* 与下游接口页面保持一致 */
|
||
background-color: #fff;
|
||
border-right: 1px solid #e8e8e8; /* 只保留右边框,与mapping-split分隔 */
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex-shrink: 0; /* 禁止收缩 */
|
||
height: 100vh; /* 使用flex布局,不需要固定定位 */
|
||
}
|
||
|
||
.sidebar-header {
|
||
padding: 10px 12px !important; /* 与下游接口的 search-section 保持一致 */
|
||
border-bottom: 1px solid #e8e8e8;
|
||
min-height: 48px !important; /* 确保最小高度与下游接口对齐 */
|
||
display: flex !important;
|
||
align-items: center !important;
|
||
}
|
||
|
||
.search-box {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.search-actions {
|
||
display: flex;
|
||
gap: 4px;
|
||
}
|
||
|
||
.button-row {
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
.add-btn {
|
||
flex: 1;
|
||
}
|
||
|
||
.refresh-btn {
|
||
flex: 1;
|
||
}
|
||
|
||
.interface-tree {
|
||
flex: 1;
|
||
padding: 0;
|
||
overflow-y: auto;
|
||
|
||
// 隐藏树节点的文档图标 - 使用更精确的选择器
|
||
:deep(.arco-tree-node) {
|
||
.arco-tree-node-icon {
|
||
display: none !important;
|
||
}
|
||
|
||
.arco-tree-node-indent {
|
||
display: none !important;
|
||
}
|
||
|
||
.arco-tree-node-switcher {
|
||
display: none !important;
|
||
}
|
||
}
|
||
|
||
// 隐藏所有可能的图标元素
|
||
:deep(.arco-tree-node-icon),
|
||
:deep(.arco-tree-node-indent),
|
||
:deep(.arco-tree-node-switcher),
|
||
:deep(.arco-icon),
|
||
:deep(.arco-tree-node-title .arco-icon) {
|
||
display: none !important;
|
||
}
|
||
}
|
||
|
||
.tree-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 8px 16px;
|
||
margin-bottom: 8px;
|
||
background-color: #f8f9fa;
|
||
border-radius: 4px;
|
||
border: 1px solid #e8e8e8;
|
||
}
|
||
|
||
.tree-title {
|
||
display: flex;
|
||
align-items: center;
|
||
font-weight: 600;
|
||
color: #262626;
|
||
|
||
.arco-icon {
|
||
color: #8c8c8c;
|
||
}
|
||
}
|
||
|
||
.tree-actions {
|
||
display: flex;
|
||
gap: 4px;
|
||
}
|
||
|
||
.action-icon-btn {
|
||
width: 28px;
|
||
height: 28px;
|
||
padding: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #8c8c8c;
|
||
border: 1px solid transparent;
|
||
border-radius: 4px;
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
|
||
&:hover {
|
||
background-color: #f0f8ff;
|
||
border-color: #d6e4ff;
|
||
}
|
||
|
||
&.add-btn {
|
||
color: #2D8C8C !important;
|
||
background-color: #e6f7f7 !important;
|
||
border: 1px solid #2D8C8C !important;
|
||
border-radius: 4px !important;
|
||
|
||
&:hover {
|
||
color: #ffffff !important;
|
||
background-color: #2D8C8C !important;
|
||
border-color: #2D8C8C !important;
|
||
}
|
||
}
|
||
|
||
&.refresh-btn {
|
||
&:hover {
|
||
color: #2D8C8C;
|
||
}
|
||
}
|
||
}
|
||
|
||
.tree-node {
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
border: 1px solid transparent; /* 预占位,避免状态切换导致宽度变化 */
|
||
padding: 6px 8px; /* 固定内边距,避免hover/selected时变化 */
|
||
margin: 2px 0; /* 固定外边距 */
|
||
border-radius: 6px;
|
||
transition: background-color 0.2s ease, border-color 0.2s ease;
|
||
cursor: pointer;
|
||
|
||
&:hover {
|
||
background-color: #f0f8ff;
|
||
border-color: #d6e4ff; /* 仅改颜色,不改宽度 */
|
||
}
|
||
}
|
||
|
||
.tree-node.selected {
|
||
background-color: #e6f7f7 !important; /* 青色浅底 */
|
||
box-shadow: none !important;
|
||
border-color: transparent !important;
|
||
}
|
||
|
||
.node-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
table-layout: fixed;
|
||
}
|
||
|
||
.node-content-cell {
|
||
text-align: left;
|
||
padding: 0;
|
||
width: auto;
|
||
}
|
||
|
||
.node-code-cell {
|
||
text-align: left;
|
||
padding: 0;
|
||
width: auto;
|
||
padding-left: 20px; /* 与POST标签对齐 */
|
||
}
|
||
|
||
.node-actions-cell {
|
||
text-align: right;
|
||
padding: 0;
|
||
width: 30px;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.node-content {
|
||
display: flex;
|
||
align-items: center;
|
||
flex: 1;
|
||
gap: 8px;
|
||
}
|
||
|
||
.node-title {
|
||
font-size: 14px;
|
||
color: #262626;
|
||
}
|
||
|
||
.map-count {
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
color: #2D8C8C; /* 数字青色 */
|
||
padding: 0;
|
||
min-width: auto;
|
||
text-align: left;
|
||
|
||
.bracket {
|
||
color: #8c8c8c; /* 方括号灰色 */
|
||
}
|
||
.count-num {
|
||
color: #2D8C8C; /* 数字青色 */
|
||
}
|
||
}
|
||
|
||
.status-dot {
|
||
width: 6px;
|
||
height: 6px;
|
||
background-color: #00b42a;
|
||
border-radius: 50%;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.selected-dot {
|
||
width: 8px;
|
||
height: 8px;
|
||
background-color: #2D8C8C;
|
||
border-radius: 50%;
|
||
flex-shrink: 0;
|
||
margin-right: 6px;
|
||
display: inline-block;
|
||
}
|
||
|
||
.node-actions {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
opacity: 1;
|
||
}
|
||
|
||
.action-btn {
|
||
padding: 0;
|
||
min-width: 20px;
|
||
height: 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
:deep(.arco-icon) {
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
|
||
.node-number {
|
||
color: #8c8c8c;
|
||
font-size: 12px;
|
||
font-weight: normal;
|
||
margin-right: 8px;
|
||
display: inline-block;
|
||
min-width: 16px;
|
||
text-align: center;
|
||
}
|
||
|
||
.post-method {
|
||
color: #ff7d00;
|
||
font-weight: bold;
|
||
font-size: 10px;
|
||
margin-right: 6px;
|
||
display: inline-block;
|
||
background-color: transparent;
|
||
padding: 0;
|
||
border-radius: 0;
|
||
border: none;
|
||
}
|
||
|
||
.interface-code {
|
||
color: #8c8c8c;
|
||
font-size: 12px;
|
||
font-weight: normal;
|
||
display: inline-block;
|
||
}
|
||
|
||
.vertical-dots-icon {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 2px;
|
||
width: 6px;
|
||
height: 14px;
|
||
}
|
||
|
||
.vertical-dots-icon span {
|
||
width: 3px;
|
||
height: 3px;
|
||
background-color: #666;
|
||
border-radius: 50%;
|
||
display: block;
|
||
}
|
||
|
||
|
||
|
||
|
||
.content-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 10px 12px !important; /* 与下游接口保持一致 */
|
||
border-bottom: 1px solid #e8e8e8;
|
||
background-color: #fafafa;
|
||
border-radius: 4px 4px 0 0;
|
||
min-height: 48px !important; /* 确保最小高度与下游接口对齐 */
|
||
|
||
h3 {
|
||
margin: 0;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: #262626;
|
||
}
|
||
}
|
||
|
||
/* 新增:右侧拆分布局 */
|
||
.right-content-area {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background-color: #fff;
|
||
height: 100vh;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.content-tabs {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
}
|
||
|
||
.content-tabs-nav {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
|
||
:deep(.arco-tabs-nav) {
|
||
background-color: #f7f8fa;
|
||
border-bottom: 1px solid #e5e6eb;
|
||
margin: 0;
|
||
padding: 0 20px;
|
||
flex-shrink: 0;
|
||
min-height: 48px !important; /* 确保最小高度与下游接口对齐 */
|
||
display: flex !important;
|
||
align-items: center !important;
|
||
}
|
||
|
||
:deep(.arco-tabs-content) {
|
||
flex: 1;
|
||
padding: 0;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
}
|
||
|
||
:deep(.arco-tabs-pane) {
|
||
height: 100%;
|
||
overflow: hidden;
|
||
}
|
||
}
|
||
|
||
.api-debugger-wrapper {
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.mapping-split {
|
||
flex: 1;
|
||
display: flex;
|
||
gap: 0; /* 移除gap,让两个pane紧贴 */
|
||
padding: 0; /* 移除padding,让pane填满区域 */
|
||
margin: 0; /* 移除margin,确保没有空白区域 */
|
||
overflow: hidden;
|
||
}
|
||
|
||
.mapping-split-content {
|
||
flex: 1;
|
||
display: flex;
|
||
gap: 0; /* 确保没有gap */
|
||
padding: 0; /* 确保没有padding */
|
||
margin: 0; /* 确保没有margin */
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* 右侧内容区域占据剩余空间 */
|
||
.mapping-split-content > .pane-body {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: #fff;
|
||
border: none;
|
||
border-radius: 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* 左侧内容区域固定为与下游服务商列表一致的宽度(250px) */
|
||
.left-content {
|
||
flex: 0 0 250px;
|
||
max-width: 250px;
|
||
min-width: 250px;
|
||
flex-shrink: 0; /* 禁止收缩,避免左右抖动 */
|
||
gap: 0; /* 确保没有gap */
|
||
padding: 0; /* 确保没有padding */
|
||
margin: 0; /* 确保没有margin */
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: #fff;
|
||
border: none;
|
||
border-radius: 0;
|
||
overflow: hidden;
|
||
}
|
||
.pane-header {
|
||
padding: 10px 12px !important; /* 与 steps-bar 保持一致 */
|
||
border-bottom: 1px solid #e8e8e8;
|
||
background: #fafafa;
|
||
font-weight: 600;
|
||
color: #262626;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
min-height: 48px !important; /* 确保最小高度与下游接口对齐 */
|
||
}
|
||
.pane-header .search-box { display: flex; align-items: center; gap: 8px; }
|
||
.pane-header .search-actions { display: flex; gap: 4px; }
|
||
.pane-header-actions { margin-left: auto; display: flex; }
|
||
.pane-header :deep(.arco-input-wrapper) { height: 28px !important; }
|
||
.pane-header-actions :deep(.arco-btn) { height: 28px !important; padding: 0 10px; }
|
||
.action-icon-btn { width: 28px; height: 28px !important; padding: 0; display: flex; align-items: center; justify-content: center; color: #8c8c8c; border: 1px solid transparent; border-radius: 4px; font-size: 16px; font-weight: bold; }
|
||
.action-icon-btn.add-btn { color: #2D8C8C !important; background-color: #e6f7f7 !important; border: 1px solid #2D8C8C !important; border-radius: 4px !important; }
|
||
.action-icon-btn.add-btn:hover { color: #ffffff !important; background-color: #2D8C8C !important; border-color: #2D8C8C !important; }
|
||
.pane-body {
|
||
flex: 1;
|
||
display: flex; /* 让 empty-state 能占满高度以便垂直居中 */
|
||
flex-direction: column;
|
||
padding: 6px 0; /* 左右改为 0,由子项控制 2px 外边距 */
|
||
overflow: auto; /* 固定内部滚动条 */
|
||
scrollbar-gutter: stable both-edges; /* 出现/消失不改变布局宽度 */
|
||
min-height: 0; /* 防止子元素撑开引发父容器高度变化 */
|
||
}
|
||
.pane-footer {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
padding: 8px 12px;
|
||
border-top: 1px solid #e8e8e8;
|
||
background: #fff;
|
||
}
|
||
/* 右下角悬浮按钮样式 */
|
||
.floating-actions { position: sticky; top: 8px; display: flex; justify-content: flex-end; pointer-events: none; z-index: 2; }
|
||
.floating-actions.fixed { position: absolute; top: 8px; right: 8px; }
|
||
.floating-actions :deep(.arco-space) {
|
||
pointer-events: auto; /* 只让按钮可点 */
|
||
background: #ffffffcc;
|
||
backdrop-filter: blur(2px);
|
||
padding: 6px 8px;
|
||
border-radius: 6px;
|
||
border: 1px solid #e8e8e8;
|
||
}
|
||
|
||
.mapping-content {
|
||
flex: 1;
|
||
padding: 8px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.empty-state {
|
||
flex: 1; /* 占满父容器剩余空间 */
|
||
min-height: 0; /* 防止高度塌陷 */
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 100%; /* 确保占满宽度 */
|
||
|
||
:deep(.arco-empty) {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
}
|
||
|
||
.loading-state {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 120px;
|
||
color: #666;
|
||
|
||
p {
|
||
margin-top: 8px;
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
|
||
// 新增映射弹窗样式
|
||
.mapping-modal-content {
|
||
padding: 0;
|
||
}
|
||
|
||
.mapping-selector {
|
||
padding: 20px;
|
||
|
||
// 强制设置弹窗内按钮为正方形
|
||
:deep(.arco-btn) {
|
||
width: 28px !important;
|
||
height: 28px !important;
|
||
min-width: 28px !important;
|
||
max-width: 28px !important;
|
||
padding: 0 !important;
|
||
}
|
||
}
|
||
|
||
.selector-tip {
|
||
margin-bottom: 20px;
|
||
|
||
.tip-text {
|
||
color: #ff7800;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
|
||
.mapping-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
}
|
||
|
||
.mapping-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
|
||
.mapping-label {
|
||
font-size: 14px;
|
||
color: #262626;
|
||
min-width: 80px;
|
||
}
|
||
|
||
:deep(.action-icon-btn) {
|
||
width: 28px !important;
|
||
height: 28px !important;
|
||
min-width: 28px !important;
|
||
max-width: 28px !important;
|
||
padding: 0 !important;
|
||
display: flex !important;
|
||
align-items: center !important;
|
||
justify-content: center !important;
|
||
color: #8c8c8c !important;
|
||
border: 1px solid transparent !important;
|
||
border-radius: 4px !important;
|
||
font-size: 16px !important;
|
||
font-weight: bold !important;
|
||
}
|
||
|
||
:deep(.action-icon-btn.add-btn) {
|
||
color: #2D8C8C !important;
|
||
background-color: #e6f7f7 !important;
|
||
border: 1px solid #2D8C8C !important;
|
||
border-radius: 4px !important;
|
||
}
|
||
|
||
:deep(.action-icon-btn.add-btn:hover) {
|
||
color: #ffffff !important;
|
||
background-color: #2D8C8C !important;
|
||
border-color: #2D8C8C !important;
|
||
}
|
||
}
|
||
|
||
.mapping-tip {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.mapping-search {
|
||
margin-bottom: 20px;
|
||
padding: 16px;
|
||
background-color: #fafafa;
|
||
border-radius: 6px;
|
||
border: 1px solid #e8e8e8;
|
||
}
|
||
|
||
.mapping-cascader {
|
||
border: 1px solid #e8e8e8;
|
||
border-radius: 6px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.cascader-header {
|
||
padding: 12px 16px;
|
||
background-color: #f5f5f5;
|
||
border-bottom: 1px solid #e8e8e8;
|
||
|
||
h4 {
|
||
margin: 0 0 4px 0;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: #262626;
|
||
}
|
||
|
||
.cascader-desc {
|
||
font-size: 12px;
|
||
color: #8c8c8c;
|
||
}
|
||
}
|
||
|
||
.cascader-content {
|
||
min-height: 300px;
|
||
max-height: 400px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.cascader-empty {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 200px;
|
||
|
||
:deep(.arco-empty) {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
}
|
||
|
||
.span-style1 {
|
||
font-size: 17px;
|
||
font-weight: 700;
|
||
color: #222;
|
||
}
|
||
|
||
.query-box {
|
||
padding: 12px 16px;
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.table-box {
|
||
padding: 0 16px;
|
||
border-radius: 2px;
|
||
}
|
||
|
||
:deep(.vxe-table--header) {
|
||
background-color: #f2f3f5;
|
||
font-weight: bold;
|
||
display: table-header-group !important;
|
||
}
|
||
|
||
// :deep(.vxe-header--column) {
|
||
// height: 48px;
|
||
// padding: 8px;
|
||
// }
|
||
|
||
:deep(.mapping-modal) {
|
||
.arco-modal-body {
|
||
height: 1500px !important;
|
||
max-height: 1500px !important;
|
||
padding: 0 !important;
|
||
}
|
||
|
||
.arco-modal {
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.arco-modal-header {
|
||
padding: 16px 20px;
|
||
border-bottom: 1px solid #e8e8e8;
|
||
}
|
||
|
||
.arco-modal-footer {
|
||
padding: 12px 20px;
|
||
border-top: 1px solid #e8e8e8;
|
||
}
|
||
}
|
||
|
||
/* toolbar spacing and control sizes */
|
||
:deep(.toolbarBtn .arco-btn) {
|
||
height: 28px;
|
||
line-height: 26px;
|
||
padding: 0 10px;
|
||
margin-left: 2px;
|
||
}
|
||
|
||
/* remove outer rectangular wrapper of search (form inline) */
|
||
:deep(.arco-form-item-label-col) {
|
||
display: none !important;
|
||
}
|
||
:deep(.arco-form-item) { margin: 0 8px 0 0; }
|
||
:deep(.arco-input-wrapper) {
|
||
height: 28px;
|
||
}
|
||
:deep(.arco-form-item-content-wrapper) {
|
||
padding-right: 0 !important;
|
||
padding-left: 0 !important;
|
||
margin: 0 !important;
|
||
background: transparent !important;
|
||
border: none !important;
|
||
box-shadow: none !important;
|
||
outline: none !important;
|
||
}
|
||
:deep(.arco-form-item-content) { margin-right: 0; }
|
||
|
||
/* kill double-layer look: remove any outer box/background around inline form items */
|
||
:deep(.arco-form-inline) {
|
||
background: transparent !important;
|
||
border: 0 !important;
|
||
}
|
||
:deep(.vxe-toolbar .arco-form) {
|
||
background: transparent !important;
|
||
border: none !important;
|
||
box-shadow: none !important;
|
||
}
|
||
/* override inline paddings/margins added by arco row */
|
||
:deep(.vxe-toolbar .arco-row[style]) {
|
||
padding-left: 0 !important;
|
||
padding-right: 0 !important;
|
||
margin-left: 0 !important;
|
||
margin-right: 0 !important;
|
||
}
|
||
:deep(.vxe-toolbar .arco-form[style]) {
|
||
padding-left: 0 !important;
|
||
padding-right: 0 !important;
|
||
margin-left: 0 !important;
|
||
margin-right: 0 !important;
|
||
border: none !important;
|
||
box-shadow: none !important;
|
||
background: transparent !important;
|
||
}
|
||
/* remove the extra rounded rectangle on form item content */
|
||
:deep(.vxe-toolbar .arco-form-item-content),
|
||
:deep(.vxe-toolbar .arco-form-item-content-flex) {
|
||
background: transparent !important;
|
||
border: none !important;
|
||
box-shadow: none !important;
|
||
outline: none !important;
|
||
}
|
||
:deep(.arco-form-inline .arco-form-item) {
|
||
background: transparent !important;
|
||
border: 0 !important;
|
||
padding: 0 !important;
|
||
}
|
||
:deep(.arco-form-item-content) {
|
||
background: transparent !important;
|
||
border: none !important;
|
||
box-shadow: none !important;
|
||
}
|
||
/* remove input focus halo so only一个边框可见 */
|
||
:deep(.arco-input-wrapper.arco-input-focus),
|
||
:deep(.arco-input-wrapper:hover) {
|
||
box-shadow: none !important;
|
||
}
|
||
:deep(.arco-input) { outline: none !important; }
|
||
|
||
.modal-footer {
|
||
margin-top: 8px;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
padding: 6px 0 0 0;
|
||
}
|
||
</style>
|