Преглед изворни кода

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

seyason пре 11 месеци
родитељ
комит
09b0a53e36
36 измењених фајлова са 1066 додато и 227 уклоњено
  1. 1 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/App.vue
  2. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/detailcompinents/type.d.ts
  3. 0 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/relatedProducts/relatedProducts.vue
  4. 7 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/main.ts
  5. 2 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/api.ts
  6. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/products.vue
  7. 0 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/detail/index.vue
  8. 3 3
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/index.vue
  9. 11 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/api.ts
  10. 160 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/component/deteleTables.vue
  11. 33 8
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/detail/index.vue
  12. 269 29
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/index.vue
  13. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/api.ts
  14. 2 4
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/customer/detail/index.vue
  15. 20 28
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/api.ts
  16. 30 25
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/index.vue
  17. 1 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/api.ts
  18. 4 4
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/tasks/index.vue
  19. 1 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/thread/constant.ts
  20. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/thread/detail/components/information.vue
  21. 3 3
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/thread/index.vue
  22. 3 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/type.d.ts
  23. 33 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/utils/customInstructions.ts
  24. 12 6
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ClueController.java
  25. 25 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ContactsController.java
  26. 9 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/SalesOrderController.java
  27. 9 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/SalesOrder.java
  28. 4 1
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/ClueService.java
  29. 3 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/ContactsService.java
  30. 215 42
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ClueServiceImpl.java
  31. 26 1
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ContactsServiceImpl.java
  32. 74 31
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/ProductServiceImpl.java
  33. 74 24
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/SalesOrderServiceImpl.java
  34. 14 1
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/SysFormServiceImpl.java
  35. 12 8
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java
  36. 2 1
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/SalesOrderMapper.xml

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

@@ -47,6 +47,7 @@ provide<GlobalPopup>('globalPopup', {
 })
 
 const notificationTiop = (options: NotificationParamsTyped) => {
+  ElNotification.closeAll()
   ElNotification(options)
 }
  

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

@@ -39,7 +39,7 @@ export interface Props {
     /**
      * 详情数据中需要关联的任务类型字段
      */
-    filed?: 'customId' | 'businessOpportunityId' | 'orderId' | 'clueId' 
+    filed?: 'customId' | 'businessOpportunityId' | 'orderId' | 'clueId' | 'contactsId'
 }
 
 export interface Emits {

fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/business/component/relatedProducts.vue → fhKeeper/formulahousekeeper/customerBuler-crm/src/components/relatedProducts/relatedProducts.vue


+ 7 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/main.ts

@@ -11,15 +11,22 @@ import App from './App.vue'
 import router from './router/index'
 import * as echarts from 'echarts';
 import zhCn from "element-plus/dist/locale/zh-cn.mjs";
+import customize from '@/utils/customInstructions'
 const app = createApp(App)
 const pinia = createPinia()
 
 pinia.use(piniaPluginPersistedstate)
 
+// element-ui
 for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
   app.component(key, component)
 }
 
