- views/app/AppList.vue(新)+ views/proxytest/ProxyTest.vue(新):应用列表与代理测试演示页 - router/routes + apiDefinitions + App.vue/layout:新页路由与菜单接线 - assets/mock/gatewayApi.ts:mock 数据扩充(+136 行) - RouteList:列表页联动增强 - vite.config:mock 相关配置调整 - theme.ts:sync 刷新至 20261006-2013-75c1d10 并补回本仓唯一允许适配(顶部 // @ts-nocheck,strict vue-tsc 契约);typecheck 零错误
130 lines
5.7 KiB
Vue
130 lines
5.7 KiB
Vue
<template>
|
||
<div class="main-wrapper">
|
||
<div class="main-container">
|
||
<div class="search-wrap fix">
|
||
<span class="tip">路由注册表(open_api_route):治理旋钮行内编辑,保存后网关热重载,无须重启。qps>0 时按 调用方×本行 限流(超限裸 429,0=不限);timeout/bodyLimit 立即生效。</span>
|
||
<Button type="primary" class="fr" @click="refresh">刷新</Button>
|
||
</div>
|
||
|
||
<TablePageAlovaNew ref="tableRef" :dataApi="tableApi" :columns="columns" :tableHeight="tableHeight">
|
||
<template #visibility="{ row }">
|
||
<Select v-model="row.visibility" size="small" style="width: 110px">
|
||
<Option value="INTERNAL">INTERNAL</Option>
|
||
<Option value="EXTERNAL">EXTERNAL</Option>
|
||
</Select>
|
||
</template>
|
||
<template #authMode="{ row }">
|
||
<Select v-model="row.authMode" size="small" style="width: 120px">
|
||
<Option value="SIGNED">SIGNED</Option>
|
||
<Option value="ANON">ANON</Option>
|
||
</Select>
|
||
</template>
|
||
<template #cacheTtlSeconds="{ row }">
|
||
<Input v-model="row.cacheTtlSeconds" type="number" size="small" style="width: 80px" />
|
||
</template>
|
||
<template #cacheScope="{ row }">
|
||
<Select v-model="row.cacheScope" size="small" style="width: 100px">
|
||
<Option value="CALLER">CALLER</Option>
|
||
<Option value="GLOBAL">GLOBAL</Option>
|
||
</Select>
|
||
</template>
|
||
<template #rateLimitQps="{ row }">
|
||
<Input v-model="row.rateLimitQps" type="number" size="small" style="width: 80px" />
|
||
</template>
|
||
<template #timeoutMs="{ row }">
|
||
<Input v-model="row.timeoutMs" type="number" size="small" style="width: 90px" placeholder="1000-120000" />
|
||
</template>
|
||
<template #requestBodyLimitMb="{ row }">
|
||
<Input v-model="row.requestBodyLimitMb" type="number" size="small" style="width: 90px" placeholder="1-100" />
|
||
</template>
|
||
<template #enabled="{ row }">
|
||
<i-switch v-model="row.enabled" size="small" />
|
||
</template>
|
||
<template #remark="{ row }">
|
||
<Input v-model="row.remark" size="small" placeholder="-" />
|
||
</template>
|
||
<template #action="{ row }">
|
||
<Button type="primary" size="small" :loading="savingId === row.id" @click="save(row)">保存</Button>
|
||
</template>
|
||
</TablePageAlovaNew>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref } from 'vue';
|
||
import useCurrentInstance from '@/utils/hook/useCurrentInstance';
|
||
import TablePageAlovaNew from '@/components/TablePageAlovaNew.vue';
|
||
|
||
defineOptions({ name: 'RouteList' });
|
||
|
||
const { $utils } = useCurrentInstance();
|
||
|
||
const tableRef = ref<InstanceType<typeof TablePageAlovaNew> | null>(null);
|
||
const savingId = ref<number | null>(null);
|
||
|
||
const tableApi = (params: { pageIndex: number; pageSize: number }) =>
|
||
Apis.GatewayAdmin.routes({ params, cacheFor: null });
|
||
|
||
const tableHeight = ref($utils.useTableHeight({ isOperat: false, isPage: true, isSearch: true }));
|
||
|
||
const columns = [
|
||
{ title: 'id', key: 'id', width: 70, align: 'center' },
|
||
{ title: 'target', key: 'targetCode', width: 120, ellipsis: true, tooltip: true },
|
||
{ title: 'path', key: 'pathPattern', minWidth: 200, ellipsis: true, tooltip: true },
|
||
{ title: 'method', key: 'httpMethod', width: 90, align: 'center' },
|
||
{ title: 'visibility', slot: 'visibility', width: 130 },
|
||
{ title: 'authMode', slot: 'authMode', width: 140 },
|
||
{ title: 'cacheTtl(s)', slot: 'cacheTtlSeconds', width: 105 },
|
||
{ title: 'cacheScope', slot: 'cacheScope', width: 120 },
|
||
{ title: 'qps', slot: 'rateLimitQps', width: 90 },
|
||
{ title: 'timeout(ms)', slot: 'timeoutMs', width: 115, align: 'right' },
|
||
{ title: 'bodyLimit(mb)', slot: 'requestBodyLimitMb', width: 125, align: 'right' },
|
||
{ title: '启用', slot: 'enabled', width: 80, align: 'center' },
|
||
{ title: '备注', slot: 'remark', minWidth: 160 },
|
||
{ title: '操作', slot: 'action', width: 90, align: 'center', fixed: 'right' as const },
|
||
];
|
||
|
||
function refresh() {
|
||
tableRef.value?.refreshData();
|
||
}
|
||
|
||
/** 只提交治理字段(target/pattern/method 是路由身份,后端不接受改动) */
|
||
async function save(row: any) {
|
||
savingId.value = row.id;
|
||
try {
|
||
const d: any = await Apis.GatewayAdmin.updateRoute({
|
||
pathParams: { id: row.id },
|
||
data: {
|
||
visibility: row.visibility,
|
||
authMode: row.authMode,
|
||
cacheTtlSeconds: Number(row.cacheTtlSeconds) || 0,
|
||
cacheScope: row.cacheScope,
|
||
rateLimitQps: Number(row.rateLimitQps) || 0,
|
||
timeoutMs: Number(row.timeoutMs) || 30000,
|
||
requestBodyLimitMb: Number(row.requestBodyLimitMb) || 10,
|
||
enabled: row.enabled,
|
||
remark: row.remark,
|
||
},
|
||
});
|
||
Message.success(`已保存,注册表加载 ${d?.loaded ?? '-'} 条路由`);
|
||
} catch (e: any) {
|
||
// 错误提示由 alova 全局 onBizError 弹出,这里只做回滚,避免双 toast
|
||
tableRef.value?.refreshData();
|
||
} finally {
|
||
savingId.value = null;
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.search-wrap {
|
||
line-height: 32px;
|
||
|
||
.tip {
|
||
color: #848c98;
|
||
font-size: 13px;
|
||
}
|
||
}
|
||
</style>
|