Browse Source

Merge branch 'master' of http://47.100.37.243:10191/wutt/manHourHousekeeper

zhouyy 5 tháng trước cách đây
mục cha
commit
9090084b34
27 tập tin đã thay đổi với 796 bổ sung144 xóa
  1. 22 0
      fhKeeper/formulahousekeeper/customerBuler-crm/package-lock.json
  2. 1 0
      fhKeeper/formulahousekeeper/customerBuler-crm/package.json
  3. 2 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/TaskModal/taskFunction.ts
  4. 79 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/svgIcon/index.vue
  5. 8 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/api.ts
  6. 2 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/information.vue
  7. 229 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/kanbanView.vue
  8. 36 16
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/stageSetting.vue
  9. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/detail/index.vue
  10. 125 63
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/index.vue
  11. 9 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/type.d.ts
  12. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/component/relatedBusiness.vue
  13. 2 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/relatedBusiness.vue
  14. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/thread/detail/components/information.vue
  15. 2 4
      fhKeeper/formulahousekeeper/customerBuler-crm/src/styles/global.scss
  16. 3 0
      fhKeeper/formulahousekeeper/customerBuler-crm/vite.config.ts
  17. 15 5
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/BusinessOpportunityController.java
  18. 4 3
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/BusinessOpportunity.java
  19. 28 14
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/BusinessOpportunityServiceImpl.java
  20. 7 4
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ContactsServiceImpl.java
  21. 10 14
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/BusinessOpportunityMapper.xml
  22. 2 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/AuthRedirectController.java
  23. 29 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/PrivateDeployUrlGenerator.java
  24. 116 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/application-privatewx.yml
  25. 9 3
      fhKeeper/formulahousekeeper/timesheet/src/common/js/appidConfiguration.js
  26. 45 0
      fhKeeper/formulahousekeeper/timesheet_h5/src/utils/appidConfiguration.js
  27. 8 5
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/login/index.vue

+ 22 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/package-lock.json

@@ -19,6 +19,7 @@
         "pinia": "^2.1.7",
         "pinia-plugin-persistedstate": "^3.2.1",
         "vue": "^3.4.19",
+        "vue-draggable-plus": "^0.6.0",
         "vue-router": "^4.3.0",
         "vuex": "^4.1.0"
       },
@@ -868,6 +869,11 @@
         "undici-types": "~5.26.4"
       }
     },
+    "node_modules/@types/sortablejs": {
+      "version": "1.15.8",
+      "resolved": "https://registry.npmmirror.com/@types/sortablejs/-/sortablejs-1.15.8.tgz",
+      "integrity": "sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg=="
+    },
     "node_modules/@types/web-bluetooth": {
       "version": "0.0.16",
       "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
@@ -2950,6 +2956,22 @@
         }
       }
     },
+    "node_modules/vue-draggable-plus": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmmirror.com/vue-draggable-plus/-/vue-draggable-plus-0.6.0.tgz",
+      "integrity": "sha512-G5TSfHrt9tX9EjdG49InoFJbt2NYk0h3kgjgKxkFWr3ulIUays0oFObr5KZ8qzD4+QnhtALiRwIqY6qul4egqw==",
+      "dependencies": {
+        "@types/sortablejs": "^1.15.8"
+      },
+      "peerDependencies": {
+        "@types/sortablejs": "^1.15.0"
+      },
+      "peerDependenciesMeta": {
+        "@vue/composition-api": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/vue-router": {
       "version": "4.3.2",
       "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.3.2.tgz",

+ 1 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/package.json

@@ -22,6 +22,7 @@
     "pinia": "^2.1.7",
     "pinia-plugin-persistedstate": "^3.2.1",
     "vue": "^3.4.19",
+    "vue-draggable-plus": "^0.6.0",
     "vue-router": "^4.3.0",
     "vuex": "^4.1.0"
   },

+ 2 - 2
fhKeeper/formulahousekeeper/customerBuler-crm/src/components/TaskModal/taskFunction.ts

