bmp-layout 0.0.25-beta.12 → 0.0.25-beta.14

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/bmp-layout.es.js CHANGED
@@ -1302,6 +1302,26 @@ const usePermissionStore = defineStore("layout-permission", {
1302
1302
  },
1303
1303
  getModuleName() {
1304
1304
  return this.moduleName;
1305
+ },
1306
+ /**
1307
+ * 获取当前用户已授权的所有菜单 ID 集合
1308
+ * 递归遍历 roleRouters 树形结构,提取所有菜单的 id
1309
+ * @returns {Set<string>} 已授权的菜单 ID 集合
1310
+ */
1311
+ getGrantedMenuIds() {
1312
+ const ids = /* @__PURE__ */ new Set();
1313
+ const traverse = (menus) => {
1314
+ if (!Array.isArray(menus))
1315
+ return;
1316
+ for (const menu of menus) {
1317
+ if (menu.id)
1318
+ ids.add(String(menu.id));
1319
+ if (menu.children)
1320
+ traverse(menu.children);
1321
+ }
1322
+ };
1323
+ traverse(this.roleRouters);
1324
+ return ids;
1305
1325
  }
1306
1326
  },
1307
1327
  actions: {
@@ -8588,11 +8608,236 @@ const _sfc_main$s = /* @__PURE__ */ Object.assign({ name: "MenuTrigger" }, {
8588
8608
  }
8589
8609
  });
8590
8610
  const MenuTrigger = /* @__PURE__ */ _export_sfc(_sfc_main$s, [["__scopeId", "data-v-df837f35"]]);
