加刷新按钮,切换tab自动刷新

This commit is contained in:
dongzp 2026-06-10 17:55:05 +08:00
parent a23a9846b3
commit 46bdff3734
2 changed files with 91 additions and 16 deletions

View File

@ -76,6 +76,7 @@
<strong>路由配置(routes)</strong> <strong>路由配置(routes)</strong>
<div style="display:flex;gap:8px;align-items:center;"> <div style="display:flex;gap:8px;align-items:center;">
<el-input size="small" v-model="routeSearch" placeholder="搜索接口名称或路径" clearable style="width:220px;" prefix-icon="el-icon-search"></el-input> <el-input size="small" v-model="routeSearch" placeholder="搜索接口名称或路径" clearable style="width:220px;" prefix-icon="el-icon-search"></el-input>
<el-button size="mini" icon="el-icon-refresh" :loading="routesRefreshing" @click="refreshRoutes">刷新</el-button>
<el-button size="mini" type="primary" @click="openRouteDialogForCreate">新增路由</el-button> <el-button size="mini" type="primary" @click="openRouteDialogForCreate">新增路由</el-button>
</div> </div>
</div> </div>
@ -142,6 +143,7 @@
<el-option v-for="g in mockGroups" :key="g.id" :label="g.name" :value="g.id"></el-option> <el-option v-for="g in mockGroups" :key="g.id" :label="g.name" :value="g.id"></el-option>
</el-select> </el-select>
<el-input size="small" v-model="mockFileSearch" placeholder="搜索别名或路径" clearable style="width:220px;" prefix-icon="el-icon-search"></el-input> <el-input size="small" v-model="mockFileSearch" placeholder="搜索别名或路径" clearable style="width:220px;" prefix-icon="el-icon-search"></el-input>
<el-button size="mini" icon="el-icon-refresh" :loading="mocksRefreshing" @click="refreshMocks">刷新</el-button>
<el-button size="mini" type="primary" @click="openMockFileDialogForCreate">新增 Mock 文件</el-button> <el-button size="mini" type="primary" @click="openMockFileDialogForCreate">新增 Mock 文件</el-button>
<el-button size="mini" @click="openMockGroupDialog">分组管理</el-button> <el-button size="mini" @click="openMockGroupDialog">分组管理</el-button>
</div> </div>
@ -193,6 +195,7 @@
<strong>接口列表</strong> <strong>接口列表</strong>
<div style="display:flex;gap:8px;align-items:center;"> <div style="display:flex;gap:8px;align-items:center;">
<el-input size="small" v-model="apiSearch" placeholder="搜索接口名称或路径" clearable style="width:220px;" prefix-icon="el-icon-search"></el-input> <el-input size="small" v-model="apiSearch" placeholder="搜索接口名称或路径" clearable style="width:220px;" prefix-icon="el-icon-search"></el-input>
<el-button size="mini" icon="el-icon-refresh" :loading="apiRefreshing" @click="refreshApiList">刷新</el-button>
<el-button size="mini" type="primary" @click="openApiDialogForCreate">新增接口</el-button> <el-button size="mini" type="primary" @click="openApiDialogForCreate">新增接口</el-button>
<el-button size="mini" type="success" @click="openBatchImportDialog">批量导入</el-button> <el-button size="mini" type="success" @click="openBatchImportDialog">批量导入</el-button>
</div> </div>
@ -229,6 +232,9 @@
<el-tab-pane label="基础配置" name="basic"> <el-tab-pane label="基础配置" name="basic">
<el-card class="section-card"> <el-card class="section-card">
<div style="display:flex;justify-content:flex-end;align-items:center;margin-bottom:12px;">
<el-button size="mini" icon="el-icon-refresh" :loading="configRefreshing" @click="refreshConfig">刷新</el-button>
</div>
<el-form :model="form.config" label-width="180px"> <el-form :model="form.config" label-width="180px">
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :span="12"> <el-col :span="12">
@ -559,6 +565,10 @@
data: function () { data: function () {
return { return {
activeMainTab: "routes", activeMainTab: "routes",
routesRefreshing: false,
mocksRefreshing: false,
apiRefreshing: false,
configRefreshing: false,
apiList: [], apiList: [],
apiPagination: { currentPage: 1, pageSize: 10 }, apiPagination: { currentPage: 1, pageSize: 10 },
apiDialog: { apiDialog: {
@ -660,6 +670,12 @@
}; };
}, },
watch: { watch: {
activeMainTab: function (tab) {
if (tab === "routes") { this.loadRoutes(); }
else if (tab === "mocks") { this.loadMockFiles(); this.loadMockGroups(); }
else if (tab === "api") { this.loadApiList(); }
else if (tab === "basic") { this.loadConfig(); }
},
routeSearch: function () { this.routePagination.currentPage = 1; }, routeSearch: function () { this.routePagination.currentPage = 1; },
mockFileSearch: function () { this.mockFilePagination.currentPage = 1; }, mockFileSearch: function () { this.mockFilePagination.currentPage = 1; },
mockGroupFilter: function () { this.mockFilePagination.currentPage = 1; }, mockGroupFilter: function () { this.mockFilePagination.currentPage = 1; },
@ -670,8 +686,64 @@
await this.loadMockFiles(); await this.loadMockFiles();
await this.loadMockGroups(); await this.loadMockGroups();
await this.loadConfig(); await this.loadConfig();
await this.loadRoutes();
}, },
methods: { methods: {
loadRoutes: async function () {
try {
var resp = await fetch("/__routes");
var data = await resp.json();
if (!resp.ok || data.success === false) {
throw new Error(data.error || "加载路由失败");
}
this.form.routes = this.toRouteArray(
data.routes || {},
data.routeStatuses || {},
data.routeEnabledMap || {},
data.routeApiNameMap || {},
);
this.routePagination.currentPage = 1;
} catch (err) {
this.$message.error("加载路由失败: " + err.message);
}
},
refreshRoutes: async function () {
this.routesRefreshing = true;
try {
await this.loadRoutes();
this.$message.success("路由配置已刷新");
} finally {
this.routesRefreshing = false;
}
},
refreshMocks: async function () {
this.mocksRefreshing = true;
try {
await this.loadMockFiles();
await this.loadMockGroups();
this.$message.success("Mock 数据已刷新");
} finally {
this.mocksRefreshing = false;
}
},
refreshApiList: async function () {
this.apiRefreshing = true;
try {
await this.loadApiList();
this.$message.success("接口列表已刷新");
} finally {
this.apiRefreshing = false;
}
},
refreshConfig: async function () {
this.configRefreshing = true;
try {
await this.loadConfig();
this.$message.success("基础配置已刷新");
} finally {
this.configRefreshing = false;
}
},
getPreviewText: function (content) { getPreviewText: function (content) {
var text = String(content || "").replace(/\s+/g, " ").trim(); var text = String(content || "").replace(/\s+/g, " ").trim();
if (!text) return "(空文件)"; if (!text) return "(空文件)";
@ -974,13 +1046,6 @@
var resp = await fetch("/__config"); var resp = await fetch("/__config");
var data = await resp.json(); var data = await resp.json();
this.form.config = Object.assign({}, this.form.config, data.config || {}); this.form.config = Object.assign({}, this.form.config, data.config || {});
this.form.routes = this.toRouteArray(
data.routes || {},
data.routeStatuses || {},
data.routeEnabledMap || {},
data.routeApiNameMap || {},
);
this.routePagination.currentPage = 1;
} catch (err) { } catch (err) {
this.$message.error("加载配置失败: " + err.message); this.$message.error("加载配置失败: " + err.message);
} }
@ -1051,7 +1116,7 @@
); );
this.routeDialog.visible = false; this.routeDialog.visible = false;
await this.loadMockFiles(); await this.loadMockFiles();
await this.loadConfig(); await this.loadRoutes();
} catch (err) { } catch (err) {
this.$message.error("创建失败: " + err.message); this.$message.error("创建失败: " + err.message);
} }