@@ -9,8 +9,8 @@ export async function createTask(submitData: any, isClose: boolean) : Promise<Ta
         const { executorId, startDate, endDate, repeatEndDate } = submitData;
         let params = {
             ...submitData,
-            startDate: startDate && dayjs(startDate).format('YYYY-MM-DD 00:00:00'),
-            endDate: endDate && dayjs(endDate).format('YYYY-MM-DD 23:59:59'),
+            startDate: startDate && dayjs(startDate).format('YYYY-MM-DD'),
+            endDate: endDate && dayjs(endDate).format('YYYY-MM-DD'),
             repeatEndDate: repeatEndDate && dayjs(repeatEndDate).format('YYYY-MM-DD 23:59:59')
         }
         if (executorId) {

+ 79 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/components/svgIcon/index.vue

@@ -0,0 +1,79 @@
+<template>
+  <div v-if="isColorIcon || isSvgIcon">
+    <svg :style="setIconSVGStyle" aria-hidden="true" class="icon">
+      <use :xlink:href="'#icon-' + name"></use>
+    </svg>
+  </div>
+  <i v-else :class="getIconName" :style="setIconSvgStyle"/>
+</template>
+
+<script lang="ts" name="svgIcon" setup>
+import 'http://at.alicdn.com/t/c/font_4766628_7ekfe85jxt9.js' // 引入阿里图标库
+import {computed} from 'vue';
+
+// 定义父组件传过来的值
+const props = defineProps({
+  name: { // svg 图标组件名字
+    type: String,
+  },
+  size: { // svg 大小
+    type: Number,
+    default: () => 14,
+  },
+  color: { // svg 颜色
+    type: String,
+  },
+  colorIcon: { //彩色
+    type: Boolean,
+    default: false,
+  },
+  isSvg: { // 是否是阿里图标库
+    type: Boolean,
+    default: true,
+  }
+});
+
+const linesString = ['https', 'http', '/src', '/assets', 'data:image', import.meta.env.VITE_PUBLIC_PATH];
+
+const getIconName = computed(() => {
+  return 'iconfont icon-' + props?.name;
+});
+// 用于判断 element plus 自带 svg 图标的显示、隐藏
+const isShowIconSvg = computed(() => {
+  return props?.name?.startsWith('ele-');
+});
+// 用于判断在线链接、本地引入等图标显示、隐藏
+const isShowIconImg = computed(() => {
+  return linesString.find((str) => props.name?.startsWith(str));
+});
+// 设置图标样式
+const setIconSvgStyle = computed(() => {
+  return `font-size: ${props.size}px;color: ${props.color};`;
+});
+// 设置图片样式
+const setIconImgOutStyle = computed(() => {
+  return `width: ${props.size}px;height: ${props.size}px;display: inline-block;overflow: hidden;`;
+});
+// 设置图片样式
+// https://gitee.com/lyt-top/vue-next-admin/issues/I59ND0
+const setIconSvgInsStyle = computed(() => {
+  const filterStyle: string[] = [];
+  const compatibles: string[] = ['-webkit', '-ms', '-o', '-moz'];
+  compatibles.forEach((j) => filterStyle.push(`${j}-filter: drop-shadow(${props.color} 30px 0);`));
+  return `width: ${props.size}px;height: ${props.size}px;position: relative;left: -${props.size}px;${filterStyle.join('')}`;
+});
+
+const setIconSVGStyle = computed(() => {
+  return `width: ${props.size}px;height: ${props.size}px;display: inline-block;overflow: hidden;`;
+});
+//是否是彩色图标
+const isColorIcon = computed(() => {
+  
+  return props.colorIcon;
+});
+// 是否是阿里图标库
+const isSvgIcon = computed(() => {
+  
+  return props.isSvg;
+});
+</script>

+ 8 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/api.ts

@@ -24,6 +24,14 @@ export const URL_SAVECONTACT = `/business-opportunity/saveContactsId`
 export const URL_STAGEIDNEXT = `/business-opportunity/saveStageId`
 export const URL_SAVEREASON = `/business-opportunity/saveReason`
 export const URL_EXPORTBUSINESS = `/business-opportunity/exportData`
+export const PANEL_MOBILE_DATA = `/business-opportunity/changeOrder`
+
+// 看板视图
+export const OBTAIN_KANBAN_VIEW_DATA = `/business-opportunity/getAllByStage`
+
+// 看板类型
+export const TABLE_VIEW = 'table'
+export const KANBAN_VIEW = 'view'
 
 
 export const stageStatus = [

+ 2 - 2
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/information.vue

@@ -130,7 +130,7 @@ import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffec
 import { GenerateForm } from '@zmjs/form-design';
 import { get, post } from '@/utils/request';
 import { BATCHTRANSFER, GETGENERATEFOEM, GETPERSONNEL, UPDATEINSET, URL_SAVECONTACT } from '../api';
-import { formatDateTime } from '@/utils/times';
+import { formatDate, formatDateTime } from '@/utils/times';
 import { confirmAction } from '@/utils/tools';
 import { useStore } from '@/store/index'
 import { URL_GETALL } from '@/pages/contacts/api';
@@ -222,7 +222,7 @@ function editBusiness() {
         let formVal = {
             id: information.value.id,
             ...res,
-            expectedTransactionDate: res.expectedTransactionDate ? formatDateTime(new Date(res.expectedTransactionDate)) : '',
+            expectedTransactionDate: res.expectedTransactionDate ? formatDate(new Date(res.expectedTransactionDate)) : '',
             businessItemProductList: JSON.stringify(productTableListValue.value)
         }
         allLoading.businessSaveLading = true

+ 229 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/kanbanView.vue

@@ -0,0 +1,229 @@
+<script lang="ts" setup>
+import { ref, reactive, onMounted, inject } from "vue";
+import { useRouter, useRoute } from "vue-router";
+import { VueDraggable } from 'vue-draggable-plus';
+import { MOD, OBTAIN_KANBAN_VIEW_DATA, PANEL_MOBILE_DATA, URL_STAGEIDNEXT } from '../api'
+import { Loading, MoreFilled } from '@element-plus/icons-vue'
+import { post, get, uploadFile } from "@/utils/request";
+
+import SvgIcon from "@/components/svgIcon/index.vue";
+import { formatDate, formatDateTime } from "@/utils/times";
+
+const emit = defineEmits()
+const router = useRouter()
+const viewList = ref<viewListInterface[]>([])
+const excessiveData = ref<any>({})
+const selectionStage = ref<number>()
+const switchingStagesVisable = ref(false)
+const allLoading = reactive({
+  kanbanViewLoading: false,
+  switchingStagesLoading: false
+})
+
+onMounted(() => {
+  getKanbanViewData();
+})
+
+function promotionStage() {
+  const item = viewList.value.find((item: any) => item.id == selectionStage.value)
+  const { id: stageId, label: stageValue } = item as any
+  allLoading.switchingStagesLoading = true
+  post(URL_STAGEIDNEXT, { id: excessiveData.value.id, stageId, stageValue }).then(() => {
+    switchingStagesVisable.value = false
+    getKanbanViewData()
+  }).finally(() => {
+    allLoading.switchingStagesLoading = false
+  })
+}
+
+function switchingStages(row: any) {
+  excessiveData.value = row
+  switchingStagesVisable.value = true
+}
+
+function onChange(e: any) {
+  const data = {
+    id: e.data.id,
+    oldIndex: e.oldIndex,
+    newIndex: e.newIndex,
+    oldStagesId: e.from.id,
+    newStagesId: e.to.id
+  }
+  setDataLoading(viewList.value, data.newStagesId, data.id, true)
+  post(PANEL_MOBILE_DATA, { ...data }).then(() => {
+    getKanbanViewData()
+  }).finally(() => {
+    setDataLoading(viewList.value, data.newStagesId, data.id, false)
+  })
+}
+
+function setDataLoading(list: any, targetLevel_1Id: number | string, targetLevel_2Id: number | string, flag: boolean) {
+  for (let i = 0; i < list.length; i++) {
+    if (list[i].id == targetLevel_1Id) {
+      for (let j = 0; j < list[i].list.length; j++) {
+        if (list[i].list[j].id == targetLevel_2Id) {
+          list[i].list[j].loadData = flag;
+        }
+      }
+    }
+  }
+}
+
+function selectData(_value: boolean, _row: any) {
+  let data = [...viewList.value].flatMap(item =>
+    item.list.filter(subItem => subItem.multipleChoice)
+  );
+  let newData =  JSON.parse(JSON.stringify(data))
+  newData.forEach((item: any) => {
+    delete item.multipleChoice
+    delete item.loadData
+  });
+
+  emit('kanbanViewClick', 'multipleChoice', newData)
+}
+
+function deteleItem(row: any) {
+  emit('kanbanViewClick', 'delete', row)
+}
+
+function editItem(row: any) {
+  emit('kanbanViewClick', 'edit', row)
+}
+
+function addTaskItem(row: any) {
+  emit('kanbanViewClick', 'addTask', row)
+}
+
+function toDetailPath(row: any) {
+  router.push({
+    path: `${MOD}/detail`,
+    query: { id: row.id }
+  })
+}
+
+function searchDashboardView(row: businessOpportunityFormType) {
+  getKanbanViewData(row || {})
+}
+
+function getKanbanViewData(formVal: any = {}) { // 获取看板视图数据
+  allLoading.kanbanViewLoading = true
+  post(OBTAIN_KANBAN_VIEW_DATA, { ...formVal }).then(res => {
+    res.data.forEach((item: any) => {
+      item.list = setArrList(item.list)
+    })
+    emit('kanbanViewClick', 'multipleChoice', [])
+    viewList.value = res.data || []
+  }).finally(() => {
+    allLoading.kanbanViewLoading = false
+  })
+}
+
+function setArrList(value: any) {
+  const val = Array.isArray(value) ? value : []
+  return val.map((item: any) => {
+    return {
+      ...item,
+      expectedTransactionDate: item.expectedTransactionDate ? formatDate(new Date(item.expectedTransactionDate)) : '',
+      multipleChoice: false,
+      loadData: false
+    }
+  })
+}
+
+defineExpose({
+  searchDashboardView,
+});
+
+</script>
+
+<template>
+  <div class="w-full h-full overflow-auto flex pb-3 scroll-bar" v-loading="allLoading.kanbanViewLoading">
+    <template v-if="viewList.length > 0">
+      <div class="w-auto h-full" v-for="(item, index) in viewList" :key="index">
+        <div class="h-full flex flex-col mx-3 w-72">
+          <div class="w-full flex justify-between px-3 py-3">
+            <div class="w-9/12">
+              <div class="w-auto px-4 py-1 text-white rounded-2xl" :style="{ backgroundColor: item.color }">
+                {{ item.label }}
+              </div>
+            </div>
+            <div class="w-2/12 text-right">{{ item.length }}</div>
+          </div>
+          <VueDraggable v-model="item.list" class="flex-1 overflow-y-auto overflow-x-hidden scroll-bar" :animation="150"
+            group="people" @update="onChange" @add="onChange" :id="item.id">
+            <div
+              class="break-words border border-inherit rounded h-72 mx-3 my-3 p-3 shadow-md hover:shadow-xl duration-300 ease-in-out cursor-pointer"
+              v-for="(subItem, subIndex) in item.list" :key="subIndex" v-loading="subItem.loadData">
+              <div class="w-full text-left text-lg flex flex-row items-center" :style="{ color: item.color }">
+                <el-checkbox v-model="subItem.multipleChoice" class="pr-2" size="large"
+                  @change="(val: any) => selectData(val, subItem)" />
+                <div class="flex-1 truncate" @click.stop="toDetailPath(subItem)" v-ellipsis-tooltip>
+                  {{ subItem.name }}
+                </div>
+                <el-dropdown placement="bottom-start">
+                  <el-link :icon="MoreFilled" :underline="false"></el-link>
+                  <template #dropdown>
+                    <el-dropdown-menu>
+                      <el-dropdown-item @click="addTaskItem(subItem)">新建任务</el-dropdown-item>
+                      <el-dropdown-item @click="switchingStages(subItem)">切换阶段</el-dropdown-item>
+                      <el-dropdown-item @click="editItem(subItem)">编辑</el-dropdown-item>
+                      <el-dropdown-item @click="deteleItem(subItem)">删除</el-dropdown-item>
+                    </el-dropdown-menu>
+                  </template>
+                </el-dropdown>
+              </div>
+              <div class="flex items-center mt-4">
+                <SvgIcon name="kehu" :size="20" class="mr-2" />
+                {{ subItem.customerName }}
+              </div>
+              <div class="flex items-center mt-4">
+                <SvgIcon name="lianxiren" :size="20" color="#606266" class="mr-2" />
+                {{ subItem.contactsName }}
+              </div>
+              <div class="flex items-center mt-4">
+                <SvgIcon name="fuzeren" :size="20" color="#606266" class="mr-2" />
+                {{ subItem.inchargerName }}
+              </div>
+              <div class="flex items-center mt-4">
+                ¥ {{ subItem.amountOfMoney || 0 }}
+              </div>
+              <div class="flex items-center mt-4">
+                {{ subItem.expectedTransactionDate }}
+              </div>
+            </div>
+          </VueDraggable>
+        </div>
+      </div>
+    </template>
+    <template v-if="viewList.length == 0">
+      <div class="w-full h-full flex items-center justify-center">
+        <el-empty description="暂无数据" />
+      </div>
+    </template>
+
+    <!-- 弹窗 -->
+    <el-dialog width="700px" v-model="switchingStagesVisable" append-to-body :show-close="false">
+      <template #header="{ close, titleId, titleClass }">
+        <div class="flex justify-between items-center border-b pb-3 dialog-header">
+          <h4 :id="titleId">切换阶段</h4>
+          <div>
+            <el-button type="primary" @click="promotionStage()" :loading="allLoading.switchingStagesLoading">保存</el-button>
+            <el-button @click="switchingStagesVisable = false">取消</el-button>
+          </div>
+        </div>
+      </template>
+      <div class="h-[80px] flex flex-col pt-5">
+        <div class="flex flex-row w-full items-center">
+          <div class="w-[100px] mr-2 text-right">切换阶段:</div>
+          <div class="flex-1">
+            <el-select v-model="selectionStage" placeholder="请选择" style="width: 240px">
+              <el-option v-for="item in viewList" :key="item.id" :label="item.label" :value="item.id" />
+            </el-select>
+          </div>
+        </div>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<style lang="scss" scoped></style>

+ 36 - 16
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/stageSetting.vue

@@ -21,6 +21,11 @@
                             </template>
                         </el-table-column>
                         <el-table-column :prop="'name'" :label="'阶段名称'"></el-table-column>
+                        <el-table-column :prop="'plan'" :label="'颜色'" width="100">
+                            <template #default="scope">
+                                <div class="w-full h-[20px]" :style="`background: ${scope.row.color}`"></div>
+                            </template>
+                        </el-table-column>
                         <el-table-column :prop="'plan'" :label="'进度'" width="100">
                             <template #default="scope">
                                 {{ scope.row.plan }} %
@@ -28,12 +33,14 @@
                         </el-table-column>
                         <el-table-column label="操作" fixed="right" width="200">
                             <template #default="scope">
-                                <el-button link type="primary" size="large" @click="addStage(scope.row)" :disabled="scope.row.isFinish == 1">编辑</el-button>
-                                <el-button link type="danger" size="large" @click="deteStage(+scope.$index, scope.row)" :disabled="scope.row.isFinish == 1">删除</el-button>
-                                <el-button link type="primary" size="large" @click="moveStage(+scope.$index, 'up')"
-                                    v-if="scope.$index != 0">上移</el-button>
-                                <el-button link type="primary" size="large" @click="moveStage(+scope.$index, 'down')"
-                                    v-if="scope.$index < stageTableList.length - 1">下移</el-button>
+                                <template v-if="scope.row.isFinish != 1">
+                                    <el-button link type="primary" size="large" @click="addStage(scope.row)" :disabled="scope.row.isFinish == 1">编辑</el-button>
+                                    <el-button link type="danger" size="large" @click="deteStage(+scope.$index, scope.row)" :disabled="scope.row.isFinish == 1">删除</el-button>
+                                    <el-button link type="primary" size="large" @click="moveStage(+scope.$index, 'up')"
+                                        v-if="scope.$index != 0">上移</el-button>
+                                    <el-button link type="primary" size="large" @click="moveStage(+scope.$index, 'down')"
+                                        v-if="scope.$index < stageTableList.length - 4">下移</el-button>
+                                </template>
                             </template>
                         </el-table-column>
                     </el-table>
@@ -59,12 +66,20 @@
                             <el-input v-model="stageForm.name" placeholder="请输入阶段名称" clearable></el-input>
                         </div>
                     </div>
-                    <div class="flex flex-row w-full items-center pt-3">
-                        <div class="w-[100px] mr-2 text-right">进度:</div>
-                        <div class="flex-1">
-                            <el-input-number v-model="stageForm.plan" controls-position="right" :min="0"
-                                :max="100"></el-input-number>
-                            <span class="inline-block ml-2">%</span>
+                    <div class="flex justify-between w-full items-center pt-3">
+                        <div class="flex items-center">
+                            <div class="w-[100px] mr-2 text-right">颜色:</div>
+                            <div class="flex-1">
+                                <el-color-picker v-model="stageForm.color" size="small" />
+                            </div>
+                        </div>
+                        <div class="flex items-center">
+                            <div class="w-[100px] mr-2 text-right">进度:</div>
+                            <div class="flex-1">
+                                <el-input-number v-model="stageForm.plan" controls-position="right" :min="0"
+                                    :max="100"></el-input-number>
+                                <span class="inline-block ml-2">%</span>
+                            </div>
                         </div>
                     </div>
                 </div>
@@ -76,18 +91,18 @@
 import { post } from '@/utils/request';
 import { ref, reactive, onMounted, watch, inject } from 'vue'
 import { BUSIESS_GETSATE, BUSIESS_SAVESAIE, URL_DETELESTAGE } from '../api';
-import { List } from 'echarts';
 
 type moveStageType = 'up' | 'down';
 type stageFormType = {
     name: string,
     plan: number,
     seq: number,
+    color: string,
     id?: number,
     isFinish?: number
 }
 
-const emits = defineEmits(['closeVisible']);
+const emits = defineEmits(['closeVisible', 'change']);
 const globalPopup = inject<GlobalPopup>('globalPopup')
 const stageVisible = ref(false)
 const stageTableList = ref<stageFormType[]>([])
@@ -102,6 +117,7 @@ const allVisible = reactive({
 const stageForm = reactive<stageFormType>({
     name: '',
     plan: 0,
+    color: '#075985',
     seq: 0,
 })
 
@@ -128,6 +144,7 @@ function saveState() {
     allLoading.saveLoading = true
     post(BUSIESS_SAVESAIE, { stages: JSON.stringify(data) }).then(() => {
         globalPopup?.showSuccess('保存成功')
+        emits('change')
         cancel()
     }).finally(() => {
         allLoading.saveLoading = false
@@ -147,7 +164,8 @@ function editState(flag: boolean) {
     if (listIndex != -1) {
         stageTableList.value.splice(listIndex, 1, newStage)
     } else {
-        stageTableList.value.push(newStage)
+        stageTableList.value.splice(stageTableList.value.length - 3, 0, newStage)
+        // stageTableList.value.push(newStage)
     }
 
     if (flag) {
@@ -166,6 +184,7 @@ function addStage(item: any) {
             name: row.name,
             plan: row.plan,
             seq: row.seq,
+            color: row.color,
             ...(row.id && { id: row.id }),
             ...(row.companyId && { companyId: row.companyId }),
             ...(row.isFinish && { isFinish: row.isFinish })
@@ -182,7 +201,8 @@ function resetStage() {
     let formVal = {
         name: '',
         plan: 0,
-        seq: +maxnum.seq + 1
+        seq: +maxnum.seq + 1,
+        color: '#075985'
     }
     delete stageForm.id
     delete stageForm.isFinish

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/detail/index.vue

@@ -11,7 +11,7 @@
           <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
         </el-select>
       </div>
-      <div class="flex-1 flex h-full justify-end overflow-auto scroll-bar-hide cursor-pointer" @wheel="handleScroll">
+      <div class="scroll-bar-hide h-full cursor-pointer" style="flex: 1;display: flex;overflow-x: auto;" @wheel="handleScroll">
         <div
           :class="`${index === 0 ? 'startStep' : 'nextStep'} ${(currentStage >= index || businessInfo.stageValue == '赢单') ? 'selected' : (currentStage >= index || businessInfo.stageValue == '输单') ? 'backOrange' : 'backGray'} relative rounded-md flex items-center pl-6 pr-6`"
           v-for="(item, index) in stageList" :key="index">

+ 125 - 63
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/index.vue

@@ -19,7 +19,7 @@
               <el-input v-model="businessOpportunityForm.contactsName" clearable placeholder="请输入"></el-input>
             </el-form-item>
             <el-form-item label="产品">
-              <el-select v-model="businessOpportunityForm.product" placeholder="请选择" clearable>
+              <el-select v-model="businessOpportunityForm.productId" placeholder="请选择" clearable>
                 <el-option v-for="item in fixedData.ProductArr" :key="item.value" :label="item.label"
                   :value="item.value" />
               </el-select>
@@ -28,7 +28,8 @@
               <!-- <el-select v-model="businessOpportunityForm.inchargerId" placeholder="请选择" clearable>
                 <el-option v-for="item in fixedData.Personnel" :key="item.id" :label="item.name" :value="item.id" />
               </el-select> -->
-              <personnel-search v-model="businessOpportunityForm.inchargerId" :size="''" placeholder="请选择"></personnel-search>
+              <personnel-search v-model="businessOpportunityForm.inchargerId" :size="''"
+                placeholder="请选择"></personnel-search>
             </el-form-item>
             <el-form-item label="创建时间">
               <el-date-picker v-model="businessOpportunityForm.startTime" type="date" placeholder="请选择"
@@ -42,61 +43,80 @@
         </div>
         <div class="w-full flex p-3 shadow-[0_-3px_5px_0px_rgba(0,0,0,0.2)]">
           <El-button class="w-full" @click="resetForm()">重置</El-Button>
-          <El-button type="primary" class="w-full" @click="getBusinessTableList()">搜索</El-Button>
+          <El-button type="primary" class="w-full" @click="searchForBusinessOpportunities()">搜索</El-Button>
         </div>
       </div>
     </div>
     <div class="flex-1 p-5 overflow-auto">
       <div class="bg-white w-full h-full p-3 shadow-md rounded-md flex flex-col">
-        <div class="flex justify-end pb-3">
-          <el-button v-permission="['businessAddAnEdit']" type="primary"
-            @click="editNewBusiness(false)">新建商机</el-button>
-          <el-button type="primary" @click="showVisible('batchTransferVisible')"
-            :disabled="batchTableData.length <= 0">批量转移</el-button>
-          <el-button type="primary" v-permission="['businessDelete']" @click="batchDeteleItem()"
-            :disabled="batchTableData.length <= 0">批量删除</el-button>
-          <el-button type="primary" @click="showVisible('stageSetVisible')">阶段设置</el-button>
-          <el-button type="primary" v-permission="['businessRecycle']"
-            @click="showVisible('deteleBusinessVisible')">回收站</el-button>
-          <el-button v-permission="['businessImport']" type="primary"
-            @click="showVisible('importVisible')">导入</el-button>
-          <el-button v-permission="['businessExport']" type="primary" @click="exportBusinessTableList()"
-            :loading="allLoading.exoprtLoading">导出</el-button>
+        <div class="flex justify-between pb-3">
+          <div>
+            <el-radio-group v-model="layoutSingleChoice" @change="viewsSwitching">
+              <el-radio-button label="看板视图" :value="KANBAN_VIEW" />
+              <el-radio-button label="表格视图" :value="TABLE_VIEW" />
+            </el-radio-group>
+          </div>
+          <div class="justify-end flex">
+            <el-button v-permission="['businessAddAnEdit']" type="primary"
+              @click="editNewBusiness(false)">新建商机</el-button>
+            <el-button type="primary" @click="showVisible('batchTransferVisible')"
+              :disabled="batchTableData.length <= 0">批量转移</el-button>
+            <el-button type="primary" v-permission="['businessDelete']" @click="batchDeteleItem()"
+              :disabled="batchTableData.length <= 0">批量删除</el-button>
+            <el-button type="primary" @click="showVisible('stageSetVisible')">阶段设置</el-button>
+            <el-button type="primary" v-permission="['businessRecycle']"
+              @click="showVisible('deteleBusinessVisible')">回收站</el-button>
+            <el-button v-permission="['businessImport']" type="primary"
+              @click="showVisible('importVisible')">导入</el-button>
+            <el-button v-permission="['businessExport']" type="primary" @click="exportBusinessTableList()"
+              :loading="allLoading.exoprtLoading">导出</el-button>
+          </div>
         </div>
-        <div class="flex-1 w-full overflow-hidden">
-          <el-table ref="businessTableRef" :data="businessTable" border v-loading="allLoading.businessTableLading"
-            :show-overflow-tooltip="tableShowOverflowTooltip" @selection-change="changeBatch"
-            style="width: 100%;height: 100%;">
-            <el-table-column type="selection" width="55" />
-            <el-table-column v-for="(item, index) in tableColumn" :prop="item.prop" :label="item.label" :key="index"
-              :width="item.width">
-              <template #default="scope">
-                <div class="table-text-textnowrap" v-if="item.eventName"
-                  @click="dealWithTableColumn(scope.row, item.eventName)">{{ scope.row[item.prop] }}</div>
-                <template v-else-if="['inchargerName', 'creatorName'].includes(item.prop)">
-                  <TextTranslation translationTypes="userName" :translationValue="scope.row[item.prop]"></TextTranslation>
+        <!-- 表格视图 -->
+        <template v-if="layoutSingleChoice == TABLE_VIEW">
+          <div class="flex-1 w-full overflow-hidden">
+            <el-table ref="businessTableRef" :data="businessTable" border v-loading="allLoading.businessTableLading"
+              :show-overflow-tooltip="tableShowOverflowTooltip" @selection-change="changeBatch"
+              style="width: 100%;height: 100%;">
+              <el-table-column type="selection" width="55" />
+              <el-table-column v-for="(item, index) in tableColumn" :prop="item.prop" :label="item.label" :key="index"
+                :width="item.width">
+                <template #default="scope">
+                  <div class="table-text-textnowrap" v-if="item.eventName"
+                    @click="dealWithTableColumn(scope.row, item.eventName)">{{ scope.row[item.prop] }}</div>
+                  <template v-else-if="['inchargerName', 'creatorName'].includes(item.prop)">
+                    <TextTranslation translationTypes="userName" :translationValue="scope.row[item.prop]">
+                    </TextTranslation>
+                  </template>
+                  <template v-else>{{ scope.row[item.prop] }}</template>
                 </template>
-                <template v-else>{{ scope.row[item.prop] }}</template>
-              </template>
-            </el-table-column>
-            <el-table-column label="操作" fixed="right" width="200"
-              v-permission="['businessAddAnEdit', 'tasksAdd', 'businessDelete']">
-              <template #default="scope">
-                <el-button link type="primary" size="large" @click="editNewBusiness(scope.row)"
-                  v-permission="['businessAddAnEdit']">编辑</el-button>
-                <el-button link type="primary" size="large" @click="newTask(scope.row)"
-                  v-permission="['tasksAdd']">新建任务</el-button>
-                <el-button link type="danger" size="large" @click="businessDeteleItem(scope.row.id, scope.row.name)"
-                  v-permission="['businessDelete']">删除</el-button>
-              </template>
-            </el-table-column>
-          </el-table>
-        </div>
-        <div class="flex justify-end pt-3">
-          <el-pagination layout="total, prev, pager, next, sizes" :page-size="businessOpportunityForm.pageFrom"
-            @size-change="handleSizeChange" @current-change="handleCurrentChange" :total="businessTotalTable"
-            :hide-on-single-page="true" />
-        </div>
+              </el-table-column>
+              <el-table-column label="操作" fixed="right" width="200"
+                v-permission="['businessAddAnEdit', 'tasksAdd', 'businessDelete']">
+                <template #default="scope">
+                  <el-button link type="primary" size="large" @click="editNewBusiness(scope.row)"
+                    v-permission="['businessAddAnEdit']">编辑</el-button>
+                  <el-button link type="primary" size="large" @click="newTask(scope.row)"
+                    v-permission="['tasksAdd']">新建任务</el-button>
+                  <el-button link type="danger" size="large" @click="businessDeteleItem(scope.row.id, scope.row.name)"
+                    v-permission="['businessDelete']">删除</el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+          <div class="flex justify-end pt-3">
+            <el-pagination layout="total, prev, pager, next, sizes" :page-size="businessOpportunityForm.pageFrom"
+              @size-change="handleSizeChange" @current-change="handleCurrentChange" :total="businessTotalTable"
+              :hide-on-single-page="true" />
+          </div>
+        </template>
+
+        <!-- 看板视图 --> 
+        <template v-else-if="layoutSingleChoice == KANBAN_VIEW">
+          <div class="flex-1 w-full h-full overflow-hidden">
+            <kanbanView ref="kanbanViewRef" @kanbanViewClick="kanbanViewClick" />
+          </div>
+        </template>
       </div>
     </div>
     <!-- 弹窗 -->
@@ -179,7 +199,7 @@
     <DeteleBusiness :visibles="allVisible.deteleBusinessVisible" @closeVisible="closeVisible" />
 
     <!-- 阶段设置 -->
-    <StageSetting :visibles="allVisible.stageSetVisible" @closeVisible="closeVisible" />
+    <StageSetting :visibles="allVisible.stageSetVisible" @closeVisible="closeVisible" @change="searchForBusinessOpportunities" />
   </div>
 </template>
 
@@ -187,7 +207,7 @@
 import { ref, reactive, onMounted, inject } from "vue";
 import type { ElTable, FormInstance, FormRules, UploadRequestOptions } from 'element-plus'
 import { useRouter, useRoute } from "vue-router";
-import { GETSYSFILED, MOD, GETPERSONNEL, GETGENERATEFOEM, GETBUSINESSLIST, UPDATEINSET, BUSINESSDETELE, BATCHTRANSFER, MODURL, tableColumn, BUSIESS_GETSATE, URL_IMPOERBUSINESS, BUSIESS_INFO, URL_EXPORTBUSINESS } from './api'
+import { GETSYSFILED, MOD, GETPERSONNEL, GETGENERATEFOEM, GETBUSINESSLIST, UPDATEINSET, BUSINESSDETELE, BATCHTRANSFER, MODURL, tableColumn, BUSIESS_GETSATE, URL_IMPOERBUSINESS, BUSIESS_INFO, URL_EXPORTBUSINESS, TABLE_VIEW, KANBAN_VIEW } from './api'
 import { GETTABLELIST } from '@/pages/product/api'
 import { post, get, uploadFile } from "@/utils/request";
 import { getAllListByCode, getFromValue, resetFromValue, getFirstDayOfMonth, createTaskFromType, formatDate, confirmAction, downloadTemplate, downloadFile, judgmentaAmounteEqual } from '@/utils/tools'
@@ -201,6 +221,7 @@ import DeteleBusiness from './component/deteleTables.vue'
 import StageSetting from './component/stageSetting.vue'
 import { GETTABLELISTPRODUCT } from "../order/api";
 import personnelSearch from '@/components/translationComponent/personnelSearch/personnelSearch.vue';
+import kanbanView from "./component/kanbanView.vue";
 
 const route = useRoute()
 const router = useRouter()
@@ -241,7 +262,7 @@ const allText = reactive({
 
 const taskModalForm = ref({}) // 任务弹窗表单
 const taskLoading = ref<saveLoadingType>("1");
-const batchTableData = ref([]) // 批量数据
+const batchTableData = ref<any>([]) // 批量数据
 const transferPersonnel = ref('') // 转移人
 
 const businessOpportunityForm = reactive<businessOpportunityFormType>({
@@ -249,7 +270,7 @@ const businessOpportunityForm = reactive<businessOpportunityFormType>({
   stageId: '',
   customerName: '',
   contactsName: '',
-  product: '',
+  productId: '',
   inchargerId: '',
   startTime: getFirstDayOfMonth(new Date()),
   endTime: formatDate(new Date()),
@@ -263,6 +284,8 @@ const fixedData = reactive({
 })
 const productTableList = ref([])
 const productTableListValue = ref([])
+const layoutSingleChoice = ref(KANBAN_VIEW)
+const kanbanViewRef = ref<any>(null)
 
 
 function editBusiness(visibles: boolean) {
@@ -278,7 +301,7 @@ function editBusiness(visibles: boolean) {
     })
     let newForm = {
       ...res,
-      expectedTransactionDate: res.expectedTransactionDate ? formatDateTime(new Date(res.expectedTransactionDate)) : '',
+      expectedTransactionDate: res.expectedTransactionDate ? formatDate(new Date(res.expectedTransactionDate)) : '',
       businessItemProductList: productTableListData ? JSON.stringify(productTableListData) : []
     }
     allLoading.businessSaveLading = true
@@ -286,7 +309,7 @@ function editBusiness(visibles: boolean) {
       post(UPDATEINSET, { ...businessTemplateValue.value, ...newForm }).then((_res) => {
         allVisible.newBusinessisible = visibles
         globalPopup?.showSuccess('保存成功')
-        getBusinessTableList()
+        searchForBusinessOpportunities()
       }).finally(() => {
         allLoading.businessSaveLading = false
       })
@@ -348,7 +371,7 @@ function transferBusiness() {
     transferPersonnel.value = ''
     globalPopup?.showSuccess('转移成功')
     closeVisible('batchTransferVisible')
-    getBusinessTableList()
+    searchForBusinessOpportunities()
   }).finally(() => {
     allLoading.transferLoading = false
   })
@@ -369,7 +392,7 @@ function businessDeteleItem(value: string | number, label: string, batch: boolea
       }
       globalPopup?.showSuccess('删除成功')
       changeBatch(false)
-      getBusinessTableList()
+      searchForBusinessOpportunities()
     }).catch((err) => {
       globalPopup?.showError(err.msg)
     })
@@ -385,7 +408,7 @@ async function importBusiness(param: UploadRequestOptions) {
   })
   if (res.code == 'ok') {
     globalPopup?.showSuccess('导入成功' || '')
-    getBusinessTableList()
+    searchForBusinessOpportunities()
     return
   }
   globalPopup?.showError(res.msg || '')
@@ -401,6 +424,34 @@ function exportBusinessTableList() {
   })
 }
 
+function viewsSwitching() {
+  batchTableData.value = []
+  resetForm()
+}
+
+function kanbanViewClick(type: 'multipleChoice' | 'delete' | 'edit' | 'addTask', data: any) {
+  if(type == 'multipleChoice') {
+    multipleChoiceBoxSwitching(Array.isArray(data) ? data : [])
+  }
+
+  if(type == 'delete') {
+    const { id, name = '' } = data
+    businessDeteleItem(id, name)
+  }
+
+  if(type == 'edit') {
+    editNewBusiness(data)
+  }
+
+  if(type == 'addTask') {
+    newTask(data)
+  }
+}
+
+function multipleChoiceBoxSwitching(list: any[] = []) {
+  batchTableData.value =  Array.isArray(list) ? list : []
+}
+
 function changeBatch(flag: boolean = true) {
   if (flag) {
     batchTableData.value = businessTableRef.value && businessTableRef.value.getSelectionRows()
@@ -431,12 +482,12 @@ function editBusinessData(item: any) {
 function handleSizeChange(val: number) {
   businessOpportunityForm.pageIndex = 1
   businessOpportunityForm.pageFrom = val
-  getBusinessTableList()
+  searchForBusinessOpportunities()
 }
 
 function handleCurrentChange(val: number) {
   businessOpportunityForm.pageIndex = val
-  getBusinessTableList()
+  searchForBusinessOpportunities()
 }
 
 function showVisible(type: keyof typeof allVisible) { // 显示弹窗
@@ -451,6 +502,17 @@ function handleClose(done: () => void) {
   done()
 }
 
+function searchForBusinessOpportunities() {
+  if(layoutSingleChoice.value == TABLE_VIEW) {
+    getBusinessTableList()
+  }
+
+  if(layoutSingleChoice.value == KANBAN_VIEW) {
+    const formValue = getFromValue(businessOpportunityForm)
+    kanbanViewRef.value.searchDashboardView({...formValue})
+  }
+}
+
 function getBusinessTableList() {
   const formValue = getFromValue(businessOpportunityForm)
   allLoading.businessTableLading = true
@@ -477,7 +539,7 @@ function resetForm() {
   }
   let newBusinessOpportunityForm = resetFromValue(businessOpportunityForm, { ...reset })
   Object.assign(businessOpportunityForm, newBusinessOpportunityForm)
-  getBusinessTableList()
+  searchForBusinessOpportunities()
 }
 
 async function getSystemField() {
@@ -560,7 +622,7 @@ function getProductTableList() {
 onMounted(() => {
   getSystemField()
   getProductTableList()
-  getBusinessTableList()
+  searchForBusinessOpportunities()
 })
 </script>
 

+ 9 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/type.d.ts

@@ -4,7 +4,7 @@ interface businessOpportunityFormType {
   stageId: string | number;
   customerName: string;
   contactsName: string;
-  product: string | number;
+  productId: string | number;
   inchargerId: string | number;
   startTime: string | number;
   endTime: string | number;
@@ -38,4 +38,12 @@ interface businessTableColumnInterface {
 interface productInterface {
   value: string | number;
   label: string;
+}
+
+interface viewListInterface {
+  label: string;
+  list: any[];
+  length?: number;
+  color?: string;
+  id: string | number;
 }

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/component/relatedBusiness.vue

@@ -109,7 +109,7 @@ function editBusiness() {
         }
         let newForm = {
             ...res,
-            expectedTransactionDate: res.expectedTransactionDate ? formatDateTime(new Date(res.expectedTransactionDate)) : '',
+            expectedTransactionDate: res.expectedTransactionDate ? formatDate(new Date(res.expectedTransactionDate)) : '',
             businessItemProductList: productTableListData ? JSON.stringify(productTableListData) : []
         }
         allLoading.businessSaveLading = true

+ 2 - 2
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/relatedBusiness.vue

@@ -62,7 +62,7 @@ import RelatedProducts from '@/components/relatedProducts/relatedProducts.vue'
 import { GETTABLELIST } from '@/pages/product/api';
 import { GETGENERATEFOEM, UPDATEINSET } from '@/pages/business/api';
 import { judgmentaAmounteEqual, setTemplateDataDisable } from '@/utils/tools';
-import { formatDateTime } from '@/utils/times';
+import { formatDate, formatDateTime } from '@/utils/times';
 import router from '@/router';
 
 const emits = defineEmits(['refreshData']);
@@ -110,7 +110,7 @@ function editBusiness(visibles: boolean) {
         })
         let newForm = {
             ...res,
-            expectedTransactionDate: res.expectedTransactionDate ? formatDateTime(new Date(res.expectedTransactionDate)) : '',
+            expectedTransactionDate: res.expectedTransactionDate ? formatDate(new Date(res.expectedTransactionDate)) : '',
             businessItemProductList: productTableListData ? JSON.stringify(productTableListData) : []
         }
         allLoading.businessSaveLading = true

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/thread/detail/components/information.vue

@@ -217,7 +217,7 @@ function transferBusiness() {
             clueId: information.value.id,
             ...generateFormVal.value,
             ...res,
-            expectedTransactionDate: res.expectedTransactionDate ? formatDateTime(new Date(res.expectedTransactionDate)) : '',
+            expectedTransactionDate: res.expectedTransactionDate ? formatDate(new Date(res.expectedTransactionDate)) : '',
             businessItemProductList: productTableListData ? JSON.stringify(productTableListData) : []
         }
         allLoading.businessSaveLading = true

+ 2 - 4
fhKeeper/formulahousekeeper/customerBuler-crm/src/styles/global.scss

@@ -23,7 +23,7 @@ $modena: #6f4afe;
 }
 
 .scroll-bar::-webkit-scrollbar-thumb {
-  background: linear-gradient(to bottom right, #c1c1c1 0%, #c1c1c1 100%);
+  background: linear-gradient(to bottom right, #DDDEE0 0%, #c1c1c1 100%);
   border-radius: 5px;
 }
 
@@ -33,9 +33,7 @@ $modena: #6f4afe;
 }
 
 .scroll-bar::-webkit-scrollbar-button {
-  background-color: #c1c1c1;
-  border-radius: 2px;
-  height: 4px;
+  height: 0px;
 }
 
 .scroll-bar::-webkit-scrollbar-button:hover {

+ 3 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/vite.config.ts

@@ -17,6 +17,9 @@ export default defineConfig({
       }
     }
   })],
+  optimizeDeps: {
+    include: ['vue-draggable-plus']
+  },
   server: {
     host: '0.0.0.0',
     port: 19123,

+ 15 - 5
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/BusinessOpportunityController.java

@@ -12,6 +12,7 @@ import com.management.platform.mapper.*;
 import com.management.platform.service.*;
 import com.management.platform.service.impl.ExcelExportServiceImpl;
 import com.management.platform.util.HttpRespMsg;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -24,6 +25,8 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -153,11 +156,11 @@ public class BusinessOpportunityController {
                     value = String.valueOf(aClass.getMethod("getCustomerName").invoke(data));
                 }
                 if(model.equals("expectedTransactionDate")){
-                    Date date = (Date) aClass.getMethod("getExpectedTransactionDate").invoke(data);
+                    LocalDate date = (LocalDate) aClass.getMethod("getExpectedTransactionDate").invoke(data);
                     // 如果日期不为空,格式化日期
                     if (date != null) {
-                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
-                        value = sdf.format(date);
+                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
+                        value = date.format(formatter);
                     } else {
                         value = "";
                 }                }
@@ -268,7 +271,14 @@ public class BusinessOpportunityController {
     public Object claim(BusinessOpportunity bo, HttpServletRequest request) {
         User user = userMapper.selectById(request.getHeader("Token"));
         HttpRespMsg msg = new HttpRespMsg();
-        msg.setMsg("操作成功");
+        String[] strings = bo.getIds().split(",");
+        for (String id : strings) {
+            BusinessOpportunity opportunity = boMapper.selectById(id);
+            if (StringUtils.isEmpty(opportunity.getInchargerId())){
+                msg.setError("商机:"+opportunity.getName()+"未被认领不能转移");
+                return msg;
+            }
+        }
         bOservice.getAndTransfer(bo, user);
         return msg;
     }
@@ -425,7 +435,7 @@ public class BusinessOpportunityController {
 
         List<HashMap<String, Object>> mapList = new ArrayList<>();
         for (Stage stage : stageList) {
-            List<BusinessOpportunity> collect = list.stream().filter(l -> l.getStageId() != null && l.getStageId().equals(stage.getId())).collect(Collectors.toList());
+            List<BusinessOpportunity> collect = list.stream().filter(l -> l.getStageId() != null && l.getStageId().equals(stage.getId())&& l.getSeq()!=null).collect(Collectors.toList());
             collect=collect.stream().sorted(Comparator.comparing(BusinessOpportunity::getSeq)).collect(Collectors.toList());
             HashMap<String, Object> map = new HashMap<>();
             map.put("id", stage.getId());

+ 4 - 3
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/BusinessOpportunity.java

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import java.math.BigDecimal;
 import com.baomidou.mybatisplus.annotation.TableField;
 import java.io.Serializable;
+import java.time.LocalDate;
 import java.util.Date;
 import java.util.List;
 
@@ -80,9 +81,9 @@ public class BusinessOpportunity extends Model<BusinessOpportunity> {
      * 预计成交日期
      */
     @TableField("expected_transaction_date")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date expectedTransactionDate;
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDate expectedTransactionDate;
 
     /**
      * 商机阶段

+ 28 - 14
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/BusinessOpportunityServiceImpl.java

@@ -40,8 +40,11 @@ import java.math.BigDecimal;
 import java.net.URLEncoder;
 import java.text.SimpleDateFormat;
 import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
 
@@ -613,32 +616,28 @@ public class BusinessOpportunityServiceImpl extends ServiceImpl<BusinessOpportun
                     }else if(modelName.equals("contactsId")){
                         if(!StringUtils.isEmpty(cell.getStringCellValue())){
                             Optional<Contacts> first = contacts.stream().filter(s -> s.getName().equals(cell.getStringCellValue())).findFirst();
-                            product.setContactsId(first.get().getId());
+                            product.setContactsId(first.map(Contacts::getId).orElse(null));
                         }
                     }else if(modelName.equals("customerId")){
                         if(!StringUtils.isEmpty(cell.getStringCellValue())){
                             Optional<Custom> first = customs.stream().filter(s -> s.getCustomName().equals(cell.getStringCellValue())).findFirst();
-                            product.setCustomerId(first.get().getId());
+                            product.setCustomerId(first.map(Custom::getId).orElse(null));
                         }
                     }else if(modelName.equals("expectedTransactionDate")){
                         if(cell != null && cell.getCellTypeEnum() != CellType.BLANK){
                             if(!org.apache.commons.lang3.StringUtils.isEmpty(cell.getStringCellValue())){
                                 try {
-                                    // 假设 cell 是一个代表 Excel 单元格的对象
-                                    String dateString = cell.getStringCellValue();
+                                    int count = Integer.parseInt(cell.getStringCellValue());
+                                    // Excel中的日期序列号的基准日期是1900年1月1日
+                                    LocalDate baseDate = LocalDate.of(1900, 1, 1);
+                                    LocalDate date = baseDate.plusDays(count - 2);
 
-                                    // 定义日期格式
-                                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
-
-                                    // 解析字符串为 Date 类型
-                                    Date parsedDate = dateFormat.parse(dateString);
-
-                                    // 设置到对象中
-                                    product.setExpectedTransactionDate(parsedDate);
+                                    // 将 ZonedDateTime 转换为 Date
+                                    product.setExpectedTransactionDate(date);
 
                                 } catch (Exception e) {
-                                    System.out.println("日期时间格式不正确, 应该是yyyy/MM/dd");
-                                    msg.setError("日期时间格式不正确, 应该是yyyy/MM/dd");
+                                    System.out.println("日期时间格式不正确,应该是yyyy/MM/dd" );
+                                    msg.setError("日期时间格式不正确,应该是yyyy/MM/dd");
                                     return msg;
                                 }
                             }
@@ -655,6 +654,21 @@ public class BusinessOpportunityServiceImpl extends ServiceImpl<BusinessOpportun
                 importProductList.add(product);
             }
             if(importProductList.size()>0){
+                List<Integer> stageIds = importProductList.stream().map(BusinessOpportunity::getStageId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
+                for (Integer stageId : stageIds) {
+                    List<BusinessOpportunity> list = bOMapper.selectList(new QueryWrapper<BusinessOpportunity>().eq("stage_id", stageId).eq("is_delete", 0).orderByDesc("seq").last(" limit 1"));
+                    AtomicInteger seq = new AtomicInteger(0); // 使用 AtomicInteger
+                    if (!list.isEmpty()){
+                        seq.set(list.get(0).getSeq());
+                    }
+                    importProductList.forEach(l->{
+                        if (l.getStageId().equals(stageId)){
+                            seq.incrementAndGet();
+                            l.setSeq(seq.get());
+                        }
+                    });
+                }
+
                 if(!saveOrUpdateBatch(importProductList)){
                     msg.setError("验证失败,请检验数据格式是否正确");
                     return msg;

+ 7 - 4
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ContactsServiceImpl.java

@@ -744,7 +744,8 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
                 Integer contactsId = businessOpportunity.getContactsId();
                 mgs.setData(contactsMapper.selectList(new QueryWrapper<Contacts>()
                         .eq("company_id",user.getCompanyId())
-                        .eq("id",contactsId)));
+                        .eq("id",contactsId)
+                        .eq("is_delete",0)));
             }
         }else if(salesId!=null){
             //要找销售订单对应的客户,然后再找客户对应的联系人
@@ -755,16 +756,18 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
                 Integer contactsId = salesOrder.getCustomId();
                 mgs.setData(contactsMapper.selectList(new QueryWrapper<Contacts>()
                         .eq("company_id",user.getCompanyId())
-                        .eq("custom_id",contactsId)));
+                        .eq("custom_id",contactsId)
+                        .eq("is_delete",0)));
             }
 
         }
         else if (customerId!=null){
             mgs.setData(contactsMapper.selectList(new QueryWrapper<Contacts>()
                     .eq("company_id",user.getCompanyId())
-                    .eq("custom_id",customerId)));
+                    .eq("custom_id",customerId)
+                    .eq("is_delete",0)));
         }else
-            mgs.setData(contactsMapper.selectList(new QueryWrapper<Contacts>().eq("company_id",user.getCompanyId())));
+            mgs.setData(contactsMapper.selectList(new QueryWrapper<Contacts>().eq("company_id",user.getCompanyId()).eq("is_delete",0)));
         return mgs;
     }
 

+ 10 - 14
fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/BusinessOpportunityMapper.xml

@@ -39,8 +39,7 @@
         (select custom_name from custom where id = customer_id) customerName,
         (select `name` from contacts where id = contacts_id) contactsName,
         (select `name` from `user` where id = incharger_id) inchargerName,
-        (select `name` from `user` where id = creator_id) creatorName,
-        (SELECT sum(total) from business_product WHERE business_id = id) total
+        (select `name` from `user` where id = creator_id) creatorName
         from business_opportunity
         where company_id = #{companyId}
         and is_delete = #{isDelete}
@@ -63,7 +62,7 @@
             and stage_id = #{stageId}
         </if>
         <if test="productId != null ">
-            and id in (select business_id from business_product where product_id = #{productId})
+            and id in (select business_id from business_item_product where product_id = #{productId})
         </if>
         ORDER BY id DESC
         <if test="pageIndex!=null and pageFrom !=null">
@@ -96,7 +95,7 @@
             and stage_id = #{stageId}
         </if>
         <if test="productId != null ">
-            and id in (select business_id from business_product where product_id = #{productId})
+            and id in (select business_id from business_item_product where product_id = #{productId})
         </if>
     </select>
     <select id="selectAllList1" resultType="com.management.platform.entity.BusinessOpportunity">
@@ -106,8 +105,7 @@
         (select custom_name from custom where id = customer_id) customerName,
         (select `name` from contacts where id = contacts_id) contactsName,
         (select `name` from `user` where id = incharger_id) inchargerName,
-        (select `name` from `user` where id = creator_id) creatorName,
-        (SELECT sum(total) from business_product WHERE business_id = id)
+        (select `name` from `user` where id = creator_id) creatorName
         from business_opportunity
         where company_id = #{bo.companyId}
         and is_delete = #{bo.isDelete}
@@ -133,7 +131,7 @@
             and stage_id = #{bo.stageId}
         </if>
         <if test="bo.productId != null ">
-            and id in (select business_id from business_product where product_id = #{bo.productId})
+            and id in (select business_id from business_item_product where product_id = #{bo.productId})
         </if>
         ORDER BY id DESC
         <if test="bo.pageIndex!=null and bo.pageFrom !=null">
@@ -168,7 +166,7 @@
             and stage_id = #{bo.stageId}
         </if>
         <if test="bo.productId != null ">
-            and id in (select business_id from business_product where product_id = #{bo.productId})
+            and id in (select business_id from business_item_product where product_id = #{bo.productId})
         </if>
     </select>
     <select id="selectAllList2" resultType="com.management.platform.entity.BusinessOpportunity">
@@ -178,8 +176,7 @@
         (select custom_name from custom where id = customer_id) customerName,
         (select `name` from contacts where id = contacts_id) contactsName,
         (select `name` from `user` where id = incharger_id) inchargerName,
-        (select `name` from `user` where id = creator_id) creatorName,
-        (SELECT sum(total) from business_product WHERE business_id = id)
+        (select `name` from `user` where id = creator_id) creatorName
         from business_opportunity
         where company_id = #{bo.companyId}
         and is_delete = #{bo.isDelete}
@@ -203,7 +200,7 @@
             and stage_id = #{bo.stageId}
         </if>
         <if test="bo.productId != null ">
-            and id in (select business_id from business_product where product_id =#{bo.productId})
+            and id in (select business_id from business_item_product where product_id =#{bo.productId})
         </if>
         ORDER BY id DESC
         <if test="bo.pageIndex!=null and bo.pageFrom !=null">
@@ -236,7 +233,7 @@
             and stage_id = #{bo.stageId}
         </if>
         <if test="bo.productId != null ">
-            and id in (select business_id from business_product where product_id = #{bo.productId})
+            and id in (select business_id from business_item_product where product_id = #{bo.productId})
         </if>
     </select>
     <select id="selectByIdToInfo" resultType="com.management.platform.entity.BusinessOpportunity">
@@ -245,8 +242,7 @@
                (select custom_name from custom where id = customer_id) customerName,
                (select `name` from contacts where id = contacts_id)    contactsName,
                (select `name` from `user` where id = incharger_id)      inchargerName,
-               (select `name` from `user` where id = creator_id)       creatorName,
-               (SELECT sum(total) from business_product WHERE business_id = id)
+               (select `name` from `user` where id = creator_id)       creatorName
         from business_opportunity
         where id = #{id}
     </select>

+ 2 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/AuthRedirectController.java

@@ -336,14 +336,13 @@ public class AuthRedirectController {
             }
         }
         if (isMobile) {
-            redirecUrl = mobUrl +"/#/"+ router;
+            redirecUrl = mobUrl + router;
         } else {
-            redirecUrl = pcUrl +"/#/"+ router;
+            redirecUrl = pcUrl + router;
         }
         ModelAndView modelAndView = new ModelAndView(
                 new RedirectView(redirecUrl), reqParam);
         reqParam.put("isPrivateCorpWX", 1);
-        System.out.println("跳转=="+redirecUrl);
         if (reqParam.containsKey("errorMsg")) {
             System.out.println(reqParam.get("errorMsg"));
         }

+ 29 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/PrivateDeployUrlGenerator.java

@@ -0,0 +1,29 @@
+package com.management.platform.util;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+/**
+ * 私有化部署的url生成器
+ */
+public class PrivateDeployUrlGenerator {
+    //企业微信私有化部署的url生成器;如果访问的网址带端口号,这里也带上传参
+    public static String generateCorpWXUrl(String corpId, String agentId, String redirectUrl) {
+        try {
+            if (redirectUrl.endsWith("/")) {
+                redirectUrl = redirectUrl.substring(0, redirectUrl.length()-1);
+            }
+            String redirectUrlEncoded = URLEncoder.encode(redirectUrl+"/api/corpInsideWXAuth", "UTF-8");
+            String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+corpId
+                    +"&redirect_uri="+redirectUrlEncoded+"&response_type=code&scope=snsapi_base&state=0&agentid="+agentId+"#wechat_redirect";
+            return url;
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void main(String[] args) {
+        //测试生成企业微信私有化部署的url,替换参数,生成的结果提供给客户,让客户配置到企业微信自建应用的【应用主页】上
+        System.out.println(generateCorpWXUrl("ww4e237fd6abb635af", "1000002", "http://worktime.ttkuaiban.com"));
+    }
+}

+ 116 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/application-privatewx.yml

@@ -0,0 +1,116 @@
+server:
+  port: 10040
+  tomcat:
+    uri-encoding: utf-8
+    max-http-form-post-size: -1
+    connection-timeout: 18000000s
+spring:
+  servlet:
+    multipart:
+      # 配置上传文件的大小设置
+      # Single file max size  即单个文件大小
+      max-file-size: 100MB
+      max-request-size: 100MB
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://127.0.0.1:17089/man_privatewx?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&&useSSL=false
+    username: root
+    password: P011430@Huoshi*
+    hikari:
+      maximum-pool-size: 10
+      minimum-idle: 3
+      max-lifetime: 30000
+      connection-test-query: SELECT 1
+    #######redis配置######
+    # redis
+    redis:
+      host: 127.0.0.1
+      port: 6479
+      timeout: 3
+      # password:
+      pool:
+        minIdle: 1
+        maxIdle: 10
+        maxWait: 3
+        maxActive: 8
+    ####全局配置时间返回格式#####
+  jackson:
+    #参数意义:
+    #JsonInclude.Include.ALWAYS       默认
+    #JsonInclude.Include.NON_DEFAULT   属性为默认值不序列化
+    #JsonInclude.Include.NON_EMPTY     属性为 空(””) 或者为 NULL 都不序列化
+    #JsonInclude.Include.NON_NULL      属性为NULL  不序列化
+    default-property-inclusion: ALWAYS
+    time-zone: GMT+8
+    date-format: yyyy-MM-dd HH:mm:ss
+
+##########日志配置
+logging:
+  level:
+    root: info
+    org.mybatis: error
+    java.sql: error
+    org.springframework.web: error
+    #打印sql语句
+    com.management.platform.mapper: error
+  path: /log/
+  file: worktime.log
+##########
+mybatis-plus:
+  #  mapper-locations: classpath:mapper/*/*.xml
+  #  #实体扫描,多个package用逗号或者分号分隔
+  #  typeAliasesPackage: com.hssx.cloudmodel
+  global-config:
+    #主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
+    id-type: 0
+    #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
+    field-strategy: 2
+    db-column-underline: true
+    refresh-mapper:
+    #################插入和更新非null判断
+    db-config:
+      insert-strategy: not_null
+      update-strategy: not_null
+  configuration:
+    map-underscore-to-camel-case: true
+    cache-enabled: false
+######mybstis配置#######
+mybatis:
+  type-aliases-package: com.management.platform.entity
+  mapper-locations: mappers/*Mapper.xml
+#####配置图片上传路径####
+upload:
+  path: /www/staticproject/timesheet_private/upload/
+referer:
+  refererDomain:
+    - localhost
+    - privatewx.ttkuaiban.com
+    - mobprivatewx.ttkuaiban.com
+    - 47.101.180.183
+#企业微信相关参数
+suitId: ww4e237fd6abb635af
+suitSecret: 1ApL6LIB4Z0v7wBrKTUNmJrerRWV3gEQWBlYOm8Kijw
+#平台作为服务商的参数
+corpId: wwf11426cf618e1703
+privateDeployURL:
+  pcUrl: http://privatewx.ttkuaiban.com/#/
+  mobUrl: http://mobprivatewx.ttkuaiban.com/#/
+##actuator健康检查配置
+management:
+  security:
+    enabled:false:
+  server:
+    port: 10041
+  #  endpoints:
+  #    web:
+  #      exposure:
+  #        include: "*"
+
+  health:
+    redis:
+      enabled: false
+
+configEnv:
+  isDev: true
+  # 企业微信私有化部署
+  isPrivateDeploy: true

+ 9 - 3
fhKeeper/formulahousekeeper/timesheet/src/common/js/appidConfiguration.js

@@ -1,7 +1,7 @@
 /**
- * 各个公司企业微信的配置, 更具域名来解析
+ * 各个公司企业微信的配置, 根据域名来解析
  * @path 完整域名
- * @appId 企业微信的appId
+ * @appId 企业微信的appId,针对私有化部署的情况appId就是corpId
  */
 const config = {
   "worktime.ttkuaiban.com": {
@@ -16,6 +16,12 @@ const config = {
     appId: "wwb12ec40df8c35139",
     agentId: "1000075",
   },
+  "privatewx.ttkuaiban.com": {
+    // 火石闪信-企业微信私有化
+    path: "http://privatewx.ttkuaiban.com",
+    appId: "wwf11426cf618e1703",
+    agentId: "1000069",
+  },
 };
 
 const fixedPath = `/api/corpWXAuth`; // 授权回调页面 (需要拼接)
@@ -29,7 +35,7 @@ export function obtainCorrespondingConfigurationInformation() {
   const tokenUrl = `${row.path}${fixedPath}`;
   const tokenUrlAgentId = `${row.path}${fixedPathAgentId}`;
   const authorizationCallback = agentId
-    ? `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${encodeURI(tokenUrlAgentId)}&response_type=code&scope=snsapi_base&state=index&agentid=${agentId}#wechat_redirect`
+    ? `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${encodeURI(tokenUrlAgentId)}&response_type=code&scope=snsapi_base&state=0&agentid=${agentId}#wechat_redirect`
     : `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${encodeURI(tokenUrl)}&response_type=code&scope=snsapi_base&state=1#wechat_redirect`;
   return {
     appId,

+ 45 - 0
fhKeeper/formulahousekeeper/timesheet_h5/src/utils/appidConfiguration.js

@@ -0,0 +1,45 @@
+/**
+ * 各个公司企业微信的配置, 根据域名来解析
+ * @path 完整域名
+ * @appId 企业微信的appId,针对私有化部署的情况appId就是corpId
+ */
+const config = {
+  "mobworktime.ttkuaiban.com": {
+    // 工时管家 
+    path: "http://mobworktime.ttkuaiban.com",
+    appId: "ww4e237fd6abb635af",
+    agentId: "",
+  },
+  "moblue.blovelight.net": {
+    // 蓝光研发 
+    path: "http://moblue.blovelight.net:2021",
+    appId: "wwb12ec40df8c35139",
+    agentId: "1000075",
+  },
+  "mobprivatewx.ttkuaiban.com": {
+    // 火石闪信-企业微信私有化 
+    path: "http://mobprivatewx.ttkuaiban.com",
+    appId: "wwf11426cf618e1703",
+    agentId: "1000069",
+  },
+};
+
+const fixedPath = `/api/corpWXAuth`; // 授权回调页面 (需要拼接)
+const fixedPathAgentId = `/api/corpInsideWXAuth`
+
+export function obtainCorrespondingConfigurationInformation() {
+  const hostname = window.location.hostname; // 获取域名和端口,(不包括http 和 https)
+  const row = config[hostname];
+  const agentId = row.agentId;
+  const appId = row.appId;
+  const tokenUrl = `${row.path}${fixedPath}`;
+  const tokenUrlAgentId = `${row.path}${fixedPathAgentId}`;
+  const authorizationCallback = agentId
+    ? `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${encodeURI(tokenUrlAgentId)}&response_type=code&scope=snsapi_base&state=0&agentid=${agentId}#wechat_redirect`
+    : `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${encodeURI(tokenUrl)}&response_type=code&scope=snsapi_base&state=1#wechat_redirect`;
+  return {
+    appId,
+    tokenUrl,
+    authorizationCallback,
+  };
+}

+ 8 - 5
fhKeeper/formulahousekeeper/timesheet_h5/src/views/login/index.vue

@@ -18,6 +18,7 @@
 <script>
     import { constants } from "crypto";
     import * as dd from 'dingtalk-jsapi'; 
+    import { obtainCorrespondingConfigurationInformation } from '../../utils/appidConfiguration';
     export default {
         data() {
             return {
@@ -165,16 +166,18 @@
                 }
             },
             tryAutoLogin() {
+                const rowConfig = obtainCorrespondingConfigurationInformation()
                 var appId = "wx749c84daac654e1e";//工时管家公众号
                 var url = "http://mobworktime.ttkuaiban.com/api/wechat/loginByWXCode";//工时管家公众号授权回调页面
-                if (this.isCorpWX) {
-                    appId = "ww4e237fd6abb635af"; //企业微信第三方的SUIT ID
-                    url = "http://worktime.ttkuaiban.com/api/corpWXAuth";//授权回调页面
-                } 
+                // if (this.isCorpWX) {
+                    // appId = "ww4e237fd6abb635af"; //企业微信第三方的SUIT ID
+                    // url = "http://worktime.ttkuaiban.com/api/corpWXAuth";//授权回调页面
+                // } 
 
                 // var appId = "ww4e237fd6abb635af";//企业微信第三方的SUIT ID
                 // var url = "http://worktime.ttkuaiban.com/api/corpWXAuth";//授权回调页面
-                var weixinUrl="https://open.weixin.qq.com/connect/oauth2/authorize?appid="+appId+"&redirect_uri="+encodeURI(url)+"&response_type=code&scope=snsapi_base&state=0#wechat_redirect";
+                
+                var weixinUrl = this.isCorpWX ? rowConfig.authorizationCallback : "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+appId+"&redirect_uri="+encodeURI(url)+"&response_type=code&scope=snsapi_base&state=0#wechat_redirect";
                 window.location.href = weixinUrl;
             },
             tryDingDingUrlRedirect() {