소스 검색

提交代码

Lijy 5 달 전
부모
커밋
e72dc07cfe

+ 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"

+ 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` // 销售订单关联产品

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

@@ -2,8 +2,8 @@
   <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>
@@ -14,29 +14,42 @@
       <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">
-            <div class="bg-[#FFA35919] ra6 p-4 mb-4">
-              <div class="w-full flex items-center justify-between">
-                <div class="text-size-in font-bold text-[#474A56]">535计划</div>
-                <div class="labelTag toBeCompleted">待完成</div>
-              </div>
-              <div class="w-full flex items-center justify-between mt-4">
-                <div class="text-[#505050]" style="width: 62%;">拜访目的: 建立客情</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" />
-                  苹果集团
+            <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>
-              <div class="w-full flex items-center justify-between mt-4">
-                <div class="w-2/3 text-[#505050]" style="width: 62%;">拜访时间: 2021-08-05 14:00</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" />
-                  13561223622
+                <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>
-            </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">新增计划</van-button>
+        <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" v-if="!visitorProgramList.length">
@@ -44,7 +57,7 @@
           <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>
 
@@ -53,12 +66,12 @@
       <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">
                 <img class="w-full h-full" src="/src/assets/image/form.png">
               </div>
-              <div class="text-white">表单{{ index }}</div>
+              <div class="text-white">{{ item.moduleName }}</div>
             </div>
           </template>
 
@@ -76,12 +89,12 @@
     <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">
               <img class="w-full h-full" src="/src/assets/image/topContacts.png">
             </div>
-            <div class="flex-1">张三</div>
+            <div class="flex-1">{{ item.name }}</div>
             <div class="rightArrow">
               <van-icon name="arrow" />
             </div>
@@ -94,15 +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 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>
@@ -116,8 +200,9 @@ useLifecycle({
   padding-left: 16px;
 }
 
-.ra6 {
-  border-radius: 6px;
+.ra-l6 {
+  border-top-left-radius: 6px;
+  border-top-right-radius: 6px;
 }
 
 .w80 {
@@ -166,6 +251,12 @@ useLifecycle({
   height: 51px;
 }
 
+.buttonCircle {
+  width: 37px;
+  height: 37px;
+  margin: 0 14px;
+}
+
 .setCaleStrle :deep(.van-calendar__month-title) {
   display: none;
 }

+ 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',