Parcourir la source

Merge remote-tracking branch 'origin/master'

yusm il y a 1 an
Parent
commit
85ab51eaa9
52 fichiers modifiés avec 18693 ajouts et 98927 suppressions
  1. 1 3
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/login.vue
  2. 6 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/system/role/api.ts
  3. 294 4
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/system/role/index.vue
  4. 9 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/ImportModal.vue
  5. 141 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/TaskModal.vue
  6. 66 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/api.ts
  7. 205 43
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/index.vue
  8. 9 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/api.ts
  9. 444 3
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/index.vue
  10. 107 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/module/AddPersonnelModal.vue
  11. 12 9
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/thread/index.vue
  12. 1 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/store/Store.d.ts
  13. 4 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/store/index.ts
  14. 58 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/utils/tools.ts
  15. 16156 27181
      fhKeeper/formulahousekeeper/management-crm/crm.log
  16. 1 1
      fhKeeper/formulahousekeeper/management-crm/pom.xml
  17. 49 13
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/BusinessOpportunityController.java
  18. 31 14
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ClueController.java
  19. 17 10
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ProductController.java
  20. 5 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/SysFormController.java
  21. 4 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/BusinessOpportunity.java
  22. 17 3
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/Product.java
  23. 9 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/mapper/BusinessOpportunityMapper.java
  24. 4 1
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/mapper/ClueMapper.java
  25. 13 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/BusinessOpportunityService.java
  26. 3 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/ClueService.java
  27. 7 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/ProductService.java
  28. 2 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/SysFormService.java
  29. 41 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/BusinessOpportunityServiceImpl.java
  30. 11 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ClueServiceImpl.java
  31. 316 4
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ProductServiceImpl.java
  32. 233 1
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/SysFormServiceImpl.java
  33. 141 2
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/BusinessOpportunityMapper.xml
  34. 65 23
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/ClueMapper.xml
  35. 2 2
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/ProductMapper.xml
  36. BIN
      fhKeeper/formulahousekeeper/management-crm/workTime.2024-03-01.log.gz
  37. 0 71539
      fhKeeper/formulahousekeeper/management-crm/workTime.log
  38. 28 7
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/GroupBudgetReviewController.java
  39. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectController.java
  40. 28 4
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TaskGroupController.java
  41. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/GroupBudgetReview.java
  42. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Project.java
  43. 7 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TaskGroup.java
  44. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectService.java
  45. 29 21
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java
  46. 17 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/BeiSenUtils.java
  47. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml
  48. 1 1
      fhKeeper/formulahousekeeper/management-workshop/src/main/resources/application.yml
  49. 3 3
      fhKeeper/formulahousekeeper/timesheet/src/views/project/budgetReview.vue
  50. 8 2
      fhKeeper/formulahousekeeper/timesheet/src/views/project/list.vue
  51. 48 10
      fhKeeper/formulahousekeeper/timesheet/src/views/project/projectInside.vue
  52. 16 16
      fhKeeper/formulahousekeeper/timesheet/src/views/task/list.vue

+ 1 - 3
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/login.vue

@@ -88,9 +88,7 @@ const login = (formEl: FormInstance | undefined) => {
         loginLoading.value = false;
         router.push(res.data?.moduleList[0].path);
       }, 1000)
-      loginLoading.value = false;
-    }).catch(err => {
-      //console.log(err)
+    }).catch(_err => {
       loginLoading.value = false;
     })
     return

+ 6 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/system/role/api.ts

@@ -0,0 +1,6 @@
+export const MOD = 'role'
+export const GETROLELIST = '/permission/getFrontRoleList'
+export const DETELEROLE = '/permission/deleteRole'
+export const EDITROLE = '/permission/editRole'
+export const GETAUTORITY = '/permission/getAuthority'
+export const SAVEPERM = '/permission/savePermission'

+ 294 - 4
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/system/role/index.vue

@@ -1,12 +1,302 @@
 <template>
-  <div>
-    角色权限
-    <div>左右</div>
-    <div></div>
+  <div class="h-full flex flex-col roleStyle">
+    <!-- 头部 -->
+    <div class="bg-white flex justify-between team-header">
+      <div class="flex items-center justify-between w-full">
+        <div></div>
+        <div>
+          <el-button type="primary" @click="changeRole()">添加角色</el-button>
+          <el-button type="primary">修改默认角色</el-button>
+        </div>
+      </div>
+    </div>
+    <!-- 内容 -->
+    <div class="flex-1 flex">
+      <div class="flex-1 p-5 overflow-auto">
+        <div class="bg-white w-full h-full shadow-md rounded-md flex flex-col">
+          <div class="flex-1 p-3">
+            <el-table :data="filterTableData" style="width: 100%;height: 100%;" v-bind:loading="allLoading.tableLoading">
+              <el-table-column label="角色" prop="rolename" width="300" />
+              <el-table-column label="描述" prop="roleDescribe" />
+              <el-table-column align="right" width="386">
+                <template #header>
+                  <el-input v-model="searchRoleName" placeholder="请输入关键字搜索" />
+                </template>
+                <template #default="scope">
+                  <el-button @click="changeRole(scope.row)">编辑角色</el-button>
+                  <el-button type="primary" @click="distributionPermissions(scope.row)">分配权限</el-button>
+                  <el-button>导出权限</el-button>
+                  <el-button type="danger" @click="deteleRole(scope.row)">删除</el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 添加角色/编辑角色 -->
+    <el-dialog v-model="allDialogVisible.roleDialogVisible" :title="roleTitle" width="600" :before-close="handleClose">
+      <div>
+        <el-form ref="roleFormRef" :model="roleFrom" label-width="auto">
+          <el-form-item prop="name" label="角色名称" :rules="[
+            {
+              required: true,
+              message: '请输入角色名称',
+              trigger: 'blur',
+            },
+          ]">
+            <el-input v-model="roleFrom.name" placeholder="请输入角色名称" clearable />
+          </el-form-item>
+          <el-form-item label="描述">
+            <el-input v-model="roleFrom.description" placeholder="请输入描述" type="textarea" clearable />
+          </el-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="allDialogVisible.roleDialogVisible = false">取消</el-button>
+          <el-button type="primary" v-bind:loading="allLoading.roleLoading" @click="addRole(roleFormRef)">确定</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 分配权限 -->
+    <el-dialog v-model="allDialogVisible.permissionsDialogVisible" :title="`分配权限-${permissionsDataItem.rolename}`" width="800"
+      :before-close="handleClose">
+      <div class="permissionsData">
+        <div v-for="(item, index) in permissionsData" :key="index" class="list">
+          <div class="itemName">
+            <el-checkbox size="large" v-model="item.checked" style="width: 16px; font-weight: bold;"
+              @change="changeCheckBox(item, true)">{{ item.name }}</el-checkbox>
+          </div>
+          <div class="flex-1 flex item">
+            <div v-for="(list, listIndex) in item.functionList" :key="listIndex" class="itemName">
+              <el-checkbox size="large" v-model="list.checked" style="width: 16px;"
+                @change="changeCheckBox(item, false)">{{ list.name }}</el-checkbox>
+            </div>
+          </div>
+        </div>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" v-bind:loading="allLoading.permissionsLoading" @click="edtPermissions()">保存</el-button>
+        </div>
+      </template>
+    </el-dialog>
   </div>
 </template>
+
 <script lang="ts" setup>
+import { ref, onMounted, reactive, inject, computed } from 'vue';
+import { Search, CirclePlusFilled, Edit, CirclePlus, Delete } from '@element-plus/icons-vue'
+import { post } from "@/utils/request";
+import { GETROLELIST, MOD, DETELEROLE, EDITROLE, GETAUTORITY, SAVEPERM } from "./api.ts";
+import { FormInstance, FormRules, ElMessageBox } from 'element-plus'
+import { useStore } from '@/store/index'
+import { getFromValue, updateDepTreeData, resetFromValue } from '@/utils/tools'
+
+interface roleRuleForm {
+  id: string
+  name: string
+  description: string
+}
+
+const { getFunctionList, getUserInfoVal } = useStore()
+const globalPopup = inject<GlobalPopup>('globalPopup')
+
+const companyId = reactive(getUserInfoVal('companyId') || '')
+const searchRoleName = ref('') // 搜索条件
+const tableData: any = ref([]) // 表格数据
+const permissionsData: any = ref([]) // 权限数据
+const permissionsDataItem: any = ref({}) // 选中的权限数据
+const roleTitle = ref('添加角色') // 弹窗标题
+const roleFormRef = ref<FormInstance>() // 表单ref
+const roleFrom = reactive<roleRuleForm>({ // 表单数据
+  id: '',
+  name: '',
+  description: ''
+})
+
+const allDialogVisible = reactive({
+  roleDialogVisible: false,
+  permissionsDialogVisible: false
+})
+
+const allLoading = reactive({
+  tableLoading: false,
+  roleLoading: false,
+  permissionsLoading: false
+})
+
+const filterTableData = computed(() =>
+  tableData.value.filter(
+    (data: any) =>
+      !searchRoleName.value ||
+      data.rolename.toLowerCase().includes(searchRoleName.value.toLowerCase())
+  )
+)
+
+function edtPermissions() {
+  allLoading.permissionsLoading = true
+  let moduleList = JSON.stringify(permissionsData.value)
+  let role = permissionsDataItem.value.id
+  post(SAVEPERM, { role, moduleList }).then(res => {
+    if (res.code != 'ok') {
+      globalPopup?.showError(res.msg)
+      return
+    }
+    globalPopup?.showSuccess('保存成功')
+    allDialogVisible.permissionsDialogVisible = false
+    allLoading.permissionsLoading = false
+    getRoleList()
+  }).catch(() => {
+    allLoading.permissionsLoading = false
+  })
+}
+
+function changeCheckBox(item: any, flag: boolean) {
+  if (flag) {
+    item.functionList.forEach((list: any) => {
+      list.checked = item.checked
+    })
+    return
+  }
+  const { id } = item
+  let mainMenuList = permissionsData.value;
+  mainMenuList.forEach((m: any) => {
+    if (m.id == id) {
+      var hasChecked = false;
+      m.functionList.forEach((c: any) => {
+        if (c.checked) {
+          hasChecked = true;
+        }
+      })
+      if (hasChecked) {
+        console.log('执行')
+        m.checked = hasChecked;
+      }
+    }
+  });
+}
+
+function distributionPermissions(item: any) {
+  const { id } = item
+  permissionsDataItem.value = item
+  post(GETAUTORITY, { role: id, companyId }).then(res => {
+    if (res.code != 'ok') {
+      globalPopup?.showError(res.msg)
+      return
+    }
+    permissionsData.value = res.data
+    allDialogVisible.permissionsDialogVisible = true
+  }).catch(() => {
+    allDialogVisible.permissionsDialogVisible = true
+  })
+}
+
+function addRole(formEl: FormInstance | undefined) {
+  if (!formEl) return
+  let data = getFromValue(roleFrom)
+  allLoading.roleLoading = true
+  post(EDITROLE, { ...data, companyId }).then(res => {
+    if (res.code != 'ok') {
+      globalPopup?.showError(res.msg)
+      return
+    }
+    globalPopup?.showSuccess('添加成功')
+    allDialogVisible.roleDialogVisible = false
+    allLoading.roleLoading = false
+    getRoleList()
+  }).catch(() => {
+    allLoading.roleLoading = false
+  })
+}
 
+function changeRole(item: any = false) {
+  if (!item) {
+    resetData()
+    allDialogVisible.roleDialogVisible = true
+  }
+  const { id, rolename, roleDescribe } = JSON.parse(JSON.stringify(item))
+  Object.assign(roleFrom, { id, name: rolename, description: roleDescribe })
+  allDialogVisible.roleDialogVisible = true
+}
+
+function deteleRole(data: any) {
+  ElMessageBox.confirm(
+    `确定删除【${data.rolename}】角色吗?`, '',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  )
+    .then(() => {
+      post(DETELEROLE, { id: data.id }).then(res => {
+        if (res.code != 'ok') {
+          globalPopup?.showError(res.msg)
+          return
+        }
+        globalPopup?.showSuccess('删除成功')
+        getRoleList()
+      })
+    })
+}
+
+function getRoleList() {
+  allLoading.tableLoading = true
+  const companyId = getUserInfoVal('companyId') || ''
+  post(GETROLELIST, { companyId }).then(res => {
+    tableData.value = res.data
+    allLoading.tableLoading = false
+  }).catch(() => {
+    allLoading.tableLoading = false
+  })
+}
+
+function resetData() {
+  let newRoleFrom = resetFromValue(roleFrom)
+  Object.assign(roleFrom, newRoleFrom)
+}
+
+function handleClose(done: any) {
+  done()
+}
+
+onMounted(() => {
+  getRoleList()
+});
 </script>
+
 <style lang="scss" scoped>
+.roleStyle {
+  .team-header {
+    padding: 0.75rem 1.25rem;
+  }
+
+  .permissionsData {
+    padding: 0 20px 0 40px;
+    height: 56vh;
+    overflow: auto;
+
+    .bold {
+      font-weight: bold;
+    }
+
+    .list {
+      display: flex;
+      justify-content: space-between;
+    }
+
+    .itemName {
+      width: 180px;
+      margin: 0 0 6px 0;
+      font-size: 16px !important;
+    }
+
+    .item {
+      flex-wrap: wrap;
+    }
+  }
+}
 </style>

+ 9 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/ImportModal.vue

@@ -0,0 +1,9 @@
+<template>
+<div>
+</div>
+</template>
+<script lang="ts" setup>
+
+</script>
+<style lang="scss" scoped>
+</style>

+ 141 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/TaskModal.vue

@@ -0,0 +1,141 @@
+<template>
+  <el-dialog v-model="modalVisible" width="30%" :show-close="false" :close-on-click-modal="false">
+    <template #header="{ titleId, titleClass }">
+      <div class="flex justify-between items-center border-b pb-3">
+        <h4 :id="titleId" :class="titleClass">{{ editForm ? '编辑任务' : '新增任务' }}</h4>
+        <div>
+          <el-button type="primary" @click="submitForm(false)">保存并新建</el-button>
+          <el-button type="primary" @click="submitForm(true)">保存</el-button>
+          <el-button @click="closeVisible()">取消</el-button>
+        </div>
+      </div>
+    </template>
+    <el-form ref="formRef" :model="form" label-width="100px" :rules="rules" class="flex flex-wrap form">
+      <el-form-item label="任务名称" prop="taskName" required>
+        <el-input v-model="form.taskName" type="textarea" placeholder="请输入任务名称" clearable maxlength="100"
+          show-word-limit />
+      </el-form-item>
+      <el-form-item prop="priority" label="优先级" required>
+        <el-select v-model="form.priority" placeholder="请选择" clearable>
+          <el-option v-for="item in PRIORITY " :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item prop="taskType" :label="form.taskType">
+        <template #label>
+          <el-select v-model="form.taskType" class="border resetSelect" style="width: 100px">
+            <el-option v-for="item in TASK_TYPE" :key="item.value" :value="item.value" :label="item.label" />
+          </el-select>
+        </template>
+        <el-select v-model="form.priority" placeholder="请选择" clearable filterable>
+          <el-option v-for="item in PRIORITY" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="联系人" v-if="TASK_TYPE.find(v => v.value === (form.taskType || '1'))?.show">
+        <el-select v-model="form.contact" placeholder="请选择" clearable filterable>
+          <el-option v-for="item in PRIORITY" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="执行人">
+        <el-select v-model="form.executeor" placeholder="请选择" clearable multiple filterable>
+          <el-option v-for="item in PRIORITY" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="重复提醒">
+        <el-switch v-model="form.repeat" active-value="1" inactive-value="0" />
+      </el-form-item>
+      <template v-if="form.repeat === '1'">
+        <el-form-item label="重复类型" label-width="7em" prop="startDate">
+          <el-select v-model="form.repeatType" placeholder="请选择">
+            <el-option v-for="item in REPEAT_TYPE" :key="item.value" :value="item.value" :label="item.label" />
+          </el-select>
+        </el-form-item>
+        <template v-if="['0', '1', '2'].includes(form.repeatType)">
+          <div>
+            {{ REPEAT_TYPE[form.repeatType].label }}
+          </div>
+        </template>
+        <template v-if="['3'].includes(form.repeatType)">
+          <div>
+            {{ '自定义周期' }}
+          </div>
+        </template>
+        <template v-if="['4'].includes(form.repeatType)">
+          <div>
+            {{ '自定义日期' }}
+          </div>
+        </template>
+      </template>
+      <el-form-item label="开始时间" label-width="7em" prop="startDate" class="w50">
+        <el-date-picker v-model="form.startDate" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" />
+      </el-form-item>
+      <el-form-item label="截止时间" label-width="7em" prop="endDate" class="w50">
+        <el-date-picker v-model="form.endDate" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" />
+      </el-form-item>
+    </el-form>
+    <el-form-item label="详细描述" prop="taskName">
+      <el-input v-model="form.taskName" type="textarea" placeholder="请输入任务名称" clearable maxlength="1000" show-word-limit
+        :autosize="{ minRows: 4 }" />
+    </el-form-item>
+  </el-dialog>
+</template>
+
+<script lang="ts" setup>
+import { ref, watch } from 'vue';
+import { PRIORITY, TASK_TYPE, modalForm, REPEAT_TYPE } from "./api"
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    default: false
+  },
+  editForm: {
+    type: Object,
+  }
+})
+const emit = defineEmits(['closeModalVisible', 'submitForm'])
+const modalVisible = ref(false)
+const form = ref<any>({})
+const rules = ref({
+  taskName: [
+    { required: true, message: '请输入任务名称', trigger: 'blur' }
+  ],
+  priority: [
+    { required: true, message: '请选择优先级', trigger: 'blur' }
+  ]
+})
+function closeVisible() {
+  emit('closeModalVisible')
+}
+function submitForm(isClose: boolean) {
+  console.log("form", form.value, isClose);
+  // emit('submitForm', { form: form.value, isClose })
+}
+watch(props, (val) => {
+  modalVisible.value = val.visible
+  form.value = val.editForm ? { ...val.editForm } : modalForm
+})
+</script>
+
+<style lang="scss">
+.resetSelect {
+  border: 0;
+
+  .el-select__wrapper {
+    box-shadow: none;
+    padding-right: 0;
+  }
+
+  .el-select__selected-item {
+    text-align: right;
+  }
+}
+
+.el-form-item {
+  width: 100%;
+}
+
+.form {
+  .w50 {
+    @apply w-1/2;
+  }
+}
+</style>

