Przeglądaj źródła

✨ CRM:完善 CRM 相关实现

YunaiV 1 rok temu
rodzic
commit
56db6bf307

+ 0 - 12
src/router/modules/remaining.ts

@@ -539,18 +539,6 @@ const remainingRouter: AppRouteRecordRaw[] = [
         },
         component: () => import('@/views/crm/contract/detail/index.vue')
       },
-      {
-        path: 'contract/detail',
-        name: 'CrmContractDetail2', // 特殊:用于适配 BPM 打开详情
-        meta: {
-          title: '合同详情XXX',
-          noCache: true,
-          hidden: true,
-          canTo: true,
-          activeMenu: '/crm/contract'
-        },
-        component: () => import('@/views/crm/contract/detail/index.vue')
-      },
       {
         path: 'contact/detail/:id',
         name: 'CrmContactDetail',

+ 1 - 0
src/views/bpm/processInstance/detail/index.vue

@@ -234,6 +234,7 @@ const getProcessInstance = async () => {
         fApi.value?.fapi?.disabled(true)
       })
     } else {
+      // 注意:data.processDefinition.formCustomViewPath 是组件的全路径,例如说:/crm/contract/detail/index.vue
       BusinessFormComponent.value = registerComponent(data.processDefinition.formCustomViewPath)
     }
 

+ 21 - 13
src/views/crm/backlog/components/CustomerPutPoolRemindList.vue

@@ -29,32 +29,31 @@
   </ContentWrap>
   <ContentWrap>
     <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
-      <el-table-column align="center" label="编号" prop="id" />
-      <el-table-column align="center" label="客户名称" prop="name" width="160">
+      <el-table-column align="center" label="客户名称" fixed="left" prop="name" width="160">
         <template #default="scope">
           <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">
             {{ scope.row.name }}
           </el-link>
         </template>
       </el-table-column>
-      <el-table-column align="center" label="手机" prop="mobile" width="120" />
-      <el-table-column align="center" label="电话" prop="telephone" width="120" />
       <el-table-column align="center" label="客户来源" prop="source" width="100">
         <template #default="scope">
           <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" />
         </template>
       </el-table-column>
-      <el-table-column align="center" label="所属行业" prop="industryId" width="120">
+      <el-table-column label="手机" align="center" prop="mobile" width="120" />
+      <el-table-column label="电话" align="center" prop="telephone" width="130" />
+      <el-table-column label="邮箱" align="center" prop="email" width="180" />
+      <el-table-column align="center" label="客户级别" prop="level" width="135">
         <template #default="scope">
-          <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" />
+          <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" />
         </template>
       </el-table-column>
-      <el-table-column align="center" label="客户级别" prop="level" width="120">
+      <el-table-column align="center" label="客户行业" prop="industryId" width="100">
         <template #default="scope">
-          <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" />
+          <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" />
         </template>
       </el-table-column>
-      <el-table-column align="center" label="网址" prop="website" width="200" />
       <el-table-column
         :formatter="dateFormatter"
         align="center"
@@ -63,12 +62,16 @@
         width="180px"
       />
       <el-table-column align="center" label="备注" prop="remark" width="200" />
+      <el-table-column align="center" label="锁定状态" prop="lockStatus">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.lockStatus" />
+        </template>
+      </el-table-column>
       <el-table-column align="center" label="成交状态" prop="dealStatus">
         <template #default="scope">
           <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealStatus" />
         </template>
       </el-table-column>
-      <el-table-column align="center" label="距进入公海天数" prop="poolDay" width="100px" />
       <el-table-column
         :formatter="dateFormatter"
         align="center"
@@ -76,10 +79,17 @@
         prop="contactLastTime"
         width="180px"
       />
+      <el-table-column align="center" label="最后跟进记录" prop="contactLastContent" width="200" />
+      <el-table-column label="地址" align="center" prop="detailAddress" width="180" />
+      <el-table-column align="center" label="距离进入公海天数" prop="poolDay" width="140">
+        <template #default="scope"> {{ scope.row.poolDay }} 天</template>
+      </el-table-column>
+      <el-table-column align="center" label="负责人" prop="ownerUserName" width="100px" />
+      <el-table-column align="center" label="所属部门" prop="ownerUserDeptName" width="100px" />
       <el-table-column
         :formatter="dateFormatter"
         align="center"
