@zamlia/mini-ui 0.0.1

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 (148) hide show
  1. package/es/components/common/BottomPopup/index.d.ts +78 -0
  2. package/es/components/common/BottomPopup/index.d.ts.map +1 -0
  3. package/es/components/common/Card/index.d.ts +33 -0
  4. package/es/components/common/Card/index.d.ts.map +1 -0
  5. package/es/components/common/CardItem/index.d.ts +60 -0
  6. package/es/components/common/CardItem/index.d.ts.map +1 -0
  7. package/es/components/common/DataSelect/index.d.ts +15 -0
  8. package/es/components/common/DataSelect/index.d.ts.map +1 -0
  9. package/es/components/common/Modal/index.d.ts +31 -0
  10. package/es/components/common/Modal/index.d.ts.map +1 -0
  11. package/es/components/common/NavBar/index.d.ts +38 -0
  12. package/es/components/common/NavBar/index.d.ts.map +1 -0
  13. package/es/components/common/Page/index.d.ts +16 -0
  14. package/es/components/common/Page/index.d.ts.map +1 -0
  15. package/es/components/common/PullToPushRefresh/index.d.ts +94 -0
  16. package/es/components/common/PullToPushRefresh/index.d.ts.map +1 -0
  17. package/es/components/common/Radio/index.d.ts +26 -0
  18. package/es/components/common/Radio/index.d.ts.map +1 -0
  19. package/es/components/common/TabPane/index.d.ts +9 -0
  20. package/es/components/common/TabPane/index.d.ts.map +1 -0
  21. package/es/components/common/Tabs/index.d.ts +27 -0
  22. package/es/components/common/Tabs/index.d.ts.map +1 -0
  23. package/es/components/common/UploadFile/index.d.ts +50 -0
  24. package/es/components/common/UploadFile/index.d.ts.map +1 -0
  25. package/es/components/common/UploadFile/upload.d.ts +11 -0
  26. package/es/components/common/UploadFile/upload.d.ts.map +1 -0
  27. package/es/components/common/UploadFile/utils.d.ts +20 -0
  28. package/es/components/common/UploadFile/utils.d.ts.map +1 -0
  29. package/es/components/common/VideoView/index.d.ts +14 -0
  30. package/es/components/common/VideoView/index.d.ts.map +1 -0
  31. package/es/components/common/index.d.ts +23 -0
  32. package/es/components/common/index.d.ts.map +1 -0
  33. package/es/components/industry/CitySelectButton/index.d.ts +17 -0
  34. package/es/components/industry/CitySelectButton/index.d.ts.map +1 -0
  35. package/es/components/industry/CitySelectModal/index.d.ts +13 -0
  36. package/es/components/industry/CitySelectModal/index.d.ts.map +1 -0
  37. package/es/components/industry/PaymentMethodSelect/index.d.ts +59 -0
  38. package/es/components/industry/PaymentMethodSelect/index.d.ts.map +1 -0
  39. package/es/components/industry/index.d.ts +5 -0
  40. package/es/components/industry/index.d.ts.map +1 -0
  41. package/es/config/classPrefix.d.ts +36 -0
  42. package/es/config/classPrefix.d.ts.map +1 -0
  43. package/es/index.d.ts +4 -0
  44. package/es/index.d.ts.map +1 -0
  45. package/es/index.js +5334 -0
  46. package/es/index.js.map +1 -0
  47. package/es/styles/_base.scss +4 -0
  48. package/es/styles/index.scss +19 -0
  49. package/es/styles/mixins.scss +15 -0
  50. package/es/styles/variables.scss +2 -0
  51. package/es/utils/city.d.ts +4005 -0
  52. package/es/utils/city.d.ts.map +1 -0
  53. package/es/utils/index.d.ts +50 -0
  54. package/es/utils/index.d.ts.map +1 -0
  55. package/lib/components/common/BottomPopup/index.d.ts +78 -0
  56. package/lib/components/common/BottomPopup/index.d.ts.map +1 -0
  57. package/lib/components/common/Card/index.d.ts +33 -0
  58. package/lib/components/common/Card/index.d.ts.map +1 -0
  59. package/lib/components/common/CardItem/index.d.ts +60 -0
  60. package/lib/components/common/CardItem/index.d.ts.map +1 -0
  61. package/lib/components/common/DataSelect/index.d.ts +15 -0
  62. package/lib/components/common/DataSelect/index.d.ts.map +1 -0
  63. package/lib/components/common/Modal/index.d.ts +31 -0
  64. package/lib/components/common/Modal/index.d.ts.map +1 -0
  65. package/lib/components/common/NavBar/index.d.ts +38 -0
  66. package/lib/components/common/NavBar/index.d.ts.map +1 -0
  67. package/lib/components/common/Page/index.d.ts +16 -0
  68. package/lib/components/common/Page/index.d.ts.map +1 -0
  69. package/lib/components/common/PullToPushRefresh/index.d.ts +94 -0
  70. package/lib/components/common/PullToPushRefresh/index.d.ts.map +1 -0
  71. package/lib/components/common/Radio/index.d.ts +26 -0
  72. package/lib/components/common/Radio/index.d.ts.map +1 -0
  73. package/lib/components/common/TabPane/index.d.ts +9 -0
  74. package/lib/components/common/TabPane/index.d.ts.map +1 -0
  75. package/lib/components/common/Tabs/index.d.ts +27 -0
  76. package/lib/components/common/Tabs/index.d.ts.map +1 -0
  77. package/lib/components/common/UploadFile/index.d.ts +50 -0
  78. package/lib/components/common/UploadFile/index.d.ts.map +1 -0
  79. package/lib/components/common/UploadFile/upload.d.ts +11 -0
  80. package/lib/components/common/UploadFile/upload.d.ts.map +1 -0
  81. package/lib/components/common/UploadFile/utils.d.ts +20 -0
  82. package/lib/components/common/UploadFile/utils.d.ts.map +1 -0
  83. package/lib/components/common/VideoView/index.d.ts +14 -0
  84. package/lib/components/common/VideoView/index.d.ts.map +1 -0
  85. package/lib/components/common/index.d.ts +23 -0
  86. package/lib/components/common/index.d.ts.map +1 -0
  87. package/lib/components/industry/CitySelectButton/index.d.ts +17 -0
  88. package/lib/components/industry/CitySelectButton/index.d.ts.map +1 -0
  89. package/lib/components/industry/CitySelectModal/index.d.ts +13 -0
  90. package/lib/components/industry/CitySelectModal/index.d.ts.map +1 -0
  91. package/lib/components/industry/PaymentMethodSelect/index.d.ts +59 -0
  92. package/lib/components/industry/PaymentMethodSelect/index.d.ts.map +1 -0
  93. package/lib/components/industry/index.d.ts +5 -0
  94. package/lib/components/industry/index.d.ts.map +1 -0
  95. package/lib/config/classPrefix.d.ts +36 -0
  96. package/lib/config/classPrefix.d.ts.map +1 -0
  97. package/lib/index.d.ts +585 -0
  98. package/lib/index.d.ts.map +1 -0
  99. package/lib/index.js +5349 -0
  100. package/lib/index.js.map +1 -0
  101. package/lib/styles/_base.scss +4 -0
  102. package/lib/styles/index.scss +19 -0
  103. package/lib/styles/mixins.scss +15 -0
  104. package/lib/styles/variables.scss +2 -0
  105. package/lib/utils/city.d.ts +4005 -0
  106. package/lib/utils/city.d.ts.map +1 -0
  107. package/lib/utils/index.d.ts +50 -0
  108. package/lib/utils/index.d.ts.map +1 -0
  109. package/package.json +81 -0
  110. package/src/components/common/BottomPopup/index.scss +34 -0
  111. package/src/components/common/BottomPopup/index.tsx +129 -0
  112. package/src/components/common/Card/index.scss +160 -0
  113. package/src/components/common/Card/index.tsx +72 -0
  114. package/src/components/common/CardItem/index.tsx +153 -0
  115. package/src/components/common/DataSelect/index.tsx +86 -0
  116. package/src/components/common/Modal/index.scss +49 -0
  117. package/src/components/common/Modal/index.tsx +105 -0
  118. package/src/components/common/NavBar/index.scss +26 -0
  119. package/src/components/common/NavBar/index.tsx +81 -0
  120. package/src/components/common/Page/index.scss +19 -0
  121. package/src/components/common/Page/index.tsx +56 -0
  122. package/src/components/common/PullToPushRefresh/index.scss +38 -0
  123. package/src/components/common/PullToPushRefresh/index.tsx +338 -0
  124. package/src/components/common/Radio/index.scss +15 -0
  125. package/src/components/common/Radio/index.tsx +56 -0
  126. package/src/components/common/TabPane/index.tsx +26 -0
  127. package/src/components/common/Tabs/index.scss +60 -0
  128. package/src/components/common/Tabs/index.tsx +107 -0
  129. package/src/components/common/UploadFile/index.scss +59 -0
  130. package/src/components/common/UploadFile/index.tsx +321 -0
  131. package/src/components/common/UploadFile/upload.ts +63 -0
  132. package/src/components/common/UploadFile/utils.ts +81 -0
  133. package/src/components/common/VideoView/index.tsx +50 -0
  134. package/src/components/common/index.ts +23 -0
  135. package/src/components/industry/CitySelectButton/index.tsx +76 -0
  136. package/src/components/industry/CitySelectModal/index.scss +122 -0
  137. package/src/components/industry/CitySelectModal/index.tsx +121 -0
  138. package/src/components/industry/PaymentMethodSelect/index.scss +146 -0
  139. package/src/components/industry/PaymentMethodSelect/index.tsx +316 -0
  140. package/src/components/industry/index.ts +5 -0
  141. package/src/config/classPrefix.ts +44 -0
  142. package/src/index.ts +9 -0
  143. package/src/styles/_base.scss +4 -0
  144. package/src/styles/index.scss +19 -0
  145. package/src/styles/mixins.scss +15 -0
  146. package/src/styles/variables.scss +2 -0
  147. package/src/utils/city.ts +4072 -0
  148. package/src/utils/index.ts +155 -0
