Lijy před 5 měsíci
rodič
revize
257b1403e7

+ 5 - 0
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/hooks/useApi.js

@@ -32,12 +32,14 @@ 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 TRANSFER_SALES_ORDERS = `/order/transfer` // 转移销售订单
 
 export const BUSINESS_OPPORTUNITY_TRANSFER = '/business-opportunity/claim' // 转移商机
 export const TRANSFER_CLUES = '/clue/claim' // 转移线索
 export const TRANSFER_CUSTOMERS = '/custom/claim' // 转移客户
 export const TRANSFER_CONTACT_PERSON = `/contacts/transferContacts` // 转移联系人
 export const NEW_BUSINESS_OPPORTUNITY_EDITING = `/business-opportunity/insertAndUpdate` // 商机新增编辑
+export const TRANSFER_PRODUCTS = `/product/transferIncharger` // 转移产品
 export const NEW_CLUE_EDITING = `/clue/insertAndUpdate` // 线索新增编辑
 export const CUSTOMER_ADDED_EDITOR = `/custom/insertAndUpdate` // 客户新增编辑
 export const CONTACT_PERSON_ADDITION_EDITOR = `/contacts/addContacts` // 联系人新增编辑
@@ -50,6 +52,7 @@ export const PLAN_TO_ADD_EDITORS = `/visitPlan/addOrUpdateVisitPlan` // 计划
 
 export const GET_BUSINESS_OPPORTUNITY_DETAILS = `/business-opportunity/getInfo` // 商机详情
 export const GET_CLUE_DETAILS = `/clue/getDetail` // 线索详情
+export const SALES_ORDER_DETAILS = `/order/getDetail` // 销售订单详情
 export const OBTAIN_CUSTOMER_DETAILS = `/custom/getInfo` // 获取客户想
 export const GET_CONTACT_DETAILS = `/contacts/getContactsDetail` // 获取联系人详情
 export const OBTAIN_PRODUCT_RELATED_BUSINESS_OPPORTUNITIES = `/product/businessListWithProduct` // 获取产品关联商机
