Prechádzať zdrojové kódy

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

zhouyy 2 mesiacov pred
rodič
commit
51918f33cd
100 zmenil súbory, kde vykonal 2412 pridanie a 371 odobranie
  1. 179 0
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/components/common/treeSelect/selectTree.vue
  2. 245 0
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/components/common/treeSelect/tree.vue
  3. 1 0
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/login.vue
  4. 4 2
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/business/addEditor.vue
  5. 13 11
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/business/businessInfo.vue
  6. 10 6
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/business/detail.vue
  7. 7 6
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/business/relatedBusinessOpportunities.vue
  8. 4 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/contacts/detail.vue
  9. 210 16
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/contract/addEditor.vue
  10. 15 4
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/contract/detail.vue
  11. 4 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/customer/detail.vue
  12. 4 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/order/orderInfo.vue
  13. 4 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/product/detail.vue
  14. 4 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/tasks/addEditor.vue
  15. 4 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/tasks/detail.vue
  16. 3 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/thread/threadInfo.vue
  17. 3 2
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/tabbar/home/component/businessEcharts.vue
  18. 8 7
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/tabbar/home/component/dataSummary.vue
  19. 4 3
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/tabbar/home/component/salesBriefings.vue
  20. 3 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/utility/defaultData.js
  21. 3 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/utility/generalVariables.js
  22. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm-h5/vite.config.js
  23. BIN
      fhKeeper/formulahousekeeper/customerBuler-crm/node_modules.zip
  24. 4 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/TaskModal/api.ts
  25. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/translationComponent/treeSelect/treeSelect.vue
  26. 11 10
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/analysis/index.vue
  27. 6 3
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/api.ts
  28. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/attachment.vue
  29. 5 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/deteleTables.vue
  30. 8 6
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/information.vue
  31. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/operationRecord.vue
  32. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/products.vue
  33. 3 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/detail/index.vue
  34. 16 13
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/index.vue
  35. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/component/attachment.vue
  36. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/component/information.vue
  37. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/component/operationRecord.vue
  38. 9 7
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/component/relatedBusiness.vue
  39. 182 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contract/component/addEditorTwo.vue
  40. 34 7
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contract/index.vue
  41. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/attachment.vue
  42. 5 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/information.vue
  43. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/operationRecord.vue
  44. 9 7
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/relatedBusiness.vue
  45. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/relatedContacts.vue
  46. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/relatedOrders.vue
  47. 1 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/login.vue
  48. 3 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/api.ts
  49. 4 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/information.vue
  50. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/operationRecord.vue
  51. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/products.vue
  52. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/rebate.vue
  53. 5 3
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/index.vue
  54. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/information.vue
  55. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/operationRecord.vue
  56. 5 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/relatedBusiness.vue
  57. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/relatedSalesOrder.vue
  58. 4 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/index.vue
  59. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/module/BatchOperation.vue
  60. 6 4
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/thread/detail/components/information.vue
  61. 1 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/type.d.ts
  62. 4 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/utils/tools.ts
  63. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/vite.config.ts
  64. 1 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/constant/Constant.java
  65. 17 3
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/BusinessOpportunityController.java
  66. 4 2
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ContractController.java
  67. 12 1
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ContractPaymentController.java
  68. 16 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/SysFormController.java
  69. 5 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/Company.java
  70. 8 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/Contract.java
  71. 36 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/ContractPayment.java
  72. 42 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/vo/ContractVo.java
  73. 8 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/mapper/ContractMapper.java
  74. 2 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/ContractService.java
  75. 16 4
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/BusinessOpportunityServiceImpl.java
  76. 467 33
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ContractServiceImpl.java
  77. 11 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/PermissionServiceImpl.java
  78. 31 17
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/SysFormServiceImpl.java
  79. 28 9
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java
  80. 2 1
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/CompanyMapper.xml
  81. 198 2
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/ContractMapper.xml
  82. 6 1
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/ContractPaymentMapper.xml
  83. 10 7
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java
  84. 18 4
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TaskController.java
  85. 2 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/WeiXinCorpController.java
  86. 7 6
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Task.java
  87. 3 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DingDingServiceImpl.java
  88. 10 4
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ExpenseSheetServiceImpl.java
  89. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  90. 56 54
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TaskMapper.xml
  91. 3 2
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  92. 10 10
      fhKeeper/formulahousekeeper/timesheet-workshop/config/index.js
  93. 3 13
      fhKeeper/formulahousekeeper/timesheet/config/index.js
  94. 3 0
      fhKeeper/formulahousekeeper/timesheet/src/components/taskComponent.vue
  95. 29 2
      fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/list.vue
  96. 14 10
      fhKeeper/formulahousekeeper/timesheet/src/views/expense/expense.vue
  97. 167 10
      fhKeeper/formulahousekeeper/timesheet/src/views/leave/list.vue
  98. 8 0
      fhKeeper/formulahousekeeper/timesheet_h5/src/router/index.js
  99. 81 10
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/exaLeave/applyLeave.vue
  100. 0 0
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/expense/customizedDetail.vue

+ 179 - 0
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/components/common/treeSelect/selectTree.vue

@@ -0,0 +1,179 @@
+<template>
+  <van-popup v-model:show="showPicker" round position="bottom"  @click-overlay="onClickOverlay" >
+    <div class="tree-box">
+      <div class="tree-container">
+        <div class="tree-data">
+          <TreeSelect
+            ref="treeSelectRef"
+            :list="data.list"
+            :listObj="data.listObj"
+            :multiple="multiple"
+            :configurationItem="configurationItem"
+            @confirm="onConfirm"
+          ></TreeSelect>
+        </div>
+      </div>
+    </div>
+
+    <div class="tree-confirm">
+      <van-button type="primary" block @click="handleConfirm">确定</van-button>
+    </div>
+  </van-popup>
+</template>
+ 
+<script setup>
+import { reactive, watch, ref, nextTick, onMounted } from "vue";
+import TreeSelect from "./tree.vue";
+import { showLoadingToast, closeToast } from "vant";
+
+const emits = defineEmits(["changeModelValue", "update:show", "confirm"]);
+const props = defineProps({
+  show: {
+    type: Boolean,
+    default: false,
+  },
+  // 绑定值
+  modelValue: {
+    type: Array,
+     default() {
+      return [];
+    },
+  },
+  multiple: {
+    type: Boolean,
+    default: false,
+  },
+  listData: {
+    type: Array,
+    default() {
+      return [];
+    },
+  },
+  // 配置项 默认为 label, value, children
+  configurationItem: {
+    type: Object,
+    default() {
+      return {
+        label: "label",
+        value: "value",
+        children: "children",
+      };
+    },
+  }
+});
+
+watch(
+  () => props.show,
+  () => {
+    showPicker.value = props.show;
+    initData(props.listData);
+  }
+);
+
+const showPicker = ref(props.show);
+const data = reactive({
+  list: props.listData, // 树数组
+  listObj: {}, // 数组对象
+  selectList: [], // 选中的数据
+  canCheckList: [], // 能够选择的数据集合
+  canCheckListFixed: [], // 固定的能够选择的数据集合
+});
+
+const treeSelectRef = ref(null);
+
+const init = (type) => {
+  data.canCheckList = [];
+  data.canCheckListFixed = [];
+};
+const initData = (options) => {
+  if (options && options.length) {
+    options[0].first=true
+    data.list = options;
+    init();
+    data.listObj = setListObj(options);
+  }
+};
+
+// 将树形数据转为扁平对象
+const setListObj = (list) => {
+  let listObj = {};
+  list.forEach((itm) => {
+    if(props.modelValue&&props.modelValue.indexOf(itm.id)!==-1){
+       itm.checked=true
+    }
+    data.canCheckList.push(itm);
+    data.canCheckListFixed.push(itm);
+    listObj[itm.id] = itm;
+    if (itm.children && itm.children.length) {
+      listObj = {
+        ...listObj,
+        ...setListObj(itm.children),
+      };
+    }
+  });
+
+  return listObj;
+};
+
+const onClickOverlay = () => {
+  emits("update:show", false);
+};
+// 确认
+const handleConfirm = () => {
+  emits("changeModelValue", data.selectList);
+  emits("update:show", false);
+};
+
+const onConfirm = (e) => {
+  const showSelectList = filterData(e);
+  console.log(showSelectList, '<==== showSelectList')
+  console.log(props.configurationItem.value)
+  data.selectList = showSelectList.map((itm) => itm[props.configurationItem.value]);
+  console.log(data.selectList, '<===== showSelectList')
+};
+
+// 过滤数据
+const filterData = (selectList) => {
+  // 过滤出展示中,且打勾的数据
+  const showSelectList = selectList.filter((itm) => {
+    return !itm.isHide && !itm.isShowChildren;
+  });
+  return showSelectList;
+};
+
+const sendWordShow = ref(false);
+
+defineExpose({
+  init,
+  setListObj,
+});
+</script>
+ 
+<style lang="scss" scoped>
+.tree-box {
+  --van-search-content-background-color: #eeeeee;
+  --van-search-content-background: #eeeeee;
+}
+
+.tree-container {
+  width: 100%;
+  padding: 32px 32px 0;
+}
+
+.tree-data {
+  height: 60vh;
+  overflow-y: auto;
+}
+
+.tree-btns {
+  width: 100%;
+  margin-bottom: 24px;
+  display: flex;
+  align-items: center;
+}
+
+.tree-confirm {
+  width: 100%;
+  padding: 12px 32px;
+}
+</style>

+ 245 - 0
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/components/common/treeSelect/tree.vue

@@ -0,0 +1,245 @@
+<template>
+  <div class="list">
+    <div class="item" v-for="item in props.list" :key="item[configurationItem.value]" v-show="!item.isHide">
+      <div class="title">
+        <div class="checkbox-box">
+          <van-checkbox  icon-size="16px" shape="square" @click.stop="checkChange(item)" v-model="item.checked">
+            <span style="font-size: 15px;">
+              {{ item[configurationItem.label]}}
+            </span>
+          </van-checkbox>
+        </div>
+        <div @click.stop="itemClick(item)" :class="item.first?'arrow':'arrowlast'">
+            <van-icon v-if="item[configurationItem.children] && item[configurationItem.children].length" :name="item.isShowChildren ? 'arrow-up' : 'arrow-down'" />
+        </div>
+        
+      </div>
+      <div class="tree" v-show="item.first||item.isShowChildren">
+        <tree  
+         :isLink="data.isLink"
+          v-if="item.children && item.children.length" 
+          :list="item.children" 
+          :listObj="props.listObj"
+          :isFirstFloor="false" 
+          :multiple="data.multiple" 
+          @confirm="onConfirm" 
+          :defaultId="defaultId">
+        </tree>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup>
+import { reactive, watch } from 'vue'
+import tree from './tree.vue'
+const emits = defineEmits(["change","confirm"])
+const props = defineProps({
+  // 是否是第一层
+  isFirstFloor: {
+    type: Boolean,
+    default() {
+      return true;
+    },
+  },
+  // 树形结构
+  list: {
+    type: Array,
+    default() {
+      return [];
+    },
+  },
+  multiple: {
+    type: Boolean,
+    default() {
+      return false;
+    },
+  },
+  // 树形扁平化数据
+  listObj: {
+    type: Object,
+    default() {
+      return {};
+    },
+  },
+  // 配置项 默认为 label, value, children
+  configurationItem: {
+    type: Object,
+    default() {
+      return {
+        label: "label",
+        value: "value",
+        children: "children",
+      };
+    },
+  },
+  // 单选默认值
+  defaultId : String
+})
+
+ 
+const data = reactive({
+  firstLoad: true,
+  checkboxValue1: [],
+  showList: [],
+  isLink: true,
+  multiple: true,
+  isOutData: true, // 需要将数据抛出
+})
+ 
+watch(() => props.list, () => {
+  if (data.firstLoad) {
+    outDataBuffer();
+    data.firstLoad = false;
+  }
+  // 判断 是第一层树 且 不是进行显示隐藏操作时,进行数据的抛出
+  if (props.isFirstFloor && data.isOutData) {
+    if(data.multiple){
+      outCheckedData();
+    }
+  }
+}, { deep: true })
+ 
+// 展开
+const itemClick = (item) => {
+  outDataBuffer();
+  item.isShowChildren = !item.isShowChildren
+  
+}
+// 数据抛出缓冲(在list数据变化时,不想抛出选择的数据时,调用该方法)
+const outDataBuffer = () => {
+  data.isOutData = false;
+  setTimeout(() => {
+    data.isOutData = true;
+  }, 500);
+}
+// 获取选中对象
+const getCheckData = (list) => {
+  let deptList = [];
+  list.forEach((itm) => {
+    if (itm.checked) {
+      deptList.push(itm);
+    }
+    if (itm.children && itm.children.length) {
+      deptList = deptList.concat(getCheckData(itm.children));
+    }
+  });
+  return deptList;
+}
+// 单项checked改变
+const checkChange = (item) => {
+
+  // 多选
+  if (data.multiple) {
+    // item.checked = !item.checked
+    if (data.isLink) {
+      // 展开所有可以展开的节点
+      if (item.checked) {
+          expandAll(item);
+      }
+  
+      // 勾选子级
+      if (item.children && item.children.length) {
+        checkChidren(item.children, item.checked);
+        outCheckedData();
+      }
+    }
+    return
+  }
+ 
+  // 单选
+  if(item.children && item.children.length) return
+  toggleAllSelectData(props.list)
+  outCheckedData();
+
+}
+ 
+// 获取全部可选择数据,进行全选/取消
+const toggleAllSelectData = (list) => {
+  list.forEach((itm) => {
+    itm.checked = false
+    if (itm.children && itm.children.length) {
+      toggleAllSelectData(itm.children)
+    }
+  });
+}
+ 
+// 展开所有可以展开的节点
+const expandAll = (item) => {
+  if (item.children?.length) {
+    item.isShowChildren = true
+    item.children.forEach(itm => {
+      expandAll(itm);
+    })
+  }
+}
+
+
+
+// 根据父级统一取消勾选或勾选
+const checkChidren = (list, isChecked) => {
+  list.forEach((itm) => {
+    itm.checked = isChecked
+    if (itm.children && itm.children.length) {
+      checkChidren(itm.children, isChecked);
+    }
+  });
+}
+// 抛出选中的数据
+const outCheckedData = () => {
+  const checkedList = getCheckData(props.list);
+  emits("change", checkedList);
+  onConfirm(checkedList)
+}
+ 
+const onConfirm = (e) => {
+  emits("confirm", e);
+}
+ 
+defineExpose({
+  itemClick,
+  outDataBuffer,
+  getCheckData,
+  checkChange,
+  expandAll,
+  // checkParent,
+  checkChidren,
+  outCheckedData,
+
+})
+</script>
+ 
+<style lang="scss" scoped>
+ 
+.list {
+  .item {
+    margin-bottom: 10px;
+ 
+    .title {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin-bottom: 10px;
+ 
+      .checkbox-box {
+        display: flex;
+        align-items: center;
+        cursor: pointer;
+        padding: 10px 0;
+      }
+ 
+      .arrow{
+        width: 80px;
+        display: flex;
+        justify-content: flex-end;
+      }
+    }
+ 
+    .tree {
+      margin-left: 50px;
+    }
+  }
+    .arrow{
+    display: none !important;
+   }
+}
+</style>

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