+ 66 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/api.ts

@@ -1 +1,67 @@
+import { EpPropMergeType } from "element-plus/es/utils";
+
 export const MDO = "/tasks";
+type StatusType = {
+  label: "全部" | "未开始" | "进行中" | "已完成" | "已超时";
+  value: string;
+  type: EpPropMergeType<
+    StringConstructor,
+    "" | "info" | "primary" | "success" | "danger" | "warning",
+    unknown
+  >;
+};
+export const defaultSearchForm = {
+  //默认搜索条件
+  taskName: "",
+  customerName: "",
+  tel: "",
+  priority: "",
+  status: "",
+  startDate: "",
+  endDate: "",
+  page: 1,
+  pageSize: 10,
+};
+export const modalForm = {
+  taskName: "", //任务名称
+  priority: "", //优先级
+  taskType: "1", //  任务类型
+  customerId: "0", //  客户id 0
+  businessId: "1", //商机id 1
+  orderId: "2", //  订单id 2
+  clueid: "3", //线索id 3
+  contactsId: "", //联系人id
+  executorId: "", //执行人id
+  repeat: "0", //是否重复
+  repeatType: "0", //重复类型
+  startDate: "", //开始日期
+  endDate: "", //截止日期
+  taskDesc: "", //任务描述
+};
+export const PRIORITY = [
+  //优先级
+  { label: "高", value: "0" },
+  { label: "中", value: "1" },
+  { label: "低", value: "2" },
+];
+export const STATUS: StatusType[] = [
+  //任务状态
+  { label: "未开始", value: "0", type: "info" },
+  { label: "进行中", value: "1", type: "primary" },
+  { label: "已完成", value: "2", type: "success" },
+  { label: "已超时", value: "3", type: "danger" },
+];
+export const TASK_TYPE = [
+  // 弹窗任务类型
+  { label: "客户", value: "0", show: true },
+  { label: "商机", value: "1", show: true },
+  { label: "销售订单", value: "2", show: true },
+  { label: "线索", value: "3", show: false },
+];
+export const REPEAT_TYPE = [
+  { label: "每天", value: "0" },
+  { label: "每周", value: "1" },
+  { label: "每月", value: "2" },
+  { label: "自定义周期", value: "3" },
+  { label: "自定义日期", value: "4" },
+];

+ 205 - 43
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/index.vue

@@ -3,40 +3,46 @@
     <div class="p-5 w-80 pr-0">
       <div class="bg-white w-full h-full shadow-md rounded-md flex flex-col">
         <div class="flex-1 p-3 overflow-y-auto">
-          <el-form :model="ruleForm">
+          <el-form :model="searchForm">
             <el-form-item label="任务名称:" label-width="7em" prop="taskName">
-              <el-input v-model="ruleForm.taskName" placeholder="请输入" />
+              <el-input v-model="searchForm.taskName" placeholder="请输入" />
+            </el-form-item>
+            <el-form-item label="优先级:" label-width="7em" prop="priority">
+              <el-select v-model="searchForm.priority" placeholder="请选择">
+                <el-option v-for="item in PRIORITY" :key="item.value" :value="item.value" :label="item.label" />
+              </el-select>
             </el-form-item>
             <el-form-item label="客户名称:" label-width="7em" prop="customerName">
-              <el-input v-model="ruleForm.customerName" placeholder="请输入" />
+              <el-input v-model="searchForm.customerName" placeholder="请输入" />
             </el-form-item>
-            <el-form-item label="联系人电话:" label-width="7em" prop="tel">
-              <el-input v-model="ruleForm.tel" placeholder="请输入" />
+            <el-form-item label="联系人:" label-width="7em" prop="tel">
+              <el-input v-model="searchForm.tel" placeholder="请输入" />
             </el-form-item>
-            <el-form-item label="优先级" label-width="7em" prop="priority">
-              <el-select v-model="ruleForm.priority" placeholder="请选择">
-                <el-option label="全部" value="0" />
-                <el-option label="高" value="1" />
-                <el-option label="中" value="2" />
-                <el-option label="低" value="3" />
+            <el-form-item label="执行人:" label-width="7em" prop="tel">
+              <el-select v-model="searchForm.status" placeholder="请选择">
+                <el-option v-for="item in STATUS" :key="item.value" :value="item.value" :label="item.label" />
               </el-select>
             </el-form-item>
-            <el-form-item label="任务状态" label-width="7em" prop="status">
-              <el-select v-model="ruleForm.status" placeholder="请选择">
-                <el-option label="全部" value="0" />
-                <el-option label="未开始" value="1" />
-                <el-option label="进行中" value="2" />
-                <el-option label="已完成" value="3" />
-                <el-option label="超时" value="4" />
+            <el-form-item label="商机名称:" label-width="7em" prop="tel">
+              <el-input v-model="searchForm.tel" placeholder="请输入" />
+            </el-form-item>
+            <el-form-item label="销售订单:" label-width="7em" prop="tel">
+              <el-input v-model="searchForm.tel" placeholder="请输入" />
+            </el-form-item>
+            <el-form-item label="线索名称:" label-width="7em" prop="tel">
+              <el-input v-model="searchForm.tel" placeholder="请输入" />
+            </el-form-item>
+            <el-form-item label="任务状态:" label-width="7em" prop="status">
+              <el-select v-model="searchForm.status" placeholder="请选择">
+                <el-option v-for="item in STATUS" :key="item.value" :value="item.value" :label="item.label" />
               </el-select>
             </el-form-item>
-            <el-form-item label="开始日期" label-width="7em" prop="startDate">
-              <el-date-picker v-model="ruleForm.startDate" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" />
+            <el-form-item label="开始时间:" label-width="7em" prop="startDate">
+              <el-date-picker v-model="searchForm.startDate" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" />
             </el-form-item>
-            <el-form-item label="结束日期" label-width="7em" prop="endDate">
-              <el-date-picker v-model="ruleForm.endDate" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" />
+            <el-form-item label="截止时间:" label-width="7em" prop="endDate">
+              <el-date-picker v-model="searchForm.endDate" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" />
             </el-form-item>
-
           </el-form>
         </div>
         <div class="w-full flex p-3 shadow-[0_-3px_5px_0px_rgba(0,0,0,0.2)]">
@@ -45,37 +51,193 @@
         </div>
       </div>
     </div>
-    <div class="flex-1 p-5">
-      <div class="bg-white w-full h-full p-3 shadow-md rounded-md">222</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="ml-auto p-3">
+          <el-button type="primary" @click="createTasks()">创建任务</el-Button>
+          <el-button type="primary" @click="deleteTasks()">批量删除</el-Button>
+          <el-button type="primary" @click="importTasks()">导入</el-Button>
+          <el-button type="primary" @click="exportTasks()">导出</el-Button>
+        </div>
+        <div class="flex-1">
+          <el-table :data="tableData" style="width: 100%;height: 100%;">
+            <el-table-column prop="taskName" label="任务名称" header-align="center" align="center" show-overflow-tooltip
+              width="200" />
+            <el-table-column prop="priority" label="优先级" width="90" :sortable="true" header-align="center"
+              align="center">
+              <template #default="scope">
+                {{ PRIORITY[scope.row.priority]?.label }}
+              </template>
+            </el-table-column>
+            <el-table-column prop="status" label="状态" width="100" header-align="center" align="center">
+
+              <template #default="scope">
+                <el-text :type="STATUS[scope.row.status]?.type">
+                  {{ STATUS[scope.row.status]?.label }}
+                </el-text>
+              </template>
+            </el-table-column>
+            <el-table-column prop="customerName" label="执行人" width="120" header-align="center" align="center" />
+            <el-table-column prop="startDate" label="开始时间" width="120" :sortable="true" header-align="center"
+              align="center" />
+            <el-table-column prop="endDate" label="截止时间" width="120" :sortable="true" header-align="center"
+              align="center" />
+            <el-table-column prop="contactsName" label="联系人" header-align="center" align="center" width="120" />
+            <el-table-column prop="contactsTel" label="联系人号码" header-align="center" align="center" width="140" />
+            <el-table-column prop="customerName" label="客户名称" header-align="center" align="center" width="120" />
+            <el-table-column prop="businessName" label="商机名称" header-align="center" align="center" width="200" />
+            <el-table-column prop="businessName" label="销售订单" header-align="center" align="center" width="200" />
+            <el-table-column prop="businessName" label="线索名称" header-align="center" align="center" width="200" />
+            <el-table-column fixed="right" label="操作" header-align="center" align="center" width="150">
+
+              <template #default="scope">
+                <el-button link type="primary" size="small" @click.prevent="editRow(scope.row)">
+                  编辑
+                </el-button>
+                <el-button link type="primary" size="small" v-if="scope.row.status == '3'"
+                  @click.prevent="restart(scope.$index)">
+                  重启
+                </el-button>
+                <el-button link type="primary" size="small" v-else @click.prevent="finishRow(scope.$index, scope)">
+                  完成
+                </el-button>
+
+                <el-button link type="danger" size="small" @click.prevent="deleteRow(scope.$index)">
+                  删除
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+        <div class="ml-auto">
+          <el-pagination layout="total, prev, pager, next, sizes" :total="20" hide-on-single-page />
+        </div>
+      </div>
     </div>
+    <TaskModal :visible="taskModalVisible" :edit-form="taskForm" @close-modal-visible="closeModal()" />
   </div>
 </template>
 
 <script lang="ts" setup>
-import { onBeforeMount, onMounted, ref } from 'vue';
+import { onBeforeMount, ref } from 'vue';
 import { useStore } from '@/store';
-import { MDO } from './api';
+import { MDO, PRIORITY, STATUS, defaultSearchForm } from './api';
+import { dayjs } from 'element-plus';
+import TaskModal from './TaskModal.vue';
 const { getFunctionList } = useStore()
