Lijy 4 mesiacov pred
rodič
commit
3b44f39295

+ 9 - 2
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/components/page/footer.vue

@@ -1,7 +1,12 @@
 <template>
   <div class="w-full bg-white">
     <van-tabbar v-model="currentRouteName" safe-area-inset-bottom :fixed="false" @change="toPath">
-      <van-tabbar-item :name="item.pathName" :icon="item.icon" v-for="item in tabBarOption">{{ item.title }}</van-tabbar-item>
+      <template v-for="item in tabBarOption">
+        <van-tabbar-item :name="item.pathName" :icon="item.icon" v-if="item.pathName != 'news'">{{ item.title
+          }}</van-tabbar-item>
+        <van-tabbar-item :name="item.pathName" :icon="item.icon"
+          :badge="userInfo.numberOfMessages" v-else>{{ item.title }}</van-tabbar-item>
+      </template>
     </van-tabbar>
   </div>
 </template>
@@ -11,18 +16,20 @@ import { ref, onActivated } from 'vue';
 import { useRoute } from 'vue-router'
 import { useLifecycle } from '@hooks/useCommon.js';
 import useRouterStore from "@store/useRouterStore.js";
+import useInfoStore from "@store/useInfoStore.js";
 import tabBarOption from "../../tabBar"
 
 const route = useRoute()
 const router = useRouterStore()
 const currentRouteName = ref(route.name)