@@ -149,6 +149,7 @@ function bindIfNessary() {
 // 登陆前的处理
 function loginProcessing(data = {}) {
   sessionStorage.setItem('token', data.id)
+  sessionStorage.setItem('isExistBusiness', data.company.isExistBusiness || 0)
   userInfo.updateState({
     userInfo: data,
     token: data.id,

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

@@ -1,7 +1,7 @@
 <template>
   <div class="w-full h-full flex flex-col">
     <div class="flex-1 overflow-y-auto">
-      <FoldingPanel :title="Object.keys(formVal).length > 0 ? '修改商机' : '新建商机'">
+      <FoldingPanel :title="Object.keys(formVal).length > 0 ? `修改${businessLabel}` : `新建${businessLabel}`">
         <template #foldContainer>
           <CustomerForm ref="formFormRef" :formJson="formJson" :formValue="formVal"></CustomerForm>
         </template>
@@ -50,6 +50,8 @@ const props = defineProps({
   formValue: { required: true },
 });
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const { toastText, toastSuccess, toastFail, toastLoading } = useToast()
 const formFormRef = ref(null)
 const formVal = ref({})
@@ -108,7 +110,7 @@ function judgmentaAmounteEqual(mob, arr) {
   console.log(amounte, totalAmounte)
 
   if (amounte != totalAmounte) {
-    toastText(`商机金额${amounte > totalAmounte ? '大于' : '小于'}产品总金额,${amounte > totalAmounte ? '保存中...' : '请修改'}`)
+    toastText(`${businessLabel}金额${amounte > totalAmounte ? '大于' : '小于'}产品总金额,${amounte > totalAmounte ? '保存中...' : '请修改'}`)
     flag = true;
   }
 

+ 13 - 11
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/business/businessInfo.vue

@@ -1,16 +1,16 @@
 <template>
   <div class="flex flex-col h-full">
     <div class="bg-white info flex-1 overflow-y-auto cellnormall">
-      <van-cell title="商机名称" :value="infoData.name" />
+      <van-cell :title="`${businessLabel}名称`" :value="infoData.name" />
       <van-cell title="客户名称" :value="infoData.customerName" />
       <van-cell title="联系人姓名" :value="infoData.contactsName" />
-      <van-cell title="商机金额">
+      <van-cell :title="`${businessLabel}金额`">
         <template #default>
           <span class="text-[#FF8B32]" v-if="infoData.amountOfMoney">¥ {{ infoData.amountOfMoney }}</span>
         </template>
       </van-cell>
       <van-cell title="预计成交" :value="infoData.expectedTransactionDate" />
-      <van-cell title="商机阶段" :value="infoData.stageValue" />
+      <van-cell :title="`${businessLabel}阶段`" :value="infoData.stageValue" />
       <van-cell title="负责人">
         <template #default>
           <TranslationComponent :openId="infoData.inchargerName" />
@@ -22,22 +22,22 @@
       <van-button type="primary" class="w-full block" v-if="!infoData.contactsName"
         @click="shoContactDialag()">关联联系人</van-button>
       <van-button type="warning" class="w-full block" v-if="infoData.inchargerName"
-        @click="showDialogCli()">转移商机</van-button>
+        @click="showDialogCli()">转移{{ businessLabel }}</van-button>
       <van-button type="primary" class="w-full block" v-if="!infoData.inchargerName"
-        @click="claimAndClaim()">认领商机</van-button>
-      <van-button type="default" class="w-full block" v-permission="[routingInformation.jurisdiction.edit]" @click="jumpEdit()">编辑商机</van-button>
-      <van-button type="danger" class="w-full block" v-permission="[routingInformation.jurisdiction.delete]" @click="deleteBusinessOpportunity()">删除商机</van-button>
+        @click="claimAndClaim()">认领{{ businessLabel }}</van-button>
+      <van-button type="default" class="w-full block" v-permission="[routingInformation.jurisdiction.edit]" @click="jumpEdit()">编辑{{ businessLabel }}</van-button>
+      <van-button type="danger" class="w-full block" v-permission="[routingInformation.jurisdiction.delete]" @click="deleteBusinessOpportunity()">删除{{ businessLabel }}</van-button>
     </div>
 
     <!-- 转移弹窗 -->
-    <van-dialog v-model:show="showDialog" :title="`转移商机`" show-cancel-button @confirm="confirmTransfer"
+    <van-dialog v-model:show="showDialog" :title="`转移${businessLabel}`" show-cancel-button @confirm="confirmTransfer"
       :before-close="dialogCloseBefo">
       <van-cell title="转移至" is-link @click="showSelect = true">
         <template #value>
           <TranslationComponent :openId="dialogSelection.label" />
         </template>
       </van-cell>
-      <div class="themeTextColor text-size-small pl-4 pt-2 pb-2">转移后,将看不到此商机了</div>
+      <div class="themeTextColor text-size-small pl-4 pt-2 pb-2">转移后,将看不到此{{ businessLabel }}了</div>
     </van-dialog>
 
     <van-dialog v-model:show="showContactDialog" :title="`关联联系人`" show-cancel-button @confirm="relatedContacts"
@@ -86,6 +86,8 @@ const props = defineProps({
 })
 const infoData = ref(props.info)
 const routingInformation = routingInfos['business']
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 
 watch(() => props.info, (newValue) => {
   infoData.value = newValue
@@ -176,8 +178,8 @@ function confirmTransfer() {
 
 function claimAndClaim() {
   showConfirmDialog({
-    title: '认领商机',
-    message: `确定认领【${props.info.name}】商机吗?`,
+    title: `认领${businessLabel}`,
+    message: `确定认领【${props.info.name}】${businessLabel}吗?`,
   }).then(() => {
     requests.post(BUSINESS_OPPORTUNITY_TRANSFER, { ids: props.info.id, inchargerId: userInfo.userInfo.id }).then((res) => {
       toastSuccess('认领成功')

+ 10 - 6
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/business/detail.vue

@@ -1,10 +1,10 @@
 <template>
   <div class="w-full h-full">
     <van-tabs v-model:active="tabActive">
-      <van-tab title="商机阶段" name="商机阶段">
+      <van-tab :title="`${businessLabel}阶段`" :name="`${businessLabel}阶段`">
         <BusinessOpportunityStage :info="infoData" @chnage="refreshData()" />
       </van-tab>
-      <van-tab title="商机信息" name="商机信息">
+      <van-tab :title="`${businessLabel}信息`" :name="`${businessLabel}信息`">
         <BusinessInfo :info="infoData" />
       </van-tab>
       <van-tab title="相关产品" name="相关产品">
@@ -36,14 +36,18 @@ const props = defineProps({
     default: () => ({})
   }
 })
-const tabActive = ref('商机信息');
+
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
+const tabActive = ref(`${businessLabel}信息`);
 const relatedProductsList = ref([]);
 const relatedTasksList = ref([]);
 const infoData = ref(props.info);
 const timeout = ref(null);
 
+
 watch(() => props.info, (newValue) => {
-  tabActive.value = '商机信息';
+  tabActive.value = `${businessLabel}信息`;
   processingData(newValue.id)
 })
 
@@ -73,11 +77,11 @@ function processingData(id) {
 
 useLifecycle({
   init: () => {
-    tabActive.value = '商机信息';
+    tabActive.value = `${businessLabel}信息`;
     processingData(props.info.id)
   },
   load: () => {
-    tabActive.value = '商机信息';
+    tabActive.value = `${businessLabel}信息`;
     processingData(props.info.id)
   },
   unLoad: () => {

+ 7 - 6
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/business/relatedBusinessOpportunities.vue

@@ -2,23 +2,23 @@
   <div class="flex flex-col h-full overflow-y-auto">
     <div class="info h-full cellnormall" v-if="infoListData.length">
       <div v-for="(item, index) in infoListData">
-        <FoldingPanel :title="`相关商机(${item.name})`">
+        <FoldingPanel :title="`相关${businessLabel}(${item.name})`">
           <template #foldContainer>
             <div class="p-5 bg-white ">
-              <van-cell title="商机名称" :value="item.name" />
+              <van-cell :title="`${businessLabel}名称`" :value="item.name" />
               <van-cell title="客户名称" :value="item.customerName" />
               <van-cell title="负责人">
                 <template #default>
                   <TranslationComponent :openId="item.inchargerName" />
                 </template>
               </van-cell>
-              <van-cell title="商机金额" :value="item.amountOfMoney">
+              <van-cell :title="`${businessLabel}金额`" :value="item.amountOfMoney">
                 <template #default>
                   <span class="text-[#FF8B32]" v-if="item.amountOfMoney">¥ {{ item.amountOfMoney }}</span>
                 </template>
               </van-cell>
               <van-cell title="预计成交时间" :value="item.expectedTransactionDate" />
-              <van-cell title="商机阶段" :value="item.stageValue" />
+              <van-cell :title="`${businessLabel}阶段`" :value="item.stageValue" />
               <van-cell title="预计成交时间" :value="item.creatorName" />
             </div>
           </template>
@@ -26,7 +26,7 @@
       </div>
     </div>
     <div v-else class="items-justify-center h-2/3">
-      <van-empty description="暂无商机" />
+      <van-empty :description="`暂无${businessLabel}`" />
     </div>
   </div>
 </template>
@@ -44,7 +44,8 @@ const props = defineProps({
     default: () => ([])
   }
 })
-
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const infoListData = ref(props.infoList);
 
 watch(() => props.infoList, (newValue) => {

+ 4 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/contacts/detail.vue

@@ -7,7 +7,7 @@
       <van-tab title="相关任务" name="相关任务">
         <RelatedTasks :infoList="relatedTasksList" />
       </van-tab>
-      <van-tab title="相关商机" name="相关商机">
+      <van-tab :title="`相关${businessLabel}`" :name="`相关${businessLabel}`">
         <RelatedBusinessOpportunities :infoList="relatedBusinessOpportunitiesList"  />
       </van-tab>
     </van-tabs>
@@ -38,6 +38,9 @@ const relatedTasksList = ref([]);
 const infoData = ref(props.info);
 const timeout = ref(null);
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
+
 watch(() => props.info, (newValue) => {
   tabActive.value = '联系人信息';
   processingData(newValue.id)

+ 210 - 16
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/contract/addEditor.vue

@@ -1,6 +1,12 @@
 <template>
   <div class="w-full h-full flex flex-col">
     <div class="flex-1 overflow-y-auto">
+      <van-field v-model="value" label="合同所属部门" placeholder="请选择" input-align="right" readonly
+        @click="showDepartmentSelection">
+        <template #input v-if="departmentRow.departmentName != ''">
+          <TranslationComponent type="departmentName" :openId="departmentRow.departmentName" />
+        </template>
+      </van-field>
       <CustomerForm ref="formFormRef" :formJson="formJson" :formValue="formVal"></CustomerForm>
       <template v-for="(item, index) in paymentPlanList">
         <FoldingPanel :title="`回款计划(${index + 1})`" class="mb-4">
@@ -19,17 +25,49 @@
                   </div>
                 </template>
               </van-cell>
-              <van-cell title="回款日期" @click="showDatePicker(index)">
+              <van-cell title="回款日期" @click="showDatePicker(index, 'payDate')">
                 <template #default>
-                  <van-field v-model="item.payDate" input-align="right" placeholder="请选择日期" class="resetStyles" readonly />
+                  <van-field v-model="item.payDate" input-align="right" placeholder="请选择日期" class="resetStyles"
+                    readonly />
                 </template>
               </van-cell>
-              <van-cell title="回款金额">
+              <van-cell title="金额(含税)">
                 <template #default>
                   <van-field v-model="item.amount" type="digit" input-align="right" placeholder="请输入金额"
                     class="resetStyles" />
                 </template>
               </van-cell>
+              <van-cell title="是否已开票">
+                <template #default>
+                  <div class="flex justify-end">
+                    <van-checkbox v-model="item.isBilled">已开票</van-checkbox>
+                  </div>
+                </template>
+              </van-cell>
+              <van-cell title="开票日期" @click="showDatePicker(index, 'billDate')">
+                <template #default>
+                  <van-field v-model="item.billDate" input-align="right" placeholder="请选择日期" class="resetStyles"
+                    readonly />
+                </template>
+              </van-cell>
+              <van-cell title="开票种类增值税" @click="showSelectTaxAmount(index)">
+                <template #default >
+                  <van-field v-model="item.invoiceTypeName" type="text" input-align="right" placeholder="请选择"
+                    class="resetStyles" readonly="" />
+                </template>
+              </van-cell>
+              <van-cell title="税率%">
+                <template #default>
+                  <van-field v-model="item.taxRate" type="digit" input-align="right" placeholder="请输入"
+                    class="resetStyles" @change="inputNumberChange(index)" />
+                </template>
+              </van-cell>
+              <van-cell title="税额">
+                <template #default>
+                  <van-field v-model="item.taxAmount" type="digit" input-align="right" placeholder="请输入"
+                    class="resetStyles" />
+                </template>
+              </van-cell>
             </div>
           </template>
         </FoldingPanel>
@@ -45,7 +83,48 @@
     <van-popup v-model:show="showPicker" destroy-on-close position="bottom" :style="{ height: '50%' }">
       <van-date-picker v-model="pickerValue" @confirm="showPickerConfirm" @cancel="showPicker = false" />
     </van-popup>
+
+    <!-- 部门选择 -->
+    <!-- <treeSelect
+      ref="treeSelectRef"
+      v-model:show="departmentShow"
+      :modelValue="departmentShow.departmentId"
+      :listData="options"
+      :multiple='false'
+      placeholder="请选择"
+      @changeModelValue="changeModelValue"
+      :configurationItem="{ label: 'label', value: 'id', children: 'children' }"
+    ></treeSelect> -->
+
+    <van-popup v-model:show="departmentShow" destroy-on-close position="bottom" :style="{ height: '85%' }">
+      <div class="selectDepartment">
+        <div class="w-full absolute top-12 z-10">
+          <van-tabs v-model:active="departmentRow.tabIndex" shrink scrollspy @click-tab="tabClick">
+            <van-tab v-for="item in tableSelectSelectionShowList">
+              <template #title>
+                <TranslationComponent type="departmentName" :openId="item.label" />
+              </template>
+            </van-tab>
+          </van-tabs>
+        </div>
+        <div class="soDept">
+          <van-cascader v-model="departmentRow.departmentId" ref="cascaderDeptRef" title="合同所属部门" :options="deptOptions"
+            @change="changeModelValue" @close="departmentShow = false" :field-names="fieldNames"
+            @finish="finishModelValue">
+            <template #option="{ option }">
+              <div>
+                <TranslationComponent type="departmentName" :openId="option.label" />
+              </div>
+            </template>
+          </van-cascader>
+        </div>
+      </div>
+    </van-popup>
   </div>
+
+  <van-popup v-model:show="showSelectTaxAmountShow" destroy-on-close position="bottom" :style="{ height: '50%' }">
+    <van-picker :columns="columns" @confirm="onConfirm" />
+  </van-popup>
 </template>
 
 <script setup>
@@ -61,6 +140,8 @@ import dayjs from 'dayjs';
 import commonUtil from "@utility/commonUtil"
 import { number } from 'echarts';
 
+import TreeSelect from "@components/common/treeSelect/selectTree.vue"
+
 const router = useRouterStore()
 const { toastText, toastSuccess, toastFail, toastLoading } = useToast()
 const props = defineProps({
@@ -74,6 +155,28 @@ const paymentPlanList = ref([{}])
 const showPicker = ref(false)
 const pickerValue = ref([])
 const rowIndex = ref(0)
+const departmentRow = ref({
+  departmentName: '',
+  departmentId: '',
+  sureDepartmentId: '',
+  tableSelect: ''
+})
+const departmentShow = ref(false)
+const deptOptions = ref([])
+const tableSelectSelectionShowList = ref([])
+const fieldNames = {
+  text: 'label',
+  value: 'id',
+  children: 'children',
+};
+const cascaderDeptRef = ref(null)
+const dataType = ref('payDate')
+const showSelectTaxAmountShow = ref(false)
+const selectIndex = ref(0)
+const columns = [
+  { text: '增值税专用发票', value: 0 },
+  { text: '增值税普通发票', value: 1 },
+]
 
 watch(() => formVal.value, (newValue) => {
   console.log(newValue, '<==== 看看')
@@ -81,10 +184,73 @@ watch(() => formVal.value, (newValue) => {
     paymentPlanList.value = [{}]
     return
   }
-
+  departmentRow.value = {
+    departmentName: newValue.departmentName,
+    departmentId: newValue.departmentId,
+    sureDepartmentId: newValue.departmentId,
+    tableSelect: ''
+  }
   getPaymentCollectionList(newValue.id)
 })
 
+function inputNumberChange(index) {
+  const { amount = 0, taxRate = 0, taxAmount = 0 } = paymentPlanList.value[index]
+  if(!amount && !amount) {
+    return
+  }
+
+  const shui = taxRate / 100
+  const zhi = amount / (1 + shui) * shui
+  paymentPlanList.value[index].taxAmount = +(zhi.toFixed(2))
+}
+
+function onConfirm(val) {
+  const selectedOptions = val.selectedOptions[0]
+  paymentPlanList.value[selectIndex.value].invoiceType = selectedOptions.value
+  paymentPlanList.value[selectIndex.value].invoiceTypeName = selectedOptions.text
+  showSelectTaxAmountShow.value = false
+}
+function showSelectTaxAmount(index) {
+  selectIndex.value = index
+  showSelectTaxAmountShow.value = true
+}
+
+function finishModelValue({ value, selectedOptions }) {
+  const row = selectedOptions.find(item => item.id == value)
+  departmentRow.value.sureDepartmentId = row.id
+  departmentRow.value.departmentName = row.label
+  departmentShow.value = false
+}
+
+function tabClick(name) {
+  const elements = cascaderDeptRef.value.$el.querySelectorAll('[role="tab"]');
+  elements[name.name].click()
+  tableSelectSelectionShowList.value.splice(name.name + 1, tableSelectSelectionShowList.value.length)
+}
+
+function changeModelValue({ value, selectedOptions, tabIndex }) {
+  const row = selectedOptions.find(item => item.id == value)
+  tableSelectSelectionShowList.value.push({
+    label: row.label,
+    index: tabIndex,
+    id: row.id
+  })
+  setTimeout(() => {
+    departmentRow.value.tabIndex = tableSelectSelectionShowList.value.length - 1
+  }, 200)
+}
+
+function showDepartmentSelection() {
+  tableSelectSelectionShowList.value = []
+  departmentRow.value.departmentId = ''
+  departmentShow.value = true
+}
+
+function obtainDepartmentalData() {
+  requests.post('/department/list', {}).then((res) => {
+    deptOptions.value = res.data
+  })
+}
 
 function onSubmit() {
   formFormRef.value.getJsonData().then((res) => {
@@ -93,33 +259,44 @@ function onSubmit() {
     }
     const determineArray = paymentPlanList.value.filter(item => item.isPayed || (item.payDate || item.amount))
     let totalNum = 0
-    for(let i in determineArray) {
+    for (let i in determineArray) {
       const row = determineArray[i]
-      if(!row.payDate) {
+      if (!row.payDate) {
         toastText('回款日期不能为空')
         return
       }
-      if(!row.amount || row.amount == 0) {
+      if (!row.amount || row.amount == 0) {
         toastText('回款金额不能为空和0')
         return
       }
       totalNum += Number(determineArray[i].amount)
-      if(formVal.value.id) {
+      if (formVal.value.id) {
         determineArray[i].contractId = formVal.value.id
       }
     }
 
-    if(totalNum > 0 && !res.data.amounts) {
+    if (totalNum > 0 && !res.data.amounts) {
       toastText('请输入合同金额')
       return
     }
-    if(totalNum > res.data.amounts) {
+    if (totalNum > res.data.amounts) {
       toastText('回款金额不能大于合同金额')
       return
     }
 
     toastLoading('保存中', 0)
-    requests.post(props.formValue?.id ? CONTRACT_EDITING : CONTRACT_ADDITION_EDITING, { ...commonUtil.getFromValue({ ...props.formValue, ...res.data, paymentListStr: JSON.stringify(determineArray || []) }) }).then(() => {
+    requests.post(props.formValue?.id ? CONTRACT_EDITING : CONTRACT_ADDITION_EDITING, { ...commonUtil.getFromValue({ 
+      ...props.formValue, 
+      ...res.data, 
+      paymentListStr: JSON.stringify((determineArray || []).map(item => {
+        delete item.invoiceTypeName
+        return {
+          ...item,
+          isBilled: item.isBilled ? 1 : 0
+        }
+      }))}),
+      departmentId: departmentRow.value.sureDepartmentId
+    }).then(() => {
       toastSuccess('保存成功')
       setTimeout(() => {
         router.navigateBack({
@@ -135,23 +312,30 @@ function onSubmit() {
 }
 
 function addPaymentCollection(index) {
-  paymentPlanList.value.splice(index + 1, 0, { isPayed: false, payDate: dayjs(new Date()).format('YYYY-MM-DD'), amount: null })
+  paymentPlanList.value.splice(index + 1, 0, { isPayed: false, payDate: dayjs(new Date()).format('YYYY-MM-DD'), amount: null, isBilled: true })
 }
 
 function deletePaymentCollection(index) {
   paymentPlanList.value.splice(index, 1)
 }
 
-function showDatePicker(index) {
-  const { payDate } = paymentPlanList.value[index];
+function showDatePicker(index, type) {
+  const { payDate, billDate } = paymentPlanList.value[index];
+  dataType.value = type
   rowIndex.value = index;
-  const currentDate = dayjs(payDate ? new Date(payDate) : new Date()).format('YYYY-MM-DD').split('-');
+  const dates = type == 'payDate' ? payDate : billDate
+  const currentDate = dayjs(dates ? new Date(dates) : new Date()).format('YYYY-MM-DD').split('-');
   pickerValue.value = currentDate;
   showPicker.value = true;
 }
 
 function showPickerConfirm({ selectedValues }) {
-  paymentPlanList.value[rowIndex.value].payDate = selectedValues.join("-");
+  if (dataType.value == 'payDate') {
+    paymentPlanList.value[rowIndex.value].payDate = selectedValues.join("-");
+  }
+  if (dataType.value == 'billDate') {
+    paymentPlanList.value[rowIndex.value].billDate = selectedValues.join("-");
+  }
   showPicker.value = false;
 }
 
@@ -165,10 +349,12 @@ useLifecycle({
   load: () => {
     formVal.value = props.formValue
     paymentPlanList.value = [{}]
+    obtainDepartmentalData()
   },
   init: () => {
     formVal.value = props.formValue
     paymentPlanList.value = [{}]
+    obtainDepartmentalData()
   }
 });
 
@@ -182,4 +368,12 @@ onActivated(() => {
 .resetStyles {
   padding: 0;
 }
+
+.soDept {
+  position: relative;
+
+  :deep(.van-tabs__nav--complete) {
+    display: none;
+  }
+}
 </style>

+ 15 - 4
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/contract/detail.vue

@@ -1,6 +1,13 @@
 <template>
   <div class="flex flex-col h-full">
     <div class="bg-white info flex-1 overflow-y-auto cellnormall">
+      <van-cell title="合同所属部门">
+        <template #default>
+          <span>
+            <TranslationComponent type="departmentName" :openId="infoData.departmentName" />
+          </span>
+        </template>
+      </van-cell>
       <van-cell title="合同编号" :value="infoData.number" />
       <van-cell title="合同名称" :value="infoData.name" />
       <van-cell title="合同金额" :value="infoData.amounts">
@@ -8,6 +15,11 @@
           <span class="text-[#FF8B32]" v-if="infoData.amounts">¥ {{ infoData.amounts }}</span>
         </template>
       </van-cell>
+      <van-cell title="开票金额" :value="infoData.invoicedAmount">
+        <template #default>
+          <span class="text-[#FF8B32]" v-if="infoData.invoicedAmount">¥ {{ infoData.invoicedAmount }}</span>
+        </template>
+      </van-cell>
       <van-cell title="已回款金额" :value="infoData.payment">
         <template #default>
           <span class="text-[#FF8B32]" v-if="infoData.payment">¥ {{ infoData.payment }}</span>
@@ -46,7 +58,7 @@
         <van-button type="danger" class="w-full block" @click="rejectOperation">驳回合同</van-button>
       </template>
       <van-button type="default" class="w-full block" v-permission="[routingInformation.jurisdiction.edit]"
-        @click="jumpEdit()">编辑合同</van-button>
+        @click="jumpEdit(infoData)">编辑合同</van-button>
       <van-button type="danger" class="w-full block" v-permission="[routingInformation.jurisdiction.delete]"
         @click="deleteRow()">删除合同</van-button>
     </div>
@@ -168,12 +180,11 @@ function deleteRow() {
   })
 }
 
-function jumpEdit() {
+function jumpEdit(row) {
   const formJson = fixedData.formJson[routingInformation.key] || []
   const formList = resetListData(formJson?.list)
   const filedObj = getListFieldKey(formList, infoData.value)
-  const formVal = { ...filedObj, id: props.info.id }
-
+  const formVal = { ...filedObj, id: props.info.id, departmentId: row.departmentId, departmentName: row.departmentName }
   router.navigateTo({
     pathName: 'addEditor',
     success: () => {

+ 4 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/customer/detail.vue

@@ -10,7 +10,7 @@
       <van-tab title="相关联系人" name="相关联系人">
         <RelatedContacts :infoList="relatedContactsList" />
       </van-tab>
-      <van-tab title="相关商机" name="相关商机">
+      <van-tab :title="`相关${businessLabel}`" :name="`相关${businessLabel}`">
         <RelatedBusinessOpportunities :infoList="relatedBusinessOpportunitiesList" />
       </van-tab>
       <van-tab title="相关销售订单" name="相关销售订单">
@@ -48,6 +48,9 @@ const relatedSalesOrdersList = ref([]);
 const infoData = ref(props.info)
 const timeout = ref(null);
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目";
+
 watch(() => props.info, (newValue) => {
   tabActive.value = '客户信息';
   processingData(newValue.id)

+ 4 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/order/orderInfo.vue

@@ -4,7 +4,7 @@
       <van-cell title="订单编号" :value="info.orderCode" />
       <van-cell title="订单名称" :value="info.orderName" />
       <van-cell title="客户名称" :value="info.customName" />
-      <van-cell title="商机名称" :value="info.businessOpportunityName" />
+      <van-cell :title="`${businessLabel}名称`" :value="info.businessOpportunityName" />
       <van-cell title="订单金额" :value="info.price">
         <template #default>
           <span class="text-[#FF8B32]" v-if="info.price">¥ {{ info.price }}</span>
@@ -103,6 +103,9 @@ const showDialog = ref(false);
 const showSelect = ref(false);
 const dialogSelection = ref({});
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
+
 function deleteRow() {
   const { name = '', searchFiled = {}, deteleFiled = '' } = routingInformation
   const row = props.info

+ 4 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/product/detail.vue

@@ -4,7 +4,7 @@
       <van-tab title="产品信息" name="产品信息">
         <ProductInfo :info="infoData" />
       </van-tab>
-      <van-tab title="相关商机" name="相关商机">
+      <van-tab :title="`相关${businessLabel}`" :name="`相关${businessLabel}`">
         <RelatedBusinessOpportunities :infoList="relatedBusinessOpportunitiesList"  />
       </van-tab>
       <van-tab title="相关销售订单" name="相关销售订单">
@@ -38,6 +38,9 @@ const relatedSalesOrdersList = ref([]);
 const infoData = ref(props.info);
 const timeout = ref(null);
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
+
 watch(() => props.info, (newValue) => {
   tabActive.value = '产品信息';
   processingData(newValue.id)

+ 4 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/tasks/addEditor.vue

@@ -28,7 +28,7 @@
         </template>
         <!-- 商机选择 -->
         <template v-if="vantFormVal.taskType == 1">
-          <van-field v-model="vantFormVal.businessOpportunityId" name="businessOpportunityId" label="商机"
+          <van-field v-model="vantFormVal.businessOpportunityId" name="businessOpportunityId" :label="`${businessLabel}`"
             placeholder="请选择" is-link readonly class="resetStyles"
             @click="showSelectionBox('businessOpportunityId', allBusinessOpportunities)">
             <template #input v-if="vantFormVal.businessOpportunityId">
@@ -229,6 +229,9 @@ const showSelectionToFlag = ref(false)
 const showSelectionToValue = ref([])
 const taskTypeFiled = ['customId', 'businessOpportunityId', 'orderId', 'clueId']
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
+
 const contactDisabled = computed(() => {
   const taskType = vantFormVal.value?.taskType
   if (!taskType && taskType != 0) {

+ 4 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/tasks/detail.vue

@@ -22,7 +22,7 @@
       <van-cell title="开始时间" :value="infoData.startDate" />
       <van-cell title="截至时间" :value="infoData.endDate" />
       <van-cell title="客户名称" :value="infoData.customName" v-if="infoData.customName" />
-      <van-cell title="商机名称" :value="infoData.businessName" v-if="infoData.businessName" />
+      <van-cell :title="`${businessLabel}名称`" :value="infoData.businessName" v-if="infoData.businessName" />
       <van-cell title="销售订单" :value="infoData.orderName" v-if="infoData.orderName" />
       <van-cell title="线索名称" :value="infoData.clueName" v-if="infoData.clueName" />
       <van-cell title="联系人名称" :value="infoData.contactsName" v-if="!infoData.clueId" />
@@ -107,6 +107,9 @@ const showEndtDelayData = ref('');
 const showDateType = ref('');
 const timeJudgment = ref(new Date())
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
+
 watch(() => props.info, (newValue) => {
   initializeData(newValue.id)
 })

+ 3 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/pageComponents/thread/threadInfo.vue

@@ -16,7 +16,7 @@
       <van-cell title="备注" :value="info.remark" />
     </div>
     <div class="bottomButton">
-      <van-button type="primary" class="w-full block" v-if="info.inchargerName && info.isBo != 1"  @click="transformBusinessOpportunities()">线索转商机</van-button>
+      <van-button type="primary" class="w-full block" v-if="info.inchargerName && info.isBo != 1"  @click="transformBusinessOpportunities()">线索转{{ businessLabel }}</van-button>
       <van-button type="warning" class="w-full block" v-if="info.inchargerName"  @click="showDialogCli()">转移线索</van-button>
       <van-button type="primary" class="w-full block" v-if="!info.inchargerName" @click="claimAndClaim()">认领线索</van-button>
       <van-button type="default" class="w-full block" v-permission="[routingInformation.jurisdiction.edit]" @click="jumpEdit()">编辑线索</van-button>
@@ -71,6 +71,8 @@ const routingInformation = routingInfos['thread']
 const showDialog = ref(false);
 const showSelect = ref(false);
 const dialogSelection = ref({});
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 
 function transformBusinessOpportunities() {
   const InfoJson = routingInfos['business']

+ 3 - 2
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/tabbar/home/component/businessEcharts.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="businessOpportunityStage box mt-4">
     <div class="box-title">
-      <div class="box-title-left text-size-in">商机阶段</div>
+      <div class="box-title-left text-size-in">{{ businessLabel }}阶段</div>
       <div class="box-title-right text-size-small" @click="showPopUpLayer()">
         {{ scopeText }}/{{ dateText }}
         <van-icon name="play" class="ml-2 rotate-90" color="#747474" />
@@ -46,7 +46,8 @@ const echartsOption = ref({})
 const scopeText = computed(() => {
   return fixedFieldPermissionOptions[filterCriteria.value.scopeSelection].label
 })
-
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const dateText = computed(() => {
   if(filterCriteria.value.dateSelection == -1) {
     const { customTime = [] } = filterCriteria.value

+ 8 - 7
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/tabbar/home/component/dataSummary.vue

@@ -32,27 +32,27 @@
       <div class="data-item flex flex-row bg-[#F8F8FA]">
         <img src="/src/assets/image/shangjihz.png" class="businessOpportunity-img">
         <div class="flex-1">
-          <div class="font-bold text-[#000]">商机汇总</div>
+          <div class="font-bold text-[#000]">{{ businessLabel }}汇总</div>
           <div class="flex mt-2">
             <div class="text-size-small text-[#999]" style="width: 40%;">
-              新增商机 <span class="ml-1 text-[#51C2FF]">
+              新增{{ businessLabel }} <span class="ml-1 text-[#51C2FF]">
                 {{ dataSummary?.businessOpportunityDataSummary?.newNum || 0 }}
               </span> 个
             </div>
             <div class="text-size-small text-[#999]" style="width: 60%;">
-              商机赢单 <span class="ml-1 text-[#51C2FF]">
+              {{ businessLabel }}赢单 <span class="ml-1 text-[#51C2FF]">
                 {{ dataSummary?.businessOpportunityDataSummary?.winning || 0 }}
               </span> 个
             </div>
           </div>
           <div class="flex mt-2">
             <div class="text-size-small text-[#999]" style="width: 40%;">
-              输单商机 <span class="ml-1 text-[#51C2FF]">
+              输单{{ businessLabel }} <span class="ml-1 text-[#51C2FF]">
                 {{ dataSummary?.businessOpportunityDataSummary?.losting || 0 }}
               </span> 个
             </div>
             <div class="text-size-small text-[#999]" style="width: 60%;">
-              商机总金额 <span class="ml-1 text-[#51C2FF]">
+              {{ businessLabel }}总金额 <span class="ml-1 text-[#51C2FF]">
                 {{ dataSummary?.businessOpportunityDataSummary?.allAmountOfMoney || 0 }}
               </span> 元
             </div>
@@ -71,7 +71,7 @@
               </span> 个
             </div>
             <div class="w-1/2 text-size-small text-[#999]">
-              线索转商机 <span class="ml-1 text-[#28C67E]">
+              线索转{{ businessLabel }} <span class="ml-1 text-[#28C67E]">
                 {{ dataSummary?.clueDataSummary?.changeNum || 0 }}
               </span> 个
             </div>
@@ -112,7 +112,8 @@ const filterCriteria = ref({
 const scopeText = computed(() => {
   return fixedFieldPermissionOptions[filterCriteria.value.scopeSelection].label
 })
-
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const dateText = computed(() => {
   if(filterCriteria.value.dateSelection == -1) {
     const { customTime = [] } = filterCriteria.value

+ 4 - 3
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/pages/tabbar/home/component/salesBriefings.vue

@@ -39,7 +39,7 @@
         <div class="item">
           <img src="/src/assets/image/salesKitlishi.png" class="item-img" />
           <div class="flex flex-col justify-center text=[#999999]">
-            <div>新增商机</div>
+            <div>新增{{ businessLabel }}</div>
             <div class="flex items-end">
               <span class="text-[#F3893C] text-size-in font-bold mr-1">
                 {{ salesBriefings?.businessOpportunity?.businessOpportunityCount || 0 }}
@@ -75,7 +75,7 @@
         <div class="item">
           <img src="/src/assets/image/salesKitshangji.png" class="item-img" />
           <div class="flex flex-col justify-center text=[#999999]">
-            <div>商机金额</div>
+            <div>{{ businessLabel }}金额</div>
             <div class="flex items-end">
               <span class="text-[#EED116] text-size-in font-bold mr-1">
                 {{ salesBriefings?.businessOpportunityPrice?.businessOpportunityPrice || 0 }}
@@ -127,7 +127,8 @@ const filterCriteria = ref({
   dateSelection: 0,
   customTime: []
 })
-
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const scopeText = computed(() => {
   return fixedFieldPermissionOptions[filterCriteria.value.scopeSelection].label
 })

+ 3 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/utility/defaultData.js

@@ -20,10 +20,12 @@ export const fixedFieldPriority = [
   { label: "低", value: 0 },
 ]
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 // 任务类型
 export const fixedFieldTaskType = [
   { label: "客户", value: 0, show: true },
-  { label: "商机", value: 1, show: true },
+  { label: businessLabel, value: 1, show: true },
   { label: "销售订单", value: 2, show: true },
   { label: "线索", value: 3, show: false },
 ]

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/src/utility/generalVariables.js


+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm-h5/vite.config.js

@@ -5,7 +5,7 @@ import Components from "unplugin-vue-components/vite";
 import { VantResolver } from "unplugin-vue-components/resolvers";
 import { postcssConfig } from "./postcss.config.js";
 
-// const target = 'http://192.168.2.7:10010';
+// const target = 'http://192.168.2.40:10099';
 // const target = 'http://192.168.2.3:10010';
 // const target = 'http://192.168.2.17:10010';
 const target = 'http://47.101.180.183:10014';

BIN
fhKeeper/formulahousekeeper/customerBuler-crm/node_modules.zip


+ 4 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/components/TaskModal/api.ts

@@ -28,10 +28,13 @@ export const PRIORITY = [
   { label: "低", value: 0 },
 ];
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
+
 export const TASK_TYPE = [
   // 弹窗任务类型
   { label: "客户", value: 0, show: true },
-  { label: "商机", value: 1, show: true },
+  { label: businessLabel, value: 1, show: true },
   { label: "销售订单", value: 2, show: true },
   { label: "线索", value: 3, show: false },
 ];

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

@@ -34,7 +34,7 @@ const props = defineProps({
 
 const { departmentList, userInfo } = storeToRefs(useStore());
 const { setValue } = useStore()
-const treeSelectVal = ref(props.modelValue); // 响应式绑定 v-model 的值
+const treeSelectVal = ref(props.modelValue || ''); // 响应式绑定 v-model 的值
 const treeSelectArray = ref<any>([]);
 const visibleFlag = ref(false);
 const selectLoading = ref(false);

+ 11 - 10
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/analysis/index.vue

@@ -19,7 +19,8 @@ import {
 } from './api';
 
 const dataAnalysisFlag = userInfo?.moduleList?.filter((item: any) => item.path == '/analysis') || []
-
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const permissionOptions = dataAnalysisFlag.length > 0 ? [
   {
     label: '仅本人',
@@ -251,7 +252,7 @@ watchEffect(() => {
             :compare="requestData?.bulletin?.contacts.contactsPromote"
           />
           <TrendCard
-            title="新增商机"
+            :title="`新增${businessLabel}`"
             unit="个"
             :selectVal="bulletinPrompt"
             :number="requestData?.bulletin?.businessOpportunity.businessOpportunityCount"
@@ -272,7 +273,7 @@ watchEffect(() => {
             :compare="requestData?.bulletin?.salesOrdersPrice.salesOrderPricePromote"
           />
           <TrendCard
-            title="商机金额"
+            :title="`${businessLabel}金额`"
             unit="元"
             :selectVal="bulletinPrompt"
             :number="requestData?.bulletin?.businessOpportunityPrice.businessOpportunityPrice"
@@ -355,25 +356,25 @@ watchEffect(() => {
               v-if="false"
             />
           </div>
-          <Divider title="商机汇总" />
+          <Divider :title="`${businessLabel}汇总`" />
           <div class="my-6 grid grid-cols-4 gap-2">
             <SimpleCard
-              title="新增商机"
+              :title="`新增${businessLabel}`"
               unit="个"
               :number="requestData.summary?.businessOpportunityDataSummary.newNum"
             />
             <SimpleCard
-              title="赢单商机"
+              :title="`赢单${businessLabel}`"
               unit="个"
               :number="requestData.summary?.businessOpportunityDataSummary.winning"
             />
             <SimpleCard
-              title="输单商机"
+              :title="`输单${businessLabel}`"
               unit="个"
               :number="requestData.summary?.businessOpportunityDataSummary.losting"
             />
             <SimpleCard
-              title="商机总金额"
+              :title="`${businessLabel}总金额`"
               unit="元"
               :number="requestData.summary?.businessOpportunityDataSummary.allAmountOfMoney"
             />
@@ -386,14 +387,14 @@ watchEffect(() => {
               :number="requestData.summary?.clueDataSummary.newNum"
             />
             <SimpleCard
-              title="线索转商机"
+              :title="`线索转${businessLabel}`"
               unit="个"
               :number="requestData.summary?.clueDataSummary.changeNum"
             />
           </div>
         </div>
         <div class="border-gray-200 border rounded p-3 flex-1">
-          <div class="text-sm font-medium">商机阶段</div>
+          <div class="text-sm font-medium">{{ `${businessLabel}阶段` }}</div>
           <div class="flex gap-3 mb-8 mt-2">
             <div class="w-40">
               <el-select

+ 6 - 3
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/api.ts

@@ -40,13 +40,16 @@ export const stageStatus = [
     { id: 3, name: "无效", progress: "0%" }
 ]
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
+
 export const tableColumn: businessTableColumnInterface[] = [
-    { prop: "name", label: "商机名称", width: "180", eventName: "toClueTableDetail" },
+    { prop: "name", label: `${businessLabel}名称`, width: "180", eventName: "toClueTableDetail" },
     { prop: "customerName", label: "客户名称", width: "180" },
     { prop: "contactsName", label: "联系人", width: "180", eventName: "showName" },
-    { prop: "amountOfMoney", label: "商机金额", width: "180" },
+    { prop: "amountOfMoney", label: `${businessLabel}金额`, width: "180" },
     { prop: "expectedTransactionDate", label: "预计成交时间", width: "180" },
-    { prop: "stageValue", label: "商机阶段", width: "180" },
+    { prop: "stageValue", label: `${businessLabel}阶段`, width: "180" },
     { prop: "inchargerName", label: "负责人", width: "180" },
     { prop: "creatorName", label: "创建人", width: "180" },
     { prop: "createTime", label: "创建时间", width: "180" }

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/attachment.vue

@@ -53,7 +53,7 @@
 import { ElMessageBox, UploadRequestOptions } from 'element-plus';
 import { post, uploadFile } from '@/utils/request';
 import { confirmAction, downloadFile } from '@/utils/tools';
-import { ref, reactive, onMounted, onUnmounted, defineEmits, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, defineEmits, inject, watchEffect } from 'vue'
 import { DETELEFILEFILE, REFIENAMEFILE, UPLOADFILEFILE } from '../api';
 import { formatDate } from '@/utils/times';
 

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

@@ -3,7 +3,7 @@
         top="10vh">
         <template #header="{ close, titleId, titleClass }">
             <div class="flex justify-between items-center border-b pb-3 dialog-header">
-                <h4 :id="titleId">商机回收站</h4>
+                <h4 :id="titleId">{{ businessLabel }}回收站</h4>
                 <div>
                     <el-button type="primary" v-loading="allLoading.batchRecoveryLoading" :disabled="batchTableData.length == 0"
                         @click="batchOperation('恢复')">批量恢复</el-button>
@@ -72,6 +72,9 @@ const tableForm = reactive({
     pageFrom: 10
 })
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
+
 const busiessTableRef = ref<InstanceType<typeof ElTable>>() // 线索table dom
 
 const props = defineProps<{
@@ -92,7 +95,7 @@ function batchOperation(type: operationType) {
 }
 
 function businessOperationItem(value: string | number, label: string, type: operationType, batch: boolean = false) {
-    confirmAction(`确定${batch ? '批量' : ''}${type}【${label}】商机吗?`).then(() => {
+    confirmAction(`确定${batch ? '批量' : ''}${type}【${label}】${businessLabel}吗?`).then(() => {
         let url = type == '恢复' ? BUSIESS_ROWBACK : BUSIESS_PERDETELE
         post(url, { ids: value }).then(res => {
             if (res.code != 'ok') {

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

@@ -12,7 +12,7 @@
         </div>
         <div class="form flex flex-wrap justify-between">
             <div class="formItem flex pt-3 pb-1">
-                <div class="w-20 text-right text-gray-500">商机名称:</div>
+                <div class="w-20 text-right text-gray-500">{{ businessLabel }}名称:</div>
                 <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1" v-ellipsis-tooltip>{{ information.name }}</div>
             </div>
             <div class="formItem flex pt-3 pb-1">
@@ -27,7 +27,7 @@
                 </div>
             </div>
             <div class="formItem flex pt-3 pb-1">
-                <div class="w-22 text-right text-gray-500">商机金额:</div>
+                <div class="w-22 text-right text-gray-500">{{ businessLabel }}金额:</div>
                 <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1" v-ellipsis-tooltip>{{ information.amountOfMoney || 0
                 }} 元</div>
             </div>
@@ -82,7 +82,7 @@
         <el-dialog v-model="allVisible.transferBusinessVisible" width="600" :show-close="false" top="10vh">
             <template #header="{ close, titleId, titleClass }">
                 <div class="flex justify-between items-center border-b pb-3 dialog-header">
-                    <h4 :id="titleId">{{ '转移商机' }}</h4>
+                    <h4 :id="titleId">转移{{ businessLabel }}</h4>
                     <div>
                         <el-button type="primary" :loading="allLoading.transferBusinessLoading"
                             @click="transferBusiness()">转移</el-button>
@@ -98,7 +98,7 @@
                     </el-select> -->
                     <personnel-search v-model="transferValue" :size="''" placeholder="请选择"></personnel-search>
                 </div>
-                <div class="pl-3 text-[#e94a4a]">转移后,将看不到此商机</div>
+                <div class="pl-3 text-[#e94a4a]">转移后,将看不到此{{ businessLabel }}</div>
             </div>
         </el-dialog>
 
@@ -126,7 +126,7 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { GenerateForm } from '@zmjs/form-design';
 import { get, post } from '@/utils/request';
 import { BATCHTRANSFER, GETGENERATEFOEM, GETPERSONNEL, UPDATEINSET, URL_SAVECONTACT } from '../api';
@@ -143,6 +143,8 @@ const props = defineProps<{
     information: any
 }>()
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const information = ref<any>({})
 const transferValue = ref('')
 const transferOptions = ref<personnelInterface[]>([])
@@ -212,7 +214,7 @@ function transferBusiness() {
 }
 
 function claimBusiness() {
-    confirmAction(`确定认领【${information.value.name}】商机吗?`).then(() => {
+    confirmAction(`确定认领【${information.value.name}】${businessLabel}吗?`).then(() => {
         transferBusiness()
     })
 }

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/operationRecord.vue

@@ -19,7 +19,7 @@
 </template>
 <script lang="ts" setup>
 import { formatDateMinutes } from '@/utils/times';
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 
 const props = defineProps<{
     information: any

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/products.vue

@@ -51,7 +51,7 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { GETTABLELIST } from '@/pages/product/api';
 import { post } from '@/utils/request';
 import router from '@/router';

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

@@ -3,7 +3,7 @@
     <div class="w-full bg-white p-2 mb-2 shadow-md rounded-md flex items-center">
       <div class="icon mr-4">
         <el-link :underline="false" @click="backPath()">
-          <el-icon class="el-icon--right"><icon-view /></el-icon> 返回商机列表
+          <el-icon class="el-icon--right"><icon-view /></el-icon> 返回{{ businessLabel }}列表
         </el-link>
       </div>
       <div class="mr-8">
@@ -123,6 +123,8 @@ type stageListType = {
   id?: number,
 }
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const route = useRoute()
 const globalPopup = inject<GlobalPopup>('globalPopup')
 const detailCompinentsData = ref([])

+ 16 - 13
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/index.vue

@@ -4,10 +4,10 @@
       <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="businessOpportunityForm" label-width="70px" style="max-width: 600px">
-            <el-form-item label="商机名称">
+            <el-form-item :label="`${businessLabel}名称`">
               <el-input v-model="businessOpportunityForm.name" clearable placeholder="请输入"></el-input>
             </el-form-item>
-            <el-form-item label="商机阶段">
+            <el-form-item :label="`${businessLabel}阶段`">
               <el-select v-model="businessOpportunityForm.stageId" placeholder="请选择" clearable>
                 <el-option v-for="item in fixedData.BusinessStage" :key="item.id" :label="item.name" :value="item.id" />
               </el-select>
@@ -58,7 +58,7 @@
           </div>
           <div class="justify-end flex">
             <el-button v-permission="['businessAddAnEdit']" type="primary"
-              @click="editNewBusiness(false)">新建商机</el-button>
+              @click="editNewBusiness(false)">新建{{ businessLabel }}</el-button>
             <el-button type="primary" @click="showVisible('batchTransferVisible')"
               :disabled="batchTableData.length <= 0">批量转移</el-button>
             <el-button type="primary" v-permission="['businessDelete']" @click="batchDeteleItem()"
@@ -163,7 +163,7 @@
           </el-select> -->
           <personnel-search v-model="transferPersonnel" :size="''" placeholder="请选择"></personnel-search>
         </div>
-        <div class="pl-3 text-[#e94a4a]">转移后,将看不到此商机</div>
+        <div class="pl-3 text-[#e94a4a]">转移后,将看不到此{{ businessLabel }}</div>
       </div>
     </el-dialog>
 
@@ -184,8 +184,8 @@
       <div class="p-8">
         <div class="ml-4 mr-4">
           <div class="flex items-center">1、点击下载 <el-link type="primary"
-              @click="downloadTemplate(MODURL, '商机导入模板.xlsx')">商机导入模板.xlsx</el-link></div>
-          <div class="mt-4">2、填写excel文件、商机名称、商机金额、商机阶段必填</div>
+              @click="downloadTemplate(MODURL, `${businessLabel}导入模板.xlsx`)">{{businessLabel}}导入模板.xlsx</el-link></div>
+          <div class="mt-4">2、填写excel文件、{{businessLabel}}名称、{{businessLabel}}金额、{{businessLabel}}阶段必填</div>
         </div>
       </div>
     </el-dialog>
@@ -222,6 +222,9 @@ import { GETTABLELISTPRODUCT } from "../order/api";
 import personnelSearch from '@/components/translationComponent/personnelSearch/personnelSearch.vue';
 import kanbanView from "./component/kanbanView.vue";
 
+
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const router = useRouter()
 const globalPopup = inject<GlobalPopup>('globalPopup')
 const businessTableRef = ref<InstanceType<typeof ElTable>>() // 商机table dom
@@ -254,8 +257,8 @@ const allVisible = reactive({
   importVisible: false
 })
 const allText = reactive({
-  newBusinessisibleText: '新建商机',
-  transferText: '转移商机'
+  newBusinessisibleText: `新建${businessLabel}`,
+  transferText: `转移${businessLabel}`
 }) // 所有文本
 
 const taskModalForm = ref({}) // 任务弹窗表单
@@ -326,14 +329,14 @@ function editNewBusiness(item: any) {
       allLoading.generateFormLading = true
       editProduct(item)
       businessTemplateValue.value = editBusinessData(item)
-      allText.newBusinessisibleText = '编辑商机'
+      allText.newBusinessisibleText = `编辑${businessLabel}`
     }
     if (!item) {
       businessTemplateRef.value && businessTemplateRef.value.reset()
       businessTemplate.value = businessTemplate.value
       businessTemplateValue.value = {}
       productTableListValue.value = []
-      allText.newBusinessisibleText = '新建商机'
+      allText.newBusinessisibleText = `新建${businessLabel}`
     }
   }, 0)
   setTimeout(() => {
@@ -382,7 +385,7 @@ function batchDeteleItem() {
 }
 
 function businessDeteleItem(value: string | number, label: string, batch: boolean = false) {
-  confirmAction(`确定${batch ? '批量' : ''}删除【${label}】商机吗?`).then(() => {
+  confirmAction(`确定${batch ? '批量' : ''}删除【${label}】${businessLabel}吗?`).then(() => {
     post(BUSINESSDETELE, { ids: value }).then(res => {
       if (res.code != 'ok') {
         globalPopup?.showError(res.msg)
@@ -405,7 +408,7 @@ async function importBusiness(param: UploadRequestOptions) {
     allLoading.importLoading = false
   })
   if (res.code == 'ok') {
-    globalPopup?.showSuccess('导入成功' || '')
+    globalPopup?.showSuccess('导入成功')
     searchForBusinessOpportunities()
     return
   }
@@ -416,7 +419,7 @@ function exportBusinessTableList() {
   allLoading.exoprtLoading = true
   let valueForm = getFromValue(businessOpportunityForm)
   post(URL_EXPORTBUSINESS, { ...valueForm }).then((res) => {
-    downloadFile(res.data, '商机表导出.xlsx')
+    downloadFile(res.data, `${businessLabel}表导出.xlsx`)
   }).finally(() => {
     allLoading.exoprtLoading = false
   })

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

@@ -53,7 +53,7 @@
 <script lang="ts" setup>
 import { post, uploadFile } from '@/utils/request';
 import { UploadRequestOptions } from 'element-plus';
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { URLFILEDETELE, URL_REFNAME, URL_UPLOADFILE } from '@/pages/api';
 import { downloadFile } from '@/utils/tools';
 

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

@@ -67,7 +67,7 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { GenerateForm } from '@zmjs/form-design';
 import { getFromValue, getTemplateKey } from '@/utils/tools';
 import { GETGENERATEFOEM, GETPERSONNEL, URL_TRANSFERCONTACTS, URL_UPLOAD } from '../api';

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

@@ -18,7 +18,7 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 const props = defineProps<{
     data: any
 }>()

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

@@ -1,14 +1,14 @@
 <template>
     <div class="relatedTasks pl-4 pr-4 pt-3 pb-3 h-full flex flex-col">
         <div class="flex justify-between">
-            <div class="title">相关商机</div>
+            <div class="title">相关{{ businessLabel }}</div>
             <div v-permission="['businessAddAnEdit']">
-                <el-button type="primary" @click="addBusiness()">新建商机</el-button>
+                <el-button type="primary" @click="addBusiness()">新建{{ businessLabel }}</el-button>
             </div>
         </div>
         <div class="flex-1 overflow-auto pt-3">
             <el-table :data="relatedTaskstable" border height="300" style="width: 100%;">
-                <el-table-column prop="name" label="商机名称">
+                <el-table-column prop="name" :label="`${businessLabel}名称`">
                     <template #default="scope">
                         <el-button link type="primary" size="large" @click="toBusDetal(scope.row)">{{
                             scope.row.name
@@ -21,9 +21,9 @@
                         <TextTranslation translationTypes="userName" :translationValue="scope.row.inchargerName"></TextTranslation>
                     </template>
                 </el-table-column>
-                <el-table-column prop="amountOfMoney" label="商机金额" width="130" />
+                <el-table-column prop="amountOfMoney" :label="`${businessLabel}金额`" width="130" />
                 <el-table-column prop="expectedTransactionDate" label="预计成交时间" width="170" />
-                <el-table-column prop="stageValue" label="商机阶段" width="130" />
+                <el-table-column prop="stageValue" :label="`${businessLabel}阶段`" width="130" />
                 <el-table-column prop="creatorName" label="创建人" width="130">
                     <template #default="scope">
                         <TextTranslation translationTypes="userName" :translationValue="scope.row.creatorName"></TextTranslation>
@@ -38,7 +38,7 @@
         <el-dialog v-model="allVisible.newBusinessisible" width="1000" :show-close="false" top="10vh">
             <template #header="{ close, titleId, titleClass }">
                 <div class="flex justify-between items-center border-b pb-3 dialog-header">
-                    <h4 :id="titleId">新建商机</h4>
+                    <h4 :id="titleId">新建{{ businessLabel }}</h4>
                     <div>
                         <el-button type="primary" @click="editBusiness()"
                             :loading="allLoading.businessSaveLading">保存</el-button>
@@ -56,7 +56,7 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { GenerateForm } from '@zmjs/form-design';
 import { get, post } from '@/utils/request';
 import { useRouter, useRoute } from "vue-router";
@@ -74,6 +74,8 @@ const props = defineProps<{
     data: any
 }>()
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const information = ref<any>({})
 const relatedTaskstable = ref([])
 const businessTemplateRef = ref<typeof GenerateForm>() // 自定义表单dom

+ 182 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contract/component/addEditorTwo.vue

@@ -0,0 +1,182 @@
+<script lang="ts" setup>
+import { ref, reactive, onMounted, inject, watch } from "vue";
+import { UploadRequestOptions } from 'element-plus';
+import { Delete } from '@element-plus/icons-vue'
+import { tableShowOverflowTooltip } from '@/utils/globalVariables'
+import { formatDate } from '@/utils/times'
+import { downloadFile } from '@/utils/tools'
+import { post, get, uploadFile } from "@/utils/request";
+const props = defineProps<{
+  paymentPlan: any[],
+  enclosure: any[],
+  enclosureDetele: any[]
+}>()
+const globalPopup = inject<GlobalPopup>('globalPopup')
+const paymentPlan = ref(props.paymentPlan)
+const enclosure = ref(props.enclosure)
+const enclosureDetele = ref<any[]>([])
+const uploadRef = ref<any>()
+
+watch(() => props.paymentPlan, (newVal, _oldVal) => {
+  paymentPlan.value = newVal || []
+})
+
+watch(() => props.enclosure, (newVal, _oldVal) => {
+  enclosure.value = newVal || []
+})
+
+watch(() => props.enclosureDetele, (newVal, _oldVal) => {
+  enclosureDetele.value = newVal || []
+})
+
+const typeOptions = [
+  { label: '增值税专用发票', value: 0 },
+  { label: '增值税普通发票', value: 1 },
+]
+
+
+function calculateTaxAmount(index: number) {
+  const { amount = 0, taxRate = 0, taxAmount = 0 } = paymentPlan.value[index]
+  if(!amount && !amount) {
+    return
+  }
+
+  const shui = taxRate / 100
+  const zhi = amount / (1 + shui) * shui
+  paymentPlan.value[index].taxAmount = +(zhi.toFixed(2))
+}
+
+// 上传附件
+async function httpUploadFile(param: UploadRequestOptions) {
+  const { file } = param
+  enclosure.value.push({ name: file.name, file, needUpload: true })
+  return
+}
+
+function addPlan() {
+  paymentPlan.value.push({
+    isPayed: false,
+    payDate: formatDate(new Date()),
+    amount: '0',
+    isBilled: true
+  })
+}
+
+function deteleTables(row: any, index: number, type: 'paymentPlan' | 'enclosure') {
+  if (type === 'paymentPlan') {
+    paymentPlan.value.splice(index, 1)
+  } else {
+    if(row.id) {
+      enclosureDetele.value.push(row.id)
+    }
+    enclosure.value.splice(index, 1)
+  }
+}
+
+function getAddEditorData() {
+  return {
+    paymentPlan: paymentPlan.value,
+    enclosure: enclosure.value,
+    enclosureDetele: enclosureDetele.value
+  }
+}
+
+defineExpose({
+  getAddEditorData
+})
+
+</script>
+<template>
+  <div>
+    <div>回款计划</div>
+    <el-table :show-overflow-tooltip="tableShowOverflowTooltip" :data="paymentPlan" height="260">
+      <el-table-column label="是否已回款" width="100">
+        <template #default="scope">
+          <el-checkbox v-model="scope.row.isPayed" label="已回款" />
+        </template>
+      </el-table-column>
+      <el-table-column label="回款日期" width="180">
+        <template #default="scope">
+          <el-date-picker v-model="scope.row.payDate" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
+            placeholder="回款日期" style="width: 150px;" />
+        </template>
+      </el-table-column>
+      <el-table-column label="金额(含税)" width="180">
+        <template #default="scope">
+          <el-input v-model="scope.row.amount" v-enter-number placeholder="金额(含税)" style="width: 150px;">
+            <template #prefix>
+              <el-text class="mx-1" type="info">¥</el-text>
+            </template>
+          </el-input>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否已开票" width="100">
+        <template #default="scope">
+          <el-checkbox v-model="scope.row.isBilled" label="已开票" />
+        </template>
+      </el-table-column>
+      <el-table-column label="开票日期" width="180">
+        <template #default="scope">
+          <el-date-picker v-model="scope.row.billDate" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
+            placeholder="开票日期" style="width: 150px;" />
+        </template>
+      </el-table-column>
+      <el-table-column label="开票种类增值税" width="180">
+        <template #default="scope">
+          <el-select v-model="scope.row.invoiceType" placeholder="请选择">
+            <el-option v-for="item in typeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
+          </el-select>
+        </template>
+      </el-table-column>
+      <el-table-column label="税率%" width="180">
+        <template #default="scope">
+          <el-input-number v-model="scope.row.taxRate" controls-position="right" :min="0.1" :max="100" @change="calculateTaxAmount(scope.$index)"></el-input-number>
+        </template>
+      </el-table-column>
+      <el-table-column label="税额" width="180">
+        <template #default="scope">
+          <el-input-number v-model="scope.row.taxAmount" controls-position="right" :min="0"></el-input-number>
+        </template>
+      </el-table-column>
+      <el-table-column prop="operation" width="80" fixed="right">
+        <template #header>
+          <el-link type="primary" :underline="false" @click="addPlan()">添加</el-link>
+        </template>
+        <template #default="scope">
+          <el-button type="danger" :icon="Delete" size="small"
+            @click="deteleTables(scope.row, scope.$index, 'paymentPlan')"></el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <div>附件</div>
+    <el-table :show-overflow-tooltip="tableShowOverflowTooltip" :data="enclosure" height="260">
+      <el-table-column label="序号" width="100">
+        <template #default="scope">
+          {{ scope.$index + 1 }}
+        </template>
+      </el-table-column>
+      <el-table-column label="文件名称" prop="name"></el-table-column>
+      <el-table-column label="操作" width="80">
+        <template #default="scope">
+          <el-link type="primary" :underline="false" v-if="scope.row.id" @click="downloadFile(scope.row.url, scope.row.name)">下载</el-link>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="80">
+        <template #header>
+          <el-upload ref="uploadRef" :http-request="httpUploadFile" :show-file-list="false" element-loading-text="正在上传"
+            multiple>
+            <template #trigger>
+              <el-link type="primary" :underline="false">添加</el-link>
+            </template>
+          </el-upload>
+        </template>
+        <template #default="scope">
+          <el-button type="danger" :icon="Delete" size="small"
+            @click="deteleTables(scope.row, scope.$index, 'enclosure')"></el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+</template>
+<style lang="scss" scoped></style>

+ 34 - 7
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contract/index.vue

@@ -8,7 +8,8 @@ import { CONTRACT_DELETION, CONTRACT_OPERATION, DELETE_CONTRACT_FILE, EDIT_CONTR
 import { GET_CONTRACT_TEMPLATE, ADD_CONTRACT } from './api'
 import { UploadRequestOptions } from "element-plus";
 
-import AddEditor from "./component/addEditor.vue";
+import AddEditorTwo from "./component/addEditorTwo.vue";
+import treeSelect from '@/components/translationComponent/treeSelect/treeSelect.vue'
 
 const globalPopup = inject<GlobalPopup>('globalPopup')
 const filterContractForm = reactive({
@@ -112,7 +113,7 @@ async function importBusiness(param: UploadRequestOptions) {
     allLoading.importLoading = false
   })
   if (res.code == 'ok') {
-    globalPopup?.showSuccess('导入成功' || '')
+    globalPopup?.showSuccess('导入成功')
     getContractTableList()
     return
   }
@@ -131,6 +132,7 @@ function exportContract() {
 async function addEditor(row?: any) {
   allLoading.addEditorSaveLoading = false
   editForm.value = row ? setEditForm(row) : {}
+  editForm.value.departmentId = row?.departmentId || ''
   allDynamicText.addEditorText = row ? '编辑合同' : '新增合同'
   contractTemplate.value.list = setTemplateDataDisable(contractTemplate.value.list, [...getTemplateKey(contractTemplate.value.list)], row?.status == 0)
   generateFormKey.value++
@@ -139,7 +141,9 @@ async function addEditor(row?: any) {
     const { data = [] } = await post(GET_PAYMENT_LIST, { contractId: row.id })
     addEditorVisableForm.paymentPlan = data.map((item: any) => {
       return {
-        isPayed: item.isPayed, amount: item.amount, payDate: item.payDate, id: item.id
+        isPayed: item.isPayed, amount: item.amount, payDate: item.payDate, id: item.id,
+        isBilled: item.isBilled == 1 ? true : false, billDate: item.billDate, invoiceType: item.invoiceType,
+        taxRate: +item.taxRate, taxAmount: +item.taxAmount
       }
     })
   }
@@ -222,7 +226,12 @@ async function addEditorSave() {
     ...data,
     startDate: data.startDate ? formatDate(new Date(data.startDate)) : '',
     endDate: data.endDate ? formatDate(new Date(data.endDate)) : '',
-    paymentListStr: JSON.stringify(newPaymentPlan)
+    paymentListStr: JSON.stringify(newPaymentPlan.map((item: any) => { 
+      return {
+        ...item,
+        isBilled: item.isBilled ? 1 : 0
+      }
+    }))
   })
 
   let totalAmount = 0
@@ -371,8 +380,14 @@ function getObtainContractType() {
             @click="exportContract()">导出</el-button>
         </div>
         <div class="flex-1 w-full overflow-hidden">
-          <el-table ref="contractTableRef" :show-overflow-tooltip="tableShowOverflowTooltip" :data="contractTableList"
+          <el-table ref="contractTableRef" :data="contractTableList"
             border v-loading="allLoading.contractTableLading" style="width: 100%;height: 100%;">
+            <el-table-column label="合同所属部门" width="180">
+              <template #default="scope">
+                <TextTranslation translationTypes="departmentName" :translationValue="scope.row.departmentName">
+                </TextTranslation>
+              </template>
+            </el-table-column>
             <el-table-column prop="number" label="合同编号" width="180"></el-table-column>
             <el-table-column prop="name" label="合同名称" width="180"></el-table-column>
             <el-table-column prop="amounts" label="合同金额" width="180">
@@ -380,6 +395,11 @@ function getObtainContractType() {
                 ¥ {{ scope.row.amounts ? scope.row.amounts.toFixed(2) : '0.00' }}
               </template>
             </el-table-column>
+            <el-table-column label="已开票金额" width="180">
+              <template #default="scope">
+                ¥ {{ scope.row.invoicedAmount ? scope.row.invoicedAmount.toFixed(2) : '0.00' }}
+              </template>
+            </el-table-column>
             <el-table-column prop="payment" label="已回款金额" width="180">
               <template #default="scope">
                 ¥ {{ scope.row.payment ? scope.row.payment.toFixed(2) : '0.00' }}
@@ -445,10 +465,17 @@ function getObtainContractType() {
       </template>
       <div class="h-[60vh] overflow-y-auto scroll-bar pt-3">
         <div class="ml-4 mr-4">
+          <div class="flex justify-between items-center mb-5">
+            <div class="w-[112px]">合同所属部门:</div>
+            <tree-select v-model="editForm.departmentId" :size="''" placeholder="请选择部门" :key="editForm.departmentId"></tree-select>
+          </div>
           <GenerateForm ref="generateForm" :data="contractTemplate" :value="editForm" :key="generateFormKey" />
-          <AddEditor ref="addEditorRef" :payment-plan="addEditorVisableForm.paymentPlan"
+          <!-- <AddEditor ref="addEditorRef" :payment-plan="addEditorVisableForm.paymentPlan"
+            :enclosure="addEditorVisableForm.enclosure" :enclosure-detele="addEditorVisableForm.enclosureDetele">
+          </AddEditor> -->
+          <AddEditorTwo ref="addEditorRef" :payment-plan="addEditorVisableForm.paymentPlan"
             :enclosure="addEditorVisableForm.enclosure" :enclosure-detele="addEditorVisableForm.enclosureDetele">
-          </AddEditor>
+          </AddEditorTwo>
         </div>
       </div>
     </el-dialog>

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/attachment.vue

@@ -51,7 +51,7 @@
 <script lang="ts" setup>
 import { post, uploadFile } from '@/utils/request';
 import { UploadRequestOptions } from 'element-plus';
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { URL_DETELEFILE, URL_REFFILENAME, URL_UPLOADFILE } from '../api';
 import { confirmAction, downloadFile } from '@/utils/tools';
 import { formatDate } from '@/utils/times';

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

@@ -147,7 +147,7 @@
 </template>
 <script lang="ts" setup>
 import { confirmAction } from '@/utils/tools';
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue';
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue';
 import { GenerateForm } from '@zmjs/form-design';
 import { useStore } from '@/store/index';
 import { get, post } from '@/utils/request';
@@ -164,6 +164,9 @@ const generateFormData = ref({
   config: {},
   list: []
 }); // 自定义表单数据
+
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const generateFormValue = ref({});
 const generateForm = ref<typeof GenerateForm>();
 const generateFormKey = ref(1);
@@ -234,7 +237,7 @@ function transferCustomer() {
 }
 
 function claimCustomer() {
-  confirmAction(`确定认领【${information.value.customName}】商机吗?`).then(() => {
+  confirmAction(`确定认领【${information.value.customName}】${businessLabel}吗?`).then(() => {
     transferCustomer();
   });
 }

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/operationRecord.vue

@@ -18,7 +18,7 @@
 </template>
 <script lang="ts" setup>
 import { formatDate } from '@/utils/times';
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 
 const operationRecordtable = ref([])
 const information = ref({})

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

@@ -1,14 +1,14 @@
 <template>
     <div class="relatedTasks pl-4 pr-4 pt-3 pb-3 h-full flex flex-col">
         <div class="flex justify-between">
-            <div class="title">相关商机</div>
+            <div class="title">相关{{ businessLabel }}</div>
             <div v-permission="['businessAddAnEdit']">
-                <el-button type="primary" @click="editNewBusiness()">新建商机</el-button>
+                <el-button type="primary" @click="editNewBusiness()">新建{{ businessLabel }}</el-button>
             </div>
         </div>
         <div class="flex-1 overflow-auto pt-3">
             <el-table :data="relatedTaskstable" border style="width: 100%;height: 300px;">
-                <el-table-column prop="taskName" label="商机名称">
+                <el-table-column prop="taskName" :label="`${businessLabel}名称`">
                     <template #default="scope">
                         <el-button link type="primary" size="large" @click="toDetail(scope.row)">{{
                             scope.row.name
@@ -21,9 +21,9 @@
                         <TextTranslation translationTypes="userName" :translationValue="scope.row.inchargerName"></TextTranslation>
                     </template>
                 </el-table-column>
-                <el-table-column prop="amountOfMoney" label="商机金额" width="130" />
+                <el-table-column prop="amountOfMoney" :label="`${businessLabel}金额`" width="130" />
                 <el-table-column prop="expectedTransactionDate" label="预计成交时间" width="200" />
-                <el-table-column prop="stageValue" label="商机阶段" width="140" />
+                <el-table-column prop="stageValue" :label="`${businessLabel}阶段`" width="140" />
                 <el-table-column prop="creatorName" label="创建人" width="130">
                     <template #default="scope">
                         <TextTranslation translationTypes="userName" :translationValue="scope.row.creatorName"></TextTranslation>
@@ -36,7 +36,7 @@
         <el-dialog v-model="allVisible.newBusinessisible" width="1000" :show-close="false" top="10vh">
             <template #header="{ close, titleId, titleClass }">
                 <div class="flex justify-between items-center border-b pb-3 dialog-header">
-                    <h4 :id="titleId">{{ '新建商机' }}</h4>
+                    <h4 :id="titleId">新建{{ businessLabel }}</h4>
                     <div>
                         <el-button type="primary" @click="editBusiness(false)" :loading="allLoading.businessSaveLading"
                             :disabled="allLoading.newBusinessSaveLading">保存</el-button>
@@ -56,7 +56,7 @@
 </template>
 <script lang="ts" setup>
 import { get, post } from '@/utils/request';
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { GenerateForm } from '@zmjs/form-design';
 import RelatedProducts from '@/components/relatedProducts/relatedProducts.vue'
 import { GETTABLELIST } from '@/pages/product/api';
@@ -71,6 +71,8 @@ const props = defineProps<{
     data: any
 }>()
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const information = ref<any>({})
 const relatedTaskstable = ref([])
 const relatedProductsRef = ref<typeof RelatedProducts>()

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/relatedContacts.vue

@@ -70,7 +70,7 @@ import { get, post } from '@/utils/request';
 import { setTemplateDataDisable } from '@/utils/tools';
 import { GenerateForm } from '@zmjs/form-design';
 import router from '@/router';
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 
 const emits = defineEmits(['refreshData']);
 const globalPopup = inject<GlobalPopup>('globalPopup')

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/relatedOrders.vue

@@ -59,7 +59,7 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { setTemplateDataDisable } from '@/utils/tools';
 import { GenerateForm } from '@zmjs/form-design';
 import { get, post } from '@/utils/request';

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

@@ -135,6 +135,7 @@ const loginLogic = (data: any) => {
     alert('无权访问,请联系管理员为您分配权限')
     return
   }
+  sessionStorage.setItem('isExistBusiness', data.company.isExistBusiness || 0)
   sessionStorage.setItem('token', data.id)
   localStorage.setItem('SUPERSONIC_TOKEN', data.supersonicToken)
   setValue(data, 'userInfo')

+ 3 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/api.ts

@@ -22,11 +22,13 @@ export const URL_ADDREBATE = `${MOD}/paymentCollection`
 export const URL_EDITEBATE = `${MOD}/editPayment`
 export const URL_DETELEITEMS = `${MOD}/deletePayment`
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 export const tableColumns: TableColumn[] = [
     { prop: 'orderCode', label: '订单编号', width: '150' },
     { prop: 'orderName', label: '订单名称', event: 'toDetali', width: '150' },
     { prop: 'customName', label: '客户名称', width: '200' },
-    { prop: 'businessOpportunityName', label: '商机名称', width: '200' },
+    { prop: 'businessOpportunityName', label: `${businessLabel}名称`, width: '200' },
     { prop: 'price', label: '订单金额(¥)', width: '140' },
     { prop: 'receivedPayment', label: '已回款(¥)', width: '140' },
     { prop: 'unReceivedPayment', label: '未回款(¥)', width: '140' },

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

@@ -66,7 +66,7 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { GenerateForm } from '@zmjs/form-design';
 import { getFromValue, getTemplateKey } from '@/utils/tools';
 import { get, post } from '@/utils/request';
@@ -95,6 +95,8 @@ const orderTemplate = ref({
     list: [],
     config: {}
 })
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const orderTemplateValue = ref({})
 const orderTemplateKey = ref(1)
 const orderTemplateRef = ref<typeof GenerateForm>()
@@ -196,7 +198,7 @@ const formItems = reactive([
     { label: '订单编号', key: 'orderCode', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
     { label: '订单名称', key: 'orderName', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
     { label: '客户名称', key: 'customName', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
-    { label: '商机名称', key: 'businessOpportunityName', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
+    { label: `${businessLabel}名称`, key: 'businessOpportunityName', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
     { label: '订单金额', key: 'price', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
     { label: '回款状态', key: 'receivedStatus', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
     { label: '已回款金额', key: 'receivedPayment', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/operationRecord.vue

@@ -17,7 +17,7 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 const props = defineProps<{
     data: any
 }>()

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/products.vue

@@ -51,7 +51,7 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { GETGENERATEFOEM, GETTABLELISTPRODUCT, URL_OEDERUPDATE } from '../api';
 import { get, post } from '@/utils/request';
 import { useRouter } from "vue-router";

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/rebate.vue

@@ -50,7 +50,7 @@
 </template>
 <script lang="ts" setup>
 import { post } from '@/utils/request';
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { URL_ADDREBATE, URL_DETELEITEMS, URL_EDITEBATE } from '../api';
 import { confirmAction } from '@/utils/tools';
 import { ITEM_RENDER_EVT } from 'element-plus/es/components/virtual-list/src/defaults';

+ 5 - 3
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/index.vue

@@ -203,11 +203,13 @@ const orderTemplate = ref({
   list: [],
   config: {}
 })
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const filterItems = ref<FilterItem[]>([
   { label: '订单编号', key: 'orderCode', type: 'input' },
   { label: '订单名称', key: 'orderName', type: 'input' },
   { label: '客户名称', key: 'customId', type: 'select', options: selectData.Customer },
-  { label: '商机名称', key: 'businessName', type: 'input' },
+  { label: `${businessLabel}名称`, key: 'businessName', type: 'input' },
   { label: '订单类型', key: 'ordertype', type: 'select', options: selectData.OrderType },
   { label: '回款状态', key: 'receivedStatus', type: 'select', options: selectData.RemittanceStatus },
   { label: '负责人', key: 'inchargerId', type: 'select', options: selectData.Personnel },
@@ -233,7 +235,7 @@ async function importBusiness(param: UploadRequestOptions) {
     allLoading.importLoading = false
   })
   if (res.code == 'ok') {
-    globalPopup?.showSuccess('导入成功' || '')
+    globalPopup?.showSuccess('导入成功')
     getTableList()
     return
   }
@@ -447,7 +449,7 @@ function setFilterItems() {
     { label: '订单编号', key: 'orderCode', type: 'input' },
     { label: '订单名称', key: 'orderName', type: 'input' },
     { label: '客户名称', key: 'customId', type: 'select', options: selectData.Customer },
-    { label: '商机名称', key: 'businessName', type: 'input' },
+    { label: `${businessLabel}名称`, key: 'businessName', type: 'input' },
     { label: '订单类型', key: 'orderType', type: 'select', options: selectData.OrderType },
     { label: '回款状态', key: 'receivedStatus', type: 'select', options: selectData.RemittanceStatus },
     { label: '负责人', key: 'inchargerId', type: 'select', options: selectData.Personnel },

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/information.vue

@@ -108,7 +108,7 @@
 </template>
 <script lang="ts" setup>
 import { formatDate } from '@/utils/times';
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { ADDPRODUCT, GETDOEMCODE, GETINCHARGER, GETPERSONNEL, GETTEMPLATE, MOD } from '../api';
 import { useStore } from '@/store/index'
 import { post, get } from '@/utils/request';

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/operationRecord.vue

@@ -17,7 +17,7 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 
 const operationRecordtable = ref([])
 const information: any = ref({})

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

@@ -1,7 +1,7 @@
 <template>
     <div class="relatedTasks pl-4 pr-4 pt-3 pb-3 h-full flex flex-col">
         <div class="flex justify-between">
-            <div class="title">相关商机</div>
+            <div class="title">相关{{ businessLabel }}</div>
         </div>
         <div class="flex-1 overflow-auto pt-3">
             <el-table :data="relatedTaskstable" :show-overflow-tooltip="tableShowOverflowTooltip" border
@@ -22,7 +22,7 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { tableColumn, MOD } from '@/pages/business/api'
 import { tableShowOverflowTooltip } from '@/utils/globalVariables'
 import router from '@/router';
@@ -37,6 +37,9 @@ const props = defineProps<{
     information: any
 }>()
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
+
 // 接收参数赋值
 function receiveAssignment(item: any) {
     relatedTaskstable.value = item.data.map((item: any) => {

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/relatedSalesOrder.vue

@@ -23,7 +23,7 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { tableColumns, MOD, paymentStatus } from '@/pages/order/api'
 import router from '@/router';
 

+ 4 - 2
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/index.vue

@@ -21,7 +21,7 @@
             <el-form-item label="执行人:" label-width="7em" prop="executorName">
               <el-input v-model="searchForm.executorName" placeholder="请输入" />
             </el-form-item>
-            <el-form-item label="商机名称:" label-width="7em" prop="businessName">
+            <el-form-item :label="`${businessLabel}名称`" label-width="7em" prop="businessName">
               <el-input v-model="searchForm.businessName" placeholder="请输入" />
             </el-form-item>
             <el-form-item label="销售订单:" label-width="7em" prop="orderName">
@@ -100,7 +100,7 @@
                 </el-link>
               </template>
             </el-table-column>
-            <el-table-column prop="businessName" label="商机名称" header-align="center" align="center" width="200">
+            <el-table-column prop="businessName" :label="`${businessLabel}名称`" header-align="center" align="center" width="200">
               <template #default="scope">
                 <el-link :underline="false" type="primary"
                   @click="goDetail(scope.row, 'business', 'businessOpportunityId')">
@@ -220,6 +220,8 @@ const taskLoading = ref<saveLoadingType>("1");
 const restartPopUpWindowVisable = ref(false);
 const restartFrom = ref<any>({});
 const dateOfTheDay = ref<any>(dayjs().format('YYYY-MM-DD'))
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 
 function closeTaskModal() {
   taskModalVisible.value = false;

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/module/BatchOperation.vue

@@ -36,7 +36,7 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import type { CascaderProps } from 'element-plus'
 import { Props } from './type';
 import { BACTHUPDATEDEPT, BACTHUPDATEROLE } from '../api';

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

@@ -4,7 +4,7 @@
             <div class="title">基本信息</div>
             <div>
                 <el-button type="primary" v-permission="['threadEdit', userInfo.id == information.inchargerId]"
-                    @click="showVisible('newBusinessisible')" v-if="!information.isBo">转为商机</el-button>
+                    @click="showVisible('newBusinessisible')" v-if="!information.isBo">转为{{ businessLabel }}</el-button>
                 <el-button type="primary" @click="claimClues()" v-if="!information.inchargerName">认领</el-button>
                 <el-button type="primary" @click="showVisible('clueDialogVisible')" v-else>转移</el-button>
                 <el-button type="primary" @click="editClue(information)" v-permission="['tasksAdd']">编辑</el-button>
@@ -126,7 +126,7 @@
                     <h4 :id="titleId">{{ allText.businessisText }}</h4>
                     <div>
                         <el-button type="primary" @click="transferBusiness()" 
-                            :loading="allLoading.businessSaveLading">转为商机</el-button>
+                            :loading="allLoading.businessSaveLading">转为{{ businessLabel }}</el-button>
                         <el-button @click="closeVisible('newBusinessisible')">取消</el-button>
                     </div>
                 </div>
@@ -140,7 +140,7 @@
     </div>
 </template>
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, inject, watchEffect } from 'vue'
 import { GenerateForm } from '@zmjs/form-design';
 import { formatDate, confirmAction, backPath, judgmentaAmounteEqual } from '@/utils/tools'
 import { GETTEMPLATE, UNDATEFORM, GETPERSONNEL, UNDATECLAIM, GETTEMPLATETWO } from '../../constant'
@@ -165,6 +165,8 @@ const props = defineProps<{
     data: any
 }>()
 
+const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+const businessLabel = isExistBusiness === "1" ? "商机" : "项目"; 
 const { userInfo } = useStore()
 const globalPopup = inject<GlobalPopup>('globalPopup')
 const emits = defineEmits(['refreshData']);
@@ -184,7 +186,7 @@ const dialogVisible = reactive({
 const allText = reactive({
     editClueText: '新建线索',
     clueText: '认领线索',
-    businessisText: '转为商机'
+    businessisText: `转为${businessLabel}`
 })
 const generateForm: any = ref(null) // 模板
 const clueTemplate = ref({

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

@@ -19,6 +19,7 @@ type ListByCodeType = (
   | "产品类型"
   | "产品单位"
   | "订单类型"
+  | "项目阶段"
 )[];
 
 type templateKey = { // 自定义模板键值

+ 4 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/utils/tools.ts

@@ -91,6 +91,7 @@ const listByCode = [
   { name: "客户行业", id: "CustomIndustry" },
   { name: "客户来源", id: "CustomSources" },
   { name: "商机阶段", id: "BusinessStage" },
+  { name: "项目阶段", id: "BusinessStage" },
   { name: "产品类型", id: "ProductType" },
   { name: "产品单位", id: "ProductUnit" },
   { name: "订单类型", id: "OrderType" },
@@ -280,11 +281,13 @@ export function judgmentaAmounteEqual(mob: any, arr: any) {
   const amounte = mob.amountOfMoney || 0;
   const totalAmounte = arr.reduce((pre: number, cur: any) => pre + (cur.totalPrice || 0), 0);
 
+  const isExistBusiness = sessionStorage.getItem("isExistBusiness");
+  const businessLabel = isExistBusiness === "1" ? "商机" : "项目";
   if (amounte != totalAmounte) {
     ElNotification.closeAll();
     ElNotification({
       title: '提示',
-      message: `商机金额${amounte > totalAmounte ? '大于' : '小于'}产品总金额,${amounte > totalAmounte ? '' : '请修改'}`,
+      message: `${businessLabel}金额${amounte > totalAmounte ? '大于' : '小于'}产品总金额,${amounte > totalAmounte ? '' : '请修改'}`,
       type: 'warning',
     });
     flag = true;

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/vite.config.ts

@@ -3,7 +3,7 @@ import vue from '@vitejs/plugin-vue';
 
 import { resolve } from 'path';
 
-// const target = 'http://192.168.2.28:10010';
+// const target = 'http://192.168.2.40:10099';
 // const target = 'http://192.168.2.17:10010';
 // const target = "http://127.0.0.1:10010";
 // const target = "http://192.168.2.178:10010";

+ 1 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/constant/Constant.java

@@ -58,4 +58,5 @@ public class Constant {
     public static final String[] LEAVE_WAIT_CHECK= {"请假人","请假类型","请假时间","备注"};
     //请假审核通知
     public static final String[] LEAVE_CHECK= {"审核结果","审核人","请假时间","备注"};
+    public static final int JUN_TIAN_COMPANY_ID= 6666;
 }

+ 17 - 3
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/BusinessOpportunityController.java

@@ -68,6 +68,8 @@ public class BusinessOpportunityController {
     private ActionLogMapper actionLogMapper;
     @Resource
     private BusinessOpportunityService businessOpportunityService;
+    @Resource
+    private CompanyMapper companyMapper;
     @Autowired
     private TaskMapper taskMapper;
 
@@ -104,6 +106,9 @@ public class BusinessOpportunityController {
         SysForm sysForm = sysFormMapper.selectOne(new LambdaQueryWrapper<SysForm>().eq(SysForm::getCompanyId, user.getCompanyId()).eq(SysForm::getCode, "business").eq(SysForm::getIsCurrent, 1));
         WxCorpInfo wxCorpInfo = wxCorpInfoService.getOne(new LambdaQueryWrapper<WxCorpInfo>().eq(WxCorpInfo::getCompanyId, user.getCompanyId()));
         String config = sysForm.getConfig();
+        Company company = companyMapper.selectById(user.getCompanyId());
+        String str = company.getIsExistBusiness() == 1 ? "商机" : "项目";
+
         JSONObject configOb = JSON.parseObject(config);
         JSONArray configObJSONArray = configOb.getJSONArray("list");
         List<List<String>> dataList=new ArrayList<>();
@@ -130,6 +135,13 @@ public class BusinessOpportunityController {
             }
         }
         dataList.add(titleList);
+        for (int i = 0; i < titleList.size(); i++) {
+            String s = titleList.get(i);
+            if (s.contains("商机")) {
+                s = s.replaceAll("商机", str);
+                titleList.set(i, s);
+            }
+        }
 
         HttpRespMsg respMsg = list(bo,request);
         Map<String, Object> msgData = (Map<String, Object>) respMsg.getData();
@@ -194,7 +206,7 @@ public class BusinessOpportunityController {
             }
             dataList.add(item);
         }
-        String fileName="商机表导出_"+ System.currentTimeMillis();
+        String fileName=str+"表导出_"+ System.currentTimeMillis();
         return excelExportService.exportGeneralExcelByTitleAndList(wxCorpInfo,fileName,dataList,path);
     }
 
@@ -265,6 +277,8 @@ public class BusinessOpportunityController {
     public HttpRespMsg insertAndUpdate( BusinessOpportunity bo, HttpServletRequest request) {
         User user = userMapper.selectById(request.getHeader("Token"));
         HttpRespMsg msg = new HttpRespMsg();
+        Company company = companyMapper.selectById(user.getCompanyId());
+        String str= company.getIsExistBusiness()==1 ? "商机" :"项目";
         if (bo.getId() == null){
             //新增
             Integer count = businessOpportunityMapper.selectCount(new LambdaQueryWrapper<BusinessOpportunity>()
@@ -272,7 +286,7 @@ public class BusinessOpportunityController {
                     .eq(BusinessOpportunity::getCompanyId,user.getCompanyId())
             );
             if(count>0){
-                msg.setError("已存在同名商机");
+                msg.setError("已存在同名"+str);
                 return msg;
             }
             if (bo.getClueId()!= null ){
@@ -309,7 +323,7 @@ public class BusinessOpportunityController {
                     .ne(BusinessOpportunity::getId,bo.getId())
             );
             if(count>0){
-                msg.setError("已存在同名商机");
+                msg.setError("已存在同名"+str);
                 return msg;
             }
             bo.setEditTime(new Date());

+ 4 - 2
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ContractController.java

@@ -92,11 +92,13 @@ public class ContractController {
     public HttpRespMsg importContract (HttpServletRequest request, MultipartFile file){
         String token = request.getHeader("TOKEN");
         User user = userMapper.selectById(token);
-        if (user.getCompanyId() == 10 || user.getCompanyId() == 4215) {
+        /*if (user.getCompanyId() == 10 || user.getCompanyId() == 4215) {
             return contractService.importContractCustom(request,file);
         } else {
             return contractService.importContract(request,file);
-        }
+        }*/
+
+        return  contractService.importContractNew(request, file);
     }
 
     /**

+ 12 - 1
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ContractPaymentController.java

@@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
+import java.util.List;
 
 /**
  * <p>
@@ -43,7 +44,17 @@ public class ContractPaymentController {
         String token = request.getHeader("token");
         User user = userService.getById(token);
         if (user.getCompanyId()!=4215){
-            msg.data = contractPaymentService.list(new QueryWrapper<ContractPayment>().eq("contract_id", contractId));
+            List<ContractPayment> paymentList = contractPaymentService.list(new QueryWrapper<ContractPayment>().eq("contract_id", contractId));
+            for (ContractPayment contractPayment : paymentList) {
+                if (contractPayment!=null&&contractPayment.getInvoiceType()!=null){
+                    if (contractPayment.getInvoiceType()==0){
+                        contractPayment.setInvoiceTypeName("增值税专用发票");
+                    }else {
+                        contractPayment.setInvoiceTypeName("增值税普通发票");
+                    }
+                }
+            }
+            msg.data = paymentList;
         }else {
             msg.data = payCustomizedService.list(new QueryWrapper<ContractPayCustomized>().eq("contract_id", contractId));
         }

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

@@ -2,7 +2,9 @@ package com.management.platform.controller;
 
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.management.platform.entity.Company;
 import com.management.platform.entity.SysForm;
+import com.management.platform.mapper.CompanyMapper;
 import com.management.platform.mapper.UserMapper;
 import com.management.platform.service.SysFormService;
 import com.management.platform.util.HttpRespMsg;
@@ -31,6 +33,9 @@ public class SysFormController {
     @Resource
     private UserMapper userMapper;
 
+    @Resource
+    private CompanyMapper companyMapper;
+
 
     @RequestMapping("/list")
     public HttpRespMsg list(){
@@ -45,7 +50,18 @@ public class SysFormController {
     public HttpRespMsg getListByCode(@PathVariable(name="code") String code){
         HttpRespMsg msg=new HttpRespMsg();
         Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        Company company = companyMapper.selectById(companyId);
         List<SysForm> sysFormList = sysFormService.list(new LambdaQueryWrapper<SysForm>().eq(SysForm::getCompanyId, companyId).eq(SysForm::getCode, code));
+        if (!sysFormList.isEmpty()&&company.getIsExistBusiness()==0){
+            for (SysForm sysForm : sysFormList) {
+                String config = sysForm.getConfig();
+                String replacedConfig = config.replaceAll("商机", "项目");
+                sysForm.setConfig(replacedConfig);
+                if (sysForm.getName().contains("商机")){
+                    sysForm.setName(sysForm.getName().replaceAll("商机","项目"));
+                }
+            }
+        }
         msg.setData(sysFormList);
         return msg;
     }

+ 5 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/Company.java

@@ -146,6 +146,11 @@ public class Company extends Model<Company> {
     @TableField("non_project_simple")
     private Integer nonProjectSimple;
 
+    /**
+     * 是否存在商机模式 默认存在1, 不存在0
+     */
+    @TableField("is_exist_business")
+    private Integer isExistBusiness;
 
     @Override
     protected Serializable pkVal() {

+ 8 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/Contract.java

@@ -219,6 +219,14 @@ public class Contract extends Model<Contract> {
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
     private Date pinTime;
 
+    @TableField("department_id")
+    private Integer departmentId;
+
+    @TableField(exist = false)
+    private String departmentName;
+
+    @TableField(exist = false)
+    private BigDecimal invoicedAmount;
 
     @Override
     protected Serializable pkVal() {

+ 36 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/ContractPayment.java

@@ -57,6 +57,42 @@ public class ContractPayment extends Model<ContractPayment> {
     private Boolean isPayed;
 
 
+    /**
+     * 是否开票 1是 0否
+     */
+    @TableField("is_billed")
+    private Integer isBilled;
+
+    /**
+     * 开票日期
+     */
+    @TableField("bill_date")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDate billDate;
+
+    /**
+     * 发票类型 0专票 1普票
+     */
+    @TableField("invoice_type")
+    private Integer invoiceType;
+
+    @TableField(exist = false)
+    private String  invoiceTypeName;
+
+    /**
+     * 税额
+     */
+    @TableField("tax_amount")
+    private BigDecimal taxAmount;
+
+    /**
+     * 税率
+     */
+    @TableField("tax_rate")
+    private BigDecimal taxRate;
+
+
     @Override
     protected Serializable pkVal() {
         return this.id;

+ 42 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/vo/ContractVo.java

@@ -0,0 +1,42 @@
+package com.management.platform.entity.vo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.management.platform.entity.ContractCustom;
+import com.management.platform.entity.ContractPayCustomized;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.Date;
+
+
+@Data
+@Accessors(chain = true)
+public class ContractVo {
+
+    private String number;
+    private String name;
+    private double contractAmount;
+    private String contractType;
+    private LocalDate startDate;
+    private LocalDate endDate;
+    private String departmentName;
+    private String design;
+    private String remark;
+    private String isreturn;
+    private LocalDate returnDate;
+    private double returnMoney;
+    private String isBill;
+    private LocalDate billDate;
+    private String billType;
+    private double taxRate;
+    private double tax;
+
+
+}

+ 8 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/mapper/ContractMapper.java

@@ -18,4 +18,12 @@ public interface ContractMapper extends BaseMapper<Contract> {
     Long selectContractCnt(Integer companyId, String number, String name, String typeName, Integer status, String startDate,String endDate, String paymentStartDate, String paymentEndDate, Integer secTypeId,String customerOrg,Integer finishStatus);
 
     List<Contract> selectContractByPin(Integer companyId, Integer pageStart, Integer pageSize, String number, String name, String typeName, Integer status, String startDate, String endDate, String paymentStartDate, String paymentEndDate, Integer secTypeId, String customerOrg, Integer finishStatus);
+
+    List<Contract> selectContractWithType(Integer companyId, Integer pageStart, Integer pageSize, String number, String name, String typeName, Integer status, String startDate, String endDate, String paymentStartDate, String paymentEndDate, Integer secTypeId, String customerOrg, Integer finishStatus, int type, Integer dept, String userId);
+
+    Long selectContractCntWithType(Integer companyId, String number, String name, String typeName, Integer status, String startDate, String endDate, String paymentStartDate, String paymentEndDate, Integer secTypeId, String customerOrg, Integer finishStatus, int type, Integer dept, String userId);
+
+    List<Contract> selectContractByPinWithType(Integer companyId, Integer pageStart, Integer pageSize, String number, String name, String typeName, Integer status, String startDate, String endDate, String paymentStartDate, String paymentEndDate, Integer secTypeId, String customerOrg, Integer finishStatus, int type, Integer dept, String userId);
+
+    Long selectContractContByPinWithType(Integer companyId, String number, String name, String typeName, Integer status, String startDate, String endDate, String paymentStartDate, String paymentEndDate, Integer secTypeId, String customerOrg, Integer finishStatus, int type, Integer dept, String userId);
 }

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

@@ -46,4 +46,6 @@ public interface ContractService extends IService<Contract> {
     HttpRespMsg undoPin(Contract contract, HttpServletRequest request);
 
     HttpRespMsg getContractDetail(HttpServletRequest request, Integer id);
+
+    HttpRespMsg importContractNew(HttpServletRequest request, MultipartFile file);
 }

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

@@ -89,6 +89,9 @@ public class BusinessOpportunityServiceImpl extends ServiceImpl<BusinessOpportun
 
     @Resource
     private SysFunctionService sysFunctionService;
+
+    @Resource
+    private CompanyMapper companyMapper;
     @Autowired
     private BusinessOpportunityMapper businessOpportunityMapper;
 
@@ -193,6 +196,7 @@ public class BusinessOpportunityServiceImpl extends ServiceImpl<BusinessOpportun
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void insert(BusinessOpportunity bo) {
+        String str = getString();
         setNull(bo);
         bOMapper.insert(bo);
         List<BusinessItemProduct> businessItemProducts = JSONArray.parseArray(bo.getBusinessItemProductList(), BusinessItemProduct.class);
@@ -205,13 +209,20 @@ public class BusinessOpportunityServiceImpl extends ServiceImpl<BusinessOpportun
         actionLog.setItemId(bo.getId());
         actionLog.setCode("business");
         actionLog.setCreatTime(new Date());
-        actionLog.setName("创建了商机");
+        actionLog.setName("创建了"+str);
         actionLogMapper.insert(actionLog);
     }
 
+    private String getString() {
+        String userId = request.getHeader("Token");
+        Company company = companyMapper.selectById(userMapper.selectById(userId).getCompanyId());
+        return company.getIsExistBusiness()==1 ? "商机" :"项目";
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void update(BusinessOpportunity bo, String userId) {
+        String str = getString();
         setNull(bo);
         bOMapper.updateById(bo);
         bipMapper.delete(new QueryWrapper<BusinessItemProduct>().eq("business_id", bo.getId()));
@@ -222,7 +233,7 @@ public class BusinessOpportunityServiceImpl extends ServiceImpl<BusinessOpportun
         }
         ActionLog log = new ActionLog();
         log.setItemId(bo.getId());
-        log.setName("编辑了商机");
+        log.setName("编辑了"+str);
         log.setCode("business");
         log.setUserId(userId);
         log.setCreatTime(new Date());
@@ -232,6 +243,7 @@ public class BusinessOpportunityServiceImpl extends ServiceImpl<BusinessOpportun
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void getAndTransfer(BusinessOpportunity bo, User user) {
+        String str = getString();
         UpdateWrapper<BusinessOpportunity> updateWrapper = new UpdateWrapper<>();
         String ids1 = bo.getIds();
         List<Integer> ids = new ArrayList<>();
@@ -252,13 +264,13 @@ public class BusinessOpportunityServiceImpl extends ServiceImpl<BusinessOpportun
         for (BusinessOpportunity clue1 : clues) {
             if (clue1.getInchargerId() == null) {
                 //认领
-                clueLog.setName("认领了商机");
+                clueLog.setName("认领了"+str);
                 clueLog.setUserId(user.getId());
                 bo.setInchargerId(user.getId());
                 actionLogMapper.insert(clueLog);
             } else {
                 //转移
-                clueLog.setName("转移了商机");
+                clueLog.setName("转移了"+str);
                 bo.setInchargerId(bo.getInchargerId());
                 actionLogMapper.insert(clueLog);
             }

+ 467 - 33
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ContractServiceImpl.java

@@ -6,13 +6,13 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.constant.Constant;
 import com.management.platform.entity.*;
 import com.management.platform.entity.vo.ContractPageVO;
+import com.management.platform.entity.vo.ContractVo;
 import com.management.platform.entity.vo.SysRichFunction;
 import com.management.platform.mapper.*;
-import com.management.platform.service.ContractService;
-import com.management.platform.service.ExcelExportService;
-import com.management.platform.service.SysDictService;
+import com.management.platform.service.*;
 import com.management.platform.util.ExcelUtil;
 import com.management.platform.util.HttpRespMsg;
 import com.management.platform.util.MessageUtils;
@@ -86,9 +86,17 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
     private ContractPayCustomizedMapper contractPayCustomizedMapper;
     @Resource
     private SysDictService sysDictService;
+    @Resource
+    private DepartmentService departmentService;
+    @Resource
+    private ContractPaymentService contractPaymentService;
 
     @Resource
     private CompanyDingdingMapper companyDingdingMapper;
+    @Autowired
+    private SysFunctionService sysFunctionService;
+
+
 
 
 
@@ -110,15 +118,18 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
                                        String typeName, Integer status, String startDate, String endDate,
                                        String paymentStartDate, String paymentEndDate, Integer secTypeId,String customerOrg,Integer finishStatus) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
+        String token = request.getHeader("token");
+        User user = userMapper.selectById(token);
+        boolean isAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看全部合同");
+        boolean isNotAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看负责部门合同数据");
         try {
-            String token = request.getHeader("token");
-            User user = userMapper.selectById(token);
+
             WxCorpInfo wxCorpInfo = wxCorpInfoMapper.selectOne(new QueryWrapper<WxCorpInfo>().eq("company_id", user.getCompanyId()));
-            List<SysRichFunction> functionContractList = sysFunctionMapper.getRoleFunctions(user.getRoleId(), "查看全部合同");
+            /*List<SysRichFunction> functionContractList = sysFunctionMapper.getRoleFunctions(user.getRoleId(), "查看全部合同");
             if(functionContractList.size() <= 0){
                 httpRespMsg.setError(MessageUtils.message("access.viewError"));
                 return httpRespMsg;
-            }
+            }*/
             List<ContractType> types = contractTypeMapper.selectList(new QueryWrapper<ContractType>().eq("company_id", user.getCompanyId()));
             if (types.size() == 0){
                 //String[] typeNames = {"买卖合同","赠与合同","租赁合同","借款合同","仓储合同","委托合同"};
@@ -134,22 +145,35 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
             if (pageIndex!=null){
                 pageStart = (pageIndex -1) * pageSize;
             }
-//            if (StringUtils.isNotBlank(number)){
-//                number = "%" + number + "%";
-//            }
-//            if (StringUtils.isNotBlank(name)){
-//                name = "%" + name + "%";
-//            }
-            List<Contract> contracts = contractMapper.selectContract(user.getCompanyId(), pageStart, pageSize, number, name , typeName , status, startDate,endDate, paymentStartDate, paymentEndDate, secTypeId,customerOrg,finishStatus);
-            Long totalCnt = contractMapper.selectContractCnt(user.getCompanyId(), number, name, typeName, status, startDate, endDate, paymentStartDate, paymentEndDate, secTypeId,customerOrg,finishStatus);
+            List<Contract> contracts = new ArrayList<>();
+            Long totalCnt=0L;
+
+            int type=0;
+            Integer dept=user.getDepartmentId();
+            String userId=user.getId();
+            if (isAll){
+                type=1;//查看全部
+            }else if (isNotAll) {
+                type=2;//查看对应部门
+            }else {
+                type=3;//查看个人
+            }
+            contracts = contractMapper.selectContractWithType(user.getCompanyId(), pageStart, pageSize, number, name , typeName , status, startDate,endDate, paymentStartDate, paymentEndDate, secTypeId,customerOrg,finishStatus,type,dept,userId);
+            totalCnt = contractMapper.selectContractCntWithType(user.getCompanyId(), number, name, typeName, status, startDate, endDate, paymentStartDate, paymentEndDate, secTypeId,customerOrg,finishStatus,type,dept,userId);
+
+
+            //首先获取所有合同的Id
+            List<Integer> contractCollect = contracts.stream().map(Contract::getId).collect(Collectors.toList());
+            contractCollect.add(-1);
+            List<ContractPayment> contractPaymentList = contractPaymentMapper.selectList(new QueryWrapper<ContractPayment>().in("contract_id", contractCollect));
             for (Contract contract : contracts) {
                 if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
                     contract.setCreatorName(contract.getCreatorWxCorpId());
                 }
+                //已开票金额
+                BigDecimal decimal = contractPaymentList.stream().filter(c -> c.getContractId().equals(contract.getId()) && c.getIsBilled() == 1).map(ContractPayment::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
+                contract.setInvoicedAmount(decimal);
             }
-            //首先获取所有合同的Id
-            List<Integer> contractCollect = contracts.stream().map(c -> c.getId()).collect(Collectors.toList());
-            contractCollect.add(-1);
             //查询所有合同的所有附件
             List<ContractDocument> fileList = contractDocumentMapper.selectList(new QueryWrapper<ContractDocument>().in("contract_id", contractCollect).eq("is_deleted",0));
             //获取所有附件的上传者id
@@ -200,6 +224,9 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
                 contractPageVO.setPlate3(contract.getPlate3());
                 contractPageVO.setPlate4(contract.getPlate4());
                 contractPageVO.setPlate5(contract.getPlate5());
+                contractPageVO.setInvoicedAmount(contract.getInvoicedAmount());
+                contractPageVO.setDepartmentId(contract.getDepartmentId());
+                contractPageVO.setDepartmentName(contract.getDepartmentName());
                 if (contract.getStatus().equals(2)){
                     for (Map<String, Object> contractLog : contractLogs) {
                         if (contractLog.get("contractId").toString().equals(contract.getId().toString())){
@@ -276,6 +303,7 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
 //        headList.add("创建时间");
 //        headList.add("备注");
         headList.add(MessageUtils.message("entry.contractNo"));
+        headList.add("部门");
         headList.add(MessageUtils.message("contract.name"));
         headList.add(MessageUtils.message("Contract.startDate"));
         headList.add(MessageUtils.message("Contract.endDate"));
@@ -290,6 +318,7 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
         for (ContractPageVO contract : data) {
             ArrayList<String> item = new ArrayList<>();
             item.add(contract.getNumber()==null?"":contract.getNumber());
+            item.add(StringUtils.isEmpty(contract.getDepartmentName())?"":contract.getDepartmentName());
             item.add(null == contract.getName()?"":contract.getName());
             item.add(contract.getStartDate()==null?"":contract.getStartDate()+"");
             item.add(contract.getEndDate()==null?"":contract.getEndDate()+"");
@@ -338,6 +367,7 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
      * @return
      */
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public HttpRespMsg addContract(HttpServletRequest request, Contract contract, ContractCustom custom, String paymentListStr) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         User user = userMapper.selectById(request.getHeader("token"));
@@ -398,7 +428,7 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
                 for (ContractPayment contractPayment:contractPaymentList) {
                     contractPayment.setContractId(contract.getId());
                     contractPaymentMapper.insert(contractPayment);
-                    if (contractPayment.getIsPayed()) {
+                    if (contractPayment.getIsPayed()!=null&&contractPayment.getIsPayed()) {
                         bg = bg.add(contractPayment.getAmount());
                     }
                 }
@@ -435,11 +465,11 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
     public HttpRespMsg editContract(HttpServletRequest request, Contract contract, ContractCustom custom, String paymentListStr) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         User user = userMapper.selectById(request.getHeader("token"));
-        List<SysRichFunction> functionContractList = sysFunctionMapper.getRoleFunctions(user.getRoleId(), "查看全部合同");
+        /*List<SysRichFunction> functionContractList = sysFunctionMapper.getRoleFunctions(user.getRoleId(), "查看全部合同");
         if(functionContractList.size() <= 0){
             httpRespMsg.setError(MessageUtils.message("access.operationError"));
             return httpRespMsg;
-        }
+        }*/
         try {
             if (contract.getId() == null) {
                 httpRespMsg.setError(MessageUtils.message("name.idNullError"));
@@ -1546,6 +1576,8 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
         try {
             String token = request.getHeader("token");
             User user = userMapper.selectById(token);
+            boolean isAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看全部合同");
+            boolean isNotAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看负责部门合同数据");
             WxCorpInfo wxCorpInfo = wxCorpInfoMapper.selectOne(new QueryWrapper<WxCorpInfo>().eq("company_id", user.getCompanyId()));
             List<SysRichFunction> functionContractList = sysFunctionMapper.getRoleFunctions(user.getRoleId(), "查看全部合同");
 //            CompanyDingding dingding = companyDingdingMapper.selectOne(new LambdaQueryWrapper<CompanyDingding>().eq(CompanyDingding::getCompanyId, user.getCompanyId()));
@@ -1555,10 +1587,6 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
 //                companyUserMap  = companyUserList.stream().collect(Collectors.toMap(User::getId, t -> t));
 //            }
 
-            if(functionContractList.size() <= 0){
-                httpRespMsg.setError(MessageUtils.message("access.viewError"));
-                return httpRespMsg;
-            }
             List<ContractType> types = contractTypeMapper.selectList(new QueryWrapper<ContractType>().eq("company_id", user.getCompanyId()));
             if (types.size() == 0){
                 //String[] typeNames = {"买卖合同","赠与合同","租赁合同","借款合同","仓储合同","委托合同"};
@@ -1574,14 +1602,18 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
             if (pageIndex!=null){
                 pageStart = (pageIndex -1) * pageSize;
             }
-//            if (StringUtils.isNotBlank(number)){
-//                number = "%" + number + "%";
-//            }
-//            if (StringUtils.isNotBlank(name)){
-//                name = "%" + name + "%";
-//            }
-            List<Contract> contracts = contractMapper.selectContractByPin(user.getCompanyId(), pageStart, pageSize, number, name , typeName , status, startDate,endDate, paymentStartDate, paymentEndDate, secTypeId,customerOrg,finishStatus);
-            Long totalCnt = contractMapper.selectContractCnt(user.getCompanyId(), number, name, typeName, status, startDate, endDate, paymentStartDate, paymentEndDate, secTypeId,customerOrg,finishStatus);
+            int type=0;
+            Integer dept=user.getDepartmentId();
+            String userId=user.getId();
+            if (isAll){
+                type=1;//查看全部
+            }else if (isNotAll) {
+                type=2;//查看对应部门
+            }else {
+                type=3;//查看个人
+            }
+            List<Contract> contracts = contractMapper.selectContractByPinWithType(user.getCompanyId(), pageStart, pageSize, number, name , typeName , status, startDate,endDate, paymentStartDate, paymentEndDate, secTypeId,customerOrg,finishStatus,type,dept,userId);
+            Long totalCnt = contractMapper.selectContractContByPinWithType(user.getCompanyId(), number, name, typeName, status, startDate, endDate, paymentStartDate, paymentEndDate, secTypeId,customerOrg,finishStatus,type,dept,userId);
             for (Contract contract : contracts) {
                 if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
                     contract.setCreatorName(contract.getCreatorWxCorpId());
@@ -1721,6 +1753,9 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
     public HttpRespMsg getContractDetail(HttpServletRequest request, Integer id) {
         HttpRespMsg respMsg = new HttpRespMsg();
         Contract contract = contractMapper.selectById(id);
+        if(contract.getDepartmentId()!=null){
+            contract.setDepartmentName(departmentService.getById(contract.getDepartmentId()).getDepartmentName());
+        }
         if (contract.getTypeId()!=null){
             SysDict dict = sysDictService.getById(contract.getTypeId());
             if (dict!=null){
@@ -1736,6 +1771,10 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
                 contract.setNextPaymentAmount(contractPayment.getAmount());
             }
         }
+        List<ContractPayment> contractPaymentList = contractPaymentMapper.selectList(new QueryWrapper<ContractPayment>().eq("is_billed", 1).eq("contract_id",contract.getId()));
+        //已开票金额
+        BigDecimal decimal = contractPaymentList.stream().map(ContractPayment::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
+        contract.setInvoicedAmount(decimal);
         List<ContractCustom> selectedList = contractCustomMapper.selectList(new QueryWrapper<ContractCustom>().eq("contract_id", contract.getId()));
         if (selectedList != null && !selectedList.isEmpty()) {
             contract.setCustomData(selectedList.get(0));
@@ -1748,4 +1787,399 @@ public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> i
         return respMsg;
 
     }
+
+    @Override
+    public HttpRespMsg importContractNew(HttpServletRequest request, MultipartFile multipartFile) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String token = request.getHeader("TOKEN");
+        User user = userMapper.selectById(token);
+        List<SysRichFunction> functionContractList = sysFunctionMapper.getRoleFunctions(user.getRoleId(), "导入合同");
+        if(functionContractList.size() <= 0){
+            msg.setError(MessageUtils.message("access.operationError"));
+            return msg;
+        }
+        Integer companyId = user.getCompanyId();
+        //然后处理文件
+        String fileName = multipartFile.getOriginalFilename();
+        File file = new File(fileName == null ? "file" : fileName);
+        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();
+            //然后解析表格
+            Workbook workbook = WorkbookFactory.create(new FileInputStream(file));
+            Sheet sheet = workbook.getSheetAt(0);
+            int rowNum = sheet.getLastRowNum();
+            if (rowNum == 0) {
+                msg.setError(MessageUtils.message("Contract.dataNull"));
+                return msg;
+            }
+            List<Contract> contractList = contractMapper.selectList(new QueryWrapper<Contract>().eq("company_id", companyId));
+            List<SysDict> sysDictList = sysDictMapper.selectList(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCompanyId, companyId).eq(SysDict::getCode, "ContractType").orderByAsc(SysDict::getSeq));
+            List<Department> departmentList = departmentService.list(new QueryWrapper<Department>().eq("company_id", companyId));
+
+            int dataIndex = 1;
+            HashMap<String, String> map = new HashMap<>();
+            for (int rowIndex = 1; rowIndex <= rowNum; rowIndex++) {
+
+                Row row = sheet.getRow(rowIndex);
+
+                for (int i = 0; i < 17; i++) {
+                    if (row.getCell(i) != null) {
+                        if (i ==2  || i == 11|| i == 15|| i == 16) {
+                            //日期类型的
+                            row.getCell(i).setCellType(CellType.NUMERIC);
+                        } else {
+                            row.getCell(i).setCellType(CellType.STRING);
+                        }
+                    }
+                }
+                if (row!=null){
+                    if (row.getCell(0)==null||row.getCell(1)==null||StringUtils.isEmpty(row.getCell(0).getStringCellValue())||StringUtils.isEmpty(row.getCell(1).getStringCellValue())){
+                        msg.setError("请填写合同编号或合同名称");
+                        return msg;
+                    }
+                    String number = row.getCell(0).getStringCellValue();
+                    String name = row.getCell(1).getStringCellValue();
+                    if (map.containsKey(number)){
+                        if (!map.get(number).equals(name)){
+                            msg.setError("文档中存在合同编号相同但是合同名称不同的数据");
+                            return msg;
+                        }
+                    }
+                    map.put(number,name);
+                }
+            }
+            List<ContractVo> contractVos = new ArrayList<>();
+            for (int rowIndex = 1; rowIndex <= rowNum; rowIndex++) {
+
+                Row row = sheet.getRow(rowIndex);
+                for (int i = 0; i < 17; i++) {
+                    if (row.getCell(i) != null) {
+                        if (i ==2  || i == 11|| i == 15|| i == 16) {
+                            //日期类型的
+                            row.getCell(i).setCellType(CellType.NUMERIC);
+                        } else {
+                            row.getCell(i).setCellType(CellType.STRING);
+                        }
+                    }
+                }
+                if (row!=null){
+                    String number = row.getCell(0).getStringCellValue();
+                    String name = row.getCell(1).getStringCellValue();
+                    double contractAmount = row.getCell(2)==null?0:row.getCell(2).getNumericCellValue();
+                    String contractTypeName =row.getCell(3)==null?"": row.getCell(3).getStringCellValue();
+                    LocalDate startDate = null;
+                    LocalDate endDate = null;
+                    if(row.getCell(4) != null && row.getCell(4).getCellTypeEnum() != CellType.BLANK){
+                        if(!StringUtils.isEmpty(row.getCell(4).getStringCellValue())){
+                            try {
+                                int count = Integer.parseInt(row.getCell(4).getStringCellValue());
+                                // Excel中的日期序列号的基准日期是1900年1月1日
+                                LocalDate baseDate = LocalDate.of(1900, 1, 1);
+                                LocalDate date = baseDate.plusDays(count - 2); // Excel的基准日期是1900年1月0日,所以需要减去2天
+                                startDate = date;
+
+                            } catch (Exception e) {
+                                System.out.println("日期时间格式不正确,应该是yyyy/MM/dd" );
+                                msg.setError("日期时间格式不正确,应该是yyyy/MM/dd");
+                                return msg;
+                            }
+                        }
+                    }
+                    if(row.getCell(5) != null && row.getCell(5).getCellTypeEnum() != CellType.BLANK){
+                        if(!StringUtils.isEmpty(row.getCell(5).getStringCellValue())){
+                            try {
+                                int count = Integer.parseInt(row.getCell(5).getStringCellValue());
+                                // Excel中的日期序列号的基准日期是1900年1月1日
+                                LocalDate baseDate = LocalDate.of(1900, 1, 1);
+                                LocalDate date = baseDate.plusDays(count - 2); // Excel的基准日期是1900年1月0日,所以需要减去2天
+                                endDate = date;
+
+                            } catch (Exception e) {
+                                System.out.println("日期时间格式不正确,应该是yyyy/MM/dd" );
+                                msg.setError("日期时间格式不正确,应该是yyyy/MM/dd");
+                                return msg;
+                            }
+                        }
+                    }
+                    String dept =row.getCell(6)==null?"":  row.getCell(6).getStringCellValue();
+                    String design =row.getCell(7)==null?"":  row.getCell(7).getStringCellValue();
+                    String remarks =row.getCell(8)==null?"":  row.getCell(8).getStringCellValue();
+                    String isReturn = row.getCell(9)==null?"": row.getCell(9).getStringCellValue();
+                    LocalDate returnDate = null;
+                    if(row.getCell(10) != null && row.getCell(10).getCellTypeEnum() != CellType.BLANK){
+                        if(!StringUtils.isEmpty(row.getCell(10).getStringCellValue())){
+                            try {
+                                int count = Integer.parseInt(row.getCell(10).getStringCellValue());
+                                // Excel中的日期序列号的基准日期是1900年1月1日
+                                LocalDate baseDate = LocalDate.of(1900, 1, 1);
+                                LocalDate date = baseDate.plusDays(count - 2); // Excel的基准日期是1900年1月0日,所以需要减去2天
+                                returnDate = date;
+
+                            } catch (Exception e) {
+                                System.out.println("日期时间格式不正确,应该是yyyy/MM/dd" );
+                                msg.setError("日期时间格式不正确,应该是yyyy/MM/dd");
+                                return msg;
+                            }
+                        }
+                    }
+                    double returnAmount = row.getCell(11)==null?0:row.getCell(11).getNumericCellValue();
+                    String isBilled =row.getCell(12)==null?"":  row.getCell(12).getStringCellValue();
+
+                    LocalDate billDate = null;
+                    if(row.getCell(13) != null && row.getCell(13).getCellTypeEnum() != CellType.BLANK){
+                        if(!StringUtils.isEmpty(row.getCell(13).getStringCellValue())){
+                            try {
+                                int count = Integer.parseInt(row.getCell(13).getStringCellValue());
+                                // Excel中的日期序列号的基准日期是1900年1月1日
+                                LocalDate baseDate = LocalDate.of(1900, 1, 1);
+                                LocalDate date = baseDate.plusDays(count - 2); // Excel的基准日期是1900年1月0日,所以需要减去2天
+                                billDate = date;
+
+                            } catch (Exception e) {
+                                System.out.println("日期时间格式不正确,应该是yyyy/MM/dd" );
+                                msg.setError("日期时间格式不正确,应该是yyyy/MM/dd");
+                                return msg;
+                            }
+                        }
+                    }
+                    String billType =row.getCell(14)==null?"":  row.getCell(14).getStringCellValue();
+                    double taxRate = row.getCell(15)==null?0:row.getCell(15).getNumericCellValue();
+                    double taxAmount = row.getCell(16)==null?0:row.getCell(16).getNumericCellValue();
+
+                    ContractVo contractVo = new ContractVo();
+                    contractVo.setNumber(number)
+                            .setName(name)
+                            .setContractAmount(contractAmount)
+                            .setContractType(contractTypeName)
+                            .setStartDate(startDate)
+                            .setEndDate(endDate)
+                            .setDepartmentName(dept)
+                            .setDesign(design)
+                            .setRemark(remarks)
+                            .setIsreturn(isReturn)
+                            .setReturnDate(returnDate)
+                            .setReturnMoney(returnAmount)
+                            .setIsBill(isBilled)
+                            .setBillDate(billDate)
+                            .setBillType(billType)
+                            .setTax(taxAmount)
+                            .setTaxRate(taxRate);
+                    contractVos.add(contractVo);
+                }
+            }
+
+
+            Set<Map.Entry<String, String>> entries = map.entrySet();
+            for (Map.Entry<String, String> entry : entries) {
+                List<ContractVo> voList = contractVos.stream().filter(c -> c.getNumber().equals(entry.getKey())).collect(Collectors.toList());
+                if (voList.size() > 1) {
+                    ContractVo contractVo = voList.get(0);
+                    Contract contract = new Contract();
+                    long count = contractList.stream().filter(c -> c.getNumber().equals(contractVo.getNumber())).count();
+                    if (count >0) {
+                        msg.setError("合同编号:"+contractVo.getNumber()+"已存在");
+                        return msg;
+                    }
+                    contract.setNumber(contractVo.getNumber())
+                            .setName(contractVo.getName())
+                            .setAmounts(BigDecimal.valueOf(contractVo.getContractAmount()))
+                            .setStartDate(contractVo.getStartDate())
+                            .setEndDate(contractVo.getEndDate())
+                            .setPlate1(contractVo.getDesign())
+                            .setRemarks(contractVo.getRemark())
+                            .setCompanyId(user.getCompanyId())
+                            .setCreatorId(user.getId())
+                            .setIndate(LocalDate.now());
+                    if (StringUtils.isNotEmpty(contractVo.getContractType())){
+                        Optional<SysDict> first = sysDictList.stream().filter(s -> s.getName().equals(contractVo.getContractType())).findFirst();
+                        if (first.isPresent()) {
+                            contract.setTypeId(first.get().getId());
+                        }else {
+                            msg.setError("合同不已存在");
+                            return msg;
+                        }
+                    }
+                    if (StringUtils.isNotEmpty(contractVo.getDepartmentName())){
+                        Optional<Department> first = departmentList.stream().filter(d -> d.getDepartmentName().equals(contractVo.getDepartmentName())).findFirst();
+                        if (first.isPresent()) {
+                            contract.setDepartmentId(first.get().getDepartmentId());
+                        }else {
+                            msg.setError("部门名称不已存在");
+                            return msg;
+                        }
+                    }
+                    contractMapper.insert(contract);
+
+                    ArrayList<ContractPayment> paymentArrayList = new ArrayList<>();
+                    for (ContractVo vo : voList) {
+                        ContractPayment payment = new ContractPayment();
+                        if (StringUtils.isNotEmpty(vo.getIsreturn())){
+                            if (vo.getIsreturn().equals("是")){
+                                payment.setIsPayed(true);
+                            }else {
+                                payment.setIsPayed(false);
+                            }
+                        }else {
+                            payment.setIsPayed(false);
+                        }
+                        if (StringUtils.isNotEmpty(vo.getIsBill())){
+                            if (vo.getIsBill().equals("是")){
+                                payment.setIsBilled(1);
+                            }else {
+                                payment.setIsBilled(0);
+                            }
+                        }else {
+                            payment.setIsBilled(0);
+                        }
+                        if (StringUtils.isNotEmpty(vo.getBillType())){
+                            if (vo.getBillType().equals("专票")){
+                                payment.setInvoiceType(0);
+                            }else if (vo.getBillType().equals("普票")){
+                                payment.setInvoiceType(1);
+                            }
+                        }
+                        payment.setContractId(contract.getId())
+                                .setPayDate(vo.getReturnDate())
+                                .setAmount(BigDecimal.valueOf(vo.getReturnMoney()))
+                                .setBillDate(vo.getBillDate())
+                                .setTaxAmount(BigDecimal.valueOf(vo.getTax()))
+                                .setTaxRate(BigDecimal.valueOf(vo.getTaxRate()));
+
+                        paymentArrayList.add(payment);
+                        BigDecimal paymented = contract.getPayment() == null ? BigDecimal.ZERO : contract.getPayment();
+                        if(vo.getIsreturn().equals("是")) {
+                            contract.setPayment(paymented.add(BigDecimal.valueOf(vo.getReturnMoney())));
+                        }
+                    }
+                    contractPaymentService.saveBatch(paymentArrayList);
+                    contractMapper.update(null,new UpdateWrapper<Contract>().set("payment",contract.getPayment()).eq("id",contract.getId()));
+                }
+                else {
+                    ContractVo contractVo = voList.get(0);
+                    Contract contract = new Contract();
+                    long count = contractList.stream().filter(c -> c.getNumber()!=null&&c.getNumber().equals(contractVo.getNumber())).count();
+                    if (count >0) {
+                        msg.setError("合同编号:"+contractVo.getNumber()+"已存在");
+                        return msg;
+                    }
+                    contract.setNumber(contractVo.getNumber())
+                            .setName(contractVo.getName())
+                            .setAmounts(BigDecimal.valueOf(contractVo.getContractAmount()))
+                            .setStartDate(contractVo.getStartDate())
+                            .setEndDate(contractVo.getEndDate())
+                            .setPlate1(contractVo.getDesign())
+                            .setRemarks(contractVo.getRemark())
+                            .setCompanyId(user.getCompanyId())
+                            .setCreatorId(user.getId())
+                            .setIndate(LocalDate.now());
+                    if (StringUtils.isNotEmpty(contractVo.getContractType())){
+                        Optional<SysDict> first = sysDictList.stream().filter(s -> s.getName().equals(contractVo.getContractType())).findFirst();
+                        if (first.isPresent()) {
+                            contract.setTypeId(first.get().getId());
+                        }else {
+                            msg.setError("合同不已存在");
+                            return msg;
+                        }
+                    }
+                    if (StringUtils.isNotEmpty(contractVo.getDepartmentName())){
+                        Optional<Department> first = departmentList.stream().filter(d -> d.getDepartmentName().equals(contractVo.getDepartmentName())).findFirst();
+                        if (first.isPresent()) {
+                            contract.setDepartmentId(first.get().getDepartmentId());
+                        }else {
+                            msg.setError("部门名称不已存在");
+                            return msg;
+                        }
+                    }
+                    contractMapper.insert(contract);
+
+                    ContractPayment payment = new ContractPayment();
+                    if (StringUtils.isNotEmpty(contractVo.getIsreturn())){
+                        if (contractVo.getIsreturn().equals("是")){
+                            payment.setIsPayed(true);
+                        }else {
+                            payment.setIsPayed(false);
+                        }
+                    }else {
+                        payment.setIsPayed(false);
+                    }
+                    if (StringUtils.isNotEmpty(contractVo.getIsBill())){
+                        if (contractVo.getIsBill().equals("是")){
+                            payment.setIsBilled(1);
+                        }else {
+                            payment.setIsBilled(0);
+                        }
+                    }else {
+                        payment.setIsBilled(0);
+                    }
+                    if (StringUtils.isNotEmpty(contractVo.getBillType())){
+                        if (contractVo.getBillType().equals("专票")){
+                            payment.setInvoiceType(0);
+                        }else if (contractVo.getBillType().equals("普票")){
+                            payment.setInvoiceType(1);
+                        }
+                    }
+                    payment.setContractId(contract.getId())
+                            .setPayDate(contractVo.getReturnDate())
+                            .setAmount(BigDecimal.valueOf(contractVo.getReturnMoney()))
+                            .setBillDate(contractVo.getBillDate())
+                            .setTaxAmount(BigDecimal.valueOf(contractVo.getTax()))
+                            .setTaxRate(BigDecimal.valueOf(contractVo.getTaxRate()));
+                    contractPaymentService.save(payment);
+
+                    BigDecimal paymented = contract.getPayment() == null ? BigDecimal.ZERO : contract.getPayment();
+                    if(contractVo.getIsreturn().equals("是")) {
+                        contract.setPayment(paymented.add(BigDecimal.valueOf(contractVo.getReturnMoney())));
+                    }
+                    contractMapper.update(null,new UpdateWrapper<Contract>().set("payment",contract.getPayment()).eq("id",contract.getId()));
+                }
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+            //msg.setError("文件处理出错");
+            msg.setError(MessageUtils.message("file.error"));
+            return msg;
+        } catch (NullPointerException e) {
+            e.printStackTrace();
+            //msg.setError("数据格式有误或存在空数据 导入失败");
+            msg.setError(MessageUtils.message("file.dataFormatError"));
+            return msg;
+        }catch (InvalidFormatException e) {
+            e.printStackTrace();
+            //msg.setError("文件格式错误,如果安装了加密软件需要先解密再上传");
+            msg.setError(MessageUtils.message("file.FormatErrorAndDecrypt"));
+            return msg;
+        }catch (EncryptedDocumentException e) {
+            e.printStackTrace();
+            //msg.setError("文件加密状态,需要先解除加密状态再上传");
+            msg.setError(MessageUtils.message("file.encryption"));
+            return msg;
+        } catch (Exception e) {
+            e.printStackTrace();
+            //msg.setError("发生其他错误:"+e.getMessage());
+            msg.setError(MessageUtils.message("other.errorByParameter",e.getMessage()));
+            return msg;
+        } finally {
+            //关闭流
+            try {
+                if (outputStream != null && inputStream != null) {
+                    outputStream.close();
+                    inputStream.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            file.delete();
+        }
+        return msg;
+    }
 }

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

@@ -306,6 +306,17 @@ public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permiss
             module.setFunctionList(resultFunList.stream().filter(item -> item.getModuleId().equals(module.getId())).collect(Collectors.toList()));
         }
         for (SysModule mainMenu : menuList) {
+            if (company.getIsExistBusiness()==0){
+                if (mainMenu.getName().contains("商机")){
+                    mainMenu.setName(mainMenu.getName().replaceAll("商机","项目"));
+                }
+                List<SysFunction> list = mainMenu.getFunctionList();
+                for (SysFunction fun : list) {
+                    if (fun.getName().contains("商机")){
+                        fun.setName(fun.getName().replaceAll("商机","项目"));
+                    }
+                }
+            }
             List<SysModule> list = moduleList.stream().filter(mod -> mainMenu.getId().equals(mod.getParentId())).collect(Collectors.toList());
             if(timeType.getProjectCustom()==0){
                 Optional<SysModule> first = list.stream().filter(l -> l.getName().equals("项目表单设置")).findFirst();

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

@@ -30,6 +30,7 @@ import javax.servlet.http.HttpServletRequest;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -61,31 +62,44 @@ public class SysFormServiceImpl extends ServiceImpl<SysFormMapper, SysForm> impl
         List<String> heads = new ArrayList<>();
         Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
         Company company = companyMapper.selectById(companyId);
+        String str = company.getIsExistBusiness() == 1 ? "商机" : "项目";
         //根据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);
-            if(item.getString("type").equals("grid")){
-                JSONArray columns = item.getJSONArray("columns");
-                for (int i1 = 0; i1 < columns.size(); i1++) {
-                    JSONObject columnsJSONObject = columns.getJSONObject(i1);
-                    JSONArray list = columnsJSONObject.getJSONArray("list");
-                    for (int i2 = 0; i2 < list.size(); i2++) {
-                        JSONObject object = list.getJSONObject(i2);
-                        heads.add(object.getString("label"));
+        if (!code.equals("Contract")) {
+            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);
+                if (item.getString("type").equals("grid")) {
+                    JSONArray columns = item.getJSONArray("columns");
+                    for (int i1 = 0; i1 < columns.size(); i1++) {
+                        JSONObject columnsJSONObject = columns.getJSONObject(i1);
+                        JSONArray list = columnsJSONObject.getJSONArray("list");
+                        for (int i2 = 0; i2 < list.size(); i2++) {
+                            JSONObject object = list.getJSONObject(i2);
+                            heads.add(object.getString("label"));
+                        }
                     }
+                } else {
+                    heads.add(item.getString("label"));
                 }
-            }else {
-                heads.add(item.getString("label"));
             }
-
+            if (code.equals("Business")){
+                for (int i = 0; i < heads.size(); i++) {
+                    String s = heads.get(i);
+                    if (s.contains("商机")) {
+                        s = s.replaceAll("商机", str);
+                        heads.set(i, s);
+                    }
+                }
+            }
+        }else {
+            Collections.addAll(heads,"合同编号","合同名称","合同金额","合同类型","计划开始时间","计划结束时间","部门","自定义字段","备注","是否已回款","回款日期","金额","是否已开票","开票日期","发票种类","税率","税额");
         }
         List<List<String>> allList = new ArrayList<>();
         allList.add(heads);
@@ -103,7 +117,7 @@ public class SysFormServiceImpl extends ServiceImpl<SysFormMapper, SysForm> impl
                 break;
             case "Contacts":title = company.getCompanyName()+"_联系人导入模板";
                 break;
-            case "Business":title = company.getCompanyName()+"_商机导入模板";
+            case "Business":title = company.getCompanyName()+"_"+str+"导入模板";
                 break;
             case "Contract":title = company.getCompanyName()+"_合同导入模板";
                 break;

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 28 - 9
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java


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

@@ -24,11 +24,12 @@
         <result column="create_date" property="createDate" />
         <result column="reg_from" property="regFrom" />
         <result column="non_project_simple" property="nonProjectSimple" />
+        <result column="is_exist_business" property="isExistBusiness" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, company_name, staff_count_max, expiration_date, set_meal, package_worktime, package_project, package_contract, package_oa, package_etimecard, package_expense, package_customer, package_engineering, package_simple, package_finance, package_provider, is_international, create_date, reg_from, non_project_simple
+        id, company_name, staff_count_max, expiration_date, set_meal, package_worktime, package_project, package_contract, package_oa, package_etimecard, package_expense, package_customer, package_engineering, package_simple, package_finance, package_provider, is_international, create_date, reg_from, non_project_simple, is_exist_business
     </sql>
 
 </mapper>

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

@@ -20,6 +20,7 @@
         <result column="remarks" property="remarks" />
         <result column="payment" property="payment" />
         <result column="sec_type_id" property="secTypeId" />
+        <result column="department_id" property="departmentId" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
@@ -30,7 +31,7 @@
         select contract.id,contract.company_id,contract.creator_id,contract.number,contract.name,contract.amounts,contract.type_id,sys_dict.name typeName,contract.status,contract.indate,contract.remarks,
         contract.start_date as startDate,contract.end_date as endDate,contract_type_sec.sec_type_name,contract.sec_type_id,
         user.name as creatorName,user.corpwx_userid as creatorWxCorpId, contract.project_id, contract.payment, cp.pay_date AS next_payment_date, cp.amount AS next_payment_amount,
-        contract.plate1,contract.plate2,contract.plate3,contract.plate4,contract.plate5,contract.need_pin,contract.pin_time
+        contract.plate1,contract.plate2,contract.plate3,contract.plate4,contract.plate5,contract.need_pin,contract.pin_time,contract.department_id
         from contract
         left join sys_dict on contract.type_id = sys_dict.id
         left join contract_type_sec on contract.sec_type_id = contract_type_sec.id
@@ -113,7 +114,7 @@
         select contract.id,contract.company_id,contract.creator_id,contract.number,contract.name,contract.amounts,contract.type_id,sys_dict.name typeName,contract.status,contract.indate,contract.remarks,
         contract.start_date as startDate,contract.end_date as endDate,contract_type_sec.sec_type_name,contract.sec_type_id,
         user.name as creatorName,user.corpwx_userid as creatorWxCorpId, contract.project_id, contract.payment, cp.pay_date AS next_payment_date, cp.amount AS next_payment_amount,
-        contract.plate1,contract.plate2,contract.plate3,contract.plate4,contract.plate5,contract.need_pin,contract.pin_time
+        contract.plate1,contract.plate2,contract.plate3,contract.plate4,contract.plate5,contract.need_pin,contract.pin_time,contract.department_id,d.department_name as departmentName
         from contract
         left join sys_dict on contract.type_id = sys_dict.id
         left join contract_type_sec on contract.sec_type_id = contract_type_sec.id
@@ -121,6 +122,7 @@
         left join user
         on contract.creator_id = user.id
         left join contract_custom cc on cc.contract_id=contract.id
+        left join department d on  d.department_id=contract.department_id
         where contract.company_id = #{companyId}
         <if test="number!=null">
             and number like CONCAT('%', #{number}, '%')
@@ -154,4 +156,198 @@
             limit #{pageStart},#{pageSize}
         </if>
     </select>
+    <select id="selectContractWithType" resultType="com.management.platform.entity.Contract">
+        select contract.id,contract.company_id,contract.creator_id,contract.number,contract.name,contract.amounts,contract.type_id,sys_dict.name typeName,contract.status,contract.indate,contract.remarks,
+        contract.start_date as startDate,contract.end_date as endDate,contract_type_sec.sec_type_name,contract.sec_type_id,
+        user.name as creatorName,user.corpwx_userid as creatorWxCorpId, contract.project_id, contract.payment, cp.pay_date AS next_payment_date, cp.amount AS next_payment_amount,
+        contract.plate1,contract.plate2,contract.plate3,contract.plate4,contract.plate5,contract.need_pin,contract.pin_time,contract.department_id,d.department_name as departmentName
+        from contract
+        left join sys_dict on contract.type_id = sys_dict.id
+        left join contract_type_sec on contract.sec_type_id = contract_type_sec.id
+        LEFT JOIN (SELECT contract_id, pay_date, amount FROM contract_payment WHERE is_payed = 0 GROUP BY contract_id) cp ON cp.contract_id=contract.id
+        left join user
+        on contract.creator_id = user.id
+        left join contract_custom cc on cc.contract_id=contract.id
+        left join department d on  d.department_id=contract.department_id
+        where contract.company_id = #{companyId}
+        <if test="number!=null">
+            and number like CONCAT('%', #{number}, '%')
+        </if>
+        <if test="name!=null">
+            and contract.name like CONCAT('%', #{name}, '%')
+        </if>
+        <if test="typeName!=null">
+            and sys_dict.id = #{typeName}
+        </if>
+        <if test="secTypeId!=null">
+            and contract.sec_type_id = #{secTypeId}
+        </if>
+        <if test="status!=null">
+            and status = #{status}
+        </if>
+        <if test="startDate!=null and endDate !=null">
+            and indate between #{startDate} and #{endDate}
+        </if>
+        <if test="paymentStartDate != null and paymentEndDate != null">
+            and cp.pay_date between #{paymentStartDate} and #{paymentEndDate}
+        </if>
+        <if test="finishStatus!=null">
+            and cc.finish_status = #{finishStatus}
+        </if>
+        <if test="customerOrg!=null">
+            and cc.customer_org like  CONCAT('%', #{customerOrg}, '%')
+        </if>
+        <if test="type == 2 and dept!=null">
+            and contract.department_id=#{dept}
+        </if>
+        <if test="type == 3 and userId!=null">
+            and contract.creator_id=#{userId}
+        </if>
+        order by contract.id desc
+        <if test="pageStart!=null and pageSize!=null">
+            limit #{pageStart},#{pageSize}
+        </if>
+    </select>
+    <select id="selectContractCntWithType" resultType="java.lang.Long">
+        select count(1) from contract
+        left join contract_type
+        on contract.type_id = contract_type.id
+        LEFT JOIN (SELECT contract_id, pay_date, amount FROM contract_payment WHERE is_payed = 0 GROUP BY contract_id) cp ON cp.contract_id=contract.id
+        left join user
+        on contract.creator_id = user.id
+        left join sys_dict on contract.type_id = sys_dict.id
+        left join contract_custom cc on cc.contract_id=contract.id
+        left join department d on d.department_id=contract.department_id
+        where contract.company_id = #{companyId}
+        <if test="number!=null">
+            and number like CONCAT('%', #{number}, '%')
+        </if>
+        <if test="name!=null">
+            and contract.name like CONCAT('%', #{name}, '%')
+        </if>
+        <if test="typeName!=null">
+            and  sys_dict.id = #{typeName}
+        </if>
+        <if test="secTypeId!=null">
+            and contract.sec_type_id = #{secTypeId}
+        </if>
+        <if test="status!=null">
+            and status = #{status}
+        </if>
+        <if test="startDate!=null and endDate !=null">
+            and indate between #{startDate} and #{endDate}
+        </if>
+        <if test="paymentStartDate != null and paymentEndDate != null">
+            and cp.pay_date between #{paymentStartDate} and #{paymentEndDate}
+        </if>
+        <if test="finishStatus!=null">
+            and cc.finish_status = #{finishStatus}
+        </if>
+        <if test="customerOrg!=null">
+            and cc.customer_org like  CONCAT('%', #{customerOrg}, '%')
+        </if>
+        <if test="type == 2 and dept!=null">
+            and contract.department_id=#{dept}
+        </if>
+        <if test="type == 3 and userId!=null">
+            and contract.creator_id=#{userId}
+        </if>
+    </select>
+    <select id="selectContractContByPinWithType" resultType="java.lang.Long">
+        select count(1)
+        from contract
+        left join sys_dict on contract.type_id = sys_dict.id
+        left join contract_type_sec on contract.sec_type_id = contract_type_sec.id
+        LEFT JOIN (SELECT contract_id, pay_date, amount FROM contract_payment WHERE is_payed = 0 GROUP BY contract_id) cp ON cp.contract_id=contract.id
+        left join user
+        on contract.creator_id = user.id
+        left join contract_custom cc on cc.contract_id=contract.id
+        left join department d on  d.department_id=contract.department_id
+        where contract.company_id = #{companyId}
+        <if test="number!=null">
+            and number like CONCAT('%', #{number}, '%')
+        </if>
+        <if test="name!=null">
+            and contract.name like CONCAT('%', #{name}, '%')
+        </if>
+        <if test="typeName!=null">
+            and sys_dict.name = #{typeName}
+        </if>
+        <if test="secTypeId!=null">
+            and contract.sec_type_id = #{secTypeId}
+        </if>
+        <if test="status!=null">
+            and status = #{status}
+        </if>
+        <if test="startDate!=null and endDate !=null">
+            and indate between #{startDate} and #{endDate}
+        </if>
+        <if test="paymentStartDate != null and paymentEndDate != null">
+            and cp.pay_date between #{paymentStartDate} and #{paymentEndDate}
+        </if>
+        <if test="finishStatus!=null">
+            and cc.finish_status = #{finishStatus}
+        </if>
+        <if test="customerOrg!=null">
+            and cc.customer_org like  CONCAT('%', #{customerOrg}, '%')
+        </if>
+        <if test="type == 2 and dept!=null">
+            and contract.department_id=#{dept}
+        </if>
+        <if test="type == 3 and userId!=null">
+            and contract.creator_id=#{userId}
+        </if>
+    </select>
+    <select id="selectContractByPinWithType" resultType="com.management.platform.entity.Contract">
+        select contract.id,contract.company_id,contract.creator_id,contract.number,contract.name,contract.amounts,contract.type_id,sys_dict.name typeName,contract.status,contract.indate,contract.remarks,
+        contract.start_date as startDate,contract.end_date as endDate,contract_type_sec.sec_type_name,contract.sec_type_id,
+        user.name as creatorName,user.corpwx_userid as creatorWxCorpId, contract.project_id, contract.payment, cp.pay_date AS next_payment_date, cp.amount AS next_payment_amount,
+        contract.plate1,contract.plate2,contract.plate3,contract.plate4,contract.plate5,contract.need_pin,contract.pin_time,contract.department_id,d.department_name as departmentName
+        from contract
+        left join sys_dict on contract.type_id = sys_dict.id
+        left join contract_type_sec on contract.sec_type_id = contract_type_sec.id
+        LEFT JOIN (SELECT contract_id, pay_date, amount FROM contract_payment WHERE is_payed = 0 GROUP BY contract_id) cp ON cp.contract_id=contract.id
+        left join user
+        on contract.creator_id = user.id
+        left join contract_custom cc on cc.contract_id=contract.id
+        left join department d on  d.department_id=contract.department_id
+        where contract.company_id = #{companyId}
+        <if test="number!=null">
+            and number like CONCAT('%', #{number}, '%')
+        </if>
+        <if test="name!=null">
+            and contract.name like CONCAT('%', #{name}, '%')
+        </if>
+        <if test="typeName!=null">
+            and sys_dict.name = #{typeName}
+        </if>
+        <if test="secTypeId!=null">
+            and contract.sec_type_id = #{secTypeId}
+        </if>
+        <if test="status!=null">
+            and status = #{status}
+        </if>
+        <if test="startDate!=null and endDate !=null">
+            and indate between #{startDate} and #{endDate}
+        </if>
+        <if test="paymentStartDate != null and paymentEndDate != null">
+            and cp.pay_date between #{paymentStartDate} and #{paymentEndDate}
+        </if>
+        <if test="finishStatus!=null">
+            and cc.finish_status = #{finishStatus}
+        </if>
+        <if test="customerOrg!=null">
+            and cc.customer_org like  CONCAT('%', #{customerOrg}, '%')
+        </if>
+        <if test="type == 2 and dept!=null">
+            and contract.department_id=#{dept}
+        </if>
+        <if test="type == 3 and userId!=null">
+            and contract.creator_id=#{userId}
+        </if>
+        order by contract.need_pin desc,contract.pin_time desc,contract.id desc
+        <if test="pageStart!=null and pageSize!=null">
+            limit #{pageStart},#{pageSize}
+        </if>
+    </select>
 </mapper>

+ 6 - 1
fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/ContractPaymentMapper.xml

@@ -9,11 +9,16 @@
         <result column="pay_date" property="payDate" />
         <result column="amount" property="amount" />
         <result column="is_payed" property="isPayed" />
+        <result column="is_billed" property="isBilled" />
+        <result column="bill_date" property="billDate" />
+        <result column="invoice_type" property="invoiceType" />
+        <result column="tax_amount" property="taxAmount" />
+        <result column="tax_rate" property="taxRate" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, contract_id, pay_date, amount, is_payed
+        id, contract_id, pay_date, amount, is_payed, is_billed, bill_date, invoice_type, tax_amount, tax_rate
     </sql>
 
 </mapper>

+ 10 - 7
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java

@@ -1359,18 +1359,21 @@ public class ReportController {
                 }
                 for (Report report : targetCheckList) {
                     HttpRespMsg httpRespMsg = new HttpRespMsg();
-                    Optional<Project> first = targetProjectList.stream().filter(tl -> tl.getId().equals(report.getProjectId())).findFirst();
+                    //按项目进行校验
+                    Integer curProjectId = report.getProjectId();
+                    Optional<Project> first = targetProjectList.stream().filter(tl -> tl.getId().equals(curProjectId)).findFirst();
                     if(first.isPresent()){
-                        double nowReport = targetCheckList.stream().filter(rl -> rl.getCreateDate().equals(report.getCreateDate()) && rl.getCreatorId().equals(report.getCreatorId())).mapToDouble(Report::getWorkingTime).sum();
+                        //增加项目id过滤
+                        double todayProjectTime = targetCheckList.stream().filter(rl -> rl.getCreateDate().equals(report.getCreateDate()) && rl.getCreatorId().equals(report.getCreatorId()) && rl.getProjectId().equals(curProjectId)).mapToDouble(Report::getWorkingTime).sum();
                         if(first.get().getManDay()!=null && first.get().getManDay()>0){
                             //已填报的工时情况
                             double sum;
                             if(first.get().getManDayStartDate()!=null){
-                                sum = oldRelatedReportList.stream().filter(npl -> npl.getProjectId().equals(first.get().getId()) &&(npl.getCreateDate().isAfter(first.get().getManDayStartDate())||npl.getCreateDate().isEqual(first.get().getManDayStartDate()))&& (npl.getState() == 0 || npl.getState() == 1)).mapToDouble(Report::getWorkingTime).sum();
+                                sum = oldRelatedReportList.stream().filter(npl -> npl.getProjectId().equals(curProjectId) &&(npl.getCreateDate().isAfter(first.get().getManDayStartDate())||npl.getCreateDate().isEqual(first.get().getManDayStartDate()))&& (npl.getState() == 0 || npl.getState() == 1)).mapToDouble(Report::getWorkingTime).sum();
                             }else {
-                                sum = oldRelatedReportList.stream().filter(npl -> npl.getProjectId().equals(first.get().getId()) && (npl.getState() == 0 || npl.getState() == 1)).mapToDouble(Report::getWorkingTime).sum();
+                                sum = oldRelatedReportList.stream().filter(npl -> npl.getProjectId().equals(curProjectId) && (npl.getState() == 0 || npl.getState() == 1)).mapToDouble(Report::getWorkingTime).sum();
                             }
-                            BigDecimal hasReport = new BigDecimal(sum).add(new BigDecimal(nowReport));
+                            BigDecimal hasReport = new BigDecimal(sum).add(new BigDecimal(todayProjectTime));
                             BigDecimal multiply = new BigDecimal(first.get().getManDay()).multiply(new BigDecimal(comTimeType.getAllday()));
                             if(hasReport.doubleValue()>multiply.doubleValue()){
                                 sendReportTimeWarningMsg(company, first.get(), null, null);
@@ -1396,8 +1399,8 @@ public class ReportController {
                                     }else {
                                         groupSum = oldRelatedReportList.stream().filter(npl -> npl.getGroupId().equals(targetGpId) && (npl.getState() == 0 || npl.getState() == 1)).mapToDouble(Report::getWorkingTime).sum();
                                     }
-                                    nowReport = targetCheckList.stream().filter(rl -> rl.getCreateDate().equals(report.getCreateDate()) && rl.getCreatorId().equals(report.getCreatorId()) && targetGpId.equals(rl.getGroupId())).mapToDouble(Report::getWorkingTime).sum();
-                                    hasReport = new BigDecimal(groupSum).add(new BigDecimal(nowReport));
+                                    todayProjectTime = targetCheckList.stream().filter(rl -> rl.getCreateDate().equals(report.getCreateDate()) && rl.getCreatorId().equals(report.getCreatorId()) && targetGpId.equals(rl.getGroupId())).mapToDouble(Report::getWorkingTime).sum();
+                                    hasReport = new BigDecimal(groupSum).add(new BigDecimal(todayProjectTime));
                                     TaskGroup tgp = taskGroupService.getById(targetGpId);
                                     //设置的数值大于0时检查是否超额
                                     if (tgp != null && tgp.getManDay() != null && tgp.getManDay() > 0) {

+ 18 - 4
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TaskController.java

@@ -528,8 +528,23 @@ public class TaskController {
                 return msg;
             }
         }
-        //检查前置任务是否都已经完成
+        //检查是否要核验成果文件
+        Task curTask = taskMapper.selectById(task.getId());
+        if (curTask.getAttachFileRequired() && task.getTaskStatus() == 0) {
+            Integer cnt = taskFilesMapper.selectCount(new QueryWrapper<TaskFiles>().eq("task_id",task.getId()));
+            if (cnt == 0) {
+                msg.setError("当前任务必须要上传成果附件才可以完成");
+                return msg;
+            } else {
+                cnt = taskFilesMapper.selectCount(new QueryWrapper<TaskFiles>().eq("task_id",task.getId()).eq("final_charge_status",0));
+                if (cnt > 0) {
+                    msg.setError("当前任务存在尚未审核通过的成果附件,不可完成");
+                    return msg;
+                }
+            }
+        }
 
+        //检查前置任务是否都已经完成
         boolean isFinishTask = false;
         if (task.getTaskStatus() == 0) {
             task.setTaskStatus(1);
@@ -620,9 +635,8 @@ public class TaskController {
         }
 
         //如果是里程碑,需要更新项目完成度
-        task = taskMapper.selectById(task.getId());
-        if (task.getTaskType() == 1) {
-            Integer projectId = task.getProjectId();
+        if (curTask.getTaskType() == 1) {
+            Integer projectId = curTask.getProjectId();
             updateProjectProgress(projectId);
         }
         return msg;

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

@@ -1184,10 +1184,10 @@ public class WeiXinCorpController {
                             if (department.contains(",")) {
                                 String[] split = department.split(",");
                                 curUserWXDeptid = getMaxDeptIdFromArray(split);
-                            } else {
+                            } else if (!StringUtils.isEmpty(department)){
                                 curUserWXDeptid = Integer.valueOf(department);
                             }
-                        } else if (jsonObject.has("MainDepartment")) {
+                        } else if (jsonObject.has("MainDepartment") && !StringUtils.isEmpty(jsonObject.getString("MainDepartment"))) {
                             //取主部门
                             curUserWXDeptid = jsonObject.getInt("MainDepartment");
                         } else {

+ 7 - 6
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Task.java

@@ -15,18 +15,13 @@ import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 import org.springframework.format.annotation.DateTimeFormat;
 
-import java.io.Serializable;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.List;
-
 /**
  * <p>
  * 
  * </p>
  *
  * @author Seyason
- * @since 2025-01-04
+ * @since 2025-02-28
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -305,6 +300,12 @@ public class Task extends Model<Task> {
      * 任务的外置状态显示 1审核中[待审核+(审核通过)] 2驳回[存在驳回文件]  3审核通过[全部审核通过]
      * */
     private int fileChargeStatus;
+    /**
+     * 完成任务时,成果文件是否必传
+     */
+    @TableField("attach_file_required")
+    private Boolean attachFileRequired;
+
 
     @Override
     protected Serializable pkVal() {

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

@@ -1364,18 +1364,18 @@ public class DingDingServiceImpl implements DingDingService {
                                         companyMapper.updateById(company);
                                     } else if ("RENEW".equals(orderType)) {
                                         System.out.println("==Push 推送事件 续费套餐=="+biz_data.toJSONString());
-                                        int serviceStopTime = biz_data.getIntValue("serviceStopTime");
+                                        long serviceStopTime = biz_data.getLongValue("serviceStopTime");
                                         company.setExpirationDate(LocalDateTime.ofEpochSecond(serviceStopTime/1000, 0, ZoneOffset.ofHours(8)));
                                         companyMapper.updateById(company);
                                     } else if ("RENEW_UPGRADE".equals(orderType)) {
                                         System.out.println("==Push 推送事件 续费升级套餐=="+biz_data.toJSONString());
-                                        int serviceStopTime = biz_data.getIntValue("serviceStopTime");
+                                        long serviceStopTime = biz_data.getLongValue("serviceStopTime");
                                         company.setStaffCountMax(subQuantity);
                                         company.setExpirationDate(LocalDateTime.ofEpochSecond(serviceStopTime/1000, 0, ZoneOffset.ofHours(8)));
                                         companyMapper.updateById(company);
                                     } else if ("RENEW_DEGRADE".equals(orderType)) {
                                         System.out.println("==Push 推送事件 续费降级套餐=="+biz_data.toJSONString());
-                                        int serviceStopTime = biz_data.getIntValue("serviceStopTime");
+                                        long serviceStopTime = biz_data.getLongValue("serviceStopTime");
                                         company.setStaffCountMax(subQuantity);
                                         company.setExpirationDate(LocalDateTime.ofEpochSecond(serviceStopTime/1000, 0, ZoneOffset.ofHours(8)));
                                         companyMapper.updateById(company);

+ 10 - 4
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ExpenseSheetServiceImpl.java

@@ -481,7 +481,7 @@ public class ExpenseSheetServiceImpl extends ServiceImpl<ExpenseSheetMapper, Exp
             }
         }
         //柘中报销人填写报销单信息,完善填报金额,第一审核人,第二审核人信息,给第一审核人发送信息
-        if (!isNew&& auditSetting != null && auditSetting.getAuditType() == 2&&sheet.getReviewProcess()==0){
+        if (!isNew&& auditSetting != null && auditSetting.getAuditType() == 2&&sheet.getReviewProcess()==0&&expenseMainType!=null){
             log.info("柘中报销人填写报销单信息,完善填报金额,第一审核人,第二审核人信息,给第一审核人发送信息");
             //发送给第一审核人审核
             List<User> targetUserList = new ArrayList<>();
@@ -745,6 +745,9 @@ public class ExpenseSheetServiceImpl extends ServiceImpl<ExpenseSheetMapper, Exp
             }
         }
         expenseSheet.setInvoiceList(list);
+        if (expenseSheet.getType()!=null){
+            expenseSheet.setExpenseMainTypeName(expenseMainTypeService.getById(expenseSheet.getType()).getName());
+        }
         double amount = list.stream().mapToDouble(item -> Optional.ofNullable(item.getAmount()).orElse(0.0)).sum();
         expenseSheet.setTotalAmount(amount);
         HttpRespMsg msg = new HttpRespMsg();
@@ -759,6 +762,7 @@ public class ExpenseSheetServiceImpl extends ServiceImpl<ExpenseSheetMapper, Exp
         String token = request.getHeader("TOKEN");
         User user = userMapper.selectById(token);
         ExpenseSheet sheet = expenseSheetMapper.selectById(id);
+        ExpenseMainType expenseMainType = expenseMainTypeService.getById(sheet.getType());
         ExpenseAuditSetting expenseAuditSetting = expenseAuditSettingMapper.selectById(user.getCompanyId());
         if(expenseAuditSetting!=null&&expenseAuditSetting.getAuditType()==2){
             if(sheet.getReviewProcess()!=null&&sheet.getReviewProcess()==0&& org.apache.commons.lang3.StringUtils.isNotEmpty(sheet.getSecondCheckerId())){
@@ -812,12 +816,14 @@ public class ExpenseSheetServiceImpl extends ServiceImpl<ExpenseSheetMapper, Exp
                         informationList.add(information);
                     }
                     informationService.saveBatch(informationList);
-                }{
+                }
+                else if(wxCorpInfo != null&&expenseMainType!=null){
                     User targetUser = userMapper.selectById(sheet.getOwnerId());
                     //推送到企业微信
                     StringBuilder stringBuilder = new StringBuilder();
-                    stringBuilder.append("报销人:").append("$userName="+targetUser.getCorpwxUserid()+"$")
-                            .append(",填写了机械费用报销单的信息,请及时审核");
+                    stringBuilder.append("请及时审核").append("报销人:").append("$userName="+targetUser.getCorpwxUserid()+"$")
+                            .append(expenseMainType.getName()).append("的报销单");
+
 
                     wxCorpInfoService.sendWXCorpMsg(wxCorpInfo,secondChecker.getCorpwxUserid(), stringBuilder.toString(), "expense",
                             WxCorpInfoServiceImpl.TEXT_CARD_MSG_EXPENSE_NEED);

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

@@ -3607,7 +3607,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                         BigDecimal leaveDays=new BigDecimal(0);
                         BigDecimal leaveTimes=new BigDecimal(0);
                         for (LeaveSheet leaveSheet : leaveSheets) {
-                            leaveDays=leaveDays.add(new BigDecimal(leaveSheet.getTimeDays()));
+                            leaveDays=leaveDays.add(new BigDecimal(leaveSheet.getTimeDays()==null?0:leaveSheet.getTimeDays()));
                             leaveTimes=leaveTimes.add(new BigDecimal(leaveSheet.getTimeHours()));
                         }
                         user.put("leaveType",leaveType);

+ 56 - 54
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TaskMapper.xml

@@ -33,7 +33,9 @@
         <result column="ahead_tid" property="aheadTid" />
         <result column="sap_task_code" property="sapTaskCode" />
         <result column="plan_cost" property="planCost" />
+        <result column="attach_file_required" property="attachFileRequired" />
     </resultMap>
+
     <resultMap id="timeResultMap" type="com.management.platform.entity.TimeTask" >
         <id column="id" property="id" />
         <result column="name" property="name" />
@@ -97,16 +99,16 @@
         <result column="sap_task_code" property="sapTaskCode" />
         <result column="stages_name" property="stagesName" />
         <result column="department_name" property="departmentName" />
-
-<!--        <result column="charge_one_id" property="chargeOneId" />-->
-<!--        <result column="charge_one_status" property="chargeOneStatus" />-->
-<!--        <result column="charge_one_time" property="chargeOneTime" />-->
-<!--        <result column="charge_two_id" property="chargeTwoId" />-->
-<!--        <result column="charge_two_status" property="chargeTwoStatus" />-->
-<!--        <result column="charge_two_time" property="chargeTwoTime" />-->
-<!--        <result column="charge_stage" property="chargeStage" />-->
-<!--        <result column="final_charge_status" property="finalChargeStatus" />-->
-<!--        <result column="file_reject_reason" property="fileRejectReason"></result>-->
+        <result column="attach_file_required" property="attachFileRequired" />
+        <!--        <result column="charge_one_id" property="chargeOneId" />-->
+        <!--        <result column="charge_one_status" property="chargeOneStatus" />-->
+        <!--        <result column="charge_one_time" property="chargeOneTime" />-->
+        <!--        <result column="charge_two_id" property="chargeTwoId" />-->
+        <!--        <result column="charge_two_status" property="chargeTwoStatus" />-->
+        <!--        <result column="charge_two_time" property="chargeTwoTime" />-->
+        <!--        <result column="charge_stage" property="chargeStage" />-->
+        <!--        <result column="final_charge_status" property="finalChargeStatus" />-->
+        <!--        <result column="file_reject_reason" property="fileRejectReason"></result>-->
     </resultMap>
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
@@ -679,61 +681,61 @@
     <select id="getTaskFileChargePageTotal" resultType="java.lang.Integer">
         select count(*)
         from
-            (
-                select tf.task_id
-                from task_files tf
-                         left join task on tf.task_id = task.id
-                         left join project p on task.project_id = p.id
-                <where>
-                    tf.need_file_charge = 1
-                    and tf.final_charge_status = 0
-                    and task.task_status = 0
-                    and task.company_id = #{queryBO.companyId}
-                    and case tf.charge_stage
-                    when 1 then tf.charge_one_id = #{queryBO.userId} and tf.charge_one_status = 0
-                    when 2 then tf.charge_two_id = #{queryBO.userId} and tf.charge_two_status = 0
-                    end
-                    <if test="queryBO.taskName != null and queryBO.taskName != ''">
-                        and task.name like concat('%',#{queryBO.taskName},'%')
-                    </if>
-                    <if test="deptIds!=null and deptIds.size()>0">
-                        and p.dept_id in
-                        <foreach collection="deptIds" open="(" close=")" separator="," item="item">
-                            #{item}
-                        </foreach>
-                    </if>
-                </where>
-                group by tf.task_id
-            )tmp1
+        (
+        select tf.task_id
+        from task_files tf
+        left join task on tf.task_id = task.id
+        left join project p on task.project_id = p.id
+        <where>
+            tf.need_file_charge = 1
+            and tf.final_charge_status = 0
+            and task.task_status = 0
+            and task.company_id = #{queryBO.companyId}
+            and case tf.charge_stage
+            when 1 then tf.charge_one_id = #{queryBO.userId} and tf.charge_one_status = 0
+            when 2 then tf.charge_two_id = #{queryBO.userId} and tf.charge_two_status = 0
+            end
+            <if test="queryBO.taskName != null and queryBO.taskName != ''">
+                and task.name like concat('%',#{queryBO.taskName},'%')
+            </if>
+            <if test="deptIds!=null and deptIds.size()>0">
+                and p.dept_id in
+                <foreach collection="deptIds" open="(" close=")" separator="," item="item">
+                    #{item}
+                </foreach>
+            </if>
+        </where>
+        group by tf.task_id
+        )tmp1
     </select>
     <select id="getProjectAllTaskTimeCost"
             resultType="com.management.platform.entity.vo.ProjectTaskTimeCostVO">
         SELECT task.id as taskId,ifnull(task_executor.`plan_hours`,0) as planHours,
-        (SELECT IFNULL(SUM(working_time),0) FROM report WHERE report.`task_id` = task.id AND report.`state` = 1
-                                                          and report.creator_id = task_executor.executor_id) AS realHours,
-        task_executor.executor_id as executorId
+               (SELECT IFNULL(SUM(working_time),0) FROM report WHERE report.`task_id` = task.id AND report.`state` = 1
+                                                                 and report.creator_id = task_executor.executor_id) AS realHours,
+               task_executor.executor_id as executorId
         FROM task
-        LEFT JOIN project ON project.id = task.`project_id`
-        left join task_executor on task_executor.task_id=task.id
+                 LEFT JOIN project ON project.id = task.`project_id`
+                 left join task_executor on task_executor.task_id=task.id
         WHERE task.project_id = #{projectId}
           and project.id = #{projectId}
     </select>
     <select id="getProjectTaskTimeCostByIds" resultType="com.management.platform.entity.vo.ProjectTimeCostVO">
         select project_id,sum(planHours) as planHoursSum,sum(realHours) as realHoursSum
         from
-            (
-                SELECT task.project_id,task.id as taskId,ifnull(task_executor.`plan_hours`,0) as planHours,
-                       (SELECT IFNULL(SUM(working_time),0) FROM report
-                        WHERE report.`task_id` = task.id AND report.`state` = 1 and report.creator_id = task_executor.executor_id) AS realHours,
-                       task_executor.executor_id as executorId
-                FROM task
-                         LEFT JOIN project ON project.id = task.`project_id`
-                         left join task_executor on task_executor.task_id=task.id
-                WHERE task.project_id in
-                      <foreach collection="projectIds" item="projectId" separator="," open="(" close=")">
-                            #{projectId}
-                        </foreach>
-            )tmp1
+        (
+        SELECT task.project_id,task.id as taskId,ifnull(task_executor.`plan_hours`,0) as planHours,
+        (SELECT IFNULL(SUM(working_time),0) FROM report
+        WHERE report.`task_id` = task.id AND report.`state` = 1 and report.creator_id = task_executor.executor_id) AS realHours,
+        task_executor.executor_id as executorId
+        FROM task
+        LEFT JOIN project ON project.id = task.`project_id`
+        left join task_executor on task_executor.task_id=task.id
+        WHERE task.project_id in
+        <foreach collection="projectIds" item="projectId" separator="," open="(" close=")">
+            #{projectId}
+        </foreach>
+        )tmp1
         group by project_id
     </select>
 </mapper>

+ 3 - 2
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java

@@ -204,8 +204,9 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
         List<Report> allFileProcReportList = reportMapper.selectList(new QueryWrapper<Report>().eq("plan_id", report.getPlanId()).eq("prod_procedure_id", report.getProdProcedureId()));
         final LocalDate fDate = targetDate;
         double allFileProcNum = allFileProcReportList.stream().filter(item->!(item.getCreatorId().equals(token) && item.getCreateDate().isEqual(fDate))).mapToDouble(Report::getFinishNum).sum();
-        if (allFileProcNum + report.getFinishNum() > plan.getNum()) {
-            httpRespMsg.setError("填报的件数超过了剩余可填报件数:"+(plan.getNum() - allFileProcNum)+", 请联系班组长协调解决");
+        double leftNum = new BigDecimal(plan.getNum() - allFileProcNum).setScale(2, RoundingMode.HALF_UP).doubleValue();
+        if (report.getFinishNum() > leftNum) {
+            httpRespMsg.setError("填报的件数超过了剩余可填报件数:"+leftNum+", 请联系班组长协调解决");
             return httpRespMsg;
         }
         //检查钢印号是否已经被同工序里面的其他人报过了

+ 10 - 10
fhKeeper/formulahousekeeper/timesheet-workshop/config/index.js

@@ -1,20 +1,20 @@
 var path = require('path')
 
-//  var ip = '192.168.2.12'
+ var ip = '192.168.2.11'
 // var ip = '47.101.180.183'
 // var ip = '47.100.37.243'
 // var ip = '192.168.10.2'
 //var ip = '192.168.2.12'
 
-var os = require('os'), ip = '', ifaces = os.networkInterfaces() // 获取本机ip
-for (var i in ifaces) {
-    for (var j in ifaces[i]) {
-        var val = ifaces[i][j]
-        if (val.family === 'IPv4' && val.address !== '127.0.0.1') {
-            ip = val.address
-        }
-    }
-}
+// var os = require('os'), ip = '', ifaces = os.networkInterfaces() // 获取本机ip
+// for (var i in ifaces) {
+//     for (var j in ifaces[i]) {
+//         var val = ifaces[i][j]
+//         if (val.family === 'IPv4' && val.address !== '127.0.0.1') {
+//             ip = val.address
+//         }
+//     }
+// }
 // 1196735749
 module.exports = {
   build: {

+ 3 - 13
fhKeeper/formulahousekeeper/timesheet/config/index.js

@@ -1,7 +1,8 @@
 var path = require('path')
 
-//  var ip = '192.168.2.12'
-var ip = '47.101.180.183'
+ var ip = '192.168.2.42'
+//  var ip = '192.168.2.49'
+// var ip = '47.101.180.183'
 // var ip = '47.100.37.243'
 // var ip = '192.168.10.2'
 // var ip = '192.168.2.11' 
@@ -60,17 +61,6 @@ module.exports = {
                 '^/api': '/' 
             }
         },
-
-
-
-        // '/ips': {    
-        //     target: 'http://'+ ip +':8080',
-        //     secure: true,
-        //     changeOrigin: true,
-        //     pathRewrite: {
-        //         '^/ips': '/' 
-        //     }
-        // },
     },
     cssSourceMap: false
   },

+ 3 - 0
fhKeeper/formulahousekeeper/timesheet/src/components/taskComponent.vue

@@ -41,6 +41,9 @@
                     </el-option>
                 </el-select>
             </el-form-item>
+            <el-form-item label="任务完成校验" v-if="user.timeType.taskFileCharge">
+                <el-checkbox v-model="addForm.attachFileRequired" >是否必须上传成果文件</el-checkbox>
+            </el-form-item>
             <el-form-item  :label="$t('taskdefinition')" prop="name">
                 <el-input v-model="addForm.name" :maxlength="40" :disabled="(this.addForm.id != null && user.id != this.addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !permissions.editAnyTask && !(groupResponsibleId == user.id)" :placeholder="$t('enterthetaskcontent')" clearable></el-input>
             </el-form-item>

+ 29 - 2
fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/list.vue

@@ -1833,9 +1833,13 @@
         <!-- 详细费用 -->
         <el-dialog :title="`${otherExpensesRow.projectName}支出明细(元)`" :visible.sync="otherExpensesVisable" width="800px" top="5.6vh" :before-close="handleClose">
           <div>
-            <el-table :data="otherExpensesRow.projectExpenseFeeList" height="50vh" border style="width: 100%">
+            <el-table :data="otherExpensesRow.projectExpenseFeeList" height="50vh" border style="width: 100%" show-summary :summary-method="expensesSummaries">
               <el-table-column prop="typeName" align="center" label="名称"></el-table-column>
-              <el-table-column prop="amount" align="center" label="费用(元)"></el-table-column>
+              <el-table-column prop="amount" align="center" label="费用(元)">
+                <template slot-scope="scope">
+                  {{ (scope.row.amount || 0).toFixed(2) }}
+                </template>
+              </el-table-column>
             </el-table>
           </div>
           <span slot="footer" class="dialog-footer">
@@ -2198,6 +2202,29 @@ export default {
       }
   },
   methods: {
+    expensesSummaries(param) {
+      const { columns, data } = param;
+        const sums = [];
+        columns.forEach((column, index) => {
+        if (index === 0) {
+          sums[index] = '总计';
+          return;
+        }
+        const values = data.map(item => Number(item[column.property]));
+        if (!values.every(value => isNaN(value))) {
+          sums[index] = values.reduce((prev, curr) => {
+            const value = Number(curr);
+            if (!isNaN(value)) {
+              return prev + curr;
+            } else {
+              return prev;
+            }
+          }, 0);
+          sums[index] = (sums[index]).toFixed(2)
+        }
+      });
+      return sums;
+    },
     showOtherExpensesClick(row) {
       console.log(row, '<====== showOtherExpensesClick')
       this.otherExpensesRow = {

+ 14 - 10
fhKeeper/formulahousekeeper/timesheet/src/views/expense/expense.vue

@@ -81,7 +81,7 @@
                 </el-select>
 
                 <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :widthStr="'150'" :distinction="'1'"
-                  :subject="users" :disabled="!permissions.costAudit" :subjectId="addForm.ownerId" ref="selectCat"
+                  :subject="users" :disabled="!permissions.costAudit && expenseMainTypeValue != 14454" :subjectId="addForm.ownerId" ref="selectCat"
                   @selectCal="selectCal"></selectCat>
 
               </el-form-item>
@@ -439,12 +439,10 @@
               v-if="this.user.timeType.easyExpense == 0 && user.companyId != 4811"></el-table-column>
             <el-table-column prop="type" :label="$t('ppertype')" v-if="this.user.timeType.easyExpense == 0">
               <template slot-scope="scope">
-                <template slot-scope="scope">
-                  <template v-if="user.companyId == 4811 && scope.row.status == 4">
-                    <span style="color: red">{{ scope.row.expenseMainTypeName }}</span>
-                  </template>
-                  <template v-else>{{ scope.row.expenseMainTypeName }}</template>
+                <template v-if="user.companyId == 4811 && scope.row.status == 4">
+                  <span style="color: red">{{ scope.row.expenseMainTypeName }}</span>
                 </template>
+                <template v-else>{{ scope.row.expenseMainTypeName }}</template>
               </template>
             </el-table-column>
             <el-table-column prop="equipmentOwnerName" label="设备归属人" v-if="user.companyId == 4811" width="150">
@@ -542,8 +540,11 @@
           <el-form-item :label="$t('peopleconcerned')" style="width: 270px"
             :rules="{ required: true, message: $t('pleaseselecttheapplicant'), trigger: 'blur' }">
 
-            <el-input v-model="ParticularsList.ownerName"
+            <!-- <el-input v-model="ParticularsList.ownerName"
               :disabled="flg || ParticularsList.ownerId == ParticularsList.operatorId"
+              v-if="user.userNameNeedTranslate != '1'"></el-input> -->
+            <el-input v-model="ParticularsList.ownerName"
+              :disabled="true"
               v-if="user.userNameNeedTranslate != '1'"></el-input>
             <!-- <el-select v-model="ParticularsList.ownerId" :placeholder="$t('pleaseselecttheapplicant')" style="width: 150px" :disabled="flg || ParticularsList.ownerId == ParticularsList.operatorId">
                 <span v-for="(item, index) in users" :key="index">
@@ -551,8 +552,11 @@
                 </span>
               </el-select> -->
 
-            <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :widthStr="'150'" :distinction="'3'"
+            <!-- <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :widthStr="'150'" :distinction="'3'"
               :subject="users" :disabled="flg || ParticularsList.ownerId == ParticularsList.operatorId"
+              :subjectId="ParticularsList.ownerId" ref="selectCat" @selectCal="selectCal"></selectCat> -->
+            <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :widthStr="'150'" :distinction="'3'"
+              :subject="users" :disabled="true"
               :subjectId="ParticularsList.ownerId" ref="selectCat" @selectCal="selectCal"></selectCat>
 
           </el-form-item>
@@ -1820,8 +1824,8 @@ export default {
       if (this.auditTypeItem.auditType == 0 || this.auditTypeItem.auditType == 2) {
         this.denyForm.id = item.id
         this.denyForm.reason = ''
-        // this.denyReasonDialog = true
-        this.deny()
+        this.denyReasonDialog = true
+        // this.deny()
       } else {
         this.downloadByA(item);
         this.showSingleAudit = true;

+ 167 - 10
fhKeeper/formulahousekeeper/timesheet/src/views/leave/list.vue

@@ -103,7 +103,7 @@
     <!-- 上面部分 -->
     <div v-if="!displayTable && apk == false" class="tops" :style="'height:' +hubs+'px'">
         <!-- 公共 -->
-        <div class="ctons" style="width: 98%">
+        <div class="ctons" style="width: 98%;overflow: auto;">
             <!-- 表单 -->
             <el-form ref="addForm" :model="addForm" label-width="80px" :rules="addFormRules">
                 <!-- 请假类型 -->
@@ -170,6 +170,22 @@
                 <el-form-item :label="$t('bei-zhu')" style="width: 100%">
                     <el-input type="textarea" v-model="addForm.remark" :rows="5" style="width: 550px" maxlength="100" show-word-limit></el-input>
                 </el-form-item>
+                <el-form-item label="相关凭证" style="width: 100%">
+                  <el-upload action="#" list-type="picture-card" multiple ref="leaveApplicationFormUploadRef" :limit="5" :http-request="imageUpload" :file-list="leaveAndUploadPictures">
+                      <i slot="default" class="el-icon-plus"></i>
+                      <div slot="file" slot-scope="{file}">
+                        <img class="el-upload-list__item-thumbnail" :src="file.url" alt="">
+                        <span class="el-upload-list__item-actions">
+                          <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
+                            <i class="el-icon-zoom-in"></i>
+                          </span>
+                          <span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file)">
+                            <i class="el-icon-delete"></i>
+                          </span>
+                        </span>
+                      </div>
+                  </el-upload>
+                </el-form-item>
                 <!--请假流程显示-->
                 <el-form-item :label="$t('other.approvalProcess')" style="width: 100%;color:#606266" >
                   <span v-for="(item, index) in curWorkflowList" :key="item.id" >
@@ -195,7 +211,7 @@
     <!-- 下面部分 -->
     <div v-if="displayTable && apk == false" class="tops" :style="'height:' +hubs+'px'">
         <!-- 公共 -->
-        <div class="ctons" style="width: 98%;">
+        <div class="ctons" style="width: 98%;overflow: auto;">
           <div class="flex">
             <div>
               <el-select v-if="user.userNameNeedTranslate != 1" v-model="ownerIds" :placeholder="$t('pleaseselectthepersonaskingforleave')" clearable @change="chufas()" style="width: 120px" size="small" v-show="permissions.leaveAll" filterable="true">
@@ -292,14 +308,18 @@
                     </div>
                   </template>
                 </el-table-column>
-                <el-table-column prop="remark" :label="$t('bei-zhu')" min-width="200" header-align="center">
+                <el-table-column prop="remark" :label="$t('bei-zhu')" min-width="200">
                   <template slot-scope="scope">
-                    <!-- <div class="apls">{{scope.row.remark}}</div> -->
                     <el-popover placement="top-start"  width="200" trigger="hover" :content="scope.row.remark">
                       <div slot="reference" class="apls">{{scope.row.remark}}</div>
                     </el-popover>
                   </template>
                 </el-table-column>
+                <el-table-column label="相关凭证" min-width="200">
+                  <template slot-scope="scope">
+                    <el-button type="primary" size="mini" v-if="scope.row.fileUrlsList.length && scope.row.fileUrlsList[0].name" @click="clickToViewTheImage(scope.row.fileUrlsList)">点击查看</el-button>
+                  </template>
+                </el-table-column>
                 <el-table-column :label="$t('operation')" min-width="180" fixed="right" v-if="isAuditList && !isSyncData">
                     <template slot-scope="scope">
                       <div>
@@ -758,6 +778,22 @@
         <el-form-item :label="$t('bei-zhu')" style="width: 100%">
             <el-input type="textarea" v-model="addForm.remark" :rows="5" style="width: 62%" maxlength="100" show-word-limit></el-input>
         </el-form-item>
+        <el-form-item label="相关凭证" style="width: 100%">
+            <el-upload action="#" list-type="picture-card" multiple ref="leaveApplicationFormUploadDetailRef" :limit="5" :http-request="imageDetailUpload" :file-list="addForm.fileUrlsList">
+              <i slot="default" class="el-icon-plus"></i>
+              <div slot="file" slot-scope="{file}">
+                <img class="el-upload-list__item-thumbnail" :src="file.url" alt="">
+                <span class="el-upload-list__item-actions">
+                  <span class="el-upload-list__item-preview" @click="handlePictureCardDetailPreview(file)">
+                    <i class="el-icon-zoom-in"></i>
+                  </span>
+                  <span v-if="!disabled" class="el-upload-list__item-delete" @click="handleDetailRemove(file)">
+                    <i class="el-icon-delete"></i>
+                  </span>
+                </span>
+              </div>
+          </el-upload>
+        </el-form-item>
     </el-form>
     <span slot="footer" class="dialog-footer">
       <el-button @click="dialog = false">{{ $t('btn.cancel') }}</el-button>
@@ -797,6 +833,13 @@
             <el-button  @click="denyReasonVisible = false" >{{ $t('btn.cancel') }}</el-button>
         </div>
     </el-dialog> -->
+
+    <!-- 文件图片显示 -->
+    <div v-show="false">
+      <viewer :images="excessiveImagesList">
+        <img ref="imgsaListRef" v-for="src in excessiveImagesList" :src="src.url">
+      </viewer>
+    </div>
   </section>
 </template>
 
@@ -811,6 +854,7 @@ import selectPersonnel from '../../components/selectPersonnel.vue';
 import vueCascader from "@/components/cascader.vue"
 
 import { getThemeColor } from '@/utils/commonMethod.js'
+import { del } from 'vue';
 export default {
   name: "expense",
   components: {
@@ -990,6 +1034,9 @@ export default {
       auditLogList:[],
       selectedAuuid: '',
       syncLeaveLoading:false,
+      relatedVouchersList: [],
+      excessiveImagesList: [],
+      leaveAndUploadPictures: []
     };
   },
   computed: {},
@@ -997,7 +1044,7 @@ export default {
   created() {
     let widTHBul = document.documentElement.clientWidth - 440
     this.kuanBl = widTHBul
-    this.hubs = (document.documentElement.clientHeight || document.body.clientHeight) - 70
+    this.hubs = (document.documentElement.clientHeight || document.body.clientHeight) - 140
     let height = window.innerHeight;
             this.tableHeight = height - 195;
             const that = this;
@@ -1022,6 +1069,85 @@ export default {
   },
   filters: {},
   methods: {
+    imageUpload(res) {
+      const row = res.file
+      const formData = new FormData();
+      formData.append('multipartFile', row);
+      this.$refs.leaveApplicationFormUploadRef.uploadFiles = [];
+      this.http.uploadFile(`/common/uploadFile`, formData, res => {
+        if (res.code == "ok") {
+          const url = res.data
+          this.leaveAndUploadPictures.push({
+            name: url,
+            url: `/upload/${url}`,
+          })
+        } else {
+            this.$message({ message: res.msg, type: "error" });
+        }
+      }, err => {
+        this.$message({ message: error, type: "error" });
+      })
+    },
+    imageDetailUpload(res) {
+      const row = res.file
+      const formData = new FormData();
+      formData.append('multipartFile', row);
+      this.$refs.leaveApplicationFormUploadDetailRef.uploadFiles = [];
+      this.http.uploadFile(`/common/uploadFile`, formData, res => {
+        if (res.code == "ok") {
+          const url = res.data
+          this.addForm.fileUrlsList.push({
+            name: url,
+            url: `/upload/${url}`,
+          })
+        } else {
+            this.$message({ message: res.msg, type: "error" });
+        }
+      }, err => {
+        this.$message({ message: error, type: "error" });
+      })
+    },
+    handlePictureCardPreview(file) {
+      const list = this.$refs.leaveApplicationFormUploadRef.uploadFiles || [];
+      const fileIndex = list.findIndex(item => item.uid === file.uid);
+      this.excessiveImagesList = list
+
+      setTimeout(() => {
+        this.$refs.imgsaListRef[fileIndex].click()
+      }, 200);
+    },
+    handlePictureCardDetailPreview(file) {
+      const list = this.$refs.leaveApplicationFormUploadDetailRef.uploadFiles || [];
+      const fileIndex = list.findIndex(item => item.uid === file.uid);
+      this.excessiveImagesList = list
+
+      setTimeout(() => {
+        this.$refs.imgsaListRef[fileIndex].click()
+      }, 200);
+    },
+    clickToViewTheImage(list) {
+      this.excessiveImagesList = list
+      setTimeout(() => {
+        this.$refs.imgsaListRef[0].click()
+      }, 200);
+    },
+    handleRemove(file) {
+      const list = this.$refs.leaveApplicationFormUploadRef.uploadFiles || [];
+      const fileIndex = list.findIndex(item => item.uid === file.uid);
+      if(list.length) {
+        console.log(list)
+        this.$refs.leaveApplicationFormUploadRef.uploadFiles.splice(fileIndex, 1);
+        this.leaveAndUploadPictures.splice(fileIndex, 1)
+      }
+    },
+    handleDetailRemove(file) {
+      const list = this.$refs.leaveApplicationFormUploadDetailRef.uploadFiles || [];
+      const fileIndex = list.findIndex(item => item.uid === file.uid);
+      if(list.length) {
+        this.$refs.leaveApplicationFormUploadDetailRef.uploadFiles.splice(fileIndex, 1);
+        this.addForm.fileUrlsList.splice(fileIndex, 1)
+      }
+    },
     showDenyReason(sheetId) {
       this.denyReasonVisible = true;
       this.auditLogList = [];
@@ -1762,6 +1888,8 @@ export default {
         this.apk2 = 9
         this.restTime()
       } 
+
+      this.leaveAndUploadPictures = []
     },
     auditList() {
       this.falg = 1
@@ -1784,7 +1912,13 @@ export default {
       this.http.post('/leave-sheet/auditList', param,
         res => {
             if (res.code == "ok") {
-              this.tableData = res.data.records
+              this.tableData = res.data.records.map(item => ({
+                ...item,
+                fileUrlsList: (item.fileUrls || '').split(',').map(em => ({
+                  name: em,
+                  url: `/upload/${em}`
+                }))
+              }));
               this.total = res.data.total
               this.loading = false
             } else {
@@ -1843,7 +1977,14 @@ export default {
       this.http.post('/leave-sheet/list', param,
         res => {
             if (res.code == "ok") {
-              this.tableData = res.data.records
+              this.tableData = res.data.records.map(item => ({
+                ...item,
+                fileUrlsList: (item.fileUrls || '').split(',').map(em => ({
+                  name: em,
+                  url: `/upload/${em}`
+                }))
+              }));
+              console.log(this.tableData)
               this.total = res.data.total
               this.loading = false
             } else {
@@ -1908,7 +2049,15 @@ export default {
           this.addForm.endDate = this.buling(this.addForm.endDate)
           this.addForm.startDate = this.buling(this.addForm.startDate)
           if (valid) {
-            this.http.post('/leave-sheet/add', this.addForm,
+            let formData = new FormData()
+            const fileList = this.leaveAndUploadPictures.map(item => item.name)
+            Object.keys(this.addForm).forEach(key => {
+              formData.append(key, this.addForm[key])
+            })
+
+            formData.append('fileUrls', fileList.join(','))
+
+            this.http.uploadFile('/leave-sheet/add', formData,
             res => {
                 if (res.code == "ok") {
                     this.$message({
@@ -1922,8 +2071,9 @@ export default {
                     this.addForm.leaveType = 0
                     this.addForm.timeHours = 8
                     this.addForm.remark = ''
-                    
                     this.flg = true
+                    this.$refs.leaveApplicationFormUploadRef.clearFiles()
+                    this.leaveAndUploadPictures = []
                 } else {
                     this.$message({
                       message: res.msg,
@@ -2250,6 +2400,7 @@ export default {
       });
     },
     editor(items) {
+      console.log(items, '<===== zhong-xin-ti-jiao')
       this.dialog = true
       this.addForm.ownerId = items.ownerId
       this.addForm.tel = items.tel
@@ -2259,11 +2410,16 @@ export default {
       this.addForm.timeDays = items.timeDays
       this.addForm.timeHours = items.timeHours
       this.addForm.remark = items.remark
+      this.addForm.fileUrlsList = items.fileUrlsList || []
       this.affId = items.id
     },
     determine () {
       var adl = this.addForm
       adl.id = this.affId
+      adl.fileUrls = this.addForm.fileUrlsList.map(item => {
+        return item.name
+      }).join(',')
+      delete adl.fileUrlsList
       this.http.post('/leave-sheet/add', adl,
           res => {
               if (res.code == "ok") {
@@ -2277,7 +2433,8 @@ export default {
                     leaveType: 0,
                     timeHours: '8',
                     tel: '',
-                    remark: ''
+                    remark: '',
+                    fileUrls: []
                   }
                   this.getUsers()
               } else {

+ 8 - 0
fhKeeper/formulahousekeeper/timesheet_h5/src/router/index.js

@@ -96,6 +96,14 @@ const router = new Router({
         },
         component: () => import("@/views/expense/details")
     },
+    {
+        path: "/customizedDetail",
+        name: "customizedDetail",
+        meta: {
+            title: "单据编辑"
+        },
+        component: () => import("@/views/expense/customizedDetail")
+    },
     {
         path: "/projectInside",
         name: "projectInside",

+ 81 - 10
fhKeeper/formulahousekeeper/timesheet_h5/src/views/exaLeave/applyLeave.vue

@@ -81,6 +81,12 @@
                 <van-field label="请假天数(天)" v-if="editForm.timeType == '0'" @blur="dayBlur()" v-model="editForm.timeDays" type="number" :rules="[{ required: true, message: '请输入请假天数' }]"></van-field>
                 <!-- 请假时长 -->
                 <van-field label="请假时长(小时)" v-else v-model="editForm.timeHours" @blur="hourBlur()" type="number" :rules="[{ required: true, message: '请输入请假时长' }]"></van-field>
+                <!-- 报销凭证 -->
+                <van-field label="相关凭证" v-if="!isCorpWX">
+                    <template #input>
+                        <van-uploader v-model="tupiansss" :after-read="uploaderAfterRead" :max-count="5" multiple :before-delete="imgDeleteFile" />
+                    </template>
+                </van-field>
                 <!-- 备注 -->
                 <van-field v-model="editForm.remark" label="备注" type="textarea" :autosize="{minHeight:100}"></van-field>
         </van-form>
@@ -111,6 +117,9 @@
                         <div><span>请假结束时间:</span><span>{{item.endDate}}</span></div>
                         <div><span>请假天数:</span><span>{{item.timeDays ? item.timeDays + '天' : '/'}}</span></div>
                         <div><span>请假时长:</span><span>{{item.timeHours ? item.timeHours + '小时' : '/'}}</span></div>
+                        <div v-if="!isCorpWX"><span>相关凭证:</span>
+                            <van-uploader v-model="item.fileUrlsList" :max-count="0" :deletable="false" />
+                        </div>
                         <div><span>备注:</span><span>{{item.remark}}</span></div>
                     </div>
                     <div class="operation" v-if="((item.status != 0 && item.ownerId == user.id) || leaveAll) && !isSyncData">
@@ -142,6 +151,9 @@
                         <div><span>请假结束时间:</span><span>{{item.endDate}}</span></div>
                         <div><span>请假天数:</span><span>{{item.timeDays ? item.timeDays + '天' : '/'}}</span></div>
                         <div><span>请假时长:</span><span>{{item.timeHours ? item.timeHours + '小时' : '/'}}</span></div>
+                        <div v-if="!isCorpWX"><span>相关凭证:</span>
+                            <van-uploader v-model="item.fileUrlsList" :max-count="0" :deletable="false" />
+                        </div>
                         <div><span>备注:</span><span>{{item.remark}}</span></div>
                     </div>
                 </van-collapse-item>
@@ -206,7 +218,8 @@ export default {
                 timeType: '0',
                 timeDays: 0,
                 timeHours: 8,
-                remark: ''
+                remark: '',
+                fileUrlsList: []
             },
             formshowText: {
                 name: '',
@@ -240,9 +253,9 @@ export default {
             denyParm: {
                 id: '',
                 denyReason: ''
-            }
-
-            
+            },
+            tupiansss: [],
+            isCorpWX: false
         }
     },
     mounted() {
@@ -271,6 +284,11 @@ export default {
                 this.active = '0'
             }
         }
+
+        var ua = navigator.userAgent.toLowerCase();
+        if (ua.indexOf("wxwork") > 0) {
+            this.isCorpWX = true;
+        }
         
         // if(!this.canExamine){
             this.editForm.ownerId = this.user.id
@@ -282,6 +300,33 @@ export default {
         // }
     },
     methods: {
+        imgDeleteFile(row, data) {
+            const { index } = data
+            this.editForm.fileUrlsList.splice(index, 1)
+            setTimeout(() => {
+                console.log(this.editForm);
+                console.log(this.tupiansss);
+            }, 2000)
+            return true
+        },
+        uploaderAfterRead(rowList) {
+            this.$toast('上传中...');
+            for(let i in rowList) {
+                const formData = new FormData()
+                formData.append('multipartFile', rowList[i].file);
+                this.$axios.post("/common/uploadFile", formData)
+                .then(res => {
+                    if(res.code == "ok") {
+                        this.editForm.fileUrlsList.push({
+                            url: `/upload/${res.data}`,
+                            name: res.data
+                        })
+                    } else {
+                        this.$toast.fail(res.msg);
+                    }
+                }).catch(err=> {console.log(err)});
+            }
+        },
         back(){
             history.back();
         },
@@ -403,9 +448,15 @@ export default {
                 if(!this.editForm.endDate) {
                     this.editForm.endDate = this.editForm.startDate
                 }
-                console.log(this.editForm, '<==== 将要提交的数据')
+                let formVal = {
+                    ...this.editForm,
+                    fileUrls: this.editForm.fileUrlsList.map(item => item.name).join(',')
+                }
+                delete formVal.fileUrlsList
                 this.submitLoading = true
-                this.$axios.post("/leave-sheet/add", this.editForm)
+                this.$axios.post("/leave-sheet/add", {
+                    ...formVal 
+                })
                 .then(res => {
                     this.submitLoading = false
                     if(res.code == "ok") {
@@ -418,8 +469,10 @@ export default {
                             timeType: '0',
                             timeDays: 0,
                             timeHours: this.user.timeType.allday,
-                            remark: ''
+                            remark: '',
+                            fileUrlsList: []
                         }
+                        this.tupiansss = []
                         this.formshowText.dateTitle = ''
                         this.$toast.success('提交成功');
                     } else {
@@ -438,8 +491,10 @@ export default {
                 timeType: '0',
                 timeDays: 0,
                 timeHours: this.user.timeType.allday,
-                remark: ''
+                remark: '',
+                fileUrlsList: []
             }
+            this.tupiansss = []
             this.formshowText.dateTitle = ''
         },
         getDingDingLeaveQt(){
@@ -497,6 +552,7 @@ export default {
         },
         submitAgain(item){
             this.editForm = item
+            this.tupiansss = item.fileUrlsList
             if(this.editForm.startDate && !this.editForm.endDate){
                 this.$set(this.editForm,'timeType','1')
             }else{
@@ -504,6 +560,7 @@ export default {
             }
             this.timeTypeChange()
             this.active = 0
+            this.editForm.fileUrls = item.fileUrlsList
         },
 // #endregion
 
@@ -578,7 +635,14 @@ export default {
             this.$axios.post("/leave-sheet/list", parameter)
             .then(res => {
                 if(res.code == "ok") {
-                    this.leaveList = res.data.records
+                    this.leaveList = res.data.records.map(item => {
+                        return {
+                            ...item,
+                            fileUrlsList: item.fileUrls ? item.fileUrls.split(',').map(em => {
+                                return { url: `/upload/${em}`, name: em}
+                            }) : []
+                        }
+                    })
                 } else {
                     this.$toast.fail('获取失败:'+res.smg);
                 }
@@ -590,7 +654,14 @@ export default {
                 pageIndex: 1
             }).then(res => {
                 if(res.code == "ok") {
-                    this.auditList = res.data.records
+                    this.auditList = res.data.records.map(item => {
+                        return {
+                            ...item,
+                            fileUrlsList: item.fileUrls ? item.fileUrls.split(',').map(em => {
+                                return { url: `/upload/${em}`, name: em}
+                            }) : []
+                        }
+                    })
                     for(let i in this.auditList){
                         this.$set(this.auditList[i],'approveLoading',false)
                     }

+ 0 - 0
fhKeeper/formulahousekeeper/timesheet_h5/src/views/expense/customizedDetail.vue


Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov