@uxda/appkit 4.0.0 → 4.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.
- package/.eslintrc.mjs +7 -7
- package/README.md +187 -187
- package/babel.config.js +12 -12
- package/dist/appkit.css +855 -36
- package/dist/assets/asset-DcH8Kg-2 +1 -0
- package/dist/index.js +3355 -610
- package/package.json +80 -78
- package/project.config.json +15 -15
- package/project.tt.json +13 -13
- package/rollup.config.mjs +56 -54
- package/src/Appkit.ts +65 -65
- package/src/balance/api/endpoints.ts +126 -126
- package/src/balance/api/index.ts +82 -82
- package/src/balance/components/AccountView.vue +748 -748
- package/src/balance/components/BalanceCard.vue +209 -209
- package/src/balance/components/BalanceReminder.vue +85 -85
- package/src/balance/components/ConsumptionFilter.vue +218 -218
- package/src/balance/components/ConsumptionRules.vue +68 -68
- package/src/balance/components/DateFilter.vue +226 -236
- package/src/balance/components/SecondBalance.vue +71 -71
- package/src/balance/components/Tip.vue +45 -45
- package/src/balance/components/index.ts +9 -9
- package/src/balance/types.ts +90 -90
- package/src/components/bt-cropper/index.vue +774 -0
- package/src/components/bt-cropper/utils/calcCropper.js +42 -0
- package/src/components/bt-cropper/utils/calcImagePosition.js +23 -0
- package/src/components/bt-cropper/utils/calcImageSize.js +37 -0
- package/src/components/bt-cropper/utils/calcPointDistance.js +12 -0
- package/src/components/bt-cropper/utils/calcRightAndBottom.js +7 -0
- package/src/components/bt-cropper/utils/ratio.js +3 -0
- package/src/components/bt-cropper/utils/tools.js +25 -0
- package/src/components/dd-area/index.vue +225 -225
- package/src/components/dd-icon/doc.md +21 -21
- package/src/components/dd-icon/index.vue +23 -23
- package/src/components/dd-notice-bar/index.vue +78 -78
- package/src/components/dd-search/doc.md +34 -34
- package/src/components/dd-search/index.vue +168 -168
- package/src/components/dd-selector/index.vue +124 -124
- package/src/components/dd-skeleton/doc.md +19 -0
- package/src/components/dd-skeleton/index.vue +36 -0
- package/src/components/ocr-id/index.vue +114 -114
- package/src/components/ocr-id/types.d.ts +12 -12
- package/src/global.ts +6 -6
- package/src/index.ts +89 -88
- package/src/main.scss +1 -1
- package/src/notice/api/endpoints.ts +17 -17
- package/src/notice/api/index.ts +82 -82
- package/src/notice/components/NoticeBanner.vue +243 -243
- package/src/notice/components/NoticeEntry.vue +99 -99
- package/src/notice/components/NoticeList.vue +315 -278
- package/src/notice/components/NoticePopup.vue +161 -163
- package/src/notice/components/index.ts +5 -6
- package/src/notice/components/useCommonList.ts +86 -86
- package/src/notice/components/useNotice.ts +35 -35
- package/src/notice/index.ts +1 -1
- package/src/notice/types.ts +25 -25
- package/src/payment/api/config.ts +7 -7
- package/src/payment/api/endpoints.ts +103 -103
- package/src/payment/api/index.ts +71 -71
- package/src/payment/components/AmountPicker.vue +93 -93
- package/src/payment/components/RechargeResult.vue +69 -69
- package/src/payment/components/RechargeView.vue +154 -154
- package/src/payment/components/RightsPicker.vue +105 -105
- package/src/payment/components/TradeView.vue +298 -298
- package/src/payment/components/UserAgreement.vue +234 -142
- package/src/payment/components/index.ts +22 -22
- package/src/payment/index.ts +5 -5
- package/src/payment/services/index.ts +16 -16
- package/src/payment/services/invoke-recharge.ts +25 -25
- package/src/payment/services/request-payment.ts +58 -58
- package/src/payment/types.ts +28 -28
- package/src/register/components/SelfRegistration.vue +254 -228
- package/src/register/components/index.ts +2 -2
- package/src/shared/components/AppDrawer.vue +58 -58
- package/src/shared/components/DeviceVersion.vue +68 -67
- package/src/shared/components/EmptyView.vue +33 -33
- package/src/shared/components/PageHeader.vue +79 -79
- package/src/shared/components/index.ts +5 -5
- package/src/shared/composables/index.ts +5 -2
- package/src/shared/composables/useCountdown.ts +46 -0
- package/src/shared/composables/useDragBox.ts +97 -0
- package/src/shared/composables/useEncode.ts +43 -0
- package/src/shared/composables/useSafeArea.ts +46 -46
- package/src/shared/composables/useTabbar.ts +24 -24
- package/src/shared/composables/useValidator.ts +31 -0
- package/src/shared/http/Http.ts +136 -135
- package/src/shared/http/index.ts +1 -1
- package/src/shared/http/types.ts +157 -157
- package/src/shared/index.ts +3 -3
- package/src/shared/weixin/payment.ts +38 -38
- package/src/styles/fonts.scss +2 -2
- package/src/styles/vars.scss +3 -3
- package/src/user/api/endpoints.ts +17 -0
- package/src/user/api/index.ts +87 -0
- package/src/{notice → user}/components/LoginSetting.vue +114 -112
- package/src/user/components/UserBinding.vue +307 -0
- package/src/user/components/UserBindingSuccess.vue +80 -0
- package/src/user/components/UserEntry.vue +142 -0
- package/src/user/components/UserFeedback.vue +440 -0
- package/src/user/components/UserFeedbackEntry.vue +192 -0
- package/src/user/components/UserHeadCrop.vue +65 -0
- package/src/user/components/UserInfo.vue +632 -0
- package/src/user/components/UserResourceEmpty.vue +75 -0
- package/src/user/components/index.ts +21 -0
- package/src/user/index.ts +1 -0
- package/tsconfig.json +30 -30
- package/types/global.d.ts +21 -21
- package/types/vue.d.ts +10 -10
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import ratio from './ratio'
|
|
2
|
+
import calcRightAndBottom from './calcRightAndBottom'
|
|
3
|
+
const defaultImagePosition = {
|
|
4
|
+
left: 0,
|
|
5
|
+
top: 0,
|
|
6
|
+
width: 9,
|
|
7
|
+
height: 16
|
|
8
|
+
}
|
|
9
|
+
const defaultTarget = {
|
|
10
|
+
width: 2,
|
|
11
|
+
height: 1
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 计算初始的裁剪框位置
|
|
15
|
+
* @param {*} imagePosition
|
|
16
|
+
* @param {*} target
|
|
17
|
+
*/
|
|
18
|
+
export default function (imagePosition = defaultImagePosition, target = defaultTarget) {
|
|
19
|
+
const cropperPosition = {
|
|
20
|
+
left: 0,
|
|
21
|
+
right: 0,
|
|
22
|
+
top: 0,
|
|
23
|
+
bottom: 0,
|
|
24
|
+
width: 0,
|
|
25
|
+
height: 0
|
|
26
|
+
}
|
|
27
|
+
const targetRatio = ratio(target.width, target.height)
|
|
28
|
+
const imageRatio = ratio(imagePosition.width, imagePosition.height)
|
|
29
|
+
if (targetRatio > imageRatio) {
|
|
30
|
+
cropperPosition.width = imagePosition.width
|
|
31
|
+
cropperPosition.height = cropperPosition.width / targetRatio
|
|
32
|
+
cropperPosition.left = imagePosition.left
|
|
33
|
+
cropperPosition.top = (imagePosition.height - cropperPosition.height) / 2 + imagePosition.top
|
|
34
|
+
} else {
|
|
35
|
+
cropperPosition.height = imagePosition.height
|
|
36
|
+
cropperPosition.width =
|
|
37
|
+
targetRatio === 0 ? imagePosition.width : cropperPosition.height * targetRatio
|
|
38
|
+
cropperPosition.left = (imagePosition.width - cropperPosition.width) / 2 + imagePosition.left
|
|
39
|
+
cropperPosition.top = imagePosition.top
|
|
40
|
+
}
|
|
41
|
+
return calcRightAndBottom(cropperPosition)
|
|
42
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import calcRightAndBottom from './calcRightAndBottom'
|
|
2
|
+
const defaultPosition = {
|
|
3
|
+
left: 0,
|
|
4
|
+
top: 0,
|
|
5
|
+
width: 0,
|
|
6
|
+
height: 0
|
|
7
|
+
}
|
|
8
|
+
const defaultTransfrom = {
|
|
9
|
+
imgTranslateX: 0,
|
|
10
|
+
imgTranslateY: 0,
|
|
11
|
+
imgScale: 1
|
|
12
|
+
}
|
|
13
|
+
// 先默认变换原点在中间
|
|
14
|
+
export default function (imagePosition = defaultPosition, transfrom = defaultTransfrom) {
|
|
15
|
+
const width = imagePosition.width * transfrom.imgScale
|
|
16
|
+
const height = imagePosition.height * transfrom.imgScale
|
|
17
|
+
return calcRightAndBottom({
|
|
18
|
+
left: imagePosition.left + transfrom.imgTranslateX - (width - imagePosition.width) / 2,
|
|
19
|
+
top: imagePosition.top + transfrom.imgTranslateY - (height - imagePosition.height) / 2,
|
|
20
|
+
width,
|
|
21
|
+
height
|
|
22
|
+
})
|
|
23
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import ratio from './ratio.js'
|
|
2
|
+
export default async function (
|
|
3
|
+
imageInfo,
|
|
4
|
+
container = {
|
|
5
|
+
width: 9,
|
|
6
|
+
height: 16
|
|
7
|
+
}
|
|
8
|
+
) {
|
|
9
|
+
const defaultcontainer = {
|
|
10
|
+
width: 9,
|
|
11
|
+
height: 16
|
|
12
|
+
}
|
|
13
|
+
if (!container) {
|
|
14
|
+
container = defaultcontainer
|
|
15
|
+
}
|
|
16
|
+
const containerRatio = ratio(container.width, container.height)
|
|
17
|
+
const imageRatio = ratio(imageInfo.width, imageInfo.height)
|
|
18
|
+
if (containerRatio > imageRatio) {
|
|
19
|
+
const width = container.height * imageRatio
|
|
20
|
+
const height = container.height
|
|
21
|
+
return {
|
|
22
|
+
width,
|
|
23
|
+
height,
|
|
24
|
+
left: (container.width - width) / 2,
|
|
25
|
+
top: 0
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
const width = container.width
|
|
29
|
+
const height = container.width / imageRatio
|
|
30
|
+
return {
|
|
31
|
+
width,
|
|
32
|
+
height,
|
|
33
|
+
left: 0,
|
|
34
|
+
top: (container.height - height) / 2
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 计算两点之间距离
|
|
3
|
+
* @param {*} point1
|
|
4
|
+
* @param {*} point2
|
|
5
|
+
*/
|
|
6
|
+
export default function (point1 = [0, 0], point2 = [0, 0]) {
|
|
7
|
+
const X1 = point1[0],
|
|
8
|
+
X2 = point2[0],
|
|
9
|
+
Y1 = point1[1],
|
|
10
|
+
Y2 = point2[1]
|
|
11
|
+
return Math.sqrt(Math.pow(X1 - X2, 2) + Math.pow(Y1 - Y2, 2))
|
|
12
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function getTouchPoints(touchs) {
|
|
2
|
+
return Array.from(touchs).map((ev) => {
|
|
3
|
+
return [ev.clientX, ev.clientY]
|
|
4
|
+
})
|
|
5
|
+
}
|
|
6
|
+
export function debounce(fn, wait = 200) {
|
|
7
|
+
var timer = null
|
|
8
|
+
console.log('debounce')
|
|
9
|
+
return function () {
|
|
10
|
+
if (timer !== null) {
|
|
11
|
+
clearTimeout(timer)
|
|
12
|
+
}
|
|
13
|
+
timer = setTimeout(fn, wait)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @description 睡眠
|
|
19
|
+
* @param {number} time 等待时间毫秒数
|
|
20
|
+
*/
|
|
21
|
+
export function sleep(time = 200) {
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
setTimeout(resolve, time)
|
|
24
|
+
})
|
|
25
|
+
}
|
|
@@ -1,225 +1,225 @@
|
|
|
1
|
-
<!--* NAME: index-->
|
|
2
|
-
<!--* AUTHOR: yanglong-->
|
|
3
|
-
<!--* UPDATE: 2022-02-21 17:43-->
|
|
4
|
-
<!--* TIP: 微信原生实现多列选择器-->
|
|
5
|
-
<script setup lang="ts">
|
|
6
|
-
import { computed, ref, watch } from 'vue'
|
|
7
|
-
import Taro from '@tarojs/taro'
|
|
8
|
-
import DdIcon from '../dd-icon/index.vue'
|
|
9
|
-
|
|
10
|
-
interface AreaItem {
|
|
11
|
-
value: string
|
|
12
|
-
shortId: string
|
|
13
|
-
label: string
|
|
14
|
-
children: AreaItem[]
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type AreaType = 'province' | 'city' | 'region'
|
|
18
|
-
|
|
19
|
-
export interface PropsType {
|
|
20
|
-
value?: string // 地址code
|
|
21
|
-
rightIcon?: boolean
|
|
22
|
-
placeholder?: string
|
|
23
|
-
disabled?: boolean
|
|
24
|
-
type?: AreaType
|
|
25
|
-
formatter?: (values: AreaItem[]) => string
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const props = withDefaults(defineProps<PropsType>(), {
|
|
29
|
-
value: '',
|
|
30
|
-
rightIcon: true,
|
|
31
|
-
placeholder: '请选择',
|
|
32
|
-
disabled: false,
|
|
33
|
-
type: 'region',
|
|
34
|
-
formatter: (values: AreaItem[]) => values.map((item: AreaItem) => item.label).join(''),
|
|
35
|
-
})
|
|
36
|
-
const emit = defineEmits(['update:value', 'change', 'cancel'])
|
|
37
|
-
|
|
38
|
-
const areaFormatOptions = computed<AreaItem[]>(() => {
|
|
39
|
-
const { province_list, city_list, county_list } = JSON.parse(Taro.getStorageSync('wechat_area'))
|
|
40
|
-
const map = new Map()
|
|
41
|
-
city_list.forEach((item: any) => {
|
|
42
|
-
const provinceShortId = item.id.slice(0, 2)
|
|
43
|
-
if (!map.has(provinceShortId)) {
|
|
44
|
-
map.set(provinceShortId, [])
|
|
45
|
-
}
|
|
46
|
-
map.get(provinceShortId).push({
|
|
47
|
-
...item,
|
|
48
|
-
shortId: item.id.slice(0, 4),
|
|
49
|
-
})
|
|
50
|
-
})
|
|
51
|
-
county_list.forEach((item: any) => {
|
|
52
|
-
const cityShortId = item.id.slice(0, 4)
|
|
53
|
-
if (!map.has(cityShortId)) {
|
|
54
|
-
map.set(cityShortId, [])
|
|
55
|
-
}
|
|
56
|
-
map.get(cityShortId).push({
|
|
57
|
-
...item,
|
|
58
|
-
shortId: item.id,
|
|
59
|
-
})
|
|
60
|
-
})
|
|
61
|
-
return province_list.map((province: any) => {
|
|
62
|
-
const provinceShortId = province.id.slice(0, 2)
|
|
63
|
-
return {
|
|
64
|
-
value: province.id,
|
|
65
|
-
shortId: provinceShortId,
|
|
66
|
-
label: province.name,
|
|
67
|
-
children:
|
|
68
|
-
(map.get(provinceShortId) || []).map((city: any) => ({
|
|
69
|
-
value: city.id,
|
|
70
|
-
shortId: city.shortId,
|
|
71
|
-
label: city.name,
|
|
72
|
-
children:
|
|
73
|
-
(map.get(city.shortId) || []).map((region: any) => ({
|
|
74
|
-
value: region.id,
|
|
75
|
-
shortId: region.shortId,
|
|
76
|
-
label: region.name,
|
|
77
|
-
children: [],
|
|
78
|
-
})) || [],
|
|
79
|
-
})) || [],
|
|
80
|
-
}
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
const tmpSelectedIndex = ref<number[]>([0, 0, 0])
|
|
85
|
-
const selectedIndex = ref<number[]>([0, 0, 0])
|
|
86
|
-
const selectedItem = ref<AreaItem[]>([])
|
|
87
|
-
|
|
88
|
-
const options = computed<AreaItem[][]>(() => {
|
|
89
|
-
const provinceOption = areaFormatOptions.value
|
|
90
|
-
if (props.type === 'province') {
|
|
91
|
-
return [provinceOption]
|
|
92
|
-
}
|
|
93
|
-
const cityOption = (provinceOption[tmpSelectedIndex.value[0]] || {}).children || []
|
|
94
|
-
if (props.type === 'city') {
|
|
95
|
-
return [provinceOption, cityOption]
|
|
96
|
-
}
|
|
97
|
-
const regionOption = (cityOption[tmpSelectedIndex.value[1]] || {}).children || []
|
|
98
|
-
return [provinceOption, cityOption, regionOption]
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
function init() {
|
|
102
|
-
selectedIndex.value = findIndexByValue()
|
|
103
|
-
tmpSelectedIndex.value = [...selectedIndex.value]
|
|
104
|
-
if (props.value) {
|
|
105
|
-
const items: any = []
|
|
106
|
-
for (let index = 0; index < options.value.length; index++) {
|
|
107
|
-
const item = (options.value[index] || {})[selectedIndex.value[index]]
|
|
108
|
-
if (item) {
|
|
109
|
-
items.push(item)
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
selectedItem.value = items
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function findIndexByValue() {
|
|
117
|
-
if (props.value) {
|
|
118
|
-
const provinceId = props.value.slice(0, 2).toString().padEnd(6, '0')
|
|
119
|
-
const cityId = props.value.slice(0, 4).toString().padEnd(6, '0')
|
|
120
|
-
const regionId = props.value.toString()
|
|
121
|
-
for (let provinceIndex = 0; provinceIndex < areaFormatOptions.value.length; provinceIndex++) {
|
|
122
|
-
const province = areaFormatOptions.value[provinceIndex]
|
|
123
|
-
if (provinceId == province.value) {
|
|
124
|
-
for (let cityIndex = 0; cityIndex < province.children.length; cityIndex++) {
|
|
125
|
-
const city = province.children[cityIndex]
|
|
126
|
-
if (cityId == city.value) {
|
|
127
|
-
for (let regionIndex = 0; regionIndex < city.children.length; regionIndex++) {
|
|
128
|
-
const region = city.children[regionIndex]
|
|
129
|
-
if (regionId == region.value) {
|
|
130
|
-
return [provinceIndex, cityIndex, regionIndex]
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return [provinceIndex, cityIndex, 0]
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return [provinceIndex, 0, 0]
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
return [0, 0, 0]
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function onChange() {
|
|
144
|
-
const lastSelectedIndex = options.value.length - 1
|
|
145
|
-
const result: any = {
|
|
146
|
-
values: [],
|
|
147
|
-
labels: [],
|
|
148
|
-
}
|
|
149
|
-
for (let index = 0; index <= lastSelectedIndex; index++) {
|
|
150
|
-
const item = (options.value[index] || {})[tmpSelectedIndex.value[index]]
|
|
151
|
-
if (item) {
|
|
152
|
-
result.values.push(item.value)
|
|
153
|
-
result.labels.push(item.label)
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
emit('update:value', result.values[result.values.length - 1])
|
|
157
|
-
emit('change', result)
|
|
158
|
-
console.log(result)
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function onCancel(e: any) {
|
|
162
|
-
init()
|
|
163
|
-
emit('cancel', e)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function onColumnChange({ detail: { column, value } }) {
|
|
167
|
-
const resetIndex = Array.from({ length: tmpSelectedIndex.value.length - column - 1 }).fill(0)
|
|
168
|
-
tmpSelectedIndex.value = [...tmpSelectedIndex.value.slice(0, column), value, ...resetIndex]
|
|
169
|
-
console.log(tmpSelectedIndex.value)
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
watch(
|
|
173
|
-
() => props.value,
|
|
174
|
-
() => {
|
|
175
|
-
init()
|
|
176
|
-
},
|
|
177
|
-
{ deep: true, immediate: true }
|
|
178
|
-
)
|
|
179
|
-
</script>
|
|
180
|
-
|
|
181
|
-
<template>
|
|
182
|
-
<picker
|
|
183
|
-
:range="options"
|
|
184
|
-
range-key="label"
|
|
185
|
-
:value="tmpSelectedIndex"
|
|
186
|
-
mode="multiSelector"
|
|
187
|
-
@columnchange="onColumnChange"
|
|
188
|
-
@change="onChange"
|
|
189
|
-
@cancel="onCancel"
|
|
190
|
-
style="flex: 1"
|
|
191
|
-
:disabled="props.disabled"
|
|
192
|
-
>
|
|
193
|
-
<div class="dd-area">
|
|
194
|
-
<div :class="props.value && !props.disabled ? 'dd-area-value' : 'dd-area-label'">
|
|
195
|
-
{{ props.value ? props.formatter(selectedItem) : props.placeholder }}
|
|
196
|
-
</div>
|
|
197
|
-
<slot name="icon">
|
|
198
|
-
<DdIcon
|
|
199
|
-
v-if="props.rightIcon"
|
|
200
|
-
name="icon-arrow"
|
|
201
|
-
size="11px"
|
|
202
|
-
:color="props.value !== '' && !props.disabled ? '#353535' : '#DFDFDF'"
|
|
203
|
-
class="icon-arrow"
|
|
204
|
-
/>
|
|
205
|
-
</slot>
|
|
206
|
-
</div>
|
|
207
|
-
</picker>
|
|
208
|
-
</template>
|
|
209
|
-
|
|
210
|
-
<style lang="scss">
|
|
211
|
-
.dd-area {
|
|
212
|
-
display: flex;
|
|
213
|
-
justify-content: flex-end;
|
|
214
|
-
align-items: center;
|
|
215
|
-
|
|
216
|
-
&-value {
|
|
217
|
-
text-align: right;
|
|
218
|
-
color: black;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
&-label {
|
|
222
|
-
color: var(--placeholder-color);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
</style>
|
|
1
|
+
<!--* NAME: index-->
|
|
2
|
+
<!--* AUTHOR: yanglong-->
|
|
3
|
+
<!--* UPDATE: 2022-02-21 17:43-->
|
|
4
|
+
<!--* TIP: 微信原生实现多列选择器-->
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
import { computed, ref, watch } from 'vue'
|
|
7
|
+
import Taro from '@tarojs/taro'
|
|
8
|
+
import DdIcon from '../dd-icon/index.vue'
|
|
9
|
+
|
|
10
|
+
interface AreaItem {
|
|
11
|
+
value: string
|
|
12
|
+
shortId: string
|
|
13
|
+
label: string
|
|
14
|
+
children: AreaItem[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type AreaType = 'province' | 'city' | 'region'
|
|
18
|
+
|
|
19
|
+
export interface PropsType {
|
|
20
|
+
value?: string // 地址code
|
|
21
|
+
rightIcon?: boolean
|
|
22
|
+
placeholder?: string
|
|
23
|
+
disabled?: boolean
|
|
24
|
+
type?: AreaType
|
|
25
|
+
formatter?: (values: AreaItem[]) => string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const props = withDefaults(defineProps<PropsType>(), {
|
|
29
|
+
value: '',
|
|
30
|
+
rightIcon: true,
|
|
31
|
+
placeholder: '请选择',
|
|
32
|
+
disabled: false,
|
|
33
|
+
type: 'region',
|
|
34
|
+
formatter: (values: AreaItem[]) => values.map((item: AreaItem) => item.label).join(''),
|
|
35
|
+
})
|
|
36
|
+
const emit = defineEmits(['update:value', 'change', 'cancel'])
|
|
37
|
+
|
|
38
|
+
const areaFormatOptions = computed<AreaItem[]>(() => {
|
|
39
|
+
const { province_list, city_list, county_list } = JSON.parse(Taro.getStorageSync('wechat_area'))
|
|
40
|
+
const map = new Map()
|
|
41
|
+
city_list.forEach((item: any) => {
|
|
42
|
+
const provinceShortId = item.id.slice(0, 2)
|
|
43
|
+
if (!map.has(provinceShortId)) {
|
|
44
|
+
map.set(provinceShortId, [])
|
|
45
|
+
}
|
|
46
|
+
map.get(provinceShortId).push({
|
|
47
|
+
...item,
|
|
48
|
+
shortId: item.id.slice(0, 4),
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
county_list.forEach((item: any) => {
|
|
52
|
+
const cityShortId = item.id.slice(0, 4)
|
|
53
|
+
if (!map.has(cityShortId)) {
|
|
54
|
+
map.set(cityShortId, [])
|
|
55
|
+
}
|
|
56
|
+
map.get(cityShortId).push({
|
|
57
|
+
...item,
|
|
58
|
+
shortId: item.id,
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
return province_list.map((province: any) => {
|
|
62
|
+
const provinceShortId = province.id.slice(0, 2)
|
|
63
|
+
return {
|
|
64
|
+
value: province.id,
|
|
65
|
+
shortId: provinceShortId,
|
|
66
|
+
label: province.name,
|
|
67
|
+
children:
|
|
68
|
+
(map.get(provinceShortId) || []).map((city: any) => ({
|
|
69
|
+
value: city.id,
|
|
70
|
+
shortId: city.shortId,
|
|
71
|
+
label: city.name,
|
|
72
|
+
children:
|
|
73
|
+
(map.get(city.shortId) || []).map((region: any) => ({
|
|
74
|
+
value: region.id,
|
|
75
|
+
shortId: region.shortId,
|
|
76
|
+
label: region.name,
|
|
77
|
+
children: [],
|
|
78
|
+
})) || [],
|
|
79
|
+
})) || [],
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
const tmpSelectedIndex = ref<number[]>([0, 0, 0])
|
|
85
|
+
const selectedIndex = ref<number[]>([0, 0, 0])
|
|
86
|
+
const selectedItem = ref<AreaItem[]>([])
|
|
87
|
+
|
|
88
|
+
const options = computed<AreaItem[][]>(() => {
|
|
89
|
+
const provinceOption = areaFormatOptions.value
|
|
90
|
+
if (props.type === 'province') {
|
|
91
|
+
return [provinceOption]
|
|
92
|
+
}
|
|
93
|
+
const cityOption = (provinceOption[tmpSelectedIndex.value[0]] || {}).children || []
|
|
94
|
+
if (props.type === 'city') {
|
|
95
|
+
return [provinceOption, cityOption]
|
|
96
|
+
}
|
|
97
|
+
const regionOption = (cityOption[tmpSelectedIndex.value[1]] || {}).children || []
|
|
98
|
+
return [provinceOption, cityOption, regionOption]
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
function init() {
|
|
102
|
+
selectedIndex.value = findIndexByValue()
|
|
103
|
+
tmpSelectedIndex.value = [...selectedIndex.value]
|
|
104
|
+
if (props.value) {
|
|
105
|
+
const items: any = []
|
|
106
|
+
for (let index = 0; index < options.value.length; index++) {
|
|
107
|
+
const item = (options.value[index] || {})[selectedIndex.value[index]]
|
|
108
|
+
if (item) {
|
|
109
|
+
items.push(item)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
selectedItem.value = items
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function findIndexByValue() {
|
|
117
|
+
if (props.value) {
|
|
118
|
+
const provinceId = props.value.slice(0, 2).toString().padEnd(6, '0')
|
|
119
|
+
const cityId = props.value.slice(0, 4).toString().padEnd(6, '0')
|
|
120
|
+
const regionId = props.value.toString()
|
|
121
|
+
for (let provinceIndex = 0; provinceIndex < areaFormatOptions.value.length; provinceIndex++) {
|
|
122
|
+
const province = areaFormatOptions.value[provinceIndex]
|
|
123
|
+
if (provinceId == province.value) {
|
|
124
|
+
for (let cityIndex = 0; cityIndex < province.children.length; cityIndex++) {
|
|
125
|
+
const city = province.children[cityIndex]
|
|
126
|
+
if (cityId == city.value) {
|
|
127
|
+
for (let regionIndex = 0; regionIndex < city.children.length; regionIndex++) {
|
|
128
|
+
const region = city.children[regionIndex]
|
|
129
|
+
if (regionId == region.value) {
|
|
130
|
+
return [provinceIndex, cityIndex, regionIndex]
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return [provinceIndex, cityIndex, 0]
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return [provinceIndex, 0, 0]
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return [0, 0, 0]
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function onChange() {
|
|
144
|
+
const lastSelectedIndex = options.value.length - 1
|
|
145
|
+
const result: any = {
|
|
146
|
+
values: [],
|
|
147
|
+
labels: [],
|
|
148
|
+
}
|
|
149
|
+
for (let index = 0; index <= lastSelectedIndex; index++) {
|
|
150
|
+
const item = (options.value[index] || {})[tmpSelectedIndex.value[index]]
|
|
151
|
+
if (item) {
|
|
152
|
+
result.values.push(item.value)
|
|
153
|
+
result.labels.push(item.label)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
emit('update:value', result.values[result.values.length - 1])
|
|
157
|
+
emit('change', result)
|
|
158
|
+
console.log(result)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function onCancel(e: any) {
|
|
162
|
+
init()
|
|
163
|
+
emit('cancel', e)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function onColumnChange({ detail: { column, value } }) {
|
|
167
|
+
const resetIndex = Array.from({ length: tmpSelectedIndex.value.length - column - 1 }).fill(0)
|
|
168
|
+
tmpSelectedIndex.value = [...tmpSelectedIndex.value.slice(0, column), value, ...resetIndex]
|
|
169
|
+
console.log(tmpSelectedIndex.value)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
watch(
|
|
173
|
+
() => props.value,
|
|
174
|
+
() => {
|
|
175
|
+
init()
|
|
176
|
+
},
|
|
177
|
+
{ deep: true, immediate: true }
|
|
178
|
+
)
|
|
179
|
+
</script>
|
|
180
|
+
|
|
181
|
+
<template>
|
|
182
|
+
<picker
|
|
183
|
+
:range="options"
|
|
184
|
+
range-key="label"
|
|
185
|
+
:value="tmpSelectedIndex"
|
|
186
|
+
mode="multiSelector"
|
|
187
|
+
@columnchange="onColumnChange"
|
|
188
|
+
@change="onChange"
|
|
189
|
+
@cancel="onCancel"
|
|
190
|
+
style="flex: 1"
|
|
191
|
+
:disabled="props.disabled"
|
|
192
|
+
>
|
|
193
|
+
<div class="dd-area">
|
|
194
|
+
<div :class="props.value && !props.disabled ? 'dd-area-value' : 'dd-area-label'">
|
|
195
|
+
{{ props.value ? props.formatter(selectedItem) : props.placeholder }}
|
|
196
|
+
</div>
|
|
197
|
+
<slot name="icon">
|
|
198
|
+
<DdIcon
|
|
199
|
+
v-if="props.rightIcon"
|
|
200
|
+
name="icon-arrow"
|
|
201
|
+
size="11px"
|
|
202
|
+
:color="props.value !== '' && !props.disabled ? '#353535' : '#DFDFDF'"
|
|
203
|
+
class="icon-arrow"
|
|
204
|
+
/>
|
|
205
|
+
</slot>
|
|
206
|
+
</div>
|
|
207
|
+
</picker>
|
|
208
|
+
</template>
|
|
209
|
+
|
|
210
|
+
<style lang="scss">
|
|
211
|
+
.dd-area {
|
|
212
|
+
display: flex;
|
|
213
|
+
justify-content: flex-end;
|
|
214
|
+
align-items: center;
|
|
215
|
+
|
|
216
|
+
&-value {
|
|
217
|
+
text-align: right;
|
|
218
|
+
color: black;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
&-label {
|
|
222
|
+
color: var(--placeholder-color);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
</style>
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
# ddIcon 空内容展示
|
|
2
|
-
### 使用iconfont图标
|
|
3
|
-
|
|
4
|
-
#
|
|
5
|
-
## 使用
|
|
6
|
-
|
|
7
|
-
``` javascript
|
|
8
|
-
import ddIcon from '~/components/ddIcon/index.vue'
|
|
9
|
-
```
|
|
10
|
-
``` html
|
|
11
|
-
<dd-icon name="icon-arrow" size="11px" color="#DFDFDF" />
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## Prop
|
|
15
|
-
|
|
16
|
-
| 字段 | 说明 | 类型 | 默认值 |
|
|
17
|
-
|-----------|-------------|---------|----------|
|
|
18
|
-
| name | icon名称 | string | '' |
|
|
19
|
-
| color | icon颜色 | string | inherit |
|
|
20
|
-
| size | icon字体大小 | string | 16px |
|
|
21
|
-
| weight | icon字体字重 | string | normal |
|
|
1
|
+
# ddIcon 空内容展示
|
|
2
|
+
### 使用iconfont图标
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
## 使用
|
|
6
|
+
|
|
7
|
+
``` javascript
|
|
8
|
+
import ddIcon from '~/components/ddIcon/index.vue'
|
|
9
|
+
```
|
|
10
|
+
``` html
|
|
11
|
+
<dd-icon name="icon-arrow" size="11px" color="#DFDFDF" />
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Prop
|
|
15
|
+
|
|
16
|
+
| 字段 | 说明 | 类型 | 默认值 |
|
|
17
|
+
|-----------|-------------|---------|----------|
|
|
18
|
+
| name | icon名称 | string | '' |
|
|
19
|
+
| color | icon颜色 | string | inherit |
|
|
20
|
+
| size | icon字体大小 | string | 16px |
|
|
21
|
+
| weight | icon字体字重 | string | normal |
|