📈 CRM:code review 联系人商机功能
							parent
							
								
									d6291382e8
								
							
						
					
					
						commit
						ce79dd68a3
					
				|  | @ -1,4 +1,3 @@ | |||
| import { getBusiness } from './../business/index'; | ||||
| import request from '@/config/axios' | ||||
| 
 | ||||
| export interface ContactBusinessLinkVO { | ||||
|  | @ -29,7 +28,7 @@ export const updateContactBusinessLink = async (data: ContactBusinessLinkVO) => | |||
| 
 | ||||
| // 删除联系人商机关联
 | ||||
| export const deleteContactBusinessLink = async (data: ContactBusinessLinkVO) => { | ||||
|   return await request.delete({ url: `/crm/contact-business-link/delete-batch` , data }) | ||||
|   return await request.delete({ url: `/crm/contact-business-link/delete-batch`, data }) | ||||
| } | ||||
| 
 | ||||
| // 导出联系人商机关联 Excel
 | ||||
|  | @ -43,5 +42,6 @@ export const createContactBusinessLinkBatch = async (data: ContactBusinessLinkVO | |||
| } | ||||
| // 查询联系人关联商机列表
 | ||||
| export const getBusinessByContactPage = async (params) => { | ||||
|   return await request.get({ url: `/crm/contact-business-link/page-by-contact` , params }) | ||||
| } | ||||
|   return await request.get({ url: `/crm/contact-business-link/page-by-contact`, params }) | ||||
| } | ||||
| // TODO @zyna:根据后端,调整下请求
 | ||||
|  |  | |||
|  | @ -3,9 +3,11 @@ | |||
|  * @Date: 2023-12-02 13:08:57 | ||||
|  * @LastEditTime: 2023-12-03 13:47:16 | ||||
|  * @FilePath: \yudao-ui-admin-vue3\src\views\crm\contact\detail\ContactDetailsHeader.vue | ||||
|  * @Description:  | ||||
|  * @Description: | ||||
| --> | ||||
| <!-- TODO @zyna:上面这个不加哈 --> | ||||
| <template> | ||||
|   <!-- TODO @zyna:loading 缺了 --> | ||||
|   <div v-loading="loading"> | ||||
|     <div class="flex items-start justify-between"> | ||||
|       <div> | ||||
|  |  | |||
|  | @ -65,13 +65,13 @@ | |||
|   </el-collapse> | ||||
| </template> | ||||
| <script setup lang="ts"> | ||||
| // TODO 芋艿:后面在 review 么? | ||||
| import * as ContactApi from '@/api/crm/contact' | ||||
| import { DICT_TYPE } from '@/utils/dict' | ||||
| import { formatDate } from '@/utils/formatTime' | ||||
| const { contact } = defineProps<{ contact: ContactApi.ContactVO }>() | ||||
| const { contact } = defineProps<{ | ||||
|   contact: ContactApi.ContactVO | ||||
| }>() | ||||
| 
 | ||||
| // 展示的折叠面板 | ||||
| const activeNames = ref(['basicInfo', 'systemInfo']) | ||||
| </script> | ||||
| <style scoped lang="scss"></style> | ||||
|  |  | |||
|  | @ -10,12 +10,11 @@ | |||
|         <PermissionList :biz-id="contact.id!" :biz-type="BizTypeEnum.CRM_CONTACT" /> | ||||
|       </el-tab-pane> | ||||
|       <el-tab-pane label="商机" lazy> | ||||
|         <BusinessList :biz-id="contact.id!" :biz-type="BizTypeEnum.CRM_CONTACT"/> | ||||
|         <BusinessList :biz-id="contact.id!" :biz-type="BizTypeEnum.CRM_CONTACT" /> | ||||
|       </el-tab-pane> | ||||
|     </el-tabs> | ||||
|   </el-col> | ||||
| </template> | ||||
| 
 | ||||
| <script setup lang="ts"> | ||||
| import { ElMessage } from 'element-plus' | ||||
| import { useTagsViewStore } from '@/store/modules/tagsView' | ||||
|  | @ -27,18 +26,13 @@ import PermissionList from '@/views/crm/permission/components/PermissionList.vue | |||
| import { BizTypeEnum } from '@/api/crm/permission' | ||||
| 
 | ||||
