Ver código fonte

提交相关代码

Lijy 4 meses atrás
pai
commit
4edfebcf2f

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

@@ -103,4 +103,7 @@ export const TOP_DATA_OF_SALES_ORDER_LIST = `/order/pageOrderByPin` // 销售订
 
 export const GET_SALES_BRIEFINGS = `/order/salesKit` // 获取销售简报
 export const OBTAIN_DATA_SUMMARY = `/order/dataSummary` // 获取数据汇总
-export const STAGE_OF_OBTAINING_BUSINESS_OPPORTUNITIES = `/order/businessOpportunityStage` // 获取商机阶段
+export const STAGE_OF_OBTAINING_BUSINESS_OPPORTUNITIES = `/order/businessOpportunityStage` // 获取商机阶段
+export const ACQUISITION_STAGE = `/business-opportunity/getStage` // 获取阶段
+export const PROMOTION_STAGE = `/business-opportunity/saveStageId` // 推进阶段
+export const STAGE_NOTES = `/business-opportunity/saveReason` // 阶段备注

+ 158 - 0
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/business/businessOpportunityStage.vue

@@ -0,0 +1,158 @@
+<template>
+  <div class="w-full h-full flex flex-col">
+    <div class="flex-1 overflow-y-auto my-3 px-6">
+      <van-steps direction="vertical" :active="stageIndex">
+        <template v-for="item in stageList">
+          <van-step>
+            <div>{{ item.name }} {{ item.plan }}</div>
+          </van-step>
+        </template>
+      </van-steps>
+    </div>
+
+    <div class="px-6 flex flex-col pb-4 mt-2" v-if="stageIndex <= stageList.length">
+      <van-button type="primary" class="btn-3" v-if="stageIndex < stageList.length - 1"
+        @click="promotionStage()">推荐下阶段({{
+          stageList[+stageIndex + 1]?.name
+        }})</van-button>
+      <van-button type="success" class="btn-3" @click="completionStage(1)">赢单</van-button>
+      <van-button type="warning" class="btn-3" @click="completionStage(2)">输单</van-button>
+      <van-button type="danger" class="btn-3" @click="completionStage(3)">无效</van-button>
+    </div>
+
+    <van-dialog v-model:show="showDisold" :title="`${transitionalData.title}原因`" show-cancel-button @confirm="stageCompletion()">
+      <van-field v-model="transitionalData.reason" rows="4" autosize type="textarea" :placeholder="`请输入${transitionalData.title}原因`"
+        show-word-limit />
+    </van-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import { useLifecycle } from '@hooks/useCommon.js';
+import { ACQUISITION_STAGE, GET_BUSINESS_OPPORTUNITY_DETAILS, PROMOTION_STAGE, STAGE_NOTES } from '@hooks/useApi'
+import requests from "@common/requests";
+import useShowToast from '@hooks/useToast'
+import useInfoStore from '@store/useInfoStore'
+import useRouterStore from "@store/useRouterStore.js";
+
+const { toastSuccess, toastFail, toastText, toastLoading } = useShowToast()
+
+const props = defineProps({
+  info: {
+    type: Object,
+    required: true,
+    default: () => ({})
+  }
+})
+
+const infoData = ref({})
+const stageList = ref([])
+const stageIndex = ref(0)
+const stageSetting = ref([])
+const transitionalData = ref({})
+const showDisold = ref(false)
+
+function completionStage(type) {
+  const typeObj = { 1: '赢单', 2: '输单', 3: '无效' }
+  const row = stageSetting.value.find(item => item.name === typeObj[type])
+  transitionalData.value = {
+    id: infoData.value.id,
+    stageId: row.id,
+    stageValue: row.name,
+    title: `${typeObj[type]}`,
+    reason: ''
+  }
+
+  if (type != 1) {
+    showDisold.value = true
+  } else {
+    stageCompletion(false)
+  }
+}
+
+function enterReason() {
+  const { id, reason } = transitionalData.value
+  requests.post(PROMOTION_STAGE, {
+    id, reason
+  }).then((res) => {
+    getBusinessOpportunityDetails(id)
+  }).catch((err) => {
+    toastFail(err.msg)
+  })
+}
+
+function stageCompletion(flag = true) {
+  const { id, stageId, stageValue } = transitionalData.value
+  requests.post(PROMOTION_STAGE, {
+    id, stageId, stageValue
+  }).then((res) => {
+    toastSuccess('操作成功')
+    if(flag) {
+      enterReason()
+    } else {
+      getBusinessOpportunityDetails(id)
+    }
+  }).catch((err) => {
+    toastFail(err.msg)
+  })
+}
+
+function promotionStage() {
+  const item = stageList.value[+stageIndex.value + 1]
+  toastLoading('推进中...', 0)
+  requests.post(PROMOTION_STAGE, {
+    id: infoData.value.id,
+    stageId: item.id,
+    stageValue: item.name
+  }).then((res) => {
+    toastSuccess('推进成功')
+    getBusinessOpportunityDetails(infoData.value.id)
+  }).catch((err) => {
+    toastFail(err.msg)
+  })
+}
+
+function acquisitionStage(row) {
+  requests.post(ACQUISITION_STAGE, {}).then((res) => {
+    stageIndex.value = (res.data || []).findIndex(item => item.id === row.stageId)
+    stageList.value = (res.data || []).filter(item => !(['赢单', '输单', '无效'].includes(item.name)))
+    stageSetting.value = (res.data || []).filter(item => (['赢单', '输单', '无效'].includes(item.name)))
+    const val = (stageSetting.value || []).find(item => item.id === row.stageId)
+    if(val.length > 0) {
+      stageList.value.push(val[0])
+      stageIndex.value = stageList.value.length - 1
+    }
+  })
+}
+
+function getBusinessOpportunityDetails(id) {
+  requests.post(GET_BUSINESS_OPPORTUNITY_DETAILS, { id }).then((res) => {
+    infoData.value = res.data || {}
+    acquisitionStage(res.data)
+  })
+}
+
+function initializeData() {
+  getBusinessOpportunityDetails(props.info.id)
+}
+
+useLifecycle({
+  load: () => {
+    initializeData()
+  },
+  init: () => {
+    initializeData()
+  }
+});
+</script>
+
+<style lang='scss' scoped>
+.btn-3 {
+  margin-bottom: 10px;
+}
+
+::v-deep(.van-steps) {
+  background: none;
+}
+</style>

