xto-fronted 0.6.2 → 0.7.0

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.
Files changed (35) hide show
  1. package/dist/api/index.js +1 -1
  2. package/dist/{index-DGrQCWU0.js → index-BO31bICK.js} +13 -13
  3. package/dist/{index-CYFcc2sd.js → index-D4K3OfZa.js} +23 -23
  4. package/dist/{index-DIlGh6S6.js → index-DkG24eV5.js} +9 -9
  5. package/dist/{index-DYmKmoMX.js → index-QdDB_2uu.js} +20 -20
  6. package/dist/{index-Dpv33ZXi.js → index-k2XmHxrU.js} +802 -795
  7. package/dist/index.js +2 -2
  8. package/dist/style.css +1 -1
  9. package/dist/{user-ChcAx-5W.js → user-77I_qZ8j.js} +6 -6
  10. package/package.json +1 -1
  11. package/src/App.vue +3 -3
  12. package/src/assets/styles/_dark.scss +170 -170
  13. package/src/assets/styles/_reset.scss +8 -8
  14. package/src/assets/styles/_root.scss +95 -93
  15. package/src/assets/styles/_variables.scss +17 -17
  16. package/src/assets/styles/index.scss +39 -39
  17. package/src/components/Layout/Footer.vue +1 -1
  18. package/src/components/Layout/Header.vue +54 -54
  19. package/src/components/Layout/MixTopMenu.vue +41 -41
  20. package/src/components/Layout/Sidebar.vue +8 -8
  21. package/src/components/Layout/SidebarMenuItem.vue +2 -2
  22. package/src/components/Layout/Tabs.vue +6 -6
  23. package/src/components/Layout/TopMenu.vue +41 -41
  24. package/src/components/Layout/index.vue +4 -4
  25. package/src/router/guards.ts +12 -1
  26. package/src/stores/app.ts +2 -2
  27. package/src/stores/menu.ts +15 -6
  28. package/src/style.scss +2 -2
  29. package/src/views/dashboard/index.vue +32 -32
  30. package/src/views/error/403.vue +13 -13
  31. package/src/views/error/404.vue +19 -19
  32. package/src/views/login/index.vue +15 -15
  33. package/src/views/system/menu/index.vue +20 -20
  34. package/src/views/system/role/index.vue +20 -20
  35. package/src/views/system/user/index.vue +23 -23
@@ -105,9 +105,9 @@ watch(displayMenuList, (newList, oldList) => {
105
105
  }, { immediate: false })
106
106
 
107
107
  // 菜单主题相关(浅色模式走 CSS 变量,深色模式保留深底硬编码以配合暗色覆盖)
108
- const menuBgColor = computed(() => appStore.isDark ? '#111A2C' : '#fff')
109
- const menuTextColor = computed(() => appStore.isDark ? '#CBD5E1' : '#334155')
110
- const menuActiveTextColor = computed(() => appStore.isDark ? '#4C8DFF' : '#1D4ED8')
108
+ const menuBgColor = computed(() => appStore.isDark ? '#161B21' : '#fff')
109
+ const menuTextColor = computed(() => appStore.isDark ? '#D9DCE1' : '#4E5566')
110
+ const menuActiveTextColor = computed(() => appStore.isDark ? '#2ED3CB' : '#12B6AF')
111
111
 
112
112
  // 菜单选择
