Przeglądaj źródła

工作台相关功能调整,报销等流程调整

wangqiang 1 rok temu
rodzic
commit
da095d3fba
40 zmienionych plików z 8257 dodań i 87 usunięć
  1. 2 1
      api/AppPath.js
  2. 23 1
      api/auth/loginService.js
  3. 144 0
      api/cw/invoice/CwFinanceInvoiceService.js
  4. 133 0
      api/cw/projectRecords/ProjectRecordsService.js
  5. 113 0
      api/cw/reimbursementApproval/ReimbursementApprovalService.js
  6. 47 0
      api/cw/reimbursementApproval/ReimbursementApprovalTypeService.js
  7. 153 0
      api/cw/workClientInfo/WorkClientService.js
  8. 70 0
      api/dailyOfficeWork/HolidayService.js
  9. 61 0
      api/human/depart/DepartRegistrationService.js
  10. 33 0
      api/human/depart/HandoverService.js
  11. 55 0
      api/materialManagement/MaterialManagementService.js
  12. 40 0
      api/materialManagement/SupplierService.js
  13. 14 0
      api/sys/OSSService.js
  14. 15 0
      api/sys/userService.js
  15. 1 1
      components/user-select/user-select-dialog.vue
  16. 178 0
      components/user-select/user-select-radio.vue
  17. 3 3
      pages/addressbook/addressbook.vue
  18. 169 0
      pages/cw/invoice/EmailForm.vue
  19. 1009 0
      pages/cw/invoice/InvoiceFormTask.vue
  20. 269 0
      pages/cw/invoice/InvoiceProjectChoose.vue
  21. 154 0
      pages/cw/invoice/WorkPlaceChoose.vue
  22. 162 0
      pages/cw/reimbursementApproval/info/CwProjectChoose.vue
  23. 115 0
      pages/cw/reimbursementApproval/info/CwReportChoose.vue
  24. 627 0
      pages/cw/reimbursementApproval/info/ReimbursementChoose.vue
  25. 1451 0
      pages/cw/reimbursementApproval/info/ReimbursementForm.vue
  26. 718 0
      pages/dailyOfficeWork/holiday/HolidayForm.vue
  27. 366 0
      pages/human/depart/handover/HandoverAddForm.vue
  28. 426 0
      pages/human/depart/registration/DepartRegistrationAddForm.vue
  29. 211 12
      pages/login/login.vue
  30. 137 21
      pages/materialManagement/collect/CollectForm.vue
  31. 104 0
      pages/materialManagement/purchase/MyDropdown.vue
  32. 961 0
      pages/materialManagement/purchase/PurchaseForm.vue
  33. 100 0
      pages/materialManagement/purchase/SupplierSelector.vue
  34. 3 2
      pages/workbench/task/ApplyList.vue
  35. 1 0
      pages/workbench/task/HistoryList.vue
  36. 64 10
      pages/workbench/task/TaskForm.vue
  37. 30 4
      pages/workbench/task/TaskFormDetail.vue
  38. 5 3
      pages/workbench/task/TaskFormEdit.vue
  39. 4 0
      pages/workbench/task/TodoList.vue
  40. 86 29
      pages/workbench/workbench.vue

+ 2 - 1
api/AppPath.js

@@ -12,4 +12,5 @@ export const REGISTER_PATH = "/human-server";
 export const PUBLIC_MODULES_PATH = "/public-modules-server";
 //中审
 export const CENTRECAREFUL_PATH = "/centrecareful-server";
-export const ASSESS_PATH = "/assess-server";
+export const ASSESS_PATH = "/assess-server";
+export const FINANCE_PATH = "/finance-server";

+ 23 - 1
api/auth/loginService.js

@@ -1,5 +1,6 @@
 import request from "../../common/request"
 import { AUTH_PATH as prefix } from "../AppPath";
+import { SYS_PATH as sysPrefix } from "../AppPath";
 
 export default {
   getCode: function () {
@@ -20,5 +21,26 @@ export default {
 	  url: prefix + "/user/logout",
       method: 'get'
     })
-  }
+  },
+  getLoginCodeNumber: function (userName) {
+    return request({
+      url: prefix + "/user/getLoginCodeNumber",
+      method: "get",
+      params: { userName: userName },
+    })
+  },
+  getPhoneCode (loginForm) {
+    return request({
+      url: sysPrefix + '/sys/user/getPhoneCode',
+      method: 'get',
+      params: {mobile: loginForm},
+    })
+  },
+  savePwd: function (loginForm) {
+    return request({
+      url:sysPrefix + "/sys/user/saveNewPassword",
+      method:"get",
+      params:{mobile:loginForm.phoneNumber,code:loginForm.phoneCode,newPassword: loginForm.newPassword},
+    })
+  },
 }

+ 144 - 0
api/cw/invoice/CwFinanceInvoiceService.js

@@ -0,0 +1,144 @@
+import request from '@/common/request';
+import { FINANCE_PATH as prefix } from "@/api/AppPath";
+
+export default {
+	list: function (params) {
+		return request({
+			url: prefix + "/cw_finance/invoice/list",
+			method: "get",
+			params: params,
+		});
+	},
+	queryById: function (id) {
+		return request({
+			url: prefix + "/cw_finance/invoice/queryById",
+			method: "get",
+			params: { id: id },
+		});
+	},
+	queryByNumber: function (number, id) {
+		return request({
+			url: prefix + "/cw_finance/invoice/queryByNumber",
+			method: "get",
+			params: { number: number, id: id },
+		});
+	},
+	save: function (inputForm) {
+		return request({
+			url: prefix + `/cw_finance/invoice/save`,
+			method: "post",
+			data: inputForm,
+		});
+	},
+	delete: function (ids) {
+		return request({
+			url: prefix + "/cw_finance/invoice/delete",
+			method: "delete",
+			params: { ids: ids },
+		});
+	},
+	updateStatusById: function (data) {
+		return request({
+			url: prefix + "/cw_finance/invoice/updateStatusById",
+			method: "post",
+			data: data,
+		});
+	},
+	isReceivables: function (data) {
+		return request({
+			url: prefix + "/cw_finance/invoice/isReceivables",
+			method: "post",
+			data: data,
+		});
+	},
+	saveForm: function (inputForm) {
+		return request({
+			url: prefix + `/cw_finance/invoice/saveForm`,
+			method: "post",
+			data: inputForm,
+		});
+	},
+	saveFormInvalid: function (inputForm) {
+		return request({
+			url: prefix + `/cw_finance/invoice/saveFormInvalid`,
+			method: "post",
+			data: inputForm,
+		});
+	},
+	queryIdByInvalidId: function (id) {
+		return request({
+			url: prefix + "/cw_finance/invoice/queryIdByInvalidId",
+			method: "get",
+			params: { id: id },
+		});
+	},
+	importDetail: function (data) {
+		return request({
+			url: prefix + "/cw_finance/invoice/importDetail",
+			method: "post",
+			data: data,
+		});
+	},
+	exportTemplate: function () {
+		return request({
+			url: prefix + "/cw_finance/invoice/importDetail/template",
+			method: "get",
+			responseType: "blob",
+		});
+	},
+	getByIds: function (projectId, invoiceForm) {
+		return request({
+			url: prefix + "/cw_finance/invoice/getByIds",
+			method: "get",
+			params: { projectId: projectId, ...invoiceForm },
+		});
+	},
+	getByIds2: function (projectId, invoiceForm) {
+		return request({
+			url: prefix + "/cw_finance/invoice/getByIds2",
+			method: "get",
+			params: { projectId: projectId, ...invoiceForm },
+		});
+	},
+	getByContractId: function (contractId, invoiceForm) {
+		return request({
+			url: prefix + "/cw_finance/invoice/getByContractId",
+			method: "get",
+			params: { contractId: contractId, ...invoiceForm },
+		});
+	},
+	getIdByClientId: function (clientId, invoiceForm) {
+		return request({
+			url: prefix + "/cw_finance/invoice/getIdByClientId",
+			method: "get",
+			params: { clientId: clientId, ...invoiceForm },
+		});
+	},
+	exportFile: function (params) {
+		return request({
+			url: prefix + "/cw_finance/invoice/export",
+			method: "get",
+			params: params,
+			responseType: "blob",
+		});
+	},
+
+	getLabelById:function (param) {
+		return request({
+			url: prefix+"/cwProjectRecords/getLabelById",
+			method:"get",
+			params: {id: param}
+		})
+
+	},
+	listByProgramId: function (params) {
+		return request({
+			url: prefix + "/cw_finance/invoice/listByProgramId",
+			method: "get",
+			params: params,
+		});
+	},
+
+
+
+};

+ 133 - 0
api/cw/projectRecords/ProjectRecordsService.js

@@ -0,0 +1,133 @@
+import request from '@/common/request';
+import { FINANCE_PATH as prefix } from "@/api/AppPath";
+
+export default {
+	list: function (params) {
+		return request({
+			url: prefix + "/cwProjectRecords/list",
+			method: "get",
+			params: params,
+		});
+	},
+	list1: function (params) {
+		return request({
+			url: prefix + "/cwProjectReport/listApp",
+			method: "get",
+			params: params,
+		});
+	},
+	getList: function (params) {
+		return request({
+			url: prefix + "/cwProjectRecords/getList",
+			method: "get",
+			params: params,
+		});
+	},
+	list2: function (params) {
+		return request({
+			url: prefix + "/cwProjectRecords/newList",
+			method: "get",
+			params: params,
+		});
+	},
+	noReportList: function (params) {
+		return request({
+			url: prefix + "/cwProjectRecords/noReportList",
+			method: "get",
+			params: params,
+		});
+	},
+	queryById: function (id) {
+		return request({
+			url: prefix + "/cwProjectRecords/queryById",
+			method: "get",
+			params: { id: id },
+		});
+	},
+	save: function (inputForm) {
+		return request({
+			url: prefix + `/cwProjectRecords/save`,
+			method: "post",
+			data: inputForm,
+		});
+	},
+	saveForm: function (inputForm) {
+		return request({
+			url: prefix + `/cwProjectRecords/saveForm`,
+			method: "post",
+			data: inputForm,
+		});
+	},
+	delete: function (ids) {
+		return request({
+			url: prefix + "/cwProjectRecords/delete",
+			method: "delete",
+			params: { ids: ids },
+		});
+	},
+	updateStatusById: function (data) {
+		return request({
+			url: prefix + "/cwProjectRecords/updateStatusById",
+			method: "post",
+			data: data,
+		});
+	},
+	exportFile: function (params) {
+		return request({
+			url: prefix + "/cwProjectRecords/export",
+			method: "get",
+			params: params,
+			responseType: "blob",
+		});
+	},
+	getByClientId: function (id, projectForm) {
+		return request({
+			url: prefix + "/cwProjectRecords/getByClientId",
+			method: "get",
+			params: { clientId: id, ...projectForm },
+		});
+	},
+	getByContractId: function (id, projectForm) {
+		return request({
+			url: prefix + "/cwProjectRecords/getByContractId",
+			method: "get",
+			params: { contractId: id, ...projectForm },
+		});
+	},
+	updateMembers: function (inputForm) {
+		return request({
+			url: prefix + `/cwProjectRecords/updateMembers`,
+			method: "post",
+			data: inputForm,
+		});
+	},
+	getHaveProjectIds: function () {
+		return request({
+			url: prefix + "/cwProjectRecords/getHaveProjectIds",
+			method: "get",
+		});
+	},
+	getContractClientList: function (params) {
+		return request({
+			url: prefix + "/cw_work_client/info/getContractClientList",
+			method: "get",
+			params: params,
+		});
+	},
+	getReportById: function (params) {
+		return request({
+			url:prefix + "/cwProjectRecords/getReportById",
+			params:params
+		})
+	},
+
+	getReportByProjectId:function (id,projectId) {
+		return request({
+			url:prefix + "/cwProjectRecords/getReportByProjectId",
+			params:{id:id,projectId:projectId}
+		})
+
+	}
+
+
+};

+ 113 - 0
api/cw/reimbursementApproval/ReimbursementApprovalService.js

@@ -0,0 +1,113 @@
+import request from '@/common/request';
+import { FINANCE_PATH as prefix } from "@/api/AppPath";
+
+
+export default {
+  list: function (param) {
+    return request({
+      url: prefix + '/reimbursementApproval/info/list',
+      method: 'get',
+      params: param
+    })
+  },
+  reportNoList: function (param) {
+    return request({
+      url: prefix + '/reimbursementApproval/info/reportNoList',
+      method: 'get',
+      params: param
+    })
+  },
+  projectList: function (params) {
+    return request({
+      url: prefix + '/reimbursementApproval/info/projectList',
+      method: 'get',
+      params: params
+    })
+  },
+  save: function (param) {
+    return request({
+      url: prefix + '/reimbursementApproval/info/save',
+      method: 'post',
+      data: param
+    })
+  },
+  findById: function (id) {
+    return request({
+      url: prefix + '/reimbursementApproval/info/findById',
+      method: 'get',
+      params: {id: id}
+    })
+  },
+  remove: function (id) {
+    return request({
+      url: prefix + '/reimbursementApproval/info/remove',
+      method: 'get',
+      params: {id: id}
+    })
+  },
+  updateStatusById: function (param) {
+    return request({
+      url: prefix + '/reimbursementApproval/info/updateStatusById',
+      method: 'post',
+      data: param
+    })
+  },
+  checkNumber: function (number) {
+    return request({
+      url: prefix + '/reimbursementApproval/info/checkNumber',
+      method: 'get',
+      params: {number: number}
+    })
+  },
+  userTree: function (name) {
+    return request({
+      url: prefix + '/reimbursementApproval/info/userTree',
+      method: 'get',
+      params: {name: name}
+    })
+  },
+  exportFile: function (params) {
+    return request({
+      url: prefix + '/reimbursementApproval/info/exportFile',
+      method: 'get',
+      params: params,
+      responseType: 'blob'
+    })
+  },
+	exportInvoiceReimbursementFile: function (params) {
+    return request({
+      url: prefix + '/reimbursementApproval/info/exportInvoiceReimbursementFile',
+      method: 'get',
+      params: params,
+      responseType: 'blob'
+    })
+  },
+  queryByProIds: function (ids) {
+    return request({
+      url: prefix + '/reimbursementApproval/info/queryByProIds',
+      method: 'get',
+      params: {ids: ids}
+    })
+  },
+  getEffectiveDataByInvoiceNumber: function (invoiceNumber,id) {
+	return request({
+		url: prefix + '/reimbursementApproval/info/getEffectiveDataByInvoiceNumber',
+		method: 'get',
+		params: {invoiceNumber: invoiceNumber,id:id}
+	})
+  },
+	findHistory: function (id) {
+		return request({
+			url: prefix + '/reimbursementApproval/info/findHistory',
+			method: 'get',
+			params: {id: id}
+		})
+	},
+	findHiById: function (id) {
+		return request({
+			url: prefix + '/reimbursementApproval/info/findHiById',
+			method: 'get',
+			params: {id: id}
+		})
+	}
+}

+ 47 - 0
api/cw/reimbursementApproval/ReimbursementApprovalTypeService.js

@@ -0,0 +1,47 @@
+import request from '@/common/request';
+import { PUBLIC_MODULES_PATH as prefix } from "@/api/AppPath";
+
+export default class ReimbursementApprovalTypeService {
+  list (param) {
+    return request({
+      url: prefix + '/reimbursementApproval/type/list',
+      method: 'get',
+      params: param
+    })
+  }
+  bxList (param) {
+    return request({
+      url: prefix + '/reimbursementApproval/type/bxList',
+      method: 'get',
+      params: param
+    })
+  }
+  cgList (param) {
+    return request({
+      url: prefix + '/reimbursementApproval/type/cgList',
+      method: 'get',
+      params: param
+    })
+  }
+  save (param) {
+    return request({
+      url: prefix + '/reimbursementApproval/type/save',
+      method: 'post',
+      data: param
+    })
+  }
+  findById (id) {
+    return request({
+      url: prefix + '/reimbursementApproval/type/findById',
+      method: 'get',
+      params: {id: id}
+    })
+  }
+  remove (id) {
+    return request({
+      url: prefix + '/reimbursementApproval/type/deleteById',
+      method: 'get',
+      params: {id: id}
+    })
+  }
+}

+ 153 - 0
api/cw/workClientInfo/WorkClientService.js

@@ -0,0 +1,153 @@
+import request from '@/common/request';
+import { FINANCE_PATH as prefix } from "@/api/AppPath";
+
+export default {
+	list: function (params) {
+		return request({
+			url: prefix + "/cw_work_client/info/list",
+			method: "get",
+			params: params,
+		});
+	},
+	listTree: function (params) {
+		return request({
+			url: prefix + "/cw_work_client/info/list_tree",
+			method: "get",
+			params: params,
+		});
+	},
+	queryById: function (id) {
+		return request({
+			url: prefix + "/cw_work_client/info/queryById",
+			method: "get",
+			params: { id: id },
+		});
+	},
+	save: function (inputForm) {
+		return request({
+			url: prefix + `/cw_work_client/info/save`,
+			method: "post",
+			data: inputForm,
+		});
+	},
+	saveForm: function (inputForm) {
+		return request({
+			url: prefix + `/cw_work_client/info/saveForm`,
+			method: "post",
+			data: inputForm,
+		});
+	},
+	delete: function (ids) {
+		return request({
+			url: prefix + "/cw_work_client/info/delete",
+			method: "delete",
+			params: { ids: ids },
+		});
+	},
+	updateStatusById: function (data) {
+		return request({
+			url: prefix + "/cw_work_client/info/updateStatusById",
+			method: "post",
+			data: data,
+		});
+	},
+	exportFile: function (params) {
+		return request({
+			url: prefix + "/cw_work_client/info/export",
+			method: "get",
+			params: params,
+			responseType: "blob",
+		});
+	},
+	pushUpdate: function (id) {
+		return request({
+			url: prefix + "/cw_work_client/info/pushUpdate",
+			method: "get",
+			params: { id: id },
+		});
+	},
+	stopUpdate: function (id) {
+		return request({
+			url: prefix + "/cw_work_client/info/stopUpdate",
+			method: "get",
+			params: { id: id },
+		});
+	},
+	rejectUpdate: function (id) {
+		return request({
+			url: prefix + "/cw_work_client/info/rebackOrAgreeUpdate",
+			method: "get",
+			params: { id: id, type: "reject" },
+		});
+	},
+	rebackUpdate: function (id) {
+		return request({
+			url: prefix + "/cw_work_client/info/rebackOrAgreeUpdate",
+			method: "get",
+			params: { id: id, type: "reback" },
+		});
+	},
+	rebackPushUpdate: function (id) {
+		return request({
+			url: prefix + "/cw_work_client/info/rebackOrAgreeUpdate",
+			method: "get",
+			params: { id: id, type: "reback_push" },
+		});
+	},
+	agreeUpdate: function (id) {
+		return request({
+			url: prefix + "/cw_work_client/info/rebackOrAgreeUpdate",
+			method: "get",
+			params: { id: id, type: "agree" },
+		});
+	},
+	reapplyUpdate: function (id) {
+		return request({
+			url: prefix + "/cw_work_client/info/rebackOrAgreeUpdate",
+			method: "get",
+			params: { id: id, type: "reapply" },
+		});
+	},
+	queryUscCodeIsUse: function (uscCode) {
+		return request({
+			url: prefix + "/cw_work_client/info/queryUscCodeIsUse",
+			method: "get",
+			params: { uscCode: uscCode },
+		});
+	},
+	queryUscCodeById: function (id) {
+		return request({
+			url: prefix + "/cw_work_client/info/queryUscCodeById",
+			method: "get",
+			params: { id: id },
+		});
+	},
+	queryNameIsUse: function (name) {
+		return request({
+			url: prefix + "/cw_work_client/info/queryNameIsUse",
+			method: "get",
+			params: { name: name },
+		});
+	},
+	queryNameById: function (id) {
+		return request({
+			url: prefix + "/cw_work_client/info/queryNameById",
+			method: "get",
+			params: { id: id },
+		});
+	},
+	queryUpdateLogList: function (params) {
+		return request({
+			url: prefix + "/cw_work_client/info/queryUpdateLogList",
+			method: "get",
+			params: params,
+		});
+	},
+	getBillingListByClientId: function (params) {
+		return request({
+			url: prefix + "/cw_work_client/info/getBillingListByClientId",
+			method: "get",
+			params: params,
+		});
+	},
+};

+ 70 - 0
api/dailyOfficeWork/HolidayService.js

@@ -0,0 +1,70 @@
+import request from "../../common/request";
+import { PUBLIC_MODULES_PATH as prefix } from "../AppPath";
+
+export default {
+	list: function (param) {
+		return request({
+			url: prefix +'/holiday/findList',
+			method: 'get',
+			params: param
+		})
+	},
+
+	saveForm: function (inputForm) {
+		return request({
+			url: prefix + `/holiday/saveForm`,
+			method: 'post',
+			data: inputForm
+		})
+	},
+
+	queryById: function (id) {
+		return request({
+			url: prefix +'/holiday/findById',
+			method: 'get',
+			params: {id: id}
+		})
+	},
+
+	updateStatusById: function (data) {
+		return request({
+			url: prefix + "/holiday/updateStatusById",
+			method: "post",
+			data: data,
+		})
+	},
+	delete: function (ids) {
+		return request({
+			url: prefix+"/holiday/delete",
+			method: 'delete',
+			params: {id: ids}
+		})
+	},
+
+
+	adminEditForm: function (param){
+		return request({
+			url: prefix + "/holiday/adminEditForm",
+			method: "post",
+			data: param,
+		})
+	},
+
+	checkType: function (inputForm) {
+		return request({
+			url: prefix + `/holiday/checkType`,
+			method: 'post',
+			data: inputForm
+		})
+	},
+
+	exportFile: function (params) {
+		return request({
+			url: prefix + "/holiday/export",
+			method: "get",
+			params: params,
+			responseType: "blob",
+		});
+	}
+
+}

+ 61 - 0
api/human/depart/DepartRegistrationService.js

@@ -0,0 +1,61 @@
+import request from "../../../common/request"
+import { REGISTER_PATH as prefix } from "@/api/AppPath";
+
+export default {
+	list: function (params) {
+		return request({
+			url: prefix + '/departRegistration/list',
+			method: 'get',
+			params: params
+		})
+	},
+	save (inputForm) {
+		return request({
+			url: prefix +  `/departRegistration/save`,
+			method: 'post',
+			data: inputForm
+		})
+	},
+	findById (id) {
+		return request({
+			url: prefix + '/departRegistration/findById',
+			method: 'get',
+			params: {id: id}
+		})
+	},
+	getByHandoverId (handoverId) {
+		return request({
+			url: prefix + '/departRegistration/getByHandoverId',
+			method: 'get',
+			params: {handoverId: handoverId}
+		})
+	},
+	updateStatusById (param) {
+		return request({
+			url: prefix + '/departRegistration/updateStatusById',
+			method: 'post',
+			data: param
+		})
+	},
+	remove (id) {
+		return request({
+			url: prefix + '/departRegistration/remove',
+			method: 'get',
+			params: {id: id}
+		})
+	},
+	selectComplete () {
+		return request({
+			url: prefix + '/departRegistration/selectComplete',
+			method: 'get',
+			params: {}
+		})
+	},
+	selectContractStartDate () {
+		return request({
+			url: prefix + '/departRegistration/selectContractStartDate',
+			method: 'get',
+			params: {}
+		})
+	},
+}

+ 33 - 0
api/human/depart/HandoverService.js

@@ -0,0 +1,33 @@
+import request from "../../../common/request"
+import { REGISTER_PATH as prefix } from "@/api/AppPath";
+
+export default {
+	selectComplete () {
+		return request({
+			url: prefix + '/handover/selectComplete',
+			method: 'get',
+			params: {}
+		})
+	},
+	save (inputForm) {
+		return request({
+			url: prefix +  `/handover/save`,
+			method: 'post',
+			data: inputForm
+		})
+	},
+	findById (id) {
+		return request({
+			url: prefix + '/handover/findById',
+			method: 'get',
+			params: {id: id}
+		})
+	},
+	updateStatusById (param) {
+		return request({
+			url: prefix + '/handover/updateStatusById',
+			method: 'post',
+			data: param
+		})
+	},
+}

+ 55 - 0
api/materialManagement/MaterialManagementService.js

@@ -0,0 +1,55 @@
+import request from "../../common/request"
+import { PUBLIC_MODULES_PATH as prefix } from "../AppPath";
+
+export default {
+  list: function (param) {
+    return request({
+      url: prefix + '/material/management/list',
+      method: 'get',
+      params: param
+    })
+  },
+  save: function (param) {
+    return request({
+      url: prefix + '/material/management/save',
+      method: 'post',
+      data: param
+    })
+  },
+  findById: function (id) {
+    return request({
+      url: prefix + '/material/management/findById',
+      method: 'get',
+      params: {id: id}
+    })
+  },
+  remove: function (id) {
+    return request({
+      url: prefix + '/material/management/remove',
+      method: 'get',
+      params: {id: id}
+    })
+  },
+  updateStatusById: function (param) {
+    return request({
+      url: prefix + '/material/management/updateStatusById',
+      method: 'post',
+      data: param
+    })
+  },
+  exportFile: function (params) {
+    return request({
+      url: prefix + '/reimbursementApproval/info/exportFile',
+      method: 'get',
+      params: params,
+      responseType: 'blob'
+    })
+  },
+  findTradeByTypeId: function (typeId) {
+    return request({
+      url: prefix + '/material/management/findTradeByTypeId',
+      method: 'get',
+      params: {typeId: typeId}
+    })
+  }
+}

+ 40 - 0
api/materialManagement/SupplierService.js

@@ -0,0 +1,40 @@
+import request from "../../common/request"
+import { PUBLIC_MODULES_PATH as prefix } from "../AppPath";
+
+export default class SupplierService {
+  save (param) {
+    return request({
+      url: prefix + '/material/supplier/save',
+      method: 'post',
+      data: param
+    })
+  }
+  queryById (id) {
+    return request({
+      url: prefix + '/material/supplier/queryById',
+      method: 'get',
+      params: {id: id}
+    })
+  }
+  list (param) {
+    return request({
+      url: prefix + '/material/supplier/list',
+      method: 'get',
+      params: param
+    })
+  }
+  delete (ids) {
+    return request({
+      url: prefix + '/material/supplier/delete',
+      method: 'delete',
+      params: {ids: ids}
+    })
+  }
+  findByName (name) {
+    return request({
+      url: prefix + '/material/supplier/findByName',
+      method: 'get',
+      params: {name: name}
+    })
+  }
+}

+ 14 - 0
api/sys/OSSService.js