-        label="创建时间"
+        label="更新时间"
         prop="updateTime"
         width="180px"
       />
@@ -90,8 +100,6 @@
         prop="createTime"
         width="180px"
       />
-      <el-table-column align="center" label="负责人" prop="ownerUserName" width="100px" />
-      <el-table-column align="center" label="所属部门" prop="ownerUserDeptName" width="100px" />
       <el-table-column align="center" label="创建人" prop="creatorName" width="100px" />
     </el-table>
     <!-- 分页 -->

+ 7 - 6
src/views/crm/business/detail/index.vue

@@ -31,10 +31,11 @@
           :customer-id="business.customerId"
         />
       </el-tab-pane>
-      <!-- TODO 合同 -->
       <el-tab-pane label="产品">
         <BusinessProductList :business="business" />
       </el-tab-pane>
+      <!-- TODO 合同 -->
+      <el-tab-pane label="合同"> 123 </el-tab-pane>
       <el-tab-pane label="操作日志">
         <OperateLogV2 :log-list="logList" />
       </el-tab-pane>
@@ -51,8 +52,8 @@
   </el-col>
 
   <!-- 表单弹窗:添加/修改 -->
-  <ContactForm ref="formRef" @success="getContact(business.id)" />
-  <BusinessUpdateStatusForm ref="statusFormRef" @success="getContact(business.id)" />
+  <BusinessForm ref="formRef" @success="getBusiness(business.id)" />
+  <BusinessUpdateStatusForm ref="statusFormRef" @success="getBusiness(business.id)" />
   <CrmTransferForm ref="transferFormRef" @success="close" />
 </template>
 <script lang="ts" setup>
@@ -65,7 +66,7 @@ import PermissionList from '@/views/crm/permission/components/PermissionList.vue
 import { BizTypeEnum } from '@/api/crm/permission'
 import { OperateLogV2VO } from '@/api/system/operatelog'
 import { getOperateLogPage } from '@/api/crm/operateLog'
-import ContactForm from '@/views/crm/contact/ContactForm.vue'
+import BusinessForm from '@/views/crm/business/BusinessForm.vue'
 import CrmTransferForm from '@/views/crm/permission/components/TransferForm.vue'
 import FollowUpList from '@/views/crm/followup/index.vue'
 import ContactList from '@/views/crm/contact/components/ContactList.vue'
@@ -81,7 +82,7 @@ const business = ref<ContactApi.ContactVO>({} as ContactApi.ContactVO) // 联系
 const permissionListRef = ref<InstanceType<typeof PermissionList>>() // 团队成员列表 Ref
 
 /** 获取详情 */