-const config = ref<any>([])
-const defaultForm = {
-  taskName: '',
-  customerName: '',
-  tel: '',
-  priority: '0',
-  status: '0',
-  startDate: '',
-  endDate: '',
+
+const pagePermission = ref<any[]>();
+const taskModalVisible = ref(false);
+const taskForm = ref<any>();
+function closeModal() {
+  taskModalVisible.value = false;
+  taskForm.value = null;
+}
+
+const searchForm = ref<any>();
+const tableData = ref<any[]>([
+  {
+    taskName: '任务1111111111111111111111111',
+    contactsTel: "15100111111",
+    contactsName: "水水水水",
+    customerName: '李四',
+    status: '0',
+    priority: '0',
+    startDate: dayjs().format('YYYY-MM-DD'),
+    endDate: dayjs().format('YYYY-MM-DD'),
+    taskType: '1'
+  },
+  {
+    taskName: '任务222',
+    customerName: '张三',
+    status: '1',
+    priority: '1',
+    startDate: dayjs().format('YYYY-MM-DD'),
+    endDate: dayjs().format('YYYY-MM-DD'),
+    taskType: '2'
+  },
+  {
+    taskName: '任务333',
+    customerName: '王五',
+    status: '2',
+    priority: '2',
+    startDate: dayjs().format('YYYY-MM-DD'),
+    endDate: dayjs().format('YYYY-MM-DD'),
+    taskType: '0'
+  },
+  {
+    taskName: '任务444',
+    customerName: '赵六',
+    status: '3',
+    priority: '1',
+    startDate: dayjs().format('YYYY-MM-DD'),
+    endDate: dayjs().format('YYYY-MM-DD'),
+    taskType: '3'
+  },
+  {
+    taskName: '任务555',
+    customerName: '马六',
+    status: '1',
+    priority: '2',
+    startDate: dayjs().format('YYYY-MM-DD'),
+    endDate: dayjs().format('YYYY-MM-DD'),
+  },
+  {
+    taskName: '任务666',
+    customerName: '吴七',
+    status: '3',
+    priority: '0',
+    startDate: dayjs().format('YYYY-MM-DD'),
+    endDate: dayjs().format('YYYY-MM-DD'),
+  },
+  {
+    taskName: '任务777',
+    customerName: '钱八',
+    status: '0',
+    priority: '1',
+    startDate: dayjs().format('YYYY-MM-DD'),
+    endDate: dayjs().format('YYYY-MM-DD'),
+  }
+])
+function search() {
+  console.log("searchForm", searchForm.value);
+}
+function reset() {
+  searchForm.value = defaultSearchForm;
+}
+function createTasks() {
+  taskModalVisible.value = true;
+  taskForm.value = null;
+}
+function deleteTasks() {
+  console.log("deleteTasks", searchForm.value);
+  console.log(dayjs().format('YYYY-MM-DD'));
+}
+
+function importTasks() {
+  console.log("importTasks", searchForm.value);
+}
+
+function exportTasks() {
+  console.log("exportTasks", searchForm.value);
+}
+
+function editRow(row: any) {
+  taskModalVisible.value = true;
+  taskForm.value = row;
+}
+function finishRow(index: any, scope: any) {
+  console.log("finishRow", index, scope);
 }
-const ruleForm = ref<any>()
-const reset = () => {
-  ruleForm.value = defaultForm;
+function restart(index: any) {
+  console.log("restart", index);
 }
-const search = () => {
-  console.log("ruleForm", ruleForm.value);
+function deleteRow(index: any) {
+  console.log("deleteRow", index);
 }
 onBeforeMount(() => {
-  config.value = getFunctionList(MDO);
-  ruleForm.value = defaultForm;
+  pagePermission.value = getFunctionList(MDO);
+  searchForm.value = defaultSearchForm;
 })
 </script>
 

+ 9 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/api.ts

@@ -0,0 +1,9 @@
+export const MOD = "/team"
+export const GET_DATA_LIST = '/user/getEmployeeList'
+export const GET_ROUTELIST = '/permission/getFrontRoleList'
+export const GET_DEPTLIST = '/department/list'
+export const GET_USERLIST = '/user/getSimpleActiveUserList'
+export const GET_ADDDEPT = '/department/add'
+export const DETELE_DEPT = '/department/delete'
+export const ADD_USER = '/user/insertUser'
+export const GET_USERINFO = '/user/getUserInfo'

+ 444 - 3
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/index.vue

@@ -1,11 +1,452 @@
 <template>
-  <div>
-    团队
+  <div class="h-full flex flex-col teamstyle">
+    <!-- 头部 -->
+    <div class="bg-white flex justify-between team-header">
+      <div class="flex items-center">
+        <el-link type="primary" class="text-nowrap mr-20" :icon="CirclePlusFilled"
+          @click="dialogFromCli('addDeptDialogVisible')">创建部门</el-link>
+        <el-link class="text-nowrap textFont textFont mr-10" type="primary" :icon="Edit"
+          @click="updateDepartment('addDeptDialogVisible')">{{ deptListItem.label || '全部人员' }}</el-link>
+        <span class="textSpan">共 0 人</span>
+      </div>
+      <div class="teamForm flex items-center">
+        <el-input v-model="teamForm.keyword" style="max-width: 650px" size="default" placeholder="请输入姓名搜索" class="mr-6">
+          <template #prepend>
+            <el-select v-model="teamForm.matchingType" style="width: 80px">
+              <el-option label="姓名" :value="0" />
+              <el-option label="电话" :value="1" />
+              <el-option label="工号" :value="2" />
+            </el-select>
+          </template>
+          <template #append>
+            <el-button :icon="Search" />
+          </template>
+        </el-input>
+
+        <div class="formItem mr-6 flex items-center">
+          <div class="text-nowrap">状态:</div>
+          <el-select v-model="teamForm.status" placeholder="请选择" size="default" style="width: 100px">
+            <el-option v-for="item in stateOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </div>
+        <div class="formItem mr-6 flex items-center">
+          <div class="text-nowrap">角色:</div>
+          <el-select v-model="teamForm.roleId" placeholder="请选择" size="default" style="width: 150px">
+            <el-option v-for="item in roleList" :key="item.id" :label="item.rolename" :value="item.id" />
+          </el-select>
+        </div>
+
+        <el-dropdown>
+          <el-button type="primary">
+            更多操作<el-icon class="el-icon--right"><arrow-down /></el-icon>
+          </el-button>
+          <template #dropdown>
+            <el-dropdown-menu>
+              <el-dropdown-item @click="addPersone(false)">添加人员</el-dropdown-item>
+              <el-dropdown-item>导出人员</el-dropdown-item>
+              <el-dropdown-item>批量导入</el-dropdown-item>
+              <el-dropdown-item>导入薪资</el-dropdown-item>
+              <el-dropdown-item>自定义配置</el-dropdown-item>
+            </el-dropdown-menu>
+          </template>
+        </el-dropdown>
+      </div>
+    </div>
+    <!-- 内容 -->
+    <div class="flex-1 flex">
+      <div class="p-5 w-80 pr-0">
+        <div class="bg-white w-full h-full shadow-md rounded-md flex flex-col">
+          <div class="flex-1 overflow-y-auto const-left">
+            <el-tree style="max-width: 600px" :data="deptList" :props="treeProps" @node-click="treeNode">
+              <template #default="{ node, data }">
+                <div class="flex justify-between treeContent">
+                  <div class="custom-tree-node">
+                    <div class="treeLabel">{{ node.label }}</div>
+                    <div class="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>
+                    </div>
+                  </div>
+                </div>
+              </template>
+            </el-tree>
+          </div>
+        </div>
+      </div>
+      <div class="flex-1 p-5 overflow-auto">
+        <div class="bg-white w-full h-full shadow-md rounded-md flex flex-col">
+          <div class="flex-1 p-3">
+            <el-table ref="multipleTableRef" :data="tableData" v-loading="loadingFrom.tableLoading"
+              style="width: 100%;height: 100%;">
+              <el-table-column type="selection" width="55" />
+              <el-table-column label="姓名" property="name" width="150"></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="roleName"></el-table-column>
+              <el-table-column label="创建时间" property="createTime"></el-table-column>
+              <el-table-column label="操作" width="150" fixed="right">
+                <template #default="scope">
+                  <el-button :size="'small'">重置</el-button>
+                  <el-button type="primary" :size="'small'" @click="addPersone(scope.row)">编辑</el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+          <div class="flex items-center justify-between p-3 bg-slate-100">
+            <div class="flex">
+              <el-button size="default">取消</el-button>
+              <el-dropdown class="ml-3">
+                <el-button type="primary">
+                  更多操作<el-icon class="el-icon--right"><arrow-down /></el-icon>
+                </el-button>
+                <template #dropdown>
+                  <el-dropdown-menu>
+                    <el-dropdown-item>批量修改部门</el-dropdown-item>
+                    <el-dropdown-item>批量修改角色</el-dropdown-item>
+                    <el-dropdown-item>修正工时所属部门</el-dropdown-item>
+                    <el-dropdown-item>批量启用员工</el-dropdown-item>
+                  </el-dropdown-menu>
+                </template>
+              </el-dropdown>
+            </div>
+            <div class="pr-4">
+              <el-pagination layout="total, prev, pager, next, sizes" :total="totalTable" :hide-on-single-page="true" />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 新增部门 -->
+    <el-dialog v-model="dialogFrom.addDeptDialogVisible" :title="deptListItem.label || '创建部门'" width="500"
+      :before-close="handleClose">
+      <div>
+        <el-form ref="deptRuleFormRef" style="max-width: 500px" :model="deptForm" :rules="deptRules" label-width="auto"
+          size="large" status-icon>
+          <el-form-item label="部门名称" prop="name">
+            <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-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="其他负责人">
+            <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-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialogFrom.addDeptDialogVisible = false">取消</el-button>
+          <el-button type="primary" @click="createDepartment(deptRuleFormRef)"
+            v-bind:loading="loadingFrom.deptDialogVisibleLoading">
+            确定
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 新增人员 -->
+    <AddPersonnelModal :data="{
+      addPersonnelDialogVisible: dialogFrom.addPersonnelDialogVisible,
+      deptList: deptListUntreated,
+      roleList: roleList,
+      personnelFromData: personnelFromData
+    }" @closeModal="closeModal" @personnelModalConfirm="personnelModalConfirm" />
   </div>
 </template>
 
 <script lang="ts" setup>
+import { ref, reactive, onMounted, onBeforeMount, inject } from 'vue';
+import { dayjs } from 'element-plus'
+import { Search, CirclePlusFilled, Edit, CirclePlus, Delete } from '@element-plus/icons-vue'
+import { FormInstance, FormRules, ElMessageBox } from 'element-plus'
+import { useStore } from '@/store/index'
+import { GET_DATA_LIST, DETELE_DEPT, MOD, GET_USERINFO, GET_ROUTELIST, GET_DEPTLIST, GET_USERLIST, GET_ADDDEPT, ADD_USER } from './api'
+import { post } from "@/utils/request";
+import { getFromValue, updateDepTreeData, resetFromValue } from '@/utils/tools'
+
+// 导入页面
+import AddPersonnelModal from './module/AddPersonnelModal.vue'
+
+const { getFunctionList, getUserInfoVal } = useStore()
+const globalPopup = inject<GlobalPopup>('globalPopup')
+
+// 定义类型
+interface deptRuleForm { // 部门表单类型
+  name: string,
+  id: string | number,
+  parentId: string | number,
+  managerId: string | number,
+  otherManagerIds: string[] | number[],
+}
+
+// 固定数据
+const stateOptions = [{ value: '3', label: '全部' }, { value: '1', label: '在职' }, { value: '0', label: '停用' }]
+
+// 定义变量
+const pagePermission: any = ref([]) // 功能权限
+const loadingFrom = reactive({ // 所有加载状态
+  tableLoading: false,
+  deptDialogVisibleLoading: false
+})
+const dialogFrom: any = reactive({ // 所有弹窗状态
+  addDeptDialogVisible: false,
+  addPersonnelDialogVisible: false
+});
+const totalTable = ref(0) // 表格总数
+const tableData: any = ref([]) // 表格数据
+const roleList: any = ref([]) // 角色列表
+const userList: any = ref([]) // 用户列表
+const deptList: any = ref([]) // 部门数据
+const deptListUntreated: any = ref([]) // 部门数据(未处理)
+const deptListItem: any = ref({}) // 选中的部门数据
+const personnelFromData = ref({}) // 人员表单数据
+const teamForm = reactive({ // 筛选条件表单
+  matchingType: 0,
+  keyword: '',
+  status: '3',
+  pageIndex: 1,
+  pageSize: 20,
+  roleId: '',
+  onlyDirect: '',
+  departmentId: '-1',
+});
+const deptRuleFormRef = ref<FormInstance>() // 表单实例
+const deptForm = reactive<deptRuleForm>({ // 部门表单
+  name: '',
+  id: '',
+  parentId: '',
+  managerId: '',
+  otherManagerIds: [],
+})
+const treeProps = { // 部门树配置
+  children: 'children',
+  label: 'label',
+}
+
+// 定义校验规则
+const deptRules = reactive<FormRules<typeof deptForm>>({ // 部门表单校验规则
+  name: [{ required: true, trigger: 'blur', message: '请输入部门名称' }]
+})
+
+// 定义方法
+function addPersone(item: any) {
+  console.log(item)
+  if(!item) {
+    dialogFrom.addPersonnelDialogVisible = true
+    return
+  } 
+  post(GET_USERINFO, { userId: item.id }).then(res => {
+    const { id, name, phone, jobNumber, roleId, departmentCascade, inductionDate } = res.data
+    let newData = { id, name, phone, jobNumber, roleId, departmentId: 
+      departmentCascade && departmentCascade.split(',').map(Number).reverse(), 
+      inductionDate 
+    }
+    personnelFromData.value = newData
+    dialogFrom.addPersonnelDialogVisible = true
+  })
+}
+
+async function personnelModalConfirm(data: any, modelType: string) {
+  post(ADD_USER, { ...data }).then(res => {
+    if (res.code != 'ok') {
+      dialogFrom[modelType] = false
+      globalPopup?.showError(res.msg)
+      return
+    }
+    dialogFrom[modelType] = false
+    globalPopup?.showSuccess('添加成功')
+    getTableData()
+  }).catch(_err => {
+    dialogFrom[modelType] = false
+  })
+}
+
+function createDepartment(formEl: FormInstance | undefined) {
+  if (!formEl) return
+  let data = getFromValue(deptForm)
+  loadingFrom.deptDialogVisibleLoading = true
+  post(GET_ADDDEPT, { ...deptForm, otherManagerIds: data.otherManagerIds && data.otherManagerIds.join(',') }).then(res => {
+    if (res.code != 'ok') {
+      loadingFrom.deptDialogVisibleLoading = false
+      globalPopup?.showError(res.msg)
+      return
+    }
+    loadingFrom.deptDialogVisibleLoading = false
+    globalPopup?.showSuccess('创建成功')
+    getDeptList()
+    dialogFrom.addDeptDialogVisible = false
+  }).catch(_err => {
+    loadingFrom.deptDialogVisibleLoading = false
+  })
+}
+
+function updateDepartment(type: string) {
+  if (!deptListItem.value.id || deptListItem.value.id <= 0) return
+  const { id, label, parentId, managerId, otherManagerIds } = deptListItem.value
+  console.log(deptListItem.value)
+  let data = { id, name: label, parentId, managerId, otherManagerIds }
+  Object.assign(deptForm, data)
+  dialogFrom[type] = true
+}
+
+function treeNode(item: any) {
+  deptListItem.value = item
+  teamForm.departmentId = item.id
+  getTableData()
+}
+
+function deteleDept(data: any) {
+  console.log(data)
+  ElMessageBox.confirm(
+    `确定删除【${data.label}】部门吗?`, '',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  )
+    .then(() => {
+      post(DETELE_DEPT, { id: data.id }).then(res => {
+        if (res.code != 'ok') {
+          globalPopup?.showError(res.msg)
+          return
+        }
+        globalPopup?.showSuccess('删除成功')
+        getDeptList()
+      })
+    })
+}
 
+function getTableData() {
+  loadingFrom.tableLoading = true
+  post(GET_DATA_LIST, { ...teamForm }).then(res => {
+    if (res.code != 'ok') {
+      loadingFrom.tableLoading = false
+      globalPopup?.showError(res.msg)
+      return
+    }
+    loadingFrom.tableLoading = false
+    totalTable.value = res.data.total
+    tableData.value = res.data.records
+  }).catch(_err => {
+    loadingFrom.tableLoading = false
+  })
+}
+
+function getRoleList() {
+  const companyId = getUserInfoVal('companyId') || ''
+  post(GET_ROUTELIST, { companyId }).then(res => {
+    if (res.code != 'ok') {
+      globalPopup?.showError(res.msg)
+      return
+    }
+    roleList.value = res.data
+  })
+}
+
+function getDeptList() {
+  post(GET_DEPTLIST, {}).then(res => {
+    if (res.code != 'ok') {
+      globalPopup?.showError(res.msg)
+      return
+    }
+    deptListUntreated.value = updateDepTreeData(res.data, false)
+    deptList.value = updateDepTreeData(res.data, true)
+  })
+}
+
+function getUserList() {
+  post(GET_USERLIST, {}).then(res => {
+    if (res.code != 'ok') {
+      globalPopup?.showError(res.msg)
+      return
+    }
+    userList.value = res.data
+  })
+}
+
+function dialogFromCli(type: string, data: any = {}, flag: boolean = false) {
+  resetDialog()
+  if (flag) {
+    const { id } = data
+    deptForm.parentId = id
+  }
+  dialogFrom[type] = true
+}
+
+function resetDialog() {
+  let newDeptForm = resetFromValue(deptForm)
+  Object.assign(deptForm, newDeptForm)
+}
+
+function handleClose(done: any) {
+  done()
+}
+
+function closeModal(modelType: string) {
+  dialogFrom[modelType] = false
+}
+
+onBeforeMount(() => {
+  pagePermission.value = getFunctionList(MOD)
+})
+
+onMounted(() => {
+  getRoleList()
+  getUserList()
+  getTableData()
+  getDeptList()
+});
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.teamstyle {
+  .team-header {
+    padding: 0.75rem 1.25rem;
+  }
+
+  .textFont {
+    font-size: 20px;
+  }
+
+  .textSpan {
+    color: $fontGray;
+  }
+}
+
+.const-left {
+  padding: 0.75rem 0;
+
+  .treeContent {
+    width: 87%;
+
+    .custom-tree-node {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      width: 100%;
+    }
+
+    .treeLabel {
+      width: 80%;
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+    }
+
+    .treeIcon {
+      display: flex;
+      align-items: center;
+      justify-self: flex-end;
+    }
+  }
+}
+</style>

+ 107 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/module/AddPersonnelModal.vue

@@ -0,0 +1,107 @@
+<template>
+    <el-dialog v-model="data.addPersonnelDialogVisible" :title="'添加人员'" width="500" :before-close="handleClose">
+        <div>
+            <el-form ref="personnelRuleFormRef" style="max-width: 500px" :model="personnelFrom" :rules="personnelRules"
+                label-width="auto" size="large" status-icon>
+                <el-form-item label="姓名" prop="name">
+                    <el-input v-model="personnelFrom.name" placeholder="请输入姓名" clearable />
+                </el-form-item>
+                <el-form-item label="电话">
+                    <el-input v-model="personnelFrom.phone" placeholder="请输入电话" clearable />
+                </el-form-item>
+                <el-form-item label="工号">
+                    <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-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-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-form-item>
+            </el-form>
+        </div>
+        <template #footer>
+            <div class="dialog-footer">
+                <el-button @click="handleClose">取消</el-button>
+                <el-button type="primary" @click="addPersonel(personnelRuleFormRef)">
+                    确定
+                </el-button>
+            </div>
+        </template>
+    </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'
+
+const emit = defineEmits(['closeModal', 'personnelModalConfirm']);
+// 定义类型
+interface Props {
+    data: {
+        addPersonnelDialogVisible: boolean,
+        deptList: any,
+        roleList: any,
+        personnelFromData: any
+    };
+}
+
+interface personnelFromType { // 类型定义
+    id: string | number,
+    name: string,
+    phone: string | number,
+    jobNumber: string,
+    roleId: string | number,
+    departmentId: string[] | number[],
+    inductionDate: string,
+}
+const data = ref<Props['data']>({
+    addPersonnelDialogVisible: false,
+    deptList: [],
+    roleList: [],
+    personnelFromData: {}
+})
+const personnelRuleFormRef = ref<FormInstance>() // 表单实例
+const personnelFrom = reactive<personnelFromType>({ // 填写的内容
+    id: '',
+    name: '',
+    phone: '',
+    jobNumber: '',
+    roleId: '',
+    departmentId: [],
+    inductionDate: '',
+});
+
+// 接收参数
+const props = defineProps<Props>();
+
+// 定义校验规则
+const personnelRules = reactive<FormRules<typeof personnelFrom>>({ // 部门表单校验规则
+    name: [{ required: true, trigger: 'blur', message: '请输入姓名' }]
+})
+
+// 定义方法
+function addPersonel(formEl: FormInstance | undefined) {
+    if (!formEl) return
+    let dataForm = getFromValue(personnelFrom)
+    const { departmentId } = dataForm
+    emit('personnelModalConfirm', { ...dataForm, departmentId: departmentId && departmentId[departmentId.length - 1]  }, 'addPersonnelDialogVisible')
+}
+
+// 监听 Props 的变化
+watch(() => props.data, (newValue) => {
+    data.value = newValue
+    Object.assign(personnelFrom, newValue.personnelFromData)
+});
+
+const handleClose = () => {
+    emit('closeModal', 'addPersonnelDialogVisible')
+}
+
+</script>
+<style scoped lang="scss"></style>

+ 12 - 9
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/thread/index.vue

@@ -1,21 +1,24 @@
 <template>
-  <div class="bg-gray-200 h-full flex">
+  <div class="h-full flex">
     <div class="p-5 w-80 pr-0">
-      <div class="bg-white w-full h-full p-3 shadow-md rounded-md">
-        线索管理
+      <div class="bg-white w-full h-full shadow-md rounded-md flex flex-col">
+        <div class="flex-1 p-3 overflow-y-auto">
+
+        </div>
+        <div class="w-full flex p-3 shadow-[0_-3px_5px_0px_rgba(0,0,0,0.2)]">
+          <El-button class="w-full">重置</El-Button>
+          <El-button type="primary" class="w-full">搜索</El-Button>
+        </div>
       </div>
     </div>
-    <div class="flex-1 bg-gray-200 p-5">
+    <div class="flex-1 p-5">
       <div class="bg-white w-full h-full p-3 shadow-md rounded-md">222</div>
     </div>
   </div>
 </template>
 
-
-<script setup lang="ts">
+<script lang="ts" setup>
 
 </script>
 
-
-<style scoped></style>
-
+<style lang="scss" scoped></style>

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

@@ -13,5 +13,6 @@ type SotreActions = {
   setValue(val: any, key: keyof SotreState): void;
   getRouterConfig(path: string): RouteRecordRaw | any;
   getFunctionList(path: string): any[];
+  getUserInfoVal(val: string): any;
   clearStore(): void;
 };

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

@@ -13,12 +13,11 @@ export const useStore = defineStore<
   }),
   getters: {
     getRoutersList() {
-      // 取值
       return this.routers;
     },
     getToken() {
       return this.userInfo?.id || "";
-    },
+    }
   },
   actions: {
     // 方法
@@ -41,6 +40,9 @@ export const useStore = defineStore<
       }
       return config.functionList || [];
     },
