Parcourir la source

Merge remote-tracking branch 'origin/master'

yusm il y a 5 mois
Parent
commit
eccd41c170
21 fichiers modifiés avec 644 ajouts et 149 suppressions
  1. 171 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/translationComponent/departmentSelection/departmentSelection.vue
  2. 0 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/translationComponent/personnelSearch/data.ts
  3. 10 10
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/translationComponent/personnelSearch/personnelSearch.vue
  4. 235 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/translationComponent/treeSelect/treeSelect.vue
  5. 0 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/translationComponent/type.d.ts
  6. 18 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/analysis/index.vue
  7. 26 11
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/index.vue
  8. 23 10
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/module/AddPersonnelModal.vue
  9. 2 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/store/Store.d.ts
  10. 2 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/store/index.ts
  11. 5 76
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/WeiXinCorpController.java
  12. 13 0
      fhKeeper/formulahousekeeper/management-platform/pom.xml
  13. 3 11
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/FinancialAuditController.java
  14. 3 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/WxCorpInfoService.java
  15. 18 15
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DingDingServiceImpl.java
  16. 18 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ExcelExportServiceImpl.java
  17. 66 4
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/WxCorpInfoServiceImpl.java
  18. 21 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java
  19. 1 0
      fhKeeper/formulahousekeeper/timesheet/src/i18n/en.json
  20. 1 0
      fhKeeper/formulahousekeeper/timesheet/src/i18n/zh.json
  21. 8 3
      fhKeeper/formulahousekeeper/timesheet/src/views/settings/timetype.vue

+ 171 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/components/translationComponent/departmentSelection/departmentSelection.vue

@@ -0,0 +1,171 @@
+<script lang="ts" setup>
+import { ref, reactive, onMounted, inject, watchEffect, computed } from 'vue';
+import type { CascaderProps, CascaderNode } from 'element-plus'
+import { cloneDeep, debounce } from 'lodash';
+import { post } from "@/utils/request";
+import { useStore } from '@/store/index'
+import { Emits } from '../type';
+import { storeToRefs } from 'pinia';
+import { updateDepTreeData, generateUniqueId } from '@/utils/tools'
+
+const emit = defineEmits<Emits>();
+const props = defineProps({
+  modelValue: { type: [String, Number, Array, Object, Boolean], required: true },
+  size: { type: String as () => assemblySize, required: true, default: () => 'small' },
+  placeholder: { type: String, required: false, default: () => '请选择' },
+  multiple: { type: Boolean, required: false, default: false },
+  disabled: { type: Boolean, required: false, default: false },
+  clearable: { type: Boolean, required: false, default: true },
+  options: { type: Array as () => any, required: false, default: () => [] },
+  width: { type: String, required: false, default: () => '100%' },
+  isAddChineseCharacters: { type: Boolean, required: false, default: false },
+  props: {
+    type: Object as () => CascaderProps, required: false, default: () => {
+      return {
+        value: 'id',
+        expandTrigger: 'hover' as const,
+        checkStrictly: true
+      }
+    }
+  }
+})
+const { departmentList, userInfo } = storeToRefs(useStore());
+const { setValue } = useStore()
+const departmentVal = ref(props.modelValue); // 响应式绑定 v-model 的值
+const departmentValTwo = ref(props.modelValue);
+const departmentProps = ref<CascaderProps>({})
+const departmantArray = ref<any>([]);
+const visibleFlag = ref<boolean>(false);
+const deptRef = ref<any>(null)
+
+const deptLabel = computed(() => {
+  if (Array.isArray(departmentVal.value)) {
+    const deptId = departmentVal.value[departmentVal.value.length - 1]
+    return findLabelById(departmantArray.value, deptId)
+  }
+  return ''
+})
+
+async function filterMethod(node: CascaderNode, keyword: string) {
+  const { userNameNeedTranslate } = userInfo.value
+  if(userNameNeedTranslate == 0) {
+    return [keyword].includes(node.label)
+  }
+  const { data = [] } = await post(`/department/listAllMemb`, { keyword, cursor: '2' })
+  const keywordList = data.flatMap(extractLabels)
+  return [...keywordList].includes(node.label)
+}
+
+function getDeptList(keyword: string = '') {
+  post(`/department/listAllMemb`, { keyword }).then(res => {
+    const deptList = updateDepTreeData(res.data, props.isAddChineseCharacters)
+    departmantArray.value = deptList
+    if (!keyword) {
+      setValue((deptList || []), 'departmentList')
+    }
+  })
+}
+
+function visibleChange(visible: boolean) { // 下拉框出现/隐藏时触发
+  if (!props.multiple) {
+    setTimeout(() => {
+      departmentVal.value = visible ? [] : cloneDeep(departmentValTwo.value)
+    }, 10)
+  }
+  visibleFlag.value = visible
+}
+
+function updateValue(val: any) { // 值改变的时候触发
+  if (!props.multiple) {
+    deptRef.value.$refs.input.value = '';
+    deptRef.value.togglePopperVisible()
+  }
+  departmentValTwo.value = cloneDeep(val)
+  emit('update:modelValue', departmentVal.value)
+  emit('change', val)
+}
+
+function findLabelById(tree: any, id: any) {
+  for (let node of tree) {
+    if (node.id == id) {
+      return node.label;
+    }
+    if (node.children && node.children.length > 0) {
+      const result: any = findLabelById(node.children, id);
+      if (result) {
+        return result;
+      }
+    }
+  }
+  return null;
+}
+
+function extractLabels(node: any) {
+  let labels: any[] = [];
+  if (node.label) {
+    labels.push(node.label);
+  }
+  if (node.children && Array.isArray(node.children)) {
+    node.children.forEach((child: any) => {
+      labels = labels.concat(extractLabels(child));
+    });
+  }
+  return labels;
+}
+
+onMounted(() => {
+  departmentProps.value = props.props
+  if (departmentList.value.length == 0) {
+    if (props.options.length > 0) {
+      departmantArray.value = props.options
+    } else {
+      getDeptList()
+    }
+  } else {
+    departmantArray.value = departmentList.value
+  }
+})
+</script>
+
+<template>
+  <div class="departmentSelectionDiv" :style="`width: ${width}`">
+    <el-cascader v-model="departmentVal" :ref="'deptRef'" :options="departmantArray" :props="departmentProps"
+      :size="size" :clearable="clearable" :placeholder="placeholder" filterable :show-all-levels="false"
+      :class="`departmentSelection ${!multiple && !visibleFlag ? 'clearColor' : ''}`" :style="`width: ${width}`"
+      :filter-method="filterMethod" @visible-change="visibleChange" @change="updateValue">
+      <template #default="{ node, data }">
+        <span>
+          <TextTranslation translationTypes="departmentName" :translationValue="data.label"></TextTranslation>
+        </span>
+      </template>
+    </el-cascader>
+    <!-- 覆盖 -->
+    <div class="coverDept" v-if="!visibleFlag">
+      <TextTranslation translationTypes="departmentName" :translationValue="deptLabel"></TextTranslation>
+    </div>
+  </div>
+</template>
+
+<style>
+.clearColor .el-input .el-input__inner {
+  color: transparent !important;
+}
+</style>
+
+<style lang="scss" scoped>
+.departmentSelectionDiv {
+  position: relative;
+  display: inline-block;
+
+  .coverDept {
+    position: absolute;
+    top: 50%;
+    transform: translateY(-50%);
+    left: 6px;
+    background: #fff;
+    color: #303133;
+    font-size: 12px;
+    height: calc(100% - 4px);
+  }
+}
+</style>

