leisure-core 0.6.90 → 0.6.91

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.
@@ -0,0 +1,540 @@
1
+ # leisure-core 组件库学习指南
2
+
3
+ > 本文档供大语言模型学习使用。基于源码静态分析生成,覆盖项目定位、架构约定、共享基础设施与全部组件的 API 契约。
4
+
5
+ ## 1. 项目定位
6
+
7
+ - **名称**:`leisure-core`
8
+ - **版本**:0.6.90
9
+ - **作者**:北方乐逍遥 (zcx7878) / 京心数据
10
+ - **性质**:基于 Vue 2.x 的后台管理系统**桌面端组件库**,封装大量实用 UI 控件模板,用于快速搭建前端应用
11
+ - **发布渠道**:npm 公共仓库 (`https://registry.npmjs.org/`)
12
+ - **使用方式**:作为 Vue 插件整体 `install`,或按需引入单个组件
13
+
14
+ ## 2. 技术栈
15
+
16
+ | 依赖 | 版本 | 用途 |
17
+ | -------------- | ---------- | -------------------------------------------------------- |
18
+ | vue | ^2.6.14 | 核心框架 |
19
+ | element-ui | ^2.15.14 | 基础 UI 组件来源 |
20
+ | vxe-table | ~3.19.28 | 报表/复杂表格 |
21
+ | vue-router | ^3.5.1 | 路由(HTTP 层跳转登录页依赖) |
22
+ | vuex | ^3.6.2 | 状态管理(HTTP 层读取 userinfo/token) |
23
+ | axios | (传递依赖) | HTTP 请求 |
24
+ | dayjs | (传递依赖) | 请求头时间戳 |
25
+ | lodash | ^4.17.21 | 工具函数 |
26
+ | exceljs | ^4.4.0 | Excel 生成/导出 |
27
+ | file-saver | ^2.0.5 | 文件下载 |
28
+ | leisure-js | ^0.2.9 | 提供 `parseTime/formatMoney/formatCurrency` 等格式化函数 |
29
+ | leisure-editor | ^0.1.8 | 富文本编辑器 |
30
+
31
+ ## 3. 目录结构
32
+
33
+ ```
34
+ leisure-core/
35
+ ├── index.js # 总入口:注册全部组件 + 全局方法 + 自定义指令 + LeTheme 初始化
36
+ ├── package.json
37
+ ├── le-libs/ # 共享基础设施
38
+ │ ├── js/
39
+ │ │ ├── hrequest.js # 通用 axios 实例(带签名鉴权)
40
+ │ │ ├── hrequestFile.js # 文件下载/Excel 导出工具
41
+ │ │ ├── tokens.js # localStorage token 读写
42
+ │ │ ├── info.js # 统一成功提示消息
43
+ │ │ ├── event.js # 全局 EventBus(new Vue())
44
+ │ │ └── drag.js # el-drag-dialog 指令实现(弹窗可拖拽)
45
+ │ ├── mixins/
46
+ │ │ └── main.js # leMixins:el-table 自适应高度 + 表头渲染
47
+ │ └── directives/src/ # (预留指令目录,当前为空)
48
+ ├── le-theme/ # 主题资源 + 一键换肤服务
49
+ │ ├── common/
50
+ │ │ ├── var.scss # SCSS 变量(编译期用)
51
+ │ │ └── vars.css # CSS 自定义属性层(运行时换肤用)+ Element UI primary 覆盖
52
+ │ ├── iconfont/ # 字体图标(css + ttf/woff/woff2)
53
+ │ ├── pages/index.css # 页面样式
54
+ │ └── index.js # LeTheme 主题服务(set/register/init)
55
+ └── le-*/ # 各功能组件(共 36 个,见下文)
56
+ ├── index.js # 组件注册入口(标准 install 模式)
57
+ └── src/main.vue # 组件实现(部分含 rmixins.js 等辅助文件)
58
+ ```
59
+
60
+ ## 4. 架构约定
61
+
62
+ ### 4.1 组件目录模板
63
+
64
+ 每个组件遵循统一结构:
65
+
66
+ ```
67
+ le-xxx/
68
+ ├── index.js # import main.vue → 挂 install → export default
69
+ └── src/main.vue # name: "le-xxx" 的 SFC
70
+ ```
71
+
72
+ `index.js` 标准形态:
73
+
74
+ ```js
75
+ import LeXxx from "./src/main.vue";
76
+ LeXxx.install = function (Vue) {
77
+ Vue.component(LeXxx.name, LeXxx);
78
+ };
79
+ export default LeXxx;
80
+ ```
81
+
82
+ ### 4.2 总入口 install 流程(`index.js`)
83
+
84
+ 1. 防重复安装(`install.installed` 标志)
85
+ 2. 遍历组件数组执行 `Vue.component(name, comp)`
86
+ 3. 挂载全局原型方法:`Vue.prototype.parseTime / formatMoney / formatCurrency`
87
+ 4. 挂载一键换肤服务:`Vue.prototype.$leTheme = LeTheme`,并调用 `LeTheme.init()` 从 localStorage 恢复上次选择的皮肤
88
+ 5. 注册自定义指令:
89
+ - `v-permission`:基于按钮 id + permission 标志移除无权限 DOM 元素
90
+ - `v-el-drag-dialog`:使 `el-dialog` 头部可拖拽(来自 `drag.js`)
91
+ - `v-rfooter`:flex 右对齐容器(参数支持 `"center"`)
92
+ 6. 若 `window.Vue` 存在(CDN 直接引入),自动安装
93
+
94
+ ### 4.3 命名规范
95
+
96
+ - 组件名:`le-` 前缀 + 业务语义(kebab-case)
97
+ - 组件 `name` 字段与目录名一致
98
+ - 业务组件(如 `le-role`)内部会拆出 `LeRoleSub` 等子组件,但**子组件不在总入口注册**,仅供父组件内部使用
99
+
100
+ ## 5. 共享基础设施(`le-libs`)
101
+
102
+ ### 5.1 `hrequest.js` — 通用 HTTP 客户端
103
+
104
+ - 基于 `axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 50000 })`
105
+ - **请求拦截器**:
106
+ - 默认 `Content-Type: application/json;`
107
+ - 从 `store.getters.userinfo.token` 读取 token,写入 `authentication` 头
108
+ - 写入 `timestamp`(dayjs 秒级)与 `sign`(由外部通过 `setCalMethod` 注入的签名函数计算)
109
+ - **响应拦截器**:
110
+ - `code === "801" / "802"` → `router.push("/")`(登录失效跳转)
111
+ - `code !== "10000"` 或 `code === "803"` → 调用 `Message.error(info)` 提示
112
+ - 否则正常返回 response
113
+ - 导出:`{ service, setCalMethod }`
114
+ - **重要约束**:依赖宿主项目提供 `@/router`、`@/store`、`store.getters.userinfo`,即组件库假定运行于具备 vuex + vue-router 的宿主应用中
115
+
116
+ ### 5.2 `hrequestFile.js` — 文件下载
117
+
118
+ - `downLoadFile(url, fileName, data)`:GET + blob + 动态 `<a>` 下载,文件名追加 `.xlsx`
119
+ - 预置业务封装:`exportExcelByParam(path, name, param)`、`exportMemberExcel`、`exportConsumeExcel`、`exportGoodsExcel`
120
+ - 鉴权头读取 `getToken()`(来自 `tokens.js`)
121
+
122
+ ### 5.3 `tokens.js` — Token 持久化
123
+
124
+ - Key:`'token'`,存储于 `localStorage`
125
+ - 提供 `getToken / setToken / removeToken`
126
+
127
+ ### 5.4 `info.js` — 统一成功提示
128
+
129
+ - `info(msg, obj)` → `obj.$message({ type: 'success', duration: 2000 })`
130
+
131
+ ### 5.5 `event.js` — 全局事件总线
132
+
133
+ - `EventBus = new Vue()`,跨组件通信用
134
+
135
+ ### 5.6 `drag.js` — `el-drag-dialog` 指令实现
136
+
137
+ - `bind` 钩子绑定 `el-dialog__header` 的 `mousedown`
138
+ - 计算可视区边界,限制拖拽范围
139
+ - 拖拽中 `vnode.child.$emit('dragDialog')`
140
+ - 兼容 IE `currentStyle` 与标准 `getComputedStyle`
141
+
142
+ ### 5.7 `mixins/main.js` — `leMixins`
143
+
144
+ - `data.elTableMaxHeight = 200`(最小 200)
145
+ - `mounted` 监听 `resize`,`destroyed` 解绑
146
+ - `changeHeight()`:根据 `eltablemain` ref 的 `getBoundingClientRect().top` 动态计算表格最大高度 = `innerHeight - top - 90`
147
+ - `renderHeader(h, { column, $index })`:根据 `.le-table-btn-container` 宽度自适应表头列宽
148
+
149
+ ## 6. 主题资源与一键换肤(`le-theme`)
150
+
151
+ ### 6.1 文件结构
152
+
153
+ | 文件 | 作用 |
154
+ | ----------------- | ----------------------------------------------------------------------------------------- |
155
+ | `common/var.scss` | SCSS 变量(编译期用) |
156
+ | `common/vars.css` | **CSS 自定义属性层**(运行时换肤的核心),定义全部语义变量 + 覆盖 Element UI primary 色族 |
157
+ | `pages/index.css` | 页面级样式 |
158
+ | `iconfont/` | 字体图标 |
159
+ | `index.js` | LeTheme 主题服务对象 |
160
+
161
+ ### 6.2 CSS 变量层(`common/vars.css`)
162
+
163
+ 在 `:root` 上定义约 30 个语义化变量,分为 4 组:
164
+
165
+ **品牌色族**
166
+
167
+ - `--le-color-primary`、`--le-color-primary-light`、`--le-color-primary-dark`、`--le-color-primary-shadow`
168
+
169
+ **功能色族**
170
+
171
+ - `--le-color-success`、`--le-color-warning`、`--le-color-danger`、`--le-color-info`
172
+
173
+ **文本 / 边框 / 容器**
174
+
175
+ - `--le-color-text-primary`、`--le-color-text-regular`、`--le-color-text-secondary`
176
+ - `--le-color-border`、`--le-color-container`、`--le-color-bg`
177
+
178
+ **le-home 框架色**(一键换肤必覆盖)
179
+
180
+ - `--le-color-header-bg`、`--le-color-aside-bg`、`--le-color-menu-bg`
181
+ - `--le-color-aside-text`、`--le-color-aside-active`
182
+ - `--le-color-aside-handle-hover`、`--le-color-aside-handle-active`
183
+ - `--le-color-aside-toggle-bg`、`--le-color-aside-toggle-color`、`--le-color-aside-toggle-active-bg`
184
+ - `--le-color-contextmenu-bg`、`--le-color-contextmenu-color`、`--le-color-contextmenu-hover`
185
+
186
+ **Element UI primary 覆盖**(让 `type="primary"` 按钮跟随换肤)
187
+
188
+ - `.el-button--primary`、`.el-tag--primary`、`.el-checkbox`、`.el-radio`、`.el-switch`、`.el-pagination`、`.el-tabs`、`.el-link` 等选择器的 `color/background/border` 均绑定到 `--le-color-primary*` 变量
189
+
190
+ ### 6.3 LeTheme 服务(`index.js`)
191
+
192
+ 单例对象,不挂在 `window` 上,生产代码统一通过 `this.$leTheme` 使用。
193
+
194
+ **预置皮肤**
195
+
196
+ | 皮肤名 | 主色 | 用途 |
197
+ | --------- | -------------- | -------- |
198
+ | `default` | 蓝色 `#3b82f6` | 当前默认 |
199
+ | `dark` | 深色背景 | 暗色模式 |
200
+ | `green` | 绿色 `#22c55e` | 绿色主色 |
201
+
202
+ **API**
203
+
204
+ ```js
205
+ // 切换皮肤(持久化到 localStorage,下次启动自动恢复)
206
+ this.$leTheme.set("dark");
207
+
208
+ // 注册自定义皮肤(接受变量对象,可用于拾色器场景)
209
+ this.$leTheme.register("custom", { "--le-color-primary": "#ff6900" });
210
+ this.$leTheme.set("custom");
211
+
212
+ // 初始化(由 install 自动调用,从 localStorage 恢复皮肤)
213
+ this.$leTheme.init();
214
+
215
+ // 读取当前皮肤名
216
+ this.$leTheme.current; // "dark"
217
+ ```
218
+
219
+ **实现原理**
220
+
221
+ 1. `set(name)` 从 `skins` 配置取出变量对象
222
+ 2. 遍历键值对,通过 `document.documentElement.style.setProperty(key, value)` 注入到 `<html>`
223
+ 3. 在 `<html>` 上打 `data-le-theme="name"` 标记
224
+ 4. 派发 `window` 级 `le-theme-change` CustomEvent(供组件侧监听)
225
+ 5. 写入 `localStorage.le-theme`
226
+
227
+ **组件侧响应模式**
228
+
229
+ 在 `le-home` / `le-login` 组件中使用:
230
+
231
+ ```js
232
+ // 方式 A:CSS 直接消费(静态样式)
233
+ .hello { color: var(--le-color-text-primary); }
234
+
235
+ // 方式 B:el-menu 等需要 prop 传值的场景
236
+ computed: {
237
+ menuBackgroundColor() {
238
+ return this.getCssVar('--le-color-menu-bg', '#3a3a3a');
239
+ }
240
+ },
241
+ mounted() {
242
+ window.addEventListener('le-theme-change', () => this.$forceUpdate());
243
+ }
244
+ ```
245
+
246
+ ### 6.4 扩展新皮肤
247
+
248
+ 添加皮肤需遵循:
249
+
250
+ 1. **必须覆盖所有 framework 变量**(header/aside/menu/handle/toggle/contextmenu),否则会出现"某些部分没跟着变"
251
+ 2. 建议在 `le-theme/index.js` 的 `skins` 对象里新增一组变量
252
+ 3. 建议从 `defaults` 复用未变项,仅覆盖差异部分
253
+
254
+ ## 7. 组件清单总览
255
+
256
+ | 组件 | 一句话用途 | 关键交互模式 |
257
+ | ------------------------------------------ | ----------------------------------- | ------------------------------------------------------------------------ |
258
+ | le-button | 封装 el-button,支持权限/显示控制 | 默认 slot |
259
+ | le-button-qr | 点击生成二维码并下载 | emit `qrMake` |
260
+ | le-button-msg | 带 popconfirm 确认的按钮 | emit `click` |
261
+ | le-button-attach | 文件上传按钮(Excel/CSV 校验) | emit `before-upload/success/error` |
262
+ | le-dialog-container | 弹窗容器 | - |
263
+ | le-login | 登录页 | emit `handleLodin/loginAfter/sendCaptcha` |
264
+ | le-home | 后台主框架 | emit `homeInit/command/userChangePwd` |
265
+ | le-form / le-form-item | 表单容器(透传 el-form) | 透传 `$attrs/$listeners` |
266
+ | le-input / le-input-number | 输入框/数字输入封装 | 透传 |
267
+ | le-input-advanced | 金额/数值带单位换算输入 | emit `input` |
268
+ | le-input-validate | 带格式校验的输入框 | emit `input/blur/focus/clear` |
269
+ | le-span | 文本展示 | - |
270
+ | le-url | 超链接展示 | required `value` |
271
+ | le-select / le-select-option | 下拉封装(透传) | 默认 slot |
272
+ | le-select-search | 远程搜索下拉 | emit `remoteMethod` |
273
+ | le-select-multi | 多级树形多选 | emit `input/change/leaf-change/clear/visible-change` |
274
+ | le-date-picker | 日期选择 | - |
275
+ | le-date-picker-auto | 自动识别秒/毫秒时间戳的日期选择 | emit `input` |
276
+ | le-table-edit | 可编辑表格(单元格/行编辑) | emit `cell-save/row-save/update:data/data-change/edit-cancel` |
277
+ | le-list | 列表页(查询/分页/增删改) | emit `getList/delRow/handleStatus/editCurrentRow/detailCurrentRow/close` |
278
+ | le-list-form | 列表配套表单弹窗 | emit `form-ready/saveData/closeDialog` |
279
+ | le-report | 报表(vxe-table + 复杂表头 + 导出) | - |
280
+ | le-upload-table | 附件管理 | 通过 props 注入 5 个 API |
281
+ | le-media / le-media-upload / le-media-list | 素材库三件套 | 通过 props 注入 API |
282
+ | le-image | 图片展示(http→https) | - |
283
+ | le-video | 视频展示 | - |
284
+ | le-upload | 通用上传 | - |
285
+ | le-area | 地区级联选择 | emit `areaChange` |
286
+ | le-menu | 角色菜单配置 | emit `close` |
287
+ | le-role | 角色管理(含子组件 LeRoleSub) | - |
288
+ | le-role-user | 角色用户管理(含 LeRoleUserSub) | - |
289
+
290
+ ## 8. 组件 API 详解
291
+
292
+ > 约定:未显式声明 props 的组件多为透传型,通过 `v-bind="$attrs"` `v-on="$listeners"` 把属性/事件透传给内部 element-ui 组件。
293
+
294
+ ### 8.1 le-button
295
+
296
+ - **用途**:封装 `el-button`,支持权限与显示控制
297
+ - **Props**:`id`、`type`(默认 `''`)、`size`(默认 `'medium'`)、`permission`、`text`、`disp`(默认 `true`)
298
+ - **Slots**:默认插槽
299
+ - **Events**:无
300
+
301
+ ### 8.2 le-button-qr
302
+
303
+ - **用途**:点击生成二维码并展示下载弹窗
304
+ - **Props**:`qrCodeUrl`、`fileName`、`btnAttr`
305
+ - **Events**:`qrMake`(参数依 `btnAttr` 是否为空传 `qrMakeCallBack` 或 `btnAttr + qrMakeCallBack`)
306
+ - **Methods**:`closeQrMake`、`qrMake`、`qrMakeCallBack`、`qrcode`、`qrDownLoad`
307
+
308
+ ### 8.3 le-button-msg
309
+
310
+ - **用途**:基于 `el-popconfirm` 的确认/删除按钮
311
+ - **Props**:`id`、`type`、`size`、`permission`、`text`、`title`、`isDispSlot`、`disp`
312
+ - **Events**:`click(param)`
313
+ - **Slots**:默认插槽
314
+
315
+ ### 8.4 le-button-attach
316
+
317
+ - **用途**:文件上传按钮,支持 Excel/CSV 校验、进度、成功/失败回调
318
+ - **Props**:`multiple`、`buttonText`、`type`、`size`、`icon`、`disabled`、`maxSize`、`uploadFunction`(必填 Function)
319
+ - **Events**:`before-upload(file)`、`success(res.data, file)`、`error(error, file)`
320
+ - **Methods**:`beforeUpload`、`uploadFile`、`triggerUpload`
321
+
322
+ ### 8.5 le-form / le-form-item / le-input / le-input-number / le-select / le-select-option
323
+
324
+ - **用途**:透传型薄封装,仅作为容器/样式占位
325
+ - **特征**:`name` 与目录名一致,无显式 props,依赖 `$attrs/$listeners` 透传,保留默认 slot
326
+
327
+ ### 8.6 le-input-advanced
328
+
329
+ - **用途**:金额/数值输入,带 `converted` 缩放、`precision` 精度、`unit` 单位
330
+ - **Props**:`value`、`converted`、`scale`、`precision`、`unit`
331
+ - **Events**:`input(value)`(由 `displayValue` setter 触发)
332
+
333
+ ### 8.7 le-input-validate
334
+
335
+ - **用途**:带格式校验的输入框,支持数字/手机/邮箱/金额/长度/自定义 validator
336
+ - **Props**:`number`、`mobile`、`email`、`amount`、`maxlength`、`showCount`、`validator`、`value`、`allowDecimal`、`decimalLimit`、`allowNegative`
337
+ - **Slots**:`prepend`、`append`、`prefix`、`suffix`
338
+ - **Events**:`input`、`blur`、`focus`、`clear`(均透传参数)
339
+ - **Methods**:`formatNumber`、`formatMobile`、`formatAmountInput`、`validateInput`、`validate`、`clearValidate`、`focus`、`blur`
340
+
341
+ ### 8.8 le-span / le-url
342
+
343
+ - **le-span**:展示字符串/数值;Props `value`、`customClass`
344
+ - **le-url**:渲染超链接;Props `value`(required)
345
+
346
+ ### 8.9 le-select-search
347
+
348
+ - **用途**:远程搜索下拉
349
+ - **Props**:`remote`(Boolean, 默认 false)
350
+ - **Events**:`remoteMethod(params, callback)`(内部驱动 `le-select` 的 `remote-method/loading`)
351
+
352
+ ### 8.10 le-select-multi
353
+
354
+ - **用途**:多级树形多选,支持仅叶子节点
355
+ - **Props**:`cols`、`options`、`value`、`valueKey`、`labelKey`、`clearable`、`filterable`、`defaultExpandAll`、`onlyLeaf`
356
+ - **Events**:`input(value)`、`change(value)`、`leaf-change(validValue)`(仅 `onlyLeaf` 模式)、`clear`、`visible-change(visible)`
357
+ - **Methods**:`expandNode`、`expandAll`、`collapseAll`
358
+
359
+ ### 8.11 le-date-picker
360
+
361
+ - **Props**:`value`、`type`、`translateDate`
362
+ - 内部做值转换,无显式 emit(通过 v-model 双向绑定)
363
+
364
+ ### 8.12 le-date-picker-auto
365
+
366
+ - **用途**:自动识别秒级/毫秒级时间戳并转换
367
+ - **Props**:`value`、`type`
368
+ - **Events**:`input(outputValue)`(watch `internalValue` 触发)
369
+ - **核心方法**:`isTimestampInSeconds`、`isTimestampInMilliseconds`、`convertValueToInternal`、`convertValueToOutput`
370
+
371
+ ### 8.13 le-table-edit
372
+
373
+ - **用途**:基于 `el-table` 的可编辑表格,支持单元格/行编辑、删除、分页、多种编辑类型(input/number/select/date/switch)
374
+ - **Props**:表格数据、列配置、编辑模式、同步数据标志、分页配置等(详见 [main.vue#L194-L312](file:///d:/leisure-core/le-table-edit/src/main.vue))
375
+ - **Events**:`cell-save`、`row-save`、`update:data`、`data-change`、`edit-cancel`
376
+ - **核心方法**:`isEdit`、`startEdit`、`saveCell`、`saveRow`、`cancelEdit`、`validate`、`deleteRow`
377
+
378
+ ### 8.14 le-list
379
+
380
+ - **用途**:列表页封装(查询参数区 + 表格 + 分页 + 增删改查按钮 + 弹窗)
381
+ - **Props**:表格数据、列配置、查询参数、分页、按钮文本、弹窗配置等(详见 [main.vue#L127-L227](file:///d:/leisure-core/le-list/src/main.vue))
382
+ - **Events**:`getList`、`delRow`、`handleStatus`、`editCurrentRow`、`detailCurrentRow`、`close`
383
+ - **Methods**:`getList`、`del`、`editItem`、`detail`、`addItem`、`closeDialog`
384
+
385
+ ### 8.15 le-list-form
386
+
387
+ - **用途**:列表页配套的表单弹窗(新增/编辑/详情)
388
+ - **Props**:表单列配置、表单数据、校验规则、字段选项、操作状态、布局与按钮配置(详见 [main.vue#L87-L146](file:///d:/leisure-core/le-list-form/src/main.vue))
389
+ - **Events**:`form-ready`、`saveData`、`closeDialog`
390
+ - **特征**:提供字段值的 set/get 内部方法
391
+
392
+ ### 8.16 le-report
393
+
394
+ - **用途**:报表组件,含查询参数区、导出 Excel 按钮、`vxe-table` 数据展示、复杂表头、分页
395
+ - **辅助**:`src/rmixins.js` 提供报表专用 mixin
396
+
397
+ ### 8.17 le-upload-table
398
+
399
+ - **用途**:附件管理(上传/列表/下载/删除)
400
+ - **API 注入 Props**:`uploadApi`、`createApi`、`deleteApi`、`listApi`、`downloadApi`(与业务层解耦)
401
+
402
+ ### 8.18 le-media / le-media-upload / le-media-list
403
+
404
+ 素材库三件套,均通过 props 注入业务 API:
405
+
406
+ - **le-media**:素材库主组件
407
+ - Props(均必填 Function):`systemMaterialDelApi`、`systemMaterialListApi`、`systemMaterialCreateApi`、`systemMaterialEditApi`、`uploadFileApi`
408
+ - Methods:编辑/删除/取消上传/打开上传弹窗/分页/搜索重置/列表加载
409
+ - **le-media-upload**:上传/编辑素材
410
+ - Props(均必填):`mediaObj`、`systemMaterialCreateApi`、`systemMaterialEditApi`、`uploadFileApi`
411
+ - Events:`callMdiaUrl(urls)`、`cancel(flag)`
412
+ - Methods:替换素材、保存/修改素材、上传文件、校验提交
413
+ - **le-media-list**:素材列表选择
414
+ - Props:`multiple`(默认 true)、`systemMaterialListApi`(必填)
415
+ - Events:`selectContent(row.url)`(单选) / `selectContent(arr)`(多选)
416
+
417
+ ### 8.19 le-image / le-video / le-upload
418
+
419
+ - **le-image**:图片展示,Props `replaceHttp`、`previewList`;computed 生成安全 `src/previewList`;方法 `replaceHttp2Https` 做 http→https 协议转换
420
+ - **le-video**:视频展示
421
+ - **le-upload**:通用上传组件
422
+
423
+ ### 8.20 le-login
424
+
425
+ - **Props**:`home`、`title`、`title1`、`captchaRequired`
426
+ - **Events**:
427
+ - `handleLodin(...)`:账号、密码、验证码、成功/失败回调
428
+ - `loginAfter(data)`:登录成功后通知
429
+ - `sendCaptcha(...)`:触发发送验证码,含成功/失败回调
430
+ - **行为**:登录成功后保存用户信息到 store、设置 token、成功提示
431
+ - **样式**:全部通过 CSS 变量消费(login-card 背景 / logo 圆形 / 输入框边框文字 / 登录按钮渐变 / 验证码表头 / 装饰线),跟随 LeTheme 一键换肤
432
+
433
+ ### 8.21 le-home
434
+
435
+ - **Props**:`extraDropdownItems`、`companyInfo`、`showClose`
436
+ - **Slots**:`otherContainer`
437
+ - **Events**:`homeInit`、`command(command)`(修改密码/退出之外的命令)、`userChangePwd(params, callback)`
438
+ - **行为**:挂载后注册键盘/鼠标事件,内置修改密码弹窗
439
+ - **样式换肤支持**:
440
+ - 顶部 header 背景 / aside 背景 / 拖动条 / aside_open_close / contextmenu 全部使用 `var(--le-color-*)`
441
+ - `el-menu` 通过 `background-color` / `text-color` / `active-text-color` prop 动态绑定 CSS 变量(computed + `getCssVar`)
442
+ - 监听 `window` 级 `le-theme-change` 事件,回调里 `$forceUpdate` 强制刷新 el-menu 的 prop
443
+
444
+ ### 8.22 le-area
445
+
446
+ - **Props**:`level`、`initCode`、`isAny`、`initArea`、`elcascader`
447
+ - **Events**:`areaChange(selectValue)`(返回选中地区的 code 和 name)
448
+
449
+ ### 8.23 le-menu / le-role / le-role-user
450
+
451
+ - **le-menu**:角色菜单配置;Props `roleInfo`;Events `close`
452
+ - **le-role**:角色管理主组件,使用 `leMixins`,内部依赖 `LeRoleSub` 子组件,维护角色列表与编辑/菜单/用户弹窗状态
453
+ - **le-role-user**:角色用户管理,内部依赖 `LeRoleUserSub`;`save()` 调子组件 `saveUserRole(uid)`,保存后 `roleSaveAfter()` 关闭弹窗
454
+
455
+ ## 9. 跨组件约定
456
+
457
+ ### 9.1 鉴权与请求
458
+
459
+ - 所有需要后端的组件**不直接发请求**,而是通过 `props` 接收业务层传入的 API 函数(如 `le-upload-table`、`le-media*`、`le-list` 等),实现组件库与业务接口解耦
460
+ - 通用 HTTP 鉴权链路集中在 `le-libs/js/hrequest.js`:`authentication`(token) + `timestamp` + `sign`
461
+ - 业务层需在应用启动时调用 `hrequest.setCalMethod(fn)` 注入签名算法
462
+
463
+ ### 9.2 权限控制
464
+
465
+ - `v-permission` 指令接收按钮配置 JSON,按 `id + permission==='no'` 移除 DOM
466
+ - `le-button` 系列 props 含 `permission` 字段,配合指令实现按钮级权限
467
+
468
+ ### 9.3 v-model 双向绑定
469
+
470
+ - `le-select-multi` / `le-date-picker-auto` / `le-input-advanced` 等通过 `emit('input', value)` 支持 v-model
471
+ - `le-table-edit` 通过 `update:data` 支持 `.sync`
472
+
473
+ ### 9.4 弹窗拖拽
474
+
475
+ - 任意 `el-dialog` 添加 `v-el-drag-dialog` 即可拖拽,拖拽中触发 `dragDialog` 事件
476
+
477
+ ### 9.5 表格自适应高度
478
+
479
+ - 使用 `leMixins` 的组件需在模板中给 `el-table` 设置 `ref="eltablemain"`
480
+ - `changeHeight()` 监听 `window.resize`,动态设置 `elTableMaxHeight = innerHeight - tableTop - 90`,最小 200
481
+
482
+ ### 9.6 CSS 变量层 + LeTheme 主题系统
483
+
484
+ **三层架构**
485
+
486
+ 1. **变量层**(`le-theme/common/vars.css`):在 `:root` 上定义 `--le-color-*` 语义变量,并覆盖 Element UI primary 选择器
487
+ 2. **服务层**(`le-theme/index.js`):LeTheme 单例,提供 `set/register/init/current` API,切换时写 `<html>` 样式 + 派发 `le-theme-change` CustomEvent + 持久化到 localStorage
488
+ 3. **消费层**:组件样式通过 `var(--le-color-*)` 直接消费;el-menu/el-dialog 等通过 computed + `getCssVar` 读取 CSS 变量作为 prop 传值,并监听 `le-theme-change` 后 `$forceUpdate`
489
+
490
+ **关键约束**
491
+
492
+ - 组件样式**禁止硬编码颜色值**(如 `#3a3a3a`),必须使用 `var(--le-color-*)`
493
+ - 新增皮肤**必须覆盖所有 framework 变量**(header/aside/menu/handle/toggle/contextmenu),否则出现局部不变
494
+ - `Vue.prototype.$leTheme` 是唯一入口,不挂 `window` 污染全局
495
+ - 初始化在 `install` 流程里调用 `LeTheme.init()`,从 localStorage 恢复上次皮肤
496
+
497
+ ## 10. 宿主项目集成要求
498
+
499
+ 使用本组件库的宿主应用需提供以下依赖:
500
+
501
+ | 依赖项 | 说明 |
502
+ | ------------------------------------ | -------------------------------- |
503
+ | `@/router` | `hrequest.js` 登录失效时跳转 `/` |
504
+ | `@/store` + `store.getters.userinfo` | 读取 token 注入请求头 |
505
+ | `process.env.VUE_APP_BASE_API` | axios baseURL |
506
+ | `dayjs` | 时间戳 |
507
+ | `leisure-js/common/dformat` | 全局格式化方法来源 |
508
+ | Element UI 全量引入 | 基础组件 |
509
+ | `vxe-table` | 报表组件依赖 |
510
+ | `localStorage` | token + LeTheme 皮肤持久化 |
511
+
512
+ ### 10.1 换肤相关宿主约束
513
+
514
+ - 若业务侧在组件外直接使用 `this.$leTheme`(如全局 header 里的换肤按钮),需通过 Vue 原型方法访问
515
+ - 组件库**不污染 `window`**,宿主无法在控制台用 `window.LeTheme` 调试;如需控制台验证,用:
516
+ ```js
517
+ document.querySelector("#app").__vue__.$leTheme.set("dark");
518
+ ```
519
+ - 皮肤切换后,依赖 `le-theme-change` CustomEvent 的组件会自动响应;不依赖该事件的组件需在 mounted 里自行监听
520
+
521
+ ## 11. LLM 学习要点
522
+
523
+ 1. **组件库而非应用**:本项目是可被多后台系统复用的组件层,不含业务路由/页面,业务逻辑由宿主通过 props/事件注入
524
+ 2. **install 模式**:每个组件 `index.js` 都挂 `install`,既支持整体 `Vue.use()`,也支持按需 `import`
525
+ 3. **透传封装**:`le-form`、`le-input` 等仅做样式/默认值占位,靠 `$attrs/$listeners` 透传,理解 Vue 2 的属性继承机制
526
+ 4. **API 注入解耦**:`le-upload-table`、`le-media*` 通过必填 Function props 把数据层完全外置,是组件库设计的典型范式
527
+ 5. **集中式鉴权**:`hrequest.js` 统一处理 token/sign/错误码跳转,业务组件不再关心 HTTP 细节
528
+ 6. **指令 + mixin 复用**:`v-permission`/`v-el-drag-dialog`/`v-rfooter` 与 `leMixins` 提供横切能力
529
+ 7. **业务复合组件**:`le-role`/`le-role-user`/`le-home` 是较重的业务组件,内部拆分子组件(`LeRoleSub` 等)但不对外注册
530
+ 8. **vxe-table + element-ui 混用**:报表用 vxe-table,常规表格用 el-table,分别承担复杂表头与可编辑场景
531
+ 9. **CSS 变量 + 服务层的换肤架构**:变量层(`vars.css`)只管语义与 Element UI 覆盖;服务层(`LeTheme`)管运行时切换/持久化/事件派发;消费层按"CSS 直接 var"与"prop 绑定 + 事件监听"两种模式消费,解耦且可扩展
532
+ 10. **避免 window 污染**:`LeTheme` 单例挂到 Vue 原型而非 `window`,符合组件库"库不污染全局"的规范
533
+ 11. **新增皮肤 checklist**:品牌色族 → 功能色 → 文本边框容器 → framework 全部变量,缺一不可,否则局部不跟随换肤
534
+ 12. **el-menu 等 prop 驱动组件的换肤坑**:不能只改外层 CSS,必须把 prop(`background-color` 等)绑定到 computed,再用 `getCssVar` 读 CSS 变量,监听 `le-theme-change` 后 `$forceUpdate` 强制刷新
535
+
536
+ ## 12. 版本与发布
537
+
538
+ - 版本号:`0.6.90`(`package.json`)
539
+ - `private: false`,发布至 npm 公共仓库
540
+ - keywords:`leisure`、`leisure-core`、`京心数据`
package/index.js CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  formatMoney,
6
6
  formatCurrency,
7
7
  } from "leisure-js/common/dformat";
8
+ import LeTheme from "./le-theme"; // 一键换肤服务:引入 vars.css + LeTheme API
8
9
  import LeLogin from "./le-login/index.js";
9
10
  import LeHome from "./le-home/index.js";
10
11
  import LeButton from "./le-button/index.js";
@@ -113,6 +114,11 @@ const install = function (Vue) {
113
114
  Vue.prototype.formatMoney = formatMoney;
114
115
  Vue.prototype.formatCurrency = formatCurrency;
115
116
 
117
+ // 一键换肤服务:挂载到 Vue 原型,组件内使用方式 this.$leTheme.set("dark")
118
+ Vue.prototype.$leTheme = LeTheme;
119
+ // 在 install 流程里初始化 LeTheme,从 localStorage 恢复上次选择的皮肤
120
+ LeTheme.init();
121
+
116
122
  Vue.directive("permission", {
117
123
  inserted: function (el, bindings) {
118
124
  let buttons = bindings.value;