+    getUserInfoVal(val) {
+      return this.userInfo[val];
+    },
     clearStore() {
       localStorage.clear();
       sessionStorage.clear();

+ 58 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/utils/tools.ts

@@ -1,3 +1,8 @@
+/**
+ * 判断值是否为空
+ * @param value 值
+ * @returns {boolean}
+ */
 export function isValueEmpty(value: any): boolean {
   if (value === null || value === undefined) {
     return true;
@@ -20,3 +25,56 @@ export function isValueEmpty(value: any): boolean {
   }
   return false;
 }
+
+/**
+ * 获取表单数据中有值的数据
+ * @param formData 表单数据
+ * @returns {T}
+ */
+export function getFromValue<T>(formData: T): T {
+  const result: any = {};
+  for (const key in formData) {
+    if (!isValueEmpty(formData[key])) {
+      result[key] = formData[key];
+    }
+  }
+  return result;
+}
+export function resetFromValue<T>(formData: T) {
+  const result: any = {};
+  for (const key in formData) {
+    result[key] = '';
+  }
+  return result;
+}
+
+/**
+ * 更新部门数据
+ * @param arr 部门数据源
+ * @param flag 是否需要添加全部人员和未分配
+ * @returns 
+ */
+export function updateDepTreeData(arr: any, flag: boolean = false) {
+  const result = []; // 创建一个新数组来存储结果
+  for (let i = 0; i < arr.length; i++) {
+    if (arr[i].id !== -1 && arr[i].id !== 0) {
+      if (Array.isArray(arr[i].children) && arr[i].children.length > 0) {
+        arr[i].children = updateDepTreeData(arr[i].children); // 递归更新子节点
+      }
+      arr[i].value = arr[i].id; // 更新value字段
+      result.push(arr[i]); // 将更新后的节点添加到结果数组
+    }
+  }
+  if(flag) {
+    result.splice(0, 0, {
+      id: -1,
+      label: '全部人员',
+    });
+    result.push({
+      id: 0,
+      label: '未分配',
+    });
+    return result;
+  }
+  return result; // 返回更新后的数组,不包含id为-1或0的节点
+}

Fichier diff supprimé car celui-ci est trop grand
+ 16156 - 27181
fhKeeper/formulahousekeeper/management-crm/crm.log


+ 1 - 1
fhKeeper/formulahousekeeper/management-crm/pom.xml

@@ -10,7 +10,7 @@
     <modelVersion>4.0.0</modelVersion>
 
     <groupId>com.hssx.parent</groupId>
-    <artifactId>timesheet</artifactId>
+    <artifactId>timesheet-crm</artifactId>
     <version>3.4.0</version>
 
     <dependencies>

+ 49 - 13
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/BusinessOpportunityController.java

@@ -6,7 +6,6 @@ import com.management.platform.entity.User;
 import com.management.platform.mapper.UserMapper;
 import com.management.platform.service.BusinessOpportunityService;
 import com.management.platform.service.SysFunctionService;
-import com.management.platform.service.UserService;
 import com.management.platform.util.HttpRespMsg;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -15,7 +14,9 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -40,37 +41,72 @@ public class BusinessOpportunityController {
 
 
     @RequestMapping("insertAndUpdate")
-    public HttpRespMsg insertAndUpdate(@RequestBody BusinessOpportunity bo) {
+    public HttpRespMsg insertAndUpdate(@RequestBody BusinessOpportunity bo, HttpServletRequest request) {
+        User user = userMapper.selectById(request.getHeader("Token"));
         HttpRespMsg msg = new HttpRespMsg();
+        if (bo.getId() == null){
+            //新增
+            bo.setCompanyId(user.getCompanyId());
+            bo.setCreatorId(user.getId());
+            bOservice.insert(bo);
+        }else {
+            //修改
+            bOservice.update(bo);
+        }
         msg.setMsg("操作成功");
         return msg;
-
     }
 
     @RequestMapping("list")
-    public HttpRespMsg list(@RequestBody BusinessOpportunity bo, HttpServletRequest request) {
-        HttpRespMsg msg = new HttpRespMsg();
+    public HashMap<Object, Object> list(@RequestBody BusinessOpportunity bo, HttpServletRequest request) {
+        HashMap<Object, Object> r = new HashMap<>();
         User user = userMapper.selectById(request.getHeader("Token"));
+        bo.setIsDelete(0);
         bo.setCompanyId(user.getCompanyId());
         List<BusinessOpportunity> list = new ArrayList<>();
         boolean isAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看全部商机");
-        boolean isNotAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看全部商机");
+        boolean isNotAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看负责部门商机");
+        int i = 0;
         if (!isAll) {
             list = bOservice.getAll(bo);
+            i = bOservice.getTotal(bo);
         } else if (!isNotAll) {
+            list = bOservice.getAll1(bo, user);
+            i = bOservice.getTotal1(bo, user);
+        } else {
+            list = bOservice.getAll2(bo, user);
+        }
+        r.put("data", list);
+        r.put("total",i);
+        return r;
+
+    }
+    @RequestMapping("deleterList")
+    public HashMap<Object, Object> deleterList(@RequestBody BusinessOpportunity bo, HttpServletRequest request) {
+        HashMap<Object, Object> r = new HashMap<>();
+        User user = userMapper.selectById(request.getHeader("Token"));
+        bo.setIsDelete(1);
+        bo.setCompanyId(user.getCompanyId());
+        List<BusinessOpportunity> list = new ArrayList<>();
+        boolean isAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看全部商机");
+        boolean isNotAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看负责部门商机");
+        int i = 0;
+        if (!isAll) {
             list = bOservice.getAll(bo);
+            i = bOservice.getTotal(bo);
+        } else if (!isNotAll) {
+            list = bOservice.getAll1(bo, user);
+            i = bOservice.getTotal1(bo, user);
+        } else {
+            list = bOservice.getAll2(bo, user);
         }
-        return msg;
+        r.put("data", list);
+        r.put("total",i);
+        return r;
 
     }
 
-    @RequestMapping("getAllProduct")
-    public HttpRespMsg getAllProduct(@RequestBody BusinessOpportunity bo) {
-        HttpRespMsg msg = new HttpRespMsg();
-        msg.setMsg("操作成功");
-        return msg;
 
-    }
 
 
 }

+ 31 - 14
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ClueController.java

@@ -47,7 +47,6 @@ public class ClueController {
     private SysDictMapper sysDictMapper;
 
 
-
     @RequestMapping("getDetail")
     public Object getDetail(@RequestBody Clue clue) {
         HttpRespMsg msg = new HttpRespMsg();
@@ -60,34 +59,56 @@ public class ClueController {
         //TODO token待定
         User user = userMapper.selectById(request.getHeader("Token"));
         clue.setCompanyId(user.getCompanyId());
+        clue.setIsDelete(0);
         boolean isAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看全部线索");
         boolean isNotAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看负责部门线索");
         List<Clue> list = new ArrayList<>();
+        int i = 0;
         if (!isAll) {
             //查看全部线索
             list = clueService.getList(clue);
+            i = clueService.getTotal(clue);
         } else if (!isNotAll) {
             //查看负责部门线索 找出所处部门下所有的负责人
             list = clueService.getList1(clue, user);
+            i = clueService.getTotal1(clue,user);
         } else {
             // 查看负责人为 自己 和 null的数据
             list = clueService.getList2(clue, user);
+            i = clueService.getTotal2(clue,user);
         }
         HashMap<Object, Object> map = new HashMap<>();
         map.put("data", list);
-        map.put("total", clueService.getTotal(clue));
+        map.put("total", i);
         return map;
     }
 
     @RequestMapping("listDeleterClue")
     public Object listDeleterClue(@RequestBody Clue clue, HttpServletRequest request) {
         //TODO token待定
-         User user = userMapper.selectById(request.getHeader(  "Token"));
-         clue.setCompanyId(user.getCompanyId());
-        List<Clue> list = clueService.getDeleterList(clue);
+        User user = userMapper.selectById(request.getHeader("Token"));
+        clue.setCompanyId(user.getCompanyId());
+        boolean isAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看全部线索");
+        boolean isNotAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看负责部门线索");
+        List<Clue> list = new ArrayList<>();
+        clue.setIsDelete(1);
+        int i = 0;
+        if (!isAll) {
+            //查看全部线索
+            list = clueService.getList(clue);
+            i = clueService.getTotal(clue);
+        } else if (!isNotAll) {
+            //查看负责部门线索 找出所处部门下所有的负责人
+            list = clueService.getList1(clue, user);
+            i = clueService.getTotal1(clue,user);
+        } else {
+            // 查看负责人为 自己 和 null的数据
+            list = clueService.getList2(clue, user);
+            i = clueService.getTotal2(clue,user);
+        }
         HashMap<Object, Object> map = new HashMap<>();
         map.put("data", list);
-        map.put("total", clueService.getDeleterTotal(clue));
+        map.put("total",i);
         return map;
     }
 
@@ -96,8 +117,8 @@ public class ClueController {
         HttpRespMsg msg = new HttpRespMsg();
         //操作前校验
         //TODO token待定
-        // User user = userMapper.selectById(request.getHeader(  "Token"));
-        // Integer companyId = user.getCompanyId();
+        User user = userMapper.selectById(request.getHeader("Token"));
+        clue.setCompanyId(user.getCompanyId());
         if (null == clue.getClueName() || "".equals(clue.getClueName())) {
             msg.setError("线索名称不能为空");
             return msg;
@@ -113,12 +134,8 @@ public class ClueController {
             msg.setMsg("操作成功");
         } else {
             //新增
-            //TODO token待定
-            // clue.setCompanyId(companyId);
-            // clue.setCreateId(user.getId());
-
+            clue.setCreateId(user.getId());
             clueService.insert(clue);
-
             msg.setMsg("操作成功");
         }
         return msg;
@@ -146,7 +163,7 @@ public class ClueController {
         User user = userMapper.selectById(request.getHeader("Token"));
         HttpRespMsg msg = new HttpRespMsg();
         msg.setMsg("操作成功");
-        clueService.getAndTransfer(clue,user);
+        clueService.getAndTransfer(clue, user);
         return msg;
     }
 

+ 17 - 10
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ProductController.java

@@ -2,12 +2,16 @@ package com.management.platform.controller;
 
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.management.platform.entity.Product;
-import com.management.platform.entity.Task;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.*;
 import com.management.platform.mapper.UserMapper;
 import com.management.platform.service.ProductService;
 import com.management.platform.service.TaskService;
 import com.management.platform.util.HttpRespMsg;
+import com.management.platform.util.MessageUtils;
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddressList;
 import org.springframework.web.bind.annotation.RequestMapping;
 
 import org.springframework.web.bind.annotation.RestController;
@@ -15,6 +19,11 @@ import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -80,16 +89,14 @@ public class ProductController {
         return msg;
     }
 
-    @RequestMapping("/getTemplate")
-    public HttpRespMsg getTemplate(Integer id){
-        HttpRespMsg msg=new HttpRespMsg();
-        return msg;
+    @RequestMapping("/importData")
+    public HttpRespMsg importData(MultipartFile multipartFile){
+        return productService.importData(multipartFile);
     }
 
-    @RequestMapping("/importData")
-    public HttpRespMsg importData(MultipartFile file){
-        HttpRespMsg msg=new HttpRespMsg();
-        return msg;
+    @RequestMapping("/exportData")
+    public HttpRespMsg exportData(String userId,String productName,String productCode) throws Exception {
+        return productService.exportData(userId,productName,productCode);
     }
 
 }

+ 5 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/SysFormController.java

@@ -82,5 +82,10 @@ public class SysFormController {
         }
         return msg;
     }
+
+    @RequestMapping("/getExportTemplate")
+    public HttpRespMsg getExportTemplate(String code){
+        return sysFormService.getExportTemplate(code);
+    }
 }
 

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

@@ -32,9 +32,13 @@ public class BusinessOpportunity extends Model<BusinessOpportunity> {
 
     @TableField("company_id")
     private Integer companyId;
+
     private Integer productId;
+
     private String inchargerId;
 
+    private String productName;
+
     /**
      * 商机名称
      */

+ 17 - 3
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/Product.java

@@ -7,9 +7,12 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import java.time.LocalDateTime;
 import com.baomidou.mybatisplus.annotation.TableField;
 import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
 
 /**
  * <p>
@@ -17,7 +20,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2024-02-28
+ * @since 2024-03-08
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -78,6 +81,8 @@ public class Product extends Model<Product> {
      * 创建时间
      */
     @TableField("create_time")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
     private LocalDateTime createTime;
 
     /**
@@ -119,8 +124,17 @@ public class Product extends Model<Product> {
     /**
      * 描述
      */
-    @TableField("desc")
-    private String desc;
+    @TableField("descs")
+    private String descs;
+
+    @TableField(exist = false)
+    private String inchargerName;
+
+    @TableField(exist = false)
+    private String typeName;
+
+    @TableField(exist = false)
+    private String unitName;
 
 
     @Override

+ 9 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/mapper/BusinessOpportunityMapper.java

@@ -2,6 +2,7 @@ package com.management.platform.mapper;
 
 import com.management.platform.entity.BusinessOpportunity;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -16,4 +17,12 @@ import java.util.List;
 public interface BusinessOpportunityMapper extends BaseMapper<BusinessOpportunity> {
 
     List<BusinessOpportunity> selectAllList(BusinessOpportunity bo);
+
+    List<BusinessOpportunity> selectAllList1(@Param("bo") BusinessOpportunity bo,@Param("userId") String userId);
+
+    List<BusinessOpportunity> selectAllList2(@Param("bo") BusinessOpportunity bo,@Param("userId") String userId);
+
+    int getTotal(BusinessOpportunity bo);
+    int getTotal1(@Param("bo") BusinessOpportunity bo,@Param("userId") String userId);
+    int getTotal2(@Param("bo") BusinessOpportunity bo,@Param("userId") String userId);
 }

+ 4 - 1
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/mapper/ClueMapper.java

@@ -23,5 +23,8 @@ public interface ClueMapper extends BaseMapper<Clue> {
     Integer getTotal(Clue clue);
     Integer getDeleterTotal(Clue clue);
 
-    List<Clue> list2(Clue clue, String id);
+    List<Clue> list2(@Param("clue") Clue clue ,@Param("userId") String userId);
+
+    int getTotal1(@Param("clue") Clue clue ,@Param("userId") String userId);
+    int getTotal2(@Param("clue") Clue clue ,@Param("userId") String userId);
 }

+ 13 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/BusinessOpportunityService.java

@@ -2,6 +2,7 @@ package com.management.platform.service;
 
 import com.management.platform.entity.BusinessOpportunity;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.management.platform.entity.User;
 
 import java.util.List;
 
@@ -16,4 +17,16 @@ import java.util.List;
 public interface BusinessOpportunityService extends IService<BusinessOpportunity> {
 
     List<BusinessOpportunity> getAll(BusinessOpportunity bo);
+    List<BusinessOpportunity> getAll1(BusinessOpportunity bo, User user);
+
+    List<BusinessOpportunity> getAll2(BusinessOpportunity bo, User user);
+
+    int getTotal(BusinessOpportunity bo);
+
+    int getTotal1(BusinessOpportunity bo, User user);
+    int getTotal2(BusinessOpportunity bo, User user);
+
+    void insert(BusinessOpportunity bo);
+
+    void update(BusinessOpportunity bo);
 }

+ 3 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/ClueService.java

@@ -37,4 +37,7 @@ public interface ClueService extends IService<Clue> {
     void deleterDelete(List<Integer> ids);
 
     void getAndTransfer(Clue clue,User user);
+
+    int getTotal1(Clue clue, User user);
+    int getTotal2(Clue clue, User user);
 }

+ 7 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/ProductService.java

@@ -3,6 +3,9 @@ package com.management.platform.service;
 import com.management.platform.entity.Product;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.management.platform.util.HttpRespMsg;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.lang.reflect.InvocationTargetException;
 
 /**
  * <p>
@@ -15,4 +18,8 @@ import com.management.platform.util.HttpRespMsg;
 public interface ProductService extends IService<Product> {
 
     HttpRespMsg getList(Integer companyId,String userId, String productName, String productCode, Integer pageIndex, Integer pageSize);
+
+    HttpRespMsg importData(MultipartFile multipartFile);
+
+    HttpRespMsg exportData(String userId, String productName, String productCode) throws Exception;
 }

+ 2 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/SysFormService.java

@@ -2,6 +2,7 @@ package com.management.platform.service;
 
 import com.management.platform.entity.SysForm;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.management.platform.util.HttpRespMsg;
 
 /**
  * <p>
@@ -13,4 +14,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface SysFormService extends IService<SysForm> {
 
+    HttpRespMsg getExportTemplate(String code);
 }

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

@@ -1,12 +1,15 @@
 package com.management.platform.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.management.platform.entity.BusinessOpportunity;
+import com.management.platform.entity.User;
 import com.management.platform.mapper.BusinessOpportunityMapper;
 import com.management.platform.service.BusinessOpportunityService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -26,4 +29,42 @@ public class BusinessOpportunityServiceImpl extends ServiceImpl<BusinessOpportun
     public List<BusinessOpportunity> getAll(BusinessOpportunity bo) {
         return bOMapper.selectAllList(bo);
     }
+
+    @Override
+    public List<BusinessOpportunity> getAll1(BusinessOpportunity bo, User user) {
+        return bOMapper.selectAllList1(bo,user.getId());
+    }
+
+    @Override
+    public List<BusinessOpportunity> getAll2(BusinessOpportunity bo, User user) {
+        return bOMapper.selectAllList2(bo,user.getId());
+    }
+
+    @Override
+    public int getTotal(BusinessOpportunity bo) {
+        return bOMapper.getTotal(bo);
+    }
+
+    @Override
+    public int getTotal1(BusinessOpportunity bo, User user) {
+        return bOMapper.getTotal1(bo,user.getId());
+    }
+
+    @Override
+    public int getTotal2(BusinessOpportunity bo, User user) {
+        return bOMapper.getTotal2(bo,user.getId());
+    }
+
+    @Override
+    public void insert(BusinessOpportunity bo) {
+        bo.setCreateTime(new Date());
+        bOMapper.insert(bo);
+    }
+
+    @Override
+    public void update(BusinessOpportunity bo) {
+        UpdateWrapper<Object> update = new UpdateWrapper<>();
+
+//        bOMapper.update(bo);
+    }
 }

+ 11 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ClueServiceImpl.java

@@ -177,5 +177,16 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
 
     }
 
+    @Override
+    public int getTotal1(Clue clue, User user) {
+        return clueMapper.getTotal1(clue,user.getId());
+    }
+
+    @Override
+    public int getTotal2(Clue clue, User user) {
+        return clueMapper.getTotal2(clue,user.getId());
+
+    }
+
 
 }

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

@@ -1,19 +1,43 @@
 package com.management.platform.service.impl;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.management.platform.entity.Product;
+import com.management.platform.entity.*;
 import com.management.platform.mapper.ProductMapper;
+import com.management.platform.mapper.SysDictMapper;
+import com.management.platform.mapper.SysFormMapper;
+import com.management.platform.mapper.UserMapper;
 import com.management.platform.service.ProductService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.service.WxCorpInfoService;
+import com.management.platform.util.ExcelUtil;
 import com.management.platform.util.HttpRespMsg;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.CellType;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
-import java.util.HashMap;
-import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+import java.io.*;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.time.DateTimeException;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.zip.DataFormatException;
 
 /**
  * <p>
@@ -28,12 +52,29 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
 
     @Resource
     private ProductMapper productMapper;
+    @Resource
+    private HttpServletRequest request;
+    @Resource
+    private UserMapper userMapper;
+    @Resource
+    private SysFormMapper sysFormMapper;
+    @Value(value = "${upload.path}")
+    private String path;
+    @Resource
+    private WxCorpInfoService wxCorpInfoService;
+    @Resource
+    private SysDictMapper sysDictMapper;
+    @Resource
+    private ExcelExportServiceImpl excelExportService;
 
     @Override
     public HttpRespMsg getList(Integer companyId,String userId, String productName, String productCode, Integer pageIndex, Integer pageSize) {
         HttpRespMsg msg=new HttpRespMsg();
         LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.eq(Product::getCompanyId,companyId);
+        List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getCompanyId, companyId));
+        List<SysDict> sysDictOfProductType = sysDictMapper.selectList(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCompanyId, companyId).eq(SysDict::getCode, "ProductType"));
+        List<SysDict> sysDictOfProductUnit = sysDictMapper.selectList(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCompanyId, companyId).eq(SysDict::getCode, "ProductUnit"));
         if(!StringUtils.isEmpty(userId)){
             queryWrapper.eq(Product::getCreatorId,userId);
         }
@@ -43,11 +84,282 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
         if(!StringUtils.isEmpty(productCode)){
             queryWrapper.like(Product::getProductCode,productCode);
         }
+        if(pageIndex==null&&pageSize==null){
+            pageIndex=-1;
+            pageSize=-1;
+        }
         IPage<Product> productIPage = productMapper.selectPage(new Page<>(pageIndex, pageSize), queryWrapper);
+        List<Product> records = productIPage.getRecords();
+        records.forEach(r->{
+            Optional<User> user = userList.stream().filter(u -> u.getId().equals(r.getCreatorId())).findFirst();
+            if(user.isPresent()){
+                r.setInchargerName(user.get().getName());
+            }
+            Optional<SysDict> unit = sysDictOfProductUnit.stream().filter(u -> u.getId().equals(r.getUnit())).findFirst();
+            if(unit.isPresent()){
+                r.setUnitName(unit.get().getName());
+            }
+            Optional<SysDict> type = sysDictOfProductType.stream().filter(u -> u.getId().equals(r.getCreatorId())).findFirst();
+            if(type.isPresent()){
+                r.setTypeName(type.get().getName());
+            }
+        });
         Map map=new HashMap();
-        map.put("record",productIPage.getRecords());
+        map.put("record",records);
         map.put("total",productIPage.getTotal());
         msg.setData(map);
         return msg;
     }
+
+    @Override
+    public HttpRespMsg importData(MultipartFile multipartFile) {
+        HttpRespMsg msg=new HttpRespMsg();
+        String fileName = multipartFile.getOriginalFilename();
+        File file = new File(fileName == null ? "file" : fileName);
+        User user = userMapper.selectById(request.getHeader("token"));
+        Integer companyId = user.getCompanyId();
+        WxCorpInfo wxCorpInfo = wxCorpInfoService.getOne(new LambdaQueryWrapper<WxCorpInfo>().eq(WxCorpInfo::getCompanyId, companyId));
+        List<Product> productList = productMapper.selectList(new LambdaQueryWrapper<Product>().eq(Product::getCompanyId, companyId));
+        List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getCompanyId, companyId));
+        List<SysDict> sysDictOfProductType = sysDictMapper.selectList(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCompanyId, companyId).eq(SysDict::getCode, "ProductType"));
+        List<SysDict> sysDictOfProductUnit = sysDictMapper.selectList(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCompanyId, companyId).eq(SysDict::getCode, "ProductUnit"));
+        InputStream inputStream = null;
+        OutputStream outputStream = null;
+        try {
+            inputStream = multipartFile.getInputStream();
+            outputStream = new FileOutputStream(file);
+            byte[] buffer = new byte[4096];
+            int temp = 0;
+            while ((temp = inputStream.read(buffer, 0, 4096)) != -1) {
+                outputStream.write(buffer, 0, temp);
+            }
+            inputStream.close();
+            outputStream.close();
+            //解析表格
+            HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(file));
+            //我们只需要第一个sheet
+            HSSFSheet sheet = workbook.getSheetAt(0);
+            //由于第一行需要指明列对应的标题
+            int rowNum = sheet.getLastRowNum();
+            //获取当前表单模板 校验规则
+            SysForm sysForm = sysFormMapper.selectOne(new LambdaQueryWrapper<SysForm>().eq(SysForm::getCode, "Product").eq(SysForm::getCompanyId, companyId).eq(SysForm::getIsCurrent, 1));
+            if(sysForm==null){
+                msg.setError("当前模块未配置自定义模板,需先完成配置");
+                return msg;
+            }
+            String config = sysForm.getConfig();
+            JSONObject configOb = JSON.parseObject(config);
+            JSONArray configObJSONArray = configOb.getJSONArray("list");
+            List<Product>  importProductList=new ArrayList<>();
+            List<String> userNameList=new ArrayList<>();
+            HttpRespMsg respMsg=new HttpRespMsg();
+            for (int rowIndex = 0; rowIndex <= rowNum; rowIndex++) {
+                HSSFRow row = sheet.getRow(rowIndex);
+                if (row == null) {
+                    continue;
+                }
+                //跳过空行
+                if (ExcelUtil.isRowEmpty(row)) {
+                    continue;
+                }
+                //获取到当前行的列数据
+                int cellNum = row.getLastCellNum();
+                for (int i = 0; i < cellNum; i++) {
+                    JSONObject item = configObJSONArray.getJSONObject(i);
+                    String modelName = item.getString("model");
+                    HSSFCell cell = row.getCell(i);
+                    if(cell!=null){
+                        switch (item.getString("type")){
+                            case "time":cell.setCellType(CellType.NUMERIC);
+                                break;
+                            default:cell.setCellType(CellType.STRING);
+                        }
+                    }
+                    if(modelName.equals("inchargerId")){
+                        if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                            userNameList.add(cell.getStringCellValue());
+                        }
+                    }
+
+                }
+            }
+            System.out.println("参与搜素的人员列表"+userNameList + userNameList.size());
+            if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1&&userNameList.size()>0){
+                respMsg = wxCorpInfoService.getBatchSearchUserInfo(wxCorpInfo, userNameList,null);
+                if(respMsg.code.equals("0")){
+                    msg.setError("姓名为["+String.valueOf(respMsg.data)+"]的人员存在重复,请使用工号!");
+                    return msg;
+                }
+            }
+            List<User> targetUserList= (List<User>) respMsg.data;
+            for (int rowIndex = 0; rowIndex <= rowNum; rowIndex++) {
+                HSSFRow row = sheet.getRow(rowIndex);
+                if (row == null) {
+                    continue;
+                }
+                //跳过空行
+                if (ExcelUtil.isRowEmpty(row)) {
+                    continue;
+                }
+                //获取到当前行的列数据
+                int cellNum = row.getLastCellNum();
+                Product product=new Product();
+                product.setCompanyId(companyId);
+                product.setCreatorId(user.getId());
+                for (int i = 0; i < cellNum; i++) {
+                    JSONObject item = configObJSONArray.getJSONObject(i);
+                    String modelName = item.getString("model");
+                    String className = modelName.substring(0, 1).toUpperCase() + modelName.substring(1);
+                    String getter="get"+className;
+                    String setter="set"+className;
+                    HSSFCell cell = row.getCell(i);
+                    if(cell!=null){
+                        switch (item.getString("type")){
+                            case "time":cell.setCellType(CellType.NUMERIC);
+                                break;
+                            default:cell.setCellType(CellType.STRING);
+                        }
+                    }
+//                    Class<?> productClass = Class.forName("com.management.platform.entity.Product");
+                    Class<Product> productClass = Product.class;
+                    Method method = productClass.getMethod(setter, String.class);
+                    //校验当前列是否为必填
+                    JSONObject options = item.getJSONObject("options");
+                    JSONObject rules = options.getJSONObject("rules");
+                    Boolean required = rules.getBoolean("required");
+                    if(required){
+                        if(StringUtils.isEmpty(cell.getStringCellValue())){
+                            msg.setError(item.getString("label")+"值不能为空值");
+                            return msg;
+                        }
+                    }
+                    if(modelName.equals("productCode")){
+                        if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                            //系统中同公司已存在的产品编码 更新
+                            Optional<Product> first = productList.stream().filter(p ->p.getProductCode()!=null&& p.getProductCode().equals(cell.getStringCellValue())).findFirst();
+                            if(first.isPresent()){
+                                product.setId(first.get().getId());
+                            }
+                        }
+                    }
+                    if(modelName.equals("inchargerId")){
+                        if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                            String userName = cell.getStringCellValue();
+                            Optional<User> first;
+                            if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                                Optional<User> optional = targetUserList.stream().filter(tl -> tl.getName().equals(userName)).findFirst();
+                                first= userList.stream().filter(u ->(u.getJobNumber()!=null&&u.getJobNumber().equals(userName))||(optional.isPresent()&&u.getCorpwxUserid()!=null&&u.getCorpwxUserid().equals(optional.get().getCorpwxUserid()))).findFirst();
+                            }else {
+                                first= userList.stream().filter(u -> u.getName().equals(userName)||(u.getJobNumber()!=null&&u.getJobNumber().equals(userName))).findFirst();
+                            }
+                            if (first.isPresent()) {
+                                product.setInchargerId(first.get().getId());
+                            } else {
+                                throw new Exception("["+userName+"]在系统中不存在");
+                            }
+                        }
+                    }
+                    if(modelName.equals("status")){
+                        if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                            switch (cell.getStringCellValue()){
+                                case "下架":product.setStatus(0);
+                                break;
+                                case "上架":product.setStatus(1);
+                                break;
+                            }
+                        }
+                    }
+                    if(modelName.equals("type")){
+                        if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                            Optional<SysDict> first = sysDictOfProductType.stream().filter(s -> s.getName().equals(cell.getStringCellValue())).findFirst();
+                            if(first.isPresent()){
+                                product.setType(first.get().getId());
+                            }else {
+                                throw new Exception("产品类型["+cell.getStringCellValue()+"不存在,请在系统字典中增加");
+                            }
+                        }
+                    }
+                    if(modelName.equals("unit")){
+                        if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                            Optional<SysDict> first = sysDictOfProductUnit.stream().filter(s -> s.getName().equals(cell.getStringCellValue())).findFirst();
+                            if(first.isPresent()){
+                                product.setUnit(first.get().getId());
+                            }else {
+                                throw new Exception("产品单位["+cell.getStringCellValue()+"不存在,请在系统字典中增加");
+                            }
+                        }
+                    }
+                    if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                        method.invoke(product,cell.getStringCellValue());
+                    }
+                }
+                importProductList.add(product);
+            }
+            if(importProductList.size()>0){
+               if(!saveOrUpdateBatch(importProductList)){
+                   msg.setError("验证失败");
+                   return msg;
+               }
+            }
+        } catch (IOException | NoSuchMethodException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg exportData(String userId, String productName, String productCode) throws Exception {
+        User user = userMapper.selectById(request.getHeader("token"));
+        SysForm sysForm = sysFormMapper.selectOne(new LambdaQueryWrapper<SysForm>().eq(SysForm::getCompanyId, user.getCompanyId()).eq(SysForm::getCode, "Product").eq(SysForm::getIsCurrent, 1));
+        WxCorpInfo wxCorpInfo = wxCorpInfoService.getOne(new LambdaQueryWrapper<WxCorpInfo>().eq(WxCorpInfo::getCompanyId, user.getCompanyId()));
+        String config = sysForm.getConfig();
+        JSONObject configOb = JSON.parseObject(config);
+        JSONArray configObJSONArray = configOb.getJSONArray("list");
+        List<List<String>> dataList=new ArrayList<>();
+        List<String> titleList=new ArrayList<>();
+        for (int i = 0; i < configObJSONArray.size(); i++) {
+            JSONObject item = configObJSONArray.getJSONObject(i);
+            titleList.add(item.getString("label"));
+        }
+        dataList.add(titleList);
+        HttpRespMsg respMsg = getList(user.getCompanyId(), userId, productName, productCode, null, null);
+        Map<String, Object> msgData = (Map<String, Object>) respMsg.getData();
+        List<Product> productList = (List<Product>) msgData.get("record");
+        for (Product product : productList) {
+            List<String> item=new ArrayList<>();
+            for (int i = 0; i < configObJSONArray.size(); i++) {
+                JSONObject target = configObJSONArray.getJSONObject(i);
+                String model = target.getString("model");
+                String targetName = model.substring(0, 1).toUpperCase() + model.substring(1);
+                Class<? extends Product> aClass = product.getClass();
+                String value = String.valueOf(aClass.getMethod("get" + targetName).invoke(product)==null?"":aClass.getMethod("get" + targetName).invoke(product));
+                if(model.equals("inchargerId")){
+                    if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                        value = "$userName"+String.valueOf(aClass.getMethod("getInchargerName").invoke(product))+"$";
+                    }else {
+                        value = String.valueOf(aClass.getMethod("getInchargerName").invoke(product));
+                    }
+                }
+                if(model.equals("unit")){
+                    value = String.valueOf(aClass.getMethod("getUnitName").invoke(product));
+                }
+                if(model.equals("type")){
+                    value = String.valueOf(aClass.getMethod("getTypeName").invoke(product));
+                }
+                if(model.equals("status")){
+                    value = Integer.valueOf(String.valueOf(aClass.getMethod("getStatus").invoke(product)))==0?"下架":"上架";
+                }
+                item.add(value);
+            }
+            dataList.add(item);
+        }
+        String fileName="产品表导出_"+ System.currentTimeMillis();
+        return excelExportService.exportGeneralExcelByTitleAndList(wxCorpInfo,fileName,dataList,path);
+    }
 }

+ 233 - 1
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/SysFormServiceImpl.java

@@ -1,11 +1,32 @@
 package com.management.platform.service.impl;
 
-import com.management.platform.entity.SysForm;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.*;
+import com.management.platform.mapper.CompanyMapper;
 import com.management.platform.mapper.SysFormMapper;
+import com.management.platform.mapper.UserMapper;
 import com.management.platform.service.SysFormService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.util.HttpRespMsg;
+import com.management.platform.util.MessageUtils;
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
 /**
  * <p>
  *  服务实现类
@@ -17,4 +38,215 @@ import org.springframework.stereotype.Service;
 @Service
 public class SysFormServiceImpl extends ServiceImpl<SysFormMapper, SysForm> implements SysFormService {
 
+    @Resource
+    private CompanyMapper companyMapper;
+    @Resource
+    private HttpServletRequest request;
+    @Resource
+    private UserMapper userMapper;
+    @Resource
+    private SysFormMapper sysFormMapper;
+    @Value(value = "${upload.path}")
+    private String path;
+
+    @Override
+    public HttpRespMsg getExportTemplate(String code) {
+        HttpRespMsg msg=new HttpRespMsg();
+        List<String> heads = new ArrayList<>();
+        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        Company company = companyMapper.selectById(companyId);
+        //根据code获取当前公司配置的表单模板
+        SysForm sysForm = sysFormMapper.selectOne(new LambdaQueryWrapper<SysForm>().eq(SysForm::getCompanyId, companyId).eq(SysForm::getCode, code).eq(SysForm::getIsCurrent, 1));
+        if(sysForm==null){
+            msg.setError("当前表单未配置模板,请先完成模板配置");
+            return msg;
+        }
+        String config = sysForm.getConfig();
+        JSONObject configOb = JSON.parseObject(config);
+        JSONArray configObJSONArray = configOb.getJSONArray("list");
+        for (int i = 0; i < configObJSONArray.size(); i++) {
+            JSONObject item = configObJSONArray.getJSONObject(i);
+            heads.add(item.getString("label"));
+        }
+        List<List<String>> allList = new ArrayList<>();
+        allList.add(heads);
+        String title;
+        switch (code){
+            case "Clue":title = company.getCompanyName()+"_线索导入模板";
+            break;
+            case "Custom":title = company.getCompanyName()+"_客户导入模板";
+                break;
+            case "Order":title = company.getCompanyName()+"_订单导入模板";
+                break;
+            case "Product":title = company.getCompanyName()+"_产品导入模板";
+                break;
+            case "Task":title = company.getCompanyName()+"_任务导入模板";
+                break;
+            case "Contacts":title = company.getCompanyName()+"_联系人导入模板";
+                break;
+            case "Business":title = company.getCompanyName()+"_商机导入模板";
+                break;
+            default:title="";
+        }
+        String result=MessageUtils.message("file.excelScu");
+        String fileName= title+".xls";
+        try {
+//            response.reset();
+//            response.setHeader("Content-disposition",
+//                "attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));
+//            //设置文件头编码格式
+//            response.setContentType("APPLICATION/OCTET-STREAM;charset=UTF-8");//设置类型
+//            response.setHeader("Cache-Control","no-cache");//设置头
+//            response.setDateHeader("Expires", 0);//设置日期头
+            // 创建工作簿
+            HSSFWorkbook workBook = new HSSFWorkbook();
+            // 创建工作类
+            HSSFSheet sheet = workBook.createSheet();
+            //设置首行冻结
+            sheet.createFreezePane(0, 1);
+            sheet.setDefaultColumnWidth(16);
+            //设置字体样式
+            HSSFFont headFont = workBook.createFont();
+            headFont.setBold(true);
+            headFont.setFontHeightInPoints((short) 10);
+            headFont.setFontName("黑体");
+
+            HSSFFont titleFont = workBook.createFont();
+            titleFont.setBold(true);
+            titleFont.setFontHeightInPoints((short) 10);
+            titleFont.setFontName("黑体");
+
+            HSSFFont font = workBook.createFont();
+            font.setFontHeightInPoints((short) 10);
+            font.setFontName("宋体");
+
+            //设置单元格样式
+            CellStyle headStyle = workBook.createCellStyle();
+            headStyle.setFont(headFont);
+            headStyle.setAlignment(HorizontalAlignment.CENTER);
+            headStyle.setVerticalAlignment(org.apache.poi.ss.usermodel.VerticalAlignment.CENTER);
+            headStyle.setWrapText(true);
+            headStyle.setBorderBottom(BorderStyle.THIN); //下边框
+            headStyle.setBorderLeft(BorderStyle.THIN);//左边框
+            headStyle.setBorderTop(BorderStyle.THIN);//上边框
+            headStyle.setBorderRight(BorderStyle.THIN);//右边框
+
+            String color = "c0c0c0";    //此处得到的color为16进制的字符串
+            //转为RGB码
+            int r = Integer.parseInt((color.substring(0,2)),16);   //转为16进制
+            int g = Integer.parseInt((color.substring(2,4)),16);
+            int b = Integer.parseInt((color.substring(4,6)),16);
+
+            //自定义cell颜色
+            HSSFPalette palette = workBook.getCustomPalette();
+            //这里的9是索引
+            palette.setColorAtIndex((short)9, (byte) r, (byte) g, (byte) b);
+
+            CellStyle titleStyle = workBook.createCellStyle();
+            titleStyle.setFont(titleFont);
+            titleStyle.setAlignment(HorizontalAlignment.CENTER);
+            titleStyle.setVerticalAlignment(org.apache.poi.ss.usermodel.VerticalAlignment.CENTER);
+            titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);  //填充单元格
+            titleStyle.setFillForegroundColor((short)9);    //填色
+            titleStyle.setWrapText(true);
+            titleStyle.setBorderBottom(BorderStyle.THIN); //下边框
+            titleStyle.setBorderLeft(BorderStyle.THIN);//左边框
+            titleStyle.setBorderTop(BorderStyle.THIN);//上边框
+            titleStyle.setBorderRight(BorderStyle.THIN);//右边框
+
+            CellStyle cellStyle = workBook.createCellStyle();
+            cellStyle.setFont(font);
+            cellStyle.setAlignment(HorizontalAlignment.CENTER);
+            cellStyle.setVerticalAlignment(org.apache.poi.ss.usermodel.VerticalAlignment.CENTER);
+            cellStyle.setWrapText(true);
+            cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
+            cellStyle.setBorderLeft(BorderStyle.THIN);//左边框
+            cellStyle.setBorderTop(BorderStyle.THIN);//上边框
+            cellStyle.setBorderRight(BorderStyle.THIN);//右边框
+
+            if(allList.size() > 0) {
+                int start = 0;
+                for(List<String> rowList : allList) {
+                    HSSFRow row = sheet.createRow(start);
+                    row.setHeightInPoints(24);
+                    for(int i = 0; i < rowList.size(); i++) {
+                        HSSFCell cell = row.createCell(i);
+                        ClientAnchor anchor = new HSSFClientAnchor();
+                        if(start == 0) {
+                            cell.setCellStyle(titleStyle);
+                            // 关键修改
+                            anchor.setDx1(0);
+                            anchor.setDx2(0);
+                            anchor.setDy1(0);
+                            anchor.setDy2(0);
+                            anchor.setCol1(cell.getColumnIndex());
+                            anchor.setRow1(cell.getRowIndex());
+                            anchor.setCol2(cell.getColumnIndex() + 5);
+                            anchor.setRow2(cell.getRowIndex() + 6);
+                            // 结束
+                            Drawing drawing = sheet.createDrawingPatriarch();
+                            Comment comment = null;
+                            String[] textList=null;
+                            DVConstraint constraint =null;
+                            CellRangeAddressList regions =null;
+                            HSSFDataValidation data_validation_list =null;
+//                            switch (rowList.get(i)){
+//                                case "是否为公共项目":
+//                                case "Whether it is a public project":
+//                                    // 加载下拉列表内容
+//                                    //textList= new String[]{"是", "否"};
+//                                    textList= new String[]{MessageUtils.message("excel.yes"), MessageUtils.message("excel.no")};
+//                                    constraint = DVConstraint
+//                                            .createExplicitListConstraint(textList);
+//                                    // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
+//                                    regions = new CellRangeAddressList(1,
+//                                            1000, i, i);
+//                                    // 数据有效性对象
+//                                    data_validation_list = new HSSFDataValidation(
+//                                            regions, constraint);
+//                                    sheet.addValidationData(data_validation_list);
+//                                    comment = drawing.createCellComment(anchor);
+//                                    // 输入批注信息
+//                                    //comment.setString(new HSSFRichTextString("是否为公共项目\n" +
+//                                    //"是:公共项目\n" +
+//                                    //"否:普通项目"));
+//                                    comment.setString(new HSSFRichTextString(MessageUtils.message("excel.publicProject")+"\n" +
+//                                            MessageUtils.message("excel.yesPublic")+"\n" +
+//                                            MessageUtils.message("excel.noPublic")));
+//                                    cell.setCellComment(comment);
+//                                    break;
+//                            }
+                        }else {
+                            cell.setCellStyle(cellStyle);
+                        }
+                        cell.setCellValue(rowList.get(i));
+                    }
+                    start++;
+                }
+            }
+            //用于非传统ajax;
+//            String headStr = "attachment; filename=\"" + fileName + "\"";
+//            response.setContentType("APPLICATION/OCTET-STREAM");//返回格式为流
+//            response.setHeader("Content-Disposition", headStr);
+//            //普通下载不需要以上三行,注掉即可
+//            OutputStream os = response.getOutputStream();//在线下载
+            File dir = null;
+            dir = new File(path);
+            // D://cloud/upload 文件上传后所存储的位置,部署到服务器上时配置服务器地址即可
+            if (!dir.exists()) {
+                dir.mkdirs();
+            }
+            FileOutputStream os = new FileOutputStream(path+fileName);//保存到本地
+            workBook.write(os);
+            os.flush();
+            os.close();
+        }catch(Exception e) {
+            e.printStackTrace();
+            //msg.setError("已存在模板名称为["+fileName+"]的文件,请删除后重新下载");
+            msg.setError(MessageUtils.message("file.duplicateTemplate",fileName));
+            return msg;
+        }
+        msg.data= "/upload/"+fileName;
+        return msg;
+    }
 }

+ 141 - 2
fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/BusinessOpportunityMapper.xml

@@ -27,17 +27,24 @@
         id, company_id, name, customer_id, amount_of_money, expected_transaction_date, stage, create_time, creator_id, remark, is_delete, plate1, plate2, plate3, plate4, plate5
     </sql>
     <select id="selectAllList" resultType="com.management.platform.entity.BusinessOpportunity">
-        select * FROM business_opportunity b
+        select
+        b.id,
+        b.`name`,
+        Sum(ip.total_price),
+        b.stage,
+        (SELECT GROUP_CONCAT(product_name) from business_item_product i LEFT JOIN product t on i.product_id = t.id  WHERE i.business_id = b.id) productName
+        FROM business_opportunity b
                  left join business_item_product ip ON ip.business_id = b.id
                  left join product p on p.id = ip.product_id
         WHERE b.company_id = #{companyId}
+          and is_delete = #{isDelete}
         <if test="name != null and name != ''" >
          and b.name = #{name}
         </if>
         <if test="stage != null " >
             and b.stage = #{stage}
         </if>
-        <if test="startTime != null and endTime != null " >
+        <if test="startTime != null and bo.endTime != null " >
             and b.expected_transaction_date BETWEEN #{startTime} and #{endTime}
         </if>
         <if test="productId != null ">
@@ -46,5 +53,137 @@
         GROUP BY b.id
         LIMIT #{pageIndex},#{pageSize}
     </select>
+    <select id="selectAllList1" resultType="com.management.platform.entity.BusinessOpportunity">
+        select
+        b.id,
+        b.`name`,
+        Sum(ip.total_price),
+        b.stage,
+        (SELECT GROUP_CONCAT(product_name) from business_item_product i LEFT JOIN product t on i.product_id = t.id WHERE
+        i.business_id = b.id) productName
+        FROM business_opportunity b
+        left join business_item_product ip ON ip.business_id = b.id
+        left join product p on p.id = ip.product_id
+        WHERE b.company_id = #{bo.companyId}
+          and b.is_delete = #{bo.isDelete}
+        and b.incharger_id in
+        (SELECT id from `user` WHERE department_id = (SELECT department_id from `user` WHERe id = #{userId}))
+        and b.incharger_id is null
+        <if test="bo.name != null and bo.name != ''">
+            and b.name = #{bo.name}
+        </if>
+        <if test="bo.stage != null ">
+            and b.stage = #{bo.stage}
+        </if>
+        <if test="bo.startTime != null and bo.endTime != null ">
+            and b.expected_transaction_date BETWEEN #{bo.startTime} and #{bo.endTime}
+        </if>
+        <if test="bo.productId != null ">
+            and p.id = #{bo.productId}
+        </if>
+        GROUP BY b.id
+        LIMIT #{bo.pageIndex},#{bo.pageSize}
+    </select>
+    <select id="selectAllList2" resultType="com.management.platform.entity.BusinessOpportunity">
+        select
+        b.id,
+        b.`name`,
+        Sum(ip.total_price),
+        b.stage,
+        (SELECT GROUP_CONCAT(product_name) from business_item_product i LEFT JOIN product t on i.product_id = t.id WHERE
+        i.business_id = b.id) productName
+        FROM business_opportunity b
+        left join business_item_product ip ON ip.business_id = b.id
+        left join product p on p.id = ip.product_id
+        WHERE b.company_id = #{bo.companyId}
+        and b.incharger_id = #{userId}
+        and b.is_delete = #{bo.isDelete}
+        and b.incharger_id is null
+        <if test="bo.name != null and bo.name != ''">
+            and b.name = #{bo.name}
+        </if>
+        <if test="bo.stage != null ">
+            and b.stage = #{bo.stage}
+        </if>
+        <if test="bo.startTime != null and bo.endTime != null ">
+            and b.expected_transaction_date BETWEEN #{bo.startTime} and #{bo.endTime}
+        </if>
+        <if test="bo.productId != null ">
+            and p.id = #{bo.productId}
+        </if>
+        GROUP BY b.id
+        LIMIT #{bo.pageIndex},#{bo.pageSize}
+    </select>
+    <select id="getTotal" resultType="java.lang.Integer">
+        select
+        conut(b.id)
+        FROM business_opportunity b
+        left join business_item_product ip ON ip.business_id = b.id
+        left join product p on p.id = ip.product_id
+        WHERE b.company_id = #{companyId}
+          and b.is_delete = #{isDelete}
+        <if test="name != null and name != ''" >
+            and b.name = #{name}
+        </if>
+        <if test="stage != null " >
+            and b.stage = #{stage}
+        </if>
+        <if test="startTime != null and endTime != null " >
+            and b.expected_transaction_date BETWEEN #{startTime} and #{endTime}
+        </if>
+        <if test="productId != null ">
+            and p.id = #{productId}
+        </if>
+        GROUP BY b.id
+    </select>
+    <select id="getTotal1" resultType="java.lang.Integer">
+        select
+        count(b.id)
+        FROM business_opportunity b
+        left join business_item_product ip ON ip.business_id = b.id
+        left join product p on p.id = ip.product_id
+        WHERE b.company_id = #{bo.companyId}
+          and b.is_delete = #{bo.isDelete}
+        and b.incharger_id in
+        (SELECT id from `user` WHERE department_id = (SELECT department_id from `user` WHERe id = #{userId}))
+        and b.incharger_id is null
+        <if test="bo.name != null and bo.name != ''">
+            and b.name = #{bo.name}
+        </if>
+        <if test="bo.stage != null ">
+            and b.stage = #{bo.stage}
+        </if>
+        <if test="bo.startTime != null and bo.endTime != null ">
+            and b.expected_transaction_date BETWEEN #{bo.startTime} and #{bo.endTime}
+        </if>
+        <if test="bo.productId != null ">
+            and p.id = #{bo.productId}
+        </if>
+        GROUP BY b.id
+    </select>
+    <select id="getTotal2" resultType="java.lang.Integer">
+        select
+        COUNT(b.id)
+        FROM business_opportunity b
+        left join business_item_product ip ON ip.business_id = b.id
+        left join product p on p.id = ip.product_id
+        WHERE b.company_id = #{bo.companyId}
+        and b.is_delete = #{bo.isDelete}
+        and b.incharger_id = #{userId}
+        and b.incharger_id is null
+        <if test="bo.name != null and bo.name != ''">
+            and b.name = #{bo.name}
+        </if>
+        <if test="bo.stage != null ">
+            and b.stage = #{bo.stage}
+        </if>
+        <if test="bo.startTime != null and bo.endTime != null ">
+            and b.expected_transaction_date BETWEEN #{bo.startTime} and #{bo.endTime}
+        </if>
+        <if test="bo.productId != null ">
+            and p.id = #{bo.productId}
+        </if>
+        GROUP BY b.id
+    </select>
 
 </mapper>

+ 65 - 23
fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/ClueMapper.xml

@@ -53,7 +53,7 @@
                c.create_id
         from Clue c
         where
-            c.company_id = #{companyId} and is_delete = 0
+            c.company_id = #{companyId} and is_delete = #{isDelete}
         <if test="startTime != null and endTime != null ">
         and  c.create_time BETWEEN  #{startTime} and #{endTime}
         </if>
@@ -91,23 +91,23 @@
         c.create_id
         from Clue c
         where
-        c.company_id = #{companyId} and is_delete = 0
+        c.company_id = #{clue.companyId} and is_delete = #{clue.isDelete}
         and c.incharger_id in
-        (SELECT id from `user` WHERE department_id = (SELECT department_id from `user` WHERe id = c.id))
+        (SELECT id from `user` WHERE department_id = (SELECT department_id from `user` WHERe id = #{userId}))
         and c.incharger_id is null
-        <if test="startTime != null and endTime != null ">
-            and  c.create_time BETWEEN  #{startTime} and #{endTime}
+        <if test="clue.startTime != null and clue.endTime != null ">
+            and  c.create_time BETWEEN  #{clue.startTime} and #{clue.endTime}
         </if>
-        <if test="clueName != null and clueName != '' ">
-            and  c.clue_name =  #{clueName}
+        <if test="clue.clueName != null and clue.clueName != '' ">
+            and  c.clue_name =  #{clue.clueName}
         </if>
-        <if test="clueSourceId != null">
-            and  c.clue_source_id =  #{clueSourceId}
+        <if test="clue.clueSourceId != null">
+            and  c.clue_source_id =  #{clue.clueSourceId}
         </if>
-        <if test="customerIndustryId != null">
-            and  c.customer_industry_id =  #{customerIndustryId}
+        <if test="clue.customerIndustryId != null">
+            and  c.customer_industry_id =  #{clue.customerIndustryId}
         </if>
-        limit #{pageIndex},#{pageFrom}
+        limit #{clue.pageIndex},#{clue.pageFrom}
     </select>
     <select id="list2" resultType="com.management.platform.entity.Clue">
         select c.id,
@@ -132,21 +132,21 @@
         c.create_id
         from Clue c
         where
-        c.company_id = #{companyId} and is_delete = 0
+        c.company_id = #{clue.companyId} and is_delete = #{clue.isDelete}
         and c.incharger_id = #{userId} and c.incharger_id is null
-        <if test="startTime != null and endTime != null ">
-            and  c.create_time BETWEEN  #{startTime} and #{endTime}
+        <if test="clue.startTime != null and clue.endTime != null ">
+            and  c.create_time BETWEEN  #{clue.startTime} and #{clue.endTime}
         </if>
-        <if test="clueName != null and clueName != '' ">
-            and  c.clue_name =  #{clueName}
+        <if test="clue.clueName != null and clue.clueName != '' ">
+            and  c.clue_name =  #{clue.clueName}
         </if>
-        <if test="clueSourceId != null">
-            and  c.clue_source_id =  #{clueSourceId}
+        <if test="clue.clueSourceId != null">
+            and  c.clue_source_id =  #{clue.clueSourceId}
         </if>
-        <if test="customerIndustryId != null">
-            and  c.customer_industry_id =  #{customerIndustryId}
+        <if test="clue.customerIndustryId != null">
+            and  c.customer_industry_id =  #{clue.customerIndustryId}
         </if>
-        limit #{pageIndex},#{pageFrom}
+        limit #{clue.pageIndex},#{clue.pageFrom}
     </select>
     <select id="Deleterlist" resultType="com.management.platform.entity.Clue">
         select c.id,
@@ -190,7 +190,7 @@
         select count(*)
         from Clue c
         where
-        c.company_id = #{companyId} and is_delete = 0
+        c.company_id = #{companyId} and is_delete = #{isDelete}
         <if test="startTime != null and endTime != null ">
             and  c.create_time BETWEEN  #{startTime} and #{endTime}
         </if>
@@ -222,5 +222,47 @@
             and  c.customer_industry_id =  #{customerIndustryId}
         </if>
     </select>
+    <select id="getTotal1" resultType="java.lang.Integer">
+        select c.id,
+        COUNT(c.company_id)
+        from Clue c
+        where
+        c.company_id = #{clue.companyId} and is_delete = #{clue.isDelete}
+        and c.incharger_id in
+        (SELECT id from `user` WHERE department_id = (SELECT department_id from `user` WHERe id = #{userId}))
+        and c.incharger_id is null
+        <if test="clue.startTime != null and clue.endTime != null ">
+            and  c.create_time BETWEEN  #{clue.startTime} and #{clue.endTime}
+        </if>
+        <if test="clue.clueName != null and clue.clueName != '' ">
+            and  c.clue_name =  #{clue.clueName}
+        </if>
+        <if test="clue.clueSourceId != null">
+            and  c.clue_source_id =  #{clue.clueSourceId}
+        </if>
+        <if test="clue.customerIndustryId != null">
+            and  c.customer_industry_id =  #{clue.customerIndustryId}
+        </if>
+    </select>
+    <select id="getTotal2" resultType="java.lang.Integer">
+        select
+        COUNT(c.id)
+        from Clue c
+        where
+        c.company_id = #{clue.companyId} and is_delete = #{clue.isDelete}
+        and c.incharger_id = #{userId} and c.incharger_id is null
+        <if test="clue.startTime != null and clue.endTime != null ">
+            and c.create_time BETWEEN #{clue.startTime} and #{clue.endTime}
+        </if>
+        <if test="clue.clueName != null and clue.clueName != '' ">
+            and c.clue_name = #{clue.clueName}
+        </if>
+        <if test="clue.clueSourceId != null">
+            and c.clue_source_id = #{clue.clueSourceId}
+        </if>
+        <if test="clue.customerIndustryId != null">
+            and c.customer_industry_id = #{clue.customerIndustryId}
+        </if>
+    </select>
 
 </mapper>

+ 2 - 2
fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/ProductMapper.xml

@@ -20,12 +20,12 @@
         <result column="plate3" property="plate3" />
         <result column="plate4" property="plate4" />
         <result column="plate5" property="plate5" />
-        <result column="desc" property="desc" />
+        <result column="descs" property="descs" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, company_id, product_name, product_code, type, unit, price, status, incharger_id, create_time, creator_id, plate1, plate2, plate3, plate4, plate5, desc
+        id, company_id, product_name, product_code, type, unit, price, status, incharger_id, create_time, creator_id, plate1, plate2, plate3, plate4, plate5, descs
     </sql>
 
 </mapper>

BIN
fhKeeper/formulahousekeeper/management-crm/workTime.2024-03-01.log.gz


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 71539
fhKeeper/formulahousekeeper/management-crm/workTime.log


+ 28 - 7
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/GroupBudgetReviewController.java

@@ -4,10 +4,7 @@ package com.management.platform.controller;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.management.platform.entity.*;
-import com.management.platform.mapper.ProjectMapper;
-import com.management.platform.mapper.TaskGroupMapper;
-import com.management.platform.mapper.UserMapper;
-import com.management.platform.mapper.WxCorpInfoMapper;
+import com.management.platform.mapper.*;
 import com.management.platform.service.ExcelExportService;
 import com.management.platform.service.GroupBudgetReviewService;
 import com.management.platform.service.TaskService;
@@ -61,6 +58,8 @@ public class GroupBudgetReviewController {
     private ExcelExportService excelExportService;
     @Resource
     private WxCorpInfoService wxCorpInfoService;
+    @Resource
+    private TimeTypeMapper timeTypeMapper;
 
     @RequestMapping("/add")
     public HttpRespMsg add(Integer groupId,Integer oldManDay,Integer changeManDay,Integer nowManDay,String remark){
@@ -113,14 +112,14 @@ public class GroupBudgetReviewController {
             //审核通过计算到任务分组的项目人天
             Integer groupId = groupBudgetReview.getGroupId();
             TaskGroup taskGroup = taskGroupMapper.selectById(groupId);
-            Integer manDay = taskGroup.getManDay();
+            Double manDay = taskGroup.getManDay();
             BigDecimal bigDecimal = new BigDecimal(manDay==null?0:manDay);
             bigDecimal=bigDecimal.add(new BigDecimal(groupBudgetReview.getChangeManDay()==null?0:groupBudgetReview.getChangeManDay()));
-            taskGroup.setManDay(bigDecimal.intValue());
+            taskGroup.setManDay(bigDecimal.doubleValue());
             taskGroupMapper.updateById(taskGroup);
             //项目人天按照分组工时增加
             Project project = projectMapper.selectById(taskGroup.getProjectId());
-            Integer day = project.getManDay();
+            double day = project.getManDay();
             day=day+groupBudgetReview.getChangeManDay();
             project.setManDay(day);
             projectMapper.updateById(project);
@@ -150,6 +149,7 @@ public class GroupBudgetReviewController {
     public HttpRespMsg list(String startDate,String endDate,Integer projectId,Integer status,String submitUserId){
         HttpRespMsg httpRespMsg=new HttpRespMsg();
         Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+
         LambdaQueryWrapper<GroupBudgetReview> queryWrapper = new LambdaQueryWrapper<GroupBudgetReview>().eq(GroupBudgetReview::getCompanyId, companyId).orderByDesc(GroupBudgetReview::getCreateTime);
         if(startDate!=null && endDate!=null){
             queryWrapper.between(GroupBudgetReview::getCreateTime,startDate,endDate);
@@ -164,6 +164,27 @@ public class GroupBudgetReviewController {
             queryWrapper.eq(GroupBudgetReview::getCreatorId,submitUserId);
         }
         List<GroupBudgetReview> list = groupBudgetReviewService.list(queryWrapper);
+        TimeType timeType = timeTypeMapper.selectById(companyId);
+        list.forEach(l->{
+            if(l.getOldManDay()!=null){
+                BigDecimal bigDecimal=new BigDecimal(l.getOldManDay());
+                bigDecimal=bigDecimal.multiply(new BigDecimal(timeType.getAllday()));
+                String format = String.format("%.1f", bigDecimal.doubleValue());
+                l.setOldEstimatedWorkTime(format);
+            }
+            if(l.getChangeManDay()!=null){
+                BigDecimal bigDecimal=new BigDecimal(l.getChangeManDay());
+                bigDecimal=bigDecimal.multiply(new BigDecimal(timeType.getAllday()));
+                String format = String.format("%.1f", bigDecimal.doubleValue());
+                l.setChangeEstimatedWorkTime(format);
+            }
+            if(l.getNowManDay()!=null){
+                BigDecimal bigDecimal=new BigDecimal(l.getNowManDay());
+                bigDecimal=bigDecimal.multiply(new BigDecimal(timeType.getAllday()));
+                String format = String.format("%.1f", bigDecimal.doubleValue());
+                l.setNowEstimatedWorkTime(format);
+            }
+        });
         httpRespMsg.setData(list);
         return httpRespMsg;
     }

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectController.java

@@ -172,7 +172,7 @@ public class ProjectController {
                                    Double outputValue,
                                    Integer deptId,
                                    @RequestParam(defaultValue = "false") boolean onlyChangeParticipate,
-                                   String buId,Integer manDay,String  manDayStartDate,String plate1,
+                                   String buId,Double manDay,String  manDayStartDate,String plate1,
                                    String plate2,
                                    String plate3,
                                    String plate4,

+ 28 - 4
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TaskGroupController.java

@@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
 import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -174,6 +175,8 @@ public class TaskGroupController {
     @RequestMapping("saveManDay")
     public HttpRespMsg saveManDay(String data) {
         HttpRespMsg msg = new HttpRespMsg();
+        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        TimeType timeType = timeTypeMapper.selectById(companyId);
         List<TaskGroup> groupList = JSON.parseArray(data, TaskGroup.class);
         List<TaskGroup> addList = new ArrayList<>();
         int totalManDay = 0;
@@ -197,7 +200,7 @@ public class TaskGroupController {
             }
             item.setId(taskGroup.getId());
             if (taskGroup.getManDay() == null) {
-                item.setManDay(0);
+                item.setManDay(0.0);
             } else {
                 item.setManDay(taskGroup.getManDay());
                 totalManDay += taskGroup.getManDay();
@@ -218,8 +221,17 @@ public class TaskGroupController {
         if (addList.size() > 0) {
             taskGroupService.updateBatchById(addList);
         }
-
-        msg.data = taskGroupService.list(new QueryWrapper<TaskGroup>().eq("project_id", groupList.get(0).getProjectId()));
+        List<TaskGroup> list = taskGroupService.list(new QueryWrapper<TaskGroup>().eq("project_id", groupList.get(0).getProjectId()));
+        list.forEach(l->{
+            //todo:计算项目预算工时
+            if(l.getManDay()!=null){
+                BigDecimal bigDecimal=new BigDecimal(l.getManDay());
+                bigDecimal=bigDecimal.multiply(new BigDecimal(timeType.getAllday()));
+                String format = String.format("%.1f", bigDecimal.doubleValue());
+                l.setEstimatedWorkTime(format);
+            }
+        });
+        msg.data = list;
         return msg;
     }
 
@@ -332,6 +344,8 @@ public class TaskGroupController {
     @RequestMapping("/list")
     public HttpRespMsg list(TaskGroup item) {
         HttpRespMsg msg = new HttpRespMsg();
+        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        TimeType timeType = timeTypeMapper.selectById(companyId);
         QueryWrapper<TaskGroup> queryWrapper = new QueryWrapper<TaskGroup>();
         queryWrapper.eq("project_id", item.getProjectId());
         if (taskGroupService.count(queryWrapper) == 0) {
@@ -410,7 +424,17 @@ public class TaskGroupController {
                 }
             }
         }
-        msg.data = taskGroupService.list(queryWrapper);
+        List<TaskGroup> list = taskGroupService.list(queryWrapper);
+        list.forEach(l->{
+            //todo:计算项目预算工时
+            if(l.getManDay()!=null){
+                BigDecimal bigDecimal=new BigDecimal(l.getManDay());
+                bigDecimal=bigDecimal.multiply(new BigDecimal(timeType.getAllday()));
+                String format = String.format("%.1f", bigDecimal.doubleValue());
+                l.setEstimatedWorkTime(format);
+            }
+        });
+        msg.data = list;
         return msg;
     }
 

+ 20 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/GroupBudgetReview.java

@@ -108,6 +108,26 @@ public class GroupBudgetReview extends Model<GroupBudgetReview> {
     @TableField("reject_reason")
     private String rejectReason;
 
+    /**
+     * 变更前预估工时
+     * */
+    @TableField(exist = false)
+    private String oldEstimatedWorkTime;
+
+    /**
+     * 预估工时变更
+     * */
+    @TableField(exist = false)
+    private String changeEstimatedWorkTime;
+
+    /**
+     * 变更后预估工时
+     * */
+    @TableField(exist = false)
+    private String nowEstimatedWorkTime;
+
+
+
 
     @Override
     protected Serializable pkVal() {

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Project.java

@@ -355,7 +355,7 @@ public class Project extends Model<Project> {
      * 项目人天
      */
     @TableField("man_day")
-    private Integer manDay;
+    private Double manDay;
 
     /**
      * 项目人天管控开始日期

+ 7 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TaskGroup.java

@@ -62,7 +62,7 @@ public class TaskGroup extends Model<TaskGroup> {
      * 预估工时:人天
      */
     @TableField("man_day")
-    private Integer manDay;
+    private Double manDay;
 
     @TableField(exist = false)
     private String uuid;
@@ -70,6 +70,12 @@ public class TaskGroup extends Model<TaskGroup> {
     @TableField(exist = false)
     private String projectIds;
 
+    /**
+     * 预估工时
+     * */
+    @TableField(exist = false)
+    private String estimatedWorkTime;
+
 
     @Override
     protected Serializable pkVal() {

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

@@ -49,7 +49,7 @@ public interface ProjectService extends IService<Project> {
                             String providerIds,
                             String providerNames,
                             HttpServletRequest request,
-                            ProjectSeparate projectSeparate,Double outputValue,Integer deptId,boolean onlyChangeParticipate,String buId,Integer manDay,String manDayStartDate,String plate1,
+                            ProjectSeparate projectSeparate,Double outputValue,Integer deptId,boolean onlyChangeParticipate,String buId,Double manDay,String manDayStartDate,String plate1,
                             String plate2,
                             String plate3,
                             String plate4,

+ 29 - 21
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java

@@ -315,7 +315,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                     .mapToDouble(r->r.getWorkingTime()).sum();
             String rWorkTime=reallWorkTime==null ? "0":df.format(reallWorkTime);
             project.setReallyWorkTime(rWorkTime);
-            String pEstimatedWork=project.getManDay()==null ? 0*allday+"": project.getManDay()*allday+"";
+            String pEstimatedWork=Integer.valueOf(String.valueOf(project.getManDay()))==null ? 0*allday+"": project.getManDay()*allday+"";
             project.setEstimatedWorkTime(pEstimatedWork);
             List<TaskGroup> taskGroupCollect = taskGroups.stream().filter(t -> t.getProjectId().equals(project.getId())).collect(Collectors.toList());
 
@@ -699,7 +699,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                    String providerIds,
                                    String providerNames,
                                    HttpServletRequest request,
-                                   ProjectSeparate projectSeparate,Double outputValue,Integer deptId,boolean onlyChangeParticipate,String buId,Integer manDay,String  manDayStartDate,String plate1,
+                                   ProjectSeparate projectSeparate,Double outputValue,Integer deptId,boolean onlyChangeParticipate,String buId,Double manDay,String  manDayStartDate,String plate1,
                                    String plate2,
                                    String plate3,
                                    String plate4,
@@ -2231,6 +2231,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
     public HttpRespMsg detail(Integer id, HttpServletRequest request) {
         User user = userMapper.selectById(request.getHeader("token"));
         Integer companyId = user.getCompanyId();
+        TimeType timeType = timeTypeMapper.selectById(companyId);
         Project project = projectMapper.selectById(id);
         List<Department> departmentList = departmentMapper.selectList(new QueryWrapper<Department>().eq("company_id", companyId));
         if (project.getInchargerId() != null) {
@@ -2257,6 +2258,13 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         } else {
             participator = participationMapper.getParticipator(id);
         }
+        //todo:计算项目预算工时
+        if(project.getManDay()!=null){
+            BigDecimal bigDecimal=new BigDecimal(project.getManDay());
+            bigDecimal=bigDecimal.multiply(new BigDecimal(timeType.getAllday()));
+            String format = String.format("%.1f", bigDecimal.doubleValue());
+            project.setEstimatedWorkTime(format);
+        }
         List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId).eq("is_active", 1));
         project.setParticipationList(participator);
         //项目日报审核人
@@ -4598,7 +4606,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                     first= userList.stream().filter(u ->(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))||(optional.isPresent()&&u.getCorpwxUserid()!=null&&u.getCorpwxUserid().equals(optional.get().getCorpwxUserid()))).findFirst();
                                     exception=1;
                                 }else {
-                                    first= userList.stream().filter(u -> u.getName().equals(split[0])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
+                                    first= userList.stream().filter(u -> u.getName().equals(split[1])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
                                 }
                             }
                             if (first.isPresent()) {
@@ -4607,7 +4615,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                             } else {
                                 switch (exception){
                                     case 0:throw new Exception("["+split[0]+"]在系统中不存在");
-                                    case 1:throw new Exception("["+split[0]+"]在系统中不存在");
+                                    case 1:throw new Exception("["+split[1]+"]在系统中不存在");
                                 }
                             }
                         }
@@ -4748,7 +4756,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                     first= userList.stream().filter(u ->(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))||(optional.isPresent()&&u.getCorpwxUserid()!=null&&u.getCorpwxUserid().equals(optional.get().getCorpwxUserid()))).findFirst();
                                     exception=1;
                                 }else {
-                                    first= userList.stream().filter(u -> u.getName().equals(split[0])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
+                                    first= userList.stream().filter(u -> u.getName().equals(split[1])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
                                 }
                             }
                             Participation p = new Participation();
@@ -4759,7 +4767,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                             } else {
                                 switch (exception){
                                     case 0:throw new Exception("["+split[0]+"]在系统中不存在");
-                                    case 1:throw new Exception("["+split[0]+"]在系统中不存在");
+                                    case 1:throw new Exception("["+split[1]+"]在系统中不存在");
                                 }
                             }
                         }
@@ -4795,7 +4803,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                         first= userList.stream().filter(u ->(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))||(optional.isPresent()&&u.getCorpwxUserid()!=null&&u.getCorpwxUserid().equals(optional.get().getCorpwxUserid()))).findFirst();
                                         exception=1;
                                     }else {
-                                        first= userList.stream().filter(u -> u.getName().equals(split[0])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
+                                        first= userList.stream().filter(u -> u.getName().equals(split[1])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
                                     }
                                 }
                                 if (first.isPresent()) {
@@ -4809,7 +4817,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                 } else {
                                     switch (exception){
                                         case 0:throw new Exception("["+split[0]+"]在系统中不存在");
-                                        case 1:throw new Exception("["+split[0]+"]在系统中不存在");
+                                        case 1:throw new Exception("["+split[1]+"]在系统中不存在");
                                     }
                                 }
                             }
@@ -4862,7 +4870,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                         first= userList.stream().filter(u ->(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))||(optional.isPresent()&&u.getCorpwxUserid()!=null&&u.getCorpwxUserid().equals(optional.get().getCorpwxUserid()))).findFirst();
                                         exception=1;
                                     }else {
-                                        first= userList.stream().filter(u -> u.getName().equals(split[0])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
+                                        first= userList.stream().filter(u -> u.getName().equals(split[1])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
                                     }
                                 }
                                 if (first.isPresent()) {
@@ -4877,7 +4885,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                 } else {
                                     switch (exception){
                                         case 0:throw new Exception("["+split[0]+"]在系统中不存在");
-                                        case 1:throw new Exception("["+split[0]+"]在系统中不存在");
+                                        case 1:throw new Exception("["+split[1]+"]在系统中不存在");
                                     }
                                 }
                             }
@@ -4929,7 +4937,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                         first= userList.stream().filter(u ->(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))||(optional.isPresent()&&u.getCorpwxUserid()!=null&&u.getCorpwxUserid().equals(optional.get().getCorpwxUserid()))).findFirst();
                                         exception=1;
                                     }else {
-                                        first= userList.stream().filter(u -> u.getName().equals(split[0])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
+                                        first= userList.stream().filter(u -> u.getName().equals(split[1])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
                                     }
                                 }
                                 if (first.isPresent()) {
@@ -4944,7 +4952,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                 } else {
                                     switch (exception){
                                         case 0:throw new Exception("["+split[0]+"]在系统中不存在");
-                                        case 1:throw new Exception("["+split[0]+"]在系统中不存在");
+                                        case 1:throw new Exception("["+split[1]+"]在系统中不存在");
                                     }
                                 }
                             }
@@ -5394,7 +5402,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                             } else {
                                 switch (exception){
                                     case 0:throw new Exception("["+split[0]+"]在系统中不存在");
-                                    case 1:throw new Exception("["+split[0]+"]在系统中不存在");
+                                    case 1:throw new Exception("["+split[1]+"]在系统中不存在");
                                 }
                             }
                         }
