leisure-core 0.7.7 → 0.7.8

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 (96) hide show
  1. package/{PROJECT_GUIDE.md → README.md} +1 -1
  2. package/license.md +201 -0
  3. package/package.json +14 -1
  4. package/index.js +0 -223
  5. package/le-area/index.js +0 -7
  6. package/le-area/src/main.vue +0 -112
  7. package/le-button/index.js +0 -7
  8. package/le-button/src/main.vue +0 -47
  9. package/le-button-attach/index.js +0 -6
  10. package/le-button-attach/src/main.vue +0 -171
  11. package/le-button-msg/index.js +0 -7
  12. package/le-button-msg/src/main.vue +0 -65
  13. package/le-button-qr/index.js +0 -7
  14. package/le-button-qr/src/main.vue +0 -96
  15. package/le-date-picker/index.js +0 -7
  16. package/le-date-picker/src/main.vue +0 -67
  17. package/le-date-picker-auto/index.js +0 -6
  18. package/le-date-picker-auto/src/main.vue +0 -131
  19. package/le-dialog-container/index.js +0 -7
  20. package/le-dialog-container/src/main.vue +0 -80
  21. package/le-form/index.js +0 -7
  22. package/le-form/src/main.vue +0 -13
  23. package/le-form-item/index.js +0 -7
  24. package/le-form-item/src/main.vue +0 -13
  25. package/le-home/index.js +0 -7
  26. package/le-home/src/LeHeaderMenu.vue +0 -60
  27. package/le-home/src/main.vue +0 -1315
  28. package/le-home/src/sub.vue +0 -82
  29. package/le-image/index.js +0 -7
  30. package/le-image/src/main.vue +0 -53
  31. package/le-input/index.js +0 -7
  32. package/le-input/src/main.vue +0 -15
  33. package/le-input-advanced/index.js +0 -7
  34. package/le-input-advanced/src/main.vue +0 -71
  35. package/le-input-number/index.js +0 -7
  36. package/le-input-number/src/main.vue +0 -15
  37. package/le-input-validate/index.js +0 -6
  38. package/le-input-validate/src/main.vue +0 -469
  39. package/le-libs/js/drag.js +0 -78
  40. package/le-libs/js/event.js +0 -3
  41. package/le-libs/js/hrequest.js +0 -76
  42. package/le-libs/js/hrequestFile.js +0 -62
  43. package/le-libs/js/info.js +0 -7
  44. package/le-libs/js/tokens.js +0 -13
  45. package/le-libs/mixins/main.js +0 -48
  46. package/le-list/index.js +0 -7
  47. package/le-list/src/main.vue +0 -645
  48. package/le-list-form/index.js +0 -7
  49. package/le-list-form/src/main.vue +0 -474
  50. package/le-login/index.js +0 -7
  51. package/le-login/src/ForgotPassword.vue +0 -613
  52. package/le-login/src/main.vue +0 -982
  53. package/le-media/index.js +0 -7
  54. package/le-media/src/main.vue +0 -298
  55. package/le-media-list/index.js +0 -7
  56. package/le-media-list/src/main.vue +0 -178
  57. package/le-media-upload/index.js +0 -7
  58. package/le-media-upload/src/main.vue +0 -329
  59. package/le-menu/index.js +0 -7
  60. package/le-menu/src/main.vue +0 -248
  61. package/le-report/index.js +0 -6
  62. package/le-report/src/main.vue +0 -1747
  63. package/le-report/src/rmixins.js +0 -30
  64. package/le-role/index.js +0 -7
  65. package/le-role/src/main.vue +0 -183
  66. package/le-role/src/sub.vue +0 -79
  67. package/le-role-user/index.js +0 -7
  68. package/le-role-user/src/main.vue +0 -160
  69. package/le-role-user/src/sub.vue +0 -90
  70. package/le-select/index.js +0 -7
  71. package/le-select/src/main.vue +0 -49
  72. package/le-select-multi/index.js +0 -6
  73. package/le-select-multi/src/main.vue +0 -816
  74. package/le-select-option/index.js +0 -7
  75. package/le-select-option/src/main.vue +0 -69
  76. package/le-select-search/index.js +0 -7
  77. package/le-select-search/src/main.vue +0 -46
  78. package/le-span/index.js +0 -7
  79. package/le-span/src/main.vue +0 -29
  80. package/le-table-edit/index.js +0 -6
  81. package/le-table-edit/src/main.vue +0 -689
  82. package/le-theme/common/vars.css +0 -131
  83. package/le-theme/iconfont/iconfont.css +0 -125
  84. package/le-theme/iconfont/iconfont.ttf +0 -0
  85. package/le-theme/iconfont/iconfont.woff +0 -0
  86. package/le-theme/iconfont/iconfont.woff2 +0 -0
  87. package/le-theme/index.js +0 -189
  88. package/le-theme/pages/index.css +0 -15
  89. package/le-upload/index.js +0 -7
  90. package/le-upload/src/main.vue +0 -134
  91. package/le-upload-table/index.js +0 -6
  92. package/le-upload-table/src/main.vue +0 -648
  93. package/le-url/index.js +0 -7
  94. package/le-url/src/main.vue +0 -27
  95. package/le-video/index.js +0 -7
  96. package/le-video/src/main.vue +0 -42