@@ -4,6 +4,20 @@ import request from "../../common/request"
 import { PUBLIC_MODULES_PATH as prefix } from "@/api/AppPath";
 
 export default class OSSSerive {
+  disposeXmlFile (data) {
+    return request({
+      url: prefix + '/oss/file/disposeXmlFile',
+      method: 'post',
+      data: data
+    })
+  }
+  downLoadFileDisposeXmlFile (url) {
+    return request({
+      url: prefix + '/oss/file/downLoadFileDisposeXmlFile',
+      method: 'post',
+      params: {file: url}
+    })
+  }
 	queryById (id) {
 		return request({
 			url: prefix + '/oss/file/queryById',

+ 15 - 0
api/sys/userService.js

@@ -65,6 +65,21 @@ export default {
 		});
 	},
 
+	treeDataRadio: function (params) {
+		return request({
+			url: prefix + "/sys/user/treeDataRadio",
+			method: "get",
+			params: params,
+		});
+	},
+	updateEmail: function (params){
+		return request({
+			url: prefix + `/sys/user/updateEmailApp`,
+			method: "post",
+			params: params,
+		});
+	},
+
 	is:function() {
 		return request({
 			url: prefix + "/sys/user/isAdmin",

+ 1 - 1
components/user-select/user-select-dialog.vue

@@ -67,7 +67,7 @@
 			}
 		  },
 		mounted() {
-			userService.treeData().then((data)=>{
+			userService.treeData({type: 'ydd'}).then((data)=>{
 				this.data = data
 				this.setTreeList(this.data)
 				let labelArra = []

+ 178 - 0
components/user-select/user-select-radio.vue

@@ -0,0 +1,178 @@
+<template>
+		<view style="width: 100%;"
+			@tap="open"
+		>
+<!--			<u&#45;&#45;input-->
+<!--				v-model="labels"-->
+<!--				suffixIcon="arrow-right"-->
+<!--				suffixIconStyle="color: #909399"-->
+<!--				disabled-->
+<!--				disabledColor="#ffffff"-->
+<!--				:placeholder="placeholder"-->
+<!--				border="none"-->
+<!--			></u&#45;&#45;input>-->
+
+			<u-action-sheet
+				:show="show"
+				@close="show = false"
+			>
+			<view class="cu-bar bg-white">
+				<view class="action text-blue" @tap="show=false">取消</view>
+				<view class="action text-green" @tap="selectUsers">确定</view>
+			</view>
+			<view>
+				  <ly-tree :tree-data="data"
+					:props="props"
+					node-key="id"
+					:checkOnClickNode ="true"
+					:showRadio="showRadio"
+					:show-checkbox ="showCheckBox"
+					:checkOnlyLeaf = "checkOnlyLeaf"
+					ref="userTree" />
+			</view>
+		</u-action-sheet>
+	</view>
+</template>
+
+<script>
+	import userService from "@/api/sys/userService"
+	export default {
+		data() {
+			return {
+				index: '',
+				show: false,
+				labels:'',
+				type:'',
+				data: [],
+				treeList: []
+			};
+		},
+		props: {
+		    limit: Number,
+		    value: String,
+		    size: String,
+			placeholder: {
+			  type: String,
+			  default: () => { return '请选择用户' }
+			},
+		    readonly: {
+		      type: Boolean,
+		      default: () => { return false }
+		    },
+			checkOnlyLeaf: {
+		      type: Boolean,
+		      default: () => { return true }
+		    },
+			showRadio: {
+		      type: Boolean,
+		      default: () => { return true }
+		    },
+			showCheckBox: {
+			  type: Boolean,
+			  default: () => { return false }
+			},
+		    disabled: {
+		      type: Boolean,
+		      default: () => { return false }
+		    },
+			props: {
+				type: Object,
+				default: () => {
+					return {
+						children: 'children',
+						label: 'label'
+					}
+				}
+			}
+		  },
+		mounted() {
+			userService.treeDataRadio({type: 'ydd'}).then((data)=>{
+				// 遍历数据结构中的每个部门,为其子集添加父级的 label
+				data[0].children.forEach(department => {
+					this.addParentLabel(department, department.label, department.id);
+				});
+				this.data = data
+				this.setTreeList(this.data)
+				let labelArra = []
+				if(this.value){
+					let keys = this.value.split(',')
+					keys.forEach((id) => {
+						this.treeList.forEach((node) => {
+						  if (id === node.id) {
+							labelArra.push(node.label)
+						  }
+						})
+					 })
+					this.labels = labelArra.join(',')
+				}
+			})
+		},
+		methods:{
+			open (index,type) {
+				this.index = index
+				this.show = true;
+				this.type = type;
+				if(this.value){
+					this.$nextTick(()=>{
+						let keys = this.value.split(',')
+						this.$refs.userTree.setCheckedKeys(keys);
+					})
+				}
+			},
+			setTreeList (datas) { // 遍历树  获取id数组
+			      for (var i in datas) {
+			        this.treeList.push(datas[i])
+			        if (datas[i].children) {
+			          this.setTreeList(datas[i].children)
+			        }
+			      }
+			    },
+			selectUsers() {
+				let user = this.$refs.userTree.getCheckedNodes().find(item => {
+					return item.type === 'user';
+				});
+
+				// 如果没有选择任何用户,则显示提示信息
+				if (!user) {
+					uni.showToast({
+						title: '请至少选择一条数据',
+						icon: 'none',
+						duration: 2000
+					});
+				} else {
+					// 提取用户的 ID 和父级 label,并形成新的对象数组
+					let usersWithParentLabel = {
+						id: user.id,
+						label: user.label,
+						parentLabel: user.parentLabel, // 获取父级 label,如果不存在则设置为 null
+						parentId: user.parentId
+					};
+
+					// 将用户信息传递给其他地方
+					this.$emit('input', usersWithParentLabel,this.index,this.type);
+
+					// 在本地更新标签显示
+					let names = user.label;
+					this.labels = names;
+					this.show = false;
+				}
+
+
+			},
+			// 给数据结构中的子集添加父级的 label
+			addParentLabel(data, parentLabel,parentId) {
+				if (data.children) {
+					data.children.forEach(child => {
+						// 如果子集是用户节点,则添加父级的 label
+						if (child.type === 'user') {
+							child.parentLabel = parentLabel;
+							child.parentId = parentId;
+						}
+						// 递归调用以处理子集的子集
+						this.addParentLabel(child, parentLabel);
+					});
+				}
+			}
+		}
+	}
+</script>

+ 3 - 3
pages/addressbook/addressbook.vue

@@ -21,18 +21,18 @@
 					<u-index-anchor :text="list[index].letter"></u-index-anchor>
 					<!-- #endif -->
 					<view class="list" v-for="(user, index1) in list[index].data" :key="index1">
-						<view class="list__item">
+						<!-- 检查user.name是否不等于"管理员" -->
+						<view class="list__item" v-if="user.name !== '管理员'">
 							<u-avatar shape="square" size="35" icon="account-fill" fontSize="26" randomBgColor></u-avatar>
 							<!-- <view class="cu-avatar round " :style="'background-image:url('+(user.photo?user.photo:'/h5/static/user/flat-avatar.png')+');'"></view> -->
 							<text class="list__item__user-name">{{user.name}}</text>
 							<!-- 新增的展示其他信息的元素 -->
 							<!-- 使用条件渲染检查 user.officeDTO.name 是否为 null -->
 							<text class="list__item__additional-info" v-if="user.officeDTO">{{ user.officeDTO.name }}</text>
-<!--							<text class="list__item__additional-info">{{ user.officeDTO.name }}</text>-->
 							<!-- 新的电话号码信息 -->
 							<text class="list__item__phone-number">{{ user.mobile }}</text>
 						</view>
-						<u-line></u-line>
+						<u-line v-if="user.name !== '管理员'"></u-line>
 					</view>
 				</u-index-item>
 			</template>

+ 169 - 0
pages/cw/invoice/EmailForm.vue

@@ -0,0 +1,169 @@
+<template>
+	<view style="width: 100%;">
+		<u-action-sheet :show="show" @close="onClose">
+			<view class="cu-bar bg-white">
+				<view class="action text-blue" @tap="onClose">取消</view>
+				<view class="action text-green" @tap="selectUsers">确定</view>
+			</view>
+			<u-form :show="show" :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" ref="inputForm">
+				<u-form-item label="姓名" prop="userName"
+							 :rules="[]">
+					<u-input v-model="inputForm.userName" :disabled="true" placeholder="请填写姓名" clearable></u-input>
+				</u-form-item>
+				<u-form-item label="邮箱" prop="userEmail"
+							 :rules="[]">
+					<u-input v-model="inputForm.userEmail" placeholder="请填写邮箱" clearable></u-input>
+				</u-form-item>
+				<u-form-item label="电话" prop="userPhone"
+							 :rules="[]">
+					<u-input v-model="inputForm.userPhone" :disabled="true" placeholder="请填写电话" clearable></u-input>
+				</u-form-item>
+			</u-form>
+		</u-action-sheet>
+	</view>
+</template>
+
+<script>
+	import userService from "@/api/sys/userService"
+
+	export default {
+		data() {
+			return {
+				show: false,
+				id: '',
+				inputForm: {
+					userName: '',
+					userEmail: '',
+					userPhone: '',
+				}
+			};
+		},
+		props: {
+			value: String,
+			placeholder: {
+				type: String,
+				default: '请选择项目'
+			},
+			readonly: {
+				type: Boolean,
+				default: false
+			},
+			disabled: {
+				type: Boolean,
+				default: false
+			},
+		},
+		mounted() {
+		},
+		methods: {
+			init(id,userEmail) {
+				this.inputForm.userEmail = userEmail
+				this.show = true;
+				this.id = id;
+			},
+			onClose() {
+				this.show = false;
+			},
+			selectUsers() {
+				return new Promise((resolve, reject) => {
+					// 表单规则验证
+					let errors = [];
+
+					// 验证邮箱
+					if (this.isNotEmpty(this.inputForm.userEmail)) {
+						var reg = /^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
+						if (!reg.test(this.inputForm.userEmail)) {
+							errors.push('请输入正确的邮箱地址');
+						}
+					}
+
+					if (errors.length > 0) {
+						// 存在错误,显示提示信息
+						errors.forEach(error => {
+							uni.showToast({
+								title: error,
+								icon: 'none',
+								duration: 2000
+							});
+						});
+						reject(errors); // 将错误数组传递给调用者
+					} else {
+						// 所有验证通过,执行保存操作
+						// 处理确定按钮点击事件
+						userService.updateEmail({ id: this.id, email: this.inputForm.userEmail })
+								.then((data) => {
+									if (data === '修改成功') {
+										uni.showToast({
+											title: '修改成功',
+											icon: 'none',
+											duration: 2000
+										});
+										this.show = false;
+										// 在邮箱更新成功后触发父组件的输入事件
+										this.$emit('input', this.inputForm.userEmail);
+										resolve(); // 通知调用者操作成功
+									}
+								})
+								.catch(error => {
+									reject(error); // 将具体的错误信息传递给调用者
+								});
+					}
+				});
+			},
+			isEmpty(value) {
+				let result = false;
+				if (value == null || value == undefined) {
+					result = true;
+				}
+				if (typeof value == 'string' && (value.replace(/\s+/g, "") == "" || value == "")) {
+					result = true;
+				}
+				if (typeof value == "object" && value instanceof Array && value.length === 0) {
+					result = true;
+				}
+				return result;
+			},
+			isNotEmpty (value) {
+				return !this.isEmpty(value)
+			},
+		}
+	};
+</script>
+
+<style scoped>
+	.u-action-sheet {
+		/* 设置为绝对定位,使其相对于父元素定位 */
+		position: absolute;
+		/* 居中显示 */
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -50%);
+		/* 设置最大宽度,以避免过宽 */
+		max-width: 90%;
+		/* 设置最大高度,以避免过高 */
+		max-height: 90%;
+		/* 设置溢出滚动 */
+		overflow-y: auto;
+		/* 设置背景颜色 */
+		background-color: #fff;
+		/* 设置边框 */
+		border: 1px solid #ddd;
+		/* 设置圆角 */
+		border-radius: 8px;
+	}
+
+	.u-form {
+		/* 设置内边距 */
+		padding: 20px;
+	}
+
+	.u-form-item {
+		/* 设置底部外边距 */
+		margin-bottom: 20px;
+	}
+
+	.u-input {
+		/* 设置输入框宽度 */
+		width: 100%;
+	}
+</style>

Plik diff jest za duży
+ 1009 - 0
pages/cw/invoice/InvoiceFormTask.vue


+ 269 - 0
pages/cw/invoice/InvoiceProjectChoose.vue

@@ -0,0 +1,269 @@
+<template>
+	<view style="width: 100%;">
+		<u-action-sheet :show="show" @close="onClose">
+			<view class="cu-bar bg-white">
+				<view class="action text-blue"  @tap="onClose">取消</view>
+				<view v-if="isShow">
+					<u-radio-group v-model="checkType" >
+						<u-radio
+								:customStyle="{marginRight: '16px'}"
+								v-for="(item, index) in checkTypeList"
+								:key="index"
+								:label="item.name"
+								:name="item.value"
+								@change="checkTypeChange"
+						></u-radio>
+					</u-radio-group>
+				</view>
+				<view class="action text-green" @tap="selectUsers">确定</view>
+			</view>
+			<view style="max-height: 300px; overflow-y: auto;">
+				<view v-for="item in data" :key="item.id" style="padding: 10px;">
+					<view @tap="onItemClick(item)" style="display: flex; align-items: center;">
+						<view style="flex: 1;text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">{{ item.projectName }}</view>
+						<view v-if="item.checked" style="color: #409eff;">已选择</view>
+					</view>
+				</view>
+			</view>
+			<view v-if="!allDataLoaded && !loading" style="text-align: center; padding: 10px;">
+				<button class="load-more-button" @tap="loadMore">加载更多</button>
+			</view>
+			<view v-if="loading" style="text-align: center; padding: 10px;">
+				Loading...
+			</view>
+		</u-action-sheet>
+	</view>
+</template>
+
+<script>
+	import projectRecordsService from '@/api/cw/projectRecords/ProjectRecordsService'
+
+	export default {
+		data() {
+			return {
+				checkType: '1',
+				checkTypeList: [{
+					name: '项目',
+					value: '1',
+					disabled: false
+				},{
+					name: '报告',
+					value: '2',
+					disabled: false
+				}],
+				show: false,
+				isShow: false,
+				labels:'',
+				index:'',
+				type:'',
+				data: [],
+				localMode: '', // 声明一个本地数据属性
+				allDataLoaded: false, // 跟踪是否所有数据都已加载
+				loading: false, // 跟踪加载状态
+				pageSize: 10, // 每页获取的项目数
+				currentPage: 1 // 当前页数
+			};
+		},
+		props: {
+			value: String,
+			placeholder: {
+				type: String,
+				default: '请选择项目'
+			},
+			readonly: {
+				type: Boolean,
+				default: false
+			},
+			disabled: {
+				type: Boolean,
+				default: false
+			},
+		},
+		mounted() {
+			// this.loadData();
+		},
+		methods: {
+			init(index, type) {
+				this.pageSize = 10
+				this.currentPage = 1
+				this.show = true;
+				this.index = index;
+				//选项的选择模式,单选或多选,默认为多选
+				// if (type === 'report') {
+				// 	this.localMode = 'single'
+				// } else {
+				// 	this.localMode = 'multiple'
+				// }
+				this.localMode = 'multiple'
+				if (this.isNotEmpty(type)) {
+					this.checkType = type
+					this.isShow = false
+				} else {
+					this.isShow = true
+				}
+				if (index === 1 || index === '1') {
+					if (type === '1') {
+						uni.showToast({
+							title: '第一条为项目后面新增只能选择项目',
+							icon: 'none',
+							duration: 2000
+						});
+					} else if (type === '2') {
+						uni.showToast({
+							title: '第一条为报告后面新增只能选择报告',
+							icon: 'none',
+							duration: 2000
+						});
+					}
+				}
+
+				this.loadData();
+			},
+			onItemClick(item) {
+				if (this.localMode  === 'single') {
+					this.data.forEach(node => {
+						node.checked = node === item;
+					});
+				} else {
+					item.checked = !item.checked;
+				}
+			},
+			selectUsers() {
+
+				if (this.data.some(item => item.checked)) {
+					let checkedItems = this.data.filter(item => item.checked).map(item => {
+						return {
+							id: item.id,
+							projectName: item.projectName,
+							contractName: item.contractName,
+							projectNumber: item.projectNumber,
+							contractId: item.contractId,
+							reportNo: item.reportNo,
+							isPreInvoice: item.isPreInvoice,
+						};
+					});
+					this.$emit('input', checkedItems, this.index);
+					this.onClose()
+				} else {
+					uni.showToast({
+						title: '请至少选择一条数据',
+						icon: 'none',
+						duration: 2000
+					});
+				}
+			},
+			loadData() {
+				this.loading = true; // 开始加载数据,显示loading状态
+				if (this.checkType === '1') {
+					projectRecordsService.noReportList({ status: 5, current: this.currentPage, pageSize: this.pageSize })
+							.then(data => {
+								this.loading = false; // 数据加载完成,隐藏loading状态
+								// 检查新返回的数据是否已经存在,如果存在,则不添加到原始数据数组中
+								let newData = data.records.filter(record => !this.data.some(item => item.id === record.id));
+								if (this.currentPage === 1) {
+									// 如果是加载第一页,则直接赋值给 data
+									this.data = newData.map(item => ({ ...item, checked: false }));
+								} else {
+									// 如果不是第一页,则追加到原始数据数组后面
+									this.data = [...this.data, ...newData.map(item => ({ ...item, checked: false }))];
+								}
+								if (data.records.length < this.pageSize) {
+									this.allDataLoaded = true; // 如果返回的数据少于每页数量,则表示所有数据都已加载
+								}
+								if (this.value) {
+									let keys = this.value.split(',');
+									this.data.forEach(node => {
+										if (keys.includes(node.id)) {
+											node.checked = true;
+										}
+									});
+									this.labels = this.data.filter(node => node.checked).map(node => node.label).join(',');
+								}
+							})
+							.catch(e => {
+								this.loading = false; // 数据加载失败,隐藏loading状态
+								throw e;
+							});
+				} else if (this.checkType === '2') {
+					projectRecordsService.list1({ status: 5, current: this.currentPage, pageSize: this.pageSize })
+							.then(data => {
+								this.loading = false; // 数据加载完成,隐藏loading状态
+								// 检查新返回的数据是否已经存在,如果存在,则不添加到原始数据数组中
+								let newData = data.records.filter(record => !this.data.some(item => item.id === record.id));
+								if (this.currentPage === 1) {
+									// 如果是加载第一页,则直接赋值给 data
+									this.data = newData.map(item => ({ ...item, checked: false }));
+								} else {
+									// 如果不是第一页,则追加到原始数据数组后面
+									this.data = [...this.data, ...newData.map(item => ({ ...item, checked: false }))];
+								}
+								if (data.records.length < this.pageSize) {
+									this.allDataLoaded = true; // 如果返回的数据少于每页数量,则表示所有数据都已加载
+								}
+								if (this.value) {
+									let keys = this.value.split(',');
+									this.data.forEach(node => {
+										if (keys.includes(node.id)) {
+											node.checked = true;
+										}
+									});
+									this.labels = this.data.filter(node => node.checked).map(node => node.label).join(',');
+								}
+							})
+							.catch(e => {
+								this.loading = false; // 数据加载失败,隐藏loading状态
+								throw e;
+							});
+				}
+			},
+			loadMore() {
+				this.currentPage++; // 增加当前页数
+				this.loadData(); // 加载更多数据
+			},
+			onClose() {
+				// 在关闭操作中清除已选择标记
+				this.data.forEach(item => {
+					item.checked = false;
+				});
+				this.labels = ''; // 清空标签
+				this.show = false;
+				this.checkType = '1';
+				this.data = []; // 清空原始数据
+			},
+			checkTypeChange(value){
+				this.checkType = value
+				this.pageSize = 10
+				this.currentPage = 1
+				this.data = []; // 清空原始数据
+				this.loadData(); // 加载更多数据
+			},
+			isEmpty(value) {
+				let result = false;
+				if (value == null || value == undefined) {
+					result = true;
+				}
+				if (typeof value == 'string' && (value.replace(/\s+/g, "") == "" || value == "")) {
+					result = true;
+				}
+				if (typeof value == "object" && value instanceof Array && value.length === 0) {
+					result = true;
+				}
+				return result;
+			},
+			isNotEmpty (value) {
+				return !this.isEmpty(value)
+			},
+		}
+	};
+</script>
+
+<style scoped>
+	.load-more-button {
+		background-color: #409eff;
+		color: #fff;
+		border: none;
+		padding: 10px 20px;
+		border-radius: 4px;
+		cursor: pointer;
+	}
+</style>

+ 154 - 0
pages/cw/invoice/WorkPlaceChoose.vue

@@ -0,0 +1,154 @@
+<template>
+	<view style="width: 100%;">
+		<u-action-sheet :show="show" @close="onClose">
+			<view class="cu-bar bg-white">
+				<view class="action text-blue"  @tap="onClose">取消</view>
+				<view class="action text-green" @tap="selectUsers">确定</view>
+			</view>
+			<view style="max-height: 300px; overflow-y: auto;">
+				<view v-for="item in data" :key="item.id" style="padding: 10px;">
+					<view @tap="onItemClick(item)" style="display: flex; align-items: center;">
+						<view style="flex: 1;text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">{{ item.name }}</view>
+						<view v-if="item.checked" style="color: #409eff;">已选择</view>
+					</view>
+				</view>
+			</view>
+			<view v-if="!allDataLoaded && !loading" style="text-align: center; padding: 10px;">
+				<button class="load-more-button" @tap="loadMore">加载更多</button>
+			</view>
+			<view v-if="loading" style="text-align: center; padding: 10px;">
+				Loading...
+			</view>
+		</u-action-sheet>
+	</view>
+</template>
+
+<script>
+	import workClientService from '@/api/cw/workClientInfo/WorkClientService'
+
+	export default {
+		data() {
+			return {
+				show: false,
+				labels:'',
+				data: [],
+				localMode: '', // 声明一个本地数据属性
+				allDataLoaded: false, // 跟踪是否所有数据都已加载
+				loading: false, // 跟踪加载状态
+				pageSize: 10, // 每页获取的项目数
+				currentPage: 1 // 当前页数
+			};
+		},
+		props: {
+			value: String,
+			placeholder: {
+				type: String,
+				default: '请选择客户'
+			},
+			readonly: {
+				type: Boolean,
+				default: false
+			},
+			disabled: {
+				type: Boolean,
+				default: false
+			},
+		},
+		mounted() {
+			// this.loadData();
+		},
+		methods: {
+			init() {
+				this.pageSize = 10
+				this.currentPage = 1
+				this.show = true;
+				//选项的选择模式,单选或多选,默认为多选
+				this.localMode = 'single'
+				this.loadData();
+			},
+			onItemClick(item) {
+				if (this.localMode  === 'single') {
+					this.data.forEach(node => {
+						node.checked = node === item;
+					});
+				} else {
+					item.checked = !item.checked;
+				}
+			},
+			selectUsers() {
+				if (this.data.some(item => item.checked)) {
+					let checkedItems = this.data.filter(item => item.checked)[0]; // 获取第一个符合条件的元素
+
+
+					this.$emit('input', checkedItems);
+					this.onClose()
+				} else {
+					uni.showToast({
+						title: '请至少选择一条数据',
+						icon: 'none',
+						duration: 2000
+					});
+				}
+
+			},
+			loadData() {
+				this.loading = true; // 开始加载数据,显示loading状态
+				workClientService.listTree({ isTrue: '1', current: this.currentPage, size: this.pageSize })
+						.then(data => {
+							this.loading = false; // 数据加载完成,隐藏loading状态
+							// 检查新返回的数据是否已经存在,如果存在,则不添加到原始数据数组中
+							let newData = data.records.filter(record => !this.data.some(item => item.id === record.id));
+							if (this.currentPage === 1) {
+								// 如果是加载第一页,则直接赋值给 data
+								this.data = newData.map(item => ({ ...item, checked: false }));
+							} else {
+								// 如果不是第一页,则追加到原始数据数组后面
+								this.data = [...this.data, ...newData.map(item => ({ ...item, checked: false }))];
+							}
+							if (data.records.length < this.pageSize) {
+								this.allDataLoaded = true; // 如果返回的数据少于每页数量,则表示所有数据都已加载
+							}
+							if (this.value) {
+								let keys = this.value.split(',');
+								this.data.forEach(node => {
+									if (keys.includes(node.id)) {
+										node.checked = true;
+									}
+								});
+								this.labels = this.data.filter(node => node.checked).map(node => node.label).join(',');
+							}
+						})
+						.catch(e => {
+							this.loading = false; // 数据加载失败,隐藏loading状态
+							throw e;
+						});
+			},
+
+
+			loadMore() {
+				this.currentPage++; // 增加当前页数
+				this.loadData(); // 加载更多数据
+			},
+			onClose() {
+				// 在关闭操作中清除已选择标记
+				this.data.forEach(item => {
+					item.checked = false;
+				});
+				this.labels = ''; // 清空标签
+				this.show = false;
+				this.data = []; // 清空原始数据
+			},
+		}
+	};
+</script>
+
+<style scoped>
+	.load-more-button {
+		background-color: #409eff;
+		color: #fff;
+		border: none;
+		padding: 10px 20px;
+		border-radius: 4px;
+		cursor: pointer;
+	}
+</style>

+ 162 - 0
pages/cw/reimbursementApproval/info/CwProjectChoose.vue

@@ -0,0 +1,162 @@
+<template>
+	<view style="width: 100%;">
+		<u-action-sheet :show="show" @close="onClose">
+			<view class="cu-bar bg-white">
+				<view class="action text-blue"  @tap="onClose">取消</view>
+				<view class="action text-green" @tap="selectUsers">确定</view>
+			</view>
+			<view style="max-height: 300px; overflow-y: auto;">
+				<view v-for="item in data" :key="item.id" style="padding: 10px;">
+					<view @tap="onItemClick(item)" style="display: flex; align-items: center;">
+						<view style="flex: 1;text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">{{ item.projectName }}</view>
+						<view v-if="item.checked" style="color: #409eff;">已选择</view>
+					</view>
+				</view>
+			</view>
+			<view v-if="!allDataLoaded && !loading" style="text-align: center; padding: 10px;">
+				<button class="load-more-button" @tap="loadMore">加载更多</button>
+			</view>
+			<view v-if="loading" style="text-align: center; padding: 10px;">
+				Loading...
+			</view>
+		</u-action-sheet>
+	</view>
+</template>
+
+<script>
+	import projectRecordsService from '@/api/cw/projectRecords/ProjectRecordsService'
+
+	export default {
+		data() {
+			return {
+				show: false,
+				labels:'',
+				index:'',
+				type:'',
+				data: [],
+				localMode: '', // 声明一个本地数据属性
+				allDataLoaded: false, // 跟踪是否所有数据都已加载
+				loading: false, // 跟踪加载状态
+				pageSize: 10, // 每页获取的项目数
+				currentPage: 1 // 当前页数
+			};
+		},
+		props: {
+			value: String,
+			placeholder: {
+				type: String,
+				default: '请选择项目'
+			},
+			readonly: {
+				type: Boolean,
+				default: false
+			},
+			disabled: {
+				type: Boolean,
+				default: false
+			},
+		},
+		mounted() {
+			// this.loadData();
+		},
+		methods: {
+			init(index,type) {
+				this.pageSize = 10
+				this.currentPage = 1
+				this.show = true;
+				this.index = index;
+				this.type = type;
+				//选项的选择模式,单选或多选,默认为多选
+				if (type === 'report') {
+					this.localMode = 'single'
+				} else {
+					this.localMode = 'multiple'
+				}
+				this.loadData();
+			},
+			onItemClick(item) {
+				if (this.localMode  === 'single') {
+					this.data.forEach(node => {
+						node.checked = node === item;
+					});
+				} else {
+					item.checked = !item.checked;
+				}
+			},
+			selectUsers() {
+				if (this.data.some(item => item.checked)) {
+					let ids = this.data.filter(item => item.checked).map(item => item.id).join(',');
+					let projectNames = this.data.filter(item => item.checked).map(item => item.projectName).join(',');
+					this.labels = projectNames;
+					this.$emit('input', ids, projectNames, this.index, this.type);
+					this.onClose()
+				} else {
+					uni.showToast({
+						title: '请至少选择一条数据',
+						icon: 'none',
+						duration: 2000
+					});
+				}
+
+			},
+			loadData() {
+				this.loading = true; // 开始加载数据,显示loading状态
+				projectRecordsService.list({ status: 5, current: this.currentPage, pageSize: this.pageSize })
+						.then(data => {
+							this.loading = false; // 数据加载完成,隐藏loading状态
+							// 检查新返回的数据是否已经存在,如果存在,则不添加到原始数据数组中
+							let newData = data.records.filter(record => !this.data.some(item => item.id === record.id));
+							if (this.currentPage === 1) {
+								// 如果是加载第一页,则直接赋值给 data
+								this.data = newData.map(item => ({ ...item, checked: false }));
+							} else {
+								// 如果不是第一页,则追加到原始数据数组后面
+								this.data = [...this.data, ...newData.map(item => ({ ...item, checked: false }))];
+							}
+							if (data.records.length < this.pageSize) {
+								this.allDataLoaded = true; // 如果返回的数据少于每页数量,则表示所有数据都已加载
+							}
+							if (this.value) {
+								let keys = this.value.split(',');
+								this.data.forEach(node => {
+									if (keys.includes(node.id)) {
+										node.checked = true;
+									}
+								});
+								this.labels = this.data.filter(node => node.checked).map(node => node.label).join(',');
+							}
+						})
+						.catch(e => {
+							this.loading = false; // 数据加载失败,隐藏loading状态
+							throw e;
+						});
+			},
+
+
+			loadMore() {
+				this.currentPage++; // 增加当前页数
+				this.loadData(); // 加载更多数据
+			},
+			onClose() {
+				// 在关闭操作中清除已选择标记
+				this.data.forEach(item => {
+					item.checked = false;
+				});
+				this.labels = ''; // 清空标签
+				this.show = false;
+				this.data = []; // 清空原始数据
+			},
+		}
+	};
+</script>
+
+<style scoped>
+	.load-more-button {
+		background-color: #409eff;
+		color: #fff;
+		border: none;
+		padding: 10px 20px;
+		border-radius: 4px;
+		cursor: pointer;
+	}
+</style>

+ 115 - 0
pages/cw/reimbursementApproval/info/CwReportChoose.vue

@@ -0,0 +1,115 @@
+<template>
+	<view style="width: 100%;">
+<!--		<view style="display: flex; align-items: center;">-->
+<!--			<view>{{ labels }}</view>-->
+<!--			<view style="color: #909399; margin-left: 5px;">-->
+<!--				<image src="YOUR_ARROW_RIGHT_ICON_URL" style="width: 16px; height: 16px;" />-->
+<!--			</view>-->
+<!--		</view>-->
+
+		<u-action-sheet style="min-height: 200px" :show="show" @close="show = false">
+			<view class="cu-bar bg-white">
+				<view class="action text-blue"  @tap="onClose">取消</view>
+				<view class="action text-green" @tap="selectUsers">确定</view>
+			</view>
+<!--			overflow-y: auto;  滚动效果-->
+			<view style="max-height: 300px; overflow-y: auto;">
+				<view v-for="item in data" :key="item.id" style="padding: 10px;">
+					<view @tap="onItemClick(item)" style="display: flex; align-items: center;">
+						<view style="flex: 1;text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">{{ item.reportNo }}</view>
+						<view v-if="item.checked" style="color: #409eff;">已选择</view>
+					</view>
+				</view>
+			</view>
+		</u-action-sheet>
+	</view>
+</template>
+
+<script>
+	import reimbursementApprovalService from '@/api/cw/reimbursementApproval/ReimbursementApprovalService'
+
+	export default {
+		data() {
+			return {
+				show: false,
+				labels:'',
+				index:'',
+				projectId:'',
+				data: [],
+				localMode: '', // 声明一个本地数据属性
+			};
+		},
+		props: {
+			value: String,
+			placeholder: {
+				type: String,
+				default: '请选择项目'
+			},
+			readonly: {
+				type: Boolean,
+				default: false
+			},
+			disabled: {
+				type: Boolean,
+				default: false
+			},
+		},
+		mounted() {
+			// this.loadData();
+		},
+		methods: {
+			init(index,projectId){
+				this.show = true;
+				if (!this.projectId) {
+					this.index = index;
+					this.projectId = projectId;
+					//选项的选择模式,单选或多选,默认为多选
+					this.localMode = 'single'
+					this.loadData();
+				}
+			},
+			onItemClick(item) {
+				if (this.localMode  === 'single') {
+					this.data.forEach(node => {
+						node.checked = node === item;
+					});
+				} else {
+					item.checked = !item.checked;
+				}
+			},
+			selectUsers() {
+				let ids = this.data.filter(item => item.checked).map(item => item.id).join(',');
+				let reportNo = this.data.filter(item => item.checked).map(item => item.reportNo).join(',');
+				this.labels = reportNo;
+				this.$emit('input', ids, reportNo, this.index);
+				this.show = false;
+			},
+			loadData() {
+				reimbursementApprovalService.reportNoList({ status: 5, projectId: this.projectId })
+						.then(data => {
+							this.data = data.records.map(item => ({ ...item, checked: false }));
+							if (this.value) {
+								let keys = this.value.split(',');
+								this.data.forEach(node => {
+									if (keys.includes(node.id)) {
+										node.checked = true;
+									}
+								});
+								this.labels = this.data.filter(node => node.checked).map(node => node.label).join(',');
+							}
+						})
+						.catch(e => {
+							throw e;
+						});
+			},
+			onClose() {
+				// 在关闭操作中清除已选择标记
+				this.data.forEach(item => {
+					item.checked = false;
+				});
+				this.labels = ''; // 清空标签
+				this.show = false;
+			},
+		}
+	};
+</script>

+ 627 - 0
pages/cw/reimbursementApproval/info/ReimbursementChoose.vue

@@ -0,0 +1,627 @@
+<!-- 树形层级选择器-->
+<!-- 1、支持单选、多选 -->
+<template>
+	<view>
+		<view class="tree-cover" :class="{'show':showDialog}" @tap="_cancel"></view>
+		<view class="tree-dialog" :class="{'show':showDialog}">
+			<view class="tree-bar">
+				<view class="tree-bar-cancel" :style="{'color':cancelColor}" hover-class="hover-c" @tap="_cancel">取消
+				</view>
+				<view class="tree-bar-title" :style="{'color':titleColor}">{{title}}</view>
+				<view class="tree-bar-confirm" :style="{'color':confirmColor}" hover-class="hover-c" @tap="_confirm">
+					{{multiple?'确定':''}}
+				</view>
+			</view>
+			<view class="tree-view">
+				<scroll-view class="tree-list" :scroll-y="true">
+					<block v-for="(item, index) in treeList" :key="index">
+						<view class="tree-item" :style="[{
+							paddingLeft: item.level*30 + 'rpx'
+						}]" :class="{
+							itemBorder: border === true,
+							show: item.isShow
+						}">
+							<view class="item-label">
+								<view class="item-icon uni-inline-item" @tap.stop="_onItemSwitch(item, index)">
+									<view v-if="!item.isLastLevel&&item.isShowChild" class="switch-on"
+										:style="{'border-left-color':switchColor}">
+									</view>
+									<view v-else-if="!item.isLastLevel&&!item.isShowChild" class="switch-off"
+										:style="{'border-top-color':switchColor}">
+									</view>
+									<view v-else class="item-last-dot" :style="{'border-top-color':switchColor}">
+									</view>
+								</view>
+								<view class="uni-flex-item uni-inline-item" @tap.stop="_onItemSelect(item, index)">
+									<view class="item-name"> {{item.name}}</view>
+									<view class="item-check" v-if="item.isLastLevel">
+										<view class="item-check-yes" v-if="item.checkStatus===1"
+											:class="{'radio':!multiple}" :style="{'border-color':confirmColor}">
+											<view class="item-check-yes-part"
+												:style="{'background-color':confirmColor}">
+											</view>
+										</view>
+										<view class="item-check-yes" v-else-if="item.checkStatus===2"
+											:class="{'radio':!multiple}" :style="{'border-color':confirmColor}">
+											<view class="item-check-yes-all" :style="{'background-color':confirmColor}">
+											</view>
+										</view>
+										<view class="item-check-no" v-else :class="{'radio':!multiple}"
+											:style="{'border-color':confirmColor}"></view>
+									</view>
+								</view>
+							</view>
+
+						</view>
+					</block>
+				</scroll-view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		emits: ['select-change'],
+		name: "ba-tree-picker",
+		props: {
+			valueKey: {
+				type: String,
+				default: 'id'
+			},
+			textKey: {
+				type: String,
+				default: 'name'
+			},
+			childrenKey: {
+				type: String,
+				default: 'children'
+			},
+			localdata: {
+				type: Array,
+				default: function() {
+					return []
+				}
+			},
+			localTreeList: { //在已经格式化好的数据
+				type: Array,
+				default: function() {
+					return []
+				}
+			},
+			selectedData: {
+				type: Array,
+				default: function() {
+					return []
+				}
+			},
+			title: {
+				type: String,
+				default: ''
+			},
+			multiple: { // 是否可以多选
+				type: Boolean,
+				default: true
+			},
+			selectParent: { //是否可以选父级
+				type: Boolean,
+				default: true
+			},
+			confirmColor: { // 确定按钮颜色
+				type: String,
+				default: '' // #0055ff
+			},
+			cancelColor: { // 取消按钮颜色
+				type: String,
+				default: '' // #757575
+			},
+			titleColor: { // 标题颜色
+				type: String,
+				default: '' //
+			},
+			switchColor: { // 节点切换图标颜色
+				type: String,
+				default: '' // #666
+			},
+			border: { // 是否有分割线
+				type: Boolean,
+				default: false
+			},
+		},
+		data() {
+			return {
+				showDialog: false,
+				index: '',
+				type: '',
+				treeList: []
+			}
+		},
+		computed: {},
+		methods: {
+			_show(index,type) {
+				this.index = index
+				this.type = type
+				this.showDialog = true
+			},
+			_hide() {
+				this.showDialog = false
+			},
+			_cancel() {
+				this._hide()
+				this.$emit("cancel", '');
+			},
+			_confirm() { //多选
+				let selectedList = []; //如果子集全部选中,只返回父级 id
+				let selectedNames;
+				let currentLevel = -1;
+				this.treeList.forEach((item, index) => {
+					if (currentLevel >= 0 && item.level > currentLevel) {
+
+					} else {
+						if (item.checkStatus === 2) {
+							currentLevel = item.level;
+							selectedList.push(item.id);
+							selectedNames = selectedNames ? selectedNames + ' / ' + item.name : item.name;
+						} else {
+							currentLevel = -1;
+						}
+					}
+				})
+				this._hide()
+				this.$emit("select-change", selectedList, selectedNames, this.index, this.type);
+			},
+			//格式化原数据(原数据为tree结构)
+			_formatTreeData(list = [], level = 0, parentItem, isShowChild = true) {
+				let nextIndex = 0;
+				let parentId = -1;
+				let initCheckStatus = 0;
+				if (parentItem) {
+					nextIndex = this.treeList.findIndex(item => item.id === parentItem.id) + 1;
+					parentId = parentItem.id;
+					if (!this.multiple) { //单选
+						initCheckStatus = 0;
+					} else
+						initCheckStatus = parentItem.checkStatus == 2 ? 2 : 0;
+				}
+				list.forEach(item => {
+					let isLastLevel = true;
+					if (item && item.children) {
+						let children = item.children;
+						if (Array.isArray(children) && children.length > 0) {
+							isLastLevel = false;
+						}
+					}
+
+					let itemT = {
+						id: item.id,
+						name: item.name,
+						level,
+						isLastLevel,
+						isShow: isShowChild,
+						isShowChild: false,
+						checkStatus: initCheckStatus,
+						orCheckStatus: 0,
+						parentId,
+						children: item.children,
+						childCount: item.children ? item.children.length : 0,
+						childCheckCount: 0,
+						childCheckPCount: 0
+					};
+
+					if (this.selectedData.indexOf(itemT.id) >= 0) {
+						itemT.checkStatus = 2;
+						itemT.orCheckStatus = 2;
+						itemT.childCheckCount = itemT.children ? itemT.children.length : 0;
+						this._onItemParentSelect(itemT, nextIndex);
+					}
+
+					this.treeList.splice(nextIndex, 0, itemT);
+					nextIndex++;
+				})
+				// console.log('this.treeList', this.treeList);
+			},
+			// 节点打开、关闭切换
+			_onItemSwitch(item, index) {
+				if (item.isLastLevel === true) {
+					return;
+				}
+				item.isShowChild = !item.isShowChild;
+				if (item.children) {
+					this._formatTreeData(item.children, item.level + 1, item);
+					item.children = undefined;
+				} else {
+					this._onItemChildSwitch(item, index);
+				}
+			},
+			_onItemChildSwitch(item, index) {
+				//console.log('_onItemChildSwitch')
+				const firstChildIndex = index + 1;
+				if (firstChildIndex > 0)
+					for (var i = firstChildIndex; i < this.treeList.length; i++) {
+						let itemChild = this.treeList[i];
+						if (itemChild.level > item.level) {
+							if (item.isShowChild) {
+								if (itemChild.parentId === item.id) {
+									itemChild.isShow = item.isShowChild;
+									if (!itemChild.isShow) {
+										itemChild.isShowChild = false;
+									}
+								}
+							} else {
+								itemChild.isShow = item.isShowChild;
+								itemChild.isShowChild = false;
+							}
+						} else {
+							return;
+						}
+					}
+			},
+			// 节点选中、取消选中
+			_onItemSelect(item, index) {
+				if (item.isLastLevel) {
+					if (!this.multiple) {
+						// 单选逻辑
+						item.checkStatus = item.checkStatus === 0 ? 2 : 0;
+
+						this.treeList.forEach((v, i) => {
+							if (i !== index) {
+								this.treeList[i].checkStatus = 0;
+							} else {
+								this.treeList[i].checkStatus = 2;
+							}
+						});
+
+						let selectedList = [item.id];
+						let selectedNames = item.name;
+						this._hide();
+						this.$emit("select-change", selectedList, selectedNames, this.index, this.type);
+					} else {
+						// 多选逻辑
+						let oldCheckStatus = item.checkStatus;
+						switch (oldCheckStatus) {
+							case 0:
+								item.checkStatus = 2;
+								item.childCheckCount = item.childCount;
+								item.childCheckPCount = 0;
+								break;
+							case 1:
+							case 2:
+								item.checkStatus = 0;
+								item.childCheckCount = 0;
+								item.childCheckPCount = 0;
+								break;
+							default:
+								break;
+						}
+						// 处理子节点选择
+						this._onItemChildSelect(item, index);
+						// 处理父节点选择状态变化
+						this._onItemParentSelect(item, index, oldCheckStatus);
+					}
+				}
+			},
+			_onItemChildSelect(item, index) {
+				//console.log('_onItemChildSelect')
+				let allChildCount = 0;
+				if (item.childCount && item.childCount > 0) {
+					index++;
+					while (index < this.treeList.length && this.treeList[index].level > item.level) {
+						let itemChild = this.treeList[index];
+						itemChild.checkStatus = item.checkStatus;
+						if (itemChild.checkStatus == 2) {
+							itemChild.childCheckCount = itemChild.childCount;
+							itemChild.childCheckPCount = 0;
+						} else if (itemChild.checkStatus == 0) {
+							itemChild.childCheckCount = 0;
+							itemChild.childCheckPCount = 0;
+						}
+						// console.log('>>>>index:', index, 'item:', itemChild.name, '  status:', itemChild
+						// 	.checkStatus)
+						index++;
+					}
+				}
+			},
+			_onItemParentSelect(item, index, oldCheckStatus) {
+				//console.log('_onItemParentSelect')
+				const parentIndex = this.treeList.findIndex(itemP => itemP.id == item.parentId);
+				//console.log('parentIndex:' + parentIndex)
+				if (parentIndex >= 0) {
+					let itemParent = this.treeList[parentIndex];
+					let count = itemParent.childCheckCount;
+					let oldCheckStatusParent = itemParent.checkStatus;
+
+					if (oldCheckStatus == 1) {
+						itemParent.childCheckPCount -= 1;
+					} else if (oldCheckStatus == 2) {
+						itemParent.childCheckCount -= 1;
+					}
+					if (item.checkStatus == 1) {
+						itemParent.childCheckPCount += 1;
+					} else if (item.checkStatus == 2) {
+						itemParent.childCheckCount += 1;
+					}
+
+					if (itemParent.childCheckCount <= 0 && itemParent.childCheckPCount <= 0) {
+						itemParent.childCheckCount = 0;
+						itemParent.childCheckPCount = 0;
+						itemParent.checkStatus = 0;
+					} else if (itemParent.childCheckCount >= itemParent.childCount) {
+						itemParent.childCheckCount = itemParent.childCount;
+						itemParent.childCheckPCount = 0;
+						itemParent.checkStatus = 2;
+					} else {
+						itemParent.checkStatus = 1;
+					}
+					//console.log('itemParent:', itemParent)
+					this._onItemParentSelect(itemParent, parentIndex, oldCheckStatusParent);
+				}
+			},
+			// 重置数据
+			_reTreeList() {
+				this.treeList.forEach((v, i) => {
+					this.treeList[i].checkStatus = v.orCheckStatus
+				})
+			},
+			_initTree() {
+				this.treeList = [];
+				this._formatTreeData(this.localdata);
+			}
+		},
+		watch: {
+			localdata() {
+				this._initTree();
+			},
+			localTreeList() {
+				this.treeList = this.localTreeList;
+			}
+		},
+		mounted() {
+			this._initTree();
+		}
+	}
+</script>
+
+<style scoped>
+
+	.uni-flex-item {
+		display: flex; /* 使用 Flex 布局 */
+		align-items: center; /* 垂直居中 */
+	}
+
+	.tree-cover {
+		position: fixed;
+		top: 0rpx;
+		right: 0rpx;
+		bottom: 0rpx;
+		left: 0rpx;
+		z-index: 100;
+		background-color: rgba(0, 0, 0, .4);
+		opacity: 0;
+		transition: all 0.3s ease;
+		visibility: hidden;
+	}
+
+	.tree-cover.show {
+		visibility: visible;
+		opacity: 1;
+	}
+
+	.tree-dialog {
+		position: fixed;
+		top: 0rpx;
+		right: 0rpx;
+		bottom: 0rpx;
+		left: 0rpx;
+		background-color: #fff;
+		border-top-left-radius: 10px;
+		border-top-right-radius: 10px;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		z-index: 102;
+		top: 20%;
+		transition: all 0.3s ease;
+		transform: translateY(100%);
+	}
+
+	.tree-dialog.show {
+		transform: translateY(0);
+	}
+
+	.tree-bar {
+		/* background-color: #fff; */
+		height: 90rpx;
+		padding-left: 25rpx;
+		padding-right: 25rpx;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		box-sizing: border-box;
+		border-bottom-width: 1rpx !important;
+		border-bottom-style: solid;
+		border-bottom-color: #f5f5f5;
+		font-size: 32rpx;
+		color: #757575;
+		line-height: 1;
+	}
+
+	.tree-bar-confirm {
+		color: #0055ff;
+		padding: 15rpx;
+	}
+
+	.tree-bar-title {}
+
+	.tree-bar-cancel {
+		color: #757575;
+		padding: 15rpx;
+	}
+
+	.tree-view {
+		flex: 1;
+		/*padding: 20rpx;*/
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		overflow: hidden;
+		height: 100%;
+	}
+
+	.tree-list {
+		flex: 1;
+		height: 100%;
+		overflow: hidden;
+	}
+
+	.tree-item {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		line-height: 1;
+		height: 0;
+		opacity: 0;
+		transition: 0.2s;
+		overflow: hidden;
+	}
+
+	.tree-item.show {
+		height: 90rpx;
+		opacity: 1;
+	}
+
+	.tree-item.showchild:before {
+		transform: rotate(90deg);
+	}
+
+	.tree-item.last:before {
+		opacity: 0;
+	}
+
+	.switch-on {
+		width: 0;
+		height: 0;
+		border-left: 10rpx solid transparent;
+		border-right: 10rpx solid transparent;
+		border-top: 15rpx solid #666;
+	}
+
+	.switch-off {
+		width: 0;
+		height: 0;
+		border-bottom: 10rpx solid transparent;
+		border-top: 10rpx solid transparent;
+		border-left: 15rpx solid #666;
+	}
+
+	.item-last-dot {
+		position: absolute;
+		width: 10rpx;
+		height: 10rpx;
+		border-radius: 100%;
+		background: #666;
+		display: none;
+	}
+
+	.item-icon {
+		width: 26rpx;
+		height: 26rpx;
+		margin-right: 8rpx;
+		padding-right: 20rpx;
+		padding-left: 20rpx;
+	}
+
+	.item-label {
+		flex: 1;
+		display: flex;
+		align-items: center;
+		height: auto;
+		line-height: 1.4;
+	}
+
+	.item-name {
+		flex: 1;
+		overflow: hidden;
+		text-overflow: ellipsis;
+		white-space: nowrap;
+		width: 450rpx;
+	}
+
+	.item-check {
+		margin-right: 8px; /* 适当的左边距 */
+		order: -1;
+		/*width: 40px;*/
+		/*height: 40px;*/
+		/*display: flex;*/
+		/*justify-content: center;*/
+		/*align-items: center;*/
+	}
+
+	.item-check-yes,
+	.item-check-no {
+		width: 20px;
+		height: 20px;
+		border-top-left-radius: 20%;
+		border-top-right-radius: 20%;
+		border-bottom-right-radius: 20%;
+		border-bottom-left-radius: 20%;
+		border-top-width: 1rpx;
+		border-left-width: 1rpx;
+		border-bottom-width: 1rpx;
+		border-right-width: 1rpx;
+		border-style: solid;
+		border-color: #0055ff;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		box-sizing: border-box;
+	}
+
+	.item-check-yes-part {
+		width: 12px;
+		height: 12px;
+		border-top-left-radius: 20%;
+		border-top-right-radius: 20%;
+		border-bottom-right-radius: 20%;
+		border-bottom-left-radius: 20%;
+		background-color: #0055ff;
+	}
+
+	.item-check-yes-all {
+		margin-bottom: 5px;
+		border: 2px solid #007aff;
+		border-left: 0;
+		border-top: 0;
+		height: 12px;
+		width: 6px;
+		transform-origin: center;
+		/* #ifndef APP-NVUE */
+		transition: all 0.3s;
+		/* #endif */
+		transform: rotate(45deg);
+	}
+
+	.item-check .radio {
+		border-top-left-radius: 50%;
+		border-top-right-radius: 50%;
+		border-bottom-right-radius: 50%;
+		border-bottom-left-radius: 50%;
+	}
+
+	.item-check .radio .item-check-yes-b {
+		border-top-left-radius: 50%;
+		border-top-right-radius: 50%;
+		border-bottom-right-radius: 50%;
+		border-bottom-left-radius: 50%;
+	}
+
+	.hover-c {
+		opacity: 0.6;
+	}
+
+	.itemBorder {
+		border-bottom: 1px solid #e5e5e5;
+	}
+
+</style>

Plik diff jest za duży
+ 1451 - 0
pages/cw/reimbursementApproval/info/ReimbursementForm.vue


+ 718 - 0
pages/dailyOfficeWork/holiday/HolidayForm.vue

@@ -0,0 +1,718 @@
+<template>
+	<view>
+		<cu-custom :backUrl="'/pages/index/index'" :isBack="true" bgColor="bg-gradual-blue" >
+			<block slot="content">请假申请</block>
+		</cu-custom>
+		<u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules" ref="inputForm" v-if="!nodeFlag">
+			<u-form-item label="请假人" borderBottom prop="createName">
+				<u--input placeholder='请填写请假人'  v-model="inputForm.createName" disabled></u--input>
+			</u-form-item>
+			<u-form-item label="请假部门" borderBottom prop="officeName">
+				<u--input placeholder='请填写请假部门'  v-model="inputForm.officeName" disabled></u--input>
+			</u-form-item>
+			<u-form-item label="请假类型" borderBottom prop="type" :required="true">
+				<jp-picker v-model="inputForm.type" rangeKey="label" rangeValue="value" :range="[
+						        { label: '年假', value: '1' },
+						        { label: '事假', value: '2' },
+						        { label: '病假', value: '3' },
+						        { label: '调休假', value: '4' },
+						        { label: '婚假', value: '5' },
+						        { label: '产假', value: '6' },
+						        { label: '陪产假', value: '7' },
+						        { label: '其他', value: '8' },
+						    ]"></jp-picker>
+			</u-form-item>
+			<u-form-item label="开始时间" borderBottom prop="startDay" :required="true">
+				<el-date-picker
+						v-model="inputForm.startDay"
+						type="date"
+						placeholder="请选择开始时间"
+						style="width:100%"
+						size="default"
+						placement="bottom-start"
+						@change="checkTime"
+						clearable>
+				</el-date-picker>
+				<el-select v-model="inputForm.beginTime" style="width: 50%" placeholder="请选择开始时间" @change="checkTime">
+					<el-option value="上午" label="上午"></el-option>
+					<el-option value="下午" label="下午"></el-option>
+				</el-select>
+			</u-form-item>
+			<u-form-item label="结束时间" borderBottom prop="endDay" :required="true">
+				<el-date-picker
+						v-model="inputForm.endDay"
+						type="date"
+						placeholder="请选择日期"
+						style="width:100%"
+						size="default"
+						placement="bottom-start"
+						@change="checkTime"
+						clearable>
+				</el-date-picker>
+				<el-select v-model="inputForm.endTime" style="width: 50%" placeholder="请选择结束时间" @change="checkTime">
+					<el-option value="上午" label="上午"></el-option>
+					<el-option value="下午" label="下午"></el-option>
+				</el-select>
+			</u-form-item>
+			<u-form-item label="请假天数" borderBottom prop="days" :required="true">
+				<u--input placeholder='请填写请假天数'  v-model="inputForm.days" disabled></u--input>
+			</u-form-item>
+			<u-form-item label="请假原因" borderBottom prop="reason">
+				<u--textarea  placeholder='请输入请假原因' :rows="5" :maxlength="500" v-model="inputForm.reason" ></u--textarea>
+			</u-form-item>
+
+			<u-form-item label="附件">
+				<el-upload
+						class="upload-demo"
+						:action="`http://sxkaf8.natappfree.cc/api/public-modules-server/oss/file/webUpload/upload`"
+						:on-remove="(file, fileList) => handleRemove(file, fileList, '','')"
+						:file-list="inputForm.files"
+						:on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList,'','')"
+						:limit="3">
+					<el-button size="small" type="primary">点击上传</el-button>
+					<div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
+					<template slot="file" slot-scope="{ file }" v-if="shouldShowFile(file) || testFlag">
+						<span @click="handleFileClick(file)">{{ file.name }}</span>
+						<el-button type="text" icon="el-icon-close" @click="handleDelete(file)">✕</el-button>
+					</template>
+				</el-upload>
+			</u-form-item>
+		</u--form>
+		<u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules" ref="inputForm" v-else-if="nodeFlag">
+			<u-form-item label="请假人" borderBottom prop="createName">
+				<u--input placeholder='请填写请假人'  v-model="inputForm.createName" disabled></u--input>
+			</u-form-item>
+			<u-form-item label="请假部门" borderBottom prop="officeName">
+				<u--input placeholder='请填写请假部门'  v-model="inputForm.officeName" disabled></u--input>
+			</u-form-item>
+			<u-form-item label="请假类型" borderBottom prop="type" :required="true">
+				<jp-picker v-model="inputForm.type" rangeKey="label" rangeValue="value" disabled :range="[
+						        { label: '年假', value: '1' },
+						        { label: '事假', value: '2' },
+						        { label: '病假', value: '3' },
+						        { label: '调休假', value: '4' },
+						        { label: '婚假', value: '5' },
+						        { label: '产假', value: '6' },
+						        { label: '陪产假', value: '7' },
+						        { label: '其他', value: '8' },
+						    ]"></jp-picker>
+			</u-form-item>
+			<u-form-item label="开始时间" borderBottom prop="startDay" :required="true">
+				<el-date-picker
+						v-model="inputForm.startDay"
+						type="date"
+						placeholder="请选择开始时间"
+						style="width:100%"
+						size="default"
+						placement="bottom-start"
+						@change="checkTime"
+						:disabled="true"
+						clearable>
+				</el-date-picker>
+				<el-select v-model="inputForm.beginTime" style="width: 50%" disabled placeholder="请选择开始时间" @change="checkTime">
+					<el-option value="上午" label="上午"></el-option>
+					<el-option value="下午" label="下午"></el-option>
+				</el-select>
+			</u-form-item>
+			<u-form-item label="结束时间" borderBottom prop="endDay" :required="true">
+				<el-date-picker
+						:disabled="true"
+						v-model="inputForm.endDay"
+						type="date"
+						placeholder="请选择日期"
+						style="width:100%"
+						size="default"
+						placement="bottom-start"
+						@change="checkTime"
+						clearable>
+				</el-date-picker>
+				<el-select v-model="inputForm.endTime" style="width: 50%" disabled placeholder="请选择结束时间" @change="checkTime">
+					<el-option value="上午" label="上午"></el-option>
+					<el-option value="下午" label="下午"></el-option>
+				</el-select>
+			</u-form-item>
+			<u-form-item label="请假天数" borderBottom prop="days" :required="true">
+				<u--input placeholder='请填写请假天数'  v-model="inputForm.days" disabled></u--input>
+			</u-form-item>
+			<u-form-item label="请假原因" borderBottom prop="reason">
+				<u--textarea  placeholder='请输入请假原因' :rows="5" :maxlength="500" v-model="inputForm.reason" disabled></u--textarea>
+			</u-form-item>
+
+			<u-form-item label="附件">
+				<el-upload
+						:disabled="true"
+						class="upload-demo"
+						:action="`http://sxkaf8.natappfree.cc/api/public-modules-server/oss/file/webUpload/upload`"
+						:on-remove="(file, fileList) => handleRemove(file, fileList, '','')"
+						:file-list="inputForm.files"
+						:on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList,'','')"
+						:limit="3">
+					<el-button size="small" :disabled="true" type="primary">点击上传</el-button>
+					<div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
+					<template slot="file" slot-scope="{ file }" v-if="shouldShowFile(file) || testFlag">
+						<span @click="handleFileClick(file)">{{ file.name }}</span>
+						<el-button type="text" icon="el-icon-close" @click="handleDelete(file)">✕</el-button>
+					</template>
+				</el-upload>
+			</u-form-item>
+		</u--form>
+	</view>
+</template>
+
+<script>
+	import OSSService from "@/api/sys/OSSService"
+	import holidayService from '@/api/dailyOfficeWork/HolidayService'
+	import CommonApi from '@/api/common/CommonApi'
+	import {mapState, mapMutations, mapActions} from 'vuex'
+	export default {
+		components: {
+		},
+		computed: mapState({
+			userInfo: (state) => state.user.userInfo,
+			avatar: (state) => state.user.avatar
+		}),
+		data () {
+			return {
+				showFileList: [], // 控制每个文件是否显示的数组
+				testFlag: false,
+				nodeFlag: false,
+				loading: false,
+				listData: [],
+				fileList3: [],
+				goodsListData: [],
+				materialList: [],
+				searchForm: {
+					wareHouseType: '',
+				},
+				inputForm: {
+					createName:'',
+					officeName:'',
+					id: '',
+					startDay:"",
+					beginTime:'',
+					reason: '',
+					endDay:"",
+					endTime:'',
+					type:'',
+					files: [], // 附件信息
+					procInsId: '',
+					days:'',
+				},
+				rules: {
+					'type': [
+						{
+							required: true,
+							message: '请假类型不能为空',
+							trigger: ['blur', 'change']
+						}
+					],
+					'startDay': [
+						{
+							required: true,
+							message: '开始时间不能为空',
+							trigger: ['blur', 'change']
+						}
+					],
+					'endDay': [
+						{
+							required: true,
+							message: '结束时间不能为空',
+							trigger: ['blur', 'change']
+						}
+					]
+				}
+			}
+		},
+		ossService: null,
+		commonApi: null,
+		// 页面加载时执行
+		created() {
+			this.ossService = new OSSService()
+			this.commonApi = new CommonApi()
+			this.inputForm.createName = this.userInfo.name
+			this.inputForm.officeName = this.userInfo.officeDTO.name
+		},
+		props: {
+			businessId: {
+				type: String,
+				default: ''
+			},
+			formReadOnly: {
+				type: Boolean,
+				default: false
+			}
+		},
+		watch: {
+			'businessId': {
+				handler (newVal) {
+					if (this.businessId) {
+						this.init(this.businessId)
+					} else {
+						this.$nextTick(() => {
+							// this.$refs.inputForm.reset()
+						})
+					}
+				},
+				immediate: true,
+				deep: false
+			}
+		},
+		methods: {
+			init (id) {
+				this.nodeFlag = true
+				this.inputForm.id = id
+				if (id) {
+					holidayService.queryById(id).then((data) => {
+
+						this.commonApi.getTaskNameByProcInsId(data.procInsId).then((data) => {
+							if (this.isNotEmpty(data)) {
+								if (data === '调整重新发起' || this.isEmpty(data)) {
+									this.nodeFlag = false
+								} else {
+									this.nodeFlag = true
+								}
+							}
+						})
+						this.inputForm = this.recover(this.inputForm, data)
+
+						if (this.inputForm.files) {
+							this.inputForm.files.forEach( (item,index) => {
+								this.$set(this.showFileList, index, true);
+							})
+						}
+					})
+				}
+			},
+			formatDate(date) {
+				const dateNew = new Date(date); // 将日期字符串转换为 Date 对象
+				const year = dateNew.getFullYear();
+				const month = (dateNew.getMonth() + 1).toString().padStart(2, '0');
+				const day = dateNew.getDate().toString().padStart(2, '0');
+				return `${year}-${month}-${day}`;
+			},
+			isEmpty(value) {
+				let result = false;
+				if (value == null || value == undefined) {
+					result = true;
+				}
+				if (typeof value == 'string' && (value.replace(/\s+/g, "") == "" || value == "")) {
+					result = true;
+				}
+				if (typeof value == "object" && value instanceof Array && value.length === 0) {
+					result = true;
+				}
+				return result;
+			},
+			isNotEmpty (value) {
+				return !this.isEmpty(value)
+			},
+			/**
+			 * 判断是否为空
+			 */
+			isNull(val) {
+				if (val instanceof Array) {
+					if (val.length === 0) return true;
+				} else if (val instanceof Object) {
+					if (JSON.stringify(val) === "{}") return true;
+				} else {
+					if (
+							val === "null" ||
+							val == null ||
+							val === "undefined" ||
+							val === undefined ||
+							val === ""
+					)
+						return true;
+					return false;
+				}
+				return false;
+			},
+			formatDateNew(date) {
+				const year = date.getFullYear();
+				const month = (date.getMonth() + 1).toString().padStart(2, '0');
+				const day = date.getDate().toString().padStart(2, '0');
+				const hours = date.getHours().toString().padStart(2, '0');
+				const minutes = date.getMinutes().toString().padStart(2, '0');
+				const seconds = date.getSeconds().toString().padStart(2, '0');
+
+				return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+			},
+			handleUploadSuccess (res, file, fileList, index, type) {
+
+				// 将 fileList 转换为你期望的格式
+				const formattedFiles = fileList.map(fileItem => {
+					return {
+						name: fileItem.name,
+						size: fileItem.size,
+						url: '/' + fileItem.response.url,
+						createBy: this.userInfo,
+						by: this.userInfo.id,
+						createTime: this.formatDateNew(new Date())
+					};
+				});
+				this.inputForm.files = formattedFiles
+
+				fileList.forEach((item, index) => {
+					if (item === file) {
+						this.$set(this.showFileList, index, true);
+					}
+				});
+
+				// 强制更新视图
+				this.$forceUpdate();
+			},
+			handleRemove(file, fileList, index, type) {
+				// 处理移除文件逻辑
+				// file 是移除的文件
+				// fileList 是当前文件列表
+				const formattedFiles = fileList.map(fileItem => {
+					return {
+						name: fileItem.name,
+						size: fileItem.size,
+						url: '/' + fileItem.response.url,
+						createBy: this.userInfo,
+						by: this.userInfo.id,
+						createTime: this.formatDateNew(new Date())
+					};
+				});
+				this.inputForm.files = formattedFiles
+
+
+				// 如果你想要更新文件列表,可以在这里更新 inputForm.fileInfoLost
+				// this.inputForm.fileInfoLost = fileList;
+			},
+			saveForm(callback) {
+				// 所有验证通过,执行保存操作
+
+				if (this.isNotEmpty(this.inputForm.startDay)) {
+					this.inputForm.startDay = this.formatDate(this.inputForm.startDay);
+				}
+				if (this.isNotEmpty(this.inputForm.endDay)) {
+					this.inputForm.endDay = this.formatDate(this.inputForm.endDay);
+				}
+
+				return new Promise((resolve, reject) => {
+
+					let errors = [];
+
+					if (this.isEmpty(this.inputForm.startDay) || this.isEmpty(this.inputForm.beginTime)){
+						errors.push('请选择开始时间');
+					}
+					if (this.isEmpty(this.inputForm.endDay) || this.isEmpty(this.inputForm.endTime)){
+						errors.push('请选择结束时间');
+					}
+					if (this.isEmpty(this.inputForm.type)){
+						errors.push('请选择请假类型');
+					}
+
+					if (this.inputForm.type === '1'){
+						if (this.isNotEmpty(this.inputForm.startDay) && this.isNotEmpty(this.inputForm.beginTime)
+							&& this.isNotEmpty(this.inputForm.endDay) && this.isNotEmpty(this.inputForm.endTime)) {
+							holidayService.checkType(this.inputForm).then((data)=>{
+								let day=data.split(",")
+								if (!day[0].includes(this.inputForm.days)){
+									errors.push(data);
+								}
+							})
+						}
+
+					}
+
+					if (errors.length > 0) {
+						// 存在错误,显示提示信息
+						errors.forEach(error => {
+							uni.showToast({
+								title: error,
+								icon: 'none',
+								duration: 1500
+							});
+						});
+						reject('Form validation failed');
+					} else {
+						this.$refs.inputForm.validate().then(res => {
+							this.inputForm.status = '2'
+							this.inputForm.userId = this.userInfo.id
+							holidayService.saveForm(this.inputForm).then((data) => {
+								this.inputForm.id = data.businessId
+								callback(data.businessTable, data.businessId, this.inputForm)
+								this.$refs.inputForm.resetFields()
+								this.loading = false
+							}).catch(() => {
+								this.$refs.inputForm.resetFields()
+							}).catch((e) => {
+
+							})
+						})
+					}
+				});
+
+				// this.$refs.inputForm.validate().then(() => {
+				// 	uni.showLoading();
+				// 	this.inputForm.status = '2';
+				// 	this.holidayService.saveForm(this.inputForm).then(data => {
+				// 		callback(data.businessTable, data.businessId,this.inputForm);
+				// 	}).catch(error => {
+				// 	});
+				// }).catch(() => {
+				// });
+			},
+
+			// 修改状态
+			async updateStatusById (type, callback) {
+				if (type === 'reject' || type === 'reback') {
+					holidayService.queryById(this.inputForm.id).then((data) => {
+						if (data.status !== '2') { // status的值不等于“审核中”,就弹出提示
+							this.loading = false
+							this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+							throw new Error()
+						} else {
+							if (type === 'reject') {
+								// 驳回
+								this.inputForm.status = '4'
+							}
+							if (type === 'reback') {
+								// 撤回
+								this.inputForm.status = '3'
+							}
+							if (type === 'reject' || type === 'reback') {
+								let param = {status: this.inputForm.status, id: this.inputForm.id}
+								holidayService.updateStatusById(param).then(() => {
+									this.loading = false
+									callback()
+								})
+							}
+						}
+					})
+				} else if (type === 'hold') {
+					holidayService.queryById(this.inputForm.id).then((data) => {
+						if (data.status !== '4') { // status的值不等于“驳回”就弹出提示
+							this.loading = false
+							this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+							throw new Error()
+						} else {
+							// 终止
+							let param = {status: '1', id: this.inputForm.id}
+							holidayService.updateStatusById(param).then(() => {
+								this.loading = false
+								callback()
+							})
+						}
+					})
+				}
+			},
+			reapplyForm (callback) {
+				this.loading = true
+				holidayService.queryById(this.inputForm.id).then((data) => {
+					if (data.status !== '4') { // 审核状态不是“驳回”,就弹出提示
+						this.loading = false
+						this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+						throw new Error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+					} else {
+						this.startFormTrue(callback)
+					}
+				})
+			},
+			// 送审
+			async startFormTrue (callback) {
+
+				if (this.isNotEmpty(this.inputForm.startDay)) {
+					this.inputForm.startDay = this.formatDate(this.inputForm.startDay);
+				}
+				if (this.isNotEmpty(this.inputForm.endDay)) {
+					this.inputForm.endDay = this.formatDate(this.inputForm.endDay);
+				}
+
+				return new Promise((resolve, reject) => {
+
+					let errors = [];
+
+					if (this.isEmpty(this.inputForm.startDay) || this.isEmpty(this.inputForm.beginTime)){
+						errors.push('请选择开始时间');
+					}
+					if (this.isEmpty(this.inputForm.endDay) || this.isEmpty(this.inputForm.endTime)){
+						errors.push('请选择结束时间');
+					}
+					if (this.isEmpty(this.inputForm.type)){
+						errors.push('请选择请假类型');
+					}
+
+					if (this.inputForm.type === '1'){
+						holidayService.checkType(this.inputForm).then((data)=>{
+							let day=data.split(",")
+							if (!day[0].includes(this.inputForm.days)){
+								errors.push(data);
+							}
+						})
+					}
+
+					if (errors.length > 0) {
+						// 存在错误,显示提示信息
+						errors.forEach(error => {
+							uni.showToast({
+								title: error,
+								icon: 'none',
+								duration: 2000
+							});
+						});
+						reject('Form validation failed');
+					} else {
+						this.$refs.inputForm.validate().then(res => {
+							this.inputForm.status = '2'
+							holidayService.saveForm(this.inputForm).then((data) => {
+								console.log('data', data)
+								this.inputForm.id = data.businessId
+								callback(data.businessTable, data.businessId, this.inputForm)
+								this.$refs.inputForm.resetFields()
+								this.loading = false
+							}).catch(() => {
+								this.$refs.inputForm.resetFields()
+							}).catch((e) => {
+
+							})
+						})
+					}
+				});
+			},
+			// 通过
+			async agreeForm (callback) {
+				console.log('this.inputForm', this.inputForm)
+				this.$refs.inputForm.validate().then(res => {
+					if (this.inputForm.days >1) {
+						this.commonApi.getTaskNameByProcInsId(this.inputForm.procInsId).then((data) => {
+							if (this.isNotEmpty(data)) {
+								if (data === '总经理审核') {
+									this.inputForm.status = '5'
+								} else {
+									this.inputForm.status = '2'
+								}
+							}
+
+							holidayService.saveForm(this.inputForm).then((data) => {
+								callback(data.businessTable, data.businessId, this.inputForm)
+								this.$refs.inputForm.resetFields()
+								this.loading = false
+							}).catch(() => {
+								this.loading = false
+								this.$refs.inputForm.resetFields()
+							})
+						})
+					} else {
+						this.inputForm.status = '5'
+						holidayService.saveForm(this.inputForm).then((data) => {
+							callback(data.businessTable, data.businessId, this.inputForm)
+							this.$refs.inputForm.resetFields()
+							this.loading = false
+						}).catch(() => {
+							this.loading = false
+							this.$refs.inputForm.resetFields()
+						})
+					}
+				})
+			},
+			checkType(){
+				if (this.inputForm.type === '1'){
+					holidayService.checkType(this.inputForm).then((data)=>{
+						console.log('data',data)
+						uni.showToast({
+							title: data,
+							icon: "none",
+							duration:2000
+						})
+					})
+				}
+			},
+			checkTime(){
+				let differenceInDays =''
+				let date1=new Date(this.inputForm.startDay)
+				let date2=new Date(this.inputForm.endDay)
+				if ((date2<date1) || (date2 === date1 && this.inputForm.beginTime === '下午' && this.inputForm.endTime === '上午')){
+					uni.showToast({
+						title: '开始时间不能小于结束时间',
+						icon: "none",
+						duration:2000
+					})
+					this.inputForm.startDay = ''
+					this.inputForm.endDay = ''
+					this.inputForm.beginTime = ''
+					this.inputForm.endTime = ''
+				}
+				differenceInDays= Math.floor((date2 - date1) / (1000 * 60 * 60 * 24));
+				console.log('differenceInDays',differenceInDays)
+				if (differenceInDays === 0 || differenceInDays > 1){
+					if ((this.inputForm.beginTime === '上午' && this.inputForm.endTime === '下午') ||(this.inputForm.beginTime === '下午' && this.inputForm.endTime === '上午') ){
+						differenceInDays=differenceInDays+1
+					}else if ((this.inputForm.beginTime === '上午' && this.inputForm.endTime === '上午') ||(this.inputForm.beginTime === '下午' && this.inputForm.endTime === '下午')){
+						differenceInDays=differenceInDays+0.5
+					}
+				}else if (differenceInDays ===1){
+					if ((this.inputForm.beginTime === '上午' && this.inputForm.endTime === '下午') ){
+						differenceInDays=differenceInDays+1
+					}else if ((this.inputForm.beginTime === '上午' && this.inputForm.endTime === '上午') ||(this.inputForm.beginTime === '下午' && this.inputForm.endTime === '下午')){
+						differenceInDays=differenceInDays+0.5
+					}else if (this.inputForm.beginTime === '下午' && this.inputForm.endTime === '上午'){
+						differenceInDays
+					}
+				}
+				if (this.isNotEmpty(this.inputForm.beginTime) && this.isNotEmpty(this.inputForm.endTime)){
+					this.inputForm.days = differenceInDays
+					this.checkType()
+				}
+
+			},
+			shouldShowFile(file,index,type) {
+				if (this.inputForm.files && this.inputForm.files.length > 0) {
+					// 返回一个布尔值,确定是否显示上传成功后的文件
+					return this.showFileList[this.inputForm.files.indexOf(file)];
+				}
+				return false; // 默认返回 false 或者其他适当的
+			},
+			async handleFileClick(file) {
+				await this.ossService.getTemporaryUrl(file.url).then((data) => {
+					file.lsUrl = data
+				})
+				console.log('file', file)
+				if (this.isImage(file.name)) {
+					// 如果是图片文件,则执行放大显示图片的逻辑
+					this.handleImageClick(file);
+				} else {
+					// window.open(file.lsUrl, '_blank')
+					window.location.href = file.lsUrl
+					// 如果不是图片文件,则执行其他操作,比如下载文件等
+				}
+			},
+			handleImageClick(file) {
+				// 在点击图片时执行放大显示的逻辑
+				this.$alert(`<img src="${file.lsUrl}" style="max-width: 100%; max-height: 100%;" />`, '图片详情', {
+					dangerouslyUseHTMLString: true,
+					customClass: 'custom-alert'
+				});
+			},
+			// 判断文件是否是图片类型
+			isImage(fileName) {
+				const ext = fileName.toLowerCase().split('.').pop(); // 获取文件的后缀名
+				return ['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(ext); // 判断后缀名是否是图片类型
+			},
+			handleDelete(file,lineIndex,type) {
+				// 处理删除文件的逻辑
+				// 从文件列表中移除文件
+				const index = this.inputForm.files.indexOf(file);
+				if (index !== -1) {
+					this.inputForm.files.splice(index, 1);
+					this.showFileList.splice(index, 1); // 从showFileList中移除对应的元素
+				}
+
+			},
+		}
+	}
+</script>
+
+<style>
+	.cu-form-group .title {
+		min-width: calc(4em + 40px);
+	}
+
+	/* 样式示例,您可能需要根据实际情况调整 */
+	.upload-demo {
+		width: 30%;
+	}
+</style>

+ 366 - 0
pages/human/depart/handover/HandoverAddForm.vue

@@ -0,0 +1,366 @@
+<template>
+    <view>
+        <cu-custom :backUrl="'/pages/index/index'" :isBack="true" bgColor="bg-gradual-blue" >
+            <block slot="content">离职交接</block>
+        </cu-custom>
+        <u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules" ref="inputForm" v-if="!nodeFlag">
+            <u-form-item label="姓名" borderBottom prop="name">
+                <u--input placeholder='请填写请假人'  v-model="inputForm.name" disabled></u--input>
+            </u-form-item>
+            <u-form-item label="所属部门" borderBottom prop="departmentName">
+                <u--input placeholder='请选择所属部门'  v-model="inputForm.departmentName" disabled></u--input>
+            </u-form-item>
+            <u-form-item label="项目经理" borderBottom prop="projectManager" :required="true">
+                <user-select v-model="inputForm.projectManager" :disabled="testFlag"></user-select>
+            </u-form-item>
+            <u-form-item label="备注" borderBottom prop="remarks">
+                <u--textarea  placeholder='请填写备注' :maxlength="500" v-model="inputForm.remarks" :disabled="testFlag"></u--textarea>
+            </u-form-item>
+        </u--form>
+        <u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules" ref="inputForm" v-else-if="nodeFlag">
+            <u-form-item label="姓名" borderBottom prop="name">
+                <u--input placeholder='请填写请假人'  v-model="inputForm.name" disabled></u--input>
+            </u-form-item>
+            <u-form-item label="所属部门" borderBottom prop="departmentName">
+                <u--input placeholder='请选择所属部门'  v-model="inputForm.departmentName" disabled></u--input>
+            </u-form-item>
+            <u-form-item label="项目经理" borderBottom prop="projectManager" :required="true" v-if="!testFlag">
+                <user-select v-model="inputForm.projectManager" ></user-select>
+            </u-form-item>
+            <u-form-item label="项目经理" borderBottom prop="projectManagerName" :required="true" v-else-if="testFlag">
+                <u--input v-model="inputForm.projectManagerName" disabled></u--input>
+            </u-form-item>
+            <u-form-item label="备注" borderBottom prop="remarks">
+                <u--textarea  placeholder='请填写备注' :maxlength="500" v-model="inputForm.remarks" :disabled="testFlag"></u--textarea>
+            </u-form-item>
+        </u--form>
+    </view>
+</template>
+
+<script>
+    import userSelect from '@/components/user-select/user-select-radio.vue'
+    import handoverService from '@/api/human/depart/HandoverService'
+    import CommonApi from '@/api/common/CommonApi'
+    import {mapState, mapMutations, mapActions} from 'vuex'
+    export default {
+        components: {
+            userSelect,
+        },
+        computed: mapState({
+            userInfo: (state) => state.user.userInfo,
+            avatar: (state) => state.user.avatar
+        }),
+        data () {
+            return {
+                inputForm: {
+                    name:'',
+                    department:'',
+                    departmentName:'',
+                    projectManager:'',
+                    projectManagerName:'',
+                    id: '',
+                    procInsId: '',
+                    type: '',
+                    remarks: '',
+                    draftAdministrator: '',
+                },
+                rules: {
+                    'projectManager': [
+                        {
+                            required: true,
+                            message: '项目经理不能为空',
+                            trigger: ['blur', 'change']
+                        }
+                    ],
+                },
+                nodeFlag: false,
+                testFlag: false,
+            }
+        },
+        commonApi: null,
+        // 页面加载时执行
+        created() {
+            this.commonApi = new CommonApi()
+            this.inputForm.name = this.userInfo.name
+            this.inputForm.department = this.userInfo.officeDTO.id
+            this.inputForm.departmentName = this.userInfo.officeDTO.name
+        },
+        props: {
+            businessId: {
+                type: String,
+                default: ''
+            },
+            formReadOnly: {
+                type: Boolean,
+                default: false
+            }
+        },
+        watch: {
+            'businessId': {
+                handler (newVal) {
+                    if (this.businessId) {
+                        this.init(this.businessId)
+                    } else {
+                        this.$nextTick(() => {
+                            // this.$refs.inputForm.reset()
+                        })
+                    }
+                },
+                immediate: true,
+                deep: false
+            }
+        },
+        methods: {
+            init (id) {
+                this.nodeFlag = true
+                this.inputForm.id = id
+                if (id) {
+                    handoverService.findById(id).then((data) => {
+
+                        this.commonApi.getTaskNameByProcInsId(data.procInsId).then((data) => {
+                            if (this.isNotEmpty(data)) {
+                                if (data === '调整重新申请' || this.isEmpty(data)) {
+                                    this.nodeFlag = false
+                                } else if (data === '部门主任审批'){
+                                    this.testFlag = true
+                                    this.nodeFlag = true
+                                } else {
+                                    this.nodeFlag = true
+                                }
+                            }
+                        })
+
+                        if (this.userInfo.id === data.projectManager) {
+                            this.testFlag = true
+                        } else {
+                            this.testFlag = false
+                        }
+
+                        this.inputForm = this.recover(this.inputForm, data)
+                    })
+                }
+            },
+            isEmpty(value) {
+                let result = false;
+                if (value == null || value == undefined) {
+                    result = true;
+                }
+                if (typeof value == 'string' && (value.replace(/\s+/g, "") == "" || value == "")) {
+                    result = true;
+                }
+                if (typeof value == "object" && value instanceof Array && value.length === 0) {
+                    result = true;
+                }
+                return result;
+            },
+            isNotEmpty (value) {
+                return !this.isEmpty(value)
+            },
+            /**
+             * 判断是否为空
+             */
+            isNull(val) {
+                if (val instanceof Array) {
+                    if (val.length === 0) return true;
+                } else if (val instanceof Object) {
+                    if (JSON.stringify(val) === "{}") return true;
+                } else {
+                    if (
+                        val === "null" ||
+                        val == null ||
+                        val === "undefined" ||
+                        val === undefined ||
+                        val === ""
+                    )
+                        return true;
+                    return false;
+                }
+                return false;
+            },
+            formatDateNew(date) {
+                const year = date.getFullYear();
+                const month = (date.getMonth() + 1).toString().padStart(2, '0');
+                const day = date.getDate().toString().padStart(2, '0');
+                const hours = date.getHours().toString().padStart(2, '0');
+                const minutes = date.getMinutes().toString().padStart(2, '0');
+                const seconds = date.getSeconds().toString().padStart(2, '0');
+
+                return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+            },
+            saveForm(callback) {
+
+                // 所有验证通过,执行保存操作
+
+                return new Promise( async (resolve, reject) => {
+
+                    let errors = [];
+
+                    //查询数据库中是否已经有了离职的申请数据,有则不能发起
+                    await handoverService.selectComplete().then((data) => {
+                        if (data) {
+                            errors.push('已存在离职交接 或 离职申请未审批,无法发起申请!');
+                        }
+                    })
+
+
+                    if (errors.length > 0) {
+                        // 存在错误,显示提示信息
+                        errors.forEach(error => {
+                            uni.showToast({
+                                title: error,
+                                icon: 'none',
+                                duration: 1500
+                            });
+                        });
+                        reject('Form validation failed');
+                    } else {
+
+                        // 如果正在提交中,则直接返回,避免重复提交
+                        if (this.submitting) return;
+
+                        // 设置提交状态为 true
+                        this.submitting = true;
+
+                        this.$refs.inputForm.validate().then(res => {
+                            this.inputForm.type = '2'
+                            this.inputForm.userId = this.userInfo.id
+                            handoverService.save(this.inputForm).then((data) => {
+                                this.inputForm.id = data.businessId
+                                this.inputForm.assignee = this.inputForm.projectManager
+                                callback(data.businessTable, data.businessId, this.inputForm)
+                                this.$refs.inputForm.resetFields()
+                                this.loading = false
+
+                                // 重置提交状态为 false
+                                this.submitting = false;
+                            }).catch(() => {
+                                this.$refs.inputForm.resetFields()
+                                // 重置提交状态为 false
+                                this.submitting = false;
+                            }).catch((e) => {
+                                // 重置提交状态为 false
+                                this.submitting = false;
+                            })
+                        })
+                    }
+                });
+            },
+
+            // 修改状态
+            async updateStatusById (type, callback) {
+                if (type === 'reject') {
+                    handoverService.findById(this.inputForm.id).then((data) => {
+                        if (data.type !== '2') { // status的值不等于“审核中”,就弹出提示
+                            this.loading = false
+                            this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+                            throw new Error()
+                        } else {
+                            this.commonApi.getTaskNameByProcInsId(this.inputForm.procInsId).then((name) => {
+                                if (this.isNotEmpty(name)) {
+                                    if (name === '项目经理审批' || name === '项目经理重新审批') {
+                                        this.inputForm.type = '4'
+                                    }
+                                }
+                                handoverService.updateStatusById(this.inputForm).then(() => {
+                                    this.loading = false
+                                    callback()
+                                })
+                            })
+                        }
+                    })
+                } else if (type === 'hold') {
+                    handoverService.findById(this.inputForm.id).then((data) => {
+                        if (data.type !== '4') { // status的值不等于“驳回”就弹出提示
+                            this.loading = false
+                            this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+                            throw new Error()
+                        } else {
+                            // 终止
+                            let param = {status: '1', id: this.inputForm.id}
+                            handoverService.updateStatusById(param).then(() => {
+                                this.loading = false
+                                callback()
+                            })
+                        }
+                    })
+                }
+            },
+            reapplyForm (callback) {
+                this.loading = true
+                handoverService.findById(this.inputForm.id).then((data) => {
+                    if (data.type !== '4') { // 审核状态不是“驳回”,就弹出提示
+                        this.loading = false
+                        this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+                        throw new Error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+                    } else {
+                        this.startFormTrue(callback)
+                    }
+                })
+            },
+            // 送审
+            async startFormTrue (callback) {
+
+                return new Promise((resolve, reject) => {
+
+                    let errors = [];
+
+                    if (errors.length > 0) {
+                        // 存在错误,显示提示信息
+                        errors.forEach(error => {
+                            uni.showToast({
+                                title: error,
+                                icon: 'none',
+                                duration: 2000
+                            });
+                        });
+                        reject('Form validation failed');
+                    } else {
+                        this.$refs.inputForm.validate().then(res => {
+                            this.inputForm.type = '2'
+                            handoverService.save(this.inputForm).then((data) => {
+                                console.log('data', data)
+                                this.inputForm.id = data.businessId
+                                this.inputForm.assignee = this.inputForm.projectManager
+                                callback(data.businessTable, data.businessId, this.inputForm)
+                                this.$refs.inputForm.resetFields()
+                                this.loading = false
+                            }).catch(() => {
+                                this.$refs.inputForm.resetFields()
+                            }).catch((e) => {
+
+                            })
+                        })
+                    }
+                });
+            },
+            // 通过
+            async agreeForm (callback) {
+                this.$refs.inputForm.validate().then(res => {
+                    this.commonApi.getTaskNameByProcInsId(this.inputForm.procInsId).then((data) => {
+                        if (this.isNotEmpty(data)) {
+                            if (data === '部门主任审批') {
+                                this.inputForm.type = '5'
+                            } else {
+                                this.inputForm.type = '2'
+                            }
+                        }
+                        handoverService.save(this.inputForm).then((data) => {
+                            callback(data.businessTable, data.businessId, this.inputForm)
+                            this.$refs.inputForm.resetFields()
+                            this.loading = false
+                        }).catch(() => {
+                            this.loading = false
+                            this.$refs.inputForm.resetFields()
+                        })
+                    })
+                })
+            },
+        }
+    }
+</script>
+
+<style>
+    .cu-form-group .title {
+        min-width: calc(4em + 40px);
+    }
+</style>

+ 426 - 0
pages/human/depart/registration/DepartRegistrationAddForm.vue

@@ -0,0 +1,426 @@
+<template>
+    <view>
+        <cu-custom :backUrl="'/pages/index/index'" :isBack="true" bgColor="bg-gradual-blue" >
+            <block slot="content">离职申请</block>
+        </cu-custom>
+        <u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules" ref="inputForm" v-if="!nodeFlag">
+            <u-form-item label="姓名" borderBottom prop="name">
+                <u--input placeholder='请填写请假人'  v-model="inputForm.name" disabled></u--input>
+            </u-form-item>
+            <u-form-item label="所属部门" borderBottom prop="departmentName">
+                <u--input placeholder='请选择所属部门'  v-model="inputForm.departmentName" disabled></u--input>
+            </u-form-item>
+            <u-form-item label="到岗日期" borderBottom prop="arrivalDate" :required="true">
+                <el-date-picker
+                        v-model="inputForm.arrivalDate"
+                        type="date"
+                        placeholder="请选择到岗日期"
+                        style="width:100%"
+                        size="default"
+                        placement="bottom-start"
+                        @change="validateDepartureDate2"
+                        clearable>
+                </el-date-picker>
+            </u-form-item>
+            <u-form-item label="预定离职日期" borderBottom prop="departResignationDate" :required="true">
+                <el-date-picker
+                        v-model="inputForm.departResignationDate"
+                        type="date"
+                        placeholder="请选择预定离职日期"
+                        style="width:100%"
+                        size="default"
+                        placement="bottom-start"
+                        @change="validateDepartureDate"
+                        clearable>
+                </el-date-picker>
+            </u-form-item>
+            <u-form-item label="备注" borderBottom prop="remarks">
+                <u--textarea  placeholder='请填写备注' :maxlength="500" v-model="inputForm.remarks" ></u--textarea>
+            </u-form-item>
+        </u--form>
+    </view>
+</template>
+
+<script>
+    import departRegistrationService from '@/api/human/depart/DepartRegistrationService'
+    import CommonApi from '@/api/common/CommonApi'
+    import {mapState, mapMutations, mapActions} from 'vuex'
+    export default {
+        components: {
+        },
+        computed: mapState({
+            userInfo: (state) => state.user.userInfo,
+            avatar: (state) => state.user.avatar
+        }),
+        data () {
+            return {
+                inputForm: {
+                    name:'',
+                    department:'',
+                    departmentName:'',
+                    arrivalDate:'',
+                    departResignationDate:'',
+                    id: '',
+                    procInsId: '',
+                    type: '',
+                },
+                rules: {
+                    'arrivalDate': [
+                        {
+                            required: true,
+                            message: '到岗日期不能为空',
+                            trigger: ['blur', 'change']
+                        }
+                    ],
+                    'departResignationDate': [
+                        {
+                            required: true,
+                            message: '预定离职日期不能为空',
+                            trigger: ['blur', 'change']
+                        }
+                    ],
+                },
+                nodeFlag: false,
+            }
+        },
+        commonApi: null,
+        // 页面加载时执行
+        created() {
+            this.commonApi = new CommonApi()
+            this.inputForm.name = this.userInfo.name
+            this.inputForm.department = this.userInfo.officeDTO.id
+            this.inputForm.departmentName = this.userInfo.officeDTO.name
+        },
+        props: {
+            businessId: {
+                type: String,
+                default: ''
+            },
+            formReadOnly: {
+                type: Boolean,
+                default: false
+            }
+        },
+        watch: {
+            'businessId': {
+                handler (newVal) {
+                    if (this.businessId) {
+                        this.init(this.businessId)
+                    } else {
+                        this.$nextTick(() => {
+                            // this.$refs.inputForm.reset()
+                        })
+                    }
+                },
+                immediate: true,
+                deep: false
+            }
+        },
+        methods: {
+            init (id) {
+                this.nodeFlag = true
+                this.inputForm.id = id
+                if (id) {
+                    departRegistrationService.findById(id).then((data) => {
+
+                        // this.commonApi.getTaskNameByProcInsId(data.procInsId).then((data) => {
+                        //     if (this.isNotEmpty(data)) {
+                        //         if (data === '调整重新发起' || this.isEmpty(data)) {
+                        //             this.nodeFlag = false
+                        //         } else {
+                        //             this.nodeFlag = true
+                        //         }
+                        //     }
+                        // })
+                        this.inputForm = this.recover(this.inputForm, data)
+                    })
+                }
+            },
+            isEmpty(value) {
+                let result = false;
+                if (value == null || value == undefined) {
+                    result = true;
+                }
+                if (typeof value == 'string' && (value.replace(/\s+/g, "") == "" || value == "")) {
+                    result = true;
+                }
+                if (typeof value == "object" && value instanceof Array && value.length === 0) {
+                    result = true;
+                }
+                return result;
+            },
+            isNotEmpty (value) {
+                return !this.isEmpty(value)
+            },
+            /**
+             * 判断是否为空
+             */
+            isNull(val) {
+                if (val instanceof Array) {
+                    if (val.length === 0) return true;
+                } else if (val instanceof Object) {
+                    if (JSON.stringify(val) === "{}") return true;
+                } else {
+                    if (
+                        val === "null" ||
+                        val == null ||
+                        val === "undefined" ||
+                        val === undefined ||
+                        val === ""
+                    )
+                        return true;
+                    return false;
+                }
+                return false;
+            },
+            formatDateNew(date) {
+                const year = date.getFullYear();
+                const month = (date.getMonth() + 1).toString().padStart(2, '0');
+                const day = date.getDate().toString().padStart(2, '0');
+                const hours = date.getHours().toString().padStart(2, '0');
+                const minutes = date.getMinutes().toString().padStart(2, '0');
+                const seconds = date.getSeconds().toString().padStart(2, '0');
+
+                return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+            },
+            formatDate(date) {
+                const dateNew = new Date(date); // 将日期字符串转换为 Date 对象
+                const year = dateNew.getFullYear();
+                const month = (dateNew.getMonth() + 1).toString().padStart(2, '0');
+                const day = dateNew.getDate().toString().padStart(2, '0');
+                return `${year}-${month}-${day}`;
+            },
+            saveForm(callback) {
+
+                // 所有验证通过,执行保存操作
+                if (this.isNotEmpty(this.inputForm.arrivalDate)) {
+                    this.inputForm.arrivalDate = this.formatDate(this.inputForm.arrivalDate);
+                }
+                if (this.isNotEmpty(this.inputForm.departResignationDate)) {
+                    this.inputForm.departResignationDate = this.formatDate(this.inputForm.departResignationDate);
+                }
+
+                return new Promise(async (resolve, reject) => {
+
+                    let errors = [];
+
+                    if (this.isEmpty(this.inputForm.arrivalDate)){
+                        errors.push('请选择到岗日期');
+                    }
+                    if (this.isEmpty(this.inputForm.departResignationDate)){
+                        errors.push('请选择预定离职日期');
+                    }
+
+                    //查询数据库中是否已经有了离职的申请数据,有则不能发起
+                    await departRegistrationService.selectComplete().then((data) => {
+                        if (data) {
+                            console.log('data', data)
+                            errors.push('已存在离职申请,无法多次提交');
+                        }
+                    })
+
+
+                    if (errors.length > 0) {
+                        // 存在错误,显示提示信息
+                        errors.forEach(error => {
+                            uni.showToast({
+                                title: error,
+                                icon: 'none',
+                                duration: 1500
+                            });
+                        });
+                        reject('Form validation failed');
+                    } else {
+                        this.$refs.inputForm.validate().then(res => {
+                            this.inputForm.type = '2'
+                            this.inputForm.userId = this.userInfo.id
+                            departRegistrationService.save(this.inputForm).then((data) => {
+                                this.inputForm.id = data.businessId
+                                callback(data.businessTable, data.businessId, this.inputForm)
+                                this.$refs.inputForm.resetFields()
+                                this.loading = false
+                            }).catch(() => {
+                                this.$refs.inputForm.resetFields()
+                            }).catch((e) => {
+
+                            })
+                        })
+                    }
+                });
+            },
+
+            // 修改状态
+            async updateStatusById (type, callback) {
+                if (type === 'reject' || type === 'reback') {
+                    departRegistrationService.findById(this.inputForm.id).then((data) => {
+                        if (data.type !== '2') { // status的值不等于“审核中”,就弹出提示
+                            this.loading = false
+                            this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+                            throw new Error()
+                        } else {
+                            if (type === 'reject') {
+                                // 驳回
+                                this.inputForm.type = '4'
+                            }
+                            if (type === 'reback') {
+                                // 撤回
+                                this.inputForm.type = '3'
+                            }
+                            if (type === 'reject' || type === 'reback') {
+                                let param = {status: this.inputForm.type, id: this.inputForm.id}
+                                departRegistrationService.updateStatusById(param).then(() => {
+                                    this.loading = false
+                                    callback()
+                                })
+                            }
+                        }
+                    })
+                } else if (type === 'hold') {
+                    departRegistrationService.findById(this.inputForm.id).then((data) => {
+                        if (data.type !== '4') { // status的值不等于“驳回”就弹出提示
+                            this.loading = false
+                            this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+                            throw new Error()
+                        } else {
+                            // 终止
+                            let param = {status: '1', id: this.inputForm.id}
+                            departRegistrationService.updateStatusById(param).then(() => {
+                                this.loading = false
+                                callback()
+                            })
+                        }
+                    })
+                }
+            },
+            reapplyForm (callback) {
+                this.loading = true
+                departRegistrationService.findById(this.inputForm.id).then((data) => {
+                    if (data.type !== '4') { // 审核状态不是“驳回”,就弹出提示
+                        this.loading = false
+                        this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+                        throw new Error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+                    } else {
+                        this.startFormTrue(callback)
+                    }
+                })
+            },
+            // 送审
+            async startFormTrue (callback) {
+
+                if (this.isNotEmpty(this.inputForm.arrivalDate)) {
+                    this.inputForm.arrivalDate = this.formatDate(this.inputForm.arrivalDate);
+                }
+                if (this.isNotEmpty(this.inputForm.departResignationDate)) {
+                    this.inputForm.departResignationDate = this.formatDate(this.inputForm.departResignationDate);
+                }
+
+                return new Promise((resolve, reject) => {
+
+                    let errors = [];
+
+                    if (this.isEmpty(this.inputForm.arrivalDate)){
+                        errors.push('请选择到岗日期');
+                    }
+                    if (this.isEmpty(this.inputForm.departResignationDate)){
+                        errors.push('请选择预定离职日期');
+                    }
+
+                    if (errors.length > 0) {
+                        // 存在错误,显示提示信息
+                        errors.forEach(error => {
+                            uni.showToast({
+                                title: error,
+                                icon: 'none',
+                                duration: 2000
+                            });
+                        });
+                        reject('Form validation failed');
+                    } else {
+                        this.$refs.inputForm.validate().then(res => {
+                            this.inputForm.type = '2'
+                            departRegistrationService.save(this.inputForm).then((data) => {
+                                console.log('data', data)
+                                this.inputForm.id = data.businessId
+                                callback(data.businessTable, data.businessId, this.inputForm)
+                                this.$refs.inputForm.resetFields()
+                                this.loading = false
+                            }).catch(() => {
+                                this.$refs.inputForm.resetFields()
+                            }).catch((e) => {
+
+                            })
+                        })
+                    }
+                });
+            },
+            // 通过
+            async agreeForm (callback) {
+                console.log('this.inputForm', this.inputForm)
+                this.$refs.inputForm.validate().then(res => {
+                    if (this.inputForm.days >1) {
+                        this.commonApi.getTaskNameByProcInsId(this.inputForm.procInsId).then((data) => {
+                            if (this.isNotEmpty(data)) {
+                                if (data === '办公室主任审批') {
+                                    this.inputForm.type = '5'
+                                } else {
+                                    this.inputForm.type = '2'
+                                }
+                            }
+                            departRegistrationService.save(this.inputForm).then((data) => {
+                                callback(data.businessTable, data.businessId, this.inputForm)
+                                this.$refs.inputForm.resetFields()
+                                this.loading = false
+                            }).catch(() => {
+                                this.loading = false
+                                this.$refs.inputForm.resetFields()
+                            })
+                        })
+                    } else {
+                        this.inputForm.type = '5'
+                        departRegistrationService.save(this.inputForm).then((data) => {
+                            callback(data.businessTable, data.businessId, this.inputForm)
+                            this.$refs.inputForm.resetFields()
+                            this.loading = false
+                        }).catch(() => {
+                            this.loading = false
+                            this.$refs.inputForm.resetFields()
+                        })
+                    }
+                })
+            },
+            // 自定义验证函数
+            validateDepartureDate() {
+                if (this.isNotEmpty(this.inputForm.arrivalDate)){
+                    if (this.inputForm.departResignationDate <= this.inputForm.arrivalDate) {
+                        this.inputForm.departResignationDate = ''
+                        uni.showToast({
+                            title: '离职日期必须晚于到岗日期',
+                            icon: "none",
+                            duration:2000
+                        })
+                    }
+                }
+
+            },
+            validateDepartureDate2() {
+                if (this.isNotEmpty(this.inputForm.departResignationDate)) {
+                    if (this.inputForm.arrivalDate >= this.inputForm.departResignationDate) {
+                        this.inputForm.arrivalDate = ''
+                        uni.showToast({
+                            title: '到岗日期必须早于离职日期',
+                            icon: "none",
+                            duration:2000
+                        })
+                    }
+                }
+
+            },
+        }
+    }
+</script>
+
+<style>
+    .cu-form-group .title {
+        min-width: calc(4em + 40px);
+    }
+</style>

+ 211 - 12
pages/login/login.vue

@@ -1,13 +1,13 @@
 <template>
 	<view class="content">
-		<view id="box">
+		<view id="box" v-if="whichPage === '1'">
 
 			<view id="top" class="">
 				<view class="top_le"></view>
 				<view class="top_ri"></view>
 			</view>
 			<view class="title">
-				<view>欢迎登录JeePlus</view>
+				<view>兴光业务管理系统平台</view>
 			</view>
 			<view class="login-form">
 				<u--form :model="inputForm" labelWidth="100px"  labelPosition="left" :rules="rules" ref="uForm">
@@ -17,7 +17,7 @@
 						<u-form-item label="密码" borderBottom prop="password">
 							<u-input border="none" password v-model="inputForm.password" />
 						</u-form-item>
-						<u-form-item label="验证码" borderBottom prop="code">
+						<u-form-item label="验证码" borderBottom prop="code" v-if="passwordErrorCount >= 5">
 							<u-input border="none" v-model="inputForm.code" />
 							<u--image :showLoading="true" :src="captchaImg" width="140px" height="40px" @click="getCaptcha"></u--image>
 						</u-form-item>
@@ -27,11 +27,48 @@
 				<u-button type="primary" shape="circle" color="linear-gradient(90deg, #1989FA, #19C2FA)" @click="bindLogin" text="欢迎登录"></u-button>
 			</view>
 			<view class="fot">
-				<text @tap="reg_ok">免费注册</text>
-				<text style="display: inline-block;width: 10vw;"></text>
-				<text @tap="forget_ok">忘记密码</text>
+				<text @tap="openForgetPassword" style="color: #1989FA;">忘记密码</text>
 			</view>
 	</view>
+		<view id="box" v-else-if="whichPage === '2'">
+
+			<view id="top" class="">
+				<view class="top_le"></view>
+				<view class="top_ri"></view>
+			</view>
+			<view class="title">
+				<view>修改密码</view>
+				<view>使用账号绑定的手机号找回密码</view>
+			</view>
+			<view class="login-form">
+				<u--form :model="inputForm" labelWidth="100px"  labelPosition="left" :rules="rules" ref="uForm">
+					<u-form-item label="绑定手机号" borderBottom prop="phoneNumber">
+						<u-input border="none" v-model="inputForm.phoneNumber" placeholder='请输入绑定手机号'/>
+					</u-form-item>
+					<u-form-item label="验证码" borderBottom prop="phoneCode">
+						<u-input border="none" v-model="inputForm.phoneCode" placeholder="请输入验证码"></u-input>
+						<u-button type="primary" @click="pushPhoneCode" :loading="!showPhoneCode" style="background-color: #3595f9; width: 100px;">
+							<span v-if="showPhoneCode" style="color: white;">获取验证码</span>
+							<span v-else class="count" style="color: white;">请等待 {{count}} s</span>
+						</u-button>
+					</u-form-item>
+					<u-form-item label="新密码" borderBottom prop="newPassword" >
+						<u-input border="none" v-model="inputForm.newPassword" placeholder='请输入新密码'/>
+					</u-form-item>
+					<u-form-item label="确认密码" borderBottom prop="newPasswordAgain" >
+						<u-input border="none" v-model="inputForm.newPasswordAgain" placeholder='请输入确认密码'/>
+					</u-form-item>
+				</u--form>
+			</view>
+			<view class="but">
+				<u-button type="primary" shape="circle" color="linear-gradient(90deg, #1989FA, #19C2FA)" @click="saveNewPass" text="保存"></u-button>
+			</view>
+			<view class="fot">
+				<!--				<text @tap="reg_ok">免费注册</text>-->
+				<!--				<text style="display: inline-block;width: 10vw;"></text>-->
+				<text @tap="backLogin" style="color: #1989FA;">前往登录页面</text>
+			</view>
+		</view>
 	</view>
 </template>
 
@@ -39,17 +76,24 @@
 	import * as $auth from "@/common/auth.js"
 	import loginService from "@/api/auth/loginService"
 	import {mapActions} from 'vuex'
-
+	var  graceChecker = require("@/common/graceChecker.js");
 	export default {
 		data() {
 			return {
+				showPhoneCode: true,
 				captchaImg: '',
 				inputForm: {
 					'username': '',
 					'password': '',
 					'code': '',
-					'uuid': ''
+					'uuid': '',
+					'phoneNumber': '',
+					'phoneCode': '',
+					'newPassword': '',
+					'newPasswordAgain': '',
 				},
+				passwordErrorCount: 0,
+				whichPage: '1', // 1为登录页面,2为忘记密码页面
 				rules: {
 					username: [
 						{
@@ -71,7 +115,35 @@
 							message: '请输入验证码',
 							trigger: ['blur', 'change']
 						}
-					]
+					],
+					phoneNumber: [
+						{
+							required: true,
+							message: '请输入绑定手机号',
+							trigger: ['blur', 'change']
+						}
+					],
+					phoneCode: [
+						{
+							required: true,
+							message: '请输入验证码',
+							trigger: ['blur', 'change']
+						}
+					],
+					newPassword: [
+						{
+							required: true,
+							message: '请输入新密码',
+							trigger: ['blur', 'change']
+						}
+					],
+					newPasswordAgain: [
+						{
+							required: true,
+							message: '请输入确认密码',
+							trigger: ['blur', 'change']
+						}
+					],
 				}
 			}
 		},
@@ -95,8 +167,15 @@
 				  // });
 					this.$router.push('/pages/index/index');
 				}).catch(e => {
-				  this.getCaptcha()
-				  console.error(e)
+					// 密码错误次数增加
+					this.passwordErrorCount++;
+					// 如果密码错误次数超过5次,显示验证码
+					if (this.passwordErrorCount >= 5) {
+						this.inputForm.code = ''; // 清空验证码输入框
+						this.getCaptcha(); // 获取验证码
+					}
+					this.getCaptcha()
+					console.error(e)
 				})
 			})
 		  },
