From 39d77b5a3c8adddaf8f71bd12a0ef81a7a8bf723 Mon Sep 17 00:00:00 2001 From: zy Date: Sat, 24 May 2025 21:39:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9-=E5=8F=8D=E9=A6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/crm/feedback/index.ts | 54 +++ src/api/crm/quotation/index.ts | 5 + src/components/SelectCustomer/src/index.vue | 22 +- src/router/modules/remaining.ts | 36 ++ src/styles/index.scss | 4 + src/utils/dict.ts | 4 + src/views/crm/business/BusinessForm.vue | 90 +++-- .../components/BusinessProductForm.vue | 43 +- src/views/crm/business/index.vue | 26 +- src/views/crm/contact/ContactForm.vue | 6 +- src/views/crm/contract/ContractChange.vue | 6 +- src/views/crm/contract/ContractForm.vue | 190 +++++++-- .../ContractAAuthorizedPersonForm.vue | 17 +- .../crm/contract/detail/ContractDetail.vue | 124 ++++-- src/views/crm/contract/index.vue | 8 +- src/views/crm/customer/CustomerForm.vue | 14 +- .../customer/detail/CustomerDetailsHeader.vue | 2 +- src/views/crm/customer/detail/index.vue | 6 +- src/views/crm/customer/index.vue | 2 +- .../crm/feedback/CustomerFeedbackDetail.vue | 374 ++++++++++++++++++ .../crm/feedback/CustomerFeedbackForm.vue | 314 +++++++++++++++ src/views/crm/feedback/index.vue | 313 +++++++++++++++ src/views/crm/quotation/QuotationForm.vue | 203 +++++++--- .../components/QuotationProductForm.vue | 40 +- src/views/crm/quotation/index.vue | 64 ++- src/views/system/user/UserForm.vue | 1 + 26 files changed, 1767 insertions(+), 201 deletions(-) create mode 100644 src/api/crm/feedback/index.ts create mode 100644 src/views/crm/feedback/CustomerFeedbackDetail.vue create mode 100644 src/views/crm/feedback/CustomerFeedbackForm.vue create mode 100644 src/views/crm/feedback/index.vue diff --git a/src/api/crm/feedback/index.ts b/src/api/crm/feedback/index.ts new file mode 100644 index 000000000..1ff57293b --- /dev/null +++ b/src/api/crm/feedback/index.ts @@ -0,0 +1,54 @@ +import request from '@/config/axios' + +// 客户反馈 VO +export interface CustomerFeedbackVO { + id: number // 主键 + customerId: number // 客户ID + contactId: number // 反馈联系人ID + mobile: string // 联系电话 + email: string // 电子邮箱 + feedbackType: number // 反馈类型 + feedbackLevel: number // 反馈级别 + urgencyLevel: number // 紧急程度 + feedbackTime: Date // 反馈时间 + relatedPerson: number // 当事人用户ID + deptId: number // 所属部门ID + customerFeedbackCount: number // 客户累计计数 + relatedPersonFeedbackCount: number // 当事人累计计数 + feedbackCompanyEntity: string // 反馈主体 + feedbackContent: string // 反馈内容 + attachment: string // 附件 +} + +// 客户反馈 API +export const CustomerFeedbackApi = { + // 查询客户反馈分页 + getCustomerFeedbackPage: async (params: any) => { + return await request.get({ url: `/crm/customer-feedback/page`, params }) + }, + + // 查询客户反馈详情 + getCustomerFeedback: async (id: number) => { + return await request.get({ url: `/crm/customer-feedback/get?id=` + id }) + }, + + // 新增客户反馈 + createCustomerFeedback: async (data: CustomerFeedbackVO) => { + return await request.post({ url: `/crm/customer-feedback/create`, data }) + }, + + // 修改客户反馈 + updateCustomerFeedback: async (data: CustomerFeedbackVO) => { + return await request.put({ url: `/crm/customer-feedback/update`, data }) + }, + + // 删除客户反馈 + deleteCustomerFeedback: async (id: number) => { + return await request.delete({ url: `/crm/customer-feedback/delete?id=` + id }) + }, + + // 导出客户反馈 Excel + exportCustomerFeedback: async (params) => { + return await request.download({ url: `/crm/customer-feedback/export-excel`, params }) + }, +} \ No newline at end of file diff --git a/src/api/crm/quotation/index.ts b/src/api/crm/quotation/index.ts index b197d71b9..f8becd6ee 100644 --- a/src/api/crm/quotation/index.ts +++ b/src/api/crm/quotation/index.ts @@ -100,6 +100,11 @@ export const QuotationApi = { return await request.get({ url: `/crm/quotation/get-quotation-times`, params }) }, + // 获取保险列表 + getInsuranceList: async (params: any) => { + return await request.get({ url: `/crm/service-fee-collection-method/get-insurance-list`, params }) + }, + // ==================== 子表(CRM 报价产品关联) ==================== // 获得CRM 报价产品关联列表 diff --git a/src/components/SelectCustomer/src/index.vue b/src/components/SelectCustomer/src/index.vue index 928522178..bf0312295 100644 --- a/src/components/SelectCustomer/src/index.vue +++ b/src/components/SelectCustomer/src/index.vue @@ -45,15 +45,27 @@ const allFilterEvents = ref([]) watch(() => props.modelValue, (val) => { selectValue.value = val - let arr = options.value.filter(v => v.id === val) - if (!arr.length) { - let selectItem = props.customerList.filter(v => v.id === val) - options.value = [...options.value, ...selectItem] - } + console.log('%csrc/components/SelectCustomer/src/index.vue:48 val,', 'green', val,props.customerList); + nextTick(() => { + let arr = options.value.filter(v => v.id === val) + if (!arr.length) { + let selectItem = props.customerList.filter(v => v.id === val) + options.value = [...options.value, ...selectItem] + } + }) }, { immediate: true }) watch(() => props.customerList, (val) => { options.value = val.slice(0, 10) + console.log('%csrc/components/SelectCustomer/src/index.vue:60 props.customerList,4444', 'color: pink;', props.modelValue,props.customerList,4444); + nextTick(() => { + let arr = options.value.filter(v => v.id === props.modelValue) + if (!arr.length) { + let selectItem = props.customerList.filter(v => v.id === props.modelValue) + console.log('%csrc/components/SelectCustomer/src/index.vue:65 selectItem', 'color: #007acc;', selectItem); + options.value = [...options.value, ...selectItem] + } + }) }, { deep: true }) let pageNo = ref(1) diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index 1ff9a2541..625807510 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -773,6 +773,42 @@ const remainingRouter: AppRouteRecordRaw[] = [ activeMenu: '/crm/customer-complaints' } }, + { + path: 'feedback/CustomerFeedbackForm', + component: () => import('@/views/crm/feedback/CustomerFeedbackForm.vue'), + name: 'CustomerFeedbackCreate', + meta: { + noCache: true, + hidden: true, + canTo: true, + title: '客户反馈新增', + activeMenu: '/crm/feed-back' + } + }, + { + path: 'feedback/CustomerFeedbackFormEdit', + component: () => import('@/views/crm/feedback/CustomerFeedbackForm.vue'), + name: 'CustomerFeedbackEdit', + meta: { + noCache: true, + hidden: true, + canTo: true, + title: '客户反馈编辑', + activeMenu: '/crm/feed-back' + } + }, + { + path: 'feedback/CustomerFeedbackDetail', + component: () => import('@/views/crm/feedback/CustomerFeedbackDetail.vue'), + name: 'CustomerFeedbackDetail', + meta: { + noCache: true, + hidden: true, + canTo: true, + title: '客户反馈详情', + activeMenu: '/crm/feed-back' + } + }, { path: 'filetemplate/previewDoc', component: () => import('@/views/crm/filetemplate/previewDoc.vue'), diff --git a/src/styles/index.scss b/src/styles/index.scss index 7607941c4..fa7dbda99 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -35,3 +35,7 @@ border-left-color: var(--el-color-primary); } } + +.mt-3 { + margin-bottom: 10px; +} \ No newline at end of file diff --git a/src/utils/dict.ts b/src/utils/dict.ts index 90a67f639..edbc8bd2b 100644 --- a/src/utils/dict.ts +++ b/src/utils/dict.ts @@ -220,6 +220,7 @@ export enum DICT_TYPE { SALE_STAGE='sale_stage',// 销售阶段 TIME_TYPE='time_type',// 时间类型 CRM_PARTNER_TYPE = 'crm_partner_type',//合作类型 + CRM_PARTNER_TYPE1 = 'CRM_PARTNER_TYPE1',//合作类型 CRM_SERVICE_FEE_COLLECTION_METHOD = 'crm_service_fee_collection_method',//服务费收取方式 CRM_CONTACT_ROLE_TYPE = 'crm_contact_role_type',//角色 @@ -242,6 +243,9 @@ export enum DICT_TYPE { SYNCHRONIZATION_STATUS="synchronization_status", //同步状态 MATCHING_PRODUCT_TYPES="matching_product_types", //对接产品类型 CRM_SERVICE_FEE_COLLECTION_METHOD_TYPE = 'crm_service_fee_collection_method_type', // 服务费收取方式类型 + CRM_URGENCY_LEVEL = "crm_urgency_level", // 紧急程度 + CRM_FEEDBACK_LEVEL = "crm_feedback_level", // 反馈级别 + CRM_FEEDBACK_TYPE = "crm_feedback_type", // 反馈类型 // ========== ERP - 企业资源计划模块 ========== diff --git a/src/views/crm/business/BusinessForm.vue b/src/views/crm/business/BusinessForm.vue index 0a6a3c939..1815308d3 100644 --- a/src/views/crm/business/BusinessForm.vue +++ b/src/views/crm/business/BusinessForm.vue @@ -8,11 +8,11 @@ v-loading="formLoading" > - + @@ -34,11 +34,11 @@ - + --> - + --> - - - - - - + + + 项目难度 + @@ -219,11 +212,39 @@ + + + + + + + + + + 注:行政自主在线上预定,无审批流,无差标,无客服服务 + + + + + + {{dict.label}} + + + @@ -232,6 +253,7 @@ @@ -288,12 +310,15 @@ import { defaultProps, handleTree } from '@/utils/tree'; import BusinessProductForm from './components/BusinessProductForm.vue'; import { erpPriceMultiply, erpPriceInputFormatter } from '@/utils'; import { propTypes } from '@/utils/propTypes' +import { json } from 'stream/consumers'; const { proxy }: any = getCurrentInstance(); const { t } = useI18n(); const message = useMessage(); +const checkList = ref([]) +const productsTypeList = ref([]) const dialogVisible = ref(false); const dialogTitle = ref(''); const formLoading = ref(false); @@ -305,7 +330,7 @@ const formData = ref({ followUpStatus: undefined, contactLastTime: undefined, contactNextTime: undefined, - ownerUserId: undefined, + clueDeveloper: undefined, deptId: undefined, requestorUserId: undefined, statusTypeId: undefined, @@ -327,7 +352,7 @@ const formData = ref({ const formRules = reactive({ name: [{ required: true, message: '商机名称不能为空', trigger: 'blur' }], customerId: [{ required: true, message: '客户不能为空', trigger: 'blur' }], - ownerUserId: [{ required: true, message: '负责人不能为空', trigger: 'blur' }], + clueDeveloper: [{ required: true, message: '负责人不能为空', trigger: 'blur' }], statusTypeId: [{ required: true, message: '商机状态组不能为空', trigger: 'blur' }], saleStage: [{ required: true, message: '销售阶段不能为空', trigger: 'change' }], paymentTerm: [{ required: true, message: '账期不能为空', trigger: 'change' }], @@ -391,10 +416,16 @@ const open = async (id?: number, customerId?: number) => { formLoading.value = true; try { const data = await BusinessApi.getBusiness(id); + productsTypeList.value = JSON.parse(JSON.stringify(data.products)) formData.value = { ...data, products: data.products || [] }; + let newData = [] + data.products.map(v => { + newData.push(v.category) + }) + checkList.value = [...new Set(newData)] } finally { formLoading.value = false; } @@ -408,6 +439,7 @@ const open = async (id?: number, customerId?: number) => { }; const setList = (newProducts) => { + checkList.value = [] formData.value.products = newProducts; }; @@ -456,7 +488,7 @@ const resetForm = () => { id: undefined, name: undefined, customerId: undefined, - ownerUserId: undefined, + clueDeveloper: undefined, statusTypeId: undefined, dealTime: undefined, totalPrice: 0, @@ -468,10 +500,15 @@ const resetForm = () => { formRef.value?.resetFields(); }; +const changeCheck = (val) => { + productFormRef.value.getData(val) +} + const route = useRoute(); onMounted(async () => { const customerId = route.query.customerId; - formData.value.ownerUserId = customerId ? '' : useUserStore().getUser.id; + formData.value.clueDeveloper = customerId ? '' : useUserStore().getUser.id; + formData.value.requestorUserId = customerId ? '' : useUserStore().getUser.id; formType.value = route.query.id || route.params.id; if (formType.value) open(formType.value, customerId) customerList.value = await CustomerApi.getSelfCustomerSimpleList(); @@ -485,3 +522,12 @@ onMounted(async () => { deptTree.value = handleTree(await DeptApi.getSimpleDeptList()); }); + + diff --git a/src/views/crm/business/components/BusinessProductForm.vue b/src/views/crm/business/components/BusinessProductForm.vue index ffddd6fce..69db18253 100644 --- a/src/views/crm/business/components/BusinessProductForm.vue +++ b/src/views/crm/business/components/BusinessProductForm.vue @@ -62,17 +62,11 @@ -