8611
+ const useFavoriteStore = defineStore("layout-favorite", {
8612
+ state: () => ({
8613
+ /**
8614
+ * 收藏列表(后端 /list 返回结构:menuId, menuName, leafPath, moduleId, modulePath, moduleName, isFavorite=true, createTime)
8615
+ */
8616
+ favorites: [],
8617
+ /**
8618
+ * 最近使用列表(后端 /list 返回结构:menuId, menuName, leafPath, moduleId, modulePath, moduleName, isFavorite, visitCount, lastVisitTime)
8619
+ */
8620
+ recents: [],
8621
+ /**
8622
+ * 已收藏菜单ID集合(Set,用于所有位置快速判断是否已收藏)
8623
+ */
8624
+ favoriteSet: /* @__PURE__ */ new Set(),
8625
+ /**
8626
+ * 是否已初始化拉取过数据(防止重复请求)
8627
+ */
8628
+ loaded: false,
8629
+ /**
8630
+ * 当前正在执行的收藏操作ID集合(防抖/防重复点击)
8631
+ */
8632
+ loadingIds: /* @__PURE__ */ new Set()
8633
+ }),
8634
+ getters: {
8635
+ /**
8636
+ * 获取当前用户已授权的菜单 ID 集合(从 permissionStore 读取)
8637
+ */
8638
+ grantedMenuIds() {
8639
+ const permissionStore = usePermissionStore();
8640
+ return permissionStore.getGrantedMenuIds;
8641
+ },
8642
+ /**
8643
+ * 收藏列表(对外只读,已过滤无权限菜单)
8644
+ */
8645
+ getFavorites() {
8646
+ const granted = this.grantedMenuIds;
8647
+ return this.favorites.filter((item) => granted.has(String(item.menuId)));
8648
+ },
8649
+ /**
8650
+ * 最近使用列表(已过滤无权限菜单,isFavorite 实时派生)
8651
+ * 注意:返回的是新数组,不直接修改 state
8652
+ */
8653
+ getRecents() {
8654
+ const granted = this.grantedMenuIds;
8655
+ return this.recents.filter((item) => granted.has(String(item.menuId))).map((item) => ({
8656
+ ...item,
8657
+ isFavorite: this.favoriteSet.has(item.menuId)
8658
+ }));
8659
+ },
8660
+ /**
8661
+ * 收藏集合(用于快速判断)
8662
+ */
8663
+ getFavoriteSet() {
8664
+ return this.favoriteSet;
8665
+ },
8666
+ /**
8667
+ * 是否已加载
8668
+ */
8669
+ isLoaded() {
8670
+ return () => this.loaded;
8671
+ },
8672
+ /**
8673
+ * 检查指定菜单是否已收藏
8674
+ */
8675
+ isFavorite() {
8676
+ return (menuId) => this.favoriteSet.has(String(menuId));
8677
+ },
8678
+ /**
8679
+ * 检查指定菜单是否正在收藏操作中
8680
+ */
8681
+ isLoading() {
8682
+ return (menuId) => this.loadingIds.has(String(menuId));
8683
+ }
8684
+ },
8685
+ actions: {
8686
+ // ==================== 由宿主项目调用 ====================
8687
+ /**
8688
+ * 初始化收藏列表(宿主在接口返回成功后调用一次)
8689
+ * @param {Array} list 后端返回的收藏列表
8690
+ */
8691
+ initFavorites(list) {
8692
+ this.favorites = Array.isArray(list) ? list : [];
8693
+ this.favoriteSet = new Set(this.favorites.map((item) => String(item.menuId)));
8694
+ this.loaded = true;
8695
+ },
8696
+ /**
8697
+ * 初始化最近使用列表(宿主在接口返回成功后调用一次)
8698
+ * @param {Array} list 后端返回的最近使用列表
8699
+ */
8700
+ initRecents(list) {
8701
+ this.recents = Array.isArray(list) ? list.map((item) => ({
8702
+ ...item,
8703
+ isFavorite: this.favoriteSet.has(String(item.menuId))
8704
+ })) : [];
8705
+ },
8706
+ // ==================== 由 ProductServicePanel 调用 ====================
8707
+ /**
8708
+ * 标记收藏操作开始(加 loading)
8709
+ * @param {String} menuId 菜单ID
8710
+ */
8711
+ startLoading(menuId) {
8712
+ this.loadingIds.add(String(menuId));
8713
+ },
8714
+ /**
8715
+ * 标记收藏操作结束(移除 loading)
8716
+ * @param {String} menuId 菜单ID
8717
+ */
8718
+ stopLoading(menuId) {
8719
+ this.loadingIds.delete(String(menuId));
8720
+ },
8721
+ /**
8722
+ * 本地添加一条收藏(宿主在接口成功后调用)
8723
+ *
8724
+ * 注意:本方法不会发起 HTTP 请求,由宿主项目调接口后手动调用。
8725
+ * 如果记录已存在则静默返回。
8726
+ *
8727
+ * @param {Object} record 收藏记录(需包含 menuId, menuName, leafPath, moduleId, modulePath, moduleName)
8728
+ */
8729
+ addFavorite(record) {
8730
+ if (!record || !record.menuId)
8731
+ return;
8732
+ const menuId = String(record.menuId);
8733
+ if (this.favoriteSet.has(menuId))
8734
+ return;
8735
+ const newFavorite = {
8736
+ menuId: record.menuId,
8737
+ menuName: record.menuName,
8738
+ leafPath: record.leafPath,
8739
+ moduleId: record.moduleId,
8740
+ modulePath: record.modulePath,
8741
+ moduleName: record.moduleName,
8742
+ isFavorite: true,
8743
+ createTime: record.createTime || (/* @__PURE__ */ new Date()).toISOString()
8744
+ };
8745
+ this.favorites = [newFavorite, ...this.favorites];
8746
+ this.favoriteSet.add(menuId);
8747
+ },
8748
+ /**
8749
+ * 本地移除一条收藏(宿主在接口成功后调用)
8750
+ * @param {String} menuId 菜单ID
8751
+ */
8752
+ cancelFavorite(menuId) {
8753
+ if (!menuId)
8754
+ return;
8755
+ const menuIdStr = String(menuId);
8756
+ this.favorites = this.favorites.filter((item) => String(item.menuId) !== menuIdStr);
8757
+ this.favoriteSet.delete(menuIdStr);
8758
+ },
8759
+ /**
8760
+ * 更新最近使用的访问计数(宿主在接口成功后调用)
8761
+ *
8762
+ * 存在则 visitCount+1 并重排到第一位,不存在则插入一条新记录到第一位
8763
+ *
8764
+ * @param {Object} record 最近使用记录
8765
+ */
8766
+ bumpVisitCount(record) {
8767
+ if (!record || !record.menuId)
8768
+ return;
8769
+ const menuIdStr = String(record.menuId);
8770
+ const idx = this.recents.findIndex((item) => String(item.menuId) === menuIdStr);
8771
+ if (idx !== -1) {
8772
+ const updated = {
8773
+ ...this.recents[idx],
8774
+ visitCount: (this.recents[idx].visitCount || 0) + 1,
8775
+ lastVisitTime: (/* @__PURE__ */ new Date()).toISOString(),
8776
+ isFavorite: this.favoriteSet.has(menuIdStr)
8777
+ };
8778
+ const newList = [...this.recents];
8779
+ newList.splice(idx, 1);
8780
+ newList.unshift(updated);
8781
+ this.recents = newList;
8782
+ } else {
8783
+ this.recents = [
8784
+ {
8785
+ menuId: record.menuId,
8786
+ menuName: record.menuName,
8787
+ leafPath: record.leafPath,
8788
+ moduleId: record.moduleId,
8789
+ modulePath: record.modulePath,
8790
+ moduleName: record.moduleName,
8791
+ isFavorite: this.favoriteSet.has(menuIdStr),
8792
+ visitCount: 1,
8793
+ lastVisitTime: (/* @__PURE__ */ new Date()).toISOString()
8794
+ },
8795
+ ...this.recents
8796
+ ];
8797
+ }
8798
+ },
8799
+ /**
8800
+ * 切换菜单的收藏状态(根据当前状态自动 add 或 cancel 本地)
8801
+ * 注意:本方法只操作本地状态,HTTP 由宿主项目负责
8802
+ *
8803
+ * @param {Object} record 菜单记录
8804
+ * @returns {Boolean} true=已收藏,false=已取消
8805
+ */
8806
+ toggleFavoriteLocal(record) {
8807
+ const menuId = String(record.menuId);
8808
+ if (this.favoriteSet.has(menuId)) {
8809
+ this.cancelFavorite(menuId);
8810
+ return false;
8811
+ } else {
8812
+ this.addFavorite(record);
8813
+ return true;
8814
+ }
8815
+ },
8816
+ /**
8817
+ * 重置 store(用户登出时调用)
8818
+ */
8819
+ resetState() {
8820
+ this.favorites = [];
8821
+ this.recents = [];
8822
+ this.favoriteSet = /* @__PURE__ */ new Set();
8823
+ this.loaded = false;
8824
+ this.loadingIds = /* @__PURE__ */ new Set();
8825
+ }
8826
+ },
8827
+ persist: false
8828
+ });
8829
+ const useFavoriteStoreWithOut = () => {
8830
+ return useFavoriteStore(store);
8831
+ };
8591
8832
  const _hoisted_1$b = { class: "sidebar-inner" };
8592
8833
  const _hoisted_2$9 = ["onClick"];
8593
8834
  const _hoisted_3$8 = ["onClick"];
8594
8835
  const _hoisted_4$7 = ["onClick"];
8595
8836
  const _hoisted_5$6 = ["onClick"];
