Browse Source

Merge remote-tracking branch 'origin/master'

yusm 11 tháng trước cách đây
mục cha
commit
6ae20237aa
22 tập tin đã thay đổi với 1170 bổ sung214 xóa
  1. 2 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/api.ts
  2. 3 3
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/index.vue
  3. 85 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/corpreport/api.ts
  4. 160 55
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/corpreport/index.vue
  5. 13 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/api.ts
  6. 87 70
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/attachment.vue
  7. 148 40
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/information.vue
  8. 38 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/operationRecord.vue
  9. 185 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/products.vue
  10. 134 0
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/rebate.vue
  11. 126 4
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/detail/index.vue
  12. 6 7
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/index.vue
  13. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/product/detail/index.vue
  14. 20 2
      fhKeeper/formulahousekeeper/customerBuler-crm/src/utils/customInstructions.ts
  15. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/vite.config.ts
  16. 95 11
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/SalesOrderController.java
  17. 6 0
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/SalesOrder.java
  18. 24 2
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/SalesOrderPayment.java
  19. 27 11
      fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/service/impl/SalesOrderServiceImpl.java
  20. 3 1
      fhKeeper/formulahousekeeper/management-crm/src/main/resources/mapper/SalesOrderPaymentMapper.xml
  21. 5 5
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserWithBeisenController.java
  22. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java

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

@@ -18,6 +18,8 @@ export const URL_RESTORE = `${URL}/returnContacts`
 export const URL_GETALL = `${URL}/getAllContacts`
 export const URL_GETDETAIL = `${URL}/getContactsDetail`
 export const URL_TRANSFERCONTACTS = `${URL}/transferContacts`
