business_tms_program 0.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 (136) hide show
  1. package/.editorconfig +12 -0
  2. package/.eslintrc-auto-import.json +113 -0
  3. package/.eslintrc.js +121 -0
  4. package/.prettierrc.js +9 -0
  5. package/.stylelintignore +4 -0
  6. package/README.md +43 -0
  7. package/components.d.ts +23 -0
  8. package/index.html +20 -0
  9. package/package.json +70 -0
  10. package/shims-uni.d.ts +10 -0
  11. package/src/App.vue +81 -0
  12. package/src/api/afterSale.ts +184 -0
  13. package/src/api/context.ts +26 -0
  14. package/src/api/device.ts +134 -0
  15. package/src/api/index.ts +80 -0
  16. package/src/api/installtion.ts +155 -0
  17. package/src/api/model/index.ts +15 -0
  18. package/src/api/model/userModel.ts +62 -0
  19. package/src/api/order.ts +49 -0
  20. package/src/api/system.ts +19 -0
  21. package/src/api/user.ts +171 -0
  22. package/src/auto-imports.d.ts +108 -0
  23. package/src/components/ConfirmDialog.vue +101 -0
  24. package/src/components/DaySelect.vue +212 -0
  25. package/src/components/Drawer.vue +104 -0
  26. package/src/components/DrawerSelect.vue +105 -0
  27. package/src/components/DropMenu.vue +144 -0
  28. package/src/components/Empty.vue +49 -0
  29. package/src/components/Loading.vue +41 -0
  30. package/src/components/RippleBtn.vue +159 -0
  31. package/src/components/SinglePick.vue +120 -0
  32. package/src/components/Skeleton.vue +43 -0
  33. package/src/components/Timeline.vue +85 -0
  34. package/src/components/Upload.vue +217 -0
  35. package/src/config/app.ts +32 -0
  36. package/src/config/env.ts +29 -0
  37. package/src/dict/afterSale.ts +161 -0
  38. package/src/dict/device.ts +29 -0
  39. package/src/dict/installtion.ts +141 -0
  40. package/src/dict/systems.ts +4 -0
  41. package/src/env.d.ts +8 -0
  42. package/src/hooks/useForm.ts +222 -0
  43. package/src/hooks/useUpload.ts +80 -0
  44. package/src/main.ts +8 -0
  45. package/src/manifest.json +39 -0
  46. package/src/pages/acceptance/DeviceInfo.vue +132 -0
  47. package/src/pages/acceptance/list.vue +276 -0
  48. package/src/pages/afterSale/DeviceInfo.vue +128 -0
  49. package/src/pages/afterSale/Step.vue +0 -0
  50. package/src/pages/afterSale/faultReport.vue +552 -0
  51. package/src/pages/afterSale/orderDetail.vue +327 -0
  52. package/src/pages/afterSale/orderFinish.vue +517 -0
  53. package/src/pages/afterSale/orderList.vue +305 -0
  54. package/src/pages/afterSale/returnVisit.vue +288 -0
  55. package/src/pages/afterSale/searchDeviceList.vue +148 -0
  56. package/src/pages/device/Search.vue +201 -0
  57. package/src/pages/device/acceptance.vue +270 -0
  58. package/src/pages/device/detail.vue +165 -0
  59. package/src/pages/device/index.vue +322 -0
  60. package/src/pages/device/info.vue +140 -0
  61. package/src/pages/device/list.vue +219 -0
  62. package/src/pages/device/materialTowerCode.vue +589 -0
  63. package/src/pages/device/searchList.vue +224 -0
  64. package/src/pages/installtion/Record.vue +145 -0
  65. package/src/pages/installtion/StatusTimeline.vue +85 -0
  66. package/src/pages/installtion/addAcceptance.vue +409 -0
  67. package/src/pages/installtion/addRecord.vue +338 -0
  68. package/src/pages/installtion/orderDetail.vue +220 -0
  69. package/src/pages/installtion/orderList.vue +100 -0
  70. package/src/pages/user/component/PersonAgree.vue +226 -0
  71. package/src/pages/user/component/PrivayAgree.vue +221 -0
  72. package/src/pages/user/component/SliderCode.vue +173 -0
  73. package/src/pages/user/forgetPassword.vue +249 -0
  74. package/src/pages/user/index.vue +139 -0
  75. package/src/pages/user/login.vue +342 -0
  76. package/src/pages/user/register.vue +348 -0
  77. package/src/pages/user/repassword.vue +329 -0
  78. package/src/pages/user/utils/mcaptcha.js +75 -0
  79. package/src/pages/user/utils/verifyCode.ts +41 -0
  80. package/src/pages/workspace/index.vue +225 -0
  81. package/src/pages.json +203 -0
  82. package/src/shime-uni.d.ts +6 -0
  83. package/src/static/icon/system/breeder_icon.png +0 -0
  84. package/src/static/icon/system/check.png +0 -0
  85. package/src/static/icon/system/factory_icon.png +0 -0
  86. package/src/static/icon/system/plus.png +0 -0
  87. package/src/static/icon/system/right.png +0 -0
  88. package/src/static/icon/system/unCheck.png +0 -0
  89. package/src/static/icon/tab/search.png +0 -0
  90. package/src/static/icon/tab/user.png +0 -0
  91. package/src/static/icon/tab/user_active.png +0 -0
  92. package/src/static/icon/tab/workspace.png +0 -0
  93. package/src/static/icon/tab/workspace_active.png +0 -0
  94. package/src/static/img/active_dot.png +0 -0
  95. package/src/static/img/afterSale_icon.png +0 -0
  96. package/src/static/img/check.png +0 -0
  97. package/src/static/img/close.png +0 -0
  98. package/src/static/img/confirm.png +0 -0
  99. package/src/static/img/empty.png +0 -0
  100. package/src/static/img/equipment_icon.png +0 -0
  101. package/src/static/img/fault_icon.png +0 -0
  102. package/src/static/img/install_icon.png +0 -0
  103. package/src/static/img/login_bg2.png +0 -0
  104. package/src/static/img/movable_right.png +0 -0
  105. package/src/static/img/navigation.png +0 -0
  106. package/src/static/img/psw_off.png +0 -0
  107. package/src/static/img/psw_on.png +0 -0
  108. package/src/static/img/scan.png +0 -0
  109. package/src/static/img/scan_icon.png +0 -0
  110. package/src/static/img/search.png +0 -0
  111. package/src/static/img/turn_right.png +0 -0
  112. package/src/static/img/unActive_dot.png +0 -0
  113. package/src/static/img/verifyBg.png +0 -0
  114. package/src/stores/index.ts +11 -0
  115. package/src/stores/modules/customer.ts +146 -0
  116. package/src/stores/modules/installtion.ts +30 -0
  117. package/src/stores/modules/system.ts +56 -0
  118. package/src/stores/modules/user.ts +133 -0
  119. package/src/stores/types.ts +16 -0
  120. package/src/stores/utils.ts +6 -0
  121. package/src/styles/index.less +63 -0
  122. package/src/types/chengyiApi.d.ts +36 -0
  123. package/src/types/index.d.ts +95 -0
  124. package/src/utils/address.ts +17 -0
  125. package/src/utils/cipher.ts +61 -0
  126. package/src/utils/form.ts +155 -0
  127. package/src/utils/httpEnum.ts +31 -0
  128. package/src/utils/image.ts +21 -0
  129. package/src/utils/index.ts +111 -0
  130. package/src/utils/request.ts +139 -0
  131. package/src/utils/requestCancelHandle.ts +67 -0
  132. package/stylelint.config.js +87 -0
  133. package/tsconfig.docs.json +11 -0
  134. package/tsconfig.json +30 -0
  135. package/typedoc.json +6 -0
  136. package/vite.config.ts +55 -0