@@ -5987,7 +5995,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                 first= userList.stream().filter(u ->(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))||(optional.isPresent()&&u.getCorpwxUserid()!=null&&u.getCorpwxUserid().equals(optional.get().getCorpwxUserid()))).findFirst();
                                 exception=1;
                             }else {
-                                first= userList.stream().filter(u -> u.getName().equals(split[0])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
+                                first= userList.stream().filter(u -> u.getName().equals(split[1])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
                             }
                         }
                         Participation p = new Participation();
@@ -5998,7 +6006,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                         } else {
                             switch (exception){
                                 case 0:throw new Exception("["+split[0]+"]在系统中不存在");
-                                case 1:throw new Exception("["+split[0]+"]在系统中不存在");
+                                case 1:throw new Exception("["+split[1]+"]在系统中不存在");
                             }
                         }
                     }
@@ -6032,7 +6040,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                         first= userList.stream().filter(u ->(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))||(optional.isPresent()&&u.getCorpwxUserid()!=null&&u.getCorpwxUserid().equals(optional.get().getCorpwxUserid()))).findFirst();
                                         exception=1;
                                     }else {
-                                        first= userList.stream().filter(u -> u.getName().equals(split[0])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
+                                        first= userList.stream().filter(u -> u.getName().equals(split[1])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
                                     }
                                 }
                                 Participation p = new Participation();
@@ -6047,7 +6055,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                 } else {
                                     switch (exception){
                                         case 0:throw new Exception("["+split[0]+"]在系统中不存在");
-                                        case 1:throw new Exception("["+split[0]+"]在系统中不存在");
+                                        case 1:throw new Exception("["+split[1]+"]在系统中不存在");
                                     }
                                 }
                             }
