修正发布临时open-api模块
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
export * from './dept';
|
||||
export * from './dict';
|
||||
export * from './menu';
|
||||
export * from './open-api';
|
||||
export * from './role';
|
||||
export * from './user';
|
||||
export * from './sys';
|
||||
export * from './user';
|
||||
|
||||
@@ -69,6 +69,17 @@ const routes: RouteRecordRaw[] = [
|
||||
},
|
||||
component: () => import('#/views/manager/menu/index.vue'),
|
||||
},
|
||||
{
|
||||
name: 'open-api',
|
||||
path: '/manager/open-api',
|
||||
meta: {
|
||||
authority: ['manager'],
|
||||
icon: 'mdi:api',
|
||||
title: 'API管理',
|
||||
keepAlive: true,
|
||||
},
|
||||
component: () => import('#/views/manager/open-api/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
component: () => import('#/views/open-api/index.vue'),
|
||||
meta: {
|
||||
authority: ['manager'],
|
||||
icon: 'lucide:waypoints',
|
||||
keepAlive: true,
|
||||
order: 3,
|
||||
title: '开放接口中心',
|
||||
},
|
||||
name: 'OpenApiCenter',
|
||||
path: '/open-api/center',
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
||||
+146
-41
@@ -1,8 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
import type { EchartsUIType } from '@vben/plugins/echarts';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
|
||||
import type { OpenApiCenterApi } from '#/api/open-api';
|
||||
import type { EchartsUIType } from '@vben/plugins/echarts';
|
||||
|
||||
import type { OpenApiCenterApi } from '#/api/manager/open-api';
|
||||
|
||||
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue';
|
||||
|
||||
@@ -36,7 +37,7 @@ import {
|
||||
getOpenApiUsage,
|
||||
updateOpenApiConsumer,
|
||||
updateOpenApiEndpoint,
|
||||
} from '#/api/open-api';
|
||||
} from '#/api/manager/open-api';
|
||||
|
||||
const RangePicker = DatePicker.RangePicker;
|
||||
const activeTab = ref('overview');
|
||||
@@ -149,7 +150,12 @@ const consumerColumns = [
|
||||
{ key: 'identity', title: '调用方', width: 260 },
|
||||
{ dataIndex: 'customId', key: 'customId', title: 'Custom ID', width: 180 },
|
||||
{ dataIndex: 'callCount', key: 'callCount', title: '累计调用', width: 120 },
|
||||
{ dataIndex: 'endpointCount', key: 'endpointCount', title: '接口数', width: 90 },
|
||||
{
|
||||
dataIndex: 'endpointCount',
|
||||
key: 'endpointCount',
|
||||
title: '接口数',
|
||||
width: 90,
|
||||
},
|
||||
{ dataIndex: 'recentIp', key: 'recentIp', title: '最近 IP', width: 150 },
|
||||
{ key: 'lastSeenAt', title: '最后调用', width: 170 },
|
||||
{ key: 'status', title: '状态', width: 100 },
|
||||
@@ -434,12 +440,12 @@ async function saveEndpoint() {
|
||||
}
|
||||
endpointSaving.value = true;
|
||||
try {
|
||||
if (editingEndpointId.value) {
|
||||
await updateOpenApiEndpoint(editingEndpointId.value, { ...endpointForm });
|
||||
} else {
|
||||
await createOpenApiEndpoint({ ...endpointForm });
|
||||
}
|
||||
message.success(editingEndpointId.value ? '接口资产已更新' : '接口资产已创建');
|
||||
await (editingEndpointId.value
|
||||
? updateOpenApiEndpoint(editingEndpointId.value, { ...endpointForm })
|
||||
: createOpenApiEndpoint({ ...endpointForm }));
|
||||
message.success(
|
||||
editingEndpointId.value ? '接口资产已更新' : '接口资产已创建',
|
||||
);
|
||||
endpointModalOpen.value = false;
|
||||
await refreshAll();
|
||||
} finally {
|
||||
@@ -537,7 +543,10 @@ onMounted(refreshAll);
|
||||
</div>
|
||||
<Button ghost size="large" @click="refreshAll">
|
||||
<template #icon>
|
||||
<IconifyIcon :class="{ spinning: loading }" icon="lucide:refresh-cw" />
|
||||
<IconifyIcon
|
||||
:class="{ spinning: loading }"
|
||||
icon="lucide:refresh-cw"
|
||||
/>
|
||||
</template>
|
||||
刷新数据
|
||||
</Button>
|
||||
@@ -597,7 +606,10 @@ onMounted(refreshAll);
|
||||
class="metric-card"
|
||||
>
|
||||
<div class="metric-head">
|
||||
<div class="metric-icon" :style="{ background: `${item.accent}16`, color: item.accent }">
|
||||
<div
|
||||
class="metric-icon"
|
||||
:style="{ background: `${item.accent}16`, color: item.accent }"
|
||||
>
|
||||
<IconifyIcon :icon="item.icon" />
|
||||
</div>
|
||||
<span class="metric-label">{{ item.label }}</span>
|
||||
@@ -614,7 +626,11 @@ onMounted(refreshAll);
|
||||
<Tabs v-model:active-key="activeTab" class="center-tabs">
|
||||
<Tabs.TabPane key="overview">
|
||||
<template #tab>
|
||||
<span class="tab-label"><IconifyIcon icon="lucide:chart-no-axes-combined" />运行总览</span>
|
||||
<span class="tab-label"
|
||||
><IconifyIcon
|
||||
icon="lucide:chart-no-axes-combined"
|
||||
/>运行总览</span
|
||||
>
|
||||
</template>
|
||||
<div class="overview-grid">
|
||||
<section class="chart-panel chart-panel-wide">
|
||||
@@ -658,9 +674,17 @@ onMounted(refreshAll);
|
||||
:key="item.key"
|
||||
class="caller-row"
|
||||
>
|
||||
<span class="rank-index" :class="{ podium: index < 3 }">{{ index + 1 }}</span>
|
||||
<span class="rank-index" :class="{ podium: index < 3 }">{{
|
||||
index + 1
|
||||
}}</span>
|
||||
<div class="caller-avatar">
|
||||
<IconifyIcon :icon="item.key.startsWith('ip:') ? 'lucide:globe-2' : 'lucide:building-2'" />
|
||||
<IconifyIcon
|
||||
:icon="
|
||||
item.key.startsWith('ip:')
|
||||
? 'lucide:globe-2'
|
||||
: 'lucide:building-2'
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="caller-copy">
|
||||
<strong>{{ item.name }}</strong>
|
||||
@@ -668,7 +692,10 @@ onMounted(refreshAll);
|
||||
</div>
|
||||
<b>{{ formatNumber(item.value) }}</b>
|
||||
</div>
|
||||
<div v-if="!overview.topConsumers.length" class="empty-state">
|
||||
<div
|
||||
v-if="overview.topConsumers.length === 0"
|
||||
class="empty-state"
|
||||
>
|
||||
<IconifyIcon icon="lucide:radio-tower" />
|
||||
<span>等待 Kong 推送首批调用数据</span>
|
||||
</div>
|
||||
@@ -679,7 +706,9 @@ onMounted(refreshAll);
|
||||
|
||||
<Tabs.TabPane key="endpoints">
|
||||
<template #tab>
|
||||
<span class="tab-label"><IconifyIcon icon="lucide:boxes" />接口资产</span>
|
||||
<span class="tab-label"
|
||||
><IconifyIcon icon="lucide:boxes" />接口资产</span
|
||||
>
|
||||
</template>
|
||||
<div class="table-toolbar">
|
||||
<div>
|
||||
@@ -702,7 +731,9 @@ onMounted(refreshAll);
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'name'">
|
||||
<div class="asset-name">
|
||||
<div class="asset-icon"><IconifyIcon icon="lucide:webhook" /></div>
|
||||
<div class="asset-icon">
|
||||
<IconifyIcon icon="lucide:webhook" />
|
||||
</div>
|
||||
<div>
|
||||
<strong>{{ record.name }}</strong>
|
||||
<span>{{ record.category }}</span>
|
||||
@@ -714,22 +745,42 @@ onMounted(refreshAll);
|
||||
</template>
|
||||
<template v-else-if="column.key === 'path'">
|
||||
<div class="path-cell">
|
||||
<Tag :color="methodColor(record.httpMethod)">{{ record.httpMethod }}</Tag>
|
||||
<Tag :color="methodColor(record.httpMethod)">
|
||||
{{ record.httpMethod }}
|
||||
</Tag>
|
||||
<Tooltip :title="record.pathTemplate">
|
||||
<code>{{ record.pathTemplate }}</code>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'lastCalledAt'">
|
||||
<span class="muted-text">{{ formatTime(record.lastCalledAt) }}</span>
|
||||
<span class="muted-text">{{
|
||||
formatTime(record.lastCalledAt)
|
||||
}}</span>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'status'">
|
||||
<Tag :color="record.monitorEnabled && record.status === 'enabled' ? 'success' : 'default'">
|
||||
{{ record.monitorEnabled && record.status === 'enabled' ? '监控中' : '已停用' }}
|
||||
<Tag
|
||||
:color="
|
||||
record.monitorEnabled && record.status === 'enabled'
|
||||
? 'success'
|
||||
: 'default'
|
||||
"
|
||||
>
|
||||
{{
|
||||
record.monitorEnabled && record.status === 'enabled'
|
||||
? '监控中'
|
||||
: '已停用'
|
||||
}}
|
||||
</Tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<Button size="small" type="link" @click="editEndpointRecord(record)">编辑</Button>
|
||||
<Button
|
||||
size="small"
|
||||
type="link"
|
||||
@click="editEndpointRecord(record)"
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
</template>
|
||||
</template>
|
||||
</Table>
|
||||
@@ -737,7 +788,9 @@ onMounted(refreshAll);
|
||||
|
||||
<Tabs.TabPane key="consumers">
|
||||
<template #tab>
|
||||
<span class="tab-label"><IconifyIcon icon="lucide:users-round" />调用方</span>
|
||||
<span class="tab-label"
|
||||
><IconifyIcon icon="lucide:users-round" />调用方</span
|
||||
>
|
||||
</template>
|
||||
<div class="table-toolbar">
|
||||
<div>
|
||||
@@ -757,23 +810,37 @@ onMounted(refreshAll);
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'identity'">
|
||||
<div class="asset-name">
|
||||
<div class="asset-icon consumer-icon"><IconifyIcon icon="lucide:building-2" /></div>
|
||||
<div class="asset-icon consumer-icon">
|
||||
<IconifyIcon icon="lucide:building-2" />
|
||||
</div>
|
||||
<div>
|
||||
<strong>{{ record.displayName || record.username || '未命名调用方' }}</strong>
|
||||
<strong>{{
|
||||
record.displayName || record.username || '未命名调用方'
|
||||
}}</strong>
|
||||
<span>{{ record.username }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'lastSeenAt'">
|
||||
<span class="muted-text">{{ formatTime(record.lastSeenAt) }}</span>
|
||||
<span class="muted-text">{{
|
||||
formatTime(record.lastSeenAt)
|
||||
}}</span>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'status'">
|
||||
<Tag :color="record.status === 'active' ? 'success' : 'default'">
|
||||
<Tag
|
||||
:color="record.status === 'active' ? 'success' : 'default'"
|
||||
>
|
||||
{{ record.status === 'active' ? '活跃' : '停用' }}
|
||||
</Tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<Button size="small" type="link" @click="editConsumerRecord(record)">编辑</Button>
|
||||
<Button
|
||||
size="small"
|
||||
type="link"
|
||||
@click="editConsumerRecord(record)"
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
</template>
|
||||
</template>
|
||||
</Table>
|
||||
@@ -781,7 +848,9 @@ onMounted(refreshAll);
|
||||
|
||||
<Tabs.TabPane key="usage">
|
||||
<template #tab>
|
||||
<span class="tab-label"><IconifyIcon icon="lucide:table-properties" />使用统计</span>
|
||||
<span class="tab-label"
|
||||
><IconifyIcon icon="lucide:table-properties" />使用统计</span
|
||||
>
|
||||
</template>
|
||||
<div class="table-toolbar usage-toolbar">
|
||||
<div>
|
||||
@@ -813,12 +882,19 @@ onMounted(refreshAll);
|
||||
<template v-else-if="column.key === 'endpoint'">
|
||||
<div class="usage-endpoint">
|
||||
<strong>{{ record.endpointName }}</strong>
|
||||
<span>{{ serviceName(record.serviceCode) }} · {{ record.category }}</span>
|
||||
<span
|
||||
>{{ serviceName(record.serviceCode) }} ·
|
||||
{{ record.category }}</span
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'caller'">
|
||||
<div class="caller-cell">
|
||||
<Tag :color="record.callerType === 'consumer' ? 'blue' : 'orange'">
|
||||
<Tag
|
||||
:color="
|
||||
record.callerType === 'consumer' ? 'blue' : 'orange'
|
||||
"
|
||||
>
|
||||
{{ record.callerType === 'consumer' ? 'Consumer' : '匿名' }}
|
||||
</Tag>
|
||||
<span>{{ record.callerName }}</span>
|
||||
@@ -840,18 +916,32 @@ onMounted(refreshAll);
|
||||
<Form class="modal-form" layout="vertical">
|
||||
<div class="form-grid">
|
||||
<FormItem label="接口名称" required>
|
||||
<Input v-model:value="endpointForm.name" placeholder="例如:蓝字发票详情" />
|
||||
<Input
|
||||
v-model:value="endpointForm.name"
|
||||
placeholder="例如:蓝字发票详情"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="业务分类" required>
|
||||
<Input v-model:value="endpointForm.category" placeholder="例如:票通开票" />
|
||||
<Input
|
||||
v-model:value="endpointForm.category"
|
||||
placeholder="例如:票通开票"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="所属服务" required>
|
||||
<Select v-model:value="endpointForm.serviceCode" :options="serviceOptions" />
|
||||
<Select
|
||||
v-model:value="endpointForm.serviceCode"
|
||||
:options="serviceOptions"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="HTTP Method">
|
||||
<Select
|
||||
v-model:value="endpointForm.httpMethod"
|
||||
:options="['*', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE'].map((value) => ({ label: value, value }))"
|
||||
:options="
|
||||
['*', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE'].map((value) => ({
|
||||
label: value,
|
||||
value,
|
||||
}))
|
||||
"
|
||||
/>
|
||||
</FormItem>
|
||||
</div>
|
||||
@@ -863,13 +953,22 @@ onMounted(refreshAll);
|
||||
</FormItem>
|
||||
<div class="form-grid">
|
||||
<FormItem label="Kong Service ID">
|
||||
<Input v-model:value="endpointForm.kongServiceId" placeholder="可选" />
|
||||
<Input
|
||||
v-model:value="endpointForm.kongServiceId"
|
||||
placeholder="可选"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="Kong Route ID">
|
||||
<Input v-model:value="endpointForm.kongRouteId" placeholder="可选" />
|
||||
<Input
|
||||
v-model:value="endpointForm.kongRouteId"
|
||||
placeholder="可选"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="负责人">
|
||||
<Input v-model:value="endpointForm.owner" placeholder="部门或负责人" />
|
||||
<Input
|
||||
v-model:value="endpointForm.owner"
|
||||
placeholder="部门或负责人"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="接口状态">
|
||||
<Select
|
||||
@@ -904,7 +1003,10 @@ onMounted(refreshAll);
|
||||
>
|
||||
<Form class="modal-form" layout="vertical">
|
||||
<FormItem label="展示名称">
|
||||
<Input v-model:value="consumerForm.displayName" placeholder="客户、系统或项目名称" />
|
||||
<Input
|
||||
v-model:value="consumerForm.displayName"
|
||||
placeholder="客户、系统或项目名称"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="状态">
|
||||
<Select
|
||||
@@ -920,7 +1022,10 @@ onMounted(refreshAll);
|
||||
</FormItem>
|
||||
<div v-if="editingConsumer" class="consumer-reference">
|
||||
<span>Kong Consumer</span>
|
||||
<code>{{ editingConsumer.username }} · {{ editingConsumer.kongConsumerId }}</code>
|
||||
<code
|
||||
>{{ editingConsumer.username }} ·
|
||||
{{ editingConsumer.kongConsumerId }}</code
|
||||
>
|
||||
</div>
|
||||
</Form>
|
||||
</Modal>
|
||||
Reference in New Issue
Block a user