haiwei-ui 1.2.6 → 1.2.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "haiwei-ui",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "description": "HaiWei前端组件库",
5
5
  "author": "Eric",
6
6
  "license": "ISC",
@@ -8,7 +8,7 @@
8
8
  "scripts": {
9
9
  "serve": "vue-cli-service lint && vue-cli-service serve",
10
10
  "build": "vue-cli-service lint && vue-cli-service build",
11
- "lint": "vue-cli-service lint",
11
+ "lint": "vue-cli-service lint --fit",
12
12
  "cm": "rimraf node_modules && rimraf dist",
13
13
  "cc": "rimraf node_modules/.cache",
14
14
  "i": "cd ./script && npm_install.bat",
@@ -101,8 +101,51 @@
101
101
  },
102
102
  /** 当用户手动勾选全选 Checkbox 时触发的事件 */
103
103
  onSelectAll(selection) {
104
- if (this.noClearSelection) {
105
- let hasSelection = this.$parent.selection
104
+ const parent = this.$parent
105
+
106
+ // 检查是否启用树形全选
107
+ const isTreeSelectAllEnabled = parent.isTreeSelectAllEnabled && parent.isTreeSelectAllEnabled()
108
+
109
+ if (isTreeSelectAllEnabled) {
110
+ // 判断是全选还是取消全选
111
+ const visibleRowsCount = this.rows.length
112
+
113
+ // 简化逻辑:如果selection为空数组,肯定是取消全选
114
+ // 如果selection不为空,需要进一步判断
115
+ let isSelectAllOperation = false
116
+
117
+ if (selection.length === 0) {
118
+ // selection为空数组,肯定是取消全选
119
+ isSelectAllOperation = false
120
+ } else {
121
+ // selection不为空,需要判断
122
+ const hasExistingSelection = parent.selection && parent.selection.length > 0
123
+ const hasManySelected = hasExistingSelection && parent.selection.length > visibleRowsCount
124
+
125
+ if (!hasExistingSelection) {
126
+ // 还没有选择任何记录,肯定是全选操作
127
+ isSelectAllOperation = true
128
+ } else if (hasManySelected) {
129
+ // 已经选择了很多记录(包括子节点),肯定是取消全选操作
130
+ isSelectAllOperation = false
131
+ } else {
132
+ // 其他情况:选择了一些记录但不多
133
+ // 如果selection包含当前页显示的所有行,那么是全选操作
134
+ // 否则是取消全选操作
135
+ isSelectAllOperation = selection.length >= visibleRowsCount
136
+ }
137
+ }
138
+
139
+ if (isSelectAllOperation) {
140
+ // 选择所有节点(包括子节点)
141
+ parent.selectAllTreeNodes(parent.rows, parent.selection)
142
+ } else {
143
+ // 取消选择所有节点(包括子节点)
144
+ parent.deselectAllTreeNodes(parent.rows, parent.selection)
145
+ }
146
+ } else if (parent.noClearSelection) {
147
+ // 原有逻辑(普通全选,不清空选择)
148
+ let hasSelection = parent.selection
106
149
  if (selection.length > 0) {
107
150
  this.rows.forEach(m => {
108
151
  if (!hasSelection.every(n => n.id !== m.id)) {
@@ -121,7 +164,8 @@
121
164
  })
122
165
  }
123
166
  }
124
- this.$parent.$emit('select-all', this.$parent.selection)
167
+
168
+ parent.$emit('select-all', parent.selection)
125
169
  },
126
170
  /** 当选择项发生变化时会触发该事件 */
127
171
  onSelectionChange(selection) {
@@ -83,8 +83,17 @@ const importOptions = {
83
83
  errorHandling: 0
84
84
  }
85
85
 
86
+ //默认树形全选配置
87
+ const treeSelectAllOptions = {
88
+ /**启用树形全选功能 */
89
+ enabled: false,
90
+ /**默认全部选择 */
91
+ defaultSelectAll: true
92
+ }
93
+
86
94
  export default {
87
95
  columnInfo,
88
96
  exportOptions,
89
- importOptions
97
+ importOptions,
98
+ treeSelectAllOptions
90
99
  }
@@ -1,14 +1,24 @@
1
1
  <template>
2
- <section :class="class_" v-loading="showLoading" :element-loading-text="loadingText || loadingText_" :element-loading-background="loadingBackground" :element-loading-spinner="loadingSpinner">
2
+ <section :class="class_" v-loading="showLoading" :element-loading-text="loadingText || loadingText_"
3
+ :element-loading-background="loadingBackground" :element-loading-spinner="loadingSpinner">
3
4
  <!--header-->
4
- <query-header v-if="!noHeader" :title="title" :icon="icon" :no-fullscreen="noFullscreen" :fullscreen="fullscreen" :no-refresh="noRefresh" :export-enabled="exportOptions_.enabled && exportOptions_.btnLocation !== 'querybar'" :exportBtnCode="exportOptions_.btnCode" :import-enabled="importOptions_.enabled && importOptions_.btnLocation !== 'querybar'" :importBtnCode="importOptions_.btnCode">
5
+ <query-header v-if="!noHeader" :title="title" :icon="icon" :no-fullscreen="noFullscreen" :fullscreen="fullscreen"
6
+ :no-refresh="noRefresh" :export-enabled="exportOptions_.enabled && exportOptions_.btnLocation !== 'querybar'"
7
+ :exportBtnCode="exportOptions_.btnCode"
8
+ :import-enabled="importOptions_.enabled && importOptions_.btnLocation !== 'querybar'"
9
+ :importBtnCode="importOptions_.btnCode">
5
10
  <template v-slot:toolbar>
6
11
  <slot name="header-toolbar" :total="total" :selection="selection" />
7
12
  </template>
8
13
  </query-header>
9
14
 
10
15
  <!--查询栏-->
11
- <querybar ref="querybar" v-if="!noQuerybar" :model="model" :rules="rules" :input-width="inputWidth" :advanced="advanced" :no-search="noSearch" :no-reset="noReset" :export-enabled="exportOptions_.enabled && exportOptions_.btnLocation === 'querybar'" :export-btn-code="exportOptions_.btnCode" :import-enabled="importOptions_.enabled && importOptions_.btnLocation === 'querybar'" :import-btn-code="importOptions_.btnCode" @reset="onQueryBarReset">
16
+ <querybar ref="querybar" v-if="!noQuerybar" :model="model" :rules="rules" :input-width="inputWidth"
17
+ :advanced="advanced" :no-search="noSearch" :no-reset="noReset"
18
+ :export-enabled="exportOptions_.enabled && exportOptions_.btnLocation === 'querybar'"
19
+ :export-btn-code="exportOptions_.btnCode"
20
+ :import-enabled="importOptions_.enabled && importOptions_.btnLocation === 'querybar'"
21
+ :import-btn-code="importOptions_.btnCode" @reset="onQueryBarReset">
12
22
  <template v-slot>
13
23
  <slot name="querybar" />
14
24
  </template>
@@ -21,7 +31,10 @@
21
31
  </querybar>
22
32
 
23
33
  <section class="nm-list-body">
24
- <query-table ref="table" :rows="rows" :cols="cols" :span-method="spanMethod" :selection="selection" :row-key="rowKey" :tree-props="treeProps" :default-expand-all="defaultExpandAll" :no-clear-selection="noClearSelection" :show-summary="showSummary" :sum-text="sumText" :summary-method="summaryMethod">
34
+ <query-table ref="table" :rows="rows" :cols="cols" :span-method="spanMethod" :selection="selection"
35
+ :row-key="rowKey" :tree-props="treeProps" :default-expand-all="defaultExpandAll"
36
+ :no-clear-selection="noClearSelection" :show-summary="showSummary" :sum-text="sumText"
37
+ :summary-method="summaryMethod">
25
38
  <!-- 多选 -->
26
39
  <el-table-column v-if="multiple" fixed="left" align="center" type="selection" width="55" />
27
40
 
@@ -39,7 +52,9 @@
39
52
 
40
53
  <!-- 自动生成列 -->
41
54
  <template v-for="(col, i) in columns">
42
- <el-table-column v-if="col.show" :key="i" :prop="col.name" :width="col.width" :sortable="col.sortable" :type="col.type" :fixed="col.fixed" :align="col.align" :header-align="col.headerAlign" :show-overflow-tooltip="col.showOverflowTooltip">
55
+ <el-table-column v-if="col.show" :key="i" :prop="col.name" :width="col.width" :sortable="col.sortable"
56
+ :type="col.type" :fixed="col.fixed" :align="col.align" :header-align="col.headerAlign"
57
+ :show-overflow-tooltip="col.showOverflowTooltip">
43
58
  <!--自定义头-->
44
59
  <template v-slot:header>
45
60
  <slot :name="`col-${col.name}-header`">
@@ -69,21 +84,24 @@
69
84
  </section>
70
85
 
71
86
  <!--footer-->
72
- <query-footer v-if="!noFooter" v-model="page" :page-sizes="pageSizes" :total="total" :columns.sync="columns" :no-select-column="noSelectColumn" :no-search-button-icon="noSearchButtonIcon" :reverse="footerReverse">
87
+ <query-footer v-if="!noFooter" v-model="page" :page-sizes="pageSizes" :total="total" :columns.sync="columns"
88
+ :no-select-column="noSelectColumn" :no-search-button-icon="noSearchButtonIcon" :reverse="footerReverse">
73
89
  <slot name="footer" :total="total" :selection="selection" :data="data" />
74
90
  </query-footer>
75
91
  <slot />
76
92
 
77
93
  <!--导出-->
78
- <query-export v-if="exportAdvancedEnabled" :options="exportOptions_" :list-title="title" :cols="columns" :visible.sync="showExport" />
79
-
94
+ <query-export v-if="exportAdvancedEnabled" :options="exportOptions_" :list-title="title" :cols="columns"
95
+ :visible.sync="showExport" />
96
+
80
97
  <!--导入-->
81
- <query-import v-if="importAdvancedEnabled" :options="importOptions_" :cols="columns" :action="importOptions_.action" :visible.sync="showImport" />
98
+ <query-import v-if="importAdvancedEnabled" :options="importOptions_" :cols="columns" :action="importOptions_.action"
99
+ :visible.sync="showImport" />
82
100
  </section>
83
101
  </template>
84
102
  <script>
85
- import { mapState } from 'vuex'
86
- import def from './default.js'
103
+ import { mapState } from 'vuex'
104
+ import def from './default.js'
87
105
  import QueryHeader from './components/header'
88
106
  import Querybar from './components/querybar'
89
107
  import QueryTable from './components/table'
@@ -91,385 +109,473 @@ import QueryFooter from './components/footer'
91
109
  import QueryExport from './components/export'
92
110
  import QueryImport from './components/import'
93
111
 
94
- export default {
95
- name: 'List',
96
- components: { QueryHeader, Querybar, QueryTable, QueryFooter, QueryExport, QueryImport },
97
- data() {
98
- return {
99
- loading_: false,
100
- fullscreen: false,
101
- // 分页数据
102
- page: {
103
- index: 1,
104
- size: this.pageSizes[0],
105
- sort: []
106
- },
107
- // 数据列表
108
- rows: [],
109
- // 扩展数据
110
- data: '',
111
- // 总数量
112
- total: 0,
113
- selection: [],
114
- showExport: false,
115
- showImport: false,
116
- columns: []
112
+ export default {
113
+ name: 'List',
114
+ components: { QueryHeader, Querybar, QueryTable, QueryFooter, QueryExport, QueryImport },
115
+ data() {
116
+ return {
117
+ loading_: false,
118
+ fullscreen: false,
119
+ // 分页数据
120
+ page: {
121
+ index: 1,
122
+ size: this.pageSizes[0],
123
+ sort: []
124
+ },
125
+ // 数据列表
126
+ rows: [],
127
+ // 扩展数据
128
+ data: '',
129
+ // 总数量
130
+ total: 0,
131
+ selection: [],
132
+ showExport: false,
133
+ showImport: false,
134
+ columns: []
135
+ }
136
+ },
137
+ props: {
138
+ /** 标题 */
139
+ title: String,
140
+ /** 图标 */
141
+ icon: String,
142
+ // 查询方法
143
+ action: {
144
+ type: Function,
145
+ required: true
146
+ },
147
+ /** 查询表单输入框宽度 */
148
+ inputWidth: String,
149
+ // 模型
150
+ model: Object,
151
+ /** 模型验证规则 */
152
+ rules: Object,
153
+ /** 高级查询 */
154
+ advanced: Object,
155
+ // 列数组
156
+ cols: {
157
+ type: Array,
158
+ default() {
159
+ return []
117
160
  }
118
161
  },
119
- props: {
120
- /** 标题 */
121
- title: String,
122
- /** 图标 */
123
- icon: String,
124
- // 查询方法
125
- action: {
126
- type: Function,
127
- required: true
128
- },
129
- /** 查询表单输入框宽度 */
130
- inputWidth: String,
131
- // 模型
132
- model: Object,
133
- /** 模型验证规则 */
134
- rules: Object,
135
- /** 高级查询 */
136
- advanced: Object,
137
- // 列数组
138
- cols: {
139
- type: Array,
140
- default() {
141
- return []
142
- }
143
- },
144
- /** 多选 */
145
- multiple: Boolean,
146
- /** 显示序号 */
147
- showNo: {
148
- type: Boolean,
149
- default: true
150
- },
151
- /** 不显示操作列 */
152
- noOperation: Boolean,
153
- /** 操作列宽度 */
154
- operationWidth: [String, Number],
155
- /** 不显示选择列按钮 */
156
- noSelectColumn: Boolean,
157
- /** 不显示查询栏 */
158
- noQuerybar: Boolean,
159
- /** 不显示全屏按钮 */
160
- noFullscreen: Boolean,
161
- /** 不显示刷新按钮 */
162
- noRefresh: Boolean,
163
- /** 不显示头部 */
164
- noHeader: Boolean,
165
- /** 不显示底部 */
166
- noFooter: Boolean,
167
- /** 不包含搜索功能 */
168
- noSearch: Boolean,
169
- /** 不显示查询按钮图标 */
170
- noSearchButtonIcon: Boolean,
171
- /**不显示重置按钮 */
172
- noReset: Boolean,
173
- /** 底部反转 */
174
- footerReverse: Boolean,
175
- /** 合并行列的方法 */
176
- spanMethod: Function,
177
- /** 加载中动画 */
178
- loading: Boolean,
179
- /** 加载中文本 */
180
- loadingText: String,
181
- /** 创建后执行一次查询 */
182
- queryOnCreated: {
183
- type: Boolean,
184
- default: true
185
- },
186
- /**导出配置 */
187
- exportOptions: Object,
188
- /**导入配置 */
189
- importOptions: Object,
190
- /** 页数选择项 */
191
- pageSizes: {
192
- type: Array,
193
- default() {
194
- return [20, 50, 100, 200]
195
- }
196
- },
197
- /**渲染嵌套数据的配置选项 */
198
- treeProps: Object,
199
- /*行数据的 Key,用来优化 Table 的渲染;
200
- 在使用 reserve-selection 功能与显示树形数据时,该属性是必填的。
201
- 类型为 String 时,支持多层访问:user.info.id,但不支持 user.info[0].id,此种情况请使用 Function。*/
202
- rowKey: [Function, String],
203
- /*是否懒加载子节点数据*/
204
- lazy: Boolean,
205
- /**加载子节点数据的函数,lazy 为 true 时生效,函数第二个参数包含了节点的层级信息 */
206
- load: Function,
207
- /**是否默认展开所有行,当 Table 包含展开行存在或者为树形表格时有效 */
208
- defaultExpandAll: Boolean,
209
- /**当刷新时不清空已选择数据 */
210
- noClearSelection: Boolean,
211
- /**是否显示合计行 */
212
- showSummary: Boolean,
213
- /**合计行文本 */
214
- sumText: String,
215
- /**合计行自定义逻辑方法 */
216
- summaryMethod: Function
217
- },
218
- computed: {
219
- ...mapState('app/loading', { loadingText_: 'text', loadingBackground: 'background', loadingSpinner: 'spinner' }),
220
- ...mapState('app/config', { serialNumberName: s => s.component.list.serialNumberName }),
221
- class_() {
222
- return ['nm-list', this.fontSize ? `nm-list-${this.fontSize}` : '', this.fullscreen ? 'fullscreen' : '']
223
- },
224
- showLoading() {
225
- return this.loading || this.loading_
226
- },
227
- exportOptions_() {
228
- return this.$_.assignIn({ title: this.title }, def.exportOptions, this.exportOptions)
229
- },
230
- exportAdvancedEnabled() {
231
- return this.exportOptions_.enabled && this.exportOptions_.advanced
232
- },
233
- importOptions_() {
234
- return this.$_.assignIn({ title: this.title }, def.importOptions, this.importOptions)
235
- },
236
- importAdvancedEnabled() {
237
- return this.importOptions_.enabled && this.importOptions_.advanced
162
+ /** 多选 */
163
+ multiple: Boolean,
164
+ /** 树形全选配置 */
165
+ treeSelectAll: {
166
+ type: Object,
167
+ default() {
168
+ return {}
169
+ }
170
+ },
171
+ /** 显示序号 */
172
+ showNo: {
173
+ type: Boolean,
174
+ default: true
175
+ },
176
+ /** 不显示操作列 */
177
+ noOperation: Boolean,
178
+ /** 操作列宽度 */
179
+ operationWidth: [String, Number],
180
+ /** 不显示选择列按钮 */
181
+ noSelectColumn: Boolean,
182
+ /** 不显示查询栏 */
183
+ noQuerybar: Boolean,
184
+ /** 不显示全屏按钮 */
185
+ noFullscreen: Boolean,
186
+ /** 不显示刷新按钮 */
187
+ noRefresh: Boolean,
188
+ /** 不显示头部 */
189
+ noHeader: Boolean,
190
+ /** 不显示底部 */
191
+ noFooter: Boolean,
192
+ /** 不包含搜索功能 */
193
+ noSearch: Boolean,
194
+ /** 不显示查询按钮图标 */
195
+ noSearchButtonIcon: Boolean,
196
+ /**不显示重置按钮 */
197
+ noReset: Boolean,
198
+ /** 底部反转 */
199
+ footerReverse: Boolean,
200
+ /** 合并行列的方法 */
201
+ spanMethod: Function,
202
+ /** 加载中动画 */
203
+ loading: Boolean,
204
+ /** 加载中文本 */
205
+ loadingText: String,
206
+ /** 创建后执行一次查询 */
207
+ queryOnCreated: {
208
+ type: Boolean,
209
+ default: true
210
+ },
211
+ /**导出配置 */
212
+ exportOptions: Object,
213
+ /**导入配置 */
214
+ importOptions: Object,
215
+ /** 页数选择项 */
216
+ pageSizes: {
217
+ type: Array,
218
+ default() {
219
+ return [20, 50, 100, 200]
238
220
  }
239
221
  },
240
- methods: {
241
- /** 查询方法 */
242
- query() {
243
- if (this.$refs.querybar) {
244
- this.$refs.querybar.validate(() => {
245
- this.doQuery()
246
- })
247
- } else {
222
+ /**渲染嵌套数据的配置选项 */
223
+ treeProps: Object,
224
+ /*行数据的 Key,用来优化 Table 的渲染;
225
+ 在使用 reserve-selection 功能与显示树形数据时,该属性是必填的。
226
+ 类型为 String 时,支持多层访问:user.info.id,但不支持 user.info[0].id,此种情况请使用 Function。*/
227
+ rowKey: [Function, String],
228
+ /*是否懒加载子节点数据*/
229
+ lazy: Boolean,
230
+ /**加载子节点数据的函数,lazy 为 true 时生效,函数第二个参数包含了节点的层级信息 */
231
+ load: Function,
232
+ /**是否默认展开所有行,当 Table 包含展开行存在或者为树形表格时有效 */
233
+ defaultExpandAll: Boolean,
234
+ /**当刷新时不清空已选择数据 */
235
+ noClearSelection: Boolean,
236
+ /**是否显示合计行 */
237
+ showSummary: Boolean,
238
+ /**合计行文本 */
239
+ sumText: String,
240
+ /**合计行自定义逻辑方法 */
241
+ summaryMethod: Function
242
+ },
243
+ computed: {
244
+ ...mapState('app/loading', { loadingText_: 'text', loadingBackground: 'background', loadingSpinner: 'spinner' }),
245
+ ...mapState('app/config', { serialNumberName: s => s.component.list.serialNumberName }),
246
+ class_() {
247
+ return ['nm-list', this.fontSize ? `nm-list-${this.fontSize}` : '', this.fullscreen ? 'fullscreen' : '']
248
+ },
249
+ showLoading() {
250
+ return this.loading || this.loading_
251
+ },
252
+ exportOptions_() {
253
+ return this.$_.assignIn({ title: this.title }, def.exportOptions, this.exportOptions)
254
+ },
255
+ exportAdvancedEnabled() {
256
+ return this.exportOptions_.enabled && this.exportOptions_.advanced
257
+ },
258
+ importOptions_() {
259
+ return this.$_.assignIn({ title: this.title }, def.importOptions, this.importOptions)
260
+ },
261
+ importAdvancedEnabled() {
262
+ return this.importOptions_.enabled && this.importOptions_.advanced
263
+ }
264
+ },
265
+ methods: {
266
+ /** 查询方法 */
267
+ query() {
268
+ if (this.$refs.querybar) {
269
+ this.$refs.querybar.validate(() => {
248
270
  this.doQuery()
249
- }
250
- },
251
- doQuery() {
252
- if (this.loading_) {
253
- return
254
- }
255
- this.loading_ = true
256
- let fullModel = Object.assign({}, this.model)
257
- // 设置分页
258
- fullModel.page = this.page
259
- this.action(fullModel)
260
- .then(data => {
261
- this.rows = data.rows
262
- this.total = data.total
263
- this.data = data.data
264
- // 回到顶部
265
- this.$refs.table.scrollTop()
266
- // 重新绘制布局
267
- this.$refs.table.doLayout()
268
- this.loading_ = false
269
- if (this.noClearSelection) {
270
- this.$nextTick(() => {
271
- this.rows.forEach(m => {
272
- if (!this.selection.every(n => n.id !== m.id)) {
273
- this.$refs.table.toggleRowSelection(m, true)
274
- }
275
- })
271
+ })
272
+ } else {
273
+ this.doQuery()
274
+ }
275
+ },
276
+ doQuery() {
277
+ if (this.loading_) {
278
+ return
279
+ }
280
+ this.loading_ = true
281
+ let fullModel = Object.assign({}, this.model)
282
+ // 设置分页
283
+ fullModel.page = this.page
284
+ this.action(fullModel)
285
+ .then(data => {
286
+ this.rows = data.rows
287
+ this.total = data.total
288
+ this.data = data.data
289
+ // 回到顶部
290
+ this.$refs.table.scrollTop()
291
+ // 重新绘制布局
292
+ this.$refs.table.doLayout()
293
+ this.loading_ = false
294
+ if (this.noClearSelection) {
295
+ this.$nextTick(() => {
296
+ this.rows.forEach(m => {
297
+ if (!this.selection.every(n => n.id !== m.id)) {
298
+ this.$refs.table.toggleRowSelection(m, true)
299
+ }
276
300
  })
277
- }
278
- // 查询事件
279
- this.$emit('query', data)
280
- })
281
- .catch(() => {
282
- this.loading_ = false
283
- })
284
- },
285
- export_(exportModel) {
286
- if (!exportModel.columns || exportModel.columns.length < 1) {
287
- this._error('请选择要导出的列')
288
- return
289
- }
290
- if (!this.exportOptions_.action) {
291
- this._error('未设置导出方法')
292
- return
293
- }
301
+ })
302
+ }
303
+ // 查询事件
304
+ this.$emit('query', data)
305
+ })
306
+ .catch(() => {
307
+ this.loading_ = false
308
+ })
309
+ },
310
+ export_(exportModel) {
311
+ if (!exportModel.columns || exportModel.columns.length < 1) {
312
+ this._error('请选择要导出的列')
313
+ return
314
+ }
315
+ if (!this.exportOptions_.action) {
316
+ this._error('未设置导出方法')
317
+ return
318
+ }
294
319
 
295
- this._openLoading('正在导出数据,请稍后...')
320
+ this._openLoading('正在导出数据,请稍后...')
296
321
 
297
- let model = Object.assign({}, this.model)
322
+ let model = Object.assign({}, this.model)
298
323
 
299
- // 设置分页
300
- model.page = this.page
301
- //设置导出信息
302
- model.export = exportModel
303
- this.exportOptions_
304
- .action(model)
305
- .then(() => {
306
- this._closeLoading()
307
- })
308
- .catch(() => {
309
- this._closeLoading()
310
- })
311
- },
312
- /** 刷新 */
313
- refresh(goFirst) {
314
- if (goFirst) this.page.index = 1
315
- this.query()
316
- },
317
- /** 查询表单重置 */
318
- reset() {
319
- this.$refs.querybar.reset()
320
- },
321
- /** 获取序号 */
322
- getNo(index) {
323
- return (this.page.index - 1) * this.page.size + index + 1
324
- },
325
- // 重新绘制布局
326
- doLayout() {
327
- this.$refs.table.doLayout()
328
- },
329
- /** 全屏切换 */
330
- triggerFullscreen() {
331
- this.fullscreen ? this.closeFullscreen() : this.openFullscreen()
332
- this.doLayout()
333
- },
334
- /** 开启全屏 */
335
- openFullscreen() {
336
- this.fullscreen = true
337
- this.$emit('fullscreen-change', this.fullscreen)
338
- },
339
- /** 关闭全屏 */
340
- closeFullscreen() {
341
- this.fullscreen = false
342
- this.$emit('fullscreen-change', this.fullscreen)
343
- },
344
- /** 切换导出对话框显示状态 */
345
- triggerExport() {
346
- let exp = this.exportOptions_
347
- //未启用高级,直接执行导出操作
348
- if (!exp.advanced) {
349
- const { format, mode, showTitle, showCopyright, showColName, showExportDate, showExportPeople } = exp
324
+ // 设置分页
325
+ model.page = this.page
326
+ //设置导出信息
327
+ model.export = exportModel
328
+ this.exportOptions_
329
+ .action(model)
330
+ .then(() => {
331
+ this._closeLoading()
332
+ })
333
+ .catch(() => {
334
+ this._closeLoading()
335
+ })
336
+ },
337
+ /** 刷新 */
338
+ refresh(goFirst) {
339
+ if (goFirst) this.page.index = 1
340
+ this.query()
341
+ },
342
+ /** 查询表单重置 */
343
+ reset() {
344
+ this.$refs.querybar.reset()
345
+ },
346
+ /** 获取序号 */
347
+ getNo(index) {
348
+ return (this.page.index - 1) * this.page.size + index + 1
349
+ },
350
+ // 重新绘制布局
351
+ doLayout() {
352
+ this.$refs.table.doLayout()
353
+ },
354
+ /** 全屏切换 */
355
+ triggerFullscreen() {
356
+ this.fullscreen ? this.closeFullscreen() : this.openFullscreen()
357
+ this.doLayout()
358
+ },
359
+ /** 开启全屏 */
360
+ openFullscreen() {
361
+ this.fullscreen = true
362
+ this.$emit('fullscreen-change', this.fullscreen)
363
+ },
364
+ /** 关闭全屏 */
365
+ closeFullscreen() {
366
+ this.fullscreen = false
367
+ this.$emit('fullscreen-change', this.fullscreen)
368
+ },
369
+ /** 切换导出对话框显示状态 */
370
+ triggerExport() {
371
+ let exp = this.exportOptions_
372
+ //未启用高级,直接执行导出操作
373
+ if (!exp.advanced) {
374
+ const { format, mode, showTitle, showCopyright, showColName, showExportDate, showExportPeople } = exp
350
375
 
351
- let model = { format, mode, showTitle, showCopyright, showColName, showExportDate, showExportPeople }
352
- model.title = this.title
353
- model.fileName = `${this.title}_${this.$dayjs().format('YYYYMMDDHHmmss')}`
354
- model.columns = []
376
+ let model = { format, mode, showTitle, showCopyright, showColName, showExportDate, showExportPeople }
377
+ model.title = this.title
378
+ model.fileName = `${this.title}_${this.$dayjs().format('YYYYMMDDHHmmss')}`
379
+ model.columns = []
355
380
 
356
- this.columns.forEach(m => {
357
- if (m.show) {
358
- model.columns.push(this.listCol2ExportCol(m))
359
- }
360
- })
381
+ this.columns.forEach(m => {
382
+ if (m.show) {
383
+ model.columns.push(this.listCol2ExportCol(m))
384
+ }
385
+ })
361
386
 
362
- this.export_(model)
363
- }
387
+ this.export_(model)
388
+ }
364
389
 
365
- this.showExport ? this.closeExport() : this.openExport()
366
- },
367
- /** 打开导出对话框 */
368
- openExport() {
369
- this.showExport = true
370
- this.$emit('export-change', this.showExport)
371
- },
372
- closeExport() {
373
- this.showExport = false
374
- this.$emit('export-change', this.showExport)
375
- },
376
- /** 切换导入对话框显示状态 */
377
- triggerImport() {
378
- let imp = this.importOptions_
379
- //未启用高级,直接执行导入操作
380
- if (!imp.advanced) {
381
- // 简单导入模式:直接打开文件选择
382
- this._info('请使用高级导入功能进行文件选择和配置')
383
- return
384
- }
390
+ this.showExport ? this.closeExport() : this.openExport()
391
+ },
392
+ /** 打开导出对话框 */
393
+ openExport() {
394
+ this.showExport = true
395
+ this.$emit('export-change', this.showExport)
396
+ },
397
+ closeExport() {
398
+ this.showExport = false
399
+ this.$emit('export-change', this.showExport)
400
+ },
401
+ /** 切换导入对话框显示状态 */
402
+ triggerImport() {
403
+ let imp = this.importOptions_
404
+ //未启用高级,直接执行导入操作
405
+ if (!imp.advanced) {
406
+ // 简单导入模式:直接打开文件选择
407
+ this._info('请使用高级导入功能进行文件选择和配置')
408
+ return
409
+ }
385
410
 
386
- this.showImport ? this.closeImport() : this.openImport()
387
- },
388
- /** 打开导入对话框 */
389
- openImport() {
390
- this.showImport = true
391
- this.$emit('import-change', this.showImport)
392
- },
393
- closeImport() {
394
- this.showImport = false
395
- this.$emit('import-change', this.showImport)
396
- },
397
- /** 列表的列转导出的列 */
398
- listCol2ExportCol(m) {
399
- let col = {
400
- name: m.name,
401
- label: m.label,
402
- align: m.align,
403
- format: m.format,
404
- width: 0
405
- }
411
+ this.showImport ? this.closeImport() : this.openImport()
412
+ },
413
+ /** 打开导入对话框 */
414
+ openImport() {
415
+ this.showImport = true
416
+ this.$emit('import-change', this.showImport)
417
+ },
418
+ closeImport() {
419
+ this.showImport = false
420
+ this.$emit('import-change', this.showImport)
421
+ },
422
+ /** 列表的列转导出的列 */
423
+ listCol2ExportCol(m) {
424
+ let col = {
425
+ name: m.name,
426
+ label: m.label,
427
+ align: m.align,
428
+ format: m.format,
429
+ width: 0
430
+ }
406
431
 
407
- //设置导出专属vip配置~
408
- if (m.export.width > 0) {
409
- col.width = m.export.width
410
- } else {
411
- let w = parseInt(m.width)
412
- if (w) col.width = w / 10 + 4 //默认取列表页中设置的宽度,该宽度与导出的Excel的列宽度比例大概10:1,所以这里进行一下转换, 转换后在+4,保可以保证有内边距,不会挤在一起
413
- }
414
- return col
415
- },
416
- /** 查询栏重置事件 */
417
- onQueryBarReset() {
418
- this.$refs.table.clearSort()
419
- this.$emit('reset')
420
- },
421
- /** 删除行 */
422
- removeRow(row) {
423
- for (let i = 0; i < this.rows.length; i++) {
424
- if (this.rows[i] === row) {
425
- this.rows.splice(i, 1)
426
- this.total--
427
- break
428
- }
432
+ //设置导出专属vip配置~
433
+ if (m.export.width > 0) {
434
+ col.width = m.export.width
435
+ } else {
436
+ let w = parseInt(m.width)
437
+ if (w) col.width = w / 10 + 4 //默认取列表页中设置的宽度,该宽度与导出的Excel的列宽度比例大概10:1,所以这里进行一下转换, 转换后在+4,保可以保证有内边距,不会挤在一起
438
+ }
439
+ return col
440
+ },
441
+ /** 查询栏重置事件 */
442
+ onQueryBarReset() {
443
+ this.$refs.table.clearSort()
444
+ this.$emit('reset')
445
+ },
446
+ /** 删除行 */
447
+ removeRow(row) {
448
+ for (let i = 0; i < this.rows.length; i++) {
449
+ if (this.rows[i] === row) {
450
+ this.rows.splice(i, 1)
451
+ this.total--
452
+ break
429
453
  }
430
- },
431
- /** 格式化 */
432
- format(row, col) {
433
- const val = row[col.name]
434
- if (!col.format) return val
435
-
436
- const format = col.format
454
+ }
455
+ },
456
+ /** 格式化 */
457
+ format(row, col) {
458
+ const val = row[col.name]
459
+ if (!col.format) return val
437
460
 
438
- //性别
439
- if (format === 'sex') {
440
- return val === 0 ? '男' : '女'
441
- }
461
+ const format = col.format
442
462
 
443
- //日期
444
- if (format === 'date') {
445
- return this.$dayjs(val).format('YYYY-MM-DD')
446
- }
463
+ //性别
464
+ if (format === 'sex') {
465
+ return val === 0 ? '' : '女'
466
+ }
447
467
 
448
- //自定义函数
449
- if (typeof format === 'function') {
450
- return format(val, row)
451
- }
468
+ //日期
469
+ if (format === 'date') {
470
+ return this.$dayjs(val).format('YYYY-MM-DD')
471
+ }
452
472
 
453
- //日期
454
- return this.$dayjs(val).format(col.format)
473
+ //自定义函数
474
+ if (typeof format === 'function') {
475
+ return format(val, row)
455
476
  }
477
+
478
+ //日期
479
+ return this.$dayjs(val).format(col.format)
456
480
  },
457
- mounted() {
458
- this.$nextTick(() => {
459
- if (this.queryOnCreated) {
460
- this.query()
481
+
482
+ /** 递归选择所有树形节点 */
483
+ selectAllTreeNodes(nodes, selection) {
484
+ if (!nodes || !Array.isArray(nodes)) return
485
+
486
+ nodes.forEach(node => {
487
+ // 获取行键值
488
+ const rowKeyValue = typeof this.rowKey === 'function' ? this.rowKey(node) : node[this.rowKey]
489
+
490
+ // 检查是否已经选择
491
+ const isSelected = selection.some(s => {
492
+ const selectedKey = typeof this.rowKey === 'function' ? this.rowKey(s) : s[this.rowKey]
493
+ return selectedKey === rowKeyValue
494
+ })
495
+
496
+ if (!isSelected) {
497
+ selection.push(node)
498
+
499
+ // 更新表格UI选择状态
500
+ if (this.$refs.table && this.$refs.table.toggleRowSelection) {
501
+ this.$refs.table.toggleRowSelection(node, true)
502
+ }
503
+ }
504
+
505
+ // 递归处理子节点
506
+ if (this.treeProps && this.treeProps.children) {
507
+ const children = node[this.treeProps.children]
508
+ if (children && children.length > 0) {
509
+ this.selectAllTreeNodes(children, selection)
510
+ }
461
511
  }
462
512
  })
463
513
  },
464
- created() {
465
- if (this.cols) {
466
- this.columns = this.cols.map(col => {
467
- return this.$_.assignIn({}, def.columnInfo, col)
514
+
515
+ /** 递归取消选择所有树形节点 */
516
+ deselectAllTreeNodes(nodes, selection) {
517
+ if (!nodes || !Array.isArray(nodes)) return
518
+
519
+ nodes.forEach(node => {
520
+ // 获取行键值
521
+ const rowKeyValue = typeof this.rowKey === 'function' ? this.rowKey(node) : node[this.rowKey]
522
+
523
+ // 从选择中移除当前节点
524
+ const selectedIndex = selection.findIndex(s => {
525
+ const selectedKey = typeof this.rowKey === 'function' ? this.rowKey(s) : s[this.rowKey]
526
+ return selectedKey === rowKeyValue
468
527
  })
469
- }
528
+
529
+ if (selectedIndex > -1) {
530
+ selection.splice(selectedIndex, 1)
531
+
532
+ // 更新表格UI选择状态
533
+ if (this.$refs.table && this.$refs.table.toggleRowSelection) {
534
+ this.$refs.table.toggleRowSelection(node, false)
535
+ }
536
+ }
537
+
538
+ // 递归处理子节点
539
+ if (this.treeProps && this.treeProps.children) {
540
+ const children = node[this.treeProps.children]
541
+ if (children && children.length > 0) {
542
+ this.deselectAllTreeNodes(children, selection)
543
+ }
544
+ }
545
+ })
470
546
  },
471
- activated() {
472
- this.doLayout()
547
+
548
+ /** 检查是否启用树形全选 */
549
+ isTreeSelectAllEnabled() {
550
+ const treeSelectAllOptions = this.$_.assignIn({}, def.treeSelectAllOptions, this.treeSelectAll)
551
+ const enabled = treeSelectAllOptions.enabled
552
+
553
+ // 检查是否启用树形全选:需要同时满足以下条件:
554
+ // 1. treeSelectAll.enabled 为 true
555
+ // 2. treeProps 存在
556
+ // 3. treeProps.children 存在(可以是任何值,只要存在就行)
557
+ const hasTreeProps = !!this.treeProps
558
+ const hasChildrenProp = hasTreeProps && this.treeProps.children !== undefined && this.treeProps.children !== null
559
+
560
+ return enabled && hasTreeProps && hasChildrenProp
561
+ }
562
+ },
563
+ mounted() {
564
+ this.$nextTick(() => {
565
+ if (this.queryOnCreated) {
566
+ this.query()
567
+ }
568
+ })
569
+ },
570
+ created() {
571
+ if (this.cols) {
572
+ this.columns = this.cols.map(col => {
573
+ return this.$_.assignIn({}, def.columnInfo, col)
574
+ })
473
575
  }
576
+ },
577
+ activated() {
578
+ this.doLayout()
474
579
  }
580
+ }
475
581
  </script>
@@ -1,11 +1,16 @@
1
1
  <template>
2
- <nm-list v-bind="list">
2
+ <nm-list ref="list" v-bind="list">
3
3
  <template v-slot:querybar>
4
4
  <el-form-item label="姓名:" prop="name">
5
5
  <el-input v-model="list.model.name" />
6
6
  </el-form-item>
7
7
  </template>
8
8
 
9
+ <!-- 操作按钮 -->
10
+ <template v-slot:querybar-buttons>
11
+ <nm-button type="primary" text="显示选中" icon="view" @click="showSelection" />
12
+ </template>
13
+
9
14
  <template v-slot:col-operation>
10
15
  <nm-button type="text" text="编辑" icon="edit" />
11
16
  <nm-button-delete type="text" :action="remove" id="1" @success="onSuccess" />
@@ -21,7 +26,24 @@
21
26
  icon: 'list',
22
27
  action: this.query,
23
28
  rowKey: 'id',
29
+
30
+ /** 启用多选功能 */
31
+ multiple: true,
32
+
33
+ /** 树形全选配置 */
34
+ treeSelectAll: {
35
+ enabled: true, // 启用树形全选
36
+ defaultSelectAll: true // 默认全部选择
37
+ },
38
+
39
+ /** 树形表格配置 */
24
40
  treeProps: { children: 'children', hasChildren: 'hasChildren' },
41
+ defaultExpandAll: true,
42
+
43
+ /** 选择列配置 */
44
+ selectionWidth: '55',
45
+ selectionFixed: true,
46
+
25
47
  model: {
26
48
  name: ''
27
49
  },
@@ -84,6 +106,20 @@
84
106
  remove() {},
85
107
  onSuccess() {
86
108
  this.query()
109
+ },
110
+
111
+ /** 显示选中的记录 */
112
+ showSelection() {
113
+ const listRef = this.$refs.list
114
+ if (listRef && listRef.getSelection) {
115
+ const selection = listRef.getSelection()
116
+ if (selection && selection.length > 0) {
117
+ const names = selection.map(item => item.name).join(', ')
118
+ this.$message.success(`已选中 ${selection.length} 条记录:${names}`)
119
+ } else {
120
+ this.$message.info('没有选中任何记录')
121
+ }
122
+ }
87
123
  }
88
124
  }
89
125
  }