@@ -106,7 +185,127 @@
 					this.captchaImg = 'data:image/gif;base64,' + data.codeImg
 					this.inputForm.uuid = data.uuid
 			   })
-		  }
+		  },
+			openForgetPassword () {
+				console.log('进来了')
+				this.inputForm.username = ''
+				this.inputForm.password = ''
+				this.inputForm.code = ''
+				this.$nextTick(() => {
+					this.whichPage = '2' // 打开忘记密码页面
+				})
+			},
+			backLogin () {
+				this.inputForm.phoneNumber = ''
+				this.inputForm.phoneCode = ''
+				this.inputForm.newPassword = ''
+				this.inputForm.newPasswordAgain = ''
+				this.whichPage = '1' // 打开登录页面
+			},
+			pushPhoneCode () {
+				// 验证手机号码格式是否正确
+				console.log('this.inputForm.phoneNumber', this.inputForm.phoneNumber)
+				console.log('this.checkMobile(this.inputForm.phoneNumber)', this.checkMobile(this.inputForm.phoneNumber))
+				if (this.isNotEmpty(this.inputForm.phoneNumber) && this.checkMobile(this.inputForm.phoneNumber)) {
+					// 向手机号发送验证码
+					loginService.getPhoneCode(this.inputForm.phoneNumber).then((data) => {
+						if (data.success) {
+							uni.showToast({ title: data.message, icon: "success" });
+							// ‘发送验证码’按钮倒计时
+							const TIME_COUNT = 60 // 更改倒计时时间
+							if (!this.timer) {
+								this.count = TIME_COUNT
+								this.showPhoneCode = false
+								this.timer = setInterval(() => {
+									if (this.count > 0 && this.count <= TIME_COUNT) {
+										this.count--
+									} else {
+										this.showPhoneCode = true
+										clearInterval(this.timer) // 清除定时器
+										this.timer = null
+									}
+								}, 1000)
+							}
+						} else {
+							this.$message.error(data.message)
+						}
+					})
+				} else {
+					uni.showToast({
+						title: '请填写正确的手机号',
+						icon: "none",
+						duration:2000
+					})
+				}
+			},
+			checkMobile (str) {
+				const phone = /(^(\d{3,4}-)?\d{6,8}$)|(^(\d{3,4}-)?\d{6,8}(-\d{1,5})?$)|(^(((13[0-9]{1})|(15[0-9]{1})|(16[0-9]{1})|(18[0-9]{1})|(17[0-9]{1})|(19[0-9]{1}))+\d{8})$)/
+				if (str && !phone.test(str)) {
+					uni.showToast({
+						title: '绑定手机号填写不正确,请重新填写',
+						icon: "none",
+						duration:2000
+					})
+					this.inputForm.phoneNumber = ''
+					return false;
+				} else {
+					return true;
+				}
+			},
+			isEmpty(value) {
+				let result = false;
+				if (value == null || value == undefined) {
+					result = true;
+				}
+				if (typeof value == 'string' && (value.replace(/\s+/g, "") == "" || value == "")) {
+					result = true;
+				}
+				if (typeof value == "object" && value instanceof Array && value.length === 0) {
+					result = true;
+				}
+				return result;
+			},
+			isNotEmpty (value) {
+				return !this.isEmpty(value)
+			},
+			saveNewPass () {
+
+				return new Promise((resolve, reject) => {
+
+					let errors = [];
+
+					if (this.inputForm.newPassword !== this.inputForm.newPasswordAgain) {
+						errors.push('两次输入的密码不相同,请重新输入!');
+					}
+
+					if (errors.length > 0) {
+						// 存在错误,显示提示信息
+						errors.forEach(error => {
+							uni.showToast({
+								title: error,
+								icon: 'none',
+								duration: 1500
+							});
+						});
+						reject('Form validation failed');
+					} else {
+						loginService.savePwd(this.inputForm).then((data) => {
+							if (data.success) {
+								this.$message.success(data.message)
+								this.inputForm.username = this.inputForm.phoneNumber
+								this.inputForm.newPassword = this.inputForm.newPassword
+								this.backLogin() // 修改密码成功后返回登录页面
+								this.loading = false
+							} else {
+								this.$message.error(data.message)
+								this.loading = false
+							}
+						}).catch(() => {
+							this.loading = false
+						})
+					}
+				});
+			},
 		}
 	}
 </script>

