Files
2025-11-17 14:11:46 +08:00

640 lines
20 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Toast from 'tdesign-miniprogram/toast/index';
import { fetchDeliveryAddress, fetchDeliveryAddressList, createAddress, updateAddress } from '../../../../services/address/fetchAddress';
import { areaData } from '../../../../config/index';
import { resolveAddress, rejectAddress } from '../../../../services/address/list';
// 添加日志工具
const logger = {
info: (module, message, data = {}) => {
console.log(`[${new Date().toISOString()}] [INFO] [${module}] ${message}`, data);
},
debug: (module, message, data = {}) => {
console.log(`[${new Date().toISOString()}] [DEBUG] [${module}] ${message}`, data);
},
error: (module, message, data = {}) => {
console.error(`[${new Date().toISOString()}] [ERROR] [${module}] ${message}`, data);
},
warn: (module, message, data = {}) => {
console.warn(`[${new Date().toISOString()}] [WARN] [${module}] ${message}`, data);
}
};
const innerPhoneReg = '^1(?:3\\d|4[4-9]|5[0-35-9]|6[67]|7[0-8]|8\\d|9\\d)\\d{8}$';
const innerNameReg = '^[a-zA-Z\\d\\u4e00-\\u9fa5]+$';
const labelsOptions = [
{ id: 0, name: '家' },
{ id: 1, name: '公司' },
];
Page({
options: {
multipleSlots: true,
},
externalClasses: ['theme-wrapper-class'],
data: {
locationState: {
labelIndex: null,
addressId: '',
addressTag: '',
cityCode: '',
cityName: '',
countryCode: '',
countryName: '',
detailAddress: '',
districtCode: '',
districtName: '',
isDefault: false,
name: '',
phone: '',
provinceCode: '',
provinceName: '',
isEdit: false,
isOrderDetail: false,
isOrderSure: false,
},
areaData: areaData,
labels: labelsOptions,
areaPickerVisible: false,
submitActive: false,
visible: false,
labelValue: '',
columns: 3,
},
privateData: {
verifyTips: '',
},
onLoad(options) {
logger.info('ADDRESS_EDIT_PAGE', '地址编辑页面加载', { options });
const { id } = options;
this.init(id);
},
onUnload() {
logger.info('ADDRESS_EDIT_PAGE', '地址编辑页面卸载', { hasSaved: this.hasSava });
if (!this.hasSava) {
logger.debug('ADDRESS_EDIT_PAGE', '页面卸载时未保存,取消地址编辑');
rejectAddress();
}
},
hasSava: false,
isWeixinImport: false, // 标记是否为微信地址导入
init(id) {
logger.info('ADDRESS_EDIT_PAGE', '初始化地址编辑页面', { addressId: id });
if (id) {
logger.debug('ADDRESS_EDIT_PAGE', '编辑模式,获取地址详情');
this.getAddressDetail(Number(id));
} else {
logger.debug('ADDRESS_EDIT_PAGE', '新建模式,检查用户是否有现有地址');
this.checkUserAddressesAndSetDefault();
}
},
// 检查用户地址数量,如果没有地址则自动开启默认地址开关
checkUserAddressesAndSetDefault() {
logger.info('ADDRESS_EDIT_PAGE', '开始检查用户现有地址数量');
fetchDeliveryAddressList().then((addressList) => {
const addressCount = addressList ? addressList.length : 0;
logger.info('ADDRESS_EDIT_PAGE', '用户地址数量检查完成', {
addressCount,
willSetDefault: addressCount === 0
});
if (addressCount === 0) {
// 用户没有地址,自动开启默认地址开关
logger.info('ADDRESS_EDIT_PAGE', '用户没有现有地址,自动开启默认地址开关');
this.setData({
'locationState.isDefault': true
});
Toast({
context: this,
selector: '#t-toast',
message: '已自动设置为默认地址',
theme: 'success',
duration: 2000,
});
} else {
logger.debug('ADDRESS_EDIT_PAGE', '用户已有地址,保持默认地址开关为关闭状态');
}
}).catch((err) => {
logger.error('ADDRESS_EDIT_PAGE', '检查用户地址数量失败', {
error: err.message || err
});
// 检查失败时,为了安全起见,不自动开启默认地址开关
logger.warn('ADDRESS_EDIT_PAGE', '由于检查失败,不自动开启默认地址开关');
});
},
getAddressDetail(id) {
logger.info('ADDRESS_EDIT_PAGE', '开始获取地址详情', { addressId: id });
// 获取地址列表,然后找到对应的地址
fetchDeliveryAddressList().then((addressList) => {
logger.debug('ADDRESS_EDIT_PAGE', '获取地址列表成功,查找目标地址', {
totalCount: addressList.length,
targetId: id
});
const address = addressList.find(addr => addr.id == id);
if (address) {
logger.info('ADDRESS_EDIT_PAGE', '找到目标地址,设置编辑数据', {
addressId: address.id,
name: address.name,
phone: address.phone,
isDefault: address.isDefault
});
const detail = {
addressId: address.id,
name: address.name,
phone: address.phone,
provinceName: address.province_name,
provinceCode: address.province_code,
cityName: address.city_name,
cityCode: address.city_code,
districtName: address.district_name,
districtCode: address.district_code,
detailAddress: address.detail_address,
isDefault: Boolean(address.is_default),
addressTag: address.address_tag || '',
isEdit: true
};
this.setData({ locationState: detail }, () => {
const { isLegal, tips } = this.onVerifyInputLegal();
this.setData({
submitActive: isLegal,
});
this.privateData.verifyTips = tips;
logger.debug('ADDRESS_EDIT_PAGE', '地址数据设置完成', {
isLegal,
tips: tips || '无验证提示'
});
});
} else {
logger.warn('ADDRESS_EDIT_PAGE', '未找到目标地址', { addressId: id });
Toast({
context: this,
selector: '#t-toast',
message: '地址不存在',
icon: '',
duration: 1000,
});
}
}).catch((err) => {
logger.error('ADDRESS_EDIT_PAGE', '获取地址详情失败', {
addressId: id,
error: err.message || err
});
console.error('获取地址详情失败:', err);
Toast({
context: this,
selector: '#t-toast',
message: '获取地址详情失败',
icon: '',
duration: 1000,
});
});
},
onInputValue(e) {
const { item } = e.currentTarget.dataset;
logger.debug('ADDRESS_EDIT_PAGE', '用户输入值变化', {
field: item,
eventType: e.type
});
if (item === 'address') {
const { selectedOptions = [] } = e.detail;
logger.info('ADDRESS_EDIT_PAGE', '用户选择地区', {
selectedCount: selectedOptions.length,
province: selectedOptions[0]?.label,
city: selectedOptions[1]?.label,
district: selectedOptions[2]?.label
});
this.setData(
{
'locationState.provinceCode': selectedOptions.length > 0 ? selectedOptions[0].value : '',
'locationState.provinceName': selectedOptions.length > 0 ? selectedOptions[0].label : '',
'locationState.cityName': selectedOptions.length > 1 ? selectedOptions[1].label : '',
'locationState.cityCode': selectedOptions.length > 1 ? selectedOptions[1].value : '',
'locationState.districtCode': selectedOptions.length > 2 ? selectedOptions[2].value : '',
'locationState.districtName': selectedOptions.length > 2 ? selectedOptions[2].label : '',
areaPickerVisible: false,
},
() => {
const { isLegal, tips } = this.onVerifyInputLegal();
this.setData({
submitActive: isLegal,
});
this.privateData.verifyTips = tips;
logger.debug('ADDRESS_EDIT_PAGE', '地区选择后验证结果', { isLegal, tips });
},
);
} else {
const { value = '' } = e.detail;
logger.debug('ADDRESS_EDIT_PAGE', '用户输入字段值', {
field: item,
valueLength: value.length,
value: item === 'phone' ? value.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') : value.substring(0, 20)
});
this.setData(
{
[`locationState.${item}`]: value,
},
() => {
const { isLegal, tips } = this.onVerifyInputLegal();
this.setData({
submitActive: isLegal,
});
this.privateData.verifyTips = tips;
logger.debug('ADDRESS_EDIT_PAGE', '字段输入后验证结果', {
field: item,
isLegal,
tips
});
},
);
}
},
onPickArea() {
this.setData({ areaPickerVisible: true });
},
onPickLabels(e) {
const { item } = e.currentTarget.dataset;
const {
locationState: { labelIndex = undefined },
labels = [],
} = this.data;
let payload = {
labelIndex: item,
addressTag: labels[item].name,
};
if (item === labelIndex) {
payload = { labelIndex: null, addressTag: '' };
}
this.setData({
'locationState.labelIndex': payload.labelIndex,
});
this.triggerEvent('triggerUpdateValue', payload);
},
addLabels() {
this.setData({
visible: true,
});
},
confirmHandle() {
const { labels, labelValue } = this.data;
this.setData({
visible: false,
labels: [...labels, { id: labels[labels.length - 1].id + 1, name: labelValue }],
labelValue: '',
});
},
cancelHandle() {
this.setData({
visible: false,
labelValue: '',
});
},
onCheckDefaultAddress({ detail }) {
const { value } = detail;
this.setData({
'locationState.isDefault': value,
});
},
onVerifyInputLegal() {
const { name, phone, detailAddress, districtName } = this.data.locationState;
const prefixPhoneReg = String(this.properties.phoneReg || innerPhoneReg);
const prefixNameReg = String(this.properties.nameReg || innerNameReg);
const nameRegExp = new RegExp(prefixNameReg);
const phoneRegExp = new RegExp(prefixPhoneReg);
if (!name || !name.trim()) {
return {
isLegal: false,
tips: '请填写收货人',
};
}
if (!nameRegExp.test(name)) {
return {
isLegal: false,
tips: '收货人仅支持输入中文、英文(区分大小写)、数字',
};
}
if (!phone || !phone.trim()) {
return {
isLegal: false,
tips: '请填写手机号',
};
}
// 如果是微信导入,跳过手机号格式验证
if (this.isWeixinImport) {
console.log('[地址编辑-验证] 微信导入模式,跳过手机号格式验证:', phone);
} else if (!phoneRegExp.test(phone)) {
return {
isLegal: false,
tips: '请填写正确的手机号',
};
}
if (!districtName || !districtName.trim()) {
return {
isLegal: false,
tips: '请选择省市区信息',
};
}
if (!detailAddress || !detailAddress.trim()) {
return {
isLegal: false,
tips: '请完善详细地址',
};
}
if (detailAddress && detailAddress.trim().length > 50) {
return {
isLegal: false,
tips: '详细地址不能超过50个字符',
};
}
return {
isLegal: true,
tips: '添加成功',
};
},
builtInSearch({ code, name }) {
return new Promise((resolve, reject) => {
wx.getSetting({
success: (res) => {
if (res.authSetting[code] === false) {
wx.showModal({
title: `获取${name}失败`,
content: `获取${name}失败,请在【右上角】-小程序【设置】项中,将【${name}】开启。`,
confirmText: '去设置',
confirmColor: '#FA550F',
cancelColor: '取消',
success(res) {
if (res.confirm) {
wx.openSetting({
success(settinRes) {
if (settinRes.authSetting[code] === true) {
resolve();
} else {
console.warn('用户未打开权限', name, code);
reject();
}
},
});
} else {
reject();
}
},
fail() {
reject();
},
});
} else {
resolve();
}
},
fail() {
reject();
},
});
});
},
onSearchAddress() {
this.builtInSearch({ code: 'scope.userLocation', name: '地址位置' }).then(() => {
wx.chooseLocation({
success: (res) => {
if (res.name) {
this.triggerEvent('addressParse', {
address: res.address,
name: res.name,
latitude: res.latitude,
longitude: res.longitude,
});
} else {
Toast({
context: this,
selector: '#t-toast',
message: '地点为空,请重新选择',
icon: '',
duration: 1000,
});
}
},
fail: function (res) {
console.warn(`wx.chooseLocation fail: ${JSON.stringify(res)}`);
if (res.errMsg !== 'chooseLocation:fail cancel') {
Toast({
context: this,
selector: '#t-toast',
message: '地点错误,请重新选择',
icon: '',
duration: 1000,
});
}
},
});
});
},
formSubmit() {
logger.info('ADDRESS_EDIT_PAGE', '用户提交地址表单', {
hasSubmitActive: this.data.submitActive,
addressId: this.data.locationState.addressId,
isEdit: this.data.locationState.isEdit
});
const { submitActive } = this.data;
if (!submitActive) {
logger.warn('ADDRESS_EDIT_PAGE', '表单验证失败,无法提交', {
verifyTips: this.privateData.verifyTips
});
Toast({
context: this,
selector: '#t-toast',
message: this.privateData.verifyTips,
icon: '',
duration: 1000,
});
return;
}
const { locationState } = this.data;
// 构造API请求数据
const addressData = {
name: locationState.name,
phone: locationState.phone,
province: locationState.provinceName,
city: locationState.cityName,
district: locationState.districtName,
detail: locationState.detailAddress,
is_default: locationState.isDefault ? 1 : 0,
};
logger.info('ADDRESS_EDIT_PAGE', '准备提交地址数据', {
isEdit: locationState.isEdit,
addressId: locationState.addressId,
locationState: {
name: locationState.name,
phone: locationState.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2'),
provinceName: locationState.provinceName,
cityName: locationState.cityName,
districtName: locationState.districtName,
detailAddress: locationState.detailAddress,
isDefault: locationState.isDefault
},
addressData: {
...addressData,
phone: addressData.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
}
});
const isEdit = locationState.addressId && locationState.isEdit;
logger.info('ADDRESS_EDIT_PAGE', `准备${isEdit ? '更新' : '创建'}地址`, {
isEdit,
addressId: locationState.addressId,
name: addressData.name,
phone: addressData.phone,
province: addressData.provinceName,
city: addressData.cityName,
district: addressData.districtName,
isDefault: addressData.isDefault,
addressTag: addressData.addressTag
});
const apiCall = isEdit
? updateAddress(locationState.addressId, addressData)
: createAddress(addressData);
apiCall.then((result) => {
this.hasSava = true;
logger.info('ADDRESS_EDIT_PAGE', `地址${isEdit ? '更新' : '创建'}成功`, {
isEdit,
addressId: result.id || locationState.addressId,
resultData: result,
resultType: typeof result,
resultKeys: result ? Object.keys(result) : 'null'
});
Toast({
context: this,
selector: '#t-toast',
message: isEdit ? '地址更新成功' : '地址创建成功',
theme: 'success',
duration: 1000,
});
// 返回给地址列表页面的数据 - 优先使用服务器返回的数据
const addressResult = {
id: result.id || locationState.addressId,
addressId: result.id || locationState.addressId,
phone: result.phone || locationState.phone,
name: result.name || locationState.name,
provinceName: result.provinceName || locationState.provinceName,
provinceCode: locationState.provinceCode, // 服务器不返回code使用本地数据
cityName: result.cityName || locationState.cityName,
cityCode: locationState.cityCode, // 服务器不返回code使用本地数据
districtName: result.districtName || locationState.districtName,
districtCode: locationState.districtCode, // 服务器不返回code使用本地数据
detailAddress: result.detailAddress || locationState.detailAddress,
isDefault: result.isDefault !== undefined ? (result.isDefault ? 1 : 0) : (locationState.isDefault ? 1 : 0),
addressTag: locationState.addressTag || '',
isEdit: isEdit
};
logger.debug('ADDRESS_EDIT_PAGE', '准备返回地址列表页面', {
addressResult
});
resolveAddress(addressResult);
wx.navigateBack({ delta: 1 });
}).catch((err) => {
logger.error('ADDRESS_EDIT_PAGE', `地址${isEdit ? '更新' : '创建'}失败`, {
isEdit,
addressId: locationState.addressId,
error: err.message || err,
addressData
});
console.error('保存地址失败:', err);
Toast({
context: this,
selector: '#t-toast',
message: isEdit ? '地址更新失败' : '地址创建失败',
icon: '',
duration: 1000,
});
});
},
getWeixinAddress(e) {
console.log('[地址编辑-微信导入] 开始处理微信地址数据');
console.log('[地址编辑-微信导入] 接收到的事件对象:', e);
console.log('[地址编辑-微信导入] 事件详情数据:', e.detail);
const { locationState } = this.data;
console.log('[地址编辑-微信导入] 当前locationState:', locationState);
const weixinAddress = e.detail;
console.log('[地址编辑-微信导入] 微信地址数据:', weixinAddress);
const mergedState = { ...locationState, ...weixinAddress };
console.log('[地址编辑-微信导入] 合并后的地址状态:', mergedState);
// 设置微信导入标记
this.isWeixinImport = true;
console.log('[地址编辑-微信导入] 设置微信导入标记,跳过手机号验证');
this.setData(
{
locationState: mergedState,
},
() => {
console.log('[地址编辑-微信导入] setData完成开始验证输入合法性');
const { isLegal, tips } = this.onVerifyInputLegal();
console.log('[地址编辑-微信导入] 验证结果:', { isLegal, tips });
this.setData({
submitActive: isLegal,
});
this.privateData.verifyTips = tips;
console.log('[地址编辑-微信导入] 提交按钮状态更新为:', isLegal);
console.log('[地址编辑-微信导入] 验证提示信息:', tips);
console.log('[地址编辑-微信导入] 微信地址数据处理完成');
// 重置微信导入标记
this.isWeixinImport = false;
},
);
},
});