Ver Fonte

Merge remote-tracking branch 'origin/master'

yusm há 5 meses atrás
pai
commit
ed7ad7fedf
38 ficheiros alterados com 790 adições e 50 exclusões
  1. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/index.html
  2. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/add.png
  3. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/back.png
  4. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/delete.png
  5. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/edit.png
  6. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/form.png
  7. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/home_logo.png
  8. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/business.png
  9. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/contacts.png
  10. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/customer.png
  11. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_business.png
  12. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_contacts.png
  13. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_customer.png
  14. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_order.png
  15. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_product.png
  16. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_tasks.png
  17. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_thread.png
  18. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/order.png
  19. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/product.png
  20. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/tasks.png
  21. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/thread.png
  22. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/more.png
  23. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/schedule.png
  24. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/topContacts.png
  25. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/topMounted.png
  26. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/transfer.png
  27. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/scss/iframe.scss
  28. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/components/common/formForm/formItem.vue
  29. 7 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/components/layout/Page.vue
  30. 8 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/hooks/useApi.js
  31. 10 12
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/moduleList/moduleList.vue
  32. 172 22
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/tabbar/home/component/workbench.vue
  33. 27 6
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/tabbar/home/index.vue
  34. 39 5
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/tabbar/work/index.vue
  35. 333 0
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/visitorProgram/addEditorVisitor.vue
  36. 165 0
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/visitorProgram/visitorDetails.vue
  37. 10 0
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/router.js
  38. 16 0
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/utility/generalVariables.js

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/index.html

@@ -4,7 +4,7 @@
     <meta charset="UTF-8" />
     <link rel="icon" type="image/svg+xml" href="/vite.svg" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Vite + Vue</title>
+    <title>客户管家</title>
   </head>
   <body>
     <div id="app"></div>

BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/add.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/back.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/delete.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/edit.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/form.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/home_logo.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/business.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/contacts.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/customer.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_business.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_contacts.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_customer.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_order.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_product.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_tasks.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/min_thread.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/order.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/product.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/tasks.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/module/thread.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/more.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/schedule.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/topContacts.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/topMounted.png


BIN
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/image/transfer.png


+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/assets/scss/iframe.scss