+ 137 - 21
pages/materialManagement/collect/CollectForm.vue

@@ -31,9 +31,9 @@
 
             <el-row  :gutter="15" :key="index_experience" v-for="(item,index_experience) in this.inputForm.detailInfos">
                 <el-col :span="24">
-                    <el-form-item label="" >
+                    <u-form-item label="" >
                         <el-divider content-position="left"> 领用详情 {{index_experience + 1}}</el-divider>
-                    </el-form-item>
+                    </u-form-item>
                 </el-col>
 
                 <el-col :span="24">
@@ -80,13 +80,17 @@
                     <u-form-item label="文件上传">
                         <el-upload
                                 class="upload-demo"
-                                :action="`http://localhost:2800/api/public-modules-server/oss/file/webUpload/upload`"
+                                :action="`http://we4k7g.natappfree.cc/api/public-modules-server/oss/file/webUpload/upload`"
                                 :on-remove="(file, fileList) => handleRemove(file, fileList, index_experience,'detail')"
-                                :file-list="fileList3[index_experience]"
+                                :file-list="inputForm.detailInfos[index_experience].fileInfoLost"
                                 :on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList,index_experience,'detail')"
                                 :limit="3">
                             <el-button size="small" type="primary">点击上传</el-button>
                             <div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
+                            <template slot="file" slot-scope="{ file }" v-if="shouldShowFile(file,index_experience,'detail') || testFlag">
+                                <span @click="handleFileClick(file)">{{ file.name }}</span>
+                                <el-button type="text" icon="el-icon-close" @click="handleDelete(file,index_experience,'detail')">✕</el-button>
+                            </template>
                         </el-upload>
                     </u-form-item>
                 </el-col>