@@ -1,1315 +0,0 @@
1
- <template>
2
- <el-container class="le-home-cp-container">
3
- <el-header class="header">
4
- <el-row type="flex" align="middle" class="header-row">
5
- <el-col :span="effectiveHeaderMenu.length ? 4 : 8" class="leftsection">
6
- <div class="grid-content bg-purple">
7
- <span class="userinfo-inner" @click="clickLeftTop">{{
8
- companyInfo.name
9
- }}</span>
10
- </div>
11
- </el-col>
12
- <el-col
13
- v-if="effectiveHeaderMenu.length"
14
- :span="12"
15
- class="middlesection"
16
- >
17
- <el-menu
18
- mode="horizontal"
19
- class="header-menu"
20
- :background-color="headerMenuBgColor"
21
- :text-color="headerMenuTextColor"
22
- :active-text-color="headerMenuActiveTextColor"
23
- :unique-opened="true"
24
- popper-class="le-header-menu-popper"
25
- >
26
- <le-header-menu
27
- v-for="item in effectiveHeaderMenu"
28
- :key="item.id || item.name"
29
- :item="item"
30
- :level="0"
31
- :on-select="handleHeaderMenuSelect"
32
- ></le-header-menu>
33
- </el-menu>
34
- </el-col>
35
- <el-col
36
- :span="effectiveHeaderMenu.length ? 8 : 16"
37
- class="rightsection"
38
- >
39
- <div class="grid-content bg-purple-light">
40
- <slot name="rightComment"> </slot>
41
- <el-dropdown size="medium" trigger="click" @command="handleCommand">
42
- <span class="el-dropdown-link userinfo-inner-t">
43
- <!-- <img src="@/assets/tx.png" class="img" /> -->
44
- {{ username }}
45
- <i class="el-icon-arrow-down el-icon--right"></i>
46
- </span>
47
- <el-dropdown-menu slot="dropdown">
48
- <el-dropdown-item
49
- v-for="item in extraDropdownItems"
50
- :key="item.command"
51
- :command="item.command"
52
- :divided="item.divided"
53
- >
54
- {{ item.label }}
55
- </el-dropdown-item>
56
- <el-dropdown-item command="openSysSettings"
57
- >系统设置</el-dropdown-item
58
- >
59
- <el-dropdown-item command="2" divided
60
- >退出系统</el-dropdown-item
61
- >
62
- </el-dropdown-menu>
63
- </el-dropdown>
64
- </div>
65
- </el-col>
66
- </el-row>
67
- </el-header>
68
- <el-container>
69
- <el-aside
70
- class="aside"
71
- :class="{ aside_hide: isHideMenu }"
72
- :style="asideStyle"
73
- ref="asideRef"
74
- >
75
- <el-menu
76
- ref="sideMenu"
77
- :unique-opened="true"
78
- class="menu"
79
- :background-color="menuBackgroundColor"
80
- :text-color="menuTextColor"
81
- :active-text-color="menuActiveTextColor"
82
- >
83
- <el-submenu
84
- :index="item1.name"
85
- v-for="item1 in menuData"
86
- :key="item1.id"
87
- >
88
- <template slot="title">
89
- <div @click="clickTitle">
90
- <i :class="item1.icon"></i>&nbsp;
91
- <span>{{ item1.title }}</span>
92
- </div>
93
- </template>
94
- <el-menu-item
95
- class="menuItem"
96
- v-for="item2 in item1.children"
97
- :key="item2.id"
98
- :index="item2.name"
99
- @click="clickMenuItem(item2)"
100
- :title="shouldShowTooltip(item2.title) ? item2.title : ''"
101
- >
102
- &nbsp;&nbsp;
103
- <span class="menu-item-text">{{ item2.title }}</span>
104
- </el-menu-item>
105
- </el-submenu>
106
- </el-menu>
107
- <!-- 只在展开时显示拖动条 -->
108
- <div
109
- v-if="!isHideMenu"
110
- class="drag-handle"
111
- @mousedown.prevent="startDrag"
112
- ></div>
113
- </el-aside>
114
- <el-main class="main" style="padding: 10px 20px">
115
- <div class="aside_open_close" @click="asidechange">
116
- <i class="el-icon-arrow-left" v-if="aside_open_close"></i>
117
- <i class="el-icon-arrow-right" v-else></i>
118
- </div>
119
- <div>
120
- <el-tabs
121
- class="el-tabs_"
122
- v-model="tabNameCurrent"
123
- closable
124
- @tab-click="handleTabClick"
125
- @tab-remove="removeTab"
126
- >
127
- <el-tab-pane
128
- v-for="item in tabsAll"
129
- :key="item.name"
130
- :label="item.title"
131
- :name="item.name"
132
- >
133
- </el-tab-pane>
134
- </el-tabs>
135
- <router-view
136
- :key="refreshKey.toString() + $route.fullPath"
137
- ></router-view>
138
- </div>
139
- </el-main>
140
- </el-container>
141
- <!-- 系统设置对话框 -->
142
- <el-dialog
143
- :visible.sync="sysSettingsVisible"
144
- title="系统设置"
145
- width="560px"
146
- :close-on-click-modal="false"
147
- custom-class="rounded-dialog"
148
- append-to-body
149
- >
150
- <el-tabs v-model="sysSettingsTab" type="border-card">
151
- <!-- 修改密码 -->
152
- <el-tab-pane label="修改密码" name="pwd">
153
- <el-form
154
- ref="sysPwdForm"
155
- :model="sysPwdForm"
156
- :rules="sysPwdRules"
157
- label-width="100px"
158
- style="padding: 20px 0"
159
- >
160
- <el-form-item label="新密码" prop="newPwd">
161
- <el-input
162
- v-model="sysPwdForm.newPwd"
163
- type="password"
164
- placeholder="请输入新密码"
165
- show-password
166
- ></el-input>
167
- </el-form-item>
168
- <el-form-item label="确认密码" prop="confirmPwd">
169
- <el-input
170
- v-model="sysPwdForm.confirmPwd"
171
- type="password"
172
- placeholder="请再次输入新密码"
173
- show-password
174
- ></el-input>
175
- </el-form-item>
176
- </el-form>
177
- </el-tab-pane>
178
-
179
- <!-- 修改个人信息 -->
180
- <el-tab-pane label="修改个人信息" name="person">
181
- <el-form
182
- ref="sysPerForm"
183
- :model="sysPerForm"
184
- :rules="sysPerRules"
185
- label-width="100px"
186
- style="padding: 20px 0"
187
- >
188
- <el-form-item label="昵称" prop="nick">
189
- <el-input
190
- v-model="sysPerForm.nick"
191
- placeholder="请输入昵称"
192
- ></el-input>
193
- </el-form-item>
194
- <el-form-item label="手机号" prop="phone">
195
- <el-input
196
- v-model="sysPerForm.phone"
197
- placeholder="请输入手机号"
198
- maxlength="11"
199
- ></el-input>
200
- </el-form-item>
201
- </el-form>
202
- </el-tab-pane>
203
-
204
- <!-- 设置皮肤 -->
205
- <el-tab-pane label="设置皮肤" name="skin">
206
- <div class="skin-picker">
207
- <div
208
- v-for="skin in availableSkins"
209
- :key="skin.name"
210
- :class="['skin-item', { active: currentSkin === skin.name }]"
211
- @click="selectSkin(skin.name)"
212
- >
213
- <div class="skin-color" :style="{ background: skin.color }"></div>
214
- <div class="skin-info">
215
- <div class="skin-name">{{ skin.label }}</div>
216
- <div class="skin-desc" v-if="skin.name === currentSkin">
217
- 当前使用
218
- </div>
219
- </div>
220
- <i
221
- v-if="currentSkin === skin.name"
222
- class="el-icon-check skin-check"
223
- ></i>
224
- </div>
225
- </div>
226
- </el-tab-pane>
227
- </el-tabs>
228
- <!-- 对话框底部按钮:根据当前 tab 显示不同按钮 -->
229
- <div slot="footer">
230
- <template v-if="sysSettingsTab === 'pwd'">
231
- <el-button @click="sysSettingsVisible = false">取消</el-button>
232
- <el-button type="primary" @click="submitSysPwd">确定</el-button>
233
- </template>
234
- <template v-else-if="sysSettingsTab === 'person'">
235
- <el-button @click="sysSettingsVisible = false">取消</el-button>
236
- <el-button type="primary" @click="submitSysPer">确定</el-button>
237
- </template>
238
- <template v-else-if="sysSettingsTab === 'skin'">
239
- <el-button @click="sysSettingsVisible = false">关闭</el-button>
240
- </template>
241
- </div>
242
- </el-dialog>
243
- <div v-show="contextMenuVisible">
244
- <ul
245
- :style="{ left: menuLeft + 'px', top: menuTop + 'px' }"
246
- class="contextmenu"
247
- >
248
- <li>
249
- <el-button
250
- type="text"
251
- size="mini"
252
- icon="el-icon-refresh"
253
- @click="closeOtherTab"
254
- >关闭其它</el-button
255
- >
256
- </li>
257
- <li>
258
- <el-button
259
- type="text"
260
- size="mini"
261
- icon="el-icon-error"
262
- @click="closeAllTabs"
263
- >关闭所有</el-button
264
- >
265
- </li>
266
- </ul>
267
- </div>
268
- <slot name="otherContainer"></slot>
269
- </el-container>
270
- </template>
271
- <script>
272
- import { cloneDeep } from "lodash";
273
- import { throttle } from "lodash"; // 可选,用于性能优化
274
- import LeHeaderMenu from "./LeHeaderMenu.vue";
275
- export default {
276
- name: "le-home",
277
- components: { LeHeaderMenu },
278
- props: {
279
- extraDropdownItems: {
280
- type: Array,
281
- default: () => [],
282
- },
283
- companyInfo: {
284
- type: Object,
285
- default: () => ({}),
286
- },
287
- showClose: {
288
- type: Boolean,
289
- default: true,
290
- },
291
- // 顶部横向菜单数据,支持多级嵌套
292
- // 数据结构: [{ id, name, title, icon, children: [...] }]
293
- headerMenu: {
294
- type: Array,
295
- default: () => [],
296
- },
297
- // 是否显示顶部横向菜单
298
- // true: 只要 headerMenu 有数据就显示
299
- // false: 即使 headerMenu 有数据也不显示
300
- showHeaderMenu: {
301
- type: Boolean,
302
- default: false,
303
- },
304
- },
305
-
306
- data() {
307
- // var validatePass = (rule, value, callback) => {
308
- // if (value === "") {
309
- // callback(new Error("请输入密码"));
310
- // } else {
311
- // if (value.length < 8) {
312
- // callback(new Error("密码至少8位"));
313
- // } else {
314
- // if (this.ruleForm.confirmPwd !== "") {
315
- // this.$refs.ruleForm.validateField("confirmPwd ");
316
- // }
317
- // callback();
318
- // }
319
- // }
320
- // };
321
- // var validatePass2 = (rule, value, callback) => {
322
- // if (value === "") {
323
- // callback(new Error("请再次输入密码"));
324
- // } else if (value !== this.ruleForm.pwd) {
325
- // callback(new Error("两次输入密码不一致!"));
326
- // } else {
327
- // callback();
328
- // }
329
- // };
330
- return {
331
- style: {
332
- display: "block",
333
- },
334
-
335
- isHideMenu: false,
336
- aside_open_close: true,
337
- menuData: [],
338
- title: "",
339
- // cacheView: [],
340
- // showChangePwd: false,
341
- // showPerInfo: false,
342
- username: "",
343
- // changeUid: "",
344
- tabNameCurrent: "",
345
- tabsAll: [],
346
- //右键菜单
347
- contextMenuVisible: false,
348
- menuLeft: 0,
349
- menuTop: 0,
350
- pwdinfo: "",
351
- refreshKey: 0,
352
- // 仅添加以下3个变量
353
- isDragging: false,
354
- asideWidth: 200, // 默认宽度,与原宽度一致
355
- dragStartInfo: null, // {startX, startWidth}
356
- // 系统设置对话框
357
- sysSettingsVisible: false,
358
- sysSettingsTab: "pwd",
359
- sysPwdForm: {
360
- oldPwd: "",
361
- newPwd: "",
362
- confirmPwd: "",
363
- },
364
- sysPwdRules: {
365
- // oldPwd: [{ required: true, message: "请输入原密码", trigger: "blur" }],//
366
- newPwd: [
367
- { required: true, message: "请输入新密码", trigger: "blur" },
368
- { min: 8, message: "密码至少8位", trigger: "blur" },
369
- ],
370
- confirmPwd: [
371
- { required: true, message: "请再次输入新密码", trigger: "blur" },
372
- {
373
- validator: (rule, value, callback) => {
374
- if (value !== this.sysPwdForm.newPwd) {
375
- callback(new Error("两次输入密码不一致"));
376
- } else {
377
- callback();
378
- }
379
- },
380
- trigger: "blur",
381
- },
382
- ],
383
- },
384
- sysPerForm: {
385
- nick: "",
386
- phone: "",
387
- },
388
- sysPerRules: {
389
- nick: [{ required: true, message: "请输入昵称", trigger: "blur" }],
390
- phone: [
391
- { required: true, message: "请输入手机号", trigger: "blur" },
392
- {
393
- pattern: /^1[3-9]\d{9}$/,
394
- message: "请输入正确的手机号",
395
- trigger: "blur",
396
- },
397
- ],
398
- },
399
- // 当前皮肤名(响应式,供皮肤选择器和 UI 刷新使用)
400
- currentSkin: "default",
401
- };
402
- },
403
- computed: {
404
- asideStyle() {
405
- // 依赖 currentSkin 让 Vue 知道需要重算(getCssVar 读取 DOM 不是响应式的)
406
- if (this.currentSkin) {
407
- // 触发访问,建立依赖关系
408
- }
409
- if (this.isHideMenu) {
410
- return {
411
- width: "0px",
412
- minWidth: "0px",
413
- maxWidth: "0px",
414
- flex: "0 0 0px",
415
- backgroundColor: this.getCssVar("--le-color-aside-bg", "#3A3A3A"),
416
- };
417
- }
418
- return {
419
- width: `${this.asideWidth}px`,
420
- minWidth: `${this.asideWidth}px`,
421
- maxWidth: `${this.asideWidth}px`,
422
- flex: `0 0 ${this.asideWidth}px`,
423
- transition: this.isDragging ? "none" : "width 0.3s",
424
- backgroundColor: this.getCssVar("--le-color-aside-bg", "#3A3A3A"),
425
- };
426
- },
427
- // el-menu 的三个颜色 prop,绑定到 CSS 变量,实现主题切换
428
- menuBackgroundColor() {
429
- return this.currentSkin, this.getCssVar("--le-color-menu-bg", "#3A3A3A");
430
- },
431
- menuTextColor() {
432
- return this.currentSkin, this.getCssVar("--le-color-aside-text", "#fff");
433
- },
434
- menuActiveTextColor() {
435
- return (
436
- this.currentSkin, this.getCssVar("--le-color-aside-active", "#ffd04b")
437
- );
438
- },
439
- // header 横向菜单:综合判断 showHeaderMenu + headerMenu 数据 + 过滤隐藏项
440
- effectiveHeaderMenu() {
441
- if (!this.showHeaderMenu) return [];
442
- if (!this.headerMenu || !this.headerMenu.length) return [];
443
- return this._filterHiddenMenus(this.headerMenu);
444
- },
445
- // header 横向菜单颜色(跟随主题)
446
- headerMenuBgColor() {
447
- return (
448
- this.currentSkin, this.getCssVar("--le-color-header-bg", "#212121")
449
- );
450
- },
451
- headerMenuTextColor() {
452
- return this.currentSkin, this.getCssVar("--le-color-aside-text", "#fff");
453
- },
454
- headerMenuActiveTextColor() {
455
- return (
456
- this.currentSkin, this.getCssVar("--le-color-aside-active", "#ffd04b")
457
- );
458
- },
459
- // 皮肤列表(供下拉子菜单渲染)
460
- availableSkins() {
461
- return [
462
- { name: "default", label: "默认蓝", color: "#409eff" },
463
- { name: "dark", label: "深色", color: "#0f172a" },
464
- { name: "green", label: "翠绿", color: "#00b96b" },
465
- ];
466
- },
467
- },
468
- mounted() {
469
- this.username =
470
- this.$store.getters.userinfo.nick || this.$store.getters.userinfo.account;
471
- let tab_top_dom = document.getElementsByClassName("el-tabs_");
472
- tab_top_dom[0].oncontextmenu = this.openContextMenu;
473
- if (
474
- this.companyInfo &&
475
- this.companyInfo.name &&
476
- this.companyInfo.name.length > 0
477
- ) {
478
- this.$store.commit("setCname", this.companyInfo.name);
479
- }
480
-
481
- // let dict = [
482
- // {
483
- // title: "是",
484
- // value: 1,
485
- // },
486
- // {
487
- // title: "否",
488
- // value: 0,
489
- // },
490
- // ];
491
-
492
- // this.$store.commit("setDict", dict);
493
-
494
- const menus = cloneDeep(this.$store.getters.menu);
495
- this.menuData = menus.filter(function (item) {
496
- if (item.children) {
497
- item.children = item.children.filter((child) => child.ishide === 0);
498
- }
499
- return item;
500
- });
501
- this.$emit("homeInit");
502
- document.addEventListener("keydown", this.handleKeyDown);
503
-
504
- // 监听全局鼠标事件
505
- document.addEventListener("mousemove", this.handleDrag);
506
- document.addEventListener("mouseup", this.stopDrag);
507
-
508
- // 2026-08-26:监听主题切换事件,更新响应式皮肤名触发 computed 重算
509
- this._themeChangeHandler = (e) => {
510
- const skinName =
511
- (e && e.detail) ||
512
- (this.$leTheme && this.$leTheme.current) ||
513
- "default";
514
- // 更新 currentSkin 后,所有依赖 currentSkin 的 computed 会自动重算
515
- // 包括 asideStyle, menuBackgroundColor, menuTextColor, headerMenuBgColor 等
516
- this.currentSkin = skinName;
517
- };
518
- // 初始化当前皮肤名
519
- if (this.$leTheme) {
520
- this.currentSkin = this.$leTheme.current;
521
- }
522
- if (typeof window !== "undefined") {
523
- window.addEventListener("le-theme-change", this._themeChangeHandler);
524
- }
525
- },
526
-
527
- watch: {
528
- contextMenuVisible() {
529
- if (this.contextMenuVisible) {
530
- document.body.addEventListener("click", this.closeMenu);
531
- } else {
532
- document.body.removeEventListener("click", this.closeMenu);
533
- }
534
- },
535
- },
536
- beforeDestroy() {
537
- document.removeEventListener("keydown", this.handleKeyDown);
538
- document.removeEventListener("mousemove", this.handleDrag);
539
- document.removeEventListener("mouseup", this.stopDrag);
540
- if (typeof window !== "undefined" && this._themeChangeHandler) {
541
- window.removeEventListener("le-theme-change", this._themeChangeHandler);
542
- }
543
- this.stopDrag();
544
- },
545
- methods: {
546
- // 递归过滤隐藏菜单项(ishide === 1 的项被过滤,其子项也一并丢弃)
547
- _filterHiddenMenus(list) {
548
- if (!Array.isArray(list)) return [];
549
- return list
550
- .filter((item) => item.ishide !== 1)
551
- .map((item) => {
552
- if (item.children && item.children.length) {
553
- return {
554
- ...item,
555
- children: this._filterHiddenMenus(item.children),
556
- };
557
- }
558
- return item;
559
- });
560
- },
561
- // 2026-08-26:读取 CSS 变量的 helper,返回指定变量值(回退到 fallback)
562
- getCssVar(name, fallback) {
563
- try {
564
- const v = getComputedStyle(document.documentElement)
565
- .getPropertyValue(name)
566
- .trim();
567
- return v || fallback;
568
- } catch (e) {
569
- return fallback;
570
- }
571
- },
572
- // header 横向菜单项点击处理(复用 clickMenuItem 的导航逻辑)
573
- handleHeaderMenuSelect(item) {
574
- this.clickMenuItem(item);
575
- },
576
- handleKeyDown(e) {
577
- // F5 键的 keyCode 是 116
578
- if (e.keyCode === 116) {
579
- e.preventDefault(); // 阻止默认刷新行为
580
- this.refreshView();
581
- }
582
- },
583
- refreshView() {
584
- this.refreshKey++;
585
- // 可以添加一些视觉反馈
586
- this.$message.success("数据已刷新");
587
- },
588
- openContextMenu(e) {
589
- e.preventDefault(); //防止默认菜单弹出
590
- this.contextMenuVisible = true;
591
-
592
- this.menuLeft = e.clientX;
593
- this.menuTop = e.clientY + 20;
594
- },
595
- closeMenu() {
596
- this.contextMenuVisible = false;
597
- },
598
- closeOtherTab() {
599
- this.tabsAll = this.tabsAll.filter(
600
- (item) => item.name == this.tabNameCurrent,
601
- );
602
- },
603
- closeAllTabs() {
604
- this.contextMenuVisible = false;
605
- this.tabNameCurrent = "";
606
- this.tabsAll = [];
607
- this.$router.push({ path: "/home" });
608
- },
609
- //解决空白标签页右键
610
- openContextMenu1(e) {
611
- if (e.srcElement.id != "") {
612
- this.contextMenuVisible = true;
613
- //这个参数是获取右键标签页的id属性,应该和你的key有关,你要截取-后面部分的
614
- this.closeindex = e.srcElement.id.split("-")[1]; //
615
- } else {
616
- this.contextMenuVisible = false;
617
- }
618
- },
619
- handleCommand(command) {
620
- if (command === "openSysSettings") {
621
- this.sysSettingsTab = "pwd";
622
- this.sysPwdForm = { oldPwd: "", newPwd: "", confirmPwd: "" };
623
- this.sysPerForm = {
624
- nick: this.$store.getters.userinfo.nick || "",
625
- phone: this.$store.getters.userinfo.phone || "",
626
- };
627
- this.sysSettingsVisible = true;
628
- } else if (command === "2") {
629
- this.signout();
630
- } else {
631
- this.$emit("command", command); // 抛出外部命令
632
- }
633
- },
634
- changPwd() {
635
- this.sysSettingsTab = "pwd";
636
- this.sysPwdForm = { oldPwd: "", newPwd: "", confirmPwd: "" };
637
- this.sysPerForm = {
638
- nick: this.$store.getters.userinfo.nick || "",
639
- phone: this.$store.getters.userinfo.phone || "",
640
- };
641
- this.sysSettingsVisible = true;
642
- },
643
- // 系统设置 - 提交修改密码
644
- submitSysPwd() {
645
- this.$refs.sysPwdForm.validate((valid) => {
646
- if (valid) {
647
- const payload = {
648
- uid: this.$store.getters.userinfo.id,
649
- pwd: this.sysPwdForm.newPwd,
650
- confirmPwd: this.sysPwdForm.confirmPwd,
651
- };
652
- // 方案一:emit 给宿主,由宿主决定如何调用接口
653
- this.$emit("userChangePwd", payload, this.changePwdAfter);
654
- }
655
- });
656
- },
657
- // 系统设置 - 提交修改个人信息
658
- submitSysPer() {
659
- this.$refs.sysPerForm.validate((valid) => {
660
- if (valid) {
661
- const payload = {
662
- uid: this.$store.getters.userinfo.id,
663
- nick: this.sysPerForm.nick,
664
- phone: this.sysPerForm.phone,
665
- };
666
- this.$emit("savePerInfo", payload, () => {
667
- this.sysSettingsVisible = false;
668
- try {
669
- let userinfo = this.$store.getters.userinfo;
670
- if (userinfo) {
671
- userinfo.nick = payload.nick;
672
- userinfo.phone = payload.phone;
673
- this.$store.commit("setUserInfo", userinfo);
674
- }
675
- } catch (e) {}
676
- });
677
- }
678
- });
679
- },
680
- // 系统设置 - 选择皮肤
681
- selectSkin(skinName) {
682
- this.$leTheme.set(skinName);
683
- this.$message.success("皮肤切换成功");
684
- },
685
- validatePhone(phone) {
686
- const phoneRegex = /^1[3-9]\d{9}$/;
687
- return phoneRegex.test(phone);
688
- },
689
-
690
- changePwdAfter(res) {
691
- if (res && res.data && res.data.code == "10000") {
692
- this.$message.success("更新成功");
693
- this.sysSettingsVisible = false;
694
- localStorage.clear();
695
- this.$store.commit("setUserInfo", null);
696
- this.$router.replace({ path: "/" });
697
- } else {
698
- this.pwdinfo = res;
699
- }
700
- },
701
- signout() {
702
- this.$confirm("退出登录, 是否继续?", "提示", {
703
- confirmButtonText: "确定",
704
- cancelButtonText: "取消",
705
- type: "warning",
706
- }).then(() => {
707
- this.$router.push({ path: "/" });
708
- localStorage.clear();
709
- });
710
- },
711
- clickMenuItem(item) {
712
- this.style.display = "none";
713
-
714
- if (item.name === this.tabNameCurrent) {
715
- this.$message.info("当前页面已经打开");
716
- return;
717
- }
718
-
719
- // 查找是否已经存在相同name的标签页
720
- const existingTabIndex = this.tabsAll.findIndex(
721
- (tab) => tab.name === item.name,
722
- );
723
-
724
- if (existingTabIndex > -1) {
725
- // 已存在,用新的替换
726
- const newTab = this._createTabItem(item);
727
- this.tabsAll[existingTabIndex] = newTab;
728
-
729
- // 如果替换的是当前激活的标签页,需要跳转
730
- if (this.tabNameCurrent === item.name) {
731
- this.$router.push(newTab);
732
- } else {
733
- // 如果替换的不是当前激活的标签页,设置当前激活并跳转
734
- this.tabNameCurrent = newTab.name;
735
- this.$router.push(newTab);
736
- }
737
- } else {
738
- this._navi2Page(item);
739
- }
740
- },
741
- _createTabItem(item) {
742
- let value;
743
- if (item.param) {
744
- value = {
745
- name: item.name,
746
- title: item.title,
747
- params: {
748
- status: item.param,
749
- btns: item.btns,
750
- },
751
- };
752
- } else {
753
- if (item.component && item.component != "") {
754
- value = {
755
- name: item.name,
756
- title: item.title,
757
- params: {
758
- btns: item.btns,
759
- },
760
- };
761
- }
762
- }
763
- return value;
764
- },
765
- _navi2Page(item) {
766
- const value = this._createTabItem(item);
767
- if (!value) return; // 防止空值
768
-
769
- this.tabNameCurrent = value.name;
770
- if (this.tabsAll && this.tabsAll.length >= 8) {
771
- let elen = this.tabsAll.length;
772
- this.tabsAll[elen - 1] = value;
773
- } else {
774
- this.tabsAll.push(value);
775
- }
776
- this.$router.push(value);
777
- },
778
- handleTabClick(clickTab, event) {
779
- // if (clickTab.name == this.tabNameCurrent) return;
780
- let tabs = this.tabsAll;
781
- let currentTab;
782
- tabs.forEach((tab, index) => {
783
- if (tab.name === clickTab.name) {
784
- currentTab = tab;
785
- }
786
- });
787
- this.$router.push(currentTab);
788
- },
789
- removeTab(targetName) {
790
- let tabs = this.tabsAll;
791
- let nextTab;
792
- tabs.forEach((tab, index) => {
793
- if (tab.name == targetName) {
794
- nextTab = tabs[index + 1] || tabs[index - 1];
795
- if (nextTab) {
796
- this.tabNameCurrent = nextTab.name;
797
- }
798
- }
799
- });
800
- this.tabsAll = tabs.filter((tab) => tab.name !== targetName);
801
- if (nextTab) {
802
- this.$router.push(nextTab);
803
- } else {
804
- this.tabNameCurrent = "";
805
- this.$router.push("/Home");
806
- }
807
- },
808
- clickTitle() {
809
- this.style.display = "block";
810
- },
811
- asidechange() {
812
- this.isHideMenu = !this.isHideMenu;
813
- if (this.isHideMenu) {
814
- this.aside_open_close = false;
815
- } else {
816
- this.aside_open_close = true;
817
- // 确保展开时使用当前保存的宽度
818
- const savedWidth = localStorage.getItem("le-aside-width");
819
- if (savedWidth) {
820
- this.asideWidth = parseInt(savedWidth, 10);
821
- }
822
- }
823
- },
824
- shouldShowTooltip(text) {
825
- return text && text.length > 8;
826
- },
827
- clickLeftTop() {
828
- this.$emit("clickLeftTop");
829
- },
830
- startDrag(e) {
831
- e.preventDefault();
832
- e.stopPropagation();
833
-
834
- this.isDragging = true;
835
- this.dragStartInfo = {
836
- startX: e.clientX,
837
- startWidth: this.asideWidth,
838
- };
839
-
840
- document.body.style.cursor = "col-resize";
841
- document.body.style.userSelect = "none";
842
-
843
- // 临时添加事件监听(更可靠)
844
- window.addEventListener("mousemove", this.handleDrag);
845
- window.addEventListener("mouseup", this.stopDrag);
846
- },
847
-
848
- handleDrag(e) {
849
- if (!this.isDragging || !this.dragStartInfo) return;
850
-
851
- e.preventDefault();
852
- e.stopPropagation();
853
-
854
- const diff = e.clientX - this.dragStartInfo.startX;
855
- let newWidth = this.dragStartInfo.startWidth + diff;
856
-
857
- // 限制宽度范围(150-500px)
858
- newWidth = Math.max(150, Math.min(500, newWidth));
859
-
860
- // 更新数据
861
- this.asideWidth = newWidth;
862
-
863
- // 直接操作 DOM 确保生效
864
- const asideEl = this.$refs.asideRef?.$el;
865
- if (asideEl) {
866
- asideEl.style.width = `${newWidth}px`;
867
- asideEl.style.minWidth = `${newWidth}px`;
868
- asideEl.style.maxWidth = `${newWidth}px`;
869
- asideEl.style.flex = `0 0 ${newWidth}px`;
870
- }
871
- },
872
-
873
- stopDrag() {
874
- if (this.isDragging) {
875
- this.isDragging = false;
876
- this.dragStartInfo = null;
877
-
878
- // 移除临时事件监听
879
- window.removeEventListener("mousemove", this.handleDrag);
880
- window.removeEventListener("mouseup", this.stopDrag);
881
-
882
- // 保存到 localStorage
883
- localStorage.setItem("le-aside-width", this.asideWidth.toString());
884
-
885
- // 恢复样式
886
- document.body.style.cursor = "";
887
- document.body.style.userSelect = "";
888
- }
889
- },
890
- },
891
- };
892
- </script>
893
- <style lang="scss" scoped>
894
- .le-home-cp-container {
895
- height: 100vh;
896
- font-size: 15px;
897
-
898
- .header {
899
- background-color: var(--le-color-header-bg) !important;
900
- color: #fff;
901
- height: 60px;
902
- border-bottom: 1px solid rgba(0, 0, 0, 0.1);
903
-
904
- /* 清除 Element UI el-row / el-col 默认背景 */
905
- .el-row,
906
- .el-col {
907
- background-color: transparent !important;
908
- }
909
-
910
- /* 清除 grid-content / bg-purple 等示例类的默认背景 */
911
- .grid-content,
912
- .bg-purple,
913
- .bg-purple-light {
914
- background-color: transparent !important;
915
- }
916
-
917
- .header-row {
918
- height: 60px;
919
- }
920
-
921
- .leftsection,
922
- .middlesection,
923
- .rightsection {
924
- height: 60px;
925
- line-height: 60px;
926
- display: flex;
927
- align-items: center;
928
- }
929
-
930
- .leftsection {
931
- .userinfo-inner {
932
- font-size: 18px;
933
- font-weight: bold;
934
- cursor: pointer;
935
- }
936
- }
937
-
938
- .middlesection {
939
- flex: 1;
940
- display: flex;
941
- align-items: center;
942
- padding: 0 16px;
943
-
944
- .header-menu {
945
- border-bottom: none;
946
- height: 60px;
947
- line-height: 60px;
948
- width: 100%;
949
-
950
- /* 菜单项悬停/激活色 */
951
- .el-menu-item,
952
- .el-submenu__title {
953
- height: 60px;
954
- line-height: 60px;
955
- border-bottom: none;
956
- font-size: 15px;
957
- min-width: 100px;
958
- text-align: center;
959
-
960
- &:hover {
961
- background-color: rgba(255, 255, 255, 0.1) !important;
962
- }
963
- }
964
-
965
- .el-submenu__icon-arrow {
966
- font-size: 12px;
967
- margin-left: 4px;
968
- }
969
-
970
- .el-menu-item.is-active {
971
- border-bottom: 2px solid var(--le-color-aside-active);
972
- }
973
- }
974
- }
975
-
976
- .rightsection {
977
- justify-content: flex-end;
978
-
979
- .el-dropdown-link {
980
- cursor: pointer;
981
- color: #fff;
982
- }
983
- }
984
- }
985
-
986
- /* 修改 .aside 样式 - 移除固定宽度 !important */
987
- .aside {
988
- background: var(--le-color-aside-bg);
989
- color: var(--le-color-aside-text);
990
- /* 移除 width: 200px !important */
991
- transform: width 0.5s;
992
- position: relative;
993
- /* 添加弹性布局相关属性 */
994
- flex-shrink: 0 !important;
995
- overflow: visible !important;
996
- height: calc(100vh - 60px);
997
- display: flex;
998
- flex-direction: column;
999
-
1000
- /* 拖动条样式 */
1001
- .drag-handle {
1002
- position: absolute;
1003
- right: 0;
1004
- top: 0;
1005
- bottom: 0;
1006
- width: 1px; /* 从6px改为4px */
1007
- cursor: col-resize;
1008
- z-index: 1000;
1009
- background-color: transparent;
1010
-
1011
- &:hover {
1012
- background-color: var(--le-color-aside-handle-hover);
1013
- width: 4px; /* 确保hover时也是4px */
1014
- }
1015
-
1016
- &:active {
1017
- background-color: var(--le-color-aside-handle-active);
1018
- }
1019
- }
1020
-
1021
- &.aside_hide {
1022
- width: 0px !important;
1023
- min-width: 0 !important;
1024
- max-width: 0 !important;
1025
- flex: 0 0 0 !important;
1026
- overflow: hidden !important;
1027
-
1028
- .drag-handle {
1029
- display: none !important;
1030
- }
1031
- }
1032
- }
1033
-
1034
- .el-aside {
1035
- height: calc(100vh - 60px);
1036
- }
1037
-
1038
- .el-main {
1039
- height: calc(100vh - 60px);
1040
- // overflow: hidden !important;
1041
- flex: 1;
1042
-
1043
- display: flex;
1044
- flex-direction: column;
1045
- overflow-y: auto;
1046
- padding: 10px 20px;
1047
- }
1048
-
1049
- .el-main > div:last-child {
1050
- flex: 1;
1051
- min-height: 0;
1052
- display: flex;
1053
- flex-direction: column;
1054
- }
1055
-
1056
- .el-main > div:last-child > *:last-child {
1057
- flex: 1;
1058
- min-height: 0;
1059
- }
1060
-
1061
- .menu {
1062
- background: none;
1063
- color: var(--le-color-aside-text);
1064
- flex: 1;
1065
- overflow-y: auto;
1066
- }
1067
-
1068
- .main {
1069
- position: relative;
1070
- color: var(--le-color-header-bg);
1071
- }
1072
-
1073
- .headerlogo {
1074
- line-height: 60px;
1075
- margin-top: 10px;
1076
- }
1077
-
1078
- .rightsection {
1079
- line-height: 60px;
1080
- text-align: right;
1081
- }
1082
-
1083
- .leftsection {
1084
- line-height: 60px;
1085
- text-align: start;
1086
- font-size: 22px;
1087
- }
1088
-
1089
- .userinfo-inner {
1090
- margin-left: 20px;
1091
- cursor: pointer;
1092
- }
1093
-
1094
- .userinfo-inner-t {
1095
- color: #fff !important;
1096
- font-size: 18px;
1097
- cursor: pointer;
1098
- }
1099
-
1100
- .el-icon-arrow-down {
1101
- font-size: 16px;
1102
- }
1103
-
1104
- .el-dropdown-menu__item {
1105
- font-size: 15px !important;
1106
- }
1107
-
1108
- .logofont {
1109
- font-size: 25px;
1110
- padding-bottom: 10px;
1111
- line-height: 60px;
1112
- }
1113
-
1114
- .cursor {
1115
- cursor: pointer;
1116
- }
1117
-
1118
- .aside_open_close {
1119
- position: absolute;
1120
- left: 0;
1121
- top: 25%;
1122
- width: 16px;
1123
- height: 60px;
1124
- line-height: 60px;
1125
- color: #fff;
1126
- background-color: var(--le-color-aside-toggle-bg);
1127
- border-radius: 0 6px 6px 0;
1128
- font-size: 20px;
1129
- z-index: 1000;
1130
- cursor: pointer;
1131
- }
1132
-
1133
- .aside_open_close:hover {
1134
- background-color: var(--le-color-aside-toggle-hover);
1135
- color: #fff;
1136
- }
1137
-
1138
- .grid-content {
1139
- }
1140
-
1141
- .bg-purple-light {
1142
- display: flex;
1143
- display: -webkit-flex;
1144
- justify-content: flex-end;
1145
- align-content: center;
1146
- align-items: center;
1147
- column-gap: 6px;
1148
- }
1149
-
1150
- .contextmenu {
1151
- width: 100px;
1152
- margin: 0;
1153
- border: 1px solid var(--le-color-contextmenu-border);
1154
- background: var(--le-color-contextmenu-bg);
1155
- z-index: 3000;
1156
- position: absolute;
1157
- list-style-type: none;
1158
- padding: 5px 0;
1159
- border-radius: 4px;
1160
- font-size: 14px;
1161
- color: var(--le-color-contextmenu-text);
1162
- box-shadow: 2px 2px 3px 0 var(--le-color-contextmenu-shadow);
1163
-
1164
- .li {
1165
- margin: 0;
1166
- padding: 0px 2px;
1167
-
1168
- :hover {
1169
- background: var(--le-color-contextmenu-hover);
1170
- cursor: pointer;
1171
- }
1172
-
1173
- .button {
1174
- color: var(--le-color-contextmenu-text);
1175
- }
1176
- }
1177
- }
1178
- }
1179
-
1180
- .img {
1181
- width: 20px;
1182
- height: 20px;
1183
- }
1184
-
1185
- ::-webkit-scrollbar {
1186
- width: 0;
1187
- height: 0;
1188
- background-color: transparent;
1189
- }
1190
-
1191
- .menuItem {
1192
- .menu-item-text {
1193
- display: inline-block;
1194
- max-width: calc(100% + 25px);
1195
- overflow: hidden;
1196
- text-overflow: ellipsis;
1197
- white-space: nowrap;
1198
- }
1199
- }
1200
-
1201
- .rounded-dialog {
1202
- border-radius: 12px !important;
1203
- overflow: hidden;
1204
- }
1205
-
1206
- /* 皮肤选择器样式 */
1207
- .skin-picker {
1208
- display: flex;
1209
- flex-direction: column;
1210
- gap: 12px;
1211
- padding: 16px 0;
1212
- }
1213
-
1214
- .skin-item {
1215
- display: flex;
1216
- align-items: center;
1217
- padding: 12px 16px;
1218
- border: 2px solid var(--le-color-border);
1219
- border-radius: 8px;
1220
- cursor: pointer;
1221
- transition: all 0.2s ease;
1222
-
1223
- &:hover {
1224
- border-color: var(--le-color-primary);
1225
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
1226
- }
1227
-
1228
- &.active {
1229
- border-color: var(--le-color-primary);
1230
- background-color: var(--le-color-primary-light-9);
1231
- }
1232
- }
1233
-
1234
- .skin-color {
1235
- width: 32px;
1236
- height: 32px;
1237
- border-radius: 50%;
1238
- margin-right: 16px;
1239
- flex-shrink: 0;
1240
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
1241
- }
1242
-
1243
- .skin-info {
1244
- flex: 1;
1245
- }
1246
-
1247
- .skin-name {
1248
- font-size: 15px;
1249
- font-weight: 600;
1250
- color: var(--le-color-text-strong);
1251
- }
1252
-
1253
- .skin-desc {
1254
- font-size: 12px;
1255
- color: var(--le-color-primary);
1256
- margin-top: 2px;
1257
- }
1258
-
1259
- .skin-check {
1260
- font-size: 20px;
1261
- color: var(--le-color-primary);
1262
- }
1263
- </style>
1264
- <style lang="scss">
1265
- /* header 菜单弹出层样式(挂在 body 上,需全局样式)
1266
- 弹出层不受 el-menu prop 控制,需手动设置背景色与 header 一致 */
1267
- .le-header-menu-popper {
1268
- background-color: var(--le-color-header-bg) !important;
1269
-
1270
- .el-menu {
1271
- border-right: none;
1272
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.3);
1273
- min-width: 160px;
1274
- background-color: var(--le-color-header-bg) !important;
1275
- }
1276
-
1277
- .el-menu-item,
1278
- .el-submenu__title {
1279
- height: 40px;
1280
- line-height: 40px;
1281
- border-bottom: none;
1282
- padding: 0 20px;
1283
- min-width: 160px;
1284
- font-size: 14px;
1285
- background-color: var(--le-color-header-bg) !important;
1286
- color: var(--le-color-aside-text) !important;
1287
-
1288
- &:hover {
1289
- background-color: rgba(255, 255, 255, 0.1) !important;
1290
- }
1291
- }
1292
-
1293
- .el-menu-item.is-active {
1294
- color: var(--le-color-aside-active) !important;
1295
- background-color: rgba(255, 255, 255, 0.1) !important;
1296
- }
1297
-
1298
- .el-submenu__icon-arrow {
1299
- float: right;
1300
- margin-right: 0;
1301
- color: var(--le-color-aside-text) !important;
1302
- }
1303
- }
1304
-
1305
- /* 用户下拉菜单(系统设置/皮肤选择)全局样式 */
1306
- .el-dropdown-menu {
1307
- .el-dropdown-menu__item {
1308
- position: relative;
1309
-
1310
- &.skin-active {
1311
- color: var(--le-color-aside-active);
1312
- }
1313
- }
1314
- }
1315
- </style>