+const userInfo = useInfoStore()
 
 function toPath(name) {
   router.switchTabBar({ pathName: name })
 }
 
 useLifecycle({
-  load: () => { 
+  load: () => {
     currentRouteName.value = route.name
   }
 });

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

@@ -16,6 +16,8 @@ export const GET_ALL_CUSTOMERSLIST = `/custom/getAll` // 获取所有客户列
 export const GET_TASK_LIST = '/tasks/pageTask' // 获取任务列表
 export const GET_PRODUCT_LIST = '/product/list' // 获取产品列表
 export const GET_CONTRACT_LIST = '/contract/getContractPage' // 获取合同列表
+export const GET_PLAN_CALENDAR = `/visitPlan/getMonthActivePlan` // 获取计划日历
+
 export const GET_SALES_ORDER_LIST = '/order/list' // 获取销售订单列表
 export const GET_VISITOR_PLAN = `/visitPlan/getVisitPlanList` // 获取访客计划
 export const GET_FREQUENTLY_USED_CONTACTS = `/contacts/getFrequentContacts` // 获取常用联系人
@@ -53,8 +55,15 @@ export const OBTAIN_PRODUCT_RELATED_BUSINESS_OPPORTUNITIES = `/product/businessL
 export const OBTAIN_SALES_ORDERS_RELATED_TO_THE_PRODUCT = `/product/orderWithProduct` // 获取产品关联销售订单
 export const GET_ORDER_RELATED_TASKS = `/order/taskWithOrder` // 获取销售订单关联任务
 export const OBTAIN_ORDER_RELATED_PRODUCTS = `/order/productWithOrder` // 获取销售订单关联产品
+export const OBTAIN_DETAILS_OF_THE_VISIT_PLAN = `/visitPlan/getVisitPlanDetail` // 获取访客计划详情
 
 export const SELL_AND_OBTAIN_RELATED_PRODUCTS = `/product/orderWithProduct` // 销售订单关联产品
 
 export const GET_CONTACTS_WITH_MORE_I_DS = `/contacts/getAllContacts` // 更具Id获取联系人
-export const CONTACT_PERSON_ASSOCIATED_WITH_BUSINESS_OPPORTUNITY = `/business-opportunity/saveContactsId` // 联系人关联商机
+export const CONTACT_PERSON_ASSOCIATED_WITH_BUSINESS_OPPORTUNITY = `/business-opportunity/saveContactsId` // 联系人关联商机
+export const POSTPONE_THE_VISIT_PLAN = `/visitPlan/delayVisitPlan` // 延期访客计划
+export const COMPLETE_THE_VISIT_PLAN = `/visitPlan/finishVisitPlan` // 完成访客计划
+export const SAVE_COMMONLY_USED_FORMS = `/userCommonModule/addOrUpdateCommonModules` // 保存常用表单
+export const GET_MESSAGE_LIST = `/information/list` // 获取消息列表
+export const READ_MESSAGE = `/information/check` // 已读消息`
+export const ONE_CLICK_READ = `/information/checkAll` // 一键已读`

+ 13 - 2
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/login.vue

@@ -17,7 +17,7 @@
 <script setup>
 import { ref } from "vue";
 import { useLifecycle } from "@hooks/useCommon.js";
-import { LOGIN_INTERFACE, USER_ID_LOGIN, WE_CHAT_LOGIN } from "@hooks/useApi.js";
+import { LOGIN_INTERFACE, USER_ID_LOGIN, WE_CHAT_LOGIN, GET_MESSAGE_LIST } from "@hooks/useApi.js";
 import { addressRedirection, obtainEnterpriseWeChatParameters } from "@utility/corpWXparam"
 import useShowToast from "../hooks/useToast";
 import useRouterStore from "@store/useRouterStore.js";
@@ -142,14 +142,25 @@ function loginProcessing(data = {}) {
   router.switchTabBar({
     pathName: 'home',
     success: function () {
-      if(isCorpWX.value) {
+      if (isCorpWX.value) {
         obtainEnterpriseWeChatParameters(data)
       }
       toastSuccess('登陆成功')
+      setTimeout(() => {
+        getMessageList()
+      }, 500)
     }
   })
 }
 
+function getMessageList() {
+  requests.post(GET_MESSAGE_LIST, {}).then(({ data = [] }) => {
+    userInfo.updateState({
+      numberOfMessages: data.filter((item) => !item.checked)?.length || ''
+    })
+  })
+}
+
 function separateRouting(list = []) {
   return (list || []).filter(item => item.isMenu && !(['/team', '/system', '/analysis', '/corpreport'].includes(item.path)))
 }

+ 2 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/contacts/detail.vue

@@ -41,6 +41,7 @@ watch(() => props.info, (newValue) => {
 
 function getDetailedData(id) {
   requests.post(GET_CONTACT_DETAILS, { id }).then(({ data }) => {
+    props.info = data
     relatedBusinessOpportunitiesList.value = data.businessOpportunityList || []
     relatedTasksList.value = data.taskList || []
   })
@@ -53,7 +54,7 @@ function processingData(id) {
 useLifecycle({
   init: () => {
     tabActive.value = '联系人信息';
-    processingData(props.info.id)
+    processingData(props.info.id || props.info.customId)
   }
 });
 </script>

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

@@ -2,10 +2,20 @@
   <div class="w-full h-full workbench">
     <!-- 日历 -->
     <div class="w-full p16 backgroundThemeColor rounded-b-lg setCaleStrle">
-      <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">
+      <van-calendar ref="calendarRef" :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', height: expandAndCollapse ? (calendarHeight ? calendarHeight + 'px' : 'auto') : usePxToVwView(140) }"
+        :formatter="formatter" @select="calendarSelect">
         <template #month-title></template>
+        <template #bottom-info="day">
+          <div class="doT" v-if="day?.bottomInfo"></div>
+        </template>
       </van-calendar>
+      <div class="flex justify-center" @click="expandAndCollapseClick">
+        <van-icon name="arrow-double-left" color="#fff" :size="usePxToVwView(20)" class="mt-3 expandAndCollapseIcon"
+          :style="expandAndCollapse ? 'transform: rotate(90deg);' : 'transform: rotate(-90deg);'" />
+      </div>
     </div>
 
     <!-- 日程安排 -->
@@ -18,7 +28,8 @@
               <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 :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>
@@ -75,7 +86,8 @@
             </div>
           </template>
 
-          <div class="w80 bg-[#357AF4] h-28 rounded-md flex flex-col items-center justify-center">
+          <div class="w80 bg-[#357AF4] h-28 rounded-md flex flex-col items-center justify-center"
+            @click="showCommonForms = true">
             <div class="formImage">
               <img class="w-full h-full" src="/src/assets/image/more.png">
             </div>
@@ -90,7 +102,7 @@
       <div class="text-size-large text-[#000] pl16">常用联系人</div>
       <div class="p16 pt-0 pb-0">
         <template v-for="item in topContactsList">
-          <div class="flex flex-row items-center rounded-md p-4 bg-white mb-5">
+          <div class="flex flex-row items-center rounded-md p-4 bg-white mb-5" @click="toContactDetails(item)">
             <div class="contactImage">
               <img class="w-full h-full" src="/src/assets/image/topContacts.png">
             </div>
@@ -102,26 +114,111 @@
         </template>
       </div>
     </div>
+
+    <!-- 添加常用表单 -->
+    <van-popup v-model:show="showCommonForms" closeable destroy-on-close position="bottom" :style="{ height: '80%' }">
+      <div class="px-5 flex flex-col h-full py-8">
+        <div class="flex-1 overflow-y-auto">
+          <div class="text-size-large mb-5">已添加表单</div>
+          <div class="flex flex-wrap mb-2">
+            <template v-for="(item) in commonExpressionsHaveBeenAdded" :key="item.id">
+              <div class="w-1/4 flex flex-col items-center mb-4 relative">
+                <div class="newModuleImage">
+                  <img class="w-full h-full" :src="returnImageAddress(item)" alt="">
+                </div>
+                <div class="mt-3 text-[#474A56]">{{ item.name }}</div>
+                <div class="absolute -top-2 right-3" @click="operationForm('delete', item)">
+                  <van-icon name="clear" color="#EE0A24" :size="`${usePxToVwView(20)}`" />
+                </div>
+              </div>
+            </template>
+          </div>
+          <div class="text-size-large mb-5">未添加表单</div>
+          <div class="flex flex-wrap mb-2">
+            <template v-for="(item) in commonExpressionsHaveBeenNodded" :key="item.id">
+              <div class="w-1/4 flex flex-col items-center mb-4 relative">
+                <div class="newModuleImage">
+                  <img class="w-full h-full" :src="returnImageAddress(item)" alt="">
+                </div>
+                <div class="mt-3 text-[#474A56]">{{ item.name }}</div>
+                <div class="absolute -top-2 right-3" @click="operationForm('add', item)">
+                  <van-icon name="add" color="#07C160" :size="`${usePxToVwView(20)}`" />
+                </div>
+              </div>
+            </template>
+          </div>
+        </div>
+        <van-button type="primary" @click="saveCommonlyUsedForms()">保存</van-button>
+      </div>
+    </van-popup>
   </div>
 </template>
 
 <script setup>
-import { ref, onActivated } from 'vue';
+import { ref, onActivated, nextTick } 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 { DELETE_VISITOR_PLAN, GET_VISITOR_PLAN, GET_FREQUENTLY_USED_CONTACTS, GET_COMMONLY_USED_MODULES, SAVE_COMMONLY_USED_FORMS, GET_PLAN_CALENDAR } from "@hooks/useApi";
+import { routingInfos } from "@utility/generalVariables.js";
+import usePxToVwView from "@hooks/usePxTransform.js";
 import useToast from "@hooks/useToast"
 import dayjs from 'dayjs';
 import requests from "@common/requests";
 import useRouterStore from "@store/useRouterStore.js";
+import useInfoStore from "@store/useInfoStore.js";
 
 const router = useRouterStore()
+const useInfo = useInfoStore()
 const { toastText, toastSuccess, toastFail, toastLoading } = useToast()
+const expandAndCollapse = ref(true)
+const calendarHeight = ref(0)
+const calendarRef = ref()
 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([])
+const planCalendarList = ref([])
+const showCommonForms = ref(false)
+const commonExpressionsHaveBeenAdded = ref([])
+const commonExpressionsHaveBeenNodded = ref([])
+
+function toContactDetails(item) {
+  router.navigateTo({
+    pathName: 'details',
+    success: () => {
+      router.emit('detailParameter', {
+        routerInfo: JSON.stringify(routingInfos['contacts']),
+        parameter: JSON.stringify(item)
+      })
+    }
+  })
+}
+
+function saveCommonlyUsedForms() {
+  const moduleIds = commonExpressionsHaveBeenAdded.value.map(item => item.id).join(',')
+  requests.post(SAVE_COMMONLY_USED_FORMS, { moduleIds }).then((res) => {
+    toastSuccess('保存成功')
+    getCommonlyUsedModules()
+    showCommonForms.value = false
+  })
+}
+
+function operationForm(type, row) {
+  const itemIndex = commonExpressionsHaveBeenNodded.value.findIndex(item => item.path === row.path);
+  if (type === 'add' && itemIndex !== -1) {
+    const item = commonExpressionsHaveBeenNodded.value.splice(itemIndex, 1)[0];
+    commonExpressionsHaveBeenAdded.value.push(item);
+  }
+
+  if (type === 'delete') {
+    const itemIndex = commonExpressionsHaveBeenAdded.value.findIndex(item => item.path === row.path);
+    if (itemIndex !== -1) {
+      const item = commonExpressionsHaveBeenAdded.value.splice(itemIndex, 1)[0];
+      commonExpressionsHaveBeenNodded.value.push(item);
+    }
+  }
+}
 
 function deleteVisitor(row) {
   const { id, planName } = row
@@ -138,6 +235,14 @@ function deleteVisitor(row) {
   })
 }
 
+function formatter(day) {
+  const { date, bottomInfo } = day
+  const currentDate = dayjs(date).format("YYYY-MM-DD");
+  const rqiList = planCalendarList.value.filter(item => item.ymd === currentDate)
+  day.bottomInfo = rqiList.length > 0 ? true : false
+  return day
+}
+
 function calendarSelect(data) {
   dateConditions.value = dayjs(data).format("YYYY-MM-DD");
   getVisitorPlan()
@@ -165,6 +270,30 @@ function jumpToAddNewVisitors(row) {
   })
 }
 
+function returnImageAddress(rows) {
+  const row = routingInfos[rows.path.replace('/', '')]
+  return row.homeImage
+}
+
+function expandAndCollapseClick() {
+  expandAndCollapse.value = !expandAndCollapse.value
+  const dates = calendarRef.value.getSelectedDate()
+  calendarRef.value.scrollToDate(new Date(dates))
+}
+
+function processForms() {
+  const selectedForm = commonModulesList.value
+  const allFormList = useInfo.modularList || []
+
+  commonExpressionsHaveBeenAdded.value = allFormList.filter(item =>
+    selectedForm.some(arrItem => arrItem.path === item.path)
+  )
+
+  commonExpressionsHaveBeenNodded.value = allFormList.filter(item =>
+    selectedForm.some(arrItem => arrItem.path !== item.path)
+  )
+}
+
 function getVisitorPlan() {
   requests.post(GET_VISITOR_PLAN, { calenderDate: dateConditions.value }).then((res) => {
     visitorProgramList.value = res.data || []
@@ -180,6 +309,14 @@ function getFrequentlyUsedContacts() {
 function getCommonlyUsedModules() {
   requests.post(GET_COMMONLY_USED_MODULES, {}).then((res) => {
     commonModulesList.value = res.data
+    processForms()
+  })
+}
+
+function getPlanCalendarList() {
+  const months = calendarRef.value.getSelectedDate()
+  requests.post(GET_PLAN_CALENDAR, { ym: dayjs(months).format('YYYY-MM') }).then(({ data }) => {
+    planCalendarList.value = data || []
   })
 }
 
@@ -189,6 +326,14 @@ useLifecycle({
     getVisitorPlan()
     getCommonlyUsedModules()
     getFrequentlyUsedContacts()
+    getPlanCalendarList()
+  },
+  init: () => {
+    setTimeout(() => {
+      if (expandAndCollapse.value) {
+        calendarHeight.value = calendarRef.value.$el.offsetHeight
+      }
+    }, 500)
   }
 });
 
@@ -216,6 +361,16 @@ onActivated(() => {
   margin-right: 12px;
 }
 
+.doT {
+  width: 10px;
+  height: 10px;
+  border-radius: 50%;
+  background-color: $themeColor;
+  margin: auto;
+  position: relative;
+  top: 6px;
+}
+
 .toBeCompleted {
   background: rgba($color: #F38B3C, $alpha: .1);
   border-color: #F38B3C;
@@ -263,6 +418,16 @@ onActivated(() => {
   margin: 0 14px;
 }
 
+.newModuleImage {
+  width: 50px;
+  height: 50px;
+  border-radius: 10px;
+}
+
+.expandAndCollapseIcon {
+  transition: 0.5s ease-in-out;
+}
+
 .setCaleStrle :deep(.van-calendar__month-title) {
   display: none;
 }
@@ -270,4 +435,8 @@ onActivated(() => {
 .setCaleStrle :deep(.van-calendar__month) {
   padding: 0.8rem 0 0.5rem 0;
 }
+
+.setCaleStrle :deep(.van-calendar) {
+  transition: 0.5s ease-in-out;
+}
 </style>

+ 47 - 12
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/tabbar/news/index.vue

@@ -1,10 +1,10 @@
 <template>
   <Page title="消息">
     <template v-slot:body>
-      <div v-for="item in 20">
-        <ElementLongPress :row="item" :popUpWindowArray="popUpWindowArray" @longPress="longPress">
-          <div class="p-[10px] bg-white my-[8px]">内容</div>
-        </ElementLongPress>
+      <div v-for="item in messageList">
+        <div class="p-[10px] bg-white my-[8px]" @click="toDetail(item)">
+          <span :class="`${item.checked ? 'text-[#07C160]' : 'themeTextColor'}`">{{ item.msg }}</span>  
+        </div>
       </div>
     </template>
 
@@ -17,18 +17,53 @@
 <script setup>
 import { ref } from "vue";
 import { useLifecycle } from "@hooks/useCommon.js";
-import Footer from "@components/page/footer.vue";
-import ElementLongPress from "@components/common/elementLongPress.vue";
+import { GET_MESSAGE_LIST, ONE_CLICK_READ } from "@hooks/useApi";
+import useShowToast from "@hooks/useToast";
+import useRouterStore from "@store/useRouterStore.js";
+import useInfoStore from "@store/useInfoStore.js";
+import requests from "@common/requests";
+import { routingInfos } from "@utility/generalVariables" 
+const { toastLoading, toastSuccess, toastFail } = useShowToast();
 
-const popUpWindowArray = ref([
-  { text: '删除', event: 'detele' },
-  { text: '新增', event: 'add' },
-  { text: '顶置', event: 'top' },
-])
+const router = useRouterStore()
+const userInfo = useInfoStore()
+
+const messageList = ref([]);
+
+function getMessageList() {
+  requests.post(GET_MESSAGE_LIST, {}).then(({ data = [] }) => {
+    messageList.value = data || []
+    userInfo.updateState({
+      numberOfMessages: data.filter((item) => !item.checked)?.length || ''
+    })
+  })
+}
+
+function toDetail(item) {
+  requests.post(READ_MESSAGE, { id: item.id }).then(() => {
+    getMessageList()
+  })
+  const jumpTo = routingInfos[item.path.replace('/', '')]
+  router.navigateTo({
+    pathName: 'moduleList',
+    success: () => {
+      router.emit('moduleListDetailParameter', {
+        row: JSON.stringify(jumpTo)
+      })
+    }
+  })
+}
+
+// 一键已读
+function oneClickRead() {
+  requests.post(ONE_CLICK_READ, {}).then(() => {
+    getMessageList()
+  })
+}
 
 useLifecycle({
   load: () => {
-
+    getMessageList()
   }
 });
 

+ 122 - 5
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/visitorProgram/visitorDetails.vue

@@ -5,7 +5,8 @@
       <div class="planDetailsHead">
         <div class="w-full flex items-center justify-between">
           <div class="text-size-in font-bold text-[#474A56]">{{ detailedData.planName }}</div>
-          <div :class="`labelTag ${detailedData.finishState == 0 ? 'toBeCompleted' : 'completed'}`">{{ ['未完成', '已完成'][detailedData.finishState] }}</div>
+          <div :class="`labelTag ${detailedData.finishState == 0 ? 'toBeCompleted' : 'completed'}`">{{ ['未完成',
+            '已完成'][detailedData.finishState] }}</div>
         </div>
         <div class="w-full mt-4">拜访目的:{{ detailedData.visitGoalName }}</div>
         <div class="w-full mt-4">拜访时间: {{ detailedData.visitTime }}</div>
@@ -29,20 +30,69 @@
         <van-cell title="备注" :value="detailedData.remark" />
       </van-cell-group>
       <div class="h-10"></div>
+
+      <!-- 弹窗 -->
+      <van-popup v-model:show="showContacts" closeable position="bottom" round>
+        <div class="newModuleAdded relative">
+          <div class="text-size-large text-[#474A56] absolute topTitle">联系人号码</div>
+          <div class="flex flex-col overflow-y-auto boxLxr">
+            <template v-for="item in contactList">
+              <a :href="`tel:+${item.phone}`">
+                <div class="bg-[#F8F8FA] flex justify-between items-center px-6 py-4 mb-3 rounded">
+                  <div class="w-3/12">{{ item.name }}</div>
+                  <div class="flex-1">{{ item.phone }}</div>
+                  <van-icon name="phone" color="#075985" size="1.4rem" />
+                </div>
+              </a>
+            </template>
+          </div>
+        </div>
+      </van-popup>
+
+      <van-popup v-model:show="showDelay" closeable position="bottom" round>
+        <div class="newModuleAdded relative">
+          <div class="text-size-large text-[#474A56] absolute topTitle">延期时间</div>
+          <div class="flex flex-col overflow-y-auto h-52">
+            <div class="flex-1">
+              <div class="px-6 py-4 bg-[#F8F8FA] flex justify-between items-center mt-2" @click="showDatePicker = true">
+                <div>选择时间</div>
+                <div class="flex items-center">
+                  {{ showDelayData }}
+                  <van-icon name="arrow" size="1.2rem" class="ml-2" />
+                </div>
+              </div>
+            </div>
+            <van-button type="primary" :disabled="!showDelayData" @click="delayTimeEvent()">保存</van-button>
+          </div>
+        </div>
+      </van-popup>
+
+      <van-popup v-model:show="showDatePicker" destroy-on-close position="bottom" :style="{ height: '50%' }">
+        <van-date-picker v-model="showDatePickerVal" @confirm="showPickerConfirm" @cancel="showDatePicker = false" />
+      </van-popup>
+
+      <van-popup
+        v-model:show="timeShowPicker"
+        destroy-on-close
+        position="bottom"
+        :style="{ height: '50%' }"
+      >
+        <van-time-picker v-model="currentTime" title="选择时间" @confirm="timeConfirm" />
+      </van-popup>
     </template>
 
-    <template v-slot:footer>
+    <template v-slot:footer v-if="detailedData.finishState == 0">
       <div class="w-full flex justify-between layout">
-        <div class="footerBtnLeft layouts">
+        <div class="footerBtnLeft layouts" @click="showContacts = true">
           <div class="imgClss"></div>
           联系人
         </div>
-        <div class="footerBtnRight layouts">
+        <div class="footerBtnRight layouts" @click="showDelay = true, showDelayData = ''">
           <div class="imgClss"></div>
           延期
         </div>
         <div class="coverWithWhite"></div>
-        <div class="bigCircle">
+        <div class="bigCircle" @click="completeThePlan()">
           <div class="imgClss"></div>
           完成
         </div>
@@ -53,19 +103,74 @@
 
 <script setup>
 import { ref } from "vue";
+import { showConfirmDialog } from 'vant';
 import { useLifecycle } from "@hooks/useCommon.js";
+import { OBTAIN_DETAILS_OF_THE_VISIT_PLAN, POSTPONE_THE_VISIT_PLAN, COMPLETE_THE_VISIT_PLAN } from "@hooks/useApi"
 import useToast from "@hooks/useToast"
 import requests from "@common/requests";
 import useRouterStore from "@store/useRouterStore.js";
+import dayjs from "dayjs";
 import useFixedData from "@store/useFixedData.js";
 import PullDownSelector from "@components/common/pullDownSelector.vue";
 
 const router = useRouterStore();
+const { toastText, toastSuccess, toastFail, toastLoading } = useToast()
 const detailedData = ref({});
+const showContacts = ref(false);
+const showDelay = ref(false)
+const showDatePicker = ref(false)
+const timeShowPicker = ref(false)
+const showDatePickerVal = ref(dayjs().format("YYYY-MM-DD").split('-'))
+const showDelayData = ref('')
+const currentTime = ref('')
+const contactList = ref([]);
+
+function completeThePlan() {
+  showConfirmDialog({
+    title: `完成访客计划`,
+    message: `确定完成【${detailedData.value.planName}】访客计划吗?`,
+  }).then(() => {
+    requests.post(COMPLETE_THE_VISIT_PLAN, { planId: detailedData.value.id, }).then((res) => {
+      toastSuccess('操作成功')
+      getDetailData(detailedData.value)
+    })
+  })
+}
+
+function delayTimeEvent() {
+  requests.post(POSTPONE_THE_VISIT_PLAN, { planId: detailedData.value.id, visitTime: showDelayData.value }).then(() => {
+    toastSuccess(`操作成功`)
+    getDetailData(detailedData.value)
+  })
+}
+
+function getDetailData(row) {
+  requests.post(OBTAIN_DETAILS_OF_THE_VISIT_PLAN, { planId: row.id }).then(({ data = [] }) => {
+    detailedData.value = data
+    contactList.value = data.contacts || []
+  })
+}
+
+function showPickerConfirm({ selectedValues }) {
+  const dates = selectedValues.join('-')
+  const times = dayjs().format("hh:mm")
+  showDelayData.value = `${dates} ${times}`
+  currentTime.value = times.split(':')
+  showDatePicker.value = false
+  timeShowPicker.value = true
+}
+
+function timeConfirm({ selectedValues }) {
+  const dates = dayjs(new Date(showDatePickerVal.value)).format("YYYY-MM-DD")
+  showDelayData.value = `${dates} ${selectedValues.join(':')}`
+  timeShowPicker.value = false
+}
 
 function processingDataSource(data) {
   const row = JSON.parse(data.row);
   detailedData.value = row || {}
+
+  getDetailData(row)
 }
 
 useLifecycle({
@@ -184,4 +289,16 @@ useLifecycle({
     }
   }
 }
+
+.newModuleAdded {
+  padding: 45px 25px 45px 25px;
+}
+
+.topTitle {
+  top: 14px;
+}
+
+.boxLxr {
+  max-height: 180px;
+}
 </style>

+ 1 - 0
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/store/useInfoStore.js

@@ -6,6 +6,7 @@ const useInfoStore = defineStore('userInfo', {
         modularList: [], // 菜单列表
         permissionList: [], // 权限列表
         token: '', // token
+        numberOfMessages: '', // 消息数量
     }),
     actions: { //actions是store的方法methods
         updateState(info) {