+ 4 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/business/detail.vue

@@ -1,7 +1,9 @@
 <template>
   <div class="w-full h-full">
     <van-tabs v-model:active="tabActive">
-      <van-tab title="商机阶段" name="商机阶段">商机阶段 1</van-tab>
+      <van-tab title="商机阶段" name="商机阶段">
+        <BusinessOpportunityStage :info="info" />
+      </van-tab>
       <van-tab title="商机信息" name="商机信息">
         <BusinessInfo :info="info" />
       </van-tab>
@@ -23,6 +25,7 @@ import requests from "@common/requests";
 import RelatedProducts from '../product/relatedProducts.vue';
 import BusinessInfo from './businessInfo.vue';
 import RelatedTasks from '../tasks/relatedTasks.vue';
+import BusinessOpportunityStage from './businessOpportunityStage.vue';
 
 const props = defineProps({
   info: {

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

@@ -317,7 +317,7 @@ function processForms() {
 
 function getVisitorPlan() {
   requests.post(GET_VISITOR_PLAN, { 
-    calenderDate: dayjs(dateConditions.value).format('YYYY-MM') 
+    calenderDate: dayjs(dateConditions.value).format('YYYY-MM-DD') 
   }).then((res) => {
     visitorProgramList.value = res.data || []
   })