OfficeSystem/pages/customer/add/index.vue
2025-11-12 15:18:21 +08:00

375 lines
10 KiB
Vue
Raw 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="add-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"
:customer-type-options="customerTypeOptions"
:source-options="sourceOptions"
:intent-options="intentOptions"
:intent-level-options="intentLevelOptions"
:customer-status-options="customerStatusOptions"
:work-wechat-options="workWechatOptions"
: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 } from 'vue';
import { createCustomer } from '@/common/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,
handleRegionChange,
handleRegionConfirm,
openRegionPicker
} = useCustomerForm();
// 表单数据
const formData = ref({
customerType: '2',
name: '',
mobile: '',
wechat: '',
source: '',
intents: [],
intentLevel: '',
customerStatus: '',
region: '',
regionIds: [],
workWechat: '',
workWechatId: null,
remark: '',
concern: '',
pain: '',
attention: '',
demand: '',
nextFollowTime: ''
});
// 显示状态
const saving = 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 pickersRef = ref(null);
// 打开选择器
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;
}
};
// 关闭选择器
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;
}
};
// uv-picker 的 change 事件处理(实现三级联动)
const onRegionChange = (e) => {
handleRegionChange(e, pickersRef.value);
};
// uv-picker 的 confirm 事件处理
const onRegionConfirm = (e) => {
handleRegionConfirm(e, formData.value);
};
// 取消
const handleCancel = () => {
uni.navigateBack();
};
// 组件挂载时加载数据并设置默认值
onMounted(async () => {
await Promise.all([
loadRegionTree(),
loadDictData(),
loadWechatList()
]);
// 设置默认值:意向=电动车按label强度=中按value来源=抖音按label状态=意向按value
try {
// 客户意向(多选,组件使用的是 label
const defaultIntentLabel = '电动车';
if (!formData.value.intents || formData.value.intents.length === 0) {
const existsIntent = intentOptions.value.some(opt => opt.label === defaultIntentLabel);
if (existsIntent) {
formData.value.intents = [defaultIntentLabel];
}
}
// 意向强度(组件使用的是 value
const defaultIntentLevelLabel = '中';
if (!formData.value.intentLevel) {
const level = intentLevelOptions.value.find(opt => opt.label === defaultIntentLevelLabel);
if (level) {
formData.value.intentLevel = level.value;
}
}
// 客户来源(组件使用的是 label
const defaultSourceLabel = '抖音';
if (!formData.value.source) {
const existsSource = sourceOptions.value.some(opt => opt.label === defaultSourceLabel);
if (existsSource) {
formData.value.source = defaultSourceLabel;
}
}
// 客户状态(组件使用的是 value
const defaultStatusLabel = '高意向';
if (!formData.value.customerStatus) {
const status = customerStatusOptions.value.find(opt => opt.label === defaultStatusLabel);
if (status) {
formData.value.customerStatus = status.value;
}
}
} catch (e) {
console.warn('设置默认字典值失败:', e);
}
});
// 保存
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 userId = userStore.userInfo?.id || userStore.userInfo?.userId || '1';
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: null,
code: null,
name: formData.value.name.trim(),
status: null,
intentLevel: null,
mobile: formData.value.mobile.trim(),
wechat: formData.value.wechat.trim() || null,
source: formData.value.source || null,
intents: intentsArray,
followId: userId,
remark: formData.value.remark.trim() || null,
type: '2',
workWechatId: formData.value.workWechatId || null,
regionIds: regionIdsArray,
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
};
await createCustomer(submitData);
uni.showToast({
title: '创建成功',
icon: 'success'
});
} catch (error) {
console.error('创建客户失败:', error);
uni.showToast({
title: error.message || '创建失败,请重试',
icon: 'none'
});
} finally {
saving.value = false;
}
};
</script>
<style lang="scss" scoped>
.add-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>