@@ -0,0 +1,105 @@
1
+ <template>
2
+ <Drawer v-model="showDrawer" :height="70" drawType="select">
3
+ <view>
4
+ <view class="header">
5
+ <view class="cancel" @click="handleCancel">取消</view>
6
+ <view class="title">{{ title }}</view>
7
+ <view class="confirm" @click="handleConfirm">确认</view>
8
+ </view>
9
+ <view class="select-box">
10
+ <checkbox-group @change="handleChange">
11
+ <label
12
+ v-for="item in options"
13
+ :key="item[valueKey]"
14
+ class="flex items-center select-item"
15
+ >
16
+ <checkbox
17
+ :value="item[valueKey]"
18
+ color="#1D6FE9"
19
+ :checked="selected.includes(item[valueKey])"
20
+ />
21
+ <view class="flex-1 select-label">{{ item[labelKey] }}</view>
22
+ </label>
23
+ </checkbox-group>
24
+ </view>
25
+ </view>
26
+ </Drawer>
27
+ </template>
28
+
29
+ <script setup lang="ts">
30
+ import Drawer from './Drawer.vue'
31
+ import { ref } from 'vue'
32
+
33
+ const props = defineProps({
34
+ visible: Boolean,
35
+ title: String,
36
+ valueKey: {
37
+ type: String,
38
+ default: 'value'
39
+ },
40
+ labelKey: {
41
+ type: String,
42
+ default: 'label'
43
+ },
44
+ options: {
45
+ type: Array,
46
+ default: () => ([])
47
+ }
48
+ })
49
+
50
+ const emit = defineEmits(['update:visible', 'change'])
51
+ const selected = ref<(string|number)[]>([])
52
+ const showDrawer = ref(false) // 控制抽屉显示
53
+ watch(() => props.visible, (val) => {
54
+ if (val) {
55
+ showDrawer.value = true
56
+ } else {
57
+ showDrawer.value = false
58
+ }
59
+ })
60
+ const handleChange = (e: CustomEvent) => {
61
+ selected.value = e.detail.value
62
+ }
63
+ const handleConfirm = () => {
64
+ emit('change', selected.value)
65
+ }
66
+ const handleCancel = () => {
67
+ emit('update:visible', false)
68
+ }
69
+ </script>
70
+ <style lang="scss" scoped>
71
+ .header{
72
+ display: flex;
73
+ align-items: center;
74
+ justify-content: space-between;
75
+ .title{
76
+ padding: 36rpx 0;
77
+ font-weight: 500;
78
+ font-size: 40rpx;
79
+ color: rgba(0,0,0,0.85);
80
+ line-height: 56rpx;
81
+ }
82
+ .cancel{
83
+ padding: 0 32rpx;
84
+ font-size: 32rpx;
85
+ color: rgba(0,0,0,0.6);
86
+ line-height: 56rpx;
87
+ }
88
+ .confirm{
89
+ padding: 0 32rpx;
90
+ font-size: 32rpx;
91
+ color: #1D6FE9;
92
+ line-height: 56rpx;
93
+ }
94
+ }
95
+ .select-box{
96
+ padding: 0 32rpx;
97
+ .select-item {
98
+ padding: 32rpx 0;
99
+ border-bottom: 1rpx solid #E8E8E8;
100
+ .select-label{
101
+ margin-left: 24rpx;
102
+ }
103
+ }
104
+ }
105
+ </style>
@@ -0,0 +1,144 @@
1
+ <script setup lang="ts">
2
+ import { ref, onMounted, onUnmounted } from 'vue'
3
+
4
+ const props = defineProps({
5
+ options: {
6
+ type: Array as () => Array<{ value: string; name: string }>,
7
+ required: true
8
+ },
9
+ modelValue: {
10
+ type: String,
11
+ required: true
12
+ }
13
+ })
14
+
15
+ const emit = defineEmits(['update:modelValue', 'change'])
16
+ const showDropdown = ref(false)
17
+ const dropdownRef = ref<any>(null)
18
+
19
+ // 切换下拉菜单
20
+ const toggleDropdown = (e: any) => {
21
+ e.stopPropagation()
22
+ showDropdown.value = !showDropdown.value
23
+ }
24
+
25
+ // 选择选项
26
+ const selectOption = (value: string) => {
27
+ emit('update:modelValue', value)
28
+ emit('change', value)
29
+ showDropdown.value = false
30
+ }
31
+
32
+ // 小程序点击外部关闭
33
+ const handleTapOutside = () => {
34
+ showDropdown.value = false
35
+ }
36
+
37
+ onMounted(() => {
38
+ // 小程序环境下添加全局点击监听
39
+ uni.$on('clickOutside', handleTapOutside)
40
+ })
41
+
42
+ onUnmounted(() => {
43
+ uni.$off('clickOutside', handleTapOutside)
44
+ })
45
+ </script>
46
+
47
+ <template>
48
+ <view class="dropdown-container" @tap.stop="toggleDropdown" ref="dropdownRef">
49
+ <view class="dropdown-trigger">
50
+ <text>{{ options.find(opt => opt.value === modelValue)?.name }}</text>
51
+ <view class="arrow" :class="{ 'rotate': showDropdown }">▼</view>
52
+ </view>
53
+
54
+ <!-- 添加遮罩层用于点击外部关闭 -->
55
+ <view
56
+ v-if="showDropdown"
57
+ class="dropdown-mask"
58
+ @tap.stop="handleTapOutside"
59
+ @touchmove.stop.prevent
60
+ ></view>
61
+
62
+ <transition name="fade">
63
+ <view v-if="showDropdown" class="dropdown-menu" @tap.stop>
64
+ <view
65
+ v-for="option in options"
66
+ :key="option.value"
67
+ class="dropdown-item"
68
+ :class="{ 'active': option.value === modelValue }"
69
+ @tap.stop="selectOption(option.value)"
70
+ >
71
+ {{ option.name }}
72
+ </view>
73
+ </view>
74
+ </transition>
75
+ </view>
76
+ </template>
77
+
78
+ <style scoped lang="less">
79
+ .dropdown-container {
80
+ position: relative;
81
+ display: inline-block;
82
+ }
83
+
84
+ .dropdown-trigger {
85
+ display: flex;
86
+ align-items: center;
87
+ padding: 12rpx 8rpx;
88
+ background-color: white;
89
+ font-size: 24rpx;
90
+
91
+ .arrow {
92
+ margin-left: 12rpx;
93
+ font-size: 18rpx;
94
+ transition: transform 0.3s ease;
95
+ &.rotate {
96
+ transform: rotate(180deg);
97
+ }
98
+ }
99
+ }
100
+
101
+ .dropdown-mask {
102
+ position: fixed;
103
+ top: 0;
104
+ left: 0;
105
+ right: 0;
106
+ bottom: 0;
107
+ z-index: 999;
108
+ background: transparent;
109
+ }
110
+
111
+ .dropdown-menu {
112
+ position: absolute;
113
+ top: 100%;
114
+ left: 0;
115
+ z-index: 1000;
116
+ min-width: 134rpx;
117
+ background-color: white;
118
+ border: 1rpx solid #dadada;
119
+ border-radius: 4rpx;
120
+ box-shadow: 0 2rpx 12rpx 0 rgba(0,0,0,0.1);
121
+ margin-top: 4rpx;
122
+ overflow: hidden;
123
+ }
124
+
125
+ .dropdown-item {
126
+ padding: 16rpx;
127
+ font-size: 24rpx;
128
+
129
+ &.active {
130
+ color: #409eff;
131
+ background-color: #ecf5ff;
132
+ }
133
+ }
134
+
135
+ .fade-enter-active,
136
+ .fade-leave-active {
137
+ transition: opacity 0.3s;
138
+ }
139
+
140
+ .fade-enter-from,
141
+ .fade-leave-to {
142
+ opacity: 0;
143
+ }
144
+ </style>
@@ -0,0 +1,49 @@
1
+ <template>
2
+ <view :style="otherStyle" :class="['empty']">
3
+ <view class="empty-content">
4
+ <image
5
+ class="empty-icon"
6
+ :src="image"
7
+ mode="scaleToFill"
8
+ />
9
+ <view class="empty-text">{{ desc }}</view>
10
+ </view>
11
+ </view>
12
+ </template>
13
+
14
+ <script setup lang="ts" name="Empty">
15
+ import emptyImage from '@/static/img/empty.png'
16
+ defineProps({
17
+ image: {
18
+ type: String,
19
+ default: emptyImage
20
+ },
21
+ desc: {
22
+ type: String,
23
+ default: '暂无数据'
24
+ },
25
+ otherStyle: {
26
+ type: String,
27
+ default: ''
28
+ }
29
+ })
30
+
31
+ </script>
32
+
33
+ <style lang="scss">
34
+
35
+ .empty-content {
36
+ text-align: center;
37
+ }
38
+ .empty-icon {
39
+ margin: 0 auto;
40
+ width: 440rpx;
41
+ height: 400rpx;
42
+ }
43
+ .empty-text {
44
+ text-align: center;
45
+ font-size: 28rpx;
46
+ color: #c9c7c7;
47
+ }
48
+ </style>
49
+
@@ -0,0 +1,41 @@
1
+ <script setup lang="ts">
2
+ const props = defineProps({
3
+ size: {
4
+ type: Number,
5
+ default: 20
6
+ },
7
+ color: {
8
+ type: String,
9
+ default: '#fff'
10
+ },
11
+ borderWidth: {
12
+ type: Number,
13
+ default: null
14
+ }
15
+ })
16
+ const computedBorderWidth = computed(() => props.borderWidth || props.size / 10)
17
+ </script>
18
+ <template>
19
+ <view class="loading-spinner" :style="{
20
+ width: `${props.size}rpx`,
21
+ height: `${props.size}rpx`,
22
+ borderWidth: `${computedBorderWidth}rpx`,
23
+ borderColor: `rgba(255, 255, 255, 0.3)`,
24
+ borderTopColor: props.color
25
+ }"></view>
26
+ </template>
27
+
28
+ <style scoped>
29
+ .loading-spinner {
30
+ border-style: solid;
31
+ border-radius: 50%;
32
+ animation: spin 1s ease-in-out infinite;
33
+ margin: 0 auto;
34
+ }
35
+
36
+ @keyframes spin {
37
+ to {
38
+ transform: rotate(360deg);
39
+ }
40
+ }
41
+ </style>
@@ -0,0 +1,159 @@
1
+ <template>
2
+ <button
3
+ class="ripple-button"
4
+ :class="{
5
+ 'loading': loading,
6
+ 'disabled': disabled,
7
+ }"
8
+ :disabled="disabled || loading"
9
+ @click="handleClick"
10
+ :style="customStyle"
11
+ >
12
+ <view v-if="loading" class="loading-spinner"></view>
13
+ <view class="button-content">
14
+ <slot></slot>
15
+ </view>
16
+ <view
17
+ v-for="(ripple, index) in ripples"
18
+ :key="index"
19
+ class="ripple"
20
+ :style="{
21
+ width: ripple.width,
22
+ height: ripple.height,
23
+ left: ripple.left,
24
+ top: ripple.top
25
+ }"
26
+ ></view>
27
+ </button>
28
+ </template>
29
+
30
+ <script setup lang="ts">
31
+ import { ref } from 'vue'
32
+
33
+ interface RippleInfo {
34
+ width: string
35
+ height: string
36
+ left: string
37
+ top: string
38
+ }
39
+
40
+ const props = defineProps({
41
+ loading: {
42
+ type: Boolean,
43
+ default: false
44
+ },
45
+ disabled: {
46
+ type: Boolean,
47
+ default: false
48
+ },
49
+ plain: {
50
+ type: Boolean,
51
+ default: false
52
+ },
53
+ round: {
54
+ type: Boolean,
55
+ default: false
56
+ },
57
+ customStyle: {
58
+ type: String,
59
+ default: ''
60
+ }
61
+ })
62
+
63
+ const emit = defineEmits(['click'])
64
+
65
+ const ripples = ref<RippleInfo[]>([])
66
+
67
+ const handleClick = (event: any) => {
68
+ if (props.loading || props.disabled) return
69
+ const target = event.currentTarget || event.target
70
+ if (target) {
71
+ const size = 40
72
+ const x = event.detail.x - target.offsetLeft - size / 2
73
+ const y = event.detail.y - target.offsetTop - size / 2
74
+
75
+ ripples.value.push({
76
+ width: `${size}px`,
77
+ height: `${size}px`,
78
+ left: `${x}px`,
79
+ top: `${y}px`
80
+ })
81
+
82
+ setTimeout(() => {
83
+ ripples.value.shift()
84
+ }, 600)
85
+ }
86
+
87
+ emit('click', event)
88
+ }
89
+ </script>
90
+
91
+ <style scoped>
92
+
93
+ .ripple-button {
94
+ position: relative;
95
+ transition: all 0.3s;
96
+ display: inline-flex;
97
+ align-items: center;
98
+ justify-content: center;
99
+ box-sizing: border-box;
100
+ /* 覆盖unibtn的样式 */
101
+ padding: 0;
102
+ margin: 0;
103
+ background: none;
104
+ }
105
+
106
+ .ripple-button::after {
107
+ display: none;
108
+ }
109
+ /* 圆角按钮 */
110
+ .ripple-button.round {
111
+ border-radius: 22rpx;
112
+ }
113
+
114
+ /* 禁用状态 */
115
+ .ripple-button.disabled {
116
+ opacity: 0.6;
117
+ cursor: not-allowed;
118
+ }
119
+
120
+ /* 波纹效果 */
121
+ .ripple {
122
+ position: absolute;
123
+ border-radius: 50%;
124
+ background-color: rgba(255, 255, 255, 0.4);
125
+ transform: scale(0);
126
+ animation: ripple 0.6s linear;
127
+ pointer-events: none;
128
+ }
129
+
130
+ @keyframes ripple {
131
+ to {
132
+ transform: scale(4);
133
+ opacity: 0;
134
+ }
135
+ }
136
+
137
+ /* 加载动画 */
138
+ .loading-spinner {
139
+ width: 28rpx;
140
+ height: 28rpx;
141
+ border: 4rpx solid rgba(255, 255, 255, 0.767);
142
+ border-radius: 50%;
143
+ border-top-color: currentColor;
144
+ animation: spin 1s linear infinite;
145
+ margin-right: 16rpx;
146
+ }
147
+
148
+ @keyframes spin {
149
+ to {
150
+ transform: rotate(360deg);
151
+ }
152
+ }
153
+
154
+ .button-content {
155
+ display: inline-flex;
156
+ align-items: center;
157
+ }
158
+
159
+ </style>
@@ -0,0 +1,120 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue';
3
+
4
+ interface DictItem {
5
+ [key: string]: any;
6
+ value: string | number;
7
+ label: string;
8
+ }
9
+
10
+ const props = defineProps({
11
+ value: [String, Number, Object],
12
+ range: {
13
+ type: Array as () => DictItem[],
14
+ default: () => []
15
+ },
16
+ valueKey: {
17
+ type: String,
18
+ default: 'value'
19
+ },
20
+ labelKey: {
21
+ type: String,
22
+ default: 'label'
23
+ },
24
+ placeholder: {
25
+ type: String,
26
+ default: '请选择'
27
+ },
28
+ type: {
29
+ type: String,
30
+ default: 'dict'
31
+ },
32
+ showRightIcon: {
33
+ type: Boolean,
34
+ default: false
35
+ },
36
+ selectColor: {
37
+ type: String,
38
+ default: '#7e7d7d'
39
+ },
40
+ disabled: {
41
+ type: Boolean,
42
+ default: false
43
+ }
44
+ });
45
+
46
+ const emit = defineEmits(['change', 'update:value']);
47
+
48
+ const currentIndex = computed(() => {
49
+ return props.range.findIndex(item => item[props.valueKey] === props.value);
50
+ });
51
+
52
+ const currentLabel = computed(() => {
53
+ const item = props.range.find(item => item[props.valueKey] === props.value);
54
+ return item ? item[props.labelKey] : '';
55
+ });
56
+
57
+ const handleChange = (e: any) => {
58
+ const index = parseInt(e.detail.value);
59
+ const selectedItem = props.range[index];
60
+ if (selectedItem) {
61
+ emit('change', selectedItem[props.valueKey]);
62
+ }
63
+ };
64
+ </script>
65
+
66
+ <template>
67
+ <view>
68
+ <view v-if="!disabled" class="select-box">
69
+ <image class="right-icon" src="/static/img/turn_right.png" />
70
+ <picker
71
+ class="common-picker"
72
+ mode="selector"
73
+ :range="range"
74
+ :value="currentIndex"
75
+ :range-key="labelKey"
76
+ @change="handleChange"
77
+ >
78
+ <view v-if="currentLabel" class="picker-content" :style="{color: selectColor}">
79
+ {{ currentLabel }}
80
+ </view>
81
+ <view v-else class="picker-placeholder">
82
+ {{ props.placeholder }}
83
+ </view>
84
+ </picker>
85
+ </view>
86
+ <view v-else="disabled" class="label-content" :style="{color: selectColor}">
87
+ {{ currentLabel }}
88
+ </view>
89
+ </view>
90
+ </template>
91
+
92
+ <style scoped>
93
+ .select-box {
94
+ display: flex;
95
+ align-items: center;
96
+ flex-direction: row-reverse;
97
+ }
98
+ .common-picker {
99
+ flex: 1;
100
+ text-align: right;
101
+ }
102
+ .label-content {
103
+ text-align: right;
104
+ }
105
+ .picker-content {
106
+ width: 100%;
107
+ line-height: 48rpx;
108
+ }
109
+ .picker-placeholder {
110
+ font-size: 32rpx;
111
+ color: #7e7d7d;
112
+ line-height: 48rpx;
113
+ }
114
+ .right-icon {
115
+ margin-left: 16rpx;
116
+ width: 32rpx;
117
+ height: 32rpx;
118
+ text-align: right;
119
+ }
120
+ </style>
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <view class="skeleton-container">
3
+
4
+ <view class="skeleton-line"></view>
5
+ <view class="skeleton-line short"></view>
6
+ <view class="skeleton-line medium"></view>
7
+ </view>
8
+ </template>
9
+
10
+ <style scoped>
11
+ .skeleton-container {
12
+ margin-bottom: 32rpx;
13
+ padding: 20rpx 20rpx 30rpx 20rpx;
14
+ background-color: #fff;
15
+ }
16
+ .skeleton-line {
17
+ height: 24rpx;
18
+ margin-bottom: 12rpx;
19
+ background: linear-gradient(
20
+ 90deg,
21
+ #eeeeee 25%,
22
+ #e0e0e0 37%,
23
+ #eeeeee 63%
24
+ );
25
+ background-size: 400% 100%;
26
+ animation: skeleton-loading 1.4s ease infinite;
27
+ border-radius: 4rpx;
28
+ }
29
+ .skeleton-line.short {
30
+ width: 60%;
31
+ }
32
+ .skeleton-line.medium {
33
+ width: 80%;
34
+ }
35
+ @keyframes skeleton-loading {
36
+ 0% {
37
+ background-position: 100% 50%;
38
+ }
39
+ 100% {
40
+ background-position: 0 50%;
41
+ }
42
+ }
43
+ </style>