View File

@ -135,13 +135,8 @@ async function handleConfig(
clientRes.end( clientRes.end(
JSON.stringify( JSON.stringify(
{ {
routes: state.rawRoutes,
routeStatuses: state.rawRouteStatuses,
routeEnabledMap: state.routeEnabledMap,
routeApiNameMap: state.routeApiNameMap,
config: state.config, config: state.config,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
totalRoutes: Object.keys(state.rawRoutes).length,
}, },
null, null,
2, 2,
@ -162,16 +157,31 @@ async function handleRoutes(
clientReq: http.IncomingMessage, clientReq: http.IncomingMessage,
clientRes: http.ServerResponse, clientRes: http.ServerResponse,
): Promise<void> { ): Promise<void> {
if (clientReq.method !== "POST") { if (clientReq.method !== "GET" && clientReq.method !== "POST") {
clientRes.writeHead(405, { clientRes.writeHead(405, {
"Content-Type": "application/json", "Content-Type": "application/json",
Allow: "POST", Allow: "GET, POST",
}); });
clientRes.end( clientRes.end(
JSON.stringify({ JSON.stringify({
success: false, success: false,
error: "Method Not Allowed", error: "Method Not Allowed",
allow: ["POST"], allow: ["GET, POST"],
}),
);
return;
}
if (clientReq.method === "GET") {
clientRes.writeHead(200, { "Content-Type": "application/json" });
clientRes.end(
JSON.stringify({
success: true,
routes: state.rawRoutes,
routeStatuses: state.rawRouteStatuses,
routeEnabledMap: state.routeEnabledMap,
routeApiNameMap: state.routeApiNameMap,
totalRoutes: Object.keys(state.rawRoutes).length,
}), }),
); );
return; return;