浏览代码

crm:完善数据权限的界面

YunaiV 1 年之前
父节点
当前提交
5f26c4afe9

+ 2 - 3
src/api/crm/contact/index.ts

@@ -61,8 +61,7 @@ export const exportContact = async (params) => {
   return await request.download({ url: `/crm/contact/export-excel`, params })
 }
 
-export const simpleAllList = async () => {
+// 获得 CRM 联系人列表(精简)
+export const getSimpleContactList = async () => {
   return await request.get({ url: `/crm/contact/simple-all-list` })
 }
-
-//

+ 23 - 7
src/api/crm/permission/index.ts

@@ -12,6 +12,11 @@ export interface PermissionVO {
   createTime?: Date
 }
 
+/**
+ * CRM 业务类型枚举
+ *
+ * @author HUIHUI
+ */
 export enum BizTypeEnum {
   CRM_LEADS = 1, // 线索
   CRM_CUSTOMER = 2, // 客户
@@ -20,36 +25,47 @@ export enum BizTypeEnum {
   CRM_CONTRACT = 6 // 合同
 }
 
-// 查询团队成员列表
+/**
+ * CRM 数据权限级别枚举
+ */
+export enum PermissionLevelEnum {
+  OWNER = 1, // 负责人
+  READ = 2, // 只读
+  WRITE = 3 // 读写
+}
+
+// 获得数据权限列表(查询团队成员列表)
 export const getPermissionList = async (params) => {
   return await request.get({ url: `/crm/permission/list`, params })
 }
 
-// 新增团队成员
+// 创建数据权限(新增团队成员
 export const createPermission = async (data: PermissionVO) => {
   return await request.post({ url: `/crm/permission/create`, data })
 }
 
-// 修改团队成员权限级别
+// 编辑数据权限(修改团队成员权限级别
 export const updatePermission = async (data) => {
   return await request.put({ url: `/crm/permission/update`, data })
 }
 
-// 删除团队成员
-export const deletePermission = async (params) => {
+// 删除数据权限(删除团队成员
+export const deletePermissionBatch = async (params) => {
   return await request.delete({ url: '/crm/permission/delete', params })
 }
 
-// 退出团队
-export const quitTeam = async (id) => {
+// 删除自己的数据权限(退出团队
+export const deleteSelfPermission = async (id) => {
   return await request.delete({ url: '/crm/permission/quit-team?id=' + id })
 }
 
+// TODO @puhui999:调整下位置
 // 领取公海数据
 export const receive = async (data: { bizType: number; bizId: number }) => {
   return await request.put({ url: `/crm/permission/receive`, data })
 }
 
+// TODO @puhui999:调整下位置
 // 数据放入公海
 export const putPool = async (data: { bizType: number; bizId: number }) => {
   return await request.put({ url: `/crm/permission/put-pool`, data })

+ 2 - 2
src/utils/dict.ts

@@ -198,6 +198,6 @@ export enum DICT_TYPE {
   CRM_PRODUCT_STATUS = 'crm_product_status',
 
   // ========== CRM - 数据权限模块 ==========
-  CRM_BIZ_TYPE = 'crm_biz_type', // 数据模块类型
-  CRM_PERMISSION_LEVEL = 'crm_permission_level' // 用户数据权限类型
+  CRM_BIZ_TYPE = 'crm_biz_type', // CRM 业务类型
+  CRM_PERMISSION_LEVEL = 'crm_permission_level' // CRM 数据权限的级别
 }

+ 0 - 16
src/views/crm/components/index.ts

@@ -1,16 +0,0 @@
-import CrmPermissionList from './CrmPermissionList.vue'
-
-// TODO @puhui999:迁移到 api/permission/index.ts 里;我已经迁移了一部分哈
-enum CrmBizTypeEnum {
-  CRM_LEADS = 1, // 线索
-  CRM_CUSTOMER = 2, // 客户
-  CRM_CONTACTS = 3, // 联系人
-  CRM_BUSINESS = 5, // 商机
-  CRM_CONTRACT = 6 // 合同
-}
-
-enum CrmPermissionLevelEnum {
-  OWNER = 1 // 负责人
-}
-
-export { CrmPermissionList, CrmBizTypeEnum, CrmPermissionLevelEnum }

+ 1 - 1
src/views/crm/contact/ContactForm.vue

@@ -235,7 +235,7 @@ const open = async (type: string, id?: number) => {
   dialogTitle.value = t('action.' + type)
   formType.value = type
   resetForm()
-  allContactList.value = await ContactApi.simpleAllList()
+  allContactList.value = await ContactApi.getSimpleContactList()
   userList.value = await UserApi.getSimpleUserList()
   customerList.value = await CustomerApi.queryAllList()
   areaList.value = await AreaApi.getAreaTree()

+ 3 - 2
src/views/crm/contact/components/ContactList.vue

@@ -1,14 +1,14 @@
 <template>
   <!-- 操作栏 -->
   <el-row justify="end">
-    <el-button class="mb-10px">
+    <el-button>
       <Icon class="mr-5px" icon="system-uicons:contacts" />
       创建联系人
     </el-button>
   </el-row>
 
   <!-- 列表 -->
-  <ContentWrap>
+  <ContentWrap class="mt-10px">
     <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
       <el-table-column label="姓名" fixed="left" align="center" prop="name">
         <template #default="scope">
@@ -136,6 +136,7 @@ const openDetail = (id: number) => {
   push({ name: 'CrmContactDetail', params: { id } })
 }
 
+/** 监听打开的 bizId + bizType,从而加载最新的列表 */
 watch(
   () => [props.bizId, props.bizType],
   () => {

+ 2 - 2
src/views/crm/contact/detail/index.vue

@@ -90,10 +90,10 @@ import ContactBasicInfo from '@/views/crm/contact/detail/ContactBasicInfo.vue'
 import ContactDetails from '@/views/crm/contact/detail/ContactDetails.vue'
 import ContactForm from '@/views/crm/contact/ContactForm.vue'
 import { formatDate } from '@/utils/formatTime'
-import * as CustomerApi from '@/api/crm/customer'
 // TODO 芋艿:后面在 review 么?
 
-defineOptions({ name: 'ContactDetail' })
+defineOptions({ name: 'CrmContactDetail' })
+
 const { delView } = useTagsViewStore() // 视图操作
 const route = useRoute()
 const { currentRoute } = useRouter() // 路由

+ 115 - 35
src/views/crm/contact/index.vue

@@ -1,54 +1,98 @@
 <template>
   <ContentWrap>
     <!-- 搜索工作栏 -->
-    <el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
       <el-form-item label="客户" prop="customerId">
         <el-select
-v-model="queryParams.customerId" placeholder="请选择客户" value-key="id" lable-key="name"
-          @keyup.enter="handleQuery" clearable>
-          <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" />
+          v-model="queryParams.customerId"
+          placeholder="请选择客户"
+          value-key="id"
+          lable-key="name"
+          @keyup.enter="handleQuery"
+          clearable
+        >
+          <el-option
+            v-for="item in customerList"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id"
+          />
         </el-select>
       </el-form-item>
       <el-form-item label="姓名" prop="name">
-        <el-input v-model="queryParams.name" placeholder="请输入姓名" clearable @keyup.enter="handleQuery" class="!w-240px" />
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入姓名"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
       </el-form-item>
       <el-form-item label="手机号" prop="mobile">
         <el-input
-v-model="queryParams.mobile" placeholder="请输入手机号" clearable @keyup.enter="handleQuery"
-          class="!w-240px" />
+          v-model="queryParams.mobile"
+          placeholder="请输入手机号"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
       </el-form-item>
       <el-form-item label="座机" prop="telephone">
         <el-input
-v-model="queryParams.telephone" placeholder="请输入电话" clearable @keyup.enter="handleQuery"
-          class="!w-240px" />
+          v-model="queryParams.telephone"
+          placeholder="请输入电话"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
       </el-form-item>
 
       <el-form-item label="QQ" prop="qq">
-        <el-input v-model="queryParams.qq" placeholder="请输入QQ" clearable @keyup.enter="handleQuery" class="!w-240px" />
+        <el-input
+          v-model="queryParams.qq"
+          placeholder="请输入QQ"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
       </el-form-item>
       <el-form-item label="微信" prop="wechat">
         <el-input
-v-model="queryParams.wechat" placeholder="请输入微信" clearable @keyup.enter="handleQuery"
-          class="!w-240px" />
+          v-model="queryParams.wechat"
+          placeholder="请输入微信"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
       </el-form-item>
       <el-form-item label="电子邮箱" prop="email">
         <el-input
-v-model="queryParams.email" placeholder="请输入电子邮箱" clearable @keyup.enter="handleQuery"
-          class="!w-240px" />
+          v-model="queryParams.email"
+          placeholder="请输入电子邮箱"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
       </el-form-item>
       <el-form-item>
-        <el-button @click="handleQuery">
-          <Icon icon="ep:search" class="mr-5px" /> 搜索
-        </el-button>
-        <el-button @click="resetQuery">
-          <Icon icon="ep:refresh" class="mr-5px" /> 重置
-        </el-button>
+        <el-button @click="handleQuery"> <Icon icon="ep:search" class="mr-5px" /> 搜索 </el-button>
+        <el-button @click="resetQuery"> <Icon icon="ep:refresh" class="mr-5px" /> 重置 </el-button>
         <el-button type="primary" @click="openForm('create')" v-hasPermi="['crm:contact:create']">
           <Icon icon="ep:plus" class="mr-5px" /> 新增
         </el-button>
         <el-button
-type="success" plain @click="handleExport" :loading="exportLoading"
-          v-hasPermi="['crm:contact:export']">
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['crm:contact:export']"
+        >
           <Icon icon="ep:download" class="mr-5px" /> 导出
         </el-button>
       </el-form-item>
@@ -60,9 +104,9 @@ type="success" plain @click="handleExport" :loading="exportLoading"
     <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
       <el-table-column label="姓名" fixed="left" align="center" prop="name">
         <template #default="scope">
-          <el-link type="primary" :underline="false" @click="openDetail(scope.row.id)">{{
-            scope.row.name
-          }}</el-link>
+          <el-link type="primary" :underline="false" @click="openDetail(scope.row.id)">
+            {{ scope.row.name }}
+          </el-link>
         </template>
       </el-table-column>
       <el-table-column label="客户" fixed="left" align="center" prop="customerName" />
@@ -84,17 +128,41 @@ type="success" plain @click="handleExport" :loading="exportLoading"
       <el-table-column label="微信" align="center" prop="wechat" />
       <el-table-column label="邮箱" align="center" prop="email" />
       <el-table-column label="地址" align="center" prop="address" />
-      <el-table-column label="下次联系时间" align="center" prop="nextTime" width="180px" :formatter="dateFormatter" />
+      <el-table-column
+        label="下次联系时间"
+        align="center"
+        prop="nextTime"
+        width="180px"
+        :formatter="dateFormatter"
+      />
       <el-table-column label="备注" align="center" prop="remark" />
-      <el-table-column label="最后跟进时间" align="center" prop="lastTime" :formatter="dateFormatter" width="180px" />
+      <el-table-column
+        label="最后跟进时间"
+        align="center"
+        prop="lastTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
       <el-table-column label="负责人" align="center" prop="ownerUserId">
         <template #default="scope">
           {{ scope.row.ownerUserName }}
         </template>
       </el-table-column>
       <!-- <el-table-column label="所属部门" align="center" prop="ownerUserId" /> -->
-      <el-table-column label="更新时间" align="center" prop="updateTime" :formatter="dateFormatter" width="180px" />
-      <el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
+      <el-table-column
+        label="更新时间"
+        align="center"
+        prop="updateTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
       <!-- <el-table-column
         label="创建人"
         align="center"
@@ -108,10 +176,20 @@ type="success" plain @click="handleExport" :loading="exportLoading"
       </el-table-column> -->
       <el-table-column label="操作" align="center" fixed="right" width="200">
         <template #default="scope">
-          <el-button plain type="primary" @click="openForm('update', scope.row.id)" v-hasPermi="['crm:contact:update']">
+          <el-button
+            plain
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['crm:contact:update']"
+          >
             编辑
           </el-button>
-          <el-button plain type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['crm:contact:delete']">
+          <el-button
+            plain
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['crm:contact:delete']"
+          >
             删除
           </el-button>
         </template>
@@ -119,8 +197,11 @@ type="success" plain @click="handleExport" :loading="exportLoading"
     </el-table>
     <!-- 分页 -->
     <Pagination
-:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
-      @pagination="getList" />
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
   </ContentWrap>
 
   <!-- 表单弹窗:添加/修改 -->
@@ -208,7 +289,7 @@ const handleDelete = async (id: number) => {
     message.success(t('common.delSuccess'))
     // 刷新列表
     await getList()
-  } catch { }
+  } catch {}
 }
 
 /** 导出按钮操作 */
@@ -232,7 +313,6 @@ const openDetail = (id: number) => {
   push({ name: 'CrmContactDetail', params: { id } })
 }
 
-
 /** 初始化 **/
 onMounted(async () => {
   await getList()

+ 0 - 18
src/views/crm/customer/detail/CustomerBasicInfo.vue

@@ -1,18 +0,0 @@
-<template>
-  <el-col>
-    <el-row>
-      <span class="text-xl font-bold">{{ customer.name }}</span>
-    </el-row>
-  </el-col>
-  <el-col class="mt-10px">
-    <!-- TODO 标签 -->
-    <!--    <Icon icon="ant-design:tag-filled" />-->
-  </el-col>
-</template>
-<script setup lang="ts">
-import * as CustomerApi from '@/api/crm/customer'
-
-const { customer } = defineProps<{
-  customer: CustomerApi.CustomerVO
-}>()
-</script>

+ 17 - 35
src/views/crm/customer/detail/CustomerDetailsHeader.vue

@@ -3,7 +3,11 @@
     <div class="flex items-start justify-between">
       <div>
         <!-- 左上:客户基本信息 -->
-        <CustomerBasicInfo :customer="customer" />
+        <el-col>
+          <el-row>
+            <span class="text-xl font-bold">{{ customer.name }}</span>
+          </el-row>
+        </el-col>
       </div>
       <div>
         <!-- 右上:按钮 -->
@@ -15,29 +19,13 @@
     </div>
     <!-- TODO 芋艿: -->
     <el-row class="mt-10px">
+      <el-button> <Icon class="mr-5px" icon="ph:calendar-fill" /> 创建任务 </el-button>
+      <el-button> <Icon class="mr-5px" icon="carbon:email" /> 发送邮件 </el-button>
+      <el-button> <Icon class="mr-5px" icon="ep:opportunity" /> 创建商机 </el-button>
+      <el-button> <Icon class="mr-5px" icon="clarity:contract-line" />创建合同 </el-button>
+      <el-button> <Icon class="mr-5px" icon="icon-park:income-one" />创建回款 </el-button>
       <el-button>
-        <Icon class="mr-5px" icon="ph:calendar-fill" />
-        创建任务
-      </el-button>
-      <el-button>
-        <Icon class="mr-5px" icon="carbon:email" />
-        发送邮件
-      </el-button>
-      <el-button>
-        <Icon class="mr-5px" icon="ep:opportunity" />
-        创建商机
-      </el-button>
-      <el-button>
-        <Icon class="mr-5px" icon="clarity:contract-line" />
-        创建合同
-      </el-button>
-      <el-button>
-        <Icon class="mr-5px" icon="icon-park:income-one" />
-        创建回款
-      </el-button>
-      <el-button>
-        <Icon class="mr-5px" icon="fluent:people-team-add-20-filled" />
-        添加团队成员
+        <Icon class="mr-5px" icon="fluent:people-team-add-20-filled" /> 添加团队成员
       </el-button>
     </el-row>
   </div>
@@ -49,15 +37,11 @@
       <el-descriptions-item label="成交状态">
         {{ customer.dealStatus ? '已成交' : '未成交' }}
       </el-descriptions-item>
-      <el-descriptions-item label="负责人">
-        {{ customer.ownerUserName }}
-      </el-descriptions-item>
+      <el-descriptions-item label="负责人">{{ customer.ownerUserName }} </el-descriptions-item>
       <!-- TODO wanwan 首要联系人? -->
       <el-descriptions-item label="首要联系人" />
       <!-- TODO wanwan 首要联系人电话? -->
-      <el-descriptions-item label="首要联系人电话">
-        {{ customer.mobile }}
-      </el-descriptions-item>
+      <el-descriptions-item label="首要联系人电话">{{ customer.mobile }} </el-descriptions-item>
     </el-descriptions>
   </ContentWrap>
 
@@ -65,15 +49,13 @@
   <CustomerForm ref="formRef" @success="emit('refresh')" />
 </template>
 <script setup lang="ts">
-import * as CustomerApi from '@/api/crm/customer'
 import { DICT_TYPE } from '@/utils/dict'
-// TODO @wanwan:是不是把 CustomerBasicInfo 也放进来。
-import CustomerBasicInfo from '@/views/crm/customer/detail/CustomerBasicInfo.vue'
-import CustomerForm from '@/views/crm/customer/CustomerForm.vue'
+import * as CustomerApi from '@/api/crm/customer'
+import CustomerForm from '../CustomerForm.vue'
 
 const { customer, loading } = defineProps<{
-  customer: CustomerApi.CustomerVO
-  loading: boolean
+  customer: CustomerApi.CustomerVO // 客户信息
+  loading: boolean // 加载中
 }>()
 
 /** 修改操作 */

+ 15 - 38
src/views/crm/customer/detail/CustomerDetails.vue → src/views/crm/customer/detail/CustomerDetailsInfo.vue

@@ -18,29 +18,15 @@
           <el-descriptions-item label="客户等级">
             <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="customer.level" />
           </el-descriptions-item>
-          <el-descriptions-item label="手机">
-            {{ customer.mobile }}
-          </el-descriptions-item>
-          <el-descriptions-item label="电话">
-            {{ customer.telephone }}
-          </el-descriptions-item>
-          <el-descriptions-item label="邮箱">
-            {{ customer.email }}
-          </el-descriptions-item>
-          <el-descriptions-item label="QQ">
-            {{ customer.qq }}
-          </el-descriptions-item>
-          <el-descriptions-item label="微信">
-            {{ customer.wechat }}
-          </el-descriptions-item>
-          <el-descriptions-item label="网址">
-            {{ customer.website }}
-          </el-descriptions-item>
-          <el-descriptions-item label="所在地">
-            {{ customer.areaName }}
-          </el-descriptions-item>
-          <el-descriptions-item label="详细地址">
-            {{ customer.detailAddress }}
+          <el-descriptions-item label="手机">{{ customer.mobile }}</el-descriptions-item>
+          <el-descriptions-item label="电话">{{ customer.telephone }}</el-descriptions-item>
+          <el-descriptions-item label="邮箱">{{ customer.email }} </el-descriptions-item>
+          <el-descriptions-item label="QQ">{{ customer.qq }} </el-descriptions-item>
+          <el-descriptions-item label="微信">{{ customer.wechat }} </el-descriptions-item>
+          <el-descriptions-item label="网址">{{ customer.website }} </el-descriptions-item>
+          <el-descriptions-item label="所在地">{{ customer.areaName }} </el-descriptions-item>
+          <el-descriptions-item label="详细地址"
+            >{{ customer.detailAddress }}
           </el-descriptions-item>
           <el-descriptions-item label="下次联系时间">
             {{
@@ -52,12 +38,8 @@
           </el-descriptions-item>
         </el-descriptions>
         <el-descriptions :column="1">
-          <el-descriptions-item label="客户描述">
-            {{ customer.description }}
-          </el-descriptions-item>
-          <el-descriptions-item label="备注">
-            {{ customer.remark }}
-          </el-descriptions-item>
+          <el-descriptions-item label="客户描述">{{ customer.description }} </el-descriptions-item>
+          <el-descriptions-item label="备注">{{ customer.remark }} </el-descriptions-item>
         </el-descriptions>
       </el-collapse-item>
       <el-collapse-item name="systemInfo">
@@ -65,12 +47,8 @@
           <span class="text-base font-bold">系统信息</span>
         </template>
         <el-descriptions :column="2">
-          <el-descriptions-item label="负责人">
-            {{ customer.ownerUserName }}
-          </el-descriptions-item>
-          <el-descriptions-item label="创建人">
-            {{ customer.creatorName }}
-          </el-descriptions-item>
+          <el-descriptions-item label="负责人">{{ customer.ownerUserName }} </el-descriptions-item>
+          <el-descriptions-item label="创建人">{{ customer.creatorName }} </el-descriptions-item>
           <el-descriptions-item label="创建时间">
             {{ customer.createTime ? formatDate(customer.createTime) : '空' }}
           </el-descriptions-item>
@@ -88,10 +66,9 @@ import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
 
 const { customer } = defineProps<{
-  customer: CustomerApi.CustomerVO
+  customer: CustomerApi.CustomerVO // 客户明细
 }>()
 
-// 展示的折叠面板
-const activeNames = ref(['basicInfo', 'systemInfo'])
+const activeNames = ref(['basicInfo', 'systemInfo']) // 展示的折叠面板
 </script>
 <style scoped lang="scss"></style>

+ 15 - 22
src/views/crm/customer/detail/index.vue

@@ -1,16 +1,16 @@
 <template>
-  <CustomerDetailsHeader :customer="customer" :loading="loading" @refresh="getCustomerData(id)" />
+  <CustomerDetailsHeader :customer="customer" :loading="loading" @refresh="getCustomer(id)" />
   <el-col>
     <el-tabs>
       <el-tab-pane label="详细资料">
-        <CustomerDetails :customer="customer" />
+        <CustomerDetailsInfo :customer="customer" />
       </el-tab-pane>
       <el-tab-pane label="操作日志" lazy>TODO 待开发</el-tab-pane>
       <el-tab-pane label="联系人" lazy>
         <ContactList :biz-id="customer.id!" :biz-type="BizTypeEnum.CRM_CUSTOMER" />
       </el-tab-pane>
       <el-tab-pane label="团队成员" lazy>
-        <CrmPermissionList :biz-id="customer.id!" :biz-type="BizTypeEnum.CRM_CUSTOMER" />
+        <PermissionList :biz-id="customer.id!" :biz-type="BizTypeEnum.CRM_CUSTOMER" />
       </el-tab-pane>
       <el-tab-pane label="商机" lazy> 商机</el-tab-pane>
       <el-tab-pane label="合同" lazy>TODO 待开发</el-tab-pane>
@@ -20,31 +20,24 @@
     </el-tabs>
   </el-col>
 </template>
-
 <script lang="ts" setup>
 import { useTagsViewStore } from '@/store/modules/tagsView'
 import * as CustomerApi from '@/api/crm/customer'
-import CustomerDetails from '@/views/crm/customer/detail/CustomerDetails.vue'
-import { CrmPermissionList } from '@/views/crm/components'
-import ContactList from '@/views/crm/contact/components/ContactList.vue'
-import CustomerDetailsHeader from './CustomerDetailsHeader.vue'
+import CustomerDetailsInfo from './CustomerDetailsInfo.vue' // 客户明细 - 详细信息
+import CustomerDetailsHeader from './CustomerDetailsHeader.vue' // 客户明细 - 头部
+import ContactList from '@/views/crm/contact/components/ContactList.vue' // 联系人列表
+import PermissionList from '@/views/crm/permission/components/PermissionList.vue' // 权限列表
 import { BizTypeEnum } from '@/api/crm/permission'
 
-defineOptions({ name: 'CustomerDetail' })
+defineOptions({ name: 'CrmCustomerDetail' })
 
-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) // 加载中
 
-/**
- * 获取详情
- *
- * @param id 客户编号
- */
+/** 获取详情 */
 const customer = ref<CustomerApi.CustomerVO>({} as CustomerApi.CustomerVO) // 客户详情
-const getCustomerData = async (id: number) => {
+const getCustomer = async (id: number) => {
   loading.value = true
   try {
     customer.value = await CustomerApi.getCustomer(id)
@@ -53,15 +46,15 @@ const getCustomerData = async (id: number) => {
   }
 }
 
-/**
- * 初始化
- */
+/** 初始化 */
+const { delView } = useTagsViewStore() // 视图操作
+const { currentRoute } = useRouter() // 路由
 onMounted(() => {
   if (!id) {
     ElMessage.warning('参数错误,客户不能为空!')
     delView(unref(currentRoute))
     return
   }
-  getCustomerData(id)
+  getCustomer(id)
 })
 </script>

+ 11 - 14
src/views/crm/customer/index.vue

@@ -72,17 +72,10 @@
         </el-select>
       </el-form-item>
       <el-form-item>
-        <el-button @click="handleQuery">
-          <Icon class="mr-5px" icon="ep:search" />
-          搜索
-        </el-button>
-        <el-button @click="resetQuery">
-          <Icon class="mr-5px" icon="ep:refresh" />
-          重置
-        </el-button>
+        <el-button @click="handleQuery"> <Icon class="mr-5px" icon="ep:search" /> 搜索 </el-button>
+        <el-button @click="resetQuery"> <Icon class="mr-5px" icon="ep:refresh" />重置 </el-button>
         <el-button v-hasPermi="['crm:customer:create']" type="primary" @click="openForm('create')">
-          <Icon class="mr-5px" icon="ep:plus" />
-          新增
+          <Icon class="mr-5px" icon="ep:plus" /> 新增
         </el-button>
         <el-button
           v-hasPermi="['crm:customer:export']"
@@ -91,8 +84,7 @@
           type="success"
           @click="handleExport"
         >
-          <Icon class="mr-5px" icon="ep:download" />
-          导出
+          <Icon class="mr-5px" icon="ep:download" /> 导出
         </el-button>
       </el-form-item>
     </el-form>
@@ -102,7 +94,13 @@
   <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="客户名称" prop="name" width="160">
+        <template #default="scope">
+          <el-link type="primary" :underline="false" @click="openDetail(scope.row.id)">
+            {{ scope.row.name }}
+          </el-link>
+        </template>
+      </el-table-column>
       <el-table-column align="center" label="所属行业" prop="industryId" width="120">
         <template #default="scope">
           <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_INDUSTRY" :value="scope.row.industryId" />
@@ -157,7 +155,6 @@
       <!--  TODO @wanwan 距进入公海天数    -->
       <el-table-column align="center" fixed="right" label="操作" min-width="150">
         <template #default="scope">
-          <el-button link type="primary" @click="openDetail(scope.row.id)">详情</el-button>
           <el-button
             v-hasPermi="['crm:customer:update']"
             link

+ 5 - 4
src/views/crm/components/CrmPermissionForm.vue → src/views/crm/permission/components/PermissionForm.vue

@@ -23,12 +23,13 @@
             v-for="dict in getIntDictOptions(DICT_TYPE.CRM_PERMISSION_LEVEL)"
             :key="dict.value"
           >
-            <el-radio v-if="dict.value != CrmPermissionLevelEnum.OWNER" :label="dict.value">
+            <el-radio v-if="dict.value != PermissionLevelEnum.OWNER" :label="dict.value">
               {{ dict.label }}
             </el-radio>
           </template>
         </el-radio-group>
       </el-form-item>
+      <!-- TODO @puhui999:同时添加至 -->
     </el-form>
     <template #footer>
       <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
@@ -39,8 +40,8 @@
 <script lang="ts" setup>
 import * as UserApi from '@/api/system/user'
 import * as PermissionApi from '@/api/crm/permission'
+import { PermissionLevelEnum } from '@/api/crm/permission'
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import { CrmPermissionLevelEnum } from '@/views/crm/components/index'
 
 defineOptions({ name: 'CrmPermissionForm' })
 
@@ -54,8 +55,8 @@ const formType = ref('') // 表单的类型:create - 新增;update - 修改
 const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
 const formData = ref<PermissionApi.PermissionVO & { ids?: number[] }>({
   userId: undefined, // 用户编号
-  bizType: undefined, // Crm 类型
-  bizId: undefined, // Crm 类型数据编号
+  bizType: undefined, // CRM 类型
+  bizId: undefined, // CRM 类型数据编号
   level: undefined // 权限级别
 })
 const formRules = reactive({

+ 52 - 45
src/views/crm/components/CrmPermissionList.vue → src/views/crm/permission/components/PermissionList.vue

@@ -1,9 +1,8 @@
 <template>
   <!-- 操作栏 -->
   <el-row justify="end">
-    <el-button type="primary" @click="openForm">
-      <Icon class="mr-5px" icon="ep:plus" />
-      新增
+    <el-button @click="openForm">
+      <Icon class="mr-5px" icon="fluent:people-team-add-20-filled" /> 添加团队成员
     </el-button>
     <el-button @click="handleUpdate">
       <Icon class="mr-5px" icon="ep:edit" />
@@ -16,47 +15,51 @@
     <el-button type="danger" @click="handleQuit"> 退出团队</el-button>
   </el-row>
 
-  <!-- 团队成员展示 -->
-  <el-table
-    v-loading="loading"
-    :data="list"
-    :show-overflow-tooltip="true"
-    :stripe="true"
-    class="mt-20px"
-    @selection-change="handleSelectionChange"
-  >
-    <el-table-column type="selection" width="55" />
-    <el-table-column align="center" label="姓名" prop="nickname" />
-    <el-table-column align="center" label="部门" prop="deptName" />
-    <el-table-column align="center" label="岗位" prop="postNames" />
-    <el-table-column align="center" label="权限级别" prop="level">
-      <template #default="{ row }">
-        <dict-tag :type="DICT_TYPE.CRM_PERMISSION_LEVEL" :value="row.level" />
-      </template>
-    </el-table-column>
-    <el-table-column :formatter="dateFormatter" align="center" label="加入时间" prop="createTime" />
-  </el-table>
+  <!-- 列表 -->
+  <ContentWrap class="mt-10px">
+    <el-table
+      v-loading="loading"
+      :data="list"
+      :show-overflow-tooltip="true"
+      :stripe="true"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55" />
+      <el-table-column align="center" label="姓名" prop="nickname" />
+      <el-table-column align="center" label="部门" prop="deptName" />
+      <el-table-column align="center" label="岗位" prop="postNames" />
+      <el-table-column align="center" label="权限" prop="level">
+        <template #default="{ row }">
+          <dict-tag :type="DICT_TYPE.CRM_PERMISSION_LEVEL" :value="row.level" />
+        </template>
+      </el-table-column>
+      <el-table-column
+        :formatter="dateFormatter"
+        align="center"
+        label="加入时间"
+        prop="createTime"
+      />
+    </el-table>
+  </ContentWrap>
 
   <!-- 表单弹窗:添加/修改 -->
   <CrmPermissionForm ref="formRef" @success="getList" />
 </template>
 <script lang="ts" setup>
 import { dateFormatter } from '@/utils/formatTime'
-import { ElTable } from 'element-plus'
+import { DICT_TYPE } from '@/utils/dict'
 import * as PermissionApi from '@/api/crm/permission'
+import { PermissionLevelEnum } from '@/api/crm/permission'
 import { useUserStoreWithOut } from '@/store/modules/user'
-import CrmPermissionForm from './CrmPermissionForm.vue'
-import { CrmPermissionLevelEnum } from './index'
-import { DICT_TYPE } from '@/utils/dict'
+import CrmPermissionForm from './PermissionForm.vue'
 
 defineOptions({ name: 'CrmPermissionList' })
-
-const message = useMessage() // 消息
-
 const props = defineProps<{
-  bizType: number // 模块类型
-  bizId: number // 模块数据编号
+  bizType: number // 业务类型
+  bizId: number // 业务编号
 }>()
+
+const message = useMessage() // 消息
 const loading = ref(true) // 列表的加载中
 const list = ref<PermissionApi.PermissionVO[]>([]) // 列表的数据
 
@@ -64,28 +67,34 @@ const list = ref<PermissionApi.PermissionVO[]>([]) // 列表的数据
 const getList = async () => {
   loading.value = true
   try {
-    const data = await PermissionApi.getPermissionList({
+    list.value = await PermissionApi.getPermissionList({
       bizType: props.bizType,
       bizId: props.bizId
     })
-    list.value = data
   } finally {
     loading.value = false
   }
 }
+
+/** 选中团队成员 */
 const multipleSelection = ref<PermissionApi.PermissionVO[]>([]) // 选择的团队成员
 const handleSelectionChange = (val: PermissionApi.PermissionVO[]) => {
   multipleSelection.value = val
 }
 
-/** 编辑团队成员 */
+/** 添加团队成员 */
 const formRef = ref<InstanceType<typeof CrmPermissionForm>>() // 权限表单 Ref
+const openForm = () => {
+  formRef.value?.open('create', props.bizType, props.bizId)
+}
+
+/** 编辑团队成员 */
 const handleUpdate = () => {
   if (multipleSelection.value?.length === 0) {
     message.warning('请先选择团队成员后操作!')
     return
   }
-  const ids = multipleSelection.value?.map((item) => item.id)
+  const ids = multipleSelection.value?.map((item) => item.id) as number[]
   formRef.value?.open('update', props.bizType, props.bizId, ids)
 }
 
@@ -95,36 +104,34 @@ const handleDelete = async () => {
     message.warning('请先选择团队成员后操作!')
     return
   }
+  // TODO @puhui999:应该有个提示哈
   await message.delConfirm()
   const ids = multipleSelection.value?.map((item) => item.id)
-  await PermissionApi.deletePermission({
+  await PermissionApi.deletePermissionBatch({
     bizType: props.bizType,
     bizId: props.bizId,
     ids
   })
 }
 
-/** 添加团队成员 */
-const openForm = () => {
-  formRef.value?.open('create', props.bizType, props.bizId)
-}
-
 /** 退出团队 */
 const userStore = useUserStoreWithOut() // 用户信息缓存
 const handleQuit = async () => {
   const permission = list.value.find(
-    (item) => item.userId === userStore.getUser.id && item.level === CrmPermissionLevelEnum.OWNER
+    (item) => item.userId === userStore.getUser.id && item.level === PermissionLevelEnum.OWNER
   )
   if (permission) {
     message.warning('负责人不能退出团队!')
     return
   }
+  // TODO @puhui999:应该有个提示哈
   const userPermission = list.value.find((item) => item.userId === userStore.getUser.id)
-  await PermissionApi.quitTeam(userPermission?.id)
+  await PermissionApi.deleteSelfPermission(userPermission?.id)
 }
 
+/** 监听打开的 bizId + bizType,从而加载最新的列表 */
 watch(
-  () => props.bizId,
+  () => [props.bizId, props.bizType],
   () => {
     getList()
   },