hookehuyr

新增地址选择组件给身份证地址使用

...@@ -7,6 +7,7 @@ export {} ...@@ -7,6 +7,7 @@ export {}
7 7
8 declare module 'vue' { 8 declare module 'vue' {
9 export interface GlobalComponents { 9 export interface GlobalComponents {
10 + AddressSelector: typeof import('./src/components/AddressSelector.vue')['default']
10 BannerSwiper: typeof import('./src/components/BannerSwiper.vue')['default'] 11 BannerSwiper: typeof import('./src/components/BannerSwiper.vue')['default']
11 BrandModelPicker: typeof import('./src/components/BrandModelPicker.vue')['default'] 12 BrandModelPicker: typeof import('./src/components/BrandModelPicker.vue')['default']
12 FeaturedRecommendations: typeof import('./src/components/FeaturedRecommendations.vue')['default'] 13 FeaturedRecommendations: typeof import('./src/components/FeaturedRecommendations.vue')['default']
...@@ -15,6 +16,7 @@ declare module 'vue' { ...@@ -15,6 +16,7 @@ declare module 'vue' {
15 NavBar: typeof import('./src/components/navBar.vue')['default'] 16 NavBar: typeof import('./src/components/navBar.vue')['default']
16 NutActionSheet: typeof import('@nutui/nutui-taro')['ActionSheet'] 17 NutActionSheet: typeof import('@nutui/nutui-taro')['ActionSheet']
17 NutButton: typeof import('@nutui/nutui-taro')['Button'] 18 NutButton: typeof import('@nutui/nutui-taro')['Button']
19 + NutCascader: typeof import('@nutui/nutui-taro')['Cascader']
18 NutCheckbox: typeof import('@nutui/nutui-taro')['Checkbox'] 20 NutCheckbox: typeof import('@nutui/nutui-taro')['Checkbox']
19 NutCol: typeof import('@nutui/nutui-taro')['Col'] 21 NutCol: typeof import('@nutui/nutui-taro')['Col']
20 NutConfigProvider: typeof import('@nutui/nutui-taro')['ConfigProvider'] 22 NutConfigProvider: typeof import('@nutui/nutui-taro')['ConfigProvider']
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
37 "license": "MIT", 37 "license": "MIT",
38 "dependencies": { 38 "dependencies": {
39 "@babel/runtime": "^7.7.7", 39 "@babel/runtime": "^7.7.7",
40 + "@nutui/icons-vue": "^0.1.1",
40 "@nutui/icons-vue-taro": "^0.0.9", 41 "@nutui/icons-vue-taro": "^0.0.9",
41 "@nutui/nutui-taro": "^4.3.13", 42 "@nutui/nutui-taro": "^4.3.13",
42 "@tarojs/components": "4.1.2", 43 "@tarojs/components": "4.1.2",
...@@ -55,6 +56,7 @@ ...@@ -55,6 +56,7 @@
55 "@tarojs/shared": "4.1.2", 56 "@tarojs/shared": "4.1.2",
56 "@tarojs/taro": "4.1.2", 57 "@tarojs/taro": "4.1.2",
57 "axios-miniprogram": "^2.7.2", 58 "axios-miniprogram": "^2.7.2",
59 + "element-china-area-data": "^6.1.0",
58 "pinia": "^3.0.3", 60 "pinia": "^3.0.3",
59 "taro-plugin-pinia": "^1.0.0", 61 "taro-plugin-pinia": "^1.0.0",
60 "vue": "^3.3.0" 62 "vue": "^3.3.0"
......
This diff could not be displayed because it is too large.
...@@ -47,6 +47,12 @@ button::after { ...@@ -47,6 +47,12 @@ button::after {
47 color: #9ca3af; 47 color: #9ca3af;
48 } 48 }
49 49
50 +/* 覆盖 NutUI Tabs 组件的 width: 0 样式 */
51 +.nut-tabs.horizontal .nut-sticky__box > .nut-tabs__titles .nut-tabs__titles-item,
52 +.nut-tabs.horizontal > .nut-tabs__titles .nut-tabs__titles-item {
53 + width: auto !important;
54 +}
55 +
50 .bg-orange-400 { 56 .bg-orange-400 {
51 background-color: #fb923c; 57 background-color: #fb923c;
52 } 58 }
......
1 +<template>
2 + <view>
3 + <!-- 地址选择弹窗 -->
4 + <nut-popup
5 + :visible="visible"
6 + position="bottom"
7 + :style="{ height: '85%' }"
8 + close-icon-position="top-right"
9 + @close="closeModal"
10 + :z-index="9999"
11 + >
12 + <view class="address-modal">
13 + <view class="address-modal-header">
14 + <text class="address-modal-title">选择地址</text>
15 + </view>
16 +
17 + <view class="address-modal-content">
18 + <!-- 省市县选择 -->
19 + <view class="address-section">
20 + <text class="address-section-title">选择省市县</text>
21 + <nut-cascader
22 + v-model="selectedAreaCodes"
23 + v-model:visible="showAreaPicker"
24 + :options="areaData"
25 + @change="onAreaChange"
26 + @path-change="onAreaPathChange"
27 + title="请选择省市县"
28 + />
29 + <view
30 + class="area-selector"
31 + @click="showAreaPicker = true"
32 + >
33 + <text class="area-text" :class="{ 'area-selected': selectedAreaText }">
34 + {{ selectedAreaText || '请选择省市县' }}
35 + </text>
36 + <ArrowRight color="#9ca3af" size="12" />
37 + </view>
38 + </view>
39 +
40 + <!-- 详细地址输入 -->
41 + <view class="address-section">
42 + <text class="address-section-title">详细地址</text>
43 + <nut-textarea
44 + v-model="detailAddress"
45 + placeholder="请输入详细地址(街道、门牌号等)"
46 + rows="3"
47 + class="detail-address-input"
48 + />
49 + </view>
50 + </view>
51 +
52 + <view class="address-modal-footer">
53 + <nut-button
54 + type="primary"
55 + color="orange"
56 + block
57 + @click="confirmAddress"
58 + :disabled="!selectedAreaText || !detailAddress.trim()"
59 + >
60 + 确定
61 + </nut-button>
62 + </view>
63 + </view>
64 + </nut-popup>
65 + </view>
66 +</template>
67 +
68 +<script setup>
69 +import { ref, computed, watch } from 'vue'
70 +import { RectRight, ArrowRight } from '@nutui/icons-vue-taro'
71 +import { regionData } from 'element-china-area-data'
72 +
73 +/**
74 + * 转换地区数据格式以适配NutUI Cascader组件
75 + * @param {Array} data - element-china-area-data的原始数据
76 + * @returns {Array} - 转换后的数据格式
77 + */
78 +const transformAreaData = (data) => {
79 + return data.map(item => ({
80 + value: item.value,
81 + text: item.label,
82 + children: item.children ? transformAreaData(item.children) : undefined
83 + }))
84 +}
85 +
86 +/**
87 + * 组件属性定义
88 + */
89 +const props = defineProps({
90 + // 当前选中的地址信息
91 + modelValue: {
92 + type: Object,
93 + default: () => ({
94 + province: '',
95 + city: '',
96 + county: '',
97 + detail_address: '',
98 + full_address: ''
99 + })
100 + },
101 + // 占位符文本
102 + placeholder: {
103 + type: String,
104 + default: '请选择省市县并填写详细地址'
105 + },
106 + // 控制弹窗显示状态
107 + visible: {
108 + type: Boolean,
109 + default: false
110 + }
111 +})
112 +
113 +/**
114 + * 组件事件定义
115 + */
116 +const emit = defineEmits(['update:modelValue', 'change', 'update:visible'])
117 +
118 +/**
119 + * 地址选择相关状态
120 + */
121 +const showAreaPicker = ref(false)
122 +const selectedAreaCodes = ref([])
123 +const selectedAreaText = ref('')
124 +const detailAddress = ref('')
125 +const areaData = ref(transformAreaData(regionData))
126 +
127 +/**
128 + * 计算完整地址
129 + */
130 +const fullAddress = computed(() => {
131 + if (selectedAreaText.value && detailAddress.value.trim()) {
132 + return `${selectedAreaText.value} ${detailAddress.value.trim()}`
133 + }
134 + return ''
135 +})
136 +
137 +/**
138 + * 初始化地址数据
139 + * @param {Object} addressData - 地址数据对象
140 + */
141 +const initAddressData = (addressData) => {
142 + if (addressData.province && addressData.city && addressData.county) {
143 + selectedAreaText.value = `${addressData.province}${addressData.city}${addressData.county}`
144 + detailAddress.value = addressData.detail_address || ''
145 + } else {
146 + selectedAreaText.value = ''
147 + detailAddress.value = ''
148 + }
149 +}
150 +
151 +/**
152 + * 监听props变化,初始化组件数据
153 + */
154 +watch(() => props.modelValue, (newValue) => {
155 + if (newValue) {
156 + initAddressData(newValue)
157 + }
158 +}, { immediate: true, deep: true })
159 +
160 +/**
161 + * 地区选择变化回调(选中值改变时触发)
162 + * @param {Array} value - 选中的值数组
163 + * @param {Array} pathNodes - 选中的路径节点数组
164 + */
165 +const onAreaChange = (value, pathNodes) => {
166 + if (pathNodes && Array.isArray(pathNodes) && pathNodes.length === 3) {
167 + selectedAreaCodes.value = value
168 + selectedAreaText.value = pathNodes
169 + .filter(node => node && node.text)
170 + .map(node => node.text)
171 + .join('')
172 + // 选择完三级地址后自动关闭选择器
173 + showAreaPicker.value = false
174 + }
175 +}
176 +
177 +/**
178 + * 地区路径选择变化回调(选中项改变时触发)
179 + * @param {Array} pathNodes - 选中的路径节点数组
180 + */
181 +const onAreaPathChange = (pathNodes) => {
182 + if (pathNodes && Array.isArray(pathNodes)) {
183 + selectedAreaText.value = pathNodes
184 + .filter(node => node && node.text)
185 + .map(node => node.text)
186 + .join('')
187 + }
188 +}
189 +
190 +
191 +
192 +/**
193 + * 关闭地址选择弹窗
194 + */
195 +const closeModal = () => {
196 + emit('update:visible', false)
197 +}
198 +
199 +/**
200 + * 确认地址选择
201 + */
202 +const confirmAddress = () => {
203 + if (selectedAreaText.value && detailAddress.value.trim()) {
204 + const codes = selectedAreaCodes.value
205 + const addressData = {
206 + province: getProvinceFromText(selectedAreaText.value),
207 + city: getCityFromText(selectedAreaText.value),
208 + county: getCountyFromText(selectedAreaText.value),
209 + province_code: codes[0] || '',
210 + city_code: codes[1] || '',
211 + county_code: codes[2] || '',
212 + detail_address: detailAddress.value.trim(),
213 + full_address: fullAddress.value
214 + }
215 +
216 + // 触发更新事件
217 + emit('update:modelValue', addressData)
218 + emit('change', addressData)
219 +
220 + // 关闭弹窗
221 + emit('update:visible', false)
222 + }
223 +}
224 +
225 +/**
226 + * 从选中文本中提取省份
227 + * @param {String} text - 选中的地区文本
228 + * @returns {String} - 省份名称
229 + */
230 +const getProvinceFromText = (text) => {
231 + // 这里可以根据实际需要实现更精确的解析逻辑
232 + // 暂时使用简单的方式
233 + const codes = selectedAreaCodes.value
234 + if (codes.length >= 1) {
235 + const provinceNode = findNodeByCode(areaData.value, codes[0])
236 + return provinceNode ? provinceNode.text : ''
237 + }
238 + return ''
239 +}
240 +
241 +/**
242 + * 从选中文本中提取城市
243 + * @param {String} text - 选中的地区文本
244 + * @returns {String} - 城市名称
245 + */
246 +const getCityFromText = (text) => {
247 + const codes = selectedAreaCodes.value
248 + if (codes.length >= 2) {
249 + const provinceNode = findNodeByCode(areaData.value, codes[0])
250 + if (provinceNode && provinceNode.children) {
251 + const cityNode = findNodeByCode(provinceNode.children, codes[1])
252 + return cityNode ? cityNode.text : ''
253 + }
254 + }
255 + return ''
256 +}
257 +
258 +/**
259 + * 从选中文本中提取县区
260 + * @param {String} text - 选中的地区文本
261 + * @returns {String} - 县区名称
262 + */
263 +const getCountyFromText = (text) => {
264 + const codes = selectedAreaCodes.value
265 + if (codes.length >= 3) {
266 + const provinceNode = findNodeByCode(areaData.value, codes[0])
267 + if (provinceNode && provinceNode.children) {
268 + const cityNode = findNodeByCode(provinceNode.children, codes[1])
269 + if (cityNode && cityNode.children) {
270 + const countyNode = findNodeByCode(cityNode.children, codes[2])
271 + return countyNode ? countyNode.text : ''
272 + }
273 + }
274 + }
275 + return ''
276 +}
277 +
278 +/**
279 + * 根据编码查找节点
280 + * @param {Array} nodes - 节点数组
281 + * @param {String} code - 编码
282 + * @returns {Object|null} - 找到的节点或null
283 + */
284 +const findNodeByCode = (nodes, code) => {
285 + return nodes.find(node => node.value === code) || null
286 +}
287 +</script>
288 +
289 +<style lang="less">
290 +// 地址选择器样式
291 +.address-selector {
292 + display: flex;
293 + align-items: center;
294 + justify-content: space-between;
295 + padding: 24rpx 32rpx;
296 + border: 1px solid #e5e7eb;
297 + border-radius: 24rpx;
298 + background-color: white;
299 + min-height: 96rpx;
300 + transition: all 0.2s ease;
301 +
302 + &:active {
303 + background-color: #f9fafb;
304 + }
305 +
306 + .address-text {
307 + font-size: 28rpx;
308 + color: #9ca3af;
309 + flex: 1;
310 + line-height: 1.6;
311 + word-break: break-all;
312 +
313 + &.address-selected {
314 + color: #111827;
315 + }
316 + }
317 +}
318 +
319 +// 地址选择弹窗样式
320 +.address-modal {
321 + display: flex;
322 + flex-direction: column;
323 + height: 100%;
324 + background-color: white;
325 +
326 + .address-modal-header {
327 + display: flex;
328 + align-items: center;
329 + justify-content: center;
330 + padding: 32rpx;
331 + border-bottom: 1px solid #f3f4f6;
332 + background-color: white;
333 + position: sticky;
334 + top: 0;
335 + z-index: 10;
336 +
337 + .address-modal-title {
338 + font-size: 36rpx;
339 + font-weight: 600;
340 + color: #111827;
341 + }
342 + }
343 +
344 + .address-modal-content {
345 + flex: 1;
346 + padding: 32rpx;
347 + overflow-y: auto;
348 +
349 + .address-section {
350 + margin-bottom: 48rpx;
351 +
352 + .address-section-title {
353 + display: block;
354 + font-size: 28rpx;
355 + font-weight: 500;
356 + color: #374151;
357 + margin-bottom: 24rpx;
358 + }
359 +
360 + .area-selector {
361 + display: flex;
362 + align-items: center;
363 + justify-content: space-between;
364 + padding: 24rpx 32rpx;
365 + border: 1px solid #e5e7eb;
366 + border-radius: 24rpx;
367 + background-color: white;
368 + transition: all 0.2s ease;
369 +
370 + &:active {
371 + background-color: #f9fafb;
372 + }
373 +
374 + .area-text {
375 + font-size: 28rpx;
376 + color: #9ca3af;
377 + flex: 1;
378 + line-height: 1.6;
379 + word-break: break-all;
380 +
381 + &.area-selected {
382 + color: #111827;
383 + }
384 + }
385 + }
386 +
387 + .detail-address-input {
388 + width: 100%;
389 +
390 + :deep(.nut-textarea) {
391 + border: 1px solid #e5e7eb;
392 + border-radius: 24rpx;
393 +
394 + .nut-textarea__textarea {
395 + padding: 24rpx 32rpx;
396 + font-size: 28rpx;
397 + line-height: 1.6;
398 + min-height: 160rpx;
399 + }
400 + }
401 + }
402 + }
403 + }
404 +
405 + .address-modal-footer {
406 + padding: 32rpx;
407 + border-top: 1px solid #f3f4f6;
408 + background-color: white;
409 + position: sticky;
410 + bottom: 0;
411 + z-index: 10;
412 +
413 + :deep(.nut-button) {
414 + border-radius: 24rpx;
415 + font-weight: 500;
416 + height: 88rpx;
417 + }
418 + }
419 +}
420 +</style>
...@@ -474,3 +474,32 @@ ...@@ -474,3 +474,32 @@
474 font-size: 28rpx; 474 font-size: 28rpx;
475 margin-right: 8rpx; 475 margin-right: 8rpx;
476 } 476 }
477 +
478 +// 地址选择器触发器样式
479 +.address-selector {
480 + display: flex;
481 + align-items: center;
482 + justify-content: space-between;
483 + padding: 24rpx 32rpx;
484 + border: 1px solid #e5e7eb;
485 + border-radius: 24rpx;
486 + background-color: white;
487 + min-height: 96rpx;
488 + transition: all 0.2s ease;
489 +
490 + &:active {
491 + background-color: #f9fafb;
492 + }
493 +
494 + .address-text {
495 + font-size: 28rpx;
496 + color: #9ca3af;
497 + flex: 1;
498 + line-height: 1.6;
499 + word-break: break-all;
500 +
501 + &.address-selected {
502 + color: #111827;
503 + }
504 + }
505 +}
......
1 <!-- 1 <!--
2 * @Date: 2022-09-19 14:11:06 2 * @Date: 2022-09-19 14:11:06
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-08-08 13:58:13 4 + * @LastEditTime: 2025-08-12 17:05:50
5 * @FilePath: /jgdl/src/pages/collectionSettings/index.vue 5 * @FilePath: /jgdl/src/pages/collectionSettings/index.vue
6 * @Description: 收款设置 6 * @Description: 收款设置
7 --> 7 -->
...@@ -32,9 +32,9 @@ ...@@ -32,9 +32,9 @@
32 </view> 32 </view>
33 <view class="setting-right"> 33 <view class="setting-right">
34 <text class="setting-status" 34 <text class="setting-status"
35 - :class="{ 'status-set': identityInfo.userName && identityInfo.idCard && identityInfo.idcard_1_img && identityInfo.idcard_2_img && identityInfo.idcard_effect_begin && identityInfo.idcard_effect_end && identityInfo.idcard_address }"> 35 + :class="{ 'status-set': identityInfo.userName && identityInfo.idCard && identityInfo.idcard_1_img && identityInfo.idcard_2_img && identityInfo.idcard_effect_begin && identityInfo.idcard_effect_end && (identityInfo.idcard_province && identityInfo.idcard_city && identityInfo.idcard_district && identityInfo.idcard_address) }">
36 {{ identityInfo.userName && identityInfo.idCard && identityInfo.idcard_1_img && identityInfo.idcard_2_img && 36 {{ identityInfo.userName && identityInfo.idCard && identityInfo.idcard_1_img && identityInfo.idcard_2_img &&
37 - identityInfo.idcard_effect_begin && identityInfo.idcard_effect_end && identityInfo.idcard_address ? '已设置' : 37 + identityInfo.idcard_effect_begin && identityInfo.idcard_effect_end && (identityInfo.idcard_province && identityInfo.idcard_city && identityInfo.idcard_district && identityInfo.idcard_address) ? '已设置' :
38 '未设置' }} 38 '未设置' }}
39 </text> 39 </text>
40 <!-- <text class="arrow">></text> --> 40 <!-- <text class="arrow">></text> -->
...@@ -194,8 +194,16 @@ ...@@ -194,8 +194,16 @@
194 <!-- 身份证地址 --> 194 <!-- 身份证地址 -->
195 <view class="form-item"> 195 <view class="form-item">
196 <text class="form-label"><text class="required-mark">*</text>身份证地址</text> 196 <text class="form-label"><text class="required-mark">*</text>身份证地址</text>
197 - <textarea v-model="tempIdentityInfo.idcard_address" placeholder="请输入身份证地址" class="form-input native-input" 197 + <!-- 地址选择器触发器 -->
198 - :cursor-spacing="50" /> 198 + <view
199 + class="address-selector"
200 + @click="showAddressSelector = true"
201 + >
202 + <text class="address-text" :class="{ 'address-selected': addressData.full_address }">
203 + {{ addressData.full_address || '请选择省市县并填写详细地址' }}
204 + </text>
205 + <RectRight color="#999" size="10" />
206 + </view>
199 </view> 207 </view>
200 </view> 208 </view>
201 209
...@@ -204,7 +212,7 @@ ...@@ -204,7 +212,7 @@
204 关闭 212 关闭
205 </nut-button> 213 </nut-button>
206 <nut-button type="primary" @click="saveIdentityInfo" color="#ffa500" 214 <nut-button type="primary" @click="saveIdentityInfo" color="#ffa500"
207 - :disabled="!tempIdentityInfo.userName || !tempIdentityInfo.idCard || !tempIdentityInfo.idcard_1_img || !tempIdentityInfo.idcard_2_img || !tempIdentityInfo.idcard_effect_begin || !tempIdentityInfo.idcard_effect_end || !tempIdentityInfo.idcard_address || !!idCardError" 215 + :disabled="!tempIdentityInfo.userName || !tempIdentityInfo.idCard || !tempIdentityInfo.idcard_1_img || !tempIdentityInfo.idcard_2_img || !tempIdentityInfo.idcard_effect_begin || !tempIdentityInfo.idcard_effect_end || !tempIdentityInfo.idcard_province || !tempIdentityInfo.idcard_city || !tempIdentityInfo.idcard_district || !tempIdentityInfo.idcard_address || !!idCardError"
208 class="footer-btn footer-btn-save"> 216 class="footer-btn footer-btn-save">
209 保存 217 保存
210 </nut-button> 218 </nut-button>
...@@ -234,6 +242,15 @@ ...@@ -234,6 +242,15 @@
234 <view v-if="showBackButton" class="fixed-back-btn" @click="goBack"> 242 <view v-if="showBackButton" class="fixed-back-btn" @click="goBack">
235 <text class="back-text">返回</text> 243 <text class="back-text">返回</text>
236 </view> 244 </view>
245 +
246 + <!-- 地址选择器组件 -->
247 + <AddressSelector
248 + v-model:visible="showAddressSelector"
249 + v-model="addressData"
250 + @change="onAddressChange"
251 + placeholder="请选择省市县并填写详细地址"
252 + />
253 +
237 </view> 254 </view>
238 </template> 255 </template>
239 256
...@@ -252,6 +269,9 @@ import BASE_URL from '@/utils/config' ...@@ -252,6 +269,9 @@ import BASE_URL from '@/utils/config'
252 // 导入用户状态管理 269 // 导入用户状态管理
253 import { useUserStore } from '@/stores/user' 270 import { useUserStore } from '@/stores/user'
254 271
272 +// 导入地址选择组件
273 +import AddressSelector from '@/components/AddressSelector.vue'
274 +
255 // 获取页面参数 275 // 获取页面参数
256 const instance = Taro.getCurrentInstance() 276 const instance = Taro.getCurrentInstance()
257 const { target } = instance.router?.params || {} 277 const { target } = instance.router?.params || {}
...@@ -308,6 +328,14 @@ const tempIdentityInfo = ref({ ...@@ -308,6 +328,14 @@ const tempIdentityInfo = ref({
308 idcard_2_img: '', 328 idcard_2_img: '',
309 idcard_effect_begin: '', 329 idcard_effect_begin: '',
310 idcard_effect_end: '', 330 idcard_effect_end: '',
331 + // 身份证地址相关字段(显示用中文名称)
332 + province: '',
333 + city: '',
334 + county: '',
335 + // 身份证地址相关字段(提交用真实字段名)
336 + idcard_province: '',
337 + idcard_city: '',
338 + idcard_district: '',
311 idcard_address: '' 339 idcard_address: ''
312 }); 340 });
313 341
...@@ -320,6 +348,7 @@ const showBankModal = ref(false); ...@@ -320,6 +348,7 @@ const showBankModal = ref(false);
320 const showIdcardBeginDate = ref(false); 348 const showIdcardBeginDate = ref(false);
321 const showIdcardEndDate = ref(false); 349 const showIdcardEndDate = ref(false);
322 const showEndDateTypeModal = ref(false); 350 const showEndDateTypeModal = ref(false);
351 +const showAddressSelector = ref(false);
323 352
324 /** 353 /**
325 * 身份证号码错误信息 354 * 身份证号码错误信息
...@@ -418,6 +447,14 @@ const getUserInfo = async () => { ...@@ -418,6 +447,14 @@ const getUserInfo = async () => {
418 idcard_2_img: userInfo.idcard_2_img || '', 447 idcard_2_img: userInfo.idcard_2_img || '',
419 idcard_effect_begin: userInfo.idcard_effect_begin || '', 448 idcard_effect_begin: userInfo.idcard_effect_begin || '',
420 idcard_effect_end: userInfo.idcard_effect_end || '', 449 idcard_effect_end: userInfo.idcard_effect_end || '',
450 + // 地址字段(用于显示的中文名称)
451 + province: userInfo.province_name || '',
452 + city: userInfo.city_name || '',
453 + county: userInfo.county_name || userInfo.district_name || '',
454 + // 身份证地址字段(真实字段名)
455 + idcard_province: userInfo.idcard_province || '',
456 + idcard_city: userInfo.idcard_city || '',
457 + idcard_district: userInfo.idcard_district || '',
421 idcard_address: userInfo.idcard_address || '' 458 idcard_address: userInfo.idcard_address || ''
422 }; 459 };
423 } 460 }
...@@ -620,10 +657,28 @@ const saveAccountInfo = async () => { ...@@ -620,10 +657,28 @@ const saveAccountInfo = async () => {
620 const openIdentityModal = () => { 657 const openIdentityModal = () => {
621 tempIdentityInfo.value = { ...identityInfo.value }; 658 tempIdentityInfo.value = { ...identityInfo.value };
622 idCardError.value = ''; 659 idCardError.value = '';
660 + // 初始化地址选择器数据
661 + initAddressData();
623 showIdentityModal.value = true; 662 showIdentityModal.value = true;
624 }; 663 };
625 664
626 /** 665 /**
666 + * 初始化地址选择器数据
667 + */
668 +const initAddressData = () => {
669 + addressData.value = {
670 + province: tempIdentityInfo.value.province || '',
671 + city: tempIdentityInfo.value.city || '',
672 + county: tempIdentityInfo.value.county || '',
673 + province_code: tempIdentityInfo.value.idcard_province || '',
674 + city_code: tempIdentityInfo.value.idcard_city || '',
675 + county_code: tempIdentityInfo.value.idcard_district || '',
676 + detail_address: tempIdentityInfo.value.idcard_address || '',
677 + full_address: (tempIdentityInfo.value.province + tempIdentityInfo.value.city + tempIdentityInfo.value.county + tempIdentityInfo.value.idcard_address) || ''
678 + }
679 +};
680 +
681 +/**
627 * 关闭身份信息弹窗 682 * 关闭身份信息弹窗
628 */ 683 */
629 const closeIdentityModal = () => { 684 const closeIdentityModal = () => {
...@@ -635,6 +690,12 @@ const closeIdentityModal = () => { ...@@ -635,6 +690,12 @@ const closeIdentityModal = () => {
635 idcard_2_img: '', 690 idcard_2_img: '',
636 idcard_effect_begin: '', 691 idcard_effect_begin: '',
637 idcard_effect_end: '', 692 idcard_effect_end: '',
693 + province: '',
694 + city: '',
695 + county: '',
696 + idcard_province: '',
697 + idcard_city: '',
698 + idcard_district: '',
638 idcard_address: '' 699 idcard_address: ''
639 }; 700 };
640 idCardError.value = ''; 701 idCardError.value = '';
...@@ -995,6 +1056,10 @@ const saveIdentityInfo = async () => { ...@@ -995,6 +1056,10 @@ const saveIdentityInfo = async () => {
995 idcard_2_img: tempIdentityInfo.value.idcard_2_img, 1056 idcard_2_img: tempIdentityInfo.value.idcard_2_img,
996 idcard_effect_begin: tempIdentityInfo.value.idcard_effect_begin, 1057 idcard_effect_begin: tempIdentityInfo.value.idcard_effect_begin,
997 idcard_effect_end: tempIdentityInfo.value.idcard_effect_end, 1058 idcard_effect_end: tempIdentityInfo.value.idcard_effect_end,
1059 + // 使用真实的身份证地址字段名
1060 + idcard_province: tempIdentityInfo.value.idcard_province,
1061 + idcard_city: tempIdentityInfo.value.idcard_city,
1062 + idcard_district: tempIdentityInfo.value.idcard_district,
998 idcard_address: tempIdentityInfo.value.idcard_address 1063 idcard_address: tempIdentityInfo.value.idcard_address
999 }); 1064 });
1000 1065
...@@ -1009,6 +1074,10 @@ const saveIdentityInfo = async () => { ...@@ -1009,6 +1074,10 @@ const saveIdentityInfo = async () => {
1009 idcard_2_img: tempIdentityInfo.value.idcard_2_img, 1074 idcard_2_img: tempIdentityInfo.value.idcard_2_img,
1010 idcard_effect_begin: tempIdentityInfo.value.idcard_effect_begin, 1075 idcard_effect_begin: tempIdentityInfo.value.idcard_effect_begin,
1011 idcard_effect_end: tempIdentityInfo.value.idcard_effect_end, 1076 idcard_effect_end: tempIdentityInfo.value.idcard_effect_end,
1077 + // 身份证地址字段
1078 + idcard_province: tempIdentityInfo.value.idcard_province,
1079 + idcard_city: tempIdentityInfo.value.idcard_city,
1080 + idcard_district: tempIdentityInfo.value.idcard_district,
1012 idcard_address: tempIdentityInfo.value.idcard_address 1081 idcard_address: tempIdentityInfo.value.idcard_address
1013 }); 1082 });
1014 1083
...@@ -1041,6 +1110,32 @@ const goBack = () => { ...@@ -1041,6 +1110,32 @@ const goBack = () => {
1041 url: '/pages/sell/index' 1110 url: '/pages/sell/index'
1042 }); 1111 });
1043 }; 1112 };
1113 +
1114 +// 地址选择相关状态
1115 +const addressData = ref({
1116 + province: '',
1117 + city: '',
1118 + county: '',
1119 + detail_address: '',
1120 + full_address: ''
1121 +})
1122 +
1123 +/**
1124 + * 地址变化处理回调
1125 + * @param {Object} address - 地址数据对象
1126 + */
1127 +const onAddressChange = (address) => {
1128 + // 更新临时身份信息中的地址字段(中文名称,用于显示)
1129 + tempIdentityInfo.value.province = address.province
1130 + tempIdentityInfo.value.city = address.city
1131 + tempIdentityInfo.value.county = address.county
1132 +
1133 + // 更新身份证地址字段(真实字段名,用于提交)
1134 + tempIdentityInfo.value.idcard_province = address.province_code || address.province
1135 + tempIdentityInfo.value.idcard_city = address.city_code || address.city
1136 + tempIdentityInfo.value.idcard_district = address.county_code || address.county
1137 + tempIdentityInfo.value.idcard_address = address.detail_address
1138 +}
1044 </script> 1139 </script>
1045 1140
1046 <script> 1141 <script>
......
1 /* 1 /*
2 * @Date: 2025-01-08 18:00:00 2 * @Date: 2025-01-08 18:00:00
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-08-07 21:50:44 4 + * @LastEditTime: 2025-08-12 16:36:02
5 * @FilePath: /jgdl/src/stores/user.js 5 * @FilePath: /jgdl/src/stores/user.js
6 * @Description: 用户状态管理 6 * @Description: 用户状态管理
7 */ 7 */
...@@ -34,6 +34,10 @@ export const useUserStore = defineStore('user', { ...@@ -34,6 +34,10 @@ export const useUserStore = defineStore('user', {
34 idcard_2_img: '', 34 idcard_2_img: '',
35 idcard_effect_begin: '', 35 idcard_effect_begin: '',
36 idcard_effect_end: '', 36 idcard_effect_end: '',
37 + // 身份证地址字段
38 + idcard_province: '',
39 + idcard_city: '',
40 + idcard_district: '',
37 idcard_address: '', 41 idcard_address: '',
38 division_agree_pic: '', 42 division_agree_pic: '',
39 }, 43 },
...@@ -55,16 +59,19 @@ export const useUserStore = defineStore('user', { ...@@ -55,16 +59,19 @@ export const useUserStore = defineStore('user', {
55 */ 59 */
56 hasCompleteCollectionInfo: (state) => { 60 hasCompleteCollectionInfo: (state) => {
57 return !!( 61 return !!(
58 - state.userInfo.bank_id && state.userInfo.bank_id && 62 + state.userInfo.bank_id &&
59 - state.userInfo.bank_no && state.userInfo.bank_no && 63 + state.userInfo.bank_no &&
60 - state.userInfo.bank_img && state.userInfo.bank_img && 64 + state.userInfo.bank_img &&
61 - state.userInfo.idcard_1_img && state.userInfo.idcard_1_img && 65 + state.userInfo.idcard_1_img &&
62 - state.userInfo.idcard_2_img && state.userInfo.idcard_2_img && 66 + state.userInfo.idcard_2_img &&
63 - state.userInfo.name && state.userInfo.name && 67 + state.userInfo.name &&
64 - state.userInfo.idcard && state.userInfo.idcard && 68 + state.userInfo.idcard &&
65 - state.userInfo.idcard_address && state.userInfo.idcard_address && 69 + state.userInfo.idcard_province &&
66 - state.userInfo.idcard_effect_begin && state.userInfo.idcard_effect_begin && 70 + state.userInfo.idcard_city &&
67 - state.userInfo.idcard_effect_end && state.userInfo.idcard_effect_end 71 + state.userInfo.idcard_district &&
72 + state.userInfo.idcard_address &&
73 + state.userInfo.idcard_effect_begin &&
74 + state.userInfo.idcard_effect_end
68 ) 75 )
69 }, 76 },
70 77
...@@ -142,6 +149,10 @@ export const useUserStore = defineStore('user', { ...@@ -142,6 +149,10 @@ export const useUserStore = defineStore('user', {
142 idcard_2_img: '', 149 idcard_2_img: '',
143 idcard_effect_begin: '', 150 idcard_effect_begin: '',
144 idcard_effect_end: '', 151 idcard_effect_end: '',
152 + // 身份证地址字段
153 + idcard_province: '',
154 + idcard_city: '',
155 + idcard_district: '',
145 idcard_address: '', 156 idcard_address: '',
146 division_agree_pic: '', 157 division_agree_pic: '',
147 } 158 }
......