@@ -104,13 +108,17 @@
             <u-form-item label="附件">
                 <el-upload
                         class="upload-demo"
-                        :action="`http://localhost:2800/api/public-modules-server/oss/file/webUpload/upload`"
+                        :action="`http://5hrd5v.natappfree.cc/api/public-modules-server/oss/file/webUpload/upload`"
                         :on-remove="(file, fileList) => handleRemove(file, fileList, '','')"
                         :file-list="inputForm.files"
                         :on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList,'','')"
                         :limit="3">
                     <el-button size="small" type="primary">点击上传</el-button>
                     <div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
+                    <template slot="file" slot-scope="{ file }" v-if="shouldShowFile(file) || testFlag">
+                        <span @click="handleFileClick(file)">{{ file.name }}</span>
+                        <el-button type="text" icon="el-icon-close" @click="handleDelete(file)">✕</el-button>
+                    </template>
                 </el-upload>
             </u-form-item>
         </u--form>
@@ -143,9 +151,9 @@
 
             <el-row  :gutter="15" :key="index_experience" v-for="(item,index_experience) in this.inputForm.detailInfos" >
                 <el-col :span="24">
-                    <el-form-item label="" >
+                    <u-form-item label="" >
                         <el-divider content-position="left"> 领用详情 {{index_experience + 1}}</el-divider>