+ 0 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/components/translationComponent/personnelSearch/data.ts


+ 10 - 10
fhKeeper/formulahousekeeper/customerBuler-crm/src/components/translationComponent/personnelSearch/personnelSearch.vue

@@ -2,7 +2,7 @@
 import { ref, reactive, onMounted, inject, watchEffect, computed } from 'vue';
 import { debounce } from 'lodash';
 import { storeToRefs } from 'pinia';
-import { Emits, optionsType } from './type';
+import { Emits, optionsType } from '../type';
 import { useStore } from '@/store/index'
 import { generateUniqueId } from '@/utils/tools'
 import { post, get, uploadFile } from "@/utils/request";
@@ -14,6 +14,7 @@ const props = defineProps({
   placeholder: { type: String, required: false, default: () => '请选择' },
   disabled: { type: Boolean, required: false, default: false },
   options: { type: Array as () => optionsType, required: false, default: () => [] },
+  clearable: { type: Boolean, required: false, default: true },
   width: { type: String, required: false, default: () => '100%' },
 });
 const emit = defineEmits<Emits>();
@@ -96,7 +97,11 @@ function updateValue(val: any) { // 值改变的时候触发
 
 onMounted(() => {
   if (personnelList.value.length == 0) {
-    getUserList()
+    if (props.options.length > 0) {
+      personnelArray.value = props.options
+    } else {
+      getUserList()
+    }
   } else {
     personnelArray.value = personnelList.value
   }
@@ -142,7 +147,7 @@ onMounted(() => {
 <el-option v-for="item in personnelArray" :key="item.value" :label="item.label" :value="item.value"></el-option>
 </el-select> -->
   <el-select-v2 v-model="selectedValue" :ref="`selectRef${timeRef}`" :multiple="multiple" :size="size"
-    :loading="selectLoading" :placeholder="placeholder" :disabled="disabled" clearable filterable collapse-tags
+    :loading="selectLoading" :placeholder="placeholder" :disabled="disabled" :clearable="clearable" filterable collapse-tags
     :style="`width: ${width}`" :options="personnelArray"
     :class="`custom-select ${!controlTranslation.visibleFlag ? 'setUpInput' : ''}`" @change="updateValue"
     @visible-change="visibleChange" :filter-method="filterMethod">
@@ -155,7 +160,7 @@ onMounted(() => {
             {{ placeholder }}
           </template>
           <template v-else>
-            <span style="color: #303133;">
+            <span style="color: #606266;">
               <TextTranslation translationTypes="userName" :translationValue="getSelectedLabel"></TextTranslation>
             </span>
           </template>
@@ -181,7 +186,6 @@ onMounted(() => {
       </div>
     </template>
   </el-select-v2>
-  <span class="aabbcc">aabbcc</span>
 </template>
 
 <style lang="scss" scoped>
@@ -195,7 +199,7 @@ onMounted(() => {
       display: none;
     }
   }
-  
+
   :deep(.el-select__input) {
     margin-left: 0;
   }
@@ -204,8 +208,4 @@ onMounted(() => {
 .setUpInput :deep(.el-input__inner) {
   color: #fff !important;
 }
-
-.aabbcc {
-  color: $modena;
-}
 </style>

+ 235 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/components/translationComponent/treeSelect/treeSelect.vue

@@ -0,0 +1,235 @@
+<script lang="ts" setup>
+import { ref, reactive, onMounted, inject, watchEffect, computed } from 'vue';
+import type { CascaderProps, CascaderNode } from 'element-plus'
+import { cloneDeep, debounce } from 'lodash';
+import { post } from "@/utils/request";
+import { useStore } from '@/store/index'
+import { Emits } from '../type';
+import { storeToRefs } from 'pinia';
+import { updateDepTreeData, generateUniqueId } from '@/utils/tools'
+const emit = defineEmits<Emits>();
+
+const props = defineProps({
+  modelValue: { type: [String, Number, Array, Object, Boolean], required: true },
+  size: { type: String as () => assemblySize, required: true, default: () => 'small' },
+  placeholder: { type: String, required: false, default: () => '请选择' },
+  multiple: { type: Boolean, required: false, default: false }, // 多选
+  anyLevel: { type: Boolean, required: false, default: true }, // 选择任意一级
+  checkStrictly: { type: Boolean, required: false, default: false }, // 是否父子级相互不关联
+  disabled: { type: Boolean, required: false, default: false },
+  clearable: { type: Boolean, required: false, default: true },
+  options: { type: Array as () => any, required: false, default: () => [] },
+  width: { type: String, required: false, default: () => '100%' },
+  isAddChineseCharacters: { type: Boolean, required: false, default: false },
+  props: {
+    type: Object as () => CascaderProps, required: false, default: () => {
+      return {
+        value: 'id',
+        expandTrigger: 'hover' as const,
+        checkStrictly: true
+      }
+    }
+  }
+})
+
+const { departmentList, userInfo } = storeToRefs(useStore());
+const { setValue } = useStore()
+const treeSelectVal = ref(props.modelValue); // 响应式绑定 v-model 的值
+const treeSelectArray = ref<any>([]);
+const visibleFlag = ref(false);
+const selectLoading = ref(false);
+const treeSelectRef = ref();
+const searchCriteria = ref<string[]>([])
+
+const getSelectedLabel = computed(() => {
+  console.log(treeSelectVal.value, '<==== 执行')
+  if (!props.multiple) {
+    return treeSelectVal.value ? findLabelById(treeSelectArray.value, treeSelectVal.value) : props.placeholder
+  }
+
+  if (props.multiple) {
+    if (Array.isArray(treeSelectVal.value)) {
+      if (treeSelectVal.value.length <= 0) {
+        return props.placeholder
+      }
+
+      return treeSelectVal.value ? findLabelById(treeSelectArray.value, treeSelectVal.value[0]) : props.placeholder
+    }
+  }
+
+  return props.placeholder
+})
+
+const filterMethod = debounce(filterMethods, 500)
+async function filterMethods(val: string) {
+  const { userNameNeedTranslate } = userInfo.value
+  if (val == '') {
+    treeSelectArray.value = departmentList.value
+    selectLoading.value = false
+    searchCriteria.value = []
+    treeSelectRef.value.filter()
+    return
+  }
+  if (userNameNeedTranslate == 0) {
+    searchCriteria.value = [val]
+    setTimeout(() => {
+      treeSelectRef.value.filter()
+    }, 10)
+    return
+  }
+  if (userNameNeedTranslate == 1) {
+    selectLoading.value = true
+    const { data = [] } = await post(`/department/listAllMemb`, { keyword: val })
+    const keywordList = data.flatMap(extractLabels)
+    searchCriteria.value = keywordList
+    console.log(searchCriteria.value)
+    setTimeout(() => {
+      selectLoading.value = false
+      treeSelectRef.value.filter()
+    }, 100)
+  }
+}
+
+function filterNode(_value: string, data: Tree) {
+  const { userNameNeedTranslate } = userInfo.value
+  if (searchCriteria.value.length == 0) {
+    return true
+  }
+  if (userNameNeedTranslate == 0) {
+    return data.label.indexOf(searchCriteria.value[0]) > -1
+  }
+  if (userNameNeedTranslate == 0) {
+    return [...searchCriteria.value].includes(data.label)
+  }
+}
+
+function tagClose(_evt: MouseEvent) {
+  if (Array.isArray(treeSelectVal.value)) {
+    treeSelectVal.value.shift()
+    updateValue(treeSelectVal.value)
+  }
+}
+
+function getDeptList(keyword: string = '') {
+  post(`/department/listAllMemb`, { keyword }).then(res => {
+    const deptList = updateDepTreeData(res.data, props.isAddChineseCharacters)
+    treeSelectArray.value = deptList
+    if (!keyword) {
+      setValue((deptList || []), 'departmentList')
+    }
+  })
+}
+
+function visibleChange(visible: boolean) { // 下拉框出现/隐藏时触发
+  visibleFlag.value = visible
+}
+
+function findLabelById(tree: any, id: any) {
+  for (let node of tree) {
+    if (node.id == id) {
+      return node.label;
+    }
+    if (node.children && node.children.length > 0) {
+      const result: any = findLabelById(node.children, id);
+      if (result) {
+        return result;
+      }
+    }
+  }
+  return null;
+}
+
+function extractLabels(node: any) {
+  let labels: any[] = [];
+  if (node.label) {
+    labels.push(node.label);
+  }
+  if (node.children && Array.isArray(node.children)) {
+    node.children.forEach((child: any) => {
+      labels = labels.concat(extractLabels(child));
+    });
+  }
+  return labels;
+}
+
+function updateValue(val: any) { // 值改变的时候触发
+  emit('update:modelValue', treeSelectVal.value)
+  emit('change', val)
+}
+
+onMounted(() => {
+  console.log(treeSelectVal.value, '<==== 数据')
+  if (departmentList.value.length == 0) {
+    if (props.options.length > 0) {
+      treeSelectArray.value = props.options
+    } else {
+      getDeptList()
+    }
+  } else {
+    treeSelectArray.value = departmentList.value
+  }
+})
+</script>
+
+<template>
+  <el-tree-select v-model="treeSelectVal" ref="treeSelectRef" :data="treeSelectArray" :size="size"
+    :loading="selectLoading" :clearable="clearable" :placeholder="placeholder" :show-checkbox="anyLevel"
+    :multiple="multiple" node-key="id" :render-after-expand="true" :check-strictly="checkStrictly" filterable
+    collapse-tags :style="`width: ${width}`" :default-expanded-keys="(!multiple && checkStrictly) ? [treeSelectVal] : Array.isArray(treeSelectVal) ? [...treeSelectVal] : [treeSelectVal]" :class="`custom-select ${!visibleFlag ? 'setUpInput' : ''}`"
+    @change="updateValue" @visible-change="visibleChange" :filter-method="filterMethod"
+    :filter-node-method="filterNode">
+    <!-- 单选 -->
+    <template #prefix v-if="!multiple">
+      <div style="height: 100%;display: flex;align-items: center;">
+        <div v-if="!visibleFlag" class="selectSingleChoice">
+          <template v-if="getSelectedLabel == placeholder">
+            {{ placeholder }}
+          </template>
+          <template v-else>
+            <span style="color: #606266;">
+              <TextTranslation translationTypes="departmentName" :translationValue="getSelectedLabel"></TextTranslation>
+            </span>
+          </template>
+        </div>
+      </div>
+    </template>
+    <!-- 多选 -->
+    <template #tag v-if="multiple">
+      <template v-if="Array.isArray(treeSelectVal) && treeSelectVal.length > 0">
+        <el-tag type="info" :size="size" closable @close="tagClose">
+          <TextTranslation translationTypes="departmentName" :translationValue="getSelectedLabel"></TextTranslation>
+        </el-tag>
+        <el-tag type="info" :size="size" v-if="treeSelectVal.length > 1">+{{ treeSelectVal.length }}</el-tag>
+      </template>
+      <template v-else>
+        <span style="color: #A8ABB2">{{ placeholder }}</span>
+      </template>
+    </template>
+    <!-- 主要内容 -->
+    <template #default="{ node, data }">
+      <TextTranslation translationTypes="departmentName" :translationValue="node.label"></TextTranslation>
+    </template>
+  </el-tree-select>
+</template>
+
+<style lang="scss" scoped>
+.custom-select {
+  :deep(.el-select__placeholder.is-transparent) {
+    color: transparent !important;
+  }
+
+  :deep(.el-select__placeholder) {
+    span {
+      display: none;
+    }
+  }
+
+  :deep(.el-select__input) {
+    margin-left: 0;
+  }
+}
+
+.setUpInput :deep(.el-input__inner) {
+  color: #fff !important;
+}
+</style>

fhKeeper/formulahousekeeper/customerBuler-crm/src/components/translationComponent/personnelSearch/type.d.ts → fhKeeper/formulahousekeeper/customerBuler-crm/src/components/translationComponent/type.d.ts


+ 18 - 2
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/analysis/index.vue

@@ -7,6 +7,8 @@ import Echarts from '@/components/ReEcharts/index.vue';
 import { EChartsOption, use } from 'echarts';
 import { dayjs } from 'element-plus';
 import personnelSearch from '@/components/translationComponent/personnelSearch/personnelSearch.vue';
+import departmentSelection from '@/components/translationComponent/departmentSelection/departmentSelection.vue'
+import treeSelect from '@/components/translationComponent/treeSelect/treeSelect.vue'
 import {
   getSummaryData,
   getBulletinData,
@@ -19,13 +21,25 @@ import {
 
 const selectVal = ref<Array<string | number>>([])
 const selectVals = ref<string | number>('')
+const departmentVal = ref<any>('')
+const treeSelectVals = ref<any>('')
 const selectChange = (val: any) => {
   console.log(val, '<===== 当前的数据 selectVal')
   console.log(selectVal.value, '<===== 双向绑定的数据 selectVal')
 }
 const selectChange2 = (val: any) => {
-  console.log(val, '<===== 当前的数据 selectVals')
-  console.log(selectVals.value, '<===== 双向绑定的数据 selectVals')
+  console.log(val, '<===== 当前的数据 2')
+  console.log(selectVals.value, '<===== 双向绑定的数据 2')
+}
+
+const selectChange3 = (val: any) => {
+  console.log(val, '<===== 当前的数据 3')
+  console.log(departmentVal.value, '<===== 双向绑定的数据 3')
+}
+
+const selectChange4 = (val: any) => {
+  console.log(val, '<===== 当前的数据 4')
+  console.log(treeSelectVals.value, '<===== 双向绑定的数据 4')
 }
 const permissionOptions = [
   {
@@ -194,6 +208,8 @@ watchEffect(() => {
         <div class="w-40">
           <personnel-search v-model="selectVal" :size="'small'" multiple placeholder="你好世界" @change="selectChange"></personnel-search>
           <personnel-search v-model="selectVals" :size="'small'" placeholder="你好世界" @change="selectChange2"></personnel-search>
+          <department-selection v-model="departmentVal" :size="'small'" placeholder="部门选择" @change="selectChange3"></department-selection>
+          <tree-select v-model="treeSelectVals" :size="'small'" placeholder="树形选择"  @change="selectChange4"></tree-select>
           <el-select
             ref="select1"
             size="small"

+ 26 - 11
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/index.vue

@@ -61,7 +61,7 @@
               <template #default="{ node, data }">
                 <div class="flex justify-between treeContent">
                   <div class="custom-tree-node" @mouseleave="mouseleave(data,$event)" @mouseover="mouseover(data,$event)">
-                    <div class="treeLabel">{{ node.label }}</div>
+                    <div class="treeLabel"><TextTranslation translationTypes="departmentName" :translationValue="node.label"></TextTranslation></div>
                     <div class="treeIcon nodeEle" id="treeIcon" v-if="data.id > 0">
                       <el-link type="primary" :icon="CirclePlus" :underline="false" @click.stop="dialogFromCli('addDeptDialogVisible', data, true)"></el-link>
                       <el-link type="primary" :icon="Delete" :underline="false" style="margin-left: 6px;" @click.stop="deteleDept(data)"></el-link>
@@ -77,12 +77,20 @@
         <div class="bg-white w-full h-full shadow-md rounded-md flex flex-col overflow-hidden pt-2 pl-2 pr-2">
           <div class="flex-1">
             <el-table ref="multipleTableRef" :data="tableData" v-loading="loadingFrom.tableLoading"
-              @selection-change="changeBatch" style="width: 100%;height: 100%;">
+              @selection-change="changeBatch" :style="`width: 100%;height: calc(100vh - 204px);`">
               <el-table-column type="selection" width="55" />
-              <el-table-column label="姓名" property="name" width="150"></el-table-column>
+              <el-table-column label="姓名" property="name" width="150">
+                <template #default="scope">
+                  <TextTranslation translationTypes="userName" :translationValue="scope.row.name"></TextTranslation>
+                </template>
+              </el-table-column>
               <el-table-column label="手机" property="phone"></el-table-column>
               <el-table-column label="工号" property="jobNumber"></el-table-column>
-              <el-table-column label="部门" property="departmentName"></el-table-column>
+              <el-table-column label="部门" property="departmentName">
+                <template #default="scope">
+                  <TextTranslation translationTypes="departmentName" :translationValue="scope.row.departmentName"></TextTranslation>
+                </template>
+              </el-table-column>
               <el-table-column label="角色" property="roleName"></el-table-column>
               <el-table-column label="创建时间" property="createTime"></el-table-column>
               <el-table-column label="操作" width="200" fixed="right">
@@ -147,14 +155,16 @@
             <el-input v-model="deptForm.name" placeholder="请输入部门名称" clearable />
           </el-form-item>
           <el-form-item label="主要负责人">
-            <el-select v-model="deptForm.managerId" placeholder="请选择" style="width: 100%" clearable>
+            <!-- <el-select v-model="deptForm.managerId" placeholder="请选择" style="width: 100%" clearable>
               <el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id" />
-            </el-select>
+            </el-select> -->
+            <personnel-search v-model="deptForm.managerId" :size="''" placeholder="请选择"></personnel-search>
           </el-form-item>
           <el-form-item label="其他负责人">
-            <el-select v-model="deptForm.otherManagerIds" placeholder="请选择" style="width: 100%" multiple clearable>
+            <!-- <el-select v-model="deptForm.otherManagerIds" placeholder="请选择" style="width: 100%" multiple clearable>
               <el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id" />
-            </el-select>
+            </el-select> -->
+            <personnel-search v-model="deptForm.otherManagerIds" :size="''" multiple placeholder="请选择"></personnel-search>
           </el-form-item>
         </el-form>
       </div>
@@ -253,6 +263,8 @@ import { GET_DATA_LIST, DETELE_DEPT, MOD, GET_USERINFO, GET_ROUTELIST, DEACTIVEU
 import { post, uploadFile } from "@/utils/request";
 import { getFromValue, updateDepTreeData, resetFromValue, confirmAction, downloadFile } from '@/utils/tools'
 
+import personnelSearch from '@/components/translationComponent/personnelSearch/personnelSearch.vue';
+
 // 导入页面
 import AddPersonnelModal from './module/AddPersonnelModal.vue'
 import BatchOperation from './module/BatchOperation.vue'
@@ -429,10 +441,11 @@ function addPersone(item: any) {
     return
   }
   post(GET_USERINFO, { userId: item.id }).then(res => {
-    const { id, name, phone, jobNumber, roleId, departmentCascade, inductionDate } = res.data
+    const { id, name, phone, jobNumber, roleId, departmentCascade, departmentId, inductionDate } = res.data
     let newData = {
-      id, name, phone, jobNumber, roleId, departmentId:
-        departmentCascade && departmentCascade.split(',').map(Number).reverse(),
+      id, name, phone, jobNumber, roleId, 
+      // departmentId: departmentCascade && departmentCascade.split(',').map(Number).reverse(),
+      departmentId: departmentId,
       inductionDate
     }
     personnelFromData.value = newData
@@ -458,6 +471,8 @@ async function personnelModalConfirm(data: any, modelType: string) {
 function createDepartment(formEl: FormInstance | undefined) {
   if (!formEl) return
   let data = getFromValue(deptForm)
+  console.log(data, '<==== 对应的数据')
+  return
   loadingFrom.deptDialogVisibleLoading = true
   post(GET_ADDDEPT, { ...deptForm, otherManagerIds: data.otherManagerIds && data.otherManagerIds.join(',') }).then(res => {
     if (res.code != 'ok') {

+ 23 - 10
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/module/AddPersonnelModal.vue

@@ -1,5 +1,6 @@
 <template>
-    <el-dialog v-model="data.addPersonnelDialogVisible" :title="'添加人员'" :show-close="false" width="600" :before-close="handleClose">
+    <el-dialog v-model="data.addPersonnelDialogVisible" :title="'添加人员'" :show-close="false" width="600"
+        :before-close="handleClose">
         <template #header="{ close, titleId, titleClass }">
             <div class="flex justify-between items-center border-b pb-3 dialog-header">
                 <h4 :id="titleId">添加/编辑人员</h4>
@@ -15,7 +16,12 @@
             <el-form ref="personnelRuleFormRef" style="max-width: 500px" :model="personnelFrom" :rules="personnelRules"
                 label-width="120px" size="large" status-icon>
                 <el-form-item label="姓名" prop="name">
-                    <el-input v-model="personnelFrom.name" placeholder="请输入姓名" clearable />
+                    <el-input v-if="userInfo.userNameNeedTranslate == 0" v-model="personnelFrom.name"
+                        placeholder="请输入姓名" clearable />
+                    <div v-if="userInfo.userNameNeedTranslate == 1">
+                        <TextTranslation translationTypes="userName" :translationValue="personnelFrom.name">
+                        </TextTranslation>
+                    </div>
                 </el-form-item>
                 <el-form-item label="电话">
                     <el-input v-model="personnelFrom.phone" placeholder="请输入电话" clearable />
@@ -24,26 +30,33 @@
                     <el-input v-model="personnelFrom.jobNumber" placeholder="请输入工号" clearable />
                 </el-form-item>
                 <el-form-item label="部门">
-                    <el-cascader v-model="personnelFrom.departmentId" :options="data.deptList" placeholder="请选择部门" :props="{ checkStrictly: true }" clearable style="width: 100%" />
+                    <!-- <el-cascader v-model="personnelFrom.departmentId" :options="data.deptList" placeholder="请选择部门" :props="{ checkStrictly: true }" clearable style="width: 100%" /> -->
+                    <tree-select v-model="personnelFrom.departmentId" :size="''" checkStrictly placeholder="请选择部门" :key="personnelFrom.departmentId"></tree-select>
                 </el-form-item>
                 <el-form-item label="角色">
                     <el-select v-model="personnelFrom.roleId" placeholder="请选择角色" size="large">
-                        <el-option v-for="item in data.roleList" :key="item.id" :label="item.rolename" :value="item.id" />
+                        <el-option v-for="item in data.roleList" :key="item.id" :label="item.rolename"
+                            :value="item.id" />
                     </el-select>
                 </el-form-item>
                 <el-form-item label="入职时间">
-                    <el-date-picker v-model="personnelFrom.inductionDate" type="date" placeholder="选择入职时间" value-format="YYYY-MM-DD" style="width: 100%" />
+                    <el-date-picker v-model="personnelFrom.inductionDate" type="date" placeholder="选择入职时间"
+                        value-format="YYYY-MM-DD" style="width: 100%" />
                 </el-form-item>
             </el-form>
-        </div> 
+        </div>
     </el-dialog>
 </template>
 <script setup lang="ts">
 import { ref, watch, reactive } from 'vue'
 import { FormRules, FormInstance } from 'element-plus'
 import { getFromValue, resetFromValue } from '@/utils/tools'
+import { storeToRefs } from 'pinia';
+import { useStore } from '@/store/index'
+import treeSelect from '@/components/translationComponent/treeSelect/treeSelect.vue'
 
 const emit = defineEmits(['closeModal', 'personnelModalConfirm']);
+const { userInfo } = storeToRefs(useStore());
 // 定义类型
 interface Props {
     data: {
@@ -60,7 +73,8 @@ interface personnelFromType { // 类型定义
     phone: string | number,
     jobNumber: string,
     roleId: string | number,
-    departmentId: string[] | number[],
+    // departmentId: string[] | number[],
+    departmentId: string | number,
     inductionDate: string,
 }
 const data = ref<Props['data']>({
@@ -76,7 +90,7 @@ const personnelFrom = ref<personnelFromType>({ // 填写的内容
     phone: '',
     jobNumber: '',
     roleId: '',
-    departmentId: [],
+    departmentId: '',
     inductionDate: '',
 });
 
@@ -92,8 +106,7 @@ const personnelRules = reactive<FormRules<typeof personnelFrom>>({ // 部门表
 function addPersonel(formEl: FormInstance | undefined) {
     if (!formEl) return
     let dataForm = getFromValue(personnelFrom.value)
-    const { departmentId } = dataForm
-    emit('personnelModalConfirm', { ...dataForm, departmentId: departmentId && departmentId[departmentId.length - 1]  }, 'addPersonnelDialogVisible')
+    emit('personnelModalConfirm', { ...dataForm }, 'addPersonnelDialogVisible')
 }
 
 // 监听 Props 的变化

+ 2 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/store/Store.d.ts

@@ -2,7 +2,8 @@ type SotreState = {
   userInfo: any;
   routers: RouteRecordRaw[];
   asyncRoutesMark: boolean;
-  personnelList: any[]
+  personnelList: any[];
+  departmentList: any[];
 };
 type SoreGetters = {
   getRoutersList: () => RouteRecordRaw[];

+ 2 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/store/index.ts

@@ -11,6 +11,7 @@ export const useStore = defineStore<
     routers: [], // 返回的所有路由
     asyncRoutesMark: false, // 是否添加过路由
     personnelList: [], // 人员列表
+    departmentList: [], // 部门列表
   }),
   getters: {
     getRoutersList() {
@@ -50,6 +51,7 @@ export const useStore = defineStore<
       this.userInfo = {};
       this.routers = [];
       this.personnelList = [];
+      this.departmentList = [];
       this.asyncRoutesMark = false;
     },
   },

+ 5 - 76
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/WeiXinCorpController.java

@@ -106,9 +106,6 @@ public class WeiXinCorpController {
     @Value("${configEnv.isPrivateDeploy}")
     private boolean isPrivateDeploy;//企业内部应用,私有化部署的情况
 
-    //自己公司的企业微信通讯录secret
-    private String concactSecret="irf7s8fy16wLhWGb8IxvGL2Nkm0sTB6dludpe_3VP6k";
-
     @Value("${token}")
     private String token;
     @Value("${encodingAesKey}")
@@ -1398,45 +1395,15 @@ public class WeiXinCorpController {
                         String editionId = wxOrder.getEditionId();
                         switch (editionId){
                             //基础版
-                            case "sp17da4a6e6f2a91f8":
-                                newCompany.setPackageProject(0);
-                                newCompany.setPackageOa(0);
-                                newCompany.setPackageExpense(0);
-                                newCompany.setPackageCustomer(0);
-                                newCompany.setPackageEngineering(0);
-                                newCompany.setPackageProvider(0);
+                            case "sp8f9473908bd5f6b0":
                                 break;
                             //专业版
-                            case "sp4a30d92ede178afd":
-                                newCompany.setPackageProject(1);//项目协作平台
-                                newCompany.setPackageOa(0);//OA平台;请假,出差等
-                                newCompany.setPackageExpense(1);//费用报销
-                                newCompany.setPackageCustomer(0);//客户管理
-                                newCompany.setPackageEngineering(0);//工程专业
-                                newCompany.setPackageProvider(0);//供应商模块
-                                break;
-                            //建筑版
-                            case "sp29bdb884f4a78392":
-                                newCompany.setPackageProject(1);//项目协作平台
-                                newCompany.setPackageOa(0);//OA平台;请假,出差等
-                                newCompany.setPackageExpense(1);//费用报销
-                                newCompany.setPackageCustomer(1);//客户管理
-                                newCompany.setPackageEngineering(1);//工程专业
-                                newCompany.setPackageProvider(0);//供应商模块
-                                break;
-                            //旗舰版
-                            case "sp852fec2d1198957a":
-                                newCompany.setPackageProject(1);//项目协作平台
-                                newCompany.setPackageOa(1);//OA平台;请假,出差等
-                                newCompany.setPackageExpense(1);//费用报销
-                                newCompany.setPackageCustomer(1);//客户管理
-                                newCompany.setPackageEngineering(0);//工程专业
-                                newCompany.setPackageProvider(1);//供应商模块
+                            case "sp158cbb42aebdeab0":
+                                newCompany.setSetMeal(1);
                                 break;
                         }
                         LocalDateTime endTime = wxOrder.getEndTime();
                         newCompany.setExpirationDate(endTime);
-                        newCompany.setSetMeal(1);
                         newCompany.setStaffCountMax(wxOrder.getUserCount());
                         companyMapper.updateById(newCompany);
                         System.out.println("版本变更成功,到期时间更新成功。");
@@ -1487,7 +1454,6 @@ public class WeiXinCorpController {
                         SysRole smanager = sysRoleMapper.selectOne(
                                 new QueryWrapper<SysRole>().eq("company_id", companyId).eq("rolename", "超级管理员"));
                         //授权人就当做是超级管理员吧
-                        log.info("===userDetail==" + userDetail.toJSONString());
                         SysRole defaultRole = null;
                         if (userMapper.selectCount(new QueryWrapper<User>().eq("role_id", smanager.getId()))> 0) {
                             //已经有超级管理员了,用默认权限
@@ -3322,45 +3288,8 @@ public class WeiXinCorpController {
             String edition_id = json.getJSONObject("edition_info").getJSONArray("agent")
                     .getJSONObject(0).getString("edition_id");
             //非体验版
-            if (!"sp4abb17b6c9df6f9f".equals(edition_id)) {
-                switch (edition_id){
-                    //基础版
-                    case "sp17da4a6e6f2a91f8":
-                        newCompany.setPackageProject(0);
-                        newCompany.setPackageOa(0);
-                        newCompany.setPackageExpense(0);
-                        newCompany.setPackageCustomer(0);
-                        newCompany.setPackageEngineering(0);
-                        newCompany.setPackageProvider(0);
-                        break;
-                    //专业版
-                    case "sp4a30d92ede178afd":
-                        newCompany.setPackageProject(1);//项目协作平台
-                        newCompany.setPackageOa(0);//OA平台;请假,出差等
-                        newCompany.setPackageExpense(1);//费用报销
-                        newCompany.setPackageCustomer(0);//客户管理
-                        newCompany.setPackageEngineering(0);//工程专业
-                        newCompany.setPackageProvider(0);//供应商模块
-                        break;
-                    //建筑版
-                    case "sp29bdb884f4a78392":
-                        newCompany.setPackageProject(1);//项目协作平台
-                        newCompany.setPackageOa(0);//OA平台;请假,出差等
-                        newCompany.setPackageExpense(1);//费用报销
-                        newCompany.setPackageCustomer(1);//客户管理
-                        newCompany.setPackageEngineering(1);//工程专业
-                        newCompany.setPackageProvider(0);//供应商模块
-                        break;
-                    //旗舰版
-                    case "sp852fec2d1198957a":
-                        newCompany.setPackageProject(1);//项目协作平台
-                        newCompany.setPackageOa(1);//OA平台;请假,出差等
-                        newCompany.setPackageExpense(1);//费用报销
-                        newCompany.setPackageCustomer(1);//客户管理
-                        newCompany.setPackageEngineering(0);//工程专业
-                        newCompany.setPackageProvider(1);//供应商模块
-                        break;
-                }
+            if (!"sp8f9473908bd5f6b0".equals(edition_id)) {
+                newCompany.setSetMeal(1);
                 companyMapper.updateById(newCompany);
                 System.out.println("已成功变更版本,版本号为:"+edition_id);
                 //开通模块和权限

+ 13 - 0
fhKeeper/formulahousekeeper/management-platform/pom.xml

@@ -14,6 +14,19 @@
     <version>3.4.0</version>
 
     <dependencies>
+
+<!--        <dependency>-->
+<!--            <groupId>cn.hutool</groupId>-->
+<!--            <artifactId>hutool-all</artifactId>-->
+<!--            <version>5.8.9</version>-->
+<!--        </dependency>-->
+<!--        <dependency>-->
+<!--            <groupId>commons-codec</groupId>-->
+<!--            <artifactId>commons-codec</artifactId>-->
+<!--            <version>1.10</version>-->
+<!--        </dependency>-->
+
+
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>

+ 3 - 11
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/FinancialAuditController.java

@@ -2,33 +2,25 @@ package com.management.platform.controller;
 
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.management.platform.entity.FinancialAudit;
-import com.management.platform.entity.Project;
-import com.management.platform.entity.ProjectStage;
 import com.management.platform.entity.User;
 import com.management.platform.mapper.UserMapper;
 import com.management.platform.service.FinancialAuditService;
-import com.management.platform.service.ProjectStageService;
 import com.management.platform.util.HttpRespMsg;
-import com.management.platform.util.MessageUtils;
-import io.lettuce.core.pubsub.PubSubOutput;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.RequestMapping;
-
-import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
-import java.util.*;
-import java.util.stream.Collectors;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * <p>

+ 3 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/WxCorpInfoService.java

@@ -48,7 +48,7 @@ public interface WxCorpInfoService extends IService<WxCorpInfo> {
 
     public String getTranslationMediaId(String fileName) throws Exception;
 
-    public String getTranslationJobId(String fileName,WxCorpInfo wxCorpInfo) throws Exception;
+    public String getTranslationJobId(String fileName,String md5,WxCorpInfo wxCorpInfo) throws Exception;
 
     public String syncTranslation(String authCorpid,String mediaId,String outPutFileName,String outputFileFormat) throws Exception;
 
@@ -87,4 +87,6 @@ public interface WxCorpInfoService extends IService<WxCorpInfo> {
     JSONArray getApprovalInfo(Integer companyId, String startDate, String endDate, String newCursor, JSONArray filterArray) throws Exception;
 
     public String applyEvent(HttpServletRequest request, JSONObject data) throws Exception;
+
+    String getAsyncJobResult(String tmpFileJobId,WxCorpInfo wxCorpInfo)  throws Exception;
 }

+ 18 - 15
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DingDingServiceImpl.java

@@ -2758,24 +2758,27 @@ public class DingDingServiceImpl implements DingDingService {
             String endTime = null;
             String realPlanStartTime = null;
             String realPlanEndTime = null;
-            for (int i=0;i<array.size(); i++) {
-                JSONObject obj = array.getJSONObject(i);
-                //出差类型
-                System.out.println(obj);
-                if (obj.getInteger("approve_biz_type") == 2) {
-                    if (obj.getString("check_type").equals("OnDuty")) {
-                        //出差开始时间
-                        System.out.println("出差开始时间=="+obj.getString("check_date_time"));
-                        startTime = obj.getString("check_date_time");
-                        realPlanStartTime = obj.getString("real_plan_time");
-                    } else {
-                        //出差结束时间
-                        System.out.println("出差结束时间=="+obj.getString("check_date_time"));
-                        endTime = obj.getString("check_date_time");
-                        realPlanEndTime = obj.getString("real_plan_time");
+            if (array != null) {
+                for (int i=0;i<array.size(); i++) {
+                    JSONObject obj = array.getJSONObject(i);
+                    //出差类型
+                    System.out.println(obj);
+                    if (obj.getInteger("approve_biz_type") == 2) {
+                        if (obj.getString("check_type").equals("OnDuty")) {
+                            //出差开始时间
+                            System.out.println("出差开始时间=="+obj.getString("check_date_time"));
+                            startTime = obj.getString("check_date_time");
+                            realPlanStartTime = obj.getString("real_plan_time");
+                        } else {
+                            //出差结束时间
+                            System.out.println("出差结束时间=="+obj.getString("check_date_time"));
+                            endTime = obj.getString("check_date_time");
+                            realPlanEndTime = obj.getString("real_plan_time");
+                        }
                     }
                 }
             }
+
             if (startTime != null && endTime != null) {
                 //获取到出差的时间,计算时长
                 DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

+ 18 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ExcelExportServiceImpl.java

@@ -13,6 +13,7 @@ import com.management.platform.util.ExcelUtil;
 import com.management.platform.util.HttpRespMsg;
 import com.management.platform.util.MessageUtils;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.FileSystemResource;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Isolation;
 import org.springframework.transaction.annotation.Transactional;
@@ -82,19 +83,33 @@ public class ExcelExportServiceImpl implements ExcelExportService {
         String resp = ExcelUtil.exportGeneralExcelByTitleAndList(title, list, downloadPath);
         String fileUrlSuffix = title + ".xlsx";
         if(wxCorpInfo != null && wxCorpInfo.getSaasSyncContact() == 1){
-//            FileSystemResource fileSystemResource = new FileSystemResource(path+fileUrlSuffix);
-//            Long checkSize = 20L*1024*1024;
+            FileSystemResource fileSystemResource = new FileSystemResource(path+fileUrlSuffix);
+//            String md5 = DigestUtils.md5Hex(FileUtil.readBytes(fileSystemResource.getFile()));
+
+            Long checkSize = 20L*1024*1024;
+            if(fileSystemResource.getFile().length() >= checkSize){
+                httpRespMsg.setError("文件过大,请缩短查询日期范围");
+                return httpRespMsg;
+            }
             String jobId = "";
             String mediaId = wxCorpInfoService.getTranslationMediaId(fileUrlSuffix);
             jobId = wxCorpInfoService.syncTranslation(wxCorpInfo.getCorpid(),mediaId,fileUrlSuffix, null);
 //            if(fileSystemResource.getFile().length() >= checkSize){
-//                jobId = wxCorpInfoService.getTranslationJobId(fileUrlSuffix,wxCorpInfo);
+//                String tmpFileJobId = wxCorpInfoService.getTranslationJobId(fileUrlSuffix,md5,wxCorpInfo);
+//                if(!StringUtils.isEmpty(tmpFileJobId)){
+//                    String mediaId = wxCorpInfoService.getAsyncJobResult(tmpFileJobId,wxCorpInfo);
+//                    jobId = wxCorpInfoService.syncTranslation(wxCorpInfo.getCorpid(),mediaId,fileUrlSuffix, null);
+//                }
 //            }else{
 //                String mediaId = wxCorpInfoService.getTranslationMediaId(fileUrlSuffix);
 //                jobId = wxCorpInfoService.syncTranslation(wxCorpInfo.getCorpid(),mediaId,fileUrlSuffix, null);
 //            }
 
             System.out.println("上传待转译文件到企业微信, jobId==" + jobId);
+//            if(StringUtils.isEmpty(jobId)){
+//                httpRespMsg.setError("转义jobId为空,请联系管理员");
+//                return httpRespMsg;
+//            }
             int i = 0;
             String syncTranslationResult = null;
             /**

+ 66 - 4
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/WxCorpInfoServiceImpl.java

@@ -174,6 +174,7 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
     //获取服务商provider_access_token
     @Override
     public String getProviderAccessToken() throws Exception {
+        System.out.println("in getProviderAccessToken  method");
         String access_token="";
         String url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_provider_token";
         HttpHeaders headers = new HttpHeaders();
@@ -192,6 +193,7 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
             }
             access_token= json.getString("provider_access_token");
         }
+        System.out.println("end getProviderAccessToken  method");
         return access_token;
     }
 
@@ -230,7 +232,7 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
     }
 
     @Override
-    public String getTranslationJobId(String fileName, WxCorpInfo wxCorpInfo) throws Exception {
+    public String getTranslationJobId(String fileName,String md5, WxCorpInfo wxCorpInfo) throws Exception {
         System.out.println("in getTranslationJobId method");
         String jobId="";
         //然后处理文件 通讯录id转译
@@ -240,8 +242,10 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
         params.put("scene",1);
         params.put("type","file");
         params.put("filename",fileName);
-        params.put("url","https://worktime.ttkuaiban.com/upload/"+fileName);
-        params.put("md5","MD5");
+//        params.put("url","https://worktime.ttkuaiban.com/upload/"+fileName);
+        params.put("url","http://47.101.180.183:9097/upload/"+fileName);
+//        System.out.println("uploadJobFileUrl=== "+"http://47.101.180.183:9097/upload/"+fileName);
+        params.put("md5",md5);
         String requestBody = JSONObject.toJSONString(params);
         HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
         String apiUrl = "https://qyapi.weixin.qq.com/cgi-bin/media/upload_by_url?access_token="+getCorpAccessToken(wxCorpInfo);
@@ -253,7 +257,7 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
         Map responseObj = objectMapper.readValue(responseBody, Map.class);
         if (responseEntity.getStatusCode() == HttpStatus.OK){
             if(null != responseObj.get("errcode") && 0 == Integer.parseInt(responseObj.get("errcode").toString())){
-                jobId = responseObj.get("job_id").toString();
+                jobId = responseObj.get("jobid").toString();
             }else{
                 System.out.println("error Trans====== "+responseObj.get("errmsg").toString());
             }
@@ -2574,4 +2578,62 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
         }
         return "";
     }
+
+    @Override
+    public String getAsyncJobResult(String tmpFileJobId,WxCorpInfo wxCorpInfo) throws Exception{
+        System.out.println("in getAsyncJobResult method");
+        String mediaId = "";
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        Map<String,Object> params = new HashMap<>();
+        params.put("jobid",tmpFileJobId);
+        String requestBody = JSONObject.toJSONString(params);
+        HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
+        String apiUrl = "https://qyapi.weixin.qq.com/cgi-bin/media/get_upload_by_url_result?access_token="+getCorpAccessToken(wxCorpInfo);
+        
+        int i = 0;
+        while(i < 100){
+            if (i < 10) {
+                Thread.sleep(300);
+            } else if (i < 20){
+                Thread.sleep(1000);
+            } else {
+                Thread.sleep(3000);
+            }
+            System.out.println("i=="+i+", "+LocalDateTime.now());
+            ResponseEntity<String> responseEntity = restTemplate.exchange(apiUrl, HttpMethod.POST, entity, String.class);
+            String responseBody = responseEntity.getBody();
+            System.out.println("getAsyncJobResult Response from API: " + responseBody);
+            JSONObject jsonRes = JSONObject.parseObject(responseBody);
+            if (responseEntity.getStatusCode() == HttpStatus.OK){
+                if(null != jsonRes.get("errcode") && 0 == Integer.parseInt(jsonRes.get("errcode").toString())){
+                    String status = jsonRes.get("status").toString();
+                    if("1".equals(status)){
+                        //处理中
+                    } else if ("2".equals(status)) {
+                        //已完成
+                        String detailStr = jsonRes.getString("detail");
+                        JSONObject detailJson = JSONObject.parseObject(detailStr);
+                        mediaId = detailJson.getString("media_id");
+                        break;
+                    } else if ("3".equals(status)) {
+                        //报错了
+                        String detailStr = jsonRes.getString("detail");
+                        System.out.println("detailStr==="+detailStr);
+                        JSONObject detailJson = JSONObject.parseObject(detailStr);
+                        System.out.println("企业微信转译报错:"+detailJson.getString("errmsg"));
+                        break;
+                    }
+                }else{
+                    System.out.println("error Trans====== "+jsonRes.get("errmsg").toString());
+                    break;
+                }
+            }
+            i++;
+        }
+
+
+        System.out.println("end getAsyncJobResult method");
+        return mediaId;
+    }
 }

+ 21 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java

@@ -1564,11 +1564,23 @@ public class TimingTask {
                         return;
                     }
                     if (alertDay.equals(localDate.getDayOfMonth())) {
-                        //获取上个月的开始和节数日期
+                        //获取上个月的开始和结束日期
                         LocalDate startDate = localDate.minusMonths(1).with(TemporalAdjusters.firstDayOfMonth());
                         LocalDate endDate = localDate.minusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
                         userList = reportService.getNotFullReportUserList(company.getId(), startDate, endDate);
                     }
+                } else if (t.getAlertType() == 5) {
+                    //3--每月固定日期提醒本月的
+                    Integer alertDay = t.getAlertDay();
+                    if (alertDay == null) {
+                        return;
+                    }
+                    if (alertDay.equals(localDate.getDayOfMonth())) {
+                        //获取本月的开始和结束日期
+                        LocalDate startDate = localDate.with(TemporalAdjusters.firstDayOfMonth());
+                        LocalDate endDate = localDate.with(TemporalAdjusters.lastDayOfMonth());
+                        userList = reportService.getNotFullReportUserList(company.getId(), startDate, endDate);
+                    }
                 } else if (t.getAlertType() == 4) {
                     //4--每周提醒上周漏填
                     LocalDate lastSunday = localDate.with(DayOfWeek.SUNDAY).minusWeeks(1);
@@ -1632,6 +1644,13 @@ public class TimingTask {
                                 } else {
                                     jsonObj.put("value", "您上个月有"+u.get("daysTxt")+"共"+(Integer)u.get("days")+"天未填写工时报告,请尽快填写");
                                 }
+                            } else if (t.getAlertType() == 5) {
+                                //每月提醒本月
+                                if ((Integer)u.get("days") > 3) {
+                                    jsonObj.put("value", "您本月有"+u.get("daysTxt")+"...共"+(Integer)u.get("days")+"天未填写工时报告,请尽快填写");
+                                } else {
+                                    jsonObj.put("value", "您本月有"+u.get("daysTxt")+"共"+(Integer)u.get("days")+"天未填写工时报告,请尽快填写");
+                                }
                             } else {
                                 if (finalLastWeekNotFill) {
                                     String text = null;
@@ -1654,7 +1673,7 @@ public class TimingTask {
                                 json.put("content_item",dataJson);
                             }
                             if (cpList.size() > 0) {
-                                System.out.println("发送企业微信漏填提醒:" + LocalDateTime.now().toString() + ", corpUid=" + corpUid + ", json=" + json.toJSONString());
+//                                System.out.println("发送企业微信漏填提醒:" + LocalDateTime.now().toString() + ", corpUid=" + corpUid + ", json=" + json.toJSONString());
                                 wxCorpInfoService.sendWXCorpTemplateMsg(cpList.get(0), corpUid, json);
                             }
                         } else if (u.get("wxOpenid") != null) {

+ 1 - 0
fhKeeper/formulahousekeeper/timesheet/src/i18n/en.json

@@ -950,6 +950,7 @@
   "lastDayOfWeek": "Remind on the last day of current week",
   "alertLastWeek": "Remind last week's missing report",
   "monthAlert": "Remind last month's missed report on fixed day",
+  "curMonthAlert": "Remind current month's missed report on fixed day",
   "morningtime": "morning time",
   "owntimeframe": "Choose your own time frame",
   "personneltoset": "Don't remind people settings",

+ 1 - 0
fhKeeper/formulahousekeeper/timesheet/src/i18n/zh.json

@@ -958,6 +958,7 @@
   "lastDayOfWeek": "每周最后一个工作日",
   "alertLastWeek": "每周提醒上周漏填",
   "monthAlert": "每月固定日期提醒上个月",
+  "curMonthAlert": "每月固定日期提醒本月",
   "remindertext": "提醒文本",
   "personneltoset": "不提醒人员设置",
   "addTian": "添加",

+ 8 - 3
fhKeeper/formulahousekeeper/timesheet/src/views/settings/timetype.vue

@@ -223,9 +223,10 @@
                             <el-option :label="$t('missingfills')" :value="1"></el-option>
                             <el-option :label="$t('lastDayOfWeek')" :value="2"></el-option>
                             <el-option :label="$t('monthAlert')" :value="3"></el-option>
+                            <el-option :label="$t('curMonthAlert')" :value="5"></el-option>
                             <el-option :label="$t('alertLastWeek')" :value="4"></el-option>
                         </el-select>
-                        <span v-if="timeType.alertType == 3" style="color:#606266;">({{ $t('meiYue') }}
+                        <span v-if="timeType.alertType == 3 || timeType.alertType == 5" style="color:#606266;">({{ $t('meiYue') }}
                         <el-select v-model="timeType.alertDay" style="width:80px;">
                             <el-option v-for="item in alertDayRange" :label="item" :value="item" :key="item"></el-option>
                         </el-select>
@@ -236,7 +237,7 @@
                         </el-select>
                         {{ $t('tiXing') }})</span>
                     </el-form-item>
-                    <el-form-item v-if="timeType.alertType != 3" :label="$t('remindertext')" prop="alertMsg" style="margin-left:10px;">
+                    <el-form-item v-if="timeType.alertType != 3 && timeType.alertType != 5" :label="$t('remindertext')" prop="alertMsg" style="margin-left:10px;">
                             <el-input :placeholder="$t('peaseenterthe')" v-model="timeType.alertMsg" clearable class="apu" maxlength="50"></el-input>
                             <span v-if="timeType.alertType == 4" style="color:orange;margin-left:10px;">{{ $t('keYong_0BiaoShiLouTianRiQiLiRu_0JiangBeiTiHuanWei_05240525') }}</span>
                     </el-form-item>
@@ -809,7 +810,7 @@
                     onPreviousStep: this.myCustomPreviousStepCallback,   //在data中定义两个回调
                     onNextStep: this.myCustomNextStepCallback
                 },
-                alertDayRange: ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15'],
+                alertDayRange: [],
                 alertWeekDayRange: [{value:1,label:this.$t('weekDay.monday')},{value:2,label:this.$t('weekDay.tuesday')},{value:3,label:this.$t('weekDay.wednesday')},{value:4,label:this.$t('weekDay.thursday')},{value:5,label:this.$t('weekDay.friday')}],
                 pushParam:{
                     day:'05',
@@ -921,6 +922,10 @@
             };
         },
         mounted() {
+            this.alertDayRange = [];
+            for(let i=1; i<=30; i++){
+                this.alertDayRange.push(''+i)
+            }
             this.timeRange = []
             for(let i=0.5; i<=20; i+=0.5){
                 this.timeRange.push(i)