OfficeSystem/pages/customer/add/index.vue

409 lines
11 KiB
Vue
Raw Permalink Normal View History

2025-11-07 11:09:30 +08:00
<template>
<view class="add-customer-page">
<!-- 自定义导航栏 -->
2025-11-08 10:39:16 +08:00
<CustomerFormNavbar title="客户信息" @cancel="handleCancel" />
2025-11-07 11:09:30 +08:00
<!-- 内容区域 -->
<scroll-view class="content-scroll" scroll-y>
<view class="scroll-content">
<!-- 客户信息部分 -->
2025-11-08 10:39:16 +08:00
<CustomerBasicInfo
:form-data="formData"
:customer-type-options="customerTypeOptions"
:intent-level-options="intentLevelOptions"
:customer-status-options="customerStatusOptions"
2025-11-11 16:11:29 +08:00
:lock-customer-type="true"
2025-11-08 10:39:16 +08:00
@update:form-data="formData = $event"
@open-picker="handleOpenPicker"
/>
2025-11-07 11:09:30 +08:00
<!-- 其他信息部分 -->
2025-11-08 10:39:16 +08:00
<CustomerOtherInfo
:form-data="formData"
@update:form-data="formData = $event"
@open-picker="handleOpenPicker"
/>
2025-11-07 11:09:30 +08:00
</view>
</scroll-view>
<!-- 保存按钮 -->
<view class="save-button-wrapper">
<button class="save-button" @click="handleSave" :disabled="saving">保存</button>
</view>
2025-11-08 10:39:16 +08:00
<!-- 选择器组件 -->
<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"
2025-11-13 14:52:54 +08:00
:show-follow-user-picker="showFollowUserPicker"
2025-11-08 10:39:16 +08:00
:customer-type-options="customerTypeOptions"
:source-options="sourceOptions"
:intent-options="intentOptions"
:intent-level-options="intentLevelOptions"
:customer-status-options="customerStatusOptions"
:work-wechat-options="workWechatOptions"
2025-11-13 14:52:54 +08:00
:follow-user-options="followUserOptions"
2025-11-08 10:39:16 +08:00
: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"
/>
2025-11-07 11:09:30 +08:00
</view>
</template>
<script setup>
2025-11-08 10:39:16 +08:00
import { ref, onMounted } from 'vue';
2025-11-13 14:52:54 +08:00
import { createCustomer, getUserListAll } from '@/api';
2025-11-07 11:09:30 +08:00
import { useUserStore } from '@/store/user';
2025-11-08 10:39:16 +08:00
import { useCustomerForm } from '@/composables/useCustomerForm';
2025-11-12 15:18:21 +08:00
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';
2025-11-08 10:39:16 +08:00
// 使用共享逻辑
const {
customerTypeOptions,
sourceOptions,
intentOptions,
intentLevelOptions,
customerStatusOptions,
workWechatOptions,
addressList,
regionLoading,
loadDictData,
loadWechatList,
loadRegionTree,
handleRegionChange,
handleRegionConfirm,
openRegionPicker
} = useCustomerForm();
2025-11-07 11:09:30 +08:00
// 表单数据
const formData = ref({
2025-11-11 16:11:29 +08:00
customerType: '2',
2025-11-08 10:39:16 +08:00
name: '',
mobile: '',
wechat: '',
source: '',
intents: [],
intentLevel: '',
customerStatus: '',
region: '',
regionIds: [],
workWechat: '',
workWechatId: null,
remark: '',
concern: '',
pain: '',
attention: '',
demand: '',
2025-11-13 14:52:54 +08:00
nextFollowTime: '',
followId: null,
followName: ''
2025-11-07 11:09:30 +08:00
});
// 显示状态
const saving = ref(false);
const showCustomerTypePicker = ref(false);
const showSourcePicker = ref(false);
const showIntentPicker = ref(false);
2025-11-07 11:09:30 +08:00
const showIntentLevelPicker = ref(false);
const showCustomerStatusPicker = ref(false);
2025-11-07 11:09:30 +08:00
const showWorkWechatPicker = ref(false);
const showNextFollowTimePicker = ref(false);
2025-11-13 14:52:54 +08:00
const showFollowUserPicker = ref(false);
// 用户列表
const followUserOptions = ref([]);
2025-11-07 11:09:30 +08:00
2025-11-08 10:39:16 +08:00
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;
2025-11-13 14:52:54 +08:00
case 'followUser':
showFollowUserPicker.value = true;
break;
}
};
2025-11-08 10:39:16 +08:00
// 关闭选择器
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;
2025-11-13 14:52:54 +08:00
case 'followUser':
showFollowUserPicker.value = false;
break;
2025-11-07 11:09:30 +08:00
}
};
// uv-picker 的 change 事件处理(实现三级联动)
const onRegionChange = (e) => {
2025-11-08 10:39:16 +08:00
handleRegionChange(e, pickersRef.value);
2025-11-07 11:09:30 +08:00
};
// uv-picker 的 confirm 事件处理
const onRegionConfirm = (e) => {
2025-11-08 10:39:16 +08:00
handleRegionConfirm(e, formData.value);
2025-11-07 11:09:30 +08:00
};
// 取消
const handleCancel = () => {
uni.navigateBack();
};
2025-11-13 14:52:54 +08:00
// 加载用户列表
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 = [];
}
};
2025-11-11 16:28:22 +08:00
// 组件挂载时加载数据并设置默认值
onMounted(async () => {
await Promise.all([
loadRegionTree(),
loadDictData(),
2025-11-13 14:52:54 +08:00
loadWechatList(),
loadUserList()
2025-11-11 16:28:22 +08:00
]);
// 设置默认值:意向=电动车按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
2025-11-11 18:12:37 +08:00
const defaultStatusLabel = '高意向';
2025-11-11 16:28:22 +08:00
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);
}
2025-11-07 11:09:30 +08:00
});
// 保存
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 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 : [];
2025-11-07 11:09:30 +08:00
const regionIdsArray = formData.value.regionIds || [];
2025-11-13 14:52:54 +08:00
// 使用选中的跟进人ID如果没有选择则使用当前用户ID
const userStore = useUserStore();
const defaultUserId = userStore.userInfo?.id || userStore.userInfo?.userId || '1';
const followId = formData.value.followId || defaultUserId;
2025-11-07 11:09:30 +08:00
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,
2025-11-08 10:39:16 +08:00
source: formData.value.source || null,
intents: intentsArray,
2025-11-13 14:52:54 +08:00
followId: followId,
2025-11-07 11:09:30 +08:00
remark: formData.value.remark.trim() || null,
2025-11-11 16:11:29 +08:00
type: '2',
2025-11-07 11:09:30 +08:00
workWechatId: formData.value.workWechatId || null,
2025-11-08 10:39:16 +08:00
regionIds: regionIdsArray,
2025-11-07 13:31:19 +08:00
attention: formData.value.attention.trim() || null,
concern: formData.value.concern.trim() || null,
demand: formData.value.demand.trim() || null,
pain: formData.value.pain.trim() || null,
2025-11-07 11:09:30 +08:00
follow: {
2025-11-08 10:39:16 +08:00
followTime: formatDateTime(now),
2025-11-07 11:09:30 +08:00
nextFollowTime: formData.value.nextFollowTime || null,
2025-11-08 10:39:16 +08:00
customerIntentLevel: formData.value.intentLevel || null,
customerStatus: formData.value.customerStatus || null
2025-11-07 11:09:30 +08:00
},
nextFollowTime: formData.value.nextFollowTime || null,
2025-11-08 10:39:16 +08:00
customerIntentLevel: formData.value.intentLevel || null,
customerStatus: formData.value.customerStatus || null
2025-11-07 11:09:30 +08:00
};
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;
2025-11-10 09:07:13 +08:00
2025-11-07 11:09:30 +08:00
background-color: #f5f5f5;
}
.content-scroll {
flex: 1;
}
.scroll-content {
padding: 16px;
2025-11-08 10:39:16 +08:00
padding-bottom: 80px;
2025-11-07 11:09:30 +08:00
}
.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>