Pārlūkot izejas kodu

✨ CRM:优化客户的列表、编辑的样式

YunaiV 1 gadu atpakaļ
vecāks
revīzija
ac9a77e6e4

+ 25 - 28
src/api/crm/customer/index.ts

@@ -1,36 +1,33 @@
 import request from '@/config/axios'
 
 export interface CustomerVO {
-  id?: number
-  name: string
-  industryId: number
-  level: number
-  source: number
-  followUpStatus?: boolean
+  id: number // 编号
+  name: string // 客户名称
+  followUpStatus: boolean // 跟进状态
+  contactLastTime: Date // 最后跟进时间
+  contactLastContent: string // 最后跟进内容
+  contactNextTime: Date // 下次联系时间
+  ownerUserId: number // 负责人的用户编号
+  ownerUserName?: string // 负责人的用户名称
+  ownerUserDept?: string // 负责人的部门名称
   lockStatus?: boolean
   dealStatus?: boolean
-  mobile: string
-  telephone: string
-  website: string
-  qq: string
-  wechat: string
-  email: string
-  description: string
-  remark: string
-  ownerUserId?: number
-  ownerUserName?: string
-  ownerUserDept?: string
-  roUserIds?: string
-  rwUserIds?: string
-  areaId?: number
-  areaName?: string
-  detailAddress: string
-  contactLastTime?: Date
-  contactNextTime: Date
-  createTime?: Date
-  updateTime?: Date
-  creator?: string
-  creatorName?: string
+  mobile: string // 手机号
+  telephone: string // 电话
+  qq: string // QQ
+  wechat: string // wechat
+  email: string // email
+  areaId: number // 所在地
+  areaName?: string // 所在地名称
+  detailAddress: string // 详细地址
+  industryId: number // 所属行业
+  level: number // 客户等级
+  source: number // 客户来源
+  remark: string // 备注
+  creator: string // 创建人
+  creatorName?: string // 创建人名称
+  createTime: Date // 创建时间
+  updateTime: Date // 更新时间
 }
 
 // 查询客户列表

+ 2 - 2
src/views/crm/backlog/components/ClueFollowList.vue

@@ -29,7 +29,7 @@
   <!-- 列表 -->
   <ContentWrap>
     <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
-      <el-table-column label="线索名称" align="center" prop="name" fixed="left" width="120">
+      <el-table-column label="线索名称" align="center" prop="name" fixed="left" width="160">
         <template #default="scope">
           <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">
             {{ scope.row.name }}
@@ -41,7 +41,7 @@
           <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" />
         </template>
       </el-table-column>
-      <el-table-column label="手机" align="center" prop="mobile" 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 label="地址" align="center" prop="detailAddress" width="180" />

+ 2 - 2
src/views/crm/clue/index.vue

@@ -68,7 +68,7 @@
       <el-tab-pane label="下属负责的" name="3" />
     </el-tabs>
     <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
-      <el-table-column label="线索名称" align="center" prop="name" fixed="left" width="120">
+      <el-table-column label="线索名称" align="center" prop="name" fixed="left" width="160">
         <template #default="scope">
           <el-link :underline="false" type="primary" @click="openDetail(scope.row.id)">
             {{ scope.row.name }}
@@ -80,7 +80,7 @@
           <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" />
         </template>
       </el-table-column>
-      <el-table-column label="手机" align="center" prop="mobile" 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 label="地址" align="center" prop="detailAddress" width="180" />

+ 62 - 70
src/views/crm/customer/CustomerForm.vue

@@ -14,10 +14,10 @@
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item label="所属行业" prop="industryId">
-            <el-select v-model="formData.industryId" placeholder="请选择所属行业">
+          <el-form-item label="客户来源" prop="source">
+            <el-select v-model="formData.source" placeholder="请选择客户来源" class="w-1/1">
               <el-option
-                v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY)"
+                v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)"
                 :key="dict.value"
                 :label="dict.label"
                 :value="dict.value"
@@ -28,25 +28,22 @@
       </el-row>
       <el-row>
         <el-col :span="12">
-          <el-form-item label="客户来源" prop="source">
-            <el-select v-model="formData.source" placeholder="请选择客户来源">
-              <el-option
-                v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_SOURCE)"
-                :key="dict.value"
-                :label="dict.label"
-                :value="dict.value"
-              />
-            </el-select>
+          <el-form-item label="手机" prop="mobile">
+            <el-input v-model="formData.mobile" placeholder="请输入手机" />
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item label="客户级别" prop="level">
-            <el-select v-model="formData.level" placeholder="请选择客户级别">
+          <el-form-item label="负责人" prop="ownerUserId">
+            <el-select
+              v-model="formData.ownerUserId"
+              :disabled="formType !== 'create'"
+              class="w-1/1"
+            >
               <el-option
-                v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL)"
-                :key="dict.value"
-                :label="dict.label"
-                :value="dict.value"
+                v-for="item in userOptions"
+                :key="item.id"
+                :label="item.nickname"
+                :value="item.id"
               />
             </el-select>
           </el-form-item>