-                    </el-form-item>
+                    </u-form-item>
                 </el-col>
 
                 <el-col :span="24">
@@ -192,13 +200,17 @@
                     <u-form-item label="文件上传">
                         <el-upload
                                 class="upload-demo"
-                                :action="`http://localhost:2800/api/public-modules-server/oss/file/webUpload/upload`"
+                                :action="`http://we4k7g.natappfree.cc/api/public-modules-server/oss/file/webUpload/upload`"
                                 :on-remove="(file, fileList) => handleRemove(file, fileList, index_experience,'detail')"
-                                :file-list="fileList3[index_experience]"
+                                :file-list="inputForm.detailInfos[index_experience].fileInfoLost"
                                 :on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList,index_experience,'detail')"
                                 :limit="3">
                             <el-button size="small" :disabled="true" type="primary">点击上传</el-button>
                             <div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
+                            <template slot="file" slot-scope="{ file }" v-if="shouldShowFile(file,index_experience,'detail') || testFlag">
+                                <span @click="handleFileClick(file)">{{ file.name }}</span>
+                                <el-button type="text" icon="el-icon-close" @click="handleDelete(file,index_experience,'detail')">✕</el-button>
+                            </template>
                         </el-upload>
                     </u-form-item>
                 </el-col>
@@ -215,14 +227,19 @@
 
             <u-form-item label="附件">
                 <el-upload
+                        style="width: 20%;"
                         class="upload-demo"
-                        :action="`http://localhost:2800/api/public-modules-server/oss/file/webUpload/upload`"
+                        :action="`http://we4k7g.natappfree.cc/api/public-modules-server/oss/file/webUpload/upload`"
                         :on-remove="(file, fileList) => handleRemove(file, fileList, '','')"
                         :file-list="inputForm.files"
                         :on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList,'','')"
                         :limit="3">
                     <el-button size="small" :disabled="true" type="primary">点击上传</el-button>
                     <div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
+                    <template slot="file" slot-scope="{ file }" v-if="shouldShowFile(file) || testFlag">
+                        <span @click="handleFileClick(file)">{{ file.name }}</span>
+                        <el-button type="text" icon="el-icon-close" @click="handleDelete(file)">✕</el-button>
+                    </template>
                 </el-upload>
             </u-form-item>
         </u--form>
@@ -234,6 +251,7 @@
 </template>
 
 <script>
+    import OSSService from "@/api/sys/OSSService"
     import goodsInfoPicker from './GoodsInfoPicker'
     import MaterialTypeService from '@/api/materialManagement/MaterialTypeService'
     import WareHouseService from '@/api/materialManagement/WareHouseService'
@@ -253,6 +271,9 @@
         }),
         data () {
             return {
+                showFileList: [], // 控制每个文件是否显示的数组
+                showFileList2: [], // 控制每个文件是否显示的数组
+                testFlag: false,
                 nodeFlag: false,
                 loading: false,
                 listData: [],
@@ -284,11 +305,13 @@
                 }
             }
         },
+        ossService: null,
         materialTypeService: null,
         wareHouseService: null,
         commonApi: null,
         // 页面加载时执行
         created() {
+            this.ossService = new OSSService()
             this.commonApi = new CommonApi()
             this.materialTypeService = new MaterialTypeService()
             this.wareHouseService = new WareHouseService()
@@ -348,17 +371,25 @@
             },
             showGoods(index) {
 
-                this.searchForm.wareHouseType = this.inputForm.detailInfos[index].collectTypeId
-                this.wareHouseService.wareHouseSummaryList({
-                    'current': 0,
-                    'size': -1,
-                    'orders': [],
-                    ...this.searchForm
-                }).then((data) => {
-                    this.goodsListData = data.records
-                })
+                if (this.isEmpty(this.inputForm.detailInfos[index].collectTypeId)) {
+                    uni.showToast({
+                        title: '请先选择领用类型',
+                        icon: 'none',
+                        duration: 2000
+                    });
+                } else {
+                    this.searchForm.wareHouseType = this.inputForm.detailInfos[index].collectTypeId
+                    this.wareHouseService.wareHouseSummaryList({
+                        'current': 0,
+                        'size': -1,
+                        'orders': [],
+                        ...this.searchForm
+                    }).then((data) => {
+                        this.goodsListData = data.records
+                    })
 
-                this.$refs.goodsPicker._show(index);
+                    this.$refs.goodsPicker._show(index);
+                }
             },
             //监听选择
             selectChange(ids, names, index) {
@@ -407,11 +438,18 @@
                         this.inputForm = this.recover(this.inputForm, data)
                         this.inputForm.collectDate = new Date(data.collectDate);
 
+                        if (this.inputForm.files) {
+                            this.inputForm.files.forEach( (item,index) => {
+                                this.$set(this.showFileList, index, true);
+                            })
+                        }
+
                         this.inputForm.detailInfos.forEach( (item,index) => {
                             if (this.isNotEmpty(item.fileInfoLost)) {
                                 this.fileList3[index] = []
                                 item.fileInfoLost.forEach( (item,index2) => {
                                     this.fileList3[index].push(item)
+                                    this.$set(this.showFileList2, index2, true);
                                 })
 
                             }
@@ -510,13 +548,15 @@
                 });
             },
             handleUploadSuccess (res, file, fileList, index, type) {
+                console.log('fileListSuccess', fileList)
 
                 // 将 fileList 转换为你期望的格式
                 const formattedFiles = fileList.map(fileItem => {
                     return {
                         name: fileItem.name,
                         size: fileItem.size,
-                        url: '/' + fileItem.response.url,
+                        url: fileItem.response ? '/' + fileItem.response.url : fileItem.url,
+                        lsUrl: fileItem.response ? fileItem.response.lsUrl : fileItem.lsUrl, // 如果没有 lsUrl,可以根据需要设置为空字符串或其他默认值
                         createBy: this.userInfo,
                         by: this.userInfo.id,
                         createTime: this.formatDateNew(new Date())
@@ -525,14 +565,25 @@
                 if (type === 'detail') {
                     // 将格式化后的数据设置到 detailInfos 的 fileInfoLost 属性中
                     this.inputForm.detailInfos[index].fileInfoLost = formattedFiles;
+                    fileList.forEach((item, i) => {
+                        if (item === file) {
+                            this.$set(this.showFileList2, i, true);
+                        }
+                    });
                 } else {
                     this.inputForm.files = formattedFiles
+                    fileList.forEach((item, index) => {
+                        if (item === file) {
+                            this.$set(this.showFileList, index, true);
+                        }
+                    });
                 }
 
                 // 强制更新视图
                 this.$forceUpdate();
             },
             handleRemove(file, fileList, index, type) {
+                console.log('fileList', fileList)
                 // 处理移除文件逻辑
                 // file 是移除的文件
                 // fileList 是当前文件列表
@@ -712,6 +763,66 @@
                     })
                 })
             },
+            shouldShowFile(file,index,type) {
+                if (type === 'detail') {
+                    if (this.inputForm.detailInfos[index].fileInfoLost && this.inputForm.detailInfos[index].fileInfoLost.length > 0) {
+                        // 返回一个布尔值,确定是否显示上传成功后的文件
+
+                        return this.showFileList2[this.inputForm.detailInfos[index].fileInfoLost.indexOf(file)];
+                    }
+
+                }else {
+                    if (this.inputForm.files && this.inputForm.files.length > 0) {
+                        // 返回一个布尔值,确定是否显示上传成功后的文件
+                        return this.showFileList[this.inputForm.files.indexOf(file)];
+                    }
+                }
+                return false; // 默认返回 false 或者其他适当的
+            },
+            async handleFileClick(file) {
+                await this.ossService.getTemporaryUrl(file.url).then((data) => {
+                    file.lsUrl = data
+                })
+                console.log('file', file)
+                if (this.isImage(file.name)) {
+                    // 如果是图片文件,则执行放大显示图片的逻辑
+                    this.handleImageClick(file);
+                } else {
+                    // window.open(file.lsUrl, '_blank')
+                    window.location.href = file.lsUrl
+                    // 如果不是图片文件,则执行其他操作,比如下载文件等
+                }
+            },
+            handleImageClick(file) {
+                // 在点击图片时执行放大显示的逻辑
+                this.$alert(`<img src="${file.lsUrl}" style="max-width: 100%; max-height: 100%;" />`, '图片详情', {
+                    dangerouslyUseHTMLString: true,
+                    customClass: 'custom-alert'
+                });
+            },
+            // 判断文件是否是图片类型
+            isImage(fileName) {
+                const ext = fileName.toLowerCase().split('.').pop(); // 获取文件的后缀名
+                return ['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(ext); // 判断后缀名是否是图片类型
+            },
+            handleDelete(file,lineIndex,type) {
+                // 处理删除文件的逻辑
+                if (type === 'detail') {
+                    const index = this.inputForm.detailInfos[lineIndex].fileInfoLost.indexOf(file);
+                    if (index !== -1) {
+                        this.inputForm.detailInfos[lineIndex].fileInfoLost.splice(index, 1);
+                        this.showFileList2.splice(index, 1); // 从showFileList中移除对应的元素
+                    }
+                } else {
+                    // 从文件列表中移除文件
+                    const index = this.inputForm.files.indexOf(file);
+                    if (index !== -1) {
+                        this.inputForm.files.splice(index, 1);
+                        this.showFileList.splice(index, 1); // 从showFileList中移除对应的元素
+                    }
+                }
+
+            },
         }
     }
 </script>
@@ -720,4 +831,9 @@
     .cu-form-group .title {
         min-width: calc(4em + 40px);
     }
+
+    /* 样式示例,您可能需要根据实际情况调整 */
+    .upload-demo {
+        width: 40%;
+    }
 </style>

+ 104 - 0
pages/materialManagement/purchase/MyDropdown.vue

@@ -0,0 +1,104 @@
+<template>
+    <u-form-item label="商品名称" :prop="'detailInfos[' + index_experience + '].tradeName'" :required="true">
+        <el-autocomplete
+                style="width: 100%;"
+                v-model="inputForm.detailInfos[index_experience].tradeName"
+                placeholder="请选择物品名称"
+                clearable
+                @focus="showDropdown"
+                :fetch-suggestions="fetchSuggestions"
+                @select="handleSelect"
+        >
+            <template slot-scope="{ item }">
+                <span style="width: 100%;">{{ item.tradeName }}</span>
+            </template>
+        </el-autocomplete>
+    </u-form-item>
+</template>
+
+<script>
+    import materialManagementService from '@/api/materialManagement/MaterialManagementService'
+    export default {
+        props: {
+            index_experience: Number,
+            inputForm: Object
+        },
+        data() {
+            return {
+                showDropdownList: false,
+                dropdownList: [],
+                selectedTradeName: ''
+            };
+        },
+        created() {
+        },
+        methods: {
+            showDropdown() {
+                let row = this.inputForm.detailInfos[this.index_experience]
+                row.tradeNameList = []
+                row.tradeNameData = []
+
+                let procurementTypeId = this.inputForm.detailInfos[this.index_experience].procurementTypeId
+
+                if (this.isNotEmpty(procurementTypeId)) {
+                    // Simulated data
+                    materialManagementService.findTradeByTypeId(procurementTypeId)
+                        .then((data) => {
+                            row.tradeNameList = JSON.parse(JSON.stringify(data))
+                            this.dropdownList = JSON.parse(JSON.stringify(data))
+                            this.showDropdownList = true; // Move this line here
+                        })
+                        .catch(() => {
+                            // Handle error
+                        });
+                }
+            },
+            isEmpty(value) {
+                let result = false;
+                if (value == null || value == undefined) {
+                    result = true;
+                }
+                if (typeof value == 'string' && (value.replace(/\s+/g, "") == "" || value == "")) {
+                    result = true;
+                }
+                if (typeof value == "object" && value instanceof Array && value.length === 0) {
+                    result = true;
+                }
+                return result;
+            },
+            isNotEmpty (value) {
+                return !this.isEmpty(value)
+            },
+            fetchSuggestions(queryString, callback) {
+                if (this.dropdownList && queryString) {
+                    const filteredList = this.dropdownList.filter(item =>
+                        item.tradeName.toLowerCase().includes(queryString.toLowerCase())
+                    );
+                    callback(filteredList);
+                } else {
+                    callback(this.dropdownList);
+                    // Handle the case when dropdownList or queryString is not properly initialized
+                }
+            },
+            handleSelect(item) {
+                this.inputForm.detailInfos[this.index_experience].tradeName = item.tradeName;
+                this.showDropdownList = false;
+            }
+        }
+    };
+</script>
+
+<style scoped>
+    .my-dropdown {
+        position: absolute;
+        top: calc(100% + 4px); /* 将下拉框定位在输入框的下方,此处增加了 4px 的间距 */
+        left: 0;
+        width: 100%;
+        background-color: #fff;
+        border: 1px solid #ccc;
+    }
+    .list-item {
+        padding: 8px;
+        cursor: pointer;
+    }
+</style>

+ 961 - 0
pages/materialManagement/purchase/PurchaseForm.vue