@@ -6099,7 +6107,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                         first= userList.stream().filter(u ->(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))||(optional.isPresent()&&u.getCorpwxUserid()!=null&&u.getCorpwxUserid().equals(optional.get().getCorpwxUserid()))).findFirst();
                                         exception=1;
                                     }else {
-                                        first= userList.stream().filter(u -> u.getName().equals(split[0])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
+                                        first= userList.stream().filter(u -> u.getName().equals(split[1])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
                                     }
                                 }
                                 ProjectAuditor p = new ProjectAuditor();
@@ -6115,7 +6123,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                 } else {
                                     switch (exception){
                                         case 0:throw new Exception("["+split[0]+"]在系统中不存在");
-                                        case 1:throw new Exception("["+split[0]+"]在系统中不存在");
+                                        case 1:throw new Exception("["+split[1]+"]在系统中不存在");
                                     }
                                 }
                             }
@@ -6167,7 +6175,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                         first= userList.stream().filter(u ->(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))||(optional.isPresent()&&u.getCorpwxUserid()!=null&&u.getCorpwxUserid().equals(optional.get().getCorpwxUserid()))).findFirst();
                                         exception=1;
                                     }else {
-                                        first= userList.stream().filter(u -> u.getName().equals(split[0])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
+                                        first= userList.stream().filter(u -> u.getName().equals(split[1])&&(u.getJobNumber()!=null&&u.getJobNumber().equals(split[1]))).findFirst();
                                     }
                                 }
                                 ProjectCcuser p = new ProjectCcuser();
