Przeglądaj źródła

fix: 组件封装

szr190 2 miesięcy temu
rodzic
commit
16c3c09c36

+ 74 - 0
src/components/HyCharge.vue

@@ -0,0 +1,74 @@
1
+<template>
2
+  <view class="charge-item-wrapper">
3
+    <view class="item-btn-wrap">快充</view>
4
+    <view class="item-content-wrap">
5
+      <view class="text">空闲</view>
6
+      <view class="content-number">
7
+        <view class="left-num">10</view>
8
+        <view class="right-num">/24</view>
9
+      </view>
10
+    </view>
11
+    <view class="item-status-wrap">排队中</view>
12
+  </view>
13
+</template>
14
+
15
+<script lang="ts" setup></script>
16
+
17
+<style lang="scss" scoped>
18
+.charge-item-wrapper {
19
+  width: 100%;
20
+  height: 70rpx;
21
+  background-color: #e2f9ef;
22
+  border-radius: 8rpx;
23
+  position: relative;
24
+  display: flex;
25
+  align-items: center;
26
+  justify-content: center;
27
+  .item-btn-wrap {
28
+    width: 94rpx;
29
+    height: 42rpx;
30
+    background-image: linear-gradient(90deg, #00d454 0%, #4ad581 100%), linear-gradient(#e5f5e7, #e5f5e7);
31
+    background-blend-mode: normal, normal;
32
+    border-radius: 8rpx;
33
+    position: absolute;
34
+    top: 14rpx;
35
+    left: 18rpx;
36
+    display: flex;
37
+    align-items: center;
38
+    justify-content: center;
39
+    font-size: 26rpx;
40
+    color: #fff;
41
+    font-weight: bold;
42
+  }
43
+  .item-content-wrap {
44
+    display: flex;
45
+    align-items: center;
46
+    .text {
47
+      font-size: 24rpx;
48
+      color: #222830;
49
+      line-height: 50rpx;
50
+      margin-right: 14rpx;
51
+    }
52
+    .content-number {
53
+      display: flex;
54
+      align-items: center;
55
+      font-size: 26rpx;
56
+      font-weight: 600;
57
+      .left-num {
58
+        color: #222830;
59
+      }
60
+      .right-num {
61
+        color: #999;
62
+      }
63
+    }
64
+  }
65
+  .item-status-wrap {
66
+    font-size: 26rpx;
67
+    line-height: 50rpx;
68
+    color: #158e45;
69
+    position: absolute;
70
+    top: 14rpx;
71
+    right: 24rpx;
72
+  }
73
+}
74
+</style>

+ 360 - 0
src/components/HyPopup.vue

@@ -0,0 +1,360 @@
1
+<template>
2
+  <transition :name="transitionName">
3
+    <view v-if="visible" class="hy-popup-wrapper" :class="positionClass" @click="handleOverlayClick">
4
+      <view class="hy-popup-overlay" :style="{ backgroundColor: overlayBackgroundColor }"></view>
5
+      <view
6
+        class="hy-popup-content"
7
+        :class="[customClass, { 'hy-popup-no-padding': noPadding }]"
8
+        @click.stop
9
+        :style="{
10
+          width: width,
11
+          maxWidth: maxWidth,
12
+          backgroundColor: backgroundColor,
13
+          borderRadius: borderRadius + 'rpx'
14
+        }"
15
+      >
16
+        <!-- 自定义头部插槽 -->
17
+        <slot name="header"></slot>
18
+
19
+        <!-- 自定义内容插槽 -->
20
+        <slot></slot>
21
+
22
+        <!-- 关闭按钮 -->
23
+        <view class="close-wrap" v-if="showClose" @click="handleClose">
24
+          <u-icon name="close-circle" size="40" color="#999"></u-icon>
25
+          <text>关闭</text>
26
+        </view>
27
+      </view>
28
+    </view>
29
+  </transition>
30
+</template>
31
+
32
+<script lang="ts" setup>
33
+import { computed } from 'vue'
34
+
35
+// 定义动画类型
36
+const AnimationType = ['scale', 'slide-up', 'slide-down', 'slide-left', 'slide-right', 'fade'] as const
37
+// eslint-disable-next-line no-redeclare
38
+type AnimationType = (typeof AnimationType)[number]
39
+
40
+// 定义弹窗位置
41
+const PositionType = ['center', 'top', 'bottom', 'left', 'right'] as const
42
+// eslint-disable-next-line no-redeclare
43
+type PositionType = (typeof PositionType)[number]
44
+
45
+// 定义组件的Props
46
+interface Props {
47
+  // v-model绑定值
48
+  modelValue: boolean
49
+  // 是否显示关闭按钮
50
+  showClose?: boolean
51
+  // 点击遮罩层是否可以关闭
52
+  closeOnClickOverlay?: boolean
53
+  // 按ESC键是否可以关闭(仅Web环境)
54
+  closeOnPressEscape?: boolean
55
+  // 自定义class
56
+  customClass?: string
57
+  // 动画类型
58
+  animationType?: AnimationType
59
+  // 弹窗位置
60
+  position?: PositionType
61
+  // 宽度
62
+  width?: string | number
63
+  // 最大宽度
64
+  maxWidth?: string | number
65
+  // 背景色
66
+  backgroundColor?: string
67
+  // 遮罩背景色
68
+  overlayBackgroundColor?: string
69
+  // 圆角大小
70
+  borderRadius?: number
71
+  // 关闭按钮颜色
72
+  closeIconColor?: string
73
+  // 关闭按钮样式
74
+  closeButtonStyle?: object
75
+  // 是否无内边距
76
+  noPadding?: boolean
77
+  // 是否显示遮罩
78
+  showOverlay?: boolean
79
+  // 是否显示已领取遮罩
80
+  showUsedReceived?: boolean
81
+}
82
+
83
+// 使用默认值定义Props
84
+const props = withDefaults(defineProps<Props>(), {
85
+  showClose: false,
86
+  closeOnClickOverlay: true,
87
+  closeOnPressEscape: true,
88
+  customClass: '',
89
+  animationType: 'scale',
90
+  position: 'center',
91
+  width: '80%',
92
+  maxWidth: '600rpx',
93
+  backgroundColor: 'transparent',
94
+  overlayBackgroundColor: 'rgba(0, 0, 0, 0.8)',
95
+  borderRadius: 24,
96
+  closeIconColor: '#fff',
97
+  closeButtonStyle: () => ({}),
98
+  noPadding: false,
99
+  showOverlay: true,
100
+  showUsedReceived: false
101
+})
102
+
103
+// 定义组件的Events
104
+const emit = defineEmits<{
105
+  'update:modelValue': [value: boolean]
106
+  close: []
107
+  opened: []
108
+  closed: []
109
+}>()
110
+
111
+// 处理v-model的双向绑定
112
+const visible = computed({
113
+  get: () => props.modelValue,
114
+  set: (value) => {
115
+    emit('update:modelValue', value)
116
+    if (value) {
117
+      emit('opened')
118
+    } else {
119
+      emit('closed')
120
+    }
121
+  }
122
+})
123
+
124
+// 计算动画名称
125
+const transitionName = computed(() => {
126
+  return `hy-popup-${props.animationType}`
127
+})
128
+
129
+// 计算位置类名
130
+const positionClass = computed(() => {
131
+  return `hy-popup-position-${props.position}`
132
+})
133
+
134
+// 点击关闭按钮
135
+const handleClose = () => {
136
+  visible.value = false
137
+  emit('close')
138
+}
139
+
140
+// 点击遮罩层
141
+const handleOverlayClick = () => {
142
+  if (props.closeOnClickOverlay) {
143
+    handleClose()
144
+  }
145
+}
146
+</script>
147
+
148
+<style lang="scss" scoped>
149
+.hy-popup-wrapper {
150
+  position: fixed;
151
+  top: 0;
152
+  left: 0;
153
+  right: 0;
154
+  bottom: 0;
155
+  z-index: 999;
156
+  display: flex;
157
+  align-items: center;
158
+  justify-content: center;
159
+  box-sizing: border-box;
160
+}
161
+.close-wrap {
162
+  display: flex;
163
+  flex-direction: column;
164
+  align-items: center;
165
+  margin-top: 20rpx;
166
+  image {
167
+    width: 62rpx;
168
+    height: 62rpx;
169
+    margin: 46rpx 0 8rpx 0;
170
+  }
171
+  text {
172
+    font-size: 30rpx;
173
+    color: rgba(255, 255, 255, 0.76);
174
+  }
175
+}
176
+// 位置控制
177
+.hy-popup-position-center {
178
+  align-items: center;
179
+  justify-content: center;
180
+}
181
+
182
+.hy-popup-position-top {
183
+  align-items: flex-start;
184
+  justify-content: center;
185
+}
186
+
187
+.hy-popup-position-bottom {
188
+  align-items: flex-end;
189
+  justify-content: center;
190
+}
191
+
192
+.hy-popup-position-left {
193
+  align-items: center;
194
+  justify-content: flex-start;
195
+}
196
+
197
+.hy-popup-position-right {
198
+  align-items: center;
199
+  justify-content: flex-end;
200
+}
201
+
202
+.hy-popup-overlay {
203
+  position: absolute;
204
+  top: 0;
205
+  left: 0;
206
+  right: 0;
207
+  bottom: 0;
208
+}
209
+
210
+.hy-popup-content {
211
+  position: relative;
212
+  box-sizing: border-box;
213
+  overflow: hidden;
214
+  padding: 30rpx;
215
+}
216
+
217
+.hy-popup-no-padding {
218
+  padding: 0;
219
+}
220
+
221
+.hy-popup-close {
222
+  position: absolute;
223
+  top: 20rpx;
224
+  right: 20rpx;
225
+  width: 60rpx;
226
+  height: 60rpx;
227
+  display: flex;
228
+  align-items: center;
229
+  justify-content: center;
230
+  border-radius: 50%;
231
+  background-color: rgba(0, 0, 0, 0.1);
232
+  z-index: 10;
233
+}
234
+
235
+.hy-popup-close-icon {
236
+  font-size: 40rpx;
237
+  font-weight: bold;
238
+}
239
+
240
+// 通用过渡设置
241
+$transition-duration: 0.3s;
242
+$transition-timing: ease;
243
+
244
+// Scale 动画
245
+.hy-popup-scale-enter-active,
246
+.hy-popup-scale-leave-active {
247
+  transition: all $transition-duration $transition-timing;
248
+}
249
+
250
+.hy-popup-scale-enter-from .hy-popup-overlay,
251
+.hy-popup-scale-leave-to .hy-popup-overlay {
252
+  opacity: 0;
253
+}
254
+
255
+.hy-popup-scale-enter-from .hy-popup-content,
256
+.hy-popup-scale-leave-to .hy-popup-content {
257
+  transform: scale(0.8);
258
+  opacity: 0;
259
+}
260
+
261
+// Slide-up 动画
262
+.hy-popup-slide-up-enter-active,
263
+.hy-popup-slide-up-leave-active {
264
+  transition: all $transition-duration $transition-timing;
265
+}
266
+
267
+.hy-popup-slide-up-enter-from .hy-popup-overlay,
268
+.hy-popup-slide-up-leave-to .hy-popup-overlay {
269
+  opacity: 0;
270
+}
271
+
272
+.hy-popup-slide-up-enter-from .hy-popup-content {
273
+  transform: translateY(100%);
274
+  opacity: 0;
275
+}
276
+
277
+.hy-popup-slide-up-leave-to .hy-popup-content {
278
+  transform: translateY(100%);
279
+  opacity: 0;
280
+}
281
+
282
+// Slide-down 动画
283
+.hy-popup-slide-down-enter-active,
284
+.hy-popup-slide-down-leave-active {
285
+  transition: all $transition-duration $transition-timing;
286
+}
287
+
288
+.hy-popup-slide-down-enter-from .hy-popup-overlay,
289
+.hy-popup-slide-down-leave-to .hy-popup-overlay {
290
+  opacity: 0;
291
+}
292
+
293
+.hy-popup-slide-down-enter-from .hy-popup-content {
294
+  transform: translateY(-100%);
295
+  opacity: 0;
296
+}
297
+
298
+.hy-popup-slide-down-leave-to .hy-popup-content {
299
+  transform: translateY(-100%);
300
+  opacity: 0;
301
+}
302
+
303
+// Slide-left 动画
304
+.hy-popup-slide-left-enter-active,
305
+.hy-popup-slide-left-leave-active {
306
+  transition: all $transition-duration $transition-timing;
307
+}
308
+
309
+.hy-popup-slide-left-enter-from .hy-popup-overlay,
310
+.hy-popup-slide-left-leave-to .hy-popup-overlay {
311
+  opacity: 0;
312
+}
313
+
314
+.hy-popup-slide-left-enter-from .hy-popup-content {
315
+  transform: translateX(-100%);
316
+  opacity: 0;
317
+}
318
+
319
+.hy-popup-slide-left-leave-to .hy-popup-content {
320
+  transform: translateX(-100%);
321
+  opacity: 0;
322
+}
323
+
324
+// Slide-right 动画
325
+.hy-popup-slide-right-enter-active,
326
+.hy-popup-slide-right-leave-active {
327
+  transition: all $transition-duration $transition-timing;
328
+}
329
+
330
+.hy-popup-slide-right-enter-from .hy-popup-overlay,
331
+.hy-popup-slide-right-leave-to .hy-popup-overlay {
332
+  opacity: 0;
333
+}
334
+
335
+.hy-popup-slide-right-enter-from .hy-popup-content {
336
+  transform: translateX(100%);
337
+  opacity: 0;
338
+}
339
+
340
+.hy-popup-slide-right-leave-to .hy-popup-content {
341
+  transform: translateX(100%);
342
+  opacity: 0;
343
+}
344
+
345
+// Fade 动画
346
+.hy-popup-fade-enter-active,
347
+.hy-popup-fade-leave-active {
348
+  transition: all $transition-duration $transition-timing;
349
+}
350
+
351
+.hy-popup-fade-enter-from .hy-popup-overlay,
352
+.hy-popup-fade-leave-to .hy-popup-overlay {
353
+  opacity: 0;
354
+}
355
+
356
+.hy-popup-fade-enter-from .hy-popup-content,
357
+.hy-popup-fade-leave-to .hy-popup-content {
358
+  opacity: 0;
359
+}
360
+</style>

