Lijy před 5 měsíci
rodič
revize
121f711e74

+ 25 - 4
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/components/common/formForm/formItem.vue

@@ -11,7 +11,9 @@
       :readonly="element.options?.readonly"
       :required="element.options?.rules?.required"
       :rules="[{ validator: characterVerification, message: '' }]"
-      :class="`${element.options?.rules?.required ? '' : 'resetStyles'} resetStyles-right`"
+      :class="`${
+        element.options?.rules?.required ? '' : 'resetStyles'
+      } resetStyles-right`"
     />
   </template>
   <template v-if="element.type === 'number'">
@@ -27,7 +29,9 @@
       :readonly="element.options?.readonly"
       :required="element.options?.rules?.required"
       :rules="[{ validator: characterVerification, message: '' }]"
-      :class="`${element.options?.rules?.required ? '' : 'resetStyles'} resetStyles-right`"
+      :class="`${
+        element.options?.rules?.required ? '' : 'resetStyles'
+      } resetStyles-right`"
     />
   </template>
   <!-- 正常的下拉框 -->
@@ -104,7 +108,9 @@
       :readonly="element.options?.readonly"
       :required="element.options?.rules?.required"
       :rules="[{ validator: characterVerification, message: '' }]"
-      :class="`${element.options?.rules?.required ? '' : 'resetStyles'} resetStyles-right`"
+      :class="`${
+        element.options?.rules?.required ? '' : 'resetStyles'
+      } resetStyles-right`"
     />
   </template>
 
@@ -132,6 +138,7 @@
     <PullDownSelector
       :options="element.options.options"
       :multipleChoice="element.options.multiple"
+      :doYouNeedTranslation="distinguishComponents"
       @change="selectChange"
     />
   </van-popup>
@@ -142,6 +149,7 @@ import { ref, reactive, computed, onMounted, defineEmits } from "vue";
 import dayjs from "dayjs";
 import requests from "@common/requests";
 import PullDownSelector from "@components/common/pullDownSelector.vue";
+import useFixedData from "@store/useFixedData";
 import { relatedField } from "./formCorrespondenceProcessing";
 
 const emit = defineEmits(["validateASingleForm", "cascadeProcessing"]);
@@ -152,6 +160,7 @@ const props = defineProps({
   },
 });
 
+const fixedData = useFixedData();
 const dateOfTheDay = dayjs().format("YYYY-MM-DD");
 const distinguishComponents = ref(false);
 const showPicker = ref(false);
@@ -234,14 +243,26 @@ function processingData() {
 // 发起接口请求
 function requestData(str = "") {
   const url = str.replace(/^(\/?api)/, "").trim();
+  if(url.indexOf("getSimpleActiveUserListNew") > -1 && fixedData.allUserData.length) {
+    props.element.options = fixedData.allUserData
+    return
+  }
+
   requests.post(url, {}).then(({ data }) => {
-    props.element.options.options = data.map((item) => {
+    const newData = data.map((item) => {
       const { props: setProps } = props.element.options;
       return {
         label: item[setProps.label || "label"],
         value: item[setProps.value || "value"],
       };
     });
+    props.element.options.options = newData
+    if(distinguishComponents.value && fixedData.allUserData.length == 0) {
+      fixedData.updateState({
+        allUserData: [ ...newData ]
+      })
+      return
+    }
   });
 }
 

+ 98 - 64
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/components/common/pullDownSelector.vue

@@ -1,106 +1,115 @@
 <template>
   <div class="w-full h-full flex flex-col">
     <div class="w-full pt-2">
-      <van-search
-        v-model.trim="searchForValue"
-        shape="round"
-        placeholder="请输入搜索关键词"
-        @update:model-value="debouncedSearchOptions"
-      />
+      <van-search v-model.trim="searchForValue" shape="round" placeholder="请输入搜索关键词"
+        @update:model-value="debouncedSearchOptions" />
     </div>
     <div class="flex-1 my-2 overflow-y-auto">
-      <template v-if="!multipleChoice">
-        <!-- 单选 -->
-        <van-radio-group v-model="selectChecked">
-          <template v-for="item in renderingOptions">
+      <!-- 加载 -->
+      <template v-if="listLoading">
+        <van-skeleton :row="10" />
+      </template>
+      <template v-else>
+        <template v-if="!multipleChoice">
+          <!-- 单选 -->
+          <van-radio-group v-model="selectChecked">
+            <template v-for="item in renderingOptions">
+              <van-cell-group inset>
+                <van-cell clickable @click="selectChecked = item.value">
+                  <template #right-icon>
+                    <van-radio :name="item.value" />
+                  </template>
+                  <template #title>
+                    {{ item.label }}
+                  </template>
+                </van-cell>
+              </van-cell-group>
+            </template>
+          </van-radio-group>
+        </template>
+        <!-- 多选 -->
+        <template v-if="multipleChoice">
+          <van-checkbox-group v-model="selectChecked">
             <van-cell-group inset>
-              <van-cell clickable @click="selectChecked = item.value">
+              <van-cell v-for="(item, index) in renderingOptions" clickable :key="index" @click="toggle(index)">
                 <template #right-icon>
-                  <van-radio :name="item.value" />
+                  <van-checkbox :name="item.value" :ref="(el) => (checkboxRefs[index] = el)" @click.stop />
                 </template>
                 <template #title>
                   {{ item.label }}
                 </template>
               </van-cell>
             </van-cell-group>
-          </template>
-        </van-radio-group>
-      </template>
-      <!-- 多选 -->
-      <template v-if="multipleChoice">
-        <van-checkbox-group v-model="selectChecked">
-          <van-cell-group inset>
-            <van-cell
-              v-for="(item, index) in renderingOptions"
-              clickable
-              :key="index"
-              @click="toggle(index)"
-            >
-              <template #right-icon>
-                <van-checkbox
-                  :name="item.value"
-                  :ref="(el) => (checkboxRefs[index] = el)"
-                  @click.stop
-                />
-              </template>
-              <template #title>
-                {{ item.label }}
-              </template>
-            </van-cell>
-          </van-cell-group>
-        </van-checkbox-group>
+          </van-checkbox-group>
+        </template>
       </template>
     </div>
     <div class="w-full pb-2 px-4">
-      <van-button
-        type="primary"
-        round
-        class="w-full"
-        :disabled="!selectChecked"
-        @click="confirmClick"
-        >确定</van-button
-      >
+      <van-button type="primary" round class="w-full" :disabled="!selectChecked || !selectChecked.length" @click="confirmClick">确定</van-button>
     </div>
   </div>
 </template>
 
 <script setup>
 import { ref, onBeforeUpdate, reactive, watch, onMounted } from "vue";
-import { manualCopying, useDebounce } from "@hooks/useCommon"
+import { manualCopying, useDebounce } from "@hooks/useCommon";
+import requests from "@common/requests";
+import { GET_ALL_PERSONNEL } from "@hooks/useApi";
+import useFixedData from "@store/useFixedData";
 
 const props = defineProps({
   options: {
     type: Array,
-    required: true,
     default: () => [],
   },
   value: {
     type: [String, Array],
-    default: () => null
+    default: () => null,
   },
-  multipleChoice: {
+  doYouNeedTranslation: {
     type: Boolean,
     default: () => true,
   },
+  multipleChoice: {
+    type: Boolean,
+    default: () => false,
+  },
 });
 
-const emit = defineEmits(['change'])
+const emit = defineEmits(["change"]);
+const fixedData = useFixedData();
 
+const listLoading = ref(false);
 const selectChecked = ref();
 const checkboxRefs = ref([]);
 const searchForValue = ref("");
-const allOptions = ref([])
-const renderingOptions = ref([])
+const allOptions = ref([]);
+const renderingOptions = ref([]);
 
 const debouncedSearchOptions = useDebounce(searchOptions, 500);
 
 function searchOptions(val) {
-  if(!val) {
-    renderingOptions.value = manualCopying(allOptions.value)
+  listLoading.value = true
+  if (!props.doYouNeedTranslation) {
+    setTimeout(() => {
+      listLoading.value = false
+    }, 200)
+    if (!val) {
+      renderingOptions.value = manualCopying(allOptions.value);
+      return;
+    }
+    const list = manualCopying(allOptions.value);
+    renderingOptions.value = list.filter((item) => item.label.indexOf(val) > -1);
     return
   }
-  const list = manualCopying(allOptions.value)
-  renderingOptions.value = list.filter(item => item.label.indexOf(val) > -1)
+
+  // 转译人员搜索
+  requests.post(GET_ALL_PERSONNEL, { keyword: val }).then((res) => {
+    const { data } = res
+    renderingOptions.value = [ ...data ]
+  }).finally(() => {
+    listLoading.value = false
+  })
 }
 
 function toggle(index) {
@@ -108,15 +117,35 @@ function toggle(index) {
 }
 
 function valueTaking(val) {
-  if(Array.isArray(val)) {
-    return allOptions.value.filter(item => val.includes(item.value)).map(item => item.label)
+  if (Array.isArray(val)) {
+    return allOptions.value
+      .filter((item) => val.includes(item.value))
+      .map((item) => item.label);
   } else {
-    return allOptions.value.find(item => item.value === val)?.label
+    return allOptions.value.find((item) => item.value === val)?.label;
+  }
+}
+
+function obtainPersonnelData() {
+  if (fixedData.allUserData && fixedData.allUserData.length) {
+    renderingOptions.value = [...fixedData.allUserData];
+    allOptions.value = [...fixedData.allUserData];
+    return;
   }
+  listLoading.value = true;
+  requests.post(GET_ALL_PERSONNEL, {}).then(({ data = [] }) => {
+    renderingOptions.value = [...data];
+    allOptions.value = [...data];
+    fixedData.updateState({
+      allUserData: [...data]
+    })
+  }).finally(() => {
+    listLoading.value = false;
+  })
 }
 
 function confirmClick() {
-  emit('change', selectChecked.value, valueTaking(selectChecked.value))
+  emit("change", selectChecked.value, valueTaking(selectChecked.value));
 }
 
 onBeforeUpdate(() => {
@@ -124,8 +153,13 @@ onBeforeUpdate(() => {
 });
 
 onMounted(() => {
-  selectChecked.value = props.multipleChoice ? [] : "";
-  renderingOptions.value = manualCopying(props.options)
-  allOptions.value = manualCopying(props.options)
+  selectChecked.value = props.multipleChoice ? [] : null;
+  const isItAnArray = Array.isArray(props.options);
+  if (isItAnArray && props.options.length > 0) {
+    renderingOptions.value = manualCopying(props.options);
+    allOptions.value = manualCopying(props.options);
+  } else {
+    obtainPersonnelData();
+  }
 });
 </script>

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

@@ -2,6 +2,7 @@ export const LOGIN_INTERFACE = `/user/loginAdmin` // 登录接口
 export const USER_ID_LOGIN = `/user/loginByUserId` // userId 登录
 export const WE_CHAT_LOGIN = `/wxcorp/corpWeiXinLogin` // 微信登录
 export const GET_CUSTOM_FORM_JSON = `/sys-form/getListByCode` // 获取自定义表单json
+export const GET_ALL_PERSONNEL = `/user/getSimpleActiveUserListNew` // 获取所有人员
 
 export const GET_A_LIST_OF_BUSINESS_OPPORTUNITIES = '/business-opportunity/list' // 获取商机列表
 export const GET_A_LIST_OF_CLUES = '/clue/listClue' // 获取线索列表
@@ -21,3 +22,6 @@ export const DELETE_PRODUCT = '/product/delete' // 删除产品
 export const DELETE_CONTRACT = '/contract/deleteContract' // 删除合同
 export const DELETE_ORDER = '/order/delete' // 删除订单
 
+export const BUSINESS_OPPORTUNITY_TRANSFER = '/business-opportunity/claim' // 转移商机
+export const TRANSFER_CLUES = '/clue/claim' // 转移线索
+export const TRANSFER_CUSTOMERS = '/custom/claim' // 转移客户

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

@@ -1,5 +1,5 @@
 import 'vant/es/notify/style';
-import { Toast, showLoadingToast, showSuccessToast, showFailToast, closeToast } from "vant";
+import { Toast, showToast, showLoadingToast, showSuccessToast, showFailToast, closeToast } from "vant";
 
 /**
  * 文字:Toast 提示组件

+ 56 - 6
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/moduleList/moduleList.vue

@@ -1,9 +1,9 @@
 <template>
-  <Page :title='`${queryParameters?.name}列表`'>
+  <Page :title='`${queryParameters.name}列表`'>
     <template v-slot:body>
       <div class="flex flex-col h-full">
         <!-- 搜索 -->
-        <div class="mx-1">
+        <div class="mx-1 headerModeuleList">
           <van-search v-model.trim="searchVal" background="#F8F8F8" :placeholder="`请输入${queryParameters?.name}关键词`"
             @search="onRefresh(true)" @clear="onRefresh(true)">
             <template v-slot:left-icon>
@@ -69,6 +69,22 @@
           添加
         </div>
       </DragBox>
+
+      <!-- 转移弹窗 -->
+      <van-dialog v-model:show="showDialog" :title="`转移${queryParameters?.name || ''}`" 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">转移后,将看不到此{{ queryParameters?.name || '' }}</div>
+      </van-dialog>
+
+      <!-- select 选择器 -->
+      <van-popup v-model:show="showSelect" destroy-on-close position="bottom" :style="{ height: '80%' }">
+        <PullDownSelector @change="selectChange" />
+      </van-popup>
     </template>
   </Page>
 </template>
@@ -91,11 +107,11 @@ const DELETE = 'delete';
 const EDIT = 'edit';
 const TOP_MOUNTED = 'topMounted';
 
-const { toastSuccess, toastFail } = useShowToast()
+const { toastSuccess, toastFail, toastText } = useShowToast()
 const router = useRouterStore()
 const fixedData = useFixedData()
 const searchVal = ref()
-const queryParameters = ref()
+const queryParameters = ref({})
 const loadingList = ref(false)
 const popUpWindowArray = ref([
   { text: '转移', event: TRANSFER, bg: '#FFA359', removeModule: ['contacts', 'tasks', 'product', 'contract', 'order'] },
@@ -103,6 +119,8 @@ const popUpWindowArray = ref([
   { text: '编辑', event: EDIT, bg: '#07C160', removeModule: [] },
   { text: '删除', event: DELETE, bg: '#FF6A6A', removeModule: [] },
 ])
+const showSelect = ref(false)
+const showDialog = ref(false)
 const refreshing = ref(false);
 const isLoading = ref(false);
 const finished = ref(false);
@@ -113,6 +131,8 @@ const listData = ref({
   total: 0,
   totalPage: 0,
 });
+const excessiveData = ref({});
+const dialogSelection = ref({});
 
 // 按钮触发的事件: row 为当前点击的行数据, item 为当前点击的按钮
 function longPress(row, item) {
@@ -145,7 +165,22 @@ function edit(row) {
 
 // 转移事件
 function transfer(row) {
-  console.log(row, '<======= 转移事件')
+  dialogSelection.value = {}
+  excessiveData.value = row
+  showDialog.value = true
+}
+
+function confirmTransfer() {
+  if(!dialogSelection.value.label) {
+    return toastText('请选择要转移的人员')
+  }
+  const { id } = excessiveData.value
+  const { value } = dialogSelection.value
+  requests.post(queryParameters?.value.transferInterface, { ids: id, inchargerId: value }).then((res) => {
+    toastSuccess('转移成功')
+    onRefresh(true)
+    showDialog.value = false
+  })
 }
 
 // 删除事件
@@ -277,6 +312,21 @@ function getFormJson(info = {}) {
   })
 }
 
+function selectChange(value, label) {
+  dialogSelection.value = {
+    value, label
+  }
+  showSelect.value = false
+}
+
+function dialogCloseBefo(val) {
+  if(val == 'confirm' && showDialog.value) {
+    return false
+  }
+
+  return true
+}
+
 useLifecycle({
   load: () => {
     router.on('moduleListDetailParameter', (data) => {
@@ -315,7 +365,7 @@ useLifecycle({
   }
 }
 
-::v-deep .van-search__content {
+.headerModeuleList  ::v-deep .van-search__content {
   background: #fff !im\portant;
   height: 42px;
   align-items: center;

+ 6 - 3
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/utility/generalVariables.js

@@ -1,4 +1,4 @@
-import { GET_A_LIST_OF_BUSINESS_OPPORTUNITIES, GET_A_LIST_OF_CLUES, GET_CONTACT_LIST, GET_CUSTOMER_LIST, GET_TASK_LIST, GET_CONTRACT_LIST, GET_SALES_ORDER_LIST, GET_PRODUCT_LIST, DELETE_BUSINESS_OPPORTUNITY, DELETE_CLUES, DELETE_CUSTOMER, DELETE_CONTACTS, DELETE_TASK, DELETE_PRODUCT, DELETE_CONTRACT, DELETE_ORDER } from '@hooks/useApi'
+import { GET_A_LIST_OF_BUSINESS_OPPORTUNITIES, GET_A_LIST_OF_CLUES, GET_CONTACT_LIST, GET_CUSTOMER_LIST, GET_TASK_LIST, GET_CONTRACT_LIST, GET_SALES_ORDER_LIST, GET_PRODUCT_LIST, DELETE_BUSINESS_OPPORTUNITY, DELETE_CLUES, DELETE_CUSTOMER, DELETE_CONTACTS, DELETE_TASK, DELETE_PRODUCT, DELETE_CONTRACT, DELETE_ORDER, BUSINESS_OPPORTUNITY_TRANSFER, TRANSFER_CLUES, TRANSFER_CUSTOMERS } from '@hooks/useApi'
 
 export const routingInfos = {
   'business': {
@@ -6,8 +6,9 @@ export const routingInfos = {
     key: 'business', // 唯一标识
     icon: 'icon-shangpin', // 图标
     listUrl: GET_A_LIST_OF_BUSINESS_OPPORTUNITIES, // 列表请求接口
-    deteleFiled: DELETE_BUSINESS_OPPORTUNITY, // 删除请求接口和字段
-    searchFiled: { search: 'name' },
+    deteleFiled: DELETE_BUSINESS_OPPORTUNITY, // 删除请求接口
+    transferInterface: BUSINESS_OPPORTUNITY_TRANSFER, // 转移请求接口
+    searchFiled: { search: 'name' }, // 搜索字段
     image: '', // 图片
   },
   'thread': {
@@ -16,6 +17,7 @@ export const routingInfos = {
     icon: 'icon-shangpin',
     listUrl: GET_A_LIST_OF_CLUES,
     deteleUrl: DELETE_CLUES,
+    transferInterface: TRANSFER_CLUES,
     searchFiled: { search: 'clueName' },
     image: '',
   },
@@ -25,6 +27,7 @@ export const routingInfos = {
     icon: 'icon-shangpin',
     listUrl: GET_CUSTOMER_LIST,
     deteleFiled: DELETE_CUSTOMER,
+    transferInterface: TRANSFER_CUSTOMERS,
     searchFiled: { search: 'customName' },
     image: '',
   },