w-ui-v1 1.0.42 → 1.0.43

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/index.ts CHANGED
@@ -13,6 +13,7 @@ import wEdit from './w-edit/w-edit.vue'
13
13
  import WSelectTable from './w-select-table/w-select-table.vue'
14
14
  import WFormMessageBox from './w-form-message-box/w-form-message-box.vue'
15
15
  import WAudio from './w-audio/w-audio.vue'
16
+ import WReportTable from './w-report-table/w-report-table.vue'
16
17
  const coms: any[] = [
17
18
  wTest,
18
19
  wLogin,
@@ -27,7 +28,8 @@ const coms: any[] = [
27
28
  wEdit,
28
29
  WSelectTable,
29
30
  WFormMessageBox,
30
- WAudio
31
+ WAudio,
32
+ WReportTable
31
33
  ]
32
34
  // 批量组件注册
33
35
  function install(Vue: App) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "w-ui-v1",
3
- "version": "1.0.42",
3
+ "version": "1.0.43",
4
4
  "description": "w-ui",
5
5
  "author": "wgxshh",
6
6
  "license": "ISC",
package/w-menu/w-menu.vue CHANGED
@@ -33,7 +33,6 @@ onMounted(() => {
33
33
 
34
34
  // 点击菜单跳转页面
35
35
  function gotoPage(item: any) {
36
- console.log(item)
37
36
  // 跳转页面
38
37
  if (goto(item))
39
38
  return
@@ -53,13 +52,25 @@ function sheetGotoPage(item: any) {
53
52
 
54
53
  // 跳转页面
55
54
  function goto(item: any) {
56
- if (item.pageType) {
57
- uni.navigateTo({
58
- url: `/pages/table/table?sourceId=${item.id}&pageTitle=${item.title}`,
59
- })
60
- return true
55
+ console.log(item.pageType)
56
+ switch (item.pageType) {
57
+ case "列表":
58
+ uni.navigateTo({
59
+ url: `/pages/table/table?sourceId=${item.id}&pageTitle=${item.title}`,
60
+ })
61
+ return true
62
+ break;
63
+ case "报表":
64
+ uni.navigateTo({
65
+ url: `/pages/report-table/report-table?sourceId=${item.id}&pageTitle=${item.title}`,
66
+ })
67
+ return true
68
+ break;
69
+
70
+ default:
71
+ return false
72
+ break;
61
73
  }
62
- return false
63
74
  }
64
75
 
65
76
  // 打开wd-action-sheet动作面板
@@ -0,0 +1,465 @@
1
+ <template>
2
+ <view class="w-report-table">
3
+ <!-- 表格容器 -->
4
+ <view class="table-container" :style="{height: tableHeight}">
5
+ <!-- 表格主体 -->
6
+ <scroll-view scroll-y="true" class="table-body">
7
+ <!-- 表头 -->
8
+ <view class="table-header">
9
+ <view class="table-row">
10
+ <view v-if="showCheckbox" class="checkbox-col header-cell">
11
+ <checkbox-group @change="toggleAllSelection">
12
+ <checkbox :checked="isAllSelected" />
13
+ </checkbox-group>
14
+ </view>
15
+
16
+ <template v-for="(col, colIndex) in columns" :key="colIndex">
17
+ <template v-if="col.children">
18
+ <view
19
+ :class="['header-cell', 'group-header', col.className]"
20
+ :style="{
21
+ flex: col.children.reduce((sum, c) => sum + (parseInt(c.width) || 1), 0),
22
+ 'text-align': 'center'
23
+ }"
24
+ :colspan="col.children.length"
25
+ >
26
+ {{ col.title }}
27
+ </view>
28
+ </template>
29
+ <template v-else>
30
+ <view
31
+ :class="['header-cell', col.className]"
32
+ :style="{
33
+ flex: col.width || 1,
34
+ 'text-align': col.align || 'center'
35
+ }"
36
+ >
37
+ {{ col.title }}
38
+ </view>
39
+ </template>
40
+ </template>
41
+
42
+ <view v-if="showAction" class="action-col header-cell">操作</view>
43
+ </view>
44
+ </view>
45
+
46
+ <!-- 表格内容 -->
47
+ <view class="table-body">
48
+ <view
49
+ v-for="(row, rowIndex) in paginatedData"
50
+ :key="rowIndex"
51
+ class="table-row"
52
+ :class="{'selected-row': isSelected(row)}"
53
+ >
54
+ <view v-if="showCheckbox" class="checkbox-col body-cell">
55
+ <checkbox-group @change="toggleSelection($event, row)">
56
+ <checkbox :checked="isSelected(row)" />
57
+ </checkbox-group>
58
+ </view>
59
+
60
+ <template v-for="(col, colIndex) in columns" :key="colIndex">
61
+ <template v-if="col.children">
62
+ <template v-for="(childCol, childIndex) in col.children" :key="childIndex">
63
+ <view
64
+ :class="['body-cell', childCol.className]"
65
+ :style="{
66
+ flex: childCol.width || 1,
67
+ 'text-align': childCol.align || 'center',
68
+ display: getRowSpan(row, childCol) === 0 ? 'none' : 'flex'
69
+ }"
70
+ :rowspan="getRowSpan(row, childCol)"
71
+ :colspan="getColSpan(row, childCol)"
72
+ >
73
+ {{ row[childCol.key] }}
74
+ </view>
75
+ </template>
76
+ </template>
77
+ <template v-else>
78
+ <view
79
+ :class="['body-cell', col.className]"
80
+ :style="{
81
+ flex: col.width || 1,
82
+ 'text-align': col.align || 'center',
83
+ display: getRowSpan(row, col) === 0 ? 'none' : 'flex'
84
+ }"
85
+ :rowspan="getRowSpan(row, col)"
86
+ :colspan="getColSpan(row, col)"
87
+ >
88
+ {{ row[col.key] }}
89
+ </view>
90
+ </template>
91
+ </template>
92
+
93
+ <view v-if="showAction" class="action-col body-cell">
94
+ <view class="action-btns">
95
+ <text v-for="(action, i) in actions" :key="i" @tap="handleAction(action, row)">
96
+ {{ action.label }}
97
+ </text>
98
+ </view>
99
+ </view>
100
+ </view>
101
+ </view>
102
+
103
+ <!-- 合计行 -->
104
+ <view v-if="showSummary" class="table-footer">
105
+ <view class="table-row summary-row">
106
+ <view v-if="showCheckbox" class="checkbox-col"></view>
107
+ <template v-for="(col, colIndex) in columns" :key="colIndex">
108
+ <template v-if="col.children">
109
+ <template v-for="(childCol, childIndex) in col.children" :key="childIndex">
110
+ <view
111
+ :class="['summary-cell', childCol.className]"
112
+ :style="{
113
+ flex: childCol.width || 1,
114
+ 'text-align': childCol.align || 'center'
115
+ }"
116
+ >
117
+ {{ getSummary(childCol) }}
118
+ </view>
119
+ </template>
120
+ </template>
121
+ <template v-else>
122
+ <view
123
+ :class="['summary-cell', col.className]"
124
+ :style="{
125
+ flex: col.width || 1,
126
+ 'text-align': col.align || 'center'
127
+ }"
128
+ >
129
+ {{ getSummary(col) }}
130
+ </view>
131
+ </template>
132
+ </template>
133
+ <view v-if="showAction"></view>
134
+ </view>
135
+ </view>
136
+ </scroll-view>
137
+ </view>
138
+
139
+ <!-- 分页 -->
140
+ <view v-if="showPagination" class="pagination">
141
+ <view class="page-info">
142
+ 共 {{ total }} 条记录
143
+ </view>
144
+ <view class="page-controls">
145
+ <button @click="prevPage" :disabled="currentPage === 1">上一页</button>
146
+ <text class="page-current">{{ currentPage }}/{{ pageCount }}</text>
147
+ <button @click="nextPage" :disabled="currentPage === pageCount">下一页</button>
148
+ </view>
149
+ </view>
150
+ </view>
151
+ </template>
152
+
153
+ <script setup lang="ts">
154
+ import { ref, computed } from 'vue'
155
+
156
+ interface Column {
157
+ title: string
158
+ key: string
159
+ width?: string
160
+ align?: string
161
+ className?: string
162
+ children?: Column[]
163
+ /**
164
+ * 单元格合并规则
165
+ * @param row 当前行数据
166
+ * @param index 当前行索引
167
+ * @returns 返回 true 表示参与合并,false 表示不合并
168
+ */
169
+ mergeRule?: (row: any, index: number) => boolean
170
+ summaryMethod?: (data: any[]) => string | number
171
+ colspan?: number
172
+ }
173
+
174
+ interface Action {
175
+ label: string
176
+ handler: (row: any) => void
177
+ }
178
+
179
+ const props = defineProps({
180
+ data: {
181
+ type: Array,
182
+ default: () => []
183
+ },
184
+ columns: {
185
+ type: Array as () => Column[],
186
+ default: () => []
187
+ },
188
+ actions: {
189
+ type: Array as () => Action[],
190
+ default: () => []
191
+ },
192
+ showCheckbox: {
193
+ type: Boolean,
194
+ default: false
195
+ },
196
+ showSummary: {
197
+ type: Boolean,
198
+ default: false
199
+ },
200
+ showPagination: {
201
+ type: Boolean,
202
+ default: false
203
+ },
204
+ showAction: {
205
+ type: Boolean,
206
+ default: true
207
+ },
208
+ pageSize: {
209
+ type: Number,
210
+ default: 10
211
+ },
212
+ tableHeight: {
213
+ type: String,
214
+ default: '500px'
215
+ }
216
+ })
217
+
218
+ const currentPage = ref(1)
219
+ const selectedRows = ref<any[]>([])
220
+
221
+ const paginatedData = computed(() => {
222
+ const start = (currentPage.value - 1) * props.pageSize
223
+ const end = start + props.pageSize
224
+ return props.data.slice(start, end)
225
+ })
226
+
227
+ const pageCount = computed(() => {
228
+ return Math.ceil(props.data.length / props.pageSize)
229
+ })
230
+
231
+ const total = computed(() => props.data.length)
232
+
233
+ const isAllSelected = computed(() => {
234
+ return selectedRows.value.length === props.data.length
235
+ })
236
+
237
+ const prevPage = () => {
238
+ if (currentPage.value > 1) {
239
+ currentPage.value--
240
+ }
241
+ }
242
+
243
+ const nextPage = () => {
244
+ if (currentPage.value < pageCount.value) {
245
+ currentPage.value++
246
+ }
247
+ }
248
+
249
+ const toggleSelection = (event: any, row: any) => {
250
+ const checked = event.detail.value.includes(row)
251
+ if (checked) {
252
+ selectedRows.value.push(row)
253
+ } else {
254
+ const index = selectedRows.value.findIndex(item => item === row)
255
+ if (index > -1) {
256
+ selectedRows.value.splice(index, 1)
257
+ }
258
+ }
259
+ }
260
+
261
+ const toggleAllSelection = (event: any) => {
262
+ if (event.detail.value.length > 0) {
263
+ selectedRows.value = [...props.data]
264
+ } else {
265
+ selectedRows.value = []
266
+ }
267
+ }
268
+
269
+ const isSelected = (row: any) => {
270
+ return selectedRows.value.includes(row)
271
+ }
272
+
273
+ const getRowSpan = (row: any, col: Column) => {
274
+ if (!col.mergeRule) return 1
275
+
276
+ const index = props.data.indexOf(row)
277
+ if (!col.mergeRule(row, index)) return 1
278
+
279
+ // 计算相同内容的连续行数
280
+ let span = 1
281
+ const currentValue = row[col.key]
282
+
283
+ for (let i = index + 1; i < props.data.length; i++) {
284
+ if (props.data[i][col.key] === currentValue &&
285
+ (!col.mergeRule || col.mergeRule(props.data[i], i))) {
286
+ span++
287
+ } else {
288
+ break
289
+ }
290
+ }
291
+
292
+ return span
293
+ }
294
+
295
+ const getColSpan = (row: any, col: Column) => {
296
+ if (col.colspan) return col.colspan
297
+
298
+ // 计算相同内容的连续列数
299
+ if (!col.mergeRule) return 1
300
+
301
+ let index = -1
302
+ for (let i = 0; i < props.columns.length; i++) {
303
+ if (props.columns[i] === col) {
304
+ index = i
305
+ break
306
+ }
307
+ }
308
+ if (index === -1) return 1
309
+
310
+ let span = 1
311
+ const currentValue = row[col.key]
312
+
313
+ for (let i = index + 1; i < props.columns.length; i++) {
314
+ const nextCol = props.columns[i]
315
+ if (row[nextCol.key] === currentValue &&
316
+ (!nextCol.mergeRule || nextCol.mergeRule(row, i))) {
317
+ span++
318
+ } else {
319
+ break
320
+ }
321
+ }
322
+
323
+ return span
324
+ }
325
+
326
+ const getSummary = (col: Column) => {
327
+ if (col.summaryMethod) {
328
+ return col.summaryMethod(props.data)
329
+ }
330
+
331
+ if (typeof props.data[0]?.[col.key] === 'number') {
332
+ return props.data.reduce((sum, row) => sum + (row[col.key] || 0), 0)
333
+ }
334
+
335
+ return ''
336
+ }
337
+
338
+ const handleAction = (action: Action, row: any) => {
339
+ action.handler(row)
340
+ }
341
+ </script>
342
+
343
+ <style lang="scss" scoped>
344
+ .w-report-table {
345
+ width: 100%;
346
+ display: flex;
347
+ flex-direction: column;
348
+
349
+ .table-container {
350
+ width: 100%;
351
+ overflow: hidden;
352
+
353
+ .table-body {
354
+ width: 100%;
355
+ height: 100%;
356
+
357
+ .table-header, .table-body, .table-footer {
358
+ width: 100%;
359
+ }
360
+
361
+ .table-row {
362
+ display: flex;
363
+ width: 100%;
364
+ border-bottom: 1px solid #ebeef5;
365
+ }
366
+
367
+ .header-cell, .body-cell, .summary-cell {
368
+ padding: 12px 8px;
369
+ word-break: break-word;
370
+ border-right: 1px solid #ebeef5;
371
+ display: flex;
372
+ align-items: center;
373
+ justify-content: center;
374
+ }
375
+
376
+ .group-header {
377
+ font-weight: bold;
378
+ background-color: #eef1f6;
379
+ }
380
+
381
+ .table-header {
382
+ background-color: #f5f7fa;
383
+
384
+ .header-cell {
385
+ font-weight: bold;
386
+ color: #333;
387
+ }
388
+ }
389
+
390
+ .table-body {
391
+ .table-row:hover {
392
+ background-color: #f5f7fa;
393
+ }
394
+
395
+ .selected-row {
396
+ background-color: #e6f7ff;
397
+ }
398
+ }
399
+
400
+ .checkbox-col {
401
+ flex: 0 0 50px;
402
+ }
403
+
404
+ .action-col {
405
+ flex: 0 0 120px;
406
+
407
+ .action-btns {
408
+ display: flex;
409
+ justify-content: space-around;
410
+
411
+ text {
412
+ color: #409eff;
413
+ cursor: pointer;
414
+
415
+ &:hover {
416
+ color: #66b1ff;
417
+ }
418
+ }
419
+ }
420
+ }
421
+ }
422
+ }
423
+
424
+ .pagination {
425
+ display: flex;
426
+ justify-content: space-between;
427
+ align-items: center;
428
+ margin-top: 16px;
429
+ padding: 8px 16px;
430
+ background-color: #f5f7fa;
431
+
432
+ .page-controls {
433
+ display: flex;
434
+ align-items: center;
435
+
436
+ button {
437
+ margin: 0 8px;
438
+ padding: 4px 12px;
439
+ background-color: #fff;
440
+ border: 1px solid #dcdfe6;
441
+ border-radius: 4px;
442
+ cursor: pointer;
443
+
444
+ &:disabled {
445
+ color: #c0c4cc;
446
+ cursor: not-allowed;
447
+ }
448
+ }
449
+
450
+ .page-current {
451
+ margin: 0 8px;
452
+ }
453
+ }
454
+ }
455
+
456
+ .summary-row {
457
+ background-color: #f5f7fa;
458
+ font-weight: bold;
459
+
460
+ .summary-cell {
461
+ color: #333;
462
+ }
463
+ }
464
+ }
465
+ </style>
@@ -39,7 +39,7 @@ export const selectPickerProps = {
39
39
  /** 设置 picker 内部的选项组尺寸大小 (单/复选框) */
40
40
  selectSize: String,
41
41
  /** 加载中 */
42
- loading: makeBooleanProp(false),
42
+ // loading: makeBooleanProp(false),
43
43
  /** 加载的颜色,只能使用十六进制的色值写法,且不能使用缩写 */
44
44
  loadingColor: makeStringProp('#4D80F0'),
45
45
  /** 点击遮罩是否关闭 */