diff --git a/App.vue b/App.vue index 0e709ea..6f72ade 100644 --- a/App.vue +++ b/App.vue @@ -8,7 +8,7 @@ // 如果还没有 token,则设置一个测试 token const token = uni.getStorageSync('token') if (!token) { - const testToken = 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImQ0ODJhYzdlLTBiYzgtNGFhNC1hMDI2LWVkMWU4YWQ3YmJkYiJ9._m4s6mcpjAHtk4u9r6LMMfIQHSCXDPCTfiWVOTyopZfbsxVFiLkY4ovec3M3u2E9KKm_jIH2fLhAduW4rfAZHQ' + const testToken = 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjlkN2JjOTU3LTllMTYtNGI5ZC04NWZiLThiZjJlZDI3MjRjNiJ9.hJ0Tf691DnryIMp4TAsKILSy9ueN8SgeMZdp0HwxbgGOIhYl5vOUu9H64tA02jpXkB-Sg5owrBjjJxUG17yA7g' uni.setStorageSync('token', testToken) console.log('已设置测试 token:', testToken) } diff --git a/common/api/customer.js b/common/api/customer.js index eaeca8f..779af75 100644 --- a/common/api/customer.js +++ b/common/api/customer.js @@ -164,3 +164,63 @@ export const createCustomer = (data) => { }); }; +/** + * 获取客户意向字典数据 + * @returns {Promise} 返回字典数据数组,包含 dictLabel 和 dictValue + */ +export const getCustomerIntentDict = () => { + return uni.$uv.http.get(`system/dict/data/type/customer_intent`, { + custom: { + auth: true + } + }); +}; + +/** + * 获取客户意向强度字典数据 + * @returns {Promise} 返回字典数据数组,包含 dictLabel 和 dictValue + */ +export const getCustomerIntentLevelDict = () => { + return uni.$uv.http.get(`system/dict/data/type/customer_intent_level`, { + custom: { + auth: true + } + }); +}; + +/** + * 获取客户来源字典数据 + * @returns {Promise} 返回字典数据数组,包含 dictLabel 和 dictValue + */ +export const getCustomerSourceDict = () => { + return uni.$uv.http.get(`system/dict/data/type/customer_source`, { + custom: { + auth: true + } + }); +}; + +/** + * 获取客户类型字典数据 + * @returns {Promise} 返回字典数据数组,包含 dictLabel 和 dictValue + */ +export const getCustomerTypeDict = () => { + return uni.$uv.http.get(`system/dict/data/type/customer_type`, { + custom: { + auth: true + } + }); +}; + +/** + * 获取客户状态字典数据 + * @returns {Promise} 返回字典数据数组,包含 dictLabel 和 dictValue + */ +export const getCustomerStatusDict = () => { + return uni.$uv.http.get(`system/dict/data/type/customer_status`, { + custom: { + auth: true + } + }); +}; + diff --git a/pages/customer/add/index.vue b/pages/customer/add/index.vue index 103be16..5d01af0 100644 --- a/pages/customer/add/index.vue +++ b/pages/customer/add/index.vue @@ -17,26 +17,10 @@ 客户信息 - - 客户类型 - - - - 个人 - - - - 企业 - - + + {{ getCustomerTypeText(formData.customerType) }} + 选择客户类型 + @@ -71,29 +55,16 @@ - - + + {{ formData.source }} + 选择客户来源 + - - - - - - - {{ getStatusText(formData.status) }} - 选择客户状态 + + {{ formData.intents.join('、') }} + 选择客户意向(可多选) @@ -104,6 +75,13 @@ + + + {{ getCustomerStatusText(formData.customerStatus) }} + 选择客户状态 + + + {{ formData.region }} @@ -207,25 +185,71 @@ - - + + - 选择客户状态 + 选择客户类型 {{ item.label }} - + - - + + + + + + + + + + 选择客户来源 + + + {{ item.label }} + + + + + + + + + + + + + + 选择客户意向(可多选) + + + {{ item.label }} + + + + + + @@ -253,6 +277,29 @@ + + + + 选择客户状态 + + + {{ item.label }} + + + + + + + + + + import { ref, computed, onMounted } from 'vue'; -import { createCustomer, getRegionTree } from '@/common/api'; +import { + createCustomer, + getRegionTree, + getCustomerIntentDict, + getCustomerIntentLevelDict, + getCustomerSourceDict, + getCustomerTypeDict, + getCustomerStatusDict +} from '@/common/api'; import { useUserStore } from '@/store/user'; // 表单数据 const formData = ref({ - customerType: '个人', // 客户类型:个人/企业 + customerType: '', // 客户类型(dictValue) name: '', // 客户名称 mobile: '', // 联系电话 wechat: '', // 微信号 - source: '', // 客户来源 - intents: '', // 客户意向(字符串,提交时转换为数组) - status: '', // 客户状态 - intentLevel: '', // 意向强度 + source: '', // 客户来源(dictLabel) + intents: [], // 客户意向(数组,dictLabel) + intentLevel: '', // 意向强度(dictValue) + customerStatus: '', // 客户状态(dictValue) region: '', // 客户地区(显示名称,如:北京/北京/朝阳) regionIds: [], // 客户地区ID数组 [省ID, 市ID, 区ID] workWechat: '', // 工作微信(显示名称) @@ -346,18 +401,31 @@ const formData = ref({ // 显示状态 const saving = ref(false); -const showStatusPicker = 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 tempStatus = ref(''); +const tempCustomerType = ref(''); +const tempSource = ref(''); +const tempIntents = ref([]); const tempIntentLevel = ref(''); +const tempCustomerStatus = ref(''); const tempWorkWechat = ref(''); const tempNextFollowDate = ref(''); const tempNextFollowTime = ref(''); +// 字典数据 +const customerTypeOptions = ref([]); // 客户类型选项 +const sourceOptions = ref([]); // 客户来源选项 +const intentOptions = ref([]); // 客户意向选项 +const intentLevelOptions = ref([]); // 意向强度选项 +const customerStatusOptions = ref([]); // 客户状态选项 + // 地区树数据 const regionTree = ref([]); // uv-picker 的列数据 @@ -374,20 +442,63 @@ const addressList = computed(() => { return [provinces.value, citys.value, areas.value]; }); -// 客户状态选项 -const statusOptions = [ - { label: '潜在', value: '1' }, - { label: '意向', value: '2' }, - { label: '成交', value: '3' }, - { label: '失效', value: '4' } -]; - -// 意向强度选项 -const intentLevelOptions = [ - { label: '高', value: '1' }, - { label: '中', value: '2' }, - { label: '低', value: '3' } -]; +// 加载字典数据 +const loadDictData = async () => { + try { + // 并行加载所有字典数据 + const [typeRes, sourceRes, intentRes, intentLevelRes, statusRes] = await Promise.all([ + getCustomerTypeDict(), + getCustomerSourceDict(), + getCustomerIntentDict(), + getCustomerIntentLevelDict(), + getCustomerStatusDict() + ]); + + // 处理客户类型数据 + customerTypeOptions.value = (typeRes || []).map(item => ({ + label: item.dictLabel, + value: item.dictValue + })); + + // 处理客户来源数据 + sourceOptions.value = (sourceRes || []).map(item => ({ + label: item.dictLabel, + value: item.dictValue + })); + + // 处理客户意向数据 + intentOptions.value = (intentRes || []).map(item => ({ + label: item.dictLabel, + value: item.dictValue + })); + + // 处理意向强度数据 + intentLevelOptions.value = (intentLevelRes || []).map(item => ({ + label: item.dictLabel, + value: item.dictValue + })); + + // 处理客户状态数据 + customerStatusOptions.value = (statusRes || []).map(item => ({ + label: item.dictLabel, + value: item.dictValue + })); + + console.log('字典数据加载成功:', { + customerType: customerTypeOptions.value, + source: sourceOptions.value, + intent: intentOptions.value, + intentLevel: intentLevelOptions.value, + customerStatus: customerStatusOptions.value + }); + } catch (err) { + console.error('加载字典数据失败:', err); + uni.showToast({ + title: '加载字典数据失败', + icon: 'none' + }); + } +}; // 加载地区树数据 const loadRegionTree = async () => { @@ -466,32 +577,78 @@ const workWechatOptions = [ { label: '工作微信4', value: '工作微信4', id: '4' } ]; -// 获取状态文本 -const getStatusText = (status) => { - const option = statusOptions.find(opt => opt.value === status); +// 获取客户类型文本 +const getCustomerTypeText = (value) => { + const option = customerTypeOptions.value.find(opt => opt.value === value); return option ? option.label : ''; }; // 获取意向强度文本 -const getIntentLevelText = (level) => { - return level || ''; +const getIntentLevelText = (value) => { + const option = intentLevelOptions.value.find(opt => opt.value === value); + return option ? option.label : ''; }; -// 打开状态选择器 -const openStatusPicker = () => { - tempStatus.value = formData.value.status; - showStatusPicker.value = true; +// 获取客户状态文本 +const getCustomerStatusText = (value) => { + const option = customerStatusOptions.value.find(opt => opt.value === value); + return option ? option.label : ''; }; -// 选择状态 -const selectStatus = (value) => { - tempStatus.value = value; +// 打开客户类型选择器 +const openCustomerTypePicker = () => { + tempCustomerType.value = formData.value.customerType; + showCustomerTypePicker.value = true; }; -// 确认状态 -const confirmStatus = () => { - formData.value.status = tempStatus.value; - showStatusPicker.value = false; +// 选择客户类型 +const selectCustomerType = (value) => { + tempCustomerType.value = value; +}; + +// 确认客户类型 +const confirmCustomerType = () => { + formData.value.customerType = tempCustomerType.value; + showCustomerTypePicker.value = false; +}; + +// 打开客户来源选择器 +const openSourcePicker = () => { + tempSource.value = formData.value.source; + showSourcePicker.value = true; +}; + +// 选择客户来源 +const selectSource = (label) => { + tempSource.value = label; +}; + +// 确认客户来源 +const confirmSource = () => { + formData.value.source = tempSource.value; + showSourcePicker.value = false; +}; + +// 打开客户意向选择器 +const openIntentPicker = () => { + tempIntents.value = [...formData.value.intents]; + showIntentPicker.value = true; +}; + +// 切换客户意向(多选) +const toggleIntent = (label) => { + const index = tempIntents.value.indexOf(label); + if (index > -1) { + tempIntents.value.splice(index, 1); + } else { + tempIntents.value.push(label); + } +}; + +// 确认客户意向 +const confirmIntent = () => { + formData.value.intents = [...tempIntents.value]; + showIntentPicker.value = false; }; // 打开意向强度选择器 @@ -511,6 +668,23 @@ const confirmIntentLevel = () => { showIntentLevelPicker.value = false; }; +// 打开客户状态选择器 +const openCustomerStatusPicker = () => { + tempCustomerStatus.value = formData.value.customerStatus; + showCustomerStatusPicker.value = true; +}; + +// 选择客户状态 +const selectCustomerStatus = (value) => { + tempCustomerStatus.value = value; +}; + +// 确认客户状态 +const confirmCustomerStatus = () => { + formData.value.customerStatus = tempCustomerStatus.value; + showCustomerStatusPicker.value = false; +}; + // 打开地区选择器 const openRegionPicker = () => { console.log('openRegionPicker called'); @@ -679,9 +853,10 @@ const handleCancel = () => { uni.navigateBack(); }; -// 组件挂载时加载地区树数据 +// 组件挂载时加载地区树数据和字典数据 onMounted(() => { loadRegionTree(); + loadDictData(); }); // 保存 @@ -721,11 +896,8 @@ const handleSave = async () => { return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; }; - // 处理意向设备数组(如果输入的是逗号分隔的字符串,转换为数组) - let intentsArray = []; - if (formData.value.intents && formData.value.intents.trim()) { - intentsArray = formData.value.intents.split(',').map(item => item.trim()).filter(item => item); - } + // 处理意向数组(已经是数组格式,包含dictLabel) + const intentsArray = Array.isArray(formData.value.intents) ? formData.value.intents : []; // 处理地区ID数组(使用已选择的regionIds) const regionIdsArray = formData.value.regionIds || []; @@ -739,11 +911,11 @@ const handleSave = async () => { intentLevel: null, mobile: formData.value.mobile.trim(), wechat: formData.value.wechat.trim() || null, - source: formData.value.source.trim() || null, - intents: intentsArray, // 数组格式 + source: formData.value.source || null, // 使用dictLabel + intents: intentsArray, // 数组格式,使用dictLabel followId: userId, // 跟进人ID remark: formData.value.remark.trim() || null, - type: '2', // 固定为2 + type: formData.value.customerType || '2', // 使用dictValue workWechatId: formData.value.workWechatId || null, regionIds: regionIdsArray, // 数组格式 // 添加关注点、顾虑点、需求点、痛点字段 @@ -754,12 +926,12 @@ const handleSave = async () => { follow: { followTime: formatDateTime(now), // 当前时间作为跟进时间 nextFollowTime: formData.value.nextFollowTime || null, - customerStatus: formData.value.status || '1', - customerIntentLevel: formData.value.intentLevel || null + customerIntentLevel: formData.value.intentLevel || null, // 使用dictValue + customerStatus: formData.value.customerStatus || null // 使用dictValue }, - customerStatus: formData.value.status || '1', nextFollowTime: formData.value.nextFollowTime || null, - customerIntentLevel: formData.value.intentLevel || null + customerIntentLevel: formData.value.intentLevel || null, // 使用dictValue + customerStatus: formData.value.customerStatus || null // 使用dictValue }; // 调用API创建客户 @@ -770,10 +942,7 @@ const handleSave = async () => { icon: 'success' }); - // 延迟返回上一页 - setTimeout(() => { - uni.navigateBack(); - }, 1500); + // 保存成功后不清空表单,留在当前页面 } catch (error) { console.error('创建客户失败:', error); uni.showToast({