whistle.mockbubu 2.1.3 → 2.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whistle.mockbubu",
3
- "version": "2.1.3",
3
+ "version": "2.1.5",
4
4
  "description": "mock response data",
5
5
  "scripts": {
6
6
  "lint": "eslint . --ext .js",
package/public/js/app.js CHANGED
@@ -9177,236 +9177,4 @@ function createSingletonHook(hook) {
9177
9177
  /******/
9178
9178
  /******/ })()
9179
9179
  ;
9180
- //# sourceMappingURL=app.js.mapult().name), (element_ui_lib_radio__WEBPACK_IMPORTED_MODULE_32___default()));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].component((element_ui_lib_tabs__WEBPACK_IMPORTED_MODULE_30___default().name), (element_ui_lib_tabs__WEBPACK_IMPORTED_MODULE_30___default()));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].component((element_ui_lib_tab_pane__WEBPACK_IMPORTED_MODULE_28___default().name), (element_ui_lib_tab_pane__WEBPACK_IMPORTED_MODULE_28___default()));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].component((element_ui_lib_alert__WEBPACK_IMPORTED_MODULE_26___default().name), (element_ui_lib_alert__WEBPACK_IMPORTED_MODULE_26___default()));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].component((element_ui_lib_dropdown__WEBPACK_IMPORTED_MODULE_24___default().name), (element_ui_lib_dropdown__WEBPACK_IMPORTED_MODULE_24___default()));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].component((element_ui_lib_dropdown_item__WEBPACK_IMPORTED_MODULE_22___default().name), (element_ui_lib_dropdown_item__WEBPACK_IMPORTED_MODULE_22___default()));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].component((element_ui_lib_dropdown_menu__WEBPACK_IMPORTED_MODULE_20___default().name), (element_ui_lib_dropdown_menu__WEBPACK_IMPORTED_MODULE_20___default()));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].component((element_ui_lib_form__WEBPACK_IMPORTED_MODULE_18___default().name), (element_ui_lib_form__WEBPACK_IMPORTED_MODULE_18___default()));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].component((element_ui_lib_form_item__WEBPACK_IMPORTED_MODULE_16___default().name), (element_ui_lib_form_item__WEBPACK_IMPORTED_MODULE_16___default()));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].component((element_ui_lib_progress__WEBPACK_IMPORTED_MODULE_14___default().name), (element_ui_lib_progress__WEBPACK_IMPORTED_MODULE_14___default()));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].component((element_ui_lib_badge__WEBPACK_IMPORTED_MODULE_12___default().name), (element_ui_lib_badge__WEBPACK_IMPORTED_MODULE_12___default()));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].component((element_ui_lib_checkbox__WEBPACK_IMPORTED_MODULE_10___default().name), (element_ui_lib_checkbox__WEBPACK_IMPORTED_MODULE_10___default()));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].component((element_ui_lib_checkbox_group__WEBPACK_IMPORTED_MODULE_8___default().name), (element_ui_lib_checkbox_group__WEBPACK_IMPORTED_MODULE_8___default()));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].use((element_ui_lib_loading__WEBPACK_IMPORTED_MODULE_6___default().directive));\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].prototype.$loading = (element_ui_lib_loading__WEBPACK_IMPORTED_MODULE_6___default().service);\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].prototype.$message = (element_ui_lib_message__WEBPACK_IMPORTED_MODULE_4___default());\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].prototype.$msgbox = (element_ui_lib_message_box__WEBPACK_IMPORTED_MODULE_2___default());\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].prototype.$confirm = (element_ui_lib_message_box__WEBPACK_IMPORTED_MODULE_2___default().confirm);\nvue__WEBPACK_IMPORTED_MODULE_59__[\"default\"].config.productionTip = false;\nnew vue__WEBPACK_IMPORTED_MODULE_59__[\"default\"]({\n render: h => h(_App_vue__WEBPACK_IMPORTED_MODULE_60__[\"default\"])\n}).$mount('#app');\n\n//# sourceURL=webpack://web/./src/main.js?\n}");
9181
-
9182
- /***/ }),
9183
-
9184
- /***/ "./src/service/index.js":
9185
- /*!******************************!*\
9186
- !*** ./src/service/index.js ***!
9187
- \******************************/
9188
- /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
9189
-
9190
- "use strict";
9191
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ addVersion: function() { return /* binding */ addVersion; },\n/* harmony export */ batchDelete: function() { return /* binding */ batchDelete; },\n/* harmony export */ batchDeleteByNames: function() { return /* binding */ batchDeleteByNames; },\n/* harmony export */ batchUpdateMock: function() { return /* binding */ batchUpdateMock; },\n/* harmony export */ check: function() { return /* binding */ check; },\n/* harmony export */ copyGroup: function() { return /* binding */ copyGroup; },\n/* harmony export */ createGroup: function() { return /* binding */ createGroup; },\n/* harmony export */ deleteApi: function() { return /* binding */ deleteApi; },\n/* harmony export */ deleteGroup: function() { return /* binding */ deleteGroup; },\n/* harmony export */ deleteVersion: function() { return /* binding */ deleteVersion; },\n/* harmony export */ exportGroupsArchive: function() { return /* binding */ exportGroupsArchive; },\n/* harmony export */ getActiveRules: function() { return /* binding */ getActiveRules; },\n/* harmony export */ getApiData: function() { return /* binding */ getApiData; },\n/* harmony export */ getCurrentGroup: function() { return /* binding */ getCurrentGroup; },\n/* harmony export */ getGroups: function() { return /* binding */ getGroups; },\n/* harmony export */ getMemoryStats: function() { return /* binding */ getMemoryStats; },\n/* harmony export */ getSavedFiles: function() { return /* binding */ getSavedFiles; },\n/* harmony export */ getStorageStats: function() { return /* binding */ getStorageStats; },\n/* harmony export */ getVersions: function() { return /* binding */ getVersions; },\n/* harmony export */ importGroupsArchive: function() { return /* binding */ importGroupsArchive; },\n/* harmony export */ init: function() { return /* binding */ init; },\n/* harmony export */ saveFile: function() { return /* binding */ saveFile; },\n/* harmony export */ search: function() { return /* binding */ search; },\n/* harmony export */ setMockVersion: function() { return /* binding */ setMockVersion; },\n/* harmony export */ switchGroup: function() { return /* binding */ switchGroup; },\n/* harmony export */ updateApiData: function() { return /* binding */ updateApiData; },\n/* harmony export */ updateApiLock: function() { return /* binding */ updateApiLock; },\n/* harmony export */ updateApiMock: function() { return /* binding */ updateApiMock; },\n/* harmony export */ updateGroup: function() { return /* binding */ updateGroup; },\n/* harmony export */ updateVersionContent: function() { return /* binding */ updateVersionContent; },\n/* harmony export */ updateVersionMeta: function() { return /* binding */ updateVersionMeta; },\n/* harmony export */ updateVersionName: function() { return /* binding */ updateVersionName; }\n/* harmony export */ });\n/**\n * 获取已保存文件列表(首屏加载)\n *\n * @returns {Promise<Object>} 响应数据\n */\nfunction getSavedFiles() {\n return fetch('/cgi-bin/mockbubu/api-list-saved', {\n method: 'post',\n body: JSON.stringify({}),\n headers: {\n 'Content-Type': 'application/json',\n 'Cache-Control': 'no-cache, no-store, must-revalidate',\n Pragma: 'no-cache'\n },\n cache: 'no-store'\n }).then(response => {\n return response.json();\n });\n}\n\n/**\n * 增量轮询查询(只返回暂存区数据)\n *\n * @param {Object} params - 查询参数\n * @param {number} params.startTime - 轮询起始时间戳(0=首次轮询,>0=增量轮询)\n * @param {string} params.keyword - 可选,搜索关键词\n * @param {boolean} params.mock - 可选,筛选 mock 状态\n * @param {boolean} params.locked - 可选,筛选锁定状态\n * @returns {Promise<Object>} 响应数据\n */\nfunction search(params) {\n return fetch('/cgi-bin/mockbubu/api-list?_=' + Date.now(), {\n method: 'post',\n body: JSON.stringify(params),\n headers: {\n 'Content-Type': 'application/json',\n 'Cache-Control': 'no-cache, no-store, must-revalidate',\n Pragma: 'no-cache'\n },\n cache: 'no-store'\n }).then(response => {\n return response.json();\n });\n}\nfunction check() {\n return fetch('/cgi-bin/mockbubu/check-api-list?_=' + Date.now(), {\n headers: {\n 'Cache-Control': 'no-cache, no-store, must-revalidate',\n Pragma: 'no-cache'\n },\n cache: 'no-store'\n }).then(response => {\n return response.json();\n });\n}\nfunction init() {\n return fetch('/cgi-bin/init?_=' + Date.now(), {\n method: 'get',\n referrer: location.origin\n }).then(response => {\n return response.json();\n });\n}\nfunction getApiData(name) {\n return fetch('/cgi-bin/mockbubu/get-api-data?_=' + Date.now(), {\n method: 'post',\n body: JSON.stringify({\n name\n }),\n headers: {\n 'Content-Type': 'application/json',\n 'Cache-Control': 'no-cache, no-store, must-revalidate',\n Pragma: 'no-cache'\n },\n cache: 'no-store'\n }).then(response => {\n return response.json();\n });\n}\nfunction updateApiData(name, data) {\n return fetch('/cgi-bin/mockbubu/update-api-data', {\n method: 'post',\n body: JSON.stringify({\n name,\n data\n }),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction updateApiMock(name, mock) {\n return fetch('/cgi-bin/mockbubu/update-api-mock', {\n method: 'post',\n body: JSON.stringify({\n name,\n mock\n }),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction updateApiLock(name, locked) {\n return fetch('/cgi-bin/mockbubu/update-api-lock', {\n method: 'post',\n body: JSON.stringify({\n name,\n locked\n }),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction deleteApi(name) {\n return fetch('/cgi-bin/mockbubu/delete-api', {\n method: 'post',\n body: JSON.stringify({\n name\n }),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction batchDelete(params) {\n return fetch('/cgi-bin/mockbubu/batch-delete-api', {\n method: 'post',\n body: JSON.stringify(params),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction getVersions(params) {\n return fetch('/cgi-bin/mockbubu/get-versions', {\n method: 'post',\n body: JSON.stringify(params),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction addVersion(params) {\n return fetch('/cgi-bin/mockbubu/add-new-version', {\n method: 'post',\n body: JSON.stringify(params),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction deleteVersion(params) {\n return fetch('/cgi-bin/mockbubu/delete-version', {\n method: 'post',\n body: JSON.stringify(params),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction updateVersionContent(params) {\n return fetch('/cgi-bin/mockbubu/update-version-content', {\n method: 'post',\n body: JSON.stringify(params),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction updateVersionName(params) {\n return fetch('/cgi-bin/mockbubu/update-version-name', {\n method: 'post',\n body: JSON.stringify(params),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction setMockVersion(params) {\n return fetch('/cgi-bin/mockbubu/set-mock-version', {\n method: 'post',\n body: JSON.stringify(params),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction updateVersionMeta(params) {\n return fetch('/cgi-bin/mockbubu/update-version-meta', {\n method: 'post',\n body: JSON.stringify(params),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction batchUpdateMock(params) {\n return fetch('/cgi-bin/mockbubu/batch-update-mock', {\n method: 'post',\n body: JSON.stringify(params),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction batchDeleteByNames(params) {\n return fetch('/cgi-bin/mockbubu/batch-delete-by-names', {\n method: 'post',\n body: JSON.stringify(params),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\n\n// ============ 导入导出 API(压缩包) ============\n\n// 导出多个组为压缩包\nfunction exportGroupsArchive(groupIds) {\n return fetch('/cgi-bin/mockbubu/export-groups-archive', {\n method: 'post',\n body: JSON.stringify({\n groupIds\n }),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(async response => {\n // 先检查 Content-Type,判断是 JSON 错误还是二进制文件\n const contentType = response.headers.get('Content-Type');\n if (contentType && contentType.includes('application/json')) {\n // 后端返回了 JSON,说明出错了\n const errorData = await response.json();\n throw new Error(errorData.msg || '导出失败');\n }\n if (!response.ok) {\n throw new Error('导出失败: HTTP ' + response.status);\n }\n return response.blob();\n });\n}\n\n// 导入多个组的压缩包\nfunction importGroupsArchive(file) {\n const formData = new FormData();\n formData.append('file', file);\n return fetch('/cgi-bin/mockbubu/import-groups-archive', {\n method: 'post',\n body: formData\n }).then(response => {\n return response.json();\n });\n}\n\n// ============ 组管理 API ============\n\nfunction getGroups() {\n return fetch('/cgi-bin/mockbubu/groups/list', {\n method: 'post',\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction getCurrentGroup() {\n return fetch('/cgi-bin/mockbubu/groups/current', {\n method: 'post',\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction createGroup(params) {\n return fetch('/cgi-bin/mockbubu/groups/create', {\n method: 'post',\n body: JSON.stringify(params),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction updateGroup(groupId, params) {\n return fetch('/cgi-bin/mockbubu/groups/update', {\n method: 'post',\n body: JSON.stringify({\n groupId,\n ...params\n }),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction deleteGroup(groupId) {\n return fetch('/cgi-bin/mockbubu/groups/delete', {\n method: 'post',\n body: JSON.stringify({\n groupId\n }),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction switchGroup(groupId) {\n return fetch('/cgi-bin/mockbubu/groups/switch', {\n method: 'post',\n body: JSON.stringify({\n groupId\n }),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\nfunction copyGroup(sourceGroupId, params) {\n return fetch('/cgi-bin/mockbubu/groups/copy', {\n method: 'post',\n body: JSON.stringify({\n sourceGroupId,\n ...params\n }),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n return response.json();\n });\n}\n\n// ============ 存储管理 API ============\n\n// 获取存储统计信息\nfunction getStorageStats() {\n return fetch('cgi-bin/mockbubu/storage-stats', {\n method: 'get',\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n return response.json();\n });\n}\n\n// 获取生效的 Whistle 规则\nfunction getActiveRules() {\n return fetch('cgi-bin/mockbubu/active-rules', {\n method: 'get',\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n return response.json();\n });\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n getSavedFiles,\n search,\n check,\n init,\n getApiData,\n updateApiData,\n updateApiMock,\n updateApiLock,\n deleteApi,\n batchDelete,\n getVersions,\n addVersion,\n deleteVersion,\n updateVersionContent,\n updateVersionName,\n setMockVersion,\n updateVersionMeta,\n batchUpdateMock,\n batchDeleteByNames,\n exportGroupsArchive,\n importGroupsArchive,\n getGroups,\n getCurrentGroup,\n createGroup,\n updateGroup,\n deleteGroup,\n switchGroup,\n copyGroup,\n getStorageStats,\n getMemoryStats,\n getActiveRules,\n saveFile\n});\nfunction getMemoryStats() {\n return fetch('/cgi-bin/mockbubu/memory-stats?_=' + Date.now(), {\n headers: {\n 'Cache-Control': 'no-cache, no-store, must-revalidate',\n Pragma: 'no-cache'\n },\n cache: 'no-store'\n }).then(response => {\n return response.json();\n });\n}\n\n/**\n * 首次保存文件(前端缓存 → 文件系统)\n *\n * @param {Object} params - 文件数据\n * @param {string} params.url - 请求URL\n * @param {string} params.method - HTTP方法\n * @param {number} params.status - 状态码\n * @param {Object} params.session - 完整会话数据\n * @returns {Promise<Object>} 响应数据\n */\nfunction saveFile(params) {\n console.log('[API] saveFile 被调用:', {\n url: params.url,\n method: params.method,\n hasSession: !!params.session\n });\n return fetch('/cgi-bin/mockbubu/file-save', {\n method: 'post',\n body: JSON.stringify(params),\n headers: {\n 'Content-Type': 'application/json'\n }\n }).then(response => {\n console.log('[API] saveFile 响应:', response.status);\n return response.json();\n }).then(data => {\n console.log('[API] saveFile 返回数据:', data);\n return data;\n });\n}\n\n//# sourceURL=webpack://web/./src/service/index.js?\n}");
9192
-
9193
- /***/ }),
9194
-
9195
- /***/ "./src/util.js":
9196
- /*!*********************!*\
9197
- !*** ./src/util.js ***!
9198
- \*********************/
9199
- /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
9200
-
9201
- eval("{__webpack_require__(/*! core-js/modules/es.iterator.constructor.js */ \"./node_modules/core-js/modules/es.iterator.constructor.js\");\n__webpack_require__(/*! core-js/modules/es.iterator.filter.js */ \"./node_modules/core-js/modules/es.iterator.filter.js\");\n__webpack_require__(/*! core-js/modules/es.iterator.map.js */ \"./node_modules/core-js/modules/es.iterator.map.js\");\nexports.getActiveRules = (rules = '') => {\n return rules.split('\\n').map(i => i.trim()).filter(i => i[0] !== '#').filter(i => ~i.indexOf('mockbubu://')).map(i => i.trim()).map(i => i.replace(/\\s+/, ' '));\n};\n\n//# sourceURL=webpack://web/./src/util.js?\n}");
9202
-
9203
- /***/ }),
9204
-
9205
- /***/ "./src/utils/cache-manager.js":
9206
- /*!************************************!*\
9207
- !*** ./src/utils/cache-manager.js ***!
9208
- \************************************/
9209
- /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
9210
-
9211
- "use strict";
9212
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var core_js_modules_es_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/es.iterator.constructor.js */ \"./node_modules/core-js/modules/es.iterator.constructor.js\");\n/* harmony import */ var core_js_modules_es_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var core_js_modules_es_iterator_for_each_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! core-js/modules/es.iterator.for-each.js */ \"./node_modules/core-js/modules/es.iterator.for-each.js\");\n/* harmony import */ var core_js_modules_es_iterator_for_each_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_iterator_for_each_js__WEBPACK_IMPORTED_MODULE_1__);\n\n\n/**\n * 前端缓存管理器\n *\n * 职责:\n * - 缓存所有捕获的请求数据(URL → session)\n * - URL 去重(已存在则跳过新数据,保留旧的)\n * - 容量管理(滑动窗口清理)\n * - 提供查询、过滤、删除等操作\n *\n * 核心规则:\n * - 完整数据生命周期管理(从捕获到保存/删除)\n * - URL 去重:已存在时跳过新数据(保留旧的)\n * - 容量上限:2000 条,超出触发滑动窗口清理\n */\n\n// 缓存容量配置\nconst CACHE_CONFIG = {\n MAX_SIZE: 2000,\n // 最大缓存容量\n CLEANUP_BATCH_SIZE: 200 // 滑动窗口清理批次大小\n};\nclass CacheManager {\n constructor() {\n // Key: url (完整 URL)\n // Value: { url, method, status, session, captureTime, groupId }\n this.cache = new Map();\n this.currentGroupId = null; // 当前激活的组ID\n }\n\n /**\n * 设置当前组ID\n *\n * @param {string} groupId - 组ID\n */\n setCurrentGroupId(groupId) {\n this.currentGroupId = groupId;\n console.log(`[CacheManager] 设置当前组ID: ${groupId}`);\n }\n\n /**\n * 切换组(清空旧组数据)\n *\n * @param {string} newGroupId - 新组ID\n */\n switchGroup(newGroupId) {\n if (this.currentGroupId === newGroupId) {\n console.log(`[CacheManager] 已经是当前组,无需切换: ${newGroupId}`);\n return;\n }\n console.log(`[CacheManager] 切换组: ${this.currentGroupId} -> ${newGroupId}`);\n\n // 清空旧组的所有缓存数据\n const oldSize = this.cache.size;\n this.cache.clear();\n console.log(`[CacheManager] 切换组时清空缓存,已清除 ${oldSize} 条`);\n\n // 更新当前组ID\n this.currentGroupId = newGroupId;\n }\n\n /**\n * 添加数据到缓存\n *\n * 去重规则:URL 已存在时跳过新数据(保留旧的)\n *\n * @param {Object} data - 捕获数据\n * @param {string} data.url - 请求URL\n * @param {string} data.method - HTTP方法\n * @param {number} data.status - 状态码\n * @param {Object} data.session - 完整会话数据\n * @param {string} data.groupId - 组ID(可选)\n * @param {boolean} skipCleanup - 是否跳过清理(批量添加时使用)\n * @returns {boolean} 是否成功添加(false 表示已存在被跳过)\n */\n add(data, skipCleanup = false) {\n const {\n url,\n method,\n status,\n session,\n captureTime,\n groupId\n } = data;\n\n // 参数校验\n if (!url || !method || !status || !session) {\n console.error('[CacheManager] add 参数不完整', {\n hasUrl: !!url,\n hasMethod: !!method,\n hasStatus: !!status,\n hasSession: !!session\n });\n return false;\n }\n\n // 去重:已存在则跳过(保留旧的)\n if (this.cache.has(url)) {\n console.log(`[CacheManager] 缓存已存在,跳过: ${url}`);\n return false;\n }\n\n // 新增到缓存\n this.cache.set(url, {\n url,\n method,\n status,\n session,\n captureTime: captureTime || Date.now(),\n groupId: groupId || this.currentGroupId // 记录组ID\n });\n console.log(`[CacheManager] 缓存新增: ${url} (组: ${groupId || this.currentGroupId}, 当前容量: ${this.cache.size})`);\n\n // 容量检查:超出上限触发滑动窗口清理(批量添加时跳过)\n if (!skipCleanup && this.cache.size > CACHE_CONFIG.MAX_SIZE) {\n this.slidingWindowCleanup();\n }\n return true;\n }\n\n /**\n * 批量添加数据\n *\n * 批量添加优化:先批量添加所有数据,最后统一清理\n * 避免每次添加都触发清理,提升性能\n *\n * @param {Array<Object>} dataList - 数据列表\n * @returns {number} 成功添加的数量\n */\n addBatch(dataList) {\n if (!Array.isArray(dataList)) {\n console.error('[CacheManager] addBatch 参数必须是数组');\n return 0;\n }\n let addedCount = 0;\n // 批量添加时跳过单次清理\n dataList.forEach(data => {\n if (this.add(data, true)) {\n addedCount++;\n }\n });\n console.log(`[CacheManager] 批量添加完成,新增 ${addedCount} 条,跳过 ${dataList.length - addedCount} 条`);\n\n // 批量添加后统一清理到合理容量\n if (this.cache.size > CACHE_CONFIG.MAX_SIZE) {\n const needCleanup = this.cache.size - CACHE_CONFIG.MAX_SIZE;\n const cleanupBatches = Math.ceil(needCleanup / CACHE_CONFIG.CLEANUP_BATCH_SIZE);\n console.log(`[CacheManager] 需要清理 ${needCleanup} 条,将执行 ${cleanupBatches} 次批量清理`);\n for (let i = 0; i < cleanupBatches; i++) {\n if (this.cache.size > CACHE_CONFIG.MAX_SIZE) {\n this.slidingWindowCleanup();\n }\n }\n }\n return addedCount;\n }\n\n /**\n * 获取所有缓存数据(数组形式)\n *\n * @returns {Array<Object>} 缓存数据列表\n */\n getAll() {\n return Array.from(this.cache.values());\n }\n\n /**\n * 根据 URL 获取数据\n *\n * @param {string} url - 请求URL\n * @returns {Object|null} 缓存数据\n */\n get(url) {\n return this.cache.get(url) || null;\n }\n\n /**\n * 检查 URL 是否存在\n *\n * @param {string} url - 请求URL\n * @returns {boolean}\n */\n has(url) {\n return this.cache.has(url);\n }\n\n /**\n * 删除指定 URL 的数据\n *\n * @param {string} url - 请求URL\n * @returns {boolean} 是否删除成功\n */\n remove(url) {\n const deleted = this.cache.delete(url);\n if (deleted) {\n console.log(`[CacheManager] 删除缓存: ${url} (剩余容量: ${this.cache.size})`);\n }\n return deleted;\n }\n\n /**\n * 批量删除\n *\n * @param {Array<string>} urls - URL 列表\n * @returns {number} 删除的数量\n */\n removeBatch(urls) {\n if (!Array.isArray(urls)) {\n console.error('[CacheManager] removeBatch 参数必须是数组');\n return 0;\n }\n let deletedCount = 0;\n urls.forEach(url => {\n if (this.remove(url)) {\n deletedCount++;\n }\n });\n console.log(`[CacheManager] 批量删除完成,删除 ${deletedCount} 条`);\n return deletedCount;\n }\n\n /**\n * 清空所有缓存\n */\n clear() {\n const oldSize = this.cache.size;\n this.cache.clear();\n console.log(`[CacheManager] 清空缓存,已清除 ${oldSize} 条`);\n }\n\n /**\n * 滑动窗口清理\n *\n * 清理策略:\n * - 按 captureTime 排序(最旧的在前)\n * - 删除最旧的 CLEANUP_BATCH_SIZE 条数据\n */\n slidingWindowCleanup() {\n const entries = Array.from(this.cache.entries());\n\n // 按时间排序(最旧的在前)\n entries.sort((a, b) => a[1].captureTime - b[1].captureTime);\n\n // 删除最旧的数据\n const toRemove = entries.slice(0, CACHE_CONFIG.CLEANUP_BATCH_SIZE);\n toRemove.forEach(([url]) => {\n this.cache.delete(url);\n });\n console.log(`[CacheManager] 滑动窗口清理 ${toRemove.length} 条 (剩余容量: ${this.cache.size})`);\n }\n\n /**\n * 获取统计信息\n *\n * @returns {Object} 统计信息\n */\n getStats() {\n return {\n size: this.cache.size,\n maxSize: CACHE_CONFIG.MAX_SIZE\n };\n }\n}\n\n// 导出单例实例\n/* harmony default export */ __webpack_exports__[\"default\"] = (new CacheManager());\n\n//# sourceURL=webpack://web/./src/utils/cache-manager.js?\n}");
9213
-
9214
- /***/ }),
9215
-
9216
- /***/ "./src/utils/createSingletonHook.js":
9217
- /*!******************************************!*\
9218
- !*** ./src/utils/createSingletonHook.js ***!
9219
- \******************************************/
9220
- /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
9221
-
9222
- "use strict";
9223
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ createSingletonHook: function() { return /* binding */ createSingletonHook; }\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm.js\");\n\n\n/**\n * @function createSingletonHook\n * @description 创建一个单例 Hook,用于确保某个 Hook 在组件树中只被初始化一次。\n * @param {Function} hook - 要包装为单例的 Hook 函数。\n * @returns {Function} 包装后的单例 Hook 函数。\n *\n * @example\n * // 定义一个普通 Hook\n * function useExampleHook(param) {\n * const state = ref(param)\n * return { state }\n * }\n *\n * // 创建单例 Hook\n * const useSingletonExampleHook = createSingletonHook(useExampleHook)\n *\n * // 在组件中使用\n * export default {\n * setup() {\n * const instance = useSingletonExampleHook('initial value')\n * return { instance }\n * }\n * }\n */\nfunction createSingletonHook(hook) {\n const key = Symbol(hook.name);\n return (...args) => {\n // 尝试获取已存在的实例\n const existing = (0,vue__WEBPACK_IMPORTED_MODULE_0__.inject)(key, null);\n if (existing) return existing;\n\n // 创建新实例\n const instance = hook(...args);\n\n // 注入单例\n (0,vue__WEBPACK_IMPORTED_MODULE_0__.provide)(key, instance);\n return instance;\n };\n}\n\n//# sourceURL=webpack://web/./src/utils/createSingletonHook.js?\n}");
9224
-
9225
- /***/ })
9226
-
9227
- /******/ });
9228
- /************************************************************************/
9229
- /******/ // The module cache
9230
- /******/ var __webpack_module_cache__ = {};
9231
- /******/
9232
- /******/ // The require function
9233
- /******/ function __webpack_require__(moduleId) {
9234
- /******/ // Check if module is in cache
9235
- /******/ var cachedModule = __webpack_module_cache__[moduleId];
9236
- /******/ if (cachedModule !== undefined) {
9237
- /******/ return cachedModule.exports;
9238
- /******/ }
9239
- /******/ // Create a new module (and put it into the cache)
9240
- /******/ var module = __webpack_module_cache__[moduleId] = {
9241
- /******/ id: moduleId,
9242
- /******/ // no module.loaded needed
9243
- /******/ exports: {}
9244
- /******/ };
9245
- /******/
9246
- /******/ // Execute the module function
9247
- /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
9248
- /******/
9249
- /******/ // Return the exports of the module
9250
- /******/ return module.exports;
9251
- /******/ }
9252
- /******/
9253
- /******/ // expose the modules object (__webpack_modules__)
9254
- /******/ __webpack_require__.m = __webpack_modules__;
9255
- /******/
9256
- /************************************************************************/
9257
- /******/ /* webpack/runtime/chunk loaded */
9258
- /******/ !function() {
9259
- /******/ var deferred = [];
9260
- /******/ __webpack_require__.O = function(result, chunkIds, fn, priority) {
9261
- /******/ if(chunkIds) {
9262
- /******/ priority = priority || 0;
9263
- /******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
9264
- /******/ deferred[i] = [chunkIds, fn, priority];
9265
- /******/ return;
9266
- /******/ }
9267
- /******/ var notFulfilled = Infinity;
9268
- /******/ for (var i = 0; i < deferred.length; i++) {
9269
- /******/ var chunkIds = deferred[i][0];
9270
- /******/ var fn = deferred[i][1];
9271
- /******/ var priority = deferred[i][2];
9272
- /******/ var fulfilled = true;
9273
- /******/ for (var j = 0; j < chunkIds.length; j++) {
9274
- /******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every(function(key) { return __webpack_require__.O[key](chunkIds[j]); })) {
9275
- /******/ chunkIds.splice(j--, 1);
9276
- /******/ } else {
9277
- /******/ fulfilled = false;
9278
- /******/ if(priority < notFulfilled) notFulfilled = priority;
9279
- /******/ }
9280
- /******/ }
9281
- /******/ if(fulfilled) {
9282
- /******/ deferred.splice(i--, 1)
9283
- /******/ var r = fn();
9284
- /******/ if (r !== undefined) result = r;
9285
- /******/ }
9286
- /******/ }
9287
- /******/ return result;
9288
- /******/ };
9289
- /******/ }();
9290
- /******/
9291
- /******/ /* webpack/runtime/compat get default export */
9292
- /******/ !function() {
9293
- /******/ // getDefaultExport function for compatibility with non-harmony modules
9294
- /******/ __webpack_require__.n = function(module) {
9295
- /******/ var getter = module && module.__esModule ?
9296
- /******/ function() { return module['default']; } :
9297
- /******/ function() { return module; };
9298
- /******/ __webpack_require__.d(getter, { a: getter });
9299
- /******/ return getter;
9300
- /******/ };
9301
- /******/ }();
9302
- /******/
9303
- /******/ /* webpack/runtime/define property getters */
9304
- /******/ !function() {
9305
- /******/ // define getter functions for harmony exports
9306
- /******/ __webpack_require__.d = function(exports, definition) {
9307
- /******/ for(var key in definition) {
9308
- /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
9309
- /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
9310
- /******/ }
9311
- /******/ }
9312
- /******/ };
9313
- /******/ }();
9314
- /******/
9315
- /******/ /* webpack/runtime/global */
9316
- /******/ !function() {
9317
- /******/ __webpack_require__.g = (function() {
9318
- /******/ if (typeof globalThis === 'object') return globalThis;
9319
- /******/ try {
9320
- /******/ return this || new Function('return this')();
9321
- /******/ } catch (e) {
9322
- /******/ if (typeof window === 'object') return window;
9323
- /******/ }
9324
- /******/ })();
9325
- /******/ }();
9326
- /******/
9327
- /******/ /* webpack/runtime/hasOwnProperty shorthand */
9328
- /******/ !function() {
9329
- /******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
9330
- /******/ }();
9331
- /******/
9332
- /******/ /* webpack/runtime/make namespace object */
9333
- /******/ !function() {
9334
- /******/ // define __esModule on exports
9335
- /******/ __webpack_require__.r = function(exports) {
9336
- /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
9337
- /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
9338
- /******/ }
9339
- /******/ Object.defineProperty(exports, '__esModule', { value: true });
9340
- /******/ };
9341
- /******/ }();
9342
- /******/
9343
- /******/ /* webpack/runtime/publicPath */
9344
- /******/ !function() {
9345
- /******/ __webpack_require__.p = "/";
9346
- /******/ }();
9347
- /******/
9348
- /******/ /* webpack/runtime/jsonp chunk loading */
9349
- /******/ !function() {
9350
- /******/ __webpack_require__.b = document.baseURI || self.location.href;
9351
- /******/
9352
- /******/ // object to store loaded and loading chunks
9353
- /******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
9354
- /******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
9355
- /******/ var installedChunks = {
9356
- /******/ "app": 0
9357
- /******/ };
9358
- /******/
9359
- /******/ // no chunk on demand loading
9360
- /******/
9361
- /******/ // no prefetching
9362
- /******/
9363
- /******/ // no preloaded
9364
- /******/
9365
- /******/ // no HMR
9366
- /******/
9367
- /******/ // no HMR manifest
9368
- /******/
9369
- /******/ __webpack_require__.O.j = function(chunkId) { return installedChunks[chunkId] === 0; };
9370
- /******/
9371
- /******/ // install a JSONP callback for chunk loading
9372
- /******/ var webpackJsonpCallback = function(parentChunkLoadingFunction, data) {
9373
- /******/ var chunkIds = data[0];
9374
- /******/ var moreModules = data[1];
9375
- /******/ var runtime = data[2];
9376
- /******/ // add "moreModules" to the modules object,
9377
- /******/ // then flag all "chunkIds" as loaded and fire callback
9378
- /******/ var moduleId, chunkId, i = 0;
9379
- /******/ if(chunkIds.some(function(id) { return installedChunks[id] !== 0; })) {
9380
- /******/ for(moduleId in moreModules) {
9381
- /******/ if(__webpack_require__.o(moreModules, moduleId)) {
9382
- /******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
9383
- /******/ }
9384
- /******/ }
9385
- /******/ if(runtime) var result = runtime(__webpack_require__);
9386
- /******/ }
9387
- /******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
9388
- /******/ for(;i < chunkIds.length; i++) {
9389
- /******/ chunkId = chunkIds[i];
9390
- /******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
9391
- /******/ installedChunks[chunkId][0]();
9392
- /******/ }
9393
- /******/ installedChunks[chunkId] = 0;
9394
- /******/ }
9395
- /******/ return __webpack_require__.O(result);
9396
- /******/ }
9397
- /******/
9398
- /******/ var chunkLoadingGlobal = self["webpackChunkweb"] = self["webpackChunkweb"] || [];
9399
- /******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
9400
- /******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
9401
- /******/ }();
9402
- /******/
9403
- /************************************************************************/
9404
- /******/
9405
- /******/ // startup
9406
- /******/ // Load entry module and return exports
9407
- /******/ // This entry module depends on other loaded chunks and execution need to be delayed
9408
- /******/ var __webpack_exports__ = __webpack_require__.O(undefined, ["chunk-vendors"], function() { return __webpack_require__("./src/main.js"); })
9409
- /******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__);
9410
- /******/
9411
- /******/ })()
9412
- ;
9180
+ //# sourceMappingURL=app.js.map