@@ -6183,7 +6191,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                 } else {
                                     switch (exception){
                                         case 0:throw new Exception("["+split[0]+"]在系统中不存在");
-                                        case 1:throw new Exception("["+split[0]+"]在系统中不存在");
+                                        case 1:throw new Exception("["+split[1]+"]在系统中不存在");
                                     }
                                 }
                             }

+ 17 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/BeiSenUtils.java

@@ -31,6 +31,23 @@ import java.util.*;
 public class BeiSenUtils {
     static String port="10.1.10.41:20170";
 
+    public static class KeyInfo{
+        String clientName;
+        String key;
+        String secret;
+        String token;
+        LocalDateTime tokenTime;
+    }
+    public static HashMap customerKeySource = new HashMap();
+
+    static {
+        KeyInfo 景昱医疗科技 = new KeyInfo();
+        景昱医疗科技.clientName="景昱医疗科技";
+        景昱医疗科技.key="70FD83474FB946E5A6A122BB2989E8D9";
+        景昱医疗科技.secret="F494856D0BCC49D18C63429D4F2CB42EDE9480D5C075449E9C97E7AEA5C7D9E1";
+        customerKeySource.put("景昱医疗科技", 景昱医疗科技);
+    }
+
     public static void main(String[] args) {
         BeiSenUtils dockWithMLD=new BeiSenUtils();
         JSONObject jsonObject=new JSONObject();

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml

@@ -1902,7 +1902,7 @@
         IFNULL(SUM(te.plan_hours),0) AS planHour
         FROM task_executor te
         LEFT JOIN task t ON t.id=te.task_id
-        LEFT JOIN USER u ON te.executor_id=u.id
+        LEFT JOIN user u ON te.executor_id=u.id
         LEFT JOIN task_group tg ON tg.id=t.group_id
         LEFT JOIN project p ON p.id=tg.project_id
         LEFT JOIN department d ON d.department_id=u.department_id

+ 1 - 1
fhKeeper/formulahousekeeper/management-workshop/src/main/resources/application.yml

@@ -15,7 +15,7 @@ spring:
       location: C:/upload/
   datasource:
     driver-class-name: com.mysql.cj.jdbc.Driver
-    url: jdbc:mysql://47.101.180.183:17089/man_workshop_lew?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&useSSL=false
+    url: jdbc:mysql://47.101.180.183:17089/man_workshop_lew_real?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&useSSL=false
     username: root
     password: P011430@Huoshi*
     hikari:

+ 3 - 3
fhKeeper/formulahousekeeper/timesheet/src/views/project/budgetReview.vue

@@ -99,7 +99,7 @@
                 <template slot-scope="scope">
                     <div>
                         <span>
-                            {{ scope.row.oldManDay }}
+                            {{ scope.row.oldManDay }}人天 / {{ scope.row.oldEstimatedWorkTime }}小时
                         </span>
                     </div>
                 </template>
@@ -109,7 +109,7 @@
                 <template slot-scope="scope">
                     <div>
                         <span>
-                            {{ scope.row.changeManDay }}
+                            {{ scope.row.changeManDay }}人天 / {{ scope.row.changeEstimatedWorkTime }}小时
                         </span>
                     </div>
                 </template>
@@ -119,7 +119,7 @@
                 <template slot-scope="scope">
                     <div>
                         <span>
-                            {{ scope.row.nowManDay }}
+                            {{ scope.row.nowManDay }}人天 / {{ scope.row.nowEstimatedWorkTime }}小时
                         </span>
                     </div>
                 </template>

+ 8 - 2
fhKeeper/formulahousekeeper/timesheet/src/views/project/list.vue

@@ -634,7 +634,8 @@
                     <!-- 增加项目人天字段 绎维固定字段 -->
                     <el-form-item  v-if="user.timeType.projectManDay == 1 && (user.company.nonProjectSimple == 0 || (user.company.nonProjectSimple == 1 && addForm.isPublic == 0))">
                         <template slot="label"><span v-if="manDaySetting.projectManDayFillMode == 2 || (manDaySetting.projectManDayFillMode == 1 && addForm.fromOutside == 0)" style="padding:5px;color:red;">*</span>项目人天</template>
-                        <el-input v-model.number="addForm.manDay" :placeholder="$t('peaseenterthe')" @input="jisuanEstimatedWorkTime(addForm.manDay)"  style="width: 100px"></el-input><span style="margin-left:10px;position:absolute;">人天(预估工时:{{this.estimatedWorkTime}}h)</span>
+                        <el-input v-model.number="addForm.manDay" :placeholder="$t('peaseenterthe')" @input="jisuanEstimatedWorkTime(addForm.manDay)"  style="width: 100px"></el-input>
+                        <span style="margin-left:10px;position:absolute;">人天(预估工时:<el-input size="small" v-model.number="addForm.estimatedWorkTime" :placeholder="$t('peaseenterthe')" @input="jisuanManDay(addForm.estimatedWorkTime)"  style="width: 100px"></el-input>h)</span>
                         <el-tooltip effect="dark" :content="$t('根据系统基础设置每日正常工作时长计算,1人天为一个每日正常工作时长')" placement="top-start" style="margin-left:180px">
                                         <i class="el-icon-question" style="color:#606266"></i>
                         </el-tooltip>
@@ -4996,6 +4997,7 @@ a {
                     if (res.code == "ok") {
                         this.chulishuju(res.data)
                         this.estimatedWorkTime=res.data.estimatedWorkTime==null?0:res.data.estimatedWorkTime
+                        this.addForm.estimatedWorkTime=res.data.estimatedWorkTime==null?0:res.data.estimatedWorkTime
                     }
                     });
                     //编辑时,非 (管理全部项目,项目创建人,项目经理),有编辑项目参与人权限的人,可以进行参与人的修改
@@ -5770,7 +5772,11 @@ a {
 
             //计算预估工时
             jisuanEstimatedWorkTime(manDay){
-                this.estimatedWorkTime=manDay*this.user.timeType.allday
+                this.addForm.estimatedWorkTime=manDay*this.user.timeType.allday
+            },
+            //计算预估工时
+            jisuanManDay(estimatedWorkTime){
+                this.addForm.manDay=estimatedWorkTime/this.user.timeType.allday
             },
             getProjectList(){
                 this.http.post(this.port.project.list,{

+ 48 - 10
fhKeeper/formulahousekeeper/timesheet/src/views/project/projectInside.vue

@@ -1146,18 +1146,24 @@
             </div>
         </el-dialog>
         
-        <el-dialog title="设置分组预估工时" v-if="modGroupManDayDialog" :visible.sync="modGroupManDayDialog" :close-on-click-modal="false" customClass="customWidth" width="500px">
+        <el-dialog title="设置分组预估工时" v-if="modGroupManDayDialog" :visible.sync="modGroupManDayDialog" :close-on-click-modal="false" customClass="customWidth" width="600px">
             <el-table :data="groupList" :key="modGroupManDayKey" size="small" :height="'400px'" show-summary="true">
                 <el-table-column prop="name" label="分组名称">
                 </el-table-column>
-                <el-table-column prop="manDay" width="200" label="预估工时" >
+                <el-table-column prop="manDay" width="200" label="预估工时(人天)" >
                     <template slot-scope="scope">
-                        <el-input v-model="scope.row.manDay" type="number" :placeholder="$t('peaseenterthe')" maxlength="10" :max="99999" style="width:120px;" :disabled="scope.row.disabled"></el-input>&nbsp;人天&nbsp;
+                        <el-input v-model="scope.row.manDay" type="number" @input="jisuanEstimatedWorkTime(scope.row.manDay,scope.row.id)" :placeholder="$t('peaseenterthe')" maxlength="10" :max="99999" style="width:120px;" :disabled="scope.row.disabled"></el-input>&nbsp;人天&nbsp;
+                        <!-- <i v-if="user.companyId=3092 && scope.row.disabled"  @click="changeBudget(scope.row)"  class="el-icon-circle-plus-outline"></i> -->
+                    </template>
+                </el-table-column>
+                <el-table-column prop="estimatedWorkTime" width="200" label="预估工时(小时)" >
+                    <template slot-scope="scope">
+                        <el-input v-model="scope.row.estimatedWorkTime" type="number"  @input="jisuanManDay(scope.row.estimatedWorkTime,scope.row.id)" :placeholder="$t('peaseenterthe')" maxlength="10" :max="99999" style="width:120px;" :disabled="scope.row.disabled"></el-input>&nbsp;小时&nbsp;
                         <i v-if="user.companyId=3092 && scope.row.disabled"  @click="changeBudget(scope.row)"  class="el-icon-circle-plus-outline"></i>
                     </template>
                 </el-table-column>
             </el-table>
-            <p style="text-align:center;">当前项目预估工时为:{{ currentProject.manDay == null? 0:currentProject.manDay }}人天</p>
+            <p style="text-align:center;">当前项目预估工时为:{{ currentProject.manDay == null? 0:currentProject.manDay }}人天 {{ currentProject.estimatedWorkTime == null? 0:currentProject.estimatedWorkTime }}小时</p>
             <div slot="footer" class="dialog-footer">
                 <el-button type="primary" @click="setManDayData()" style="width:100%;" >{{ $t('save') }}</el-button>
             </div>
@@ -1165,11 +1171,12 @@
 
         <el-dialog title="预估工时变更" v-if="changeBudgetDig" :visible.sync="changeBudgetDig" :close-on-click-modal="false" customClass="customWidth" width="500px">
             <el-form :model="groupBudgetData" label-width="120px">
-                <el-form-item :label="'原预估工时'"><span>{{groupBudgetData.manDay}}{{ '人天' }}</span></el-form-item>
+                <el-form-item :label="'原预估工时'"><span>{{groupBudgetData.manDay}}{{ '人天' }} / {{groupBudgetData.estimatedWorkTime}}{{ '小时' }}</span></el-form-item>
                 <el-form-item :label="'预估工时修改'" prop="changeManDay">
-                   <el-input v-model="groupBudgetData.changeManDay" type="number" @change="changeNowManDay(groupBudgetData)" :placeholder="$t('peaseenterthe')" maxlength="10" :max="99999" style="width:120px;"></el-input>&nbsp;人天
+                   <el-input v-model="groupBudgetData.changeManDay"  type="number"  @input="changeNowManDay(groupBudgetData)" :placeholder="$t('peaseenterthe')" maxlength="10" :max="99999" style="width:120px;"></el-input>&nbsp;人天
+                   <el-input v-model="groupBudgetData.changeEstimatedWorkTime"  type="number" @input="changeEstimatedWorkTime(groupBudgetData)" :placeholder="$t('peaseenterthe')" maxlength="10" :max="99999" style="width:120px;"></el-input>&nbsp;小时
                 </el-form-item>
-                <el-form-item :label="'变更后预估工时'"><span>{{nowManDay}}{{'人天'}}</span></el-form-item>
+                <el-form-item :label="'变更后预估工时'"><span>{{nowManDay}}{{'人天'}} / {{nowEstimatedWorkTime}}{{'小时'}}</span></el-form-item>
                 <el-form-item :label="'变更理由'">
                     <el-input
                         type="textarea"
@@ -1525,6 +1532,7 @@
                 changeBudgetDig:false,
                 groupBudgetData:{},
                 nowManDay:0,
+                nowEstimatedWorkTime:0,
 
                 modGroupManDayKey: 1
             };
@@ -2702,7 +2710,28 @@
                             });
                         });
             },