@@ -57,6 +60,7 @@ export const OBTAIN_SALES_ORDERS_RELATED_TO_THE_PRODUCT = `/product/orderWithPro
 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 GET_PRODUCT_DETAILS = `/product/detail` // 获取产品详情
 
 export const SELL_AND_OBTAIN_RELATED_PRODUCTS = `/product/orderWithProduct` // 销售订单关联产品
 
@@ -94,6 +98,7 @@ export const CANCEL_THE_TOP_PLACEMENT_OF_THE_PRODUCT = `/product/undoPin` // 取
 export const TOP_DATA_OF_PRODUCT_LIST = `/product/pageProductByPin` // 产品列表顶置数据
 
 export const TOP_OF_THE_CONTRACT = `/contract/pinContract` // 合同顶置
+export const CONTRACT_APPROVED = `/contract/processContract` // 合同审批
 export const CONTRACT_CANCELLATION_WITH_TOP_PLACEMENT = `/contract/undoPin` // 取消顶置
 export const TOP_DATA_OF_CONTRACT_LIST = `/contract/pageContractByPin` // 合同列表顶置数据
 

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

@@ -156,13 +156,13 @@
                       <div class="flex items-center h-full bg-white">
                         <template v-if="!item.inchargerName">
                           <div class="buttonCircle rounded-full" @click="claimAndClaim(item)" v-if="['business', 'thread',
-                            'customer'].includes(queryParameters?.key)">
+                            'customer', 'product'].includes(queryParameters?.key)">
                             <img src="/src/assets/image/claimAndClaim.png" class="w-full h-full">
                           </div>
                         </template>
                         <template v-if="item.inchargerName || item.ownerName">
                           <div class="buttonCircle rounded-full" @click="transfer(item)" v-if="['business', 'thread',
-                            'customer', 'contacts'].includes(queryParameters?.key)">
+                            'customer', 'contacts', 'product', 'order'].includes(queryParameters?.key)">
                             <img src="/src/assets/image/transfer.png" class="w-full h-full">
                           </div>
                         </template>
@@ -323,6 +323,8 @@ function confirmTransfer() {
   let formVal = {}
   if(queryParameters?.value.key == 'contacts') {
     formVal = { id, inchargerId: value, ownerId: value }
+  } else if(queryParameters?.value.key == 'product' || queryParameters?.value.key == 'order') {
+    formVal = { id, userId: value }
   } else {
     formVal = { ids: id, inchargerId: value, }
   }
@@ -335,13 +337,18 @@ function confirmTransfer() {
 
 // 认领
 function claimAndClaim(item) {
-  const { id, name, clueName, customName } = item
+  const { id, name, clueName, customName, productName } = item
+  const { key } = queryParameters.value
   const userId = userInfo.userInfo.id
+  const formVal = {
+    [key == 'product' ? 'id' : 'ids']: id,
+    [key == 'product' ? 'userId' : 'inchargerId']: userId
+  }
   showConfirmDialog({
     title: `认领${queryParameters.value.name}`,
-    message: `确定认领【${name || clueName || customName}】${queryParameters.value.name}吗?`,
+    message: `确定认领【${name || clueName || customName || productName}】${queryParameters.value.name}吗?`,
   }).then(() => {
-    requests.post(queryParameters?.value.transferInterface, { ids: id, inchargerId: userId }).then((res) => {
+    requests.post(queryParameters?.value.transferInterface, { ...formVal }).then((res) => {
       toastSuccess('认领成功')
       onRefresh(true)
     })

+ 163 - 18
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/contract/detail.vue

@@ -1,50 +1,81 @@
 <template>
   <div class="flex flex-col h-full">
     <div class="bg-white info flex-1 overflow-y-auto cellnormall">
-      <van-cell title="合同编号" :value="info.number" />
-      <van-cell title="合同名称" :value="info.name" />
-      <van-cell title="合同金额" :value="info.amounts">
+      <van-cell title="合同编号" :value="infoData.number" />
+      <van-cell title="合同名称" :value="infoData.name" />
+      <van-cell title="合同金额" :value="infoData.amounts">
         <template #default>
-          <span class="text-[#FF8B32]" v-if="info.amounts">¥ {{ info.amounts }}</span>
+          <span class="text-[#FF8B32]" v-if="infoData.amounts">¥ {{ infoData.amounts }}</span>
         </template>
       </van-cell>
-      <van-cell title="已回款金额" :value="info.payment">
+      <van-cell title="已回款金额" :value="infoData.payment">
         <template #default>
-          <span class="text-[#FF8B32]" v-if="info.payment">¥ {{ info.payment }}</span>
+          <span class="text-[#FF8B32]" v-if="infoData.payment">¥ {{ infoData.payment }}</span>
         </template>
       </van-cell>
-      <van-cell title="已回款进度" :value="info.payment">
+      <van-cell title="已回款进度" :value="infoData.payment">
         <template #default>
-          {{ info.payment ? (100 * info.payment / info.amounts).toFixed(1) + '%' : '0%' }}
+          {{ infoData.payment ? (100 * infoData.payment / infoData.amounts).toFixed(1) + '%' : '0%' }}
         </template>
       </van-cell>
-      <van-cell title="下笔回款日期" :value="info.nextPaymentDate">
+      <van-cell title="下笔回款日期" :value="infoData.nextPaymentDate">
         <template #default>
-          {{ info.nextPaymentDate ? info.nextPaymentDate : '-' }}
+          {{ infoData.nextPaymentDate ? infoData.nextPaymentDate : '-' }}
         </template>
       </van-cell>
-      <van-cell title="下笔回款金额" :value="info.payment">
+      <van-cell title="下笔回款金额" :value="infoData.payment">
         <template #default>
-          <span class="text-[#FF8B32]" v-if="info.payment">¥ {{ info.payment.toFixed(2) }}</span>
+          <span class="text-[#FF8B32]" v-if="infoData.payment">¥ {{ infoData.payment.toFixed(2) }}</span>
         </template>
       </van-cell>
-      <van-cell title="合同类型" :value="info.typeName" />
-      <van-cell title="状态" :value="info.status">
+      <van-cell title="合同类型" :value="infoData.typeName" />
+      <van-cell title="状态" :value="infoData.status">
         <template #default>
-          <span :style="fixedFieldStatusArray[info.status].color">
-            {{ fixedFieldStatusArray[info.status].label }}
+          <span :style="fixedFieldStatusArray[infoData.status].color">
+            {{ fixedFieldStatusArray[infoData.status].label }}
           </span>
         </template>
       </van-cell>
     </div>
+    <div class="bottomButton">
+      <template v-if="infoData.status == 1">
+        <van-button type="success" class="w-full block" @click="adoptOperation">通过合同</van-button>
+        <van-button type="danger" class="w-full block" @click="rejectOperation">驳回合同</van-button>
+      </template>
+      <van-button type="default" class="w-full block" v-permission="[routingInformation.jurisdiction.edit]"
+        @click="jumpEdit()">编辑合同</van-button>
+      <van-button type="danger" class="w-full block" v-permission="[routingInformation.jurisdiction.delete]"
+        @click="deleteRow()">删除合同</van-button>
+    </div>
+
+    <!-- 驳回弹窗 -->
+    <van-dialog v-model:show="showDialog" :title="`转移线索`" show-cancel-button @confirm="confirmTransfer"
+      :before-close="dialogCloseBefo">
+      <template #default>
+        <van-field v-model.trim="dialogSelection" type="textarea" rows="3" label="驳回原因" placeholder="请输入驳回原因" />
+      </template>
+    </van-dialog>
   </div>
 </template>
 
 <script setup>
-import { ref } from 'vue';
+import { ref, watch } from 'vue';
+import requests from "@common/requests";
+import { showConfirmDialog } from 'vant';
 import { useLifecycle } from '@hooks/useCommon.js';
 import { fixedFieldStatusArray } from '@/utility/defaultData.js';
+import { CONTRACT_APPROVED } from '@hooks/useApi'
+import useShowToast from '@hooks/useToast'
+import useInfoStore from '@store/useInfoStore'
+import useRouterStore from "@store/useRouterStore.js";
+import { routingInfos } from "@utility/generalVariables"
+import { resetListData, getListFieldKey } from '@components/common/formForm/formCorrespondenceProcessing'
+import useFixedData from "@store/useFixedData.js"
 
+const fixedData = useFixedData()
+const router = useRouterStore()
+const userInfo = useInfoStore()
+const { toastSuccess, toastFail, toastText } = useShowToast()
 const props = defineProps({
   info: {
     type: Object,
@@ -53,9 +84,123 @@ const props = defineProps({
   }
 })
 
+const routingInformation = routingInfos['contract']
+const showDialog = ref(false);
+const showSelect = ref(false);
+const dialogSelection = ref({});
+
+watch(() => props.info, (newValue) => {
+  processingData(newValue.id)
+})
+
+const infoData = ref(props.info);
+const timeout = ref(null);
+
+function adoptOperation() {
+  const { name = '', id } = infoData.value
+  showConfirmDialog({
+    title: `合同通过`,
+    message: `确认审核通过吗?,通过后合同基本信息无法修改`,
+  }).then(() => {
+    requests.post(CONTRACT_APPROVED, { id, status: 0 }).then((res) => {
+      toastSuccess('操作成功')
+      processingData(id)
+    }).catch((err) => {
+      toastFail(err.msg ? err.msg : '操作失败')
+    })
+  })
+}
+
+function rejectOperation() {
+  dialogSelection.value = ''
+  showDialog.value = true
+}
+
+function confirmTransfer() {
+  const { name = '', id } = infoData.value
+  if (!dialogSelection.value) {
+    return toastText('请输入驳回原因')
+  }
+
+  showConfirmDialog({
+    title: `合同驳回`,
+    message: `确认驳回吗?,驳回后合同基本信息无法修改`,
+  }).then(() => {
+    requests.post(CONTRACT_APPROVED, { id, status: 0, msg: dialogSelection.value }).then((res) => {
+      toastSuccess('操作成功')
+      showDialog.value = false
+      processingData(id)
+    })
+  })
+}
+
+function dialogCloseBefo(val) {
+  if (val == 'confirm' && showDialog.value) {
+    return false
+  }
+
+  return true
+}
+
+function deleteRow() {
+  const { name = '', searchFiled = {}, deteleFiled = '' } = routingInformation
+  const row = props.info
+  const foemVal = { [routingInformation.key == 'tasks' ? 'taskIds' : 'ids']: row.id }
+  showConfirmDialog({
+    title: `删除${name}`,
+    message: `确定删除【${row[searchFiled?.search]}】${name}吗?`,
+  }).then(() => {
+    requests.post(deteleFiled, { ...foemVal }).then((res) => {
+      toastSuccess('删除成功')
+      router.navigateBack({
+        success: () => {
+          router.emit('moduleListDetailParameter', {
+            row: JSON.stringify(routingInformation)
+          })
+        }
+      })
+    }).catch((err) => {
+      toastFail(err.msg ? err.msg : '删除失败')
+    })
+  })
+}
+
+function jumpEdit() {
+  const formJson = fixedData.formJson[routingInformation.key] || []
+  const formList = resetListData(formJson?.list)
+  const filedObj = getListFieldKey(formList, props.info)
+  const formVal = { ...filedObj, id: props.info.id }
+
+  router.navigateTo({
+    pathName: 'addEditor',
+    success: () => {
+      router.emit('addEditorParameter', {
+        routerInfo: JSON.stringify(routingInformation),
+        filedValue: JSON.stringify(formVal)
+      })
+    }
+  })
+}
+
+function getDetails(id) {
+  // 获取合同详情
+}
+function processingData(id) {
+  clearTimeout(timeout.value);
+  timeout.value = setTimeout(() => {
+    getDetails(id)
+  }, 100);
+}
+
 useLifecycle({
+  init: () => {
+    processingData(props.info.id)
+  },
   load: () => {
-    // 添加加载逻辑
+    processingData(props.info.id)
+  },
+  unload: () => {
+    clearTimeout(timeout.value)
   }
 });
 </script>

+ 2 - 2
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/order/addEditor.vue

@@ -38,7 +38,7 @@
 <script setup>
 import { ref, onActivated } from 'vue';
 import { useLifecycle } from '@hooks/useCommon.js';
-import { SELL_AND_OBTAIN_RELATED_PRODUCTS, ORDER_ADDITION_EDITING } from "@hooks/useApi"
+import { OBTAIN_ORDER_RELATED_PRODUCTS, ORDER_ADDITION_EDITING } from "@hooks/useApi"
 import { defaultRelatedProductDataFields } from "@utility/defaultData"
 import dayjs from 'dayjs';
 import requests from "@common/requests";
@@ -123,7 +123,7 @@ function getBusinessOpportunityDetails(row) {
     businessItemProductList.value = [{ ...defaultRelatedProductDataFields }]
     return
   }
-  requests.post(SELL_AND_OBTAIN_RELATED_PRODUCTS, { id }).then(({ data }) => {
+  requests.post(OBTAIN_ORDER_RELATED_PRODUCTS, { id }).then(({ data }) => {
     if ((data || []).length === 0) {
       businessItemProductList.value = [{ ...defaultRelatedProductDataFields }]
       return

+ 18 - 3
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/order/detail.vue

@@ -2,7 +2,7 @@
   <div class="w-full h-full">
     <van-tabs v-model:active="tabActive">
       <van-tab title="销售订单信息" name="销售订单信息">
-        <OrderInfo :info="info" />
+        <OrderInfo :info="infoData" />
       </van-tab>
       <van-tab title="相关任务" name="相关任务">
         <RelatedTasks :infoList="relatedTasksList"  />
@@ -17,7 +17,7 @@
 <script setup>
 import { ref, onActivated, watch } from 'vue';
 import { useLifecycle } from '@hooks/useCommon.js';
-import { GET_ORDER_RELATED_TASKS, OBTAIN_ORDER_RELATED_PRODUCTS } from "@hooks/useApi"
+import { GET_ORDER_RELATED_TASKS, OBTAIN_ORDER_RELATED_PRODUCTS, SALES_ORDER_DETAILS } from "@hooks/useApi"
 import requests from "@common/requests";
 import OrderInfo from './orderInfo.vue';
 import RelatedTasks from '../tasks/relatedTasks.vue';
@@ -33,6 +33,8 @@ const props = defineProps({
 const tabActive = ref('销售订单信息');
 const relatedTasksList = ref([]);
 const relatedProductsList = ref([]);
+const infoData = ref(props.info);
+const timeout = ref(null);
 
 watch(() => props.info, (newValue) => {
   tabActive.value = '销售订单信息';
@@ -40,6 +42,9 @@ watch(() => props.info, (newValue) => {
 })
 
 function getDetailedData(id) {
+  requests.post(SALES_ORDER_DETAILS, { id }).then(({ data }) => {
+    infoData.value = data || []
+  })
   requests.post(GET_ORDER_RELATED_TASKS, { id }).then(({ data }) => {
     relatedTasksList.value = data || []
   })
@@ -60,13 +65,23 @@ function getDetailedData(id) {
 }
 
 function processingData(id) {
-  getDetailedData(id)
+  clearTimeout(timeout.value);
+  timeout.value = setTimeout(() => {
+    getDetailedData(id)
+  }, 100);
 }
 
 useLifecycle({
   init: () => {
     tabActive.value = '销售订单信息';
     processingData(props.info.id)
+  },
+  load: () => {
+    tabActive.value = '销售订单信息';
+    processingData(props.info.id)
+  },
+  unload: () => {
+    clearTimeout(timeout.value)
   }
 });
 </script>

+ 121 - 0
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/order/orderInfo.vue

@@ -46,14 +46,49 @@
       </van-cell>
       <van-cell title="备注" :value="info.remark" />
     </div>
+    <div class="bottomButton">
+      <van-button type="warning" class="w-full block" v-if="info.inchargerName"  @click="showDialogCli()">转移销售订单</van-button>
+      <van-button type="default" class="w-full block" v-permission="[routingInformation.jurisdiction.edit]" @click="jumpEdit()">编辑销售订单</van-button>
+      <van-button type="danger" class="w-full block" v-permission="[routingInformation.jurisdiction.delete]" @click="deleteRow()">删除销售订单</van-button>
+    </div>
+
+    <!-- 转移弹窗 -->
+    <van-dialog v-model:show="showDialog" :title="`转移线索`" show-cancel-button
+      @confirm="confirmTransfer" :before-close="dialogCloseBefo">
+      <van-cell title="转移至" is-link @click="showSelect = true">
+        <template #value>
+          {{ dialogSelection.label }}
+        </template>
+      </van-cell>
+      <div class="themeTextColor text-size-small pl-4 pt-2 pb-2">转移后,将看不到此线索了</div>
+    </van-dialog>
+
+    <!-- select 选择器 -->
+    <van-popup v-model:show="showSelect" destroy-on-close position="bottom" :style="{ height: '80%' }">
+      <PullDownSelector @change="selectChange" />
+    </van-popup>
   </div>
 </template>
 
 <script setup>
 import { ref } from 'vue';
+import { showConfirmDialog } from 'vant';
 import { useLifecycle } from '@hooks/useCommon.js';
 import { fixedFieldPaymentStatus } from "@utility/defaultData" 
+import { TRANSFER_CLUES } from '@hooks/useApi'
+import requests from "@common/requests";
+import useShowToast from '@hooks/useToast'
+import useInfoStore from '@store/useInfoStore'
+import useRouterStore from "@store/useRouterStore.js";
+import { routingInfos } from "@utility/generalVariables"
+import { resetListData, getListFieldKey } from '@components/common/formForm/formCorrespondenceProcessing'
+import useFixedData from "@store/useFixedData.js"
+
 
+const fixedData = useFixedData()
+const router = useRouterStore()
+const userInfo = useInfoStore()
+const { toastSuccess, toastFail, toastText } = useShowToast()
 const props = defineProps({
   info: {
     type: Object,
@@ -62,6 +97,92 @@ const props = defineProps({
   }
 })
 
+const routingInformation = routingInfos['order']
+const showDialog = ref(false);
+const showSelect = ref(false);
+const dialogSelection = ref({});
+
+function deleteRow() {
+  const { name = '', searchFiled = {}, deteleFiled = '' } = routingInformation
+  const row = props.info
+  const foemVal = { [routingInformation.key == 'tasks' ? 'taskIds' : 'ids']: row.id }
+  showConfirmDialog({
+    title: `删除${name}`,
+    message: `确定删除【${row[searchFiled?.search]}】${name}吗?`,
+  }).then(() => {
+    requests.post(deteleFiled, { ...foemVal }).then((res) => {
+      toastSuccess('删除成功')
+      router.navigateBack({
+        success: () => {
+          router.emit('moduleListDetailParameter', {
+            row: JSON.stringify(routingInformation)
+          })
+        }
+      })
+    }).catch((err) => {
+      toastFail(err.msg ? err.msg : '删除失败')
+    })
+  })
+}
+
+function jumpEdit() {
+  const formJson = fixedData.formJson[routingInformation.key] || []
+  const formList = resetListData(formJson?.list)
+  const filedObj = getListFieldKey(formList, props.info)
+  const formVal = { ...filedObj, id: props.info.id }
+
+  router.navigateTo({
+    pathName: 'addEditor',
+    success: () => {
+      router.emit('addEditorParameter', {
+        routerInfo: JSON.stringify(routingInformation),
+        filedValue: JSON.stringify(formVal)
+      })
+    }
+  })
+}
+
+function listReloadData() {
+  router.navigateBack({
+    success: () => {
+      router.eventEmit('moduleListRefreshData', {})
+    }
+  })
+}
+function confirmTransfer() {
+  if(!dialogSelection.value.label) {
+    return toastText('请选择要转移的人员')
+  }
+
+  requests.post(TRANSFER_CLUES, { ids: props.info.id, inchargerId: dialogSelection.value.value }).then((res) => {
+    toastSuccess('转移成功')
+    showDialog.value = false
+    setTimeout(() => {
+      listReloadData()
+    }, 2000)
+  })
+}
+
+function selectChange(value, label) {
+  dialogSelection.value = {
+    value, label
+  }
+  showSelect.value = false
+}
+
+function showDialogCli() {
+  showDialog.value = true
+}
+
+function dialogCloseBefo(val) {
+  if(val == 'confirm' && showDialog.value) {
+    return false
+  }
+
+  return true
+}
+
+
 useLifecycle({
   load: () => {
     // 添加加载逻辑

+ 18 - 3
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/product/detail.vue

@@ -2,7 +2,7 @@
   <div class="w-full h-full">
     <van-tabs v-model:active="tabActive">
       <van-tab title="产品信息" name="产品信息">
-        <ProductInfo :info="info" />
+        <ProductInfo :info="infoData" />
       </van-tab>
       <van-tab title="相关商机" name="相关商机">
         <RelatedBusinessOpportunities :infoList="relatedBusinessOpportunitiesList"  />
@@ -17,7 +17,7 @@
 <script setup>
 import { ref, onActivated, watch } from 'vue';
 import { useLifecycle } from '@hooks/useCommon.js';
-import { OBTAIN_PRODUCT_RELATED_BUSINESS_OPPORTUNITIES, OBTAIN_SALES_ORDERS_RELATED_TO_THE_PRODUCT } from "@hooks/useApi"
+import { OBTAIN_PRODUCT_RELATED_BUSINESS_OPPORTUNITIES, OBTAIN_SALES_ORDERS_RELATED_TO_THE_PRODUCT, GET_PRODUCT_DETAILS } from "@hooks/useApi"
 import requests from "@common/requests";
 import ProductInfo from './productInfo.vue';
 import RelatedSalesOrders from '../order/relatedSalesOrders.vue';
@@ -33,6 +33,8 @@ const props = defineProps({
 const tabActive = ref('产品信息');
 const relatedBusinessOpportunitiesList = ref([]);
 const relatedSalesOrdersList = ref([]);
+const infoData = ref(props.info);
+const timeout = ref(null);
 
 watch(() => props.info, (newValue) => {
   tabActive.value = '产品信息';
@@ -40,6 +42,9 @@ watch(() => props.info, (newValue) => {
 })
 
 function getDetailedData(id) {
+  requests.post(GET_PRODUCT_DETAILS, { id }).then(({ data }) => {
+    infoData.value = data || {}
+  })
   requests.post(OBTAIN_PRODUCT_RELATED_BUSINESS_OPPORTUNITIES, { id }).then(({ data }) => {
     relatedBusinessOpportunitiesList.value = data || []
   })
@@ -49,13 +54,23 @@ function getDetailedData(id) {
 }
 
 function processingData(id) {
-  getDetailedData(id)
+  clearTimeout(timeout.value);
+  timeout.value = setTimeout(() => {
+    getDetailedData(id)
+  }, 100);
 }
 
 useLifecycle({
   init: () => {
     tabActive.value = '产品信息';
     processingData(props.info.id)
+  },
+  load: () => {
+    tabActive.value = '产品信息';
+    processingData(props.info.id)
+  },
+  unload: () => {
+    clearTimeout(timeout.value)
   }
 });
 </script>

+ 138 - 0
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/product/productInfo.vue

@@ -19,13 +19,52 @@
       </van-cell>
       <van-cell title="备注" :value="info.descs" />
     </div>
+    <div class="bottomButton">
+      <van-button type="warning" class="w-full block" v-if="info.inchargerName"
+        @click="showDialogCli()">转移产品</van-button>
+      <van-button type="primary" class="w-full block" v-if="!info.inchargerName"
+        @click="claimAndClaim()">认领产品</van-button>
+      <van-button type="default" class="w-full block" v-permission="[routingInformation.jurisdiction.edit]"
+        @click="jumpEdit()">编辑产品</van-button>
+      <van-button type="danger" class="w-full block" v-permission="[routingInformation.jurisdiction.delete]"
+        @click="deleteRow()">删除产品</van-button>
+    </div>
+
+    <!-- 转移弹窗 -->
+    <van-dialog v-model:show="showDialog" :title="`转移产品`" show-cancel-button @confirm="confirmTransfer"
+      :before-close="dialogCloseBefo">
+      <van-cell title="转移至" is-link @click="showSelect = true">
+        <template #value>
+          {{ dialogSelection.label }}
+        </template>
+      </van-cell>
+      <div class="themeTextColor text-size-small pl-4 pt-2 pb-2">转移后,将看不到此产品了</div>
+    </van-dialog>
+
+    <!-- select 选择器 -->
+    <van-popup v-model:show="showSelect" destroy-on-close position="bottom" :style="{ height: '80%' }">
+      <PullDownSelector @change="selectChange" />
+    </van-popup>
   </div>
 </template>
 
 <script setup>
 import { ref } from 'vue';
+import { showConfirmDialog } from 'vant';
 import { useLifecycle } from '@hooks/useCommon.js';
+import { TRANSFER_PRODUCTS } from '@hooks/useApi'
+import requests from "@common/requests";
+import useShowToast from '@hooks/useToast'
+import useInfoStore from '@store/useInfoStore'
+import useRouterStore from "@store/useRouterStore.js";
+import { routingInfos } from "@utility/generalVariables"
+import { resetListData, getListFieldKey } from '@components/common/formForm/formCorrespondenceProcessing'
+import useFixedData from "@store/useFixedData.js"
 
+const fixedData = useFixedData()
+const router = useRouterStore()
+const userInfo = useInfoStore()
+const { toastSuccess, toastFail, toastText } = useShowToast()
 const props = defineProps({
   info: {
     type: Object,
@@ -34,6 +73,105 @@ const props = defineProps({
   }
 })
 
+const routingInformation = routingInfos['product']
+const showDialog = ref(false);
+const showSelect = ref(false);
+const dialogSelection = ref({});
+
+function deleteRow() {
+  const { name = '', searchFiled = {}, deteleFiled = '' } = routingInformation
+  const row = props.info
+  const foemVal = { [routingInformation.key == 'tasks' ? 'taskIds' : 'ids']: row.id }
+  showConfirmDialog({
+    title: `删除${name}`,
+    message: `确定删除【${row[searchFiled?.search]}】${name}吗?`,
+  }).then(() => {
+    requests.post(deteleFiled, { ...foemVal }).then((res) => {
+      toastSuccess('删除成功')
+      router.navigateBack({
+        success: () => {
+          router.emit('moduleListDetailParameter', {
+            row: JSON.stringify(routingInformation)
+          })
+        }
+      })
+    }).catch((err) => {
+      toastFail(err.msg ? err.msg : '删除失败')
+    })
+  })
+}
+
+function jumpEdit() {
+  const formJson = fixedData.formJson[routingInformation.key] || []
+  const formList = resetListData(formJson?.list)
+  const filedObj = getListFieldKey(formList, props.info)
+  const formVal = { ...filedObj, id: props.info.id }
+
+  router.navigateTo({
+    pathName: 'addEditor',
+    success: () => {
+      router.emit('addEditorParameter', {
+        routerInfo: JSON.stringify(routingInformation),
+        filedValue: JSON.stringify(formVal)
+      })
+    }
+  })
+}
+
+function listReloadData() {
+  router.navigateBack({
+    success: () => {
+      router.eventEmit('moduleListRefreshData', {})
+    }
+  })
+}
+function confirmTransfer() {
+  if (!dialogSelection.value.label) {
+    return toastText('请选择要转移的人员')
+  }
+
+  requests.post(TRANSFER_PRODUCTS, { id: props.info.id, userId: dialogSelection.value.value }).then((res) => {
+    toastSuccess('转移成功')
+    showDialog.value = false
+    setTimeout(() => {
+      listReloadData()
+    }, 2000)
+  })
+}
+
+function claimAndClaim() {
+  showConfirmDialog({
+    title: '认领线索',
+    message: `确定认领【${props.info.clueName}】线索吗?`,
+  }).then(() => {
+    requests.post(TRANSFER_PRODUCTS, { id: props.info.id, userId: userInfo.userInfo.id }).then((res) => {
+      toastSuccess('认领成功')
+      listReloadData()
+      props.info.inchargerName = userInfo.userInfo.clueName
+      showDialog.value = false
+    })
+  })
+}
+
+function selectChange(value, label) {
+  dialogSelection.value = {
+    value, label
+  }
+  showSelect.value = false
+}
+
+function showDialogCli() {
+  showDialog.value = true
+}
+
+function dialogCloseBefo(val) {
+  if (val == 'confirm' && showDialog.value) {
+    return false
+  }
+
+  return true
+}
+
 useLifecycle({
   load: () => {
     // 添加加载逻辑

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 3 - 3
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/utility/generalVariables.js