@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,229 @@
1
+ <!--搜索高亮关键字组件, 2021-05-11, kingchem zzc-->
2
+ <template>
3
+ <view class="keyword-select">
4
+ <view style="padding-right: 36rpx;flex: 1;">
5
+ <slot></slot>
6
+ </view>
7
+ <text v-if="content && showClear" class="form-clear iconfont" @click="clear">&#xe622;</text>
8
+ <scroll-view v-if="showTips" :scroll-y="true" :style="{ top: top + 'rpx' }" class="keyword-list">
9
+ <view
10
+ v-for="(item, index) in list"
11
+ :key="index"
12
+ class="keyword-item"
13
+ @click.stop="select(item)"
14
+ >
15
+ {{ item[keyName] }}
16
+ <!-- <text
17
+ v-for="(str, idx) in item[keyName].split('')"
18
+ :key="idx"
19
+ :class="{ red: setRed(str) }"
20
+ >
21
+ {{ str }}
22
+ </text> -->
23
+ </view>
24
+ </scroll-view>
25
+ </view>
26
+ </template>
27
+
28
+ <script>
29
+ import { debounce } from '@/utils/index.js'
30
+
31
+ export default {
32
+ props: {
33
+ // 关键字
34
+ value: {
35
+ type: String,
36
+ default: ''
37
+ },
38
+
39
+ // 询价位置
40
+ searchPosition: {
41
+ type: String,
42
+ default: ''
43
+ },
44
+
45
+ // 要返回的键名名称
46
+ keyName: {
47
+ type: String,
48
+ default: 'name'
49
+ },
50
+
51
+ // 查询列表的api地址
52
+ api: {
53
+ type: String,
54
+ default: ''
55
+ },
56
+
57
+ // 显示清除按钮
58
+ showClear: {
59
+ type: Boolean,
60
+ default: false
61
+ },
62
+ top: {
63
+ type: String,
64
+ default: '100'
65
+ },
66
+ // 初始化赋值的时候是否要显示,兼容小程序,小程序value会走watch
67
+ noShow: {
68
+ type: Boolean,
69
+ default: false
70
+ },
71
+ },
72
+ data() {
73
+ return {
74
+ content: '',
75
+ list: [],
76
+ curr: '',
77
+ showTips: false,
78
+ close: false
79
+ }
80
+ },
81
+ watch: {
82
+ value(newValue) {
83
+ this.content = newValue
84
+ this.onInput(newValue)
85
+ },
86
+ noShow(v) {
87
+ this.close = v
88
+ },
89
+ },
90
+ mounted() {
91
+ this.content = this.value
92
+ this.close = this.noShow
93
+ },
94
+ methods: {
95
+ clear() {
96
+ this.content = ''
97
+ this.curr = {}
98
+ this.showTips = false
99
+ this.$emit('change', this.curr)
100
+ this.$emit('input', '')
101
+ },
102
+
103
+ setRed(str) {
104
+ return this.content.toLocaleUpperCase().indexOf(str.toLocaleUpperCase()) > -1
105
+ },
106
+
107
+ // 名称输入
108
+ onInput(val) {
109
+ if (!val) {
110
+ this.clear()
111
+ this.curr = {}
112
+ this.showTips = false
113
+ this.$emit('change', this.curr)
114
+ this.$emit('input', '')
115
+ } else {
116
+ if (!this.curr[this.keyName]) {
117
+ debounce(this.search, 1000)
118
+ }
119
+ }
120
+ this.close = false
121
+ },
122
+
123
+ // 选中
124
+ select(item) {
125
+ this.showTips = false
126
+ this.content = item[this.keyName]
127
+ this.curr = item
128
+ this.$emit('input', this.content)
129
+ this.$emit('change', item)
130
+ setTimeout(() => {
131
+ this.curr = {}
132
+ })
133
+ },
134
+
135
+ onFocus() {
136
+ if (this.list.length) {
137
+ this.showTips = true
138
+ }
139
+ if (!this.content) {
140
+ this.list = []
141
+ }
142
+ },
143
+
144
+ closeTip() {
145
+ this.showTips = false
146
+ },
147
+
148
+ // 查找
149
+ async search() {
150
+ if (!this.api) {
151
+ return
152
+ }
153
+ if (!this.content) {
154
+ return
155
+ }
156
+ if (this.close) {
157
+ return
158
+ }
159
+ try {
160
+ const apiUrl = this.api.split('.')
161
+ const { data } = await this.$api[apiUrl[0]][apiUrl[1]](this.content, '', this.searchPosition)
162
+ this.list = data.lists || data.items || data || []
163
+ if (!this.list.length) {
164
+ this.$toast('未查找到相关内容')
165
+ } else {
166
+ this.showTips = true
167
+ }
168
+ this.$emit('finish', this.list)
169
+ } catch (e) {
170
+ this.curr = {}
171
+ this.showTips = false
172
+ this.$emit('change', this.curr)
173
+ console.log(e)
174
+ }
175
+ },
176
+ }
177
+ }
178
+ </script>
179
+
180
+ <style scoped lang="scss">
181
+ .keyword-select {
182
+ position: relative;
183
+ background: var(--bg-white);
184
+ display: flex;
185
+ .keyword-list {
186
+ width: 100%;
187
+ left: 0;
188
+ right: 0;
189
+ position: absolute;
190
+ background: var(--bg-white);
191
+ box-shadow: 0 12rpx 12rpx #dddddd;
192
+ z-index: 3;
193
+ max-height: 500rpx;
194
+ overflow-y: auto;
195
+ border-top: 1px solid var(--border-1);;
196
+ .keyword-item {
197
+ display: block;
198
+ padding: 24rpx;
199
+ color: #666666;
200
+ border-bottom: 1px solid var(--border-1);;
201
+ &:last-child {
202
+ border: 0;
203
+ }
204
+ &:active {
205
+ background-color: #EEEEEE;
206
+ }
207
+ &.kl-close {
208
+ display: flex;
209
+ justify-content: flex-end;
210
+ border: 0;
211
+ text {
212
+ font-size: 26rpx;
213
+ color: #999999;
214
+ }
215
+ }
216
+ }
217
+ .red {
218
+ color: red;
219
+ font-weight: bold;
220
+ }
221
+ }
222
+ .form-clear {
223
+ position: absolute;
224
+ right: 24rpx;
225
+ color: #999999;
226
+ top: 40%;
227
+ }
228
+ }
229
+ </style>
@@ -0,0 +1,64 @@
1
+ <template>
2
+ <view :class="{ isRelative }" class="ky-loading-box loading5">
3
+ <view class="shape shape1"></view>
4
+ <view class="shape shape2"></view>
5
+ <view class="shape shape3"></view>
6
+ </view>
7
+ </template>
8
+
9
+ <script>
10
+ export default {
11
+ props: {
12
+ isRelative: {
13
+ type: Boolean,
14
+ default: false,
15
+ }
16
+ }
17
+ }
18
+ </script>
19
+
20
+ <style scoped lang="scss">
21
+ .ky-loading-box {
22
+ height: 25rpx;
23
+ position: absolute;
24
+ top: 0;
25
+ left: 0;
26
+ right: 0;
27
+ bottom: 0;
28
+ margin: auto;
29
+ display: flex;
30
+ justify-content: center;
31
+ align-items: center;
32
+ z-index: 0;
33
+ &.isRelative {
34
+ position: relative;
35
+ min-height: 100rpx;
36
+ }
37
+ }
38
+ .shape {
39
+ width: 25rpx;
40
+ height: 25rpx;
41
+ border-radius: 50%;
42
+ background-color: var(--color-primary);
43
+ margin: 0 6rpx;
44
+ }
45
+ .shape1 {
46
+ animation: pulse .4s ease 0s infinite alternate;
47
+ }
48
+ .shape2 {
49
+ animation: pulse .4s ease .2s infinite alternate;
50
+ }
51
+ .shape3 {
52
+ animation: pulse .4s ease .4s infinite alternate;
53
+ }
54
+ @keyframes pulse {
55
+ from {
56
+ opacity: 1;
57
+ transform: scale(1);
58
+ }
59
+ to {
60
+ opacity: .25;
61
+ transform: scale(.5);
62
+ }
63
+ }
64
+ </style>
@@ -0,0 +1,47 @@
1
+ <template>
2
+ <!--未登录遮罩-->
3
+ <view class="nologin-mask">
4
+ <view class="nologin-btn">
5
+ <slot></slot>
6
+ <text class="block ft-24 mb-12 gray-color">{{ msg }}</text>
7
+ <ky-btn size="mini" width="200rpx" round @click="$nav.push('Login')">去登录</ky-btn>
8
+ </view>
9
+ </view>
10
+ <!--end 未登录遮罩-->
11
+ </template>
12
+
13
+ <script>
14
+ export default {
15
+ props: {
16
+ msg: {
17
+ type: String,
18
+ default: ''
19
+ }
20
+ }
21
+ }
22
+ </script>
23
+
24
+ <style scoped lang="scss">
25
+ .nologin-mask {
26
+ position: fixed;
27
+ z-index: 2;
28
+ left: 0;
29
+ right: 0;
30
+ top: 0;
31
+ bottom: 0;
32
+ width: 100%;
33
+ height: 100%;
34
+ background: linear-gradient(to top, var(--color-white) 45%, rgba(var(--rgb-white), 0.25));
35
+ display: flex;
36
+ align-items: center;
37
+ justify-content: center;
38
+ .nologin-btn {
39
+ margin-top: 100rpx;
40
+ width: 480rpx;
41
+ display: flex;
42
+ align-items: center;
43
+ justify-content: center;
44
+ flex-direction: column;
45
+ }
46
+ }
47
+ </style>
@@ -0,0 +1,86 @@
1
+ <!--悬浮电话按钮 首页、推荐产品页,产品详情页)-->
2
+ <template>
3
+ <view class="float-icon-box">
4
+ <view class="float-icon-wrap">
5
+ <view class="float-item" @click.stop="toPage('/pages/User/Feedback/Create')">
6
+ <text class="iconfont" style="font-size: 22rpx;">&#xe60e;</text>
7
+ <text class="iconname">建议</text>
8
+ </view>
9
+ <view class="float-item" @click.stop="callPhone">
10
+ <text v-if="noPhone" class="iconfont" >&#xe680;</text>
11
+ <text v-else class="iconfont">&#xe8ab;</text>
12
+ <text class="iconname">{{ !noPhone ? '客服' : '经纪人' }}</text>
13
+ </view>
14
+ </view>
15
+ </view>
16
+ </template>
17
+
18
+ <script>
19
+ import { useUserInfo, useToken } from '@/stores/index.js'
20
+ import config from '@/config.js'
21
+
22
+ export default {
23
+ data() {
24
+ return {}
25
+ },
26
+ computed: {
27
+ noPhone() {
28
+ return useUserInfo().value && useUserInfo().value.customerOwnerPhone
29
+ }
30
+ },
31
+ methods: {
32
+ callPhone() {
33
+ const user = useUserInfo().value
34
+ const phoneNumber = user.customerOwnerPhone || config.CONTACT
35
+ uni.makePhoneCall({ phoneNumber })
36
+ },
37
+
38
+ toPage(url) {
39
+ this.$nav.push(useToken().value ? url : '/pages/Login')
40
+ },
41
+ }
42
+ }
43
+ </script>
44
+
45
+ <style scoped lang="scss">
46
+ .float-icon-box {
47
+ position: fixed;
48
+ bottom: calc(var(--window-bottom) + env(safe-area-inset-bottom) + 24rpx);
49
+ right: 24rpx;
50
+ z-index: 99;
51
+ width: 75rpx;
52
+ }
53
+ .float-icon-menu {
54
+ position: relative;
55
+ z-index: 1;
56
+ }
57
+ .float-item {
58
+ width: 100%;
59
+ height: 75rpx;
60
+ background: linear-gradient(to bottom, var(--color-light-primary), var(--color-primary));
61
+ box-shadow: 0 0 12rpx rgba(0,0,0,.2);
62
+ display: flex;
63
+ flex-direction: column;
64
+ align-items: center;
65
+ justify-content: center;
66
+ border-radius: 50%;
67
+ margin-bottom: 24rpx;
68
+ &:active {
69
+ filter: contrast(2);
70
+ }
71
+ .iconfont {
72
+ display: block;
73
+ color: #f5f5f5;
74
+ font-size: 24rpx;
75
+ }
76
+ .iconname {
77
+ font-size: 14rpx;
78
+ color: #f5f5f5;
79
+ line-height: 10rpx;
80
+ margin-top: 8rpx;
81
+ /* #ifdef H5 */
82
+ transform: scale(0.7);
83
+ /* #endif */
84
+ }
85
+ }
86
+ </style>
@@ -0,0 +1,211 @@
1
+ <template>
2
+ <picker
3
+ :value="mode === 'selector' ? index : multiIndex"
4
+ :range="names"
5
+ :mode="mode"
6
+ :disabled="disabled"
7
+ :range-key="mode === 'selector' ? '' : 'name'"
8
+ @change="bindPickerChange"
9
+ @columnchange="onColumnchange"
10
+ >
11
+ <view v-if="!$slots.default">
12
+ <view v-if="mode === 'selector'" class="picker">
13
+ <text v-if="checked !== ''">{{ names[index] }}</text>
14
+ <text v-else class="gray-color">{{ placeholder }}</text>
15
+ </view>
16
+ <view v-else class="picker">
17
+ <text v-if="checked !== '' && checked.data[0]">{{ checked.data[0].name }} / {{ checked.data[1].name }}</text>
18
+ <text v-else class="gray-color">{{ placeholder }}</text>
19
+ </view>
20
+ </view>
21
+ <slot v-else></slot>
22
+ </picker>
23
+ </template>
24
+
25
+ <script>
26
+ export default {
27
+ emits: ['update:value', 'change'],
28
+ props: {
29
+ /**
30
+ * 回显对象
31
+ */
32
+ value: {
33
+ type: [Object, String, Number, Array],
34
+ },
35
+ /**
36
+ * 格式,[{ name: 'xx': id: 'xxx' }]
37
+ */
38
+ list: {
39
+ type: Array,
40
+ default: () => []
41
+ },
42
+ placeholder: {
43
+ type: String,
44
+ default: '请选择'
45
+ },
46
+ keyName: {
47
+ type: String,
48
+ default: 'name'
49
+ },
50
+ valueName: {
51
+ type: String,
52
+ default: 'id'
53
+ },
54
+ mode: {
55
+ type: String,
56
+ default: 'selector',
57
+ },
58
+ disabled: {
59
+ type: Boolean,
60
+ default: false,
61
+ }
62
+ },
63
+ data() {
64
+ return {
65
+ index: 0,
66
+ multiIndex: [0, 0],
67
+ names: [],
68
+ ids: [],
69
+ checked: ''
70
+ }
71
+ },
72
+ watch: {
73
+ value(v) {
74
+ this.mapVal(v)
75
+ },
76
+ list(v) {
77
+ this.mapList(v)
78
+ },
79
+ },
80
+ mounted() {
81
+ this.mapList(this.list)
82
+ this.mapVal(this.value)
83
+ },
84
+ methods: {
85
+ bindPickerChange({ detail }) {
86
+ if (this.mode === 'multiSelector') {
87
+ this.onMultichange(detail.value)
88
+ return
89
+ }
90
+ const index = +detail.value
91
+ const currVal = this.list[index]
92
+ this.checked = this.ids[index]
93
+ const valProps = this.setVal(this.value)
94
+ if (valProps === this.checked) {
95
+ return
96
+ }
97
+ this.index = index
98
+ currVal.index = index
99
+ this.$emit('update:value', this.checked)
100
+ this.$emit('change', currVal)
101
+ },
102
+ mapVal(v) {
103
+ if (typeof v === 'undefined') {
104
+ return
105
+ }
106
+ this.$nextTick(function() {
107
+ if (this.mode === 'multiSelector') {
108
+ return
109
+ }
110
+ const val = this.setVal(v)
111
+ const itemIndex = this.list.findIndex(e => e[this.valueName] == val)
112
+ this.index = itemIndex
113
+ this.checked = this.ids[itemIndex]
114
+ })
115
+ },
116
+ mapList(v) {
117
+ if (typeof v === 'undefined') {
118
+ return
119
+ }
120
+ if (this.mode === 'multiSelector') {
121
+ const secondColumn = []
122
+ const firstColumn = this.list.map((e, i) => {
123
+ if (e.child) {
124
+ e.child.forEach((j, k) => {
125
+ secondColumn.push({
126
+ parentId: e.id,
127
+ parentIndex: i,
128
+ id: j.id,
129
+ name: j.name,
130
+ })
131
+ })
132
+ }
133
+ return { id: e.id, name: e.name, index: i }
134
+ })
135
+ this.names = [firstColumn, secondColumn]
136
+ setTimeout(() => {
137
+ this.setMultiIndex(this.value, firstColumn, secondColumn)
138
+ }, 200)
139
+ return
140
+ }
141
+ this.names = v.map(e => e[this.keyName])
142
+ this.ids = v.map(e => e[this.valueName])
143
+ this.mapVal(this.value)
144
+ },
145
+ setVal(v) {
146
+ if (!v && typeof v !== 'number') {
147
+ return ''
148
+ }
149
+ if (typeof v === 'string' || typeof v === 'number') {
150
+ return v
151
+ }
152
+ return v[this.valueName]
153
+ },
154
+
155
+ // 根据id进行反选索引, 延迟是因为等待value变化
156
+ setMultiIndex(v, firstColumn, secondColumn) {
157
+ if (v.length) {
158
+ v.forEach(i => {
159
+ firstColumn.forEach((e) => {
160
+ if (i === e.id) {
161
+ this.multiIndex[0] = e.index
162
+ }
163
+ })
164
+ secondColumn.forEach((e, k) => {
165
+ if (i === e.id) {
166
+ this.multiIndex[1] = k
167
+ }
168
+ })
169
+ })
170
+ console.log(this.multiIndex)
171
+ this.onMultichange(this.multiIndex, false)
172
+ }
173
+ },
174
+
175
+ // 多列的时候触发修改
176
+ onColumnchange({ detail }) {
177
+
178
+ const { column, value } = detail
179
+ const result = [...this.multiIndex]
180
+
181
+ console.log(detail)
182
+
183
+ if (column === 0) {
184
+ result[0] = value
185
+ result[1] = this.names[1].findIndex(e => e.parentIndex === value)
186
+ } else {
187
+ result[0] = this.names[1].find((e, i) => i === value).parentIndex
188
+ result[1] = value
189
+ }
190
+
191
+ console.log(result)
192
+
193
+ this.multiIndex = result
194
+ },
195
+
196
+ // 多列完成的时候触发
197
+ onMultichange(val, noEmit) {
198
+ this.checked = {
199
+ index: val,
200
+ data: [this.names[0][val[0]], this.names[1][val[1]]]
201
+ }
202
+ if (!noEmit) {
203
+ this.$emit('update:value', this.checked)
204
+ this.$emit('input', val)
205
+ }
206
+ }
207
+ }
208
+ }
209
+ </script>
210
+
211
+ <style scoped lang="scss"></style>