@@ -54,48 +51,63 @@
       </el-row>
       <el-row>
         <el-col :span="12">
-          <el-form-item label="手机" prop="mobile">
-            <el-input v-model="formData.mobile" placeholder="请输入手机" />
+          <el-form-item label="电话" prop="telephone">
+            <el-input v-model="formData.telephone" placeholder="请输入电话" />
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item label="电话" prop="telephone">
-            <el-input v-model="formData.telephone" placeholder="请输入电话" />
+          <el-form-item label="邮箱" prop="email">
+            <el-input v-model="formData.email" placeholder="请输入邮箱" />
           </el-form-item>
         </el-col>
       </el-row>
       <el-row>
         <el-col :span="12">
-          <el-form-item label="邮箱" prop="email">
-            <el-input v-model="formData.email" placeholder="请输入邮箱" />
+          <el-form-item label="微信" prop="wechat">
+            <el-input v-model="formData.wechat" placeholder="请输入微信" />
           </el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="QQ" prop="qq">
-            <el-input v-model="formData.qq" placeholder="请输入QQ" />
+            <el-input v-model="formData.qq" placeholder="请输入 QQ" />
           </el-form-item>
         </el-col>
       </el-row>
       <el-row>
         <el-col :span="12">
-          <el-form-item label="微信" prop="wechat">
-            <el-input v-model="formData.wechat" placeholder="请输入微信" />
+          <el-form-item label="客户行业" prop="industryId">
+            <el-select v-model="formData.industryId" placeholder="请选择客户行业" class="w-1/1">
+              <el-option
+                v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item label="网址" prop="website">
-            <el-input v-model="formData.website" placeholder="请输入网址" />
+          <el-form-item label="客户级别" prop="level">
+            <el-select v-model="formData.level" placeholder="请选择客户级别" class="w-1/1">
+              <el-option
+                v-for="dict in getIntDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL)"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
           </el-form-item>
         </el-col>
       </el-row>
       <el-row>
         <el-col :span="12">
-          <el-form-item label="所在地" prop="areaId">
+          <el-form-item label="地" prop="areaId">
             <el-tree-select
               v-model="formData.areaId"
               :data="areaList"
               :props="defaultProps"
               :render-after-expand="true"
+              class="w-1/1"
             />
           </el-form-item>
         </el-col>
@@ -105,16 +117,7 @@
           </el-form-item>
         </el-col>
       </el-row>
-      <el-form-item v-if="formType === 'create'" label="负责人" prop="userIds" span="24">
-        <el-select v-model="formData.ownerUserId">
-          <el-option
-            v-for="item in userOptions"
-            :key="parseInt(item.id)"
-            :label="item.nickname"
-            :value="parseInt(item.id)"
-          />
-        </el-select>
-      </el-form-item>
+      <!-- TODO 芋艿:待整理 -->
       <el-row>
         <el-col :span="12">
           <el-form-item label="下次联系时间" prop="contactNextTime">
@@ -126,17 +129,12 @@
             />
           </el-form-item>
         </el-col>
+        <el-col :span="12">
+          <el-form-item label="备注" prop="remark">
+            <el-input type="textarea" v-model="formData.remark" placeholder="请输入备注" />
+          </el-form-item>
+        </el-col>
       </el-row>
-      <el-col :span="24">
-        <el-form-item label="客户描述" prop="description">
-          <el-input v-model="formData.description" placeholder="请输入客户描述" />
-        </el-form-item>
-      </el-col>
-      <el-col :span="24">
-        <el-form-item label="备注" prop="remark">
-          <el-input v-model="formData.remark" placeholder="请输入备注" />
-        </el-form-item>
-      </el-col>
     </el-form>
     <template #footer>
       <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
@@ -150,7 +148,7 @@ import * as CustomerApi from '@/api/crm/customer'
 import * as AreaApi from '@/api/system/area'
 import { defaultProps } from '@/utils/tree'
 import * as UserApi from '@/api/system/user'
