forked from gxwebsoft/mp-10550
feat(user): 添加地址编辑时的地区锁定功能
- 新增 regionLocked 状态管理地区锁定状态 - 编辑模式下有经纬度时自动锁定地区,防止被识别覆盖 - 地图选点后锁定地区并验证省市区完整性 - 锁定状态下点击地区选择器显示提示信息 - 表单提交前验证必填的省市区字段 - 使用 View 组件替换 div 优化 Taro 兼容性 - 识别成功时根据锁定状态显示不同提示文案
This commit is contained in:
@@ -47,6 +47,7 @@ const AddUserAddress = () => {
|
||||
const [FormData, setFormData] = useState<ShopUserAddress>({})
|
||||
const [inputText, setInputText] = useState<string>('')
|
||||
const [selectedLocation, setSelectedLocation] = useState<SelectedLocation | null>(null)
|
||||
const [regionLocked, setRegionLocked] = useState(false)
|
||||
const formRef = useRef<any>(null)
|
||||
const wxDraftRef = useRef<Partial<ShopUserAddress> | null>(null)
|
||||
const wxDraftPatchedRef = useRef(false)
|
||||
@@ -120,7 +121,12 @@ const AddUserAddress = () => {
|
||||
// 设置所在地区
|
||||
setText(`${address.province} ${address.city} ${address.region}`)
|
||||
// 回显已保存的经纬度(编辑模式)
|
||||
if (hasValidLngLat(address)) setSelectedLocation({ lng: String(address.lng), lat: String(address.lat) })
|
||||
if (hasValidLngLat(address)) {
|
||||
setSelectedLocation({ lng: String(address.lng), lat: String(address.lat) })
|
||||
setRegionLocked(true)
|
||||
} else {
|
||||
setRegionLocked(false)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载地址失败:', error)
|
||||
Taro.showToast({
|
||||
@@ -172,30 +178,39 @@ const AddUserAddress = () => {
|
||||
const result = parseAddressText(inputText);
|
||||
|
||||
// 更新表单数据
|
||||
const newFormData = {
|
||||
const newFormData: any = {
|
||||
...FormData,
|
||||
name: result.name || FormData.name,
|
||||
phone: result.phone || FormData.phone,
|
||||
address: result.address || FormData.address,
|
||||
province: result.province || FormData.province,
|
||||
city: result.city || FormData.city,
|
||||
region: result.region || FormData.region
|
||||
address: result.address || FormData.address
|
||||
};
|
||||
|
||||
if (!regionLocked) {
|
||||
newFormData.province = result.province || FormData.province
|
||||
newFormData.city = result.city || FormData.city
|
||||
newFormData.region = result.region || FormData.region
|
||||
}
|
||||
|
||||
setFormData(newFormData);
|
||||
|
||||
// 更新地区显示文本
|
||||
if (result.province && result.city && result.region) {
|
||||
if (!regionLocked && result.province && result.city && result.region) {
|
||||
setText(`${result.province} ${result.city} ${result.region}`);
|
||||
}
|
||||
|
||||
// 更新表单字段值
|
||||
if (formRef.current) {
|
||||
formRef.current.setFieldsValue(newFormData);
|
||||
const patch: any = {
|
||||
name: newFormData.name,
|
||||
phone: newFormData.phone,
|
||||
address: newFormData.address
|
||||
}
|
||||
if (!regionLocked && newFormData.region) patch.region = newFormData.region
|
||||
formRef.current.setFieldsValue(patch);
|
||||
}
|
||||
|
||||
Taro.showToast({
|
||||
title: '识别成功',
|
||||
title: regionLocked ? '识别成功(所在地区以定位为准)' : '识别成功',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
@@ -311,7 +326,6 @@ const AddUserAddress = () => {
|
||||
name: res.name,
|
||||
address: res.address
|
||||
}
|
||||
setSelectedLocation(next)
|
||||
|
||||
// 尝试从地图返回的 address 文本解析省市区(best-effort)
|
||||
const regionResult = res?.provinceName || res?.cityName || res?.adName
|
||||
@@ -322,15 +336,22 @@ const AddUserAddress = () => {
|
||||
}
|
||||
: parseRegion(String(res.address || ''))
|
||||
|
||||
const province = String(regionResult?.province || '').trim()
|
||||
const city = String(regionResult?.city || '').trim()
|
||||
const region = String(regionResult?.region || '').trim()
|
||||
if (!province || !city || !region) {
|
||||
Taro.showToast({ title: '定位未识别到所在地区,请重新选择定位', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
setSelectedLocation(next)
|
||||
setRegionLocked(true)
|
||||
|
||||
// 将地图选点的地址同步到“收货地址”(不额外拼接省市区字段,省市区由独立字段保存)
|
||||
const nextDetailAddress = (() => {
|
||||
const rawAddr = String(res.address || '').trim()
|
||||
const name = String(res.name || '').trim()
|
||||
|
||||
const province = String(regionResult?.province || '').trim()
|
||||
const city = String(regionResult?.city || '').trim()
|
||||
const region = String(regionResult?.region || '').trim()
|
||||
|
||||
// 选择定位返回的 address 往往包含省市区,这里尽量剥离掉,避免和表单的省市区字段重复
|
||||
let detail = rawAddr
|
||||
for (const part of [province, city, region]) {
|
||||
@@ -350,20 +371,18 @@ const AddUserAddress = () => {
|
||||
lng: next.lng,
|
||||
lat: next.lat,
|
||||
address: nextDetailAddress || prev.address,
|
||||
province: regionResult?.province || prev.province,
|
||||
city: regionResult?.city || prev.city,
|
||||
region: regionResult?.region || prev.region
|
||||
province,
|
||||
city,
|
||||
region
|
||||
}))
|
||||
|
||||
if (regionResult?.province && regionResult?.city && regionResult?.region) {
|
||||
setText(`${regionResult.province} ${regionResult.city} ${regionResult.region}`)
|
||||
}
|
||||
setText(`${province} ${city} ${region}`)
|
||||
|
||||
// 更新表单展示值(Form initialValues 不会跟随 FormData 变化)
|
||||
if (formRef.current) {
|
||||
const patch: any = {}
|
||||
if (nextDetailAddress) patch.address = nextDetailAddress
|
||||
if (regionResult?.region) patch.region = regionResult.region
|
||||
patch.region = region
|
||||
formRef.current.setFieldsValue(patch)
|
||||
}
|
||||
}
|
||||
@@ -407,6 +426,14 @@ const AddUserAddress = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const openRegionPicker = () => {
|
||||
if (regionLocked) {
|
||||
Taro.showToast({ title: '所在地区已由定位确定,修改请重新选择定位', icon: 'none' })
|
||||
return
|
||||
}
|
||||
setVisible(true)
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const submitSucceed = async (values: any) => {
|
||||
const loc =
|
||||
@@ -416,6 +443,10 @@ const AddUserAddress = () => {
|
||||
Taro.showToast({ title: '请选择定位', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!FormData.province || !FormData.city || !FormData.region) {
|
||||
Taro.showToast({ title: '请先选择定位以自动填写所在地区', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 准备提交的数据
|
||||
@@ -487,6 +518,12 @@ const AddUserAddress = () => {
|
||||
})
|
||||
}, [fromWx, isEditMode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!regionLocked) return
|
||||
if (!visible) return
|
||||
setVisible(false)
|
||||
}, [regionLocked, visible])
|
||||
|
||||
// NutUI Form 的 initialValues 在首次渲染后不再响应更新;微信导入时做一次 setFieldsValue 兜底回填。
|
||||
useEffect(() => {
|
||||
if (loading) return
|
||||
@@ -523,7 +560,7 @@ const AddUserAddress = () => {
|
||||
onFinishFailed={(errors) => submitFailed(errors)}
|
||||
>
|
||||
<CellGroup className={'px-3'}>
|
||||
<div
|
||||
<View
|
||||
style={{
|
||||
border: '1px dashed #22c55e',
|
||||
display: 'flex',
|
||||
@@ -549,7 +586,7 @@ const AddUserAddress = () => {
|
||||
>
|
||||
识别
|
||||
</Button>
|
||||
</div>
|
||||
</View>
|
||||
</CellGroup>
|
||||
<View className={'bg-gray-100 h-3'}></View>
|
||||
<CellGroup style={{padding: '4px 0'}}>
|
||||
@@ -581,10 +618,10 @@ const AddUserAddress = () => {
|
||||
rules={[{message: '请输入您的所在地区'}]}
|
||||
required
|
||||
>
|
||||
<div className={'flex justify-between items-center'} onClick={() => setVisible(true)}>
|
||||
<View className={'flex justify-between items-center'} onClick={openRegionPicker}>
|
||||
<Input placeholder="选择所在地区" value={text} disabled/>
|
||||
<ArrowRight className={'text-gray-400'}/>
|
||||
</div>
|
||||
</View>
|
||||
</Form.Item>
|
||||
<Form.Item name="address" label="收货地址" initialValue={FormData.address} required>
|
||||
<TextArea maxLength={50} placeholder="请输入详细收货地址"/>
|
||||
@@ -598,15 +635,15 @@ const AddUserAddress = () => {
|
||||
(selectedLocation ? `经纬度:${selectedLocation.lng}, ${selectedLocation.lat}` : '用于计算是否超出配送范围')
|
||||
}
|
||||
extra={(
|
||||
<div className={'flex items-center gap-2'}>
|
||||
<div
|
||||
<View className={'flex items-center gap-2'}>
|
||||
<View
|
||||
className={'text-gray-900 text-sm'}
|
||||
style={{maxWidth: '200px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap'}}
|
||||
>
|
||||
{selectedLocation?.name || (selectedLocation ? '已选择' : '请选择')}
|
||||
</div>
|
||||
</View>
|
||||
<ArrowRight className={'text-gray-400'}/>
|
||||
</div>
|
||||
</View>
|
||||
)}
|
||||
onClick={chooseGeoLocation}
|
||||
/>
|
||||
@@ -618,6 +655,10 @@ const AddUserAddress = () => {
|
||||
options={optionsDemo1}
|
||||
title="选择地址"
|
||||
onChange={(value, _) => {
|
||||
if (regionLocked) {
|
||||
Taro.showToast({ title: '所在地区已由定位确定,修改请重新选择定位', icon: 'none' })
|
||||
return
|
||||
}
|
||||
setFormData({
|
||||
...FormData,
|
||||
province: `${value[0]}`,
|
||||
|
||||
Reference in New Issue
Block a user