+ 85 - 0
src/components/HyService.vue

@@ -0,0 +1,85 @@
1
+<template>
2
+  <view class="service-item-wrapper">
3
+    <view class="item-left-wrap">
4
+      <image src="/static/images/icon_service_01.png" mode="scaleToFill" />
5
+      <text>停车场</text>
6
+    </view>
7
+    <view class="item-right-wrap">
8
+      <!-- <view class="main-text">淋浴/洗衣</view> -->
9
+      <view class="block-content">
10
+        <view class="label">空闲</view>
11
+        <view class="number-box">
12
+          <view class="left-num">30</view>
13
+          <view class="right-num">/60</view>
14
+        </view>
15
+      </view>
16
+    </view>
17
+  </view>
18
+</template>
19
+
20
+<script lang="ts" setup></script>
21
+
22
+<style lang="scss" scoped>
23
+.service-item-wrapper {
24
+  width: 314rpx;
25
+  height: 56rpx;
26
+  background-image: linear-gradient(90deg, #3f8bf9 0%, #4eaefa 100%), linear-gradient(#f0f6ff, #f0f6ff);
27
+  background-blend-mode: normal, normal;
28
+  border-radius: 8rpx;
29
+  padding: 2rpx 2rpx 2rpx 12rpx;
30
+  box-sizing: border-box;
31
+  display: flex;
32
+  align-items: center;
33
+  justify-content: space-between;
34
+  .item-left-wrap {
35
+    display: flex;
36
+    align-items: center;
37
+    image {
38
+      width: 26rpx;
39
+      height: 34rpx;
40
+      margin-right: 6rpx;
41
+    }
42
+    text {
43
+      font-size: 22rpx;
44
+      color: #fff;
45
+      font-weight: 500;
46
+    }
47
+  }
48
+  .item-right-wrap {
49
+    width: 157rpx;
50
+    height: 52rpx;
51
+    background: url('/static/images/bg_service_03.png') no-repeat center center;
52
+    background-size: 157rpx 52rpx;
53
+    display: flex;
54
+    align-items: center;
55
+    justify-content: center;
56
+    .main-text {
57
+      font-size: 25rpx;
58
+      color: #222830;
59
+    }
60
+    .block-content {
61
+      display: flex;
62
+      align-items: center;
63
+      .label {
64
+        font-size: 24rpx;
65
+        color: #333;
66
+        line-height: 50rpx;
67
+        margin-left: 6rpx;
68
+      }
69
+      .number-box {
70
+        font-size: 28rpx;
71
+        display: flex;
72
+        align-items: center;
73
+        margin-left: 10rpx;
74
+        .left-num {
75
+          color: #333;
76
+          line-height: 50rpx;
77
+        }
78
+        .right-num {
79
+          color: #999;
80
+        }
81
+      }
82
+    }
83
+  }
84
+}
85
+</style>

+ 77 - 0
src/components/HyShopItem.vue

@@ -0,0 +1,77 @@
1
+<template>
2
+  <view class="shop-item-wrapper">
3
+    <view class="item-left-wrap"></view>
4
+    <view class="item-right-wrap">
5
+      <view class="top">
6
+        <view class="title u-line-1">肯德基</view>
7
+        <view class="rate-box">
8
+          <uni-rate allow-half v-model="rate" color="#ddd" activeColor="#ff5702" />
9
+          <text class="rate-text">{{ rate }}</text>
10
+        </view>
11
+      </view>
12
+      <view class="bottom">
13
+        <view class="tag-item">西式快餐</view>
14
+        <view class="tag-item">汉堡</view>
15
+      </view>
16
+    </view>
17
+  </view>
18
+</template>
19
+
20
+<script lang="ts" setup>
21
+import { ref } from 'vue'
22
+
23
+const rate = ref(3.5)
24
+</script>
25
+
26
+<style lang="scss" scoped>
27
+.shop-item-wrapper {
28
+  width: 100%;
29
+  box-sizing: border-box;
30
+  padding: 30rpx;
31
+  background-color: #fff;
32
+  border-radius: 14rpx;
33
+  display: flex;
34
+  .item-left-wrap {
35
+    width: 188rpx;
36
+    height: 188rpx;
37
+    background-color: #f6f7fb;
38
+    border-radius: 14rpx;
39
+    margin-right: 28rpx;
40
+    image {
41
+      width: 188rpx;
42
+      height: 199rpx;
43
+      border-radius: 14rpx;
44
+    }
45
+  }
46
+  .item-right-wrap {
47
+    display: flex;
48
+    flex-direction: column;
49
+    justify-content: space-between;
50
+    .top {
51
+      .title {
52
+        font-size: 28rpx;
53
+        color: #333;
54
+        font-weight: 500;
55
+        width: 400rpx;
56
+        margin-bottom: 10rpx;
57
+      }
58
+      .rate-box {
59
+        display: flex;
60
+        align-items: flex-end;
61
+        .rate-text {
62
+          margin-left: 14rpx;
63
+        }
64
+      }
65
+    }
66
+    .bottom {
67
+      display: flex;
68
+      align-items: center;
69
+      .tag-item {
70
+        font-size: 26rpx;
71
+        color: #999;
72
+        margin-right: 22rpx;
73
+      }
74
+    }
75
+  }
76
+}
77
+</style>

+ 7 - 0
src/components/HyStation.vue

@@ -0,0 +1,7 @@
1
+<template>
2
+  <view></view>
3
+</template>
4
+
5
+<script lang="ts" setup></script>
6
+
7
+<style lang="scss" scoped></style>

+ 0 - 5
src/main.js

@@ -4,11 +4,6 @@ import App from './App.vue'
4 4
 import resetStore from './stores/reset'
5 5
 import uView from './uni_modules/vk-uview-ui'
6 6
 
7
-// #ifdef H5
8
-import quill from 'quill'
9
-window.Quill = quill
10
-// #endif
11
-
12 7
 export function createApp() {
13 8
   const app = createSSRApp(App)
14 9
 

+ 13 - 2
src/pages/index.vue

@@ -1,8 +1,19 @@
1 1
 <script setup lang="ts">
2
+import { ref } from 'vue'
3
+
4
+const showCustomPopup = ref(false)
2 5
 </script>
3 6
 
4 7
 <template>
8
+  <view class="index-container u-padding-20">
9
+    <HyCharge /><br />
10
+    <HyService /><br />
11
+    <HyShopItem /><br />
12
+    <HyStation /><br />
13
+    <HyPopup v-model="showCustomPopup" width="650rpx" showClose>
14
+      <view style="height: 500rpx; background-color: #fff"></view>
15
+    </HyPopup>
16
+  </view>
5 17
 </template>
6 18
 
7
-<style lang="scss" scoped>
8
-</style>
19
+<style lang="scss" scoped></style>

BIN
src/static/images/bg_service_03.png


BIN
src/static/images/icon_service_01.png


BIN
src/static/images/icon_sm_jiayou.png


+ 0 - 10
src/types/global.d.ts

@@ -1,17 +1,7 @@
1
-/*
2
- * @Author: wyd
3
- * @Date: 2024-02
4
- * @LastEditors: wyd
5
- * @LastEditTime: 2024-03
6
- * @Description: 全局类型
7
- */
8
-
9 1
 declare module 'lodash/cloneDeep'
10 2
 declare module 'lodash'
11 3
 declare module 'qs'
12 4
 
13
-declare module '@dcloudio/uni-app'
14
-
15 5
 /* 数组类型 */
16 6
 declare type ArrayItem = {
17 7
   /* id */