Kaynağa Gözat

refactor(pc): 重构 PC 端组件并添加新功能

- 重新组织 PC 端组件结构,增加新的静态卡片组件
- 添加电话确认对话框组件
- 更新二维码展示逻辑,支持两种不同布局
- 优化内容卡片组件,增加不同类型支持
- 调整底部信息样式,使其更加灵活可配置

Signed-off-by: tangshizhe <48740614+tangshizhe@users.noreply.github.com>
tangshizhe 2 hafta önce
ebeveyn
işleme
ebbb76dd71

+ 25 - 16
plugins/leave-source/src/api/api.js

@@ -2,22 +2,31 @@
 import request from './index'
 
 export function requestBehaviorClues(data = {}) {
-  return new Promise((resolve) => {
-    request({
-      url: '/salesLeads/behaviorClues',
-      method: 'post',
-      data
-    }).finally(() => {
-      resolve({
-        error_code: 0,
-        data: {
-          name: '专属客服',
-          remark: '专属客服',
-          wxer: 'https://cdn-ali2.jianyu360.cn/qmxupload/2024/06/20/202406201338370067907a438.png'
-        },
-        message: 'success'
-      })
-    })
+  // return new Promise((resolve) => {
+  //   request({
+  //     url: '/salesLeads/behaviorClues',
+  //     method: 'post',
+  //     data
+  //   }).finally(() => {
+  //     resolve({
+  //       error_code: 0,
+  //       data: {
+  //         name: '专属客服',
+  //         remark: '专属客服',
+  //         wxer: 'https://cdn-ali2.jianyu360.cn/qmxupload/2024/06/20/202406201338370067907a438.png'
+  //       },
+  //       message: 'success'
+  //     })
+  //   })
+  // })
+  return Promise.resolve({
+    error_code: 0,
+    data: {
+      name: '专属客服',
+      remark: '专属客服',
+      wxer: 'https://cdn-ali2.jianyu360.cn/qmxupload/2024/06/20/202406201338370067907a438.png'
+    },
+    message: 'success'
   })
   // return request({
   //   url: '/salesLeads/behaviorClues',

+ 8 - 0
plugins/leave-source/src/assets/style/pic-icon.scss

@@ -39,7 +39,15 @@
   background-size: contain;
 }
 
+.icon-pc-close {
+  background-image: url(@/assets/images/icon-close.png);
+  background-size: contain;
+}
 .icon-mobile-close {
   background-image: url(@/assets/images/icon-mobile-close.png);
   background-size: contain;
 }
+.icon-mobile-phone {
+  background-image: url(@/assets/images/icon-mobile-phone.png);
+  background-size: contain;
+}

+ 4 - 1
plugins/leave-source/src/entry.js

@@ -2,15 +2,17 @@
  * description: 打包入口文件,可输出js插件供外部html调用
  */
 
-import PCContentCard from './lib/pc/content-card.vue'
+import PCContentCard from './lib/pc/components/content-card.vue'
 import MobileContentCard from './lib/mobile/content-card.vue'
 import PCLeaveDialog from './lib/pc/content-dialog.vue'
 import MobileLeavePopup from './lib/mobile/content-popup.vue'
 import registryToast from './components/toast/index'
+import PCContentStatic from './lib/pc/components/content-static.vue'
 
 function install(Vue) {
   // 注册全局组件
   Vue.component('pc-leave-dialog', PCLeaveDialog)
+  Vue.component('pc-content-static', PCContentStatic)
   Vue.component('mobile-leave-popup', MobileLeavePopup)
 }
 
@@ -18,6 +20,7 @@ export default {
   install,
   registryToast,
   PCContentCard,
+  PCContentStatic,
   MobileContentCard,
   PCLeaveDialog,
   MobileLeavePopup,

+ 24 - 1
plugins/leave-source/src/lib/pc/components/QrCode.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="qr-code-container">
-    <div class="qr-code-content">
+    <div v-if="type === '1'" class="qr-code-content">
       <div class="qr-code-title">
         2. 添加企业微信:
       </div>
@@ -8,9 +8,29 @@
         <img src="@/assets/images/商务合作.png" alt="">
       </div>
     </div>
+    <div v-if="type === '2'" class="qr-code-content">
+      <div class="qr-code">
+        <img src="@/assets/images/商务合作.png" alt="">
+        <div class="qr-code-title qr-code-title-small">
+          <span>添加企业微信</span>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
+<script>
+export default {
+  name: 'QrCode',
+  props: {
+    type: String,
+    default() {
+      return '1'
+    }
+  },
+}
+</script>
+
 <style lang="scss" scoped>
 .qr-code-container {
   display: flex;
@@ -23,6 +43,9 @@
     font-size: 16px;
     line-height: 24px;
     color: #1d1d1d;
+    &-small {
+      text-align: center;
+    }
   }
   .qr-code {
     margin-top: 8px;

+ 76 - 0
plugins/leave-source/src/lib/pc/components/content-card.vue

@@ -0,0 +1,76 @@
+<template>
+  <div class="content-card">
+    <span class="j-icon icon-pc-close" />
+    <ContractCard v-if="type === '1'" />
+    <ContractCardQrcode v-if="type === '2'" class="qrcode-module" />
+    <LeaveCommon :class="{ 'samll-footer': type === '2' }" />
+  </div>
+</template>
+
+<script>
+import ContractCard from './contract-card.vue'
+import ContractCardQrcode from './contract-card-qrcode.vue'
+import LeaveCommon from './footer'
+
+export default {
+  name: 'ContentCard',
+  components: {
+    ContractCard,
+    ContractCardQrcode,
+    LeaveCommon
+  },
+  props: {
+    type: {
+      type: String,
+      default: '2'
+    },
+    source: {
+      type: String,
+      default: ''
+    },
+    sourceDesc: {
+      type: String,
+      default: ''
+    },
+    popupTitle: {
+      type: String,
+      default: '联系专属客服,申请免费体验'
+    }
+  },
+
+  data() {
+    return {}
+  },
+  methods: {
+    // 手动触发绑定弹框
+    handle() {}
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.content-card {
+  position: relative;
+  .icon-pc-close {
+    position: absolute;
+    top: 16px;
+    right: 16px;
+    cursor: pointer;
+  }
+  .qrcode-module {
+    ::v-deep {
+      .qr-code-container {
+        &::after {
+          display: none;
+        }
+        &::before {
+          display: none;
+        }
+      }
+    }
+  }
+  .samll-footer {
+    height: 216px;
+  }
+}
+</style>

+ 48 - 0
plugins/leave-source/src/lib/pc/components/contract-card-qrcode.vue

@@ -0,0 +1,48 @@
+<template>
+  <div class="contract-card-qrcode">
+    <div class="contract-card-title">
+      <span class="title">添加客服,立享1V1管家式服务</span>
+    </div>
+    <div class="contract-card-content">
+      <QrCode type="2" @handle="handle" />
+    </div>
+  </div>
+</template>
+
+<script>
+import QrCode from './QrCode.vue'
+
+export default {
+  name: 'ContractCardQrcode',
+  components: {
+    QrCode
+  },
+  methods: {
+    handle() {
+      this.$emit('handle')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.contract-card-qrcode {
+  padding: 32px 32px;
+  .contract-card-title {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    .title {
+      font-size: 18px;
+      line-height: 28px;
+      color: #1D1D1D;
+    }
+  }
+  .contract-card-content {
+    display: flex;
+    justify-content: center;
+    margin-top: 24px;
+    height: 154px;
+  }
+}
+</style>

+ 3 - 3
plugins/leave-source/src/lib/pc/contract-card.vue → plugins/leave-source/src/lib/pc/components/contract-card.vue

@@ -13,9 +13,9 @@
 </template>
 
 <script>
-import CallPhone from './components/CallPhone.vue'
-import ContractMine from './components/ContractMine.vue'
-import QrCode from './components/QrCode.vue'
+import CallPhone from './CallPhone.vue'
+import ContractMine from './ContractMine.vue'
+import QrCode from './QrCode.vue'
 
 export default {
   name: 'ContractCard',

+ 6 - 1
plugins/leave-source/src/lib/pc/components/footer.vue

@@ -38,8 +38,13 @@ export default {
 
 <style lang="scss" scoped>
 .leave-common-footer {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 196px;
   background: url(@/assets/images/BG.png) no-repeat;
-  background-size: cover;
+  background-size: 100% 100%;
   .leave-common-title {
     text-align: center;
     color: #2ABED1;

+ 34 - 0
plugins/leave-source/src/lib/pc/components/phoneConfirmDialog.vue

@@ -0,0 +1,34 @@
+<template>
+  <div class="phone-confirm-dialog">
+    <AnimatedOverlay
+      :visible="visible"
+      @update:visible="updateVisible"
+      @close="close"
+    >
+      <div class="phone-confirm">
+        <h1>Phone Confirm</h1>
+        <p>Please enter the code sent to your phone</p>
+      </div>
+    </AnimatedOverlay>
+  </div>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import AnimatedOverlay from '../../../components/dialog/AnimatedOverlay.vue'
+
+const visible = ref(false)
+function updateVisible(f = false) {
+  visible.value = f
+}
+function close() {
+  visible.value = false
+}
+defineExpose({
+  updateVisible
+})
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 82 - 0
plugins/leave-source/src/lib/pc/components/static-card.vue

@@ -0,0 +1,82 @@
+<template>
+  <div class="contract-card-container">
+    <div class="contract-card-title">
+      <span class="title">联系客服,立享1V1管家式服务</span>
+    </div>
+    <div class="contract-card-content">
+      <CallPhone class="call-phone" @handle="handle" />
+      <QrCode type="1" @handle="handle" />
+    </div>
+    <LeaveCommon class="static-footer" />
+  </div>
+</template>
+
+<script>
+import CallPhone from './CallPhone.vue'
+import QrCode from './QrCode.vue'
+import LeaveCommon from './footer.vue'
+
+export default {
+  name: 'ContractCard',
+  components: {
+    CallPhone,
+    QrCode,
+    LeaveCommon
+  },
+  methods: {
+    handle() {
+      this.$emit('handle')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.contract-card-container {
+  background: #FFFFFF;
+
+  .contract-card-title {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    padding: 12px 20px 0;
+    .title {
+      font-size: 18px;
+      line-height: 28px;
+      color: #1D1D1D;
+    }
+    .subtitle {
+      margin-top: 4px;
+      font-size: 16px;
+      line-height: 24px;
+      color: #686868;
+    }
+  }
+  .contract-card-content {
+    display: flex;
+    justify-content: center;
+    margin: 8px 0 16px;
+    height: 154px;
+    ::v-deep {
+      .qr-code-container::after {
+        display: none;
+      }
+    }
+  }
+  .static-footer {
+    height: 136px;
+    background: linear-gradient(to bottom, rgba(237, 253, 255, 1), rgba(237, 253, 255, 0));
+    ::v-deep {
+      .leave-common-footer-content {
+        padding: 10px 0 3px 20px;
+      }
+      .leave-common-footer-list {
+        margin-top: 8px;
+      }
+      .leave-common-footer-item {
+        margin-bottom: 10px;
+      }
+    }
+  }
+}
+</style>

+ 0 - 29
plugins/leave-source/src/lib/pc/content-card.vue

@@ -1,29 +0,0 @@
-<template>
-  <div>
-    <ContractCard />
-    <LeaveCommon />
-  </div>
-</template>
-
-<script>
-import ContractCard from './contract-card.vue'
-import LeaveCommon from './components/footer'
-
-export default {
-  name: 'ContentCard',
-  components: {
-    ContractCard,
-    LeaveCommon
-  },
-
-  data() {
-    return {}
-  },
-  methods: {
-    // 手动触发绑定弹框
-    handle() {}
-  }
-}
-</script>
-
-<style scoped lang="scss"></style>

+ 13 - 1
plugins/leave-source/src/lib/pc/content-dialog.vue

@@ -1,6 +1,6 @@
 <script setup>
 import AnimatedOverlay from '../../components/dialog/AnimatedOverlay.vue'
-import ContentCard from './content-card.vue'
+import ContentCard from './components/content-card.vue'
 import { usePreLeaveInfo } from '@/utils/hooks'
 
 const props = defineProps({
@@ -17,6 +17,10 @@ const props = defineProps({
     type: String,
     default: '联系专属客服,申请免费体验'
   },
+  type: {
+    type: String,
+    default: '2'
+  }
 })
 
 const {
@@ -42,6 +46,7 @@ export default {
 <template>
   <AnimatedOverlay
     class="pc-leave-dialog"
+    :class="`pc-leave-dialog-${props.type}`"
     :visible="visible"
     @update:visible="updateVisible"
     @close="close"
@@ -60,5 +65,12 @@ export default {
       border-radius: 8px;
     }
   }
+  &-2 {
+    ::v-deep {
+      .overlay-content {
+        width: 480px;
+      }
+    }
+  }
 }
 </style>

+ 45 - 0
plugins/leave-source/src/lib/pc/content-static.vue

@@ -0,0 +1,45 @@
+<script setup>
+import StaticCard from './components/static-card'
+import { useStaticCustomInfo } from '@/utils/hooks'
+
+const props = defineProps({
+  source: {
+    type: String,
+    default: '',
+    // required: true,
+  },
+  sourceDesc: {
+    type: String,
+    default: '',
+  },
+  popupTitle: {
+    type: String,
+    default: '联系客服,立享1V1管家式服务'
+  },
+  type: {
+    type: String,
+    default: '2'
+  }
+})
+
+const {
+  configInfo,
+} = useStaticCustomInfo({ props })
+
+console.log(configInfo)
+</script>
+
+<script>
+export default {
+  name: 'PCContentStatic',
+}
+</script>
+
+<template>
+  <div class="pc-content-static">
+    <StaticCard />
+  </div>
+</template>
+
+<style scoped lang="scss">
+</style>

+ 37 - 0
plugins/leave-source/src/utils/hooks.js

@@ -1,6 +1,28 @@
 import { computed, reactive, ref, watch } from 'vue'
 import { requestBehaviorClues, requestGetStaticInfo, requestRetainedCapital } from '@/api/api'
 
+// pc静态弹窗卡片信息获取
+export function useStaticCustomInfo() {
+  const configInfo = reactive({
+    name: '',
+    remark: '',
+    wxer: '',
+    phone: '',
+  })
+
+  // 获取静态信息
+  useStaticInfoRequest().then((r) => {
+    if (r) {
+      Object.assign(configInfo, r)
+    }
+  })
+
+  return {
+    configInfo
+  }
+}
+
+// 线索弹窗卡片信息获取
 export function usePreLeaveInfo(options = {}) {
   const { props } = options
   const visible = ref(false)
@@ -55,6 +77,21 @@ export function usePreLeaveInfo(options = {}) {
   }
 }
 
+// 与我联系-判断逻辑
+export async function useContactMeLogic(options = {}) {
+  const { props } = options
+  const visible = ref(false)
+  function updateVisible(e) {
+    visible.value = e
+  }
+  const { info } = await useLeaveInfoRequest({ source: props.source })
+  return {
+    updateVisible,
+    close: () => (visible.value = false),
+    visible,
+  }
+}
+
 export async function useBehaviorCluesRequest(value) {
   const res = await requestBehaviorClues({ source_desc: value })
   const { error_code: code, data } = res

+ 9 - 6
plugins/leave-source/src/utils/leave.js

@@ -1,12 +1,14 @@
 import Vue from 'vue'
+import phoneConfirmDialog from '../lib/pc/components/phoneConfirmDialog.vue'
 import PCLeaveDialog from '@/lib/pc/content-dialog.vue'
 import MobileLeavePopup from '@/lib/mobile/content-popup.vue'
 import { isDOMElement } from '@/utils/utils'
 
 const instanceMap = {
-  wx: null,
-  app: null,
-  pc: null,
+  'wx': null,
+  'app': null,
+  'pc': null,
+  'phone-confirm': null,
 }
 
 export function createInstance(platform, options = {}) {
@@ -17,9 +19,10 @@ export function createInstance(platform, options = {}) {
   }
 
   const componentMap = {
-    wx: MobileLeavePopup,
-    app: MobileLeavePopup,
-    pc: PCLeaveDialog,
+    'wx': MobileLeavePopup,
+    'app': MobileLeavePopup,
+    'pc': PCLeaveDialog,
+    'phone-confirm': phoneConfirmDialog,
   }
   const MyComponent = componentMap[platform]
   if (!MyComponent)