@@ -0,0 +1,122 @@
1
+ // 样式基础文件(变量和 mixin)已通过 Taro 配置自动注入,无需手动导入
2
+ .we-select-city {
3
+ .nut-overlay {
4
+ z-index: 2001;
5
+ }
6
+
7
+ &__wrapper {
8
+ padding-bottom: 50px;
9
+ box-sizing: border-box;
10
+ width: 100vw;
11
+ height: 100vh;
12
+ overflow: hidden;
13
+ background: #ffffff;
14
+ }
15
+
16
+ // &__content {}
17
+
18
+ &__title {
19
+ display: flex;
20
+ align-items: center;
21
+ margin-bottom: 34px;
22
+ padding-inline: 20px;
23
+ box-sizing: border-box;
24
+ font-size: 48px;
25
+ color: #303030;
26
+
27
+ &__back {
28
+ margin-right: 20px;
29
+ }
30
+ }
31
+
32
+ &__search {
33
+ padding: 0 40px 0 50px;
34
+ box-sizing: border-box;
35
+ margin: 0 auto 48px;
36
+ display: flex;
37
+ align-items: center;
38
+ width: 670px;
39
+ height: 74px;
40
+ background: #F5F5F5;
41
+ border-radius: 37px;
42
+
43
+ .nut-input {
44
+ padding-left: 12px;
45
+ background: transparent;
46
+ }
47
+
48
+ &-icon {
49
+ width: 31px;
50
+ height: 31px;
51
+ }
52
+
53
+ &-btn {
54
+ width: 74px;
55
+ height: 74px;
56
+ display: flex;
57
+ align-items: center;
58
+ justify-content: center;
59
+ font-size: 26px;
60
+ color: $primary-color;
61
+ }
62
+ }
63
+
64
+ &__hot {
65
+ margin-bottom: 30px;
66
+
67
+ &-title {
68
+ margin-bottom: 30px;
69
+ padding-inline: 20px;
70
+ box-sizing: border-box;
71
+ font-size: 34px;
72
+ color: #303030;
73
+ }
74
+
75
+ &-list {
76
+ margin: 0 auto;
77
+ width: 690px;
78
+ display: flex;
79
+ align-items: center;
80
+ flex-wrap: wrap;
81
+
82
+ &-item {
83
+ margin-bottom: 18px;
84
+ margin-right: 20px;
85
+ height: 68px;
86
+ text-align: center;
87
+ line-height: 68px;
88
+ background: #F5F5F5;
89
+ border-radius: 10px;
90
+ font-size: 28px;
91
+ border-radius: 10px;
92
+ @include text-ellipsis(calc(690px / 4 - 10px * 3))
93
+ }
94
+
95
+ &-item:nth-child(4n) {
96
+ margin-right: 0;
97
+ }
98
+ }
99
+ }
100
+
101
+ &__list {
102
+ height: calc(100vh - 250px);
103
+ overflow-y: scroll;
104
+
105
+ &-item {
106
+ padding-left: 10px;
107
+ box-sizing: border-box;
108
+ margin: 0 auto;
109
+ display: flex;
110
+ align-items: center;
111
+ width: 690px;
112
+ height: 86px;
113
+ font-size: 28px;
114
+ border-radius: 10px;
115
+ border-bottom: 1px solid #f7f4f4;
116
+ }
117
+
118
+ &-item:nth-last-child(1) {
119
+ border-bottom: none;
120
+ }
121
+ }
122
+ }
@@ -0,0 +1,121 @@
1
+ import React, { useState } from 'react';
2
+ import { View } from '@tarojs/components';
3
+ import { Input, Overlay } from '@nutui/nutui-react-taro';
4
+ import { ArrowLeft, Search } from '@nutui/icons-react-taro';
5
+ import DICT_CITY from '@utils/city';
6
+ import { Utils } from '@utils';
7
+ import Taro from '@tarojs/taro';
8
+ import './index.scss';
9
+
10
+ export type CitySelectModalProps = {
11
+ visible: boolean
12
+ onChange: (city: CityData) => void
13
+ onClose: () => void
14
+ };
15
+
16
+ export type CityData = { id: string; value: string; }
17
+
18
+ const hotCity = [
19
+ { id: "510100", value: "成都" },
20
+ { id: "310000", value: "上海" },
21
+ { id: "320500", value: "苏州" },
22
+ { id: "440300", value: "深圳" },
23
+ { id: "110100", value: "北京" }
24
+ ]
25
+
26
+ const CitySelectModal: React.FC<CitySelectModalProps> = (props) => {
27
+ const {
28
+ visible,
29
+ onChange,
30
+ onClose
31
+ } = props;
32
+ const [list, setList] = useState<CityData[]>(DICT_CITY);
33
+ const [keyword, setKeyword] = useState<string>('');
34
+
35
+ const itemRender = (data: CityData) => {
36
+ return (
37
+ <View
38
+ className='we-select-city__list-item'
39
+ key={data?.id}
40
+ onClick={() => handleClick(data)}
41
+ >
42
+ {data?.value}
43
+ </View>
44
+ )
45
+ }
46
+
47
+ const handleConfirm = () => {
48
+ if (!keyword) setList(DICT_CITY)
49
+ const filter = DICT_CITY?.filter(it => it?.value?.indexOf(keyword) !== -1)
50
+
51
+ setList(filter)
52
+ }
53
+
54
+ /**
55
+ * 选择中
56
+ * @param {CityData}data
57
+ */
58
+ const handleClick = async (data: CityData) => {
59
+ Taro.showLoading({ title: '选择中...' })
60
+ await Utils.delay()
61
+
62
+ Taro.hideLoading({
63
+ complete: () => {
64
+ onChange(data)
65
+ onClose()
66
+ }
67
+ })
68
+ }
69
+
70
+ return (
71
+ <View className='we-select-city'>
72
+ <Overlay visible={visible} onClick={() => { }}>
73
+ <View className='we-select-city__wrapper'>
74
+ <View className='we-select-city__content'>
75
+ <View className='we-select-city__title' onClick={onClose}>
76
+ <View className='we-select-city__title-back'>
77
+ <ArrowLeft />
78
+ </View>
79
+ 选择城市
80
+ </View>
81
+ <View className='we-select-city__search'>
82
+ <View className="we-select-city__search-icon">
83
+ <Search />
84
+ </View>
85
+ <Input
86
+ placeholder="请输入城市名称"
87
+ value={keyword}
88
+ onChange={(v) => setKeyword(v)}
89
+ onConfirm={handleConfirm}
90
+ />
91
+ <View className="we-select-city__search-btn" onClick={handleConfirm}>
92
+ 搜索
93
+ </View>
94
+ </View>
95
+ <View className='we-select-city__list'>
96
+ <View className='we-select-city__hot'>
97
+ <View className='we-select-city__hot-title'>热门城市</View>
98
+ <View className='we-select-city__hot-list'>
99
+ {
100
+ hotCity?.map(it => (
101
+ <View
102
+ className='we-select-city__hot-list-item'
103
+ onClick={() => handleClick(it)}
104
+ key={it?.id}
105
+ >
106
+ {it?.value}
107
+ </View>
108
+ ))
109
+ }
110
+ </View>
111
+ </View>
112
+ {list?.map(it => itemRender(it))}
113
+ </View>
114
+ </View>
115
+ </View>
116
+ </Overlay>
117
+ </View>
118
+ );
119
+ };
120
+
121
+ export default CitySelectModal;
@@ -0,0 +1,146 @@
1
+ .we-payment-method {
2
+ padding: 32px 32px 40px;
3
+ min-height: 400px;
4
+
5
+ &__item {
6
+ display: flex;
7
+ align-items: center;
8
+ justify-content: space-between;
9
+ padding: 24px 0;
10
+ border-bottom: 1px solid #f5f5f5;
11
+ cursor: pointer;
12
+ transition: background-color 0.2s;
13
+
14
+ &:active {
15
+ background-color: #fafafa;
16
+ }
17
+
18
+ &:last-of-type {
19
+ border-bottom: none;
20
+ }
21
+ }
22
+
23
+ &__item-left {
24
+ display: flex;
25
+ align-items: center;
26
+ flex: 1;
27
+ }
28
+
29
+ &__icon {
30
+ width: 64px;
31
+ height: 64px;
32
+ border-radius: 8px;
33
+ display: flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ margin-right: 24px;
37
+ flex-shrink: 0;
38
+ }
39
+
40
+ &__icon-wechat {
41
+ background-color: #07c160;
42
+ position: relative;
43
+ }
44
+
45
+ &__icon-wechat-inner {
46
+ width: 40px;
47
+ height: 40px;
48
+ background-color: #fff;
49
+ border-radius: 6px;
50
+ position: relative;
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: center;
54
+ }
55
+
56
+ &__icon-wechat-dot {
57
+ width: 6px;
58
+ height: 6px;
59
+ background-color: #07c160;
60
+ border-radius: 50%;
61
+ position: absolute;
62
+
63
+ &:first-child {
64
+ top: 8px;
65
+ left: 8px;
66
+ }
67
+
68
+ &:last-child {
69
+ bottom: 8px;
70
+ right: 8px;
71
+ }
72
+ }
73
+
74
+ &__icon-alipay {
75
+ background-color: #1677ff;
76
+ }
77
+
78
+ &__icon-alipay-text {
79
+ color: #fff;
80
+ font-size: 36px;
81
+ font-weight: 600;
82
+ }
83
+
84
+ &__name {
85
+ font-size: 32px;
86
+ color: #333;
87
+ font-weight: 400;
88
+ }
89
+
90
+ &__check {
91
+ width: 40px;
92
+ height: 40px;
93
+ border-radius: 50%;
94
+ border: 2px solid #d9d9d9;
95
+ display: flex;
96
+ align-items: center;
97
+ justify-content: center;
98
+ flex-shrink: 0;
99
+ transition: all 0.2s;
100
+ }
101
+
102
+ &__check-selected {
103
+ background-color: #1677ff;
104
+ border-color: #1677ff;
105
+ }
106
+
107
+ &__check-icon {
108
+ width: 20px;
109
+ height: 20px;
110
+ position: relative;
111
+
112
+ &::before,
113
+ &::after {
114
+ content: '';
115
+ position: absolute;
116
+ background-color: #fff;
117
+ border-radius: 2px;
118
+ }
119
+
120
+ &::before {
121
+ width: 2px;
122
+ height: 10px;
123
+ left: 6px;
124
+ top: 2px;
125
+ transform: rotate(45deg);
126
+ }
127
+
128
+ &::after {
129
+ width: 2px;
130
+ height: 6px;
131
+ right: 6px;
132
+ top: 6px;
133
+ transform: rotate(-45deg);
134
+ }
135
+ }
136
+
137
+ &__footer {
138
+ margin-top: 40px;
139
+ padding-top: 32px;
140
+ border-top: 1px solid #f5f5f5;
141
+ }
142
+
143
+ &__confirm-btn {
144
+ width: 100%;
145
+ }
146
+ }
@@ -0,0 +1,316 @@
1
+ import React, { useState, useEffect } from 'react'
2
+ import { View, Text } from '@tarojs/components'
3
+ import BottomPopup from '@components/common/BottomPopup'
4
+ import { prefixClass, prefixElement } from '@config/classPrefix'
5
+ import classNames from 'classnames'
6
+ import { Button } from '@nutui/nutui-react-taro'
7
+ import './index.scss'
8
+
9
+ export type PaymentMethod = 'WECHAT' | 'ALIPAY'
10
+
11
+ export interface PaymentMethodSelectProps {
12
+ /**
13
+ * 实例 ID,用于区分多个实例
14
+ */
15
+ id: string
16
+ /**
17
+ * 默认选中的支付方式
18
+ * @default 'wechat'
19
+ */
20
+ defaultMethod?: PaymentMethod
21
+ /**
22
+ * 确认按钮文本
23
+ * @default '确认支付'
24
+ */
25
+ confirmText?: string
26
+ }
27
+
28
+ interface PaymentMethodSelectInstance {
29
+ id: string
30
+ visible: boolean
31
+ selectedMethod: PaymentMethod
32
+ resolvePromise: ((value: PaymentMethod | null) => void) | null
33
+ defaultMethod: PaymentMethod
34
+ confirmText: string
35
+ }
36
+
37
+ // 全局实例管理器
38
+ const instances = new Map<string, PaymentMethodSelectInstance>()
39
+
40
+ // 更新通知回调 Map
41
+ const updateCallbacks = new Map<string, (() => void)>()
42
+
43
+ /**
44
+ * 通知指定实例的组件更新
45
+ */
46
+ const notifyUpdate = (id: string) => {
47
+ const callback = updateCallbacks.get(id)
48
+ if (callback) {
49
+ callback()
50
+ }
51
+ }
52
+
53
+ // 支付方式配置
54
+ const paymentMethods: Array<{
55
+ key: PaymentMethod
56
+ name: string
57
+ }> = [
58
+ {
59
+ key: 'WECHAT',
60
+ name: '微信支付',
61
+ },
62
+ {
63
+ key: 'ALIPAY',
64
+ name: '支付宝支付',
65
+ },
66
+ ]
67
+
68
+ // 内部组件实现
69
+ const PaymentMethodSelectComponent: React.FC<PaymentMethodSelectProps> = (props) => {
70
+ const { id, defaultMethod = 'WECHAT', confirmText = '确认支付' } = props
71
+
72
+ // 初始化实例
73
+ useEffect(() => {
74
+ if (!instances.has(id)) {
75
+ instances.set(id, {
76
+ id,
77
+ visible: false,
78
+ selectedMethod: defaultMethod,
79
+ resolvePromise: null,
80
+ defaultMethod,
81
+ confirmText,
82
+ })
83
+ } else {
84
+ // 更新配置
85
+ const instance = instances.get(id)!
86
+ instance.defaultMethod = defaultMethod
87
+ instance.confirmText = confirmText
88
+ }
89
+ }, [id, defaultMethod, confirmText])
90
+
91
+ // 监听全局状态变化
92
+ const [instance, setInstance] = useState<PaymentMethodSelectInstance | null>(
93
+ instances.get(id) || null
94
+ )
95
+
96
+ useEffect(() => {
97
+ // 注册更新回调
98
+ const callback = () => {
99
+ const currentInstance = instances.get(id)
100
+ if (currentInstance) {
101
+ setInstance({ ...currentInstance })
102
+ }
103
+ }
104
+ updateCallbacks.set(id, callback)
105
+
106
+ return () => {
107
+ updateCallbacks.delete(id)
108
+ }
109
+ }, [id])
110
+
111
+ // 如果实例不存在,返回 null
112
+ if (!instance) {
113
+ return null
114
+ }
115
+
116
+ const { visible, selectedMethod } = instance
117
+
118
+ // 选择支付方式
119
+ const handleSelectMethod = (method: PaymentMethod) => {
120
+ const currentInstance = instances.get(id)
121
+ if (currentInstance) {
122
+ currentInstance.selectedMethod = method
123
+ notifyUpdate(id)
124
+ }
125
+ }
126
+
127
+ // 确认支付
128
+ const handleConfirm = () => {
129
+ const currentInstance = instances.get(id)
130
+ if (currentInstance && currentInstance.resolvePromise) {
131
+ currentInstance.resolvePromise(currentInstance.selectedMethod)
132
+ currentInstance.resolvePromise = null
133
+ currentInstance.visible = false
134
+ notifyUpdate(id)
135
+ }
136
+ }
137
+
138
+ // 关闭弹窗时的处理
139
+ const handleClose = () => {
140
+ const currentInstance = instances.get(id)
141
+ if (currentInstance) {
142
+ if (currentInstance.resolvePromise) {
143
+ currentInstance.resolvePromise(null)
144
+ currentInstance.resolvePromise = null
145
+ }
146
+ currentInstance.visible = false
147
+ notifyUpdate(id)
148
+ }
149
+ }
150
+
151
+ return (
152
+ <BottomPopup
153
+ title="选择支付方式"
154
+ showClose
155
+ maskClose
156
+ visible={visible}
157
+ onClose={handleClose}
158
+ >
159
+ <View className={prefixClass('payment-method')}>
160
+ {paymentMethods.map((method) => (
161
+ <View
162
+ key={method.key}
163
+ className={classNames(
164
+ prefixElement('payment-method', 'item'),
165
+ {
166
+ [prefixElement('payment-method', 'item-selected')]: selectedMethod === method.key,
167
+ }
168
+ )}
169
+ onClick={() => handleSelectMethod(method.key)}
170
+ >
171
+ <View className={prefixElement('payment-method', 'item-left')}>
172
+ <View
173
+ className={classNames(
174
+ prefixElement('payment-method', 'icon'),
175
+ prefixElement('payment-method', `icon-${method.key}`)
176
+ )}
177
+ >
178
+ {method.key === 'WECHAT' && (
179
+ <View className={prefixElement('payment-method', 'icon-wechat-inner')}>
180
+ <View className={prefixElement('payment-method', 'icon-wechat-dot')} />
181
+ <View className={prefixElement('payment-method', 'icon-wechat-dot')} />
182
+ </View>
183
+ )}
184
+ {method.key === 'ALIPAY' && (
185
+ <Text className={prefixElement('payment-method', 'icon-alipay-text')}>支</Text>
186
+ )}
187
+ </View>
188
+ <Text className={prefixElement('payment-method', 'name')}>
189
+ {method.name}
190
+ </Text>
191
+ </View>
192
+ <View
193
+ className={classNames(
194
+ prefixElement('payment-method', 'check'),
195
+ {
196
+ [prefixElement('payment-method', 'check-selected')]: selectedMethod === method.key,
197
+ }
198
+ )}
199
+ >
200
+ {selectedMethod === method.key && (
201
+ <View className={prefixElement('payment-method', 'check-icon')} />
202
+ )}
203
+ </View>
204
+ </View>
205
+ ))}
206
+
207
+ <View className={prefixElement('payment-method', 'footer')}>
208
+ <Button
209
+ type="primary"
210
+ size="large"
211
+ onClick={handleConfirm}
212
+ className={prefixElement('payment-method', 'confirm-btn')}
213
+ >
214
+ {confirmText}
215
+ </Button>
216
+ </View>
217
+ </View>
218
+ </BottomPopup>
219
+ )
220
+ }
221
+
222
+ // 创建组件,包含静态方法
223
+ const PaymentMethodSelect = PaymentMethodSelectComponent as typeof PaymentMethodSelectComponent & {
224
+ /**
225
+ * 打开支付方式选择弹窗(静态方法)
226
+ *
227
+ * @param id 实例 ID,需要在页面中先渲染 <PaymentMethodSelect id={id} />
228
+ * @param options 可选配置
229
+ * @returns Promise<PaymentMethod | null> 返回选择的支付方式,取消时返回 null
230
+ *
231
+ * @example
232
+ * ```tsx
233
+ * // 在页面中渲染组件
234
+ * <PaymentMethodSelect id="payment" />
235
+ *
236
+ * // 然后调用静态方法
237
+ * const method = await PaymentMethodSelect.open('payment')
238
+ * if (method) {
239
+ * console.log('选择的支付方式:', method) // 'wechat' | 'alipay'
240
+ * } else {
241
+ * console.log('用户取消了选择')
242
+ * }
243
+ * ```
244
+ */
245
+ open: (id: string, options?: { defaultMethod?: PaymentMethod; confirmText?: string }) => Promise<PaymentMethod | null>
246
+
247
+ /**
248
+ * 关闭支付方式选择弹窗(静态方法)
249
+ *
250
+ * @param id 实例 ID
251
+ *
252
+ * @example
253
+ * ```tsx
254
+ * PaymentMethodSelect.close('payment')
255
+ * ```
256
+ */
257
+ close: (id: string) => void
258
+ }
259
+
260
+ /**
261
+ * 添加静态方法
262
+ * @param id
263
+ * @param options
264
+ * @returns
265
+ */
266
+ PaymentMethodSelect.open = (id: string, options?: { defaultMethod?: PaymentMethod; confirmText?: string }): Promise<PaymentMethod | null> => {
267
+ let instance = instances.get(id)
268
+
269
+ if (!instance) {
270
+ // 如果实例不存在,创建新实例
271
+ instance = {
272
+ id,
273
+ visible: false,
274
+ selectedMethod: options?.defaultMethod || 'WECHAT',
275
+ resolvePromise: null,
276
+ defaultMethod: options?.defaultMethod || 'WECHAT',
277
+ confirmText: options?.confirmText || '确认支付',
278
+ }
279
+ instances.set(id, instance)
280
+ console.warn(`PaymentMethodSelect: 实例 ${id} 不存在,已自动创建。建议在页面中先渲染 <PaymentMethodSelect id="${id}" />`)
281
+ }
282
+
283
+ // 更新配置
284
+ if (options) {
285
+ if (options.defaultMethod !== undefined) {
286
+ instance.defaultMethod = options.defaultMethod
287
+ instance.selectedMethod = options.defaultMethod
288
+ }
289
+ if (options.confirmText !== undefined) {
290
+ instance.confirmText = options.confirmText
291
+ }
292
+ }
293
+
294
+ return new Promise<PaymentMethod | null>((resolve) => {
295
+ instance!.resolvePromise = resolve
296
+ instance!.visible = true
297
+ instance!.selectedMethod = instance!.defaultMethod
298
+ notifyUpdate(id)
299
+ })
300
+ }
301
+
302
+ PaymentMethodSelect.close = (id: string) => {
303
+ const instance = instances.get(id)
304
+ if (instance) {
305
+ if (instance.resolvePromise) {
306
+ instance.resolvePromise(null)
307
+ instance.resolvePromise = null
308
+ }
309
+ instance.visible = false
310
+ notifyUpdate(id)
311
+ }
312
+ }
313
+
314
+ PaymentMethodSelectComponent.displayName = 'PaymentMethodSelect'
315
+
316
+ export default PaymentMethodSelect
@@ -0,0 +1,5 @@
1
+ export { default as PaymentMethodSelect } from './PaymentMethodSelect'
2
+ export { default as CitySelectButton } from './CitySelectButton';
3
+
4
+ export type { PaymentMethodSelectProps, PaymentMethod } from './PaymentMethodSelect'
5
+ export type { CitySelectButtonProps } from './CitySelectButton'