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 @@
{
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;
}