wl-design-mobile 0.8.19 → 0.8.21

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 (101) hide show
  1. package/README.md +6 -6
  2. package/api/doc.js +25 -25
  3. package/api/x1.js +56 -56
  4. package/btn/components/lambo-info-btn.vue +123 -123
  5. package/btn/components/lambo-primary-btn.vue +117 -117
  6. package/btn/components/lambo-text-btn.vue +116 -116
  7. package/btn/lambo-btn-divide.vue +35 -120
  8. package/btn/lambo-btn-group.vue +46 -46
  9. package/btn/lambo-btn-split-line.vue +41 -41
  10. package/btn/lambo-btn.vue +68 -68
  11. package/btn/lambo-extend-btn.vue +121 -121
  12. package/btn/lambo-icon-btn.vue +82 -82
  13. package/card-item/card-row-icon.vue +71 -71
  14. package/card-item/filtrate-row.vue +73 -73
  15. package/card-item/lambo-card-footer.vue +40 -40
  16. package/card-item/lambo-card-head.vue +66 -66
  17. package/card-item/lambo-card-row.vue +59 -59
  18. package/collapse/lambo-collapse.vue +93 -93
  19. package/config/config.js +14 -14
  20. package/detail/lambo-detail-grid.vue +58 -58
  21. package/detail/lambo-detail-row.vue +59 -59
  22. package/doc/file/compoents/lambo-file-list.vue +42 -42
  23. package/doc/file/compoents/lambo-file-row.vue +77 -77
  24. package/doc/file/lambo-file-upload-collapse.vue +107 -107
  25. package/doc/file-type/file-type.js +286 -286
  26. package/doc/img/comonents/lambo-img-grid.vue +109 -109
  27. package/doc/img/lambo-img-upload-collapse.vue +107 -107
  28. package/doc/img/styles/css/index.css +3 -3
  29. package/edit/list/Lambo-edit-list.vue +87 -87
  30. package/edit/list/lambo-edit-card-group.vue +100 -100
  31. package/edit/list/styles/css/index.css +39 -39
  32. package/edit/select/lambo-edit-date-range.vue +147 -147
  33. package/edit/select/lambo-edit-date-time.vue +122 -122
  34. package/edit/select/lambo-edit-date.vue +120 -120
  35. package/edit/select/lambo-edit-input-textarea.vue +91 -91
  36. package/edit/select/lambo-edit-input.vue +91 -91
  37. package/edit/select/lambo-edit-multi-select.vue +168 -168
  38. package/edit/select/lambo-edit-search-single-select.vue +186 -186
  39. package/edit/select/lambo-edit-single-select.vue +162 -162
  40. package/edit/select/styles/css/index.css +133 -133
  41. package/flow/approval/flow-approval.vue +552 -552
  42. package/flow/comps/flow-attachment-list.vue +230 -230
  43. package/flow/comps/flow-attachment-modal.vue +194 -194
  44. package/flow/comps/flow-copy-users.vue +358 -358
  45. package/flow/comps/flow-node-card.vue +150 -150
  46. package/flow/comps/flow-node-header.vue +172 -172
  47. package/flow/comps/flow-util.js +156 -156
  48. package/flow/comps/icons/approved.svg +11 -11
  49. package/flow/comps/icons/canceled.svg +11 -11
  50. package/flow/comps/icons/rejected.svg +11 -11
  51. package/flow/comps/icons/underway.svg +11 -11
  52. package/flow/detail/flow-detail.vue +467 -467
  53. package/flow/index.js +51 -51
  54. package/flow/lambo-flow-detail.vue +912 -912
  55. package/flow/lambo-flow-edit.vue +15 -15
  56. package/flow/submit/flow-submit.vue +383 -383
  57. package/icon/lambo-required-red-star.vue +47 -47
  58. package/icon/lambo-vector-icon.vue +71 -71
  59. package/list/lambo-list.vue +412 -413
  60. package/nav/lambo-top-nav.vue +81 -81
  61. package/order/comps/icons/approved.svg +10 -10
  62. package/order/comps/icons/underway.svg +10 -10
  63. package/order/comps/order-attachment-list.vue +228 -228
  64. package/order/comps/order-attachment-modal.vue +194 -194
  65. package/order/comps/order-node-card.vue +126 -126
  66. package/order/comps/order-node-header.vue +133 -133
  67. package/order/comps/order-util.js +132 -132
  68. package/order/detail/order-detail.vue +432 -432
  69. package/order/handle/order-handle.vue +517 -517
  70. package/order/index.js +33 -33
  71. package/package.json +38 -37
  72. package/search/lambo-date-range-page.vue +196 -196
  73. package/search/lambo-date-range.vue +111 -111
  74. package/search/lambo-date.vue +105 -105
  75. package/search/lambo-input.vue +74 -74
  76. package/search/lambo-multi-select.vue +129 -129
  77. package/search/lambo-org-select-page.vue +109 -109
  78. package/search/lambo-search-box.vue +61 -61
  79. package/search/lambo-search-single-select.vue +152 -152
  80. package/search/lambo-single-select.vue +123 -123
  81. package/search/lambo-week-date-select.vue +521 -521
  82. package/search/styles/css/index.css +138 -138
  83. package/styles/base.less +77 -77
  84. package/styles/components/btn.less +7 -7
  85. package/styles/components/search.less +33 -33
  86. package/styles/components/tag.less +181 -181
  87. package/styles/index.less +4 -4
  88. package/table/lambo-ag-table.vue +227 -227
  89. package/tag/lambo-tag.vue +23 -23
  90. package/title/lambo-title1.vue +151 -151
  91. package/title/lambo-title2.vue +37 -37
  92. package/title/lambo-title3.vue +77 -77
  93. package/util/assist.js +43 -43
  94. package/util/axios/cacheconf.js +19 -19
  95. package/util/axios/index.js +11 -11
  96. package/util/axios/interceptors.js +101 -101
  97. package/util/bus.js +4 -4
  98. package/util/jssdk-sczy.js +104 -104
  99. package/util/jssdk.js +608 -565
  100. package/util/math.js +76 -76
  101. package/util/token.js +36 -36