@@ -34,7 +34,7 @@ $themeColor: #075985;
 }
 
 .resetStyles {
-  ::v-deep .van-field__label {
+  :deep(.van-field__label) {
     padding-left: 7.35px;
   }
 }

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/components/common/formForm/formItem.vue

@@ -119,7 +119,7 @@
     v-model:show="showPicker"
     destroy-on-close
     position="bottom"
-    :style="{ height: '35%' }"
+    :style="{ height: '50%' }"
   >
     <van-date-picker
       v-model="pickerValue"

+ 7 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/components/layout/Page.vue

@@ -6,7 +6,8 @@
                      :border="!!props.title"
                      :style="`height:${usePxToVwView(headerHeight)}`">
             <template v-slot:left>
-                <van-icon @click="goBack" name="revoke" size="1.29rem" color="#000000" class="font-bold" v-if="routerStore.currentPages?.length>1"/>
+                <!-- <van-icon @click="goBack" name="revoke" size="1.29rem" color="#000000" class="font-bold" v-if="routerStore.currentPages?.length>1"/> -->
+                <img src="/src/assets/image/back.png" @click="goBack" class="headerBack" v-if="routerStore.currentPages?.length>1">
                 <slot name="headerLeft"></slot>
             </template>
             <template v-slot:title>
@@ -70,6 +71,11 @@ const goBack = ()=>{
 </script>
 
 <style lang="scss" scoped>
+.headerBack {
+  width: 18px;
+  height: 18px;
+}
+
 .page{
     width: 100%;
     height: 100%;

+ 8 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/hooks/useApi.js

@@ -1,6 +1,7 @@
 export const LOGIN_INTERFACE = `/user/loginAdmin` // 登录接口
 export const USER_ID_LOGIN = `/user/loginByUserId` // userId 登录
 export const WE_CHAT_LOGIN = `/wxcorp/corpWeiXinLogin` // 微信登录
+export const RETRIEVE_DICTIONARY_ENTRIES = `/sys-dict/getListByCode` // 获取字典
 export const GET_CUSTOM_FORM_JSON = `/sys-form/getListByCode` // 获取自定义表单json
 export const GET_ALL_PERSONNEL = `/user/getSimpleActiveUserListNew` // 获取所有人员
 
@@ -8,10 +9,14 @@ export const GET_A_LIST_OF_BUSINESS_OPPORTUNITIES = '/business-opportunity/list'
 export const GET_A_LIST_OF_CLUES = '/clue/listClue' // 获取线索列表
 export const GET_CONTACT_LIST = '/contacts/pageContacts' // 获取联系人列表
 export const GET_CUSTOMER_LIST = '/custom/list' // 获取客户列表
+export const GET_ALL_CUSTOMERS = `/custom/getAllCustom` // 获取所有客户
 export const GET_TASK_LIST = '/tasks/pageTask' // 获取任务列表
 export const GET_PRODUCT_LIST = '/product/list' // 获取产品列表
 export const GET_CONTRACT_LIST = '/contract/getContractPage' // 获取合同列表
 export const GET_SALES_ORDER_LIST = '/order/list' // 获取销售订单列表
+export const GET_VISITOR_PLAN = `/visitPlan/getPageVisitPlan` // 获取访客计划
+export const GET_FREQUENTLY_USED_CONTACTS = `/contacts/getFrequentContacts` // 获取常用联系人
+export const GET_COMMONLY_USED_MODULES = `/userCommonModule/getCommonModules` // 常用模块
 
 export const DELETE_BUSINESS_OPPORTUNITY = '/business-opportunity/delete' // 删除商机
 export const DELETE_CLUES = '/clue/delete' // 删除线索
@@ -21,6 +26,7 @@ export const DELETE_TASK = '/tasks/deleteTasks' // 删除任务
 export const DELETE_PRODUCT = '/product/delete' // 删除产品
 export const DELETE_CONTRACT = '/contract/deleteContract' // 删除合同
 export const DELETE_ORDER = '/order/delete' // 删除订单
+export const DELETE_VISITOR_PLAN = `/visitPlan/delVisitPlan` // 删除访客计划
 
 export const BUSINESS_OPPORTUNITY_TRANSFER = '/business-opportunity/claim' // 转移商机
 export const TRANSFER_CLUES = '/clue/claim' // 转移线索
@@ -33,7 +39,8 @@ export const TASK_ADD_EDIT = `/tasks/addTask` // 任务新增编辑
 export const PRODUCT_ADD_EDITOR = `/product/addOrUpdate` // 产品新增编辑
 export const CONTRACT_ADDITION_EDITING = `/contract/addContract` // 合同新增编辑
 export const ORDER_ADDITION_EDITING = `/order/addOrUpdate` // 订单新增编辑
+export const PLAN_TO_ADD_EDITORS = `/visitPlan/addOrUpdateVisitPlan` // 计划新增编辑
 
 export const GET_BUSINESS_OPPORTUNITY_DETAILS = `/business-opportunity/getInfo` // 商机详情
 
-export const SELL_AND_OBTAIN_RELATED_PRODUCTS = `/order/productWithOrder` // 销售订单关联产品
+export const SELL_AND_OBTAIN_RELATED_PRODUCTS = `/order/productWithOrder` // 销售订单关联产品

+ 10 - 12
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/moduleList/moduleList.vue

@@ -20,7 +20,7 @@
                   <van-swipe-cell>
                     <div class="bg-white px-5 py-5 flex items-center flex-row w-full listContent">
                       <div class="listOfImages items-justify-center rounded-full overflow-hidden bg-[#FFEEEC]">
-                        图片
+                        <img :src="queryParameters.homeImage" class="w-full h-full">
                       </div>
                       <div class="flex-1 h-full">
                         <!-- 商机 -->
@@ -44,9 +44,8 @@
                     <template #right>
                       <div class="flex items-center h-full bg-white">
                         <template v-for="subItem in popUpWindowArray">
-                          <div class="buttonCircle rounded-full items-justify-center text-white"
-                            :style="`background-color: ${subItem.bg}`" @click="longPress(item, subItem)">
-                            按钮
+                          <div class="buttonCircle rounded-full items-justify-center text-white" @click="longPress(item, subItem)">
+                            <img :src="subItem.icon" class="w-full h-full">
                           </div>
                         </template>
                       </div>
@@ -64,9 +63,8 @@
 
       <!-- 可拖拽添加 -->
       <DragBox>
-        <div class="addButton backgroundThemeColor rounded-full flex items-center justify-center text-white"
-          @click="toAddEditor()">
-          添加
+        <div class="addButton" @click="toAddEditor()">
+          <img src="/src/assets/image/add.png" class="w-full h-full" />
         </div>
       </DragBox>
 
@@ -114,10 +112,10 @@ const searchVal = ref()
 const queryParameters = ref({})
 const loadingList = ref(false)
 const popUpWindowArray = ref([
-  { text: '转移', event: TRANSFER, bg: '#FFA359', removeModule: ['contacts', 'tasks', 'product', 'contract', 'order'] },
-  { text: '顶置', event: TOP_MOUNTED, bg: '#075985', removeModule: [] },
-  { text: '编辑', event: EDIT, bg: '#07C160', removeModule: [] },
-  { text: '删除', event: DELETE, bg: '#FF6A6A', removeModule: [] },
+  { text: '转移', event: TRANSFER, icon: '/src/assets/image/transfer.png', removeModule: ['contacts', 'tasks', 'product', 'contract', 'order'] },
+  { text: '顶置', event: TOP_MOUNTED, icon: '/src/assets/image/topMounted.png', removeModule: [] },
+  { text: '编辑', event: EDIT, icon: '/src/assets/image/edit.png', removeModule: [] },
+  { text: '删除', event: DELETE, icon: '/src/assets/image/delete.png', removeModule: [] },
 ])
 const showSelect = ref(false)
 const showDialog = ref(false)
@@ -365,7 +363,7 @@ useLifecycle({
   }
 }
 
-.headerModeuleList  ::v-deep .van-search__content {
+.headerModeuleList  :deep(.van-search__content) {
   background: #fff !im\portant;
   height: 42px;
   align-items: center;

+ 172 - 22
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/tabbar/home/component/workbench.vue

@@ -2,20 +2,62 @@
   <div class="w-full h-full workbench">
     <!-- 日历 -->
     <div class="w-full p16 backgroundThemeColor rounded-b-lg setCaleStrle">
-      <van-calendar switch-mode="year-month" :show-title="false" :show-mark="false" :poppable="false" :show-confirm="false" :row-height="'3rem'" :min-date="minDate" :style="{ borderRadius: '0.3rem' }">
+      <van-calendar :default-date="(new Date(dateConditions))" switch-mode="year-month" :show-title="false" :show-mark="false" :poppable="false"
+        :show-confirm="false" :row-height="'3rem'" :min-date="minDate" :style="{ borderRadius: '0.3rem' }" @select="calendarSelect">
         <template #month-title></template>
       </van-calendar>
     </div>
 
     <!-- 日程安排 -->
-    <div class="h-52 overflow-y-auto mt-5">
+    <div class="min-h-52 overflow-y-auto mt-5">
       <!-- 有数据的情况 -->
-      <div></div>
+      <div class="w-full h-full flex flex-col items-center" v-if="visitorProgramList.length">
+        <div class="w-full overflow-y-auto max-h-72 px-5 mb-5">
+          <template v-for="item in visitorProgramList">
+            <van-swipe-cell>
+              <div class="bg-[#FFA35919] ra6 p-4 mb-4" @click="jumpToVisitorDetails(item)">
+                <div class="w-full flex items-center justify-between">
+                  <div class="text-size-in font-bold text-[#474A56]">{{ item.planName }}</div>
+                  <div :class="`labelTag ${item.finishState == 0 ? 'toBeCompleted' : 'completed'}`">{{ ['未完成', '已完成'][item.finishState] }}</div>
+                </div>
+                <div class="w-full flex items-center justify-between mt-4">
+                  <div class="text-[#505050]" style="width: 62%;">拜访目的: {{ item.visitGoalName }}</div>
+                  <div class="w-1/3 text-[#505050] flex items-center" style="width: 38%;">
+                    <van-icon name="user-circle-o" class="text-size-in mr-2" />
+                    {{ item.customName }}
+                  </div>
+                </div>
+                <div class="w-full flex items-center justify-between mt-4">
+                  <div class="w-2/3 text-[#505050]" style="width: 62%;">拜访时间: {{ item.visitTime }}</div>
+                  <div class="w-1/3 text-[#505050] flex items-center" style="width: 38%;">
+                    <van-icon name="phone-o" class="text-size-in mr-2" />
+                    {{ item.telPhone }}
+                  </div>
+                </div>
+              </div>
+
+              <template #right>
+                <div class="flex items-center flex-col justify-around h-full bg-[#F9F0E9] ra-l6 py-4">
+                  <div class="buttonCircle text-white" @click.stop="jumpToAddNewVisitors(item)">
+                    <img src="/src/assets/image/edit.png" class="w-full h-full">
+                  </div>
+                  <div class="buttonCircle text-white" @click.stop="deleteVisitor(item)">
+                    <img src="/src/assets/image/delete.png" class="w-full h-full">
+                  </div>
+                </div>
+              </template>
+            </van-swipe-cell>
+          </template>
+        </div>
+        <van-button type="primary" icon="add-o" class="m-auto w-3/5" @click="jumpToAddNewVisitors()">新增计划</van-button>
+      </div>
       <!-- 没有数据的情况下 -->
-      <div class="w-full h-full flex flex-col items-center justify-center">
-        <div class="schedulePicture bg-black mb-5"></div>
+      <div class="w-full h-full flex flex-col items-center justify-center" v-if="!visitorProgramList.length">
+        <div class="schedulePicture mb-5">
+          <img class="w-full h-full" src="/src/assets/image/schedule.png">
+        </div>
         <div class="text-center text-[#C4C4C4] mb-5">您今天还没安排日程哦!</div>
-        <van-button type="primary" class="m-auto w-3/5">马上安排</van-button>
+        <van-button type="primary" class="m-auto w-3/5" @click="jumpToAddNewVisitors()">马上安排</van-button>
       </div>
     </div>
 
@@ -24,15 +66,19 @@
       <div class="text-size-large text-[#000] pl16">常用表单</div>
       <div class="p16 pt-0 pb-0 flex justify-between overflow-x-auto">
         <div class="flex">
-          <template v-for="(item, index) in 10">
+          <template v-for="item in commonModulesList">
             <div class="w80 bg-[#FFA359] h-28 rounded-md flex flex-col items-center justify-center">
-              <div class="formImage"></div>
-              <div class="text-white">表单{{ index }}</div>
+              <div class="formImage">
+                <img class="w-full h-full" src="/src/assets/image/form.png">
+              </div>
+              <div class="text-white">{{ item.moduleName }}</div>
             </div>
           </template>
-          
+
           <div class="w80 bg-[#357AF4] h-28 rounded-md flex flex-col items-center justify-center">
-            <div class="formImage"></div>
+            <div class="formImage">
+              <img class="w-full h-full" src="/src/assets/image/more.png">
+            </div>
             <div class="text-white">更多</div>
           </div>
         </div>
@@ -43,11 +89,15 @@
     <div class="mt-3">
       <div class="text-size-large text-[#000] pl16">常用联系人</div>
       <div class="p16 pt-0 pb-0">
-        <template v-for="item in 10">
+        <template v-for="item in topContactsList">
           <div class="flex flex-row items-center rounded-md p-4 bg-white mb-5">
-            <div class="contactImage"></div>
-            <div class="flex-1">张三</div>
-            <div class="rightArrow"></div>
+            <div class="contactImage">
+              <img class="w-full h-full" src="/src/assets/image/topContacts.png">
+            </div>
+            <div class="flex-1">{{ item.name }}</div>
+            <div class="rightArrow">
+              <van-icon name="arrow" />
+            </div>
           </div>
         </template>
       </div>
@@ -57,14 +107,86 @@
 
 <script setup>
 import { ref } from 'vue';
+import { showConfirmDialog } from 'vant';
 import { useLifecycle } from '@hooks/useCommon.js';
+import { DELETE_VISITOR_PLAN, GET_VISITOR_PLAN, GET_FREQUENTLY_USED_CONTACTS, GET_COMMONLY_USED_MODULES } from "@hooks/useApi";
 import dayjs from 'dayjs';
+import requests from "@common/requests";
+import useRouterStore from "@store/useRouterStore.js";
 
+const router = useRouterStore()
+const dateConditions = ref(dayjs().format('YYYY-MM-DD'))
 const minDate = ref(new Date('2024-01-01'))
+const visitorProgramList = ref([])
+const topContactsList = ref([])
+const commonModulesList = ref([])
+
+function deleteVisitor(row) {
+  const { id } = row
+  showConfirmDialog({
+    title: `删除访客`,
+    message: `确定删除【访客名称】访客吗?`,
+  }).then(() => {
+    requests.post(DELETE_VISITOR_PLAN, { planId: id }).then((res) => {
+      toastSuccess('删除成功')
+      getVisitorPlan()
+    }).catch((err) => {
+      toastFail(err.msg ? err.msg : '删除失败')
+    })
+  })
+}
+
+function calendarSelect(data) {
+  dateConditions.value = dayjs(data).format("YYYY-MM-DD");
+  getVisitorPlan()
+}
+
+function jumpToVisitorDetails(row) {
+  router.navigateTo({
+    pathName: 'visitorDetails',
+    success: () => {
+      router.emit('visitorDetailsParameter', {
+        row: JSON.stringify(row || {})
+      })
+    }
+  })
+}
+
+function jumpToAddNewVisitors(row) {
+  router.navigateTo({
+    pathName: 'addEditorVisitor',
+    success: () => {
+      router.emit('addEditorVisitorParameter', {
+        row: JSON.stringify(row || {})
+      })
+    }
+  })
+}
+
+function getVisitorPlan() {
+  requests.post(GET_VISITOR_PLAN, { calenderDate: dateConditions.value }).then((res) => {
+    visitorProgramList.value = res.data.records || []
+  })
+}
+
+function getFrequentlyUsedContacts() {
+  requests.post(GET_FREQUENTLY_USED_CONTACTS, {}).then((res) => {
+    topContactsList.value = res.data
+  })
+}
+
+function getCommonlyUsedModules() {
+  requests.post(GET_COMMONLY_USED_MODULES, {}).then((res) => {
+    commonModulesList.value = res.data
+  })
+}
 
 useLifecycle({
   load: () => {
     // 添加加载逻辑
+    getVisitorPlan()
+    getCommonlyUsedModules()
+    getFrequentlyUsedContacts()
   }
 });
 </script>
@@ -78,40 +200,68 @@ useLifecycle({
   padding-left: 16px;
 }
 
+.ra-l6 {
+  border-top-left-radius: 6px;
+  border-top-right-radius: 6px;
+}
+
 .w80 {
   width: 80px;
   margin-right: 12px;
 }
 
+.toBeCompleted {
+  background: rgba($color: #F38B3C, $alpha: .1);
+  border-color: #F38B3C;
+  color: #F38B3C;
+}
+
+.completed {
+  background: rgba($color: #07C160, $alpha: .1);
+  border-color: #07C160;
+  color: #07C160;
+}
+
+.labelTag {
+  font-size: 10px;
+  padding: 3px 8px;
+  border-radius: 4px;
+  border: 1px solid;
+}
+
 .formImage {
   width: 24px;
   height: 24px;
   margin-bottom: 12px;
-  background: #000;
 }
 
 .contactImage {
   width: 29px;
   height: 29px;
   border-radius: 50%;
-  background: #000;
   margin-right: 12px;
 }
 
 .rightArrow {
-  width: 24px;
-  height: 27px;
-  background: #000;
+  font-size: 16px;
 }
 
 .schedulePicture {
   width: 48px;
   height: 51px;
 }
-.setCaleStrle ::v-deep .van-calendar__month-title {
+
+.buttonCircle {
+  width: 37px;
+  height: 37px;
+  margin: 0 14px;
+}
+
+.setCaleStrle :deep(.van-calendar__month-title) {
   display: none;
 }
-.setCaleStrle ::v-deep .van-calendar__month {
+
+.setCaleStrle :deep(.van-calendar__month) {
   padding: 0.8rem 0 0.5rem 0;
 }
 </style>

+ 27 - 6
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/tabbar/home/index.vue

@@ -1,10 +1,13 @@
 <template>
   <Page styleReset="headerClass">
     <template v-slot:headerLeft>
-      <div class="text-white">客户管家</div>
+      <div class="homeheaderleft">
+        <img src="/src/assets/image/home_logo.png">
+        <div class="text-white">客户管家</div>
+      </div>
     </template>
     <template v-slot:headerRight>
-      <div class="newButton" @click="showModule = true">新建</div>
+      <div class="newButton" @click="showModule = true">新建</div>
     </template>
 
     <template v-slot:body>
@@ -36,7 +39,9 @@
           <div class="flex flex-wrap">
             <template v-for="(item) in moduleList" :key="item.id">
               <div class="w-16 flex flex-col items-center mrSpacing" @click.stop="toAddEditor(item)">
-                <div class="newModuleImage"></div>
+                <div class="newModuleImage">
+                  <img class="w-full h-full" :src="returnImageAddress(item)" alt="">
+                </div>
                 <div class="mt-3 text-[#474A56]">{{ item.name }}</div>
               </div>
             </template>
@@ -80,6 +85,11 @@ function toAddEditor(rows) {
   })
 }
 
+function returnImageAddress(rows) {
+  const row = routingInfos[rows.path.replace('/', '')]
+  return row.homeImage
+}
+
 useLifecycle({
   load: () => {
 
@@ -90,13 +100,25 @@ useLifecycle({
 </script>
 
 <style lang="scss" scoped>
-::v-deep .van-tabs__content {
+:deep(.van-tabs__content) {
   flex: 1;
   overflow-y: auto;
 }
-::v-deep .van-tabs__wrap {
+:deep(.van-tabs__wrap) {
   background-color: $themeColor;
 }
+.homeheaderleft {
+  font-size: 20px;
+  font-weight: bold;
+  display: flex;
+  align-items: center;
+  img {
+    width: 30px;
+  }
+  div {
+    margin-left: 10px;
+  }
+}
 .newButton {
   width: 86px;
   line-height: 30px;
@@ -130,7 +152,6 @@ useLifecycle({
   width: 50px;
   height: 50px;
   border-radius: 10px;
-  background: #000;
 }
 .mrSpacing {
   margin-top: 16px;

+ 39 - 5
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/tabbar/work/index.vue

@@ -1,11 +1,12 @@
 <template>
   <Page title="工作">
     <template v-slot:body>
-      <div class="w-full h-full flex items-center">
-        <div class="w-3/4 h-3/4 m-auto flex flex-wrap items-center" @click.stop>
-          <div class="text-gray-950 w-1/2 text-center" v-for="(item) in moduleList" :key="item.id"
+      <div class="w-full h-full">
+        <div class="workLayout" @click.stop>
+          <div class="text-gray-950 text-center modulistImage" v-for="(item) in moduleList" :key="item.id"
             @click.stop="toModuleList(item)">
-            {{ item.name }}
+            <img :src="returnImageAddress(item)"  />
+            <div class="modulistText">{{ item.name }}</div>
           </div>
         </div>
       </div>
@@ -41,10 +42,43 @@ function toModuleList(item) {
   })
 }
 
+function returnImageAddress(rows) {
+  const row = routingInfos[rows.path.replace('/', '')]
+  return row.moduleImage
+}
+
 useLifecycle({
   load: () => {
   }
 });
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.workLayout {
+  margin: 20px;
+  padding-bottom: 20px;
+  overflow: auto;
+  background-color: #fff;
+  border-radius: 8px;
+  display: flex;
+  flex-wrap: wrap;
+}
+.modulistImage {
+  width: 140px;
+  height: 140px;
+  position: relative;
+  margin-left: 18px;
+  margin-top: 18px;
+  img {
+    width: 100%;
+    height: 100%;
+  }
+
+  .modulistText {
+    position: absolute;
+    font-size: 18px;
+    top: 20px;
+    left:  16px;
+  }
+}
+</style>

+ 333 - 0
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/visitorProgram/addEditorVisitor.vue

@@ -0,0 +1,333 @@
+<template>
+  <Page :title="`${addOrEdit ? '编辑' : '新增'}访客计划`">
+    <template v-slot:body>
+      <div class="w-full h-full flex flex-col">
+        <van-form
+          ref="addEditFormRef"
+          show-error
+          :show-error-message="false"
+          label-align="left"
+          input-align="right"
+          class="bg-white flex-1 overflow-y-auto"
+        >
+          <van-field
+            v-model="form.planName"
+            required
+            name="planName"
+            label="计划名称"
+            placeholder="请输入"
+            :rules="[{ required: true, message: '' }]"
+          >
+          </van-field>
+          <van-field
+            v-model="form.customId"
+            is-link
+            readonly
+            required
+            name="customId"
+            label="客户姓名"
+            placeholder="请选择"
+            :rules="[{ required: true, message: '' }]"
+            @click="customerShowPicker = true"
+          >
+            <template #input v-if="form.customId">
+              {{ form.customName }}
+            </template>
+          </van-field>
+          <van-field
+            v-model="form.inchargerId"
+            is-link
+            readonly
+            required
+            name="inchargerId"
+            label="负责人"
+            placeholder="请选择"
+            :rules="[{ required: true, message: '' }]"
+            @click="personnelShowPicker = true"
+          >
+            <template #input v-if="form.inchargerId">
+              {{ form.inchargerName }}
+            </template>
+          </van-field>
+          <van-field
+            v-model="form.visitGoal"
+            is-link
+            readonly
+            required
+            name="visitGoal"
+            label="拜访目的"
+            placeholder="请选择"
+            :rules="[{ required: true, message: '' }]"
+            @click="visitShowPicker = true"
+          >
+            <template #input v-if="form.visitGoal">
+              {{ form.visitGoalName }}
+            </template>
+          </van-field>
+          <van-field
+            v-model="form.visitTime"
+            is-link
+            readonly
+            required
+            name="visitTime"
+            label="拜访时间"
+            placeholder="请选择"
+            :disabled="addOrEdit"
+            :rules="[{ required: true, message: '' }]"
+            @click="showPickerClick('visitTime')"
+          >
+          </van-field>
+          <van-field
+            v-model="form.remindType"
+            class="resetStyles"
+            is-link
+            readonly
+            name="remindType"
+            label="提醒"
+            placeholder="请选择"
+            @click="remindShowPicker = true"
+          >
+            <template #input v-if="form.remindType">
+              {{ form.remindTypeName }}
+            </template>
+          </van-field>
+          <van-field
+            v-model="form.remindTime"
+            v-if="form.remindType == -1"
+            readonly
+            required
+            name="remindTime"
+            label="提醒时间"
+            placeholder="请选择"
+            :disabled="addOrEdit"
+            :rules="[{ required: true, message: '' }]"
+            @click="showPickerClick('remindTime')"
+          >
+          </van-field>
+          <van-field
+            v-model="form.remark"
+            class="resetStyles"
+            type="textarea"
+            name="remark"
+            label="备注"
+            placeholder="请输入"
+          >
+          </van-field>
+        </van-form>
+
+        <div class="flex justify-center mx-5 my-10">
+          <van-button
+            type="primary"
+            block
+            @click="onSubmit"
+            :loading="submitLoading"
+          >
+            保存
+          </van-button>
+        </div>
+      </div>
+      <!-- 日期选择器 -->
+      <van-popup
+        v-model:show="showPicker"
+        destroy-on-close
+        position="bottom"
+        :style="{ height: '50%' }"
+      >
+        <van-date-picker
+          v-model="dateSelectionValue"
+          @confirm="showPickerConfirm"
+          @cancel="showPicker = false"
+        />
+      </van-popup>
+      <!-- 客户选择 -->
+      <van-popup
+        v-model:show="customerShowPicker"
+        destroy-on-close
+        position="bottom"
+        :style="{ height: '80%' }"
+      >
+        <PullDownSelector
+          :options="customerAllList"
+          :doYouNeedTranslation="false"
+          @change="customerSelectChange"
+        />
+      </van-popup>
+      <!-- 人员选择 -->
+      <van-popup
+        v-model:show="personnelShowPicker"
+        destroy-on-close
+        position="bottom"
+        :style="{ height: '80%' }"
+      >
+        <PullDownSelector @change="personnelSelectChange" />
+      </van-popup>
+      <!-- 拜访目的 -->
+      <van-popup
+        v-model:show="visitShowPicker"
+        destroy-on-close
+        position="bottom"
+        :style="{ height: '80%' }"
+      >
+        <PullDownSelector
+          :options="purposeOfVisitList"
+          :doYouNeedTranslation="false"
+          @change="visitSelectChange"
+        />
+      </van-popup>
+      <!-- 提醒时间 -->
+      <van-popup
+        v-model:show="remindShowPicker"
+        destroy-on-close
+        position="bottom"
+        :style="{ height: '80%' }"
+      >
+        <PullDownSelector
+          :options="reminderTimeList"
+          :doYouNeedTranslation="false"
+          @change="remindSelectChange"
+        />
+      </van-popup>
+    </template>
+  </Page>
+</template>
+
+<script setup>
+import { ref } from "vue";
+import { useLifecycle } from "@hooks/useCommon.js";
+import dayjs from "dayjs";
+import { GET_ALL_CUSTOMERS, RETRIEVE_DICTIONARY_ENTRIES } from "@hooks/useApi";
+import requests from "@common/requests";
+import useRouterStore from "@store/useRouterStore.js";
+import useFixedData from "@store/useFixedData.js";
+import PullDownSelector from "@components/common/pullDownSelector.vue";
+
+const router = useRouterStore();
+const fixedData = useFixedData();
+const form = ref({});
+const addEditFormRef = ref()
+const submitLoading = ref(false);
+const showPicker = ref(false);
+const customerShowPicker = ref(false);
+const personnelShowPicker = ref(false);
+const visitShowPicker = ref(false);
+const remindShowPicker = ref(false);
+const customerAllList = ref([]);
+const purposeOfVisitList = ref([]); // 拜访目的
+const reminderTimeList = ref([]); // 提醒时间
+const dateSelectionValue = dayjs(new Date()).format("YYYY-MM-DD").split("-");
+const dateSelectionFiled = ref("");
+const addOrEdit = ref(true); // true 编辑,false 新增
+
+function onSubmit() {
+  addEditFormRef.value.validate().then((res) => {
+    const data = addEditFormRef.value.getValues()
+    submitLoading.value = true
+    requests.post(PLAN_TO_ADD_EDITORS, { ...data }).then(() => {
+      toastSuccess("保存成功")
+      setTimeout(() => {
+        history.back();
+      }, 2000)
+    }).catch(err => {
+      toastFail(`保存失败:${err.message}`)
+    }).finally(() => {
+      submitLoading.value = false
+    })
+  })
+}
+
+function customerSelectChange(value, label) {
+  form.value = { ...form.value, customId: value, customName: label };
+  customerShowPicker.value = false;
+}
+
+function personnelSelectChange(value, label) {
+  form.value = {
+    ...form.value,
+    inchargerId: value,
+    inchargerName: label,
+  };
+  personnelShowPicker.value = false;
+}
+
+function visitSelectChange(value, label) {
+  form.value = {
+    ...form.value,
+    visitGoal: value,
+    visitGoalName: label,
+  };
+  visitShowPicker.value = false;
+}
+
+function remindSelectChange(value, label) {
+  form.value = { ...form.value, remindType: value, remindTypeName: label };
+  remindShowPicker.value = false;
+}
+
+function showPickerConfirm({ selectedValues }) {
+  form.value[dateSelectionFiled.value] = selectedValues.join("-");
+  showPicker.value = false;
+}
+
+function showPickerClick(filed) {
+  (dateSelectionValue.value = form.value[filed]
+    ? form.value[filed]
+    : dayjs(new Date()).format("YYYY-MM-DD").split("-")),
+    (dateSelectionFiled.value = filed);
+  showPicker.value = true;
+}
+
+function processingDataSource(data) {
+  const row = JSON.parse(data.row);
+  addOrEdit.value = Object.keys(row).length > 0 ? true : false;
+  obtainThePurposeOfTheVisit();
+  getReminderTime();
+  getAllCustomers();
+}
+
+function getAllCustomers() {
+  requests.post(GET_ALL_CUSTOMERS, {}).then((res) => {
+    customerAllList.value = res.data.map((item) => {
+      return {
+        label: item.customName,
+        value: item.id,
+      };
+    });
+  });
+}
+
+function obtainThePurposeOfTheVisit() {
+  requests.get(`${RETRIEVE_DICTIONARY_ENTRIES}?code=VisitGoal`).then((res) => {
+    purposeOfVisitList.value = res.data.map((item) => {
+      return {
+        label: item.name,
+        value: item.id,
+      };
+    });
+  });
+}
+
+function getReminderTime() {
+  requests.get(`${RETRIEVE_DICTIONARY_ENTRIES}?code=RemindType`).then((res) => {
+    let list = res.data.map((item) => {
+      return {
+        label: item.name,
+        value: item.id,
+      };
+    });
+    list.push({ value: -1, label: "自定义时间" });
+    reminderTimeList.value = list;
+  });
+}
+
+useLifecycle({
+  load: () => {
+    router.on("addEditorVisitorParameter", (data) => {
+      processingDataSource(data);
+    });
+  },
+});
+</script>
+
+<style lang="scss" scoped>
+/* 样式代码 */
+</style>

+ 165 - 0
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/visitorProgram/visitorDetails.vue

@@ -0,0 +1,165 @@
+<template>
+  <Page title="访客计划详情">
+    <template v-slot:body>
+      <!-- 头部 -->
+      <div class="planDetailsHead">
+        <div class="w-full flex items-center justify-between">
+          <div class="text-size-in font-bold text-[#474A56]">535计划</div>
+          <div :class="`labelTag completed`">待完成</div>
+        </div>
+        <div class="w-full mt-4">拜访目的:建立客情</div>
+        <div class="w-full mt-4">拜访时间:2021-08-05 14:00</div>
+        <div class="line"></div>
+        <div class="w-full flex items-center">
+          <van-icon name="user-circle-o" class="text-size-in mr-2" />
+          客户:
+          <div class="ml-2 themeTextColor decoration-auto underline">苹果集团</div>
+        </div>
+      </div>
+
+      <!-- 主体 -->
+      <van-cell-group>
+        <van-cell title="计划名称" value="内容" />
+        <van-cell title="客户姓名" value="内容" />
+        <van-cell title="负责人" value="内容" />
+        <van-cell title="拜访目的" value="内容" />
+        <van-cell title="拜访时间" value="内容" />
+        <van-cell title="提醒" value="内容" />
+        <van-cell title="提醒时间" value="内容" />
+        <van-cell title="备注" value="内容" />
+      </van-cell-group>
+      <div class="h-10"></div>
+    </template>
+
+    <template v-slot:footer>
+      <div class="w-full flex justify-between layout">
+        <div class="footerBtnLeft layouts">
+          <div class="imgClss"></div>
+          联系人
+        </div>
+        <div class="footerBtnRight layouts">
+          <div class="imgClss"></div>
+          延期
+        </div>
+        <div class="coverWithWhite"></div>
+        <div class="bigCircle">
+          <div class="imgClss"></div>
+          完成
+        </div>
+      </div>
+    </template>
+  </Page>
+</template>
+
+<script setup>
+import { ref } from "vue";
+import { useLifecycle } from "@hooks/useCommon.js";
+
+useLifecycle({
+  load: () => {
+    // 添加加载逻辑
+  },
+});
+</script>
+
+<style lang="scss" scoped>
+.planDetailsHead {
+  background: #ffa35919;
+  padding: 14px 18px;
+  margin: 10px;
+
+  .toBeCompleted {
+    background: rgba($color: #f38b3c, $alpha: 0.1);
+    border-color: #f38b3c;
+    color: #f38b3c;
+  }
+
+  .completed {
+    background: rgba($color: #07c160, $alpha: 0.1);
+    border-color: #07c160;
+    color: #07c160;
+  }
+
+  .labelTag {
+    font-size: 10px;
+    padding: 3px 8px;
+    border-radius: 4px;
+    border: 1px solid;
+  }
+
+  .line {
+    width: 100%;
+    height: 1px;
+    background-color: #E6D3C7;
+    margin: 14px 0;
+  }
+}
+.layout {
+  height: 90px;
+  position: relative;
+  .layouts {
+    width: 40%;
+    height: 100%;
+    background: #fff;
+    box-shadow: 0px -2px 30px 0px #00000014;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+  }
+
+  .footerBtnLeft {
+    border-top-right-radius: 25px;
+    .imgClss {
+      width: 30px;
+      height: 30px;
+      background-color: #000;
+      margin-bottom: 6px;
+    }
+  }
+  .footerBtnRight {
+    border-top-left-radius: 25px;
+    .imgClss {
+      width: 26px;
+      height: 24px;
+      background-color: #000;
+      margin-bottom: 9px;
+    }
+  }
+
+  .coverWithWhite {
+    width: 20%;
+    background: #fff;
+    position: absolute;
+    bottom: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    height: 70px;
+    z-index: 1;
+  }
+
+  .bigCircle{
+    width: 80px;
+    height: 80px;;
+    border-radius: 50%;
+    background: $themeColor;
+    box-shadow: 0px -2px 30px 0px #00000014;
+    position: absolute;
+    bottom: 27px;
+    left: 50%;
+    transform: translateX(-50%);
+    z-index: 2;
+    color: #fff;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex-direction: column;
+    .imgClss {
+      width: 25.5px;
+      height: 25.5px;
+      margin-bottom: 4px;
+      background: #000;
+    }
+  }
+}
+</style>

+ 10 - 0
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/router.js

@@ -47,6 +47,16 @@ const routes = [
         name: 'addEditor',
         meta: { title: '模块新增编辑' },
         component: () => import("@pages/addEditor/index.vue"),
+    }, {
+        path: '/addEditorVisitor',
+        name: 'addEditorVisitor',
+        meta: { title: '新增编辑访客计划' },
+        component: () => import("@pages/visitorProgram/addEditorVisitor.vue"),
+    }, {
+        path: '/visitorDetails',
+        name: 'visitorDetails',
+        meta: { title: '访客计划详情' },
+        component: () => import("@pages/visitorProgram/visitorDetails.vue"),
     }, {
         path: '/:pathMatch(.*)*',
         name: 'notFound',

+ 16 - 0
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/utility/generalVariables.js

@@ -9,6 +9,8 @@ export const routingInfos = {
     deteleFiled: DELETE_BUSINESS_OPPORTUNITY, // 删除请求接口
     transferInterface: BUSINESS_OPPORTUNITY_TRANSFER, // 转移请求接口
     addEditingInterface: NEW_BUSINESS_OPPORTUNITY_EDITING, // 新增/编辑请求接口
+    homeImage: '/src/assets/image/module/min_business.png', // 首页图片
+    moduleImage: '/src/assets/image/module/business.png', // 模块图片
     searchFiled: { search: 'name' }, // 搜索字段
     image: '', // 图片
   },
@@ -20,6 +22,8 @@ export const routingInfos = {
     deteleUrl: DELETE_CLUES,
     transferInterface: TRANSFER_CLUES,
     addEditingInterface: NEW_CLUE_EDITING,
+    homeImage:  '/src/assets/image/module/min_thread.png',
+    moduleImage: '/src/assets/image/module/thread.png',
     searchFiled: { search: 'clueName' },
     image: '',
   },
@@ -31,6 +35,8 @@ export const routingInfos = {
     deteleFiled: DELETE_CUSTOMER,
     transferInterface: TRANSFER_CUSTOMERS,
     addEditingInterface: CUSTOMER_ADDED_EDITOR,
+    homeImage:  '/src/assets/image/module/min_customer.png',
+    moduleImage: '/src/assets/image/module/customer.png',
     searchFiled: { search: 'customName' },
     image: '',
   },
@@ -42,6 +48,8 @@ export const routingInfos = {
     deteleFiled: DELETE_CONTACTS,
     transferInterface: '',
     addEditingInterface: CONTACT_PERSON_ADDITION_EDITOR,
+    homeImage:  '/src/assets/image/module/min_contacts.png',
+    moduleImage: '/src/assets/image/module/contacts.png',
     searchFiled: { search: 'name' },
     image: '',
   },
@@ -53,6 +61,8 @@ export const routingInfos = {
     deteleFiled: DELETE_TASK,
     transferInterface: '',
     addEditingInterface: TASK_ADD_EDIT,
+    homeImage:  '/src/assets/image/module/min_tasks.png',
+    moduleImage: '/src/assets/image/module/tasks.png',
     searchFiled: { search: 'taskName' },
     image: '',
   },
@@ -64,6 +74,8 @@ export const routingInfos = {
     deteleFiled: DELETE_PRODUCT,
     transferInterface: '',
     addEditingInterface: PRODUCT_ADD_EDITOR,
+    homeImage:  '/src/assets/image/module/min_product.png',
+    moduleImage: '/src/assets/image/module/product.png',
     searchFiled: { search: 'productName' },
     image: '',
   },
@@ -75,6 +87,8 @@ export const routingInfos = {
     deteleFiled: DELETE_CONTRACT,
     transferInterface: '',
     addEditingInterface: CONTRACT_ADDITION_EDITING,
+    homeImage:  '/src/assets/image/module/min_contract.png',
+    moduleImage: '/src/assets/image/module/contract.png',
     searchFiled: { search: 'name' },
     image: '',
   },
@@ -86,6 +100,8 @@ export const routingInfos = {
     deteleFiled: DELETE_ORDER,
     transferInterface: '',
     addEditingInterface: ORDER_ADDITION_EDITING,
+    homeImage:  '/src/assets/image/module/min_order.png',
+    moduleImage: '/src/assets/image/module/order.png',
     searchFiled: { search: 'orderName' },
     image: '',
   }