+export const URL_IMPORTDATACONTACTS = `${URL}/importData`
+export const URL_EXPORTDATACONTACTS = `${URL}/exportData`
 
 export const actionButtons: any[] = [
     { text: '新建联系人' },

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

@@ -127,7 +127,7 @@
 import { ref, reactive, onMounted, inject } from "vue";
 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 { actionButtons, tableColumns, GETSYSFILED, GETPERSONNEL, GETGENERATEFOEM, MOD, URL_PAGECONTACTS, getSex, URL_ADD, URL_UPLOAD, URL_BATCHDETELE, URL_DETELERECYCLE, IMPORTMOD, URL_IMPORTDATACONTACTS, URL_EXPORTDATACONTACTS } from "./api";
 import { useRouter, useRoute } from "vue-router";
 import { GenerateForm } from '@zmjs/form-design';
 import { URL_FETALL } from "../customer/api";
@@ -221,7 +221,7 @@ function newTask(item: any) {
 function exportCustomerTableList() {
   allLoading.exoprtLoading = true
   let valueForm = getFromValue(filterForm)
-  post('接口名称', { ...valueForm }).then((res) => {
+  post(URL_EXPORTDATACONTACTS, { ...valueForm }).then((res) => {
     downloadFile(res.data, allText.exportText)
   }).finally(() => {
     allLoading.exoprtLoading = false
@@ -232,7 +232,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_IMPORTDATACONTACTS, formData).finally(() => {
     allLoading.importLoading = false
   })
   if (res.code == 'ok') {

+ 85 - 0
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/corpreport/api.ts

@@ -0,0 +1,85 @@
+import { post, get } from '@/utils/request';
+import { dayjs } from 'element-plus';
+
+export type RequestProps = {
+  startDate?: string;
+  endDate?: string;
+  type?: 0 | 1;
+  userId?: number;
+  departmentId?: number;
+};
+
+export async function getOverallData(payload?: RequestProps): Promise<any> {
+  return await post('report/getCustomerTotalCount', payload);
+}
+
+export async function getConversionData(payload?: RequestProps): Promise<any> {
+  return await post('report/getCustomerTransferRate', payload);
+}
+
+export async function getDepartmentData(): Promise<any> {
+  return await get('/department/normalList');
+}
+
+export async function getStaffData(): Promise<any> {
+  return await get('/user/getSimpleActiveUserList');
+}
+
+export async function exportFile(
+  payload: RequestProps,
+  type: number
+): Promise<any> {
+  return await post(
+    type === 0
+      ? '/report/exportCustomerTotalCount'
+      : '/report/exportCustomerTransferRate',
+    payload
+  );
+}
+
+export const dateCollections = [
+  {
+    name: '当日',
+    start_time: dayjs().startOf('date').toISOString(),
+    end_time: dayjs().endOf('date').toISOString()
+  },
+  {
+    name: '昨日',
+    start_time: dayjs().startOf('date').subtract(1, 'day').toISOString(),
+    end_time: dayjs().endOf('date').subtract(1, 'day').toISOString()
+  },
+  {
+    name: '本周',
+    start_time: dayjs().startOf('week').add(1, 'day').toISOString(),
+    end_time: dayjs().endOf('week').add(1, 'day').toISOString()
+  },
+  {
+    name: '上周',
+    start_time: dayjs()
+      .add(-1, 'week')
+      .startOf('week')
+      .add(1, 'day')
+      .toISOString(),
+    end_time: dayjs().add(-1, 'week').endOf('week').add(1, 'day').toISOString()
+  },
+  {
+    name: '本月',
+    start_time: dayjs().startOf('month').toISOString(),
+    end_time: dayjs().endOf('month').toISOString()
+  },
+  {
+    name: '上月',
+    start_time: dayjs().add(-1, 'month').startOf('month').toISOString(),
+    end_time: dayjs().add(-1, 'month').endOf('month').toISOString()
+  },
+  {
+    name: '本季度',
+    start_time: dayjs().month(0).toISOString(),
+    end_time: dayjs().month(2).endOf('month').toISOString()
+  },
+  {
+    name: '上季度',
+    start_time: dayjs().add(-1, 'year').month(9).toISOString(),
+    end_time: dayjs().add(-1, 'year').month(11).endOf('month').toISOString()
+  }
+];

+ 160 - 55
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/corpreport/index.vue

@@ -3,30 +3,36 @@ import { ref, reactive, onMounted, watchEffect } from 'vue';
 
 import Echarts from '@/components/ReEcharts/index.vue';
 import { EChartsOption } from 'echarts';
+import {
+  type RequestProps,
+  getOverallData,
+  getDepartmentData,
+  getStaffData,
+  dateCollections,
+  getConversionData,
+  exportFile
+} from './api';
+import { downloadFile } from '@/utils/tools';
 
-const chartOptions: EChartsOption = {
+const isLoading = ref(false);
+const dataSource = ref([]);
+const form = reactive({ type: undefined, date: undefined, member: undefined });
+const memberOptions = ref([]);
+// 0 客户总量  1 客户转化率
+const dataType = ref<0 | 1>(0);
+
+const chartOptions: EChartsOption = reactive({
   grid: { bottom: 30 },
   legend: {},
   tooltip: {},
   dataset: {
-    dimensions: ['product', '2015', '2016', '2017'],
-    source: [
-      { product: 'Matcha Latte', 2015: 43.3, 2016: 85.8, 2017: 93.7 },
-      { product: 'Milk Tea', 2015: 83.1, 2016: 73.4, 2017: 55.1 },
-      { product: 'Cheese Cocoa', 2015: 86.4, 2016: 65.2, 2017: 82.5 },
-      { product: 'Walnut Brownie', 2015: 72.4, 2016: 53.9, 2017: 39.1 }
-    ]
+    dimensions: [],
+    source: []
   },
   xAxis: { type: 'category' },
   yAxis: {},
-  // Declare several bar series, each will be mapped
-  // to a column of dataset.source by default.
-  series: [
-    { type: 'bar', barWidth: 20 },
-    { type: 'bar', barWidth: 20 },
-    { type: 'bar', barWidth: 20 }
-  ]
-};
+  series: []
+});
 
 const dateOptions = [
   { label: '今天', value: '1' },
@@ -38,36 +44,97 @@ const dateOptions = [
   { label: '本季度', value: '7' },
   { label: '上季度', value: '8' }
 ];
-const dataSource = [
-  {
-    date: '2016-05-03',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
-  },
-  {
-    date: '2016-05-02',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
-  },
-  {
-    date: '2016-05-04',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
-  },
-  {
-    date: '2016-05-01',
-    name: 'Tom',
-    address: 'No. 189, Grove St, Los Angeles'
+
+const onSubmit = async (isExport?: boolean) => {
+  const payload = {
+    startDate: form.date && dateCollections[form.date - 1].start_time,
+    endDate: form.date && dateCollections[form.date - 1].end_time,
+    type: form.type,
+    userId: form.type === 1 ? form.member : undefined,
+    departmentId: form.type === 1 ? undefined : form.member
+  } as RequestProps;
+
+  if (isExport === true) {
+    const { data } = await exportFile(payload, dataType.value);
+    console.log(data, '----------------');
+    await downloadFile(data, data?.split('/')?.[2] || '客户表');
+    return;
   }
-];
+
+  dataType.value === 0 ? queryOverall(payload) : queryConversion(payload);
+};
+
+const queryOverall = async (payload?: RequestProps) => {
+  isLoading.value = true;
+  const { data = [] } = await getOverallData(payload);
+  isLoading.value = false;
+
+  dataSource.value = data.map((d) => ({
+    name: d.name,
+    dealRate: d.dealRate * 100,
+    customerDeal: d.customerDeal,
+    customertotal: d.customertotal
+  }));
+
+  // @ts-ignore
+  chartOptions.series = [
+    { type: 'bar', barWidth: 20 },
+    { type: 'bar', barWidth: 20, color: '#b91c1c' }
+  ];
+  // @ts-ignore
+  chartOptions.dataset.dimensions = ['name', '成交客户数', '新增客户数'];
+  // @ts-ignore
+  chartOptions.dataset.source = data.map((d) => ({
+    name: d.name,
+    ['成交客户数']: d.customerDeal,
+    ['新增客户数']: d.customertotal
+  }));
+  chartOptions.legend = {};
+};
+
+const queryConversion = async (payload?: RequestProps) => {
+  isLoading.value = true;
+  const { data = [] } = await getConversionData(payload);
+  isLoading.value = false;
+
+  dataSource.value = data.map((d) => ({
+    name: d.name,
+    dealRate: d.dealRate * 100
+  }));
+
+  // @ts-ignore
+  chartOptions.series = [{ type: 'bar', barWidth: 20 }];
+  // @ts-ignore
+  chartOptions.dataset.dimensions = ['name', '客户转化率(%)'];
+  // @ts-ignore
+  chartOptions.dataset.source = data.map((d) => ({
+    name: d.name,
+    ['客户转化率(%)']: d.dealRate * 100
+  }));
+  chartOptions.legend = undefined;
+};
+
+watchEffect(() => {
+  dataType.value === 0 ? queryOverall() : queryConversion();
+});
+
+watchEffect(async () => {
+  const { data = [] } =
+    form.type === 1 ? await getStaffData() : await getDepartmentData();
+
+  memberOptions.value = data.map((d) => ({
+    name: form.type === 1 ? d.name : d.departmentName,
+    id: form.type === 1 ? d.id : d.departmentId
+  }));
+});
 </script>
 
 <template>
   <div class="m-5 bg-white h-full p-4 rounded">
     <div class="flex justify-between">
-      <el-form class="flex gap-4">
+      <el-form :model="form" class="flex gap-4">
         <el-form-item class="w-28">
-          <el-select>
+          <el-select clearable v-model="form.date">
             <el-option
               v-for="date in dateOptions"
               :key="date.value"
@@ -77,33 +144,71 @@ const dataSource = [
           </el-select>
         </el-form-item>
         <el-form-item class="w-28">
-          <el-select>
-            <el-option label="按部门" value="1" />
-            <el-option label="按员工" value="2" />
+          <el-select
+            clearable
+            v-model="form.type"
+            @change="form.member = undefined"
+          >
+            <el-option label="按部门" :value="0" />
+            <el-option label="按员工" :value="1" />
           </el-select>
         </el-form-item>
         <el-form-item class="w-52">
-          <el-select></el-select>
+          <el-select
+            clearable
+            v-model="form.member"
+            placeholder="选择部门(默认为本部门及下属部门)"
+          >
+            <el-option
+              v-for="date in memberOptions"
+              :key="date.id"
+              :label="date.name"
+              :value="date.id"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button
+            type="primary"
+            :loading="isLoading"
+            @click="onSubmit(false)"
+            >搜索</el-button
+          >
+          <el-button type="primary" @click="onSubmit(true)">导出</el-button>
         </el-form-item>
-        <el-button type="primary">搜索</el-button>
       </el-form>
-      <el-tabs type="card">
-        <el-tab-pane label="客户总量分析" name="first" />
-        <el-tab-pane label="客户转化率分析" name="first" />
-        <el-tab-pane label="合同数量分析" name="first" />
+
+      <el-tabs
+        type="card"
+        v-model="dataType"
+        @tab-change="
+          () => {
+            form.date = undefined;
+            form.member = undefined;
+            form.type = undefined;
+            dataSource = [];
+          }
+        "
+      >
+        <el-tab-pane label="客户总量分析" :name="0" />
+        <el-tab-pane label="客户转化率分析" :name="1" />
       </el-tabs>
-      <!-- <span class="mr-12 font-bold text-gray-900">客户总量分析</span> -->
     </div>
     <div class="h-96">
       <Echarts :option="chartOptions"></Echarts>
     </div>
     <el-table :data="dataSource">
-      <el-table-column prop="date" label="员工姓名" />
-      <el-table-column prop="date" label="新增客户数" />
-      <el-table-column prop="date" label="成交客户数" />
-      <el-table-column prop="date" label="客户成交率(%)" />
-      <el-table-column prop="date" label="合同总金额" />
-      <el-table-column prop="date" label="回款金额" />
+      <el-table-column prop="name" label="员工姓名" />
+      <el-table-column
+        prop="dealRate"
+        label="客户转化率(%)"
+        v-if="dataType === 1"
+      />
+      <template v-else>
+        <el-table-column prop="customertotal" label="新增客户数" />
+        <el-table-column prop="customerDeal" label="成交客户数" />
+        <el-table-column prop="dealRate" label="客户成交率(%)" />
+      </template>
     </el-table>
   </div>
 </template>

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

@@ -14,6 +14,13 @@ export const EXPORTTIME = `${MOD}/exportData`
 export const IMPORITEM = `${MOD}/importData`
 export const URL_BATCHDELETE = `${MOD}/batchDeleteOrder`
 export const URL_RECOVER = `${MOD}/recover`
+export const URL_DETEALORDER = `${MOD}/getDetail`
+export const URL_TRANSFER = `${MOD}/transfer`
+export const URL_FERDETAILTASK = `${MOD}/taskWithOrder`
+export const URL_PAYLIST = `${MOD}/paymentCollectionList`
+export const URL_ADDREBATE = `${MOD}/paymentCollection`
+export const URL_EDITEBATE = `${MOD}/editPayment`
+export const URL_DETELEITEMS = `${MOD}/deletePayment`
 
 export const tableColumns: TableColumn[] = [
     { prop: 'orderCode', label: '订单编号', event: 'toDetali', width: '150' },
@@ -33,4 +40,10 @@ export const tableColumns: TableColumn[] = [
     { prop: 'inchargerName', label: '负责人', width: '200' },
     { prop: 'creatorName', label: '创建人', width: '200' },
     { prop: 'createTime', label: '创建时间', width: '200' },
+]
+
+export const paymentStatus = [
+    { value: 0, label: '未回款' },
+    { value: 1, label: '已回款' },
+    { value: 2, label: '完全回款' },
 ]

+ 87 - 70
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/attachment.vue

@@ -4,141 +4,158 @@
             <div class="title">附件</div>
             <div>
                 <el-upload ref="uploadRef" :http-request="httpUploadFile" :limit="1" :show-file-list="false"
-                    element-loading-text="正在上传" :loading="allLoading.uploadFileLoading">
+                    element-loading-text="正在上传">
                     <template #trigger>
-                        <el-button type="primary">上传</el-button>
+                        <el-button type="primary" :loading="allLoading.uploadLoading">上传</el-button>
                     </template>
                 </el-upload>
             </div>
         </div>
         <div class="flex-1 overflow-auto pt-3">
             <el-table :data="attachmenttable" border style="width: 100%;height: 200px;">
-                <el-table-column prop="documentName" label="附件名称" width="180" />
+                <el-table-column prop="attachmentName" label="附件名称" width="180" />
                 <el-table-column prop="size" label="附件大小" width="120" />
                 <el-table-column prop="creatorName" label="上传人" width="120" />
                 <el-table-column prop="indate" label="上传时间" width="180" />
                 <el-table-column label="操作" width="180" fixed="right">
                     <template #default="scope">
                         <el-button link type="primary" size="large" @click="fileDownload(scope.row)">下载</el-button>
-                        <el-button link type="primary" size="large" @click="operation(scope.row)">重命名</el-button>
-                        <el-button link type="danger" size="large" @click="fileDetele(scope.row)">删除</el-button>
+                        <el-button link type="primary" size="large" @click="showVisible(scope.row)">重命名</el-button>
+                        <el-button link type="danger" size="large" @click="deteleFile(scope.row)">删除</el-button>
                     </template>
                 </el-table-column>
             </el-table>
         </div>
 
         <!-- 弹窗 -->
-        <el-dialog v-model="allVisible.renameDialogVisible" width="800" :show-close="false" top="10vh">
+        <el-dialog v-model="allVisible.renameVisible" width="800" :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" @click="saveEditClue()" :loading="allLoading.saveLoading">保存</el-button>
-                        <el-button @click="allVisible.renameDialogVisible = false">取消</el-button>
+                        <el-button type="primary" :loading="allLoading.renameLoading" :disabled="!renameVal"
+                            @click="saveEditClue()">保存</el-button>
+                        <el-button @click="allVisible.renameVisible = false">取消</el-button>
                     </div>
                 </div>
             </template>
             <div class="pt-3">
-                <el-input v-model.trim="fileFormVal.name" style="width: 100%" class="pb-3" clearable />
+                <el-input v-model.trim="renameVal" style="width: 100%" class="pb-3" clearable />
             </div>
         </el-dialog>
     </div>
 </template>
 <script lang="ts" setup>
-import { post, uploadFile } from '@/utils/request';
+import { get, post, uploadFile } from '@/utils/request';
 import { UploadRequestOptions } from 'element-plus';
-import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
-import { URLFILEDETELE, URL_REFNAME, URL_UPLOADFILE } from '@/pages/api';
-import { downloadFile } from '@/utils/tools';
+import { ref, reactive, onMounted, onUnmounted, defineEmits, inject, watchEffect } from 'vue'
+import { confirmAction, downloadFile } from '@/utils/tools';
+import { FILEDETELE, FILERENAME, UPLOADATTACHMENT } from '@/pages/product/api';
+import { IMPORTMOD } from '../api';
 
 const globalPopup = inject<GlobalPopup>('globalPopup')
 const emits = defineEmits(['refreshData']);
-const props = defineProps<{
-    data?: any
-}>()
-
-type fileFormVal = {
-    id?: string,
-    name?: string
-}
 
 const uploadRef = ref<any>()
-const information = ref<any>({})
 const attachmenttable = ref([])
-const fileTypeStr = ref('') // 文件重命名的类型
-const fileFormVal = ref<fileFormVal>({})
+const information: any = ref({})
+const renameItem: any = ref({})
+const renameVal = ref('')
 const allLoading = reactive({
-    uploadFileLoading: false,
-    saveLoading: false
+    uploadLoading: false,
+    renameLoading: false,
 })
 const allVisible = reactive({
-    renameDialogVisible: false
+    renameVisible: false
 })
 
+const props = defineProps<{
+    data: any,
+    information: any
+}>()
+
+// 下载文件
+function fileDownload(item: any) {
+    downloadFile(item.url, `${item.attachmentName}${item.attachmentSuffix}`)
+}
+
+// 保存重命名
 function saveEditClue() {
-    if(!fileFormVal.value.name) {
-        globalPopup?.showWarning('请输入文件名称')
-        return
-    }
-    allLoading.saveLoading = true
-    post(URL_REFNAME, {
-        fileId: fileFormVal.value.id,
-        newName: fileFormVal.value.name + '.' + fileTypeStr.value
-    }).then(() => {
-        allVisible.renameDialogVisible = false
-        globalPopup?.showSuccess('重命名成功')
-        emits('refreshData');
+    const id = renameItem.value.id
+    allLoading.renameLoading = true
+    post(FILERENAME, { name: renameVal.value, id }).then((res) => {
+        if (res.code == 'ok') {
+            allVisible.renameVisible = false
+            globalPopup?.showSuccess(res.msg || '')
+            emits('refreshData', 'getFileList')
+        }
+    }).catch((err) => {
+        globalPopup?.showError(err.msg || '')
     }).finally(() => {
-        allLoading.saveLoading = false
+        allLoading.renameLoading = false
     })
 }
 
-function operation(item: any) {
-    fileTypeStr.value = item.documentName.split('.').pop()
-    fileFormVal.value = {
-        id: item.id,
-        name: item.documentName.replace(/\.[^/.]+$/, '')
-    }
-    allVisible.renameDialogVisible = true
-}
-
-function fileDownload(item: any) {
-    downloadFile(`${item.url}`, item.documentName)
+// 删除文件
+function deteleFile(item: any) {
+    const id = item.id
+    confirmAction(`确定删除【${item.attachmentName}】文件吗?`).then(() => {
+        post(FILEDETELE, { id }).then((_res) => {
+            globalPopup?.showSuccess('删除成功')
+            emits('refreshData', 'getFileList')
+        }).catch((err) => {
+            globalPopup?.showError(err.msg || '')
+        })
+    })
 }
 
-function fileDetele(item: any) {
-    post(URLFILEDETELE, { fileIds: item.id }).then(() => {
-        globalPopup?.showSuccess('删除成功')
-        emits('refreshData');
-    })
+// 显示弹窗
+function showVisible(item: any) {
+    renameItem.value = JSON.parse(JSON.stringify(item))
+    renameVal.value = renameItem.value.attachmentName
+    allVisible.renameVisible = true
 }
 
 // 上传附件
 async function httpUploadFile(param: UploadRequestOptions) {
+    allLoading.uploadLoading = true
     const id = information.value.id
     const formData = new FormData();
     formData.append('file', param.file)
-    formData.append('contactsId', id)
-    allLoading.uploadFileLoading = true
-    const res = await uploadFile(URL_UPLOADFILE, formData).finally(() => {
-        allLoading.uploadFileLoading = false
-        uploadRef.value.clearFiles()
-    })
+    formData.append('moduleId', id)
+    formData.append('moduleCode', IMPORTMOD)
+    const res = await uploadFile(UPLOADATTACHMENT, formData)
+    allLoading.uploadLoading = false
+    uploadRef.value.clearFiles()
     if (res.code == 'ok') {
-        globalPopup?.showSuccess(res.msg || '')
-        emits('refreshData');
+        globalPopup?.showSuccess('上传成功')
+        emits('refreshData', 'getFileList')
         return
     }
     globalPopup?.showError(res.msg || '')
     return res
 }
 
+// 接收参数赋值
+function receiveAssignment(item: any) {
+    attachmenttable.value = item.data
+    information.value = item.information
+}
+
 watchEffect(() => {
-    const { data } = props
-    // information.value = data
-    // attachmenttable.value = data.contactsDocumentList || []
-    information.value = {}
-    attachmenttable.value = []
+    receiveAssignment(props)
+});
+
+// 生命周期钩子
+onMounted(() => {
+    receiveAssignment(props)
 });
 </script>
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.attachment {
+    .title {
+        font-size: 18px;
+        color: #000
+    }
+}
+</style>

+ 148 - 40
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/component/information.vue

@@ -3,9 +3,8 @@
         <div class="flex justify-between">
             <div class="title">基本信息</div>
             <div>
-                <el-button type="primary">认领</el-button>
-                <el-button type="primary">转移</el-button>
-                <el-button type="primary">编辑</el-button>
+                <el-button type="primary" @click="transferCli()">转移</el-button>
+                <el-button type="primary" @click="editInfo(info)">编辑</el-button>
             </div>
         </div>
         <div class="form flex flex-wrap justify-between">
@@ -15,30 +14,13 @@
             </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">编辑联系人</h4>
-                    <div>
-                        <el-button type="primary" :loading="allLoading.editContactsSaveLoading">保存</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>
-
         <el-dialog v-model="allVisible.transferVisible" width="600" :show-close="false" top="10vh">
             <template #header="{ close, titleId, titleClass }">
                 <div class="flex justify-between items-center border-b pb-3 dialog-header">
                     <h4 :id="titleId">{{ allText.operationText }}</h4>
                     <div>
-                        <el-button type="primary" :loading="allLoading.transferLoading">转移</el-button>
+                        <el-button type="primary" :loading="allLoading.transferLoading"
+                            @click="transferChange()">转移</el-button>
                         <el-button @click="allVisible.transferVisible = false">取消</el-button>
                     </div>
                 </div>
@@ -46,7 +28,7 @@
             <div class="scroll-bar m-6">
                 <div class="flex mb-4">
                     <div class="w-20 flex items-center justify-end pr-4">转移至:</div>
-                    <el-select v-model="transferValue" placeholder="请选择" class="flex1">
+                    <el-select v-model.trim="transferValue" placeholder="请选择" class="flex1">
                         <el-option v-for="item in transferOptions" :key="item.value" :label="item.label"
                             :value="item.value" />
                     </el-select>
@@ -54,6 +36,25 @@
                 <div class="pl-3 text-[#e94a4a]">转移后,将看不到此联系人</div>
             </div>
         </el-dialog>
+
+        <el-dialog v-model="allVisible.editOrderVisible" width="1000" :show-close="false" top="10vh">
+            <template #header="{ close, titleId, titleClass }">
+                <div class="flex justify-between items-center border-b pb-3 dialog-header">
+                    <h4 :id="titleId">编辑销售订单</h4>
+                    <div>
+                        <el-button type="primary" @click="editOrderSave()"
+                            :loading="allLoading.editOrderSaveLoading">保存</el-button>
+                        <el-button @click="closeVisible('editOrderVisible')">取消</el-button>
+                    </div>
+                </div>
+            </template>
+            <div class="h-[60vh] overflow-y-auto scroll-bar pt-3">
+                <div class="ml-4 mr-4" v-loading="allLoading.orderTemplateLoading">
+                    <GenerateForm ref="orderTemplateRef" :data="orderTemplate" :value="orderTemplateValue"
+                        :key="orderTemplateKey" />
+                </div>
+            </div>
+        </el-dialog>
     </div>
 </template>
 <script lang="ts" setup>
@@ -61,34 +62,112 @@ import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffec
 import { GenerateForm } from '@zmjs/form-design';
 import { getFromValue, getTemplateKey } from '@/utils/tools';
 import { get, post } from '@/utils/request';
+import { GETGENERATEFOEM, GETPERSONNEL, URL_OEDERUPDATE, URL_PRODUTWITHORDER, URL_TRANSFER } from '../api';
+import { formatDate } from '@/utils/times';
 
 const globalPopup = inject<GlobalPopup>('globalPopup')
 const emits = defineEmits(['refreshData']);
 const props = defineProps<{
-    data?: any
+    data: any
 }>()
 const allLoading = reactive({
-    contactsTemplateRefLoading: false,
-    editContactsSaveLoading: false,
+    orderTemplateLoading: false,
+    editOrderSaveLoading: false,
     transferLoading: false
 })
 const allVisible = reactive({
-    editContactsVisible: false,
+    editOrderVisible: false,
     transferVisible: false
 })
 const allText = reactive({
     operationText: '认领联系人'
 })
-const contactsTemplate = ref({
+const orderTemplate = ref({
     list: [],
     config: {}
 })
-const contactsTemplateValue = ref({})
-const contactsTemplateRef = ref<typeof GenerateForm>()
-const contactsTemplateRefKey = ref(1)
+const orderTemplateValue = ref({})
+const orderTemplateKey = ref(1)
+const orderTemplateRef = ref<typeof GenerateForm>()
 const info: any = ref({})
 const transferValue = ref('')
 const transferOptions = ref<optionType[]>([])
+const productTableListValue = ref([])
+
+function editOrderSave() {
+    orderTemplateRef.value?.getData().then((res: any) => {
+        allLoading.editOrderSaveLoading = true
+        post(URL_OEDERUPDATE, {
+            ...orderTemplateValue.value,
+            ...res,
+            orderEndDate: res.orderEndDate ? formatDate(res.orderEndDate) : '',
+            orderStartDate: res.orderStartDate ? formatDate(res.orderStartDate) : '',
+            orderProductDetailString: JSON.stringify(productTableListValue.value || [])
+        }).then((_res) => {
+            closeVisible('editOrderVisible')
+            globalPopup?.showSuccess('操作成功')
+            emits('refreshData', 'getDetail')
+        }).finally(() => {
+            allLoading.editOrderSaveLoading = false
+        })
+    }).catch((_err: any) => {
+        console.log(_err)
+        globalPopup?.showError('请填写完整')
+    })
+}
+
+function editInfo(item: any) {
+    showVisible('editOrderVisible')
+    allLoading.orderTemplateLoading = true
+    if (item) {
+        const templateKey = getTemplateKey(orderTemplate.value.list)
+        let formVal: templateKey = { id: item.id }
+        for (let i = 0; i < templateKey.length; i++) {
+            const key = templateKey[i]
+            formVal[key] = item[key]
+        }
+        console.log(formVal, templateKey, item)
+        orderTemplateValue.value = formVal
+        editProduct(item)
+    }
+
+    setTimeout(() => {
+        orderTemplateKey.value++
+        allLoading.orderTemplateLoading = false
+    }, 500)
+}
+
+function editProduct(row: any) {
+    post(URL_PRODUTWITHORDER, { id: row.id }).then(({ data }) => {
+        const list = data.map((item: any) => {
+            const { id, productName, productCode, unit, unitName, typeName, type, price, inventory, orderProductDetail } = item
+            return {
+                id, productId: id, productName, productCode, unit, unitName, typeName, type, price, inventory,
+                num: +orderProductDetail?.num,
+                discount: +orderProductDetail?.discount,
+                sealPrice: +orderProductDetail?.sealPrice,
+                totalPrice: +orderProductDetail?.totalPrice
+            }
+        })
+        productTableListValue.value = list
+    })
+}
+
+function transferCli() {
+    transferValue.value = ''
+    showVisible('transferVisible')
+}
+
+function transferChange() {
+    allLoading.transferLoading = true
+    post(URL_TRANSFER, { id: info.value.id, userId: transferValue.value }).then(() => {
+        globalPopup?.showSuccess('操作成功')
+        closeVisible('transferVisible')
+        emits('refreshData', 'getDetail')
+    }).finally(() => {
+        allLoading.transferLoading = false
+    })
+}
 
 function showVisible(type: keyof typeof allVisible) {
     allVisible[type] = true
@@ -99,22 +178,51 @@ function closeVisible(type: keyof typeof allVisible) {
 }
 
 const formItems = reactive([
-    { label: '联系人', key: 'name', value: '', labelClass: 'w-20 text-right text-gray-500', width: '48%' },
-    { label: '客户', key: 'productName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '电话', key: 'phone', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '邮箱', key: 'email', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '职务', key: 'position', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '性别', key: 'sexValue', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '地址', key: 'address', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
+    { label: '订单编号', key: 'orderCode', value: '', labelClass: 'w-20 text-right text-gray-500', width: '48%' },
+    { label: '订单名称', key: 'orderName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
+    { label: '客户名称', key: 'customName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
+    { label: '商机名称', key: 'businessOpportunityName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
+    { label: '订单金额', key: 'price', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
+    { label: '回款状态', key: 'receivedStatus', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
+    { label: '已回款金额', key: 'receivedPayment', value: '', labelClass: 'w-24 text-right text-gray-500', width: '48%' },
+    { label: '未回款', key: 'unReceivedPayment', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
+    { label: '订单类型', key: 'type', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
+    { label: '下单时间', key: 'placeTime', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
+    { label: '订单开始时间', key: 'orderStartDate', value: '', labelClass: 'w-30 text-right text-gray-500', width: '48%' },
+    { label: '订单结束时间', key: 'orderEndDate', value: '', labelClass: 'w-30 text-right text-gray-500', width: '48%' },
     { label: '负责人', key: 'inchargerName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
-    { label: '创建人', key: 'creatorName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
+    { label: '创建人', key: 'createName', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
     { label: '创建时间', key: 'createTime', value: '', labelClass: 'w-22 text-right text-gray-500', width: '48%' },
+    { label: '客户签约人', key: 'customSigner', value: '', labelClass: 'w-24 text-right text-gray-500', width: '48%' },
+    { label: '公司签约人', key: 'companySigner', value: '', labelClass: 'w-24 text-right text-gray-500', width: '48%' },
     { label: '备注', key: 'remark', value: '', labelClass: 'w-22 text-right text-gray-500', width: '100%' },
 ])
 
+watchEffect(() => {
+    const { data } = props
+    info.value = data
+    formItems.forEach(item => {
+        item.value = info.value[item.key] || '';
+    });
+})
+
+async function getSystemField() {
+    const { data } = await post(GETPERSONNEL, {})
+    transferOptions.value = data.map((item: any) => {
+        const { id, name, phone, jobNumber } = item
+        return {
+            value: id,
+            label: name
+        }
+    })
+
+    const datas = await get(GETGENERATEFOEM)
+    orderTemplate.value = JSON.parse(datas.data[0].config)
+}
+
 // 生命周期钩子
 onMounted(async () => {
-
+    getSystemField()
 });
 </script>
 <style scoped lang="scss">

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

@@ -0,0 +1,38 @@
+<template>
+    <div class="operationRecord pl-4 pr-4 pt-3 pb-3 h-full flex flex-col">
+        <div class="flex justify-between">
+            <div class="title">操作记录</div>
+        </div>
+        <div class="flex-1 overflow-auto pt-5">
+            <el-table :data="operationRecordtable" border style="width: 100%;height: 278px;">
+                <el-table-column prop="operateDate" label="操作时间" width="150" />
+                <el-table-column prop="operateName" label="操作人" width="120" />
+                <el-table-column prop="msg" label="操作内容" />
+            </el-table>
+        </div>
+    </div>
+</template>
+<script lang="ts" setup>
+import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+const props = defineProps<{
+    data: any
+}>()
+
+const operationRecordtable = ref([])
+
+watchEffect(() => {
+    const { data } = props
+    operationRecordtable.value = data.contactsLogList || []
+});
+// 生命周期钩子
+onMounted(() => {
+});
+</script>
+<style scoped lang="scss">
+.operationRecord {
+    .title {
+        font-size: 18px;
+        color: #000
+    }
+}
+</style>

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

@@ -0,0 +1,185 @@
+<template>
+    <div class="relatedTasks pl-4 pr-4 pt-3 pb-3 h-full flex flex-col">
+        <div class="flex justify-between">
+            <div class="title">相关产品</div>
+            <div class="flex">
+                <el-button type="primary" @click="productClick()">编辑产品</el-button>
+            </div>
+        </div>
+        <div class="flex-1 overflow-auto pt-3">
+            <el-table :data="relatedTaskstable" border style="width: 100%;height: 300px;">
+                <el-table-column label="序号" width="80">
+                    <template #default="scope">
+                        {{ scope.$index + 1 }}
+                    </template>
+                </el-table-column>
+                <el-table-column prop="productName" label="产品名称" width="200">
+                    <template #default="scope">
+                        <el-button link type="primary" size="large">{{
+                            scope.row.productName
+                        }}</el-button>
+                    </template>
+                </el-table-column>
+                <el-table-column prop="productName" label="产品类别" width="130" />
+                <el-table-column prop="typeName" label="产品类型" width="130" />
+                <el-table-column prop="unitName" label="单位" width="130" />
+                <el-table-column prop="price" label="标准价格" width="130" />
+                <el-table-column prop="inventory" label="库存" width="130" />
+                <el-table-column prop="sellingPrice" label="售价" width="130" />
+                <el-table-column prop="quantity" label="数量" width="130" />
+                <el-table-column prop="discount" label="折扣(%)" width="130" />
+                <el-table-column prop="totalPrice" label="合计" width="130" />
+            </el-table>
+        </div>
+
+        <!-- 弹窗 -->
+        <el-dialog v-model="allVisible.editOrderVisible" width="1000" :show-close="false" top="10vh">
+            <template #header="{ close, titleId, titleClass }">
+                <div class="flex justify-between items-center border-b pb-3 dialog-header">
+                    <h4 :id="titleId">{{ '编辑产品' }}</h4>
+                    <div>
+                        <el-button type="primary" :loading="allLoading.editSaveLading" @click="saveOrder()">保存</el-button>
+                        <el-button @click="closeVisible('editOrderVisible')">取消</el-button>
+                    </div>
+                </div>
+            </template>
+            <div class="h-[60vh] overflow-y-auto scroll-bar pt-3" v-loading="allLoading.orderTemplateLoadinng">
+                <RelatedProducts ref="relatedProductsRef" :productTableList="productTableList"
+                    :productTableListValue="productTableListValue" :height="'55vh'" />
+            </div>
+        </el-dialog>
+    </div>
+</template>
+<script lang="ts" setup>
+import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { GETGENERATEFOEM, GETTABLELISTPRODUCT, URL_OEDERUPDATE } from '../api';
+import { get, post } from '@/utils/request';
+import RelatedProducts from '@/components/relatedProducts/relatedProducts.vue'
+import { all } from 'axios';
+import { formatDate } from '@/utils/times';
+import { getTemplateKey } from '@/utils/tools';
+
+const globalPopup = inject<GlobalPopup>('globalPopup')
+const emits = defineEmits(['refreshData']);
+const props = defineProps<{
+    data: any,
+    information: any
+}>()
+const allVisible = reactive({
+    editOrderVisible: false
+})
+const allLoading = reactive({
+    editSaveLading: false,
+    orderTemplateLoadinng: false
+})
+const info = ref({})
+const infoValue = ref({})
+const relatedProductsRef = ref<typeof RelatedProducts>()
+const relatedTaskstable = ref([])
+const productTableListValue = ref([])
+const productTableList = ref([])
+const orderTemplate = ref({
+    list: [],
+    config: {}
+})
+
+function saveOrder() {
+    let productTableListData = relatedProductsRef?.value?.returnData()
+    const items: any = infoValue.value
+    for (var i in productTableListData) {
+        productTableListData[i].sealPrice = productTableListData[i].sellingPrice,
+            productTableListData[i].discount = productTableListData[i].discount,
+            productTableListData[i].num = productTableListData[i].quantity
+    }
+    const produt = productTableListData ? JSON.stringify(productTableListData) : []
+    allLoading.editSaveLading = true
+    post(URL_OEDERUPDATE, {
+        ...items,
+        orderEndDate: items.orderEndDate ? items.orderEndDate : '',
+        orderStartDate: items.orderStartDate ? items.orderStartDate : '',
+        orderProductDetailString: produt
+    }).then(() => {
+        globalPopup?.showSuccess('操作成功')
+        allLoading.editSaveLading = false
+        closeVisible('editOrderVisible')
+        emits('refreshData', 'getRelatedProducts')
+    }).finally(() => {
+        allLoading.editSaveLading = false
+    })
+}
+
+function productClick() {
+    productTableListValue.value = JSON.parse(JSON.stringify(relatedTaskstable.value))
+    showVisible('editOrderVisible')
+}
+
+function showVisible(type: keyof typeof allVisible) { // 显示弹窗
+    allVisible[type] = true
+}
+
+function closeVisible(type: keyof typeof allVisible) {
+    allVisible[type] = false
+}
+
+function getProductTableList() {
+    post(GETTABLELISTPRODUCT, { pageIndex: -1, pageSize: -1 }).then((res) => {
+        if (res.code == 'ok') {
+            const { record, total } = res.data
+            productTableList.value = record.map((item: any) => {
+                const { id, productName, productCode, unit, unitName, typeName, type, price, inventory } = item
+                return {
+                    id,
+                    productId: id,
+                    productName,
+                    productCode,
+                    unit,
+                    unitName,
+                    price,
+                    type,
+                    typeName,
+                    inventory,
+                    quantity: '',
+                    discount: '',
+                    totalPrice: ''
+                }
+            })
+        }
+    })
+}
+
+async function getSystemField() {
+    const datas = await get(GETGENERATEFOEM)
+    orderTemplate.value = JSON.parse(datas.data[0].config)
+    setInfoValue(info.value)
+}
+
+function setInfoValue(item: any) {
+    const templateKey = getTemplateKey(orderTemplate.value.list)
+    let formVal: templateKey = { id: item.id }
+    for (let i = 0; i < templateKey.length; i++) {
+        const key = templateKey[i]
+        formVal[key] = item[key]
+    }
+    infoValue.value = formVal
+}
+
+watchEffect(() => {
+    const { data, information } = props
+    relatedTaskstable.value = data || []
+    info.value = information || {}
+});
+
+// 生命周期钩子
+onMounted(() => {
+    getProductTableList()
+    getSystemField()
+});
+</script>
+<style scoped lang="scss">
+.relatedTasks {
+    .title {
+        font-size: 18px;
+        color: #000
+    }
+}
+</style>

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

@@ -0,0 +1,134 @@
+<template>
+    <div class="operationRecord pl-4 pr-4 pt-3 pb-3 h-full flex flex-col">
+        <div class="flex justify-between">
+            <div class="title">回款</div>
+            <div class="flex">
+                <el-button type="primary" @click="editRebate(false)">新增回款</el-button>
+            </div>
+        </div>
+        <div class="flex-1 overflow-auto pt-5">
+            <el-table :data="operationRecordtable" border style="width: 100%;height: 278px;">
+                <el-table-column prop="createTime" label="回款时间" width="170" />
+                <el-table-column prop="creatorName" label="操作人" width="120" />
+                <el-table-column prop="money" label="回款金额" width="120" />
+                <el-table-column prop="unReceivedPayment" label="未回款金额" width="120" />
+                <el-table-column :label="'操作'" :width="'120px'" fixed="right">
+                    <template #default="scope">
+                        <el-button link type="primary" size="large" @click="editRebate(scope.row)">编辑</el-button>
+                        <el-button link type="danger" size="large" @click="deteItem(scope.row)">删除</el-button>
+                    </template>
+                </el-table-column>
+            </el-table>
+        </div>
+
+        <!-- 弹窗 -->
+        <el-dialog v-model="allVisible.rebateVisible" 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">{{ allText.rebateText }}</h4>
+                    <div class="flex">
+                        <el-button @click="allVisible.rebateVisible = false">取消</el-button>
+                        <el-button type="primary" @click="saveRebate" :loading="allLoading.rebateLoading">保存</el-button>
+                    </div>
+                </div>
+            </template>
+            <div class="p-8">
+                <div class="flex flex-row items-center">
+                    <div>回款金额:</div>
+                    <div class="flex-1">
+                        <el-input v-model.trim="mony" v-enterNumber placeholder="请输入" clearable class="w-full"></el-input>
+                    </div>
+                    <div class="ml-4">元</div>
+                </div>
+            </div>
+        </el-dialog>
+    </div>
+</template>
+<script lang="ts" setup>
+import { post } from '@/utils/request';
+import { ref, reactive, onMounted, onUnmounted, defineExpose, inject, watchEffect } from 'vue'
+import { URL_ADDREBATE, URL_DETELEITEMS, URL_EDITEBATE } from '../api';
+import { confirmAction } from '@/utils/tools';
+import { ITEM_RENDER_EVT } from 'element-plus/es/components/virtual-list/src/defaults';
+const globalPopup = inject<GlobalPopup>('globalPopup')
+const emits = defineEmits(['refreshData']);
+const props = defineProps<{
+    data: any,
+    information: any
+}>()
+
+const allVisible = reactive({
+    rebateVisible: false,
+})
+const allLoading = reactive({
+    rebateLoading: false
+})
+const allText = reactive({
+    rebateText: '新增回款'
+})
+
+const operationRecordtable = ref([])
+const mony = ref('')
+const monyItem = ref<any>({})
+const info = ref<any>({})
+
+function deteItem(item: any) {
+    confirmAction(`确定删除该回款记录吗?`).then(() => {
+        post(URL_DETELEITEMS, { paymentId: item.id }).then((_res) => {
+            globalPopup?.showSuccess('删除成功')
+            emits('refreshData', 'getPaymentCollectionList')
+        }).catch((err) => {
+            globalPopup?.showError(err.msg || '')
+        })
+    })
+}
+
+function editRebate(item: any) {
+    if (!item) {
+        allText.rebateText = '新增回款'
+        mony.value = ''
+        monyItem.value = {}
+    } else {
+        monyItem.value = item
+        mony.value = item.money
+        allText.rebateText = '编辑回款'
+    }
+
+    allVisible.rebateVisible = true
+}
+
+function saveRebate() {
+    if (!mony.value || mony.value == '.') {
+        globalPopup?.showWarning('请输入金额')
+        return
+    }
+    allLoading.rebateLoading = true
+    const { url, formVal } = Object.keys(monyItem.value).length === 0
+        ? { url: URL_ADDREBATE, formVal: { orderId: info.value.id, money: mony.value } }
+        : { url: URL_EDITEBATE, formVal: { paymentId: monyItem.value.id, money: mony.value } };
+    post(url, { ...formVal }).then(() => {
+        globalPopup?.showSuccess('操作成功')
+        allVisible.rebateVisible = false
+        emits('refreshData', 'getPaymentCollectionList')
+    }).finally(() => {
+        allLoading.rebateLoading = false
+    })
+}
+
+watchEffect(() => {
+    const { data, information } = props
+    operationRecordtable.value = data || []
+    info.value = information
+});
+// 生命周期钩子
+onMounted(() => {
+});
+</script>
+<style scoped lang="scss">
+.operationRecord {
+    .title {
+        font-size: 18px;
+        color: #000
+    }
+}
+</style>

+ 126 - 4
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/detail/index.vue

@@ -7,7 +7,7 @@
                 </el-link>
             </div>
             <div class="mr-8">
-                <el-select v-model="values" placeholder="请选择" style="width: 300px">
+                <el-select v-model="values" placeholder="请选择" style="width: 300px" @change="getAll('')">
                     <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
                 </el-select>
             </div>
@@ -16,10 +16,29 @@
         <div class="flex-1 flex flex-col overflow-y-auto overflow-x-hidden scroll-bar" v-loading="pageLoading">
             <div class="w-full h-auto flex justify-between">
                 <div class="bg-white shadow-md rounded-md" style="width: 46%;">
-                    <Information />
+                    <Information :data="information" @refreshData="getAll" />
                 </div>
                 <div class="bg-white ml-2 shadow-md rounded-md flex-1">
-                    <Attachment />
+                    <Attachment :data="attachment" :information="information" @refreshData="getAll" />
+                </div>
+            </div>
+
+            <div class="w-full h-auto flex justify-between mt-2">
+                <div class="bg-white shadow-md rounded-md" style="width: 65%;">
+                    <Detailcompinents :data="relatedTasks" :information="information" :formTaskType="2" :filed="'orderId'"
+                        :disabled-list="['taskType', 'orderId']" @refreshData="refreshData" />
+                </div>
+                <div class="bg-white ml-2 shadow-md rounded-md flex-1">
+                    <OperationRecord :data="operationRecord" />
+                </div>
+            </div>
+
+            <div class="w-full h-auto flex justify-between mt-2">
+                <div class="bg-white shadow-md rounded-md" style="width: 65%;">
+                    <Products :data="relatedProducts" :information="information" @refreshData="getAll" />
+                </div>
+                <div class="bg-white ml-2 shadow-md rounded-md flex-1" style="width: 33%;">
+                    <Rebate :data="paymentCollectionList" :information="information" @refreshData="getAll" />
                 </div>
             </div>
         </div>
@@ -32,10 +51,15 @@ 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 { GETTABLELIST } from "../api";
+import { GETTABLELIST, IMPORTMOD, URL_DETEALORDER, URL_FERDETAILTASK, URL_PAYLIST, URL_PRODUTWITHORDER } from "../api";
 
 import Information from '../component/information.vue'
 import Attachment from '../component/attachment.vue'
+import OperationRecord from '../component/operationRecord.vue'
+import Products from '../component/products.vue'
+import Rebate from '../component/rebate.vue'
+import Detailcompinents from '@/components/detailcompinents/relatedTasks.vue'
+import { GETATTACHMENT, GETCENTERLIST } from "@/pages/product/api";
 
 const route = useRoute()
 const globalPopup = inject<GlobalPopup>('globalPopup')
@@ -43,17 +67,115 @@ const pageLoading = ref(false)
 const rowId = ref(+(route.query.id || ''))
 const values = ref<number | string>('')
 const options = ref<optionType[]>([])
+const information = ref({}) // 基本信息
+const attachment = ref<any[]>([]) // 附件信息
+const relatedTasks = ref<any[]>([]) // 相关任务
+const operationRecord = ref<any[]>([]) // 操作记录
+const relatedProducts = ref<any[]>([]) // 相关产品
+const paymentCollectionList = ref<any[]>([]) // 回款
+
+// 获取基本信息
+function getDetail() {
+    post(URL_DETEALORDER, { id: values.value }).then(({ data }) => {
+        information.value = data
+    })
+}
 
+// 获取附件
+function getFileList() {
+    post(GETATTACHMENT, { moduleId: values.value, moduleCode: IMPORTMOD }).then((res) => {
+        attachment.value = res.data
+    })
+}
+
+// 获取所有销售订单
 function getAllContacts() {
     post(GETTABLELIST, { pageIndex: -1, pageSize: -1 }).then(({ data }) => {
         options.value = (data.record || []).map((item: any) => ({ value: item.id, label: item.orderName }))
+        values.value = rowId.value
     }).catch((err) => {
         globalPopup?.showError(err.message)
     })
 }
 
+// 获取相关任务
+function getRelatedTasks() {
+    post(URL_FERDETAILTASK, { id: values.value }).then(({ data }) => {
+        relatedTasks.value = data
+    })
+}
+function refreshData() {
+    getAll('getRelatedTasks')
+}
+
+// 获取操作记录
+function getOperationRecord() {
+    post(GETCENTERLIST, { id: values.value, moduleCode: 'SalesOrder' }).then(({ data }) => {
+        operationRecord.value = data
+    })
+}
+
+function getPaymentCollectionList() {
+    post(URL_PAYLIST, { orderId: values.value }).then(({ data }) => {
+        paymentCollectionList.value = data || []
+    })
+}
+
+// 获取相关产品
+function getRelatedProducts() {
+    post(URL_PRODUTWITHORDER, { id: values.value }).then(({ data }) => {
+        const list = (data || []).map((item: any) => {
+            const { id, productName, productCode, unit, unitName, typeName, type, price, inventory, orderProductDetail } = item
+            return {
+                id, productId: id, productName, productCode, unit, unitName, typeName, type, price, inventory,
+                quantity: +orderProductDetail?.num,
+                discount: +orderProductDetail?.discount,
+                sellingPrice: +orderProductDetail?.sealPrice,
+                totalPrice: +orderProductDetail?.totalPrice
+            }
+        })
+        relatedProducts.value = list
+    })
+}
+
+type allTypeStr = 'getDetail' | 'getFileList' | 'getRelatedTasks' | 'getOperationRecord' | 'getRelatedProducts' | 'getPaymentCollectionList' | ''
+
+async function getAll(event: allTypeStr) {
+    try {
+        pageLoading.value = true
+        if (!event) {
+            await Promise.all([
+                getDetail(),
+                getFileList(),
+                getRelatedTasks(),
+                getOperationRecord(),
+                getRelatedProducts(),
+                getPaymentCollectionList()
+            ])
+        } else if (event == 'getDetail') {
+            await getDetail()
+        } else if (event == 'getFileList') {
+            await getFileList()
+        } else if (event == 'getRelatedTasks') {
+            await getFileList()
+        } else if (event == 'getOperationRecord') {
+            await getOperationRecord()
+        } else if (event == 'getRelatedProducts') {
+            await getRelatedProducts()
+        } else if (event == 'getPaymentCollectionList') {
+            await getPaymentCollectionList()
+        }
+
+        pageLoading.value = false
+    } catch {
+        pageLoading.value = false
+    }
+}
+
 onMounted(() => {
+    values.value = rowId.value
     getAllContacts()
+    getAll('')
 })
 
 </script>

+ 6 - 7
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/order/index.vue

@@ -88,10 +88,10 @@
         </div>
       </template>
       <div class="h-[60vh] overflow-y-auto scroll-bar pt-3" v-loading="allLoading.orderTemplateLoadinng">
-        <GenerateForm ref="orderTemplateRef" :data="orderTemplate" :value="orderTemplateValue" />
+        <GenerateForm ref="orderTemplateRef" :data="orderTemplate" :key="orderTemplateKey" :value="orderTemplateValue" />
         <div>相关产品</div>
         <RelatedProducts ref="relatedProductsRef" :productTableList="productTableList"
-          :productTableListValue="productTableListValue" />
+          :productTableListValue="productTableListValue"  />
       </div>
     </el-dialog>
 
@@ -277,7 +277,6 @@ function submitForm(submitData: any, isClose: boolean) {
 function newTask(item: any) {
   const { id } = item
   taskModalForm.value = { ...createTaskFromType(2), orderId: id, }
-  console.log(taskModalForm.value)
   allVisible.taskModalVisible = true
 }
 
@@ -308,7 +307,6 @@ function saveOrder(flag: boolean) {
       allLoading.editSaveLading = false
     })
   }).catch((_err: any) => {
-    console.log(_err)
     globalPopup?.showError('请填写完整')
   })
 }
@@ -320,11 +318,12 @@ function editOrder(item: any) {
     editProduct(item)
     const templateKey = getTemplateKey(orderTemplate.value.list)
     let formVal: templateKey = { id: item.id }
-    for (let i = 0; i < orderTemplate.value.list.length; i++) {
+    for (let i = 0; i < templateKey.length; i++) {
       const key = templateKey[i]
       formVal[key] = item[key]
     }
     orderTemplateValue.value = formVal
+    console.log(formVal, '<============ 数据')
     allText.orderEditText = '编辑订单'
   }
   if (!item) {
@@ -333,9 +332,10 @@ function editOrder(item: any) {
     allText.orderEditText = '新增订单'
   }
   setTimeout(() => {
+    orderTemplateRef.value && orderTemplateRef.value.reset()
     orderTemplateKey.value++
     allLoading.orderTemplateLoadinng = false
-  }, 500)
+  }, 1000)
 }
 
 function toDetali(row: any) {
@@ -441,7 +441,6 @@ function editProduct(row: any) {
         totalPrice: +orderProductDetail?.totalPrice
       }
     })
-    console.log('开始执行', list)
     productTableListValue.value = list
   })
 }

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

@@ -93,7 +93,7 @@ async function getDetail(flag: boolean) {
       getInformationData(id),
       getFileList(id),
       post(GETCENTERLIST, { id, moduleCode: MODUCODE }).then((res) => {
-        operationRecord.value = res.datag
+        operationRecord.value = res.data
       }),
       post(GETORDER, { id }).then((res) => {
         products.value = res.data

+ 20 - 2
fhKeeper/formulahousekeeper/customerBuler-crm/src/utils/customInstructions.ts

@@ -1,4 +1,4 @@
-import { Directive } from 'vue';
+import { Directive, ObjectDirective } from 'vue';
 
 // 权限控制
 const PermissionDirective: Directive = {
@@ -19,6 +19,23 @@ const PermissionDirective: Directive = {
     }
 };
 
+const PositiveIntegerDirective: ObjectDirective = {
+    mounted(el: HTMLElement) {
+        el.addEventListener('input', handleInput);
+    },
+    beforeUnmount(el: HTMLElement) {
+        el.removeEventListener('input', handleInput);
+    },
+};
+
+function handleInput(event: Event) {
+    const input = event.target as HTMLInputElement;
+    const regex = /^\d*\.?\d*$/;
+    if (!regex.test(input.value)) {
+        input.value = input.value.replace(/[^\d\.]/g, '');
+    }
+}
+
 function extractPath(str: any) {
     const startIndex = str.indexOf('/');
     const endIndex = str.indexOf('/', startIndex + 1);
@@ -27,7 +44,8 @@ function extractPath(str: any) {
 
 // 导出的自定义指令
 const customize = [
-    { key: 'permission', directive: PermissionDirective, name: '角色权限' }
+    { key: 'permission', directive: PermissionDirective, name: '角色权限' },
+    { key: 'enterNumber', directive: PositiveIntegerDirective, name: 'input正整数' }
 ]
 
 export default customize;

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

@@ -3,7 +3,7 @@ import vue from '@vitejs/plugin-vue';
 
 import { resolve } from 'path';
 
-const target = 'http://192.168.2.8:10010';
+const target = 'http://192.168.2.142:10010';
 // const target = "http://127.0.0.1:10010";
 // const target = "http://192.168.2.178:10010";
 // const target = 'http://47.101.180.183:10010';

+ 95 - 11
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/controller/SalesOrderController.java

@@ -85,6 +85,9 @@ public class SalesOrderController {
         Integer companyId = user.getCompanyId();
         order.setCompanyId(companyId);
         order.setCreatorId(user.getId());
+        if(order.getPrice()!=null){
+            order.setUnReceivedPayment(order.getPrice());
+        }
         int count;
         if(order.getId()==null){
             count = salesOrderService.count(new LambdaQueryWrapper<SalesOrder>().eq(SalesOrder::getCompanyId, companyId).eq(SalesOrder::getOrderCode, order.getOrderCode()));
@@ -99,7 +102,8 @@ public class SalesOrderController {
         AuditLogCenter auditLogCenter =new AuditLogCenter();
         auditLogCenter.setAuditorId(user.getId());
         auditLogCenter.setAuditorName(user.getName());
-        boolean isNew=true;
+        auditLogCenter.setModuleId(order.getId());
+        auditLogCenter.setModuleCode("SalesOrder");;
         if(order.getId()==null){
             auditLogCenter.setAuditorContent("创建了订单");
         }else {
@@ -108,14 +112,11 @@ public class SalesOrderController {
             String content = beanChangeUtil.contrastObj(oldOrder, order);
             //发生变化才生成记录
             if(!StringUtils.isEmpty(content.trim())){
-                isNew=false;
-                auditLogCenter.setModuleId(order.getId());
-                auditLogCenter.setModuleCode("SalesOrder");
                 auditLogCenter.setAuditorContent("编辑了订单");
-                auditLogCenterService.save(auditLogCenter);
             }
 
         }
+        auditLogCenterService.save(auditLogCenter);
         if(!salesOrderService.saveOrUpdate(order)){
             msg.setError("验证失败");
             return msg;
@@ -308,10 +309,17 @@ public class SalesOrderController {
         List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getCompanyId, companyId));
         List<Task> taskList = taskService.list(new LambdaQueryWrapper<Task>().eq(Task::getOrderId, id));
         taskList.forEach(p->{
-            Optional<User> user = userList.stream().filter(u -> u.getId().equals(p.getExecutorId())).findFirst();
-            if(user.isPresent()){
-                p.setExecutorName(user.get().getName());
+            String executorIds = p.getExecutorId();
+            String[] split = executorIds.split(",");
+            List<String> executorNameList=new ArrayList<>();
+            for (String s : split) {
+                Optional<User> user = userList.stream().filter(u -> u.getId().equals(s)).findFirst();
+                if(user.isPresent()){
+                    executorNameList.add(user.get().getName());
+                }
             }
+//            String collect = executorNameList.stream().map(i -> i).collect(Collectors.joining(","));
+            p.setExecutorNames(executorNameList);
         });
         msg.setData(taskList);
         return msg;
@@ -351,8 +359,8 @@ public class SalesOrderController {
     @RequestMapping("/paymentCollection")
     public HttpRespMsg paymentCollection(Integer orderId,Double money){
         HttpRespMsg msg=new HttpRespMsg();
+        User user = userMapper.selectById(request.getHeader("token"));
         SalesOrder salesOrder = salesOrderService.getById(orderId);
-        BigDecimal price = salesOrder.getPrice();
         SalesOrderPayment salesOrderPayment=new SalesOrderPayment();
         salesOrderPayment.setMoney(new BigDecimal(money));
         salesOrderPayment.setOrderId(orderId);
@@ -361,8 +369,8 @@ public class SalesOrderController {
         //订单未回款金额
         BigDecimal unReceivedPayment = salesOrder.getUnReceivedPayment();
         //更新订单数据
-        receivedPayment=receivedPayment.add(price);
-        unReceivedPayment=unReceivedPayment.subtract(price);
+        receivedPayment=receivedPayment.add(new BigDecimal(money));
+        unReceivedPayment=unReceivedPayment.subtract(new BigDecimal(money));
         salesOrder.setReceivedPayment(receivedPayment);
         salesOrder.setUnReceivedPayment(unReceivedPayment);
         if(money>0){
@@ -375,6 +383,7 @@ public class SalesOrderController {
             }
         }
         salesOrderPayment.setUnReceivedPayment(unReceivedPayment);
+        salesOrderPayment.setCreatorId(user.getId());
         salesOrderService.updateById(salesOrder);
         salesOrderPaymentService.save(salesOrderPayment);
         return msg;
@@ -402,11 +411,86 @@ public class SalesOrderController {
     @RequestMapping("/paymentCollectionList")
     public HttpRespMsg paymentCollectionList(Integer orderId){
         HttpRespMsg msg=new HttpRespMsg();
+        User user = userMapper.selectById(request.getHeader("token"));
+        List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getCompanyId, user.getCompanyId()));
         List<SalesOrderPayment> list = salesOrderPaymentService.list(new LambdaQueryWrapper<SalesOrderPayment>().eq(SalesOrderPayment::getOrderId, orderId));
+        list.forEach(l->{
+            Optional<User> first = userList.stream().filter(u -> u.getId().equals(l.getCreatorId())).findFirst();
+            if(first.isPresent()){
+                l.setCreatorName(first.get().getName());
+            }
+        });
         msg.setData(list);
         return msg;
     }
 
 
+    /**
+    * @Description:编辑回款数据
+    * @Param: [paymentId, money]
+    * @return: com.management.platform.util.HttpRespMsg
+    * @Author: yurk
+    * @Date: 2024/5/31
+    */
+    @RequestMapping("/editPayment")
+    public HttpRespMsg editPayment(Integer paymentId,Double money){
+        HttpRespMsg msg=new HttpRespMsg();
+        SalesOrderPayment payment = salesOrderPaymentService.getById(paymentId);
+        SalesOrder salesOrder = salesOrderService.getById(payment.getOrderId());
+        if(money!=null){
+            //找到原回款数据
+            BigDecimal nowMoney = new BigDecimal(money);
+            BigDecimal oldMoney = payment.getMoney();
+            nowMoney=nowMoney.subtract(oldMoney);
+            BigDecimal unReceivedPayment = payment.getUnReceivedPayment();
+            unReceivedPayment=unReceivedPayment.add(nowMoney);
+            payment.setMoney(new BigDecimal(money));
+            payment.setUnReceivedPayment(unReceivedPayment);
+            if(!salesOrderPaymentService.updateById(payment)){
+                msg.setError("验证失败");
+                return msg;
+            }
+            //订单上的已回款金额
+            BigDecimal receivedPayment = salesOrder.getReceivedPayment();
+            receivedPayment=receivedPayment.subtract(oldMoney).add(nowMoney);
+            salesOrder.setReceivedPayment(receivedPayment);
+            salesOrder.setUnReceivedPayment(unReceivedPayment);
+            if(!salesOrderService.updateById(salesOrder)){
+                msg.setError("验证失败");
+                return msg;
+            }
+        }
+       return msg;
+    }
+
+    /**
+    * @Description:删除回款数据
+    * @Param: [paymentId]
+    * @return: com.management.platform.util.HttpRespMsg
+    * @Author: yurk
+    * @Date: 2024/5/31
+    */
+    @RequestMapping("/deletePayment")
+    public HttpRespMsg deletePayment(Integer paymentId){
+        HttpRespMsg msg=new HttpRespMsg();
+        SalesOrderPayment payment = salesOrderPaymentService.getById(paymentId);
+        SalesOrder salesOrder = salesOrderService.getById(payment.getOrderId());
+        BigDecimal oldMoney = payment.getMoney();
+        //订单上的已回款金额
+        BigDecimal receivedPayment = salesOrder.getReceivedPayment();
+        receivedPayment=receivedPayment.subtract(oldMoney);
+        BigDecimal unReceivedPayment = salesOrder.getUnReceivedPayment();
+        unReceivedPayment=unReceivedPayment.add(oldMoney);
+        salesOrder.setReceivedPayment(receivedPayment);
+        salesOrder.setUnReceivedPayment(unReceivedPayment);
+        if(!salesOrderService.updateById(salesOrder)){
+            msg.setError("验证失败");
+            return msg;
+        }
+        salesOrderPaymentService.removeById(paymentId);
+        return msg;
+    }
+
+
 }
 

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

@@ -215,6 +215,12 @@ public class SalesOrder extends Model<SalesOrder> {
     @TableField(exist = false)
     private String creatorName;
 
+    @TableField(exist = false)
+    private String customSignerName;
+
+    @TableField(exist = false)
+    private String companySignerName;
+
     @TableField(exist = false)
     private String businessOpportunityName;
 

+ 24 - 2
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/SalesOrderPayment.java

@@ -1,13 +1,18 @@
 package com.management.platform.entity;
 
 import java.math.BigDecimal;
+import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.extension.activerecord.Model;
 import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
 import com.baomidou.mybatisplus.annotation.TableField;
 import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
 
 /**
  * <p>
@@ -15,7 +20,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2024-05-21
+ * @since 2024-05-31
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -24,7 +29,7 @@ public class SalesOrderPayment extends Model<SalesOrderPayment> {
 
     private static final long serialVersionUID=1L;
 
-    @TableId("id")
+    @TableId(value = "id", type = IdType.AUTO)
     private Integer id;
 
     /**
@@ -45,6 +50,23 @@ public class SalesOrderPayment extends Model<SalesOrderPayment> {
     @TableField("un_received_payment")
     private BigDecimal unReceivedPayment;
 
+    /**
+     * 操作人
+     */
+    @TableField("creator_id")
+    private String creatorId;
+
+    @TableField(exist = false)
+    private String creatorName;
+
+    /**
+     * 操作时间
+     */
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField("create_time")
+    private LocalDateTime createTime;
+
 
     @Override
     protected Serializable pkVal() {

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

@@ -196,6 +196,14 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
             if(incharger.isPresent()){
                 r.setInchargerName(incharger.get().getName());
             }
+            Optional<User> companySigner = userList.stream().filter(u -> u.getId().equals(r.getCompanySigner())).findFirst();
+            if(companySigner.isPresent()){
+                r.setCompanySignerName(companySigner.get().getName());
+            }
+            Optional<User> customSigner = userList.stream().filter(u -> u.getId().equals(r.getCustomSigner())).findFirst();
+            if(customSigner.isPresent()){
+                r.setCustomSignerName(customSigner.get().getName());
+            }
             Optional<SysDict> type = sysDictOfOrderType.stream().filter(s -> s.getId().equals(r.getType())).findFirst();
             if(type.isPresent()){
                 r.setTypeName(type.get().getName());
@@ -241,6 +249,14 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
         if(incharger.isPresent()){
             salesOrder.setInchargerName(incharger.get().getName());
         }
+        Optional<User> companySigner = userList.stream().filter(u -> u.getId().equals(salesOrder.getCompanySigner())).findFirst();
+        if(companySigner.isPresent()){
+            salesOrder.setCompanySignerName(companySigner.get().getName());
+        }
+        Optional<User> customSigner = userList.stream().filter(u -> u.getId().equals(salesOrder.getCustomSigner())).findFirst();
+        if(customSigner.isPresent()){
+            salesOrder.setCustomSignerName(customSigner.get().getName());
+        }
         Optional<SysDict> type = sysDictOfOrderType.stream().filter(s -> s.getId().equals(salesOrder.getType())).findFirst();
         if(type.isPresent()){
             salesOrder.setTypeName(type.get().getName());
@@ -546,7 +562,7 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
     @Override
     public HttpRespMsg exportData(String userId, String orderName, String orderCode, String productCode) throws Exception {
         User user = userMapper.selectById(request.getHeader("token"));
-        SysForm sysForm = sysFormMapper.selectOne(new LambdaQueryWrapper<SysForm>().eq(SysForm::getCompanyId, user.getCompanyId()).eq(SysForm::getCode, "Product").eq(SysForm::getIsCurrent, 1));
+        SysForm sysForm = sysFormMapper.selectOne(new LambdaQueryWrapper<SysForm>().eq(SysForm::getCompanyId, user.getCompanyId()).eq(SysForm::getCode, "Order").eq(SysForm::getIsCurrent, 1));
         WxCorpInfo wxCorpInfo = wxCorpInfoService.getOne(new LambdaQueryWrapper<WxCorpInfo>().eq(WxCorpInfo::getCompanyId, user.getCompanyId()));
         String config = sysForm.getConfig();
         JSONObject configOb = JSON.parseObject(config);
@@ -572,8 +588,8 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
         dataList.add(titleList);
         HttpRespMsg respMsg = getList( userId,null, orderName,orderCode,null,null,null,null,null,productCode, null,null,0);
         Map<String, Object> msgData = (Map<String, Object>) respMsg.getData();
-        List<Product> productList = (List<Product>) msgData.get("record");
-        for (Product product : productList) {
+        List<SalesOrder> salesOrderList = (List<SalesOrder>) msgData.get("record");
+        for (SalesOrder salesOrder : salesOrderList) {
             List<String> item=new ArrayList<>();
             for (int i = 0; i < configObJSONArray.size(); i++) {
                 JSONObject target = configObJSONArray.getJSONObject(i);
@@ -586,13 +602,13 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
                             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));
+                            Class<? extends SalesOrder> aClass = salesOrder.getClass();
+                            String value = String.valueOf(aClass.getMethod("get" + targetName).invoke(salesOrder)==null?"":aClass.getMethod("get" + targetName).invoke(salesOrder));
                             if(model.equals("inchargerId")){
                                 if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
-                                    value = "$userName"+String.valueOf(aClass.getMethod("getInchargerName").invoke(product))+"$";
+                                    value = "$userName"+String.valueOf(aClass.getMethod("getInchargerName").invoke(salesOrder))+"$";
                                 }else {
-                                    value = String.valueOf(aClass.getMethod("getInchargerName").invoke(product));
+                                    value = String.valueOf(aClass.getMethod("getInchargerName").invoke(salesOrder));
                                 }
                             }
                             item.add(value);
@@ -601,13 +617,13 @@ public class SalesOrderServiceImpl extends ServiceImpl<SalesOrderMapper, SalesOr
                 }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));
+                    Class<? extends SalesOrder> aClass = salesOrder.getClass();
+                    String value = String.valueOf(aClass.getMethod("get" + targetName).invoke(salesOrder)==null?"":aClass.getMethod("get" + targetName).invoke(salesOrder));
                     if(model.equals("inchargerId")){
                         if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
-                            value = "$userName"+String.valueOf(aClass.getMethod("getInchargerName").invoke(product))+"$";
+                            value = "$userName"+String.valueOf(aClass.getMethod("getInchargerName").invoke(salesOrder))+"$";
                         }else {
-                            value = String.valueOf(aClass.getMethod("getInchargerName").invoke(product));
+                            value = String.valueOf(aClass.getMethod("getInchargerName").invoke(salesOrder));
                         }
                     }
                     item.add(value);

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

@@ -8,11 +8,13 @@
         <result column="order_id" property="orderId" />
         <result column="money" property="money" />
         <result column="un_received_payment" property="unReceivedPayment" />
+        <result column="creator_id" property="creatorId" />
+        <result column="create_time" property="createTime" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, order_id, money, un_received_payment
+        id, order_id, money, un_received_payment, creator_id, create_time
     </sql>
 
 </mapper>

+ 5 - 5
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserWithBeisenController.java

@@ -237,7 +237,7 @@ public class UserWithBeisenController {
                                 if(LocalDateTime.parse(o.getString("StartDate"),df1).toLocalDate().isEqual(LocalDateTime.parse(o.getString("StopDate"),df1).toLocalDate())){
                                     //开始日期和结束日期是相同的情况 说明是加班区间只存在于当天的情况
                                     //判断打卡时间是不是大于19:00 大于才算加班 通过打卡计算加班时长 与加班单作比较 取小
-                                    Duration timeDurantion = Duration.between(LocalTime.parse("18:00:00", df4), max.get());
+                                    Duration timeDurantion = Duration.between(LocalTime.parse(workDay?"18:00:00":"08:30:00", df4), max.get());
                                     BigDecimal decimal = new BigDecimal(timeDurantion.toMinutes());
                                     decimal=decimal.divide(new BigDecimal(60),1,RoundingMode.HALF_UP);
                                     double l = decimal.doubleValue();
@@ -255,7 +255,7 @@ public class UserWithBeisenController {
                                     decimal=decimal.divide(new BigDecimal(60),1,RoundingMode.HALF_UP);
                                     double l = decimal.doubleValue();
                                     //判断打卡时间是不是大于19:00 通过打卡计算加班时长 与加班单作比较 取小
-                                    Duration timeDurantion = Duration.between(LocalTime.parse("18:00:00", df4), max.get());
+                                    Duration timeDurantion = Duration.between(LocalTime.parse(workDay?"18:00:00":"08:30:00", df4), max.get());
                                     BigDecimal decimal1 = new BigDecimal(timeDurantion.toMinutes());
                                     decimal1=decimal1.divide(new BigDecimal(60),1,RoundingMode.HALF_UP);
                                     double l1 = decimal1.doubleValue();
@@ -270,7 +270,7 @@ public class UserWithBeisenController {
                                 if(LocalDateTime.parse(o.getString("StartDate"),df1).toLocalDate().isEqual(LocalDateTime.parse(o.getString("StopDate"),df1).toLocalDate())){
                                     //开始日期和结束日期是相同的情况 说明是加班区间只存在于当天的情况
                                     //判断打卡时间是不是大于19:00 通过打卡计算加班时长 与加班单作比较 取小
-                                    Duration timeDurantion = Duration.between(LocalTime.parse("18:00:00", df4), max.get());
+                                    Duration timeDurantion = Duration.between(LocalTime.parse(workDay?"18:00:00":"08:30:00", df4), max.get());
                                     BigDecimal decimal = new BigDecimal(timeDurantion.toMinutes());
                                     decimal=decimal.divide(new BigDecimal(60),1,RoundingMode.HALF_UP);
                                     double l = decimal.doubleValue();
@@ -288,7 +288,7 @@ public class UserWithBeisenController {
                                     decimal=decimal.divide(new BigDecimal(60),1,RoundingMode.HALF_UP);
                                     double l = decimal.doubleValue();
                                     //判断打卡时间是不是大于19:00 通过打卡计算加班时长 与加班单作比较 取小
-                                    Duration timeDurantion = Duration.between(LocalTime.parse("18:00:00", df4), max.get());
+                                    Duration timeDurantion = Duration.between(LocalTime.parse(workDay?"18:00:00":"08:30:00", df4), max.get());
                                     BigDecimal decimal1 = new BigDecimal(timeDurantion.toMinutes());
                                     decimal1=decimal1.divide(new BigDecimal(60),1,RoundingMode.HALF_UP);
                                     double l1 = decimal1.doubleValue();
@@ -402,7 +402,7 @@ public class UserWithBeisenController {
                     leaveSheet.setRemark(jsonObject.getString("Reason"));
                     leaveSheet.setStatus(jsonObject.getString("ApproveStatus").equals("通过")?0:jsonObject.getString("Reason").equals("审批中")?1:2);
                     leaveSheet.setProcinstId(jsonObject.getString("VacationId"));
-                    LeaveSheet one = leaveSheetService.getOne(new LambdaQueryWrapper<LeaveSheet>().eq(LeaveSheet::getProcinstId,leaveSheet.getProcinstId()).eq(LeaveSheet::getOwnerId, first.get().getId()).eq(LeaveSheet::getStartDate, leaveSheet.getStartDate()).eq(LeaveSheet::getEndDate, endDate));
+                    LeaveSheet one = leaveSheetService.getOne(new LambdaQueryWrapper<LeaveSheet>().eq(LeaveSheet::getProcinstId,leaveSheet.getProcinstId()).eq(LeaveSheet::getOwnerId, first.get().getId()).eq(LeaveSheet::getStartDate, leaveSheet.getStartDate()).eq(LeaveSheet::getEndDate, leaveSheet.getEndDate()));
                     if(one==null){
                         leaveSheetList.add(leaveSheet);
                     }

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

@@ -2350,7 +2350,7 @@ public class TimingTask {
                     leaveSheet.setRemark(jsonObject.getString("Reason"));
                     leaveSheet.setStatus(jsonObject.getString("ApproveStatus").equals("通过")?0:jsonObject.getString("Reason").equals("审批中")?1:2);
                     leaveSheet.setProcinstId(jsonObject.getString("VacationId"));
-                    LeaveSheet one = leaveSheetService.getOne(new LambdaQueryWrapper<LeaveSheet>().eq(LeaveSheet::getOwnerId, first.get().getId()).eq(LeaveSheet::getStartDate, leaveSheet.getStartDate()).eq(LeaveSheet::getProcinstId,leaveSheet.getProcinstId()).eq(LeaveSheet::getEndDate, endDate));
+                    LeaveSheet one = leaveSheetService.getOne(new LambdaQueryWrapper<LeaveSheet>().eq(LeaveSheet::getOwnerId, first.get().getId()).eq(LeaveSheet::getStartDate, leaveSheet.getStartDate()).eq(LeaveSheet::getProcinstId,leaveSheet.getProcinstId()).eq(LeaveSheet::getEndDate, leaveSheet.getEndDate()));
                     if(one==null){
                         leaveSheetList.add(leaveSheet);
                     }