-import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
+import { useUserStore } from '@/store/modules/user'
 
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
@@ -164,21 +162,19 @@ const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
 const formData = ref({
   id: undefined,
   name: undefined,
+  contactNextTime: undefined,
+  ownerUserId: 0,
   mobile: undefined,
-  industryId: undefined,
-  level: undefined,
-  source: undefined,
   telephone: undefined,
-  website: undefined,
   qq: undefined,
   wechat: undefined,
   email: undefined,
-  description: undefined,
-  remark: undefined,
   areaId: undefined,
   detailAddress: undefined,
-  contactNextTime: undefined,
-  ownerUserId: undefined
+  industryId: undefined,
+  level: undefined,
+  source: undefined,
+  remark: undefined
 })
 const formRules = reactive({
   name: [{ required: true, message: '客户名称不能为空', trigger: 'blur' }],
@@ -207,9 +203,7 @@ const open = async (type: string, id?: number) => {
   userOptions.value = await UserApi.getSimpleUserList()
   // 默认新建时选中自己
   if (formType.value === 'create') {
-    const { wsCache } = useCache()
-    const user = wsCache.get(CACHE_KEY.USER).user
-    formData.value.ownerUserId = user.id
+    formData.value.ownerUserId = useUserStore().getUser.id
   }
 }
 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
@@ -245,21 +239,19 @@ const resetForm = () => {
   formData.value = {
     id: undefined,
     name: undefined,
+    contactNextTime: undefined,
+    ownerUserId: 0,
     mobile: undefined,
-    industryId: undefined,
-    level: undefined,
-    source: undefined,
     telephone: undefined,
-    website: undefined,
     qq: undefined,
     wechat: undefined,
     email: undefined,
-    description: undefined,
-    remark: undefined,
     areaId: undefined,
     detailAddress: undefined,
-    contactNextTime: undefined,
-    ownerUserId: undefined
+    industryId: undefined,
+    level: undefined,
+    source: undefined,
+    remark: undefined
   }
   formRef.value?.resetFields()
 }

+ 31 - 67
src/views/crm/customer/index.vue

@@ -104,13 +104,12 @@
 
   <!-- 列表 -->
   <ContentWrap>
-    <el-tabs v-model="activeName" @tab-click="handleClick">
+    <el-tabs v-model="activeName" @tab-click="handleTabClick">
       <el-tab-pane label="我负责的" name="1" />
       <el-tab-pane label="我参与的" name="2" />
       <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" label="编号" fixed="left" prop="id" />
       <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)">
@@ -118,24 +117,24 @@
           </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="130">
+      <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"
@@ -144,14 +143,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="120">
-        <template #default="scope"> {{ scope.row.poolDay }} 天</template>
-      </el-table-column>
       <el-table-column
         :formatter="dateFormatter"
         align="center"
@@ -159,10 +160,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"
       />
@@ -173,8 +181,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-column align="center" fixed="right" label="操作" min-width="150">
         <template #default="scope">
@@ -228,62 +234,32 @@ const { t } = useI18n() // 国际化
 const loading = ref(true) // 列表的加载中
 const total = ref(0) // 列表的总页数
 const list = ref([]) // 列表的数据
-const queryParams = ref<{
-  pageNo: number
-  pageSize: number
-  name: string
-  mobile: string
-  industryId: number | undefined
-  level: number | undefined
-  source: number | undefined
-  sceneType: number | undefined
-  pool: boolean | undefined
-}>({
+const queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
+  sceneType: '1', // 默认和 activeName 相等
   name: '',
   mobile: '',
   industryId: undefined,
   level: undefined,
   source: undefined,
-  sceneType: undefined,
   pool: undefined
 })
 const queryFormRef = ref() // 搜索的表单
 const exportLoading = ref(false) // 导出的加载中
 const activeName = ref('1') // 列表 tab
 
-enum CrmSceneTypeEnum {
-  OWNER = 1,
-  INVOLVED = 2,
-  SUBORDINATE = 3
-}
-
-const handleClick = (tab: TabsPaneContext) => {
-  switch (tab.paneName) {
-    case '1':
-      resetQuery(() => {
-        queryParams.value.sceneType = CrmSceneTypeEnum.OWNER
-      })
-      break
-    case '2':
-      resetQuery(() => {
-        queryParams.value.sceneType = CrmSceneTypeEnum.INVOLVED
-      })
-      break
-    case '3':
-      resetQuery(() => {
-        queryParams.value.sceneType = CrmSceneTypeEnum.SUBORDINATE
-      })
-      break
-  }
+/** tab 切换 */
+const handleTabClick = (tab: TabsPaneContext) => {
+  queryParams.sceneType = tab.paneName
+  handleQuery()
 }
 
 /** 查询列表 */
 const getList = async () => {
   loading.value = true
   try {
-    const data = await CustomerApi.getCustomerPage(queryParams.value)
+    const data = await CustomerApi.getCustomerPage(queryParams)
     list.value = data.list
     total.value = data.total
   } finally {
@@ -293,25 +269,13 @@ const getList = async () => {
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
-  queryParams.value.pageNo = 1
+  queryParams.pageNo = 1
   getList()
 }
 
 /** 重置按钮操作 */
-const resetQuery = (func: Function | undefined = undefined) => {
+const resetQuery = () => {
   queryFormRef.value.resetFields()
-  queryParams.value = {
-    pageNo: 1,
-    pageSize: 10,
-    name: '',
-    mobile: '',
-    industryId: undefined,
-    level: undefined,
-    source: undefined,
-    sceneType: undefined,
-    pool: undefined
-  }
-  func && func()
   handleQuery()
 }
 
@@ -353,7 +317,7 @@ const handleExport = async () => {
     await message.exportConfirm()
     // 发起导出
     exportLoading.value = true
-    const data = await CustomerApi.exportCustomer(queryParams.value)
+    const data = await CustomerApi.exportCustomer(queryParams)
     download.excel(data, '客户.xls')
   } catch {
   } finally {