+// 注册自定义指令
+for (const [key, value] of Object.entries(customize)) {
+  app.directive(value.key, value.directive)
+}
+
 app.config.globalProperties.$echarts = echarts;
 app
   .use(ElementPlus, {

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

@@ -1,5 +1,5 @@
 export const MOD = "/business";
-export const MODURL = "business";
+export const MODURL = "Business";
 export const prefix = "/clue";
 export const GETSYSFILED = "/sys-dict/getListByCode";
 export const GETPERSONNEL = "/user/getSimpleActiveUserList";
@@ -18,6 +18,7 @@ export const BUSIESS_INFO = `/business-opportunity/getInfo`
 export const DETELEFILEFILE = `/business-opportunity/deleteFile`
 export const REFIENAMEFILE = `/business-opportunity/reFileName`
 export const UPLOADFILEFILE = `/business-opportunity/uploadFile`
+export const URL_IMPOERBUSINESS = `/business-opportunity/importData`
 
 
 export const stageStatus = [

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

@@ -55,7 +55,7 @@ import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffec
 import { GETTABLELIST } from '@/pages/product/api';
 import { post } from '@/utils/request';
 
-import RelatedProducts from './relatedProducts.vue'
+import RelatedProducts from '@/components/relatedProducts/relatedProducts.vue'
 
 const props = defineProps<{
     information: any

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

@@ -91,7 +91,6 @@ import DetailCompinents from '@/components/detailcompinents/relatedTasks.vue'
 import OperationRecord from '../component/operationRecord.vue';
 import Products from '../component/products.vue';
 import { post } from "@/utils/request";
-import { number } from "echarts";
 
 type stageListType = {
   name: string,

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

@@ -165,14 +165,14 @@
 import { ref, reactive, onMounted, inject } from "vue";
 import type { ElTable, FormInstance, FormRules, UploadRequestOptions } from 'element-plus'
 import { useRouter, useRoute } from "vue-router";
-import { GETSYSFILED, MOD, GETPERSONNEL, GETGENERATEFOEM, GETBUSINESSLIST, UPDATEINSET, BUSINESSDETELE, BATCHTRANSFER, MODURL, tableColumn, BUSIESS_GETSATE } from './api'
+import { GETSYSFILED, MOD, GETPERSONNEL, GETGENERATEFOEM, GETBUSINESSLIST, UPDATEINSET, BUSINESSDETELE, BATCHTRANSFER, MODURL, tableColumn, BUSIESS_GETSATE, URL_IMPOERBUSINESS } from './api'
 import { GETTABLELIST } from '@/pages/product/api'
 import { post, get, uploadFile } from "@/utils/request";
 import { getAllListByCode, getFromValue, resetFromValue, getFirstDayOfMonth, createTaskFromType, formatDate, confirmAction, downloadTemplate, downloadFile } from '@/utils/tools'
 import { createTask } from '@/components/TaskModal/taskFunction'
 import { formatDateTime } from '@/utils/times'
 import { GenerateForm } from '@zmjs/form-design';
-import RelatedProducts from './component/relatedProducts.vue'
+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'
@@ -322,7 +322,7 @@ async function importBusiness(param: UploadRequestOptions) {
   allLoading.importLoading = true
   const formData = new FormData();
   formData.append('multipartFile', param.file)
-  const res = await uploadFile('接口名称', formData).finally(() => {
+  const res = await uploadFile(URL_IMPOERBUSINESS, formData).finally(() => {
     allLoading.importLoading = false
   })
   if (res.code == 'ok') {

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

@@ -1,15 +1,25 @@
 import { SEX } from '../api.ts'
 export const MOD = 'contacts'
 export const URL = '/contacts'
+export const IMPORTMOD = 'Contacts'
 
 export const GETSYSFILED = "/sys-dict/getListByCode";
 export const GETPERSONNEL = "/user/getSimpleActiveUserList";
 export const GETGENERATEFOEM = `sys-form/getListByCode/${MOD}`
 
 export const URL_PAGECONTACTS = `${URL}/pageContacts`
+export const URL_ADD = `${URL}/addContacts`
+export const URL_UPLOAD = `${URL}/updateContacts`
+export const URL_DETELERECYCLE =  `${URL}/deleteContacts`
+export const URL_BATCHDETELE = `${URL}/confirmDeleteContacts`
+export const URL_RECYCLELIST = `${URL}/getDeletedContacts`
+export const URL_DETELEITEM = `${URL}/confirmDeleteContacts`
+export const URL_RESTORE = `${URL}/returnContacts`
+export const URL_GETALL = `${URL}/getAllContacts`
+export const URL_GETDETAIL = `${URL}/getContactsDetail`
 
 export const actionButtons: any[] = [
-    { text: '新建' },
+    { text: '新建联系人' },
     { text: '批量删除' },
     { text: '导入' },
     { text: '导出' },

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

@@ -0,0 +1,160 @@
+<template>
+    <el-dialog v-model="deteleBusinessDialogVisible" width="1000" :before-close="beForeCancel" :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>
+                    <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>
+        </template>
+        <div class="h-[60vh] flex flex-col">
+            <div class="flex-1 w-full overflow-hidden">
+                <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">
+                        <template #default="scope">
+                            <span>{{ scope.row[item.prop] }}</span>
+                        </template>
+                    </el-table-column>
+                    <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>
+                            <el-button link type="danger" size="large"
+                                @click="businessOperationItem(scope.row.id, scope.row.name, '删除')">删除</el-button>
+                        </template>
+                    </el-table-column>
+                </el-table>
+            </div>
+            <div class="flex justify-end pt-3">
+                <el-pagination layout="total, prev, pager, next, sizes" :page-size="tableForm.pageSize"
+                    @size-change="handleSizeChange" @current-change="handleCurrentChange" :total="businessTotalTable"
+                    :hide-on-single-page="true" />
+            </div>
+        </div>
+    </el-dialog>
+</template>
+<script lang="ts" setup>
+import { post } from '@/utils/request';
+import { ref, reactive, onMounted, watchEffect, watch, inject } from 'vue'
+import { URL_RECYCLELIST, URL_DETELEITEM, URL_RESTORE, tableColumns } from '../api';
+import { ElTable } from 'element-plus';
+import { confirmAction } from '@/utils/tools';
+import { formatDate } from '@/utils/times';
+
+type operationType = '恢复' | '删除'
+
+const emits = defineEmits(['closeVisible']);
+const globalPopup = inject<GlobalPopup>('globalPopup')
+const deteleBusinessTable = ref([])
+const deteleBusinessDialogVisible = ref(false)
+const businessTotalTable = ref(0)
+const batchTableData = ref([])
+const allLoading = reactive({
+    batchRecoveryLoading: false,
+    batchDeteleLoading: false,
+    tableLoading: false
+})
+
+const tableForm = reactive({
+    pageIndex: 1,
+    pageSize: 10
+})
+
+const busiessTableRef = ref<InstanceType<typeof ElTable>>() // 线索table dom
+
+const props = defineProps<{
+    visibles: boolean
+}>()
+
+watch(() => props.visibles, (newVal) => {
+    deteleBusinessDialogVisible.value = newVal
+    if (newVal) {
+        getTableList()
+    }
+})
+
+function batchOperation(type: operationType) {
+    const value = batchTableData.value.map((item: any) => item.id).join(',')
+    const label = batchTableData.value.map((item: any) => item.name).join(',')
+    businessOperationItem(value, label, type, true)
+}
+
+function businessOperationItem(value: string | number, label: string, type: operationType, batch: boolean = false) {
+    confirmAction(`确定${batch ? '批量' : ''}${type}【${label}】商机吗?`).then(() => {
+        let url = type == '恢复' ? URL_RESTORE : URL_DETELEITEM
+        post(url, { ids: value }).then(res => {
+            if (res.code != 'ok') {
+                globalPopup?.showError(res.msg)
+                return
+            }
+            globalPopup?.showSuccess(`${type}成功`)
+            getTableList()
+            changeBatch(false)
+        }).catch((err) => {
+            globalPopup?.showError(err.message)
+        })
+    })
+}
+
+function changeBatch(flag: boolean = true) {
+    if (flag) {
+        batchTableData.value = busiessTableRef.value && busiessTableRef.value.getSelectionRows()
+    } else {
+        batchTableData.value = []
+        busiessTableRef.value && busiessTableRef.value.clearSelection()
+    }
+}
+
+function getTableList() {
+    allLoading.tableLoading = true
+    post(URL_RECYCLELIST, { ...tableForm }).then((res) => {
+        if (res.code == 'ok') {
+            const { data, total } = res.data
+            deteleBusinessTable.value = data.map((item: any) => {
+                return {
+                    ...item,
+                    expectedTransactionDate: formatDate(new Date(item.expectedTransactionDate))
+                }
+            })
+            businessTotalTable.value = total
+        }
+    }).finally(() => {
+        allLoading.tableLoading = false
+    })
+}
+
+function handleSizeChange(val: number) {
+    tableForm.pageIndex = 1
+    tableForm.pageSize = val
+    getTableList()
+}
+
+function handleCurrentChange(val: number) {
+    tableForm.pageIndex = val
+    getTableList()
+}
+
+function cancel() {
+    emits('closeVisible', 'deteleContactsVisible')
+}
+
+function beForeCancel(done: () => void) {
+    emits('closeVisible', 'deteleContactsVisible')
+    done()
+}
+
+onMounted(() => {
+
+})
+
+</script>
+<style lang="scss" scoped></style>

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

@@ -1,5 +1,5 @@
 <template>
-    <div class="h-full flex p-3 flex-col businessDetail">
+    <div class="h-full flex p-3 flex-col businessDetail" v-loading="pageLoading">
         <div class="w-full bg-white p-2 mb-2 shadow-md rounded-md flex items-center">
             <div class="icon mr-4">
                 <el-link :underline="false" @click="backPath()">
@@ -7,8 +7,8 @@
                 </el-link>
             </div>
             <div class="mr-8">
-                <el-select v-model="value" placeholder="请选择" style="width: 150px">
-                    <el-option v-for="item in options" :key="item.id" :label="item.productName" :value="item.id" />
+                <el-select v-model="values" placeholder="请选择" style="width: 150px">
+                    <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
             </div>
         </div>
@@ -25,7 +25,8 @@
 
             <div class="w-full h-auto flex justify-between mt-2">
                 <div class="bg-white shadow-md rounded-md" style="width: 65%;">
-                    <RelatedTasks :data="relatedTasks" :information="information" />
+                    <!-- <RelatedTasks :data="relatedTasks" :information="information" /> -->
+                    <Detailcompinents :data="relatedTasks" :information="information" :formTaskType="0" :filed="'contactsId'" :disabledList="['contactsId']" @refreshData="getDetail" />
                 </div>
                 <div class="bg-white ml-2 shadow-md rounded-md flex-1">
                     <OperationRecord :data="operationRecord" />
@@ -45,26 +46,50 @@
 import { ref, reactive, onMounted, inject } from "vue";
 import { Edit, ArrowLeft as IconView } from '@element-plus/icons-vue'
 import { backPath } from '../../../utils/tools'
+import { useRoute } from "vue-router";
+import { post } from "@/utils/request";
+import { URL_GETALL, URL_GETDETAIL } from "../api";
 
 import Information from '../component/information.vue'
 import Attachment from '../component/attachment.vue'
 import RelatedTasks from '../component/relatedTasks.vue'
 import OperationRecord from '../component/operationRecord.vue'
+import Detailcompinents from '@/components/detailcompinents/relatedTasks.vue'
 import RelatedBusiness from '../component/relatedBusiness.vue'
 
+const route = useRoute()
+const globalPopup = inject<GlobalPopup>('globalPopup')
 const information = ref({}) // 基本信息
 const attachment = ref([]) // 附件
 const relatedTasks = ref([]) // 相关任务
 const operationRecord = ref([]) // 操作记录
 const relatedBusiness = ref([]) // 相关商机
-
+const rowId = ref(+(route.query.id || ''))
+const values = ref<number | string>('')
+const options = ref<optionType[]>([])
 const pageLoading = ref(false)
 
-const value = ref('')
-const options: any = ref([])
+function getDetail() {
+    pageLoading.value = true
+    post(URL_GETDETAIL, {}).then((res) => {
+        console.log(res)
+    }).finally(() => {
+        pageLoading.value = false
+    })
+}
+
+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)
+    })
+}
 
 onMounted(() => {
-    
+    values.value = rowId.value || ''
+    getAllContacts()
+    getDetail()
 })
 </script>
     

+ 269 - 29
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/index.vue

@@ -25,12 +25,18 @@
       <div class="bg-white w-full h-full p-3 shadow-md rounded-md flex flex-col">
         <div class="flex justify-end pb-3">
           <!-- 操作按钮 -->
-          <el-button v-for="(button, index) in actionButtons" :key="index" type="primary">{{ button.text }}</el-button>
+          <!-- <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>
         </div>
         <div class="flex-1 w-full overflow-hidden">
           <!-- 表格 -->
-          <el-table ref="clueTableRef" :data="formTable" border v-loading="allLoading.formTableLading"
-            style="width: 100%;height: 100%;">
+          <el-table ref="contactsTableRef" :data="formTable" 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">
@@ -45,30 +51,94 @@
             </el-table-column>
             <el-table-column :label="'操作'" :width="'200px'" fixed="right">
               <template #default="scope">
-                <el-button link type="primary" size="large">编辑</el-button>
-                <el-button link type="primary" size="large">新建任务</el-button>
-                <el-button link type="danger" size="large">删除</el-button>
+                <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"
+                  @click="contactsDeteleItem(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="tableTotal" :hide-on-single-page="true" />
+          <el-pagination layout="total, prev, pager, next, sizes" @size-change="handleSizeChange"
+            @current-change="handleCurrentChange" :total="tableTotal" :hide-on-single-page="true" />
         </div>
       </div>
     </div>
+
+    <!-- 弹窗 -->
+    <el-dialog v-model="allVisible.editContactsVisible" width="1000" :show-close="false" top="10vh">
+      <template #header="{ close, titleId, titleClass }">
+        <div class="flex justify-between items-center border-b pb-3 dialog-header">
+          <h4 :id="titleId">{{ allText.editContactsText }}</h4>
+          <div>
+            <el-button type="primary" :loading="allLoading.editContactsSaveLoading"
+              @click="editContactsSave(true)">保存并新建</el-button>
+            <el-button type="primary" :loading="allLoading.editContactsSaveLoading"
+              @click="editContactsSave(false)">保存</el-button>
+            <el-button @click="closeVisible('editContactsVisible')">取消</el-button>
+          </div>
+        </div>
+      </template>
+      <div class="h-[60vh] overflow-y-auto scroll-bar pt-3">
+        <div class="ml-4 mr-4">
+          <GenerateForm ref="contactsTemplateRef" :data="contactsTemplate" :value="contactsTemplateValue"
+            :key="contactsTemplateRefKey" v-loading="allLoading.contactsTemplateRefLoading" />
+        </div>
+      </div>
+    </el-dialog>
+
+    <!-- 回收站 -->
+    <DeteleTables :visibles="allVisible.deteleContactsVisible" @closeVisible="closeVisible" />
+
+    <!-- 导入 -->
+    <el-dialog v-model="allVisible.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-upload class="upload-demo mr-3" :limit="1" :show-file-list="false" accept=".xlsx"
+              :http-request="importBusiness">
+              <el-button type="primary" :loading="allLoading.importLoading">导入</el-button>
+            </el-upload>
+            <el-button @click="allVisible.importVisible = false">取消</el-button>
+          </div>
+        </div>
+      </template>
+      <div class="p-8">
+        <div class="ml-4 mr-4">
+          <div class="flex items-center">1、点击下载 <el-link type="primary"
+              @click="downloadTemplate(IMPORTMOD, allText.importText)">{{ allText.importText }}</el-link></div>
+          <div class="mt-4">2、填写excel文件、联系人、客户名称必填</div>
+        </div>
+      </div>
+    </el-dialog>
+
+    <!-- 任务 -->
+    <TaskModal :visible="allVisible.taskModalVisible" :edit-form="taskModalForm" :save-loading="taskLoading"
+      @close="closeVisible('taskModalVisible')" @submit="submitForm" :title="'新建任务'"
+      :disabled-list="['contactsId']" />
+
   </div>
 </template>
 
 <script lang="ts" setup>
 import { ref, reactive, onMounted, inject } from "vue";
-import { getAllListByCode, getFromValue, resetFromValue, getFirstDayOfMonth, getLastDayOfMonth, formatDate } from '@/utils/tools'
-import { post, get } from "@/utils/request";
-import { actionButtons, tableColumns, GETSYSFILED, GETPERSONNEL, GETGENERATEFOEM, MOD, URL_PAGECONTACTS, getSex } from "./api";
+import { getAllListByCode, getFromValue, resetFromValue, getTemplateKey, confirmAction, downloadTemplate, downloadFile, createTaskFromType } from '@/utils/tools'
+import { post, get, uploadFile } from "@/utils/request";
+import { actionButtons, tableColumns, GETSYSFILED, GETPERSONNEL, GETGENERATEFOEM, MOD, URL_PAGECONTACTS, getSex, URL_ADD, URL_UPLOAD, URL_BATCHDETELE, URL_DETELERECYCLE, IMPORTMOD } from "./api";
 import { useRouter, useRoute } from "vue-router";
+import { GenerateForm } from '@zmjs/form-design';
+import { URL_FETALL } from "../customer/api";
+import { ElTable, UploadRequestOptions } from "element-plus";
+
+import DeteleTables from './component/deteleTables.vue'
+import TaskModal from '@/components/TaskModal/index.vue'
+import { createTask } from "@/components/TaskModal/taskFunction";
 
 const router = useRouter()
+const globalPopup = inject<GlobalPopup>('globalPopup')
 
 const filterForm = reactive<FilterForm>({ // 筛选条件
   contactPerson: "",
@@ -95,20 +165,170 @@ const filterItems = ref<FilterItem[]>([
   { label: '负责人', key: 'responsibleId', type: 'select', options: selectData.Personnel },
   { label: '创建人', key: 'createId', type: 'select', options: selectData.Personnel },
 ])
-const generateFormData = ref([]) // 自定义表单数据
-
+const contactsTemplate = ref({
+  list: [],
+  config: {}
+})
+const contactsTemplateValue = ref({})
+const contactsTemplateRefKey = ref(1)
+const contactsTemplateRef = ref<typeof GenerateForm>()
+const contactsTableRef = ref<InstanceType<typeof ElTable>>()
 const formTable = ref([]) // 表格数据
+const batchTableData = ref([])
+const taskModalForm = ref({})
+const taskLoading = ref<saveLoadingType>('1')
 const allLoading = reactive({ // 按钮加载 Loading
   formTableLading: false,
+  editContactsSaveLoading: false,
+  contactsTemplateRefLoading: false,
+  importLoading: false,
+  exoprtLoading: false
 })
-const dialogVisible = reactive({
-
+const allVisible = reactive({
+  editContactsVisible: false,
+  taskModalVisible: false,
+  deteleContactsVisible: false,
+  importVisible: false
+})
+const allText = reactive({
+  editContactsText: '新建联系人',
+  importText: '联系人导入模板.xlsx',
+  exportText: '联系人导出.xlsx'
 })
 
+// 方法
+function submitForm(submitData: any, isClose: boolean) {
+  taskLoading.value = '2'
+  createTask(submitData, isClose).then((res) => {
+    const { saveLoading, isClose } = res
+    taskLoading.value = saveLoading
+    allVisible.taskModalVisible = isClose
+    globalPopup?.showSuccess('新增成功')
+  }).catch((err) => {
+    const { saveLoading, isClose, message } = err
+    taskLoading.value = saveLoading
+    allVisible.taskModalVisible = isClose
+    globalPopup?.showError(message)
+  })
+}
+
+function newTask(item: any) {
+  const { id } = item
+  taskModalForm.value = { ...createTaskFromType(0), contactsId: id, }
+  showVisible('taskModalVisible')
+}
+
+function exportCustomerTableList() {
+  allLoading.exoprtLoading = true
+  let valueForm = getFromValue(filterForm)
+  post('接口名称', { ...valueForm }).then((res) => {
+    downloadFile(res.data, allText.exportText)
+  }).finally(() => {
+    allLoading.exoprtLoading = false
+  })
+}
+
+async function importBusiness(param: UploadRequestOptions) {
+  allLoading.importLoading = true
+  const formData = new FormData();
+  formData.append('multipartFile', param.file)
+  const res = await uploadFile('接口名称', formData).finally(() => {
+    allLoading.importLoading = false
+  })
+  if (res.code == 'ok') {
+    globalPopup?.showSuccess('导入成功' || '')
+    getContactPerson()
+    return
+  }
+  globalPopup?.showError(res.msg || '')
+}
+
+function batchDeteleItem() {
+  const value = batchTableData.value.map((item: any) => item.id).join(',')
+  const label = batchTableData.value.map((item: any) => item.customName).join(',')
+  contactsDeteleItem(value, label, true)
+}
+
+function contactsDeteleItem(value: string | number, label: string, batch: boolean = false) {
+  confirmAction(`确定${batch ? '批量' : ''}删除【${label}】客户吗?`).then(() => {
+    let url = batch ? URL_BATCHDETELE : URL_DETELERECYCLE
+    post(url, { ids: value }).then(res => {
+      if (res.code != 'ok') {
+        globalPopup?.showError(res.msg)
+        return
+      }
+      globalPopup?.showSuccess('删除成功')
+      changeBatch(false)
+      getContactPerson()
+    }).catch((err) => {
+      globalPopup?.showError(err.message)
+    })
+  })
+}
+
+function changeBatch(flag: boolean = true) {
+  if (flag) {
+    batchTableData.value = contactsTableRef.value && contactsTableRef.value.getSelectionRows()
+  } else {
+    batchTableData.value = []
+    contactsTableRef.value && contactsTableRef.value.clearSelection()
+  }
+}
+
+
+function editContactsSave(flag: boolean) {
+  contactsTemplateRef.value?.getData().then((res: any) => {
+    allLoading.editContactsSaveLoading = true
+    let url = allText.editContactsText == '新建联系人' ? URL_ADD : URL_UPLOAD
+    post(url, { ...contactsTemplateValue.value, ...res }).then((_res) => {
+      allVisible.editContactsVisible = flag
+      globalPopup?.showSuccess('保存成功')
+      if (flag) {
+        contactsTemplateRef.value?.reset()
+        allText.editContactsText = '新建联系人'
+      }
+      getContactPerson()
+    }).finally(() => {
+      allLoading.editContactsSaveLoading = false
+    })
+  }).catch((_err: any) => {
+    console.log(_err)
+    globalPopup?.showError('请填写完整')
+  })
+}
+
+function editContacts(row: any) { // row 有数据代表编辑
+  showVisible('editContactsVisible')
+  if (row) {
+    const templateKey = getTemplateKey(contactsTemplate.value.list)
+    const formVal: templateKey = { id: row.id }
+    for (let i in templateKey) {
+      if(row[templateKey[i]]) {
+        formVal[templateKey[i]] = templateKey[i] == 'sex' ? row[templateKey[i]] + '' : row[templateKey[i]]
+      }
+    }
+    setTemplateVal(formVal)
+    allText.editContactsText = '编辑联系人'
+  } else {
+    setTemplateVal()
+    allText.editContactsText = '新建联系人'
+  }
+}
+
+function setTemplateVal(val: any = {}) {
+  console.log(val)
+  contactsTemplateValue.value = val
+  allLoading.contactsTemplateRefLoading = true
+  setTimeout(() => {
+    contactsTemplateRefKey.value++
+    allLoading.contactsTemplateRefLoading = false
+  }, 1000);
+}
+
 function toDetali(row: any) {
   router.push({
     path: `${MOD}/detail`,
-    query: { id: row.name }
+    query: { id: row.id }
   })
 }
 
@@ -116,7 +336,7 @@ function getContactPerson() {
   allLoading.formTableLading = true
   const formVal = getFromValue(filterForm)
   post(URL_PAGECONTACTS, { ...formVal, ...formTablePaging }).then((res) => {
-    const { records, total } =  res.data
+    const { records, total } = res.data
     formTable.value = records
     tableTotal.value = total
   }).finally(() => {
@@ -125,20 +345,12 @@ function getContactPerson() {
 }
 
 function resetForm() {
-  console.log('重置联系人');
+  let newResetForm = resetFromValue(filterForm)
+  Object.assign(filterForm, newResetForm)
+  getContactPerson()
 }
 
 async function getSystemField() {
-  const systemField = getAllListByCode([])
-  for (let i in systemField) {
-    const { data } = await get(`${GETSYSFILED}?code=${systemField[i]}`)
-    for (let key of Object.keys(selectData)) {
-      if (systemField[i] == key) {
-        Object.assign(selectData, { [key]: data })
-      }
-    }
-  }
-
   const { data } = await post(GETPERSONNEL, {})
   selectData.Personnel = data.map((item: any) => {
     const { id, name, phone, jobNumber } = item
@@ -147,12 +359,40 @@ async function getSystemField() {
     }
   })
 
-  // const res = await get(GETGENERATEFOEM)
-  // generateFormData.value = JSON.parse(res.data[0].config)
+  const res = await get(URL_FETALL, {})
+  selectData.Customer = (res.data || []).map((item: any) => {
+    const { id, customName } = item
+    return {
+      id,
+      name: customName
+    }
+  })
+
+  const datas = await get(GETGENERATEFOEM)
+  contactsTemplate.value = JSON.parse(datas.data[0].config)
 
   setFilterItems()
 }
 
+function handleSizeChange(val: number) {
+  formTablePaging.pageIndex = 1
+  formTablePaging.pageSize = val
+  getContactPerson()
+}
+
+function handleCurrentChange(val: number) {
+  formTablePaging.pageIndex = val
+  getContactPerson()
+}
+
+function showVisible(type: keyof typeof allVisible) {
+  allVisible[type] = true
+}
+
+function closeVisible(type: keyof typeof allVisible) {
+  allVisible[type] = false
+}
+
 function setFilterItems() {
   console.log(selectData)
   filterItems.value = [

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

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

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

@@ -92,12 +92,10 @@ function getDetail() {
 
 function getAllCustomer() {
   get(URL_FETALL).then(({ data }) => {
-      options.value = data.map((item: any) => {
-        return {
+      options.value = data.map((item: any) => ({
           value: item.id,
           label: item.customName
-        }
-      })
+      }))
   })
 }
 

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

@@ -1,36 +1,28 @@
 export const MOD = '/order'
+export const IMPOERMOD = 'Order'
 
 export const GETSYSFILED = "/sys-dict/getListByCode";
 export const GETPERSONNEL = "/user/getSimpleActiveUserList";
 export const GETGENERATEFOEM = `/sys-form/getListByCode${MOD}`
-export const GETALLPRODUCT = `/sys-form/getListByCode/product`
-export const GETTABLELIST =  `${MOD}/list`
-
-export const actionButtons: any[] = [
-    { text: '新建订单' },
-    { text: '批量转移' },
-    { text: '批量删除' },
-    { text: '回收站' },
-    { text: '导入' },
-    { text: '导出' },
-]
+export const GETALLPRODUCT = `/sys-form/getListByCode/Order`
+export const GETTABLELIST = `${MOD}/list`
 
 export const tableColumns: TableColumn[] = [
-    { prop: 'name', label: '订单编号', event: 'toDetali', width: '150' },
-    { prop: 'mobile', label: '订单名称', width: '150' },
-    { prop: 'email', label: '客户名称', width: '200' },
-    { prop: 'wechat', label: '商机名称', width: '200' },
-    { prop: 'position', label: '订单金额', width: '100' },
-    { prop: 'company', label: '已回款', width: '100' },
-    { prop: 'companya', label: '未回款', width: '100' },
-    { prop: 'companyb', label: '回放状态', width: '100' },
-    { prop: 'companyc', label: '订单类型', width: '200' },
-    { prop: 'companyd', label: '下单时间', width: '200' },
-    { prop: 'companye', label: '订单开始时间', width: '200' },
-    { prop: 'companyf', label: '订单结束时间', width: '200' },
-    { prop: 'companyg', label: '客户签的人', width: '200' },
-    { prop: 'companyh', label: '公司签的人', width: '200' },
-    { prop: 'companyj', label: '负责人', width: '200' },
-    { prop: 'companyk', label: '创建人', width: '200' },
-    { prop: 'companyl', label: '创建时间', width: '200' },
+    { prop: 'orderCode', label: '订单编号', event: 'toDetali', width: '150' },
+    { prop: 'orderName', label: '订单名称', 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: '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: 'inchargerName', label: '负责人', width: '200' },
+    { prop: 'creatorName', label: '创建人', width: '200' },
+    { prop: 'createTime', label: '创建时间', width: '200' },
 ]

+ 30 - 25
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/index.vue

@@ -36,17 +36,22 @@
       <div class="bg-white w-full h-full p-3 shadow-md rounded-md flex flex-col">
         <div class="flex justify-end pb-3">
           <!-- 操作按钮 -->
-          <el-button v-for="(button, index) in actionButtons" :key="index" type="primary">{{ button.text }}</el-button>
+          <el-button v-permission="['aabbc']" type="primary">新建订单</el-button>
+          <el-button type="primary">批量转移</el-button>
+          <el-button type="primary">批量删除</el-button>
+          <el-button type="primary">回收站</el-button>
+          <el-button type="primary">导入</el-button>
+          <el-button type="primary">导出</el-button>
         </div>
         <div class="flex-1 w-full overflow-hidden">
           <!-- 表格 -->
-          <el-table ref="clueTableRef" :data="formTable" border v-loading="allLoading.formTableLading"
+          <el-table ref="otherTableRef" :data="formTable" border v-loading="allLoading.formTableLading"
             style="width: 100%;height: 100%;">
             <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.name
+                  <el-button link type="primary" size="large" @click="toDetali(scope.row)">{{ scope.row[column.prop]
                   }}</el-button>
                 </template>
               </template>
@@ -71,11 +76,12 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, reactive, onMounted, inject } from "vue";
+import { ref, reactive, onMounted, inject, defineExpose } from "vue";
 import { getAllListByCode, getFromValue, resetFromValue, getFirstDayOfMonth, getLastDayOfMonth, formatDate } from '@/utils/tools'
 import { post, get } from "@/utils/request";
-import { actionButtons, tableColumns, GETSYSFILED, GETPERSONNEL, GETGENERATEFOEM, MOD, GETTABLELIST, GETALLPRODUCT } from "./api";
+import { tableColumns, GETSYSFILED, GETPERSONNEL, GETGENERATEFOEM, MOD, GETTABLELIST, GETALLPRODUCT } from "./api";
 import { useRouter, useRoute } from "vue-router";
+import { URL_FETALL } from "../customer/api";
 
 const router = useRouter()
 
@@ -93,7 +99,7 @@ const selectData = reactive({ // 下拉数据
   Personnel: [] as personnelInterface[],
   Customer: [] as any[], // 客户名称
   OrderType: [] as any[], // 订单类型
-  RemittanceStatus: [] as any[], // 回款状态
+  RemittanceStatus: [{ id: 0, name: '已回款' }, { id: 1, name: '未回款' }, { id: 2, name: '已完全回款' }] as any[], // 回款状态
   AllProduct: [] as any[] // 所有产品
 })
 const filterItems = ref<FilterItem[]>([]) // 渲染筛选条件
@@ -102,22 +108,18 @@ const formTablePaging = reactive({ // 分页条件
   pageSize: 10,
   total: 0,
 })
-const generateFormData = ref([]) // 自定义表单数据
-
-const formTable = ref([
-  { name: '订单名称', mobile: '13311112222', email: '123@qq.com', responsible: '张三', createId: '张三' }
-]) // 表格数据
+const formTable = ref([]) // 表格数据
 const allLoading = reactive({ // 按钮加载 Loading
   formTableLading: false,
 })
-const dialogVisible = reactive({
-  
+const allVisible = reactive({
+
 })
 
 function toDetali(row: any) {
   router.push({
     path: `${MOD}/detail`,
-    query: { id: row.name }
+    query: { id: row.id }
   })
 }
 
@@ -141,14 +143,14 @@ function resetFilterForm() {
 }
 
 function getAllProduct() {
-  post(GETALLPRODUCT, { pageIndex: -1, pageSize: -1 }).then((res) => {
+  get(GETALLPRODUCT, { pageIndex: -1, pageSize: -1 }).then((res) => {
     const { record } = res.data
     selectData.AllProduct = record
   })
 }
 
 async function getSystemField() {
-  const systemField = getAllListByCode([])
+  const systemField = getAllListByCode(['订单类型'])
   for (let i in systemField) {
     const { data } = await get(`${GETSYSFILED}?code=${systemField[i]}`)
     for (let key of Object.keys(selectData)) {
@@ -158,14 +160,17 @@ async function getSystemField() {
     }
   }
 
-  const { data } = await post(GETPERSONNEL, {})
-  selectData.Personnel = data.map((item: any) => {
+  const { data: personnelData } = await post(GETPERSONNEL, {})
+  selectData.Personnel = personnelData.map((item: any) => {
     const { id, name, phone, jobNumber } = item
-    return {
-      id, name, phone, jobNumber
-    }
+    return { id, name, phone, jobNumber }
   })
 
+  const { data: customerData } = await post(URL_FETALL, {})
+  selectData.Customer = (customerData || []).map((item: any) => {
+    const { id, customName } = item
+    return { id, name: customName }
+  })
   // const res = await get(GETGENERATEFOEM)
   // generateFormData.value = JSON.parse(res.data[0].config)
 
@@ -177,10 +182,10 @@ function setFilterItems() {
     { label: '订单编号', key: 'orderCode', type: 'input' },
     { label: '订单名称', key: 'orderName', type: 'input' },
     { label: '客户名称', key: 'customId', type: 'select', options: selectData.Customer },
-    { label: '商机名称', key: 'email', type: 'input' },
-    { label: '订单类型', key: 'type', type: 'select', options: selectData.OrderType },
-    { label: '回款状态', key: 'remittanceStatus', type: 'select', options: selectData.RemittanceStatus },
-    { label: '负责人', key: 'responsibleId', type: 'select', options: selectData.Personnel },
+    { label: '商机名称', key: 'businessOpportunityId', 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' },
   ]
 }

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

@@ -1,5 +1,6 @@
 import { EpPropMergeType } from "element-plus/es/utils";
 export const MOD = "/tasks";
+export const IMPORTMOD = "Task"
 
 type StatusType = {
   label: "全部" | "未开始" | "进行中" | "已完成" | "已超时";

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

@@ -121,18 +121,18 @@
             <el-table-column fixed="right" label="操作" header-align="center" align="center" width="150">
 
               <template #default="scope">
-                <el-button link type="primary" size="small" @click.prevent="editRow(scope.row)">
+                <el-button link type="primary" @click.prevent="editRow(scope.row)">
                   编辑
                 </el-button>
-                <el-button link type="primary" size="small" v-if="scope.row.status == '2'"
+                <el-button link type="primary" v-if="scope.row.status == '2'"
                   @click.prevent="restart(scope.row)">
                   重启
                 </el-button>
-                <el-button link type="primary" size="small" v-else @click.prevent="finishRow(scope.row)">
+                <el-button link type="primary" v-else @click.prevent="finishRow(scope.row)">
                   完成
                 </el-button>
 
-                <el-button link type="danger" size="small" @click.prevent="deleteRow(scope.row)">
+                <el-button link type="danger" @click.prevent="deleteRow(scope.row)">
                   删除
                 </el-button>
               </template>

+ 1 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/thread/constant.ts

@@ -17,3 +17,4 @@ export const UPLOADFILE = `${prefix}/uploadFile`
 export const DEYELWCLUE = `${prefix}/listDeleterClue`
 export const DETERDETELE = `${prefix}/deleterDelete`
 export const ROLLBACK = `${prefix}/rollback`
+export const URL_IMPORTTHREAD = `${prefix}/importData`

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

@@ -133,7 +133,7 @@ import { GETTEMPLATE, UNDATEFORM, GETPERSONNEL, UNDATECLAIM, GETTEMPLATETWO } fr
 import { get, post } from '@/utils/request'
 import { useStore } from '@/store/index'
 import { ElMessageBox } from 'element-plus';
-import RelatedProducts from '@/pages/business/component/relatedProducts.vue'
+import RelatedProducts from '@/components/relatedProducts/relatedProducts.vue'
 import { all } from 'axios';
 import { formatDateTime } from '@/utils/times';
 import { UPDATEINSET } from '@/pages/business/api';

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

@@ -169,7 +169,7 @@
 
 <script lang="ts" setup>
 import { ref, reactive, onMounted, inject } from "vue";
-import { GETSYSFILED, MOD, IMPORMOD, GETPERSONNEL, GETTABLE, GETTEMPLATE, GETDETAIL, UNDATECLAIM, UNDATEFORM, DELTEROW } from './constant'
+import { GETSYSFILED, MOD, IMPORMOD, GETPERSONNEL, GETTABLE, GETTEMPLATE, GETDETAIL, UNDATECLAIM, UNDATEFORM, DELTEROW, URL_IMPORTTHREAD } from './constant'
 import { getAllListByCode, getFromValue, resetFromValue, getFirstDayOfMonth, getLastDayOfMonth, formatDate, createTaskFromType, confirmAction, downloadTemplate } from '@/utils/tools'
 import { FormInstance, FormRules, ElMessageBox, ElTable, UploadRequestOptions } from 'element-plus'
 import { post, get, uploadFile } from "@/utils/request";
@@ -368,13 +368,13 @@ async function importProducts(param: UploadRequestOptions) {
   allLoading.importLoading = true
   const formData = new FormData();
   formData.append('multipartFile', param.file)
-  const res = await uploadFile('导入接口', formData).finally(() => {
+  const res = await uploadFile(URL_IMPORTTHREAD, formData).finally(() => {
     allLoading.importLoading = false
   })
   allLoading.importLoading = false
   if (res.code == 'ok') {
     globalPopup?.showSuccess('导入成功' || '')
-    
+    getClueTable()
     return
   }
   globalPopup?.showError(res.msg || '')

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

@@ -36,4 +36,6 @@ type TaskResponse = { saveLoading: saveLoadingType, isClose: boolean, message?:
 
 type optionType = { value: number | string, label: string | number }
 
-type sexTYpe = { value: number | string, label: string }
+type sexTYpe = { value: number | string, label: string }
+
+type buttonType = { label?: string, value?: string, type?: string, icon?: string, disabled?: boolean, loading?: boolean, text?: string, event?: void }

+ 33 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/utils/customInstructions.ts

@@ -0,0 +1,33 @@
+import { Directive } from 'vue';
+
+// 权限控制
+const PermissionDirective: Directive = {
+    mounted(el: HTMLElement, binding: { value: string[] }, vnode: any) {
+        const routePath = vnode.ctx.appContext.config.globalProperties.$route.path;
+        console.log(extractPath(routePath))
+        // const currentRoute = getCurrentInstance()?.appContext.config.globalProperties.$route;
+        // console.log('Current Route:', currentRoute);
+
+        // const permissions = binding.value;
+        // if (!Array.isArray(permissions)) {
+        //     console.error('Permissions must be provided as an array.');
+        //     return;
+        // }
+        // if (!permissions.some((permission: string) => permission === 'admin')) {
+        //     el.parentNode && el.parentNode.removeChild(el)
+        // }
+    }
+};
+
+function extractPath(str: any) {
+    const startIndex = str.indexOf('/');
+    const endIndex = str.indexOf('/', startIndex + 1);
+    return str.slice(startIndex, endIndex !== -1 ? endIndex : undefined);
+}
+
+// 导出的自定义指令
+const customize = [
+    { key: 'permission', directive: PermissionDirective, name: '角色权限' }
+]
+
+export default customize;

+ 12 - 6
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ClueController.java

@@ -73,12 +73,6 @@ public class ClueController {
         return msg;
     }
 
-    // 导入
-    @RequestMapping("exportData")
-    public Object exportData(Clue clue, HttpServletRequest request) throws Exception {
-        return clueService.exportData(clue, request);
-    }
-
     // 上传
     @RequestMapping("uploadFile")
     public Object uploadFile(Clue clue, HttpServletRequest request, MultipartFile file) throws Exception {
@@ -167,6 +161,18 @@ public class ClueController {
         return httpRespMsg;
     }
 
+    @RequestMapping("/importData")
+    public HttpRespMsg importData(MultipartFile multipartFile){
+        return clueService.importData(multipartFile);
+    }
+
+
+    @RequestMapping("/exportData")
+    public HttpRespMsg exportData(Clue clue) throws Exception {
+        return clueService.exportData(clue);
+    }
+
+
     @RequestMapping("/insertAndUpdate")
     public Object inserANdUpdate(Clue clue, HttpServletRequest request) {
         HttpRespMsg msg = new HttpRespMsg();

+ 25 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/ContactsController.java

@@ -9,6 +9,7 @@ import com.management.platform.mapper.ContactsMapper;
 import com.management.platform.mapper.UserMapper;
 import com.management.platform.service.ContactsService;
 import com.management.platform.util.HttpRespMsg;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -161,5 +162,29 @@ public class ContactsController {
     }
 
 
+    //转移联系人 conctacts 里面要有要转移的负责人的 owner_id,id
+    @RequestMapping("transferContacts")
+    public HttpRespMsg transferContacts(Contacts contacts,HttpServletRequest request){
+        User user = userMapper.selectById(request.getHeader("Token"));//当前登陆的用户
+        HttpRespMsg msg = new HttpRespMsg();
+        if (contacts.getOwnerId()==null|| StringUtils.isEmpty(contacts.getOwnerId())){
+            msg.setError("请选择要转移的负责人");
+            return msg;
+        }
+        Contacts contactsGet=contactsService.getById(contacts.getId());
+        if (contacts.getOwnerId().equals(contactsGet.getOwnerId())){
+            msg.setError("该联系人已属于所选负责人");
+            return msg;
+        }
+        contactsGet.setOwnerId(contacts.getOwnerId());
+        int count= contactsService.transferContacts(contactsGet, user);
+        if (count>0){
+            msg.setMsg("操作成功");
+            return msg;
+        }else {
+            msg.setError("操作失败");
+            return msg;
+        }
+    }
 }
 

+ 9 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/SalesOrderController.java

@@ -360,6 +360,15 @@ public class SalesOrderController {
         unReceivedPayment=unReceivedPayment.subtract(price);
         salesOrder.setReceivedPayment(receivedPayment);
         salesOrder.setUnReceivedPayment(unReceivedPayment);
+        if(money>0){
+            //回款金额大于0的情况下才能算一次回款
+            if(unReceivedPayment.doubleValue()<=0){
+                //未回款金额小于等于0 说明完全回款修改状态
+                salesOrder.setReceivedStatus(2);
+            }else {
+                salesOrder.setReceivedStatus(1);
+            }
+        }
         salesOrderPayment.setUnReceivedPayment(unReceivedPayment);
         salesOrderService.updateById(salesOrder);
         salesOrderPaymentService.save(salesOrderPayment);

+ 9 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/SalesOrder.java

@@ -115,6 +115,13 @@ public class SalesOrder extends Model<SalesOrder> {
     @TableField("un_received_payment")
     private BigDecimal unReceivedPayment;
 
+    /**
+     * 回款状态 0-未回款 1-已回款 2-已完全回款
+     */
+    @TableField("received_status")
+    private Integer receivedStatus;
+
+
     /**
      * 客户签约人
      */
@@ -208,6 +215,8 @@ public class SalesOrder extends Model<SalesOrder> {
     @TableField(exist = false)
     private String creatorName;
 
+    @TableField(exist = false)
+    private String businessOpportunityName;
 
     @Override
     protected Serializable pkVal() {

+ 4 - 1
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/ClueService.java

@@ -43,7 +43,6 @@ public interface ClueService extends IService<Clue> {
     int getTotal1(Clue clue, User user);
     int getTotal2(Clue clue, User user);
 
-    HttpRespMsg exportData(Clue clue, HttpServletRequest request) throws Exception;
 
     Object uploadFile(Clue clue, HttpServletRequest request, MultipartFile file);
 
@@ -52,4 +51,8 @@ public interface ClueService extends IService<Clue> {
     Object deleteFile(UploadFile file, HttpServletRequest request);
 
     Object downFile(UploadFile file, HttpServletRequest request, HttpServletResponse response);
+
+    HttpRespMsg importData(MultipartFile multipartFile);
+
+    HttpRespMsg exportData(Clue clue);
 }

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

@@ -3,6 +3,7 @@ package com.management.platform.service;
 import com.management.platform.entity.Contacts;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.management.platform.entity.Custom;
+import com.management.platform.entity.User;
 import com.management.platform.util.HttpRespMsg;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -42,4 +43,6 @@ public interface ContactsService extends IService<Contacts> {
     HttpRespMsg exportData(String customName, String name, String email, String creatorName, String phone, String ownerName, HttpServletRequest request) throws Exception;
 
     HttpRespMsg getAllContacts(HttpServletRequest request);
+
+    int transferContacts(Contacts contactsGet, User user);
 }

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

@@ -14,14 +14,21 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.management.platform.service.SysFunctionService;
 import com.management.platform.service.UserService;
 import com.management.platform.service.WxCorpInfoService;
+import com.management.platform.util.ExcelUtil;
 import com.management.platform.util.FileUtil;
 import com.management.platform.util.HttpRespMsg;
 import com.management.platform.util.MessageUtils;
 import org.apache.poi.ss.formula.functions.T;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+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.factory.annotation.Autowired;
 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.multipart.MultipartFile;
 
 import javax.annotation.Resource;
@@ -29,8 +36,10 @@ import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.beans.Transient;
-import java.io.File;
-import java.io.IOException;
+import java.io.*;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
 import java.net.URLEncoder;
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
@@ -51,6 +60,8 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
     private SysFunctionService sysFunctionService;
     @Autowired
     private ClueMapper clueMapper;
+    @Resource
+    private HttpServletRequest request;
     @Autowired
     private TaskMapper taskMapper;
     @Autowired
@@ -71,7 +82,8 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
     private ActionLogMapper actionLogMapper;
     @Resource
     private ExcelExportServiceImpl excelExportService;
-
+    @Resource
+    private SysDictMapper sysDictMapper;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -255,28 +267,7 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
     }
 
 
-    @Override
-    public HttpRespMsg exportData(Clue clue, HttpServletRequest request) throws Exception {
-        User user = userMapper.selectById(request.getHeader("token"));
-        SysForm sysForm = sysFormMapper.selectOne(new LambdaQueryWrapper<SysForm>().eq(SysForm::getCompanyId, user.getCompanyId()).eq(SysForm::getCode, "Clue").eq(SysForm::getIsCurrent, 1));
-        WxCorpInfo wxCorpInfo = wxCorpInfoService.getOne(new LambdaQueryWrapper<WxCorpInfo>().eq(WxCorpInfo::getCompanyId, user.getCompanyId()));
-        String config = sysForm.getConfig();
-        JSONObject configOb = JSON.parseObject(config);
-        JSONArray configObJSONArray = configOb.getJSONArray("list");
-        List<List<String>> dataList = new ArrayList<>();
-        List<String> titleList = new ArrayList<>();
-        for (int i = 0; i < configObJSONArray.size(); i++) {
-            JSONObject item = configObJSONArray.getJSONObject(i);
-            titleList.add(item.getString("label"));
-        }
-        dataList.add(titleList);//设置表头
-
-
-        clue.setCompanyId(user.getCompanyId());
 
-        String fileName = "线索表导出_" + System.currentTimeMillis();
-        return excelExportService.exportGeneralExcelByTitleAndList(wxCorpInfo, fileName, dataList, path);
-    }
 
     @Value(value = "${upload.file}")
     private String filePath;
@@ -371,30 +362,212 @@ public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements Cl
     @Override
     public Object downFile(UploadFile file, HttpServletRequest request, HttpServletResponse response) {
         HttpRespMsg msg = new HttpRespMsg();
-//        try {
-//            ServletOutputStream os = response.getOutputStream();
-            UploadFile uploadFile = uploadFileMapper.selectById(file.getId());
+        UploadFile uploadFile = uploadFileMapper.selectById(file.getId());
         String path1 = uploadFile.getPath();
         path1 = path1.substring(2);
         msg.setData(path1);
-//            if (uploadFile == null ){
-//                msg.setError("文件未找到");
-//                return msg;
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg importData(MultipartFile multipartFile) {
+        HttpRespMsg msg=new HttpRespMsg();
+        String fileName = multipartFile.getOriginalFilename();
+        File file = new File(fileName == null ? "file" : fileName);
+        User user = userMapper.selectById(request.getHeader("token"));
+        Integer companyId = user.getCompanyId();
+        WxCorpInfo wxCorpInfo = wxCorpInfoService.getOne(new LambdaQueryWrapper<WxCorpInfo>().eq(WxCorpInfo::getCompanyId, companyId));
+//        List<Clue> clueList = clueMapper.selectList(new LambdaQueryWrapper<Clue>().eq(Clue::getCompanyId, companyId));
+        List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getCompanyId, companyId));
+        List<SysDict> sysDictOfClueSources = sysDictMapper.selectList(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCompanyId, companyId).eq(SysDict::getCode, "ClueSources"));
+        List<SysDict> sysDictOfCustomLevel = sysDictMapper.selectList(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCompanyId, companyId).eq(SysDict::getCode, "CustomLevel"));
+        List<SysDict> sysDictOfCustomIndustry = sysDictMapper.selectList(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCompanyId, companyId).eq(SysDict::getCode, "CustomIndustry"));
+        InputStream inputStream = null;
+        OutputStream outputStream = null;
+        try {
+            inputStream = multipartFile.getInputStream();
+            outputStream = new FileOutputStream(file);
+            byte[] buffer = new byte[4096];
+            int temp = 0;
+            while ((temp = inputStream.read(buffer, 0, 4096)) != -1) {
+                outputStream.write(buffer, 0, temp);
+            }
+            inputStream.close();
+            outputStream.close();
+            //解析表格
+            XSSFWorkbook workbook = new XSSFWorkbook(file);
+            //我们只需要第一个sheet
+            XSSFSheet sheet = workbook.getSheetAt(0);
+            //由于第一行需要指明列对应的标题
+            int rowNum = sheet.getLastRowNum();
+            //获取当前表单模板 校验规则
+            SysForm sysForm = sysFormMapper.selectOne(new LambdaQueryWrapper<SysForm>().eq(SysForm::getCode, "Thread").eq(SysForm::getCompanyId, companyId).eq(SysForm::getIsCurrent, 1));
+            if(sysForm==null){
+                msg.setError("当前模块未配置自定义模板,需先完成配置");
+                return msg;
+            }
+            String config = sysForm.getConfig();
+            JSONObject configOb = JSON.parseObject(config);
+            JSONArray configObJSONArray = configOb.getJSONArray("list");
+//            List<Clue> importClueList=new ArrayList<>();
+            List<String> userNameList=new ArrayList<>();
+            HttpRespMsg respMsg=new HttpRespMsg();
+            for (int rowIndex = 0; rowIndex <= rowNum; rowIndex++) {
+                XSSFRow row = sheet.getRow(rowIndex);
+                if (row == null) {
+                    continue;
+                }
+                //跳过空行
+                if (ExcelUtil.isRowEmpty(row)) {
+                    continue;
+                }
+                //获取到当前行的列数据
+                int cellNum = row.getLastCellNum();
+                for (int i = 0; i < cellNum; i++) {
+                    JSONObject item = configObJSONArray.getJSONObject(i);
+                    String modelName = item.getString("model");
+                    XSSFCell cell = row.getCell(i);
+                    if(cell!=null){
+                        switch (item.getString("type")){
+                            case "time":cell.setCellType(CellType.NUMERIC);
+                                break;
+                            default:cell.setCellType(CellType.STRING);
+                        }
+                    }
+//                    if(modelName.equals("inchargerId")){
+//                        System.out.println("=====");
+//                        System.out.println(modelName);
+//                        System.out.println(cell.toString());
+//                        if(!StringUtils.isEmpty(cell.getStringCellValue())){
+//                            userNameList.add(cell.getStringCellValue());
+//                        }
+//                    }
+
+                }
+            }
+//            System.out.println("参与搜索的人员列表"+userNameList + userNameList.size());
+//            if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1&&userNameList.size()>0){
+//                respMsg = wxCorpInfoService.getBatchSearchUserInfo(wxCorpInfo, userNameList,null);
+//                if(respMsg.code.equals("0")){
+//                    msg.setError("姓名为["+String.valueOf(respMsg.data)+"]的人员存在重复,请使用工号!");
+//                    return msg;
+//                }
 //            }
-//
-//            File uploadFile1 = new File(uploadFile.getPath());
-//            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(uploadFile.getName(), "UTF-8"));
-//            response.setContentType("application/octet-stream");
-//            // 读取文件的字节流
-//            os.write(FileUtil.readFileByBytes(uploadFile1));
-//            os.flush();
-//
-//        } catch (IOException e) {
-//            msg.setError(MessageUtils.message("file.error"));
-//            e.printStackTrace();
-//        }
+            List<User> targetUserList= (List<User>) respMsg.data;
+            //直接忽略空行 从row1开始
+            for (int rowIndex = 1; rowIndex <= rowNum; rowIndex++) {
+                XSSFRow row = sheet.getRow(rowIndex);
+                if (row == null) {
+                    continue;
+                }
+                //跳过空行
+                if (ExcelUtil.isRowEmpty(row)) {
+                    continue;
+                }
+                //获取到当前行的列数据
+                int cellNum = row.getLastCellNum();
+                Clue clue =new Clue();
+                clue.setCompanyId(companyId);
+                clue.setCreateTime(new Date());
+                clue.setCreateId(user.getId());
+                for (int i = 0; i < cellNum; i++) {
+                    JSONObject item = configObJSONArray.getJSONObject(i);
+                    String modelName = item.getString("model");
+                    String className = modelName.substring(0, 1).toUpperCase() + modelName.substring(1);
+                    String getter="get"+className;
+                    String setter="set"+className;
+                    XSSFCell cell = row.getCell(i);
+                    if(cell!=null){
+                        switch (item.getString("type")){
+                            case "time":cell.setCellType(CellType.NUMERIC);
+                                break;
+                            default:cell.setCellType(CellType.STRING);
+                        }
+                    }
+                    //校验当前列是否为必填
+                    JSONObject options = item.getJSONObject("options");
+                    JSONObject rules = options.getJSONObject("rules");
+                    Boolean required = rules.getBoolean("required");
+                    if(required){
+                        if(StringUtils.isEmpty(cell.getStringCellValue())){
+                            msg.setError(item.getString("label")+"值不能为空值");
+                            return msg;
+                        }
+                    }
+                   if(modelName.equals("inchargerId")){
+                        if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                            String userName = cell.getStringCellValue();
+                            Optional<User> first;
+                            if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                                Optional<User> optional = targetUserList.stream().filter(tl -> tl.getName().equals(userName)).findFirst();
+                                first= userList.stream().filter(u ->(u.getJobNumber()!=null&&u.getJobNumber().equals(userName))||(optional.isPresent()&&u.getCorpwxUserid()!=null&&u.getCorpwxUserid().equals(optional.get().getCorpwxUserid()))).findFirst();
+                            }else {
+                                first= userList.stream().filter(u -> u.getName().equals(userName)||(u.getJobNumber()!=null&&u.getJobNumber().equals(userName))).findFirst();
+                            }
+                            if (first.isPresent()) {
+                                clue.setInchargerId(first.get().getId());
+                            } else {
+                                msg.setError("负责人["+userName+"]在系统中不存在");
+                                return msg;
+                            }
+                        }
+                    }else if(modelName.equals("customLevel")){
+                        if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                            Optional<SysDict> first = sysDictOfCustomLevel.stream().filter(s -> s.getName().equals(cell.getStringCellValue())).findFirst();
+                            if(first.isPresent()){
+                                clue.setCustomerLevelId(first.get().getId());
+                            }else {
+                                throw new Exception("客户级别["+cell.getStringCellValue()+"不存在,请在系统字典中增加");
+                            }
+                        }
+                    }else if(modelName.equals("clueSources")){
+                       if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                           Optional<SysDict> first = sysDictOfClueSources.stream().filter(s -> s.getName().equals(cell.getStringCellValue())).findFirst();
+                           if(first.isPresent()){
+                               Integer id = first.get().getId();
+                               clue.setClueSourceId(id);
+                           }else {
+                               throw new Exception("线索来源["+cell.getStringCellValue()+"不存在,请在系统字典中增加");
+                           }
+                       }
+                   }else if(modelName.equals("customIndustry")){
+                       if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                           Optional<SysDict> first = sysDictOfCustomIndustry.stream().filter(s -> s.getName().equals(cell.getStringCellValue())).findFirst();
+                           if(first.isPresent()){
+                               clue.setCustomerIndustryId(first.get().getId());
+                           }else {
+                               throw new Exception("线索来源["+cell.getStringCellValue()+"不存在,请在系统字典中增加");
+                           }
+                       }
+                   }else {
+                        if(!StringUtils.isEmpty(cell.getStringCellValue())){
+                            Class<Clue> clueClass = Clue.class;
+                            Method method = clueClass.getMethod(setter,String.class);
+                            method.invoke(clue,cell.getStringCellValue());
+                        }
+                    }
+
+                }
+                clueMapper.insert(clue);
+            }
+        } catch (IOException | NoSuchMethodException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        } catch (Exception e) {
+            e.printStackTrace();
+            msg.setError("验证失败");
+            return msg;
+        }
         return msg;
     }
 
+    @Override
+    public HttpRespMsg exportData(Clue clue) {
+        return null;
+    }
+
 
 }

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

@@ -80,7 +80,7 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
 
 
     @Override
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     public HttpRespMsg addContacts(Contacts contacts, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         String token = String.valueOf(request.getHeader("Token"));
@@ -167,6 +167,7 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public HttpRespMsg updateContacts(Contacts contacts, HttpServletRequest request) {
         HttpRespMsg msg = new HttpRespMsg();
         String token = String.valueOf(request.getHeader("Token"));
@@ -189,6 +190,7 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public HttpRespMsg deleteContacts(List<Integer> ids, HttpServletRequest request) {
         HttpRespMsg msg = new HttpRespMsg();
         UpdateWrapper<Contacts> contactsUpdateWrapper = new UpdateWrapper<>();
@@ -245,6 +247,7 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public HttpRespMsg returnContacts(List<Integer> ids) {
         HttpRespMsg msg = new HttpRespMsg();
         UpdateWrapper<Contacts> contactsUpdateWrapper = new UpdateWrapper<>();
@@ -583,5 +586,27 @@ public class ContactsServiceImpl extends ServiceImpl<ContactsMapper, Contacts> i
         return mgs;
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int transferContacts(Contacts contactsGet, User user) {
+        UpdateWrapper<Contacts> contactsUpdateWrapper = new UpdateWrapper<>();
+        contactsUpdateWrapper.eq("id", contactsGet.getId());
+        contactsUpdateWrapper.set("owner_id", contactsGet.getOwnerId());
+        int count1 = contactsMapper.update(null, contactsUpdateWrapper);
+
+        ContactsLog contactsLog = new ContactsLog();
+        contactsLog.setCompanyId(user.getCompanyId());
+        contactsLog.setContactsId(contactsGet.getId());
+        contactsLog.setOperateId(user.getId());
+        contactsLog.setOperateDate(LocalDateTime.now());
+        contactsLog.setMsg("转移联系人");
+        int count2 = contactsLogMapper.insert(contactsLog);
+        if (count1>0&&count2>0){
+            return 1;
+        }else {
+            return 0;
+        }
+    }
+
 
 }

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

@@ -216,10 +216,28 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
             String config = sysForm.getConfig();
             JSONObject configOb = JSON.parseObject(config);
             JSONArray configObJSONArray = configOb.getJSONArray("list");
+            //可能存在栅格布局的情况需要特殊处理
+            List<String> modelNameList=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"));
+                        }
+                    }
+                }else {
+                    modelNameList.add(jsonObject.getString("model"));
+                }
+            }
             List<Product>  importProductList=new ArrayList<>();
             List<String> userNameList=new ArrayList<>();
             HttpRespMsg respMsg=new HttpRespMsg();
-            for (int rowIndex = 0; rowIndex <= rowNum; rowIndex++) {
+            for (int rowIndex = 1; rowIndex <= rowNum; rowIndex++) {
                 XSSFRow row = sheet.getRow(rowIndex);
                 if (row == null) {
                     continue;
@@ -231,16 +249,8 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
                 //获取到当前行的列数据
                 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){
-                        switch (item.getString("type")){
-                            case "time":cell.setCellType(CellType.NUMERIC);
-                                break;
-                            default:cell.setCellType(CellType.STRING);
-                        }
-                    }
                     if(modelName.equals("inchargerId")){
                         if(!StringUtils.isEmpty(cell.getStringCellValue())){
                             userNameList.add(cell.getStringCellValue());
@@ -282,8 +292,9 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
                     XSSFCell cell = row.getCell(i);
                     if(cell!=null){
                         switch (item.getString("type")){
-                            case "time":cell.setCellType(CellType.NUMERIC);
-                                break;
+//                            case "time":cell.setCellType(CellType.NUMERIC);
+//                                break;
+                            //默认读取所有数据都是文本格式
                             default:cell.setCellType(CellType.STRING);
                         }
                     }
@@ -412,27 +423,59 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
             List<String> item=new ArrayList<>();
             for (int i = 0; i < configObJSONArray.size(); i++) {
                 JSONObject target = configObJSONArray.getJSONObject(i);
-                String model = target.getString("model");
-                String targetName = model.substring(0, 1).toUpperCase() + model.substring(1);
-                Class<? extends Product> aClass = product.getClass();
-                String value = String.valueOf(aClass.getMethod("get" + targetName).invoke(product)==null?"":aClass.getMethod("get" + targetName).invoke(product));
-                if(model.equals("inchargerId")){
-                    if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
-                        value = "$userName"+String.valueOf(aClass.getMethod("getInchargerName").invoke(product))+"$";
-                    }else {
-                        value = String.valueOf(aClass.getMethod("getInchargerName").invoke(product));
+                if(target.getString("type").equals("grid")){
+                    JSONArray columns = target.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);
+                            String model = object.getString("model");
+                            String targetName = model.substring(0, 1).toUpperCase() + model.substring(1);
+                            Class<? extends Product> aClass = product.getClass();
+                            String value = String.valueOf(aClass.getMethod("get" + targetName).invoke(product)==null?"":aClass.getMethod("get" + targetName).invoke(product));
+                            if(model.equals("inchargerId")){
+                                if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                                    value = "$userName"+String.valueOf(aClass.getMethod("getInchargerName").invoke(product))+"$";
+                                }else {
+                                    value = String.valueOf(aClass.getMethod("getInchargerName").invoke(product));
+                                }
+                            }
+                            if(model.equals("unit")){
+                                value = String.valueOf(aClass.getMethod("getUnitName").invoke(product));
+                            }
+                            if(model.equals("type")){
+                                value = String.valueOf(aClass.getMethod("getTypeName").invoke(product));
+                            }
+                            if(model.equals("status")){
+                                value = Integer.valueOf(String.valueOf(aClass.getMethod("getStatus").invoke(product)))==0?"下架":"上架";
+                            }
+                            item.add(value);
+                        }
                     }
+                }else {
+                    String model = target.getString("model");
+                    String targetName = model.substring(0, 1).toUpperCase() + model.substring(1);
+                    Class<? extends Product> aClass = product.getClass();
+                    String value = String.valueOf(aClass.getMethod("get" + targetName).invoke(product)==null?"":aClass.getMethod("get" + targetName).invoke(product));
+                    if(model.equals("inchargerId")){
+                        if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                            value = "$userName"+String.valueOf(aClass.getMethod("getInchargerName").invoke(product))+"$";
+                        }else {
+                            value = String.valueOf(aClass.getMethod("getInchargerName").invoke(product));
+                        }
+                    }
+                    if(model.equals("unit")){
+                        value = String.valueOf(aClass.getMethod("getUnitName").invoke(product));
+                    }
+                    if(model.equals("type")){
+                        value = String.valueOf(aClass.getMethod("getTypeName").invoke(product));
+                    }
+                    if(model.equals("status")){
+                        value = Integer.valueOf(String.valueOf(aClass.getMethod("getStatus").invoke(product)))==0?"下架":"上架";
+                    }
+                    item.add(value);
                 }
-                if(model.equals("unit")){
-                    value = String.valueOf(aClass.getMethod("getUnitName").invoke(product));
-                }
-                if(model.equals("type")){
-                    value = String.valueOf(aClass.getMethod("getTypeName").invoke(product));
-                }
-                if(model.equals("status")){
-                    value = Integer.valueOf(String.valueOf(aClass.getMethod("getStatus").invoke(product)))==0?"下架":"上架";
-                }
-                item.add(value);
             }
             dataList.add(item);
         }

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

@@ -98,6 +98,7 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
         List<SysDict> sysDictOfOrderType = sysDictMapper.selectList(new LambdaQueryWrapper<SysDict>().eq(SysDict::getCompanyId, user.getCompanyId()).eq(SysDict::getCode, "OrderType"));
         LambdaQueryWrapper<SalesOrder> orderLambdaQueryWrapper = new LambdaQueryWrapper<>();
         List<Custom> customList = customService.list(new LambdaQueryWrapper<Custom>().eq(Custom::getCompanyId, user.getCompanyId()));
+        List<BusinessOpportunity> businessOpportunityList = businessOpportunityService.list(new LambdaQueryWrapper<BusinessOpportunity>().eq(BusinessOpportunity::getCompanyId, user.getCompanyId()));
         orderLambdaQueryWrapper.eq(SalesOrder::getCompanyId,user.getCompanyId());
         if(isDelete!=null){
             orderLambdaQueryWrapper.eq(SalesOrder::getIsDelete,isDelete);
@@ -194,6 +195,10 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
             if(custom.isPresent()){
                 r.setCustomName(custom.get().getCustomName());
             }
+            Optional<BusinessOpportunity> businessOpportunity = businessOpportunityList.stream().filter(b -> r.getBusinessOpportunityId() != null && b.getId().equals(r.getBusinessOpportunityId())).findFirst();
+            if(businessOpportunity.isPresent()){
+                r.setBusinessOpportunityName(businessOpportunity.get().getName());
+            }
         });
         Map map=new HashMap();
         map.put("record",records);
@@ -242,10 +247,28 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
             String config = sysForm.getConfig();
             JSONObject configOb = JSON.parseObject(config);
             JSONArray configObJSONArray = configOb.getJSONArray("list");
+            //可能存在栅格布局的情况需要特殊处理
+            List<String> modelNameList=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"));
+                        }
+                    }
+                }else {
+                    modelNameList.add(jsonObject.getString("model"));
+                }
+            }
             List<SalesOrder>  importOrderList=new ArrayList<>();
             List<String> userNameList=new ArrayList<>();
             HttpRespMsg respMsg=new HttpRespMsg();
-            for (int rowIndex = 0; rowIndex <= rowNum; rowIndex++) {
+            for (int rowIndex = 1; rowIndex <= rowNum; rowIndex++) {
                 HSSFRow row = sheet.getRow(rowIndex);
                 if (row == null) {
                     continue;
@@ -257,16 +280,8 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
                 //获取到当前行的列数据
                 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);
                     HSSFCell cell = row.getCell(i);
-                    if(cell!=null){
-                        switch (item.getString("type")){
-                            case "time":cell.setCellType(CellType.NUMERIC);
-                                break;
-                            default:cell.setCellType(CellType.STRING);
-                        }
-                    }
                     if(modelName.equals("inchargerId")){
                         if(!StringUtils.isEmpty(cell.getStringCellValue())){
                             userNameList.add(cell.getStringCellValue());
@@ -294,7 +309,7 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
                 }
             }
             List<User> targetUserList= (List<User>) respMsg.data;
-            for (int rowIndex = 0; rowIndex <= rowNum; rowIndex++) {
+            for (int rowIndex = 1; rowIndex <= rowNum; rowIndex++) {
                 HSSFRow row = sheet.getRow(rowIndex);
                 if (row == null) {
                     continue;
@@ -317,8 +332,8 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
                     HSSFCell cell = row.getCell(i);
                     if(cell!=null){
                         switch (item.getString("type")){
-                            case "time":cell.setCellType(CellType.NUMERIC);
-                                break;
+//                            case "time":cell.setCellType(CellType.NUMERIC);
+//                                break;
                             default:cell.setCellType(CellType.STRING);
                         }
                     }
@@ -488,7 +503,19 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
         List<String> titleList=new ArrayList<>();
         for (int i = 0; i < configObJSONArray.size(); i++) {
             JSONObject item = configObJSONArray.getJSONObject(i);
-            titleList.add(item.getString("label"));
+            if(item.getString("type").equals("grid")){
+                JSONArray columns = item.getJSONArray("columns");
+                for (int i1 = 0; i1 < columns.size(); i1++) {
+                    JSONObject columnsJSONObject = columns.getJSONObject(i1);
+                    JSONArray list = columnsJSONObject.getJSONArray("list");
+                    for (int i2 = 0; i2 < list.size(); i2++) {
+                        JSONObject object = list.getJSONObject(i2);
+                        titleList.add(object.getString("label"));
+                    }
+                }
+            }else {
+                titleList.add(item.getString("label"));
+            }
         }
         dataList.add(titleList);
         HttpRespMsg respMsg = getList( userId,null, orderName,orderCode,null,null,null,null,null,productCode, null,null,0);
@@ -498,18 +525,41 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
             List<String> item=new ArrayList<>();
             for (int i = 0; i < configObJSONArray.size(); i++) {
                 JSONObject target = configObJSONArray.getJSONObject(i);
-                String model = target.getString("model");
-                String targetName = model.substring(0, 1).toUpperCase() + model.substring(1);
-                Class<? extends Product> aClass = product.getClass();
-                String value = String.valueOf(aClass.getMethod("get" + targetName).invoke(product)==null?"":aClass.getMethod("get" + targetName).invoke(product));
-                if(model.equals("inchargerId")){
-                    if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
-                        value = "$userName"+String.valueOf(aClass.getMethod("getInchargerName").invoke(product))+"$";
-                    }else {
-                        value = String.valueOf(aClass.getMethod("getInchargerName").invoke(product));
+                if(target.getString("type").equals("grid")){
+                    JSONArray columns = target.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);
+                            String model = object.getString("model");
+                            String targetName = model.substring(0, 1).toUpperCase() + model.substring(1);
+                            Class<? extends Product> aClass = product.getClass();
+                            String value = String.valueOf(aClass.getMethod("get" + targetName).invoke(product)==null?"":aClass.getMethod("get" + targetName).invoke(product));
+                            if(model.equals("inchargerId")){
+                                if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                                    value = "$userName"+String.valueOf(aClass.getMethod("getInchargerName").invoke(product))+"$";
+                                }else {
+                                    value = String.valueOf(aClass.getMethod("getInchargerName").invoke(product));
+                                }
+                            }
+                            item.add(value);
+                        }
+                    }
+                }else {
+                    String model = target.getString("model");
+                    String targetName = model.substring(0, 1).toUpperCase() + model.substring(1);
+                    Class<? extends Product> aClass = product.getClass();
+                    String value = String.valueOf(aClass.getMethod("get" + targetName).invoke(product)==null?"":aClass.getMethod("get" + targetName).invoke(product));
+                    if(model.equals("inchargerId")){
+                        if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                            value = "$userName"+String.valueOf(aClass.getMethod("getInchargerName").invoke(product))+"$";
+                        }else {
+                            value = String.valueOf(aClass.getMethod("getInchargerName").invoke(product));
+                        }
                     }
+                    item.add(value);
                 }
-                item.add(value);
             }
             dataList.add(item);
         }

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

@@ -72,7 +72,20 @@ public class SysFormServiceImpl extends ServiceImpl<SysFormMapper, SysForm> impl
         JSONArray configObJSONArray = configOb.getJSONArray("list");
         for (int i = 0; i < configObJSONArray.size(); i++) {
             JSONObject item = configObJSONArray.getJSONObject(i);
-            heads.add(item.getString("label"));
+            if(item.getString("type").equals("grid")){
+                JSONArray columns = item.getJSONArray("columns");
+                for (int i1 = 0; i1 < columns.size(); i1++) {
+                    JSONObject columnsJSONObject = columns.getJSONObject(i1);
+                    JSONArray list = columnsJSONObject.getJSONArray("list");
+                    for (int i2 = 0; i2 < list.size(); i2++) {
+                        JSONObject object = list.getJSONObject(i2);
+                        heads.add(object.getString("label"));
+                    }
+                }
+            }else {
+                heads.add(item.getString("label"));
+            }
+
         }
         List<List<String>> allList = new ArrayList<>();
         allList.add(heads);

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

@@ -17,6 +17,10 @@ import com.management.platform.util.HttpRespMsg;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.poi.hssf.usermodel.*;
 import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+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.Value;
 import org.springframework.stereotype.Service;
@@ -302,9 +306,9 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
             outputStream.close();
 
             //解析表格
-            HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(file));
+            XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(file));
             //我们只需要第一个sheet
-            HSSFSheet sheet = workbook.getSheetAt(0);
+            XSSFSheet sheet = workbook.getSheetAt(0);
             //由于第一行需要指明列对应的标题
             int rowNum = sheet.getLastRowNum();
             //获取当前表单模板 校验规则
@@ -329,7 +333,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
             List<SalesOrder> orderList = salesOrderMapper.getList(user);
              List<Clue> clueList = clueMapper.selectList(new LambdaQueryWrapper<Clue>().eq(Clue::getCompanyId, user.getCompanyId()).eq(Clue::getIsDelete, 0).orderByDesc(Clue::getCreateTime));
             for (int rowIndex = 1; rowIndex <= rowNum; rowIndex++) {
-                HSSFRow row = sheet.getRow(rowIndex);
+                XSSFRow row = sheet.getRow(rowIndex);
                 if (row == null) {
                     continue;
                 }
@@ -343,8 +347,8 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
                 for (int i = 0; i < cellNum; i++) {
                     JSONObject item = configObJSONArray.getJSONObject(i);
                     String modelName = item.getString("model");
-                    HSSFCell cell = row.getCell(i);
-                    if(cell!=null&&StringUtils.isNotEmpty(cell.getStringCellValue())){
+                    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());
@@ -353,7 +357,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
                                 break;
                             default:cell.setCellType(CellType.STRING);
                         }
-                    }
+                    }*/
                     if(modelName.equals("executorId")){
                         if(!StringUtils.isEmpty(cell.getStringCellValue())){
                             List<String> executorNames = new ArrayList<>();
@@ -382,7 +386,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
             List<User> targetUserList= (List<User>) respMsg.data;
 
             for (int rowIndex = 1; rowIndex <= rowNum; rowIndex++) {
-                HSSFRow row = sheet.getRow(rowIndex);
+                XSSFRow row = sheet.getRow(rowIndex);
                 if (row == null) {
                     continue;
                 }
@@ -403,7 +407,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
                     String className = modelName.substring(0, 1).toUpperCase() + modelName.substring(1);
                     String getter="get"+className;
                     String setter="set"+className;
-                    HSSFCell cell = row.getCell(i);
+                    XSSFCell cell = row.getCell(i);
                     if(cell!=null&&StringUtils.isNotEmpty(cell.getStringCellValue())){
                         switch (item.getString("type")){
                             case "time":cell.setCellType(CellType.NUMERIC);

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

@@ -18,6 +18,7 @@
         <result column="order_end_date" property="orderEndDate" />
         <result column="received_payment" property="receivedPayment" />
         <result column="un_received_payment" property="unReceivedPayment" />
+        <result column="received_status" property="receivedStatus" />
         <result column="custom_signer" property="customSigner" />
         <result column="company_signer" property="companySigner" />
         <result column="incharger_id" property="inchargerId" />
@@ -35,7 +36,7 @@
 
     <!-- 通用查询结果列 -->
     <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, 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
     </sql>
 
 </mapper>