| defineOptions({ name: 'CrmContactDetail' }) | ||||
| const { delView } = useTagsViewStore() // 视图操作 | ||||
| 
 | ||||
| const route = useRoute() | ||||
| const { currentRoute } = useRouter() // 路由 | ||||
| const id = Number(route.params.id) | ||||
| const id = Number(route.params.id) // 联系人编号 | ||||
| const loading = ref(true) // 加载中 | ||||
| // 联系人详情 | ||||
| const contact = ref<ContactApi.ContactVO>({} as ContactApi.ContactVO) | ||||
| /** | ||||
|  * 获取详情 | ||||
|  * | ||||
|  * @param id | ||||
|  */ | ||||
| const contact = ref<ContactApi.ContactVO>({} as ContactApi.ContactVO) // 联系人详情 | ||||
| 
 | ||||
| /** 获取详情 */ | ||||
| const getContactData = async (id: number) => { | ||||
|   loading.value = true | ||||
|   try { | ||||
|  | @ -47,9 +41,10 @@ const getContactData = async (id: number) => { | |||
|     loading.value = false | ||||
|   } | ||||
| } | ||||
| /** | ||||
|  * 初始化 | ||||
|  */ | ||||
| 
 | ||||
| /** 初始化 */ | ||||
| const { delView } = useTagsViewStore() // 视图操作 | ||||
| const { currentRoute } = useRouter() // 路由 | ||||
| onMounted(async () => { | ||||
|   if (!id) { | ||||
|     ElMessage.warning('参数错误,联系人不能为空!') | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| <template> | ||||
|   <Dialog :title="dialogTitle" v-model="dialogVisible"> | ||||
|     <!-- 搜索工作栏 --> | ||||
|     <ContentWrap> | ||||
|       <!-- 搜索工作栏 --> | ||||
|       <el-form | ||||
|         class="-mb-15px" | ||||
|         :model="queryParams" | ||||
|  | @ -27,9 +27,17 @@ | |||
|         </el-form-item> | ||||
|       </el-form> | ||||
|     </ContentWrap> | ||||
| 
 | ||||
|     <!-- 列表 --> | ||||
|     <!-- TODO @zyna:字段按照他们对齐下 --> | ||||
|     <ContentWrap class="mt-10px"> | ||||
|       <el-table v-loading="loading" ref="businessRef" :data="list" :stripe="true" :show-overflow-tooltip="true"> | ||||
|       <el-table | ||||
|         v-loading="loading" | ||||
|         ref="businessRef" | ||||
|         :data="list" | ||||
|         :stripe="true" | ||||
|         :show-overflow-tooltip="true" | ||||
|       > | ||||
|         <el-table-column type="selection" width="55" /> | ||||
|         <el-table-column label="商机名称" fixed="left" align="center" prop="name"> | ||||
|           <template #default="scope"> | ||||
|  | @ -38,7 +46,12 @@ | |||
|             </el-link> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column label="商机金额" align="center" prop="price" :formatter="fenToYuanFormat" /> | ||||
|         <el-table-column | ||||
|           label="商机金额" | ||||
|           align="center" | ||||
|           prop="price" | ||||
|           :formatter="fenToYuanFormat" | ||||
|         /> | ||||
|         <el-table-column label="客户名称" align="center" prop="customerName" /> | ||||
|         <el-table-column label="商机组" align="center" prop="statusTypeName" /> | ||||
|         <el-table-column label="商机阶段" align="center" prop="statusName" /> | ||||
|  | @ -55,6 +68,7 @@ | |||
|       <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> | ||||
|       <el-button @click="dialogVisible = false">取 消</el-button> | ||||
|     </template> | ||||
| 
 | ||||
|     <!-- 表单弹窗:添加 --> | ||||
|     <BusinessForm ref="formRef" @success="getList" /> | ||||
|   </Dialog> | ||||
|  | @ -62,31 +76,37 @@ | |||
| <script setup lang="ts"> | ||||
| import * as BusinessApi from '@/api/crm/business' | ||||
| import BusinessForm from '../../business/BusinessForm.vue' | ||||
| import { BizTypeEnum } from '@/api/crm/permission' | ||||
| import { fenToYuanFormat } from '@/utils/formatter' | ||||
| // TODO @zyna:下面这个拼接,要注意大小写哈 | ||||
| import * as ContactbusinesslinkApi from '@/api/crm/contactbusinesslink' | ||||
| const message = useMessage() // 消息弹窗 | ||||
| 
 | ||||
| defineOptions({ name: 'CrmBusinessLinkContactList' }) | ||||
| 
 | ||||
| const dialogVisible = ref(false) // 弹窗的是否展示 | ||||
| const dialogTitle = ref('') // 弹窗的标题 | ||||
| const dialogTitle = ref('') // 弹窗的标题 TODO @zyna:是不是搞个标题? | ||||
| const loading = ref(true) // 列表的加载中 | ||||
| const total = ref(0) // 列表的总页数 | ||||
| const list = ref([]) // 列表的数据 | ||||
| const queryFormRef = ref() // 搜索的表单 | ||||
| const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 | ||||
| const contactIdProp = ref(undefined) | ||||
| const queryParams = reactive({ | ||||
|   pageNo: 1, | ||||
|   pageSize: 10, | ||||
|   name: undefined as unknown, // 允许 undefined + number | ||||
|   // TODO @zyna:是不是要根据 customerId 筛选? | ||||
|   name: undefined | ||||
| }) | ||||
| const contactIdProp = ref(0) // 联系人编号 | ||||
| 
 | ||||
| /** 打开弹窗 */ | ||||
| const open = async (contactId?: number) => { | ||||
| const open = async (contactId: number) => { | ||||
|   dialogVisible.value = true | ||||
|   contactIdProp.value = contactId | ||||
|   // TODO @zyna:下面要 await 下;一般 idea 如果有黄色警告,最好都看看哈 | ||||
|   getList() | ||||
| } | ||||
| defineExpose({ open }) // 提供 open 方法,用于打开弹窗 | ||||
| 
 | ||||
| /** 查询列表 */ | ||||
| const getList = async () => { | ||||
|   loading.value = true | ||||
|  | @ -104,32 +124,38 @@ const handleQuery = () => { | |||
|   queryParams.pageNo = 1 | ||||
|   getList() | ||||
| } | ||||
| 
 | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value.resetFields() | ||||
|   handleQuery() | ||||
| } | ||||
| 
 | ||||
| /** 添加操作 */ | ||||
| const formRef = ref() | ||||
| const openForm = () => { | ||||
|   formRef.value.open('create') | ||||
| } | ||||
| /**关联商机提交 */ | ||||
| 
 | ||||
| /** 关联商机提交 */ | ||||
| const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 | ||||
| const businessRef = ref() | ||||
| const submitForm = async () =>{ | ||||
|   if(businessRef.value.getSelectionRows().length === 0){ | ||||
| const submitForm = async () => { | ||||
|   // TODO @zyna:可以 if return,这样括号层级简单一点 | ||||
|   if (businessRef.value.getSelectionRows().length === 0) { | ||||
|     message.success('未选择商机') | ||||
|   }else{ | ||||
|   } else { | ||||
|     // TODO @zyna:这里 postData 应该不用 ref,搞个 数组就好了? | ||||
|     const postData = ref<ContactbusinesslinkApi.ContactBusinessLinkVO[]>([]) | ||||
|     businessRef.value.getSelectionRows().forEach(element => { | ||||
|     businessRef.value.getSelectionRows().forEach((element) => { | ||||
|       // TODO @zyna:可以直接 push,不用声明 data | ||||
|       let data = { | ||||
|         id:undefined, | ||||
|         businessId : element.id, | ||||
|         contactId : contactIdProp.value | ||||
|         id: undefined, | ||||
|         businessId: element.id, | ||||
|         contactId: contactIdProp.value | ||||
|       } | ||||
|       postData.value.push(data) | ||||
|     }); | ||||
|     }) | ||||
|     await ContactbusinesslinkApi.createContactBusinessLinkBatch(postData.value) | ||||
|     dialogVisible.value = false | ||||
|     emit('success') | ||||
|  |  | |||
|  | @ -5,17 +5,19 @@ | |||
|       <Icon class="mr-5px" icon="ep:opportunity" /> | ||||
|       创建商机 | ||||
|     </el-button> | ||||
|     <el-button @click="openBusinessLink"> | ||||
|       关联 | ||||
|     </el-button> | ||||
|     <el-button @click="deleteBusinessLink"> | ||||
|       解除关联 | ||||
|     </el-button> | ||||
|     <el-button @click="openBusinessLink"> 关联 </el-button> | ||||
|     <el-button @click="deleteBusinessLink"> 解除关联 </el-button> | ||||
|   </el-row> | ||||
| 
 | ||||
|   <!-- 列表 --> | ||||
|   <ContentWrap class="mt-10px"> | ||||
|     <el-table v-loading="loading" ref="businessRef" :data="list" :stripe="true" :show-overflow-tooltip="true"> | ||||
|     <el-table | ||||
|       v-loading="loading" | ||||
|       ref="businessRef" | ||||
|       :data="list" | ||||
|       :stripe="true" | ||||
|       :show-overflow-tooltip="true" | ||||
|     > | ||||
|       <el-table-column type="selection" width="55" /> | ||||
|       <el-table-column label="商机名称" fixed="left" align="center" prop="name"> | ||||
|         <template #default="scope"> | ||||
|  | @ -39,9 +41,9 @@ | |||
|   </ContentWrap> | ||||
| 
 | ||||
|   <!-- 表单弹窗:添加 --> | ||||
|   <BusinessForm ref="formRef" @success="getList"/> | ||||
|   <BusinessForm ref="formRef" @success="getList" /> | ||||
|   <!----> | ||||
|   <BusinessLink ref="businessLinkRef" @success="getList"/> | ||||
|   <BusinessLink ref="businessLinkRef" @success="getList" /> | ||||
| </template> | ||||
| <script setup lang="ts"> | ||||
| import * as ContactBusinessLinkApi from '@/api/crm/contactbusinesslink' | ||||
|  | @ -50,6 +52,7 @@ import { BizTypeEnum } from '@/api/crm/permission' | |||
| import { fenToYuanFormat } from '@/utils/formatter' | ||||
| import BusinessLink from './BusinessLinkContactList.vue' | ||||
| const message = useMessage() // 消息弹窗 | ||||
| // TODO @zyna:这个组件,可以服用 BusinessList,然后根据传入的编号类型,做一些判断? | ||||
| defineOptions({ name: 'CrmBusinessContactList' }) | ||||
| const props = defineProps<{ | ||||
|   bizType: number // 业务类型 | ||||
|  | @ -107,18 +110,18 @@ const openBusinessLink = () => { | |||
| /**解除关联 */ | ||||
| const businessRef = ref() | ||||
| const deleteBusinessLink = async () => { | ||||
|   if(businessRef.value.getSelectionRows().length === 0){ | ||||
|   if (businessRef.value.getSelectionRows().length === 0) { | ||||
|     message.success('未选择商机') | ||||
|   }else{ | ||||
|   } else { | ||||
|     const postData = ref<ContactBusinessLinkApi.ContactBusinessLinkVO[]>([]) | ||||
|     businessRef.value.getSelectionRows().forEach(element => { | ||||
|     businessRef.value.getSelectionRows().forEach((element) => { | ||||
|       let data = { | ||||
|         id:undefined, | ||||
|         businessId : element.id, | ||||
|         contactId : props.bizId | ||||
|         id: undefined, | ||||
|         businessId: element.id, | ||||
|         contactId: props.bizId | ||||
|       } | ||||
|       postData.value.push(data) | ||||
|     }); | ||||
|     }) | ||||
|     await ContactBusinessLinkApi.deleteContactBusinessLink(postData.value) | ||||
|     handleQuery() | ||||
|   } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 YunaiV
						YunaiV