muzhiyu-ui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +202 -0
  2. package/components/muzhiyu/mu-action-sheet/mu-action-sheet.vue +335 -0
  3. package/components/muzhiyu/mu-alert/mu-alert.vue +220 -0
  4. package/components/muzhiyu/mu-back-top/mu-back-top.vue +161 -0
  5. package/components/muzhiyu/mu-badge/mu-badge.vue +150 -0
  6. package/components/muzhiyu/mu-barcode/mu-barcode.vue +100 -0
  7. package/components/muzhiyu/mu-blank/mu-blank.vue +30 -0
  8. package/components/muzhiyu/mu-bottom-nav/mu-bottom-nav.vue +331 -0
  9. package/components/muzhiyu/mu-bubble/mu-bubble.vue +316 -0
  10. package/components/muzhiyu/mu-button/mu-button.vue +431 -0
  11. package/components/muzhiyu/mu-calendar/mu-calendar.vue +429 -0
  12. package/components/muzhiyu/mu-car-input/mu-car-input.vue +209 -0
  13. package/components/muzhiyu/mu-card/mu-card.vue +317 -0
  14. package/components/muzhiyu/mu-cascader/mu-cascader.vue +336 -0
  15. package/components/muzhiyu/mu-cell/mu-cell.vue +368 -0
  16. package/components/muzhiyu/mu-checkbox/mu-checkbox.vue +116 -0
  17. package/components/muzhiyu/mu-checkbox-group/mu-checkbox-group.vue +40 -0
  18. package/components/muzhiyu/mu-code-input/mu-code-input.vue +264 -0
  19. package/components/muzhiyu/mu-collapse/mu-collapse.vue +316 -0
  20. package/components/muzhiyu/mu-color-picker/mu-color-picker.vue +466 -0
  21. package/components/muzhiyu/mu-config/index.js +34 -0
  22. package/components/muzhiyu/mu-config/mu-config.vue +54 -0
  23. package/components/muzhiyu/mu-countdown/mu-countdown.vue +338 -0
  24. package/components/muzhiyu/mu-cropper/mu-cropper.vue +415 -0
  25. package/components/muzhiyu/mu-date-picker/mu-date-picker.vue +290 -0
  26. package/components/muzhiyu/mu-datetime/mu-datetime.vue +262 -0
  27. package/components/muzhiyu/mu-divider/mu-divider.vue +229 -0
  28. package/components/muzhiyu/mu-drawer/mu-drawer.vue +172 -0
  29. package/components/muzhiyu/mu-dropdown/mu-dropdown.vue +215 -0
  30. package/components/muzhiyu/mu-dropdown-top/mu-dropdown-top.vue +243 -0
  31. package/components/muzhiyu/mu-empty/mu-empty.vue +217 -0
  32. package/components/muzhiyu/mu-fab/mu-fab.vue +324 -0
  33. package/components/muzhiyu/mu-footer/mu-footer.vue +21 -0
  34. package/components/muzhiyu/mu-form/mu-form.vue +170 -0
  35. package/components/muzhiyu/mu-grid/mu-grid.vue +95 -0
  36. package/components/muzhiyu/mu-grid-item/mu-grid-item.vue +247 -0
  37. package/components/muzhiyu/mu-html/mu-html.vue +145 -0
  38. package/components/muzhiyu/mu-icon/mu-icon.vue +822 -0
  39. package/components/muzhiyu/mu-image-grid/mu-image-grid.vue +225 -0
  40. package/components/muzhiyu/mu-image-preview/mu-image-preview.vue +286 -0
  41. package/components/muzhiyu/mu-index-list/mu-index-list.vue +381 -0
  42. package/components/muzhiyu/mu-input/mu-input.vue +570 -0
  43. package/components/muzhiyu/mu-input-number/mu-input-number.vue +193 -0
  44. package/components/muzhiyu/mu-keyboard/mu-keyboard.vue +415 -0
  45. package/components/muzhiyu/mu-list/mu-list.vue +89 -0
  46. package/components/muzhiyu/mu-loading/mu-loading.vue +124 -0
  47. package/components/muzhiyu/mu-loading-page/mu-loading-page.vue +529 -0
  48. package/components/muzhiyu/mu-loadmore/mu-loadmore.vue +26 -0
  49. package/components/muzhiyu/mu-modal/mu-modal.vue +298 -0
  50. package/components/muzhiyu/mu-navbar/mu-navbar.vue +223 -0
  51. package/components/muzhiyu/mu-nomore/mu-nomore.vue +107 -0
  52. package/components/muzhiyu/mu-notice-bar/mu-notice-bar.vue +284 -0
  53. package/components/muzhiyu/mu-notify/mu-notify.vue +202 -0
  54. package/components/muzhiyu/mu-overlay/mu-overlay.vue +94 -0
  55. package/components/muzhiyu/mu-pagination/mu-pagination.vue +330 -0
  56. package/components/muzhiyu/mu-password-input/mu-password-input.vue +119 -0
  57. package/components/muzhiyu/mu-picker/mu-picker.vue +297 -0
  58. package/components/muzhiyu/mu-popup/mu-popup.vue +297 -0
  59. package/components/muzhiyu/mu-progress/mu-progress.vue +156 -0
  60. package/components/muzhiyu/mu-pull-refresh/mu-pull-refresh.vue +54 -0
  61. package/components/muzhiyu/mu-qrcode/mu-qrcode.vue +340 -0
  62. package/components/muzhiyu/mu-qrcode/qrcode.js +2237 -0
  63. package/components/muzhiyu/mu-radio/mu-radio.vue +125 -0
  64. package/components/muzhiyu/mu-radio-group/mu-radio-group.vue +37 -0
  65. package/components/muzhiyu/mu-rate/mu-rate.vue +103 -0
  66. package/components/muzhiyu/mu-search/mu-search.vue +320 -0
  67. package/components/muzhiyu/mu-section/mu-section.vue +206 -0
  68. package/components/muzhiyu/mu-select/mu-select.vue +440 -0
  69. package/components/muzhiyu/mu-share-sheet/mu-share-sheet.vue +269 -0
  70. package/components/muzhiyu/mu-sidebar/mu-sidebar.vue +304 -0
  71. package/components/muzhiyu/mu-signature/mu-signature.vue +449 -0
  72. package/components/muzhiyu/mu-skeleton/mu-skeleton.vue +225 -0
  73. package/components/muzhiyu/mu-slider/mu-slider.vue +228 -0
  74. package/components/muzhiyu/mu-space/mu-space.vue +84 -0
  75. package/components/muzhiyu/mu-steps/mu-steps.vue +311 -0
  76. package/components/muzhiyu/mu-sticky/mu-sticky.vue +57 -0
  77. package/components/muzhiyu/mu-swipe-cell/mu-swipe-cell.vue +281 -0
  78. package/components/muzhiyu/mu-swiper/mu-swiper.vue +107 -0
  79. package/components/muzhiyu/mu-switch/mu-switch.vue +99 -0
  80. package/components/muzhiyu/mu-tabbar/mu-tabbar.vue +382 -0
  81. package/components/muzhiyu/mu-table/mu-table.vue +420 -0
  82. package/components/muzhiyu/mu-tabs/mu-tabs.vue +339 -0
  83. package/components/muzhiyu/mu-tag/mu-tag.vue +65 -0
  84. package/components/muzhiyu/mu-text-ellipsis/mu-text-ellipsis.vue +54 -0
  85. package/components/muzhiyu/mu-timeline/mu-timeline.vue +166 -0
  86. package/components/muzhiyu/mu-tips/mu-tips.vue +36 -0
  87. package/components/muzhiyu/mu-toast/mu-toast.vue +151 -0
  88. package/components/muzhiyu/mu-transfer/mu-transfer.vue +114 -0
  89. package/components/muzhiyu/mu-tree/mu-tree.vue +263 -0
  90. package/components/muzhiyu/mu-upload/mu-upload.vue +415 -0
  91. package/components/muzhiyu/mu-waterfall/mu-waterfall.vue +321 -0
  92. package/components/muzhiyu/mu-watermark/mu-watermark.vue +60 -0
  93. package/index.js +83 -0
  94. package/package.json +38 -0
  95. package/utils/index.js +600 -0
  96. package/utils/request.js +265 -0
