diff --git a/src/api/crm/backlog/index.ts b/src/api/crm/backlog/index.ts
index 614b0ef2..7ea01990 100644
--- a/src/api/crm/backlog/index.ts
+++ b/src/api/crm/backlog/index.ts
@@ -1,11 +1,6 @@
 import request from '@/config/axios'
 // TODO 芋艿:融合下
 
-// 3. 获得分配给我的客户数量
-export const getFollowCustomerCount = async () => {
-  return await request.get({ url: '/crm/customer/follow-customer-count' })
-}
-
 // 5. 获得待审核合同数量
 export const getCheckContractCount = async () => {
   return await request.get({ url: '/crm/contract/check-contract-count' })
diff --git a/src/api/crm/contact/index.ts b/src/api/crm/contact/index.ts
index e16646cc..67036194 100644
--- a/src/api/crm/contact/index.ts
+++ b/src/api/crm/contact/index.ts
@@ -37,6 +37,11 @@ export interface ContactBusinessReqVO {
   businessIds: number[]
 }
 
+export interface ContactBusiness2ReqVO {
+  businessId: number
+  contactIds: number[]
+}
+
 // 查询 CRM 联系人列表
 export const getContactPage = async (params) => {
   return await request.get({ url: `/crm/contact/page`, params })
@@ -87,11 +92,21 @@ export const createContactBusinessList = async (data: ContactBusinessReqVO) => {
   return await request.post({ url: `/crm/contact/create-business-list`, data })
 }
 
+// 批量新增联系人商机关联
+export const createContactBusinessList2 = async (data: ContactBusiness2ReqVO) => {
+  return await request.post({ url: `/crm/contact/create-business-list2`, data })
+}
+
 // 解除联系人商机关联
 export const deleteContactBusinessList = async (data: ContactBusinessReqVO) => {
   return await request.delete({ url: `/crm/contact/delete-business-list`, data })
 }
 
+// 解除联系人商机关联
+export const deleteContactBusinessList2 = async (data: ContactBusiness2ReqVO) => {
+  return await request.delete({ url: `/crm/contact/delete-business-list2`, data })
+}
+
 // 联系人转移
 export const transferContact = async (data: TransferReqVO) => {
   return await request.put({ url: '/crm/contact/transfer', data })
diff --git a/src/api/crm/contract/index.ts b/src/api/crm/contract/index.ts
index 494c60c7..bd9e93e0 100644
--- a/src/api/crm/contract/index.ts
+++ b/src/api/crm/contract/index.ts
@@ -101,3 +101,13 @@ export const submitContract = async (id: number) => {
 export const transferContract = async (data: TransferReqVO) => {
   return await request.put({ url: '/crm/contract/transfer', data })
 }
+
+// 获得待审核合同数量
+export const getAuditContractCount = async () => {
+  return await request.get({ url: '/crm/contract/audit-count' })
+}
+
+// 获得即将到期(提醒)的合同数量
+export const getRemindContractCount = async () => {
+  return await request.get({ url: '/crm/contract/remind-count' })
+}
diff --git a/src/api/crm/bi/rank.ts b/src/api/crm/statistics/rank.ts
similarity index 65%
rename from src/api/crm/bi/rank.ts
rename to src/api/crm/statistics/rank.ts
index 13ceb7ef..a9b355e0 100644
--- a/src/api/crm/bi/rank.ts
+++ b/src/api/crm/statistics/rank.ts
@@ -1,66 +1,66 @@
 import request from '@/config/axios'
 
-export interface BiRankRespVO {
+export interface StatisticsRankRespVO {
   count: number
   nickname: string
   deptName: string
 }
 
 // 排行 API
-export const RankApi = {
+export const StatisticsRankApi = {
   // 获得合同排行榜
   getContractPriceRank: (params: any) => {
     return request.get({
-      url: '/crm/bi-rank/get-contract-price-rank',
+      url: '/crm/statistics-rank/get-contract-price-rank',
       params
     })
   },
   // 获得回款排行榜
   getReceivablePriceRank: (params: any) => {
     return request.get({
-      url: '/crm/bi-rank/get-receivable-price-rank',
+      url: '/crm/statistics-rank/get-receivable-price-rank',
       params
     })
   },
   // 签约合同排行
   getContractCountRank: (params: any) => {
     return request.get({
-      url: '/crm/bi-rank/get-contract-count-rank',
+      url: '/crm/statistics-rank/get-contract-count-rank',
       params
     })
   },
   // 产品销量排行
   getProductSalesRank: (params: any) => {
     return request.get({
-      url: '/crm/bi-rank/get-product-sales-rank',
+      url: '/crm/statistics-rank/get-product-sales-rank',
       params
     })
   },
   // 新增客户数排行
   getCustomerCountRank: (params: any) => {
     return request.get({
-      url: '/crm/bi-rank/get-customer-count-rank',
+      url: '/crm/statistics-rank/get-customer-count-rank',
       params
     })
   },
   // 新增联系人数排行
   getContactsCountRank: (params: any) => {
     return request.get({
-      url: '/crm/bi-rank/get-contacts-count-rank',
+      url: '/crm/statistics-rank/get-contacts-count-rank',
       params
     })
   },
   // 跟进次数排行
   getFollowCountRank: (params: any) => {
     return request.get({
-      url: '/crm/bi-rank/get-follow-count-rank',
+      url: '/crm/statistics-rank/get-follow-count-rank',
       params
     })
   },
   // 跟进客户数排行
   getFollowCustomerCountRank: (params: any) => {
     return request.get({
-      url: '/crm/bi-rank/get-follow-customer-count-rank',
+      url: '/crm/statistics-rank/get-follow-customer-count-rank',
       params
     })
   }
diff --git a/src/views/crm/backlog/tables/CheckContract.vue b/src/views/crm/backlog/components/ContractAuditList.vue
similarity index 67%
rename from src/views/crm/backlog/tables/CheckContract.vue
rename to src/views/crm/backlog/components/ContractAuditList.vue
index ad4782e0..62a80b4d 100644
--- a/src/views/crm/backlog/tables/CheckContract.vue
+++ b/src/views/crm/backlog/components/ContractAuditList.vue
@@ -30,8 +30,14 @@
 
   <ContentWrap>
     <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" label="合同名称" prop="name" width="130" />
+      <el-table-column align="center" fixed="left" label="合同编号" prop="no" width="180" />
+      <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)">
+            {{ scope.row.name }}
+          </el-link>
+        </template>
+      </el-table-column>
       <el-table-column align="center" label="客户名称" prop="customerName" width="120">
         <template #default="scope">
           <el-link
@@ -43,8 +49,24 @@
           </el-link>
         </template>
       </el-table-column>
-      <!-- TODO @puhui999:做了商机详情后,可以把这个超链接加上 -->
-      <el-table-column align="center" label="商机名称" prop="businessName" width="130" />
+      <el-table-column align="center" label="商机名称" prop="businessName" width="130">
+        <template #default="scope">
+          <el-link
+            :underline="false"
+            type="primary"
+            @click="openBusinessDetail(scope.row.businessId)"
+          >
+            {{ scope.row.businessName }}
+          </el-link>
+        </template>
+      </el-table-column>
+      <el-table-column
+        align="center"
+        label="合同金额(元)"
+        prop="totalPrice"
+        width="140"
+        :formatter="erpPriceTableColumnFormatter"
+      />
       <el-table-column
         align="center"
         label="下单时间"
@@ -52,13 +74,6 @@
         width="120"
         :formatter="dateFormatter2"
       />
-      <el-table-column
-        align="center"
-        label="合同金额"
-        prop="price"
-        width="130"
-        :formatter="fenToYuanFormat"
-      />
       <el-table-column
         align="center"
         label="合同开始时间"
@@ -78,17 +93,24 @@
           <el-link
             :underline="false"
             type="primary"
-            @click="openContactDetail(scope.row.contactId)"
+            @click="openContactDetail(scope.row.signContactId)"
           >
-            {{ scope.row.contactName }}
+            {{ scope.row.signContactName }}
           </el-link>
         </template>
       </el-table-column>
       <el-table-column align="center" label="公司签约人" prop="signUserName" width="130" />
-      <el-table-column align="center" label="备注" prop="remark" width="130" />
+      <el-table-column align="center" label="备注" prop="remark" width="200" />
       <!-- TODO @puhui999:后续可加 【已收款金额】、【未收款金额】 -->
+      <el-table-column
+        :formatter="dateFormatter"
+        align="center"
+        label="最后跟进时间"
+        prop="contactLastTime"
+        width="180px"
+      />
       <el-table-column align="center" label="负责人" prop="ownerUserName" width="120" />
-      <el-table-column align="center" label="创建人" prop="creatorName" width="120" />
+      <el-table-column align="center" label="所属部门" prop="ownerUserDeptName" width="100px" />
       <el-table-column
         :formatter="dateFormatter"
         align="center"
@@ -103,11 +125,24 @@
         prop="createTime"
         width="180px"
       />
+      <el-table-column align="center" label="创建人" prop="creatorName" width="120" />
       <el-table-column align="center" fixed="right" label="合同状态" prop="auditStatus" width="120">
         <template #default="scope">
           <dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="scope.row.auditStatus" />
         </template>
       </el-table-column>
+      <el-table-column fixed="right" label="操作" width="90">
+        <template #default="scope">
+          <el-button
+            link
+            v-hasPermi="['crm:contract:update']"
+            type="primary"
+            @click="handleProcessDetail(scope.row)"
+          >
+            查看审批
+          </el-button>
+        </template>
+      </el-table-column>
     </el-table>
     <!-- 分页 -->
     <Pagination
@@ -122,9 +157,9 @@
 <script setup lang="ts" name="CheckContract">
 import { dateFormatter, dateFormatter2 } from '@/utils/formatTime'
 import * as ContractApi from '@/api/crm/contract'
-import { fenToYuanFormat } from '@/utils/formatter'
 import { DICT_TYPE } from '@/utils/dict'
 import { AUDIT_STATUS } from './common'
+import { erpPriceTableColumnFormatter } from '@/utils'
 
 const loading = ref(true) // 列表的加载中
 const total = ref(0) // 列表的总页数
@@ -132,7 +167,8 @@ const list = ref([]) // 列表的数据
 const queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
-  auditStatus: 20
+  sceneType: 1, // 我负责的
+  auditStatus: 10
 })
 const queryFormRef = ref() // 搜索的表单
 
@@ -154,8 +190,18 @@ const handleQuery = () => {
   getList()
 }
 
+/** 查看审批 */
+const handleProcessDetail = (row: ContractApi.ContractVO) => {
+  push({ name: 'BpmProcessInstanceDetail', query: { id: row.processInstanceId } })
+}
+
+/** 打开合同详情 */
+const { push } = useRouter()
+const openDetail = (id: number) => {
+  push({ name: 'CrmContractDetail', params: { id } })
+}
+
 /** 打开客户详情 */
-const { push } = useRouter() // 路由
 const openCustomerDetail = (id: number) => {
   push({ name: 'CrmCustomerDetail', params: { id } })
 }
@@ -165,6 +211,16 @@ const openContactDetail = (id: number) => {
   push({ name: 'CrmContactDetail', params: { id } })
 }
 
+/** 打开商机详情 */
+const openBusinessDetail = (id: number) => {
+  push({ name: 'CrmBusinessDetail', params: { id } })
+}
+
+/** 激活时 */
+onActivated(async () => {
+  await getList()
+})
+
 /** 初始化 **/
 onMounted(() => {
   getList()
diff --git a/src/views/crm/backlog/tables/EndContract.vue b/src/views/crm/backlog/components/ContractRemindList.vue
similarity index 68%
rename from src/views/crm/backlog/tables/EndContract.vue
rename to src/views/crm/backlog/components/ContractRemindList.vue
index f31bb524..2f87f44c 100644
--- a/src/views/crm/backlog/tables/EndContract.vue
+++ b/src/views/crm/backlog/components/ContractRemindList.vue
@@ -30,8 +30,14 @@
 
   <ContentWrap>
     <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" label="合同名称" prop="name" width="130" />
+      <el-table-column align="center" fixed="left" label="合同编号" prop="no" width="180" />
+      <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)">
+            {{ scope.row.name }}
+          </el-link>
+        </template>
+      </el-table-column>
       <el-table-column align="center" label="客户名称" prop="customerName" width="120">
         <template #default="scope">
           <el-link
@@ -43,8 +49,24 @@
           </el-link>
         </template>
       </el-table-column>
-      <!-- TODO @puhui999:做了商机详情后,可以把这个超链接加上 -->
-      <el-table-column align="center" label="商机名称" prop="businessName" width="130" />
+      <el-table-column align="center" label="商机名称" prop="businessName" width="130">
+        <template #default="scope">
+          <el-link
+            :underline="false"
+            type="primary"
+            @click="openBusinessDetail(scope.row.businessId)"
+          >
+            {{ scope.row.businessName }}
+          </el-link>
+        </template>
+      </el-table-column>
+      <el-table-column
+        align="center"
+        label="合同金额(元)"
+        prop="totalPrice"
+        width="140"
+        :formatter="erpPriceTableColumnFormatter"
+      />
       <el-table-column
         align="center"
         label="下单时间"
@@ -52,13 +74,6 @@
         width="120"
         :formatter="dateFormatter2"
       />
-      <el-table-column
-        align="center"
-        label="合同金额"
-        prop="price"
-        width="130"
-        :formatter="fenToYuanFormat"
-      />
       <el-table-column
         align="center"
         label="合同开始时间"
@@ -78,17 +93,24 @@
           <el-link
             :underline="false"
             type="primary"
-            @click="openContactDetail(scope.row.contactId)"
+            @click="openContactDetail(scope.row.signContactId)"
           >
-            {{ scope.row.contactName }}
+            {{ scope.row.signContactName }}
           </el-link>
         </template>
       </el-table-column>
       <el-table-column align="center" label="公司签约人" prop="signUserName" width="130" />
-      <el-table-column align="center" label="备注" prop="remark" width="130" />
+      <el-table-column align="center" label="备注" prop="remark" width="200" />
       <!-- TODO @puhui999:后续可加 【已收款金额】、【未收款金额】 -->
+      <el-table-column
+        :formatter="dateFormatter"
+        align="center"
+        label="最后跟进时间"
+        prop="contactLastTime"
+        width="180px"
+      />
       <el-table-column align="center" label="负责人" prop="ownerUserName" width="120" />
-      <el-table-column align="center" label="创建人" prop="creatorName" width="120" />
+      <el-table-column align="center" label="所属部门" prop="ownerUserDeptName" width="100px" />
       <el-table-column
         :formatter="dateFormatter"
         align="center"
@@ -103,11 +125,24 @@
         prop="createTime"
         width="180px"
       />
+      <el-table-column align="center" label="创建人" prop="creatorName" width="120" />
       <el-table-column align="center" fixed="right" label="合同状态" prop="auditStatus" width="120">
         <template #default="scope">
           <dict-tag :type="DICT_TYPE.CRM_AUDIT_STATUS" :value="scope.row.auditStatus" />
         </template>
       </el-table-column>
+      <el-table-column fixed="right" label="操作" width="90">
+        <template #default="scope">
+          <el-button
+            link
+            v-hasPermi="['crm:contract:update']"
+            type="primary"
+            @click="handleProcessDetail(scope.row)"
+          >
+            查看审批
+          </el-button>
+        </template>
+      </el-table-column>
     </el-table>
     <!-- 分页 -->
     <Pagination
@@ -125,8 +160,7 @@ import * as ContractApi from '@/api/crm/contract'
 import { fenToYuanFormat } from '@/utils/formatter'
 import { DICT_TYPE } from '@/utils/dict'
 import { CONTRACT_EXPIRY_TYPE } from './common'
-
-const { push } = useRouter() // 路由
+import { erpPriceTableColumnFormatter } from '@/utils'
 
 const loading = ref(true) // 列表的加载中
 const total = ref(0) // 列表的总页数
@@ -134,6 +168,7 @@ const list = ref([]) // 列表的数据
 const queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
+  sceneType: '1', // 自己负责的
   expiryType: 1
 })
 const queryFormRef = ref() // 搜索的表单
@@ -156,6 +191,17 @@ const handleQuery = () => {
   getList()
 }
 
+/** 查看审批 */
+const handleProcessDetail = (row: ContractApi.ContractVO) => {
+  push({ name: 'BpmProcessInstanceDetail', query: { id: row.processInstanceId } })
+}
+
+/** 打开合同详情 */
+const { push } = useRouter()
+const openDetail = (id: number) => {
+  push({ name: 'CrmContractDetail', params: { id } })
+}
+
 /** 打开客户详情 */
 const openCustomerDetail = (id: number) => {
   push({ name: 'CrmCustomerDetail', params: { id } })
@@ -166,10 +212,18 @@ const openContactDetail = (id: number) => {
   push({ name: 'CrmContactDetail', params: { id } })
 }
 
+/** 打开商机详情 */
+const openBusinessDetail = (id: number) => {
+  push({ name: 'CrmBusinessDetail', params: { id } })
+}
+
+/** 激活时 */
+onActivated(async () => {
+  await getList()
+})
+
 /** 初始化 **/
 onMounted(() => {
   getList()
 })
 </script>
-
-<style scoped></style>
diff --git a/src/views/crm/backlog/components/CustomerFollowList.vue b/src/views/crm/backlog/components/CustomerFollowList.vue
index 8e1017a3..0f367a3f 100644
--- a/src/views/crm/backlog/components/CustomerFollowList.vue
+++ b/src/views/crm/backlog/components/CustomerFollowList.vue
@@ -130,8 +130,8 @@ const list = ref([]) // 列表的数据
 const queryParams = ref({
   pageNo: 1,
   pageSize: 10,
-  followUpStatus: false,
-  sceneType: 1
+  sceneType: 1,
+  followUpStatus: false
 })
 const queryFormRef = ref() // 搜索的表单
 
@@ -158,10 +158,13 @@ const openDetail = (id: number) => {
   push({ name: 'CrmCustomerDetail', params: { id } })
 }
 
+/** 激活时 */
+onActivated(async () => {
+  await getList()
+})
+
 /** 初始化 **/
 onMounted(() => {
   getList()
 })
 </script>
-
-<style scoped></style>
diff --git a/src/views/crm/backlog/components/common.ts b/src/views/crm/backlog/components/common.ts
index d18763aa..9ff6bfc3 100644
--- a/src/views/crm/backlog/components/common.ts
+++ b/src/views/crm/backlog/components/common.ts
@@ -20,8 +20,9 @@ export const CONTACT_STATUS = [
 
 /** 审批状态 */
 export const AUDIT_STATUS = [
-  { label: '已审批', value: 20 },
-  { label: '待审批', value: 10 }
+  { label: '待审批', value: 10 },
+  { label: '审核通过', value: 20 },
+  { label: '审核不通过', value: 30 }
 ]
 
 /** 回款提醒类型 */
diff --git a/src/views/crm/backlog/index.vue b/src/views/crm/backlog/index.vue
index b1351a2d..b5c3a9a4 100644
--- a/src/views/crm/backlog/index.vue
+++ b/src/views/crm/backlog/index.vue
@@ -17,9 +17,9 @@
     <el-col :span="20" :xs="24">
       <CustomerTodayContactList v-if="leftMenu === 'customerTodayContact'" />
       <ClueFollowList v-if="leftMenu === 'clueFollow'" />
-      <CheckContract v-if="leftMenu === 'checkContract'" />
+      <ContractAuditList v-if="leftMenu === 'contractAudit'" />
       <CheckReceivables v-if="leftMenu === 'checkReceivables'" />
-      <EndContract v-if="leftMenu === 'endContract'" />
+      <ContractRemindList v-if="leftMenu === 'contractRemind'" />
       <CustomerFollowList v-if="leftMenu === 'customerFollow'" />
       <CustomerPutPoolRemindList v-if="leftMenu === 'customerPutPoolRemind'" />
       <RemindReceivables v-if="leftMenu === 'remindReceivables'" />
@@ -33,25 +33,26 @@ import CustomerFollowList from './components/CustomerFollowList.vue'
 import CustomerTodayContactList from './components/CustomerTodayContactList.vue'
 import CustomerPutPoolRemindList from './components/CustomerPutPoolRemindList.vue'
 import ClueFollowList from './components/ClueFollowList.vue'
-import CheckContract from './tables/CheckContract.vue'
-import CheckReceivables from './tables/CheckReceivables.vue'
-import EndContract from './tables/EndContract.vue'
+import ContractAuditList from './components/ContractAuditList.vue'
+import ContractRemindList from './components/ContractRemindList.vue'
 import RemindReceivables from './tables/RemindReceivables.vue'
+import CheckReceivables from './tables/CheckReceivables.vue'
 import * as CustomerApi from '@/api/crm/customer'
 import * as ClueApi from '@/api/crm/clue'
+import * as ContractApi from '@/api/crm/contract'
 
 defineOptions({ name: 'CrmBacklog' })
 
 const leftMenu = ref('customerTodayContact')
 
-const customerTodayContactCount = ref(0)
 const clueFollowCount = ref(0)
 const customerFollowCount = ref(0)
 const customerPutPoolRemindCount = ref(0)
-const checkContractCount = ref(0)
+const customerTodayContactCount = ref(0)
+const contractAuditCount = ref(0)
+const contractRemindCount = ref(0)
 const checkReceivablesCount = ref(0)
 const remindReceivablesCount = ref(0)
-const endContractCount = ref(0)
 
 const leftSides = ref([
   {
@@ -76,8 +77,8 @@ const leftSides = ref([
   },
   {
     name: '待审核合同',
-    menu: 'checkContract',
-    count: checkContractCount
+    menu: 'contractAudit',
+    count: contractAuditCount
   },
   {
     name: '待审核回款',
@@ -91,8 +92,8 @@ const leftSides = ref([
   },
   {
     name: '即将到期的合同',
-    menu: 'endContract',
-    count: endContractCount
+    menu: 'contractRemind',
+    count: contractRemindCount
   }
 ])
 
@@ -110,10 +111,10 @@ const getCount = () => {
   )
   CustomerApi.getFollowCustomerCount().then((count) => (customerFollowCount.value = count))
   ClueApi.getFollowClueCount().then((count) => (clueFollowCount.value = count))
-  BacklogApi.getCheckContractCount().then((count) => (checkContractCount.value = count))
+  ContractApi.getAuditContractCount().then((count) => (contractAuditCount.value = count))
+  ContractApi.getRemindContractCount().then((count) => (contractRemindCount.value = count))
   BacklogApi.getCheckReceivablesCount().then((count) => (checkReceivablesCount.value = count))
   BacklogApi.getRemindReceivablePlanCount().then((count) => (remindReceivablesCount.value = count))
-  BacklogApi.getEndContractCount().then((count) => (endContractCount.value = count))
 }
 
 /** 激活时 */
diff --git a/src/views/crm/contact/components/ContactList.vue b/src/views/crm/contact/components/ContactList.vue
index 7de9a3cd..83af1e52 100644
--- a/src/views/crm/contact/components/ContactList.vue
+++ b/src/views/crm/contact/components/ContactList.vue
@@ -5,11 +5,32 @@
       <Icon class="mr-5px" icon="system-uicons:contacts" />
       创建联系人
     </el-button>
+    <el-button
+      @click="openBusinessModal"
+      v-hasPermi="['crm:contact:create-business']"
+      v-if="queryParams.businessId"
+    >
+      <Icon class="mr-5px" icon="ep:circle-plus" />关联
+    </el-button>
+    <el-button
+      @click="deleteContactBusinessList"
+      v-hasPermi="['crm:contact:delete-business']"
+      v-if="queryParams.businessId"
+    >
+      <Icon class="mr-5px" icon="ep:remove" />解除关联
+    </el-button>
   </el-row>
 
   <!-- 列表 -->
   <ContentWrap class="mt-10px">
-    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+    <el-table
+      ref="contactRef"
+      v-loading="loading"
+      :data="list"
+      :stripe="true"
+      :show-overflow-tooltip="true"
+    >
+      <el-table-column type="selection" width="55" v-if="queryParams.businessId" />
       <el-table-column label="姓名" fixed="left" align="center" prop="name">
         <template #default="scope">
           <el-link type="primary" :underline="false" @click="openDetail(scope.row.id)">
@@ -37,12 +58,19 @@
 
   <!-- 表单弹窗:添加 -->
   <ContactForm ref="formRef" @success="getList" />
+  <!-- 关联商机选择弹框 -->
+  <ContactListModal
+    ref="contactModalRef"
+    :customer-id="props.customerId"
+    @success="createContactBusinessList"
+  />
 </template>
 <script setup lang="ts">
 import * as ContactApi from '@/api/crm/contact'
 import ContactForm from './../ContactForm.vue'
 import { DICT_TYPE } from '@/utils/dict'
 import { BizTypeEnum } from '@/api/crm/permission'
+import ContactListModal from './ContactListModal.vue'
 
 defineOptions({ name: 'CrmContactList' })
 const props = defineProps<{
@@ -58,8 +86,10 @@ const list = ref([]) // 列表的数据
 const queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
-  customerId: undefined as unknown // 允许 undefined + number
+  customerId: undefined as unknown, // 允许 undefined + number
+  businessId: undefined as unknown // 允许 undefined + number
 })
+const message = useMessage()
 
 /** 查询列表 */
 const getList = async () => {
@@ -106,6 +136,41 @@ const openDetail = (id: number) => {
   push({ name: 'CrmContactDetail', params: { id } })
 }
 
+/** 打开联系人与商机的关联弹窗 */
+const contactModalRef = ref()
+const openBusinessModal = () => {
+  contactModalRef.value.open()
+}
+const createContactBusinessList = async (contactIds: number[]) => {
+  const data = {
+    businessId: props.bizId,
+    contactIds: contactIds
+  } as ContactApi.ContactBusiness2ReqVO
+  contactRef.value.getSelectionRows().forEach((row: ContactApi.ContactVO) => {
+    data.businessIds.push(row.id)
+  })
+  await ContactApi.createContactBusinessList2(data)
+  // 刷新列表
+  message.success('关联联系人成功')
+  handleQuery()
+}
+
+/** 解除联系人与商机的关联 */
+const contactRef = ref()
+const deleteContactBusinessList = async () => {
+  const data = {
+    businessId: props.bizId,
+    contactIds: contactRef.value.getSelectionRows().map((row: ContactApi.ContactVO) => row.id)
+  } as ContactApi.ContactBusiness2ReqVO
+  if (data.contactIds.length === 0) {
+    return message.error('未选择联系人')
+  }
+  await ContactApi.deleteContactBusinessList2(data)
+  // 刷新列表
+  message.success('取关联系人成功')
+  handleQuery()
+}
+
 /** 监听打开的 bizId + bizType,从而加载最新的列表 */
 watch(
   () => [props.bizId, props.bizType],
diff --git a/src/views/crm/contract/index.vue b/src/views/crm/contract/index.vue
index 9064e161..ed266057 100644
--- a/src/views/crm/contract/index.vue
+++ b/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="160" />
+      <el-table-column align="center" fixed="left" label="合同编号" prop="no" width="180" />
       <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)">
diff --git a/src/views/crm/bi/rank/ContactsCountRank.vue b/src/views/crm/statistics/rank/ContactsCountRank.vue
similarity index 91%
rename from src/views/crm/bi/rank/ContactsCountRank.vue
rename to src/views/crm/statistics/rank/ContactsCountRank.vue
index 61ef91a6..199d94bd 100644
--- a/src/views/crm/bi/rank/ContactsCountRank.vue
+++ b/src/views/crm/statistics/rank/ContactsCountRank.vue
@@ -18,7 +18,7 @@
   </el-card>
 </template>
 <script setup lang="ts">
-import { RankApi, BiRankRespVO } from '@/api/crm/bi/rank'
+import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank'
 import { EChartsOption } from 'echarts'
 import { clone } from 'lodash-es'
 
@@ -26,7 +26,7 @@ defineOptions({ name: 'ContactsCountRank' })
 const props = defineProps<{ queryParams: any }>() // 搜索参数
 
 const loading = ref(false) // 加载中
-const list = ref<BiRankRespVO[]>([]) // 列表的数据
+const list = ref<StatisticsRankRespVO[]>([]) // 列表的数据
 
 /** 柱状图配置:横向 */
 const echartsOption = reactive<EChartsOption>({
@@ -80,7 +80,7 @@ const echartsOption = reactive<EChartsOption>({
 const loadData = async () => {
   // 1. 加载排行数据
   loading.value = true
-  const rankingList = await RankApi.getContactsCountRank(props.queryParams)
+  const rankingList = await StatisticsRankApi.getContactsCountRank(props.queryParams)
   // 2.1 更新 Echarts 数据
   if (echartsOption.dataset && echartsOption.dataset['source']) {
     echartsOption.dataset['source'] = clone(rankingList).reverse()
diff --git a/src/views/crm/bi/rank/ContractCountRank.vue b/src/views/crm/statistics/rank/ContractCountRank.vue
similarity index 90%
rename from src/views/crm/bi/rank/ContractCountRank.vue
rename to src/views/crm/statistics/rank/ContractCountRank.vue
index 28332653..fc50a6db 100644
--- a/src/views/crm/bi/rank/ContractCountRank.vue
+++ b/src/views/crm/statistics/rank/ContractCountRank.vue
@@ -18,7 +18,7 @@
   </el-card>
 </template>
 <script setup lang="ts">
-import { RankApi, BiRankRespVO } from '@/api/crm/bi/rank'
+import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank'
 import { EChartsOption } from 'echarts'
 import { clone } from 'lodash-es'
 
@@ -26,7 +26,7 @@ defineOptions({ name: 'ContractCountRank' })
 const props = defineProps<{ queryParams: any }>() // 搜索参数
 
 const loading = ref(false) // 加载中
-const list = ref<BiRankRespVO[]>([]) // 列表的数据
+const list = ref<StatisticsRankRespVO[]>([]) // 列表的数据
 
 /** 柱状图配置:横向 */
 const echartsOption = reactive<EChartsOption>({
@@ -80,7 +80,7 @@ const echartsOption = reactive<EChartsOption>({
 const loadData = async () => {
   // 1. 加载排行数据
   loading.value = true
-  const rankingList = await RankApi.getContractCountRank(props.queryParams)
+  const rankingList = await StatisticsRankApi.getContractCountRank(props.queryParams)
   // 2.1 更新 Echarts 数据
   if (echartsOption.dataset && echartsOption.dataset['source']) {
     echartsOption.dataset['source'] = clone(rankingList).reverse()
diff --git a/src/views/crm/bi/rank/ContractPriceRank.vue b/src/views/crm/statistics/rank/ContractPriceRank.vue
similarity index 90%
rename from src/views/crm/bi/rank/ContractPriceRank.vue
rename to src/views/crm/statistics/rank/ContractPriceRank.vue
index 067fa36c..79794c4e 100644
--- a/src/views/crm/bi/rank/ContractPriceRank.vue
+++ b/src/views/crm/statistics/rank/ContractPriceRank.vue
@@ -18,7 +18,7 @@
   </el-card>
 </template>
 <script setup lang="ts">
-import { RankApi, BiRankRespVO } from '@/api/crm/bi/rank'
+import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank'
 import { EChartsOption } from 'echarts'
 import { clone } from 'lodash-es'
 
@@ -26,7 +26,7 @@ defineOptions({ name: 'ContractPriceRank' })
 const props = defineProps<{ queryParams: any }>() // 搜索参数
 
 const loading = ref(false) // 加载中
-const list = ref<BiRankRespVO[]>([]) // 列表的数据
+const list = ref<StatisticsRankRespVO[]>([]) // 列表的数据
 
 /** 柱状图配置:横向 */
 const echartsOption = reactive<EChartsOption>({
@@ -80,7 +80,7 @@ const echartsOption = reactive<EChartsOption>({
 const loadData = async () => {
   // 1. 加载排行数据
   loading.value = true
-  const rankingList = await RankApi.getContractPriceRank(props.queryParams)
+  const rankingList = await StatisticsRankApi.getContractPriceRank(props.queryParams)
   // 2.1 更新 Echarts 数据
   if (echartsOption.dataset && echartsOption.dataset['source']) {
     echartsOption.dataset['source'] = clone(rankingList).reverse()
diff --git a/src/views/crm/bi/rank/CustomerCountRank.vue b/src/views/crm/statistics/rank/CustomerCountRank.vue
similarity index 90%
rename from src/views/crm/bi/rank/CustomerCountRank.vue
rename to src/views/crm/statistics/rank/CustomerCountRank.vue
index aeafd039..b66a6816 100644
--- a/src/views/crm/bi/rank/CustomerCountRank.vue
+++ b/src/views/crm/statistics/rank/CustomerCountRank.vue
@@ -18,7 +18,7 @@
   </el-card>
 </template>
 <script setup lang="ts">
-import { RankApi, BiRankRespVO } from '@/api/crm/bi/rank'
+import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank'
 import { EChartsOption } from 'echarts'
 import { clone } from 'lodash-es'
 
@@ -26,7 +26,7 @@ defineOptions({ name: 'CustomerCountRank' })
 const props = defineProps<{ queryParams: any }>() // 搜索参数
 
 const loading = ref(false) // 加载中
-const list = ref<BiRankRespVO[]>([]) // 列表的数据
+const list = ref<StatisticsRankRespVO[]>([]) // 列表的数据
 
 /** 柱状图配置:横向 */
 const echartsOption = reactive<EChartsOption>({
@@ -80,7 +80,7 @@ const echartsOption = reactive<EChartsOption>({
 const loadData = async () => {
   // 1. 加载排行数据
   loading.value = true
-  const rankingList = await RankApi.getCustomerCountRank(props.queryParams)
+  const rankingList = await StatisticsRankApi.getCustomerCountRank(props.queryParams)
   // 2.1 更新 Echarts 数据
   if (echartsOption.dataset && echartsOption.dataset['source']) {
     echartsOption.dataset['source'] = clone(rankingList).reverse()
diff --git a/src/views/crm/bi/rank/FollowCountRank.vue b/src/views/crm/statistics/rank/FollowCountRank.vue
similarity index 90%
rename from src/views/crm/bi/rank/FollowCountRank.vue
rename to src/views/crm/statistics/rank/FollowCountRank.vue
index e86cd7fa..43352ab0 100644
--- a/src/views/crm/bi/rank/FollowCountRank.vue
+++ b/src/views/crm/statistics/rank/FollowCountRank.vue
@@ -18,7 +18,7 @@
   </el-card>
 </template>
 <script setup lang="ts">
-import { RankApi, BiRankRespVO } from '@/api/crm/bi/rank'
+import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank'
 import { EChartsOption } from 'echarts'
 import { clone } from 'lodash-es'
 
@@ -26,7 +26,7 @@ defineOptions({ name: 'FollowCountRank' })
 const props = defineProps<{ queryParams: any }>() // 搜索参数
 
 const loading = ref(false) // 加载中
-const list = ref<BiRankRespVO[]>([]) // 列表的数据
+const list = ref<StatisticsRankRespVO[]>([]) // 列表的数据
 
 /** 柱状图配置:横向 */
 const echartsOption = reactive<EChartsOption>({
@@ -80,7 +80,7 @@ const echartsOption = reactive<EChartsOption>({
 const loadData = async () => {
   // 1. 加载排行数据
   loading.value = true
-  const rankingList = await RankApi.getFollowCountRank(props.queryParams)
+  const rankingList = await StatisticsRankApi.getFollowCountRank(props.queryParams)
   // 2.1 更新 Echarts 数据
   if (echartsOption.dataset && echartsOption.dataset['source']) {
     echartsOption.dataset['source'] = clone(rankingList).reverse()
diff --git a/src/views/crm/bi/rank/FollowCustomerCountRank.vue b/src/views/crm/statistics/rank/FollowCustomerCountRank.vue
similarity index 90%
rename from src/views/crm/bi/rank/FollowCustomerCountRank.vue
rename to src/views/crm/statistics/rank/FollowCustomerCountRank.vue
index 81d3b99d..92a22058 100644
--- a/src/views/crm/bi/rank/FollowCustomerCountRank.vue
+++ b/src/views/crm/statistics/rank/FollowCustomerCountRank.vue
@@ -18,7 +18,7 @@
   </el-card>
 </template>
 <script setup lang="ts">
-import { RankApi, BiRankRespVO } from '@/api/crm/bi/rank'
+import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank'
 import { EChartsOption } from 'echarts'
 import { clone } from 'lodash-es'
 
@@ -26,7 +26,7 @@ defineOptions({ name: 'FollowCustomerCountRank' })
 const props = defineProps<{ queryParams: any }>() // 搜索参数
 
 const loading = ref(false) // 加载中
-const list = ref<BiRankRespVO[]>([]) // 列表的数据
+const list = ref<StatisticsRankRespVO[]>([]) // 列表的数据
 
 /** 柱状图配置:横向 */
 const echartsOption = reactive<EChartsOption>({
@@ -80,7 +80,7 @@ const echartsOption = reactive<EChartsOption>({
 const loadData = async () => {
   // 1. 加载排行数据
   loading.value = true
-  const rankingList = await RankApi.getFollowCustomerCountRank(props.queryParams)
+  const rankingList = await StatisticsRankApi.getFollowCustomerCountRank(props.queryParams)
   // 2.1 更新 Echarts 数据
   if (echartsOption.dataset && echartsOption.dataset['source']) {
     echartsOption.dataset['source'] = clone(rankingList).reverse()
diff --git a/src/views/crm/bi/rank/ProductSalesRank.vue b/src/views/crm/statistics/rank/ProductSalesRank.vue
similarity index 90%
rename from src/views/crm/bi/rank/ProductSalesRank.vue
rename to src/views/crm/statistics/rank/ProductSalesRank.vue
index 3401dd91..e2a02b70 100644
--- a/src/views/crm/bi/rank/ProductSalesRank.vue
+++ b/src/views/crm/statistics/rank/ProductSalesRank.vue
@@ -18,7 +18,7 @@
   </el-card>
 </template>
 <script setup lang="ts">
-import { RankApi, BiRankRespVO } from '@/api/crm/bi/rank'
+import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank'
 import { EChartsOption } from 'echarts'
 import { clone } from 'lodash-es'
 
@@ -26,7 +26,7 @@ defineOptions({ name: 'ProductSalesRank' })
 const props = defineProps<{ queryParams: any }>() // 搜索参数
 
 const loading = ref(false) // 加载中
-const list = ref<BiRankRespVO[]>([]) // 列表的数据
+const list = ref<StatisticsRankRespVO[]>([]) // 列表的数据
 
 /** 柱状图配置:横向 */
 const echartsOption = reactive<EChartsOption>({
@@ -80,7 +80,7 @@ const echartsOption = reactive<EChartsOption>({
 const loadData = async () => {
   // 1. 加载排行数据
   loading.value = true
-  const rankingList = await RankApi.getProductSalesRank(props.queryParams)
+  const rankingList = await StatisticsRankApi.getProductSalesRank(props.queryParams)
   // 2.1 更新 Echarts 数据
   if (echartsOption.dataset && echartsOption.dataset['source']) {
     echartsOption.dataset['source'] = clone(rankingList).reverse()
diff --git a/src/views/crm/bi/rank/ReceivablePriceRank.vue b/src/views/crm/statistics/rank/ReceivablePriceRank.vue
similarity index 90%
rename from src/views/crm/bi/rank/ReceivablePriceRank.vue
rename to src/views/crm/statistics/rank/ReceivablePriceRank.vue
index b073dcda..a2f38422 100644
--- a/src/views/crm/bi/rank/ReceivablePriceRank.vue
+++ b/src/views/crm/statistics/rank/ReceivablePriceRank.vue
@@ -18,7 +18,7 @@
   </el-card>
 </template>
 <script setup lang="ts">
-import { RankApi, BiRankRespVO } from '@/api/crm/bi/rank'
+import { StatisticsRankApi, StatisticsRankRespVO } from '@/api/crm/statistics/rank'
 import { EChartsOption } from 'echarts'
 import { clone } from 'lodash-es'
 
@@ -26,7 +26,7 @@ defineOptions({ name: 'ReceivablePriceRank' })
 const props = defineProps<{ queryParams: any }>() // 搜索参数
 
 const loading = ref(false) // 加载中
-const list = ref<BiRankRespVO[]>([]) // 列表的数据
+const list = ref<StatisticsRankRespVO[]>([]) // 列表的数据
 
 /** 柱状图配置:横向 */
 const echartsOption = reactive<EChartsOption>({
@@ -81,7 +81,7 @@ const echartsOption = reactive<EChartsOption>({
 const loadData = async () => {
   // 1. 加载排行数据
   loading.value = true
-  const rankingList = await RankApi.getReceivablePriceRank(props.queryParams)
+  const rankingList = await StatisticsRankApi.getReceivablePriceRank(props.queryParams)
   // 2.1 更新 Echarts 数据
   if (echartsOption.dataset && echartsOption.dataset['source']) {
     echartsOption.dataset['source'] = clone(rankingList).reverse()
diff --git a/src/views/crm/bi/rank/index.vue b/src/views/crm/statistics/rank/index.vue
similarity index 99%
rename from src/views/crm/bi/rank/index.vue
rename to src/views/crm/statistics/rank/index.vue
index b82ff9a1..50f2f43f 100644
--- a/src/views/crm/bi/rank/index.vue
+++ b/src/views/crm/statistics/rank/index.vue
@@ -90,7 +90,7 @@ import * as DeptApi from '@/api/system/dept'
 import { beginOfDay, defaultShortcuts, endOfDay, formatDate } from '@/utils/formatTime'
 import { useUserStore } from '@/store/modules/user'
 
-defineOptions({ name: 'CrmBiRank' })
+defineOptions({ name: 'CrmStatisticsRank' })
 
 const queryParams = reactive({
   deptId: useUserStore().getUser.deptId,