@@ -1,413 +1,412 @@
1
- <template>
2
- <div :class="{ 'card-mode': card }">
3
- <div class="top-btn-div">
4
- <div class="opt-btn-div">
5
- <slot name="opt"></slot>
6
- </div>
7
- <div class="filter-btn-div">
8
- <slot name="filter"></slot>
9
- </div>
10
- </div>
11
- <div class="tab-btn-div">
12
- <div class="tabs-btn-div">
13
- <slot name="tabs"></slot>
14
- </div>
15
- </div>
16
- <div ref="listBox" :style="listBoxStyle" class="custom-list"
17
- :class="{ 'scrolled': scrolled && card,
18
- 'sb-classic': card && classicScrollbar > 0 }" @scroll="onListScroll">
19
- <!-- 卡片模式滚动边界: 卡片滑到顶部被裁切时, 浮现顶部投影提示层级 -->
20
- <div class="card-top-boundary"></div>
21
- <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
22
- <van-list v-model="loading" :finished="finished" :finished-text="finishedTxt" :offset="200" @load="onLoad"
23
- :error.sync="error" :error-text="errorText" :immediate-check="false">
24
- <div v-for="(item, index) in list" :key="index" class="list-item">
25
- <div class="card-item">
26
- <slot name="head" v-bind:item="item"></slot>
27
- <slot name="content" v-bind:item="item"></slot>
28
- <slot name="footer" v-bind:item="item"></slot>
29
- </div>
30
- </div>
31
- </van-list>
32
- </van-pull-refresh>
33
- </div>
34
- </div>
35
- </template>
36
- <script>
37
- import {axios} from "../util/axios/index"
38
- import {Toast} from "vant"
39
-
40
- export default {
41
- name: "LamboList",
42
- components: {},
43
- props: {
44
- heightRatio: {
45
- type: Number,
46
- default: 0.5,
47
- },
48
- url: {
49
- type: String
50
- },
51
- searchParams: {
52
- type: Object
53
- },
54
- testMode: false,
55
- /* 卡片分组模式: 灰底 + 独立白卡片。移动端统一使用卡片模式, 默认开启;
56
- 需要旧的扁平分割线模式时显式传 :card="false" */
57
- card: {
58
- type: Boolean,
59
- default: true,
60
- },
61
- },
62
- data() {
63
- return {
64
- loading: false,
65
- finished: false,
66
- finishedTxt: "",
67
- pageNum: 1, // 当前页数
68
- pageSize: 10, // 每页数据条数
69
- listHeight: '100vh',
70
- refreshing: false,
71
- offset: 0,
72
- limit: 10,
73
- list: [],
74
- error:false,
75
- errorText:'',
76
- scrolled: false, // 列表是否已离开顶部(控制滚动边界阴影)
77
- classicScrollbar: 0, // 占布局的传统滚动条宽度(桌面通常6px, 真机悬浮为0)
78
- currentRequestId: 0 // 当前请求标识符
79
- };
80
- },
81
- mounted() {
82
- this.getListHeight();
83
- this.detectClassicScrollbar();
84
- },
85
- computed: {
86
- listBoxStyle() {
87
- const style = {height: this.listHeight};
88
- // 传统滚动条会吃掉内容宽度, 把右侧 padding 收小 (8 - 滚动条宽),
89
- // 使滚动条落在 8px 右缝隙内, 卡片左右仍对称; 真机滚动条悬浮时不处理
90
- if (this.card && this.classicScrollbar > 0) {
91
- style.paddingRight = `${Math.max(0, 8 - this.classicScrollbar)}px`;
92
- }
93
- return style;
94
- }
95
- },
96
- watch: {
97
- // 模式切换后滚动条相关规则可能变化, 重新测量占宽
98
- card() {
99
- this.$nextTick(this.detectClassicScrollbar);
100
- },
101
- searchParams: {
102
- handler: function (val, oldVal) {
103
- console.log("searchParams -- val,oldVal:", {val, oldVal})
104
- console.log("searchParams -- val===oldVal:", val === oldVal)
105
- //查询时重置页码和请求标识符
106
- this.pageNum = 1
107
- this.offset = 0
108
- this.limit = 10
109
- this.list = []
110
- this.currentRequestId = 0 // 重置请求标识符
111
- this.resetScrollTop()
112
-
113
- this.onLoad()
114
- },
115
- deep: true
116
- },
117
- },
118
- methods: {
119
- onLoad() {
120
- if (this.refreshing) {
121
- this.list = [];
122
- this.refreshing = false;
123
- }
124
- this.loading = true
125
- const requestId = ++this.currentRequestId;
126
- if (this.testMode === true) {
127
- console.log("lambo-list -- onLoad -- loadData:", this.pageNum)
128
- setTimeout(() => {
129
- // 检查是否是最新的请求
130
- if (requestId !== this.currentRequestId) {
131
- return;
132
- }
133
- console.log('this.searchParams',this.searchParams)
134
- let arr = [
135
- {title: "XX市XXXX酒业商行", time: "2024-01-01", person:"01", dpt: "储配部", note: "XX工作"},
136
- {title: "XX市XXXX酒业商行", time: "2024-01-02", person:"02", dpt: "储配部", note: "XX工作"},
137
- {title: "XX市XXXX酒业商行", time: "2024-01-01", person:"01", dpt: "储配部", note: "XX工作"},
138
- {title: "XX市XXXX酒业商行", time: "2024-01-02", person:"02", dpt: "储配部", note: "XX工作"},
139
- {title: "XX市XXXX酒业商行", time: "2024-01-01", person:"01", dpt: "储配部", note: "XX工作"},
140
- {title: "XX市XXXX酒业商行", time: "2024-01-02", person:"02", dpt: "储配部", note: "XX工作"},
141
- {title: "XX市XXXX酒业商行", time: "2024-01-01", person:"01", dpt: "储配部", note: "XX工作"},
142
- {title: "XX市XXXX酒业商行", time: "2024-01-02", person:"02", dpt: "储配部", note: "XX工作"},
143
- {title: "XX市XXXX酒业商行", time: "2024-01-01", person:"01", dpt: "储配部", note: "XX工作"},
144
- {title: "XX市XXXX酒业商行", time: "2024-01-02", person:"02", dpt: "储配部", note: "XX工作"},
145
- ]
146
- this.list.push(...arr)
147
- this.finished = false
148
- this.loading = false
149
- this.offset = this.pageNum * 10
150
- this.pageNum++;
151
- // 手动触发list-change事件
152
- this.$emit('list-change', this.list);
153
- }, 1000); // 暂停1秒
154
-
155
- }else{
156
- let params = {offset: this.offset, limit: this.limit, ...this.searchParams}
157
- axios.get(this.url, {params}).then(res => {
158
- // 检查是否是最新的请求
159
- if (requestId !== this.currentRequestId) {
160
- return;
161
- }
162
- console.log("lambo-list -- onLoad -- loadData:", res)
163
- if (res && res.code === 1) {
164
- let pageData = res.data
165
- if (pageData && pageData.rows.length > 0) {
166
-
167
- for (let item of pageData.rows) {
168
- if (this.list.length < pageData.total) {
169
- this.list.push(item)
170
- this.finished = false
171
- } else {
172
- this.finished = true // 数据加载完毕
173
- }
174
- }
175
- this.offset = this.pageNum * 10
176
- this.pageNum++;
177
- this.finishedTxt = "没有更多了"
178
- // 手动触发list-change事件
179
- this.$emit('list-change', this.list);
180
- } else {
181
- this.finished = true; // 数据加载完毕
182
- // 手动触发list-change事件
183
- this.$emit('list-change', this.list);
184
- }
185
-
186
- } else {
187
- console.error("lambo-init-list -- onLoad -- 查询[" + this.title + "]数据失败", res)
188
- Toast.fail("查询[" + this.title + "]数据失败:" + res.data || '')
189
- this.error = true;
190
- this.errorText = '请求失败\n'+res.data
191
- }
192
- this.loading = false; // 加载状态结束
193
- }).catch(err => {
194
- // 检查是否是最新的请求
195
- if (requestId !== this.currentRequestId) {
196
- return;
197
- }
198
- console.error("lambo-init-list -- onLoad -- 查询[" + this.title + "]异常:", err)
199
- Toast.fail("查询[" + this.url + "]数据异常")
200
- this.error = true;
201
- this.errorText = '请求失败\n'+err
202
- this.loading = false; // 加载状态结束
203
- })
204
- }
205
- },
206
- getListHeight() {
207
- const windowHeight = window.innerHeight;
208
- this.listHeight = `${windowHeight * this.heightRatio}px`;
209
- },
210
- detectClassicScrollbar() {
211
- // 临时强制显示滚动条, 测量其是否占布局(不依赖列表当前是否溢出)
212
- const box = this.$refs.listBox;
213
- const prevOverflow = box.style.overflowY;
214
- box.style.overflowY = 'scroll';
215
- this.classicScrollbar = box.offsetWidth - box.clientWidth;
216
- box.style.overflowY = prevOverflow;
217
- },
218
- onListScroll(e) {
219
- // 扁平模式下, 列表离开顶部时在滚动容器上缘浮现阴影提示滚动边界
220
- this.scrolled = e.target.scrollTop > 0
221
- },
222
- resetScrollTop() {
223
- // 重新查询/下拉刷新时回到顶部; 赋值会触发 scroll 事件同步 scrolled
224
- if (this.$refs.listBox) {
225
- this.$refs.listBox.scrollTop = 0
226
- }
227
- },
228
- onRefresh() {
229
- console.log("lambo-init-list -- onRefresh")
230
-
231
- this.finished = false
232
- this.pageNum = 1
233
- this.offset = 0
234
- this.limit = 10
235
- this.currentRequestId = 0 // 重置请求标识符
236
- this.resetScrollTop()
237
-
238
- this.loading = true
239
- this.onLoad()
240
- }
241
- },
242
- beforeDestroy() {
243
- this.pageNum = 1
244
- this.offset = 0
245
- this.limit = 10
246
- this.list = []
247
- }
248
- };
249
- </script>
250
- <style scoped>
251
- @import "../styles/index.less";
252
-
253
- /* 滚动条: 统一窄至 3px、淡灰色, 尽量不抢眼(两种模式共用) */
254
- ::-webkit-scrollbar {
255
- width: 3px;
256
- }
257
-
258
- ::-webkit-scrollbar-track {
259
- background: transparent;
260
- }
261
-
262
- ::-webkit-scrollbar-thumb {
263
- border-radius: 2px;
264
- background-color: rgba(0, 0, 0, 0.18);
265
- }
266
-
267
- ::-webkit-scrollbar-thumb:hover {
268
- background-color: rgba(0, 0, 0, 0.3);
269
- }
270
-
271
- .custom-list {
272
- overflow-y: auto;
273
- background-color: var(--scl-white-1);
274
- padding: 0 8px 0 14px;
275
- margin-top: -6px;
276
- }
277
-
278
- /* 卡片模式滚动边界: sticky 钉在容器顶部不随内容滚动, 卡片被裁切时
279
- 用一段顶部投影暗示卡片是从白色按钮区下方滑过; 静止在顶部时完全透明 */
280
- .card-top-boundary {
281
- display: none;
282
- }
283
-
284
- .card-mode .card-top-boundary {
285
- display: block;
286
- position: -webkit-sticky;
287
- position: sticky;
288
- top: 0;
289
- z-index: 1;
290
- height: 8px;
291
- margin-bottom: -8px;
292
- background: linear-gradient(to bottom, rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0));
293
- opacity: 0;
294
- transition: opacity 0.2s;
295
- pointer-events: none;
296
- }
297
-
298
- .card-mode .custom-list.scrolled .card-top-boundary {
299
- opacity: 1;
300
- }
301
-
302
- .list-item {
303
- border-bottom: 1px solid var(--scl-gray-5);
304
- }
305
-
306
- .card-item {
307
- padding: 10px 0 0 0;
308
- background-color: var(--scl-white-1);
309
- }
310
-
311
- .top-btn-div {
312
- display: flex;
313
- flex-direction: row;
314
- flex-wrap: wrap;
315
- justify-content: flex-start;
316
- align-items: center;
317
- align-content: flex-start;
318
- background-color: var(--scl-white-1);
319
- }
320
-
321
- .tab-btn-div {
322
- display: flex;
323
- flex-direction: row;
324
- flex-wrap: wrap;
325
- justify-content: flex-start;
326
- align-items: center;
327
- align-content: flex-start;
328
- width: auto;
329
- background-color: var(--scl-white-1);
330
- }
331
-
332
- .opt-btn-div {
333
- display: flex;
334
- flex-direction: row;
335
- flex-wrap: wrap;
336
- justify-content: flex-start;
337
- align-items: center;
338
- align-content: flex-start;
339
- flex: 1;
340
- margin: 10px 10px 10px 14px;
341
- }
342
-
343
- .filter-btn-div {
344
- display: flex;
345
- flex-direction: row;
346
- flex-wrap: wrap;
347
- justify-content: flex-end;
348
- align-items: center;
349
- align-content: flex-end;
350
- width: 100px;
351
- margin: 10px 14px 10px 10px;
352
- }
353
-
354
- .tabs-btn-div {
355
- width: -webkit-fill-available;
356
-
357
- }
358
-
359
- /* 控制 .filter-btn-div 内的元素的左边距为 6px */
360
- .filter-btn-div > * {
361
- margin-left: 6px;
362
- }
363
-
364
- /* 控制 .opt-btn-div 内的元素的右边距为 6px */
365
- .opt-btn-div > * {
366
- margin-right: 6px;
367
- }
368
-
369
- /* ===== 卡片分组模式(card=true): 露出页面灰底, 每项为独立白卡片, 靠灰色缝隙分组 ===== */
370
- .card-mode .custom-list {
371
- background-color: transparent;
372
- /* 卡片距屏幕 8px, 卡片内边距 6px, 文字合计 14px 与上方按钮对齐 */
373
- padding: 0 8px;
374
- /* 收回默认的 -6px, 第一张卡片与标题间距和卡间缝隙保持一致 */
375
- margin-top: 0;
376
- }
377
-
378
- /* Firefox 不识别 ::-webkit-scrollbar, 仅对它启用细滚动条;
379
- 切不可直接写 scrollbar-width: thin —— Chrome 中该标准属性会覆盖
380
- ::-webkit-scrollbar 的 6px, 而 thin 桌面实际渲染为 11px, 导致右缝错位 */
381
- @supports not selector(::-webkit-scrollbar) {
382
- .custom-list {
383
- scrollbar-width: thin;
384
- scrollbar-color: rgba(0, 0, 0, 0.18) transparent;
385
- }
386
- }
387
-
388
- .card-mode .list-item {
389
- margin: 8px 0;
390
- border-bottom: none;
391
- border-radius: 6px;
392
- background-color: var(--scl-white-1);
393
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
394
- }
395
-
396
- .card-mode .card-item {
397
- /* 卡片内容距卡片边缘 6px(上下左右统一) */
398
- padding: 6px;
399
- }
400
-
401
- /* 无按钮组时, 末位信息行自带的 8px 下边距收回, 由卡片 padding 统一兜底;
402
- 有按钮组时最后一行不是 last-child, 到按钮的 8px 间距自然保留。
403
- slot 内容不带本组件 scope, 用 /deep/ 穿透。
404
- 注意: 无操作按钮时应在业务侧 v-if 掉整个按钮组, 不要留空组 */
405
- .card-mode .card-item /deep/ > :last-child .title-tb {
406
- margin-bottom: 0;
407
- }
408
-
409
- /* 按钮组自带 0 14px 内边距, 卡片内收回, 与信息行左对齐 */
410
- .card-mode .card-item /deep/ .button-group {
411
- padding: 0;
412
- }
413
- </style>
1
+ <template>
2
+ <div :class="{ 'card-mode': card }">
3
+ <div class="top-btn-div">
4
+ <div class="opt-btn-div">
5
+ <slot name="opt"></slot>
6
+ </div>
7
+ <div class="filter-btn-div">
8
+ <slot name="filter"></slot>
9
+ </div>
10
+ </div>
11
+ <div class="tab-btn-div">
12
+ <div class="tabs-btn-div">
13
+ <slot name="tabs"></slot>
14
+ </div>
15
+ </div>
16
+ <div ref="listBox" :style="listBoxStyle" class="custom-list"
17
+ :class="{ 'scrolled': scrolled && card,
18
+ 'sb-classic': card && classicScrollbar > 0 }" @scroll="onListScroll">
19
+ <!-- 卡片模式滚动边界: 卡片滑到顶部被裁切时, 浮现顶部投影提示层级 -->
20
+ <div class="card-top-boundary"></div>
21
+ <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
22
+ <van-list v-model="loading" :finished="finished" :finished-text="finishedTxt" :offset="200" @load="onLoad"
23
+ :error.sync="error" :error-text="errorText" :immediate-check="false">
24
+ <div v-for="(item, index) in list" :key="index" class="list-item">
25
+ <div class="card-item">
26
+ <slot name="head" v-bind:item="item"></slot>
27
+ <slot name="content" v-bind:item="item"></slot>
28
+ <slot name="footer" v-bind:item="item"></slot>
29
+ </div>
30
+ </div>
31
+ </van-list>
32
+ </van-pull-refresh>
33
+ </div>
34
+ </div>
35
+ </template>
36
+ <script>
37
+ import {axios} from "../util/axios/index"
38
+ import {Toast} from "vant"
39
+
40
+ export default {
41
+ name: "LamboList",
42
+ components: {},
43
+ props: {
44
+ heightRatio: {
45
+ type: Number,
46
+ default: 0.5,
47
+ },
48
+ url: {
49
+ type: String
50
+ },
51
+ searchParams: {
52
+ type: Object
53
+ },
54
+ testMode: false,
55
+ /* 卡片分组模式: 灰底 + 独立白卡片(默认扁平分割线模式, 保持向后兼容) */
56
+ card: {
57
+ type: Boolean,
58
+ default: false,
59
+ },
60
+ },
61
+ data() {
62
+ return {
63
+ loading: false,
64
+ finished: false,
65
+ finishedTxt: "",
66
+ pageNum: 1, // 当前页数
67
+ pageSize: 10, // 每页数据条数
68
+ listHeight: '100vh',
69
+ refreshing: false,
70
+ offset: 0,
71
+ limit: 10,
72
+ list: [],
73
+ error:false,
74
+ errorText:'',
75
+ scrolled: false, // 列表是否已离开顶部(控制滚动边界阴影)
76
+ classicScrollbar: 0, // 占布局的传统滚动条宽度(桌面通常6px, 真机悬浮为0)
77
+ currentRequestId: 0 // 当前请求标识符
78
+ };
79
+ },
80
+ mounted() {
81
+ this.getListHeight();
82
+ this.detectClassicScrollbar();
83
+ },
84
+ computed: {
85
+ listBoxStyle() {
86
+ const style = {height: this.listHeight};
87
+ // 传统滚动条会吃掉内容宽度, 把右侧 padding 收小 (8 - 滚动条宽),
88
+ // 使滚动条落在 8px 右缝隙内, 卡片左右仍对称; 真机滚动条悬浮时不处理
89
+ if (this.card && this.classicScrollbar > 0) {
90
+ style.paddingRight = `${Math.max(0, 8 - this.classicScrollbar)}px`;
91
+ }
92
+ return style;
93
+ }
94
+ },
95
+ watch: {
96
+ // 模式切换后滚动条相关规则可能变化, 重新测量占宽
97
+ card() {
98
+ this.$nextTick(this.detectClassicScrollbar);
99
+ },
100
+ searchParams: {
101
+ handler: function (val, oldVal) {
102
+ console.log("searchParams -- val,oldVal:", {val, oldVal})
103
+ console.log("searchParams -- val===oldVal:", val === oldVal)
104
+ //查询时重置页码和请求标识符
105
+ this.pageNum = 1
106
+ this.offset = 0
107
+ this.limit = 10
108
+ this.list = []
109
+ this.currentRequestId = 0 // 重置请求标识符
110
+ this.resetScrollTop()
111
+
112
+ this.onLoad()
113
+ },
114
+ deep: true
115
+ },
116
+ },
117
+ methods: {
118
+ onLoad() {
119
+ if (this.refreshing) {
120
+ this.list = [];
121
+ this.refreshing = false;
122
+ }
123
+ this.loading = true
124
+ const requestId = ++this.currentRequestId;
125
+ if (this.testMode === true) {
126
+ console.log("lambo-list -- onLoad -- loadData:", this.pageNum)
127
+ setTimeout(() => {
128
+ // 检查是否是最新的请求
129
+ if (requestId !== this.currentRequestId) {
130
+ return;
131
+ }
132
+ console.log('this.searchParams',this.searchParams)
133
+ let arr = [
134
+ {title: "XX市XXXX酒业商行", time: "2024-01-01", person:"01", dpt: "储配部", note: "XX工作"},
135
+ {title: "XX市XXXX酒业商行", time: "2024-01-02", person:"02", dpt: "储配部", note: "XX工作"},
136
+ {title: "XX市XXXX酒业商行", time: "2024-01-01", person:"01", dpt: "储配部", note: "XX工作"},
137
+ {title: "XX市XXXX酒业商行", time: "2024-01-02", person:"02", dpt: "储配部", note: "XX工作"},
138
+ {title: "XX市XXXX酒业商行", time: "2024-01-01", person:"01", dpt: "储配部", note: "XX工作"},
139
+ {title: "XX市XXXX酒业商行", time: "2024-01-02", person:"02", dpt: "储配部", note: "XX工作"},
140
+ {title: "XX市XXXX酒业商行", time: "2024-01-01", person:"01", dpt: "储配部", note: "XX工作"},
141
+ {title: "XX市XXXX酒业商行", time: "2024-01-02", person:"02", dpt: "储配部", note: "XX工作"},
142
+ {title: "XX市XXXX酒业商行", time: "2024-01-01", person:"01", dpt: "储配部", note: "XX工作"},
143
+ {title: "XX市XXXX酒业商行", time: "2024-01-02", person:"02", dpt: "储配部", note: "XX工作"},
144
+ ]
145
+ this.list.push(...arr)
146
+ this.finished = false
147
+ this.loading = false
148
+ this.offset = this.pageNum * 10
149
+ this.pageNum++;
150
+ // 手动触发list-change事件
151
+ this.$emit('list-change', this.list);
152
+ }, 1000); // 暂停1秒
153
+
154
+ }else{
155
+ let params = {offset: this.offset, limit: this.limit, ...this.searchParams}
156
+ axios.get(this.url, {params}).then(res => {
157
+ // 检查是否是最新的请求
158
+ if (requestId !== this.currentRequestId) {
159
+ return;
160
+ }
161
+ console.log("lambo-list -- onLoad -- loadData:", res)
162
+ if (res && res.code === 1) {
163
+ let pageData = res.data
164
+ if (pageData && pageData.rows.length > 0) {
165
+
166
+ for (let item of pageData.rows) {
167
+ if (this.list.length < pageData.total) {
168
+ this.list.push(item)
169
+ this.finished = false
170
+ } else {
171
+ this.finished = true // 数据加载完毕
172
+ }
173
+ }
174
+ this.offset = this.pageNum * 10
175
+ this.pageNum++;
176
+ this.finishedTxt = "没有更多了"
177
+ // 手动触发list-change事件
178
+ this.$emit('list-change', this.list);
179
+ } else {
180
+ this.finished = true; // 数据加载完毕
181
+ // 手动触发list-change事件
182
+ this.$emit('list-change', this.list);
183
+ }
184
+
185
+ } else {
186
+ console.error("lambo-init-list -- onLoad -- 查询[" + this.title + "]数据失败", res)
187
+ Toast.fail("查询[" + this.title + "]数据失败:" + res.data || '')
188
+ this.error = true;
189
+ this.errorText = '请求失败\n'+res.data
190
+ }
191
+ this.loading = false; // 加载状态结束
192
+ }).catch(err => {
193
+ // 检查是否是最新的请求
194
+ if (requestId !== this.currentRequestId) {
195
+ return;
196
+ }
197
+ console.error("lambo-init-list -- onLoad -- 查询[" + this.title + "]异常:", err)
198
+ Toast.fail("查询[" + this.url + "]数据异常")
199
+ this.error = true;
200
+ this.errorText = '请求失败\n'+err
201
+ this.loading = false; // 加载状态结束
202
+ })
203
+ }
204
+ },
205
+ getListHeight() {
206
+ const windowHeight = window.innerHeight;
207
+ this.listHeight = `${windowHeight * this.heightRatio}px`;
208
+ },
209
+ detectClassicScrollbar() {
210
+ // 临时强制显示滚动条, 测量其是否占布局(不依赖列表当前是否溢出)
211
+ const box = this.$refs.listBox;
212
+ const prevOverflow = box.style.overflowY;
213
+ box.style.overflowY = 'scroll';
214
+ this.classicScrollbar = box.offsetWidth - box.clientWidth;
215
+ box.style.overflowY = prevOverflow;
216
+ },
217
+ onListScroll(e) {
218
+ // 扁平模式下, 列表离开顶部时在滚动容器上缘浮现阴影提示滚动边界
219
+ this.scrolled = e.target.scrollTop > 0
220
+ },
221
+ resetScrollTop() {
222
+ // 重新查询/下拉刷新时回到顶部; 赋值会触发 scroll 事件同步 scrolled
223
+ if (this.$refs.listBox) {
224
+ this.$refs.listBox.scrollTop = 0
225
+ }
226
+ },
227
+ onRefresh() {
228
+ console.log("lambo-init-list -- onRefresh")
229
+
230
+ this.finished = false
231
+ this.pageNum = 1
232
+ this.offset = 0
233
+ this.limit = 10
234
+ this.currentRequestId = 0 // 重置请求标识符
235
+ this.resetScrollTop()
236
+
237
+ this.loading = true
238
+ this.onLoad()
239
+ }
240
+ },
241
+ beforeDestroy() {
242
+ this.pageNum = 1
243
+ this.offset = 0
244
+ this.limit = 10
245
+ this.list = []
246
+ }
247
+ };
248
+ </script>
249
+ <style scoped>
250
+ @import "../styles/index.less";
251
+
252
+ /* 滚动条: 统一窄至 3px、淡灰色, 尽量不抢眼(两种模式共用) */
253
+ ::-webkit-scrollbar {
254
+ width: 3px;
255
+ }
256
+
257
+ ::-webkit-scrollbar-track {
258
+ background: transparent;
259
+ }
260
+
261
+ ::-webkit-scrollbar-thumb {
262
+ border-radius: 2px;
263
+ background-color: rgba(0, 0, 0, 0.18);
264
+ }
265
+
266
+ ::-webkit-scrollbar-thumb:hover {
267
+ background-color: rgba(0, 0, 0, 0.3);
268
+ }
269
+
270
+ .custom-list {
271
+ overflow-y: auto;
272
+ background-color: var(--scl-white-1);
273
+ padding: 0 8px 0 14px;
274
+ margin-top: -6px;
275
+ }
276
+
277
+ /* 卡片模式滚动边界: sticky 钉在容器顶部不随内容滚动, 卡片被裁切时
278
+ 用一段顶部投影暗示卡片是从白色按钮区下方滑过; 静止在顶部时完全透明 */
279
+ .card-top-boundary {
280
+ display: none;
281
+ }
282
+
283
+ .card-mode .card-top-boundary {
284
+ display: block;
285
+ position: -webkit-sticky;
286
+ position: sticky;
287
+ top: 0;
288
+ z-index: 1;
289
+ height: 8px;
290
+ margin-bottom: -8px;
291
+ background: linear-gradient(to bottom, rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0));
292
+ opacity: 0;
293
+ transition: opacity 0.2s;
294
+ pointer-events: none;
295
+ }
296
+
297
+ .card-mode .custom-list.scrolled .card-top-boundary {
298
+ opacity: 1;
299
+ }
300
+
301
+ .list-item {
302
+ border-bottom: 1px solid var(--scl-gray-5);
303
+ }
304
+
305
+ .card-item {
306
+ padding: 10px 0 0 0;
307
+ background-color: var(--scl-white-1);
308
+ }
309
+
310
+ .top-btn-div {
311
+ display: flex;
312
+ flex-direction: row;
313
+ flex-wrap: wrap;
314
+ justify-content: flex-start;
315
+ align-items: center;
316
+ align-content: flex-start;
317
+ background-color: var(--scl-white-1);
318
+ }
319
+
320
+ .tab-btn-div {
321
+ display: flex;
322
+ flex-direction: row;
323
+ flex-wrap: wrap;
324
+ justify-content: flex-start;
325
+ align-items: center;
326
+ align-content: flex-start;
327
+ width: auto;
328
+ background-color: var(--scl-white-1);
329
+ }
330
+
331
+ .opt-btn-div {
332
+ display: flex;
333
+ flex-direction: row;
334
+ flex-wrap: wrap;
335
+ justify-content: flex-start;
336
+ align-items: center;
337
+ align-content: flex-start;
338
+ flex: 1;
339
+ margin: 10px 10px 10px 14px;
340
+ }
341
+
342
+ .filter-btn-div {
343
+ display: flex;
344
+ flex-direction: row;
345
+ flex-wrap: wrap;
346
+ justify-content: flex-end;
347
+ align-items: center;
348
+ align-content: flex-end;
349
+ width: 100px;
350
+ margin: 10px 14px 10px 10px;
351
+ }
352
+
353
+ .tabs-btn-div {
354
+ width: -webkit-fill-available;
355
+
356
+ }
357
+
358
+ /* 控制 .filter-btn-div 内的元素的左边距为 6px */
359
+ .filter-btn-div > * {
360
+ margin-left: 6px;
361
+ }
362
+
363
+ /* 控制 .opt-btn-div 内的元素的右边距为 6px */
364
+ .opt-btn-div > * {
365
+ margin-right: 6px;
366
+ }
367
+
368
+ /* ===== 卡片分组模式(card=true): 露出页面灰底, 每项为独立白卡片, 靠灰色缝隙分组 ===== */
369
+ .card-mode .custom-list {
370
+ background-color: transparent;
371
+ /* 卡片距屏幕 8px, 卡片内边距 6px, 文字合计 14px 与上方按钮对齐 */
372
+ padding: 0 8px;
373
+ /* 收回默认的 -6px, 第一张卡片与标题间距和卡间缝隙保持一致 */
374
+ margin-top: 0;
375
+ }
376
+
377
+ /* Firefox 不识别 ::-webkit-scrollbar, 仅对它启用细滚动条;
378
+ 切不可直接写 scrollbar-width: thin —— Chrome 中该标准属性会覆盖
379
+ ::-webkit-scrollbar 的 6px, 而 thin 桌面实际渲染为 11px, 导致右缝错位 */
380
+ @supports not selector(::-webkit-scrollbar) {
381
+ .custom-list {
382
+ scrollbar-width: thin;
383
+ scrollbar-color: rgba(0, 0, 0, 0.18) transparent;
384
+ }
385
+ }
386
+
387
+ .card-mode .list-item {
388
+ margin: 8px 0;
389
+ border-bottom: none;
390
+ border-radius: 6px;
391
+ background-color: var(--scl-white-1);
392
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
393
+ }
394
+
395
+ .card-mode .card-item {
396
+ /* 卡片内容距卡片边缘 6px(上下左右统一) */
397
+ padding: 6px;
398
+ }
399
+
400
+ /* 无按钮组时, 末位信息行自带的 8px 下边距收回, 由卡片 padding 统一兜底;
401
+ 有按钮组时最后一行不是 last-child, 到按钮的 8px 间距自然保留。
402
+ slot 内容不带本组件 scope, 用 /deep/ 穿透。
403
+ 注意: 无操作按钮时应在业务侧 v-if 掉整个按钮组, 不要留空组 */
404
+ .card-mode .card-item /deep/ > :last-child .title-tb {
405
+ margin-bottom: 0;
406
+ }
407
+
408
+ /* 按钮组自带 0 14px 内边距, 卡片内收回, 与信息行左对齐 */
409
+ .card-mode .card-item /deep/ .button-group {
410
+ padding: 0;
411
+ }
412
+ </style>