From ad1d7606537f9c5fa9e4273a93ce395178a340d5 Mon Sep 17 00:00:00 2001 From: iqudoo Date: Thu, 4 Jun 2026 11:56:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=8C=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E6=94=AF=E6=8C=81=E9=80=9A=E8=BF=87url?= =?UTF-8?q?=E8=BF=87=E6=BB=A4=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 166 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 140 insertions(+), 26 deletions(-) diff --git a/src/App.vue b/src/App.vue index 1486908..9829a41 100644 --- a/src/App.vue +++ b/src/App.vue @@ -234,6 +234,34 @@
接口

{{ currentApi.action }}

+
+
+ 用户组 + + {{ item }} + +
+
+ 场景组 + + {{ item }} + +
+
{ if (isMobile.value) return "100%"; return `${Math.min(800, windowWidth.value)}px`; }); +const displayApiGroups = computed(() => { + const source = apiDetail.value || currentApi.value; + return normalizeStringList(source?.groups); +}); + +const displayApiScenes = computed(() => { + const source = apiDetail.value || currentApi.value; + return normalizeStringList(source?.scenes); +}); + // 监听搜索,如果有搜索则自动返回根级别显示所有匹配结果 watch(searchQuery, (newVal) => { if (newVal && newVal.trim()) { @@ -878,13 +918,54 @@ const initDB = () => { }; // 从 IndexedDB 获取缓存的接口列表 +const getApiListCacheKey = () => { + const group = filterGroup.value || ""; + const scene = filterScene.value || ""; + return `api-list|${group}|${scene}`; +}; + +const normalizeStringList = (value) => { + if (!value) return []; + return Array.isArray(value) ? value.filter((item) => item != null && item !== "") : [String(value)]; +}; + +const readFiltersFromUrl = () => { + const urlParams = new URLSearchParams(window.location.search); + filterGroup.value = urlParams.get("group") || ""; + filterScene.value = urlParams.get("scene") || ""; +}; + +const syncFiltersToUrl = (url) => { + if (filterGroup.value) { + url.searchParams.set("group", filterGroup.value); + } else { + url.searchParams.delete("group"); + } + if (filterScene.value) { + url.searchParams.set("scene", filterScene.value); + } else { + url.searchParams.delete("scene"); + } +}; + +const buildActionListQueryParams = () => { + const query = { action: "getActionList" }; + if (filterGroup.value) { + query.group = filterGroup.value; + } + if (filterScene.value) { + query.scene = filterScene.value; + } + return query; +}; + const getCachedApiList = async () => { try { const db = await initDB(); return new Promise((resolve, reject) => { const transaction = db.transaction([STORE_NAME], "readonly"); const store = transaction.objectStore(STORE_NAME); - const request = store.get("api-list"); + const request = store.get(getApiListCacheKey()); request.onsuccess = () => resolve(request.result || null); request.onerror = () => reject(request.error); }); @@ -901,7 +982,7 @@ const saveApiListToCache = async (apiList) => { return new Promise((resolve, reject) => { const transaction = db.transaction([STORE_NAME], "readwrite"); const store = transaction.objectStore(STORE_NAME); - const request = store.put(apiList, "api-list"); + const request = store.put(apiList, getApiListCacheKey()); request.onsuccess = () => resolve(); request.onerror = () => reject(request.error); }); @@ -956,10 +1037,22 @@ const processApiList = (apiData) => { onMounted(async () => { checkDeviceType(); window.addEventListener("resize", checkDeviceType); + readFiltersFromUrl(); loading.value = true; // 先显示加载状态,避免显示空白页面 loadError.value = null; + const openApiFromUrl = () => { + const urlParams = new URLSearchParams(window.location.search); + const id = urlParams.get("id"); + if (id) { + const apiToShow = findApiById(id); + if (apiToShow) { + goToApi(apiToShow); + } + } + }; + // 先从缓存获取接口列表 let cachedApiList = null; try { @@ -969,16 +1062,7 @@ onMounted(async () => { apis.value = processApiList(cachedApiList); // 有缓存数据后,立即隐藏加载状态,让用户看到内容 loading.value = false; - - // 检查URL是否包含API id参数 - const urlParams = new URLSearchParams(window.location.search); - const id = urlParams.get("id"); - if (id) { - const apiToShow = findApiById(id); - if (apiToShow) { - goToApi(apiToShow); - } - } + openApiFromUrl(); } // 如果没有缓存数据,继续显示加载状态,等待请求完成 } catch (error) { @@ -989,9 +1073,7 @@ onMounted(async () => { // 然后请求最新的接口列表(后台无感刷新) try { const response = await axios.get(hostUrl.value, { - params: { - action: "getActionList", - }, + params: buildActionListQueryParams(), }); // 处理并保存最新的接口列表 @@ -1001,15 +1083,7 @@ onMounted(async () => { // 保存到缓存 await saveApiListToCache(response.data.data); - // 检查URL是否包含API id参数 - const urlParams = new URLSearchParams(window.location.search); - const id = urlParams.get("id"); - if (id) { - const apiToShow = findApiById(id); - if (apiToShow) { - goToApi(apiToShow); - } - } + openApiFromUrl(); } catch (error) { console.error("Failed to fetch API list:", error); // 如果请求失败且没有缓存数据,显示错误 @@ -1024,7 +1098,6 @@ onMounted(async () => { // 确保最终隐藏加载状态(如果没有缓存数据,这里会隐藏;如果有缓存数据,已经在上面隐藏了) loading.value = false; } - }); // 根据id查找API @@ -1032,9 +1105,10 @@ const findApiById = (id) => { return apis.value.find((a) => a.uniqueId === id || a.originalId === id) || null; }; -// 更新URL参数 +// 更新URL参数(保留 group / scene 过滤参数) const updateUrlParameter = (id) => { const url = new URL(window.location); + syncFiltersToUrl(url); if (id) { url.searchParams.set("id", id); } else { @@ -1914,6 +1988,18 @@ const generateSingleApiMarkdown = (api, detail) => { // 接口详情 markdown += `## ${api.action}\n\n`; + const groups = normalizeStringList(detail?.groups ?? api.groups); + const scenes = normalizeStringList(detail?.scenes ?? api.scenes); + if (groups.length) { + markdown += `- 用户组:${groups.join("、")}\n`; + } + if (scenes.length) { + markdown += `- 场景组:${scenes.join("、")}\n`; + } + if (groups.length || scenes.length) { + markdown += "\n"; + } + if (detail) { // 请求参数 if (detail.paramModel) { @@ -2746,6 +2832,34 @@ const handleExportSelected = async () => { font-family: "SF Mono", "Menlo", "Monaco", "Consolas", monospace; } +.api-meta-row { + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 10px; +} + +.api-meta-item { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 6px; +} + +.api-meta-label { + font-size: 12px; + color: #8f959e; + flex-shrink: 0; +} + +.api-meta-tag { + font-family: "SF Mono", "Menlo", "Monaco", "Consolas", monospace; +} + +.brand-filter-hint { + color: #8f959e; +} + .api-detail-alert { margin-bottom: 16px; }