-                  
+            //计算预估工时
+            jisuanEstimatedWorkTime(manDay,groupId){
+                if(groupId){
+                    this.groupList.forEach(item=>{
+                        if(item.id==groupId){
+                            item.estimatedWorkTime=manDay*this.user.timeType.allday
+                        }
+                    })
+                }
+                
+            },
+            //计算预估工时
+            jisuanManDay(estimatedWorkTime,groupId){
+                if(groupId){
+                    this.groupList.forEach(item=>{
+                        if(item.id==groupId){
+                            item.manDay=estimatedWorkTime/this.user.timeType.allday
+                        }
+                    })
+                }
+            
+            },    
             toggleGroup() {
                 if (this.groupWidth == 0) {
                     this.groupWidth = 260;
@@ -2934,11 +2963,20 @@
                 this.changeBudgetDig=true,
                 this.groupBudgetData=task,
                 this.nowManDay=(this.groupBudgetData.changeManDay==null?0:parseInt(this.groupBudgetData.changeManDay))+(this.groupBudgetData.manDay==null?0:parseInt(this.groupBudgetData.manDay))
+                this.nowEstimatedWorkTime=(this.groupBudgetData.changeEstimatedWorkTime==null?0:parseInt(this.groupBudgetData.changeEstimatedWorkTime))+(this.groupBudgetData.estimatedWorkTime==null?0:parseInt(this.groupBudgetData.estimatedWorkTime))
             },
             //预估工时变更
             changeNowManDay(task){
-                console.log(task)
-                this.nowManDay=(this.groupBudgetData.changeManDay==null?0:parseInt(this.groupBudgetData.changeManDay))+(this.groupBudgetData.manDay==null?0:parseInt(this.groupBudgetData.manDay))
+                this.nowManDay=(this.groupBudgetData.changeManDay==null||this.groupBudgetData.changeManDay==''?0:parseInt(this.groupBudgetData.changeManDay))+(this.groupBudgetData.manDay==null||this.groupBudgetData.manDay==''?0:parseInt(this.groupBudgetData.manDay))
+                this.groupBudgetData.changeEstimatedWorkTime=(this.groupBudgetData.changeManDay==null||this.groupBudgetData.changeManDay==''?0:this.groupBudgetData.changeManDay)*this.user.timeType.allday
+                this.nowEstimatedWorkTime=this.nowManDay*this.user.timeType.allday
+                
+            },
+            //预估工时变更
+            changeEstimatedWorkTime(task){
+                this.nowEstimatedWorkTime=(this.groupBudgetData.changeEstimatedWorkTime==null||this.groupBudgetData.changeEstimatedWorkTime==''?0:parseInt(this.groupBudgetData.changeEstimatedWorkTime))+(this.groupBudgetData.estimatedWorkTime==null||this.groupBudgetData.estimatedWorkTime==''?0:parseInt(this.groupBudgetData.estimatedWorkTime))
+                this.groupBudgetData.changeManDay=(this.groupBudgetData.changeEstimatedWorkTime==null||this.groupBudgetData.changeEstimatedWorkTime==''?0:this.groupBudgetData.changeEstimatedWorkTime)/this.user.timeType.allday
+                this.nowManDay=this.nowEstimatedWorkTime/this.user.timeType.allday
             },
             changeBudgetTrue(groupBudgetData){
                 let param;

+ 16 - 16
fhKeeper/formulahousekeeper/timesheet/src/views/task/list.vue

@@ -21,6 +21,16 @@
                     ></el-cascader>
                 </el-form-item>
 
+                <el-form-item :label="'部门'" v-if="!user.timeType.projectWithDept">
+                    <div style="margin-left: 8px">
+                        <el-cascader v-if="user.userNameNeedTranslate != 1" v-model="screenDeptId" :placeholder="$t('defaultText.pleaseChoose')" style="width: 125px"
+                        :options="departmentList" :props="{ checkStrictly: true,expandTrigger: 'hover' }" :show-all-levels="false" clearable
+                        @change="getList()" size="mini"></el-cascader>
+
+                        <vueCascader :size="'mini'" :widthStr="'125'" :clearable="true" :subject="departmentList" :radios="true" :distinction="'1'" @vueCasader="vueCasader" v-if="user.userNameNeedTranslate == 1"></vueCascader>
+                    </div>
+                </el-form-item>
+
                 <el-form-item :label="$t('types')">
                     <div style="margin-left: 8px">
                         <el-select v-model="typeField" style="width:120px;" size="small" slot="prepend" :placeholder="$t('defaultText.pleaseChoose')" clearable @change="hiddens()">
@@ -39,16 +49,6 @@
                     </div>
                 </el-form-item>
 
-                <el-form-item :label="'部门'">
-                    <div style="margin-left: 8px">
-                        <el-cascader v-if="user.userNameNeedTranslate != 1" v-model="screenDeptId" :placeholder="$t('defaultText.pleaseChoose')" style="width: 125px"
-                        :options="departmentList" :props="{ checkStrictly: false,expandTrigger: 'hover' }" :show-all-levels="false" clearable
-                        @change="getList()" size="mini"></el-cascader>
-
-                        <vueCascader :size="'mini'" :widthStr="'125'" :clearable="true" :subject="departmentList" :radios="false" :distinction="'1'" @vueCasader="vueCasader" v-if="user.userNameNeedTranslate == 1"></vueCascader>
-                    </div>
-                </el-form-item>
-
                 <el-form-item :label="'任务分组'">
                     <div style="margin-left: 8px">
                         <el-select v-model="screenTaskGroupingId" style="width:150px;" size="small" :disabled="!screenProjectId" slot="prepend" :placeholder="$t('defaultText.pleaseChoose')" clearable @change="hiddens()">
@@ -112,6 +112,11 @@
                             {{scope.$index+1+(page-1)*size}} 
                         </template>
                     </el-table-column>
+                    <el-table-column prop="projectName" :label="$t('headerTop.projectName')" sortable width="260" show-overflow-tooltip>
+                        <template slot-scope="scope">
+                            <el-link type="primary" :href="'#/projectInside/'+scope.row.projectId">{{scope.row.projectName}}</el-link>
+                        </template>
+                    </el-table-column>
                     <el-table-column prop="stagesName" :label="$t('taskstage')" sortable width="180" @mouseover="mouseOver">
                     </el-table-column>
                     <el-table-column prop="taskLevel" label="优先级" sortable width="100">
@@ -165,11 +170,6 @@
                     </el-table-column>
                     
                     <el-table-column prop="startDate" :label="$t('starttimes')" sortable width="180"></el-table-column>
-                    <el-table-column prop="projectName" :label="$t('headerTop.projectName')" sortable width="260" show-overflow-tooltip>
-                        <template slot-scope="scope">
-                            <el-link type="primary" :href="'#/projectInside/'+scope.row.projectId">{{scope.row.projectName}}</el-link>
-                        </template>
-                    </el-table-column>
                     <el-table-column prop="endDate" :label="$t('deadline')" width="310" fixed="right" sortable>
                         <template slot-scope="scope">
                             <div style="display: flex;justify-content: space-between;padding-right: 40px">
@@ -2003,7 +2003,7 @@ import { error } from 'dingtalk-jsapi';
                 });
             },
 
-            vueCasader() {
+            vueCasader(obj) {
                 if(obj.distinction == '1') {
                     if(obj.id != '') {
                         let arr = []