-const getContact = async (id: number) => {
+const getBusiness = async (id: number) => {
   loading.value = true
   try {
     business.value = await BusinessApi.getBusiness(id)
@@ -138,6 +139,6 @@ onMounted(async () => {
     return
   }
   businessId.value = params.id as unknown as number
-  await getContact(businessId.value)
+  await getBusiness(businessId.value)
 })
 </script>

+ 2 - 0
src/views/crm/contract/detail/index.vue

@@ -19,6 +19,8 @@
       <el-tab-pane label="产品">
         <ContractProductList :contract="contract" />
       </el-tab-pane>
+      <!-- TODO 合同 -->
+      <el-tab-pane label="回款"> 123 </el-tab-pane>
       <!-- TODO @puhui999:回款信息 -->
       <el-tab-pane label="团队成员">
         <PermissionList

+ 1 - 1
src/views/crm/contract/index.vue

@@ -79,7 +79,7 @@
       <el-tab-pane label="下属负责的" name="3" />
     </el-tabs>
     <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
-      <el-table-column align="center" fixed="left" label="合同编号" prop="no" width="130" />
+      <el-table-column align="center" fixed="left" label="合同编号" prop="no" width="160" />
       <el-table-column align="center" fixed="left" label="合同名称" prop="name" width="160">
         <template #default="scope">
           <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">

+ 0 - 221
src/views/crm/contract/oa/ContractDetail/index.vue

@@ -1,221 +0,0 @@
-<!-- TODO @puhui999:这个好像和 detail 重复了???能不能复用 detail 哈? -->
-<template>
-  <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="110px">
-    <el-row>
-      <el-col :span="24" class="mb-10px">
-        <CardTitle title="基本信息" />
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="合同名称" prop="name">
-          <el-input v-model="formData.name" placeholder="请输入合同名称" />
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="合同编号" prop="no">
-          <el-input v-model="formData.no" placeholder="请输入合同编号" />
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="客户" prop="customerId">
-          <el-select v-model="formData.customerId">
-            <el-option
-              v-for="item in customerList"
-              :key="item.id"
-              :label="item.name"
-              :value="item.id!"
-            />
-          </el-select>
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="客户签约人" prop="contactId">
-          <el-select v-model="formData.contactId" :disabled="!formData.customerId">
-            <el-option
-              v-for="item in getContactOptions"
-              :key="item.id"
-              :label="item.name"
-              :value="item.id!"
-            />
-          </el-select>
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="公司签约人" prop="signUserId">
-          <el-select v-model="formData.signUserId">
-            <el-option
-              v-for="item in userList"
-              :key="item.id"
-              :label="item.nickname"
-              :value="item.id!"
-            />
-          </el-select>
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="负责人" prop="ownerUserId">
-          <el-select v-model="formData.ownerUserId">
-            <el-option
-              v-for="item in userList"
-              :key="item.id"
-              :label="item.nickname"
-              :value="item.id!"
-            />
-          </el-select>
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="商机名称" prop="businessId">
-          <el-select v-model="formData.businessId">
-            <el-option
-              v-for="item in businessList"
-              :key="item.id"
-              :label="item.name"
-              :value="item.id!"
-            />
-          </el-select>
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="合同金额(元)" prop="price">
-          <el-input v-model="formData.price" placeholder="请输入合同金额" />
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="下单日期" prop="orderDate">
-          <el-date-picker
-            v-model="formData.orderDate"
-            placeholder="选择下单日期"
-            type="date"
-            value-format="x"
-          />
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="开始时间" prop="startTime">
-          <el-date-picker
-            v-model="formData.startTime"
-            placeholder="选择开始时间"
-            type="date"
-            value-format="x"
-          />
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="结束时间" prop="endTime">
-          <el-date-picker
-            v-model="formData.endTime"
-            placeholder="选择结束时间"
-            type="date"
-            value-format="x"
-          />
-        </el-form-item>
-      </el-col>
-      <el-col :span="24">
-        <el-form-item label="备注" prop="remark">
-          <el-input v-model="formData.remark" :rows="3" placeholder="请输入备注" type="textarea" />
-        </el-form-item>
-      </el-col>
-      <el-col :span="24">
-        <el-form-item label="产品列表" prop="productList">
-          <ProductList v-model="formData.productItems" />
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="整单折扣(%)" prop="discountPercent">
-          <el-input v-model="formData.discountPercent" placeholder="请输入整单折扣" />
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item label="产品总金额(元)" prop="productPrice">
-          <el-input v-model="formData.productPrice" placeholder="请输入产品总金额" />
-        </el-form-item>
-      </el-col>
-      <el-col :span="24">
-        <CardTitle class="mb-10px" title="审批信息" />
-      </el-col>
-      <el-col :span="12">
-        <el-button
-          class="m-20px"
-          link
-          type="primary"
-          @click="BPMLModelRef?.handleBpmnDetail('contract-approve')"
-        >
-          查看工作流
-        </el-button>
-      </el-col>
-    </el-row>
-  </el-form>
-  <BPMLModel ref="BPMLModelRef" />
-</template>
-<script lang="ts" setup>
-import * as CustomerApi from '@/api/crm/customer'
-import * as ContractApi from '@/api/crm/contract'
-import * as UserApi from '@/api/system/user'
-import * as ContactApi from '@/api/crm/contact'
-import * as BusinessApi from '@/api/crm/business'
-import ProductList from '@/views/crm/contract/components/ProductList.vue'
-// import BPMLModel from '@/views/crm/contract/components/BPMLModel.vue'
-
-defineOptions({ name: 'ContractDetailOA' })
-const props = defineProps<{ id?: number }>()
-const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
-const formData = ref<ContractApi.ContractVO>({} as ContractApi.ContractVO)
-const formRef = ref() // 表单 Ref
-const BPMLModelRef = ref<InstanceType<typeof BPMLModel>>()
-watch(
-  () => formData.value.productItems,
-  (val) => {
-    if (!val || val.length === 0) {
-      formData.value.productPrice = 0
-      return
-    }
-    // 使用reduce函数进行累加
-    formData.value.productPrice = val.reduce(
-      (accumulator, currentValue) =>
-        isNaN(accumulator + currentValue.totalPrice) ? 0 : accumulator + currentValue.totalPrice,
-      0
-    )
-  },
-  { deep: true }
-)
-/** 打开弹窗 */
-const getFormData = async () => {
-  await getAllApi()
-  formLoading.value = true
-  try {
-    formData.value = await ContractApi.getContract(props.id!)
-  } finally {
-    formLoading.value = false
-  }
-}
-const getAllApi = async () => {
-  await Promise.all([getCustomerList(), getUserList(), getContactListList(), getBusinessList()])
-}
-const customerList = ref<CustomerApi.CustomerVO[]>([])
-/** 获取客户 */
-const getCustomerList = async () => {
-  customerList.value = await CustomerApi.getCustomerSimpleList()
-}
-const contactList = ref<ContactApi.ContactVO[]>([])
-/** 动态获取客户联系人 */
-const getContactOptions = computed(() =>
-  contactList.value.filter((item) => item.customerId === formData.value.customerId)
-)
-const getContactListList = async () => {
-  contactList.value = await ContactApi.getSimpleContactList()
-}
-const userList = ref<UserApi.UserVO[]>([])
-/** 获取用户列表 */
-const getUserList = async () => {
-  userList.value = await UserApi.getSimpleUserList()
-}
-const businessList = ref<BusinessApi.BusinessVO[]>([])
-/** 获取商机 */
-const getBusinessList = async () => {
-  businessList.value = await BusinessApi.getSimpleBusinessList()
-}
-
-onMounted(() => {
-  getFormData()
-})
-</script>

+ 3 - 1
src/views/crm/customer/detail/index.vue

@@ -103,7 +103,7 @@ const customerId = ref(0) // 客户编号
 const loading = ref(true) // 加载中
 const message = useMessage() // 消息弹窗
 const { delView } = useTagsViewStore() // 视图操作
-const { currentRoute } = useRouter() // 路由
+const { push, currentRoute } = useRouter() // 路由
 
 const permissionListRef = ref<InstanceType<typeof PermissionList>>() // 团队成员列表 Ref
 
@@ -180,6 +180,7 @@ const handlePutPool = async () => {
   await message.confirm(`确定将客户【${customer.value.name}】放入公海吗?`)
   await CustomerApi.putCustomerPool(unref(customerId.value))
   message.success(`客户【${customer.value.name}】放入公海成功`)
+  // 加载
   close()
 }
 
@@ -198,6 +199,7 @@ const getOperateLog = async () => {
 
 const close = () => {
   delView(unref(currentRoute))
+  push({ name: 'CrmCustomer' })
 }
 
 /** 初始化 */

+ 12 - 85
src/views/crm/customer/limitConfig/CustomerLimitConfigForm.vue

@@ -8,16 +8,14 @@
       v-loading="formLoading"
     >
       <el-form-item label="规则适用人群" prop="userIds">
-        <el-tree-select
-          v-model="formData.userIds"
-          :data="userTree"
-          :props="defaultProps"
-          multiple
-          filterable
-          check-on-click-node
-          node-key="id"
-          placeholder="请选择规则适用人群"
-        />
+        <el-select multiple filterable v-model="formData.userIds">
+          <el-option
+            v-for="item in userOptions"
+            :key="item.id"
+            :label="item.nickname"
+            :value="item.id"
+          />
+        </el-select>
       </el-form-item>
       <el-form-item label="规则适用部门" prop="deptIds">
         <el-tree-select
@@ -62,6 +60,7 @@ import { defaultProps, handleTree } from '@/utils/tree'
 import * as UserApi from '@/api/system/user'
 import { cloneDeep } from 'lodash-es'
 import { LimitConfType } from '@/api/crm/customer/limitConfig'
+import { aw } from '../../../../../dist-prod/assets/index-9eac537b'
 
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
@@ -85,7 +84,7 @@ const formRules = reactive({
 const formRef = ref() // 表单 Ref
 // TODO @芋艿:看看怎么搞个部门选择组件
 const deptTree = ref() // 部门树形结构
-const userTree = ref() // 用户树形结构
+const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
 
 /** 打开弹窗 */
 const open = async (type: string, limitConfType: LimitConfType, id?: number) => {
@@ -105,9 +104,9 @@ const open = async (type: string, limitConfType: LimitConfType, id?: number) =>
     formData.value.type = limitConfType
   }
   // 获得部门树
-  await getDeptTree()
+  deptTree.value = handleTree(await DeptApi.getSimpleDeptList())
   // 获得用户
-  await getUserTree()
+  userOptions.value = await UserApi.getSimpleUserList()
 }
 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
 
@@ -149,76 +148,4 @@ const resetForm = () => {
   }
   formRef.value?.resetFields()
 }
-
-/**
- * 获取部门树
- */
-const getDeptTree = async () => {
-  const res = await DeptApi.getSimpleDeptList()
-  deptTree.value = []
-  deptTree.value.push(...handleTree(res))
-}
-
-/**
- * 获取用户树
- */
-const getUserTree = async () => {
-  const res = await UserApi.getAllUser()
-  userTree.value = []
-  userTree.value = cloneDeep(unref(deptTree))
-
-  const deptUserMap = {}
-  res.forEach((user) => {
-    if (user.dept) {
-      if (!deptUserMap[user.deptId]) {
-        deptUserMap[user.deptId] = []
-      }
-      deptUserMap[user.deptId].push(user)
-    }
-  })
-
-  handleUserData(userTree.value, deptUserMap)
-}
-
-// TODO @芋艿:看看怎么搞个用户选择的组件
-/**
- * 处理用户树
- *
- * @param deptTree
- * @param deptUserMap
- */
-const handleUserData = (deptTree, deptUserMap) => {
-  for (let i = 0; i < deptTree.length; i++) {
-    // 如果是用户,就不用继续找部门下的用户
-    if (deptTree[i].isUser) {
-      continue
-    }
-    const users = deptUserMap[deptTree[i].id]
-    if (users) {
-      if (!deptTree[i].children) {
-        deptTree[i].children = []
-      }
-      deptTree[i].children.push(
-        ...users.map((user) => {
-          return {
-            id: user.id,
-            name: user.username + '-' + user.nickname,
-            isUser: true,
-            // 用户状态为关闭
-            disabled: user.status === 1
-          }
-        })
-      )
-    }
-
-    if (deptTree[i].children && deptTree[i].children.length !== 0) {
-      handleUserData(deptTree[i].children, deptUserMap)
-    }
-
-    // 非人员选项禁用
-    deptTree[i].disabled = true
-    // 将非人员的 id 置为空
-    deptTree[i].id = 'null'
-  }
-}
 </script>

+ 1 - 1
src/views/crm/customer/limitConfig/CustomerLimitConfigList.vue

@@ -16,7 +16,6 @@
     class="mt-4"
   >
     <el-table-column label="编号" align="center" prop="id" />
-    <el-table-column label="规则类型" align="center" prop="type" />
     <el-table-column
       label="规则适用人群"
       align="center"
@@ -39,6 +38,7 @@
       label="成交客户是否占用拥有客户数"
       align="center"
       prop="dealCountEnabled"
+      min-width="100"
     >
       <template #default="scope">
         <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.dealCountEnabled" />