113
113
  const handleMenuSelect = (index: string) => {
@@ -168,7 +168,7 @@ const handleLogout = () => {
168
168
  display: flex;
169
169
  flex-direction: column;
170
170
  background-color: var(--xto-bg-color, #FFFFFF);
171
- border-right: 1px solid var(--xto-border-color-light, #E2E8F0);
171
+ border-right: 1px solid var(--xto-border-color-light, #E5E6EB);
172
172
 
173
173
  &--collapsed {
174
174
  .sidebar__logo {
@@ -183,7 +183,7 @@ const handleLogout = () => {
183
183
  align-items: center;
184
184
  padding: 0 20px;
185
185
  gap: 10px;
186
- border-bottom: 1px solid var(--xto-border-color-light, #E2E8F0);
186
+ border-bottom: 1px solid var(--xto-border-color-light, #E5E6EB);
187
187
  }
188
188
 
189
189
  &__logo-img {
@@ -194,7 +194,7 @@ const handleLogout = () => {
194
194
  &__logo-text {
195
195
  font-size: 16px;
196
196
  font-weight: 600;
197
- color: var(--xto-color-primary, #1D4ED8);
197
+ color: var(--xto-color-primary, #12B6AF);
198
198
  }
199
199
 
200
200
  &__menu {
@@ -220,7 +220,7 @@ const handleLogout = () => {
220
220
 
221
221
  &__user {
222
222
  padding: 10px;
223
- border-top: 1px solid var(--xto-border-color-light, #E2E8F0);
223
+ border-top: 1px solid var(--xto-border-color-light, #E5E6EB);
224
224
  display: flex;
225
225
  align-items: center;
226
226
  justify-content: space-between;
@@ -239,7 +239,7 @@ const handleLogout = () => {
239
239
 
240
240
  &__user-role {
241
241
  font-size: 12px;
242
- color: var(--xto-color-text-secondary, #64748B);
242
+ color: var(--xto-color-text-secondary, #86909C);
243
243
  }
244
244
  }
245
245
  </style>
@@ -156,8 +156,8 @@ const hasChildren = computed(() => {
156
156
  height: 16px;
157
157
  font-size: 12px;
158
158
  font-weight: 600;
159
- color: var(--xto-color-primary, #1D4ED8);
160
- background-color: var(--xto-color-primary-light-8, #DBEAFE);
159
+ color: var(--xto-color-primary, #12B6AF);
160
+ background-color: var(--xto-color-primary-light-8, #DDF6F4);
161
161
  border-radius: var(--xto-border-radius-small, 4px);
162
162
  }
163
163
  </style>
@@ -83,7 +83,7 @@ const handleClose = (path: string) => {
83
83
  height: 100%;
84
84
  padding: 0 16px;
85
85
  background-color: var(--xto-bg-color, #FFFFFF);
86
- border-bottom: 1px solid var(--xto-border-color-light, #E2E8F0);
86
+ border-bottom: 1px solid var(--xto-border-color-light, #E5E6EB);
87
87
  box-sizing: border-box;
88
88
 
89
89
  :deep(.t-tabs) {
@@ -106,17 +106,17 @@ const handleClose = (path: string) => {
106
106
  margin-right: 4px;
107
107
  border-radius: 0;
108
108
  padding: 0 16px;
109
- color: var(--xto-color-text-regular, #334155);
109
+ color: var(--xto-color-text-regular, #4E5566);
110
110
  position: relative;
111
111
  transition: color 0.2s;
112
112
 
113
113
  &:hover {
114
- color: var(--xto-color-primary, #1D4ED8);
114
+ color: var(--xto-color-primary, #12B6AF);
115
115
  }
116
116
 
117
117
  &.is-active {
118
118
  background-color: transparent;
119
- color: var(--xto-color-primary, #1D4ED8);
119
+ color: var(--xto-color-primary, #12B6AF);
120
120
  font-weight: 600;
121
121
 
122
122
  &::after {
@@ -127,7 +127,7 @@ const handleClose = (path: string) => {
127
127
  right: 12px;
128
128
  height: 2px;
129
129
  border-radius: 2px;
130
- background-color: var(--xto-color-primary, #1D4ED8);
130
+ background-color: var(--xto-color-primary, #12B6AF);
131
131
  }
132
132
  }
133
133
  }
@@ -150,7 +150,7 @@ const handleClose = (path: string) => {
150
150
 
151
151
  &:hover {
152
152
  background-color: var(--xto-color-danger-light, #FEE2E2);
153
- color: var(--xto-color-danger, #EF4444);
153
+ color: var(--xto-color-danger, #F53F3F);
154
154
  }
155
155
  }
156
156
  </style>
@@ -584,7 +584,7 @@ onUnmounted(() => {
584
584
  &__logo-text {
585
585
  font-size: 16px;
586
586
  font-weight: 600;
587
- color: var(--xto-color-primary, #4F46E5);
587
+ color: var(--xto-color-primary, #12B6AF);
588
588
  }
589
589
 
590
590
  &__menu {
@@ -676,7 +676,7 @@ onUnmounted(() => {
676
676
  height: 16px;
677
677
  font-size: 12px;
678
678
  font-weight: 600;
679
- color: var(--xto-color-primary, #4F46E5);
679
+ color: var(--xto-color-primary, #12B6AF);
680
680
  background-color: var(--xto-color-primary-light-8, #C7D2FE);
681
681
  border-radius: var(--xto-border-radius-small, 4px);
682
682
  }
@@ -692,28 +692,28 @@ onUnmounted(() => {
692
692
  position: relative;
693
693
  display: flex;
694
694
  align-items: center;
695
- background-color: var(--xto-fill-color-light, #F5F7FA);
695
+ background-color: var(--xto-fill-color-light, #F7F8FA);
696
696
  border-radius: var(--xto-border-radius-base, 6px);
697
697
  padding: 0 12px;
698
698
  height: 32px;
699
699
  width: 200px;
700
700
 
701
701
  &-icon {
702
- color: var(--xto-color-text-secondary, #6B7280);
702
+ color: var(--xto-color-text-secondary, #86909C);
703
703
  }
704
704
 
705
705
  &-input {
706
706
  flex: 1;
707
707
  height: 100%;
708
708
  font-size: 14px;
709
- color: var(--xto-color-text-primary, #1F2937);
709
+ color: var(--xto-color-text-primary, #1F2329);
710
710
  background: transparent;
711
711
  border: none;
712
712
  outline: none;
713
713
  padding-left: 8px;
714
714
 
715
715
  &::placeholder {
716
- color: var(--xto-color-text-placeholder, #9CA3AF);
716
+ color: var(--xto-color-text-placeholder, #A9AEB8);
717
717
  }
718
718
  }
719
719
 
@@ -744,17 +744,17 @@ onUnmounted(() => {
744
744
  transition: background-color 0.2s;
745
745
 
746
746
  &:hover {
747
- background-color: var(--xto-fill-color, #EDF2F7);
747
+ background-color: var(--xto-fill-color, #EDEEF1);
748
748
  }
749
749
 
750
750
  &-title {
751
751
  font-size: 14px;
752
- color: var(--xto-color-text-primary, #1F2937);
752
+ color: var(--xto-color-text-primary, #1F2329);
753
753
  }
754
754
 
755
755
  &-parent {
756
756
  font-size: 12px;
757
- color: var(--xto-color-text-secondary, #6B7280);
757
+ color: var(--xto-color-text-secondary, #86909C);
758
758
  margin-left: auto;
759
759
  }
760
760
  }
@@ -776,7 +776,7 @@ onUnmounted(() => {
776
776
  height: 16px;
777
777
  font-size: 12px;
778
778
  font-weight: 600;
779
- color: var(--xto-color-primary, #4F46E5);
779
+ color: var(--xto-color-primary, #12B6AF);
780
780
  background-color: var(--xto-color-primary-light-8, #C7D2FE);
781
781
  border-radius: var(--xto-border-radius-small, 4px);
782
782
  }
@@ -784,7 +784,7 @@ onUnmounted(() => {
784
784
  &-empty {
785
785
  padding: 16px 12px;
786
786
  text-align: center;
787
- color: var(--xto-color-text-secondary, #6B7280);
787
+ color: var(--xto-color-text-secondary, #86909C);
788
788
  font-size: 14px;
789
789
  }
790
790
  }
@@ -797,12 +797,12 @@ onUnmounted(() => {
797
797
  justify-content: center;
798
798
  cursor: pointer;
799
799
  border-radius: var(--xto-border-radius-base, 6px);
800
- color: var(--xto-color-text-regular, #4B5563);
800
+ color: var(--xto-color-text-regular, #4E5566);
801
801
  transition: all 0.2s;
802
802
 
803
803
  &:hover {
804
- background-color: var(--xto-fill-color, #EDF2F7);
805
- color: var(--xto-color-primary, #4F46E5);
804
+ background-color: var(--xto-fill-color, #EDEEF1);
805
+ color: var(--xto-color-primary, #12B6AF);
806
806
  }
807
807
  }
808
808
 
@@ -821,13 +821,13 @@ onUnmounted(() => {
821
821
  transition: background-color 0.2s;
822
822
 
823
823
  &:hover {
824
- background-color: var(--xto-fill-color, #EDF2F7);
824
+ background-color: var(--xto-fill-color, #EDEEF1);
825
825
  }
826
826
  }
827
827
 
828
828
  &-name {
829
829
  font-size: 14px;
830
- color: var(--xto-color-text-primary, #1F2937);
830
+ color: var(--xto-color-text-primary, #1F2329);
831
831
  max-width: 100px;
832
832
  overflow: hidden;
833
833
  text-overflow: ellipsis;
@@ -836,7 +836,7 @@ onUnmounted(() => {
836
836
 
837
837
  &-arrow {
838
838
  font-size: 10px;
839
- color: var(--xto-color-text-secondary, #6B7280);
839
+ color: var(--xto-color-text-secondary, #86909C);
840
840
  transition: transform 0.2s;
841
841
 
842
842
  &.is-active {
@@ -849,7 +849,7 @@ onUnmounted(() => {
849
849
  width: 32px;
850
850
  height: 32px;
851
851
  border-radius: 50%;
852
- background: linear-gradient(135deg, var(--xto-color-primary, #4F46E5), var(--xto-color-primary-light-3, #818CF8));
852
+ background: linear-gradient(135deg, var(--xto-color-primary, #12B6AF), var(--xto-color-primary-light-3, #51DAD3));
853
853
  display: flex;
854
854
  align-items: center;
855
855
  justify-content: center;
@@ -881,7 +881,7 @@ onUnmounted(() => {
881
881
  width: 40px;
882
882
  height: 40px;
883
883
  border-radius: 50%;
884
- background: linear-gradient(135deg, var(--xto-color-primary, #4F46E5), var(--xto-color-primary-light-3, #818CF8));
884
+ background: linear-gradient(135deg, var(--xto-color-primary, #12B6AF), var(--xto-color-primary-light-3, #51DAD3));
885
885
  display: flex;
886
886
  align-items: center;
887
887
  justify-content: center;
@@ -897,18 +897,18 @@ onUnmounted(() => {
897
897
  &-name {
898
898
  font-size: 14px;
899
899
  font-weight: 500;
900
- color: var(--xto-color-text-primary, #1F2937);
900
+ color: var(--xto-color-text-primary, #1F2329);
901
901
  }
902
902
 
903
903
  &-role {
904
904
  font-size: 12px;
905
- color: var(--xto-color-text-secondary, #6B7280);
905
+ color: var(--xto-color-text-secondary, #86909C);
906
906
  margin-top: 2px;
907
907
  }
908
908
 
909
909
  &-divider {
910
910
  height: 1px;
911
- background-color: var(--xto-border-color-lighter, #EDF2F7);
911
+ background-color: var(--xto-border-color-lighter, #EDEEF1);
912
912
  }
913
913
 
914
914
  &-menu {
@@ -922,20 +922,20 @@ onUnmounted(() => {
922
922
  padding: 10px 16px;
923
923
  cursor: pointer;
924
924
  font-size: 14px;
925
- color: var(--xto-color-text-regular, #4B5563);
925
+ color: var(--xto-color-text-regular, #4E5566);
926
926
  transition: all 0.2s;
927
927
 
928
928
  &:hover {
929
- background-color: var(--xto-fill-color, #EDF2F7);
930
- color: var(--xto-color-text-primary, #1F2937);
929
+ background-color: var(--xto-fill-color, #EDEEF1);
930
+ color: var(--xto-color-text-primary, #1F2329);
931
931
  }
932
932
 
933
933
  &--danger {
934
- color: var(--xto-color-danger, #EF4444);
934
+ color: var(--xto-color-danger, #F53F3F);
935
935
 
936
936
  &:hover {
937
937
  background-color: var(--xto-color-danger-light, #FEE2E2);
938
- color: var(--xto-color-danger, #EF4444);
938
+ color: var(--xto-color-danger, #F53F3F);
939
939
  }
940
940
  }
941
941
  }
@@ -951,7 +951,7 @@ onUnmounted(() => {
951
951
  .settings-title {
952
952
  font-size: 14px;
953
953
  font-weight: 500;
954
- color: var(--xto-color-text-primary, #1F2937);
954
+ color: var(--xto-color-text-primary, #1F2329);
955
955
  margin-bottom: 12px;
956
956
  }
957
957
 
@@ -967,7 +967,7 @@ onUnmounted(() => {
967
967
  align-items: center;
968
968
  gap: 8px;
969
969
  padding: 12px;
970
- border: 1px solid var(--xto-border-color, #D1D5DB);
970
+ border: 1px solid var(--xto-border-color, #D9DCE1);
971
971
  border-radius: var(--xto-border-radius-base, 6px);
972
972
  cursor: pointer;
973
973
  transition: all 0.2s;
@@ -977,21 +977,21 @@ onUnmounted(() => {
977
977
  }
978
978
 
979
979
  &.is-active {
980
- border-color: var(--xto-color-primary, #4F46E5);
980
+ border-color: var(--xto-color-primary, #12B6AF);
981
981
  background-color: var(--xto-color-primary-light-9, #EEF2FF);
982
982
  }
983
983
 
984
984
  &__preview {
985
985
  width: 48px;
986
986
  height: 36px;
987
- border: 1px solid var(--xto-border-color-light, #E5E7EB);
987
+ border: 1px solid var(--xto-border-color-light, #E5E6EB);
988
988
  border-radius: 2px;
989
989
  overflow: hidden;
990
990
  }
991
991
 
992
992
  &__label {
993
993
  font-size: 12px;
994
- color: var(--xto-color-text-regular, #4B5563);
994
+ color: var(--xto-color-text-regular, #4E5566);
995
995
  }
996
996
  }
997
997
 
@@ -1013,12 +1013,12 @@ onUnmounted(() => {
1013
1013
 
1014
1014
  .preview-header {
1015
1015
  height: 20%;
1016
- background-color: var(--xto-border-color-light, #E5E7EB);
1016
+ background-color: var(--xto-border-color-light, #E5E6EB);
1017
1017
  }
1018
1018
 
1019
1019
  .preview-content {
1020
1020
  flex: 1;
1021
- background-color: var(--xto-bg-color-page, #F5F7FA);
1021
+ background-color: var(--xto-bg-color-page, #F7F8FA);
1022
1022
  }
1023
1023
  }
1024
1024
  }
@@ -1035,7 +1035,7 @@ onUnmounted(() => {
1035
1035
 
1036
1036
  .preview-content-full {
1037
1037
  flex: 1;
1038
- background-color: var(--xto-bg-color-page, #F5F7FA);
1038
+ background-color: var(--xto-bg-color-page, #F7F8FA);
1039
1039
  }
1040
1040
  }
1041
1041
 
@@ -1051,7 +1051,7 @@ onUnmounted(() => {
1051
1051
 
1052
1052
  .preview-mix-left {
1053
1053
  width: 30%;
1054
- background-color: var(--xto-color-primary, #4F46E5);
1054
+ background-color: var(--xto-color-primary, #12B6AF);
1055
1055
  }
1056
1056
  }
1057
1057
 
@@ -1066,7 +1066,7 @@ onUnmounted(() => {
1066
1066
 
1067
1067
  .preview-mix-content {
1068
1068
  flex: 1;
1069
- background-color: var(--xto-bg-color-page, #F5F7FA);
1069
+ background-color: var(--xto-bg-color-page, #F7F8FA);
1070
1070
  }
1071
1071
  }
1072
1072
  }
@@ -1091,7 +1091,7 @@ onUnmounted(() => {
1091
1091
  }
1092
1092
 
1093
1093
  &.is-active {
1094
- box-shadow: 0 0 0 2px var(--xto-bg-color, #FFFFFF), 0 0 0 4px var(--xto-color-primary, #4F46E5);
1094
+ box-shadow: 0 0 0 2px var(--xto-bg-color, #FFFFFF), 0 0 0 4px var(--xto-color-primary, #12B6AF);
1095
1095
  }
1096
1096
  }
1097
1097
 
@@ -1108,7 +1108,7 @@ onUnmounted(() => {
1108
1108
 
1109
1109
  span {
1110
1110
  font-size: 14px;
1111
- color: var(--xto-color-text-regular, #4B5563);
1111
+ color: var(--xto-color-text-regular, #4E5566);
1112
1112
  }
1113
1113
  }
1114
1114
 
@@ -1123,7 +1123,7 @@ onUnmounted(() => {
1123
1123
  width: 100%;
1124
1124
  height: 100%;
1125
1125
  border-radius: 11px;
1126
- background-color: var(--xto-border-color, #D1D5DB);
1126
+ background-color: var(--xto-border-color, #D9DCE1);
1127
1127
  position: relative;
1128
1128
  transition: background-color 0.2s;
1129
1129
 
@@ -1142,7 +1142,7 @@ onUnmounted(() => {
1142
1142
 
1143
1143
  &.is-checked {
1144
1144
  .switch-core {
1145
- background-color: var(--xto-color-primary, #4F46E5);
1145
+ background-color: var(--xto-color-primary, #12B6AF);
1146
1146
 
1147
1147
  &::after {
1148
1148
  left: 24px;
@@ -139,7 +139,7 @@ const showMixSidebar = computed(() => {
139
139
  width: 100%;
140
140
  height: 50px;
141
141
  background-color: var(--xto-bg-color, #FFFFFF);
142
- border-bottom: 1px solid var(--xto-border-color-lighter, #EDF2F7);
142
+ border-bottom: 1px solid var(--xto-border-color-lighter, #EDEEF1);
143
143
  flex-shrink: 0;
144
144
  }
145
145
 
@@ -163,7 +163,7 @@ const showMixSidebar = computed(() => {
163
163
  height: 50px;
164
164
  box-sizing: border-box;
165
165
  background-color: var(--xto-bg-color, #FFFFFF);
166
- border-bottom: 1px solid var(--xto-border-color-lighter, #EDF2F7);
166
+ border-bottom: 1px solid var(--xto-border-color-lighter, #EDEEF1);
167
167
  flex-shrink: 0;
168
168
  }
169
169
 
@@ -186,14 +186,14 @@ const showMixSidebar = computed(() => {
186
186
  height: 50px;
187
187
  box-sizing: border-box;
188
188
  background-color: var(--xto-bg-color, #FFFFFF);
189
- border-bottom: 1px solid var(--xto-border-color-lighter, #EDF2F7);
189
+ border-bottom: 1px solid var(--xto-border-color-lighter, #EDEEF1);
190
190
  flex-shrink: 0;
191
191
  }
192
192
 
193
193
  &__content {
194
194
  flex: 1;
195
195
  overflow: auto;
196
- background-color: var(--xto-bg-color-page, #F5F7FA);
196
+ background-color: var(--xto-bg-color-page, #F7F8FA);
197
197
  padding: 0;
198
198
  }
199
199
  }
@@ -73,7 +73,18 @@ export function setupRouterGuards(router: Router, options: RouterGuardOptions =
73
73
  } else {
74
74
  // 检查是否已获取用户信息
75
75
  if (userStore.isLoggedIn) {
76
- // 已有用户信息,直接放行
76
+ // 已有用户信息,直接放行;但当前应用菜单为空时(跨应用共享 localStorage 场景)补拉菜单
77
+ if (!menuStore.hasMenu) {
78
+ try {
79
+ const menuList = options.fetchMenu
80
+ ? await options.fetchMenu()
81
+ : await getMenuTree(options.appId)
82
+ menuStore.setMenuList(menuList)
83
+ } catch (error) {
84
+ // 菜单拉取失败不影响页面访问,仅记录日志
85
+ console.warn('补拉菜单失败:', error)
86
+ }
87
+ }
77
88
  // 添加缓存页面
78
89
  if (to.name && to.meta.keepAlive) {
79
90
  appStore.addCachedView(to.name as string)
package/src/stores/app.ts CHANGED
@@ -21,7 +21,7 @@ export const useAppStore = defineStore('app', () => {
21
21
  const showTabs = ref<boolean>(local.get<boolean>('showTabs') ?? true)
22
22
  const showFooter = ref<boolean>(local.get<boolean>('showFooter') ?? true)
23
23
  const showBreadcrumb = ref<boolean>(local.get<boolean>('showBreadcrumb') ?? true)
24
- const primaryColor = ref<string>(local.get<string>('primaryColor') || '#4F46E5')
24
+ const primaryColor = ref<string>(local.get<string>('primaryColor') || '#12B6AF')
25
25
  const cachedViews = ref<string[]>([])
26
26
  const mixSubMenus = ref<any[]>([])
27
27
 
@@ -137,7 +137,7 @@ export const useAppStore = defineStore('app', () => {
137
137
  // 初始化主题
138
138
  const initTheme = () => {
139
139
  updateTheme()
140
- if (primaryColor.value !== '#4F46E5') {
140
+ if (primaryColor.value !== '#12B6AF') {
141
141
  document.documentElement.style.setProperty('--xto-color-primary', primaryColor.value)
142
142
  }
143
143
  }
@@ -6,10 +6,19 @@ import { defineStore } from 'pinia'
6
6
  import { ref, computed } from 'vue'
7
7
  import type { MenuItem } from '@/types/api'
8
8
  import { local } from '@/utils/storage'
9
+ import { getAppId } from '@/utils/config'
9
10
 
10
11
  const MENU_LIST_KEY = 'menu_list'
11
12
  const PERMISSION_LIST_KEY = 'permission_list'
12
13
 
14
+ /**
15
+ * 菜单存储 key 按应用隔离:
16
+ * 多个前端部署在同一域名下(如 appli.tooyu.service/portal、/tangyang)共享 localStorage,
17
+ * 固定 key 会导致 A 应用的菜单被 B 应用复用,必须加 appId 命名空间
18
+ */
19
+ const menuListKey = () => `${MENU_LIST_KEY}_${getAppId()}`
20
+ const permissionListKey = () => `${PERMISSION_LIST_KEY}_${getAppId()}`
21
+
13
22
  // 首页菜单(参考 tineco-ui)
14
23
  const indexMenu: MenuItem = {
15
24
  menuCode: 'home',
@@ -62,9 +71,9 @@ function extractPermissions(menus: MenuItem[]): string[] {
62
71
 
63
72
  export const useMenuStore = defineStore('menu', () => {
64
73
  // 状态
65
- const menuList = ref<MenuItem[]>(local.get<MenuItem[]>(MENU_LIST_KEY) || [])
74
+ const menuList = ref<MenuItem[]>(local.get<MenuItem[]>(menuListKey()) || [])
66
75
  // 功能权限列表
67
- const permissions = ref<string[]>(local.get<string[]>(PERMISSION_LIST_KEY) || [])
76
+ const permissions = ref<string[]>(local.get<string[]>(permissionListKey()) || [])
68
77
 
69
78
  // 计算属性
70
79
  const hasMenu = computed(() => menuList.value.length > 0)
@@ -73,22 +82,22 @@ export const useMenuStore = defineStore('menu', () => {
73
82
  const setMenuList = (menus: MenuItem[]) => {
74
83
  // 提取功能权限
75
84
  permissions.value = extractPermissions(menus)
76
- local.set(PERMISSION_LIST_KEY, permissions.value)
85
+ local.set(permissionListKey(), permissions.value)
77
86
 
78
87
  // 过滤菜单,只保留菜单项(type !== 1)
79
88
  const filteredMenus = filterMenus(menus)
80
89
 
81
90
  // 添加首页菜单到开头
82
91
  menuList.value = [indexMenu, ...filteredMenus]
83
- local.set(MENU_LIST_KEY, menuList.value)
92
+ local.set(menuListKey(), menuList.value)
84
93
  }
85
94
 
86
95
  // 清除菜单
87
96
  const clearMenu = () => {
88
97
  menuList.value = []
89
98
  permissions.value = []
90
- local.remove(MENU_LIST_KEY)
91
- local.remove(PERMISSION_LIST_KEY)
99
+ local.remove(menuListKey())
100
+ local.remove(permissionListKey())
92
101
  }
93
102
 
94
103
  // 检查是否有某个权限
package/src/style.scss CHANGED
@@ -9,8 +9,8 @@
9
9
  /* 全局样式变量(与 @xto/core 主题系统对齐) */
10
10
  :root {
11
11
  --xto-bg-color: #FFFFFF;
12
- --xto-bg-color-page: #F5F7FA;
13
- --xto-border-color-lighter: #EDF2F7;
12
+ --xto-bg-color-page: #F7F8FA;
13
+ --xto-border-color-lighter: #EDEEF1;
14
14
  }
15
15
 
16
16
  /* ===== 交互光标与文本选中规范 =====