Bladeren bron

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

# Conflicts:
#	fhKeeper/formulahousekeeper/management-crm/crm.log
Guo1B0 1 jaar geleden
bovenliggende
commit
a65d41e20a
100 gewijzigde bestanden met toevoegingen van 4095 en 2338 verwijderingen
  1. 6 0
      fhKeeper/formulahousekeeper/buildWorkshop.bat
  2. 5 0
      fhKeeper/formulahousekeeper/copy_deploy_files.bat
  3. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/App.vue
  4. 21 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/TaskModal/index.vue
  5. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/TaskModal/taskFunction.ts
  6. 12 3
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/relatedProducts/relatedProducts.vue
  7. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/main.ts
  8. 19 61
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/analysis/index.vue
  9. 8 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/attachment.vue
  10. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/deteleTables.vue
  11. 22 12
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/information.vue
  12. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/products.vue
  13. 32 14
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/detail/index.vue
  14. 30 17
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/index.vue
  15. 5 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/type.d.ts
  16. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/api.ts
  17. 2 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/component/deteleTables.vue
  18. 5 5
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/component/information.vue
  19. 10 5
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/component/relatedBusiness.vue
  20. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/detail/index.vue
  21. 24 23
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/index.vue
  22. 19 28
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/corpreport/api.ts
  23. 25 33
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/corpreport/index.vue
  24. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/api.ts
  25. 9 3
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/attachment.vue
  26. 4 4
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/deteleTables.vue
  27. 22 12
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/information.vue
  28. 9 3
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/operationRecord.vue
  29. 13 14
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/relatedBusiness.vue
  30. 11 11
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/relatedContacts.vue
  31. 25 19
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/relatedOrders.vue
  32. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/detail/index.vue
  33. 48 22
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/index.vue
  34. 2 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/login.vue
  35. 9 9
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/api.ts
  36. 18 12
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/deteleTables.vue
  37. 41 26
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/information.vue
  38. 13 6
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/products.vue
  39. 11 3
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/rebate.vue
  40. 3 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/detail/index.vue
  41. 37 23
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/index.vue
  42. 12 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/attachment.vue
  43. 23 6
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/information.vue
  44. 0 63
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/products.vue
  45. 23 10
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/relatedBusiness.vue
  46. 72 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/relatedSalesOrder.vue
  47. 5 4
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/detail/index.vue
  48. 21 19
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/index.vue
  49. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/type.d.ts
  50. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/register.vue
  51. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/system/role/index.vue
  52. 2 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/api.ts
  53. 49 27
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/index.vue
  54. 8 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/api.ts
  55. 276 48
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/index.vue
  56. 18 15
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/module/AddPersonnelModal.vue
  57. 100 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/module/BatchOperation.vue
  58. 26 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/module/type.ts
  59. 1 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/type.d.ts
  60. 29 13
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/thread/index.vue
  61. 2 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/thread/type.d.ts
  62. 31 11
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ProductController.java
  63. 46 13
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/SalesOrderController.java
  64. 13 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/Product.java
  65. 23 3
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/SalesOrder.java
  66. 3 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/dto/TaskDto.java
  67. 7 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/vo/DepartmentVO.java
  68. 5 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/mapper/DepartmentMapper.java
  69. 2 2
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/SalesOrderService.java
  70. 52 12
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ContactsServiceImpl.java
  71. 64 19
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/CustomServiceImpl.java
  72. 75 9
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ProductServiceImpl.java
  73. 1445 1383
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  74. 48 26
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/SalesOrderServiceImpl.java
  75. 1 1
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/SysFormServiceImpl.java
  76. 198 94
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java
  77. 1 1
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/BusinessOpportunityMapper.xml
  78. 7 1
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/ContactsMapper.xml
  79. 56 0
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/DepartmentMapper.xml
  80. 2 1
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/ProductMapper.xml
  81. 2 1
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/SalesOrderMapper.xml
  82. 37 8
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/TaskMapper.xml
  83. 23 3
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/UserMapper.xml
  84. 3 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java
  85. 42 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportLogController.java
  86. 7 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeType.java
  87. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ReportMapper.java
  88. 6 6
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java
  89. 102 36
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  90. 104 72
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java
  91. 9 15
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml
  92. 2 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ReportMapper.xml
  93. 2 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TimeTypeMapper.xml
  94. 13 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/PlanController.java
  95. 13 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/ProdProcedureController.java
  96. 25 2
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/ProductController.java
  97. 12 2
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/ReportController.java
  98. 105 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/UpdatePackController.java
  99. 309 6
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/WxCorpInfoController.java
  100. 0 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/WxCorpTemplateController.java

+ 6 - 0
fhKeeper/formulahousekeeper/buildWorkshop.bat

@@ -0,0 +1,6 @@
+cd timesheet-workshop
+call build.bat
+cd ../timesheet-workshop_h5
+call build.bat
+cd ../management-workshop
+call build_package.bat

+ 5 - 0
fhKeeper/formulahousekeeper/copy_deploy_files.bat

@@ -0,0 +1,5 @@
+xcopy timesheet\dist\* timesheet_deploy\static_pc\dist\ /y /e /i /q
+xcopy timesheet_h5\dist\* timesheet_deploy\static_h5\dist\ /y /e /i /q
+xcopy management-platform\target\timesheet-3.4.0.jar timesheet_deploy\ /y
+echo "all deployment files are ready!"
+pause

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/App.vue

@@ -72,7 +72,7 @@ body,
 .layouts {
   width: 100%;
   height: 100%;
-  /* overflow: hidden; */
+  overflow: hidden;
   min-width: 800px;
 }
 * {

+ 21 - 2
fhKeeper/formulahousekeeper/customerBuler-crm/src/components/TaskModal/index.vue

@@ -24,6 +24,7 @@
             <el-option v-for="item in PRIORITY " :key="item.value" :value="item.value" :label="item.label" />
           </el-select>
         </el-form-item>
+        {{ form.taskType }}
         <el-form-item :label="form.taskType">
           <template #label>
             <el-select v-model="form.taskType" class="border resetSelect" style="width: 100px" @change="changeTaskType"
@@ -33,7 +34,7 @@
           </template>
           <template v-for="item in TASK_TYPE_FIELD">
             <el-select v-model="form[item.field]" v-if="form.taskType == item.type" placeholder="请选择" clearable
-              filterable :disabled="disabledList && disabledList.includes(item.field)">
+              filterable :disabled="disabledList && disabledList.includes(item.field)" @change="(e: any) => {taskFormChange(e, item.field)}">
               <el-option v-for="v in taskTypeValueData" :key="v.id" :value="v[item.valueIndex]"
                 :label="v[item.labelIndex]" />
             </el-select>
@@ -41,7 +42,7 @@
         </el-form-item>
         <el-form-item label="联系人:" v-if="TASK_TYPE.find(v => v.value == (form.taskType || '1'))?.show">
           <el-select v-model="form.contactsId" placeholder="请选择" clearable filterable
-            :disabled="disabledList && disabledList.includes('contactsId')">
+            :disabled="(disabledList && disabledList.includes('contactsId'))">
             <el-option v-for="item in contactValueData" :key="item.id" :value="item.id" :label="item.name" />
           </el-select>
         </el-form-item>
@@ -135,6 +136,7 @@ import { Delete, Plus } from "@element-plus/icons-vue"
 import { FormInstance, dayjs } from 'element-plus';
 import { getFromValue } from '@/utils/tools';
 import { Props, Emits } from './type';
+import { URL_GETALL } from '@/pages/contacts/api';
 const props = defineProps<Props>()
 const emits = defineEmits<Emits>();
 watch(() => props.saveLoading, (val) => {
@@ -142,6 +144,7 @@ watch(() => props.saveLoading, (val) => {
     formRef.value?.resetFields();
     form.value = { ...defalutModalForm };
     generateFormRef.value?.reset();
+    taskTypeValueData.value = customeData.value
   }
 })
 watch(() => props.visible, (val) => {
@@ -214,6 +217,22 @@ const form = ref<any>({});
 const formRef = ref<FormInstance>();
 const generateFormRef = ref<InstanceType<typeof GenerateForm>>();
 const generateFormData = ref<any>({ ...defaultGenerateFormData });
+function taskFormChange(e: any, field: 'customId' | 'businessOpportunityId' | 'orderId' | 'clueId') {
+  const fieldMap = {
+    'customId': 'customerId',
+    'businessOpportunityId': 'businessId',
+    'orderId': 'salesId',
+    'clueId': ''
+  };
+  let fieldStr = fieldMap[field] || '';
+  updateContactPerson(e, fieldStr)
+}
+function updateContactPerson(val: any, field: string) {
+  let formVal = field ? { [field]: val } : {}
+  get(URL_GETALL, { ...formVal }).then(({ data }) => {
+    contactValueData.value = data;//联系人
+  })
+}
 function closeVisible() {
   formRef.value?.resetFields();
   generateFormData.value = { ...defaultGenerateFormData };

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

@@ -24,7 +24,7 @@ export async function createTask(submitData: any, isClose: boolean) : Promise<Ta
         post(ADD_TASK, getFromValue(params)).then(() => {
             resolve({ saveLoading: '3', isClose })
         }).catch((err) => {
-            reject({ saveLoading: '4', isClose, message: err.message })
+            reject({ saveLoading: '4', isClose, message: err.msg })
         })
     })
 }

+ 12 - 3
fhKeeper/formulahousekeeper/customerBuler-crm/src/components/relatedProducts/relatedProducts.vue

@@ -33,7 +33,7 @@
             <el-table-column prop="quantity" label="数量" width="180">
                 <template #default="scope">
                     <el-input-number @change="inputNumberChange('quantity', productTable[scope.$index])"
-                        v-model="productTable[scope.$index].quantity" class="mx-4" :min="0" :max="100000000"
+                        v-model="productTable[scope.$index].quantity" class="mx-4" :min="0" :max="scope.row.inventory"
                         controls-position="right" v-if="productTableIndex == scope.$index" />
                     <span v-else>{{ productTable[scope.$index].quantity }}</span>
                 </template>
@@ -57,11 +57,11 @@
         </el-table>
 
         <div class="flex w-full justify-between pt-2 pb-1">
-            <div>整单折扣率(%)</div>
+            <div>整单折扣率(<span class="text-[red]">{{ discountEfficiency }}</span>)</div>
             <div class="flex">
                 <div>已选中产品:<span class="text-[red] pr-2">{{ selectedQuantity }}</span>个</div>
                 <div class="pl-4">
-                    总金额:<span class="pr-1">{{ totalAmount }}</span> 元
+                    总金额:<span class="pr-1 text-[red]">{{ totalAmount }}</span> 元
                 </div>
             </div>
         </div>
@@ -158,6 +158,15 @@ const totalAmount = computed(() => {
     }, 0)
 })
 
+const discountEfficiency = computed(() => {
+    const newProductTable = productTable.value.filter((item: any) => item.productId && item.sellingPrice && item.quantity && item.discount && item.totalPrice)
+    const list = JSON.parse(JSON.stringify(newProductTable || []))
+    const totalAmount = list.reduce((pre: number, cur: any) => { return pre + (cur.totalPrice || 0) }, 0)
+    const totalPrice = list.reduce((pre: number, cur: any) => { return pre + (cur.price * cur.quantity || 0) }, 0)
+    const num = totalAmount / totalPrice * 100
+    return num > 0 ? Number(num.toFixed(2)) + '%' : ''
+})
+
 watchEffect(() => {
     const { productTableList, height, productTableListValue = [] } = props
     console.log(productTableListValue, '<==== 数据')

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/main.ts

@@ -31,7 +31,7 @@ app.config.globalProperties.$echarts = echarts;
 app
   .use(ElementPlus, {
     locale: zhCn,
-    zIndex: 1900,
+    zIndex: 1800,
   })
   .use(createPinia())
   .use(router)

+ 19 - 61
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/analysis/index.vue

@@ -56,18 +56,18 @@ type PromptType = {
 };
 
 const bulletinPrompt = reactive<PromptType>({
-  permission: undefined,
-  date: undefined,
+  permission: 0,
+  date: 0,
   sliceDate: [new Date(), new Date()]
 });
 const summaryPrompt = reactive<PromptType>({
-  permission: undefined,
-  date: undefined,
+  permission: 0,
+  date: 0,
   sliceDate: [new Date(), new Date()]
 });
 const stagePrompt = reactive<PromptType>({
-  permission: undefined,
-  date: undefined,
+  permission: 0,
+  date: 0,
   sliceDate: [new Date(), new Date()]
 });
 
@@ -155,12 +155,7 @@ watchEffect(() => {
 });
 
 watchEffect(() => {
-  console.log(
-    bulletinPrompt.date,
-    '-----',
-    bulletinPrompt.sliceDate,
-    '88888888---watchEffect'
-  );
+  console.log(bulletinPrompt.date, '-----', bulletinPrompt.sliceDate, '88888888---watchEffect');
 });
 </script>
 
@@ -170,7 +165,6 @@ watchEffect(() => {
       <div class="flex gap-3 mb-4">
         <div class="w-40">
           <el-select
-            clearable
             size="small"
             :model-value="bulletinPrompt.permission"
             @change="(value) => (bulletinPrompt.permission = value)"
@@ -184,16 +178,11 @@ watchEffect(() => {
         </div>
         <div class="w-40">
           <el-select
-            clearable
             size="small"
             :model-value="bulletinPrompt.date"
             @change="(value) => (bulletinPrompt.date = value)"
           >
-            <el-option
-              v-for="date in dateOptions"
-              :label="date.label"
-              :value="date.value"
-            />
+            <el-option v-for="date in dateOptions" :label="date.label" :value="date.value" />
             <el-option label="自定义" value="ignore">
               <div class="flex gap-2 w-80">
                 <el-date-picker
@@ -233,14 +222,8 @@ watchEffect(() => {
           <TrendCard
             title="新增商机"
             unit="个"
-            :number="
-              requestData?.bulletin?.businessOpportunity
-                .businessOpportunityCount
-            "
-            :compare="
-              requestData?.bulletin?.businessOpportunity
-                .businessOpportunityPromote
-            "
+            :number="requestData?.bulletin?.businessOpportunity.businessOpportunityCount"
+            :compare="requestData?.bulletin?.businessOpportunity.businessOpportunityPromote"
           />
           <TrendCard
             title="新增销售订单"
@@ -252,21 +235,13 @@ watchEffect(() => {
             title="销售订单金额"
             unit="元"
             :number="requestData?.bulletin?.salesOrdersPrice.salesOrdersPrice"
-            :compare="
-              requestData?.bulletin?.salesOrdersPrice.salesOrderPricePromote
-            "
+            :compare="requestData?.bulletin?.salesOrdersPrice.salesOrderPricePromote"
           />
           <TrendCard
             title="商机金额"
             unit="元"
-            :number="
-              requestData?.bulletin?.businessOpportunityPrice
-                .businessOpportunityPrice
-            "
-            :compare="
-              requestData?.bulletin?.businessOpportunityPrice
-                .businessOpportunityPromote
-            "
+            :number="requestData?.bulletin?.businessOpportunityPrice.businessOpportunityPrice"
+            :compare="requestData?.bulletin?.businessOpportunityPrice.businessOpportunityPromote"
           />
           <TrendCard
             title="新增线索"
@@ -301,11 +276,7 @@ watchEffect(() => {
                 :model-value="summaryPrompt.date"
                 @change="(value) => (summaryPrompt.date = value)"
               >
-                <el-option
-                  v-for="date in dateOptions"
-                  :label="date.label"
-                  :value="date.value"
-                />
+                <el-option v-for="date in dateOptions" :label="date.label" :value="date.value" />
                 <el-option label="自定义" value="ignore">
                   <div class="flex gap-2 w-80">
                     <el-date-picker
@@ -341,31 +312,22 @@ watchEffect(() => {
             <SimpleCard
               title="新增商机"
               unit="个"
-              :number="
-                requestData.summary?.businessOpportunityDataSummary.newNum
-              "
+              :number="requestData.summary?.businessOpportunityDataSummary.newNum"
             />
             <SimpleCard
               title="赢单商机"
               unit="个"
-              :number="
-                requestData.summary?.businessOpportunityDataSummary.winning
-              "
+              :number="requestData.summary?.businessOpportunityDataSummary.winning"
             />
             <SimpleCard
               title="输单商机"
               unit="个"
-              :number="
-                requestData.summary?.businessOpportunityDataSummary.losting
-              "
+              :number="requestData.summary?.businessOpportunityDataSummary.losting"
             />
             <SimpleCard
               title="商机总金额"
               unit="元"
-              :number="
-                requestData.summary?.businessOpportunityDataSummary
-                  .allAmountOfMoney
-              "
+              :number="requestData.summary?.businessOpportunityDataSummary.allAmountOfMoney"
             />
           </div>
           <Divider title="线索汇总" />
@@ -406,11 +368,7 @@ watchEffect(() => {
                 :model-value="stagePrompt.date"
                 @change="(value) => (stagePrompt.date = value)"
               >
-                <el-option
-                  v-for="date in dateOptions"
-                  :label="date.label"
-                  :value="date.value"
-                />
+                <el-option v-for="date in dateOptions" :label="date.label" :value="date.value" />
                 <el-option label="自定义" value="ignore">
                   <div class="flex gap-2 w-80">
                     <el-date-picker

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

@@ -16,7 +16,7 @@
                 <el-table-column prop="name" label="附件名称" width="180" />
                 <el-table-column prop="size" label="附件大小" width="120" />
                 <el-table-column prop="userName" label="上传人" width="120" />
-                <el-table-column prop="createTime" label="上传时间" width="180" />
+                <el-table-column prop="newCreateTime" label="上传时间" width="180" />
                 <el-table-column label="操作" width="180" fixed="right">
                     <template #default="scope">
                         <el-button link type="primary" size="large" @click="fileDownload(scope.row)">下载</el-button>
@@ -50,6 +50,7 @@ import { post, uploadFile } from '@/utils/request';
 import { confirmAction, downloadFile } from '@/utils/tools';
 import { ref, reactive, onMounted, onUnmounted, defineEmits, defineExpose, inject, watchEffect } from 'vue'
 import { DETELEFILEFILE, REFIENAMEFILE, UPLOADFILEFILE } from '../api';
+import { formatDate } from '@/utils/times';
 
 const emits = defineEmits(['refreshData']);
 const globalPopup = inject<GlobalPopup>('globalPopup')
@@ -119,7 +120,12 @@ async function httpUploadFile(param: UploadRequestOptions) {
 
 watchEffect(() => {
     information.value = props.information
-    attachmenttable.value = (props.information.uploadFilePList || [])
+    attachmenttable.value = (props.information.uploadFilePList || []).map((item: any) => {
+        return {
+            ...item,
+            newCreateTime: formatDate(new Date(item.createTime))
+        }
+    })
 });
 
 // 生命周期钩子

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

@@ -100,7 +100,7 @@ function businessOperationItem(value: string | number, label: string, type: oper
             getTableList()
             changeBatch(false)
         }).catch((err) => {
-            globalPopup?.showError(err.message)
+            globalPopup?.showError(err.msg)
         })
     })
 }

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

@@ -7,41 +7,50 @@
                 <el-button type="primary" @click="claimBusiness()" v-if="!information.customerId">认领</el-button>
                 <el-button type="primary" @click="showVisible('transferBusinessVisible')"
                     v-if="information.customerId">转移</el-button>
-                <el-button type="primary" @click="showVisible('editBusinessVisible')">编辑</el-button>
+                <el-button type="primary" v-permission="['businessAddAnEdit']" @click="showVisible('editBusinessVisible')">编辑</el-button>
             </div>
         </div>
         <div class="form flex flex-wrap justify-between">
-            <div class="formItem flex pt-5 pb-1">
+            <div class="formItem flex pt-3 pb-1">
                 <div class="w-20 text-right text-gray-500">商机名称:</div>
-                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ information.name }}</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-5 pb-1">
+            <div class="formItem flex pt-3 pb-1">
                 <div class="w-22 text-right text-gray-500">客户名称:</div>
-                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ information.customerName }}
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1" v-ellipsis-tooltip>{{ information.customerName }}
                 </div>
             </div>
-            <div class="formItem flex pt-5 pb-1">
+            <div class="formItem flex pt-3 pb-1">
                 <div class="w-22 text-right text-gray-500">联系人:</div>
                 <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ information.contactsName }}
                 </div>
             </div>
-            <div class="formItem flex pt-5 pb-1">
+            <div class="formItem flex pt-3 pb-1">
                 <div class="w-22 text-right text-gray-500">商机金额:</div>
-                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ information.amountOfMoney || 0
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1" v-ellipsis-tooltip>{{ information.amountOfMoney || 0
                 }} 元</div>
             </div>
-            <div class="formItem flex pt-5 pb-1">
+            <div class="formItem flex pt-3 pb-1">
                 <div class="w-22 text-right text-gray-500">负责人:</div>
                 <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ information.inchargerName }}</div>
             </div>
-            <div class="formItem flex pt-5 pb-1">
+            <div class="formItem flex pt-3 pb-1">
                 <div class="w-22 text-right text-gray-500">预计成交日期:</div>
                 <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{
                     information.expectedTransactionDate }}</div>
             </div>
-            <div class="formItem flex pt-5 pb-1" style="width: 100%;">
+            <div class="formItem flex pt-3 pb-1">
+                <div class="w-22 text-right text-gray-500">创建人:</div>
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ information.creatorName }}</div>
+            </div>
+            <div class="formItem flex pt-3 pb-1">
+                <div class="w-22 text-right text-gray-500">创建时间:</div>
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{
+                    information.createTime }}</div>
+            </div>
+            <div class="formItem flex pt-3 pb-1" style="width: 100%;">
                 <div class="w-22 text-right text-gray-500">备注:</div>
-                <div class="flex-1 ml-1 text ">
+                <div class="flex-1 ml-1 text " v-ellipsis-tooltip>
                     {{ information.remark }}
                 </div>
             </div>
@@ -204,6 +213,7 @@ function claimBusiness() {
 function editBusiness() {
     generateForm.value?.getData().then((res: any) => {
         let formVal = {
+            id: information.value.id,
             ...res,
             expectedTransactionDate: res.expectedTransactionDate ? formatDateTime(new Date(res.expectedTransactionDate)) : '',
             businessItemProductList: JSON.stringify(productTableListValue.value)

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

@@ -3,7 +3,7 @@
         <div class="flex justify-between">
             <div class="title">相关产品</div>
             <div>
-                <el-button type="primary" @click="editProductShow()">编辑产品</el-button>
+                <el-button type="primary" v-permission="['businessAddAnEdit']" @click="editProductShow()">编辑产品</el-button>
             </div>
         </div>
         <div class="flex-1 overflow-auto pt-3">

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

@@ -7,7 +7,7 @@
         </el-link>
       </div>
       <div class="mr-8">
-        <el-select v-model="optionVal" placeholder="请选择" style="width: 150px" filterable @change="selectChange()">
+        <el-select v-model="optionVal" placeholder="请选择" style="width: 250px" filterable @change="selectChange()">
           <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
         </el-select>
       </div>
@@ -19,29 +19,38 @@
           <div class="text-nowrap">{{ item.plan }}</div>
         </div>
       </div>
-      <div class="relative rounded-md flex items-center itemPing backGray endStep item pl-6 pr-6 mr-4 resetStyle" v-if="currentStage >= 0">
+      <div class="relative rounded-md flex items-center itemPing backGray endStep item pl-6 pr-6 mr-4 resetStyle"
+        v-if="currentStage >= 0">
         <el-select v-model="stageStatusVal" placeholder="结束" style="width: 100px" class="selectClas"
           @change="advanceChange()">
           <el-option v-for="(item, index) in stageListOption" :key="index" :label="item.label" :value="item.value" />
         </el-select>
       </div>
-      <div class="relative rounded-md flex items-center justify-around backOrange endStep item pl-6 pr-6 mr-4 resetStyle" v-if="businessInfo.stageValue == '输单'" style="padding-top: 6px;padding-bottom: 6px;">
+      <div
+        class="relative rounded-md flex items-center justify-around backOrange endStep item pl-6 pr-6 mr-4 resetStyle"
+        v-if="businessInfo.stageValue == '输单'" style="padding-top: 6px;padding-bottom: 6px;">
         <div>{{ businessInfo.stageValue }}</div>
         <div class="ml-5">0%</div>
       </div>
-      <div class="relative rounded-md flex items-center justify-around backWan endStep item pl-6 pr-6 mr-4 resetStyle" v-if="businessInfo.stageValue == '赢单'" style="padding-top: 6px;padding-bottom: 6px;">
+      <div class="relative rounded-md flex items-center justify-around backWan endStep item pl-6 pr-6 mr-4 resetStyle"
+        v-if="businessInfo.stageValue == '赢单'" style="padding-top: 6px;padding-bottom: 6px;">
         <div>{{ businessInfo.stageValue }}</div>
         <div class="ml-4"> 100%</div>
       </div>
-      <div class="relative rounded-md flex items-center justify-around backGray endStep item pl-6 pr-6 mr-4 resetStyle" v-if="businessInfo.stageValue == '无效'" style="padding-top: 6px;padding-bottom: 6px;">
+      <div class="relative rounded-md flex items-center justify-around backGray endStep item pl-6 pr-6 mr-4 resetStyle"
+        v-if="businessInfo.stageValue == '无效'" style="padding-top: 6px;padding-bottom: 6px;">
         <div>{{ businessInfo.stageValue }}</div>
         <div class="ml-5">0%</div>
       </div>
-      <div class="bg-[#075985] rounded-md text itemPing pl-2 pr-2 flex items-center aloneText" @click="advancementStage()"
+      <div class="bg-[#075985] rounded-md text itemPing pl-2 pr-2 flex items-center aloneText"
         v-if="currentStage != -1">
-        <el-link :underline="false" v-if="(currentStage + 1) != stageList.length">推进至下个阶段【{{ stageList[currentStage +
-          1]?.name }}】</el-link>
-        <el-link :underline="false" v-else>赢单</el-link>
+        <!-- <el-link :underline="false" v-if="(currentStage + 1) != stageList.length"
+          @click="advancementStage(false)">推进至下个阶段【{{ stageList[currentStage +
+            1]?.name }}】</el-link> -->
+        <el-link :underline="false" v-if="(currentStage + 1) != stageList.length"
+          @click="advancementStageNext(false)">推进至下个阶段【{{ stageList[currentStage +
+            1]?.name }}】</el-link>
+        <el-link :underline="false" v-else class="ml-4 mr-4" @click="advancementStage(true)">赢单</el-link>
       </div>
     </div>
     <!-- 内容 -->
@@ -91,7 +100,7 @@
     </el-dialog>
   </div>
 </template>
-  
+
 <script lang="ts" setup>
 import { ref, reactive, onMounted, inject } from "vue";
 import type { FormInstance, FormRules } from 'element-plus'
@@ -118,7 +127,7 @@ const route = useRoute()
 const globalPopup = inject<GlobalPopup>('globalPopup')
 const detailCompinentsData = ref([])
 const optionVal = ref<any>('')
-const stageStatusVal = ref('')
+const stageStatusVal = ref<any>('')
 const stageStatusValOriginally = ref('')
 const advanceVal = ref('')
 const options = ref<optionType[]>([])
@@ -142,9 +151,16 @@ function refreshData() {
   getDetail()
 }
 
-function advancementStage() {
+function advancementStage(flag: boolean) {
   console.log('点击了推进阶段')
-  advanceSave(false)
+  if (!flag) {
+    allLoading.advanceSaveLoading = true
+    advancementStageNext(true)
+    return
+  }
+  let val = stageListOption.value.find((item: any) => item.label == '赢单')
+  stageStatusVal.value = Number(val?.value || '')
+  advanceChange()
 }
 
 function advanceChange() {
@@ -289,7 +305,7 @@ onMounted(() => {
   }, 500)
 })
 </script>
-  
+
 <style lang="scss" scoped>
 .businessDetail {
   .selected {
@@ -319,10 +335,12 @@ onMounted(() => {
     background-color: #F4F5F7;
     color: #000;
   }
+
   .backOrange {
     background-color: #FF5531;
     color: #fff;
   }
+
   .backWan {
     background-color: #075985;
     color: #fff;

+ 30 - 17
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/index.vue

@@ -8,7 +8,7 @@
               <el-input v-model="businessOpportunityForm.name" clearable placeholder="请输入"></el-input>
             </el-form-item>
             <el-form-item label="商机阶段">
-              <el-select v-model="businessOpportunityForm.stageId" placeholder="请选择">
+              <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>
             </el-form-item>
@@ -19,12 +19,13 @@
               <el-input v-model="businessOpportunityForm.contactPerson" clearable placeholder="请输入"></el-input>
             </el-form-item>
             <el-form-item label="产品">
-              <el-select v-model="businessOpportunityForm.product" placeholder="请选择">
-                <el-option v-for="item in fixedData.Personnel" :key="item.id" :label="item.name" :value="item.id" />
+              <el-select v-model="businessOpportunityForm.product" placeholder="请选择" clearable>
+                <el-option v-for="item in fixedData.ProductArr" :key="item.value" :label="item.label"
+                  :value="item.value" />
               </el-select>
             </el-form-item>
             <el-form-item label="负责人">
-              <el-select v-model="businessOpportunityForm.inchargerId" placeholder="请选择">
+              <el-select v-model="businessOpportunityForm.inchargerId" placeholder="请选择" clearable>
                 <el-option v-for="item in fixedData.Personnel" :key="item.id" :label="item.name" :value="item.id" />
               </el-select>
             </el-form-item>
@@ -51,9 +52,9 @@
             @click="editNewBusiness(false)">新建商机</el-button>
           <el-button type="primary" @click="showVisible('batchTransferVisible')"
             :disabled="batchTableData.length <= 0">批量转移</el-button>
-          <el-button type="primary" @click="batchDeteleItem()" :disabled="batchTableData.length <= 0">批量删除</el-button>
+          <el-button type="primary" v-permission="['businessDelete']" @click="batchDeteleItem()" :disabled="batchTableData.length <= 0">批量删除</el-button>
           <el-button type="primary" @click="showVisible('stageSetVisible')">阶段设置</el-button>
-          <el-button type="primary" @click="showVisible('deteleBusinessVisible')">回收站</el-button>
+          <el-button type="primary" v-permission="['businessRecycle']" @click="showVisible('deteleBusinessVisible')">回收站</el-button>
           <el-button v-permission="['businessImport']" type="primary"
             @click="showVisible('importVisible')">导入</el-button>
           <el-button v-permission="['businessExport']" type="primary" @click="exportBusinessTableList()"
@@ -61,24 +62,24 @@
         </div>
         <div class="flex-1 w-full overflow-hidden">
           <el-table ref="businessTableRef" :data="businessTable" border v-loading="allLoading.businessTableLading"
-            @selection-change="changeBatch" style="width: 100%;height: 100%;">
+            :show-overflow-tooltip="tableShowOverflowTooltip" @selection-change="changeBatch"
+            style="width: 100%;height: 100%;">
             <el-table-column type="selection" width="55" />
             <el-table-column v-for="(item, index) in tableColumn" :prop="item.prop" :label="item.label" :key="index"
               :width="item.width">
               <template #default="scope">
-                <el-button link type="primary" size="large" @click="dealWithTableColumn(scope.row, item.eventName)"
-                  v-if="item.eventName">{{ scope.row[item.prop] }}</el-button>
+                <div class="table-text-textnowrap" v-if="item.eventName" @click="dealWithTableColumn(scope.row, item.eventName)">{{ scope.row[item.prop] }}</div>
                 <template v-else>{{ scope.row[item.prop] }}</template>
               </template>
             </el-table-column>
-            <el-table-column label="操作" fixed="right" width="200">
+            <el-table-column label="操作" fixed="right" width="200" v-permission="['businessAddAnEdit', 'tasksAdd', 'businessDelete']">
               <template #default="scope">
                 <el-button link type="primary" size="large" @click="editNewBusiness(scope.row)"
                   v-permission="['businessAddAnEdit']">编辑</el-button>
                 <el-button link type="primary" size="large" @click="newTask(scope.row)"
                   v-permission="['tasksAdd']">新建任务</el-button>
                 <el-button link type="danger" size="large" @click="businessDeteleItem(scope.row.id, scope.row.name)"
-                  v-permission="['businessAddAnEdit']">删除</el-button>
+                  v-permission="['businessDelete']">删除</el-button>
               </template>
             </el-table-column>
           </el-table>
@@ -98,7 +99,7 @@
           <h4 :id="titleId">{{ allText.newBusinessisibleText }}</h4>
           <div>
             <el-button type="primary" :loading="allLoading.newBusinessSaveLading"
-              :disabled="allLoading.businessSaveLading" @click="editBusiness(true)">保存并新建</el-button>
+              :disabled="allLoading.businessSaveLading" @click="editBusiness(true)" v-if="!businessTemplateValue.id">保存并新建</el-button>
             <el-button type="primary" @click="editBusiness(false)" :loading="allLoading.businessSaveLading"
               :disabled="allLoading.newBusinessSaveLading">保存</el-button>
             <el-button @click="closeVisible('newBusinessisible')">取消</el-button>
@@ -183,10 +184,12 @@ import { getAllListByCode, getFromValue, resetFromValue, getFirstDayOfMonth, cre
 import { createTask } from '@/components/TaskModal/taskFunction'
 import { formatDateTime } from '@/utils/times'
 import { GenerateForm } from '@zmjs/form-design';
+import { tableShowOverflowTooltip } from '@/utils/globalVariables'
 import RelatedProducts from '@/components/relatedProducts/relatedProducts.vue'
 import TaskModal from '@/components/TaskModal/index.vue'
 import DeteleBusiness from './component/deteleTables.vue'
 import StageSetting from './component/stageSetting.vue'
+import { GETTABLELISTPRODUCT } from "../order/api";
 
 const route = useRoute()
 const router = useRouter()
@@ -195,7 +198,7 @@ const businessTableRef = ref<InstanceType<typeof ElTable>>() // 商机table dom
 const businessTotalTable = ref(0)
 const businessTemplateRef = ref<typeof GenerateForm>() // 自定义表单dom
 const relatedProductsRef = ref<typeof RelatedProducts>()
-const businessTemplateValue = ref({})
+const businessTemplateValue = ref<any>({})
 const businessTemplateKey = ref(1)
 const businessTemplate = ref({
   config: {},
@@ -244,7 +247,8 @@ const businessOpportunityForm = reactive<businessOpportunityFormType>({
 })
 const fixedData = reactive({
   BusinessStage: [] as fixedDataInterface[],
-  Personnel: [] as personnelInterface[]
+  Personnel: [] as personnelInterface[],
+  ProductArr: [] as productInterface[]
 })
 const productTableList = ref([])
 const productTableListValue = ref([])
@@ -253,8 +257,8 @@ const productTableListValue = ref([])
 function editBusiness(visibles: boolean) {
   businessTemplateRef.value?.getData().then((res: any) => {
     let productTableListData = relatedProductsRef?.value?.returnData()
-    console.log(!productTableListData, judgmentaAmounteEqual({...businessTemplateValue.value, ...res}, productTableListData))
-    if(!productTableListData || judgmentaAmounteEqual({...businessTemplateValue.value, ...res}, productTableListData)) {
+    console.log(!productTableListData, judgmentaAmounteEqual({ ...businessTemplateValue.value, ...res }, productTableListData))
+    if (!productTableListData || judgmentaAmounteEqual({ ...businessTemplateValue.value, ...res }, productTableListData)) {
       return
     }
 
@@ -352,7 +356,7 @@ function businessDeteleItem(value: string | number, label: string, batch: boolea
       changeBatch(false)
       getBusinessTableList()
     }).catch((err) => {
-      globalPopup?.showError(err.message)
+      globalPopup?.showError(err.msg)
     })
   })
 }
@@ -481,6 +485,15 @@ async function getSystemField() {
     }
   })
 
+  post(GETTABLELISTPRODUCT, { pageIndex: -1, pageSize: -1 }).then(({ data }) => {
+    fixedData.ProductArr = (data.record || []).map((item: any) => {
+      const { id, productName } = item
+      return {
+        value: id, label: productName
+      }
+    })
+  })
+
   const res = await get(GETGENERATEFOEM)
   businessTemplate.value = JSON.parse(res.data[0].config)
 }

+ 5 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/type.d.ts

@@ -33,4 +33,9 @@ interface businessTableColumnInterface {
   width: string;
   eventName?: string;
   event?: () => void;
+}
+
+interface productInterface {
+  value: string | number;
+  label: string;
 }

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

@@ -29,7 +29,7 @@ export const actionButtons: any[] = [
 ]
 
 export const tableColumns: TableColumn[] = [
-    { prop: 'name', label: '联系人', event: 'toDetali', width: '150' },
+    { prop: 'name', label: '联系人姓名', event: 'toDetali', width: '150' },
     { prop: 'customName', label: '客户名称', width: '150' },
     { prop: 'phone', label: '电话号码', width: '200' },
     { prop: 'email', label: '邮箱', width: '200' },

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

@@ -89,7 +89,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}】联系人吗?`).then(() => {
         let url = type == '恢复' ? URL_RESTORE : URL_DETELEITEM
         post(url, { ids: value }).then(res => {
             if (res.code != 'ok') {
@@ -100,7 +100,7 @@ function businessOperationItem(value: string | number, label: string, type: oper
             getTableList()
             changeBatch(false)
         }).catch((err) => {
-            globalPopup?.showError(err.message)
+            globalPopup?.showError(err.msg)
         })
     })
 }

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

@@ -5,13 +5,13 @@
             <div>
                 <el-button type="primary" v-if="!info.ownerId">认领</el-button>
                 <el-button type="primary" v-else @click="operationCli(false)">转移</el-button>
-                <el-button type="primary" @click="editInfo(info)">编辑</el-button>
+                <el-button type="primary" v-permission="['contactsEdit']" @click="editInfo(info)">编辑</el-button>
             </div>
         </div>
         <div class="form flex flex-wrap justify-between">
             <div v-for="item in formItems" :key="item.label" class="formItem flex pt-2 pb-1" :style="{ width: item.width }">
                 <div :class="item.labelClass">{{ item.label }}:</div>
-                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ item.value }}</div>
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1" v-ellipsis-tooltip>{{ item.value }}</div>
             </div>
         </div>
 
@@ -159,14 +159,14 @@ function closeVisible(type: keyof typeof allVisible) {
 }
 
 const formItems = reactive([
-    { label: '联系人', key: 'contactsName', value: '', labelClass: 'w-20 text-right text-gray-500', width: '48%' },
-    { label: '客户', key: 'productName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
+    { label: '联系人', key: 'name', value: '', labelClass: 'w-20 text-right text-gray-500', width: '48%' },
+    { label: '客户', key: 'customName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
     { label: '电话', key: 'phone', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
     { label: '邮箱', key: 'email', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
     { label: '职务', key: 'position', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
     { label: '性别', key: 'sexValue', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
     { label: '地址', key: 'address', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '负责人', key: 'inchargerName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
+    { label: '负责人', key: 'ownerName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
     { label: '创建人', key: 'creatorName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
     { label: '创建时间', key: 'createTime', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
     { label: '备注', key: 'remark', value: '', labelClass: 'w-22 text-right text-gray-500', width: '100%' },

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

@@ -2,7 +2,7 @@
     <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>
+            <div v-permission="['businessAddAnEdit']">
                 <el-button type="primary" @click="addBusiness()">新建商机</el-button>
             </div>
         </div>
@@ -15,14 +15,14 @@
                         }}</el-button>
                     </template>
                 </el-table-column>
-                <el-table-column prop="customerName" label="客户名称" width="130" />
+                <el-table-column prop="customerName" label="客户名称" width="140" />
                 <el-table-column prop="inchargerName" label="负责人" width="130" />
                 <el-table-column prop="amountOfMoney" label="商机金额" width="130" />
                 <el-table-column prop="expectedTransactionDate" label="预计成交时间" width="170" />
                 <el-table-column prop="stageValue" label="商机阶段" width="130" />
                 <el-table-column prop="creatorName" label="创建人" width="130" />
                 <el-table-column prop="createTime" label="创建时间" width="130" />
-                <el-table-column prop="modifyTime" label="修改时间" width="130" />
+                <el-table-column prop="editTime" label="修改时间" width="130" />
             </el-table>
         </div>
 
@@ -54,7 +54,7 @@ import { get, post } from '@/utils/request';
 import { useRouter, useRoute } from "vue-router";
 
 import RelatedProducts from '@/components/relatedProducts/relatedProducts.vue'
-import { formatDateTime } from '@/utils/times';
+import { formatDate, formatDateTime } from '@/utils/times';
 import { GETGENERATEFOEM, UPDATEINSET } from '@/pages/business/api';
 import { GETTABLELIST } from '@/pages/product/api';
 import { judgmentaAmounteEqual } from '@/utils/tools';
@@ -143,7 +143,12 @@ function closeVisible(type: keyof typeof allVisible) {
 watchEffect(() => {
     const { data } = props
     information.value = data
-    relatedTaskstable.value = data.businessOpportunityList
+    relatedTaskstable.value = data.businessOpportunityList.map((item: any) => {
+        return {
+            ...item,
+            expectedTransactionDate: item.expectedTransactionDate ? formatDate(new Date(item.expectedTransactionDate)) : ''
+        }
+    })
 });
 
 async function getSystemField() {

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

@@ -81,7 +81,7 @@ function getAllContacts() {
     post(URL_GETALL, {}).then(({ data }) => {
         options.value = (data || []).map((item: any) => ({ value: item.id, label: item.name }))
     }).catch((err) => {
-        globalPopup?.showError(err.message)
+        globalPopup?.showError(err.msg)
     })
 }
 

+ 24 - 23
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/index.vue

@@ -26,11 +26,11 @@
         <div class="flex justify-end pb-3">
           <!-- 操作按钮 -->
           <!-- <el-button v-for="(button, index) in actionButtons" :key="index" type="primary">{{ button.text }}</el-button> -->
-          <el-button type="primary" @click="editContacts(false)">新建联系人</el-button>
-          <el-button type="primary" @click="batchDeteleItem" :disabled="batchTableData.length <= 0">批量删除</el-button>
-          <el-button type="primary" @click="showVisible('deteleContactsVisible')">回收站</el-button>
-          <el-button type="primary" @click="showVisible('importVisible')">导入</el-button>
-          <el-button type="primary" @click="exportCustomerTableList()" :loading="allLoading.exoprtLoading">导出</el-button>
+          <el-button type="primary" v-permission="['contactsAdd']" @click="editContacts(false)">新建联系人</el-button>
+          <el-button type="primary" v-permission="['contactsDelete']" @click="batchDeteleItem" :disabled="batchTableData.length <= 0">批量删除</el-button>
+          <el-button type="primary" v-permission="['contactsRecycle']" @click="showVisible('deteleContactsVisible')">回收站</el-button>
+          <el-button type="primary" v-permission="['contactsImport']" @click="showVisible('importVisible')">导入</el-button>
+          <el-button type="primary" v-permission="['contactsExport']" @click="exportCustomerTableList()" :loading="allLoading.exoprtLoading">导出</el-button>
         </div>
         <div class="flex-1 w-full overflow-hidden">
           <!-- 表格 -->
@@ -49,11 +49,11 @@
                 </template>
               </template>
             </el-table-column>
-            <el-table-column :label="'操作'" :width="'200px'" fixed="right">
+            <el-table-column :label="'操作'" :width="'200px'" fixed="right" v-permission="['contactsEdit', 'tasksAdd', 'contactsDelete']">
               <template #default="scope">
-                <el-button link type="primary" size="large" @click="editContacts(scope.row)">编辑</el-button>
-                <el-button link type="primary" size="large" @click="newTask(scope.row)">新建任务</el-button>
-                <el-button link type="danger" size="large"
+                <el-button link type="primary" size="large" v-permission="['contactsEdit']" @click="editContacts(scope.row)">编辑</el-button>
+                <el-button link type="primary" size="large" v-permission="['tasksAdd']" @click="newTask(scope.row)">新建任务</el-button>
+                <el-button link type="danger" size="large" v-permission="['contactsDelete']"
                   @click="contactsDeteleItem(scope.row.id, scope.row.customName)">删除</el-button>
               </template>
             </el-table-column>
@@ -73,7 +73,7 @@
         <div class="flex justify-between items-center border-b pb-3 dialog-header">
           <h4 :id="titleId">{{ allText.editContactsText }}</h4>
           <div>
-            <el-button type="primary" :loading="allLoading.editContactsSaveLoading"
+            <el-button type="primary" :loading="allLoading.editContactsSaveLoading" v-if="!contactsTemplateValue.id"
               @click="editContactsSave(true)">保存并新建</el-button>
             <el-button type="primary" :loading="allLoading.editContactsSaveLoading"
               @click="editContactsSave(false)">保存</el-button>
@@ -158,18 +158,18 @@ const selectData = reactive({ // 下拉数据
   Customer: [] as any[],
 })
 const filterItems = ref<FilterItem[]>([
-  { label: '联系人', key: 'contactPerson', type: 'input' },
-  { label: '客户名称', key: 'customerId', type: 'select', options: selectData.Customer },
-  { label: '电话号码', key: 'phoneNumber', type: 'input' },
+  { label: '联系人', key: 'name', type: 'input' },
+  { label: '客户名称', key: 'customId', type: 'select', options: selectData.Customer },
+  { label: '电话号码', key: 'phone', type: 'input' },
   { label: '邮箱', key: 'email', type: 'input' },
-  { label: '负责人', key: 'responsibleId', type: 'select', options: selectData.Personnel },
-  { label: '创建人', key: 'createId', type: 'select', options: selectData.Personnel },
+  { label: '负责人', key: 'ownerId', type: 'select', options: selectData.Personnel },
+  { label: '创建人', key: 'creatorId', type: 'select', options: selectData.Personnel },
 ])
 const contactsTemplate = ref({
   list: [],
   config: {}
 })
-const contactsTemplateValue = ref({})
+const contactsTemplateValue = ref<any>({})
 const contactsTemplateRefKey = ref(1)
 const contactsTemplateRef = ref<typeof GenerateForm>()
 const contactsTableRef = ref<InstanceType<typeof ElTable>>()
@@ -250,8 +250,9 @@ function batchDeteleItem() {
 }
 
 function contactsDeteleItem(value: string | number, label: string, batch: boolean = false) {
-  confirmAction(`确定${batch ? '批量' : ''}删除【${label}】客户吗?`).then(() => {
-    let url = batch ? URL_BATCHDETELE : URL_DETELERECYCLE
+  confirmAction(`确定${batch ? '批量' : ''}删除【${label}】联系人吗?`).then(() => {
+    // let url = batch ? URL_BATCHDETELE : URL_DETELERECYCLE
+    let url = URL_DETELERECYCLE
     post(url, { ids: value }).then(res => {
       if (res.code != 'ok') {
         globalPopup?.showError(res.msg)
@@ -396,12 +397,12 @@ function closeVisible(type: keyof typeof allVisible) {
 function setFilterItems() {
   console.log(selectData)
   filterItems.value = [
-    { label: '联系人', key: 'contactPerson', type: 'input' },
-    { label: '客户名称', key: 'customerId', type: 'select', options: selectData.Customer },
-    { label: '电话号码', key: 'phoneNumber', type: 'input' },
+    { label: '联系人', key: 'name', type: 'input' },
+    { label: '客户名称', key: 'customId', type: 'select', options: selectData.Customer },
+    { label: '电话号码', key: 'phone', type: 'input' },
     { label: '邮箱', key: 'email', type: 'input' },
-    { label: '负责人', key: 'responsibleId', type: 'select', options: selectData.Personnel },
-    { label: '创建人', key: 'createId', type: 'select', options: selectData.Personnel },
+    { label: '负责人', key: 'ownerId', type: 'select', options: selectData.Personnel },
+    { label: '创建人', key: 'creatorId', type: 'select', options: selectData.Personnel },
   ]
 }
 

+ 19 - 28
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/corpreport/api.ts

@@ -4,7 +4,7 @@ import { dayjs } from 'element-plus';
 export type RequestProps = {
   startDate?: string;
   endDate?: string;
-  type?: 0 | 1;
+  exportType?: 0 | 1;
   userId?: number;
   departmentId?: number;
 };
@@ -25,14 +25,9 @@ export async function getStaffData(): Promise<any> {
   return await get('/user/getSimpleActiveUserList');
 }
 
-export async function exportFile(
-  payload: RequestProps,
-  type: number
-): Promise<any> {
+export async function exportFile(payload: RequestProps, type: number): Promise<any> {
   return await post(
-    type === 0
-      ? '/report/exportCustomerTotalCount'
-      : '/report/exportCustomerTransferRate',
+    type === 0 ? '/report/exportCustomerTotalCount' : '/report/exportCustomerTransferRate',
     payload
   );
 }
@@ -40,46 +35,42 @@ export async function exportFile(
 export const dateCollections = [
   {
     name: '当日',
-    start_time: dayjs().startOf('date').toISOString(),
-    end_time: dayjs().endOf('date').toISOString()
+    start_time: dayjs().startOf('date').format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().endOf('date').format('YYYY-MM-DD HH:mm:ss')
   },
   {
     name: '昨日',
-    start_time: dayjs().startOf('date').subtract(1, 'day').toISOString(),
-    end_time: dayjs().endOf('date').subtract(1, 'day').toISOString()
+    start_time: dayjs().startOf('date').subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().endOf('date').subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss')
   },
   {
     name: '本周',
-    start_time: dayjs().startOf('week').add(1, 'day').toISOString(),
-    end_time: dayjs().endOf('week').add(1, 'day').toISOString()
+    start_time: dayjs().startOf('week').add(1, 'day').format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().endOf('week').add(1, 'day').format('YYYY-MM-DD HH:mm:ss')
   },
   {
     name: '上周',
-    start_time: dayjs()
-      .add(-1, 'week')
-      .startOf('week')
-      .add(1, 'day')
-      .toISOString(),
-    end_time: dayjs().add(-1, 'week').endOf('week').add(1, 'day').toISOString()
+    start_time: dayjs().add(-1, 'week').startOf('week').add(1, 'day').format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().add(-1, 'week').endOf('week').add(1, 'day').format('YYYY-MM-DD HH:mm:ss')
   },
   {
     name: '本月',
-    start_time: dayjs().startOf('month').toISOString(),
-    end_time: dayjs().endOf('month').toISOString()
+    start_time: dayjs().startOf('month').format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().endOf('month').format('YYYY-MM-DD HH:mm:ss')
   },
   {
     name: '上月',
-    start_time: dayjs().add(-1, 'month').startOf('month').toISOString(),
-    end_time: dayjs().add(-1, 'month').endOf('month').toISOString()
+    start_time: dayjs().add(-1, 'month').startOf('month').format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().add(-1, 'month').endOf('month').format('YYYY-MM-DD HH:mm:ss')
   },
   {
     name: '本季度',
-    start_time: dayjs().month(0).toISOString(),
-    end_time: dayjs().month(2).endOf('month').toISOString()
+    start_time: dayjs().month(0).format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().month(2).endOf('month').format('YYYY-MM-DD HH:mm:ss')
   },
   {
     name: '上季度',
-    start_time: dayjs().add(-1, 'year').month(9).toISOString(),
-    end_time: dayjs().add(-1, 'year').month(11).endOf('month').toISOString()
+    start_time: dayjs().add(-1, 'year').month(9).format('YYYY-MM-DD HH:mm:ss'),
+    end_time: dayjs().add(-1, 'year').month(11).endOf('month').format('YYYY-MM-DD HH:mm:ss')
   }
 ];

+ 25 - 33
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/corpreport/index.vue

@@ -16,7 +16,7 @@ import { downloadFile } from '@/utils/tools';
 
 const isLoading = ref(false);
 const dataSource = ref([]);
-const form = reactive({ type: undefined, date: undefined, member: undefined });
+const form = reactive({ type: 1, date: undefined, member: undefined });
 const memberOptions = ref([]);
 // 0 客户总量  1 客户转化率
 const dataType = ref<0 | 1>(0);
@@ -49,7 +49,7 @@ const onSubmit = async (isExport?: boolean) => {
   const payload = {
     startDate: form.date && dateCollections[form.date - 1].start_time,
     endDate: form.date && dateCollections[form.date - 1].end_time,
-    type: form.type,
+    exportType: form.type,
     userId: form.type === 1 ? form.member : undefined,
     departmentId: form.type === 1 ? undefined : form.member
   } as RequestProps;
@@ -70,10 +70,10 @@ const queryOverall = async (payload?: RequestProps) => {
   isLoading.value = false;
 
   dataSource.value = data.map((d) => ({
-    name: d.name,
     dealRate: d.dealRate * 100,
     customerDeal: d.customerDeal,
-    customertotal: d.customertotal
+    customertotal: d.customertotal,
+    name: form.type === 1 ? d.name : d.departmentName
   }));
 
   // @ts-ignore
@@ -85,7 +85,7 @@ const queryOverall = async (payload?: RequestProps) => {
   chartOptions.dataset.dimensions = ['name', '成交客户数', '新增客户数'];
   // @ts-ignore
   chartOptions.dataset.source = data.map((d) => ({
-    name: d.name,
+    name: form.type === 1 ? d.name : d.departmentName,
     ['成交客户数']: d.customerDeal,
     ['新增客户数']: d.customertotal
   }));
@@ -93,12 +93,13 @@ const queryOverall = async (payload?: RequestProps) => {
 };
 
 const queryConversion = async (payload?: RequestProps) => {
+  console.log(payload, '--------');
   isLoading.value = true;
   const { data = [] } = await getConversionData(payload);
   isLoading.value = false;
 
   dataSource.value = data.map((d) => ({
-    name: d.name,
+    name: form.type === 1 ? d.name : d.departmentName,
     dealRate: d.dealRate * 100
   }));
 
@@ -108,19 +109,18 @@ const queryConversion = async (payload?: RequestProps) => {
   chartOptions.dataset.dimensions = ['name', '客户转化率(%)'];
   // @ts-ignore
   chartOptions.dataset.source = data.map((d) => ({
-    name: d.name,
+    name: form.type === 1 ? d.name : d.departmentName,
     ['客户转化率(%)']: d.dealRate * 100
   }));
   chartOptions.legend = undefined;
 };
 
 watchEffect(() => {
-  dataType.value === 0 ? queryOverall() : queryConversion();
+  dataType.value === 0 ? queryOverall({ exportType: 1 }) : queryConversion({ exportType: 1 });
 });
 
 watchEffect(async () => {
-  const { data = [] } =
-    form.type === 1 ? await getStaffData() : await getDepartmentData();
+  const { data = [] } = form.type === 1 ? await getStaffData() : await getDepartmentData();
 
   memberOptions.value = data.map((d) => ({
     name: form.type === 1 ? d.name : d.departmentName,
@@ -133,8 +133,8 @@ watchEffect(async () => {
   <div class="m-5 bg-white h-full p-4 rounded">
     <div class="flex justify-between">
       <el-form :model="form" class="flex gap-4">
-        <el-form-item class="w-28">
-          <el-select clearable v-model="form.date">
+        <el-form-item>
+          <el-select clearable v-model="form.date" style="width: 112px">
             <el-option
               v-for="date in dateOptions"
               :key="date.value"
@@ -143,18 +143,15 @@ watchEffect(async () => {
             />
           </el-select>
         </el-form-item>
-        <el-form-item class="w-28">
-          <el-select
-            clearable
-            v-model="form.type"
-            @change="form.member = undefined"
-          >
+        <el-form-item>
+          <el-select v-model="form.type" @change="form.member = undefined" style="width: 112px">
             <el-option label="按部门" :value="0" />
             <el-option label="按员工" :value="1" />
           </el-select>
         </el-form-item>
-        <el-form-item class="w-52">
+        <el-form-item>
           <el-select
+            style="width: 208px"
             clearable
             v-model="form.member"
             placeholder="选择部门(默认为本部门及下属部门)"
@@ -168,13 +165,12 @@ watchEffect(async () => {
           </el-select>
         </el-form-item>
         <el-form-item>
-          <el-button
-            type="primary"
-            :loading="isLoading"
-            @click="onSubmit(false)"
-            >搜索</el-button
-          >
-          <el-button type="primary" @click="onSubmit(true)">导出</el-button>
+          <!-- :loading="isLoading" -->
+
+          <div class="flex gap-1">
+            <el-button type="primary" @click="onSubmit(false)">搜索</el-button>
+            <el-button type="primary" @click="onSubmit(true)">导出</el-button>
+          </div>
         </el-form-item>
       </el-form>
 
@@ -185,7 +181,7 @@ watchEffect(async () => {
           () => {
             form.date = undefined;
             form.member = undefined;
-            form.type = undefined;
+            form.type = 1;
             dataSource = [];
           }
         "
@@ -198,12 +194,8 @@ watchEffect(async () => {
       <Echarts :option="chartOptions"></Echarts>
     </div>
     <el-table :data="dataSource">
-      <el-table-column prop="name" label="员工姓名" />
-      <el-table-column
-        prop="dealRate"
-        label="客户转化率(%)"
-        v-if="dataType === 1"
-      />
+      <el-table-column prop="name" label="名称" />
+      <el-table-column prop="dealRate" label="客户转化率(%)" v-if="dataType === 1" />
       <template v-else>
         <el-table-column prop="customertotal" label="新增客户数" />
         <el-table-column prop="customerDeal" label="成交客户数" />

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

@@ -1,5 +1,5 @@
 export const MOD = '/customer'
-export const IMPORTMOD = 'Custom'
+export const IMPORTMOD = 'Customer'
 export const PREFIX = '/custom'
 export const GETSYSFILED = '/sys-dict/getListByCode'
 export const GETPERSONNEL = '/user/getSimpleActiveUserList'

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

@@ -2,7 +2,7 @@
     <div class="attachment pl-4 pr-4 pt-3 pb-3 h-full flex flex-col">
         <div class="flex justify-between">
             <div class="title">附件</div>
-            <div>
+            <div v-permission="['customerEdit']">
                 <el-upload ref="uploadRef" :http-request="httpUploadFile" :limit="1" :show-file-list="false"
                     element-loading-text="正在上传">
                     <template #trigger>
@@ -16,7 +16,7 @@
                 <el-table-column prop="name" label="附件名称" width="180" />
                 <el-table-column prop="size" label="附件大小" width="120" />
                 <el-table-column prop="userName" label="上传人" width="120" />
-                <el-table-column prop="createTime" label="上传时间" width="180" />
+                <el-table-column prop="createTime" label="上传时间" width="180" sortable />
                 <el-table-column label="操作" width="180" fixed="right">
                     <template #default="scope">
                         <el-button link type="primary" size="large" @click="fileDownload(scope.row)">下载</el-button>
@@ -50,6 +50,7 @@ import { UploadRequestOptions } from 'element-plus';
 import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
 import { URL_DETELEFILE, URL_REFFILENAME, URL_UPLOADFILE } from '../api';
 import { confirmAction, downloadFile } from '@/utils/tools';
+import { formatDate } from '@/utils/times';
 
 const emits = defineEmits(['refreshData']);
 const globalPopup = inject<GlobalPopup>('globalPopup')
@@ -118,7 +119,12 @@ function showVisible(item: any) {
 
 watchEffect(() => {
     information.value = props.data
-    attachmenttable.value = (props.data.files || [])
+    attachmenttable.value = (props.data.files || []).map((item: any) => {
+        return {
+            ...item,
+            createTime: formatDate(new Date(item.createTime))
+        }
+    })
 });
 
 // 生命周期钩子

+ 4 - 4
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/deteleTables.vue

@@ -30,9 +30,9 @@
                     <el-table-column label="操作" fixed="right" width="120">
                         <template #default="scope">
                             <el-button link type="primary" size="large"
-                                @click="operationItem(scope.row.id, scope.row.name, '恢复')">恢复</el-button>
+                                @click="operationItem(scope.row.id, scope.row.customName, '恢复')">恢复</el-button>
                             <el-button link type="danger" size="large"
-                                @click="operationItem(scope.row.id, scope.row.name, '删除')">删除</el-button>
+                                @click="operationItem(scope.row.id, scope.row.customName, '删除')">删除</el-button>
                         </template>
                     </el-table-column>
                 </el-table>
@@ -87,7 +87,7 @@ watch(() => props.visibles, (newVal) => {
 
 function batchOperation(type: operationType) {
     const value = batchTableData.value.map((item: any) => item.id).join(',')
-    const label = batchTableData.value.map((item: any) => item.name).join(',')
+    const label = batchTableData.value.map((item: any) => item.customName).join(',')
     operationItem(value, label, type, true)
 }
 
@@ -103,7 +103,7 @@ function operationItem(value: string | number, label: string, type: operationTyp
             getTableList()
             changeBatch(false)
         }).catch((err) => {
-            globalPopup?.showError(err.message)
+            globalPopup?.showError(err.msg)
         })
     })
 }

+ 22 - 12
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/component/information.vue

@@ -5,27 +5,31 @@
             <div>
                 <el-button type="primary" @click="claimCustomer()" v-if="!information.inchargerName">认领</el-button>
                 <el-button type="primary" @click="transferCli()">转移</el-button>
-                <el-button type="primary" @click="editCustomer()">编辑</el-button>
+                <el-button type="primary" v-permission="['customerEdit']" @click="editCustomer()">编辑</el-button>
             </div>
         </div>
         <div class="form flex flex-wrap justify-between">
             <div class="formItem flex pt-2 pb-1">
                 <div class="w-20 text-right text-gray-500">客户名称:</div>
-                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ information.customName }}</div>
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1" v-ellipsis-tooltip>{{
+                    information.customName }}</div>
             </div>
             <div class="formItem flex pt-2 pb-1">
                 <div class="w-22 text-right text-gray-500">客户来源:</div>
-                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ information.customSourceValue }}
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{
+                    information.customSourceValue }}
                 </div>
             </div>
             <div class="formItem flex pt-2 pb-1">
                 <div class="w-22 text-right text-gray-500">电话号码:</div>
-                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ information.companyPhone }}
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1" v-ellipsis-tooltip>{{
+                    information.companyPhone }}
                 </div>
             </div>
             <div class="formItem flex pt-2 pb-1">
                 <div class="w-22 text-right text-gray-500">邮箱:</div>
-                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ information.email }}</div>
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1" v-ellipsis-tooltip>{{
+                    information.email }}</div>
             </div>
             <div class="formItem flex pt-2 pb-1">
                 <div class="w-22 text-right text-gray-500">客户行业:</div>
@@ -34,7 +38,8 @@
             </div>
             <div class="formItem flex pt-2 pb-1">
                 <div class="w-22 text-right text-gray-500">客户级别:</div>
-                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ information.customerLevelValue
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{
+                    information.customerLevelValue
                 }}</div>
             </div>
             <div class="formItem flex pt-2 pb-1">
@@ -48,7 +53,8 @@
             </div>
             <div class="formItem flex pt-2 pb-1">
                 <div class="w-22 text-right text-gray-500">创建人:</div>
-                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ information.creatorName }}</div>
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ information.creatorName }}
+                </div>
             </div>
             <div class="formItem flex pt-2 pb-1">
                 <div class="w-22 text-right text-gray-500">创建时间:</div>
@@ -57,7 +63,7 @@
             </div>
             <div class="formItem flex pt-2 pb-1" style="width: 100%;">
                 <div class="w-22 text-right text-gray-500">备注:</div>
-                <div class="flex-1 ml-1 text ">
+                <div class="flex-1 ml-1 text " v-ellipsis-tooltip>
                     {{ information.customDesc }}
                 </div>
             </div>
@@ -91,7 +97,8 @@
                 <div class="flex justify-between items-center border-b pb-3 dialog-header">
                     <h4 :id="titleId">{{ '编辑客户' }}</h4>
                     <div>
-                        <el-button type="primary" @click="saveCustomer()" :loading="allLoading.saveLading">保存</el-button>
+                        <el-button type="primary" @click="saveCustomer()"
+                            :loading="allLoading.saveLading">保存</el-button>
                         <el-button @click="closeVisible('editCustomerVisible')">取消</el-button>
                     </div>
                 </div>
@@ -144,7 +151,9 @@ const allVisible = reactive({
 function saveCustomer() {
     generateForm.value?.getData().then((res: any) => {
         allLoading.saveLading = true
-        post(URL_EDITSAVE, { ...generateFormValue.value, ...res }).then((_res) => {
+        let formVal = { ...generateFormValue.value, ...res }
+        delete formVal.createTime
+        post(URL_EDITSAVE, { ...formVal }).then((_res) => {
             globalPopup?.showSuccess('操作成功')
             closeVisible('editCustomerVisible')
             emits('refreshData')
@@ -188,11 +197,12 @@ function claimCustomer() {
 }
 
 function editCustomer() {
-    const { id, companyPhone, customName, inchargerId, createTime, customSourceId, customerIndustryId, customerLevelId, email, telPhone } = information.value
+    const { id, companyPhone, customName, inchargerId, createTime, customSourceId, customerIndustryId, customerLevelId, email, telPhone, customDesc } = information.value
     const formVal = {
         id, customName, inchargerId, customerIndustryId, customerLevelId, email, customSourceId,
         createTime: formatDate(new Date(createTime)),
-        telPhone, companyPhone
+        telPhone, companyPhone,
+        customDesc
     }
     generateFormValue.value = formVal
     allLoading.generateFormDataLoading = true

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

@@ -5,14 +5,15 @@
         </div>
         <div class="flex-1 overflow-auto pt-5">
             <el-table :data="operationRecordtable" border style="width: 100%;height: 278px;">
-                <el-table-column prop="creaTime" label="操作时间" width="140" />
-                <el-table-column prop="username" label="操作人" width="120" />
+                <el-table-column prop="creatTime" label="操作时间" width="140" />
+                <el-table-column prop="userName" label="操作人" width="120" />
                 <el-table-column prop="name" label="操作内容" />
             </el-table>
         </div>
     </div>
 </template>
 <script lang="ts" setup>
+import { formatDate } from '@/utils/times';
 import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
 
 const operationRecordtable = ref([])
@@ -25,7 +26,12 @@ const props = defineProps<{
 watchEffect(() => {
     const { data } = props
     information.value = data
-    operationRecordtable.value = data.actionLogs || []
+    operationRecordtable.value = (data.actionLogs || []).map((item: any) => {
+        return {
+            ...item,
+            creatTime: formatDate(new Date(item.creatTime))
+        }
+    })
 })
 
 // 生命周期钩子

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

@@ -2,27 +2,26 @@
     <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>
+            <div v-permission="['businessAddAnEdit']">
                 <el-button type="primary" @click="editNewBusiness()">新建商机</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="name">
                     <template #default="scope">
                         <el-button link type="primary" size="large">{{
-                            scope.row.taskName
-                        }}</el-button>
+                            scope.row.name
+                            }}</el-button>
                     </template>
                 </el-table-column>
-                <el-table-column prop="priority" label="客户名称" width="130" />
-                <el-table-column prop="status" label="负责人" width="130" />
-                <el-table-column prop="executor" label="商机金额" width="130" />
-                <el-table-column prop="startTime" label="预计成交时间" width="130" />
-                <el-table-column prop="endTime" label="商机阶段" width="130" />
-                <el-table-column prop="endTime" label="创建人" width="130" />
-                <el-table-column prop="endTime" label="创建时间" width="130" />
-                <el-table-column prop="endTime" label="修改时间" width="130" />
+                <el-table-column prop="customerName" label="客户名称" width="130" />
+                <el-table-column prop="inchargerName" label="负责人" width="130" />
+                <el-table-column prop="amountOfMoney" label="商机金额" width="130" />
+                <el-table-column prop="expectedTransactionDate" label="预计成交时间" width="200" />
+                <el-table-column prop="stageValue" label="商机阶段" width="140" />
+                <el-table-column prop="creatorName" label="创建人" width="130" />
+                <el-table-column prop="createTime" label="创建时间" width="130" />
             </el-table>
         </div>
 
@@ -87,7 +86,7 @@ const allLoading = reactive({
 function editBusiness(visibles: boolean) {
     businessTemplateRef.value?.getData().then((res: any) => {
         let productTableListData = relatedProductsRef?.value?.returnData()
-        if(!productTableListData || judgmentaAmounteEqual({ ...businessTemplateValue.value, ...res }, productTableListData)) {
+        if (!productTableListData || judgmentaAmounteEqual({ ...businessTemplateValue.value, ...res }, productTableListData)) {
             return
         }
         productTableListData.forEach((item: any) => {
@@ -168,7 +167,7 @@ function getProductTableList() {
 watchEffect(() => {
     const { data } = props
     information.value = data
-    relatedTaskstable.value = []
+    relatedTaskstable.value = (data.businessOpportunitys || [])
 })
 
 // 生命周期钩子

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

@@ -2,7 +2,7 @@
     <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>
+            <div v-permission="['contactsAdd']">
                 <el-button type="primary" @click="editContacts(information)">新建联系人</el-button>
             </div>
         </div>
@@ -13,20 +13,20 @@
                         {{ scope.$index + 1 }}
                     </template>
                 </el-table-column>
-                <el-table-column prop="taskName" label="联系人姓名">
+                <el-table-column prop="name" label="联系人姓名">
                     <template #default="scope">
                         <el-button link type="primary" size="large">{{
-                            scope.row.taskName
+                            scope.row.name
                         }}</el-button>
                     </template>
                 </el-table-column>
-                <el-table-column prop="priority" label="电话号码" width="130" />
-                <el-table-column prop="status" label="邮箱" width="130" />
-                <el-table-column prop="executor" label="职务" width="130" />
-                <el-table-column prop="startTime" label="性别" width="130" />
-                <el-table-column prop="endTime" label="负责人" width="130" />
-                <el-table-column prop="endTime" label="创建人" width="130" />
-                <el-table-column prop="endTime" label="创建时间" width="130" />
+                <el-table-column prop="phone" label="电话号码" width="130" />
+                <el-table-column prop="email" label="邮箱" width="130" />
+                <el-table-column prop="position" label="职务" width="130" />
+                <el-table-column prop="sexValue" label="性别" width="130" />
+                <el-table-column prop="ownerName" label="负责人" width="130" />
+                <el-table-column prop="creatorName" label="创建人" width="130" />
+                <el-table-column prop="createTime" label="创建时间" width="130" />
             </el-table>
         </div>
 
@@ -116,7 +116,7 @@ const allVisible = reactive({
 watchEffect(() => {
     const { data } = props
     information.value = data
-    relatedCustomertable.value = []
+    relatedCustomertable.value = (data.contacts || [])
 })
 
 async function getSystemField() {

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

@@ -2,29 +2,29 @@
     <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>
+            <div v-permission="['orderAdd']">
                 <el-button type="primary" @click="editOrder()">新建销售订单</el-button>
             </div>
         </div>
         <div class="flex-1 overflow-auto pt-3">
             <el-table :data="relatedOrders" border style="width: 100%;height: 300px;">
-                <el-table-column prop="priority" label="订单编号" width="130" />
-                <el-table-column prop="taskName" label="订单名称">
+                <el-table-column prop="orderCode" label="订单编号" width="130" />
+                <el-table-column prop="orderName" label="订单名称" min-width="200">
                     <template #default="scope">
                         <el-button link type="primary" size="large">{{
-                            scope.row.taskName
-                        }}</el-button>
+                            scope.row.orderName
+                            }}</el-button>
                     </template>
                 </el-table-column>
-                <el-table-column prop="priority" label="客户名称" width="130" />
-                <el-table-column prop="status" label="订单金额" width="130" />
-                <el-table-column prop="executor" label="已回款" width="130" />
-                <el-table-column prop="startTime" label="未回款" width="130" />
-                <el-table-column prop="endTime" label="订单类型" width="130" />
-                <el-table-column prop="endTime" label="下单时间" width="130" />
-                <el-table-column prop="endTime" label="负责人" width="130" />
-                <el-table-column prop="endTime" label="创建人" width="130" />
-                <el-table-column prop="endTime" label="创建时间" width="130" />
+                <el-table-column prop="customName" label="客户名称" width="130" />
+                <el-table-column prop="price" label="订单金额(¥)" width="130" />
+                <el-table-column prop="receivedPayment" label="已回款(¥)" width="130" />
+                <el-table-column prop="unReceivedPayment" label="未回款(¥)" width="130" />
+                <el-table-column prop="typeName" label="订单类型" width="130" />
+                <el-table-column prop="placeTime" label="下单时间" width="200" />
+                <el-table-column prop="inchargerName" label="负责人" width="130" />
+                <el-table-column prop="creatorName" label="创建人" width="130" />
+                <el-table-column prop="createTime" label="创建时间" width="200" />
             </el-table>
         </div>
 
@@ -97,14 +97,20 @@ function saveOrder(flag: boolean) {
                 productTableListData[i].num = productTableListData[i].quantity
         }
         const produt = productTableListData ? JSON.stringify(productTableListData) : []
-        allLoading.editSaveLading = true
-        post(URL_OEDERUPDATE, {
+        const formVal = {
             ...orderTemplateValue.value,
             ...res,
             orderEndDate: res.orderEndDate ? formatDate(res.orderEndDate) : '',
             orderStartDate: res.orderStartDate ? formatDate(res.orderStartDate) : '',
+            placeTime: res.placeTime ? formatDate(res.placeTime) : '',
             orderProductDetailString: produt
-        }).then((_res) => {
+        }
+        if((formVal.price || 0) < (formVal.receivedPayment || 0)) {
+            globalPopup?.showError('已回款金额不能大于订单金额')
+            return
+        }
+        allLoading.editSaveLading = true
+        post(URL_OEDERUPDATE, formVal).then((_res) => {
             allVisible.editOrderVisible = flag
             globalPopup?.showSuccess('操作成功')
             if (flag) {
@@ -122,7 +128,7 @@ function saveOrder(flag: boolean) {
 function editOrder() {
     showVisible('editOrderVisible')
     allLoading.orderTemplateLoadinng = true
-    
+
     orderTemplateValue.value = { customId: information.value.id }
     productTableListValue.value = []
     setTimeout(() => {
@@ -176,7 +182,7 @@ function getProductTableList() {
 watchEffect(() => {
     const { data } = props
     information.value = data
-    relatedOrders.value = []
+    relatedOrders.value = (data.salesOrders || [])
 })
 
 // 生命周期钩子

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

@@ -7,7 +7,7 @@
         </el-link>
       </div>
       <div class="mr-8">
-        <el-select v-model="values" placeholder="请选择" style="width: 150px" @change="getDetail()">
+        <el-select v-model="values" placeholder="请选择" style="width: 250px" @change="getDetail()">
           <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
         </el-select>
       </div>

+ 48 - 22
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/index.vue

@@ -12,7 +12,7 @@
                 <el-option v-for="item in fixedData.ClueSources" :key="item.id" :label="item.name" :value="item.id" />
               </el-select>
             </el-form-item>
-            <el-form-item label="电话号码">
+            <el-form-item label="公司号码">
               <el-input v-model="customerCriteriaForm.telPhone" clearable placeholder="请输入"></el-input>
             </el-form-item>
             <el-form-item label="邮箱">
@@ -20,7 +20,8 @@
             </el-form-item>
             <el-form-item label="客户行业">
               <el-select v-model="customerCriteriaForm.customerIndustryId" placeholder="请选择" clearable>
-                <el-option v-for="item in fixedData.CustomIndustry" :key="item.id" :label="item.name" :value="item.id" />
+                <el-option v-for="item in fixedData.CustomIndustry" :key="item.id" :label="item.name"
+                  :value="item.id" />
               </el-select>
             </el-form-item>
             <el-form-item label="客户级别">
@@ -52,46 +53,48 @@
     <div class="flex-1 p-5 overflow-auto">
       <div class="bg-white w-full h-full p-3 shadow-md rounded-md flex flex-col">
         <div class="flex justify-end pb-3">
-          <el-button type="primary" @click="editCustomer(false)">新建客户</el-button>
+          <el-button type="primary" v-permission="['customerAdd']" @click="editCustomer(false)">新建客户</el-button>
           <el-button type="primary" @click="showVisible('batchTransferVisible')"
             :disabled="batchTableData.length <= 0">批量转移</el-button>
-          <el-button type="primary" @click="batchDeteleItem()" :disabled="batchTableData.length <= 0">批量删除</el-button>
-          <el-button type="primary" @click="showVisible('deteleCustomerVisible')">回收站</el-button>
-          <el-button type="primary" @click="showVisible('importVisible')">导入</el-button>
-          <el-button type="primary" @click="exportCustomerTableList()" :loading="allLoading.exoprtLoading">导出</el-button>
+          <el-button type="primary" v-permission="['customerDelete']" @click="batchDeteleItem()" :disabled="batchTableData.length <= 0">批量删除</el-button>
+          <el-button type="primary" v-permission="['customerRecycle']" @click="showVisible('deteleCustomerVisible')">回收站</el-button>
+          <el-button type="primary" v-permission="['customerImport']" @click="showVisible('importVisible')">导入</el-button>
+          <el-button type="primary" v-permission="['customerExport']" @click="exportCustomerTableList()"
+            :loading="allLoading.exoprtLoading">导出</el-button>
         </div>
         <div class="flex-1 w-full overflow-hidden">
-          <el-table ref="customerTableRef" :data="customerTable" border v-loading="allLoading.customerTableLading"
-            style="width: 100%;height: 100%;" @selection-change="changeBatch">
+          <el-table ref="customerTableRef" :show-overflow-tooltip="tableShowOverflowTooltip" :data="customerTable" border v-loading="allLoading.customerTableLading"
+            style="width: 100%;height: 100%;" @selection-change="changeBatch" @sort-change="sortChange">
             <el-table-column type="selection" width="55" />
             <el-table-column prop="customName" label="客户名称" width="180">
               <template #default="scope">
-                <el-button link type="primary" size="large" @click.prevent="toCustomerTableDetail(scope.row)">{{
+                <!-- <el-button link type="primary" size="large" @click.prevent="toCustomerTableDetail(scope.row)">{{
                   scope.row.customName
-                }}</el-button>
+                }}</el-button> -->
+                <div class="table-text-textnowrap" @click.prevent="toCustomerTableDetail(scope.row)">{{ scope.row.customName }}</div>
               </template>
             </el-table-column>
             <el-table-column prop="customSourceValue" label="客户来源" width="180"></el-table-column>
             <el-table-column prop="companyPhone" label="公司电话" width="180"></el-table-column>
             <el-table-column prop="email" label="邮箱" width="200"></el-table-column>
             <el-table-column prop="customerIndustryValue" label="客户行业" width="180"></el-table-column>
-            <el-table-column prop="customerLevelValue" label="客户级别" width="180"></el-table-column>
+            <el-table-column prop="customerLevelValue" label="客户级别" width="180" sortable="custom"></el-table-column>
             <el-table-column prop="inchargerName" label="负责人" width="190"></el-table-column>
             <el-table-column prop="creatorName" label="创建人" width="180"></el-table-column>
             <el-table-column prop="newCreateTime" label="创建时间" width="180"></el-table-column>
-            <el-table-column label="操作" fixed="right" width="200">
+            <el-table-column label="操作" fixed="right" width="200" v-permission="['customerEdit', 'tasksAdd', 'customerDelete']">
               <template #default="scope">
-                <el-button link type="primary" size="large" @click="editCustomer(scope.row)">编辑</el-button>
-                <el-button link type="primary" size="large" @click="newTask(scope.row)">新建任务</el-button>
-                <el-button link type="danger" size="large"
+                <el-button link type="primary" size="large" v-permission="['customerEdit']" @click="editCustomer(scope.row)">编辑</el-button>
+                <el-button link type="primary" size="large" v-permission="['tasksAdd']" @click="newTask(scope.row)">新建任务</el-button>
+                <el-button link type="danger" size="large" v-permission="['customerDelete']"
                   @click="customerDeteleItem(scope.row.id, scope.row.customName)">删除</el-button>
               </template>
             </el-table-column>
           </el-table>
         </div>
         <div class="flex justify-end pt-3">
-          <el-pagination layout="total, prev, pager, next, sizes" :total="customerTotalTable" :hide-on-single-page="true"
-            @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+          <el-pagination layout="total, prev, pager, next, sizes" :total="customerTotalTable"
+            :hide-on-single-page="true" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
         </div>
       </div>
     </div>
@@ -102,7 +105,7 @@
         <div class="flex justify-between items-center border-b pb-3 dialog-header">
           <h4 :id="titleId">{{ allText.editCustomerText }}</h4>
           <div>
-            <el-button type="primary" :loading="allLoading.editCustomerSaveLoading"
+            <el-button type="primary" :loading="allLoading.editCustomerSaveLoading" v-if="!customerTemplateValue.id"
               @click="editCustomerSave(true)">保存并新建</el-button>
             <el-button type="primary" :loading="allLoading.editCustomerSaveLoading"
               @click="editCustomerSave(false)">保存</el-button>
@@ -181,6 +184,7 @@ import { useRouter, useRoute } from "vue-router";
 import { GenerateForm } from '@zmjs/form-design';
 import { createTask } from "@/components/TaskModal/taskFunction";
 import { ElTable, UploadRequestOptions } from "element-plus";
+import { tableShowOverflowTooltip } from '@/utils/globalVariables'
 
 import TaskModal from '@/components/TaskModal/index.vue'
 import DeteleBusiness from './component/deteleTables.vue'
@@ -209,6 +213,7 @@ interface customerCriteriaFormType { // 线索筛选条件类型
   customerIndustryId: string | number,
   customerLevelId: string | number,
   inchargerId: string | number,
+  isDesc?: string | number,
   startTime: string | number,
   endTime: string | number,
   pageIndex: string | number,
@@ -226,6 +231,7 @@ const customerCriteriaForm = reactive<customerCriteriaFormType>({ // 筛选条
   customerIndustryId: '',
   customerLevelId: '',
   inchargerId: '',
+  isDesc: '',
   startTime: getFirstDayOfMonth(new Date()),
   endTime: formatDate(new Date()),
   pageIndex: 1,
@@ -266,7 +272,7 @@ const customerTemplate = ref({
   config: {}
 })
 const customerTemplateRef = ref<typeof GenerateForm>() // 自定义表单dom
-const customerTemplateValue = ref({})
+const customerTemplateValue = ref<any>({})
 const customerTemplateRefKey = ref(1)
 const taskModalForm = ref({})
 const taskLoading = ref<saveLoadingType>('1')
@@ -276,6 +282,21 @@ const transferPersonnel = ref('')
 
 
 // 定义方法
+function sortChange(data: any) {
+  customerCriteriaForm.pageIndex = 1
+  switch (data.order) {
+    case 'ascending':
+      customerCriteriaForm.isDesc = 1
+      break
+    case 'descending':
+      customerCriteriaForm.isDesc = 0
+      break
+    default:
+      customerCriteriaForm.isDesc = ''
+  }
+  getCustomerTable()
+}
+
 async function importBusiness(param: UploadRequestOptions) {
   allLoading.importLoading = true
   const formData = new FormData();
@@ -331,7 +352,7 @@ function customerDeteleItem(value: string | number, label: string, batch: boolea
       changeBatch(false)
       getCustomerTable()
     }).catch((err) => {
-      globalPopup?.showError(err.message)
+      globalPopup?.showError(err.msg)
     })
   })
 }
@@ -360,7 +381,12 @@ function newTask(item: any) {
 function editCustomerSave(flag: boolean) {
   customerTemplateRef.value?.getData().then((res: any) => {
     allLoading.editCustomerSaveLoading = true
-    post(URL_EDITSAVE, { ...res }).then((_res) => {
+    let formVal = {
+      ...customerTemplateValue.value,
+      ...res
+    }
+    delete formVal.createTime
+    post(URL_EDITSAVE, { ...formVal }).then((_res) => {
       allVisible.editCustomerVisible = flag
       globalPopup?.showSuccess('保存成功')
       if (flag) {

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

@@ -7,11 +7,11 @@
       <h2 class="text-xl text-center pt-4 font-bold">客户管家</h2>
       <el-form class="pt-4" ref="ruleFormRef" :model="ruleForm" :rules="rules">
         <el-form-item prop="username">
-          <el-input clearable :prefix-icon="UserFilled" size="large" class="mt-2" v-model="ruleForm.username"
+          <el-input clearable :prefix-icon="UserFilled" size="large" class="mt-2" v-model.trim="ruleForm.username"
             autocomplete="off" placeholder="账号/手机号" />
         </el-form-item>
         <el-form-item prop="password">
-          <el-input clearable :prefix-icon="Lock" show-password size="large" class="mt-4" v-model="ruleForm.password"
+          <el-input clearable :prefix-icon="Lock" show-password size="large" class="mt-4" v-model.trim="ruleForm.password"
             autocomplete="off" placeholder="密码" />
         </el-form-item>
         <div class="pt-4">

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

@@ -23,20 +23,20 @@ export const URL_EDITEBATE = `${MOD}/editPayment`
 export const URL_DETELEITEMS = `${MOD}/deletePayment`
 
 export const tableColumns: TableColumn[] = [
-    { prop: 'orderCode', label: '订单编号', event: 'toDetali', width: '150' },
-    { prop: 'orderName', label: '订单名称', width: '150' },
+    { prop: 'orderCode', label: '订单编号', width: '150' },
+    { prop: 'orderName', label: '订单名称', event: 'toDetali', width: '150' },
     { prop: 'customName', label: '客户名称', width: '200' },
     { prop: 'businessOpportunityName', label: '商机名称', width: '200' },
-    { prop: 'price', label: '订单金额', width: '100' },
-    { prop: 'receivedPayment', label: '已回款', width: '100' },
-    { prop: 'unReceivedPayment', label: '未回款', width: '100' },
-    { prop: 'status', label: '回放状态', width: '100' },
+    { prop: 'price', label: '订单金额(¥)', width: '120' },
+    { prop: 'receivedPayment', label: '已回款(¥)', width: '100' },
+    { prop: 'unReceivedPayment', label: '未回款(¥)', width: '100' },
+    { prop: 'statusValue', label: '回款状态', width: '100' },
     { prop: 'typeName', label: '订单类型', width: '200' },
     { prop: 'placeTime', label: '下单时间', width: '200' },
     { prop: 'orderStartDate', label: '订单开始时间', width: '200' },
-    { prop: 'orderEndDate', label: '订单结束时间', width: '200' },
-    { prop: 'customSigner', label: '客户签的人', width: '200' },
-    { prop: 'companySigner', label: '公司签的人', width: '200' },
+    { prop: 'orderEndDate', label: '订单结束时间', width: '140' },
+    { prop: 'customSignerName', label: '客户签约人', width: '140' },
+    { prop: 'companySignerName', label: '公司签约人', width: '200' },
     { prop: 'inchargerName', label: '负责人', width: '200' },
     { prop: 'creatorName', label: '创建人', width: '200' },
     { prop: 'createTime', label: '创建时间', width: '200' },

+ 18 - 12
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/deteleTables.vue

@@ -5,10 +5,10 @@
             <div class="flex justify-between items-center border-b pb-3 dialog-header">
                 <h4 :id="titleId">销售订单回收站</h4>
                 <div>
-                    <el-button type="primary" v-loading="allLoading.batchRecoveryLoading" :disabled="batchTableData.length == 0"
-                        @click="batchOperation('恢复')">批量恢复</el-button>
-                    <el-button type="primary" v-loading="allLoading.batchDeteleLoading" :disabled="batchTableData.length == 0"
-                        @click="batchOperation('删除')">批量删除</el-button>
+                    <el-button type="primary" v-loading="allLoading.batchRecoveryLoading"
+                        :disabled="batchTableData.length == 0" @click="batchOperation('恢复')">批量恢复</el-button>
+                    <el-button type="primary" v-loading="allLoading.batchDeteleLoading"
+                        :disabled="batchTableData.length == 0" @click="batchOperation('删除')">批量删除</el-button>
                     <el-button @click="cancel()">取消</el-button>
                 </div>
             </div>
@@ -18,8 +18,8 @@
                 <el-table ref="busiessTableRef" :data="deteleBusinessTable" border v-loading="allLoading.tableLoading"
                     @selection-change="changeBatch" style="width: 100%;height: 100%;">
                     <el-table-column type="selection" width="55" />
-                    <el-table-column v-for="(item, index) in tableColumns" :prop="item.prop" :label="item.label" :key="index"
-                        :width="item.width">
+                    <el-table-column v-for="(item, index) in tableColumns" :prop="item.prop" :label="item.label"
+                        :key="index" :width="item.width">
                         <template #default="scope">
                             <span>{{ scope.row[item.prop] }}</span>
                         </template>
@@ -27,9 +27,9 @@
                     <el-table-column label="操作" fixed="right" width="120">
                         <template #default="scope">
                             <el-button link type="primary" size="large"
-                                @click="businessOperationItem(scope.row.id, scope.row.name, '恢复')">恢复</el-button>
+                                @click="businessOperationItem(scope.row.id, scope.row.orderName, '恢复')">恢复</el-button>
                             <el-button link type="danger" size="large"
-                                @click="businessOperationItem(scope.row.id, scope.row.name, '删除')">删除</el-button>
+                                @click="businessOperationItem(scope.row.id, scope.row.orderName, '删除')">删除</el-button>
                         </template>
                     </el-table-column>
                 </el-table>
@@ -45,7 +45,7 @@
 <script lang="ts" setup>
 import { post } from '@/utils/request';
 import { ref, reactive, onMounted, watchEffect, watch, inject } from 'vue'
-import { GETTABLELIST, tableColumns, URL_BATCHDELETE, URL_RECOVER } from '../api';
+import { GETTABLELIST, paymentStatus, tableColumns, URL_BATCHDELETE, URL_RECOVER } from '../api';
 import { ElTable } from 'element-plus';
 import { confirmAction } from '@/utils/tools';
 import { formatDate } from '@/utils/times';
@@ -84,7 +84,7 @@ watch(() => props.visibles, (newVal) => {
 
 function batchOperation(type: operationType) {
     const value = batchTableData.value.map((item: any) => item.id).join(',')
-    const label = batchTableData.value.map((item: any) => item.name).join(',')
+    const label = batchTableData.value.map((item: any) => item.orderName).join(',')
     businessOperationItem(value, label, type, true)
 }
 
@@ -101,7 +101,7 @@ function businessOperationItem(value: string | number, label: string, type: oper
             getTableList()
             changeBatch(false)
         }).catch((err) => {
-            globalPopup?.showError(err.message)
+            globalPopup?.showError(err.msg)
         })
     })
 }
@@ -120,7 +120,13 @@ function getTableList() {
     post(GETTABLELIST, { ...tableForm, isDelete: 1 }).then((res) => {
         if (res.code == 'ok') {
             const { record, total } = res.data
-            deteleBusinessTable.value = record
+            deteleBusinessTable.value = (record || []).map((item: any) => {
+                let val = paymentStatus.find((items: any) => items.value == item.status)
+                return {
+                    ...item,
+                    statusValue: val ? val.label : ''
+                }
+            })
             businessTotalTable.value = total
         }
     }).finally(() => {

+ 41 - 26
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/information.vue

@@ -4,13 +4,14 @@
             <div class="title">基本信息</div>
             <div>
                 <el-button type="primary" @click="transferCli()">转移</el-button>
-                <el-button type="primary" @click="editInfo(info)">编辑</el-button>
+                <el-button type="primary" v-permission="['orderEdit']" @click="editInfo(info)">编辑</el-button>
             </div>
         </div>
         <div class="form flex flex-wrap justify-between">
-            <div v-for="item in formItems" :key="item.label" class="formItem flex" :style="{ width: item.width }">
+            <div v-for="item in formItems" :key="item.label" class="formItem flex" :style="`width: ${item.width}`">
                 <div :class="item.labelClass">{{ item.label }}:</div>
-                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ item.value }}</div>
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1" v-ellipsis-tooltip>{{
+                    item.value }}</div>
             </div>
         </div>
 
@@ -62,7 +63,7 @@ import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffec
 import { GenerateForm } from '@zmjs/form-design';
 import { getFromValue, getTemplateKey } from '@/utils/tools';
 import { get, post } from '@/utils/request';
-import { GETGENERATEFOEM, GETPERSONNEL, URL_OEDERUPDATE, URL_PRODUTWITHORDER, URL_TRANSFER } from '../api';
+import { GETGENERATEFOEM, GETPERSONNEL, URL_OEDERUPDATE, URL_PRODUTWITHORDER, URL_TRANSFER, paymentStatus } from '../api';
 import { formatDate } from '@/utils/times';
 
 const globalPopup = inject<GlobalPopup>('globalPopup')
@@ -96,14 +97,20 @@ const productTableListValue = ref([])
 
 function editOrderSave() {
     orderTemplateRef.value?.getData().then((res: any) => {
-        allLoading.editOrderSaveLoading = true
-        post(URL_OEDERUPDATE, {
+        const formVal = {
             ...orderTemplateValue.value,
             ...res,
             orderEndDate: res.orderEndDate ? formatDate(res.orderEndDate) : '',
             orderStartDate: res.orderStartDate ? formatDate(res.orderStartDate) : '',
+            placeTime: res.placeTime ? formatDate(res.placeTime) : '',
             orderProductDetailString: JSON.stringify(productTableListValue.value || [])
-        }).then((_res) => {
+        }
+        if((formVal.price || 0) < (formVal.receivedPayment || 0)) {
+            globalPopup?.showError('已回款金额不能大于订单金额')
+            return
+        }
+        allLoading.editOrderSaveLoading = true
+        post(URL_OEDERUPDATE, formVal).then((_res) => {
             closeVisible('editOrderVisible')
             globalPopup?.showSuccess('操作成功')
             emits('refreshData', 'getDetail')
@@ -178,32 +185,38 @@ function closeVisible(type: keyof typeof allVisible) {
 }
 
 const formItems = reactive([
-    { label: '订单编号', key: 'orderCode', value: '', labelClass: 'w-20 text-right text-gray-500', width: '48%' },
-    { label: '订单名称', key: 'orderName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '客户名称', key: 'customName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '商机名称', key: 'businessOpportunityName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '订单金额', key: 'price', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '回款状态', key: 'receivedStatus', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '已回款金额', key: 'receivedPayment', value: '', labelClass: 'w-24 text-right text-gray-500', width: '48%' },
-    { label: '未回款', key: 'unReceivedPayment', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '订单类型', key: 'type', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '下单时间', key: 'placeTime', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '订单开始时间', key: 'orderStartDate', value: '', labelClass: 'w-30 text-right text-gray-500', width: '48%' },
-    { label: '订单结束时间', key: 'orderEndDate', value: '', labelClass: 'w-30 text-right text-gray-500', width: '48%' },
-    { label: '负责人', key: 'inchargerName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '创建人', key: 'createName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '创建时间', key: 'createTime', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '客户签约人', key: 'customSigner', value: '', labelClass: 'w-24 text-right text-gray-500', width: '48%' },
-    { label: '公司签约人', key: 'companySigner', value: '', labelClass: 'w-24 text-right text-gray-500', width: '48%' },
-    { label: '备注', key: 'remark', value: '', labelClass: 'w-22 text-right text-gray-500', width: '100%' },
+    { 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: '订单金额', key: 'price', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
+    { label: '回款状态', key: 'statusValue', 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%' },
+    { label: '未回款', key: 'unReceivedPayment', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
+    { label: '订单类型', key: 'type', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
+    { label: '下单时间', key: 'placeTime', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
+    { label: '订单开始时间', key: 'orderStartDate', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
+    { label: '订单结束时间', key: 'orderEndDate', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
+    { label: '负责人', key: 'inchargerName', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
+    { label: '创建人', key: 'creatorName', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
+    { label: '创建时间', key: 'createTime', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
+    { label: '客户签约人', key: 'customSigner', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
+    { label: '公司签约人', key: 'companySigner', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '48%' },
+    { label: '备注', key: 'remark', value: '', labelClass: 'w-[115px] text-right text-gray-500', width: '100%' },
 ])
 
 watchEffect(() => {
     const { data } = props
     info.value = data
     formItems.forEach(item => {
-        item.value = info.value[item.key] || '';
+        if (item.key === 'statusValue') {
+            const status = info.value['status'];
+            item.value = status !== '' && status !== null ? (paymentStatus.find(p => p.value === status)?.label || '') : '';
+        } else {
+            item.value = info.value[item.key] || '';
+        }
     });
+
 })
 
 async function getSystemField() {
@@ -234,6 +247,8 @@ onMounted(async () => {
 
     .form {
         .formItem {
+            width: 48%;
+
             .text {
                 display: -webkit-box;
                 /* Safari */

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

@@ -2,7 +2,7 @@
     <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="flex">
+            <div class="flex" v-permission="['productEdit']">
                 <el-button type="primary" @click="productClick()">编辑产品</el-button>
             </div>
         </div>
@@ -88,17 +88,24 @@ function saveOrder() {
     const items: any = infoValue.value
     for (var i in productTableListData) {
         productTableListData[i].sealPrice = productTableListData[i].sellingPrice,
-            productTableListData[i].discount = productTableListData[i].discount,
-            productTableListData[i].num = productTableListData[i].quantity
+        productTableListData[i].discount = productTableListData[i].discount,
+        productTableListData[i].num = productTableListData[i].quantity
     }
     const produt = productTableListData ? JSON.stringify(productTableListData) : []
-    allLoading.editSaveLading = true
-    post(URL_OEDERUPDATE, {
+    const formVal = {
         ...items,
         orderEndDate: items.orderEndDate ? items.orderEndDate : '',
         orderStartDate: items.orderStartDate ? items.orderStartDate : '',
+        placeTime: items.placeTime ? formatDate(items.placeTime) : '',
         orderProductDetailString: produt
-    }).then(() => {
+    }
+    if((formVal.price || 0) < (formVal.receivedPayment || 0)) {
+      globalPopup?.showError('已回款金额不能大于订单金额')
+      return
+    }
+    allLoading.editSaveLading = true
+    console.log(formVal, '<==== 将要传的值')
+    post(URL_OEDERUPDATE, formVal).then(() => {
         globalPopup?.showSuccess('操作成功')
         allLoading.editSaveLading = false
         closeVisible('editOrderVisible')

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

@@ -2,7 +2,7 @@
     <div class="operationRecord pl-4 pr-4 pt-3 pb-3 h-full flex flex-col">
         <div class="flex justify-between">
             <div class="title">回款</div>
-            <div class="flex">
+            <div class="flex" v-permission="['orderEdit']">
                 <el-button type="primary" @click="editRebate(false)">新增回款</el-button>
             </div>
         </div>
@@ -71,6 +71,7 @@ const operationRecordtable = ref([])
 const mony = ref('')
 const monyItem = ref<any>({})
 const info = ref<any>({})
+const theRebate = ref<number>(0)
 
 function deteItem(item: any) {
     confirmAction(`确定删除该回款记录吗?`).then(() => {
@@ -84,11 +85,13 @@ function deteItem(item: any) {
 }
 
 function editRebate(item: any) {
+    console.log(theRebate.value)
     if (!item) {
         allText.rebateText = '新增回款'
         mony.value = ''
         monyItem.value = {}
     } else {
+        theRebate.value = theRebate.value + Number(item.money)
         monyItem.value = item
         mony.value = item.money
         allText.rebateText = '编辑回款'
@@ -98,8 +101,12 @@ function editRebate(item: any) {
 }
 
 function saveRebate() {
-    if (!mony.value || mony.value == '.') {
-        globalPopup?.showWarning('请输入金额')
+    if (!mony.value || mony.value == '.' || Number(mony.value as string) < 0) {
+        globalPopup?.showWarning(Number(mony.value as string) < 0 ? '请不要输入负数' : '请输入金额')
+        return
+    }
+    if(Number(mony.value as string) > theRebate.value) {
+        globalPopup?.showWarning('回款金额超过了未回款金额')
         return
     }
     allLoading.rebateLoading = true
@@ -119,6 +126,7 @@ watchEffect(() => {
     const { data, information } = props
     operationRecordtable.value = data || []
     info.value = information
+    theRebate.value = Number(information.unReceivedPayment || 0)
 });
 // 生命周期钩子
 onMounted(() => {

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

@@ -94,7 +94,7 @@ function getAllContacts() {
         options.value = (data.record || []).map((item: any) => ({ value: item.id, label: item.orderName }))
         values.value = rowId.value
     }).catch((err) => {
-        globalPopup?.showError(err.message)
+        globalPopup?.showError(err.msg)
     })
 }
 
@@ -157,12 +157,13 @@ async function getAll(event: allTypeStr) {
         } else if (event == 'getFileList') {
             await getFileList()
         } else if (event == 'getRelatedTasks') {
-            await getFileList()
+            await getRelatedTasks()
         } else if (event == 'getOperationRecord') {
             await getOperationRecord()
         } else if (event == 'getRelatedProducts') {
             await getRelatedProducts()
         } else if (event == 'getPaymentCollectionList') {
+            await getDetail()
             await getPaymentCollectionList()
         }
 

+ 37 - 23
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/index.vue

@@ -36,32 +36,33 @@
       <div class="bg-white w-full h-full p-3 shadow-md rounded-md flex flex-col">
         <div class="flex justify-end pb-3">
           <!-- 操作按钮 -->
-          <el-button type="primary" @click="editOrder(false)">新建订单</el-button>
+          <el-button type="primary" v-permission="['orderAdd']" @click="editOrder(false)">新建订单</el-button>
           <el-button type="primary" :disabled="batchTableData.length <= 0">批量转移</el-button>
-          <el-button type="primary" @click="batchDeteleItem()" :disabled="batchTableData.length <= 0">批量删除</el-button>
-          <el-button type="primary" @click="showVisible('deteleOrderVisible')">回收站</el-button>
-          <el-button type="primary" @click="showVisible('importVisible')">导入</el-button>
-          <el-button type="primary" @click="exportOrderTableList()" :loading="allLoading.exoprtLoading">导出</el-button>
+          <el-button type="primary" v-permission="['orderDelete']" @click="batchDeteleItem()" :disabled="batchTableData.length <= 0">批量删除</el-button>
+          <el-button type="primary" v-permission="['orderRecycle']" @click="showVisible('deteleOrderVisible')">回收站</el-button>
+          <el-button type="primary" v-permission="['orderImport']" @click="showVisible('importVisible')">导入</el-button>
+          <el-button type="primary" v-permission="['orderExport']" @click="exportOrderTableList()" :loading="allLoading.exoprtLoading">导出</el-button>
         </div>
         <div class="flex-1 w-full overflow-hidden">
           <!-- 表格 -->
-          <el-table ref="otherTableRef" :data="formTable" border v-loading="allLoading.formTableLading"
+          <el-table ref="otherTableRef" :data="formTable" :show-overflow-tooltip="tableShowOverflowTooltip" border v-loading="allLoading.formTableLading"
             style="width: 100%;height: 100%;" @selection-change="changeBatch">
             <el-table-column type="selection" width="55" />
             <el-table-column v-for="(column, index) in tableColumns" :key="index" :prop="column.prop"
               :label="column.label" :width="column.width">
               <template #default="scope">
                 <template v-if="column.event === 'toDetali'">
-                  <el-button link type="primary" size="large" @click="toDetali(scope.row)">{{ scope.row[column.prop]
-                  }}</el-button>
+                  <!-- <el-button link type="primary" size="large" @click="toDetali(scope.row)">{{ scope.row[column.prop]
+                  }}</el-button> -->
+                  <div class="table-text-textnowrap" @click.prevent="toDetali(scope.row)">{{ scope.row[column.prop] }}</div>
                 </template>
               </template>
             </el-table-column>
-            <el-table-column :label="'操作'" :width="'200px'" fixed="right">
+            <el-table-column :label="'操作'" :width="'200px'" fixed="right" v-permission="['orderEdit']">
               <template #default="scope">
                 <el-button link type="primary" size="large" @click="editOrder(scope.row)">编辑</el-button>
-                <el-button link type="primary" size="large" @click="newTask(scope.row)">新建任务</el-button>
-                <el-button link type="danger" size="large"
+                <el-button link type="primary" size="large" v-permission="['tasksEdit']" @click="newTask(scope.row)">新建任务</el-button>
+                <el-button link type="danger" size="large" v-permission="['orderDelete']"
                   @click="orderDeteleItem(scope.row.id, scope.row.orderName)">删除</el-button>
               </template>
             </el-table-column>
@@ -81,7 +82,7 @@
         <div class="flex justify-between items-center border-b pb-3 dialog-header">
           <h4 :id="titleId">{{ allText.orderEditText }}</h4>
           <div>
-            <el-button type="primary" :loading="allLoading.editSaveLading" @click="saveOrder(true)">保存并新建</el-button>
+            <el-button type="primary" :loading="allLoading.editSaveLading" v-if="!orderTemplateValue.id" @click="saveOrder(true)">保存并新建</el-button>
             <el-button type="primary" :loading="allLoading.editSaveLading" @click="saveOrder(false)">保存</el-button>
             <el-button @click="closeVisible('editOrderVisible')">取消</el-button>
           </div>
@@ -132,12 +133,13 @@
 import { ref, reactive, onMounted, inject, defineExpose } from "vue";
 import { getAllListByCode, getFromValue, resetFromValue, getFirstDayOfMonth, getLastDayOfMonth, formatDate, getTemplateKey, createTaskFromType, confirmAction, downloadFile, downloadTemplate } from '@/utils/tools'
 import { post, get, uploadFile } from "@/utils/request";
-import { tableColumns, GETSYSFILED, GETPERSONNEL, GETGENERATEFOEM, MOD, GETTABLELIST, GETALLPRODUCT, GETTABLELISTPRODUCT, URL_OEDERUPDATE, URL_PRODUTWITHORDER, URL_DETELEITEM, EXPORTTIME, IMPORTMOD, IMPORITEM } from "./api";
+import { tableColumns, GETSYSFILED, GETPERSONNEL, GETGENERATEFOEM, MOD, GETTABLELIST, GETALLPRODUCT, GETTABLELISTPRODUCT, URL_OEDERUPDATE, URL_PRODUTWITHORDER, URL_DETELEITEM, EXPORTTIME, IMPORTMOD, IMPORITEM, paymentStatus } from "./api";
 import { useRouter, useRoute } from "vue-router";
 import { GenerateForm } from '@zmjs/form-design';
 import { formatDateTime } from "@/utils/times";
 import { ElTable, UploadRequestOptions } from "element-plus";
 import { createTask } from "@/components/TaskModal/taskFunction";
+import { tableShowOverflowTooltip } from '@/utils/globalVariables'
 import { URL_FETALL } from "../customer/api";
 
 import RelatedProducts from '@/components/relatedProducts/relatedProducts.vue'
@@ -194,13 +196,13 @@ const filterItems = ref<FilterItem[]>([
   { label: '订单编号', key: 'orderCode', type: 'input' },
   { label: '订单名称', key: 'orderName', type: 'input' },
   { label: '客户名称', key: 'customId', type: 'select', options: selectData.Customer },
-  { label: '商机名称', key: 'businessOpportunityId', type: 'input' },
+  { label: '商机名称', 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 },
   { label: '下单时间', key: '', type: 'date' },
 ]) // 渲染筛选条件
-const orderTemplateValue = ref({})
+const orderTemplateValue = ref<any>({})
 const orderTemplateKey = ref(1)
 const orderTemplateRef = ref<typeof GenerateForm>()
 const relatedProductsRef = ref<typeof RelatedProducts>()
@@ -244,7 +246,7 @@ function batchDeteleItem() {
 }
 
 function orderDeteleItem(value: string | number, label: string, batch: boolean = false) {
-  confirmAction(`确定${batch ? '批量' : ''}删除【${label}】客户吗?`).then(() => {
+  confirmAction(`确定${batch ? '批量' : ''}删除【${label}】销售订单吗?`).then(() => {
     post(URL_DETELEITEM, { ids: value }).then(res => {
       if (res.code != 'ok') {
         globalPopup?.showError(res.msg)
@@ -254,7 +256,7 @@ function orderDeteleItem(value: string | number, label: string, batch: boolean =
       changeBatch(false)
       getTableList()
     }).catch((err) => {
-      globalPopup?.showError(err.message)
+      globalPopup?.showError(err.msg)
     })
   })
 }
@@ -289,14 +291,20 @@ function saveOrder(flag: boolean) {
         productTableListData[i].num = productTableListData[i].quantity
     }
     const produt = productTableListData ? JSON.stringify(productTableListData) : []
-    allLoading.editSaveLading = true
-    post(URL_OEDERUPDATE, {
+    const formVal = {
       ...orderTemplateValue.value,
       ...res,
       orderEndDate: res.orderEndDate ? formatDate(res.orderEndDate) : '',
       orderStartDate: res.orderStartDate ? formatDate(res.orderStartDate) : '',
+      placeTime: res.placeTime ? formatDate(res.placeTime) : '',
       orderProductDetailString: produt
-    }).then((_res) => {
+    }
+    if((formVal.price || 0) < (formVal.receivedPayment || 0)) {
+      globalPopup?.showError('已回款金额不能大于订单金额')
+      return
+    }
+    allLoading.editSaveLading = true
+    post(URL_OEDERUPDATE, formVal).then((_res) => {
       allVisible.editOrderVisible = flag
       globalPopup?.showSuccess('保存成功')
       if (flag) {
@@ -351,7 +359,13 @@ function getTableList() {
   allLoading.formTableLading = true
   post(GETTABLELIST, { ...formValue, ...formPaging }).then(res => {
     const { total, record } = res.data
-    formTable.value = record
+    formTable.value = (record || []).map((item: any) => {
+      let val = paymentStatus.find((items: any) => items.value == item.status)
+      return {
+        ...item,
+        statusValue: val ? val.label : ''
+      }
+    })
     formTablePaging.total = total
   }).finally(() => {
     allLoading.formTableLading = false
@@ -421,8 +435,8 @@ function setFilterItems() {
     { label: '订单编号', key: 'orderCode', type: 'input' },
     { label: '订单名称', key: 'orderName', type: 'input' },
     { label: '客户名称', key: 'customId', type: 'select', options: selectData.Customer },
-    { label: '商机名称', key: 'businessOpportunityId', type: 'input' },
-    { label: '订单类型', key: 'ordertype', type: 'select', options: selectData.OrderType },
+    { label: '商机名称', 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 },
     { label: '下单时间', key: '', type: 'date' },

+ 12 - 2
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/attachment.vue

@@ -71,10 +71,18 @@ const props = defineProps<{
     data: any,
     information: any
 }>()
+const uploadRef = ref()
 
 // 下载文件
 function fileDownload(item: any) {
-    downloadFile(item.url, `${item.attachmentName}${item.attachmentSuffix}`)
+    downloadFile(item.url, `${removeSuffix(item.attachmentName, item.attachmentSuffix)}${item.attachmentSuffix}`)
+}
+
+function removeSuffix(str: string, suffix: string) {
+    if (str.endsWith(suffix)) {
+        return str.slice(0, -suffix.length);
+    }
+    return str;
 }
 
 // 保存重命名
@@ -122,7 +130,9 @@ async function httpUploadFile(param: UploadRequestOptions) {
     formData.append('file', param.file)
     formData.append('moduleId', id)
     formData.append('moduleCode', MODUCODE)
-    const res = await uploadFile(UPLOADATTACHMENT, formData)
+    const res = await uploadFile(UPLOADATTACHMENT, formData).finally(() => {
+        uploadRef.value.clearFiles()
+    })
     allLoading.uploadLoading = false
     if (res.code == 'ok') {
         globalPopup?.showSuccess('上传成功')

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

@@ -3,18 +3,19 @@
         <div class="flex justify-between">
             <div class="title">基本信息</div>
             <div>
-                <el-button type="primary" @click="showVisible('proudDialogVisible')">转移</el-button>
-                <el-button type="primary" @click="editProduct(info)">编辑</el-button>
+                <el-button type="primary" @click="claimProduct()" v-loading="allLoading.claimLoading" v-if="!info.inchargerName">认领</el-button>
+                <el-button type="primary" @click="showVisible('proudDialogVisible')" v-if="info.inchargerName">转移</el-button>
+                <el-button type="primary" v-permission="['productEdit']" @click="editProduct(info)">编辑</el-button>
             </div>
         </div>
         <div class="form flex flex-wrap justify-between">
             <div class="formItem flex pt-2 pb-1">
                 <div class="w-20 text-right text-gray-500">产品编号:</div>
-                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ info.productCode }}</div>
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1" v-ellipsis-tooltip>{{ info.productCode }}</div>
             </div>
             <div class="formItem flex pt-2 pb-1">
                 <div class="w-22 text-right text-gray-500">产品名称:</div>
-                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1">{{ info.productName }}</div>
+                <div class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap ml-1" v-ellipsis-tooltip>{{ info.productName }}</div>
             </div>
             <div class="formItem flex pt-2 pb-1">
                 <div class="w-22 text-right text-gray-500">产品类别:</div>
@@ -50,7 +51,7 @@
             </div>
             <div class="formItem flex pt-2 pb-1" style="width: 100%;">
                 <div class="w-22 text-right text-gray-500">备注:</div>
-                <div class="flex-1 ml-1 text ">
+                <div class="flex-1 ml-1 text " v-ellipsis-tooltip>
                     {{ info.descs }}
                 </div>
             </div>
@@ -129,7 +130,8 @@ const dialogVisible = reactive({
 const allLoading = reactive({
     productLoading: false,
     generateFormLading: false,
-    saveBtnLoading: false
+    saveBtnLoading: false,
+    claimLoading: false
 })
 const allText = reactive({
     productText: '转移产品'
@@ -185,6 +187,21 @@ function transferProduct() {
     })
 }
 
+function claimProduct() {
+    const ids = info.value?.id
+    const inchargerId = userInfo.id
+    allLoading.claimLoading = true
+    post(GETINCHARGER, { id: ids, userId: inchargerId }).then((res) => {
+        if (res.code == 'ok') {
+            globalPopup?.showSuccess('操作成功')
+            dialogVisible.proudDialogVisible = false
+            emits('getInformationData')
+        }
+    }).finally(() => {
+        allLoading.claimLoading = false
+    })
+}
+
 // 显示弹窗
 function showVisible(filed: keyof typeof dialogVisible) {
     if (filed == 'proudDialogVisible') {

+ 0 - 63
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/products.vue

@@ -1,63 +0,0 @@
-<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>
-        <div class="flex-1 overflow-auto pt-3">
-            <el-table :data="relatedTaskstable" border style="width: 100%;height: 300px;">
-                <el-table-column label="序号" width="80">
-                    <template #default="scope">
-                        {{ scope.$index + 1 }}
-                    </template>
-                </el-table-column>
-                <el-table-column prop="taskName" label="产品名称">
-                    <template #default="scope">
-                        <el-button link type="primary" size="large">{{
-                            scope.row.taskName
-                        }}</el-button>
-                    </template>
-                </el-table-column>
-                <el-table-column prop="priority" label="产品类别" width="130" />
-                <el-table-column prop="status" label="产品类型" width="130" />
-                <el-table-column prop="executor" label="单位" width="130" />
-                <el-table-column prop="startTime" label="标准价格" width="130" />
-                <el-table-column prop="endTime" label="库存" width="130" />
-                <el-table-column prop="endTime" label="售价" width="130" />
-                <el-table-column prop="endTime" label="数量" width="130" />
-                <el-table-column prop="endTime" label="折扣(%)" width="130" />
-                <el-table-column prop="endTime" label="合计" width="130" />
-            </el-table>
-        </div>
-    </div>
-</template>
-<script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
-
-const relatedTaskstable = ref([])
-
-const props = defineProps<{
-    data: any
-}>()
-
-// 接收参数赋值
-function receiveAssignment(item: any) {
-    relatedTaskstable.value = item.data
-}
-
-watchEffect(() => {
-    receiveAssignment(props)
-});
-
-// 生命周期钩子
-onMounted(() => {
-    receiveAssignment(props)
-});
-</script>
-<style scoped lang="scss">
-.relatedTasks {
-    .title {
-        font-size: 18px;
-        color: #000
-    }
-}
-</style>

+ 23 - 10
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/component/relatedBusiness.vue

@@ -4,25 +4,25 @@
             <div class="title">相关商机</div>
         </div>
         <div class="flex-1 overflow-auto pt-3">
-            <el-table :data="relatedTaskstable" border style="width: 100%;height: 100%;">
-                <el-table-column prop="taskName" label="任务名称">
+            <el-table :data="relatedTaskstable" :show-overflow-tooltip="tableShowOverflowTooltip" border
+                style="width: 100%;height: 100%;">
+                <el-table-column v-for="(item, index) in tableColumn" :prop="item.prop" :label="item.label" :key="index"
+                    :width="item.width">
                     <template #default="scope">
-                        <el-button link type="primary" size="large">{{
-                            scope.row.taskName
-                        }}</el-button>
+                        <div class="table-text-textnowrap" v-if="item.eventName"
+                            @click="dealWithTableColumn(scope.row, item.eventName)">{{ scope.row[item.prop] }}</div>
+                        <template v-else>{{ scope.row[item.prop] }}</template>
                     </template>
                 </el-table-column>
-                <el-table-column prop="priority" label="优先级" width="130" />
-                <el-table-column prop="status" label="状态" width="130" />
-                <el-table-column prop="executor" label="执行人" width="130" />
-                <el-table-column prop="startTime" label="开始时间" width="130" />
-                <el-table-column prop="endTime" label="截至时间" width="130" />
             </el-table>
         </div>
     </div>
 </template>
 <script lang="ts" setup>
 import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { tableColumn, MOD } from '@/pages/business/api'
+import { tableShowOverflowTooltip } from '@/utils/globalVariables'
+import router from '@/router';
 
 const relatedTaskstable = ref([])
 const information: any = ref({})
@@ -38,6 +38,19 @@ function receiveAssignment(item: any) {
     information.value = item.information
 }
 
+function dealWithTableColumn(row: any, eventName: string) {
+  if (eventName == 'toClueTableDetail') {
+    toBusinessTableDetail(row)
+  }
+}
+
+function toBusinessTableDetail(row: any) {
+  router.push({
+    path: `${MOD}/detail`,
+    query: { id: row.id }
+  })
+}
+
 watchEffect(() => {
     receiveAssignment(props)
 });

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

@@ -0,0 +1,72 @@
+<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>
+        <div class="flex-1 overflow-auto pt-3">
+            <el-table :data="relatedTaskstable" border style="width: 100%;height: 300px;">
+                <el-table-column v-for="(column, index) in newTableColumns" :key="index" :prop="column.prop"
+                    :label="column.label" :width="column.width">
+                    <template #default="scope">
+                        <template v-if="column.event === 'toDetali'">
+                            <el-button link type="primary" size="large" @click="toDetali(scope.row)">{{
+                                scope.row[column.prop]
+                                }}</el-button>
+                        </template>
+                    </template>
+                </el-table-column>
+            </el-table>
+        </div>
+    </div>
+</template>
+<script lang="ts" setup>
+import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { tableColumns, MOD, paymentStatus } from '@/pages/order/api'
+import router from '@/router';
+
+const relatedTaskstable = ref([])
+const newTableColumns = ref<any>([])
+
+const props = defineProps<{
+    data: any
+}>()
+
+// 接收参数赋值
+function receiveAssignment(item: any) {
+    relatedTaskstable.value = (item.data || []).map((item: any) => {
+      let val = paymentStatus.find((items: any) => items.value == item.status)
+      return {
+        ...item,
+        statusValue: val ? val.label : ''
+      }
+    })
+}
+
+function toDetali(row: any) {
+  router.push({
+    path: `${MOD}/detail`,
+    query: { id: row.id }
+  })
+}
+
+watchEffect(() => {
+    receiveAssignment(props)
+});
+
+// 生命周期钩子
+onMounted(() => {
+    newTableColumns.value = tableColumns.filter((item: any) => {
+        const excludedProps = ['businessOpportunityName', 'orderStartDate', 'orderEndDate', 'companySignerName', 'inchargerName', 'customSignerName'];
+        return !excludedProps.includes(item.prop);
+    })
+    receiveAssignment(props)
+});
+</script>
+<style scoped lang="scss">
+.relatedTasks {
+    .title {
+        font-size: 18px;
+        color: #000
+    }
+}
+</style>

+ 5 - 4
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/detail/index.vue

@@ -7,7 +7,7 @@
         </el-link>
       </div>
       <div class="mr-8">
-        <el-select v-model="value" placeholder="请选择" style="width: 150px" @change="getDetail(false)">
+        <el-select v-model="addressParameters" placeholder="请选择" style="width: 250px" @change="getDetail(false)">
           <el-option v-for="item in options" :key="item.id" :label="item.productName" :value="item.id" />
         </el-select>
       </div>
@@ -34,7 +34,7 @@
 
       <div class="w-full h-auto flex justify-between mt-2">
         <div class="bg-white shadow-md rounded-md w-full">
-          <Products :data="products" />
+          <RelatedSalesOrder :data="products" />
         </div>
       </div>
     </div>
@@ -52,9 +52,10 @@ import Information from '../component/information.vue'
 import Attachment from '../component/attachment.vue'
 import RelatedBusiness from '../component/relatedBusiness.vue';
 import OperationRecord from '../component/operationRecord.vue';
-import Products from '../component/products.vue';
+import RelatedSalesOrder from '../component/relatedSalesOrder.vue';
 import { GETBUSINESS, GETDETAIL, GETCENTERLIST, GETORDER, MODUCODE, GETATTACHMENT, GETTABLELIST } from "../api";
 import { post } from "@/utils/request";
+import { number } from "echarts";
 
 const route = useRoute()
 const globalPopup = inject<GlobalPopup>('globalPopup')
@@ -121,7 +122,7 @@ function getProductList() {
 
 onMounted(() => {
   const { id } = route.query
-  addressParameters.value = id
+  addressParameters.value = (id || '') ? Number(id) : ''
   getProductList()
   getDetail(true)
 })

+ 21 - 19
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/index.vue

@@ -11,17 +11,17 @@
               <el-input v-model="filterProductForm.productName" clearable placeholder="请输入"></el-input>
             </el-form-item>
             <el-form-item label="产品类别">
-              <el-select v-model="filterProductForm.type" placeholder="请选择" clearable>
+              <el-select v-model="filterProductForm.productType" placeholder="请选择" clearable filterable>
                 <el-option v-for="item in fixedData.ProductType" :key="item.id" :label="item.name" :value="item.id" />
               </el-select>
             </el-form-item>
             <el-form-item label="状态">
-              <el-select v-model="filterProductForm.status" placeholder="请选择">
-                <el-option v-for="item in fixedData.Personnel" :key="item.id" :label="item.name" :value="item.id" />
+              <el-select v-model="filterProductForm.status" placeholder="请选择" filterable clearable>
+                <el-option v-for="item in SELECTSTATUS" :key="item.value" :label="item.label" :value="item.value" />
               </el-select>
             </el-form-item>
             <el-form-item label="负责人">
-              <el-select v-model="filterProductForm.userId" placeholder="请选择">
+              <el-select v-model="filterProductForm.userId" placeholder="请选择" filterable clearable>
                 <el-option v-for="item in fixedData.Personnel" :key="item.id" :label="item.name" :value="item.id" />
               </el-select>
             </el-form-item>
@@ -44,22 +44,23 @@
     <div class="flex-1 p-5 overflow-auto">
       <div class="bg-white w-full h-full p-3 shadow-md rounded-md flex flex-col">
         <div class="flex justify-end pb-3">
-          <el-button type="primary" @click="editProduct(false)">新建产品</el-button>
-          <el-button type="primary" @click="batchDelete()">批量删除</el-button>
-          <el-button type="primary" @click="showDeteleProduct(true)">回收站</el-button>
-          <el-button type="primary" @click="dialogVisible.importVisible = true">导入</el-button>
-          <el-button type="primary" @click="exportProductTableList()" :loading="allLoading.exoprtLoading">导出</el-button>
+          <el-button type="primary" v-permission="['productAdd']" @click="editProduct(false)">新建产品</el-button>
+          <el-button type="primary" v-permission="['productDelete']" @click="batchDelete()">批量删除</el-button>
+          <el-button type="primary" v-permission="['productRecycle']" @click="showDeteleProduct(true)">回收站</el-button>
+          <el-button type="primary" v-permission="['productImport']" @click="dialogVisible.importVisible = true">导入</el-button>
+          <el-button type="primary" v-permission="['productExport']" @click="exportProductTableList()" :loading="allLoading.exoprtLoading">导出</el-button>
         </div>
         <div class="flex-1 w-full overflow-hidden">
-          <el-table ref="productTableRef" :data="productTableList" border v-loading="allLoading.productTableLading"
+          <el-table ref="productTableRef" :show-overflow-tooltip="tableShowOverflowTooltip" :data="productTableList" border v-loading="allLoading.productTableLading"
             style="width: 100%;height: 100%;">
             <el-table-column type="selection" width="55" />
             <el-table-column prop="productCode" label="产品编号" width="180"></el-table-column>
             <el-table-column prop="productName" label="产品名称" width="180">
               <template #default="scope">
-                <el-button link type="primary" size="large" @click="toProductDetail(scope.row)">{{
+                <!-- <el-button link type="primary" size="large" @click="toProductDetail(scope.row)">{{
                   scope.row.productName
-                }}</el-button>
+                }}</el-button> -->
+                <div class="table-text-textnowrap" @click.prevent="toProductDetail(scope.row)">{{ scope.row.productName }}</div>
               </template>
             </el-table-column>
             <el-table-column prop="typeName" label="产品类别" width="180"></el-table-column>
@@ -74,10 +75,10 @@
             <el-table-column prop="inchargerName" label="负责人" width="190"></el-table-column>
             <el-table-column prop="creatorName" label="创建人" width="180"></el-table-column>
             <el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
-            <el-table-column label="操作" fixed="right" width="200">
+            <el-table-column label="操作" fixed="right" width="200" v-permission="['productEdit', 'productDelete']">
               <template #default="scope">
                 <el-button link type="primary" size="large" @click.stop="editProduct(scope.row)">编辑</el-button>
-                <el-button link type="danger" size="large" @click.stop="deteleRow([scope.row])">删除</el-button>
+                <el-button link type="danger" v-permission="['productDelete']" size="large" @click.stop="deteleRow([scope.row])">删除</el-button>
               </template>
             </el-table-column>
           </el-table>
@@ -96,7 +97,7 @@
         <div class="flex justify-between items-center border-b pb-3 dialog-header">
           <h4 :id="titleId">{{ allText.editClueText }}</h4>
           <div>
-            <el-button type="primary" @click="saveProductRow(true)" :loading="allLoading.saveLoading">保存并新建</el-button>
+            <el-button type="primary" @click="saveProductRow(true)" v-if="!genereditForm.id":loading="allLoading.saveLoading">保存并新建</el-button>
             <el-button type="primary" @click="saveProductRow(false)" :loading="allLoading.saveLoading">保存</el-button>
             <el-button @click="dialogVisible.editProductVisible = false">取消</el-button>
           </div>
@@ -136,9 +137,10 @@
 
 <script lang="ts" setup>
 import { ref, reactive, onMounted, inject } from "vue";
-import { GETSYSFILED, MOD, MODUCODE, GETPERSONNEL, GETTEMPLATE, GETTABLELIST, ADDPRODUCT, ALLDETELE, UPLOADFILE, EXPORTTIME } from './api'
+import { GETSYSFILED, MOD, MODUCODE, GETPERSONNEL, GETTEMPLATE, GETTABLELIST, ADDPRODUCT, ALLDETELE, UPLOADFILE, EXPORTTIME, SELECTSTATUS } from './api'
 import { getAllListByCode, getFromValue, resetFromValue, getFirstDayOfMonth, downloadFile, formatDate, createTaskFromType, confirmAction, downloadTemplate } from '@/utils/tools'
 import { FormInstance, FormRules, ElMessageBox, ElTable, UploadRequestOptions } from 'element-plus'
+import { tableShowOverflowTooltip } from '@/utils/globalVariables'
 import { post, get, uploadFile } from "@/utils/request";
 import { useRouter, useRoute } from "vue-router";
 import { GenerateForm } from '@zmjs/form-design';
@@ -155,7 +157,7 @@ const filterProductForm = reactive<filterProductFormType>({ // 筛选条件form
   pageIndex: 1,
   pageSize: 10,
   id: '',
-  type: '',
+  productType: '',
   status: '',
 })
 const allLoading = reactive({
@@ -188,7 +190,7 @@ const productTemplate = ref({
   list: [],
   config: {}
 }) // 产品模板
-const genereditForm = ref({}) // 编辑表单
+const genereditForm = ref<any>({}) // 编辑表单
 const generateFormKey = ref(1)
 
 // 方法定义
@@ -311,7 +313,7 @@ function handleCurrentChange(val: number) {
 }
 
 function resetFilter() {
-  let newResetForm = resetFromValue(filterProductForm, { startTime: getFirstDayOfMonth(new Date()), endTime: formatDate(new Date()), pageIndex: 1, pageFrom: 10 })
+  let newResetForm = resetFromValue(filterProductForm, { startTime: getFirstDayOfMonth(new Date()), endTime: formatDate(new Date()), pageIndex: 1, pageSize: 10 })
   Object.assign(filterProductForm, newResetForm)
   getProductTableList()
 }

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

@@ -4,7 +4,7 @@ interface filterProductFormType {
     productCode: string,
     pageIndex: number,
     pageSize: number,
-    type: string | number,
+    productType: string | number,
     id: string | number,
     startTime: string,
     endTime: string,

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

@@ -163,7 +163,7 @@ const register = (formEl: FormInstance | undefined) => {
         registerLoading.value = false;
       }
     }).catch(err => {
-      globalPopup?.showError(err.message || err.msg || "注册失败")
+      globalPopup?.showError(err.msg || err.msg || "注册失败")
       registerLoading.value = false;
     })
 

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

@@ -65,7 +65,7 @@
       :before-close="handleClose">
       <div class="permissionsData">
         <div v-for="(item, index) in permissionsData" :key="index" class="list">
-          <div class="itemName">
+          <div class="itemName" v-if="item.name.indexOf('详情') == -1">
             <el-checkbox size="large" v-model="item.checked" style="width: 16px; font-weight: bold;"
               @change="changeCheckBox(item, true)">{{ item.name }}</el-checkbox>
           </div>

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

@@ -30,9 +30,9 @@ export const defaultSearchForm = {
 };
 export const PRIORITY = [
   //优先级
-  { label: "", value: 2 },
+  { label: "", value: 2 },
   { label: "中", value: 1 },
-  { label: "", value: 0 },
+  { label: "", value: 0 },
 ];
 export const STATUS: StatusType[] = [
   //任务状态

+ 49 - 27
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/index.vue

@@ -15,7 +15,7 @@
             <el-form-item label="客户名称:" label-width="7em" prop="customName">
               <el-input v-model="searchForm.customName" placeholder="请输入" />
             </el-form-item>
-            <el-form-item label="联系人:" label-width="7em" prop="contactsName">
+            <el-form-item label="联系人号码:" label-width="7em" prop="contactsName">
               <el-input v-model="searchForm.contactsName" placeholder="请输入" />
             </el-form-item>
             <el-form-item label="执行人:" label-width="7em" prop="executorName">
@@ -52,13 +52,14 @@
     <div class="flex-1 p-5 overflow-auto">
       <div class="bg-white w-full h-full p-3 shadow-md rounded-md flex flex-col">
         <div class="ml-auto p-3">
-          <el-button type="primary" @click="createTasks()">创建任务</el-Button>
-          <el-button type="primary" :disabled="len == 0" :loading="btnLoading" @click="deleteTasks()">批量删除</el-Button>
-          <el-button type="primary" @click="openImportModal()">导入</el-Button>
-          <el-button type="primary" :loading="btnLoading" @click="exportTasks()">导出</el-Button>
+          <el-button type="primary" v-permission="['tasksAdd']" @click="createTasks()">创建任务</el-Button>
+          <el-button type="primary" v-permission="['tasksDelete']" :disabled="len == 0" :loading="btnLoading" @click="deleteTasks()">批量删除</el-Button>
+          <el-button type="primary" v-permission="['tasksImport']" @click="openImportModal()">导入</el-Button>
+          <!-- <el-button type="primary" :loading="btnLoading" @click="exportTasks()">导出</el-Button> -->
+          <el-button type="primary" v-permission="['tasksExport']" :loading="btnLoading" @click="newExportTasks()">导出</el-Button>
         </div>
         <div class="flex-1 overflow-y-auto">
-          <el-table :data="tableData" style="width: 100%;height: 100%;" ref="tableRef" v-loading="loading">
+          <el-table :data="tableData" :show-overflow-tooltip="tableShowOverflowTooltip" style="width: 100%;height: 100%;" ref="tableRef" v-loading="loading">
             <el-table-column type="selection" width="55" />
             <el-table-column prop="taskName" label="任务名称" header-align="center" align="center" show-overflow-tooltip
               width="200" />
@@ -75,19 +76,11 @@
                 </el-text>
               </template>
             </el-table-column>
-            <el-table-column prop="customName" label="执行人" width="120" header-align="center" align="center" />
+            <el-table-column prop="executorNames" label="执行人" width="120" header-align="center" align="center" />
             <el-table-column prop="startDate" label="开始时间" width="200" :sortable="true" header-align="center"
               align="center" value-format="YYYY-MM-DD" />
             <el-table-column prop="endDate" label="截止时间" width="200" :sortable="true" header-align="center"
               align="center" value-format="YYYY-MM-DD" />
-            <el-table-column prop="contactsName" label="联系人" header-align="center" align="center" width="120">
-              <template #default="scope">
-                <el-link :underline="false" type="primary" @click="goDetail(scope.row, 'contacts', 'contactsId')">
-                  {{ scope.row.contactsName }}
-                </el-link>
-              </template>
-            </el-table-column>
-            <el-table-column prop="contactsTel" label="联系人号码" header-align="center" align="center" width="140" />
             <el-table-column prop="customName" label="客户名称" header-align="center" align="center" width="120">
               <template #default="scope">
                 <el-link :underline="false" type="primary" @click="goDetail(scope.row, 'customer', 'customId')">
@@ -117,8 +110,16 @@
                 </el-link>
               </template>
             </el-table-column>
+            <el-table-column prop="contactsName" label="联系人名称" header-align="center" align="center" width="120">
+              <template #default="scope">
+                <el-link :underline="false" type="primary" @click="goDetail(scope.row, 'contacts', 'contactsId')">
+                  {{ scope.row.contactsName }}
+                </el-link>
+              </template>
+            </el-table-column>
+            <el-table-column prop="contactsTel" label="联系人号码" header-align="center" align="center" width="140" />
 
-            <el-table-column fixed="right" label="操作" header-align="center" align="center" width="150">
+            <el-table-column fixed="right" label="操作" header-align="center" align="center" width="160" v-permission="['tasksEdit']">
 
               <template #default="scope">
                 <el-button link type="primary" @click.prevent="editRow(scope.row)">
@@ -132,7 +133,7 @@
                   完成
                 </el-button>
 
-                <el-button link type="danger" @click.prevent="deleteRow(scope.row)">
+                <el-button link type="danger" v-permission="['tasksDelete']" @click.prevent="deleteRow(scope.row)">
                   删除
                 </el-button>
               </template>
@@ -165,6 +166,7 @@ import ImportModal from './ImportModal.vue';
 import ExportModal from './ExportModal.vue';
 import { post, uploadFile } from '@/utils/request';
 import { getFromValue, confirmAction, downloadFile } from '@/utils/tools';
+import { tableShowOverflowTooltip } from '@/utils/globalVariables'
 import { pushMap } from './type';
 const router = useRouter()
 const { getFunctionList } = useStore()
@@ -206,7 +208,7 @@ function submitForm(data: any, isClose: boolean) {
     search();
   }).catch(err => {
     taskLoading.value = "4"
-    globalPopup?.showError(err.message)
+    globalPopup?.showError(err.msg)
   })
 
 }
@@ -216,6 +218,23 @@ const tableRef = ref<InstanceType<typeof ElTable>>();
 const loading = ref<boolean>(false);
 const totalCount = ref<number>(0);
 const tableData = ref<any[]>([])
+
+function newExportTasks() {
+  btnLoading.value = true
+  const { startDate, endDate } = searchForm.value;
+  let params = {
+    ...searchForm.value,
+    startDate: startDate && dayjs(startDate).format('YYYY-MM-DD 00:00:00'),
+    endDate: endDate && dayjs(endDate).format('YYYY-MM-DD 23:59:59')
+  }
+  post(EXPORT_DATA, {...getFromValue(params)}).then((res) => {
+    globalPopup?.showSuccess("导出成功")
+    downloadFile(res.data, "任务列表.xlsx");
+  }).finally(() => {
+    btnLoading.value = false
+  })
+}
+
 function search() {
   loading.value = true;
   const { startDate, endDate } = searchForm.value;
@@ -228,9 +247,12 @@ function search() {
     loading.value = false;
     const { total, record } = data;
     totalCount.value = total;
-    tableData.value = record;
+    tableData.value = record.map((item: any) => ({
+      ...item,
+      executorNames: item.taskExecutors?.join(',') ?? ''
+    }));
   }).catch(err => {
-    globalPopup?.showError(err);
+    globalPopup?.showError(err.msg);
     loading.value = false;
   })
 }
@@ -268,7 +290,7 @@ function deleteTasks() {
       search();
       globalPopup?.showSuccess("删除成功")
     }).catch(err => {
-      globalPopup?.showError(err)
+      globalPopup?.showError(err.msg)
     })
   });
 }
@@ -291,7 +313,7 @@ function importExcel(data: any) {
     importLoading.value = "3";
     search();
   }).catch(err => {
-    globalPopup?.showError(err)
+    globalPopup?.showError(err.msg)
     importLoading.value = "4";
   })
 }
@@ -315,7 +337,7 @@ function exportTasks() {
     btnLoading.value = false;
   }).catch(err => {
     btnLoading.value = false;
-    globalPopup?.showError(err)
+    globalPopup?.showError(err.msg)
   })
 }
 function closeExportModal() {
@@ -328,7 +350,7 @@ function exportExcel(data: any) {
     exportLoading.value = "3";
     exportVisible.value = false;
   }).catch(err => {
-    globalPopup?.showError(err)
+    globalPopup?.showError(err.msg)
   })
   setTimeout(() => {
 
@@ -353,7 +375,7 @@ function finishRow(item: any) {
     search()
     globalPopup?.showSuccess("操作成功")
   }).catch(err => {
-    globalPopup?.showError(err)
+    globalPopup?.showError(err.msg)
   })
 }
 function restart(item: any) {
@@ -364,7 +386,7 @@ function restart(item: any) {
     search()
     globalPopup?.showSuccess("操作成功")
   }).catch(err => {
-    globalPopup?.showError(err)
+    globalPopup?.showError(err.msg)
   })
 }
 function deleteRow(item: any) {
@@ -376,7 +398,7 @@ function deleteRow(item: any) {
       globalPopup?.showSuccess("删除成功")
     }).catch(err => {
       console.log("err", err);
-      globalPopup?.showError(err)
+      globalPopup?.showError(err.msg)
     })
   })
 }

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

@@ -7,3 +7,11 @@ export const GET_ADDDEPT = '/department/add'
 export const DETELE_DEPT = '/department/delete'
 export const ADD_USER = '/user/insertUser'
 export const GET_USERINFO = '/user/getUserInfo'
+export const BACTHUPDATEDEPT = `/user/batchUpdateDept`
+export const BACTHUPDATEROLE = `/user/batchUpdateRole`
+export const BACTHSERROLE = `/user/setActiveByIds`
+export const SETRESETPWD = `/user/resetPwd`
+export const DEACTIVEUSER = `/user/deactiveUser`
+export const SETACTIVE = `/user/setActive`
+export const EXPOERTUSER = `/user/exportUsers`
+export const URL_IMPORTUSER = `/user/importUser`

+ 276 - 48
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="h-full flex flex-col teamstyle">
+  <div class="h-full flex flex-col teamstyle overflow-hidden">
     <!-- 头部 -->
     <div class="bg-white flex justify-between team-header">
       <div class="flex items-center">
@@ -10,7 +10,8 @@
         <span class="textSpan">共 0 人</span>
       </div>
       <div class="teamForm flex items-center">
-        <el-input v-model="teamForm.keyword" style="max-width: 650px" size="default" placeholder="请输入姓名搜索" class="mr-6">
+        <el-input v-model="teamForm.keyword" style="max-width: 650px" size="default" placeholder="请输入姓名搜索" class="mr-6"
+          clearable @clear="getTableData()" @keyup.enter.native="getTableData()">
           <template #prepend>
             <el-select v-model="teamForm.matchingType" style="width: 80px">
               <el-option label="姓名" :value="0" />
@@ -19,19 +20,21 @@
             </el-select>
           </template>
           <template #append>
-            <el-button :icon="Search" />
+            <el-button :icon="Search" @click="getTableData()" />
           </template>
         </el-input>
 
         <div class="formItem mr-6 flex items-center">
           <div class="text-nowrap">状态:</div>
-          <el-select v-model="teamForm.status" placeholder="请选择" size="default" style="width: 100px">
+          <el-select v-model="teamForm.status" placeholder="请选择" size="default" style="width: 100px"
+            @change="getTableData()">
             <el-option v-for="item in stateOptions" :key="item.value" :label="item.label" :value="item.value" />
           </el-select>
         </div>
         <div class="formItem mr-6 flex items-center">
           <div class="text-nowrap">角色:</div>
-          <el-select v-model="teamForm.roleId" placeholder="请选择" size="default" style="width: 150px">
+          <el-select v-model="teamForm.roleId" placeholder="请选择" size="default" style="width: 150px" clearable
+            @change="getTableData()">
             <el-option v-for="item in roleList" :key="item.id" :label="item.rolename" :value="item.id" />
           </el-select>
         </div>
@@ -42,11 +45,9 @@
           </el-button>
           <template #dropdown>
             <el-dropdown-menu>
-              <el-dropdown-item @click="addPersone(false)">添加人员</el-dropdown-item>
-              <el-dropdown-item>导出人员</el-dropdown-item>
-              <el-dropdown-item>批量导入</el-dropdown-item>
-              <el-dropdown-item>导入薪资</el-dropdown-item>
-              <el-dropdown-item>自定义配置</el-dropdown-item>
+              <el-dropdown-item @click="addPersone(false)" v-permission="['teamAdd']">添加人员</el-dropdown-item>
+              <el-dropdown-item @click="transitionOperation('exportUser', '')" v-permission="['teamExport']">导出人员</el-dropdown-item>
+              <el-dropdown-item @click="transitionOperation('importUser', '')" v-permission="['teamImport']">批量导入</el-dropdown-item>
             </el-dropdown-menu>
           </template>
         </el-dropdown>
@@ -54,7 +55,7 @@
     </div>
     <!-- 内容 -->
     <div class="flex-1 flex">
-      <div class="p-5 w-80 pr-0">
+      <div class="p-4 w-80 pr-0">
         <div class="bg-white w-full h-full shadow-md rounded-md flex flex-col">
           <div class="flex-1 overflow-y-auto const-left">
             <el-tree style="max-width: 600px" :data="deptList" :props="treeProps" @node-click="treeNode">
@@ -75,45 +76,53 @@
           </div>
         </div>
       </div>
-      <div class="flex-1 p-5 overflow-auto">
-        <div class="bg-white w-full h-full shadow-md rounded-md flex flex-col">
-          <div class="flex-1 p-3">
+      <div class="flex-1 p-4 overflow-auto">
+        <div class="bg-white w-full h-full shadow-md rounded-md flex flex-col overflow-hidden pt-2 pl-2 pr-2">
+          <div class="flex-1">
             <el-table ref="multipleTableRef" :data="tableData" v-loading="loadingFrom.tableLoading"
-              style="width: 100%;height: 100%;">
+              @selection-change="changeBatch" style="width: 100%;height: 100%;">
               <el-table-column type="selection" width="55" />
               <el-table-column label="姓名" property="name" width="150"></el-table-column>
-              <el-table-column label="手机" property="phone" ></el-table-column>
+              <el-table-column label="手机" property="phone"></el-table-column>
               <el-table-column label="工号" property="jobNumber"></el-table-column>
               <el-table-column label="部门" property="departmentName"></el-table-column>
               <el-table-column label="角色" property="roleName"></el-table-column>
               <el-table-column label="创建时间" property="createTime"></el-table-column>
-              <el-table-column label="操作" width="150" fixed="right">
+              <el-table-column label="操作" width="200" fixed="right">
                 <template #default="scope">
-                  <el-button :size="'small'">重置</el-button>
+                  <el-button :size="'small'" @click="resetPwd(scope.row)">重置</el-button>
                   <el-button type="primary" :size="'small'" @click="addPersone(scope.row)">编辑</el-button>
+                  <el-button :size="'small'" @click="transitionOperation('disable', scope.row)"
+                    v-if="scope.row.isActive == 1">停用</el-button>
+                  <el-button type="success" :size="'small'" @click="enableUser(scope.row)"
+                    v-if="scope.row.isActive == 0">启用</el-button>
                 </template>
               </el-table-column>
             </el-table>
           </div>
-          <div class="flex items-center justify-between p-3 bg-slate-100">
+          <div class="flex justify-between pb-2 pt-2 pl-3 pr-3">
             <div class="flex">
-              <el-button size="default">取消</el-button>
+              <el-button size="default" @click="changeBatch(false)"
+                :disabled="batchTableData.length == 0">取消</el-button>
               <el-dropdown class="ml-3">
                 <el-button type="primary">
                   更多操作<el-icon class="el-icon--right"><arrow-down /></el-icon>
                 </el-button>
                 <template #dropdown>
                   <el-dropdown-menu>
-                    <el-dropdown-item>批量修改部门</el-dropdown-item>
-                    <el-dropdown-item>批量修改角色</el-dropdown-item>
-                    <el-dropdown-item>修正工时所属部门</el-dropdown-item>
-                    <el-dropdown-item>批量启用员工</el-dropdown-item>
+                    <el-dropdown-item @click="batchItem('批量修改部门', 'dept', deptList)"
+                      :disabled="batchTableData.length == 0">批量修改部门</el-dropdown-item>
+                    <el-dropdown-item @click="batchItem('批量修改角色', 'role', roleList)"
+                      :disabled="batchTableData.length == 0">批量修改角色</el-dropdown-item>
+                    <el-dropdown-item @click="batchEnableItem"
+                      :disabled="batchTableData.length == 0">批量启用员工</el-dropdown-item>
                   </el-dropdown-menu>
                 </template>
               </el-dropdown>
             </div>
             <div class="pr-4">
-              <el-pagination layout="total, prev, pager, next, sizes" :total="totalTable" :hide-on-single-page="true" />
+              <el-pagination layout="total, prev, pager, next, sizes" :total="totalTable" :page-size="teamForm.pageSize"
+                @size-change="handleSizeChange" @current-change="handleCurrentChange" />
             </div>
           </div>
         </div>
@@ -121,10 +130,21 @@
     </div>
 
     <!-- 新增部门 -->
-    <el-dialog v-model="dialogFrom.addDeptDialogVisible" :title="deptListItem.label || '创建部门'" width="500"
-      :before-close="handleClose">
-      <div>
-        <el-form ref="deptRuleFormRef" style="max-width: 500px" :model="deptForm" :rules="deptRules" label-width="auto"
+    <el-dialog v-model="dialogFrom.addDeptDialogVisible" width="600" :show-close="false" :before-close="handleClose">
+      <template #header="{ close, titleId, titleClass }">
+        <div class="flex justify-between items-center border-b pb-3 dialog-header">
+          <h4 :id="titleId">{{ deptListItem.label || '创建部门' }}</h4>
+          <div class="flex">
+            <el-button @click="dialogFrom.addDeptDialogVisible = false">取消</el-button>
+            <el-button type="primary" @click="createDepartment(deptRuleFormRef)"
+              v-bind:loading="loadingFrom.deptDialogVisibleLoading">
+              确定
+            </el-button>
+          </div>
+        </div>
+      </template>
+      <div class="pt-5">
+        <el-form ref="deptRuleFormRef" style="max-width: 500px" :model="deptForm" :rules="deptRules" label-width="140px"
           size="large" status-icon>
           <el-form-item label="部门名称" prop="name">
             <el-input v-model="deptForm.name" placeholder="请输入部门名称" clearable />
@@ -141,15 +161,75 @@
           </el-form-item>
         </el-form>
       </div>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button @click="dialogFrom.addDeptDialogVisible = false">取消</el-button>
-          <el-button type="primary" @click="createDepartment(deptRuleFormRef)"
-            v-bind:loading="loadingFrom.deptDialogVisibleLoading">
-            确定
-          </el-button>
+    </el-dialog>
+
+    <!-- 停用 -->
+    <el-dialog v-model="dialogFrom.resignationVisible" width="600" :show-close="false" :before-close="handleClose">
+      <template #header="{ close, titleId, titleClass }">
+        <div class="flex justify-between items-center border-b pb-3 dialog-header">
+          <h4 :id="titleId">离职停用员工</h4>
+          <div class="flex">
+            <el-button @click="dialogFrom.resignationVisible = false">取消</el-button>
+            <el-button type="primary" @click="resignation" v-bind:loading="loadingFrom.resignationLoading">
+              确定
+            </el-button>
+          </div>
         </div>
       </template>
+      <div class="pt-4 pb-2">
+        <div class="flex items-center justify-center">
+          <div class="pr-2">员工离职日期:</div>
+          <el-date-picker v-model="resignationDate" type="date" placeholder="请选择日期" value-format="YYYY-MM-DD"
+            :clearable="false" />
+        </div>
+      </div>
+    </el-dialog>
+
+    <!-- 导出人员列表 -->
+    <el-dialog v-model="dialogFrom.exportUserVisible" width="600" :show-close="false" :before-close="handleClose">
+      <template #header="{ close, titleId, titleClass }">
+        <div class="flex justify-between items-center border-b pb-3 dialog-header">
+          <h4 :id="titleId">导出人员列表</h4>
+          <div class="flex">
+            <el-button @click="dialogFrom.exportUserVisible = false">取消</el-button>
+            <el-button type="primary" @click="exportUser" v-bind:loading="loadingFrom.exportUserLoading">
+              导出
+            </el-button>
+          </div>
+        </div>
+      </template>
+      <div class="pt-4 pb-2">
+        <div class="flex items-center justify-center">
+          <div class="pr-2">导出:</div>
+          <el-radio-group v-model="exportRadio" class="ml-4">
+            <el-radio value="1" size="large">全部人员</el-radio>
+            <el-radio value="0" size="large">仅在职人员</el-radio>
+          </el-radio-group>
+        </div>
+      </div>
+    </el-dialog>
+
+    <!-- 人员导入 -->
+    <el-dialog v-model="dialogFrom.importVisible" width="680" :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>
+          <div class="flex">
+            <el-button class="mr-3" @click="dialogFrom.importVisible = false">取消</el-button>
+            <el-upload ref="importUserRef" class="upload-demo" :limit="1" :show-file-list="false" accept=".xlsx"
+              :http-request="importUser">
+              <el-button type="primary" :loading="loadingFrom.importLoading">导入</el-button>
+            </el-upload>
+          </div>
+        </div>
+      </template>
+      <div class="p-8">
+        <div class="ml-4 mr-4">
+          <div class="flex items-center">1、点击下载 <el-link type="primary"
+              @click="downloadFile('/upload/人员导入模板.xlsx', '人员导入模板.xlsx')">人员导入模板.xlsx</el-link></div>
+          <div class="mt-4">2、填写excel模板,并上传</div>
+        </div>
+      </div>
     </el-dialog>
 
     <!-- 新增人员 -->
@@ -159,21 +239,28 @@
       roleList: roleList,
       personnelFromData: personnelFromData
     }" @closeModal="closeModal" @personnelModalConfirm="personnelModalConfirm" />
+
+    <!-- 批量操作 -->
+    <BatchOperation :batchData="visibleData" :batchNode="batchTableData" :visibleText="allText.batchText"
+      :popup="visibleType" :batchOperationVisible="dialogFrom.batchOperationVisible" @close="closeModal" />
   </div>
 </template>
 
 <script lang="ts" setup>
 import { ref, reactive, onMounted, onBeforeMount, inject } from 'vue';
-import { dayjs } from 'element-plus'
+import { UploadRequestOptions, dayjs } from 'element-plus'
 import { Search, CirclePlusFilled, Edit, CirclePlus, Delete } from '@element-plus/icons-vue'
 import { FormInstance, FormRules, ElMessageBox } from 'element-plus'
 import { useStore } from '@/store/index'
-import { GET_DATA_LIST, DETELE_DEPT, MOD, GET_USERINFO, GET_ROUTELIST, GET_DEPTLIST, GET_USERLIST, GET_ADDDEPT, ADD_USER } from './api'
-import { post } from "@/utils/request";
-import { getFromValue, updateDepTreeData, resetFromValue } from '@/utils/tools'
+import { GET_DATA_LIST, DETELE_DEPT, MOD, GET_USERINFO, GET_ROUTELIST, DEACTIVEUSER, SETACTIVE, GET_DEPTLIST, BACTHSERROLE, GET_USERLIST, GET_ADDDEPT, ADD_USER, SETRESETPWD, EXPOERTUSER } from './api'
+import { post, uploadFile } from "@/utils/request";
+import { getFromValue, updateDepTreeData, resetFromValue, confirmAction, downloadFile } from '@/utils/tools'
 
 // 导入页面
 import AddPersonnelModal from './module/AddPersonnelModal.vue'
+import BatchOperation from './module/BatchOperation.vue'
+import { formatDate } from '@/utils/times';
+import { URL_IMPORTTHREAD } from '../thread/constant';
 
 const { getFunctionList, getUserInfoVal } = useStore()
 const globalPopup = inject<GlobalPopup>('globalPopup')
@@ -190,24 +277,44 @@ interface deptRuleForm { // 部门表单类型
 // 固定数据
 const stateOptions = [{ value: '3', label: '全部' }, { value: '1', label: '在职' }, { value: '0', label: '停用' }]
 
+// ref
+const importUserRef = ref<any>()
+
 // 定义变量
+const transitiondata = ref<any>() // 过度数据(针对二次弹窗)
 const pagePermission: any = ref([]) // 功能权限
 const loadingFrom = reactive({ // 所有加载状态
   tableLoading: false,
-  deptDialogVisibleLoading: false
+  deptDialogVisibleLoading: false,
+  resignationLoading: false,
+  exportUserLoading: false,
+  importLoading: false
 })
 const dialogFrom: any = reactive({ // 所有弹窗状态
   addDeptDialogVisible: false,
-  addPersonnelDialogVisible: false
+  addPersonnelDialogVisible: false,
+  batchOperationVisible: false,
+  resignationVisible: false,
+  exportUserVisible: false,
+  importVisible: false,
 });
+const allText = reactive({
+  batchText: '批量操作'
+})
+const visibleType = ref<batchOperationType>('dept') // 弹窗类型
+const visibleData = ref<any>([]) // 批量弹窗数据源
 const totalTable = ref(0) // 表格总数
 const tableData: any = ref([]) // 表格数据
 const roleList: any = ref([]) // 角色列表
 const userList: any = ref([]) // 用户列表
 const deptList: any = ref([]) // 部门数据
+const batchTableData: any = ref([]) // 批量数据
+const multipleTableRef: any = ref()
 const deptListUntreated: any = ref([]) // 部门数据(未处理)
 const deptListItem: any = ref({}) // 选中的部门数据
 const personnelFromData = ref({}) // 人员表单数据
+const resignationDate = ref(formatDate(new Date())) // 员工离职日期
+const exportRadio = ref('1') // 导出人员列表
 const teamForm = reactive({ // 筛选条件表单
   matchingType: 0,
   keyword: '',
@@ -237,17 +344,99 @@ const deptRules = reactive<FormRules<typeof deptForm>>({ // 部门表单校验
 })
 
 // 定义方法
+async function importUser(param: UploadRequestOptions) {
+  loadingFrom.importLoading = true
+  const formData = new FormData();
+  formData.append('file', param.file)
+  const res = await uploadFile(URL_IMPORTTHREAD, formData).finally(() => {
+    importUserRef.value.clearFiles()
+    loadingFrom.importLoading = false
+  })
+  loadingFrom.importLoading = false
+  if (res.code == 'ok') {
+    globalPopup?.showSuccess('导入成功' || '')
+    closeModal('importVisible')
+    getTableData()
+    return
+  }
+  globalPopup?.showError(res.msg || '')
+}
+
+function exportUser() {
+  loadingFrom.exportUserLoading = true
+  post(EXPOERTUSER, { containInvalid: exportRadio.value }).then((res) => {
+    downloadFile(`${res.data}`, '人员列表.xlsx')
+    globalPopup?.showSuccess('导出成功')
+    closeModal('exportUserVisible')
+  }).finally(() => {
+    loadingFrom.exportUserLoading = false
+  })
+}
+
+function enableUser(row: any) {
+  const id = row.id
+  post(SETACTIVE, { id, isActive: 1 }).then(() => {
+    globalPopup?.showSuccess('启用成功')
+    getTableData()
+  })
+}
+
+function resignation() {
+  const id = transitiondata.value.id || ''
+  loadingFrom.resignationLoading = true
+  post(DEACTIVEUSER, { id, inactiveDate: resignationDate.value }).then(() => {
+    globalPopup?.showSuccess('停用成功')
+    getTableData()
+    closeModal('resignationVisible')
+  }).finally(() => {
+    loadingFrom.resignationLoading = false
+  })
+}
+
+function resetPwd(row: any) {
+  const userId = row.id
+  confirmAction(`确定要为${row.name}重置密码吗?`, '重置密码').then(() => {
+    post(SETRESETPWD, { userId }).then(() => {
+      globalPopup?.showSuccess('密码已重置为000000,请通知员工及时修改')
+    }).catch((err) => {
+      globalPopup?.showError(err.msg)
+    })
+  })
+}
+
+function batchEnableItem() {
+  const userIds = batchTableData.value.map((item: any) => item.id)
+  post(BACTHSERROLE, { ids: JSON.stringify(userIds), isActive: 1 }).then(() => {
+    globalPopup?.showSuccess('操作成功')
+    changeBatch(false)
+    getTableData()
+  }).catch((err) => {
+    globalPopup?.showError(err.msg)
+  })
+}
+
+function changeBatch(flag: boolean = true) {
+  if (flag) {
+    batchTableData.value = multipleTableRef.value && multipleTableRef.value.getSelectionRows()
+  } else {
+    batchTableData.value = []
+    multipleTableRef.value && multipleTableRef.value.clearSelection()
+  }
+}
+
 function addPersone(item: any) {
   console.log(item)
-  if(!item) {
+  if (!item) {
+    personnelFromData.value = {}
     dialogFrom.addPersonnelDialogVisible = true
     return
-  } 
+  }
   post(GET_USERINFO, { userId: item.id }).then(res => {
     const { id, name, phone, jobNumber, roleId, departmentCascade, inductionDate } = res.data
-    let newData = { id, name, phone, jobNumber, roleId, departmentId: 
-      departmentCascade && departmentCascade.split(',').map(Number).reverse(), 
-      inductionDate 
+    let newData = {
+      id, name, phone, jobNumber, roleId, departmentId:
+        departmentCascade && departmentCascade.split(',').map(Number).reverse(),
+      inductionDate
     }
     personnelFromData.value = newData
     dialogFrom.addPersonnelDialogVisible = true
@@ -382,17 +571,54 @@ function dialogFromCli(type: string, data: any = {}, flag: boolean = false) {
   dialogFrom[type] = true
 }
 
+function handleSizeChange(val: number) {
+  teamForm.pageIndex = 1
+  teamForm.pageSize = val
+  getTableData()
+}
+
+function handleCurrentChange(val: number) {
+  teamForm.pageIndex = val
+  getTableData()
+}
+
 function resetDialog() {
   let newDeptForm = resetFromValue(deptForm)
   Object.assign(deptForm, newDeptForm)
 }
 
+function batchItem(text: string, type: batchOperationType, data: any) {
+  allText.batchText = text,
+    visibleType.value = type
+  visibleData.value = data
+  dialogFrom.batchOperationVisible = true
+}
+
 function handleClose(done: any) {
   done()
 }
 
-function closeModal(modelType: string) {
+function transitionOperation(type: string, data: any) {
+  if (type == 'disable') { // 停用
+    resignationDate.value = formatDate(new Date())
+    console.log(resignationDate.value, '<==== 离职')
+    dialogFrom.resignationVisible = true
+  } else if (type == 'exportUser') { // 导出
+    exportRadio.value = '1'
+    dialogFrom.exportUserVisible = true
+  } else if (type == 'importUser') { // 导入
+    dialogFrom.importVisible = true
+  }
+
+  transitiondata.value = data
+}
+
+function closeModal(modelType: string, flag: boolean = false) {
   dialogFrom[modelType] = false
+  if (flag) {
+    changeBatch(false)
+    getTableData()
+  }
 }
 
 onBeforeMount(() => {
@@ -411,6 +637,7 @@ onMounted(() => {
 .teamstyle {
   .team-header {
     padding: 0.75rem 1.25rem;
+    box-sizing: border-box
   }
 
   .textFont {
@@ -449,6 +676,7 @@ onMounted(() => {
     }
   }
 }
+
 .operation {
   cursor: pointer;
 }

+ 18 - 15
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/module/AddPersonnelModal.vue

@@ -1,8 +1,19 @@
 <template>
-    <el-dialog v-model="data.addPersonnelDialogVisible" :title="'添加人员'" width="500" :before-close="handleClose">
-        <div>
+    <el-dialog v-model="data.addPersonnelDialogVisible" :title="'添加人员'" :show-close="false" width="600" :before-close="handleClose">
+        <template #header="{ close, titleId, titleClass }">
+            <div class="flex justify-between items-center border-b pb-3 dialog-header">
+                <h4 :id="titleId">添加/编辑人员</h4>
+                <div class="flex">
+                    <el-button @click="handleClose">取消</el-button>
+                    <el-button type="primary" @click="addPersonel(personnelRuleFormRef)">
+                        确定
+                    </el-button>
+                </div>
+            </div>
+        </template>
+        <div class="pt-5">
             <el-form ref="personnelRuleFormRef" style="max-width: 500px" :model="personnelFrom" :rules="personnelRules"
-                label-width="auto" size="large" status-icon>
+                label-width="120px" size="large" status-icon>
                 <el-form-item label="姓名" prop="name">
                     <el-input v-model="personnelFrom.name" placeholder="请输入姓名" clearable />
                 </el-form-item>
@@ -24,15 +35,7 @@
                     <el-date-picker v-model="personnelFrom.inductionDate" type="date" placeholder="选择入职时间" value-format="YYYY-MM-DD" style="width: 100%" />
                 </el-form-item>
             </el-form>
-        </div>
-        <template #footer>
-            <div class="dialog-footer">
-                <el-button @click="handleClose">取消</el-button>
-                <el-button type="primary" @click="addPersonel(personnelRuleFormRef)">
-                    确定
-                </el-button>
-            </div>
-        </template>
+        </div> 
     </el-dialog>
 </template>
 <script setup lang="ts">
@@ -67,7 +70,7 @@ const data = ref<Props['data']>({
     personnelFromData: {}
 })
 const personnelRuleFormRef = ref<FormInstance>() // 表单实例
-const personnelFrom = reactive<personnelFromType>({ // 填写的内容
+const personnelFrom = ref<personnelFromType>({ // 填写的内容
     id: '',
     name: '',
     phone: '',
@@ -88,7 +91,7 @@ const personnelRules = reactive<FormRules<typeof personnelFrom>>({ // 部门表
 // 定义方法
 function addPersonel(formEl: FormInstance | undefined) {
     if (!formEl) return
-    let dataForm = getFromValue(personnelFrom)
+    let dataForm = getFromValue(personnelFrom.value)
     const { departmentId } = dataForm
     emit('personnelModalConfirm', { ...dataForm, departmentId: departmentId && departmentId[departmentId.length - 1]  }, 'addPersonnelDialogVisible')
 }
@@ -96,7 +99,7 @@ function addPersonel(formEl: FormInstance | undefined) {
 // 监听 Props 的变化
 watch(() => props.data, (newValue) => {
     data.value = newValue
-    Object.assign(personnelFrom, newValue.personnelFromData)
+    personnelFrom.value = newValue.personnelFromData
 });
 
 const handleClose = () => {

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

@@ -0,0 +1,100 @@
+<template>
+    <el-dialog v-model="props.batchOperationVisible" width="800px" :show-close="false" :close-on-click-modal="false"
+        top="10vh">
+        <template #header="{ titleId, titleClass }">
+            <div class="flex justify-between items-center border-b pb-3">
+                <h4 :id="titleId">{{ '批量操作' }}</h4>
+                <div>
+                    <el-button @click="cancel">取消</el-button>
+                    <el-button type="primary" @click="confirm" v-loading="confirmloading">确认</el-button>
+                </div>
+            </div>
+        </template>
+        <div class="pt-4 pb-2">
+            <template v-if="props.popup == 'dept'">
+                <div class="w-full flex items-center">
+                    <div class="w-[100px] text-right">设置部门:</div>
+                    <div class="flex-1 pl-3">
+                        <el-cascader v-model="bindingVal" :options="props.batchData" class="w-full"
+                            :props="cascaderProps" />
+                    </div>
+                </div>
+            </template>
+            <template v-if="props.popup == 'role'">
+                <div class="w-full flex items-center">
+                    <div class="w-[100px] text-right">设置角色:</div>
+                    <div class="flex-1 pl-3">
+                        <el-select v-model="bindingVal" placeholder="请选择" class="w-full" filterable>
+                            <el-option v-for="item in props.batchData" :key="item.id" :label="item.rolename"
+                                :value="item.id" />
+                        </el-select>
+                    </div>
+                </div>
+            </template>
+        </div>
+    </el-dialog>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import type { CascaderProps } from 'element-plus'
+import { Props } from './type';
+import { BACTHUPDATEDEPT, BACTHUPDATEROLE } from '../api';
+import { post } from '@/utils/request';
+const props = defineProps<Props>()
+const emits = defineEmits(['close']);
+
+const globalPopup = inject<GlobalPopup>('globalPopup')
+const confirmloading = ref<boolean>(false)
+const cascaderProps = ref<CascaderProps>({
+    value: 'id',
+    expandTrigger: 'hover',
+    checkStrictly: true
+})
+const bindingVal = ref<any>([])
+
+const submitParameters = ref<any>({
+    'dept': {
+        url: BACTHUPDATEDEPT, // 请求地址
+        whether_str: false, // 是否转成字符串
+        filed: 'deptId', // 参数字段
+        param: {}
+    },
+    'role': {
+        url: BACTHUPDATEROLE, // 请求地址
+        whether_str: false, // 是否转成字符串
+        filed: 'roleId', // 参数字段
+        param: {}
+    }
+})
+
+function confirm() {
+    let params = processingParameters()
+    confirmloading.value = true
+    post(params.url, { ...params.param }).then(_res => {
+        globalPopup?.showSuccess('操作成功')
+        cancel()
+    }).catch(err => {
+        globalPopup?.showError(err.msg)
+    }).finally(() => {
+        confirmloading.value = false
+    })
+}
+
+function processingParameters() {
+    let { url, whether_str, filed, param } = submitParameters.value[props.popup]
+    const userIds = props.batchNode.map((item: any) => item.id)
+    let val = bindingVal.value
+    if (Array.isArray(bindingVal.value)) {
+        val = bindingVal.value[bindingVal.value.length - 1]
+    }
+    let rsult = { [filed]: val, userIds: !whether_str ? JSON.stringify(userIds) : userIds.join(',') }
+    return { url, param: { ...param, ...rsult } }
+}
+
+function cancel() {
+    emits('close', 'batchOperationVisible', true)
+}
+</script>
+
+<style lang="scss"></style>

+ 26 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/team/module/type.ts

@@ -0,0 +1,26 @@
+export interface Props {
+    /**
+     *  弹窗是否显示
+     */
+    batchOperationVisible: boolean;
+    /**
+     * 弹窗标题
+     */
+    visibleText: String;
+    /**
+     * 弹窗类型
+     */
+    popup: batchOperationType;
+    /**
+     * 数据源
+     */
+    batchData: any;
+    /**
+     * 批量节点
+     */
+    batchNode: any[]
+    /**
+     * 其他配置
+     */
+    otherConfig?: any;
+  }

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

@@ -0,0 +1 @@
+type batchOperationType = 'dept' | 'role'

+ 29 - 13
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/thread/index.vue

@@ -8,7 +8,7 @@
               <el-input v-model="filterCriteriaForm.clueName" clearable placeholder="请输入"></el-input>
             </el-form-item>
             <el-form-item label="线索来源">
-              <el-select v-model="filterCriteriaForm.clueSourceId" placeholder="请选择" clearable>
+              <el-select v-model="filterCriteriaForm.clueSourceId" placeholder="请选择" clearable filterable>
                 <el-option v-for="item in fixedData.ClueSources" :key="item.id" :label="item.name" :value="item.id" />
               </el-select>
             </el-form-item>
@@ -19,17 +19,17 @@
               <el-input v-model="filterCriteriaForm.email" clearable placeholder="请输入"></el-input>
             </el-form-item>
             <el-form-item label="客户行业">
-              <el-select v-model="filterCriteriaForm.customerIndustryId" placeholder="请选择">
+              <el-select v-model="filterCriteriaForm.customerIndustryId" placeholder="请选择" filterable clearable>
                 <el-option v-for="item in fixedData.CustomIndustry" :key="item.id" :label="item.name" :value="item.id" />
               </el-select>
             </el-form-item>
             <el-form-item label="客户级别">
-              <el-select v-model="filterCriteriaForm.customerLevelId" placeholder="请选择">
+              <el-select v-model="filterCriteriaForm.customerLevelId" placeholder="请选择" filterable clearable>
                 <el-option v-for="item in fixedData.CustomLevel" :key="item.id" :label="item.name" :value="item.id" />
               </el-select>
             </el-form-item>
             <el-form-item label="负责人">
-              <el-select v-model="filterCriteriaForm.inchargerId" placeholder="请选择">
+              <el-select v-model="filterCriteriaForm.inchargerId" placeholder="请选择" filterable clearable>
                 <el-option v-for="item in fixedData.Personnel" :key="item.id" :label="item.name" :value="item.id" />
               </el-select>
             </el-form-item>
@@ -54,14 +54,14 @@
         <div class="flex justify-end pb-3">
           <el-button type="primary" v-permission="['threadAdd']" @click="editClue(false)">新建线索</el-button>
           <el-button type="primary" :disabled="batchTableData.length <= 0" @click="batchTransfer()">批量转移</el-button>
-          <el-button type="primary" :disabled="batchTableData.length <= 0" @click="batchDeletes()">批量删除</el-button>
-          <el-button type="primary" @click="showDeteleClue(true)">回收站</el-button>
+          <el-button type="primary" v-permission="['threadDelete']" :disabled="batchTableData.length <= 0" @click="batchDeletes()">批量删除</el-button>
+          <el-button type="primary" v-permission="['threadRecycle']" @click="showDeteleClue(true)">回收站</el-button>
           <el-button type="primary" v-permission="['threadImport']" @click="dialogVisible.importVisible = true">导入</el-button>
           <el-button type="primary" v-permission="['threadExport']" @click="exportTheadTableList()" :loading="allLoading.exoprtLoading">导出</el-button>
         </div>
         <div class="flex-1 w-full overflow-hidden">
           <el-table :show-overflow-tooltip="tableShowOverflowTooltip" ref="clueTableRef" :data="clueTable" border v-loading="allLoading.clueTableLading"
-            style="width: 100%;height: 100%;" @selection-change="changeBatch">
+            style="width: 100%;height: 100%;" @selection-change="changeBatch" @sort-change="sortChange">
             <el-table-column type="selection" width="55" />
             <el-table-column prop="clueName" label="线索名称" width="180">
               <template #default="scope">
@@ -72,17 +72,17 @@
             <el-table-column prop="phone" label="电话号码" width="180"></el-table-column>
             <el-table-column prop="email" label="邮箱" width="180"></el-table-column>
             <el-table-column prop="customerIndustryValue" label="客户行业" width="180"></el-table-column>
-            <el-table-column prop="customerLevelValue" label="客户级别" width="180"></el-table-column>
+            <el-table-column prop="customerLevelValue" label="客户级别" width="180" sortable="custom"></el-table-column>
             <el-table-column prop="inchargerName" label="负责人" width="190"></el-table-column>
             <el-table-column prop="createName" label="创建人" width="180"></el-table-column>
             <el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
-            <el-table-column label="操作" fixed="right" width="200">
+            <el-table-column label="操作" fixed="right" width="200" v-permission="['threadEdit', 'tasksAdd', 'threadDelete']">
               <template #default="scope">
                 <el-button link type="primary" size="large" @click="editClue(scope.row)" v-permission="['threadEdit']">编辑</el-button>
                 <!-- <el-button link type="primary" size="large"
                   @click="dialogVisible.taskModalVisible = true">新建任务</el-button> -->
                 <el-button link type="primary" size="large" @click="newTask(scope.row)" v-permission="['tasksAdd']">新建任务</el-button>
-                <el-button link type="danger" size="large" @click.prevent="deleteRow(scope.row)" v-permission="['threadEdit']">删除</el-button>
+                <el-button link type="danger" size="large" @click.prevent="deleteRow(scope.row)" v-permission="['threadDelete']">删除</el-button>
               </template>
             </el-table-column>
           </el-table>
@@ -101,7 +101,7 @@
         <div class="flex justify-between items-center border-b pb-3 dialog-header">
           <h4 :id="titleId">{{ allText.editClueText }}</h4>
           <div>
-            <el-button type="primary" :loading="allLoading.clueSaveLoading" @click="saveEditClue(true)">保存并新建</el-button>
+            <el-button type="primary" v-if="!editForm.id" :loading="allLoading.clueSaveLoading" @click="saveEditClue(true)">保存并新建</el-button>
             <el-button type="primary" :loading="allLoading.clueSaveLoading" @click="saveEditClue(false)">保存</el-button>
             <el-button @click="dialogVisible.editClueDialogVisible = false">取消</el-button>
           </div>
@@ -208,6 +208,7 @@ const filterCriteriaForm = reactive<filterCriteriaFormType>({ // 筛选条件for
   inchargerId: '',
   startTime: getFirstDayOfMonth(new Date()),
   endTime: formatDate(new Date()),
+  isDesc: '',
   pageIndex: 1,
   pageFrom: 10
 })
@@ -236,7 +237,7 @@ const fixedData = reactive({
   ClueSources: [] as fixedDataInterface[],
   CustomIndustry: [] as fixedDataInterface[],
   CustomLevel: [] as fixedDataInterface[],
-  Personnel: [] as personnelInterface[]
+  Personnel: [] as personnelInterface[],
 })
 const clueTable = ref([]) // 线索table数据
 const clueTotalTable = ref(0) // 线索 table 数据总数
@@ -246,7 +247,7 @@ const clueTemplate = ref({
   list: [],
   config: {}
 }) // 线索模板
-const editForm = ref({}) // 编辑表单
+const editForm = ref<any>({}) // 编辑表单
 const taskModalForm = ref({}) // 任务弹窗表单
 const batchTableData = ref([])
 
@@ -258,6 +259,21 @@ const transferForm = reactive({
 
 
 // 定义方法
+function sortChange(data: any) {
+  filterCriteriaForm.pageIndex = 1
+  switch (data.order) {
+    case 'ascending':
+      filterCriteriaForm.isDesc = 1
+      break
+    case 'descending':
+      filterCriteriaForm.isDesc = 0
+      break
+    default:
+      filterCriteriaForm.isDesc = ''
+  }
+  getClueTable()
+}
+
 function exportTheadTableList() {
   allLoading.exoprtLoading = true
   let valueForm = getFromValue(filterCriteriaForm)

+ 2 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/thread/type.d.ts

@@ -9,5 +9,6 @@ interface filterCriteriaFormType { // 线索筛选条件类型
   startTime: string | number,
   endTime: string | number,
   pageIndex: number,
-  pageFrom: number
+  pageFrom: number,
+  isDesc?: number | string
 }

+ 31 - 11
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ProductController.java

@@ -7,6 +7,7 @@ import com.management.platform.mapper.UserMapper;
 import com.management.platform.service.*;
 import com.management.platform.util.BeanChangeUtil;
 import com.management.platform.util.HttpRespMsg;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.RequestMapping;
 
@@ -54,6 +55,10 @@ public class ProductController {
     private SalesOrderService salesOrderService;
     @Resource
     private SysDictService sysDictService;
+    @Resource
+    private StageService stageService;
+    @Resource
+    private ContactsService contactsService;
 
 
     /**
@@ -77,6 +82,7 @@ public class ProductController {
     * @Date: 2024/5/21
     */
     @RequestMapping("/addOrUpdate")
+    @Transactional
     public HttpRespMsg addOrUpdate(Product product){
         HttpRespMsg msg=new HttpRespMsg();
         User user = userMapper.selectById(request.getHeader("token"));
@@ -97,18 +103,17 @@ public class ProductController {
         AuditLogCenter auditLogCenter =new AuditLogCenter();
         auditLogCenter.setAuditorId(user.getId());
         auditLogCenter.setAuditorName(user.getName());
-        boolean isNew=true;
+        auditLogCenter.setModuleId(product.getId());
+        auditLogCenter.setModuleCode("Product");
         if(product.getId()==null){
             auditLogCenter.setAuditorContent("创建了产品");
+            auditLogCenterService.save(auditLogCenter);
         }else {
             Product oldProduct = productService.getById(product.getId());
             BeanChangeUtil<Product> beanChangeUtil = new BeanChangeUtil();
             String content = beanChangeUtil.contrastObj(oldProduct, product);
             //发生变化才生成记录
             if(!StringUtils.isEmpty(content.trim())){
-                isNew=false;
-                auditLogCenter.setModuleId(product.getId());
-                auditLogCenter.setModuleCode("Product");
                 auditLogCenter.setAuditorContent("编辑了产品");
                 auditLogCenterService.save(auditLogCenter);
             }
@@ -118,11 +123,6 @@ public class ProductController {
             msg.setError("验证失败");
             return msg;
         }
-        if(isNew){
-            auditLogCenter.setModuleId(product.getId());
-            auditLogCenter.setModuleCode("Product");
-            auditLogCenterService.save(auditLogCenter);
-        }
         return msg;
     }
 
@@ -268,7 +268,9 @@ public class ProductController {
         List<BusinessOpportunity> opportunityList = businessOpportunityService.list(new LambdaQueryWrapper<BusinessOpportunity>().in(BusinessOpportunity::getId, businessIds));
         List<Custom> customList = customService.list(new LambdaQueryWrapper<Custom>().eq(Custom::getCompanyId, companyId));
         List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getCompanyId, companyId));
-        List<SysDict> businessStageList = sysDictService.list(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCode, "BusinessStage"));
+//        List<SysDict> businessStageList = sysDictService.list(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCode, "BusinessStage"));
+        List<Stage> businessStageList = stageService.list(new LambdaQueryWrapper<Stage>().eq(Stage::getCompanyId, companyId));
+        List<Contacts> contactsList = contactsService.list(new LambdaQueryWrapper<Contacts>().eq(Contacts::getCompanyId, companyId));
         opportunityList.forEach(c->{
             Optional<Custom> custom = customList.stream().filter(ct -> ct.getId().equals(c.getCustomerId())).findFirst();
             if(custom.isPresent()){
@@ -278,11 +280,15 @@ public class ProductController {
             if(user.isPresent()){
                 c.setCreatorName(user.get().getName());
             }
+            Optional<Contacts> contacts = contactsList.stream().filter(u -> u.getId().equals(c.getContactsId())).findFirst();
+            if(contacts.isPresent()){
+                c.setContactsName(contacts.get().getName());
+            }
             Optional<User> incharger = userList.stream().filter(u -> u.getId().equals(c.getInchargerId())).findFirst();
             if(incharger.isPresent()){
                 c.setInchargerName(incharger.get().getName());
             }
-            Optional<SysDict> businessStage = businessStageList.stream().filter(b -> b.getId().equals(c.getStageId())).findFirst();
+            Optional<Stage> businessStage = businessStageList.stream().filter(b -> b.getId().equals(c.getStageId())).findFirst();
             if(businessStage.isPresent()){
                 c.setStageValue(businessStage.get().getName());
             }
@@ -309,6 +315,8 @@ public class ProductController {
         orderIds.add(-1);
         List<SalesOrder> orderList = salesOrderService.list(new LambdaQueryWrapper<SalesOrder>().in(SalesOrder::getId, orderIds));
         List<SysDict> orderTypeList = sysDictService.list(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCode, "OrderType"));
+        List<Integer> businessOpportunityIds = orderList.stream().map(SalesOrder::getBusinessOpportunityId).distinct().collect(Collectors.toList());
+        List<BusinessOpportunity> businessOpportunityList = businessOpportunityService.list(new LambdaQueryWrapper<BusinessOpportunity>().in(BusinessOpportunity::getId, businessOpportunityIds));
         orderList.forEach(o->{
             Optional<Custom> custom = customList.stream().filter(ct -> ct.getId().equals(o.getCustomId())).findFirst();
             if(custom.isPresent()){
@@ -318,10 +326,22 @@ public class ProductController {
             if(user.isPresent()){
                 o.setCreatorName(user.get().getName());
             }
+            Optional<User> customSigner = userList.stream().filter(u -> u.getId().equals(o.getCustomSigner())).findFirst();
+            if(customSigner.isPresent()){
+                o.setCustomSignerName(customSigner.get().getName());
+            }
+            Optional<User> companySigner = userList.stream().filter(u -> u.getId().equals(o.getCompanySigner())).findFirst();
+            if(companySigner.isPresent()){
+                o.setCompanySigner(companySigner.get().getName());
+            }
             Optional<User> incharger = userList.stream().filter(u -> u.getId().equals(o.getInchargerId())).findFirst();
             if(incharger.isPresent()){
                 o.setInchargerName(incharger.get().getName());
             }
+            Optional<BusinessOpportunity> businessOpportunity = businessOpportunityList.stream().filter(b -> o.getBusinessOpportunityId() != null && b.getId().equals(o.getBusinessOpportunityId())).findFirst();
+            if(businessOpportunity.isPresent()){
+                o.setBusinessOpportunityName(businessOpportunity.get().getName());
+            }
             Optional<SysDict> orderType = orderTypeList.stream().filter(ot -> ot.getId().equals(o.getType())).findFirst();
             if(orderType.isPresent()){
                 o.setTypeName(orderType.get().getName());

+ 46 - 13
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/SalesOrderController.java

@@ -9,6 +9,7 @@ import com.management.platform.mapper.UserMapper;
 import com.management.platform.service.*;
 import com.management.platform.util.BeanChangeUtil;
 import com.management.platform.util.HttpRespMsg;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.RequestMapping;
 
@@ -50,6 +51,8 @@ public class SalesOrderController {
     private AuditLogCenterService auditLogCenterService;
     @Resource
     private SalesOrderPaymentService salesOrderPaymentService;
+    @Resource
+    private ProductService productService;
 
 
     /**
@@ -58,8 +61,8 @@ public class SalesOrderController {
     @RequestMapping("/list")
     public HttpRespMsg list(String inchargerId,Integer orderType, String orderName,
                             String orderCode,Integer customId,String businessName,
-                            Integer receivedStatus,String startDate,String endDate, String productCode, Integer pageIndex, Integer pageSize,Integer isDelete){
-        return salesOrderService.getList(inchargerId,orderType,orderName,orderCode,customId,businessName,receivedStatus,startDate,endDate,productCode,pageIndex,pageSize,isDelete);
+                            Integer receivedStatus,String startTime,String endTime, String productCode, Integer pageIndex, Integer pageSize,Integer isDelete){
+        return salesOrderService.getList(inchargerId,orderType,orderName,orderCode,customId,businessName,receivedStatus,startTime,endTime,productCode,pageIndex,pageSize,isDelete);
     }
 
     /**
@@ -79,6 +82,7 @@ public class SalesOrderController {
      * 新增编辑订单数据
      * */
     @RequestMapping("/addOrUpdate")
+    @Transactional
     public HttpRespMsg addOrUpdate(SalesOrder order){
         HttpRespMsg msg=new HttpRespMsg();
         User user = userMapper.selectById(request.getHeader("token"));
@@ -88,16 +92,23 @@ public class SalesOrderController {
         if(order.getPrice()!=null){
             order.setUnReceivedPayment(order.getPrice());
         }
-        int count;
+        int countCode;
+        int countName;
         if(order.getId()==null){
-            count = salesOrderService.count(new LambdaQueryWrapper<SalesOrder>().eq(SalesOrder::getCompanyId, companyId).eq(SalesOrder::getOrderCode, order.getOrderCode()));
+            countCode = salesOrderService.count(new LambdaQueryWrapper<SalesOrder>().eq(SalesOrder::getCompanyId, companyId).eq(SalesOrder::getOrderCode, order.getOrderCode()));
+            countName = salesOrderService.count(new LambdaQueryWrapper<SalesOrder>().eq(SalesOrder::getCompanyId, companyId).eq(SalesOrder::getOrderName, order.getOrderName()));
         }else {
-            count = salesOrderService.count(new LambdaQueryWrapper<SalesOrder>().eq(SalesOrder::getCompanyId, companyId).ne(SalesOrder::getId,order.getId()).eq(SalesOrder::getOrderCode,order.getOrderCode()));
+            countCode = salesOrderService.count(new LambdaQueryWrapper<SalesOrder>().eq(SalesOrder::getCompanyId, companyId).ne(SalesOrder::getId,order.getId()).eq(SalesOrder::getOrderCode,order.getOrderCode()));
+            countName = salesOrderService.count(new LambdaQueryWrapper<SalesOrder>().eq(SalesOrder::getCompanyId, companyId).ne(SalesOrder::getId,order.getId()).eq(SalesOrder::getOrderName,order.getOrderName()));
         }
-        if(count>0){
+        if(countCode>0){
             msg.setError("订单编号为["+order.getOrderCode()+"]的订单已存在");
             return msg;
         }
+        if(countName>0){
+            msg.setError("订单名称为["+order.getOrderName()+"]的订单已存在");
+            return msg;
+        }
         //todo:生成操作记录
         AuditLogCenter auditLogCenter =new AuditLogCenter();
         auditLogCenter.setAuditorId(user.getId());
@@ -106,6 +117,7 @@ public class SalesOrderController {
         auditLogCenter.setModuleCode("SalesOrder");;
         if(order.getId()==null){
             auditLogCenter.setAuditorContent("创建了订单");
+            auditLogCenterService.save(auditLogCenter);
         }else {
             SalesOrder oldOrder = salesOrderService.getById(order.getId());
             BeanChangeUtil<Product> beanChangeUtil = new BeanChangeUtil();
@@ -113,10 +125,10 @@ public class SalesOrderController {
             //发生变化才生成记录
             if(!StringUtils.isEmpty(content.trim())){
                 auditLogCenter.setAuditorContent("编辑了订单");
+                auditLogCenterService.save(auditLogCenter);
             }
 
         }
-        auditLogCenterService.save(auditLogCenter);
         if(!salesOrderService.saveOrUpdate(order)){
             msg.setError("验证失败");
             return msg;
@@ -125,11 +137,28 @@ public class SalesOrderController {
         if(!StringUtils.isEmpty(order.getOrderProductDetailString())){
             String orderProductDetailString = order.getOrderProductDetailString();
             List<OrderProductDetail> orderProductDetails = JSONArray.parseArray(orderProductDetailString, OrderProductDetail.class);
+            List<Integer> productIds = orderProductDetails.stream().map(OrderProductDetail::getProductId).distinct().collect(Collectors.toList());
+            productIds.add(-1);
+            List<Product> productList = productService.list(new LambdaQueryWrapper<Product>().in(Product::getId, productIds));
+            //移除旧的数据进行更新
+            orderProductDetailService.remove(new LambdaQueryWrapper<OrderProductDetail>().eq(OrderProductDetail::getOrderId,order.getId()));
             if(orderProductDetails.size()>0){
-                orderProductDetails.forEach(o->{
-                    o.setOrderId(order.getId());
-                });
-                orderProductDetailService.saveOrUpdateBatch(orderProductDetails);
+                for (OrderProductDetail orderProductDetail : orderProductDetails) {
+                    orderProductDetail.setId(null);
+                    orderProductDetail.setOrderId(order.getId());
+                    Optional<Product> first = productList.stream().filter(p -> p.getId().equals(orderProductDetail.getProductId())).findFirst();
+                    if(first.isPresent()){
+                        if(orderProductDetail.getNum().intValue()>first.get().getInventory()){
+                            try {
+                                throw new Exception("相关产品["+first.get().getProductName()+"]库存数量不足");
+                            } catch (Exception e) {
+                                e.printStackTrace();
+                                msg.setError(e.getMessage());
+                            }
+                        }
+                    }
+                }
+                orderProductDetailService.saveBatch(orderProductDetails);
             }
         }
         return msg;
@@ -285,8 +314,8 @@ public class SalesOrderController {
     * @Date: 2024/5/14
     */
     @RequestMapping("/exportData")
-    public HttpRespMsg exportData(String userId, String orderName,String orderCode, String productCode) throws Exception {
-        return salesOrderService.exportData(userId,orderName,orderCode,productCode);
+    public HttpRespMsg exportData(String userId, String orderName,String orderCode, String productCode,String startTime,String endTime) throws Exception {
+        return salesOrderService.exportData(userId,orderName,orderCode,productCode,startTime,endTime);
     }
 
 
@@ -364,6 +393,10 @@ public class SalesOrderController {
         SalesOrderPayment salesOrderPayment=new SalesOrderPayment();
         salesOrderPayment.setMoney(new BigDecimal(money));
         salesOrderPayment.setOrderId(orderId);
+        if(money>salesOrder.getUnReceivedPayment().doubleValue()){
+            msg.setError("回款金额不能大于当前未回款金额");
+            return msg;
+        }
         //订单已回款金额
         BigDecimal receivedPayment = salesOrder.getReceivedPayment();
         //订单未回款金额

+ 13 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/Product.java

@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
 import java.io.Serializable;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.management.platform.config.PropertyMsg;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
@@ -39,48 +40,56 @@ public class Product extends Model<Product> {
      * 产品名称
      */
     @TableField("product_name")
+    @PropertyMsg("产品名称")
     private String productName;
 
     /**
      * 产品编号
      */
     @TableField("product_code")
+    @PropertyMsg("产品编号")
     private String productCode;
 
     /**
      * 类型
      */
     @TableField("type")
+    @PropertyMsg("类型")
     private Integer type;
 
     /**
      * 单位
      */
     @TableField("unit")
+    @PropertyMsg("单位")
     private Integer unit;
 
     /**
      * 单价
      */
     @TableField("price")
+    @PropertyMsg("单价")
     private BigDecimal price;
 
     /**
      * 库存数量
      */
     @TableField("inventory")
+    @PropertyMsg("库存数量")
     private Integer inventory;
 
     /**
      * 状态 0-下架 1-上架
      */
     @TableField("status")
+    @PropertyMsg("状态")
     private Integer status;
 
     /**
      * 负责人id
      */
     @TableField("incharger_id")
+    @PropertyMsg("负责人")
     private String inchargerId;
 
     /**
@@ -131,6 +140,7 @@ public class Product extends Model<Product> {
      * 描述
      */
     @TableField("descs")
+    @PropertyMsg("描述")
     private String descs;
 
     /**
@@ -139,6 +149,9 @@ public class Product extends Model<Product> {
     @TableField("is_delete")
     private Integer isDelete;
 
+    @TableField("update_time")
+    private LocalDateTime updateTime;
+
     @TableField(exist = false)
     private String inchargerName;
 

+ 23 - 3
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/SalesOrder.java

@@ -11,6 +11,7 @@ import java.io.Serializable;
 import java.util.List;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.management.platform.config.PropertyMsg;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
@@ -41,51 +42,58 @@ public class SalesOrder extends Model<SalesOrder> {
      * 订单名称
      */
     @TableField("order_name")
+    @PropertyMsg("订单名称")
     private String orderName;
 
     /**
      * 订单编号
      */
     @TableField("order_code")
+    @PropertyMsg("订单编号")
     private String orderCode;
 
     /**
      * 客户id
      */
     @TableField("custom_id")
+    @PropertyMsg("客户")
     private Integer customId;
 
     /**
      * 商机id
      */
     @TableField("business_opportunity_id")
+    @PropertyMsg("商机")
     private Integer businessOpportunityId;
 
     /**
      * 订单金额
      */
     @TableField("price")
+    @PropertyMsg("订单金额")
     private BigDecimal price;
 
     /**
      * 联系人id
      */
     @TableField("contacts_id")
+    @PropertyMsg("联系人")
     private Integer contactsId;
 
     /**
      * 订单类型
      */
     @TableField("type")
+    @PropertyMsg("订单类型")
     private Integer type;
 
     /**
      * 下单时间
      */
     @TableField("place_time")
-    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private LocalDateTime placeTime;
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDate placeTime;
 
     /**
      * 订单开始时间
@@ -93,6 +101,7 @@ public class SalesOrder extends Model<SalesOrder> {
     @TableField("order_start_date")
     @DateTimeFormat(pattern = "yyyy-MM-dd")
     @JsonFormat(pattern = "yyyy-MM-dd")
+    @PropertyMsg("订单开始时间")
     private LocalDate orderStartDate;
 
     /**
@@ -101,24 +110,28 @@ public class SalesOrder extends Model<SalesOrder> {
     @TableField("order_end_date")
     @DateTimeFormat(pattern = "yyyy-MM-dd")
     @JsonFormat(pattern = "yyyy-MM-dd")
+    @PropertyMsg("订单结束时间")
     private LocalDate orderEndDate;
 
     /**
      * 已回款金额
      */
     @TableField("received_payment")
+    @PropertyMsg("已回款金额")
     private BigDecimal receivedPayment;
 
     /**
      * 未回款金额
      */
     @TableField("un_received_payment")
+    @PropertyMsg("未回款金额")
     private BigDecimal unReceivedPayment;
 
     /**
      * 回款状态 0-未回款 1-已回款 2-已完全回款
      */
     @TableField("received_status")
+    @PropertyMsg("回款状态")
     private Integer receivedStatus;
 
 
@@ -126,24 +139,28 @@ public class SalesOrder extends Model<SalesOrder> {
      * 客户签约人
      */
     @TableField("custom_signer")
+    @PropertyMsg("客户签约人")
     private String customSigner;
 
     /**
      * 公司签约人
      */
     @TableField("company_signer")
+    @PropertyMsg("公司签约人")
     private String companySigner;
 
     /**
      * 负责人
      */
     @TableField("incharger_id")
+    @PropertyMsg("负责人")
     private String inchargerId;
 
     /**
      * 备注
      */
     @TableField("remark")
+    @PropertyMsg("备注")
     private String remark;
 
     @TableField("create_time")
@@ -196,6 +213,9 @@ public class SalesOrder extends Model<SalesOrder> {
     @TableField("plate5")
     private String plate5;
 
+    @TableField("update_time")
+    private LocalDateTime updateTime;
+
 
     @TableField(exist = false)
     private String orderProductDetailString;

+ 3 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/dto/TaskDto.java

@@ -24,5 +24,8 @@ public class TaskDto extends Task {
     private String clueName;
     private String phone;
 
+    private Integer departmentId;
+    private String departmentIdByMyselfOrNull;
+
 
 }

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

@@ -23,4 +23,11 @@ public class DepartmentVO {
     private List<String> otherManagerIds;
     private Integer ddDeptid;
     private Integer pushToSap;
+
+    private Integer customertotal;//客户总量
+    private Integer customerDeal;//客户成交量
+    private Double dealRate;//客户成交量率
+    private Integer num;//客户数量
+    private Integer saleNum;//交易客户数量
+    private String departmentName;
 }

+ 5 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/mapper/DepartmentMapper.java

@@ -2,6 +2,7 @@ package com.management.platform.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.management.platform.entity.Department;
+import com.management.platform.entity.vo.DepartmentVO;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Update;
 
@@ -31,4 +32,8 @@ public interface DepartmentMapper extends BaseMapper<Department> {
 
     @Update("update department set superior_id = null where department_id = #{departmentId}")
     void updateNullSuperior(Integer departmentId);
+
+    List<DepartmentVO> getCustomerTotalCount(String startDate, String endDate, Integer departmentId, Integer companyId);
+
+    List<DepartmentVO> getCustomerTransferRate(String startDate, String endDate, Integer departmentId, Integer companyId);
 }

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

@@ -17,11 +17,11 @@ public interface SalesOrderService extends IService<SalesOrder> {
 
     HttpRespMsg getList(String inchargerId,Integer orderType, String orderName,
                         String orderCode,Integer customId,String businessName,
-                        Integer receivedStatus,String startDate,String endDate, String productCode, Integer pageIndex, Integer pageSize,Integer isDelete);
+                        Integer receivedStatus,String startTime,String endTime, String productCode, Integer pageIndex, Integer pageSize,Integer isDelete);
 
     HttpRespMsg importData(MultipartFile multipartFile);
 
-    HttpRespMsg exportData(String userId, String orderName, String orderCode, String productCode) throws Exception;
+    HttpRespMsg exportData(String userId, String orderName, String orderCode, String productCode,String startTime,String endTime) throws Exception;
 
     HttpRespMsg salesKit(Integer queryType,Integer dateType, String startDate, String endDate);
 

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

@@ -12,6 +12,7 @@ import com.management.platform.entity.vo.ContactsVo;
 import com.management.platform.mapper.*;
 import com.management.platform.service.ContactsService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.service.SysFunctionService;
 import com.management.platform.service.WxCorpInfoService;
 import com.management.platform.util.ExcelUtil;
 import com.management.platform.util.HttpRespMsg;
@@ -78,6 +79,9 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
     @Resource
     private ExcelExportServiceImpl excelExportService;
 
+    @Resource
+    private SysFunctionService sysFunctionService;
+
     @Resource
     private StageMapper stageMapper;
 
@@ -111,8 +115,8 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
 
         LambdaQueryWrapper<Contacts> lqw_contacts = new LambdaQueryWrapper<>();
         lqw_contacts.eq(Contacts::getPhone,contacts.getPhone());
-        Contacts selectedOne = contactsMapper.selectOne(lqw_contacts);
-        if (selectedOne != null) {
+        List<Contacts> list = contactsMapper.selectList(lqw_contacts);
+        if (!list.isEmpty()) {
             httpRespMsg.setError("已存在该联系人,手机号重复!");
             return httpRespMsg;
         }
@@ -137,6 +141,11 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
 
     @Override
     public HttpRespMsg pageContacts(Integer pageIndex, Integer pageSize, Integer customId, String name, String email, String creatorId, String phone, String ownerId, HttpServletRequest request) {
+        String token = String.valueOf(request.getHeader("Token"));
+        User user = userMapper.selectById(token);
+        boolean isAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看全部联系人");
+        boolean isNotAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看负责部门联系人");
+
         Map<String, Object> map = new HashMap<>();
         map.put("customId", customId);
         map.put("name", name);
@@ -144,11 +153,22 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
         map.put("ownerId", ownerId);
         map.put("email", email);
         map.put("creatorId", creatorId);
-        String token = String.valueOf(request.getHeader("Token"));
-        User user = userMapper.selectById(token);
         map.put("companyId", user.getCompanyId());
         map.put("isDelete", 0);
-        Page<ContactsVo> pageContacts = contactsMapper.pageContacts(new Page((long) (pageIndex - 1) *pageSize, pageSize), map);
+
+
+        if (isAll){
+            System.out.println("do nothing");
+        }else if (isNotAll){
+            Integer departmentId = user.getDepartmentId();//找出对应的部门id
+            map.put("departmentId",departmentId);
+        }else {
+            //查看负责人为自己和null的数据
+            map.put("ownerIdByMyselfAndNull",user.getId());
+
+        }
+
+        Page<ContactsVo> pageContacts = contactsMapper.pageContacts(new Page( pageIndex, pageSize), map);
 
         List<ContactsVo> records = pageContacts.getRecords();
         long total = pageContacts.getTotal();
@@ -516,7 +536,7 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
                     Method method = contactsClass.getMethod(setter, type);
                     //校验当前列是否为必填
                     if(requiredList.get(i)){
-                        if(StringUtils.isEmpty(cell.getStringCellValue())){
+                        if(cell==null || StringUtils.isEmpty(cell.getStringCellValue())){
                             msg.setError(labelList.get(i)+"值不能为空值");
                             return msg;
                         }
@@ -530,7 +550,7 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
                                 contacts.setCustomId(custom.getId());
                             }
                              else {
-                                msg.setError("负责人["+customerName+"]在系统中不存在");
+                                msg.setError("客户["+customerName+"]在系统中不存在");
                                 return msg;
                             }
                         }
@@ -557,11 +577,12 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
                             if (first.isPresent()) {
                                 contacts.setOwnerId(first.get().getId());
                             } else {
-                                throw new Exception("["+userName+"]在系统中不存在");
+                                msg.setError("负责人["+userName+"]在系统中不存在");
+                                return msg;
                             }
                         }
                     }else{
-                        if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                        if(cell!=null && !StringUtils.isEmpty(cell.getStringCellValue())){
                             System.out.println(cell.getStringCellValue());
                             method.invoke(contacts,cell.getStringCellValue());
                         }
@@ -571,6 +592,23 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
             }
 
             if(importContactsList.size()>0){
+                LambdaQueryWrapper<Contacts> lqw_contacts = new LambdaQueryWrapper<>();
+                for (Contacts contacts : importContactsList) {
+                    lqw_contacts.eq(Contacts::getPhone,contacts.getPhone());
+                    List<Contacts> list = contactsMapper.selectList(lqw_contacts);
+                    if (!list.isEmpty()) {
+                        msg.setError("手机号:"+contacts.getPhone()+"重复");
+                        return msg;
+                    }
+                    if (contacts.getName()==null||StringUtils.isEmpty(contacts.getName())){
+                        msg.setError("请确保联系人名称不为空");
+                        return msg;
+                    }
+                    if (contacts.getCustomId()==null){
+                        msg.setError("请确保客户名称不为空");
+                        return msg;
+                    }
+                }
                 if(!saveOrUpdateBatch(importContactsList)){
                     msg.setError("验证失败");
                     return msg;
@@ -621,6 +659,7 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
         dataList.add(titleList);
 
         Map<String, Object> map = new HashMap<>();
+        map.put("isDelete", 0);
         map.put("customName", customName);
         map.put("name", name);
         map.put("phone", phone);
@@ -689,14 +728,15 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
                         .eq("id",contactsId)));
             }
         }else if(salesId!=null){
+            //要找销售订单对应的客户,然后再找客户对应的联系人
             SalesOrder salesOrder = salesOrderMapper.selectById(salesId);
-            if (salesOrder==null||salesOrder.getContactsId()==null){
+            if (salesOrder==null||salesOrder.getCustomId()==null){
                 mgs.setData(new ArrayList<Contacts>());
             }else {
-                Integer contactsId = salesOrder.getContactsId();
+                Integer contactsId = salesOrder.getCustomId();
                 mgs.setData(contactsMapper.selectList(new QueryWrapper<Contacts>()
                         .eq("company_id",user.getCompanyId())
-                        .eq("id",contactsId)));
+                        .eq("custom_id",contactsId)));
             }
 
         }

+ 64 - 19
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/CustomServiceImpl.java

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.management.platform.entity.*;
+import com.management.platform.entity.vo.DepartmentVO;
 import com.management.platform.entity.vo.UserVO;
 import com.management.platform.mapper.*;
 import com.management.platform.service.CustomService;
@@ -69,6 +70,9 @@ public class CustomServiceImpl extends ServiceImpl<CustomMapper, Custom> impleme
     @Autowired
     private UploadFileMapper uploadFileMapper;
 
+    @Autowired
+    private DepartmentMapper departmentMapper;
+
 
     @Resource
     private HttpServletRequest request;
@@ -441,40 +445,81 @@ public class CustomServiceImpl extends ServiceImpl<CustomMapper, Custom> impleme
 
     @Override
     public HttpRespMsg getCustomerTotalCount(String startDate, String endDate, String userId, Integer departmentId, Integer exportType, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
         User user = userMapper.selectById(request.getHeader("token"));
         Integer companyId = user.getCompanyId();
-        List<UserVO> userVoList=userMapper.getCustomerTotalCount(startDate,endDate,userId,companyId);
-        if (userVoList!=null&&!userVoList.isEmpty()){
-            for (UserVO userVO : userVoList) {
-                if (userVO.getCustomertotal()==0){
-                    userVO.setDealRate((double) 0);
-                }else {
-                    userVO.setDealRate((double) (userVO.getCustomerDeal()/userVO.getCustomertotal()));
+        if (exportType==1){//员工
+            List<UserVO> userVoList=userMapper.getCustomerTotalCount(startDate,endDate,userId,companyId);
+            if (userVoList!=null&&!userVoList.isEmpty()){
+                for (UserVO userVO : userVoList) {
+                    if (userVO.getCustomertotal()==0){
+                        userVO.setDealRate((double) 0);
+                    }else {
+                        double v = ((double) userVO.getCustomerDeal() / userVO.getCustomertotal());
+                        String formattedValue = String.format("%.2f", v);
+                        userVO.setDealRate(Double.parseDouble(formattedValue));
+                    }
+                }
+            }
+            msg.setData(userVoList);
+        }else {
+            List<DepartmentVO> departmentVoList=departmentMapper.getCustomerTotalCount(startDate,endDate,departmentId,companyId);
+            if (departmentVoList!=null&&!departmentVoList.isEmpty()){
+                for (DepartmentVO departmentVO : departmentVoList) {
+                    if (departmentVO.getCustomertotal()==0){
+                        departmentVO.setDealRate((double)0);
+                    }else {
+                        double v=((double) departmentVO.getCustomerDeal() /departmentVO.getCustomertotal());
+                        String formattedValue = String.format("%.2f", v);
+                        departmentVO.setDealRate(Double.parseDouble(formattedValue));
+                    }
                 }
             }
+            msg.setData(departmentVoList);
         }
-        HttpRespMsg msg = new HttpRespMsg();
-        msg.setData(userVoList);
         return msg;
     }
 
     @Override
     public HttpRespMsg getCustomerTransferRate(String startDate, String endDate, String userId, Integer departmentId, Integer exportType, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+
         User user = userMapper.selectById(request.getHeader("token"));
         Integer companyId = user.getCompanyId();
-        List<UserVO> userVoList=userMapper.getCustomerTransferRate(startDate,endDate,userId,companyId);
-        if (userVoList!=null&&!userVoList.isEmpty()){
-            for (UserVO userVO : userVoList) {
-                if (userVO.getNum()==0){
-                    userVO.setDealRate((double) 0);
-                }else {
-                    double v = (double) userVO.getSaleNum() / userVO.getNum();
-                    userVO.setDealRate(v);
+
+        if (exportType==1) {//员工
+            List<UserVO> userVoList=userMapper.getCustomerTransferRate(startDate,endDate,userId,companyId);
+            if (userVoList!=null&&!userVoList.isEmpty()){
+                for (UserVO userVO : userVoList) {
+                    if (userVO.getNum()==0){
+                        userVO.setDealRate((double) 0);
+                    }else {
+                        double v = (double) userVO.getSaleNum() / userVO.getNum();
+                        String formattedValue = String.format("%.2f", v);
+                        userVO.setDealRate(Double.parseDouble(formattedValue));
+                        userVO.setDealRate(v);
+                    }
                 }
             }
+            msg.setData(userVoList);
         }
-        HttpRespMsg msg = new HttpRespMsg();
-        msg.setData(userVoList);
+        else {//部门
+            List<DepartmentVO> departmentVoList=departmentMapper.getCustomerTransferRate(startDate,endDate,departmentId,companyId);
+            if (departmentVoList!=null&&!departmentVoList.isEmpty()){
+                for (DepartmentVO departmentVO : departmentVoList) {
+                    if (departmentVO.getNum()==0){
+                        departmentVO.setDealRate((double)0);
+                    }else {
+                        double v = (double) departmentVO.getSaleNum() / departmentVO.getNum();
+                        String formattedValue = String.format("%.2f", v);
+                        departmentVO.setDealRate(Double.parseDouble(formattedValue));
+                    }
+                }
+            }
+            msg.setData(departmentVoList);
+        }
+
+
         return msg;
 
     }

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

@@ -122,11 +122,12 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
                 deptIds=deptIds.stream().distinct().collect(Collectors.toList());
                 List<Integer> finalDeptIds2 = deptIds;
                 List<String> userIds = userList.stream().filter(u -> finalDeptIds2.contains(u.getDepartmentId())).map(User::getId).collect(Collectors.toList());
-                queryWrapper.in(Product::getCreatorId,userIds);
+                userIds.add(targetUsr.getId());
+                queryWrapper.and(wrapper->wrapper.in(Product::getCreatorId,userIds).or().in(Product::getInchargerId,userIds));
             }
         }
         if(!StringUtils.isEmpty(userId)){
-            queryWrapper.eq(Product::getCreatorId,userId);
+            queryWrapper.eq(Product::getInchargerId,userId);
         }
         if(!StringUtils.isEmpty(productName)){
             queryWrapper.like(Product::getProductName,productName);
@@ -150,6 +151,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
             pageIndex=-1;
             pageSize=-1;
         }
+        queryWrapper.orderByDesc(Product::getCreateTime);
         IPage<Product> productIPage = productMapper.selectPage(new Page<>(pageIndex, pageSize,true), queryWrapper);
         List<Product> records = productIPage.getRecords();
         records.forEach(r->{
@@ -180,6 +182,10 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
     @Override
     public HttpRespMsg importData(MultipartFile multipartFile) {
         HttpRespMsg msg=new HttpRespMsg();
+        if(!multipartFile.getOriginalFilename().endsWith(".xlsx")){
+            msg.setError("文件格式错误,请使用.xlsx格式的Excel文件进行导入");
+            return msg;
+        }
         String fileName = multipartFile.getOriginalFilename();
         File file = new File(fileName == null ? "file" : fileName);
         User user = userMapper.selectById(request.getHeader("token"));
@@ -389,6 +395,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
             }
         } catch (IOException | NoSuchMethodException e) {
             e.printStackTrace();
+            msg.setError("验证失败");
         } catch (IllegalAccessException e) {
             e.printStackTrace();
         } catch (InvocationTargetException e) {
@@ -514,13 +521,72 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
     @Override
     public HttpRespMsg recycleList(Integer pageIndex, Integer pageSize) {
         HttpRespMsg msg=new HttpRespMsg();
-        User user = userMapper.selectById(request.getHeader("token"));
-        LambdaQueryWrapper<Product> productLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        productLambdaQueryWrapper.eq(Product::getCompanyId,user.getCompanyId());
-        productLambdaQueryWrapper.eq(Product::getIsDelete,1);
-        IPage<Product> productIPage = productMapper.selectPage(new Page<>(pageIndex, pageSize), productLambdaQueryWrapper);
-        Map<String,Object> map=new HashMap<>();
-        map.put("record",productIPage.getRecords());
+        User targetUsr = userMapper.selectById(request.getHeader("token"));
+        Integer companyId=targetUsr.getCompanyId();
+        List<Department> departments = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, companyId));
+        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(Product::getCompanyId,companyId);
+        queryWrapper.eq(Product::getIsDelete,1);
+        List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getCompanyId, companyId));
+        List<SysDict> sysDictOfProductType = sysDictMapper.selectList(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCompanyId, companyId).eq(SysDict::getCode, "ProductType"));
+        List<SysDict> sysDictOfProductUnit = sysDictMapper.selectList(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCompanyId, companyId).eq(SysDict::getCode, "ProductUnit"));
+        boolean hasPriviledgeAll = sysFunctionService.hasPriviledge(targetUsr.getRoleId(), "查看全部产品数据");
+        boolean hasPriviledgeDept = sysFunctionService.hasPriviledge(targetUsr.getRoleId(), "查看负责部门产品数据");
+        //判断查看全部的权限
+        if(!hasPriviledgeAll){
+            //判断查看负责部门的权限
+            if(!hasPriviledgeDept){
+                //都没有就只能看自己创建的
+                queryWrapper.eq(Product::getCreatorId,targetUsr.getId());
+            }else {
+                List<Department> departmentList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getManagerId, targetUsr.getId()));
+                List<DepartmentOtherManager> otherManagerList = departmentOtherManagerMapper.selectList(new LambdaQueryWrapper<DepartmentOtherManager>().eq(DepartmentOtherManager::getOtherManagerId, targetUsr.getId()));
+                List<Integer> deptIds=new ArrayList<>();
+                deptIds.add(-1);
+                List<Integer> managerDeptIds = departmentList.stream().map(Department::getDepartmentId).distinct().collect(Collectors.toList());
+                List<Integer> otherManagerDeptIds = otherManagerList.stream().map(DepartmentOtherManager::getDepartmentId).distinct().collect(Collectors.toList());
+                deptIds.addAll(managerDeptIds);
+                List<Integer> finalDeptIds1 = deptIds;
+                managerDeptIds.forEach(m->{
+                    List<Integer> branchDepartment = getBranchDepartment(m, departments);
+                    finalDeptIds1.addAll(branchDepartment);
+                });
+                deptIds.addAll(otherManagerDeptIds);
+                List<Integer> finalDeptIds = deptIds;
+                otherManagerDeptIds.forEach(o->{
+                    List<Integer> branchDepartment = getBranchDepartment(o, departments);
+                    finalDeptIds.addAll(branchDepartment);
+                });
+                deptIds=deptIds.stream().distinct().collect(Collectors.toList());
+                List<Integer> finalDeptIds2 = deptIds;
+                List<String> userIds = userList.stream().filter(u -> finalDeptIds2.contains(u.getDepartmentId())).map(User::getId).collect(Collectors.toList());
+                userIds.add(targetUsr.getId());
+                queryWrapper.and(wrapper->wrapper.in(Product::getCreatorId,userIds).or().in(Product::getInchargerId,userIds));
+            }
+        }
+        queryWrapper.orderByDesc(Product::getUpdateTime);
+        IPage<Product> productIPage = productMapper.selectPage(new Page<>(pageIndex, pageSize,true), queryWrapper);
+        List<Product> records = productIPage.getRecords();
+        records.forEach(r->{
+            Optional<User> user = userList.stream().filter(u -> u.getId().equals(r.getInchargerId())).findFirst();
+            if(user.isPresent()){
+                r.setInchargerName(user.get().getName());
+            }
+            Optional<User> creator = userList.stream().filter(u -> u.getId().equals(r.getCreatorId())).findFirst();
+            if(creator.isPresent()){
+                r.setCreatorName(creator.get().getName());
+            }
+            Optional<SysDict> unit = sysDictOfProductUnit.stream().filter(u -> u.getId().equals(r.getUnit())).findFirst();
+            if(unit.isPresent()){
+                r.setUnitName(unit.get().getName());
+            }
+            Optional<SysDict> type = sysDictOfProductType.stream().filter(u -> u.getId().equals(r.getType())).findFirst();
+            if(type.isPresent()){
+                r.setTypeName(type.get().getName());
+            }
+        });
+        Map map=new HashMap();
+        map.put("record",records);
         map.put("total",productIPage.getTotal());
         msg.setData(map);
         return msg;

File diff suppressed because it is too large
+ 1445 - 1383
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java


+ 48 - 26
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/SalesOrderServiceImpl.java

@@ -19,6 +19,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.usermodel.CellType;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.multipart.MultipartFile;
@@ -94,7 +95,7 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
     @Override
     public HttpRespMsg getList(String inchargerId,Integer orderType, String orderName,
                                String orderCode,Integer customId,String businessName,
-                               Integer receivedStatus,String startDate,String endDate, String productCode, Integer pageIndex, Integer pageSize,Integer isDelete) {
+                               Integer receivedStatus,String startTime,String endTime, String productCode, Integer pageIndex, Integer pageSize,Integer isDelete) {
         HttpRespMsg msg=new HttpRespMsg();
         User user = userMapper.selectById(request.getHeader("token"));
         List<Department> departments = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, user.getCompanyId()));
@@ -116,8 +117,8 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
         if(!viewAll){
             //判断查看负责部门的权限
             if(!viewDept){
-                //都没有就只能看自己创建的
-                orderLambdaQueryWrapper.eq(SalesOrder::getCreatorId,user.getId());
+                //都没有就只能看自己创建的或者负责的
+                orderLambdaQueryWrapper.and(wrapper->wrapper.eq(SalesOrder::getCreatorId,user.getId()).or().eq(SalesOrder::getInchargerId,user.getId()));
             }else {
                 List<Department> departmentList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getManagerId, user.getId()));
                 List<DepartmentOtherManager> otherManagerList = departmentOtherManagerMapper.selectList(new LambdaQueryWrapper<DepartmentOtherManager>().eq(DepartmentOtherManager::getOtherManagerId, user.getId()));
@@ -140,7 +141,9 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
                 deptIds=deptIds.stream().distinct().collect(Collectors.toList());
                 List<Integer> finalDeptIds2 = deptIds;
                 List<String> userIds = userList.stream().filter(u -> finalDeptIds2.contains(u.getDepartmentId())).map(User::getId).collect(Collectors.toList());
-                orderLambdaQueryWrapper.in(SalesOrder::getCreatorId,userIds);
+                //加上本人
+                userIds.add(user.getId());
+                orderLambdaQueryWrapper.and(wrapper->wrapper.in(SalesOrder::getCreatorId,userIds).or().in(SalesOrder::getInchargerId,userIds));
             }
         }
         if (!StringUtils.isEmpty(inchargerId)){
@@ -156,16 +159,18 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
             orderLambdaQueryWrapper.inSql(SalesOrder::getBusinessOpportunityId,"select id from business_opportunity where name like '%"+businessName+"%'");
         }
         if(receivedStatus!=null){
-            if(receivedStatus==1){
-                //回款金额不为空 切大于0 作为已回款状态
-                orderLambdaQueryWrapper.and(wrapper->wrapper.isNotNull(SalesOrder::getReceivedPayment).gt(SalesOrder::getReceivedPayment,0));
-            }else {
-                //回款金额为空 或者等于0 作为未回款状态
-                orderLambdaQueryWrapper.and(wrapper->wrapper.isNull(SalesOrder::getReceivedPayment).or().eq(SalesOrder::getReceivedPayment,0));
-            }
+//            if(receivedStatus==1){
+//                //回款金额不为空 切大于0 作为已回款状态
+//                orderLambdaQueryWrapper.and(wrapper->wrapper.isNotNull(SalesOrder::getReceivedPayment).gt(SalesOrder::getReceivedPayment,0));
+//            }else {
+//                //回款金额为空 或者等于0 作为未回款状态
+//                orderLambdaQueryWrapper.and(wrapper->wrapper.isNull(SalesOrder::getReceivedPayment).or().eq(SalesOrder::getReceivedPayment,0));
+//            }
+            orderLambdaQueryWrapper.eq(SalesOrder::getReceivedStatus,receivedStatus);
         }
-        if(!StringUtils.isEmpty(startDate)&&!StringUtils.isEmpty(endDate)){
-            orderLambdaQueryWrapper.lt(SalesOrder::getOrderStartDate,endDate).gt(SalesOrder::getOrderEndDate,startDate);
+        if(!StringUtils.isEmpty(startTime)&&!StringUtils.isEmpty(endTime)){
+//            orderLambdaQueryWrapper.lt(SalesOrder::getOrderStartDate,endTime).gt(SalesOrder::getOrderEndDate,startTime);
+            orderLambdaQueryWrapper.between(SalesOrder::getPlaceTime,startTime,endTime);
         }
         if(!StringUtils.isEmpty(orderName)){
             orderLambdaQueryWrapper.like(SalesOrder::getOrderName,orderName);
@@ -182,6 +187,13 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
             pageIndex=-1;
             pageSize=-1;
         }
+        if(isDelete!=null){
+            orderLambdaQueryWrapper.eq(SalesOrder::getIsDelete,isDelete);
+            orderLambdaQueryWrapper.orderByDesc(SalesOrder::getUpdateTime);
+        }else {
+            orderLambdaQueryWrapper.eq(SalesOrder::getIsDelete,0);
+            orderLambdaQueryWrapper.orderByDesc(SalesOrder::getCreateTime);
+        }
         IPage<SalesOrder> orderIPage = salesOrderMapper.selectPage(new Page<>(pageIndex, pageSize), orderLambdaQueryWrapper);
         List<SalesOrder> records = orderIPage.getRecords();
         List<Integer> orderIds = records.stream().map(SalesOrder::getId).distinct().collect(Collectors.toList());
@@ -276,8 +288,13 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
     }
 
     @Override
+    @Transactional
     public HttpRespMsg importData(MultipartFile multipartFile) {
         HttpRespMsg msg=new HttpRespMsg();
+        if(!multipartFile.getOriginalFilename().endsWith(".xlsx")){
+            msg.setError("文件格式错误,请使用.xlsx格式的Excel文件进行导入");
+            return msg;
+        }
         String fileName = multipartFile.getOriginalFilename();
         File file = new File(fileName == null ? "file" : fileName);
         User user = userMapper.selectById(request.getHeader("token"));
@@ -470,7 +487,7 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
                         }
                     }else if(modelName.equals("placeTime")){
                         if(!StringUtils.isEmpty(cell.getStringCellValue())){
-                            order.setPlaceTime(LocalDateTime.parse(cell.getStringCellValue(),df1));
+                            order.setPlaceTime(LocalDate.parse(cell.getStringCellValue(),df));
                         }
                     }else if(modelName.equals("orderStartDate")){
                         if(!StringUtils.isEmpty(cell.getStringCellValue())){
@@ -549,18 +566,20 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
             }
         } catch (IOException | NoSuchMethodException e) {
             e.printStackTrace();
+            msg.setError("验证失败");
         } catch (IllegalAccessException e) {
             e.printStackTrace();
         } catch (InvocationTargetException e) {
             e.printStackTrace();
         } catch (Exception e) {
             e.printStackTrace();
+            msg.setError("验证失败");
         }
         return msg;
     }
 
     @Override
-    public HttpRespMsg exportData(String userId, String orderName, String orderCode, String productCode) throws Exception {
+    public HttpRespMsg exportData(String userId, String orderName, String orderCode, String productCode,String startTime,String endTime) throws Exception {
         User user = userMapper.selectById(request.getHeader("token"));
         SysForm sysForm = sysFormMapper.selectOne(new LambdaQueryWrapper<SysForm>().eq(SysForm::getCompanyId, user.getCompanyId()).eq(SysForm::getCode, "Order").eq(SysForm::getIsCurrent, 1));
         WxCorpInfo wxCorpInfo = wxCorpInfoService.getOne(new LambdaQueryWrapper<WxCorpInfo>().eq(WxCorpInfo::getCompanyId, user.getCompanyId()));
@@ -586,7 +605,7 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
             }
         }
         dataList.add(titleList);
-        HttpRespMsg respMsg = getList( userId,null, orderName,orderCode,null,null,null,null,null,productCode, null,null,0);
+        HttpRespMsg respMsg = getList( userId,null, orderName,orderCode,null,null,null,startTime,endTime,productCode, null,null,0);
         Map<String, Object> msgData = (Map<String, Object>) respMsg.getData();
         List<SalesOrder> salesOrderList = (List<SalesOrder>) msgData.get("record");
         for (SalesOrder salesOrder : salesOrderList) {
@@ -639,6 +658,7 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
     public HttpRespMsg salesKit(Integer queryType,Integer dateType,String startDate, String endDate) {
         HttpRespMsg msg=new HttpRespMsg();
         DateTimeFormatter df=DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        DateTimeFormatter df1=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
         LambdaQueryWrapper<Custom> customLambdaQueryWrapper = new LambdaQueryWrapper<>();
         LambdaQueryWrapper<Custom> customLambdaQueryWrapper1 = new LambdaQueryWrapper<>();
         LambdaQueryWrapper<Contacts> contactsLambdaQueryWrapper = new LambdaQueryWrapper<>();
@@ -652,11 +672,13 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
         User user = userMapper.selectById(request.getHeader("token"));
         List<Department> allDeptList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, user.getCompanyId()));
         if(!StringUtils.isEmpty(startDate)&&!StringUtils.isEmpty(endDate)){
-            customLambdaQueryWrapper.between(Custom::getCreateTime,startDate,endDate);
+            startDate=startDate+" 00:00:00";
+            endDate=endDate+" 23:59:59";
+            customLambdaQueryWrapper.between(Custom::getCreateTime,LocalDateTime.parse(startDate,df1),LocalDateTime.parse(endDate,df1));
             contactsLambdaQueryWrapper.between(Contacts::getCreateTime,startDate,endDate);
-            businessOpportunityLambdaQueryWrapper.between(BusinessOpportunity::getCreateTime,startDate,endDate);
-            salesOrderLambdaQueryWrapper.between(SalesOrder::getCreateTime,startDate,endDate);
-            clueLambdaQueryWrapper.between(Clue::getCreateTime,startDate,endDate);
+            businessOpportunityLambdaQueryWrapper.between(BusinessOpportunity::getCreateTime,LocalDateTime.parse(startDate,df1),LocalDateTime.parse(endDate,df1));
+            salesOrderLambdaQueryWrapper.between(SalesOrder::getCreateTime,LocalDateTime.parse(startDate,df1),LocalDateTime.parse(endDate,df1));
+            clueLambdaQueryWrapper.between(Clue::getCreateTime,LocalDateTime.parse(startDate,df1),LocalDateTime.parse(endDate,df1));
         }
         if(dateType!=null){
             switch (dateType){
@@ -733,7 +755,7 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
                     deptIds.add(-1);
                     List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().in(User::getDepartmentId, deptIds));
                     List<String> userIds = userList.stream().map(User::getId).distinct().collect(Collectors.toList());
-                    userIds.add("-1");
+                    userIds.add(user.getId());
                     customLambdaQueryWrapper.in(Custom::getCreatorId,userIds);
                     contactsLambdaQueryWrapper.in(Contacts::getCreatorId,userIds);
                     businessOpportunityLambdaQueryWrapper.in(BusinessOpportunity::getCreatorId,userIds);
@@ -751,7 +773,7 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
                     Integer targetDeptId = user.getDepartmentId();
                     List<User> users = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getDepartmentId, targetDeptId));
                     List<String> targetUserIds = users.stream().map(User::getId).distinct().collect(Collectors.toList());
-                    targetUserIds.add("-1");
+                    targetUserIds.add(user.getId());
                     customLambdaQueryWrapper.in(Custom::getCreatorId,targetUserIds);
                     contactsLambdaQueryWrapper.in(Contacts::getCreatorId,targetUserIds);
                     businessOpportunityLambdaQueryWrapper.in(BusinessOpportunity::getCreatorId,targetUserIds);
@@ -770,7 +792,7 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
                     List<Integer> branchDepartment = getBranchDepartment(targetDeptId1, allDeptList);
                     List<User> users1 = userMapper.selectList(new LambdaQueryWrapper<User>().in(User::getDepartmentId, branchDepartment));
                     List<String> targetUserIds1 = users1.stream().map(User::getId).distinct().collect(Collectors.toList());
-                    targetUserIds1.add("-1");
+                    targetUserIds1.add(user.getId());
                     customLambdaQueryWrapper.in(Custom::getCreatorId,targetUserIds1);
                     contactsLambdaQueryWrapper.in(Contacts::getCreatorId,targetUserIds1);
                     businessOpportunityLambdaQueryWrapper.in(BusinessOpportunity::getCreatorId,targetUserIds1);
@@ -794,7 +816,7 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
         double businessOpportunityPrice = businessOpportunityList.stream().filter(b->!StringUtils.isEmpty(b.getAmountOfMoney())).mapToDouble(b ->Double.valueOf(b.getAmountOfMoney())).sum();
         Integer salesOrderCount = salesOrderMapper.selectCount(salesOrderLambdaQueryWrapper);
         List<SalesOrder> salesOrders = salesOrderMapper.selectList(salesOrderLambdaQueryWrapper);
-        double salesOrdersPrice = salesOrders.stream().mapToDouble(s -> s.getPrice().doubleValue()).sum();
+        double salesOrdersPrice = salesOrders.stream().filter(i->i.getPrice()!=null).mapToDouble(s -> s.getPrice().doubleValue()).sum();
         Integer clueCount = clueMapper.selectCount(clueLambdaQueryWrapper);
 
         int customCount1 = customService.count(customLambdaQueryWrapper1);
@@ -804,7 +826,7 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
         double businessOpportunityPrice1 = businessOpportunityList1.stream().filter(b->!StringUtils.isEmpty(b.getAmountOfMoney())).mapToDouble(b -> Double.valueOf(b.getAmountOfMoney())).sum();
         Integer salesOrderCount1 = salesOrderMapper.selectCount(salesOrderLambdaQueryWrapper1);
         List<SalesOrder> salesOrders1 = salesOrderMapper.selectList(salesOrderLambdaQueryWrapper1);
-        double salesOrdersPrice1 = salesOrders1.stream().mapToDouble(s -> s.getPrice().doubleValue()).sum();
+        double salesOrdersPrice1 = salesOrders1.stream().filter(s->s.getPrice()!=null).mapToDouble(s ->s.getPrice().doubleValue()).sum();
         Integer clueCount1 = clueMapper.selectCount(clueLambdaQueryWrapper1);
         Map<String,Object> customMap=new HashMap<>();
         customMap.put("customCount",customCount);
@@ -819,7 +841,7 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
         businessOpportunityMap.put("businessOpportunityPromote",getPromote(businessOpportunityCount,businessOpportunityCount1));
         resultMap.put("businessOpportunity",businessOpportunityMap);
         Map<String,Object> businessOpportunityPriceMap=new HashMap<>();
-        businessOpportunityPriceMap.put("businessOpportunityPrice",businessOpportunityPrice);
+        businessOpportunityPriceMap.put("businessOpportunityPrice",String.format("%.2f",businessOpportunityPrice));
         businessOpportunityPriceMap.put("businessOpportunityPromote",getPromote((int)businessOpportunityPrice,(int)businessOpportunityPrice1));
         resultMap.put("businessOpportunityPrice",businessOpportunityPriceMap);
         Map<String,Object> salesOrderMap=new HashMap<>();

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

@@ -93,7 +93,7 @@ public class SysFormServiceImpl extends ServiceImpl<SysFormMapper, SysForm> impl
         switch (code){
             case "Thread":title = company.getCompanyName()+"_线索导入模板";
             break;
-            case "Custom":title = company.getCompanyName()+"_客户导入模板";
+            case "Customer":title = company.getCompanyName()+"_客户导入模板";
                 break;
             case "Order":title = company.getCompanyName()+"_订单导入模板";
                 break;

+ 198 - 94
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java

@@ -22,6 +22,7 @@ import org.apache.poi.xssf.usermodel.XSSFRow;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -33,6 +34,7 @@ import java.io.*;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.text.SimpleDateFormat;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
@@ -52,6 +54,9 @@ import java.util.stream.Collectors;
 @Transactional
 public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements TaskService {
 
+    @Autowired
+    private ContactsService contactsService;
+
     @Resource
     private UserMapper userMapper;
     @Resource
@@ -61,6 +66,9 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
     @Resource
     private TaskExecutorMapper taskExecutorMapper;
 
+    @Resource
+    private SysFunctionService sysFunctionService;
+
     @Resource
     private TaskRepeatDesignMapper taskRepeatDesignMapper;
 
@@ -119,9 +127,12 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
         BeanUtils.copyProperties(taskDto,task);
         task.setCreateDate(LocalDateTime.now());//任务的创建时间
         //根据任务的开始时间与当下时间判断任务的状态
-        if (taskDto.getStartDate()==null||taskDto.getStartDate().isAfter(LocalDateTime.now())){
+        if (taskDto.getStartDate()!=null&&taskDto.getStartDate().isAfter(LocalDateTime.now())){
             task.setStatus(0);
-        }else {
+        }else if (taskDto.getEndDate()!=null&&taskDto.getEndDate().isBefore(LocalDateTime.now())){
+            task.setStatus(3);
+        } else if (taskDto.getStartDate()!=null&&taskDto.getStartDate().isBefore(LocalDateTime.now())&&taskDto.getEndDate()!=null&&taskDto.getEndDate().isAfter(LocalDateTime.now()))
+        {
             task.setStatus(1);
         }
         task.setCreaterName(user.getName());
@@ -175,6 +186,21 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
         List<TaskExecutor> taskExecutorList = taskExecutorMapper.selectList(new LambdaQueryWrapper<TaskExecutor>().eq(TaskExecutor::getCompanyId,user.getCompanyId()));
         List<TaskLog> taskLogList = taskLogMapper.selectList(new LambdaQueryWrapper<TaskLog>().eq(TaskLog::getCompanyId,user.getCompanyId()).orderByDesc(TaskLog::getModTime));
         taskDto.setPageIndex((taskDto.getPageIndex()-1)*taskDto.getPageSize());
+
+        boolean isAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看全部任务");
+        boolean isNotAll = sysFunctionService.hasPriviledge(user.getRoleId(), "查看负责部门任务");
+
+        if (isAll){
+            System.out.println("do nothing");
+        }else if (isNotAll){
+            Integer departmentId = user.getDepartmentId();//找出对应的部门id
+            taskDto.setDepartmentId(departmentId);
+        }else {
+            //查看负责人为自己和null的数据
+            taskDto.setDepartmentIdByMyselfOrNull(user.getId());
+
+        }
+
         List<TasKVo> taskVoList =taskMapper.getPageListTask(taskDto);
         for (TasKVo tasKVo : taskVoList) {
             if (!taskExecutorList.isEmpty()){
@@ -270,7 +296,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
         }
         List<Task> taskList = taskMapper.selectList(new QueryWrapper<Task>().in("id", taskIds));
         if (!taskList.isEmpty()){
-            List<Task> collect = taskList.stream().filter(task ->task.getStatus()!=0&& task.getStatus() != 2).collect(Collectors.toList());
+            List<Task> collect = taskList.stream().filter(task ->task.getStatus()!=null&&task.getStatus()!=0&&task.getStatus()!=2).collect(Collectors.toList());
             if (collect.size()>0){
                 msg.setError("存在任务未完成,不能删除");
                 return msg;
@@ -324,6 +350,37 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
             JSONObject configOb = JSON.parseObject(config);
             JSONArray configObJSONArray = configOb.getJSONArray("list");
 
+            //可能存在栅格布局的情况需要特殊处理
+            List<String> modelNameList=new ArrayList<>();
+            List<String> typeList=new ArrayList<>();
+            List<String> labelList=new ArrayList<>();
+            List<Boolean> requiredList=new ArrayList<>();
+
+            for (int i = 0; i < configObJSONArray.size(); i++) {
+                JSONObject jsonObject = configObJSONArray.getJSONObject(i);
+                if(jsonObject.getString("type").equals("grid")){
+                    JSONArray columns = jsonObject.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);
+                            modelNameList.add(object.getString("model"));
+                            typeList.add(object.getString("type"));
+                            labelList.add(object.getString("label"));
+                            Boolean required = object.getJSONObject("options").getJSONObject("rules").getBoolean("required");
+                            requiredList.add(required);
+                        }
+                    }
+                }else {
+                    modelNameList.add(jsonObject.getString("model"));
+                    typeList.add(jsonObject.getString("type"));
+                    labelList.add(jsonObject.getString("label"));
+                    Boolean required = jsonObject.getJSONObject("options").getJSONObject("rules").getBoolean("required");
+                    requiredList.add(required);
+                }
+            }
+
             List<Task>  importTaskList=new ArrayList<>();
             List<String> userNameList=new ArrayList<>();
             HttpRespMsg respMsg=new HttpRespMsg();
@@ -347,19 +404,8 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
                 int cellNum = row.getLastCellNum();
 
                 for (int i = 0; i < cellNum; i++) {
-                    JSONObject item = configObJSONArray.getJSONObject(i);
-                    String modelName = item.getString("model");
+                    String modelName = modelNameList.get(i);
                     XSSFCell cell = row.getCell(i);
-/*                    if(cell!=null&&StringUtils.isNotEmpty(cell.getStringCellValue())){
-                        switch (item.getString("type")){
-                            case "time":cell.setCellType(CellType.NUMERIC);
-                                System.out.println(cell.getNumericCellValue());
-                                break;
-                            case "int":cell.setCellType(CellType.NUMERIC);
-                                break;
-                            default:cell.setCellType(CellType.STRING);
-                        }
-                    }*/
                     if(modelName.equals("executorId")){
                         if(!StringUtils.isEmpty(cell.getStringCellValue())){
                             List<String> executorNames = new ArrayList<>();
@@ -402,22 +448,26 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
                 task.setCompanyId(companyId);
                 task.setCreaterId(user.getId());
                 task.setCreateDate(LocalDateTime.now());
-                task.setStatus(0);
+//                task.setStatus(0);
                 task.setIsDelete(0);
+
+                //统计 线索不应与客户/商机/销售订单/联系人一同存在
+                boolean b1=false; //客户/商机/销售订单/联系人
+                boolean b2=false;//线索
+
+                //客户/商机/销售订单不应一同存在
+                boolean b3=false;//客户
+                boolean b4=false;//商机
+                boolean b5=false;//销售订单
+
                 for (int i = 0; i < cellNum; i++) {
-                    JSONObject item = configObJSONArray.getJSONObject(i);
-                    String modelName = item.getString("model");
+                    String modelName = modelNameList.get(i);
                     String className = modelName.substring(0, 1).toUpperCase() + modelName.substring(1);
                     String getter="get"+className;
                     String setter="set"+className;
                     XSSFCell cell = row.getCell(i);
-                    if(cell!=null&&StringUtils.isNotEmpty(cell.getStringCellValue())){
-                        switch (item.getString("type")){
-                            case "time":cell.setCellType(CellType.NUMERIC);
-                                System.out.println(cell.getNumericCellValue());
-                                break;
-                            case "int":cell.setCellType(CellType.NUMERIC);
-                                break;
+                    if(cell!=null){
+                        switch (typeList.get(i)){
                             default:cell.setCellType(CellType.STRING);
                         }
                     }
@@ -425,25 +475,14 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
 //                    Field field = taskClass.getDeclaredField(modelName);
 //                    Class<?> type = field.getType();
 //                    Method method = taskClass.getMethod(setter, type);
-                    //校验当前列是否为必填
-                    JSONObject options = item.getJSONObject("options");
-                    JSONObject rules = options.getJSONObject("rules");
-                    Boolean required = rules.getBoolean("required");
-                    if(required){
-                        if(StringUtils.isEmpty(cell.getStringCellValue())){
-                            msg.setError(item.getString("label")+"值不能为空值");
+
+                    if(requiredList.get(i)){
+                        if(cell==null||StringUtils.isEmpty(cell.getStringCellValue())){
+                            msg.setError(labelList.get(i)+"值不能为空值");
                             return msg;
                         }
                     }
-                    /*if(modelName.equals("taskCode")){
-                        if(!org.springframework.util.StringUtils.isEmpty(cell.getStringCellValue())){
-                            //系统中同公司已存在的产品编码 更新
-                            Optional<Task> first = taskList.stream().filter(p ->p.getTaskCode()!=null&& p.getTaskCode().equals(cell.getStringCellValue())).findFirst();
-                            if(first.isPresent()){
-                                task.setId(first.get().getId());
-                            }
-                        }
-                    }*/
+
                     if(modelName.equals("executorId")){
                         if(cell!=null&&!StringUtils.isEmpty(cell.getStringCellValue())){
 
@@ -469,7 +508,8 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
                                 if (first.isPresent()) {
                                     executorIds.add(first.get().getId());
                                 } else {
-                                    throw new Exception("["+userName+"]在系统中不存在");
+                                    msg.setError("["+userName+"]在系统中不存在");
+                                    return msg;
                                 }
                             }
                             StringJoiner joiner = new StringJoiner(",");
@@ -485,12 +525,12 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
 
 
                     }*/
-                    if(modelName.equals("taskName")){
+                   else if(modelName.equals("taskName")){
                         if(!StringUtils.isEmpty(cell.getStringCellValue())){
                             task.setTaskName(cell.getStringCellValue());
                         }
                     }
-                    if(modelName.equals("priority")){
+                   else if(modelName.equals("priority")){
                         if(cell!=null&&!StringUtils.isEmpty(cell.getStringCellValue())){
                             switch (cell.getStringCellValue()){
                                 case "低":task.setPriority(0);
@@ -502,150 +542,162 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
                             }
                         }
                     }
-                    if(modelName.equals("startDate")){
+                    else if(modelName.equals("startDate")){
                         if(cell != null && cell.getCellTypeEnum() != CellType.BLANK){
-                            if (cell.getCellTypeEnum() == CellType.NUMERIC){
-                                Date dateCellValue = cell.getDateCellValue();
-                                if (dateCellValue.before(new Date(-2208988800L))){
-                                    continue;
-                                }else {
-                                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-                                    String string = format.format(dateCellValue);
-                                    System.out.println(string);
-                                    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-                                    LocalDateTime time = LocalDateTime.parse(string, dateTimeFormatter);
-                                    task.setStartDate(time);
-                                }
+                            if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+                                task.setStartDate(LocalDateTime.parse(cell.getStringCellValue(),df));
                             }
                         }
                     }
-                    if(modelName.equals("endDate")){
+                    else if(modelName.equals("endDate")){
                         if(cell != null && cell.getCellTypeEnum() != CellType.BLANK){
-                            if (cell.getCellTypeEnum() == CellType.NUMERIC){
-                                Date dateCellValue = cell.getDateCellValue();
-                                if (dateCellValue.before(new Date(-2208988800L))){
-                                    continue;
-                                }else {
-                                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-                                    String string = format.format(dateCellValue);
-                                    System.out.println(string);
-                                    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-                                    LocalDateTime time = LocalDateTime.parse(string, dateTimeFormatter);
-                                    task.setEndDate(time);
-                                }
+                            if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+                                task.setEndDate(LocalDateTime.parse(cell.getStringCellValue(),df));
                             }
                         }
                     }
 
-                    if(modelName.equals("contactsId")){
+                    else if(modelName.equals("contactsId")){
                         if(cell!=null&&!StringUtils.isEmpty(cell.getStringCellValue())){
+                            b1=true;
+
                             String contactsName = cell.getStringCellValue();
                             List<Contacts> collect = contactsList.stream().filter(contacts -> contacts.getName().equals(contactsName)).collect(Collectors.toList());
-                            if (collect.size()>1){
-                                throw new Exception("["+contactsName+"]对应的联系人存在多个");
-                            }else if (collect.size()==1) {
+                            if (!collect.isEmpty()) {
                                 Contacts contacts = collect.get(0);
                                 task.setContactsId(contacts.getId());
                             }else {
-                                throw new Exception("["+contactsName+"]对应的联系人不存在");
+                                msg.setError("["+contactsName+"]对应的联系人不存在");
+                                return msg;
                             }
                         }
                     }
 
-                    if(modelName.equals("customId")){
+                    else if(modelName.equals("customId")){
                         if(cell!=null&&!StringUtils.isEmpty(cell.getStringCellValue())){
+                            b1=true;
+                            b3=true;
+
                             String customName = cell.getStringCellValue();
                             List<Custom> customs = customList.stream().filter(custom -> customName.equals(custom.getCustomName())).collect(Collectors.toList());
                             if (customs.size()>1){
-                                throw new Exception("["+customName+"]对应的客户存在多个");
+                                msg.setError("["+customName+"]对应的客户存在多个");
+                                return msg;
                             }else if (customs.size()==1){
                                 Custom custom = customs.get(0);
                                 if (task.getContactsId()!=null){
                                     boolean isExist = contactsList.stream().anyMatch(contacts -> custom.getId().equals(contacts.getCustomId())&&contacts.getId().equals(task.getContactsId()));
                                     if(!isExist){
-                                        throw new Exception("["+customName+"]对应的客户没有对应填写的联系人");
+                                        msg.setError("["+customName+"]对应的客户没有对应填写的联系人");
+                                        return msg;
                                     }
                                     else {
                                         task.setCustomId(custom.getId());
+                                        task.setTaskType(0);
                                     }
                                 }else {
                                     task.setCustomId(custom.getId());
+                                    task.setTaskType(0);
                                 }
                             }else {
-                                throw new Exception("["+customName+"]对应的客户不存在");
+                                msg.setError("["+customName+"]对应的客户不存在");
+                                return msg;
                             }
                         }
                     }
-                    if (modelName.equals("businessOpportunityId")){
+                    else if (modelName.equals("businessOpportunityId")){
                         if(cell!=null&&!StringUtils.isEmpty(cell.getStringCellValue())){
+                            b1=true;
+                            b4=true;
+
                             String businessName = cell.getStringCellValue();
                             List<BusinessOpportunity> collect = opportunityList.stream().filter(o -> businessName.equals(o.getName())).collect(Collectors.toList());
                             if (collect.size()>1){
-                                throw new Exception("["+businessName+"]对应的商机存在多个");
+                                msg.setError("["+businessName+"]名称,对应的商机存在多个");
+                                return msg;
                             }else if (collect.size()==1) {
                                 BusinessOpportunity businessOpportunity = collect.get(0);
                                 if (task.getContactsId()!=null){
                                     if (!businessOpportunity.getContactsId().equals(task.getContactsId())){
-                                        throw new Exception("["+businessName+"]对应的商机没有对应填写的联系人");
+                                        msg.setError("["+businessName+"]对应的商机没有对应填写的联系人");
+                                        return msg;
                                     }else {
                                         task.setBusinessOpportunityId(businessOpportunity.getId());
+                                        task.setTaskType(1);
                                     }
                                 }
                             }else {
-                                throw new Exception("["+businessName+"]对应的商机不存在");
+                                msg.setError("["+businessName+"]对应的商机不存在");
+                                return msg;
                             }
 
                         }
                     }
-                    if (modelName.equals("orderId")){
+                    else if (modelName.equals("orderId")){
                         if(cell!=null&&!StringUtils.isEmpty(cell.getStringCellValue())){
+                            b1=true;
+                            b5=true;
+
                             String orderName = cell.getStringCellValue();
                             List<SalesOrder> collect = orderList.stream().filter(order -> orderName.equals(order.getOrderName())).collect(Collectors.toList());
                             if (collect.size()>1){
-                                throw new Exception("["+orderName+"]对应的销售订单存在多个");
+                                msg.setError("["+orderName+"]对应的销售订单存在多个");
+                                return msg;
                             }else if (collect.size()==1) {
                                 SalesOrder order=collect.get(0);
                                 if (task.getContactsId()!=null){
                                     if (!order.getContactsId().equals(task.getContactsId())){
-                                        throw new Exception("["+orderName+"]对应的销售订单没有对应填写的联系人");
+                                        msg.setError("["+orderName+"]对应的销售订单没有对应填写的联系人");
+                                        return msg;
                                     }
                                     else {
                                         task.setOrderId(order.getId());
+                                        task.setTaskType(2);
                                     }
                                 }
                             }else {
-                                throw new Exception("["+orderName+"]对应的销售订单不存在");
+                                msg.setError("["+orderName+"]对应的销售订单不存在");
+                                return msg;
                             }
                         }
                     }
 
-                    if (modelName.equals("clueId")) {
+                    else if (modelName.equals("clueId")) {
                         if (cell!=null&&!StringUtils.isEmpty(cell.getStringCellValue())) {
+                            b2=true;
+
                             String clueName = cell.getStringCellValue();
                             if (task.getContactsId()!=null){
-                                throw new Exception("["+clueName+"]对应的线索不存在联系人");
+                                msg.setError("["+clueName+"]对应的线索不存在联系人");
+                                return msg;
                             }
                             List<Clue> collect = clueList.stream().filter(clue -> clueName.equals(clue.getClueName())).collect(Collectors.toList());
                             if (!collect.isEmpty()) {
                                 Clue clue = collect.get(0);
                                 task.setClueId(clue.getId());
+                                task.setTaskType(3);
                             }else {
-                                throw new Exception("["+clueName+"]对应的线索不存在");
+                                msg.setError("["+clueName+"]对应的线索不存在");
+                                return msg;
                             }
                         }
                     }
 
-                    if (modelName.equals("phone")) {
+                    else if (modelName.equals("phone")) {
                         if (cell!=null&&!StringUtils.isEmpty(cell.getStringCellValue())) {
                             String contactsPhone = cell.getStringCellValue();
                             List<Contacts> collect = contactsList.stream().filter(contacts -> contactsPhone.equals(contacts.getPhone())).collect(Collectors.toList());
                             if (collect.size()>1){
-                                throw new Exception("联系人号码"+"["+contactsPhone+"]对应的联系人存在多个");
+                                msg.setError("联系人号码"+"["+contactsPhone+"]对应的联系人存在多个");
+                                return msg;
                             } else if (collect.size() == 1) {
                                 Contacts contacts = collect.get(0);
                                 if (task.getContactsId()!=null){
                                     if (!contacts.getId().equals(task.getContactsId())){
-                                        throw new Exception("联系人号码"+"["+contactsPhone+"]与联系人不绑定");
+                                        msg.setError("联系人号码"+"["+contactsPhone+"]与联系人不绑定");
+                                        return msg;
                                     }
                                 }else {
                                     task.setContactsId(contacts.getId());
@@ -654,7 +706,28 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
 
                         }
                     }
+                    else {
+                        if(cell!=null && !StringUtils.isEmpty(cell.getStringCellValue())){
+                            Class<Task> taskClass = Task.class;
+                            Field field = taskClass.getDeclaredField(modelName);
+                            Class<?> type = field.getType();
+                            Method method = taskClass.getMethod(setter, type);
+                            System.out.println(cell.getStringCellValue());
+                            method.invoke(task,cell.getStringCellValue());
+                        }
+                    }
+
                 }
+
+                if (b1&&b2){
+                    msg.setError("任务名称:"+task.getTaskName()+",线索不应与客户/商机/销售订单/联系人一同存在");
+                    return msg;
+                }
+                if (b3&&b4&&b5){
+                    msg.setError("任务名称:"+task.getTaskName()+",客户/商机/销售订单不应一同存在");
+                    return msg;
+                }
+
                 importTaskList.add(task);
             }
 
@@ -671,6 +744,37 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
                         msg.setError("任务:"+task.getTaskName()+"中客户/商机/销售订单不应一同存在");
                         return msg;
                     }
+                    if (task.getStartDate()!=null&&task.getStartDate().isAfter(LocalDateTime.now())){
+                        task.setStatus(0);
+                    }else if (task.getEndDate()!=null&&task.getEndDate().isBefore(LocalDateTime.now())){
+                        task.setStatus(3);
+                    } else if (task.getStartDate()!=null&&task.getStartDate().isBefore(LocalDateTime.now())&&task.getEndDate()!=null&&task.getEndDate().isAfter(LocalDateTime.now()))
+                    {
+                        task.setStatus(1);
+                    }
+
+                    //判断客户/商机/销售订单跟联系人时候绑定
+                    if (task.getTaskType()!=null&&task.getTaskType()<3&&task.getContactsId()!=null){
+                        HttpRespMsg httpRespMsg = contactsService.getAllContacts(task.getBusinessOpportunityId(), task.getOrderId(), task.getCustomId(), request);
+                        List<Contacts> list = (List<Contacts>) httpRespMsg.getData();
+                        if (!list.isEmpty()){
+                            boolean present = list.stream().anyMatch(contacts -> contacts.getId().equals(task.getContactsId()));
+                            if (!present){
+                                String type="";
+                                //客户0, 商机1 ,订单2 ,
+                                if (task.getTaskType()==0){
+                                    type="客户";
+                                }else if (task.getTaskType()==1){
+                                    type="商机";
+                                }else {
+                                    type="订单";
+                                }
+                                msg.setError("存在"+type+"与联系人不一一对应:");
+                                return msg;
+                            }
+                        }
+                    }
+
                 }
                 if(saveOrUpdateBatch(importTaskList)){
                     ArrayList<TaskExecutor> taskExecutors = new ArrayList<>();
@@ -762,7 +866,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
         dataList.add(titleList);//设置表头
 
         taskDto.setCompanyId(user.getCompanyId());
-        taskDto.setPageIndex(null).setPageSize(null);//暂时部不分页
+        taskDto.setPageIndex(null).setPageSize(null);
         List<TasKVo> taskVoList =taskMapper.getPageListTask(taskDto);
         if (!taskVoList.isEmpty()){
             for (TasKVo tasKVo : taskVoList) {

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

@@ -245,7 +245,7 @@
     <select id="getDataSummary" resultType="java.util.Map">
         SELECT COUNT(*) newNum,SUM(bo.amount_of_money) AS allAmountOfMoney,SUM(s.name='赢单') winning,SUM(s.name='输单') losting  FROM business_opportunity bo
         LEFT JOIN stage s ON bo.stage_id=s.id
-        WHERE company_id=#{companyId} and is_delete=0
+        WHERE bo.company_id=#{companyId} and is_delete=0
         <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
             and DATE_FORMAT(bo.create_time,'%Y-%m-%d') BETWEEN #{startDate} AND #{endDate}
         </if>

+ 7 - 1
fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/ContactsMapper.xml

@@ -56,7 +56,7 @@
                 AND own.id =#{map.ownerId}
             </if>
             <if test="map.creatorId != null and map.creatorId != ''">
-                AND own.id =#{map.creatorId}
+                AND u.id =#{map.creatorId}
             </if>
             <if test="map.phone != null and map.phone != ''">
                 AND c.phone LIKE CONCAT('%', #{map.phone}, '%')
@@ -70,6 +70,12 @@
             <if test="map.companyId != null">
                 AND c.company_id=#{map.companyId}
             </if>
+            <if test="map.departmentId != null">
+                AND own.department_id=#{map.departmentId}
+            </if>
+            <if test="map.ownerIdByMyselfAndNull != null and map.ownerIdByMyselfAndNull != ''">
+                AND ( own.id=#{map.ownerIdByMyselfAndNull} or own.id is null )
+            </if>
         </where>
         order by create_time desc
 

+ 56 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/DepartmentMapper.xml

@@ -118,4 +118,60 @@
         GROUP BY b.project_id, a.department_id
         having IFNULL(SUM(b.custom_data),0) > 0
     </select>
+<!--    <select id="getCustomerTotalCount" resultType="com.management.platform.entity.vo.DepartmentVO">
+        select count(*) as customertotal ,
+        sum(case when c.close_deal=1 then 1 else 0 end) as customerDeal ,
+        u.department_id as id,d.department_name as departmentName
+        from custom c
+        left join user u on c.incharger_id=u.id
+        left join department d on d.department_id=u.department_id
+        <where>
+            1=1 AND u.department_id IS NOT NULL and c.company_id=#{companyId}
+
+            <if test="startDate !=null and startDate !='' and endDate !=null and endDate !=''">
+                AND  c.create_time BETWEEN #{startDate} AND #{endDate}
+            </if>
+            <if test="departmentId !=null ">
+                AND  u.department_id=#{departmentId}
+            </if>
+        </where>
+        group by u.department_id
+    </select>-->
+    <select id="getCustomerTotalCount" resultType="com.management.platform.entity.vo.DepartmentVO">
+        select count(*) as customertotal ,
+               sum(case when b.stage_id=15 then 1 else 0 end) as customerDeal,
+               u.department_id as id,d.department_name as departmentName
+        from business_opportunity b
+                 left join user u on b.incharger_id=u.id
+                 left join department d on d.department_id=u.department_id
+        <where>
+            1=1 AND u.department_id IS NOT NULL and b.company_id=#{companyId}
+
+            <if test="startDate !=null and startDate !='' and endDate !=null and endDate !=''">
+                AND  b.create_time BETWEEN #{startDate} AND #{endDate}
+            </if>
+            <if test="departmentId !=null ">
+                AND  u.department_id=#{departmentId}
+            </if>
+        </where>
+        group by u.department_id
+    </select>
+    <select id="getCustomerTransferRate" resultType="com.management.platform.entity.vo.DepartmentVO">
+        select count(distinct c.id) as num, count(distinct s.custom_id) as saleNum,
+            u.department_id as id,d.department_name as departmentName
+        from  custom c
+        left join sales_order s on c.id=s.custom_id
+        INNER JOIN user u on u.id=c.incharger_id
+        left join department d on d.department_id=u.department_id
+        <where>
+            1=1 AND u.department_id IS NOT NULL and c.company_id=#{companyId}
+            <if test="startDate !=null and startDate !='' and endDate !=null and endDate !=''">
+                AND  c.create_time BETWEEN #{startDate} AND #{endDate}
+            </if>
+            <if test="departmentId !=null ">
+                AND  u.department_id=#{departmentId}
+            </if>
+        </where>
+        group by  u.department_id
+    </select>
 </mapper>

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

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

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

@@ -32,11 +32,12 @@
         <result column="plate3" property="plate3" />
         <result column="plate4" property="plate4" />
         <result column="plate5" property="plate5" />
+        <result column="update_time" property="updateTime" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, company_id, order_name, order_code, custom_id, business_opportunity_id, price, contacts_id, type, place_time, order_start_date, order_end_date, received_payment, un_received_payment, received_status, custom_signer, company_signer, incharger_id, remark, create_time, creator_id, is_delete, status, plate1, plate2, plate3, plate4, plate5
+        id, company_id, order_name, order_code, custom_id, business_opportunity_id, price, contacts_id, type, place_time, order_start_date, order_end_date, received_payment, un_received_payment, received_status, custom_signer, company_signer, incharger_id, remark, create_time, creator_id, is_delete, status, plate1, plate2, plate3, plate4, plate5, update_time
     </sql>
 
 </mapper>

+ 37 - 8
fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/TaskMapper.xml

@@ -88,16 +88,16 @@
         <result column="order_name" property="orderName"/>
         <result column="clue_name" property="clueName"/>
         <result column="contacts_name" property="contactsName"/>
-        <result column="phone" property="contactsPhone"/>
+        <result column="contacts_phone" property="contactsPhone"/>
     </resultMap>
 
     <select id="getPageListTask" resultMap="TaskVoMap">
-        select task.* ,
+        select DISTINCT task.* ,
                custom.custom_name,
                business_opportunity.name businessName,
               `sales_order`.order_name ,
                clue.clue_name,
-               contacts.name contacts_name ,contacts.phone
+               contacts.name contacts_name ,contacts.phone contacts_phone
         from task
             left join  custom on task.custom_id=custom.id
             left join  business_opportunity on task.business_opportunity_id=business_opportunity.id
@@ -105,9 +105,14 @@
             left join  clue on task.clue_id=clue.id
             left join  contacts on task.contacts_id=contacts.id
             <if test=" executorName!= null and executorName != '' " >
-                inner join task_executor on task.id=task_executor.task_id
+                inner join task_executor te on task.id=te.task_id
+            </if>
+            <if test=" departmentId!= null " >
+            inner join task_executor on task.id=task_executor.task_id
+            </if>
+            <if test=" departmentIdByMyselfOrNull!= null and departmentIdByMyselfOrNull != '' " >
+            inner join task_executor on task.id=task_executor.task_id
             </if>
-
         <where>
             and 1=1 and task.is_delete=0
 
@@ -139,7 +144,7 @@
                 AND task.status = #{status}
             </if>
             <if test=" executorName!= null and executorName != '' ">
-                AND task_executor.executor_name LIKE CONCAT('%', #{executorName}, '%')
+                AND te.executor_name LIKE CONCAT('%', #{executorName}, '%')
             </if>
             <if test=" startDate!= null">
                 AND task.start_date &gt; #{startDate}
@@ -150,6 +155,15 @@
             <if test=" companyId!= null ">
                 AND task.company_id = #{companyId}
             </if>
+            <if test=" departmentId!= null " >
+                AND task_executor.task_id in ( SELECT DISTINCT te.task_id FROM task_executor te
+                LEFT JOIN `user` u ON u.id=te.executor_id
+                where u.department_id = #{departmentId} )
+            </if>
+            <if test=" departmentIdByMyselfOrNull!= null and departmentIdByMyselfOrNull != '' " >
+                AND task_executor.task_id in ( SELECT DISTINCT te.task_id FROM task_executor te
+                where te.executor_id= #{departmentIdByMyselfOrNull } or te.executor_id is null )
+            </if>
 
         </where>
         order by task.create_date desc
@@ -163,7 +177,7 @@
 
 
     <select id="getPageListTotalTask" resultMap="TaskVoMap">
-        select task.id
+        select DISTINCT task.id
         from task
         left join  custom on task.custom_id=custom.id
         left join  business_opportunity on task.business_opportunity_id=business_opportunity.id
@@ -171,6 +185,12 @@
         left join  clue on task.clue_id=clue.id
         left join  contacts on task.contacts_id=contacts.id
         <if test=" executorName!= null and executorName != '' " >
+            inner join task_executor te on task.id=te.task_id
+        </if>
+        <if test=" departmentId!= null " >
+            inner join task_executor on task.id=task_executor.task_id
+        </if>
+        <if test=" departmentIdByMyselfOrNull!= null and departmentIdByMyselfOrNull != '' " >
             inner join task_executor on task.id=task_executor.task_id
         </if>
 
@@ -206,7 +226,7 @@
                 AND task.status = #{status}
             </if>
             <if test=" executorName!= null and executorName != '' ">
-                AND task_executor.executor_name LIKE CONCAT('%', #{executorName}, '%')
+                AND te.executor_name LIKE CONCAT('%', #{executorName}, '%')
             </if>
             <if test=" startDate!= null  ">
                 AND task.start_date &gt; #{startDate}
@@ -217,6 +237,15 @@
             <if test=" companyId!= null ">
                 AND task.company_id = #{companyId}
             </if>
+            <if test=" departmentId!= null " >
+                AND  task_executor.task_id in ( SELECT DISTINCT te.task_id FROM task_executor te
+                LEFT JOIN `user` u ON u.id=te.executor_id
+                where u.department_id = #{departmentId} )
+            </if>
+            <if test=" departmentIdByMyselfOrNull!= null and departmentIdByMyselfOrNull != '' " >
+                AND task_executor.task_id in ( SELECT DISTINCT te.task_id FROM task_executor te
+                where te.executor_id= #{departmentIdByMyselfOrNull} or te.executor_id is null )
+            </if>
         </where>
     </select>
     <select id="getListByTaskIds" resultType="com.management.platform.entity.vo.TasKVo">

+ 23 - 3
fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/UserMapper.xml

@@ -277,7 +277,7 @@
         AND (induction_date &lt;= #{startDate} OR induction_date is NULL)
         AND id not IN (SELECT * from user_exclude)
     </select>
-    <select id="getCustomerTotalCount" resultType="com.management.platform.entity.vo.UserVO">
+   <!-- <select id="getCustomerTotalCount" resultType="com.management.platform.entity.vo.UserVO">
 
         select count(*) as customertotal ,
                sum(case when c.close_deal=1 then 1 else 0 end) as customerDeal ,
@@ -285,7 +285,7 @@
             from custom c
             left join user u on c.incharger_id=u.id
         <where>
-            1=1 and c.company_id=#{companyId}
+            1=1 and c.incharger_id is not null and c.company_id=#{companyId}
 
             <if test="startDate !=null and startDate !='' and endDate !=null and endDate !=''">
                 AND  c.create_time BETWEEN #{startDate} AND #{endDate}
@@ -293,17 +293,37 @@
             <if test="userId !=null and userId!=''">
                 AND  c.incharger_id=#{userId}
             </if>
+
         </where>
             group by c.incharger_id
 
+    </select>-->
+    <select id="getCustomerTotalCount" resultType="com.management.platform.entity.vo.UserVO">
+        SELECT count(*) customertotal ,
+        sum(case when b.stage_id=15 then 1 else 0 end) as customerDeal,
+        b.incharger_id id,u.name
+        from business_opportunity b
+        left join user u on b.incharger_id=u.id
+        <where>
+            1=1 and b.incharger_id is not null and b.company_id=#{companyId}
+
+            <if test="startDate !=null and startDate !='' and endDate !=null and endDate !=''">
+                AND  b.create_time BETWEEN #{startDate} AND #{endDate}
+            </if>
+            <if test="userId !=null and userId!=''">
+                AND  b.incharger_id=#{userId}
+            </if>
+        </where>
+        GROUP BY b.incharger_id
     </select>
+
     <select id="getCustomerTransferRate" resultType="com.management.platform.entity.vo.UserVO">
         select count(distinct c.id) as num, count(distinct s.custom_id) as saleNum, c.incharger_id as id  ,u.name
         from  custom c
                   left join sales_order s on c.id=s.custom_id
                   INNER JOIN user u on u.id=c.incharger_id
         <where>
-            1=1 and c.company_id=#{companyId}
+            1=1 and c.incharger_id is not null  and c.company_id=#{companyId}
             <if test="startDate !=null and startDate !='' and endDate !=null and endDate !=''">
                 AND  c.create_time BETWEEN #{startDate} AND #{endDate}
             </if>

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

@@ -1061,11 +1061,11 @@ public class ReportController {
                                     .setSubProjectId(subProjectId[i])
                                     .setGroupId(groupId[i])
                                     .setReportTimeType(reportTimeType[i])
-                                    .setMultiWorktime(multiWorktime[i])
-                                    .setContent(content[i])
+                                    .setMultiWorktime(multiWorktime.length > 0?multiWorktime[i]:0)
+                                    .setContent(content.length > 0?content[i]:"-")
                                     .setDegreeId(degreeId.length > 0?degreeId[i]:null)
                                     .setCustomData(customData[i])
-                                    .setStage(stage[i])
+                                    .setStage(stage != null && stage.length>0?stage[i]:"-")
 //                                    .setState(auditWorkflowList.size() == 0?1:0)//代填的如果没有自定义审核流程就直接审核通过了
                                     .setCompanyId(user.getCompanyId())
                                     .setPicAdd(pics!=null?pics[i]:null)

+ 42 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportLogController.java

@@ -3,8 +3,10 @@ package com.management.platform.controller;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.api.R;
 import com.management.platform.entity.*;
 import com.management.platform.mapper.*;
+import com.management.platform.service.ReportLogDetailService;
 import com.management.platform.service.ReportLogService;
 import com.management.platform.service.ReportService;
 import com.management.platform.util.ExcelUtil;
@@ -66,6 +68,8 @@ public class ReportLogController {
     private String path;
     @Resource
     private ReportService reportService;
+    @Resource
+    private ReportLogDetailService reportLogDetailService;
 
     @RequestMapping("/get")
     public HttpRespMsg get(String creatorId, String createDate) {
@@ -233,6 +237,7 @@ public class ReportLogController {
             StringBuilder sb=new StringBuilder();
             List<Report> needUpdateReportList=new ArrayList<>();
             List<ReportLog> needUpdateReportLogList=new ArrayList<>();
+            List<ReportLogDetail> needUpdateReportLogDetailList=new ArrayList<>();
             for (int rowIndex = 0; rowIndex <= rowNum; rowIndex++) {
                 XSSFRow row = sheet.getRow(rowIndex);
                 if (row == null) {
@@ -293,13 +298,24 @@ public class ReportLogController {
                             msg.setError("第"+row+"行审核时间格式错误,请检查审核时间数据");
                             return msg;
                         }
-                        reportLog.setOperateDate(auditDateTime);
-                        needUpdateReportLogList.add(reportLog);
+                        String creatorId = reports.get(0).getCreatorId();
+                        if(reportLog.getMsg().contains("审核通过了")){
+                            reportLog.setOperateDate(auditDateTime);
+                            needUpdateReportLogList.add(reportLog);
+                        }
                         LocalDateTime finalAuditDateTime = auditDateTime;
-                        LocalDateTime finalCreateTimeTime = createTimeTime;
                         reports.forEach(r->{
                             r.setProjectAuditTime(finalAuditDateTime);
                         });
+                        List<Integer> details = reports.stream().map(Report::getId).distinct().collect(Collectors.toList());
+                        List<ReportLogDetail> reportLogDetails = reportLogDetailService.list(new LambdaQueryWrapper<ReportLogDetail>().in(ReportLogDetail::getReportId, details));
+                        reportLogDetails.forEach(r->{
+//                            if(r.getMsg()!=null&&r.getMsg().contains("审核通过了")&&!r.getOperatorId().equals(creatorId)){
+                            if(r.getMsg()!=null&&r.getMsg().contains("审核通过了")){
+                                r.setOperateDate(finalAuditDateTime);
+                                needUpdateReportLogDetailList.add(r);
+                            }
+                        });
                         needUpdateReportList.addAll(reports);
                     }
                     if(createTimeCellValue!=null&&!StringUtils.isEmpty(createTimeCellValue)){
@@ -309,10 +325,30 @@ public class ReportLogController {
                             msg.setError("第"+row+"行填报时间格式错误,请检查审核时间数据");
                             return msg;
                         }
+                        String creatorId = reports.get(0).getCreatorId();
+                        Integer id = reports.get(0).getId();
+                        List<ReportLog> list = reportLogService.list(new LambdaQueryWrapper<ReportLog>().apply("FIND_IN_SET(" + id + ",report_ids)"));
+                        List<ReportLog> reportLogs = list.stream().filter(l -> l.getMsg().contains("提交了")).collect(Collectors.toList());
+                        LocalDateTime finalCreateTimeTime1 = createTimeTime;
+                        reportLogs.forEach(r->{
+                            if(creatorId.equals(r.getOperatorId())){
+                                r.setOperateDate(finalCreateTimeTime1);
+                                needUpdateReportLogList.add(r);
+                            }
+                        });
                         LocalDateTime finalCreateTimeTime = createTimeTime;
                         reports.forEach(r->{
                             r.setCreateTime(finalCreateTimeTime);
                         });
+                        List<Integer> details = reports.stream().map(Report::getId).distinct().collect(Collectors.toList());
+                        List<ReportLogDetail> reportLogDetails = reportLogDetailService.list(new LambdaQueryWrapper<ReportLogDetail>().in(ReportLogDetail::getReportId, details));
+                        reportLogDetails.forEach(r->{
+//                            if(r.getMsg()!=null&&r.getMsg().contains("提交了")&&r.getOperatorId().equals(creatorId)){
+                            if(r.getMsg()!=null&&r.getMsg().contains("提交了")){
+                                r.setOperateDate(finalCreateTimeTime1);
+                                needUpdateReportLogDetailList.add(r);
+                            }
+                        });
                         needUpdateReportList.addAll(reports);
                     }
                 }else {
@@ -329,6 +365,9 @@ public class ReportLogController {
             if(needUpdateReportLogList.size()>0){
                 reportLogService.updateBatchById(needUpdateReportLogList);
             }
+            if(needUpdateReportLogDetailList.size()>0){
+                reportLogDetailService.updateBatchById(needUpdateReportLogDetailList);
+            }
             if(sb.length()>0){
                 msg.setMsg("更新完成,其中编号["+sb.toString()+"]的填报数据不存在");
             }else {

+ 7 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeType.java

@@ -17,7 +17,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2024-06-06
+ * @since 2024-06-22
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -584,6 +584,12 @@ public class TimeType extends Model<TimeType> {
     @TableField("alert_check_msg")
     private String alertCheckMsg;
 
+    /**
+     * 导入的日报,按照正常审批来处理,非单独设置的部门直属领导审核
+     */
+    @TableField("import_report_audit_normal")
+    private Integer importReportAuditNormal;
+
 
     @TableField(exist = false)
     private List<User> userList;
@@ -592,7 +598,6 @@ public class TimeType extends Model<TimeType> {
     @TableField(exist = false)
     private Integer saasSyncContact;
 
-
     @Override
     protected Serializable pkVal() {
         return this.companyId;

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ReportMapper.java

@@ -57,7 +57,7 @@ public interface ReportMapper extends BaseMapper<Report> {
     List<HashMap<String, Object>> getDeptMembReportByDate(@Param("startDate") String startDate,
                                                              @Param("companyId") Integer companyId,
                                                              @Param("deptIds") List<Integer> deptIds,
-                                                             @Param("endDate") String endDate, @Param("projectId") Integer projectId,@Param("stateKey")Integer stateKey,@Param("branchDepartment")List<Integer> branchDepartment);
+                                                             @Param("endDate") String endDate, @Param("projectId") Integer projectId,@Param("stateKey")Integer stateKey,@Param("branchDepartment")List<Integer> branchDepartment, @Param("viewUserId")String viewUserId);
 
 
     //获取项目经理所管理的人员的报告

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

@@ -13277,8 +13277,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         //需要统计的部门
         List<Integer> targetDeptIds=new ArrayList<>();
         targetDeptIds.add(7458);
-        targetDeptIds.add(7459);
-        targetDeptIds.add(7460);
+        targetDeptIds.add(8696);
+        targetDeptIds.add(8695);
         //需要统计的分组名称
         List<String> targetGroupNameList=new ArrayList<>();
         targetGroupNameList.add("生产部电气");
@@ -13309,8 +13309,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         if(user.getCompanyId()==3092){
             List<String> nameString=new ArrayList<>();
             nameString.add("4");
-            nameString.add("12");
-            nameString.add("14");
+            nameString.add("46");
+            nameString.add("45");
             List<Department> departmentList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, user.getCompanyId()).in(Department::getDepartmentName, nameString));
             List<Integer> theCollect = departmentList.stream().map(dm -> dm.getDepartmentId()).distinct().collect(Collectors.toList());
             theCollect.add(-1);
@@ -13351,7 +13351,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                 String departmentName = department.get().getDepartmentName();
                 List<Integer> subDeptIds;
                 switch (deptId){
-                    case 7459:
+                    case 8696:
                         //获取此部门下的子部门id列表
                         subDeptIds = getBranchDepartment(deptId, allDeptList);
                         groupNames=new ArrayList<>();
@@ -13406,7 +13406,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                             itemList.add(item);
                         }
                         break;
-                    case 7460:
+                    case 8695:
                         //获取此部门下的子部门id列表
                         subDeptIds = getBranchDepartment(deptId, allDeptList);
                         groupNames=new ArrayList<>();

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

@@ -1894,15 +1894,16 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                                     item.put("key","审核人");
                                     item.put("value",wxCorpInfo.getSaasSyncContact() == 1?("$userName="+user.getName()+"$"): user.getName());
                                     dataJson.add(item);
-                                    if(timeType.getNeedEvaluate()==1){
-                                        JSONObject item1=new JSONObject();
-                                        item1.put("key","评价");
-                                        item1.put("value",StringUtils.isEmpty(report.getEvaluate())?"":report.getEvaluate());
-                                        dataJson.add(item1);
-                                        json.put("template_id","tty9TkCAAAWoUyhGnXRCZuhkgCqw_Uow");
-                                    }else {
-                                        json.put("template_id","tty9TkCAAANpvEtLrkPUGeOEd1-U7W2w");
-                                    }
+//                                    if(timeType.getNeedEvaluate()==1){
+//                                        JSONObject item1=new JSONObject();
+//                                        item1.put("key","评价");
+//                                        item1.put("value",StringUtils.isEmpty(report.getEvaluate())?"":report.getEvaluate());
+//                                        dataJson.add(item1);
+//                                        json.put("template_id","tty9TkCAAAWoUyhGnXRCZuhkgCqw_Uow");
+//                                    }else {
+//                                        json.put("template_id","tty9TkCAAANpvEtLrkPUGeOEd1-U7W2w");
+//                                    }
+                                    json.put("template_id","tty9TkCAAANpvEtLrkPUGeOEd1-U7W2w");
                                     JSONObject item2=new JSONObject();
                                     item2.put("key","日期");
                                     item2.put("value",report.getCreateDate());
@@ -2447,15 +2448,16 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                                     item.put("key","审核人");
                                     item.put("value",user.getName());
                                     dataJson.add(item);
-                                    if(timeType.getNeedEvaluate()==1){
-                                        JSONObject item1=new JSONObject();
-                                        item1.put("key","评价");
-                                        item1.put("value",StringUtils.isEmpty(report.getEvaluate())?"":report.getEvaluate());
-                                        dataJson.add(item1);
-                                        json.put("template_id","tty9TkCAAAWoUyhGnXRCZuhkgCqw_Uow");
-                                    }else {
-                                        json.put("template_id","tty9TkCAAANpvEtLrkPUGeOEd1-U7W2w");
-                                    }
+//                                    if(timeType.getNeedEvaluate()==1){
+//                                        JSONObject item1=new JSONObject();
+//                                        item1.put("key","评价");
+//                                        item1.put("value",StringUtils.isEmpty(report.getEvaluate())?"":report.getEvaluate());
+//                                        dataJson.add(item1);
+//                                        json.put("template_id","tty9TkCAAAWoUyhGnXRCZuhkgCqw_Uow");
+//                                    }else {
+//                                        json.put("template_id","tty9TkCAAANpvEtLrkPUGeOEd1-U7W2w");
+//                                    }
+                                    json.put("template_id","tty9TkCAAANpvEtLrkPUGeOEd1-U7W2w");
                                     JSONObject item2=new JSONObject();
                                     item2.put("key","日期");
                                     item2.put("value",report.getCreateDate());
@@ -3777,15 +3779,16 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                                     item.put("key","审核人");
                                     item.put("value",user.getName());
                                     dataJson.add(item);
-                                    if(timeType.getNeedEvaluate()==1){
-                                        JSONObject item1=new JSONObject();
-                                        item1.put("key","评价");
-                                        item1.put("value",StringUtils.isEmpty(report.getEvaluate())?"":report.getEvaluate());
-                                        dataJson.add(item1);
-                                        json.put("template_id","tty9TkCAAAWoUyhGnXRCZuhkgCqw_Uow");
-                                    }else {
-                                        json.put("template_id","tty9TkCAAANpvEtLrkPUGeOEd1-U7W2w");
-                                    }
+//                                    if(timeType.getNeedEvaluate()==1){
+//                                        JSONObject item1=new JSONObject();
+//                                        item1.put("key","评价");
+//                                        item1.put("value",StringUtils.isEmpty(report.getEvaluate())?"":report.getEvaluate());
+//                                        dataJson.add(item1);
+//                                        json.put("template_id","tty9TkCAAAWoUyhGnXRCZuhkgCqw_Uow");
+//                                    }else {
+//
+//                                    }
+                                    json.put("template_id","tty9TkCAAANpvEtLrkPUGeOEd1-U7W2w");
                                     JSONObject item2=new JSONObject();
                                     item2.put("key","日期");
                                     item2.put("value",report.getCreateDate());
@@ -5298,13 +5301,33 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                             report.setWorkingTime(time);
                             report.setContent(workContent);
                             report.setMultiWorktime(timeType.getMultiWorktime());
-                            report.setFillUserid(user.getId());
-                            if (timeType.getNeedDeptAudit() == 0) {
-                                report.setState(1);//导入的直接算审核通过
+//                            report.setFillUserid(user.getId());  导入时,处理为自己填写的
+                            if (timeType.getImportReportAuditNormal() == 0) {
+                                //老的导入日报审核模式
+                                if (timeType.getNeedDeptAudit() == 0) {
+                                    report.setState(1);//导入的直接算审核通过
+                                } else {
+                                    report.setState(-1);//待部门上级审核员审核
+                                    report.setDepartmentAuditState(1);//部门已审核,到上层领导审核
+                                }
                             } else {
-                                report.setState(-1);//待部门上级审核员审核
-                                report.setDepartmentAuditState(1);//部门已审核,到上层领导审核
+                                report.setState(0);//待审核
+                                //目前仅支持项目审核人审核的模式,叠加审批流
+                                if (timeType.getReportAuditType() == 0) {
+                                    //设置日报审核人
+                                    List<ProjectAuditor> projectAuditors = projectAuditorMapper.selectList(new QueryWrapper<ProjectAuditor>().eq("project_id", project.getId()));
+                                    if (projectAuditors.size() > 0) {
+                                        report.setProjectAuditorId(projectAuditors.get(0).getAuditorId());
+                                    }
+
+                                    List<AuditWorkflowTimeSetting> auditWorkflowList
+                                            = auditWorkflowTimeSettingMapper.selectList(
+                                            new QueryWrapper<AuditWorkflowTimeSetting>().eq("dept_id", reportCreator.getDepartmentId()).orderByAsc("seq"));
+                                    List<Department> allDeptList = departmentMapper.selectList(new QueryWrapper<Department>().eq("company_id", reportCreator.getCompanyId()));
+                                    setReportWorkflowAuditor(auditWorkflowList, allDeptList, report,timeType);
+                                }
                             }
+
                             report.setCreateDate(LocalDate.parse(reportDate, dtf));
                             report.setCost(reportCreator.getCost()==null?new BigDecimal(0) : reportCreator.getCost().multiply(new BigDecimal(time)));
                             reportList.add(report);
@@ -5317,9 +5340,15 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             }
 
             if (reportList.size() > 0) {
+                int shouldSkipPassData = 0;
+                if (timeType.getImportReportAuditNormal() == 1) {
+                    shouldSkipPassData = 1;
+                } else {
+                    shouldSkipPassData = timeType.getNeedDeptAudit();
+                }
                 //依赖于对是否需要部门审核的判断,如果不需要则认为导入的就是审核通过的,重新导入就直接覆盖之前的。
-                reportMapper.deleteUserSameDayReport(companyId, reportList, timeType.getNeedDeptAudit());
-                if (timeType.getNeedDeptAudit() == 1) {
+                reportMapper.deleteUserSameDayReport(companyId, reportList, shouldSkipPassData);
+                if (shouldSkipPassData == 1) {
                     //如果需要导入审核,则对审核通过的进行排除
                     List<Map> passReports = reportMapper.getSameDayPassReport(companyId, reportList);
                     StringBuilder sb = new StringBuilder();
@@ -5354,7 +5383,11 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     msg.setError(MessageUtils.message("finance.importErrorByAllAdopt"));
                     return msg;
                 } else {
+                    //如果开启了审批流的显示,需要插入日报提交记录表
                     reportService.saveBatch(reportList);
+                    if (timeType.getShowFillauditTime() == 1) {
+                        saveFillReportLog(reportList);
+                    }
                     msg.data = dataCount;
                     String originName = fileName;
                     //定义一个独立的文件夹
@@ -5421,7 +5454,39 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
         return msg;
     }
 
-
+    private void setReportWorkflowAuditor(List<AuditWorkflowTimeSetting> auditWorkflowList, List<Department> allDeptList, Report report, TimeType comTimeType) {
+        if (auditWorkflowList.size() == 0) {
+            //没有自定义审核流,默认的直接是项目负责人审核
+            report.setIsDeptAudit(0);
+            report.setIsFinalAudit(1);
+        } else {
+            //取第一个审核节点
+            AuditWorkflowTimeSetting firstNode = auditWorkflowList.get(0);
+            report.setIsFinalAudit(auditWorkflowList.size() > 1?0:1);
+            report.setIsDeptAudit(firstNode.getIsDeptAudit());
+            report.setAuditDeptid(firstNode.getAuditDeptId());
+            if (firstNode.getIsDeptAudit() == 1) {
+                Department curDept = allDeptList.stream()
+                        .filter(ad->ad.getDepartmentId().equals(firstNode.getAuditDeptId())).findFirst().get();
+                String curDeptManagerId = curDept.getManagerId();
+                //启用了本部门负责人的日报由上级部门主要负责人审核
+                if (comTimeType.getReportAuditFlowEnableSuperDeptAduit() == 1 && curDeptManagerId.equals(report.getCreatorId())) {
+                    //当前提交的人是这个部门的主要负责人,那么要取该部门的上一级部门的主要负责人来审核
+                    Integer parentDeptId = curDept.getSuperiorId();
+                    if (parentDeptId == null) {
+                        //没有上级部门,直接取当前部门的负责人
+                        report.setAuditDeptManagerid(curDeptManagerId);
+                    } else {
+//                        report.setAuditDeptid(parentDeptId);
+                        report.setAuditDeptManagerid(allDeptList.stream()
+                                .filter(ad->ad.getDepartmentId().equals(parentDeptId)).findFirst().get().getManagerId());
+                    }
+                } else {
+                    report.setAuditDeptManagerid(curDeptManagerId);
+                }
+            }
+        }
+    }
     private void fillDeptUser(List<DepartmentVO> list, List<HashMap> userList) {
         list.forEach(l->{
             List<HashMap> collect = userList.stream().filter(u -> u.get("departmentId").equals(l.getId())).collect(Collectors.toList());
@@ -5582,7 +5647,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 //检查是否是部门负责人
                 List<Integer> allVisibleDeptIdList = getAllVisibleDeptIdList(user, null);
                 if (allVisibleDeptIdList.size() > 0) {
-                    allReportByDate = reportMapper.getDeptMembReportByDate(startDate, null, allVisibleDeptIdList, endDate, projectId,stateKey,branchDepartment);
+                    allReportByDate = reportMapper.getDeptMembReportByDate(startDate, null, allVisibleDeptIdList, endDate, projectId,stateKey,branchDepartment, user.getId());
                 }
 
                 List<HashMap<String, Object>> reportsFromProjects = null;
@@ -5622,6 +5687,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                         allReportByDate.addAll(filteredReports);
                     }
                 }
+
             }
             else {
                 //看公司所有人的

+ 104 - 72
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java

@@ -954,39 +954,48 @@ public class TimingTask {
             //判断日报审核类型
             timeTypeList.stream().filter(timeType -> timeType.getCompanyId().equals(companyId)).findFirst().ifPresent(timeType -> {
                 if (timeType.getReportAuditType() == 7) {//并行审核模式
-                    List<User> userList = userMapper.selectList(new QueryWrapper<User>().select("id,dingding_userid", "corpwx_userid").eq("company_id", companyId));
-                    List<Report> reportList = reportMapper.selectList(new QueryWrapper<Report>().select("id, project_auditor_id, audit_dept_managerid,project_audit_state,department_audit_state").eq("company_id", companyId).eq("state", 0));
-                    HashMap<String, Long> auditorMap = new HashMap();
-                    for (Report report : reportList) {
-                        //按审核人汇总统计
-                        String pAuditorId = null;
-                        if (report.getProjectAuditState() == 0) {
-                            pAuditorId = report.getProjectAuditorId();
-                            if (auditorMap.get(pAuditorId) == null) {
-                                auditorMap.put(pAuditorId, 1L);
-                            } else {
-                                auditorMap.put(pAuditorId, auditorMap.get(pAuditorId) + 1);
-                            }
+                    boolean shouldAlert = true;
+                    if (timeType.getAlertType() == 4) {
+                        //每周提醒一次,校验日期是否正确
+                        if (LocalDate.now().getDayOfWeek().getValue() != timeType.getAlertCheckDay()) {
+                            shouldAlert = false;
                         }
-                        String deptAuditorId = null;
-                        if (report.getDepartmentAuditState() == 0) {
-                            deptAuditorId = report.getAuditDeptManagerid();
-                            if (deptAuditorId != null &&!deptAuditorId.equals(pAuditorId)) {
-                                //不是同一个人,需要单独统计
-                                if (auditorMap.get(deptAuditorId) == null) {
-                                    auditorMap.put(deptAuditorId, 1L);
+                    }
+                    if (shouldAlert) {
+                        List<User> userList = userMapper.selectList(new QueryWrapper<User>().select("id,dingding_userid", "corpwx_userid").eq("company_id", companyId));
+                        List<Report> reportList = reportMapper.selectList(new QueryWrapper<Report>().select("id, project_auditor_id, audit_dept_managerid,project_audit_state,department_audit_state").eq("company_id", companyId).eq("state", 0));
+                        HashMap<String, Long> auditorMap = new HashMap();
+                        for (Report report : reportList) {
+                            //按审核人汇总统计
+                            String pAuditorId = null;
+                            if (report.getProjectAuditState() == 0) {
+                                pAuditorId = report.getProjectAuditorId();
+                                if (auditorMap.get(pAuditorId) == null) {
+                                    auditorMap.put(pAuditorId, 1L);
                                 } else {
-                                    auditorMap.put(deptAuditorId, auditorMap.get(deptAuditorId) + 1);
+                                    auditorMap.put(pAuditorId, auditorMap.get(pAuditorId) + 1);
+                                }
+                            }
+                            String deptAuditorId = null;
+                            if (report.getDepartmentAuditState() == 0) {
+                                deptAuditorId = report.getAuditDeptManagerid();
+                                if (deptAuditorId != null &&!deptAuditorId.equals(pAuditorId)) {
+                                    //不是同一个人,需要单独统计
+                                    if (auditorMap.get(deptAuditorId) == null) {
+                                        auditorMap.put(deptAuditorId, 1L);
+                                    } else {
+                                        auditorMap.put(deptAuditorId, auditorMap.get(deptAuditorId) + 1);
+                                    }
                                 }
                             }
                         }
-                    }
-                    for (Map.Entry<String, Long> entry : auditorMap.entrySet()) {
-                        String auditorId = entry.getKey();
-                        Long num = entry.getValue();
-                        Optional<User> first = userList.stream().filter(ul -> ul.getId().equals(auditorId)).findFirst();
-                        if (first.isPresent()) {
-                            companyDingdingService.sendReportWaitingApplyMsg(companyId, companyDingding.getAgentId(), num, first.get().getDingdingUserid());
+                        for (Map.Entry<String, Long> entry : auditorMap.entrySet()) {
+                            String auditorId = entry.getKey();
+                            Long num = entry.getValue();
+                            Optional<User> first = userList.stream().filter(ul -> ul.getId().equals(auditorId)).findFirst();
+                            if (first.isPresent()) {
+                                companyDingdingService.sendReportWaitingApplyMsg(companyId, companyDingding.getAgentId(), num, first.get().getDingdingUserid());
+                            }
                         }
                     }
                 } else {
@@ -1026,60 +1035,83 @@ public class TimingTask {
                 }
                 //判断日报审核类型
                 timeTypeList.stream().filter(timeType -> timeType.getCompanyId().equals(companyId)).findFirst().ifPresent(timeType -> {
+                    //校验审核的日期,是否是每周提醒;目前仅景昱采用了这个模式审核,他们需要设置每周几审核
                     if (timeType.getReportAuditType() == 7) {//并行审核模式
-                        List<User> userList = userMapper.selectList(new QueryWrapper<User>().select("id,dingding_userid", "corpwx_userid").eq("company_id", companyId));
-                        List<Report> reportList = reportMapper.selectList(new QueryWrapper<Report>().select("id, project_auditor_id, audit_dept_managerid,project_audit_state,department_audit_state").eq("company_id", companyId).eq("state", 0));
-                        HashMap<String, Long> auditorMap = new HashMap();
-                        for (Report report : reportList) {
-                            //按审核人汇总统计
-                            String pAuditorId = null;
-                            if (report.getProjectAuditState() == 0) {
-                                pAuditorId = report.getProjectAuditorId();
-                                if (auditorMap.get(pAuditorId) == null) {
-                                    auditorMap.put(pAuditorId, 1L);
-                                } else {
-                                    auditorMap.put(pAuditorId, auditorMap.get(pAuditorId) + 1);
-                                }
+                        boolean shouldAlert = true;
+                        if (timeType.getAlertType() == 4) {
+                            //每周提醒一次,校验日期是否正确
+                            if (LocalDate.now().getDayOfWeek().getValue() != timeType.getAlertCheckDay()) {
+                                shouldAlert = false;
                             }
-                            String deptAuditorId = null;
-                            if (report.getDepartmentAuditState() == 0) {
-                                deptAuditorId = report.getAuditDeptManagerid();
-                                if (!deptAuditorId.equals(pAuditorId)) {
-                                    //不是同一个人,需要单独统计
-                                    if (auditorMap.get(deptAuditorId) == null) {
-                                        auditorMap.put(deptAuditorId, 1L);
+                        }
+                        if (shouldAlert) {
+                            List<User> userList = userMapper.selectList(new QueryWrapper<User>().select("id,dingding_userid", "corpwx_userid").eq("company_id", companyId));
+                            List<Report> reportList = reportMapper.selectList(new QueryWrapper<Report>().select("id, project_auditor_id, audit_dept_managerid,project_audit_state,department_audit_state").eq("company_id", companyId).eq("state", 0));
+                            HashMap<String, Long> auditorMap = new HashMap();
+                            for (Report report : reportList) {
+                                //按审核人汇总统计
+                                String pAuditorId = null;
+                                if (report.getProjectAuditState() == 0) {
+                                    pAuditorId = report.getProjectAuditorId();
+                                    if (auditorMap.get(pAuditorId) == null) {
+                                        auditorMap.put(pAuditorId, 1L);
                                     } else {
-                                        auditorMap.put(deptAuditorId, auditorMap.get(deptAuditorId) + 1);
+                                        auditorMap.put(pAuditorId, auditorMap.get(pAuditorId) + 1);
                                     }
                                 }
-                            }
-                        }
-                        for (Map.Entry<String, Long> entry : auditorMap.entrySet()) {
-                            String auditorId = entry.getKey();
-                            Long num = entry.getValue();
-                            Optional<User> first = userList.stream().filter(ul -> ul.getId().equals(auditorId)).findFirst();
-                            if (first.isPresent()) {
-                                if (first.get().getCorpwxUserid() != null) {
-                                    String corpwxUserid = first.get().getCorpwxUserid();
-                                    //推送到企业微信
-                                    JSONObject json=new JSONObject();
-                                    JSONArray dataJson=new JSONArray();
-                                    JSONObject jsonObj=new JSONObject();
-                                    jsonObj.put("key", "待审核数量");
-                                    jsonObj.put("value",num+"");
-                                    dataJson.add(jsonObj);
-                                    if(isPrivateDeploy){
-                                        json.put("content","待审核数量: "+num+"\\n<a href=\\\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=ww4e237fd6abb635af&redirect_uri="+pcUrl+"/api/corpWXAuth&response_type=code&scope=snsapi_base&state=0#wechat_redirect\\\">去审核</a>");
-                                    }else {
-                                        json.put("template_id","tty9TkCAAAuPvPjabDdQXGocnG0K24EQ");
-                                        json.put("url","https://open.weixin.qq.com/connect/oauth2/authorize?appid=ww4e237fd6abb635af&redirect_uri=http://worktime.ttkuaiban.com/api/corpWXAuth&response_type=code&scope=snsapi_base&state=review#wechat_redirect");
-                                        json.put("content_item",dataJson);
+                                String deptAuditorId = null;
+                                if (report.getDepartmentAuditState() == 0) {
+                                    deptAuditorId = report.getAuditDeptManagerid();
+                                    if (!deptAuditorId.equals(pAuditorId)) {
+                                        //不是同一个人,需要单独统计
+                                        if (auditorMap.get(deptAuditorId) == null) {
+                                            auditorMap.put(deptAuditorId, 1L);
+                                        } else {
+                                            auditorMap.put(deptAuditorId, auditorMap.get(deptAuditorId) + 1);
+                                        }
                                     }
+                                }
+                            }
+                            for (Map.Entry<String, Long> entry : auditorMap.entrySet()) {
+                                String auditorId = entry.getKey();
+                                Long num = entry.getValue();
+                                Optional<User> first = userList.stream().filter(ul -> ul.getId().equals(auditorId)).findFirst();
+                                if (first.isPresent()) {
+                                    if (first.get().getCorpwxUserid() != null) {
+                                        String corpwxUserid = first.get().getCorpwxUserid();
+                                        //推送到企业微信
+                                        JSONObject json=new JSONObject();
+                                        JSONArray dataJson=new JSONArray();
+                                        JSONObject jsonObj=new JSONObject();
+                                        if (timeType.getAlertType() == 4) {
+                                            jsonObj.put("key", "提示");
+                                            String msgContent = timeType.getAlertCheckMsg();
+                                            if (StringUtils.isEmpty(msgContent)) {
+                                                msgContent = "待审核数量:"+num;
+                                            } else {
+                                                msgContent = msgContent.replace("{0}", ""+num);
+                                            }
+                                            jsonObj.put("value",msgContent);
+                                        } else {
+                                            jsonObj.put("key", "待审核数量");
+                                            jsonObj.put("value",num+"");
+                                        }
+                                        dataJson.add(jsonObj);
+                                        if(isPrivateDeploy){
+                                            json.put("content","待审核数量: "+num+"\\n<a href=\\\"https://open.weixin.qq.com/connect/oauth2/authorize?appid=ww4e237fd6abb635af&redirect_uri="+pcUrl+"/api/corpWXAuth&response_type=code&scope=snsapi_base&state=0#wechat_redirect\\\">去审核</a>");
+                                        }else {
+                                            String templateId = timeType.getAlertType() == 4 ? "tty9TkCAAAtDDCqY796mGulF9c5Jmwng":"tty9TkCAAAuPvPjabDdQXGocnG0K24EQ";
+                                            json.put("template_id",templateId);
+                                            json.put("url","https://open.weixin.qq.com/connect/oauth2/authorize?appid=ww4e237fd6abb635af&redirect_uri=http://worktime.ttkuaiban.com/api/corpWXAuth&response_type=code&scope=snsapi_base&state=review#wechat_redirect");
+                                            json.put("content_item",dataJson);
+                                        }
 //                                    System.out.println("发送企业微信消息==用户:"+first.get().getId()+", name="+first.get().getName()+", "+json.toJSONString());
-                                    wxCorpInfoService.sendWXCorpTemplateMsg(wxCorpInfo, corpwxUserid, json);
+                                        wxCorpInfoService.sendWXCorpTemplateMsg(wxCorpInfo, corpwxUserid, json);
+                                    }
                                 }
                             }
                         }
+
                     } else {
                         List<Map<String, Object>> result = reportMapper.getProWaitingApproveCnt(wxCorpInfo.getCompanyId());
                         List<Map<String, Object>> result1 = reportMapper.getDeptWaitingApproveCnt(wxCorpInfo.getCompanyId());

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

@@ -1690,24 +1690,18 @@
     </select>
 
     <select id="selectNearProject" resultType="com.management.platform.entity.Project">
-        select * from project
-        where status = 1 and id in (
+        SELECT * FROM project
+        WHERE STATUS = 1 AND id IN (
             SELECT project_id
-            from (
-                     SELECT project_id
-                     FROM (
-                              SELECT DISTINCT *
-                              FROM report
-                              WHERE creator_id = #{userId}
-                              order by create_time
-                                      DESC
-                          ) p1
+            FROM (
+                     SELECT DISTINCT report.project_id
+                     FROM report
+                     WHERE creator_id = #{userId}
                      GROUP BY project_id
-                     order by create_time
-                             DESC
-                         LIMIT 3
+                     ORDER BY MAX(create_time)
+                             DESC LIMIT 3
                  ) p2
-        )
+        ) AND id IN(SELECT project_id FROM participation WHERE user_id=#{userId})
     </select>
 
     <select id="getFTEData" resultType="java.util.Map">

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

@@ -385,10 +385,11 @@
             </foreach>
         </if>
         <if test="deptIds != null">
-            AND c.department_id in
+            AND (c.department_id in
             <foreach collection="deptIds" item="deptId" separator="," close=")" open="(" index="index">
                 #{deptId}
             </foreach>
+        or a.creator_id=#{viewUserId})
         </if>
         ORDER BY a.creator_id, a.create_date desc
     </select>

File diff suppressed because it is too large
+ 2 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TimeTypeMapper.xml


+ 13 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/PlanController.java

@@ -171,5 +171,18 @@ public class PlanController {
     public HttpRespMsg deletePlan(Integer id){
         return planService.deletePlan(id);
     }
+
+
+    /**
+    * @Description:拒收导致的数据丢失修复
+    * @Param: []
+    * @return: com.management.platform.util.HttpRespMsg
+    * @Author: yurk
+    * @Date: 2024/6/20
+    */
+    @RequestMapping("/updateHasDeleteTeamData")
+    public HttpRespMsg updateHasDeleteTeamData(){
+        return reportService.updateHasDeleteTeamData();
+    }
 }
 

+ 13 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/ProdProcedureController.java

@@ -85,5 +85,18 @@ public class ProdProcedureController {
     public HttpRespMsg updateData(){
         return prodProcedureService.updateData();
     }
+
+
+    /**
+    * @Description:供恢复南京雷啊伟数据
+    * @Param: []
+    * @return: com.management.platform.util.HttpRespMsg
+    * @Author: yurk
+    * @Date: 2024/6/18
+    */
+    @RequestMapping("/updateHistoryData")
+    public HttpRespMsg updateHistoryData(){
+        return prodProcedureService.updateHistoryData();
+    }
 }
 

+ 25 - 2
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/ProductController.java

@@ -1,6 +1,7 @@
 package com.management.platform.controller;
 
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.management.platform.entity.Product;
 import com.management.platform.mapper.UserMapper;
 import com.management.platform.service.PlanService;
@@ -15,6 +16,11 @@ import org.springframework.web.multipart.MultipartFile;
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import javax.validation.Valid;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -38,8 +44,8 @@ public class ProductController {
     PlanService planService;
 
     @RequestMapping("/getProductPage")
-    public HttpRespMsg getProductPage(Integer cateId, @RequestParam Integer pageIndex, @RequestParam Integer pageSize, String name, String code,@RequestParam(defaultValue = "0")Integer status) {
-        return productService.getProductPage(cateId, pageIndex, pageSize, name, code,status, request);
+    public HttpRespMsg getProductPage(Integer cateId, @RequestParam Integer pageIndex, @RequestParam Integer pageSize, String name, String code,@RequestParam(defaultValue = "0")Integer status,String projectName) {
+        return productService.getProductPage(cateId, pageIndex, pageSize, name, code,status,projectName, request);
     }
 
     @RequestMapping("/saveProductInfo")
@@ -109,5 +115,22 @@ public class ProductController {
         }
         return msg;
     }
+
+    @RequestMapping("/getProductProjectNames")
+    public HttpRespMsg getProductProjectNames(String value){
+        HttpRespMsg msg=new HttpRespMsg();
+        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        List<Product> list = productService.list(new LambdaQueryWrapper<Product>().like(Product::getProjectName, value).eq(Product::getCompanyId,companyId));
+        List<String> stringList = list.stream().map(Product::getProjectName).distinct().collect(Collectors.toList());
+        List<Map<String,Object>> mapList=new ArrayList<>();
+        for (int i = 0; i < stringList.size(); i++) {
+            Map<String,Object> map=new HashMap<>();
+            map.put("label",i);
+            map.put("value",stringList.get(i));
+            mapList.add(map);
+        }
+        msg.setData(mapList);
+        return msg;
+    }
 }
 

+ 12 - 2
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/ReportController.java

@@ -1537,8 +1537,18 @@ public class ReportController {
     }
 
     @RequestMapping("getPersonWorkHoursWagesDetail")
-    public HttpRespMsg getPersonWorkHoursWagesDetail(String date,String userId,String startDate,String endDate,Integer checkStatus,Integer detailStatus){
-        return reportService.getPersonWorkHoursWagesDetail(date,userId,startDate,endDate,checkStatus,detailStatus);
+    public HttpRespMsg getPersonWorkHoursWagesDetail(String date,String userId,String startDate,String endDate){
+        return reportService.getPersonWorkHoursWagesDetail(date,userId,startDate,endDate);
+    }
+
+    @RequestMapping("getPersonWorkHoursWagesDetailForTemp")
+    public HttpRespMsg getPersonWorkHoursWagesDetailForTemp(String date,String userId,String startDate,String endDate){
+        return reportService.getPersonWorkHoursWagesDetailForTemp(date,userId,startDate,endDate);
+    }
+
+    @RequestMapping("getPersonWorkHoursWagesDetailForMob")
+    public HttpRespMsg getPersonWorkHoursWagesDetailForMob(String date,String userId,String startDate,String endDate,Integer checkStatus,Integer detailStatus){
+        return reportService.getPersonWorkHoursWagesDetailForMob(date,userId,startDate,endDate,checkStatus,detailStatus);
     }
 
     @RequestMapping("exportPersonWorkHoursWorkTime")

+ 105 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/UpdatePackController.java

@@ -0,0 +1,105 @@
+package com.management.platform.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.UpdatePack;
+import com.management.platform.mapper.UpdatePackMapper;
+import com.management.platform.util.FileUtil;
+import com.management.platform.util.HttpRespMsg;
+import com.management.platform.util.ZipUtils;
+import org.apache.commons.io.FileUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-01-21
+ */
+@RestController
+@RequestMapping("/update-pack")
+public class UpdatePackController {
+
+    @Value(value = "${upload.tempUpdatePath}")
+    private String tempUpdatePath;
+
+    @Resource
+    private UpdatePackMapper updatePackMapper;
+
+    @RequestMapping("/save")
+    public HttpRespMsg save(UpdatePack pack) throws IOException {
+        HttpRespMsg msg = new HttpRespMsg();
+        updatePackMapper.insert(pack);
+        //获取地址,进行更新系统
+        String serverPackUrl = pack.getServerPackUrl();
+        if (pack.getH5Url() != null) {
+            File h5File = new File(tempUpdatePath + pack.getH5Url());
+            String h5Target = h5File.getParent() + "\\h5";
+            ZipUtils.unzip(h5File.getAbsolutePath(), h5Target);
+            File targetFile = new File(h5Target);
+            File[] files = targetFile.listFiles();
+            //进入dist目录下
+            File distFile = files[0];
+
+            if (!distFile.getName().equals("dist")) {
+                System.out.println("压缩包内文件结构不正确,应该包含dist目录");
+                msg.setError("压缩包内文件结构不正确,应该包含dist目录");
+                return msg;
+            }
+            File finalTargetDirectory = new File("D:\\www\\staticproject\\workshop_h5");
+            //拷贝文件到目标文件夹进行覆盖
+            FileUtils.copyDirectory(distFile, finalTargetDirectory);
+            System.out.println("H5端文件拷贝完成");
+        }
+        if (pack.getPcUrl() != null) {
+            File pcFile = new File(tempUpdatePath + pack.getPcUrl());
+            String pcTarget = pcFile.getParent() + "\\pc";
+            ZipUtils.unzip(pcFile.getAbsolutePath(), pcTarget);
+
+            File targetFile = new File(pcTarget);
+            File[] files = targetFile.listFiles();
+            //进入dist目录下
+            File distFile = files[0];
+            if (!distFile.getName().equals("dist")) {
+                System.out.println("压缩包内文件结构不正确,应该包含dist目录");
+                msg.setError("压缩包内文件结构不正确,应该包含dist目录");
+                return msg;
+            }
+            File finalTargetDirectory = new File("D:\\www\\staticproject\\workshop_pc");
+            //拷贝文件到目标文件夹进行覆盖
+            FileUtils.copyDirectory(distFile, finalTargetDirectory);
+            System.out.println("PC端文件拷贝完成");
+        }
+        //检查解压后的文件结构目录
+        if (serverPackUrl != null) {
+            File file = new File(tempUpdatePath + serverPackUrl);
+            //拷贝文件到目标目录进行覆盖
+            FileUtils.copyFileToDirectory(file, new File("D:\\www\\webapps\\workshop-lew"));
+            System.out.println("后端文件拷贝完成");
+        }
+
+
+        //执行更新脚本
+        return msg;
+    }
+
+    @RequestMapping("/getHistory")
+    public HttpRespMsg getHistory() {
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = updatePackMapper.selectList(new QueryWrapper<UpdatePack>().orderByDesc("id").last("limit 30"));
+        return msg;
+    }
+
+
+}
+

+ 309 - 6
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/WxCorpInfoController.java

@@ -3,18 +3,26 @@ package com.management.platform.controller;
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.management.platform.entity.User;
-import com.management.platform.entity.WxCorpInfo;
+import com.management.platform.entity.*;
 import com.management.platform.mapper.UserMapper;
-import com.management.platform.service.WxCorpInfoService;
+import com.management.platform.service.*;
+import com.management.platform.util.DateTimeUtil;
 import com.management.platform.util.HttpRespMsg;
+import org.springframework.http.*;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
-import java.util.List;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.*;
 
 /**
  * <p>
@@ -32,6 +40,18 @@ public class WxCorpInfoController {
     WxCorpInfoService wxCorpInfoService;
     @Resource
     UserMapper userMapper;
+    @Resource
+    LeaveSheetService leaveSheetService;
+    @Resource
+    ReportService reportService;
+    @Resource
+    WxCorpTemplateService wxCorpTemplateService;
+    @Resource
+    DepartmentService departmentService;
+    @Resource
+    TaskTypeService taskTypeService;
+    @Resource
+    PlanService planService;
 
     @RequestMapping("/testDownload")
     public HttpRespMsg testDownload() {
@@ -83,6 +103,7 @@ public class WxCorpInfoController {
 
 
     @RequestMapping("/testGetApprovalList")
+    @Transactional
     public HttpRespMsg testGetApprovalList(String startDate,String endDate) throws Exception {
         HttpRespMsg msg=new HttpRespMsg();
         JSONArray jsonArrayFilter = new JSONArray();
@@ -94,8 +115,290 @@ public class WxCorpInfoController {
         filter2.put("key","sp_status");
         filter2.put("value",2);
         jsonArrayFilter.add(filter2);
-        JSONArray approvalInfo = wxCorpInfoService.getApprovalInfo(7, startDate, endDate, "", jsonArrayFilter);
-        msg.setData(approvalInfo.toArray());
+        List<String> approvalInfo = wxCorpInfoService.getApprovalInfo(7, startDate, endDate, "", jsonArrayFilter);
+        List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getCompanyId,7));
+        if(approvalInfo!=null){
+            List<LeaveSheet> leaveSheets = new ArrayList<>();
+            for (int i = 0; i < approvalInfo.size(); i++) {
+                String codeNum = approvalInfo.get(i);
+                String approvalInfoDetailResp = wxCorpInfoService.getApprovalInfoDetail(7, codeNum);
+                JSONObject approvalInfoDetail = JSONObject.parseObject(approvalInfoDetailResp);
+                JSONObject info = approvalInfoDetail.getJSONObject("info");
+                JSONObject applyer = info.getJSONObject("applyer");
+                String userid = applyer.getString("userid");
+                Optional<User> first = userList.stream().filter(u ->u.getCorpwxRealUserid()!=null&&u.getCorpwxRealUserid().equals(userid)).findFirst();
+                if(!first.isPresent()){
+                    continue;
+                }
+                LeaveSheet leaveSheet=new LeaveSheet();
+                leaveSheet.setCompanyId(7);
+                leaveSheet.setStatus(0);
+                leaveSheet.setOwnerId(first.get().getId());
+                leaveSheet.setOwnerName(first.get().getName());
+                JSONObject apply_data = info.getJSONObject("apply_data");
+                System.out.println("获取到的单据信息===========>"+apply_data);
+                JSONArray contents = apply_data.getJSONArray("contents");
+                for (int i1 = 0; i1 < contents.size(); i1++) {
+                    JSONObject map = contents.getJSONObject(i1);
+                    JSONArray title = map.getJSONArray("title");
+                    JSONObject value = map.getJSONObject("value");
+                    String control = map.getString("control");
+                    if(control.equals("Vacation")){
+                        JSONObject vacation = value.getJSONObject("vacation");
+                        JSONObject selector = vacation.getJSONObject("selector");
+                        //企业微信请假默认单选
+                        JSONArray options = selector.getJSONArray("options");
+                        JSONObject option = options.getJSONObject(0);
+                        int leaveType;
+                        switch (option.getJSONArray("value").getJSONObject(0).getString("text")){
+                            case "事假":leaveType=0;
+                                break;
+                            case "病假":leaveType=1;
+                                break;
+                            case "年假":leaveType=2;
+                                break;
+                            case "产假":leaveType=3;
+                                break;
+                            case "婚假":leaveType=4;
+                                break;
+                            case "丧假":leaveType=5;
+                                break;
+                            case "调休":leaveType=6;
+                                break;
+                            case "陪产假":leaveType=7;
+                                break;
+                            default:leaveType=8;
+                        }
+                        leaveSheet.setLeaveType(leaveType);
+                        JSONObject attendance = vacation.getJSONObject("attendance");
+                        JSONObject date_range = attendance.getJSONObject("date_range");
+                        leaveSheet.setTimeType(date_range.getString("type").equals("hour")?1:0);
+                        long new_begin = date_range.getLongValue("new_begin");
+                        long new_end = date_range.getLongValue("new_end");
+                        LocalDate startDate1 = DateTimeUtil.getLocalDateFromUnix(new_begin);
+                        LocalDate endDate1 = DateTimeUtil.getLocalDateFromUnix(new_end);
+                        leaveSheet.setStartDate(startDate1);
+                        leaveSheet.setEndDate(endDate1);
+                        long new_duration = date_range.getLongValue("new_duration");
+                        BigDecimal bigDecimal = new BigDecimal(new_duration);
+                        bigDecimal=bigDecimal.divide(new BigDecimal(3600),1, RoundingMode.HALF_DOWN);
+                        leaveSheet.setTimeHours(bigDecimal.floatValue());
+                        bigDecimal=bigDecimal.divide(new BigDecimal(8),1,RoundingMode.HALF_DOWN);
+                        leaveSheet.setTimeDays(bigDecimal.floatValue());
+                        leaveSheet.setLeaveType(1);
+                    }
+                    if(control.equals("Text")||control.equals("Textarea")){
+                        if(title.getJSONObject(0).getString("text").equals("请假事由")){
+                            leaveSheet.setRemark(value.getString("text"));
+                        }
+                    }
+                }
+                LeaveSheet one = leaveSheetService.getOne(new LambdaQueryWrapper<LeaveSheet>().eq(LeaveSheet::getStartDate, leaveSheet.getStartDate()).eq(LeaveSheet::getEndDate, leaveSheet.getEndDate()).eq(LeaveSheet::getOwnerId, leaveSheet.getOwnerId()));
+                if(one!=null){
+                    leaveSheet.setId(one.getId());
+                }
+                leaveSheets.add(leaveSheet);
+            }
+            if(leaveSheets.size()>0){
+                leaveSheetService.saveOrUpdateBatch(leaveSheets);
+            }
+        }
+        msg.setData(approvalInfo);
+        return msg;
+    }
+
+    @RequestMapping("/testSyncTemporaryJobApplication")
+    @Transactional
+    public HttpRespMsg testSyncTemporaryJobApplication(String startDate,String endDate)throws Exception{
+        HttpRespMsg msg=new HttpRespMsg();
+        JSONArray jsonArrayFilter = new JSONArray();
+        JSONObject filter1 = new JSONObject();
+        WxCorpTemplate template = wxCorpTemplateService.getById(7);
+        filter1.put("key","template_id");
+        filter1.put("value",template.getTemplateId());
+        jsonArrayFilter.add(filter1);
+        JSONObject filter2 = new JSONObject();
+        filter2.put("key","sp_status");
+        filter2.put("value",2);
+        jsonArrayFilter.add(filter2);
+        List<String> approvalInfo = wxCorpInfoService.getApprovalInfo(7, startDate, endDate, "", jsonArrayFilter);
+        List<Department> departmentList = departmentService.list(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, 7));
+        List<TaskType> taskTypeList = taskTypeService.list(new LambdaQueryWrapper<TaskType>().eq(TaskType::getCompanyId, 7));
+        List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getCompanyId,7));
+        if(approvalInfo!=null){
+            for (int i = 0; i < approvalInfo.size(); i++) {
+                String codeNum = approvalInfo.get(i);
+                String approvalInfoDetailResp = wxCorpInfoService.getApprovalInfoDetail(7, codeNum);
+                JSONObject approvalInfoDetail = JSONObject.parseObject(approvalInfoDetailResp);
+                JSONObject info = approvalInfoDetail.getJSONObject("info");
+                JSONObject applyer = info.getJSONObject("applyer");
+                String userid = applyer.getString("userid");
+                Optional<User> first = userList.stream().filter(u ->u.getCorpwxRealUserid()!=null&&u.getCorpwxRealUserid().equals(userid)).findFirst();
+                if(!first.isPresent()){
+                    continue;
+                }
+                JSONObject apply_data = info.getJSONObject("apply_data");
+                System.out.println("获取到的单据信息===========>"+apply_data);
+                JSONArray contents = apply_data.getJSONArray("contents");
+                //生成 车间插单计划
+                Plan plan=new Plan();
+                plan.setCompanyId(7);
+                plan.setCreateTime(LocalDateTime.now());
+                plan.setPlanType(1);
+                plan.setCreateId(first.get().getId());
+                //参与人员列表
+                List<String> userTeams=new ArrayList<>();
+                //初始化 单价(元/小时)
+                BigDecimal price=new BigDecimal(0);
+                //初始化 工作时长
+                double workTime=0;
+//                //初始话 工作日期
+//                JSONArray sp_record = info.getJSONArray("sp_record");
+//                //获取最后一个审批节点
+//                JSONObject last_sp_record = sp_record.getJSONObject(sp_record.size() - 1);
+//                JSONArray details = last_sp_record.getJSONArray("details");
+//                //获取最后详情
+//                JSONObject lastDetail = details.getJSONObject(details.size() - 1);
+//                long sptime = lastDetail.getLongValue("sptime");
+//                LocalDate createDate=LocalDate.now();
+                long apply_time = info.getLongValue("apply_time");
+                LocalDate createDate;
+                if(apply_time>0){
+                    createDate=  DateTimeUtil.getLocalDateFromUnix(apply_time);
+                }else {
+                    createDate  =LocalDate.now();
+                }
+                //初始化工位
+                Integer deptId=0;
+                for (int i1 = 0; i1 < contents.size(); i1++) {
+                    JSONObject map = contents.getJSONObject(i1);
+                    JSONArray title = map.getJSONArray("title");
+                    JSONObject value = map.getJSONObject("value");
+                    String control = map.getString("control");
+                    if(title.getJSONObject(0).getString("text").equals("临时报工分类")){
+                        if(control.equals("Selector")){
+                            JSONObject selector = value.getJSONObject("selector");
+                            JSONArray options = selector.getJSONArray("options");
+                            JSONObject object = options.getJSONObject(0);
+                            JSONArray value1 = object.getJSONArray("value");
+                            JSONObject jsonObject = value1.getJSONObject(0);
+                            String text = jsonObject.getString("text");
+                            Optional<TaskType> first1 = taskTypeList.stream().filter(t -> t.getTaskTypeName().equals(text)).findFirst();
+                            if(first1.isPresent()){
+                                plan.setTaskTypeId(first1.get().getId());
+                                plan.setTaskTypeName(first1.get().getTaskTypeName());
+                            }
+                        }
+                    }
+                    if(title.getJSONObject(0).getString("text").equals("事由")){
+                        if(control.equals("Text")||control.equals("Textarea")){
+                            String text = value.getString("text");
+                            plan.setTaskName(text);
+                        }
+                    }
+                    //先处理多个人员 公用此单据非工时部分内容
+                    if(title.getJSONObject(0).getString("text").equals("参与人员")){
+                        if(control.equals("Contact")){
+                            JSONArray members = value.getJSONArray("members");
+                            for (int i2 = 0; i2 < members.size(); i2++) {
+                                JSONObject jsonObject = members.getJSONObject(i2);
+                                String userid1 = jsonObject.getString("userid");
+                                userTeams.add(userid1);
+                            }
+
+                        }
+                    }
+                    if(title.getJSONObject(0).getString("text").equals("参与人数")){
+                        if(control.equals("Number")){
+                            int new_number = value.getIntValue("new_number");
+                            plan.setPlanManNum(new_number);
+                        }
+                    }
+                    if(title.getJSONObject(0).getString("text").equals("开始时间")){
+                        if(control.equals("Date")){
+                            JSONObject date = value.getJSONObject("date");
+                            long s_timestamp = date.getLongValue("s_timestamp");
+                            LocalDate localDateFromUnix = DateTimeUtil.getLocalDateFromUnix(s_timestamp);
+                            plan.setStartDate(localDateFromUnix);
+                        }
+                    }
+                    if(title.getJSONObject(0).getString("text").equals("结束时间")){
+                        if(control.equals("Date")){
+                            JSONObject date = value.getJSONObject("date");
+                            long s_timestamp = date.getLongValue("s_timestamp");
+                            LocalDate localDateFromUnix = DateTimeUtil.getLocalDateFromUnix(s_timestamp);
+                            plan.setEndDate(localDateFromUnix);
+                        }
+                    }
+                    if(title.getJSONObject(0).getString("text").equals("工作时长")){
+                        if(control.equals("Number")){
+                            double new_number = value.getDoubleValue("new_number");
+                            workTime=new_number;
+                        }
+                    }
+                    BigDecimal bigDecimal = new BigDecimal(plan.getPlanManNum()==null?0:plan.getPlanManNum());
+                    //工时以分钟为单位 *60
+                    bigDecimal=bigDecimal.multiply(new BigDecimal(workTime));
+                    bigDecimal=bigDecimal.multiply(new BigDecimal(60));
+                    plan.setPlanWorkHour(bigDecimal.doubleValue());
+                    if(title.getJSONObject(0).getString("text").equals("所属工位")){
+                        if(control.equals("Contact")){
+                            JSONArray departments = value.getJSONArray("departments");
+                            String openapi_id = departments.getJSONObject(0).getString("openapi_id");
+                            Optional<Department> first1 = departmentList.stream().filter(d -> d.getCorpwxDeptid().equals(Integer.valueOf(openapi_id))).findFirst();
+                            if(first1.isPresent()){
+                                plan.setStationId(first1.get().getDepartmentId());
+                                plan.setStationName(first1.get().getDepartmentName());
+                                plan.setForemanId(first1.get().getManagerId());
+                                Optional<User> first2 = userList.stream().filter(u -> u.getId().equals(first1.get().getManagerId())).findFirst();
+                                if(first2.isPresent()){
+                                    plan.setForemanName(first2.get().getName());
+                                }
+                                deptId=first1.get().getDepartmentId();
+                            }
+                        }
+                    }
+                    if(title.getJSONObject(0).getString("text").contains("单价")){
+                        if(control.equals("Number")){
+                            Double new_money = value.getDouble("new_number");
+                            plan.setMoneyOfJob(new BigDecimal(new_money));
+                            price=new BigDecimal(new_money);
+                        }
+                    }
+                    if(title.getJSONObject(0).getString("text").equals("备注")){
+                        if(control.equals("Text")||control.equals("Textarea")){
+                            String text = value.getString("text");
+                            plan.setDescribtion(text);
+                        }
+                    }
+                }
+                planService.save(plan);
+                List<Report> reportList=new ArrayList<>();
+                //处理人员日报数据
+                for (String userTeam : userTeams) {
+                    Optional<User> user = userList.stream().filter(u -> u.getCorpwxRealUserid() != null && u.getCorpwxRealUserid().equals(userTeam)).findFirst();
+                    if(user.isPresent()){
+                        Report report=new Report();
+                        report.setCreateDate(createDate);
+                        report.setCreatorId(user.get().getId());
+                        report.setCreateTime(LocalDateTime.now());
+                        BigDecimal bigDecimal = new BigDecimal(workTime);
+                        bigDecimal=bigDecimal.multiply(price);
+                        report.setCost(bigDecimal);
+                        report.setWorkingTime(workTime);
+                        report.setStatus(2);
+                        report.setPlanId(plan.getId());
+                        report.setCompanyId(7);
+                        report.setDeptId(deptId);
+                        reportList.add(report);
+                    }
+                }
+                if(reportList.size()>0){
+                    reportService.saveBatch(reportList);
+                }
+            }
+        }
+        msg.setData(approvalInfo);
         return msg;
     }
 }

+ 0 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/WxCorpTemplateController.java


Some files were not shown because too many files changed in this diff