@@ -0,0 +1,961 @@
+<template>
+    <view>
+        <cu-custom :backUrl="'/pages/index/index'" :isBack="true" bgColor="bg-gradual-blue" >
+            <block slot="content">采购申请</block>
+        </cu-custom>
+        <u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules" ref="inputForm" v-if="!nodeFlag">
+            <u-form-item label="采购编号" borderBottom prop="purchaseNo">
+                <u--input placeholder='自动生成'  v-model="inputForm.purchaseNo" disabled></u--input>
+            </u-form-item>
+            <u-form-item label="采购名称" borderBottom prop="purchaseSketch" :required="true">
+                <u--input placeholder='请填写采购名称'  v-model="inputForm.purchaseSketch" ></u--input>
+            </u-form-item>
+            <u-form-item label="经办人" borderBottom prop="handledBy">
+                <u--input placeholder=''  v-model="inputForm.handledBy" disabled></u--input>
+            </u-form-item>
+            <u-form-item label="经办人部门" borderBottom prop="handledByOfficeName">
+                <u--input placeholder=''  v-model="inputForm.handledByOfficeName" disabled></u--input>
+            </u-form-item>
+            <u-form-item label="采购申请时间" borderBottom prop="purchaseDate" :required="true">
+                <el-date-picker
+                        v-model="inputForm.purchaseDate"
+                        type="date"
+                        placeholder="请选择采购申请时间"
+                        style="width:100%"
+                        size="default"
+                        placement="bottom-start"
+                        clearable>
+                </el-date-picker>
+            </u-form-item>
+            <u-form-item label="采购方式" borderBottom prop="purchaseMode" :required="true">
+                <jp-picker placeholder='请选择采购方式' v-model="inputForm.purchaseMode" rangeKey="label" rangeValue="value" :range="[
+						        { label: '办公室采购', value: '1' },
+						        { label: '自行采购', value: '2' },
+						    ]"></jp-picker>
+            </u-form-item>
+            <u-form-item label="备注" borderBottom prop="remarks">
+                <u--textarea  placeholder='请填写备注信息' :rows="5" :maxlength="500" v-model="inputForm.remarks" ></u--textarea>
+            </u-form-item>
+
+
+            <el-row  :gutter="15" :key="index_experience" v-for="(item,index_experience) in this.inputForm.detailInfos">
+                <el-col :span="24">
+                    <u-form-item label="" >
+                        <el-divider content-position="left"> 采购详情 {{index_experience + 1}}</el-divider>
+                    </u-form-item>
+                </el-col>
+
+                <el-col :span="24">
+                    <u-form-item label="采购人" :prop="'detailInfos[' + index_experience + '].purchaserAgent'" :required="true"
+                                 :rules="[
+				     ]">
+                        <el-input v-model="inputForm.detailInfos[index_experience].purchaserAgent" placeholder="请选择采购人" @focus="openUserPullForm(index_experience)" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="采购人部门" :prop="'detailInfos[' + index_experience + '].procurementOffice'" :required="true"
+                                 :rules="[
+				     ]">
+                        <el-input v-model="inputForm.detailInfos[index_experience].procurementOffice" placeholder="" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="采购类型" :prop="'detailInfos[' + index_experience + '].procurementType'" :required="true"
+                                 :rules="[
+				     ]">
+                        <el-input v-model="inputForm.detailInfos[index_experience].procurementType" placeholder="请选择采购类型" @focus="showPicker(index_experience)" clearable></el-input>
+                    </u-form-item>
+                    <my-dropdown :index_experience="index_experience" :inputForm="inputForm"></my-dropdown>
+                    <!--<u-form-item label="商品名称" :prop="'detailInfos[' + index_experience + '].tradeName'"
+                                 :rules="[
+				     ]">
+                        <el-input v-model="inputForm.detailInfos[index_experience].tradeName" placeholder="请选择物品名称" clearable></el-input>
+                    </u-form-item>-->
+
+                    <supplier-selector :index_experience="index_experience" :inputForm="inputForm"></supplier-selector>
+<!--                    <u-form-item label="供应商" :prop="'detailInfos[' + index_experience + '].supplierName'" -->
+<!--                                 :rules="[-->
+<!--				     ]">-->
+<!--                        <el-input v-model="inputForm.detailInfos[index_experience].supplierName" placeholder="请选择供应商" @focus="showGoods(index_experience)" clearable></el-input>-->
+<!--                    </u-form-item>-->
+                    <u-form-item label="商品单价(元)" :prop="'detailInfos[' + index_experience + '].tradePrice'"
+                                 :rules="[
+				     ]">
+                        <el-input @input="changeValue" v-model="inputForm.detailInfos[index_experience].tradePrice" placeholder="请输入商品单价(元)" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="商品数量" :prop="'detailInfos[' + index_experience + '].tradeNumber'"
+                                 :rules="[
+				     ]">
+                        <el-input @input="changeValue" v-model="inputForm.detailInfos[index_experience].tradeNumber" placeholder="请输入商品数量" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="商品总价" :prop="'detailInfos[' + index_experience + '].priceSum'"
+                                 :rules="[
+				     ]">
+                        <el-input v-model="inputForm.detailInfos[index_experience].priceSum" placeholder="请输入商品总价" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="单位" :prop="'detailInfos[' + index_experience + '].company'"
+                                 :rules="[
+				     ]">
+                        <el-input v-model="inputForm.detailInfos[index_experience].company"  placeholder="请输入单位" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="备注" :prop="'detailInfos[' + index_experience + '].remarks'"
+                                 :rules="[
+				     ]">
+                        <el-input v-model="inputForm.detailInfos[index_experience].remarks"  placeholder="请输入备注" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="文件上传">
+                        <el-upload
+                                class="upload-demo"
+                                :action="`http://pv4uct.natappfree.cc/api/public-modules-server/oss/file/webUpload/upload`"
+                                :on-remove="(file, fileList) => handleRemove(file, fileList, index_experience,'detail')"
+                                :file-list="inputForm.detailInfos[index_experience].fileInfoLost"
+                                :on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList,index_experience,'detail')"
+                                :limit="3">
+                            <el-button size="small" type="primary">点击上传</el-button>
+                            <div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
+                            <template slot="file" slot-scope="{ file }" v-if="shouldShowFile(file,index_experience,'detail') || testFlag">
+                                <span @click="handleFileClick(file)">{{ file.name }}</span>
+                                <el-button type="text" icon="el-icon-close" @click="handleDelete(file,index_experience,'detail')">✕</el-button>
+                            </template>
+                        </el-upload>
+                    </u-form-item>
+                </el-col>
+
+                <el-col :span="24" style="text-align: center">
+                    <u-form-item label="" >
+                        <el-button style="width: 100%" type="danger" @click="removeRow(index_experience)" plain>删除采购详情 {{index_experience + 1}}</el-button>
+                    </u-form-item>
+                </el-col>
+            </el-row>
+            <u-form-item label="" >
+                <el-button style="width: 100%" type="primary" @click="addRow()" plain>新增采购详情</el-button>
+            </u-form-item>
+
+            <u-form-item label="附件">
+                <el-upload
+                        class="upload-demo"
+                        :action="`http://pv4uct.natappfree.cc/api/public-modules-server/oss/file/webUpload/upload`"
+                        :on-remove="(file, fileList) => handleRemove(file, fileList, '','')"
+                        :file-list="inputForm.files"
+                        :on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList,'','')"
+                        :limit="3">
+                    <el-button size="small" type="primary">点击上传</el-button>
+                    <div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
+                    <template slot="file" slot-scope="{ file }" v-if="shouldShowFile(file) || testFlag">
+                        <span @click="handleFileClick(file)">{{ file.name }}</span>
+                        <el-button type="text" icon="el-icon-close" @click="handleDelete(file)">✕</el-button>
+                    </template>
+                </el-upload>
+
+            </u-form-item>
+        </u--form>
+        <u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules" ref="inputForm" v-else-if="nodeFlag">
+            <u-form-item label="采购编号" borderBottom prop="purchaseNo">
+                <u--input placeholder='自动生成'  v-model="inputForm.purchaseNo" disabled></u--input>
+            </u-form-item>
+            <u-form-item label="采购名称" borderBottom prop="purchaseSketch" :required="true">
+                <u--input placeholder='请填写采购名称'  v-model="inputForm.purchaseSketch" ></u--input>
+            </u-form-item>
+            <u-form-item label="经办人" borderBottom prop="handledBy">
+                <u--input placeholder=''  v-model="inputForm.handledBy" disabled></u--input>
+            </u-form-item>
+            <u-form-item label="经办人部门" borderBottom prop="handledByOfficeName">
+                <u--input placeholder=''  v-model="inputForm.handledByOfficeName" disabled></u--input>
+            </u-form-item>
+            <u-form-item label="采购申请时间" borderBottom prop="purchaseDate" :required="true">
+                <el-date-picker
+                        v-model="inputForm.purchaseDate"
+                        type="date"
+                        placeholder="请选择采购申请时间"
+                        style="width:100%"
+                        size="default"
+                        placement="bottom-start"
+                        clearable>
+                </el-date-picker>
+            </u-form-item>
+            <u-form-item label="采购方式" borderBottom prop="purchaseMode" :required="true">
+                <jp-picker placeholder='请选择采购方式' v-model="inputForm.purchaseMode" rangeKey="label" rangeValue="value" :range="[
+						        { label: '办公室采购', value: '1' },
+						        { label: '自行采购', value: '2' },
+						    ]"></jp-picker>
+            </u-form-item>
+            <u-form-item label="备注" borderBottom prop="remarks">
+                <u--textarea  placeholder='请填写备注信息' :rows="5" :maxlength="500" v-model="inputForm.remarks" ></u--textarea>
+            </u-form-item>
+
+
+            <el-row  :gutter="15" :key="index_experience" v-for="(item,index_experience) in this.inputForm.detailInfos">
+                <el-col :span="24">
+                    <u-form-item label="" >
+                        <el-divider content-position="left"> 采购详情 {{index_experience + 1}}</el-divider>
+                    </u-form-item>
+                </el-col>
+
+                <el-col :span="24">
+                    <u-form-item label="采购人" :prop="'detailInfos[' + index_experience + '].purchaserAgent'" :required="true"
+                                 :rules="[
+				     ]">
+                        <el-input v-model="inputForm.detailInfos[index_experience].purchaserAgent" placeholder="请选择采购人" @focus="openUserPullForm(index_experience)" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="采购人部门" :prop="'detailInfos[' + index_experience + '].procurementOffice'" :required="true"
+                                 :rules="[
+				     ]">
+                        <el-input v-model="inputForm.detailInfos[index_experience].procurementOffice" placeholder="" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="采购类型" :prop="'detailInfos[' + index_experience + '].procurementType'" :required="true"
+                                 :rules="[
+				     ]">
+                        <el-input v-model="inputForm.detailInfos[index_experience].procurementType" placeholder="请选择采购类型" @focus="showPicker(index_experience)" clearable></el-input>
+                    </u-form-item>
+                    <my-dropdown :index_experience="index_experience" :inputForm="inputForm"></my-dropdown>
+<!--                    <u-form-item label="商品名称" :prop="'detailInfos[' + index_experience + '].tradeName'" -->
+<!--                                 :rules="[-->
+<!--				     ]">-->
+<!--                        <el-input v-model="inputForm.detailInfos[index_experience].tradeName" placeholder="请选择物品名称" @focus="showGoods(index_experience)" clearable></el-input>-->
+<!--                    </u-form-item>-->
+                    <supplier-selector :index_experience="index_experience" :inputForm="inputForm"></supplier-selector>
+<!--                    <u-form-item label="供应商" :prop="'detailInfos[' + index_experience + '].supplierName'" -->
+<!--                                 :rules="[-->
+<!--				     ]">-->
+<!--                        <el-input v-model="inputForm.detailInfos[index_experience].supplierName" placeholder="请选择供应商" @focus="showGoods(index_experience)" clearable></el-input>-->
+<!--                    </u-form-item>-->
+                    <u-form-item label="商品单价(元)" :prop="'detailInfos[' + index_experience + '].tradePrice'"
+                                 :rules="[
+				     ]">
+                        <el-input @change="changeValue" v-model="inputForm.detailInfos[index_experience].tradePrice" placeholder="请输入商品单价(元)" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="商品数量" :prop="'detailInfos[' + index_experience + '].tradeNumber'"
+                                 :rules="[
+				     ]">
+                        <el-input @change="changeValue" v-model="inputForm.detailInfos[index_experience].tradeNumber" placeholder="请输入商品数量" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="商品总价" :prop="'detailInfos[' + index_experience + '].priceSum'"
+                                 :rules="[
+				     ]">
+                        <el-input v-model="inputForm.detailInfos[index_experience].priceSum" placeholder="请输入商品总价" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="单位" :prop="'detailInfos[' + index_experience + '].company'"
+                                 :rules="[
+				     ]">
+                        <el-input v-model="inputForm.detailInfos[index_experience].company"  placeholder="请输入单位" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="备注" :prop="'detailInfos[' + index_experience + '].remarks'"
+                                 :rules="[
+				     ]">
+                        <el-input v-model="inputForm.detailInfos[index_experience].remarks"  placeholder="请输入备注" clearable></el-input>
+                    </u-form-item>
+                    <u-form-item label="文件上传">
+                        <el-upload
+                                class="upload-demo"
+                                :action="`http://pv4uct.natappfree.cc/api/public-modules-server/oss/file/webUpload/upload`"
+                                :on-remove="(file, fileList) => handleRemove(file, fileList, index_experience,'detail')"
+                                :file-list="inputForm.detailInfos[index_experience].fileInfoLost"
+                                :on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList,index_experience,'detail')"
+                                :limit="3">
+                            <el-button size="small" type="primary">点击上传</el-button>
+                            <div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
+                            <template slot="file" slot-scope="{ file }" v-if="shouldShowFile(file,index_experience,'detail') || testFlag">
+                                <span @click="handleFileClick(file)">{{ file.name }}</span>
+                                <el-button type="text" icon="el-icon-close" @click="handleDelete(file,index_experience,'detail')">✕</el-button>
+                            </template>
+                        </el-upload>
+                    </u-form-item>
+                </el-col>
+
+                <el-col :span="24" style="text-align: center">
+                    <u-form-item label="" >
+                        <el-button style="width: 100%" type="danger" @click="removeRow(index_experience)" plain>删除采购详情 {{index_experience + 1}}</el-button>
+                    </u-form-item>
+                </el-col>
+            </el-row>
+            <u-form-item label="" >
+                <el-button style="width: 100%" type="primary" @click="addRow()" plain>新增采购详情</el-button>
+            </u-form-item>
+
+            <u-form-item label="附件">
+                <el-upload
+                        class="upload-demo"
+                        :action="`http://pv4uct.natappfree.cc/api/public-modules-server/oss/file/webUpload/upload`"
+                        :on-remove="(file, fileList) => handleRemove(file, fileList, '','')"
+                        :file-list="inputForm.files"
+                        :on-success="(response, file, fileList) => handleUploadSuccess(response, file, fileList,'','')"
+                        :limit="3">
+                    <el-button size="small" type="primary">点击上传</el-button>
+                    <div slot="tip" class="el-upload__tip">只能上传不超过 3 个文件</div>
+                    <template slot="file" slot-scope="{ file }" v-if="shouldShowFile(file) || testFlag">
+                        <span @click="handleFileClick(file)">{{ file.name }}</span>
+                        <el-button type="text" icon="el-icon-close" @click="handleDelete(file)">✕</el-button>
+                    </template>
+                </el-upload>
+
+            </u-form-item>
+        </u--form>
+        <user-select ref="userPicker" @input="handleEvent"></user-select>
+        <ba-tree-picker ref="treePicker" :multiple='false' @select-change="selectChange" title="类型选择"
+                        :localdata="listData" valueKey="value" textKey="label" childrenKey="children" />
+        <goods-info-picker ref="goodsPicker" :multiple='false' @select-goods-change="selectGoodsChange" title="物品名称"
+                        :localdata="goodsListData" valueKey="value" textKey="label" childrenKey="children" />
+    </view>
+</template>
+
+<script>
+    import userSelect from '@/components/user-select/user-select-radio.vue'
+    import OSSService from "@/api/sys/OSSService"
+    import SupplierSelector from './SupplierSelector';
+    import MyDropdown from './MyDropdown';
+    import goodsInfoPicker from '../collect/GoodsInfoPicker'
+    import MaterialTypeService from '@/api/materialManagement/MaterialTypeService'
+    import WareHouseService from '@/api/materialManagement/WareHouseService'
+    import materialManagementService from '@/api/materialManagement/MaterialManagementService'
+    import CommonApi from '@/api/common/CommonApi'
+    import baTreePicker from "@/components/ba-tree-picker/ba-tree-picker.vue"
+    import {mapState, mapMutations, mapActions} from 'vuex'
+    import registerService from '@/api/human/register/RegisterService'
+    export default {
+        components: {
+            userSelect,
+            baTreePicker,
+            goodsInfoPicker,
+            'my-dropdown': MyDropdown,
+            'supplier-selector': SupplierSelector
+        },
+        computed: mapState({
+            userInfo: (state) => state.user.userInfo,
+            avatar: (state) => state.user.avatar
+        }),
+        data () {
+            return {
+                showFileList: [], // 控制每个文件是否显示的数组
+                showFileList2: [], // 控制每个文件是否显示的数组
+                testFlag: false,
+                nodeFlag: false,
+                loading: false,
+                listData: [],
+                fileList3: [],
+                goodsListData: [],
+                materialList: [],
+                searchForm: {
+                    wareHouseType: '',
+                },
+                inputForm: {
+                    purchaseNo: '',
+                    purchaseSketch: '',
+                    handledBy: '',
+                    handledById: '',
+                    handledByOffice: '',
+                    handledByOfficeName: '',
+                    purchaseDate: '',
+                    purchaseMode: '',
+                    remarks: '',
+                    detailInfos: [],
+                    files: [], // 附件信息
+                    procInsId: ''
+                },
+                rules: {
+                    'purchaseDate': [
+                        {
+                            required: true,
+                            message: '采购申请时间不能为空',
+                            trigger: ['blur', 'change']
+                        }
+                    ],
+                    'purchaseSketch': [
+                        {
+                            required: true,
+                            message: '采购名称不能为空',
+                            trigger: ['blur', 'change']
+                        }
+                    ],
+                    'purchaseMode': [
+                        {
+                            required: true,
+                            message: '采购方式不能为空',
+                            trigger: ['blur', 'change']
+                        }
+                    ],
+                }
+            }
+        },
+        materialTypeService: null,
+        ossService: null,
+        wareHouseService: null,
+        commonApi: null,
+        // 页面加载时执行
+        created() {
+            this.commonApi = new CommonApi()
+            this.materialTypeService = new MaterialTypeService()
+            this.ossService = new OSSService()
+            this.wareHouseService = new WareHouseService()
+            this.materialTypeService.cgList().then((data)=>{
+                this.materialList = data
+            }).catch((e)=>{
+                throw e
+            })
+
+            this.inputForm.handledBy = this.userInfo.name
+            this.inputForm.handledById = this.userInfo.id
+            this.inputForm.handledByOffice = this.userInfo.officeDTO.id
+            this.inputForm.handledByOfficeName = this.userInfo.officeDTO.name
+
+            // 监听事件
+            uni.$on('eventName', (data) => {
+                // 在这里处理传递过来的数据
+                //循环遍历采购详情,估计index将用户id与用户名称放入到采购人里面
+                this.inputForm.detailInfos.forEach((detail,index) => {
+                    if (index === parseInt(data.index)) {
+                        detail.purchaserAgent = data.name
+                        detail.purchaserAgentId = data.id
+                        detail.procurementOffice = data.officeDTO.name
+                    }
+                })
+            });
+        },
+        props: {
+            businessId: {
+                type: String,
+                default: ''
+            },
+            formReadOnly: {
+                type: Boolean,
+                default: false
+            }
+        },
+        watch: {
+            'businessId': {
+                handler (newVal) {
+                    if (this.businessId) {
+                        this.init(this.businessId)
+                    } else {
+                        this.$nextTick(() => {
+                            // this.$refs.inputForm.reset()
+                        })
+                    }
+                },
+                immediate: true,
+                deep: false
+            }
+        },
+        methods: {
+            // 显示选择器
+            showPicker(index) {
+                this.$refs.treePicker._show(index);
+            },
+            showGoods(index) {
+
+                this.searchForm.wareHouseType = this.inputForm.detailInfos[index].procurementTypeId
+                this.wareHouseService.wareHouseSummaryList({
+                    'current': 0,
+                    'size': -1,
+                    'orders': [],
+                    ...this.searchForm
+                }).then((data) => {
+                    this.goodsListData = data.records
+                })
+
+                this.$refs.goodsPicker._show(index);
+            },
+            //监听选择
+            selectChange(ids, names, index) {
+                // this.inputForm.detailInfos.forEach((detail,inde) => {
+                //     if (inde === parseInt(index)) {
+                //         detail.collectType = names
+                //         detail.collectTypeId = ids[0]
+                //     }
+                // })
+                this.$set(this.inputForm.detailInfos, index, {
+                    ...this.inputForm.detailInfos[index],
+                    procurementType: names,
+                    procurementTypeId: ids[0]
+                });
+
+            },
+            //监听选择
+            selectGoodsChange(ids, names, index,tradeNumber) {
+                // this.inputForm.detailInfos.forEach((detail,inde) => {
+                //     if (inde === parseInt(index)) {
+                //         detail.goodsName = names
+                //         detail.tradeNumber = tradeNumber
+                //     }
+                // })
+                this.$set(this.inputForm.detailInfos, index, {
+                    ...this.inputForm.detailInfos[index],
+                    tradeName: names,
+                    surplusNumber: tradeNumber
+                });
+            },
+            init (id) {
+                this.nodeFlag = true
+                this.inputForm.id = id
+                if (id) {
+                    materialManagementService.findById(id).then((data) => {
+
+                        this.commonApi.getTaskNameByProcInsId(data.procInsId).then((data) => {
+                            if (this.isNotEmpty(data)) {
+                                if (data === '重新发起申请' || this.isEmpty(data)) {
+                                    this.nodeFlag = false
+                                } else {
+                                    this.nodeFlag = true
+                                }
+                            }
+                        })
+                        this.inputForm = this.recover(this.inputForm, data)
+                        this.inputForm.purchaseDate = new Date(data.purchaseDate);
+
+                        if (this.inputForm.files) {
+                            this.inputForm.files.forEach( (item,index) => {
+                                this.$set(this.showFileList, index, true);
+                            })
+                        }
+
+                        this.inputForm.detailInfos.forEach( (item,index) => {
+                            if (this.isNotEmpty(item.fileInfoLost)) {
+                                this.fileList3[index] = []
+                                item.fileInfoLost.forEach( (item,index2) => {
+                                    this.fileList3[index].push(item)
+                                    this.$set(this.showFileList2, index2, true);
+                                })
+
+                            }
+                            this.inputForm.detailInfos[index].priceSum = parseFloat(parseFloat(this.inputForm.detailInfos[index].tradePrice)
+                                * parseFloat(this.inputForm.detailInfos[index].tradeNumber)).toFixed(2)
+
+                        })
+                    })
+                }
+            },
+            buildTree(nodes, parentId = '0') {
+                const tree = [];
+                for (const node of nodes) {
+                    if (node.parentId === parentId) {
+                        const children = this.buildTree(nodes, node.id);
+                        if (children.length) {
+                            node.children = children;
+                        }
+                        tree.push(node);
+                    }
+                }
+                return tree;
+            },
+            formatDate(date) {
+                const dateNew = new Date(date); // 将日期字符串转换为 Date 对象
+                const year = dateNew.getFullYear();
+                const month = (dateNew.getMonth() + 1).toString().padStart(2, '0');
+                const day = dateNew.getDate().toString().padStart(2, '0');
+                return `${year}-${month}-${day}`;
+            },
+            isEmpty(value) {
+                let result = false;
+                if (value == null || value == undefined) {
+                    result = true;
+                }
+                if (typeof value == 'string' && (value.replace(/\s+/g, "") == "" || value == "")) {
+                    result = true;
+                }
+                if (typeof value == "object" && value instanceof Array && value.length === 0) {
+                    result = true;
+                }
+                return result;
+            },
+            isNotEmpty (value) {
+                return !this.isEmpty(value)
+            },
+            /**
+             * 判断是否为空
+             */
+            isNull(val) {
+                if (val instanceof Array) {
+                    if (val.length === 0) return true;
+                } else if (val instanceof Object) {
+                    if (JSON.stringify(val) === "{}") return true;
+                } else {
+                    if (
+                        val === "null" ||
+                        val == null ||
+                        val === "undefined" ||
+                        val === undefined ||
+                        val === ""
+                    )
+                        return true;
+                    return false;
+                }
+                return false;
+            },
+            addRow() {
+                // 点击新增按钮时,向表格中添加一行空数据
+                this.inputForm.detailInfos.push({ purchaserAgent: this.userInfo.name,
+                    purchaserAgentId: this.userInfo.id, procurementOffice: this.userInfo.officeDTO.name });
+                let valueData = this.materialList;
+                // 将扁平数据转换为树形结构
+                const result = this.buildTree(valueData);
+                this.listData = result
+
+            },
+            removeRow(index) {
+                // 点击删除按钮时,从表格中移除指定行
+                // this.tableData.splice(index, 1);
+                this.inputForm.detailInfos.splice(index, 1);
+            },
+            formatDateNew(date) {
+                const year = date.getFullYear();
+                const month = (date.getMonth() + 1).toString().padStart(2, '0');
+                const day = date.getDate().toString().padStart(2, '0');
+                const hours = date.getHours().toString().padStart(2, '0');
+                const minutes = date.getMinutes().toString().padStart(2, '0');
+                const seconds = date.getSeconds().toString().padStart(2, '0');
+
+                return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+            },
+            // 采购人下拉弹窗
+            openUserPullForm(index) {
+                // 点击 "采购人" 输入框时打开userPullForm页面,传入index用于区分不同的行
+                // uni.navigateTo({
+                //     url: '/pages/materialManagement/collect/UserPullForm?index=' + index // userPullForm页面的路径
+                // });
+                this.$refs.userPicker.open(index,"");
+            },
+            handleEvent(data,index,type) {
+                // 在这里处理子组件传递过来的数据
+                this.inputForm.detailInfos[index].purchaserAgentId = data.id
+                this.inputForm.detailInfos[index].purchaserAgent = data.label
+                this.inputForm.detailInfos[index].procurementOffice = data.parentLabel
+                this.inputForm.detailInfos[index].deptId = data.parentId
+                // 进行进一步处理...
+            },
+            handleUploadSuccess (res, file, fileList, index, type) {
+                // 将 fileList 转换为你期望的格式
+                const formattedFiles = fileList.map(fileItem => {
+                    return {
+                        name: fileItem.name,
+                        size: fileItem.size,
+                        url: fileItem.response ? '/' + fileItem.response.url : fileItem.url,
+                        lsUrl: fileItem.response ? fileItem.response.lsUrl : fileItem.lsUrl, // 如果没有 lsUrl,可以根据需要设置为空字符串或其他默认值
+                        createBy: this.userInfo,
+                        by: this.userInfo.id,
+                        createTime: this.formatDateNew(new Date())
+                    };
+                });
+                if (type === 'detail') {
+                    // 将格式化后的数据设置到 detailInfos 的 fileInfoLost 属性中
+                    this.inputForm.detailInfos[index].fileInfoLost = formattedFiles;
+                    // 遍历 fileList,找到上传成功的文件,设置对应索引的 showFileList2 为 true
+                    fileList.forEach((item, i) => {
+                        if (item === file) {
+                            this.$set(this.showFileList2, i, true);
+                        }
+                    });
+                } else {
+                    this.inputForm.files = formattedFiles
+                    fileList.forEach((item, index) => {
+                        if (item === file) {
+                            this.$set(this.showFileList, index, true);
+                        }
+                    });
+                }
+                // this.inputForm.files = formattedFiles;
+                // fileList.forEach((item, index) => {
+                //     if (item === file) {
+                //         this.$set(this.showFileList, index, true);
+                //     }
+                // });
+                // 强制更新视图
+                this.$forceUpdate();
+            },
+            handleRemove(file, fileList, index, type) {
+                // 处理移除文件逻辑
+                // file 是移除的文件
+                // fileList 是当前文件列表
+                const formattedFiles = fileList.map(fileItem => {
+                    return {
+                        name: fileItem.name,
+                        size: fileItem.size,
+                        url: '/' + fileItem.response.url,
+                        createBy: this.userInfo,
+                        by: this.userInfo.id,
+                        createTime: this.formatDateNew(new Date())
+                    };
+                });
+                if (type === 'detail') {
+
+                    this.inputForm.detailInfos[index].fileInfoLost = formattedFiles;
+                } else {
+                    this.inputForm.files = formattedFiles
+                }
+
+
+                // 如果你想要更新文件列表,可以在这里更新 inputForm.fileInfoLost
+                // this.inputForm.fileInfoLost = fileList;
+            },
+            saveForm(callback) {
+                return new Promise((resolve, reject) => {
+                    // 表单规则验证
+                    // ...
+
+                    let errors = [];
+
+                    if (this.isNotEmpty(this.inputForm.purchaseDate)) {
+                        this.inputForm.purchaseDate = this.formatDate(this.inputForm.purchaseDate);
+                    }
+
+                    if (this.isEmpty(this.inputForm.detailInfos)) {
+                        errors.push('至少填写一条采购详情信息');
+                    } else {
+                        let i = this.inputForm.detailInfos.length;
+                        for (let j = 0; j < i; j++) {
+                            let k = j + 1
+                            if (this.isEmpty(this.inputForm.detailInfos[j].purchaserAgent)) {
+                                this.$message.error('采购详情第' + k + '行请选择采购人')
+                                this.loading = false
+                                return
+                            }
+                            if (this.isEmpty(this.inputForm.detailInfos[j].procurementType)) {
+                                this.$message.error('采购详情第' + k + '行请选择采购类型')
+                                this.loading = false
+                                return
+                            }
+                            if (this.isEmpty(this.inputForm.detailInfos[j].tradeName)) {
+                                this.$message.error('采购详情第' + k + '行请填写商品名称')
+                                this.loading = false
+                                return
+                            }
+                        }
+                        for (let j = 0; j < i; j++) {
+                            for (let k = j + 1; k < i; k++) {
+                                if (this.inputForm.detailInfos[j].procurementType === this.inputForm.detailInfos[k].procurementType) { // 如果采购类型相同
+                                    if (this.inputForm.detailInfos[j].tradeName === this.inputForm.detailInfos[k].tradeName) { // 如果商品名称相同
+                                        if (this.inputForm.detailInfos[j].supplierName === this.inputForm.detailInfos[k].supplierName) {
+                                            this.$message.warning(`采购详情中,同种采购类型、同一供应商的商品名称只能输入一条`)
+                                            this.loading = false
+                                            throw new Error('采购详情中,同种采购类型、同一供应商的商品名称只能输入一条')
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                    // 计算总价
+                    const tradeTotalPrice = this.inputForm.detailInfos.reduce((total, item) => {
+                        // 将每个 detailInfo 的 priceSum 加到总价中
+                        return total + parseFloat(item.priceSum || 0); // 转换为浮点数并累加,避免字符串拼接
+                    }, 0); // 初始值为 0
+
+                    if (errors.length > 0) {
+                        // 存在错误,显示提示信息
+                        errors.forEach(error => {
+                            uni.showToast({
+                                title: error,
+                                icon: 'none',
+                                duration: 2000
+                            });
+                        });
+                        reject('Form validation failed');
+                    } else {
+                        // 所有验证通过,执行保存操作
+                        this.$refs.inputForm.validate().then(() => {
+                            uni.showLoading();
+                            this.inputForm.status = '2';
+                            materialManagementService.save(this.inputForm).then(data => {
+                                callback(data.businessTable, data.businessId);
+                                resolve('Form saved successfully');
+                            }).catch(error => {
+                                reject('Save operation failed');
+                            });
+                        }).catch(() => {
+                            reject('Form validation failed');
+                        });
+                    }
+                });
+            },
+
+            // 修改状态
+            async updateStatusById (type, callback) {
+                if (type === 'reject' || type === 'reback') {
+                    materialManagementService.findById(this.inputForm.id).then((data) => {
+                        if (data.status !== '2') { // status的值不等于“审核中”,就弹出提示
+                            this.loading = false
+                            this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+                            throw new Error()
+                        } else {
+                            if (type === 'reject') {
+                                // 驳回
+                                this.inputForm.status = '4'
+                            }
+                            if (type === 'reback') {
+                                // 撤回
+                                this.inputForm.status = '3'
+                            }
+                            if (type === 'reject' || type === 'reback') {
+                                let param = {status: this.inputForm.status, id: this.inputForm.id}
+                                materialManagementService.updateStatusById(param).then(() => {
+                                    this.loading = false
+                                    callback()
+                                })
+                            }
+                        }
+                    })
+                } else if (type === 'hold') {
+                    materialManagementService.findById(this.inputForm.id).then((data) => {
+                        if (data.status !== '4') { // status的值不等于“驳回”就弹出提示
+                            this.loading = false
+                            this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+                            throw new Error()
+                        } else {
+                            // 终止
+                            let param = {status: '1', id: this.inputForm.id}
+                            materialManagementService.updateStatusById(param).then(() => {
+                                this.loading = false
+                                callback()
+                            })
+                        }
+                    })
+                }
+            },
+            reapplyForm (callback) {
+                this.loading = true
+                materialManagementService.findById(this.inputForm.id).then((data) => {
+                    if (data.status !== '4') { // 审核状态不是“驳回”,就弹出提示
+                        this.loading = false
+                        this.$message.error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+                        throw new Error('任务数据已发生改变或不存在,请在待办任务中确认此任务是否存在')
+                    } else {
+                        this.startFormTrue(callback)
+                    }
+                })
+            },
+            // 送审
+            async startFormTrue (callback) {
+                if (this.isNotEmpty(this.inputForm.purchaseDate)) {
+                    this.inputForm.purchaseDate = this.formatDate(this.inputForm.purchaseDate);
+                }
+                this.$refs.inputForm.validate().then(res => {
+                    this.inputForm.status = '2'
+                    // 计算总价
+                    const tradeTotalPrice = this.inputForm.detailInfos.reduce((total, item) => {
+                        // 将每个 detailInfo 的 priceSum 加到总价中
+                        return total + parseFloat(item.priceSum || 0); // 转换为浮点数并累加,避免字符串拼接
+                    }, 0); // 初始值为 0
+
+                    materialManagementService.save(this.inputForm).then((data) => {
+                        this.inputForm.id = data.businessId
+                        callback(data.businessTable, data.businessId, this.inputForm)
+                        this.$refs.inputForm.resetFields()
+                        this.loading = false
+                    }).catch(() => {
+                        this.$refs.inputForm.resetFields()
+                    }).catch((e) => {
+
+                    })
+                })
+            },
+            // 通过
+            async agreeForm (callback) {
+                if (this.isNotEmpty(this.inputForm.purchaseDate)) {
+                    this.inputForm.purchaseDate = this.formatDate(this.inputForm.purchaseDate);
+                }
+                this.$refs.inputForm.validate().then(res => {
+                    this.commonApi.getTaskNameByProcInsId(this.inputForm.procInsId).then((data) => {
+                        if (this.isNotEmpty(data)) {
+                            if (data === '公司领导审批') {
+                                this.inputForm.status = '5'
+                            }
+                        }
+                        materialManagementService.save(this.inputForm).then((data) => {
+                            callback(data.businessTable, data.businessId, this.inputForm)
+                            this.$refs.inputForm.resetFields()
+                            this.loading = false
+                        }).catch(() => {
+                            this.loading = false
+                            this.$refs.inputForm.resetFields()
+                        })
+                    })
+                })
+            },
+            // 值改变事件
+            changeValue () {
+                let i = this.inputForm.detailInfos.length
+                for (let j = 0; j < i; j++) {
+                    if (this.isNotEmpty(this.inputForm.detailInfos[j].tradePrice)) {
+                        if (this.isNotEmpty(this.inputForm.detailInfos[j].tradeNumber)) {
+                            // parseFloat(item.account).toFixed(2)
+                            this.inputForm.detailInfos[j].priceSum = parseFloat(parseFloat(this.inputForm.detailInfos[j].tradePrice) * parseFloat(this.inputForm.detailInfos[j].tradeNumber)).toFixed(2)
+                        } else {
+                            this.inputForm.detailInfos[j].priceSum = ''
+                        }
+                    } else {
+                        this.inputForm.detailInfos[j].priceSum = ''
+                    }
+                }
+            },
+            async handleFileClick(file) {
+                await this.ossService.getTemporaryUrl(file.url).then((data) => {
+                    file.lsUrl = data
+                })
+                if (this.isImage(file.name)) {
+                    // 如果是图片文件,则执行放大显示图片的逻辑
+                    this.handleImageClick(file);
+                } else {
+                    // window.open(file.lsUrl, '_blank')
+                    window.location.href = file.lsUrl
+                    // 如果不是图片文件,则执行其他操作,比如下载文件等
+                }
+            },
+            // 判断文件是否是图片类型
+            isImage(fileName) {
+                const ext = fileName.toLowerCase().split('.').pop(); // 获取文件的后缀名
+                return ['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(ext); // 判断后缀名是否是图片类型
+            },
+            handleImageClick(file) {
+                // 在点击图片时执行放大显示的逻辑
+                this.$alert(`<img src="${file.lsUrl}" style="max-width: 100%; max-height: 100%;" />`, '图片详情', {
+                    dangerouslyUseHTMLString: true,
+                    customClass: 'custom-alert'
+                });
+            },
+            handleDelete(file,lineIndex,type) {
+                // 处理删除文件的逻辑
+                if (type === 'detail') {
+                    const index = this.inputForm.detailInfos[lineIndex].fileInfoLost.indexOf(file);
+                    if (index !== -1) {
+                        this.inputForm.detailInfos[lineIndex].fileInfoLost.splice(index, 1);
+                        this.showFileList2.splice(index, 1); // 从showFileList中移除对应的元素
+                    }
+                } else {
+                    // 从文件列表中移除文件
+                    const index = this.inputForm.files.indexOf(file);
+                    if (index !== -1) {
+                        this.inputForm.files.splice(index, 1);
+                        this.showFileList.splice(index, 1); // 从showFileList中移除对应的元素
+                    }
+                }
+
+            },
+            shouldShowFile(file,index,type) {
+                if (type === 'detail') {
+                    if (this.inputForm.detailInfos[index].fileInfoLost && this.inputForm.detailInfos[index].fileInfoLost.length > 0) {
+                        // 返回一个布尔值,确定是否显示上传成功后的文件
+
+                        return this.showFileList2[this.inputForm.detailInfos[index].fileInfoLost.indexOf(file)];
+                    }
+
+                }else {
+                    if (this.inputForm.files && this.inputForm.files.length > 0) {
+                        // 返回一个布尔值,确定是否显示上传成功后的文件
+                        return this.showFileList[this.inputForm.files.indexOf(file)];
+                    }
+                }
+                return false; // 默认返回 false 或者其他适当的
+            },
+        }
+    }
+</script>
+
+<style>
+    .cu-form-group .title {
+        min-width: calc(4em + 40px);
+    }
+    .custom-alert {
+        max-width: 80% !important;
+        max-height: 80% !important;
+    }
+
+    /* 样式示例,您可能需要根据实际情况调整 */
+    .upload-demo {
+        width: 40%;
+    }
+</style>

+ 100 - 0
pages/materialManagement/purchase/SupplierSelector.vue

@@ -0,0 +1,100 @@
+<template>
+    <u-form-item label="供应商" :prop="'detailInfos[' + index_experience + '].supplierName'" :required="true">
+        <el-autocomplete
+                style="width: 100%;"
+                v-model="inputForm.detailInfos[index_experience].supplierName"
+                placeholder="请选择供应商"
+                clearable
+                @focus="showDropdown"
+                :fetch-suggestions="fetchSuggestions"
+                @select="handleSelect"
+        >
+            <template slot-scope="{ item }">
+                <span style="width: 100%;">{{ item.name }}</span>
+            </template>
+        </el-autocomplete>
+    </u-form-item>
+</template>
+
+<script>
+    import SupplierService from '@/api/materialManagement/SupplierService'
+    export default {
+        props: {
+            index_experience: Number,
+            inputForm: Object
+        },
+        data() {
+            return {
+                showDropdownList: false,
+                selectedSupplier: null,
+                suppliers: [] // 供应商对象数组 [{id: 1, name: 'Supplier 1'}, ...]
+            };
+        },
+        supplierService: null,
+        created () {
+            this.supplierService = new SupplierService()
+            this.showDropdown()
+        },
+        methods: {
+
+            showDropdown() {
+                // 将获取的供应商赋值给 this.suppliers
+                this.supplierService.list({
+                    'current': 1,
+                    'size': -1,
+                }).then((data) => {
+                    this.suppliers = data.records
+                    this.showDropdownList = true;
+                })
+            },
+            isEmpty(value) {
+                let result = false;
+                if (value == null || value == undefined) {
+                    result = true;
+                }
+                if (typeof value == 'string' && (value.replace(/\s+/g, "") == "" || value == "")) {
+                    result = true;
+                }
+                if (typeof value == "object" && value instanceof Array && value.length === 0) {
+                    result = true;
+                }
+                return result;
+            },
+            isNotEmpty (value) {
+                return !this.isEmpty(value)
+            },
+            fetchSuggestions(queryString, callback) {
+
+                if (this.suppliers && queryString) {
+                    const filteredList = this.suppliers.filter(item =>
+                        item.name.toLowerCase().includes(queryString.toLowerCase())
+                    );
+                    callback(filteredList);
+                } else {
+                    callback(this.suppliers);
+                    // Handle the case when suppliers or queryString is not properly initialized
+                }
+            },
+            handleSelect(item) {
+                this.inputForm.detailInfos[this.index_experience].supplierName = item.name;
+                this.inputForm.detailInfos[this.index_experience].supplierId = item.id;
+                this.showDropdownList = false;
+            }
+        }
+    };
+</script>
+
+<style scoped>
+    .my-dropdown {
+        position: absolute;
+        top: calc(100% + 4px); /* 将下拉框定位在输入框的下方,此处增加了 4px 的间距 */
+        left: 0;
+        width: 100%;
+        background-color: #fff;
+        border: 1px solid #ccc;
+    }
+    .list-item {
+        padding: 8px;
+        cursor: pointer;
+    }
+</style>

+ 3 - 2
pages/workbench/task/ApplyList.vue

@@ -122,9 +122,10 @@
 				//联网加载数据
 				this.status = 'loading';
 				taskService.myApplyedList({
-					current: this.tablePage.currentPage,
-					size: this.tablePage.pageSize,
+					current: 1,
+					size: -1,
 					orders: this.tablePage.orders,
+					type: 'ydd',
 					...this.searchForm
 				}).then((data)=>{
 					//追加新数据

+ 1 - 0
pages/workbench/task/HistoryList.vue

@@ -166,6 +166,7 @@
 					current: this.tablePage.currentPage,
 					size: this.tablePage.pageSize,
 					orders: this.tablePage.orders,
+					type: 'ydd',
 					...this.searchForm
 				}).then((data)=>{
 					//追加新数据

+ 64 - 10
pages/workbench/task/TaskForm.vue

@@ -10,12 +10,18 @@
 		<view v-show="0 === tabIndex">
 			<scroll-view scroll-y>
 			<view class=" bg-white ">
-				
+
 				<TestActivitiLeaveForm  v-if="formUrl.endsWith('TestActivitiLeaveForm')" :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''"  ref="form" :businessId="businessId"></TestActivitiLeaveForm>
 				<EnrollmentRegistrationAddForm  v-if="formUrl.endsWith('EnrollmentRegistrationAddForm')" :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''"  ref="form" :businessId="businessId"></EnrollmentRegistrationAddForm>
+				<DepartRegistrationAddForm  v-else-if="formUrl.endsWith('DepartRegistrationAddForm')" :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''"  ref="form" :businessId="businessId"></DepartRegistrationAddForm>
+				<HandoverAddForm  v-else-if="formUrl.endsWith('HandoverAddForm')" :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''"  ref="form" :businessId="businessId"></HandoverAddForm>
+				<ReimbursementForm  v-else-if="formUrl.endsWith('ReimbursementForm')" :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''"  ref="form" :businessId="businessId"></ReimbursementForm>
+				<InvoiceFormTask  v-else-if="formUrl.endsWith('InvoiceFormTask')" :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''"  ref="form" :businessId="businessId"></InvoiceFormTask>
 				<RegistrationAddForm  v-else-if="formUrl.endsWith('RegistrationAddForm')" :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''"  ref="form" :businessId="businessId"></RegistrationAddForm>
 				<CollectForm  v-else-if="formUrl.endsWith('CollectForm')" :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''"  ref="form" :businessId="businessId"></CollectForm>
-				  <!-- <component :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''"  ref="form" :businessId="businessId" :is="form"></component> -->
+				<PurchaseForm  v-else-if="formUrl.endsWith('PurchaseForm')" :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''"  ref="form" :businessId="businessId"></PurchaseForm>
+				<HolidayForm  v-else-if="formUrl.endsWith('HolidayForm')" :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''"  ref="form" :businessId="businessId"></HolidayForm>
+				<!-- <component :formReadOnly="formReadOnly" :class="formReadOnly?'readonly':''"  ref="form" :businessId="businessId" :is="form"></component> -->
 				  <PreviewForm :formData="formData"  v-if="formType !== '2'"  :processDefinitionId="procDefId" :edit="true" ref="form"></PreviewForm>
 			</view>
 			<view class=" bg-white margin-top" v-if="!procInsId || taskId">
@@ -92,6 +98,11 @@
 </template>
 
 <script>
+	import HolidayForm from '@/pages/dailyOfficeWork/holiday/HolidayForm.vue'
+	import DepartRegistrationAddForm from '@/pages/human/depart/registration/DepartRegistrationAddForm.vue'
+	import HandoverAddForm from '@/pages/human/depart/handover/HandoverAddForm.vue'
+	import ReimbursementForm from '@/pages/cw/reimbursementApproval/info/ReimbursementForm.vue'
+	import InvoiceFormTask from '@/pages/cw/invoice/InvoiceFormTask.vue'
 	import userSelect from '@/components/user-select/user-select.vue'
 	import userSelectDialog from '@/components/user-select/user-select-dialog.vue'
 	import PreviewForm from '../form/GenerateFlowableForm'
@@ -99,6 +110,7 @@
 	import TestActivitiLeaveForm from '@/pages/test/activiti/TestActivitiLeaveForm.vue'
 	import RegistrationAddForm from '@/pages/human/practice/register/RegistrationAddForm.vue'
 	import CollectForm from '@/pages/materialManagement/collect/CollectForm.vue'
+	import PurchaseForm from '@/pages/materialManagement/purchase/PurchaseForm.vue'
 	import EnrollmentRegistrationAddForm from '@/pages/human/enrollment/registration/EnrollmentRegistrationAddForm.vue'
 	import moment from 'moment'
 	import taskService from "@/api/flowable/taskService"
@@ -142,10 +154,22 @@
 					  this.form = TestActivitiLeaveForm
 				  }else if(this.formUrl.endsWith('EnrollmentRegistrationAddForm')){ 
 					  this.form = EnrollmentRegistrationAddForm
+				  }else if(this.formUrl.endsWith('DepartRegistrationAddForm')){
+					  this.form = DepartRegistrationAddForm
+				  }else if(this.formUrl.endsWith('HandoverAddForm')){
+					  this.form = HandoverAddForm
+				  }else if(this.formUrl.endsWith('ReimbursementForm')){
+					  this.form = ReimbursementForm
+				  }else if(this.formUrl.endsWith('InvoiceFormTask')){
+					  this.form = InvoiceFormTask
 				  }else if(this.formUrl.endsWith('RegistrationAddForm')){
 					  this.form = RegistrationAddForm
 				  }else if(this.formUrl.endsWith('CollectForm')){
 					  this.form = CollectForm
+				  }else if(this.formUrl.endsWith('PurchaseForm')){
+					  this.form = PurchaseForm
+				  }else if(this.formUrl.endsWith('HolidayForm')){
+					  this.form = HolidayForm
 				  }else{
 					  uni.showToast({ title: '没有关联流程表单!', icon: "none" });
 				  }
@@ -193,9 +217,12 @@
 				})
 			  }
 			// 读取历史任务列表
-			  taskService.historicTaskList(this.procInsId).then((data) => {
-				this.historicTaskList = data.reverse()
-			  })
+			if (this.procInsId) {
+				taskService.historicTaskList(this.procInsId).then((data) => {
+					this.historicTaskList = data.reverse()
+				})
+			}
+
 		},
 		components:{
 		  userSelect,
@@ -203,12 +230,19 @@
 		  TestActivitiLeaveForm,
 		  RegistrationAddForm,
 		  CollectForm,
+			PurchaseForm,
+			HolidayForm,
+			DepartRegistrationAddForm,
+			HandoverAddForm,
+			ReimbursementForm,
+			InvoiceFormTask,
 		  EnrollmentRegistrationAddForm,
 		  TaskBackNodes,
 		  PreviewForm
 		},
 		data() {
 			return {
+				days: '',
 				flow: null,
 				tabIndex: 0,
 				form: null,
@@ -353,14 +387,23 @@
 			// 启动流程
 			start (vars) {
 			  if (this.formType === '2') { // 外置表单启动
-				this.$refs.form.saveForm((businessTable, businessId) => {
+				this.$refs.form.saveForm((businessTable, businessId,inputForm) => {
+
+					if (inputForm.days){
+						this.days=inputForm.days
+					}
+					let assignee = this.auditForm.assignee
+					if (inputForm.assignee) {
+						assignee = inputForm.assignee
+					}
 				  taskService.start({
 					procDefKey: this.procDefKey,
 					businessTable: businessTable,
 					businessId: businessId,
 					...vars,
 					title: this.title,
-					assignee: this.auditForm.assignee
+					assignee: assignee,
+					days: this.days
 				  }).then((data) => {
 					  uni.showToast({ title: "启动成功", icon: "success" });
 					  uni.navigateTo({
@@ -420,7 +463,13 @@
 						if (inputForm.procDefId) {
 							param.procDefId = inputForm.procDefId
 						}
+						if (inputForm.days) {
+							this.days=inputForm.days
+						}
 						let assignee = this.auditForm.assignee
+						if (inputForm.assignee) {
+							assignee = inputForm.assignee
+						}
 
 						console.log('recordType', recordType)
 						this.recordType=recordType
@@ -433,7 +482,8 @@
 							vars: vars,
 							comment: this.auditForm,
 							assignee: assignee,
-							recordType: this.recordType
+							recordType: this.recordType,
+							days: this.days,
 						}).then((data) => {
 							uni.showToast({ title: "审批成功", icon: "success" });
 							uni.navigateTo({
@@ -597,7 +647,10 @@
 				  return;
 				}
 				 if (this.formType === '2') { //外置表单审批
-					this.$refs.form.agreeForm((businessTable, businessId) => {
+					this.$refs.form.agreeForm((businessTable, businessId,inputForm) => {
+						if (inputForm.days) {
+							this.days = inputForm.days
+						}
 					  taskService.audit({
 						taskId: this.taskId,
 						taskDefKey: this.taskDefKey,
@@ -605,7 +658,8 @@
 						procDefId: this.procDefId,
 						vars: vars,
 						comment: this.auditForm,
-						assignee: this.auditForm.assignee
+						assignee: this.auditForm.assignee,
+						days :this.days,
 				  }).then((data) => {
 						uni.showToast({ title: "审批成功", icon: "success" });
 						uni.navigateTo({

+ 30 - 4
pages/workbench/task/TaskFormDetail.vue

@@ -53,11 +53,17 @@
 </template>
 
 <script>
+	import ReimbursementForm from '@/pages/cw/reimbursementApproval/info/ReimbursementForm.vue'
+	import InvoiceFormTask from '@/pages/cw/invoice/InvoiceFormTask.vue'
+	import HolidayForm from '@/pages/dailyOfficeWork/holiday/HolidayForm.vue'
+	import HandoverAddForm from '@/pages/human/depart/handover/HandoverAddForm.vue'
+	import DepartRegistrationAddForm from '@/pages/human/depart/registration/DepartRegistrationAddForm.vue'
 	import userSelect from '@/components/user-select/user-select.vue'
 	import PreviewForm from '../form/GenerateFlowableForm'
 	import TestActivitiLeaveForm from '@/pages/test/activiti/TestActivitiLeaveForm.vue'
 	import RegistrationAddForm from '@/pages/human/practice/register/RegistrationAddForm.vue'
 	import CollectForm from '@/pages/materialManagement/collect/CollectForm.vue'
+	import PurchaseForm from '@/pages/materialManagement/purchase/PurchaseForm.vue'
 	import EnrollmentRegistrationAddForm from '@/pages/human/enrollment/registration/EnrollmentRegistrationAddForm.vue'
 	import taskService from "@/api/flowable/taskService"
 	import formService from "@/api/flowable/formService"
@@ -88,12 +94,24 @@
 					// uniapp 不支持动态组件,所以通过名称匹配决定调用的表单组件
 					if(this.formUrl.endsWith('TestActivitiLeaveForm')){ 
 						this.form = TestActivitiLeaveForm
-					}else if(this.formUrl.endsWith('EnrollmentRegistrationAddForm')){ 
+					}else if(this.formUrl.endsWith('DepartRegistrationAddForm')){
+						this.form = DepartRegistrationAddForm
+					}else if(this.formUrl.endsWith('HandoverAddForm')){
+						this.form = HandoverAddForm
+					}else if(this.formUrl.endsWith('ReimbursementForm')){
+						this.form = ReimbursementForm
+					}else if(this.formUrl.endsWith('InvoiceFormTask')){
+						this.form = InvoiceFormTask
+					}else if(this.formUrl.endsWith('EnrollmentRegistrationAddForm')){
 						this.form = EnrollmentRegistrationAddForm
 					}else if(this.formUrl.endsWith('RegistrationAddForm')){ 
 						this.form = RegistrationAddForm
 					}else if(this.formUrl.endsWith('CollectForm')){
 						this.form = CollectForm
+					}else if(this.formUrl.endsWith('PurchaseForm')){
+						this.form = PurchaseForm
+					}else if(this.formUrl.endsWith('HolidayForm')){
+						this.form = HolidayForm
 					}else{
 						uni.showToast({ title: '没有关联流程表单!', icon: "none" });
 					}
@@ -124,15 +142,23 @@
 				}
 			  }
 			// 读取历史任务列表
-			  taskService.historicTaskList(this.procInsId).then((data) => {
-				this.historicTaskList = data.reverse()
-			  })
+			if (this.procInsId) {
+				taskService.historicTaskList(this.procInsId).then((data) => {
+					this.historicTaskList = data.reverse()
+				})
+			}
 		},
 		components:{
 		  userSelect,
 		  TestActivitiLeaveForm,
 		  RegistrationAddForm,
 			CollectForm,
+			PurchaseForm,
+			HolidayForm,
+			DepartRegistrationAddForm,
+			HandoverAddForm,
+			ReimbursementForm,
+			InvoiceFormTask,
 		  EnrollmentRegistrationAddForm,
 		  PreviewForm
 		},

+ 5 - 3
pages/workbench/task/TaskFormEdit.vue

@@ -180,9 +180,11 @@
 				})
 			  }
 			// 读取历史任务列表
-			  taskService.historicTaskList(this.procInsId).then((data) => {
-				this.historicTaskList = data.reverse()
-			  })
+			if (this.procInsId) {
+				taskService.historicTaskList(this.procInsId).then((data) => {
+					this.historicTaskList = data.reverse()
+				})
+			}
 		},
 		components:{
 		  userSelect,

+ 4 - 0
pages/workbench/task/TodoList.vue

@@ -1,5 +1,8 @@
 <template>
 	<view>
+		<cu-custom style="height: 10px;" :backUrl="'/pages/index/index'" :isBack="true" bgColor="bg-gradual-blue" >
+			<block slot="content">待办事项</block>
+		</cu-custom>
 		<u-search  :show-action="false" v-model="searchForm.title" @change="inputWord" margin="20rpx 50rpx"></u-search>
 		<view>
 			<u-swipe-action>
@@ -120,6 +123,7 @@
 					current: this.tablePage.currentPage,
 					size: this.tablePage.pageSize,
 					orders: this.tablePage.orders,
+					type: 'ydd',
 					...this.searchForm
 				}).then((data)=>{
 					//追加新数据

+ 86 - 29
pages/workbench/workbench.vue

@@ -119,40 +119,97 @@
 	    async mounted() {
 			
 			let res = await actCategoryService.treeData()
-			let data = await processService.list({current: 1, size: -1})
+			let data = await processService.list({current: 1, size: -1,type: 'ydd'})
 			this.processMap = new Map()
 
-			if (this.isAdmin) {
-				//如果是管理员 查看所有的流程图信息
-				res.forEach((item)=>{
-					this.processMap.set(item.name, [])
-				})
-				let list = data.records
-				list.forEach((item)=>{
-					if(this.processMap.has(item.category)){
-						let list = this.processMap.get(item.category)
-						list.push(item)
-					}else{
-						this.processMap.set(item.category, [item])
+			let list = data.records
+			let test = []
+			let leaveTest = []
+			let resignation = []
+			let accounting = []
+			console.log('list', list)
+			list.forEach((item)=>{
+				if (item.category === '未设置') {
+					if (item.name === '物资管理-领用申请') {
+						test.push(item)
+						// this.processMap.set('物资管理', [item])
 					}
-				})
-
-				for(let [key,value] of this.processMap){
-					console.log(key,value);
-				}
-			} else {
-				//非管理员用户  只能查看物资领用 与 请假流程信息
-				let list = data.records
-				list.forEach((item)=>{
-					if (item.category === '未设置') {
-						if (item.name === '物资管理-领用申请') {
-							this.processMap.set('物资管理', [item])
-						}
+					if (item.name === '物资管理-采购申请') {
+						// console.log('item', item)
+						// this.processMap.set('物资管理', [item])
+						test.push(item)
+					}
+					if (item.name === '日常办公-请假申请') {
+						// console.log('item', item)
+						// this.processMap.set('物资管理', [item])
+						leaveTest.push(item)
+					}
+					if (item.name === '离职申请') {
+						// console.log('item', item)
+						// this.processMap.set('物资管理', [item])
+						resignation.push(item)
+					}
+					if (item.name === '离职交接申请') {
+						// console.log('item', item)
+						// this.processMap.set('物资管理', [item])
+						resignation.push(item)
 					}
+					if (item.name === '会计-报销审批') {
+						// console.log('item', item)
+						// this.processMap.set('物资管理', [item])
+						accounting.push(item)
+					}
+					if (item.name === '会计-发票申请') {
+						accounting.push(item)
+					}
+				}
 
-				})
-				console.log('this.processMap', this.processMap)
-			}
+			})
+			this.processMap.set('物资管理', test)
+			this.processMap.set('日常办公', leaveTest)
+			this.processMap.set('人力资源管理', resignation)
+			this.processMap.set('会计', accounting)
+
+			// if (this.isAdmin) {
+			// 	//如果是管理员 查看所有的流程图信息
+			// 	res.forEach((item)=>{
+			// 		this.processMap.set(item.name, [])
+			// 	})
+			// 	let list = data.records
+			// 	list.forEach((item)=>{
+			// 		if(this.processMap.has(item.category)){
+			// 			let list = this.processMap.get(item.category)
+			// 			list.push(item)
+			// 		}else{
+			// 			this.processMap.set(item.category, [item])
+			// 		}
+			// 	})
+			//
+			// 	for(let [key,value] of this.processMap){
+			// 		console.log(key,value);
+			// 	}
+			// } else {
+			// 	//非管理员用户  只能查看物资领用 与 请假流程信息
+			// 	let list = data.records
+			// 	let test = []
+			// 	console.log('list', list)
+			// 	list.forEach((item)=>{
+			// 		if (item.category === '未设置') {
+			// 			if (item.name === '物资管理-领用申请') {
+			// 				test.push(item)
+			// 				// this.processMap.set('物资管理', [item])
+			// 			}
+			// 			if (item.name === '物资管理-采购申请') {
+			// 				// console.log('item', item)
+			// 				// this.processMap.set('物资管理', [item])
+			// 				test.push(item)
+			// 			}
+			// 		}
+			//
+			// 	})
+			// 	this.processMap.set('物资管理', test)
+			// 	console.log('this.processMap', this.processMap)
+			// }