OfficeSystem/pages/customer/edit/index.vue
2025-11-13 15:02:30 +08:00

457 lines
13 KiB
Vue
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.

<template>
<view class="edit-customer-page">
<!-- 自定义导航栏 -->
<CustomerFormNavbar title="编辑客户" @cancel="handleCancel" />
<!-- 内容区域 -->
<scroll-view class="content-scroll" scroll-y>
<view class="scroll-content">
<!-- 客户信息部分 -->
<CustomerBasicInfo
:form-data="formData"
:customer-type-options="customerTypeOptions"
:intent-level-options="intentLevelOptions"
:customer-status-options="customerStatusOptions"
:lock-customer-type="true"
@update:form-data="formData = $event"
@open-picker="handleOpenPicker"
/>
<!-- 其他信息部分 -->
<CustomerOtherInfo
:form-data="formData"
@update:form-data="formData = $event"
@open-picker="handleOpenPicker"
/>
</view>
</scroll-view>
<!-- 保存按钮 -->
<view class="save-button-wrapper">
<button class="save-button" @click="handleSave" :disabled="saving">保存</button>
</view>
<!-- 选择器组件 -->
<CustomerPickers
:show-customer-type-picker="showCustomerTypePicker"
:show-source-picker="showSourcePicker"
:show-intent-picker="showIntentPicker"
:show-intent-level-picker="showIntentLevelPicker"
:show-customer-status-picker="showCustomerStatusPicker"
:show-work-wechat-picker="showWorkWechatPicker"
:show-next-follow-time-picker="showNextFollowTimePicker"
:show-follow-user-picker="showFollowUserPicker"
:customer-type-options="customerTypeOptions"
:source-options="sourceOptions"
:intent-options="intentOptions"
:intent-level-options="intentLevelOptions"
:customer-status-options="customerStatusOptions"
:work-wechat-options="workWechatOptions"
:follow-user-options="followUserOptions"
:address-list="addressList"
:region-loading="regionLoading"
:form-data="formData"
ref="pickersRef"
@update:form-data="formData = $event"
@close-picker="handleClosePicker"
@region-confirm="onRegionConfirm"
@region-change="onRegionChange"
/>
</view>
</template>
<script setup>
import { ref, onMounted, nextTick } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { updateCustomer, getCustomerDetail, getUserListAll } from '@/api';
import { useUserStore } from '@/store/user';
import { useCustomerForm } from '@/composables/useCustomerForm';
import CustomerFormNavbar from '@/components/customer/customer-form/CustomerFormNavbar.vue';
import CustomerBasicInfo from '@/components/customer/customer-form/CustomerBasicInfo.vue';
import CustomerOtherInfo from '@/components/customer/customer-form/CustomerOtherInfo.vue';
import CustomerPickers from '@/components/customer/customer-form/CustomerPickers.vue';
// 使用共享逻辑
const {
customerTypeOptions,
sourceOptions,
intentOptions,
intentLevelOptions,
customerStatusOptions,
workWechatOptions,
addressList,
regionLoading,
loadDictData,
loadWechatList,
loadRegionTree,
handlePickValueDefault,
handleRegionChange,
handleRegionConfirm,
openRegionPicker
} = useCustomerForm();
// 客户ID
const customerId = ref('');
// 表单数据
const formData = ref({
id: null,
customerType: '',
name: '',
mobile: '',
wechat: '',
source: '',
intents: [],
intentLevel: '',
customerStatus: '',
region: '',
regionIds: [],
workWechat: '',
workWechatId: null,
remark: '',
concern: '',
pain: '',
attention: '',
demand: '',
nextFollowTime: '',
followId: null,
followName: ''
});
// 显示状态
const saving = ref(false);
const loading = ref(false);
const showCustomerTypePicker = ref(false);
const showSourcePicker = ref(false);
const showIntentPicker = ref(false);
const showIntentLevelPicker = ref(false);
const showCustomerStatusPicker = ref(false);
const showWorkWechatPicker = ref(false);
const showNextFollowTimePicker = ref(false);
const showFollowUserPicker = ref(false);
// 用户列表
const followUserOptions = ref([]);
const pickersRef = ref(null);
// 获取页面参数
onLoad((options) => {
if (options && options.id) {
customerId.value = options.id;
loadCustomerDetail();
}
});
// 加载客户详情
const loadCustomerDetail = async () => {
if (!customerId.value) return;
loading.value = true;
try {
const res = await getCustomerDetail(customerId.value);
if (res) {
console.log('客户详情数据:', res);
// 将后端数据转换为表单数据格式
formData.value = {
id: res.id,
customerType: res.type || '',
name: res.name || '',
mobile: res.mobile || '',
wechat: res.wechat ||'',
source: res.source || '',
intents: Array.isArray(res.intents) ? res.intents : (res.intents ? res.intents.split(',') : []),
intentLevel: res.intentLevel || '',
customerStatus: res.customerStatus || res.status || '',
region: res.region || res.regionName || '',
// 从后端返回的 provinceId, cityId, countyId 构建 regionIds 数组(用于前端显示和选择器)
regionIds: [res.provinceId, res.cityId, res.countyId],
workWechat: res.wechatId || '',
workWechatId: res.workWechatId || null,
remark: res.remark || '',
concern: res.concern || '',
pain: res.pain || '',
attention: res.attention || '',
demand: res.demand || '',
nextFollowTime: res.nextFollowTime || '',
followId: res.followId || res.followUserId || null,
followName: res.followName || res.followUserName || ''
};
console.log('表单数据:', formData.value);
// 数据加载完成后初始化地区数据
await nextTick();
if (formData.value.regionIds && formData.value.regionIds.length > 0 && pickersRef.value) {
handlePickValueDefault(formData.value, pickersRef.value);
}
}
} catch (error) {
console.error('加载客户详情失败:', error);
uni.showToast({
title: '加载客户详情失败',
icon: 'none'
});
} finally {
loading.value = false;
}
};
// 打开选择器
const handleOpenPicker = (pickerType) => {
switch (pickerType) {
case 'customerType':
showCustomerTypePicker.value = true;
break;
case 'source':
showSourcePicker.value = true;
break;
case 'intent':
showIntentPicker.value = true;
break;
case 'intentLevel':
showIntentLevelPicker.value = true;
break;
case 'customerStatus':
showCustomerStatusPicker.value = true;
break;
case 'region':
openRegionPicker(formData.value, pickersRef.value);
break;
case 'workWechat':
showWorkWechatPicker.value = true;
break;
case 'nextFollowTime':
showNextFollowTimePicker.value = true;
break;
case 'followUser':
showFollowUserPicker.value = true;
break;
}
};
// 关闭选择器
const handleClosePicker = (pickerType) => {
switch (pickerType) {
case 'customerType':
showCustomerTypePicker.value = false;
break;
case 'source':
showSourcePicker.value = false;
break;
case 'intent':
showIntentPicker.value = false;
break;
case 'intentLevel':
showIntentLevelPicker.value = false;
break;
case 'customerStatus':
showCustomerStatusPicker.value = false;
break;
case 'workWechat':
showWorkWechatPicker.value = false;
break;
case 'nextFollowTime':
showNextFollowTimePicker.value = false;
break;
case 'followUser':
showFollowUserPicker.value = false;
break;
}
};
// uv-picker 的 change 事件处理(实现三级联动)
const onRegionChange = (e) => {
handleRegionChange(e, pickersRef.value);
};
// uv-picker 的 confirm 事件处理
const onRegionConfirm = (e) => {
handleRegionConfirm(e, formData.value);
};
// 取消
const handleCancel = () => {
uni.navigateBack();
};
// 加载用户列表
const loadUserList = async () => {
try {
const res = await getUserListAll();
if (res && res.data && Array.isArray(res.data)) {
followUserOptions.value = res.data;
} else if (res && Array.isArray(res)) {
followUserOptions.value = res;
} else {
followUserOptions.value = [];
}
} catch (error) {
console.error('加载用户列表失败:', error);
followUserOptions.value = [];
}
};
// 组件挂载时加载数据
onMounted(async () => {
await Promise.all([
loadRegionTree(),
loadDictData(),
loadWechatList(),
loadUserList()
]);
// 如果客户详情已加载,初始化地区选择器
if (formData.value.regionIds && formData.value.regionIds.length > 0 && pickersRef.value) {
handlePickValueDefault(formData.value, pickersRef.value);
}
});
// 保存
const handleSave = async () => {
if (!formData.value.name || formData.value.name.trim() === '') {
uni.showToast({
title: '请输入客户名称',
icon: 'none'
});
return;
}
if (!formData.value.mobile || formData.value.mobile.trim() === '') {
uni.showToast({
title: '请输入联系电话',
icon: 'none'
});
return;
}
saving.value = true;
try {
const userStore = useUserStore();
const defaultUserId = userStore.userInfo?.id || userStore.userInfo?.userId || '1';
// 使用选中的跟进人ID如果没有选择则使用当前用户ID
const followId = formData.value.followId || defaultUserId;
const now = new Date();
const formatDateTime = (date) => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
const intentsArray = Array.isArray(formData.value.intents) ? formData.value.intents : [];
const regionIdsArray = formData.value.regionIds || [];
const submitData = {
id: formData.value.id,
code: null,
name: formData.value.name.trim(),
status: formData.value.customerStatus || null,
intentLevel: formData.value.intentLevel || null,
mobile: formData.value.mobile.trim(),
wechat: (formData.value.wechat && formData.value.wechat.trim()) ? formData.value.wechat.trim() : null,
source: formData.value.source || null,
intents: intentsArray,
followId: followId,
remark: formData.value.remark.trim() || null,
type: formData.value.customerType || '2',
workWechatId: formData.value.workWechatId || null,
// 将 regionIds 数组转换为三个独立的字段传给后端
provinceId: (regionIdsArray[0] !== undefined && regionIdsArray[0] !== null) ? regionIdsArray[0] : null,
cityId: (regionIdsArray[1] !== undefined && regionIdsArray[1] !== null) ? regionIdsArray[1] : null,
countyId: (regionIdsArray[2] !== undefined && regionIdsArray[2] !== null) ? regionIdsArray[2] : null,
attention: formData.value.attention.trim() || null,
concern: formData.value.concern.trim() || null,
demand: formData.value.demand.trim() || null,
pain: formData.value.pain.trim() || null,
follow: {
followTime: formatDateTime(now),
nextFollowTime: formData.value.nextFollowTime || null,
customerIntentLevel: formData.value.intentLevel || null,
customerStatus: formData.value.customerStatus || null
},
nextFollowTime: formData.value.nextFollowTime || null,
customerIntentLevel: formData.value.intentLevel || null,
customerStatus: formData.value.customerStatus || null
};
console.log('提交的数据:', submitData);
console.log('地区数据:', {
regionIds: regionIdsArray,
provinceId: submitData.provinceId,
cityId: submitData.cityId,
countyId: submitData.countyId
});
await updateCustomer(submitData);
uni.showToast({
title: '更新成功',
icon: 'success'
});
// 延迟返回,让用户看到成功提示
setTimeout(() => {
uni.navigateBack();
}, 1500);
} catch (error) {
console.error('更新客户失败:', error);
uni.showToast({
title: error.message || '更新失败,请重试',
icon: 'none'
});
} finally {
saving.value = false;
}
};
</script>
<style lang="scss" scoped>
.edit-customer-page {
display: flex;
flex-direction: column;
background-color: #f5f5f5;
}
.content-scroll {
flex: 1;
}
.scroll-content {
padding: 16px;
padding-bottom: 80px;
}
.save-button-wrapper {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 12px 16px;
padding-bottom: calc(12px + env(safe-area-inset-bottom));
background-color: #fff;
border-top: 1px solid #eee;
z-index: 100;
}
.save-button {
width: 100%;
height: 44px;
background-color: #1976d2;
color: #fff;
font-size: 16px;
font-weight: 600;
border-radius: 6px;
border: none;
&:disabled {
background-color: #ccc;
opacity: 0.6;
}
}
</style>