@kaiyinchem/ky-uniui 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,339 @@
1
+ <template>
2
+ <view class="ky-fetch-wrap">
3
+
4
+ <view v-show="loadState === 1" class="ky-fetch-content">
5
+ <slot v-if="!noLoadmore" :list="list"></slot>
6
+ <slot v-else :data="data"></slot>
7
+ <view v-if="loadState === 1 && !noLoadmore" class="ky-fetch-more-nodata" @click="reload">
8
+ <text class="ky-fetch-more-tips">{{ tips }}</text>
9
+ <image v-if="!noMore && !loadError" class="ky-fetch-more-loading" src="/static/img/load.gif"></image>
10
+ </view>
11
+ </view>
12
+
13
+ <view v-if="loadState === 0 || !loadState" :class="{ isRelative }" class="ky-fetch-loading">
14
+ <ky-loading v-if="!$slots.loading"></ky-loading>
15
+ <slot name="loading"></slot>
16
+ </view>
17
+
18
+ <view v-if="loadState !== 0 && loadState !== 1" class="ky-fetch-error">
19
+
20
+ <view v-if="!$slots.nodata || !$slots.error" class="ky-fetch-error-tip" @click="reload">
21
+ <template v-if="!noIcon">
22
+ <image v-if="loadState === -1" class="ky-fetch-err-img" src="@/static/img/nodata.png"></image>
23
+ <image v-else-if="loadState === -2" class="ky-fetch-err-img" src="@/static/img/request_error.png"></image>
24
+ <image v-else class="ky-fetch-err-img" src="@/static/img/network_error.png"></image>
25
+ </template>
26
+ <text class="ky-fetch-err-txt">{{ msg || noDataMsg || (loadState === -1 ? '暂无相关内容' : '加载失败,请点击重试') }}</text>
27
+ </view>
28
+
29
+ <view v-if="$slots.nodata && loadState === -1" class="ky-fetch-error-tip">
30
+ <slot name="nodata" ></slot>
31
+ </view>
32
+
33
+ <view v-if="$slots.error && loadState === -2" class="ky-fetch-error-tip">
34
+ <slot name="error" ></slot>
35
+ </view>
36
+
37
+ </view>
38
+
39
+ </view>
40
+ </template>
41
+
42
+ <script>
43
+ export default {
44
+ emits: ['load', 'error', 'all'],
45
+ props: {
46
+ // 是否加载列表
47
+ noLoadmore: {
48
+ type: Boolean,
49
+ default: false
50
+ },
51
+ // api地址
52
+ api: {
53
+ type: String,
54
+ default: '',
55
+ required: true,
56
+ },
57
+ // status 1:请求成功, -1:暂无数据, -2:请求失败, -3: 无网络
58
+ status: {
59
+ type: Number,
60
+ default: 0
61
+ },
62
+ // 筛选条件
63
+ condition: {
64
+ type: Object,
65
+ default: () => {}
66
+ },
67
+ // 不主动执行请求
68
+ manual: {
69
+ type: Boolean,
70
+ default: false
71
+ },
72
+ // 是否相对定位
73
+ isRelative: {
74
+ type: Boolean,
75
+ default: false,
76
+ },
77
+ // 是否请求完成就隐藏loading
78
+ autoHideLoading: {
79
+ type: Boolean,
80
+ default: true
81
+ },
82
+ // 是否返回合并后的数据
83
+ concat: {
84
+ type: Boolean,
85
+ default: true
86
+ },
87
+ noDataMsg: {
88
+ type: String,
89
+ default: '',
90
+ },
91
+ errMsg: {
92
+ type: String,
93
+ default: '',
94
+ },
95
+ // 无内容或者错误时不显示图标
96
+ noIcon: {
97
+ type: Boolean,
98
+ default: false
99
+ }
100
+ },
101
+ data() {
102
+ return {
103
+ noMore: false,
104
+ loadState: 0,
105
+ filter: {
106
+ page: 1,
107
+ size: 10
108
+ },
109
+ data: {},
110
+ list: [],
111
+ tips: '没有更多了',
112
+ loadError: false,
113
+ loading: false,
114
+ isChangeCondition: false,
115
+ msg: '',
116
+ }
117
+ },
118
+ watch: {
119
+ status(v) {
120
+ this.loadState = v
121
+ },
122
+ },
123
+ mounted() {
124
+ if (!this.manual) {
125
+ this.init()
126
+ }
127
+ this.msg = this.errMsg
128
+ this.loadState = this.status
129
+ this.setFilters(this.condition)
130
+ },
131
+ methods: {
132
+ async init() {
133
+ this.filter.page = 1
134
+ this.list = []
135
+ return await this.getList()
136
+ },
137
+ // 为了条件查询后使用的, noReload是否设置loadState为1
138
+ refresh(noReload) {
139
+ this.filter.page = 1
140
+ this.list = []
141
+ // 不延迟的话,condition里面的东西拿不到
142
+ setTimeout(() => {
143
+ this.getList(noReload)
144
+ })
145
+ },
146
+ reload() {
147
+ if (this.loading || this.noMore) {
148
+ return
149
+ }
150
+ this.loading = false
151
+ this.getList()
152
+ },
153
+ hideLoading() {
154
+ this.loadState = 1
155
+ },
156
+ setErrMsg(msg) {
157
+ this.msg = msg
158
+ this.loadState = -2
159
+ },
160
+ setFilters(data = {}) {
161
+ const obj = { ...this.filter, ...data, }
162
+ for (let a in obj) {
163
+ if (!obj[a] && typeof obj[a] !== 'number') {
164
+ delete obj[a]
165
+ }
166
+ }
167
+ this.filter = obj
168
+ },
169
+ async getList(noReload) {
170
+ this.loading = true
171
+ this.setFilters(this.condition)
172
+ let rows = []
173
+ const params = { ...this.filter }
174
+ const { page, size } = params
175
+
176
+ if (page === 1 && !noReload) {
177
+ this.loadState = 0
178
+ }
179
+
180
+ if (params.requestBodyDic && !this.noLoadmore) {
181
+ params.requestBodyDic.page = page
182
+ params.requestBodyDic.size = size
183
+ delete params.page
184
+ delete params.size
185
+ }
186
+
187
+ if (this.noLoadmore) {
188
+ delete params.page
189
+ delete params.size
190
+ }
191
+
192
+ try {
193
+ const apiUrl = this.api.split('.')
194
+ const res = await this.$api[apiUrl[0]][apiUrl[1]](params)
195
+ const { data, lists, list, count } = res
196
+
197
+ if (this.noLoadmore) {
198
+ this.data = data || res
199
+ this.loadState = 1
200
+ this.$emit('load', this.data)
201
+ return this.data
202
+ }
203
+
204
+ if (!data) {
205
+ rows = lists || list || []
206
+ } else {
207
+ rows = Array.isArray(data) ? data : data.lists
208
+ }
209
+
210
+ if (Array.isArray(res)) {
211
+ rows = res
212
+ }
213
+
214
+ const newList = rows
215
+ const isNoData = !newList.length && page === 1
216
+
217
+ this.list = this.concat ? [...this.list, ...newList] : newList
218
+
219
+ this.noMore = newList.length < size
220
+
221
+ if (data && data.count) {
222
+ this.noMore = this.list.length >= data.count
223
+ }
224
+
225
+ if (count) {
226
+ this.noMore = this.list.length >= count
227
+ }
228
+
229
+ this.tips = this.noMore ? '没有更多了' : '加载中...'
230
+
231
+ if (this.autoHideLoading) {
232
+ this.loadState = isNoData ? -1 : 1
233
+ }
234
+
235
+ this.loadError = false
236
+ this.$emit('load', this.list)
237
+
238
+ if (page === 1 && data) {
239
+ const obj = { ...data }
240
+ delete obj.lists
241
+ this.$emit('all', obj)
242
+ }
243
+
244
+ } catch(e) {
245
+ if (page === 1) {
246
+ this.loadState = -2
247
+ }
248
+ if (e.code === 504) {
249
+ this.loadState = -3
250
+ }
251
+ this.tips = e.msg || '加载失败,请点击重试'
252
+ this.msg = this.tips
253
+ this.loadError = true
254
+ this.$emit('error', e)
255
+ return Promise.reject(e)
256
+ } finally {
257
+ this.loading = false
258
+ }
259
+ },
260
+ loadMore() {
261
+ if (this.noMore) {
262
+ return
263
+ }
264
+ if (this.loading) {
265
+ return
266
+ }
267
+ if (this.loadError) {
268
+ return
269
+ }
270
+ this.filter.page ++
271
+ this.getList()
272
+ }
273
+ },
274
+ }
275
+ </script>
276
+
277
+ <style scoped lang="scss">
278
+ .ky-fetch-more-nodata {
279
+ text-align: center;
280
+ padding: 24rpx 0;
281
+ display: flex;
282
+ align-items: center;
283
+ justify-content: center;
284
+ .ky-fetch-more-tips {
285
+ font-size: 24rpx;
286
+ color: var(--color-gray);
287
+ }
288
+ .ky-fetch-more-loading {
289
+ width: 40rpx;
290
+ height: 40rpx;
291
+ display: inline-block;
292
+ margin-left: 12rpx;
293
+ }
294
+ }
295
+ .ky-fetch-loading {
296
+ position: absolute;
297
+ top: 0;
298
+ left: 0;
299
+ right: 0;
300
+ bottom: 0;
301
+ margin: auto;
302
+ display: flex;
303
+ justify-content: center;
304
+ align-items: center;
305
+ z-index: 0;
306
+ padding: 24rpx;
307
+ &.isRelative {
308
+ position: relative;
309
+ min-height: 100rpx;
310
+ }
311
+ }
312
+ .ky-fetch-error {
313
+ position: absolute;
314
+ top: 24rpx;
315
+ left: 24rpx;
316
+ right: 24rpx;
317
+ bottom: 24rpx;
318
+ margin: auto;
319
+ display: flex;
320
+ justify-content: center;
321
+ align-items: center;
322
+ z-index: 0;
323
+ .ky-fetch-error-tip {
324
+ display: flex;
325
+ align-items: center;
326
+ justify-content: center;
327
+ flex-direction: column;
328
+ }
329
+ .ky-fetch-err-img {
330
+ width: 500rpx;
331
+ height: 333rpx;
332
+ }
333
+ .ky-fetch-err-txt {
334
+ font-size: 24rpx;
335
+ color: var(--color-gray);
336
+ word-break: break-all;
337
+ }
338
+ }
339
+ </style>
@@ -0,0 +1,292 @@
1
+ <template>
2
+ <view class="top-bar">
3
+ <!--noSpace为false时可以把页面内容顶下来-->
4
+ <view v-if="!noSpace" class="space">
5
+ <view v-if="!noBar" class="status-height"></view>
6
+ <view v-if="!noMenuBtn" :style="{ height: menuButtonTop + 'px' }" class="menu-height"></view>
7
+ <view :style="{ height: height + 'px' }" class="nav-height"></view>
8
+ </view>
9
+ <!--头部-->
10
+ <view class="tb-main">
11
+ <view class="tb-bg" :class="{ blur }" :style="{ opacity, background: noBg ? 'transparent' : bgColor }"></view>
12
+ <!--电量条高度-->
13
+ <view v-if="!noBar" class="status-height"></view>
14
+ <view v-if="!noMenuBtn" :style="{ height: menuButtonTop + 'px' }" class="menu-height"></view>
15
+ <!--end 电量条高度-->
16
+ <view :class="{ 'white-color': transparent && !isScrollTo }" class="top-nav" :style="{ height: height + 'px' }">
17
+
18
+ <view class="tn-left">
19
+ <text v-if="!noBack" class="iconfont inline-block" style="transform: rotate(180deg);" @click="goBack">&#xe62a;</text>
20
+ <slot name="left"></slot>
21
+ </view>
22
+
23
+ <view :class="{ hasCenter: $slots.center }" class="tn-center">
24
+ <text v-if="title && !$slots.center" :style="{ opacity }">{{ title }}</text>
25
+ <slot name="center"></slot>
26
+ </view>
27
+
28
+ <view class="tn-right">
29
+ <text v-if="right" @click="onRightClick">{{ right }}</text>
30
+ <slot name="right"></slot>
31
+ </view>
32
+ </view>
33
+ </view>
34
+ <!--电量条背景-->
35
+ </view>
36
+ </template>
37
+
38
+ <script>
39
+ const isDark = uni.getSystemInfoSync().theme === 'dark'
40
+
41
+ export default {
42
+ emits: ['rightClick', 'scrollTo'],
43
+ props: {
44
+ /**
45
+ * 标题
46
+ */
47
+ title: {
48
+ type: String,
49
+ default: ''
50
+ },
51
+ /**
52
+ * 背景颜色
53
+ */
54
+ background: {
55
+ type: String,
56
+ default: isDark ? 'rgba(55,55,55, 0.9)' : 'rgba(255,255,255, 0.9)'
57
+ },
58
+ /**
59
+ * 右侧文字
60
+ */
61
+ right: {
62
+ type: String,
63
+ default: ''
64
+ },
65
+ /**
66
+ * 是否显示后退按钮
67
+ */
68
+ noBack: {
69
+ type: Boolean,
70
+ default: false
71
+ },
72
+ /**
73
+ * 是否把导航部分的间距顶下来
74
+ */
75
+ noSpace: {
76
+ type: Boolean,
77
+ default: false
78
+ },
79
+ /**
80
+ * 不显示statusBar高度
81
+ */
82
+ noBar: {
83
+ type: Boolean,
84
+ default: false
85
+ },
86
+ /**
87
+ * 不显示小程序胶囊高度
88
+ */
89
+ noMenuBtn: {
90
+ type: Boolean,
91
+ default: false
92
+ },
93
+ /**
94
+ * 是否只在网页显示
95
+ */
96
+ onlyH5: {
97
+ type: Boolean,
98
+ default: false
99
+ },
100
+ /**
101
+ * 是否透明背景
102
+ */
103
+ transparent: {
104
+ type: Boolean,
105
+ default: false
106
+ },
107
+ /**
108
+ * 标题栏高度,px
109
+ */
110
+ height: {
111
+ type: Number,
112
+ default: 45
113
+ },
114
+ /**
115
+ * 背景高斯模糊
116
+ */
117
+ blur: {
118
+ type: Boolean,
119
+ default: false
120
+ }
121
+ },
122
+ data() {
123
+ return {
124
+ sLoad: false,
125
+ isLogin: false,
126
+ messageNum: 0,
127
+ barTop: 0,
128
+ opacity: 0,
129
+ isScrollTo: false,
130
+ menuButtonTop: 0, // 小程序胶囊按钮高度
131
+ isDark
132
+ };
133
+ },
134
+ computed: {
135
+ noBg() {
136
+ return this.opacity <= 0
137
+ },
138
+ bgColor() {
139
+ if (!this.background) {
140
+ return this.color
141
+ }
142
+ return this.isDark ? 'rgba(55,55,55, 0.9)' : 'rgba(255,255,255, 0.9)'
143
+ }
144
+ },
145
+ created() {
146
+ this.barTop = uni.getSystemInfoSync().safeArea.top + 50
147
+ // #ifdef MP-WEIXIN
148
+ const button = uni.getMenuButtonBoundingClientRect()
149
+ this.menuButtonTop = button.top + 5
150
+ // #endif
151
+ this.opacity = this.transparent ? 0 : 1
152
+ uni.onThemeChange(res => {
153
+ this.isDark = res.theme === 'dark'
154
+ })
155
+ },
156
+ destroyed() {
157
+ uni.offThemeChange()
158
+ },
159
+ methods: {
160
+ goBack() {
161
+ this.$nav.back()
162
+ },
163
+ onRightClick() {
164
+ this.$emit('rightClick')
165
+ },
166
+ setOpacity(scrollTop) {
167
+ const barTop = this.barTop + this.menuButtonTop
168
+ let opacity = Number((1 / barTop) * scrollTop).toFixed(2)
169
+
170
+ if (opacity >= 1) {
171
+ this.opacity = 1
172
+ if (!this.isScrollTo) {
173
+ this.isScrollTo = true
174
+ this.$setBarStyle(!this.isDark ? 'dark' : 'light');
175
+ this.$emit('scrollTo', true)
176
+ }
177
+ } else {
178
+ if (opacity <= 0.5 && this.isScrollTo) {
179
+ this.isScrollTo = false
180
+ this.$setBarStyle(!this.isDark ? 'light' : 'dark')
181
+ this.$emit('scrollTo', false)
182
+ }
183
+ this.opacity = opacity
184
+ }
185
+ },
186
+ },
187
+ }
188
+ </script>
189
+
190
+ <style scoped lang="scss">
191
+ $barheight: var(--status-bar-height);
192
+ $navheight: 45px;
193
+ $txtcolor: var(--color-dark);
194
+
195
+ .tb-main {
196
+ position: fixed;
197
+ left: 0;
198
+ right: 0;
199
+ top: 0;
200
+ z-index: 99;
201
+ background: none;
202
+
203
+ .tb-bg {
204
+ position: absolute;
205
+ top: 0;
206
+ left: 0;
207
+ width: 100%;
208
+ height: 100%;
209
+ z-index: 0;
210
+ &.blur {
211
+ backdrop-filter: saturate(100%) blur(10rpx);
212
+ }
213
+ }
214
+
215
+ .top-nav {
216
+ background: none;
217
+ height: $navheight;
218
+ display: flex;
219
+ justify-content: space-between;
220
+ align-items: center;
221
+ position: relative;
222
+ z-index: 1;
223
+
224
+ &.hasOneRight {
225
+ width: 100%;
226
+ justify-content: flex-end;
227
+ }
228
+ }
229
+
230
+ .status-height {
231
+ height: $barheight;
232
+ background: none;
233
+ position: relative;
234
+ z-index: 1;
235
+ }
236
+
237
+ .tn-left,
238
+ .tn-right {
239
+ position: absolute;
240
+ min-width: 32rpx;
241
+ display: block;
242
+ height: 32px;
243
+ text-align: center;
244
+ line-height: 32px;
245
+ color: inherit;
246
+ font-size: 18px;
247
+ z-index: 2;
248
+ }
249
+
250
+ .tn-left {
251
+ left: 15px;
252
+ &:active {
253
+ opacity: 0.8;
254
+ }
255
+ }
256
+
257
+ .tn-right {
258
+ right: 15px;
259
+ font-size: 16px;
260
+ }
261
+
262
+ .tn-center {
263
+ flex: 1;
264
+ display: flex;
265
+ align-items: center;
266
+ justify-content: center;
267
+ margin: auto 15px;
268
+ white-space: nowrap;
269
+ overflow: hidden;
270
+ text-overflow: ellipsis;
271
+ color: inherit;
272
+ font-size: 16px;
273
+ text-align: center;
274
+ &.hasCenter {
275
+ flex: none;
276
+ margin: auto;
277
+ }
278
+ }
279
+ }
280
+
281
+ .space {
282
+ background: none;
283
+
284
+ .status-height {
285
+ height: $barheight;
286
+ }
287
+
288
+ .nav-height {
289
+ height: $navheight;
290
+ }
291
+ }
292
+ </style>