feat: 服务商公共参数配置并回落到接口明细
All checks were successful
Build and Deploy Front / deploy (push) Successful in 6m38s
All checks were successful
Build and Deploy Front / deploy (push) Successful in 6m38s
新增服务商级公共参数入口与弹窗,按位置只读落入 Query/Header/Body,并完善授权入参与调试页按钮样式。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
a0fea7d001
commit
a5ef7e542d
@ -1955,7 +1955,6 @@
|
||||
</a-button>
|
||||
<a-button
|
||||
size="small"
|
||||
type="primary"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
@click="sendRequest"
|
||||
|
||||
@ -416,7 +416,7 @@
|
||||
>
|
||||
<a-dropdown
|
||||
trigger="click"
|
||||
:popup-max-height="250"
|
||||
:popup-max-height="false"
|
||||
@select="handleActionSelect"
|
||||
>
|
||||
<a-button
|
||||
@ -460,7 +460,7 @@
|
||||
</span>
|
||||
<a-dropdown
|
||||
trigger="click"
|
||||
:popup-max-height="250"
|
||||
:popup-max-height="false"
|
||||
@select="handleActionSelect"
|
||||
>
|
||||
<a-button
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
buildSmartFillResult,
|
||||
} from '@/utils/curlToInterfaceFill';
|
||||
import { useTabRowCounts } from '@/utils/useTabRowCounts';
|
||||
import { FormKvPlaceholderOptions, ParameterType } from '@/constants/itfxEnums';
|
||||
import { FormKvPlaceholderOptions, ParameterType, FieldPosition } from '@/constants/itfxEnums';
|
||||
import {
|
||||
flattenTreeTableRows,
|
||||
getTreeTableFlatRows,
|
||||
@ -440,6 +440,7 @@
|
||||
function validateKvParamRows(rows: any[], label: string): string | null {
|
||||
const seen = new Set<string>();
|
||||
for (const row of rows || []) {
|
||||
if (isCommonParamRow(row)) continue;
|
||||
const name = String(row?.name ?? '').trim();
|
||||
if (!name) return `${label} 存在未填写参数名的行,请补全或删除空行`;
|
||||
const key = name.toLowerCase();
|
||||
@ -583,6 +584,138 @@
|
||||
() => props.showQuery && !isDownstreamMode.value,
|
||||
);
|
||||
const showHeaderTab = computed(() => isDownstreamMode.value && props.showQuery);
|
||||
|
||||
/** 下游:服务商公共参数按位置回落到 Query/Header/Body(只读置灰) */
|
||||
const inheritedCommonParams = ref<any[]>([]);
|
||||
const inheritedCommonParamsLoading = ref(false);
|
||||
|
||||
function normalizePositionList(row: any): number[] {
|
||||
const list = row?.fieldPositionList;
|
||||
if (Array.isArray(list) && list.length) {
|
||||
return list.map((x: any) => Number(x)).filter((n: number) => Number.isFinite(n));
|
||||
}
|
||||
const fp = row?.fieldPositions;
|
||||
if (typeof fp === 'string' && fp.trim()) {
|
||||
return fp
|
||||
.split(',')
|
||||
.map((x) => Number(x.trim()))
|
||||
.filter((n) => Number.isFinite(n));
|
||||
}
|
||||
if (Array.isArray(fp)) {
|
||||
return fp.map((x: any) => Number(x)).filter((n: number) => Number.isFinite(n));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function commonParamsForPosition(position: number) {
|
||||
return inheritedCommonParams.value.filter((row) =>
|
||||
normalizePositionList(row).includes(position),
|
||||
);
|
||||
}
|
||||
|
||||
const inheritedQueryParams = computed(() =>
|
||||
isDownstreamMode.value ? commonParamsForPosition(FieldPosition.Query) : [],
|
||||
);
|
||||
const inheritedHeaderParams = computed(() =>
|
||||
isDownstreamMode.value ? commonParamsForPosition(FieldPosition.Header) : [],
|
||||
);
|
||||
const inheritedBodyParams = computed(() =>
|
||||
isDownstreamMode.value ? commonParamsForPosition(FieldPosition.Body) : [],
|
||||
);
|
||||
|
||||
function isCommonParamRow(row: any) {
|
||||
return !!row?.__fromCommonParams;
|
||||
}
|
||||
|
||||
function stripCommonRows<T extends Record<string, any>>(rows: T[] | undefined | null): T[] {
|
||||
return (Array.isArray(rows) ? rows : []).filter((r) => !isCommonParamRow(r));
|
||||
}
|
||||
|
||||
function filterCommonFromActionRows(actions: any) {
|
||||
const filterRows = (arr: any[]) =>
|
||||
(Array.isArray(arr) ? arr : []).filter((r) => !isCommonParamRow(r));
|
||||
return {
|
||||
insertRecords: filterRows(actions?.insertRecords),
|
||||
removeRecords: filterRows(actions?.removeRecords),
|
||||
updateRecords: filterRows(actions?.updateRecords),
|
||||
};
|
||||
}
|
||||
|
||||
function toCommonKvRows(list: any[]) {
|
||||
return (list || []).map((row, idx) => ({
|
||||
__fromCommonParams: true,
|
||||
disableEdit: true,
|
||||
id: `common-kv-${row.id ?? idx}`,
|
||||
name: row.fieldName || '',
|
||||
value: row.fieldValue || '',
|
||||
description: row.description || '公共参数',
|
||||
__commonParamId: row.id,
|
||||
}));
|
||||
}
|
||||
|
||||
function mergeCommonKvRows(ownRows: any[] | undefined, commonList: any[]) {
|
||||
return [...toCommonKvRows(commonList), ...stripCommonRows(ownRows)];
|
||||
}
|
||||
|
||||
async function applyKvTableWithCommon(
|
||||
tableProps: { data: any[] },
|
||||
tableRef: { value?: { reloadData?: (rows: any[]) => any } },
|
||||
ownRows: any[] | undefined,
|
||||
commonList: any[],
|
||||
) {
|
||||
const next = mergeCommonKvRows(ownRows, commonList);
|
||||
tableProps.data = next;
|
||||
await nextTick();
|
||||
tableRef.value?.reloadData?.(next);
|
||||
}
|
||||
|
||||
async function remergeInheritedCommonIntoKvTables() {
|
||||
if (!isDownstreamMode.value) return;
|
||||
await applyKvTableWithCommon(
|
||||
queryTableProps,
|
||||
queryTableRef,
|
||||
stripCommonRows(queryTableProps.data),
|
||||
inheritedQueryParams.value,
|
||||
);
|
||||
if (showHeaderTab.value) {
|
||||
await applyKvTableWithCommon(
|
||||
headerTableProps,
|
||||
headerTableRef,
|
||||
stripCommonRows(headerTableProps.data),
|
||||
inheritedHeaderParams.value,
|
||||
);
|
||||
}
|
||||
await applyKvTableWithCommon(
|
||||
bodyFormTableProps,
|
||||
bodyFormTableRef,
|
||||
stripCommonRows(bodyFormTableProps.data),
|
||||
inheritedBodyParams.value,
|
||||
);
|
||||
refreshTabCounts();
|
||||
}
|
||||
|
||||
async function refreshInheritedCommonParams() {
|
||||
const spId = Number(props.serviceProviderId);
|
||||
if (!isDownstreamMode.value || !Number.isFinite(spId) || spId <= 0) {
|
||||
inheritedCommonParams.value = [];
|
||||
await remergeInheritedCommonIntoKvTables();
|
||||
return;
|
||||
}
|
||||
inheritedCommonParamsLoading.value = true;
|
||||
try {
|
||||
const res: any = await getFixedParameterGetFixedParameterList({
|
||||
serviceProviderId: spId,
|
||||
});
|
||||
const data = res?.data || res || [];
|
||||
inheritedCommonParams.value = Array.isArray(data) ? data : [];
|
||||
} catch {
|
||||
inheritedCommonParams.value = [];
|
||||
} finally {
|
||||
inheritedCommonParamsLoading.value = false;
|
||||
}
|
||||
await remergeInheritedCommonIntoKvTables();
|
||||
}
|
||||
|
||||
const isNoneBodyContentType = computed(
|
||||
() => isDownstreamMode.value && isNoneContentType(props.basicFormData?.contentType),
|
||||
);
|
||||
@ -992,7 +1125,9 @@
|
||||
mode: 'row',
|
||||
showStatus: true,
|
||||
autoClear: false,
|
||||
beforeEditMethod: ({ row }: { row: any }) => !isCommonParamRow(row),
|
||||
},
|
||||
rowClassName: ({ row }: { row: any }) => (isCommonParamRow(row) ? 'row-common-param' : ''),
|
||||
},
|
||||
showIndex: false,
|
||||
data: [] as any[],
|
||||
@ -1017,6 +1152,14 @@
|
||||
data: [] as any[],
|
||||
});
|
||||
|
||||
watch(
|
||||
() => [props.serviceProviderId, props.parameterMode] as const,
|
||||
() => {
|
||||
refreshInheritedCommonParams();
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// Query 固定配置表格(不传 height,随内容自然增高,与 Query 列表的固定高度区分)
|
||||
const queryFixedTableProps = computed(() => ({
|
||||
columns: [
|
||||
@ -1327,11 +1470,17 @@
|
||||
|
||||
const canClearCurrentRequestTab = computed(() => {
|
||||
if (!showRequestTabClearAction.value) return false;
|
||||
if (requestTab.value === 'query') return queryTabCount.value > 0;
|
||||
if (requestTab.value === 'header') return headerTabCount.value > 0;
|
||||
if (requestTab.value === 'query') {
|
||||
return stripCommonRows(getTableFullData(queryTableRef, queryTableProps.data)).length > 0;
|
||||
}
|
||||
if (requestTab.value === 'header') {
|
||||
return stripCommonRows(getTableFullData(headerTableRef, headerTableProps.data)).length > 0;
|
||||
}
|
||||
if (requestTab.value === 'fixed') return fixedConfigTabCount.value > 0;
|
||||
if (requestTab.value === 'body') {
|
||||
if (isBodyKvMode.value) return !isBodyKvEmpty.value;
|
||||
if (isBodyKvMode.value) {
|
||||
return stripCommonRows(getTableFullData(bodyFormTableRef, bodyFormTableProps.data)).length > 0;
|
||||
}
|
||||
return !isBodyTreeEmpty.value;
|
||||
}
|
||||
if (requestTab.value === 'mappingBody') return !isMappingBodyEmpty.value;
|
||||
@ -1339,48 +1488,65 @@
|
||||
return false;
|
||||
});
|
||||
|
||||
// 监听 queryParams prop 变化,同步到表格数据
|
||||
// 监听 queryParams prop 变化,同步到表格数据(并合并公共参数)
|
||||
watch(
|
||||
() => props.queryParams,
|
||||
(newVal: any) => {
|
||||
if (newVal && Array.isArray(newVal)) {
|
||||
// 只在数据真正变化时才更新,避免循环
|
||||
const currentData = queryTableProps.data || [];
|
||||
if (currentData.length !== newVal.length || JSON.stringify(currentData) !== JSON.stringify(newVal)) {
|
||||
queryTableProps.data = [...newVal] as any[];
|
||||
if (queryTableRef.value) {
|
||||
queryTableRef.value.reloadData([...newVal]);
|
||||
}
|
||||
}
|
||||
async (newVal: any) => {
|
||||
if (!newVal || !Array.isArray(newVal)) return;
|
||||
const own = stripCommonRows(newVal);
|
||||
const currentOwn = stripCommonRows(queryTableProps.data || []);
|
||||
if (
|
||||
currentOwn.length !== own.length
|
||||
|| JSON.stringify(currentOwn) !== JSON.stringify(own)
|
||||
) {
|
||||
await applyKvTableWithCommon(
|
||||
queryTableProps,
|
||||
queryTableRef,
|
||||
own,
|
||||
inheritedQueryParams.value,
|
||||
);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
function syncKvTableProps(
|
||||
propList: any[] | undefined,
|
||||
tableProps: { data: any[] },
|
||||
tableRef: typeof queryTableRef,
|
||||
commonList: any[],
|
||||
) {
|
||||
if (!propList || !Array.isArray(propList)) return;
|
||||
const currentData = tableProps.data || [];
|
||||
const own = stripCommonRows(propList);
|
||||
const currentOwn = stripCommonRows(tableProps.data || []);
|
||||
if (
|
||||
currentData.length !== propList.length
|
||||
|| JSON.stringify(currentData) !== JSON.stringify(propList)
|
||||
currentOwn.length !== own.length
|
||||
|| JSON.stringify(currentOwn) !== JSON.stringify(own)
|
||||
) {
|
||||
tableProps.data = [...propList] as any[];
|
||||
tableRef.value?.reloadData?.([...propList]);
|
||||
applyKvTableWithCommon(tableProps, tableRef, own, commonList);
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.headerParams,
|
||||
(newVal) => syncKvTableProps(newVal as any[], headerTableProps, headerTableRef),
|
||||
(newVal) =>
|
||||
syncKvTableProps(
|
||||
newVal as any[],
|
||||
headerTableProps,
|
||||
headerTableRef,
|
||||
inheritedHeaderParams.value,
|
||||
),
|
||||
{ immediate: true },
|
||||
);
|
||||
watch(
|
||||
() => props.bodyFormParams,
|
||||
(newVal) => syncKvTableProps(newVal as any[], bodyFormTableProps, bodyFormTableRef),
|
||||
(newVal) =>
|
||||
syncKvTableProps(
|
||||
newVal as any[],
|
||||
bodyFormTableProps,
|
||||
bodyFormTableRef,
|
||||
inheritedBodyParams.value,
|
||||
),
|
||||
{ immediate: true },
|
||||
);
|
||||
watch(
|
||||
@ -1839,13 +2005,13 @@
|
||||
tableRef: any,
|
||||
keepRow?: (row: any) => boolean,
|
||||
) {
|
||||
const roots = [...(getTableFullData(tableRef) || [])];
|
||||
const roots = [...(getTableFullData(tableRef) || [])].filter((r) => !isCommonParamRow(r));
|
||||
if (!keepRow) return roots;
|
||||
const toRemove: any[] = [];
|
||||
roots.forEach((row) => {
|
||||
if (keepRow(row)) {
|
||||
if (Array.isArray(row?.children) && row.children.length) {
|
||||
toRemove.push(...row.children);
|
||||
toRemove.push(...row.children.filter((c: any) => !isCommonParamRow(c)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1858,17 +2024,32 @@
|
||||
const tab = requestTab.value;
|
||||
if (tab === 'query') {
|
||||
await removeTableRows(queryTableRef, collectRemovableTableRows(queryTableRef));
|
||||
queryTableProps.data = [];
|
||||
await applyKvTableWithCommon(
|
||||
queryTableProps,
|
||||
queryTableRef,
|
||||
[],
|
||||
inheritedQueryParams.value,
|
||||
);
|
||||
} else if (tab === 'header') {
|
||||
await removeTableRows(headerTableRef, collectRemovableTableRows(headerTableRef));
|
||||
headerTableProps.data = [];
|
||||
await applyKvTableWithCommon(
|
||||
headerTableProps,
|
||||
headerTableRef,
|
||||
[],
|
||||
inheritedHeaderParams.value,
|
||||
);
|
||||
} else if (tab === 'fixed') {
|
||||
await removeTableRows(queryFixedTableRef, collectRemovableTableRows(queryFixedTableRef));
|
||||
fixedParams.value = [];
|
||||
fixedParamsHasChanges.value = true;
|
||||
} else if (tab === 'body' && isBodyKvMode.value) {
|
||||
await removeTableRows(bodyFormTableRef, collectRemovableTableRows(bodyFormTableRef));
|
||||
bodyFormTableProps.data = [];
|
||||
await applyKvTableWithCommon(
|
||||
bodyFormTableProps,
|
||||
bodyFormTableRef,
|
||||
[],
|
||||
inheritedBodyParams.value,
|
||||
);
|
||||
} else if (tab === 'body' && !isNoneBodyContentType.value) {
|
||||
if (hoistedBodyArrayWrapper.value) {
|
||||
const persisted = getRequestBodyFlatParams();
|
||||
@ -1941,6 +2122,7 @@
|
||||
|
||||
// 删除 Query 参数行
|
||||
async function deleteQueryRow(row: any) {
|
||||
if (isCommonParamRow(row)) return;
|
||||
markDirty();
|
||||
await queryTableRef.value?.removeRow(row);
|
||||
refreshTabCounts();
|
||||
@ -1955,6 +2137,7 @@
|
||||
}
|
||||
|
||||
async function deleteHeaderRow(row: any) {
|
||||
if (isCommonParamRow(row)) return;
|
||||
markDirty();
|
||||
await headerTableRef.value?.removeRow(row);
|
||||
refreshTabCounts();
|
||||
@ -1969,6 +2152,7 @@
|
||||
}
|
||||
|
||||
async function deleteBodyFormRow(row: any) {
|
||||
if (isCommonParamRow(row)) return;
|
||||
markDirty();
|
||||
await bodyFormTableRef.value?.removeRow(row);
|
||||
refreshTabCounts();
|
||||
@ -2922,10 +3106,9 @@
|
||||
tableProps: { data: any[] },
|
||||
tableRef: { value?: { reloadData?: (rows: any[]) => void } },
|
||||
rows: any[],
|
||||
commonList: any[] = [],
|
||||
) {
|
||||
tableProps.data = rows;
|
||||
await nextTick();
|
||||
tableRef.value?.reloadData?.(rows);
|
||||
await applyKvTableWithCommon(tableProps, tableRef, rows, commonList);
|
||||
}
|
||||
|
||||
async function loadFlatListIntoTreeTable(
|
||||
@ -3022,11 +3205,26 @@
|
||||
await nextTick();
|
||||
refBasicForm.value?.setFormValue?.(nextBasic);
|
||||
|
||||
await reloadKvTable(queryTableProps, queryTableRef, payload.queryParams);
|
||||
await reloadKvTable(
|
||||
queryTableProps,
|
||||
queryTableRef,
|
||||
payload.queryParams,
|
||||
inheritedQueryParams.value,
|
||||
);
|
||||
|
||||
if (isDownstreamMode.value) {
|
||||
await reloadKvTable(headerTableProps, headerTableRef, payload.headerParams ?? []);
|
||||
await reloadKvTable(bodyFormTableProps, bodyFormTableRef, isForm ? payload.bodyFormParams : []);
|
||||
await reloadKvTable(
|
||||
headerTableProps,
|
||||
headerTableRef,
|
||||
payload.headerParams ?? [],
|
||||
inheritedHeaderParams.value,
|
||||
);
|
||||
await reloadKvTable(
|
||||
bodyFormTableProps,
|
||||
bodyFormTableRef,
|
||||
isForm ? payload.bodyFormParams : [],
|
||||
inheritedBodyParams.value,
|
||||
);
|
||||
if (!isForm && !isNone) {
|
||||
mappingBodyTableProps.data = [];
|
||||
await nextTick();
|
||||
@ -3197,20 +3395,27 @@
|
||||
validateDetailParamsBeforeSave,
|
||||
captureDirtyBaseline,
|
||||
markDirty,
|
||||
refreshInheritedCommonParams,
|
||||
isDirty: () => isDirty.value,
|
||||
getSaveSnapshot: (): InterfaceDetailSnapshot => ({
|
||||
queryParams: queryTableRef.value?.getTableData?.()?.fullData
|
||||
queryParams: stripCommonRows(
|
||||
queryTableRef.value?.getTableData?.()?.fullData
|
||||
|| queryTableRef.value?.xGrid?.getTableData()?.fullData
|
||||
|| queryTableProps.data
|
||||
|| [],
|
||||
headerParams: headerTableRef.value?.getTableData?.()?.fullData
|
||||
),
|
||||
headerParams: stripCommonRows(
|
||||
headerTableRef.value?.getTableData?.()?.fullData
|
||||
|| headerTableRef.value?.xGrid?.getTableData()?.fullData
|
||||
|| headerTableProps.data
|
||||
|| [],
|
||||
bodyFormParams: bodyFormTableRef.value?.getTableData?.()?.fullData
|
||||
),
|
||||
bodyFormParams: stripCommonRows(
|
||||
bodyFormTableRef.value?.getTableData?.()?.fullData
|
||||
|| bodyFormTableRef.value?.xGrid?.getTableData()?.fullData
|
||||
|| bodyFormTableProps.data
|
||||
|| [],
|
||||
),
|
||||
requestParams: getRequestBodyFlatParams(),
|
||||
mappingBodyParams: getTreeTableFlatRows(
|
||||
mappingBodyTableRef.value?.getTableData?.()?.fullData
|
||||
@ -3221,9 +3426,9 @@
|
||||
|| responseTableRef.value?.xGrid?.getTableData()?.fullData
|
||||
|| responseTableProps.data
|
||||
|| [],
|
||||
queryActionRows: queryTableRef.value?.getActionRows?.() || { insertRecords: [], removeRecords: [], updateRecords: [] },
|
||||
headerActionRows: headerTableRef.value?.getActionRows?.() || { insertRecords: [], removeRecords: [], updateRecords: [] },
|
||||
bodyFormActionRows: bodyFormTableRef.value?.getActionRows?.() || { insertRecords: [], removeRecords: [], updateRecords: [] },
|
||||
queryActionRows: filterCommonFromActionRows(queryTableRef.value?.getActionRows?.()),
|
||||
headerActionRows: filterCommonFromActionRows(headerTableRef.value?.getActionRows?.()),
|
||||
bodyFormActionRows: filterCommonFromActionRows(bodyFormTableRef.value?.getActionRows?.()),
|
||||
requestActionRows: stripBodyRootFromActionRows(
|
||||
requestTableRef.value?.getActionRows?.() || {
|
||||
insertRecords: [],
|
||||
@ -3472,7 +3677,10 @@
|
||||
placeholder="请输入参数名"
|
||||
/>
|
||||
</template>
|
||||
<span v-else>{{ row.name || '-' }}</span>
|
||||
<span v-else class="kv-name-cell">
|
||||
{{ row.name || '-' }}
|
||||
<span v-if="isCommonParamRow(row)" class="common-param-tag">公共</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #name_edit="{ row }">
|
||||
@ -3540,13 +3748,14 @@
|
||||
</template>
|
||||
|
||||
<template #action="{ row }">
|
||||
<a-space>
|
||||
<a-space v-if="!isCommonParamRow(row)">
|
||||
<a-popconfirm content="确定删除该参数?" @ok="deleteQueryRow(row)">
|
||||
<a-button type="text" class="row-action-btn">
|
||||
<IconDelete />
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
<span v-else class="common-param-action">—</span>
|
||||
</template>
|
||||
</TablePro>
|
||||
</div>
|
||||
@ -3640,7 +3849,10 @@
|
||||
>
|
||||
<template #name="{ row }">
|
||||
<a-input v-if="isHeaderRowEditing(row)" v-model="row.name" allow-clear placeholder="请输入参数名" />
|
||||
<span v-else>{{ row.name || '-' }}</span>
|
||||
<span v-else class="kv-name-cell">
|
||||
{{ row.name || '-' }}
|
||||
<span v-if="isCommonParamRow(row)" class="common-param-tag">公共</span>
|
||||
</span>
|
||||
</template>
|
||||
<template #name_edit="{ row }">
|
||||
<a-input v-model="row.name" allow-clear placeholder="请输入参数名" />
|
||||
@ -3671,11 +3883,16 @@
|
||||
<a-input v-model="row.description" allow-clear placeholder="请输入描述" />
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<a-popconfirm content="确定删除该参数?" @ok="deleteHeaderRow(row)">
|
||||
<a-popconfirm
|
||||
v-if="!isCommonParamRow(row)"
|
||||
content="确定删除该参数?"
|
||||
@ok="deleteHeaderRow(row)"
|
||||
>
|
||||
<a-button type="text" class="row-action-btn">
|
||||
<IconDelete />
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
<span v-else class="common-param-action">—</span>
|
||||
</template>
|
||||
</TablePro>
|
||||
</div>
|
||||
@ -3687,7 +3904,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Body KV(FormUrlEncoded) -->
|
||||
<div v-show="requestTab === 'body' && isBodyKvMode" class="table-content">
|
||||
<div v-show="requestTab === 'body' && isBodyKvMode" class="table-content body-kv-pane">
|
||||
<TablePro
|
||||
ref="bodyFormTableRef"
|
||||
v-bind="bodyFormTableProps"
|
||||
@ -3696,7 +3913,10 @@
|
||||
>
|
||||
<template #name="{ row }">
|
||||
<a-input v-if="isBodyFormRowEditing(row)" v-model="row.name" allow-clear placeholder="参数名" />
|
||||
<span v-else>{{ row.name || '-' }}</span>
|
||||
<span v-else class="kv-name-cell">
|
||||
{{ row.name || '-' }}
|
||||
<span v-if="isCommonParamRow(row)" class="common-param-tag">公共</span>
|
||||
</span>
|
||||
</template>
|
||||
<template #name_edit="{ row }">
|
||||
<a-input v-model="row.name" allow-clear placeholder="参数名" />
|
||||
@ -3727,11 +3947,16 @@
|
||||
<a-input v-model="row.description" allow-clear />
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<a-popconfirm content="确定删除该参数?" @ok="deleteBodyFormRow(row)">
|
||||
<a-popconfirm
|
||||
v-if="!isCommonParamRow(row)"
|
||||
content="确定删除该参数?"
|
||||
@ok="deleteBodyFormRow(row)"
|
||||
>
|
||||
<a-button type="text" class="row-action-btn">
|
||||
<IconDelete />
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
<span v-else class="common-param-action">—</span>
|
||||
</template>
|
||||
</TablePro>
|
||||
</div>
|
||||
@ -4597,6 +4822,46 @@
|
||||
}
|
||||
}
|
||||
|
||||
.kv-name-cell {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.common-param-tag {
|
||||
flex-shrink: 0;
|
||||
padding: 0 5px;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
border-radius: 3px;
|
||||
font-size: 11px;
|
||||
color: var(--color-text-3);
|
||||
background: var(--color-fill-2);
|
||||
border: 1px solid var(--color-border-2);
|
||||
}
|
||||
|
||||
.common-param-action {
|
||||
color: var(--color-text-4);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.row-common-param) {
|
||||
color: var(--color-text-3) !important;
|
||||
background: var(--color-fill-1) !important;
|
||||
|
||||
td {
|
||||
color: var(--color-text-3) !important;
|
||||
background: var(--color-fill-1) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.body-kv-pane {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
// 请求方式 + 请求地址 - 符合设计规范
|
||||
.api-test-header {
|
||||
display: flex;
|
||||
|
||||
@ -2514,12 +2514,12 @@ export default {
|
||||
'system.serviceProviders.dropdown.authConfig': 'Auth config',
|
||||
'system.serviceProviders.dropdown.accountManage': 'Account management',
|
||||
'system.serviceProviders.dropdown.export': 'Export',
|
||||
'system.serviceProviders.dropdown.fixedParams': 'Common parameters',
|
||||
'system.serviceProviders.dropdown.fixedParams': 'Common params',
|
||||
'system.serviceProviders.dropdown.delete': 'Delete',
|
||||
|
||||
'system.serviceProviders.publish.title': 'Publish mapping cache · {name}',
|
||||
'system.serviceProviders.publish.tip': 'After auth/provider changes are saved, remapped system interfaces must be republished to refresh the live cache.',
|
||||
'system.serviceProviders.publish.confirmAfterSave': 'Saved. Check and publish mapping cache for this provider now?',
|
||||
'system.serviceProviders.publish.tip': 'After auth, common params, or provider changes are saved, remapped system interfaces must be republished to refresh the live cache.',
|
||||
'system.serviceProviders.publish.confirmAfterSave': 'Saved. Common params / config take effect online only after publishing mapping cache. Check and publish now?',
|
||||
'system.serviceProviders.publish.goPublish': 'Publish',
|
||||
'system.serviceProviders.publish.later': 'Later',
|
||||
'system.serviceProviders.publish.close': 'Close',
|
||||
|
||||
@ -2412,12 +2412,12 @@ export default {
|
||||
'system.serviceProviders.dropdown.authConfig': '授权配置',
|
||||
'system.serviceProviders.dropdown.accountManage': '账户管理',
|
||||
'system.serviceProviders.dropdown.export': '导出',
|
||||
'system.serviceProviders.dropdown.fixedParams': '公共参数配置',
|
||||
'system.serviceProviders.dropdown.fixedParams': '公共参数',
|
||||
'system.serviceProviders.dropdown.delete': '删除',
|
||||
|
||||
'system.serviceProviders.publish.title': '发布映射缓存 · {name}',
|
||||
'system.serviceProviders.publish.tip': '授权配置、服务商信息等变更写入数据库后,需对已映射的系统接口重新发布,线上缓存才会更新。',
|
||||
'system.serviceProviders.publish.confirmAfterSave': '保存成功。是否立即检查并发布该服务商相关的映射缓存?',
|
||||
'system.serviceProviders.publish.tip': '授权配置、公共参数、服务商信息等变更写入数据库后,需对已映射的系统接口重新发布,线上缓存才会更新。',
|
||||
'system.serviceProviders.publish.confirmAfterSave': '保存成功。公共参数/配置需发布映射缓存后才对线上生效,是否立即检查并发布?',
|
||||
'system.serviceProviders.publish.goPublish': '去发布',
|
||||
'system.serviceProviders.publish.later': '稍后',
|
||||
'system.serviceProviders.publish.close': '关闭',
|
||||
|
||||
@ -547,6 +547,8 @@
|
||||
confirmLeaveUnsaved: (options?: { content?: string }) =>
|
||||
interfaceDetailRef.value?.confirmLeaveUnsaved?.(options) ?? Promise.resolve(true),
|
||||
captureDirtyBaseline: () => interfaceDetailRef.value?.captureDirtyBaseline?.(),
|
||||
refreshInheritedCommonParams: () =>
|
||||
interfaceDetailRef.value?.refreshInheritedCommonParams?.(),
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
getServiceProviderChangeAuthInterface,
|
||||
getServiceProviderGetAuthInfo,
|
||||
} from '@/api/ServiceProviderInterface/serviceProviderAuth';
|
||||
import { getDictionaryGetList } from '@/api/ApplicationServices/dictionary';
|
||||
import { addModalForm, configData, interfaceId } from './data';
|
||||
import { $baseConfirm } from '@/utils/confirm';
|
||||
import FormPro from '@/components/FormPro/index.vue';
|
||||
@ -234,66 +233,18 @@
|
||||
key: number;
|
||||
};
|
||||
|
||||
const dictionaryLoaded = ref(false);
|
||||
const loadingDictionary = ref(false);
|
||||
const restaurants = ref<RestaurantItem[]>([]);
|
||||
const restaurants = ref<RestaurantItem[]>([{ value: '$FromAccount', key: 1 }]);
|
||||
|
||||
async function loadDictionaryData() {
|
||||
if (dictionaryLoaded.value || loadingDictionary.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadingDictionary.value = true;
|
||||
try {
|
||||
const response: any = await getDictionaryGetList({ type: 'ParameterPlaceholder' });
|
||||
let data: API.EnumCacheEntry[] = [];
|
||||
if (Array.isArray(response)) {
|
||||
data = response;
|
||||
} else if (response && Array.isArray(response.data)) {
|
||||
data = response.data;
|
||||
} else if (response && response.data) {
|
||||
data = Array.isArray(response.data) ? response.data : [];
|
||||
}
|
||||
|
||||
const options = data.map((item: any, index: number) => ({
|
||||
value: String(item.value || ''),
|
||||
key: item.key || index,
|
||||
}));
|
||||
|
||||
const defaultOptions = [
|
||||
{ value: '$FromAccount', key: 1 },
|
||||
{ value: '$TimeStamp', key: 2 },
|
||||
];
|
||||
|
||||
const allOptions = [...defaultOptions];
|
||||
options.forEach((option: RestaurantItem) => {
|
||||
if (!allOptions.find((item) => item.value === option.value)) {
|
||||
allOptions.push(option);
|
||||
}
|
||||
});
|
||||
|
||||
restaurants.value = allOptions;
|
||||
dictionaryLoaded.value = true;
|
||||
} catch {
|
||||
restaurants.value = [
|
||||
{ value: '$FromAccount', key: 1 },
|
||||
{ value: '$TimeStamp', key: 2 },
|
||||
];
|
||||
} finally {
|
||||
loadingDictionary.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function loadAll() {
|
||||
return [
|
||||
{ value: '$FromAccount', key: 1 },
|
||||
{ value: '$TimeStamp', key: 2 },
|
||||
];
|
||||
function filterOption(inputValue: string, option: any) {
|
||||
return (
|
||||
!inputValue ||
|
||||
String(option.value || '')
|
||||
.toLowerCase()
|
||||
.includes(String(inputValue).toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
restaurants.value = loadAll();
|
||||
|
||||
if (configData.interfaceCode) {
|
||||
oldVal.value = configData.interfaceCode;
|
||||
await nextTick();
|
||||
@ -312,15 +263,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
function filterOption(inputValue: string, option: any) {
|
||||
return (
|
||||
!inputValue ||
|
||||
String(option.value || '')
|
||||
.toLowerCase()
|
||||
.includes(String(inputValue).toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
function deleteRow(row: any) {
|
||||
tableRef.value.removeRow(row);
|
||||
}
|
||||
@ -354,8 +296,8 @@
|
||||
v-model="record.value"
|
||||
:data="restaurants"
|
||||
allow-clear
|
||||
placeholder="请选择或输入 $FromAccount"
|
||||
:filter-option="filterOption"
|
||||
@focus="() => { if (!dictionaryLoaded && !loadingDictionary) loadDictionaryData(); }"
|
||||
@select="(val) => (record.value = val)"
|
||||
@change="(val) => { record.value = val; }"
|
||||
/>
|
||||
|
||||
406
src/views/api/downstreamInterface/comps/FixedParameterConfig.vue
Normal file
406
src/views/api/downstreamInterface/comps/FixedParameterConfig.vue
Normal file
@ -0,0 +1,406 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, nextTick } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import useModal from '@/components/ModalPro/useModal';
|
||||
import ModalPro from '@/components/ModalPro/index.vue';
|
||||
import SelectPro from '@/components/SelectPro/index.vue';
|
||||
import { getDictionaryGetList } from '@/api/ApplicationServices/dictionary';
|
||||
import {
|
||||
getFixedParameterGetFixedParameterList,
|
||||
postFixedParameterMaintainParameter,
|
||||
} from '@/api/ParameterServices/fixedParameter';
|
||||
import { IconDelete, IconPlus } from '@arco-design/web-vue/es/icon';
|
||||
import { $baseMessage } from '@/utils';
|
||||
|
||||
defineOptions({
|
||||
name: 'FixedParameterConfig',
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'saved', payload: { id: number; name?: string; code?: string }): void;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
const [register, { openModal, setModalProps }] = useModal() as any;
|
||||
|
||||
const serviceProviderId = ref(0);
|
||||
const serviceProviderMeta = ref<{ id: number; name?: string; code?: string } | null>(null);
|
||||
const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
|
||||
type FixedRow = {
|
||||
__rowKey: string | number;
|
||||
id?: number;
|
||||
fieldName?: string;
|
||||
fieldValue?: string;
|
||||
fieldPositionList?: Array<number | string>;
|
||||
description?: string;
|
||||
};
|
||||
|
||||
const tableData = ref<FixedRow[]>([]);
|
||||
const originalById = ref<Map<number, FixedRow>>(new Map());
|
||||
let rowKeySeq = 0;
|
||||
|
||||
const placeholderOptions = ref<{ value: string; label: string }[]>([]);
|
||||
|
||||
const tableColumns = computed(() => [
|
||||
{
|
||||
title: '序号',
|
||||
width: 64,
|
||||
align: 'center' as const,
|
||||
render: ({ rowIndex }: any) => rowIndex + 1,
|
||||
},
|
||||
{
|
||||
title: '参数名',
|
||||
dataIndex: 'fieldName',
|
||||
slotName: 'fieldName',
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
title: '参数值',
|
||||
dataIndex: 'fieldValue',
|
||||
slotName: 'fieldValue',
|
||||
minWidth: 180,
|
||||
},
|
||||
{
|
||||
title: '位置',
|
||||
dataIndex: 'fieldPositionList',
|
||||
slotName: 'fieldPositions',
|
||||
minWidth: 180,
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'description',
|
||||
slotName: 'description',
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
slotName: 'action',
|
||||
width: 72,
|
||||
align: 'center' as const,
|
||||
fixed: 'right' as const,
|
||||
},
|
||||
]);
|
||||
|
||||
async function loadDictionaries() {
|
||||
try {
|
||||
const phRes: any = await getDictionaryGetList({ type: 'ParameterPlaceholder' });
|
||||
const phList = phRes?.data || phRes || [];
|
||||
placeholderOptions.value = (Array.isArray(phList) ? phList : []).map((item: any) => ({
|
||||
value: String(item.value ?? item.key ?? ''),
|
||||
label: String(item.value ?? item.key ?? ''),
|
||||
}));
|
||||
} catch {
|
||||
placeholderOptions.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeRow(item: any): FixedRow {
|
||||
const id = item?.id != null ? Number(item.id) : undefined;
|
||||
return {
|
||||
__rowKey: id ?? `new_${++rowKeySeq}`,
|
||||
id,
|
||||
fieldName: item?.fieldName ?? '',
|
||||
fieldValue: item?.fieldValue ?? '',
|
||||
fieldPositionList: Array.isArray(item?.fieldPositionList)
|
||||
? [...item.fieldPositionList]
|
||||
: [],
|
||||
description: item?.description ?? '',
|
||||
};
|
||||
}
|
||||
|
||||
async function loadList() {
|
||||
if (!serviceProviderId.value) return;
|
||||
loading.value = true;
|
||||
try {
|
||||
const res: any = await getFixedParameterGetFixedParameterList({
|
||||
serviceProviderId: serviceProviderId.value,
|
||||
});
|
||||
const data = res?.data || res || [];
|
||||
const list = (Array.isArray(data) ? data : []).map(normalizeRow);
|
||||
tableData.value = list;
|
||||
const map = new Map<number, FixedRow>();
|
||||
list.forEach((row) => {
|
||||
if (row.id != null) {
|
||||
map.set(row.id, {
|
||||
...row,
|
||||
fieldPositionList: [...(row.fieldPositionList || [])],
|
||||
});
|
||||
}
|
||||
});
|
||||
originalById.value = map;
|
||||
} catch {
|
||||
tableData.value = [];
|
||||
originalById.value = new Map();
|
||||
$baseMessage('加载公共参数失败', 'error');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function init(input: number | { id: number; name?: string; code?: string }) {
|
||||
const id = typeof input === 'number' ? input : Number(input?.id);
|
||||
if (!Number.isFinite(id) || id <= 0) {
|
||||
$baseMessage('请先选择服务商', 'warning');
|
||||
return;
|
||||
}
|
||||
serviceProviderId.value = id;
|
||||
serviceProviderMeta.value =
|
||||
typeof input === 'number'
|
||||
? { id, name: undefined, code: undefined }
|
||||
: { id, name: input?.name, code: input?.code };
|
||||
|
||||
setModalProps?.({
|
||||
title: `${t('system.serviceProviders.dropdown.fixedParams')}${
|
||||
serviceProviderMeta.value?.name ? ` - ${serviceProviderMeta.value.name}` : ''
|
||||
}`,
|
||||
showFooter: true,
|
||||
okText: '保存',
|
||||
confirmLoading: false,
|
||||
});
|
||||
openModal();
|
||||
await nextTick();
|
||||
await loadDictionaries();
|
||||
await loadList();
|
||||
}
|
||||
|
||||
function handleAddRow() {
|
||||
tableData.value.push({
|
||||
__rowKey: `new_${++rowKeySeq}`,
|
||||
fieldName: '',
|
||||
fieldValue: '',
|
||||
fieldPositionList: [],
|
||||
description: '',
|
||||
});
|
||||
}
|
||||
|
||||
function handleDeleteRow(record: FixedRow) {
|
||||
tableData.value = tableData.value.filter((r) => r.__rowKey !== record.__rowKey);
|
||||
}
|
||||
|
||||
function positionsEqual(a?: Array<number | string>, b?: Array<number | string>) {
|
||||
const aa = [...(a || [])].map(String).sort();
|
||||
const bb = [...(b || [])].map(String).sort();
|
||||
if (aa.length !== bb.length) return false;
|
||||
return aa.every((v, i) => v === bb[i]);
|
||||
}
|
||||
|
||||
function rowChanged(curr: FixedRow, orig: FixedRow) {
|
||||
return (
|
||||
String(curr.fieldName ?? '') !== String(orig.fieldName ?? '') ||
|
||||
String(curr.fieldValue ?? '') !== String(orig.fieldValue ?? '') ||
|
||||
String(curr.description ?? '') !== String(orig.description ?? '') ||
|
||||
!positionsEqual(curr.fieldPositionList, orig.fieldPositionList)
|
||||
);
|
||||
}
|
||||
|
||||
function buildItems() {
|
||||
const items: any[] = [];
|
||||
const currentIds = new Set<number>();
|
||||
|
||||
for (const row of tableData.value) {
|
||||
const name = String(row.fieldName ?? '').trim();
|
||||
if (!name) continue;
|
||||
|
||||
const payload = {
|
||||
fieldName: name,
|
||||
fieldValue: row.fieldValue ?? '',
|
||||
fieldPositionList: row.fieldPositionList || [],
|
||||
description: row.description ?? '',
|
||||
};
|
||||
|
||||
if (row.id == null) {
|
||||
items.push({ ...payload, options: 1, id: undefined });
|
||||
continue;
|
||||
}
|
||||
|
||||
currentIds.add(row.id);
|
||||
const orig = originalById.value.get(row.id);
|
||||
if (!orig || rowChanged(row, orig)) {
|
||||
items.push({ ...payload, options: 3, id: row.id });
|
||||
}
|
||||
}
|
||||
|
||||
for (const [id, orig] of originalById.value.entries()) {
|
||||
if (!currentIds.has(id)) {
|
||||
items.push({
|
||||
id,
|
||||
fieldName: orig.fieldName,
|
||||
fieldValue: orig.fieldValue,
|
||||
fieldPositionList: orig.fieldPositionList || [],
|
||||
description: orig.description,
|
||||
options: 2,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
async function onModalSave() {
|
||||
if (!serviceProviderId.value) return false;
|
||||
|
||||
const emptyName = tableData.value.some((r) => !String(r.fieldName ?? '').trim());
|
||||
if (emptyName) {
|
||||
$baseMessage('请填写参数名', 'warning');
|
||||
return false;
|
||||
}
|
||||
|
||||
const names = tableData.value.map((r) => String(r.fieldName ?? '').trim().toLowerCase());
|
||||
if (new Set(names).size !== names.length) {
|
||||
$baseMessage('参数名不能重复', 'warning');
|
||||
return false;
|
||||
}
|
||||
|
||||
const items = buildItems();
|
||||
if (items.length === 0) {
|
||||
$baseMessage('暂无变更需要保存', 'warning');
|
||||
return false;
|
||||
}
|
||||
|
||||
saving.value = true;
|
||||
setModalProps?.({ confirmLoading: true });
|
||||
try {
|
||||
await postFixedParameterMaintainParameter({
|
||||
serviceProviderId: serviceProviderId.value,
|
||||
items,
|
||||
});
|
||||
$baseMessage('保存成功,如需生效请去发布', 'success');
|
||||
emit('saved', {
|
||||
id: Number(serviceProviderId.value),
|
||||
name: serviceProviderMeta.value?.name,
|
||||
code: serviceProviderMeta.value?.code,
|
||||
});
|
||||
await loadList();
|
||||
return true;
|
||||
} catch {
|
||||
$baseMessage('保存失败', 'error');
|
||||
return false;
|
||||
} finally {
|
||||
saving.value = false;
|
||||
setModalProps?.({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ init });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="fixed-parameter-config">
|
||||
<ModalPro
|
||||
:width="920"
|
||||
:title="t('system.serviceProviders.dropdown.fixedParams')"
|
||||
:loading="loading || saving"
|
||||
@register="register"
|
||||
@ok="onModalSave"
|
||||
>
|
||||
<div class="fixed-parameter-body">
|
||||
<a-alert type="info" :show-icon="false" class="modal-form-tip">
|
||||
配置当前服务商的公共参数,供其下接口共用。路径:修改 → 保存 → 发布映射缓存后才对线上生效。
|
||||
</a-alert>
|
||||
|
||||
<div class="table-toolbar">
|
||||
<div class="toolbar-left">
|
||||
<a-button type="primary" class="app-btn-primary-soft" size="small" @click="handleAddRow">
|
||||
<template #icon><IconPlus /></template>
|
||||
新增
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
<span class="row-count">共 {{ tableData.length }} 条</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-table
|
||||
size="small"
|
||||
row-key="__rowKey"
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
:loading="loading"
|
||||
:pagination="false"
|
||||
:bordered="{ cell: true }"
|
||||
:scroll="{ y: 420 }"
|
||||
class="fixed-parameter-table"
|
||||
>
|
||||
<template #empty>
|
||||
<div class="empty-tip">暂无公共参数,点击「新增」添加</div>
|
||||
</template>
|
||||
<template #fieldName="{ record }">
|
||||
<a-input v-model="record.fieldName" allow-clear placeholder="请输入参数名" />
|
||||
</template>
|
||||
<template #fieldValue="{ record }">
|
||||
<a-auto-complete
|
||||
v-model="record.fieldValue"
|
||||
:data="placeholderOptions"
|
||||
allow-clear
|
||||
placeholder="请选择或输入参数值"
|
||||
:filter-option="
|
||||
(inputValue, option) =>
|
||||
!inputValue ||
|
||||
String(option.value || '')
|
||||
.toLowerCase()
|
||||
.includes(String(inputValue).toLowerCase())
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<template #fieldPositions="{ record }">
|
||||
<SelectPro
|
||||
v-model="record.fieldPositionList"
|
||||
:api="getDictionaryGetList"
|
||||
:extra="{ type: 'FieldPosition' }"
|
||||
:is-page="false"
|
||||
:immediate="true"
|
||||
:label-keys="['value']"
|
||||
:multiple="true"
|
||||
id-key="key"
|
||||
placeholder="请选择位置"
|
||||
/>
|
||||
</template>
|
||||
<template #description="{ record }">
|
||||
<a-input v-model="record.description" allow-clear placeholder="可选" />
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<a-button type="text" size="small" status="danger" title="删除" @click="handleDeleteRow(record)">
|
||||
<template #icon><IconDelete /></template>
|
||||
</a-button>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</ModalPro>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.fixed-parameter-body {
|
||||
.modal-form-tip {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.table-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.row-count {
|
||||
font-size: 13px;
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
padding: 24px 0;
|
||||
color: var(--color-text-3);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.fixed-parameter-table {
|
||||
:deep(.arco-input-wrapper),
|
||||
:deep(.arco-select-view),
|
||||
:deep(.arco-auto-complete) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -18,6 +18,7 @@
|
||||
postServiceProviderImport,
|
||||
} from '@/api/interface-serviceProvider/serviceProviderImportExport';
|
||||
import ParameterConfig from '@/views/api/downstreamInterface/comps/ParameterConfig.vue';
|
||||
import FixedParameterConfig from '@/views/api/downstreamInterface/comps/FixedParameterConfig.vue';
|
||||
import FormPro from '@/components/FormPro/index.vue';
|
||||
import TableButtons from '@/components/TableButtons/index.vue';
|
||||
import {
|
||||
@ -32,6 +33,7 @@
|
||||
import dayjs from 'dayjs';
|
||||
import { getDictionaryGetList } from '@/api/ApplicationServices/dictionary';
|
||||
import { getAppGetDropDownList } from '@/api/ApplicationServices/apps';
|
||||
import { getFixedParameterGetFixedParameterList } from '@/api/ParameterServices/fixedParameter';
|
||||
import ServiceProviderInterfaceModal from './components/ServiceProviderInterfaceModal.vue';
|
||||
import AccountList from './comps/AccountList.vue';
|
||||
import ProviderMapPublishModal from './comps/ProviderMapPublishModal.vue';
|
||||
@ -48,6 +50,7 @@
|
||||
IconRefresh,
|
||||
IconMore,
|
||||
IconDelete,
|
||||
IconList,
|
||||
} from '@arco-design/web-vue/es/icon';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
@ -111,6 +114,8 @@
|
||||
const searchKeyword = ref('');
|
||||
const serviceProviderList = ref<any[]>([]);
|
||||
const selectedProvider = ref<any>(null);
|
||||
const commonParamsCount = ref<number | null>(null);
|
||||
const commonParamsLoading = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
// 接口弹窗相关
|
||||
@ -960,11 +965,63 @@
|
||||
}
|
||||
|
||||
const accountList = ref();
|
||||
const fixedParameterConfigRef = ref<InstanceType<typeof FixedParameterConfig> | null>(null);
|
||||
|
||||
function accountManageClick(row: any) {
|
||||
accountList.value?.init?.(row);
|
||||
}
|
||||
|
||||
function handleFixedParamsWithSelect(provider: any) {
|
||||
handleProviderSelect(provider);
|
||||
setTimeout(() => {
|
||||
fixedParameterConfigRef.value?.init?.(provider);
|
||||
}, 150);
|
||||
}
|
||||
|
||||
async function refreshCommonParamsCount(providerLike?: any) {
|
||||
const id = Number(providerLike?.id || selectedProvider.value?.id || 0);
|
||||
if (!Number.isFinite(id) || id <= 0) {
|
||||
commonParamsCount.value = null;
|
||||
return;
|
||||
}
|
||||
commonParamsLoading.value = true;
|
||||
try {
|
||||
const res: any = await getFixedParameterGetFixedParameterList({
|
||||
serviceProviderId: id,
|
||||
});
|
||||
const data = res?.data || res || [];
|
||||
commonParamsCount.value = Array.isArray(data) ? data.length : 0;
|
||||
} catch {
|
||||
commonParamsCount.value = null;
|
||||
} finally {
|
||||
commonParamsLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => selectedProvider.value?.id,
|
||||
() => {
|
||||
refreshCommonParamsCount();
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
function openCommonParamsFromTabs() {
|
||||
const provider = selectedProvider.value;
|
||||
if (!provider?.id) {
|
||||
$baseMessage('请先选择服务商', 'warning');
|
||||
return;
|
||||
}
|
||||
fixedParameterConfigRef.value?.init?.(provider);
|
||||
}
|
||||
|
||||
function onFixedParamsSaved(payload: any) {
|
||||
refreshCommonParamsCount(payload);
|
||||
interfaceDetailModalRef.value?.refreshInheritedCommonParams?.();
|
||||
interfaceModalRef.value?.refreshInheritedCommonParams?.();
|
||||
askGoPublish(payload);
|
||||
}
|
||||
|
||||
function mapAccountClick(row: { id: any; code: any; name?: string }) {
|
||||
accountList.value?.init?.(row);
|
||||
}
|
||||
@ -1644,6 +1701,10 @@
|
||||
<IconSettings style="margin-right: 8px;" />
|
||||
{{ t('system.serviceProviders.dropdown.authConfig') }}
|
||||
</a-doption>
|
||||
<a-doption @click="handleFixedParamsWithSelect(nodeData)">
|
||||
<IconList style="margin-right: 8px;" />
|
||||
{{ t('system.serviceProviders.dropdown.fixedParams') }}
|
||||
</a-doption>
|
||||
<a-doption @click="accountManageClick(nodeData)">
|
||||
<IconUser style="margin-right: 8px;" />
|
||||
{{ t('system.serviceProviders.dropdown.accountManage') }}
|
||||
@ -1719,7 +1780,22 @@
|
||||
:items="interfaceDetailTabItems"
|
||||
@change="switchInterfaceDetailTab"
|
||||
/>
|
||||
<div class="tabs-extra" v-if="selectedInterface && interfaceDetailTab !== 'detail'"></div>
|
||||
<div v-if="selectedProvider" class="tabs-extra">
|
||||
<a-button
|
||||
size="small"
|
||||
class="common-params-entry"
|
||||
title="服务商公共参数,发布映射后对该服务商下接口生效"
|
||||
@click="openCommonParamsFromTabs"
|
||||
>
|
||||
公共参数{{
|
||||
commonParamsLoading
|
||||
? ''
|
||||
: commonParamsCount != null
|
||||
? ` · ${commonParamsCount}`
|
||||
: ''
|
||||
}}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1813,6 +1889,7 @@
|
||||
ref="parameterConfigFlag"
|
||||
@saved="askGoPublish"
|
||||
/>
|
||||
<FixedParameterConfig ref="fixedParameterConfigRef" @saved="onFixedParamsSaved" />
|
||||
<AccountList ref="accountList" @saved="askGoPublish" />
|
||||
<ProviderMapPublishModal ref="providerPublishRef" />
|
||||
</div>
|
||||
@ -1995,6 +2072,11 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
gap: 8px;
|
||||
|
||||
.common-params-entry {
|
||||
color: var(--color-text-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user