@@ -0,0 +1,420 @@
1
+ <template>
2
+ <view class="mu-table" :class="{ 'mu-table--bordered': bordered, 'mu-table--striped': striped }">
3
+ <scroll-view scroll-x class="mu-table__scroll" :show-scrollbar="false">
4
+ <view class="mu-table__inner" :style="innerStyle">
5
+ <!-- Header -->
6
+ <view class="mu-table__header">
7
+ <view
8
+ v-for="(col, ci) in columns"
9
+ :key="ci"
10
+ class="mu-table__th"
11
+ :class="{
12
+ 'mu-table__col--fixed-left': isFixedLeft(col),
13
+ 'mu-table__col--fixed-right': isFixedRight(col)
14
+ }"
15
+ :style="getColStyle(col, ci, true)"
16
+ @tap="handleSort(col, ci)"
17
+ >
18
+ <text class="mu-table__th-text" :style="{ textAlign: getAlign(col, true) }">{{ col.title }}</text>
19
+ <view v-if="col.sortable" class="mu-table__sort">
20
+ <text class="mu-table__sort-up" :class="{ active: sortCol === ci && sortDir === 'asc' }">▲</text>
21
+ <text class="mu-table__sort-down" :class="{ active: sortCol === ci && sortDir === 'desc' }">▼</text>
22
+ </view>
23
+ </view>
24
+ </view>
25
+
26
+ <!-- Body -->
27
+ <view class="mu-table__body">
28
+ <view v-if="sortedData.length === 0" class="mu-table__empty">
29
+ <slot name="empty"><text class="mu-table__empty-text">暂无数据</text></slot>
30
+ </view>
31
+ <view
32
+ v-for="(row, ri) in sortedData"
33
+ :key="ri"
34
+ class="mu-table__row"
35
+ :class="{ 'mu-table__row--striped': striped && ri % 2 === 1 }"
36
+ @tap="handleRowClick(row, ri)"
37
+ >
38
+ <view
39
+ v-for="(col, ci) in columns"
40
+ :key="ci"
41
+ class="mu-table__td"
42
+ :class="{
43
+ 'mu-table__col--fixed-left': isFixedLeft(col),
44
+ 'mu-table__col--fixed-right': isFixedRight(col)
45
+ }"
46
+ :style="getColStyle(col, ci, false, ri)"
47
+ >
48
+ <slot :name="`cell-${col.prop || col.key}`" :row="row" :index="ri">
49
+ <text class="mu-table__td-text" :style="{ textAlign: getAlign(col) }">{{ getCellValue(row, col) }}</text>
50
+ </slot>
51
+ </view>
52
+ </view>
53
+ </view>
54
+ </view>
55
+ </scroll-view>
56
+ </view>
57
+ </template>
58
+
59
+ <script setup>
60
+ import { ref, computed } from 'vue'
61
+
62
+ const props = defineProps({
63
+ columns: { type: Array, default: () => [] },
64
+ data: { type: Array, default: () => [] },
65
+ bordered: { type: Boolean, default: false },
66
+ striped: { type: Boolean, default: false },
67
+ minWidth: { type: [Number, String], default: '' },
68
+ defaultSort: { type: Object, default: () => ({ col: -1, dir: 'asc' }) }
69
+ })
70
+
71
+ const emit = defineEmits(['sort-change', 'row-click'])
72
+
73
+ const sortCol = ref(props.defaultSort.col)
74
+ const sortDir = ref(props.defaultSort.dir)
75
+
76
+ // 格式化尺寸
77
+ function formatSize(val) {
78
+ if (!val && val !== 0) return ''
79
+ if (typeof val === 'number' || /^\d+$/.test(String(val))) {
80
+ return val + 'rpx'
81
+ }
82
+ return String(val)
83
+ }
84
+
85
+ const innerStyle = computed(() => {
86
+ const s = {}
87
+ if (props.minWidth) {
88
+ s.minWidth = formatSize(props.minWidth)
89
+ }
90
+ return s
91
+ })
92
+
93
+ function isFixedLeft(col) {
94
+ return col.fixed === 'left' || col.fixed === true
95
+ }
96
+
97
+ function isFixedRight(col) {
98
+ return col.fixed === 'right'
99
+ }
100
+
101
+ function getAlign(col, isHeader = false) {
102
+ if (isHeader && col.headerAlign) return col.headerAlign
103
+ return col.align || 'left'
104
+ }
105
+
106
+ function getJustifyContent(align) {
107
+ if (align === 'center') return 'center'
108
+ if (align === 'right') return 'flex-end'
109
+ return 'flex-start'
110
+ }
111
+
112
+ // 计算各固定列的累计 left / right 偏移
113
+ const leftOffsets = computed(() => {
114
+ const offsets = []
115
+ let currentOffset = 0
116
+ props.columns.forEach((col) => {
117
+ offsets.push(currentOffset + 'rpx')
118
+ if (isFixedLeft(col)) {
119
+ const w = col.width ? (typeof col.width === 'number' ? col.width : parseInt(col.width, 10) || 160) : 160
120
+ currentOffset += w
121
+ }
122
+ })
123
+ return offsets
124
+ })
125
+
126
+ const rightOffsets = computed(() => {
127
+ const offsets = new Array(props.columns.length).fill('0rpx')
128
+ let currentOffset = 0
129
+ for (let i = props.columns.length - 1; i >= 0; i--) {
130
+ const col = props.columns[i]
131
+ offsets[i] = currentOffset + 'rpx'
132
+ if (isFixedRight(col)) {
133
+ const w = col.width ? (typeof col.width === 'number' ? col.width : parseInt(col.width, 10) || 160) : 160
134
+ currentOffset += w
135
+ }
136
+ }
137
+ return offsets
138
+ })
139
+
140
+ function getColStyle(col, index, isHeader = false, rowIndex = 0) {
141
+ const align = getAlign(col, isHeader)
142
+ const s = {
143
+ justifyContent: getJustifyContent(align)
144
+ }
145
+
146
+ // 宽度与弹性拉伸设置
147
+ if (col.width) {
148
+ const w = formatSize(col.width)
149
+ s.minWidth = w
150
+ if (col.fixed) {
151
+ s.width = w
152
+ s.flexShrink = 0
153
+ } else {
154
+ s.flex = 1
155
+ s.flexShrink = 0
156
+ }
157
+ } else {
158
+ s.flex = 1
159
+ s.minWidth = '160rpx'
160
+ s.flexShrink = 0
161
+ }
162
+
163
+ // 固定列 sticky 布局
164
+ if (isFixedLeft(col)) {
165
+ s.position = 'sticky'
166
+ s.left = leftOffsets.value[index]
167
+ s.zIndex = isHeader ? 3 : 2
168
+ } else if (isFixedRight(col)) {
169
+ s.position = 'sticky'
170
+ s.right = rightOffsets.value[index]
171
+ s.zIndex = isHeader ? 3 : 2
172
+ }
173
+
174
+ return s
175
+ }
176
+
177
+ function getCellValue(row, col) {
178
+ if (col.formatter) return col.formatter(row)
179
+ const keys = String(col.prop || col.key || '').split('.')
180
+ let val = row
181
+ for (const k of keys) {
182
+ val = (val && val[k])
183
+ }
184
+ return (val !== undefined && val !== null ? val : '')
185
+ }
186
+
187
+ const sortedData = computed(() => {
188
+ if (!props.data || !Array.isArray(props.data)) return []
189
+ if (sortCol.value < 0) return props.data
190
+ const col = props.columns[sortCol.value]
191
+ if (!col || !col.sortable) return props.data
192
+ return [...props.data].sort((a, b) => {
193
+ const va = getCellValue(a, col)
194
+ const vb = getCellValue(b, col)
195
+ const cmp = typeof va === 'number' ? va - vb : String(va).localeCompare(String(vb))
196
+ return sortDir.value === 'asc' ? cmp : -cmp
197
+ })
198
+ })
199
+
200
+ function handleSort(col, ci) {
201
+ if (!col.sortable) return
202
+ if (sortCol.value === ci) {
203
+ sortDir.value = sortDir.value === 'asc' ? 'desc' : 'asc'
204
+ } else {
205
+ sortCol.value = ci
206
+ sortDir.value = 'asc'
207
+ }
208
+ emit('sort-change', { column: col, index: ci, direction: sortDir.value })
209
+ }
210
+
211
+ function handleRowClick(row, index) {
212
+ emit('row-click', { row, index })
213
+ }
214
+ </script>
215
+
216
+ <style lang="scss" scoped>
217
+ @import "@/uni.scss";
218
+
219
+ .mu-table {
220
+ background: #ffffff;
221
+ border-radius: $mu-radius-xl;
222
+ overflow: hidden;
223
+ border: 1rpx solid $mu-border;
224
+ box-shadow: 0 2rpx 12rpx rgba(15, 23, 42, 0.04);
225
+ width: 100%;
226
+ box-sizing: border-box;
227
+
228
+ &--bordered {
229
+ .mu-table__th, .mu-table__td {
230
+ border-right: 1rpx solid rgba(226, 232, 240, 0.7);
231
+ &:last-child { border-right: none; }
232
+ }
233
+ .mu-table__row {
234
+ border-bottom: 1rpx solid rgba(226, 232, 240, 0.7);
235
+ &:last-child { border-bottom: none; }
236
+ }
237
+ }
238
+
239
+ &__scroll {
240
+ width: 100%;
241
+ white-space: nowrap;
242
+ }
243
+
244
+ &__inner {
245
+ display: inline-block;
246
+ min-width: 100%;
247
+ box-sizing: border-box;
248
+ vertical-align: top;
249
+ }
250
+
251
+ &__header {
252
+ display: flex;
253
+ background: #F8FAFC;
254
+ border-bottom: 1rpx solid $mu-border;
255
+ min-width: 100%;
256
+ }
257
+
258
+ &__th {
259
+ display: flex;
260
+ align-items: center;
261
+ padding: 20rpx 24rpx;
262
+ box-sizing: border-box;
263
+ background: #F8FAFC;
264
+
265
+ &-text {
266
+ font-size: 26rpx;
267
+ color: $mu-text-primary;
268
+ font-weight: 700;
269
+ letter-spacing: -0.5rpx;
270
+ flex: 1;
271
+ }
272
+ }
273
+
274
+ &__sort {
275
+ display: flex;
276
+ flex-direction: column;
277
+ margin-left: 8rpx;
278
+ line-height: 0.6;
279
+ flex-shrink: 0;
280
+
281
+ &-up, &-down {
282
+ font-size: 16rpx;
283
+ color: #94A3B8;
284
+ &.active {
285
+ color: #171717;
286
+ font-weight: 800;
287
+ }
288
+ }
289
+ }
290
+
291
+ &__body {
292
+ min-width: 100%;
293
+ }
294
+
295
+ &__row {
296
+ display: flex;
297
+ transition: background $mu-duration-fast $mu-ease;
298
+ border-bottom: 1rpx solid rgba(226, 232, 240, 0.6);
299
+ min-width: 100%;
300
+
301
+ &:last-child { border-bottom: none; }
302
+ &:active { background: rgba(0, 0, 0, 0.02); }
303
+ &--striped { background: #FAFAFA; }
304
+ }
305
+
306
+ &__td {
307
+ display: flex;
308
+ align-items: center;
309
+ padding: 22rpx 24rpx;
310
+ box-sizing: border-box;
311
+ background: #ffffff;
312
+
313
+ &-text {
314
+ font-size: 26rpx;
315
+ color: $mu-text-secondary;
316
+ font-weight: 400;
317
+ word-break: break-all;
318
+ flex: 1;
319
+ }
320
+ }
321
+
322
+ /* 斑马纹下的固定列背景 */
323
+ &__row--striped &__td {
324
+ background: #FAFAFA;
325
+ }
326
+
327
+ /* 粘性固定列投影增强 */
328
+ &__col--fixed-left {
329
+ box-shadow: 4rpx 0 12rpx -2rpx rgba(15, 23, 42, 0.06);
330
+ }
331
+
332
+ &__col--fixed-right {
333
+ box-shadow: -4rpx 0 12rpx -2rpx rgba(15, 23, 42, 0.06);
334
+ }
335
+
336
+ &__empty {
337
+ padding: 60rpx 24rpx;
338
+ display: flex;
339
+ align-items: center;
340
+ justify-content: center;
341
+ &-text { font-size: 26rpx; color: #94A3B8; font-weight: 500; }
342
+ }
343
+ }
344
+
345
+ .mu-dark, page.mu-dark {
346
+
347
+ .mu-table {
348
+ background: $mu-dark-bg-base;
349
+ border-color: $mu-dark-border;
350
+
351
+ &__header {
352
+ background: rgba(255, 255, 255, 0.04);
353
+ border-color: $mu-dark-border;
354
+ }
355
+ &__th {
356
+ background: rgba(255, 255, 255, 0.04);
357
+ }
358
+ &__th-text { color: $mu-dark-text-primary; }
359
+
360
+ &__row {
361
+ border-color: rgba(255, 255, 255, 0.08);
362
+ &:active { background: rgba(255, 255, 255, 0.05); }
363
+ &--striped { background: rgba(255, 255, 255, 0.02); }
364
+ }
365
+
366
+ &__td {
367
+ background: $mu-dark-bg-base;
368
+ }
369
+ &__row--striped &__td {
370
+ background: rgba(255, 255, 255, 0.02);
371
+ }
372
+ &__td-text { color: $mu-dark-text-secondary; }
373
+
374
+ &__col--fixed-left {
375
+ box-shadow: 4rpx 0 12rpx -2rpx rgba(0, 0, 0, 0.4);
376
+ }
377
+ &__col--fixed-right {
378
+ box-shadow: -4rpx 0 12rpx -2rpx rgba(0, 0, 0, 0.4);
379
+ }
380
+ }
381
+ }
382
+
383
+ @media (prefers-color-scheme: dark) {
384
+
385
+ .mu-table {
386
+ background: $mu-dark-bg-base;
387
+ border-color: $mu-dark-border;
388
+
389
+ &__header {
390
+ background: rgba(255, 255, 255, 0.04);
391
+ border-color: $mu-dark-border;
392
+ }
393
+ &__th {
394
+ background: rgba(255, 255, 255, 0.04);
395
+ }
396
+ &__th-text { color: $mu-dark-text-primary; }
397
+
398
+ &__row {
399
+ border-color: rgba(255, 255, 255, 0.08);
400
+ &:active { background: rgba(255, 255, 255, 0.05); }
401
+ &--striped { background: rgba(255, 255, 255, 0.02); }
402
+ }
403
+
404
+ &__td {
405
+ background: $mu-dark-bg-base;
406
+ }
407
+ &__row--striped &__td {
408
+ background: rgba(255, 255, 255, 0.02);
409
+ }
410
+ &__td-text { color: $mu-dark-text-secondary; }
411
+
412
+ &__col--fixed-left {
413
+ box-shadow: 4rpx 0 12rpx -2rpx rgba(0, 0, 0, 0.4);
414
+ }
415
+ &__col--fixed-right {
416
+ box-shadow: -4rpx 0 12rpx -2rpx rgba(0, 0, 0, 0.4);
417
+ }
418
+ }
419
+ }
420
+ </style>