8837
+ const _hoisted_6$5 = ["onClick"];
8838
+ const _hoisted_7$3 = ["onClick"];
8839
+ const RECENT_DISPLAY_LIMIT = 20;
8840
+ const TRACK_DEBOUNCE_MS = 3e3;
8596
8841
  const _sfc_main$r = /* @__PURE__ */ Object.assign({ name: "ProductServicePanel" }, {
8597
8842
  __name: "ProductServicePanel",
8598
8843
  props: {
@@ -8601,7 +8846,17 @@ const _sfc_main$r = /* @__PURE__ */ Object.assign({ name: "ProductServicePanel"
8601
8846
  default: false
8602
8847
  }
8603
8848
  },
8604
- emits: ["update:visible", "select"],
8849
+ emits: [
8850
+ "update:visible",
8851
+ "select",
8852
+ // 菜单收藏相关事件(宿主监听后调接口,完成后同步 store)
8853
+ "menu-favorite-add",
8854
+ // 添加收藏,参数:menu record 对象
8855
+ "menu-favorite-cancel",
8856
+ // 取消收藏,参数:menuId (String)
8857
+ "menu-recent-track"
8858
+ // 记录菜单访问,参数:完整 menu record 对象(含 menuId, menuName, leafPath, moduleId, modulePath, moduleName)
8859
+ ],
8605
8860
  setup(__props, { emit: __emit }) {
8606
8861
  const { getPrefixCls: getPrefixCls2 } = useDesign();
8607
8862
  const prefixCls2 = getPrefixCls2("product-service-panel");
@@ -8610,6 +8865,7 @@ const _sfc_main$r = /* @__PURE__ */ Object.assign({ name: "ProductServicePanel"
8610
8865
  const emit = __emit;
8611
8866
  const router = useRouter();
8612
8867
  const permissionStore = usePermissionStore();
8868
+ const favoriteStore = useFavoriteStore();
8613
8869
  const getMenuTitle = (item) => {
8614
8870
  var _a2;
8615
8871
  const rawTitle = ((_a2 = item.meta) == null ? void 0 : _a2.title) || item.name || "";
@@ -8695,16 +8951,117 @@ const _sfc_main$r = /* @__PURE__ */ Object.assign({ name: "ProductServicePanel"
8695
8951
  return [];
8696
8952
  const thirdMenus = (activeModule.value.children || []).filter(isVisible);
8697
8953
  return thirdMenus.map((third) => ({
8698
- id: third.id,
8954
+ // 使用 extractMenuId 多源提取(宿主路由数据中 id 可能位于不同层级)
8955
+ id: extractMenuId(third),
8699
8956
  title: getMenuTitle(third),
8700
8957
  path: third.path,
8701
8958
  items: (third.children || []).filter(isVisible).map((fourth) => ({
8702
- id: fourth.id,
8959
+ id: extractMenuId(fourth),
8703
8960
  title: getMenuTitle(fourth),
8704
8961
  path: fourth.path
8705
8962
  }))
8706
8963
  }));
8707
8964
  });
8965
+ const isFavoriteView = computed(() => activeProductIndex.value === -1);
8966
+ const favoriteList = computed(() => favoriteStore.getFavorites);
8967
+ const recentList = computed(() => favoriteStore.getRecents.slice(0, RECENT_DISPLAY_LIMIT));
8968
+ const isFavoriteLoading = (menuId) => favoriteStore.isLoading(String(menuId));
8969
+ const isFavorite = (menuId) => favoriteStore.isFavorite(String(menuId));
8970
+ const lastTrackMap = /* @__PURE__ */ new Map();
8971
+ const emitMenuTrack = (record) => {
8972
+ if (!record || !record.menuId)
8973
+ return;
8974
+ const menuIdStr = String(record.menuId);
8975
+ const now = Date.now();
8976
+ const last = lastTrackMap.get(menuIdStr) || 0;
8977
+ if (now - last < TRACK_DEBOUNCE_MS)
8978
+ return;
8979
+ lastTrackMap.set(menuIdStr, now);
8980
+ emit("menu-recent-track", record);
8981
+ };
8982
+ const handleAddFavorite = (record) => {
8983
+ if (!record || !record.menuId || record.menuId === "undefined") {
8984
+ console.warn("[ProductServicePanel] 无法收藏:缺少有效 menuId", record);
8985
+ return;
8986
+ }
8987
+ if (isFavoriteLoading(record.menuId))
8988
+ return;
8989
+ favoriteStore.startLoading(record.menuId);
8990
+ emit("menu-favorite-add", record);
8991
+ };
8992
+ const handleCancelFavorite = (menuId) => {
8993
+ if (!menuId || String(menuId) === "undefined") {
8994
+ console.warn("[ProductServicePanel] 无法取消收藏:缺少有效 menuId");
8995
+ return;
8996
+ }
8997
+ if (isFavoriteLoading(menuId))
8998
+ return;
8999
+ favoriteStore.startLoading(menuId);
9000
+ emit("menu-favorite-cancel", String(menuId));
9001
+ };
9002
+ const handleFavoriteNavigate = (record, trackVisit = true) => {
9003
+ if (!record || !record.leafPath)
9004
+ return;
9005
+ const currentModuleId = permissionStore.getModuleId;
9006
+ const modulePath = record.modulePath === "/" ? "" : record.modulePath || "";
9007
+ const leafPath = record.leafPath || "";
9008
+ if (record.moduleId === currentModuleId) {
9009
+ const normalizedLeaf = leafPath.startsWith("/") ? leafPath : `/${leafPath}`;
9010
+ router.push(normalizedLeaf);
9011
+ if (trackVisit)
9012
+ emitMenuTrack(record);
9013
+ closePanel();
9014
+ return;
9015
+ }
9016
+ const currentOrigin = window.location.origin;
9017
+ let finalPath = leafPath;
9018
+ if (modulePath) {
9019
+ const hasPrefix = finalPath === modulePath || finalPath.startsWith(modulePath + "/");
9020
+ finalPath = hasPrefix ? finalPath : `${modulePath}/${finalPath.replace(/^\//, "")}`;
9021
+ }
9022
+ const targetUrl = `${currentOrigin}${finalPath.startsWith("/") ? finalPath : `/${finalPath}`}`;
9023
+ window.location.href = targetUrl;
9024
+ if (trackVisit)
9025
+ emitMenuTrack(record);
9026
+ closePanel();
9027
+ };
9028
+ const extractMenuId = (item) => {
9029
+ var _a2;
9030
+ if (!item)
9031
+ return "";
9032
+ const rawId = item.id ?? ((_a2 = item.meta) == null ? void 0 : _a2.id) ?? item.menuId ?? item.name;
9033
+ if (rawId == null || rawId === "" || rawId === "undefined")
9034
+ return "";
9035
+ return String(rawId);
9036
+ };
9037
+ const buildFavoriteRecord = (leafItem, group, activeModule2, activeProduct2) => {
9038
+ const parentParts = [];
9039
+ if (activeProduct2 == null ? void 0 : activeProduct2.path)
9040
+ parentParts.push(activeProduct2.path);
9041
+ if (activeModule2 == null ? void 0 : activeModule2.path)
9042
+ parentParts.push(activeModule2.path);
9043
+ if (group == null ? void 0 : group.path)
9044
+ parentParts.push(group.path);
9045
+ const parentPath = parentParts.join("/");
9046
+ const menuId = extractMenuId(leafItem);
9047
+ if (!menuId) {
9048
+ console.warn("[ProductServicePanel] 无法收藏:菜单ID提取失败", leafItem);
9049
+ return null;
9050
+ }
9051
+ const fullLeafPath = joinPath(parentPath, leafItem.path);
9052
+ return {
9053
+ menuId,
9054
+ menuName: leafItem.title || leafItem.menuName || getMenuTitle(leafItem),
9055
+ leafPath: fullLeafPath,
9056
+ parentPath,
9057
+ moduleId: extractMenuId(activeModule2),
9058
+ modulePath: activeModule2 == null ? void 0 : activeModule2.modulePath,
9059
+ moduleName: (activeModule2 == null ? void 0 : activeModule2.title) || (activeModule2 == null ? void 0 : activeModule2.moduleName)
9060
+ };
9061
+ };
9062
+ const buildTrackRecord = (leafItem, group, activeModule2, activeProduct2) => {
9063
+ return buildFavoriteRecord(leafItem, group, activeModule2, activeProduct2);
9064
+ };
8708
9065
  const joinPath = (...paths) => {
8709
9066
  return paths.filter(Boolean).reduce((result, path) => {
8710
9067
  if (!result)
@@ -8755,7 +9112,8 @@ const _sfc_main$r = /* @__PURE__ */ Object.assign({ name: "ProductServicePanel"
8755
9112
  }
8756
9113
  };
8757
9114
  const handleProductSelect = (index) => {
8758
- activeProductIndex.value = index;
9115
+ const safeIndex = typeof index === "number" && index >= 0 ? index : 0;
9116
+ activeProductIndex.value = safeIndex;
8759
9117
  activeModuleIndex.value = 0;
8760
9118
  };
8761
9119
  const handleModuleSelect = (index) => {
@@ -8763,14 +9121,23 @@ const _sfc_main$r = /* @__PURE__ */ Object.assign({ name: "ProductServicePanel"
8763
9121
  };
8764
9122
  const handleItemClick = (fourthItem, group) => {
8765
9123
  var _a2, _b;
9124
+ const trackRecord = buildTrackRecord(fourthItem, group, activeModule.value, activeProduct.value);
9125
+ emitMenuTrack(trackRecord);
8766
9126
  const parentPath = joinPath((_a2 = activeProduct.value) == null ? void 0 : _a2.path, (_b = activeModule.value) == null ? void 0 : _b.path, group.path);
8767
9127
  handleSelect(fourthItem, parentPath);
8768
9128
  };
8769
9129
  const handleGroupClick = (group) => {
8770
9130
  var _a2, _b;
9131
+ const trackRecord = buildTrackRecord(group, group, activeModule.value, activeProduct.value);
9132
+ emitMenuTrack(trackRecord);
8771
9133
  const parentPath = joinPath((_a2 = activeProduct.value) == null ? void 0 : _a2.path, (_b = activeModule.value) == null ? void 0 : _b.path);
8772
9134
  handleSelect({ path: group.path, children: [] }, parentPath);
8773
9135
  };
9136
+ const handleCommonSelect = () => {
9137
+ activeProductIndex.value = -1;
9138
+ activeModuleIndex.value = 0;
9139
+ expandedCardIndex.value = null;
9140
+ };
8774
9141
  const syncActiveSelection = () => {
8775
9142
  const currentModuleId = permissionStore.getModuleId;
8776
9143
  if (!currentModuleId)
@@ -8818,7 +9185,9 @@ const _sfc_main$r = /* @__PURE__ */ Object.assign({ name: "ProductServicePanel"
8818
9185
  closePanel();
8819
9186
  }
8820
9187
  };
8821
- onMounted(() => document.addEventListener("keydown", handleKeydown));
9188
+ onMounted(() => {
9189
+ document.addEventListener("keydown", handleKeydown);
9190
+ });
8822
9191
  onUnmounted(() => document.removeEventListener("keydown", handleKeydown));
8823
9192
  return (_ctx, _cache) => {
8824
9193
  return openBlock(), createBlock(Teleport, { to: "body" }, [
@@ -8851,12 +9220,30 @@ const _sfc_main$r = /* @__PURE__ */ Object.assign({ name: "ProductServicePanel"
8851
9220
  createVNode(unref(ElScrollbar), null, {
8852
9221
  default: withCtx(() => [
8853
9222
  createElementVNode("div", _hoisted_1$b, [
9223
+ createElementVNode("div", {
9224
+ class: normalizeClass([
9225
+ unref(prefixCls2) + "__product-card",
9226
+ unref(prefixCls2) + "__product-card--common",
9227
+ { "is-active": activeProductIndex.value === -1 }
9228
+ ]),
9229
+ onClick: handleCommonSelect
9230
+ }, [
9231
+ createElementVNode("div", {
9232
+ class: normalizeClass([unref(prefixCls2) + "__product-name"])
9233
+ }, [
9234
+ createVNode(unref(_sfc_main$x), {
9235
+ icon: "svg-icon:favorite-filled",
9236
+ size: 16
9237
+ }),
9238
+ createElementVNode("span", null, toDisplayString(unref(t2)("layout.common.commonGroup")), 1)
9239
+ ], 2)
9240
+ ], 2),
8854
9241
  (openBlock(true), createElementBlock(Fragment, null, renderList(productList.value, (product, pIndex) => {
8855
9242
  return openBlock(), createElementBlock("div", {
8856
9243
  key: product.id || pIndex,
8857
9244
  class: normalizeClass([
8858
9245
  unref(prefixCls2) + "__product-card",
8859
- { "is-active": activeProductIndex.value === pIndex },
9246
+ { "is-active": activeProductIndex.value === pIndex && activeProductIndex.value !== -1 },
8860
9247
  { "is-expanded": expandedCardIndex.value === pIndex }
8861
9248
  ]),
8862
9249
  onClick: ($event) => {
@@ -8894,7 +9281,7 @@ const _sfc_main$r = /* @__PURE__ */ Object.assign({ name: "ProductServicePanel"
8894
9281
  class: normalizeClass([
8895
9282
  unref(prefixCls2) + "__module-tag",
8896
9283
  {
8897
- "is-active": activeProductIndex.value === pIndex && activeModuleIndex.value === mIndex
9284
+ "is-active": activeProductIndex.value === pIndex && activeModuleIndex.value === mIndex && activeProductIndex.value !== -1
8898
9285
  }
8899
9286
  ]),
8900
9287
  onClick: withModifiers(($event) => (handleProductSelect(pIndex), handleModuleSelect(mIndex)), ["stop"])
@@ -8946,7 +9333,109 @@ const _sfc_main$r = /* @__PURE__ */ Object.assign({ name: "ProductServicePanel"
8946
9333
  createElementVNode("div", {
8947
9334
  class: normalizeClass([unref(prefixCls2) + "__grid-container"])
8948
9335
  }, [
8949
- contentGroups.value.length > 0 ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(contentGroups.value, (group) => {
9336
+ isFavoriteView.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
9337
+ createElementVNode("div", {
9338
+ class: normalizeClass([unref(prefixCls2) + "__group"])
9339
+ }, [
9340
+ createElementVNode("div", {
9341
+ class: normalizeClass([unref(prefixCls2) + "__group-title"])
9342
+ }, [
9343
+ createElementVNode("span", null, toDisplayString(unref(t2)("layout.common.myFavorites")), 1)
9344
+ ], 2),
9345
+ favoriteList.value.length > 0 ? (openBlock(), createElementBlock("div", {
9346
+ key: 0,
9347
+ class: normalizeClass([unref(prefixCls2) + "__group-grid"])
9348
+ }, [
9349
+ (openBlock(true), createElementBlock(Fragment, null, renderList(favoriteList.value, (fav) => {
9350
+ return openBlock(), createElementBlock("div", {
9351
+ key: "fav-" + fav.menuId,
9352
+ class: normalizeClass([unref(prefixCls2) + "__group-item"])
9353
+ }, [
9354
+ createElementVNode("span", {
9355
+ class: normalizeClass([unref(prefixCls2) + "__group-item-title"]),
9356
+ onClick: ($event) => handleFavoriteNavigate(fav, true)
9357
+ }, toDisplayString(fav.menuName), 11, _hoisted_4$7),
9358
+ !isFavoriteLoading(fav.menuId) ? (openBlock(), createBlock(unref(_sfc_main$x), {
9359
+ key: 0,
9360
+ class: normalizeClass([unref(prefixCls2) + "__favorite-icon", "is-active"]),
9361
+ icon: "svg-icon:favorite-filled",
9362
+ size: 14,
9363
+ onClick: withModifiers(($event) => handleCancelFavorite(fav.menuId), ["stop"])
9364
+ }, null, 8, ["class", "onClick"])) : (openBlock(), createBlock(unref(_sfc_main$x), {
9365
+ key: 1,
9366
+ icon: "ep:loading",
9367
+ size: 14,
9368
+ class: normalizeClass([unref(prefixCls2) + "__favorite-icon", "is-loading"])
9369
+ }, null, 8, ["class"]))
9370
+ ], 2);
9371
+ }), 128))
9372
+ ], 2)) : (openBlock(), createElementBlock("div", {
9373
+ key: 1,
9374
+ class: normalizeClass([unref(prefixCls2) + "__group-empty-hint"])
9375
+ }, [
9376
+ createVNode(unref(_sfc_main$x), {
9377
+ icon: "svg-icon:favorite-outline",
9378
+ size: 16
9379
+ }),
9380
+ createElementVNode("span", null, toDisplayString(unref(t2)("layout.common.noFavoritesHint")), 1)
9381
+ ], 2))
9382
+ ], 2),
9383
+ createElementVNode("div", {
9384
+ class: normalizeClass([unref(prefixCls2) + "__group"]),
9385
+ style: { "margin-top": "24px" }
9386
+ }, [
9387
+ createElementVNode("div", {
9388
+ class: normalizeClass([unref(prefixCls2) + "__group-title"])
9389
+ }, [
9390
+ createElementVNode("span", null, toDisplayString(unref(t2)("layout.common.recentUsed")), 1)
9391
+ ], 2),
9392
+ recentList.value.length > 0 ? (openBlock(), createElementBlock("div", {
9393
+ key: 0,
9394
+ class: normalizeClass([unref(prefixCls2) + "__group-grid"])
9395
+ }, [
9396
+ (openBlock(true), createElementBlock(Fragment, null, renderList(recentList.value, (rec) => {
9397
+ return openBlock(), createElementBlock("div", {
9398
+ key: "rec-" + rec.menuId,
9399
+ class: normalizeClass([unref(prefixCls2) + "__group-item"])
9400
+ }, [
9401
+ createElementVNode("span", {
9402
+ class: normalizeClass([unref(prefixCls2) + "__group-item-title"]),
9403
+ onClick: ($event) => handleFavoriteNavigate(rec, false)
9404
+ }, toDisplayString(rec.menuName), 11, _hoisted_5$6),
9405
+ !isFavoriteLoading(rec.menuId) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
9406
+ isFavorite(rec.menuId) ? (openBlock(), createBlock(unref(_sfc_main$x), {
9407
+ key: 0,
9408
+ class: normalizeClass([unref(prefixCls2) + "__favorite-icon", "is-active"]),
9409
+ icon: "svg-icon:favorite-filled",
9410
+ size: 14,
9411
+ onClick: withModifiers(($event) => handleCancelFavorite(rec.menuId), ["stop"])
9412
+ }, null, 8, ["class", "onClick"])) : (openBlock(), createBlock(unref(_sfc_main$x), {
9413
+ key: 1,
9414
+ class: normalizeClass([unref(prefixCls2) + "__favorite-icon"]),
9415
+ icon: "svg-icon:favorite-outline",
9416
+ size: 14,
9417
+ onClick: withModifiers(($event) => handleAddFavorite(rec), ["stop"])
9418
+ }, null, 8, ["class", "onClick"]))
9419
+ ], 64)) : (openBlock(), createBlock(unref(_sfc_main$x), {
9420
+ key: 1,
9421
+ icon: "ep:loading",
9422
+ size: 14,
9423
+ class: normalizeClass([unref(prefixCls2) + "__favorite-icon", "is-loading"])
9424
+ }, null, 8, ["class"]))
9425
+ ], 2);
9426
+ }), 128))
9427
+ ], 2)) : (openBlock(), createElementBlock("div", {
9428
+ key: 1,
9429
+ class: normalizeClass([unref(prefixCls2) + "__group-empty-hint"])
9430
+ }, [
9431
+ createVNode(unref(_sfc_main$x), {
9432
+ icon: "ant-design:inbox-outlined",
9433
+ size: 16
9434
+ }),
9435
+ createElementVNode("span", null, toDisplayString(unref(t2)("layout.common.noRecentHint")), 1)
9436
+ ], 2))
9437
+ ], 2)
9438
+ ], 64)) : contentGroups.value.length > 0 ? (openBlock(true), createElementBlock(Fragment, { key: 1 }, renderList(contentGroups.value, (group) => {
8950
9439
  return openBlock(), createElementBlock("div", {
8951
9440
  key: group.id || group.title,
8952
9441
  class: normalizeClass([unref(prefixCls2) + "__group"])
@@ -8962,22 +9451,66 @@ const _sfc_main$r = /* @__PURE__ */ Object.assign({ name: "ProductServicePanel"
8962
9451
  group.items.length > 0 ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(group.items, (item) => {
8963
9452
  return openBlock(), createElementBlock("div", {
8964
9453
  key: item.id || item.path,
8965
- class: normalizeClass([unref(prefixCls2) + "__group-item"]),
8966
- onClick: ($event) => handleItemClick(item, group)
9454
+ class: normalizeClass([unref(prefixCls2) + "__group-item"])
8967
9455
  }, [
8968
- createElementVNode("span", null, toDisplayString(item.title), 1)
8969
- ], 10, _hoisted_4$7);
9456
+ createElementVNode("span", {
9457
+ class: normalizeClass([unref(prefixCls2) + "__group-item-title"]),
9458
+ onClick: ($event) => handleItemClick(item, group)
9459
+ }, toDisplayString(item.title), 11, _hoisted_6$5),
9460
+ !isFavoriteLoading(item.id) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
9461
+ isFavorite(item.id) ? (openBlock(), createBlock(unref(_sfc_main$x), {
9462
+ key: 0,
9463
+ class: normalizeClass([unref(prefixCls2) + "__favorite-icon", "is-active"]),
9464
+ icon: "svg-icon:favorite-filled",
9465
+ size: 14,
9466
+ onClick: withModifiers(($event) => handleCancelFavorite(item.id), ["stop"])
9467
+ }, null, 8, ["class", "onClick"])) : (openBlock(), createBlock(unref(_sfc_main$x), {
9468
+ key: 1,
9469
+ class: normalizeClass([unref(prefixCls2) + "__favorite-icon"]),
9470
+ icon: "svg-icon:favorite-outline",
9471
+ size: 14,
9472
+ onClick: withModifiers(($event) => handleAddFavorite(buildFavoriteRecord(item, group, activeModule.value, activeProduct.value)), ["stop"])
9473
+ }, null, 8, ["class", "onClick"]))
9474
+ ], 64)) : (openBlock(), createBlock(unref(_sfc_main$x), {
9475
+ key: 1,
9476
+ icon: "ep:loading",
9477
+ size: 14,
9478
+ class: normalizeClass([unref(prefixCls2) + "__favorite-icon", "is-loading"])
9479
+ }, null, 8, ["class"]))
9480
+ ], 2);
8970
9481
  }), 128)) : (openBlock(), createElementBlock("div", {
8971
9482
  key: 1,
8972
- class: normalizeClass([unref(prefixCls2) + "__group-item"]),
8973
- onClick: ($event) => handleGroupClick(group)
9483
+ class: normalizeClass([unref(prefixCls2) + "__group-item"])
8974
9484
  }, [
8975
- createElementVNode("span", null, toDisplayString(group.title), 1)
8976
- ], 10, _hoisted_5$6))
9485
+ createElementVNode("span", {
9486
+ class: normalizeClass([unref(prefixCls2) + "__group-item-title"]),
9487
+ onClick: ($event) => handleGroupClick(group)
9488
+ }, toDisplayString(group.title), 11, _hoisted_7$3),
9489
+ !isFavoriteLoading(group.id) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
9490
+ isFavorite(group.id) ? (openBlock(), createBlock(unref(_sfc_main$x), {
9491
+ key: 0,
9492
+ class: normalizeClass([unref(prefixCls2) + "__favorite-icon", "is-active"]),
9493
+ icon: "svg-icon:favorite-filled",
9494
+ size: 14,
9495
+ onClick: withModifiers(($event) => handleCancelFavorite(group.id), ["stop"])
9496
+ }, null, 8, ["class", "onClick"])) : (openBlock(), createBlock(unref(_sfc_main$x), {
9497
+ key: 1,
9498
+ class: normalizeClass([unref(prefixCls2) + "__favorite-icon"]),
9499
+ icon: "svg-icon:favorite-outline",
9500
+ size: 14,
9501
+ onClick: withModifiers(($event) => handleAddFavorite(buildFavoriteRecord(group, group, activeModule.value, activeProduct.value)), ["stop"])
9502
+ }, null, 8, ["class", "onClick"]))
9503
+ ], 64)) : (openBlock(), createBlock(unref(_sfc_main$x), {
9504
+ key: 1,
9505
+ icon: "ep:loading",
9506
+ size: 14,
9507
+ class: normalizeClass([unref(prefixCls2) + "__favorite-icon", "is-loading"])
9508
+ }, null, 8, ["class"]))
9509
+ ], 2))
8977
9510
  ], 2)
8978
9511
  ], 2);
8979
9512
  }), 128)) : activeProduct.value ? (openBlock(), createElementBlock("div", {
8980
- key: 1,
9513
+ key: 2,
8981
9514
  class: normalizeClass([unref(prefixCls2) + "__empty"])
8982
9515
  }, [
8983
9516
  createVNode(unref(_sfc_main$x), {
@@ -9004,10 +9537,16 @@ const _sfc_main$r = /* @__PURE__ */ Object.assign({ name: "ProductServicePanel"
9004
9537
  };
9005
9538
  }
9006
9539
  });
9007
- const ProductServicePanel = /* @__PURE__ */ _export_sfc(_sfc_main$r, [["__scopeId", "data-v-f9a0a896"]]);
9540
+ const ProductServicePanel = /* @__PURE__ */ _export_sfc(_sfc_main$r, [["__scopeId", "data-v-15e398e8"]]);
9008
9541
  const _sfc_main$q = /* @__PURE__ */ Object.assign({ name: "Logo" }, {
9009
9542
  __name: "Logo",
9010
- emits: ["logo-click"],
9543
+ emits: [
9544
+ "logo-click",
9545
+ // 转发 ProductServicePanel 的菜单收藏事件
9546
+ "menu-favorite-add",
9547
+ "menu-favorite-cancel",
9548
+ "menu-recent-track"
9549
+ ],
9011
9550
  setup(__props, { emit: __emit }) {
9012
9551
  const emit = __emit;
9013
9552
  const { getPrefixCls: getPrefixCls2 } = useDesign();
@@ -9054,7 +9593,10 @@ const _sfc_main$q = /* @__PURE__ */ Object.assign({ name: "Logo" }, {
9054
9593
  ], 2),
9055
9594
  createVNode(unref(ProductServicePanel), {
9056
9595
  visible: panelVisible.value,
9057
- "onUpdate:visible": _cache[0] || (_cache[0] = ($event) => panelVisible.value = $event)
9596
+ "onUpdate:visible": _cache[0] || (_cache[0] = ($event) => panelVisible.value = $event),
9597
+ onMenuFavoriteAdd: _cache[1] || (_cache[1] = (record) => emit("menu-favorite-add", record)),
9598
+ onMenuFavoriteCancel: _cache[2] || (_cache[2] = (menuId) => emit("menu-favorite-cancel", menuId)),
9599
+ onMenuRecentTrack: _cache[3] || (_cache[3] = (menuId) => emit("menu-recent-track", menuId))
9058
9600
  }, null, 8, ["visible"])
9059
9601
  ]);
9060
9602
  };
@@ -10075,7 +10617,7 @@ const setI18nLanguage = (locale) => {
10075
10617
  const useLocale = () => {
10076
10618
  const changeLocale = async (locale) => {
10077
10619
  const globalI18n = i18n.global;
10078
- const langModule = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "../../locales/en.js": () => import("./en-BLMsUBCM.mjs"), "../../locales/zh-CN.js": () => import("./zh-CN-i4M-o5m6.mjs"), "../../locales/zh-TW.js": () => import("./zh-TW-DYC8NCr4.mjs") }), `../../locales/${locale}.js`);
10620
+ const langModule = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "../../locales/en.js": () => import("./en-DFjC_Whi.mjs"), "../../locales/zh-CN.js": () => import("./zh-CN-CYQhpMit.mjs"), "../../locales/zh-TW.js": () => import("./zh-TW-CWRW7QKU.mjs") }), `../../locales/${locale}.js`);
10079
10621
  globalI18n.setLocaleMessage(locale, langModule.default);
10080
10622
  setI18nLanguage(locale);
10081
10623
  };
@@ -10695,6 +11237,9 @@ const useRenderLayout = (props, {
10695
11237
  onLogoutClick,
10696
11238
  onClearCacheLogoutClick,
10697
11239
  onSwitchCompanyClick,
11240
+ onMenuFavoriteAdd,
11241
+ onMenuFavoriteCancel,
11242
+ onMenuRecentTrack,
10698
11243
  unreadCount
10699
11244
  }) => {
10700
11245
  const appStore = useAppStore();
@@ -10739,7 +11284,10 @@ const useRenderLayout = (props, {
10739
11284
  "w-[var(--left-menu-min-width)]": collapse.value,
10740
11285
  "w-[var(--left-menu-max-width)]": !collapse.value
10741
11286
  }],
10742
- "onLogoClick": onLogoClick
11287
+ "onLogoClick": onLogoClick,
11288
+ "onMenuFavoriteAdd": onMenuFavoriteAdd,
11289
+ "onMenuFavoriteCancel": onMenuFavoriteCancel,
11290
+ "onMenuRecentTrack": onMenuRecentTrack
10743
11291
  }, null) : void 0, createVNode(ToolHeader, {
10744
11292
  "class": "flex-1",
10745
11293
  "onMessageClick": onMessageClick,
@@ -10758,6 +11306,9 @@ const useRenderLayout = (props, {
10758
11306
  "w-[var(--left-menu-max-width)]": !collapse.value
10759
11307
  }],
10760
11308
  "onLogoClick": onLogoClick,
11309
+ "onMenuFavoriteAdd": onMenuFavoriteAdd,
11310
+ "onMenuFavoriteCancel": onMenuFavoriteCancel,
11311
+ "onMenuRecentTrack": onMenuRecentTrack,
10761
11312
  "style": "transition: all var(--transition-time-02);"
10762
11313
  }, null) : void 0, createVNode(ToolHeader, {
10763
11314
  "class": "flex-1",
@@ -10800,7 +11351,10 @@ const useRenderLayout = (props, {
10800
11351
  }, festivalTopClass.value]
10801
11352
  }, [logo.value ? createVNode(_sfc_main$q, {
10802
11353
  "class": ["shrink-0 w-[var(--left-menu-max-width)]"],
10803
- "onLogoClick": onLogoClick
11354
+ "onLogoClick": onLogoClick,
11355
+ "onMenuFavoriteAdd": onMenuFavoriteAdd,
11356
+ "onMenuFavoriteCancel": onMenuFavoriteCancel,
11357
+ "onMenuRecentTrack": onMenuRecentTrack
10804
11358
  }, null) : void 0, tagsView.value && createVNode(TagsView, {
10805
11359
  "class": ["layout-border__bottom flex-1 min-w-0"]
10806
11360
  }, null), createVNode(ToolHeader, {
@@ -10829,7 +11383,10 @@ const useRenderLayout = (props, {
10829
11383
  "w-[var(--left-menu-min-width)]": appStore.getCollapse,
10830
11384
  "w-[var(--left-menu-max-width)]": !appStore.getCollapse
10831
11385
  }],
10832
- "onLogoClick": onLogoClick
11386
+ "onLogoClick": onLogoClick,
11387
+ "onMenuFavoriteAdd": onMenuFavoriteAdd,
11388
+ "onMenuFavoriteCancel": onMenuFavoriteCancel,
11389
+ "onMenuRecentTrack": onMenuRecentTrack
10833
11390
  }, null) : void 0, createVNode(ToolHeader, {
10834
11391
  "class": "flex-1",
10835
11392
  "onMessageClick": onMessageClick,
@@ -10888,7 +11445,10 @@ const renderLayout = (layout, props, {
10888
11445
  handleMessageClick,
10889
11446
  handleLogoutClick,
10890
11447
  handleClearCacheLogoutClick,
10891
- handleSwitchCompanyClick
11448
+ handleSwitchCompanyClick,
11449
+ handleMenuFavoriteAdd,
11450
+ handleMenuFavoriteCancel,
11451
+ handleMenuRecentTrack
10892
11452
  }) => {
10893
11453
  const {
10894
11454
  renderLeft,
@@ -10901,6 +11461,9 @@ const renderLayout = (layout, props, {
10901
11461
  onLogoutClick: handleLogoutClick,
10902
11462
  onClearCacheLogoutClick: handleClearCacheLogoutClick,
10903
11463
  onSwitchCompanyClick: handleSwitchCompanyClick,
11464
+ onMenuFavoriteAdd: handleMenuFavoriteAdd,
11465
+ onMenuFavoriteCancel: handleMenuFavoriteCancel,
11466
+ onMenuRecentTrack: handleMenuRecentTrack,
10904
11467
  unreadCount: props.unreadCount
10905
11468
  });
10906
11469
  layoutScrollRef.value = scrollRef2.value;
@@ -10925,7 +11488,17 @@ const _sfc_main$e = /* @__PURE__ */ defineComponent({
10925
11488
  default: 0
10926
11489
  }
10927
11490
  },
10928
- emits: ["logo-click", "message-click", "logout-click", "clear-cache-logout-click", "switch-company-click"],
11491
+ emits: [
11492
+ "logo-click",
11493
+ "message-click",
11494
+ "logout-click",
11495
+ "clear-cache-logout-click",
11496
+ "switch-company-click",
11497
+ // 菜单收藏相关事件(宿主监听后调接口,同步 store)
11498
+ "menu-favorite-add",
11499
+ "menu-favorite-cancel",
11500
+ "menu-recent-track"
11501
+ ],
10929
11502
  setup(props, {
10930
11503
  emit
10931
11504
  }) {
@@ -10948,6 +11521,15 @@ const _sfc_main$e = /* @__PURE__ */ defineComponent({
10948
11521
  const handleSwitchCompanyClick = (company) => {
10949
11522
  emit("switch-company-click", company);
10950
11523
  };
11524
+ const handleMenuFavoriteAdd = (record) => {
11525
+ emit("menu-favorite-add", record);
11526
+ };
11527
+ const handleMenuFavoriteCancel = (menuId) => {
11528
+ emit("menu-favorite-cancel", menuId);
11529
+ };
11530
+ const handleMenuRecentTrack = (record) => {
11531
+ emit("menu-recent-track", record);
11532
+ };
10951
11533
  return () => createVNode("section", {
10952
11534
  "class": [prefixCls, `${prefixCls}__${layout.value}`, "w-[100%] h-[100%] relative", `${prefixCls}__${theme.value}`]
10953
11535
  }, [renderLayout(layout, props, {
@@ -10955,11 +11537,14 @@ const _sfc_main$e = /* @__PURE__ */ defineComponent({
10955
11537
  handleMessageClick,
10956
11538
  handleLogoutClick,
10957
11539
  handleClearCacheLogoutClick,
10958
- handleSwitchCompanyClick
11540
+ handleSwitchCompanyClick,
11541
+ handleMenuFavoriteAdd,
11542
+ handleMenuFavoriteCancel,
11543
+ handleMenuRecentTrack
10959
11544
  }), props.scroll && createVNode(_sfc_main$y, null, null)]);
10960
11545
  }
10961
11546
  });
10962
- const Layout = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["__scopeId", "data-v-a2e9339e"]]);
11547
+ const Layout = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["__scopeId", "data-v-8a9b45c4"]]);
10963
11548
  const _sfc_main$d = {
10964
11549
  __name: "ConfigGlobal",
10965
11550
  props: {
@@ -13135,6 +13720,8 @@ export {
13135
13720
  UploadImgs as BmpUploadImgs,
13136
13721
  useAppStore as BmpUseAppStore,
13137
13722
  useAppStoreWithOut as BmpUseAppStoreWithOut,
13723
+ useFavoriteStore as BmpUseFavoriteStore,
13724
+ useFavoriteStoreWithOut as BmpUseFavoriteStoreWithOut,
13138
13725
  useLayout as BmpUseLayout,
13139
13726
  useLocaleStore as BmpUseLocaleStore,
13140
13727
  useLocaleStoreWithOut as BmpUseLocaleStoreWithOut,