From 2264630f3bc0483fd432cdd8e85e55abd3c4b10f Mon Sep 17 00:00:00 2001
From: 许鹏程 <1821349743@qq.com>
Date: 星期二, 05 十一月 2024 17:34:19 +0800
Subject: [PATCH] commit

---
 src/main/java/com/product/patch/controller/PatchImportController.java |   65 +++
 src/main/java/com/product/patch/service/idel/IPatchImportService.java |   17 +
 src/main/java/com/product/patch/config/ErrorCode.java                 |    2 
 src/main/java/com/product/patch/controller/PatchExportController.java |   81 ++++
 src/main/java/com/product/patch/service/PatchExportService.java       |  372 +++++++++++++++++++++
 pom.xml                                                               |    8 
 src/main/java/com/product/patch/service/PatchImportService.java       |  466 +++++++++++++++++++++++++++
 7 files changed, 1,011 insertions(+), 0 deletions(-)

diff --git a/pom.xml b/pom.xml
index e02bb1f..0650014 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,7 +30,15 @@
         </dependency>
         <dependency>
             <groupId>com.lx</groupId>
+            <artifactId>product-server-file</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.lx</groupId>
             <artifactId>product-server-tool-table</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.lx</groupId>
+            <artifactId>product-server-admin</artifactId>
+        </dependency>
     </dependencies>
 </project>
diff --git a/src/main/java/com/product/patch/config/ErrorCode.java b/src/main/java/com/product/patch/config/ErrorCode.java
index f097226..606bace 100644
--- a/src/main/java/com/product/patch/config/ErrorCode.java
+++ b/src/main/java/com/product/patch/config/ErrorCode.java
@@ -31,6 +31,8 @@
 
     SYNC_DB_FIELD_2_CACHE_TABLE("灏嗘暟鎹簱琛ㄧ粨鏋勫瓧娈靛悓姝ヨ嚦缂撳瓨瀛楁琛ㄥ瓧娈靛け璐�", ModuleEnum.PATCH.getValue() + "104"),
 
+    //鑾峰彇琛ㄥ瓧娈靛弬鐓уけ璐�
+    GET_TABLE_FIELD_REFERENCE_FAIL("鑾峰彇琛ㄥ瓧娈靛弬鐓уけ璐�", ModuleEnum.PATCH.getValue() + "105"),
     ;
 
     private String text;
diff --git a/src/main/java/com/product/patch/controller/PatchExportController.java b/src/main/java/com/product/patch/controller/PatchExportController.java
new file mode 100644
index 0000000..3f09159
--- /dev/null
+++ b/src/main/java/com/product/patch/controller/PatchExportController.java
@@ -0,0 +1,81 @@
+package com.product.patch.controller;
+
+import com.product.common.utils.StringUtils;
+import com.product.core.cache.DataPoolCacheImpl;
+import com.product.core.entity.DataTableEntity;
+import com.product.core.entity.FieldSetEntity;
+import com.product.core.exception.BaseException;
+import com.product.module.sys.version.ApiVersion;
+import com.product.patch.config.ErrorCode;
+import com.product.patch.service.PatchExportService;
+import com.product.util.BaseUtil;
+import com.product.util.support.AbstractBaseController;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @Author cheng
+ * @Date 2024/10/23 10:05
+ * @Desc 琛ヤ竵瀵煎嚭
+ */
+@RestController
+@RequestMapping("/api/patch/export")
+public class PatchExportController extends AbstractBaseController {
+
+	@Resource
+	private PatchExportService patchExportService;
+
+	@PostMapping("/get-table-field-reference/{version}")
+	@ApiVersion(1)
+	public String getTableFieldReference(HttpServletRequest request) {
+		try {
+			FieldSetEntity fse = BaseUtil.getFieldSetEntity(request);
+			String tableUuid = fse.getString("table_uuid");
+			String[] uuids = tableUuid.split(",");
+			DataTableEntity fields = new DataTableEntity();
+			for (String uuid : uuids) {
+				DataTableEntity f = DataPoolCacheImpl.getInstance().getCacheData("鎵�鏈夊瓧娈典俊鎭苟鎸夎〃鍒嗙粍", new String[]{uuid});
+				BaseUtil.dataTableMerge(fields, f);
+			}
+			List<String> result = new ArrayList<>();
+			for (int i = 0; i < fields.getRows(); i++) {
+				if (StringUtils.isEmpty(fields.getString(i, "field_reference"))) {
+					result.add(fields.getString(i, "field_reference"));
+				}
+			}
+			return BaseUtil.success(result);
+		} catch (BaseException e) {
+			return error(e);
+		} catch (Exception e) {
+			e.printStackTrace();
+			return error(ErrorCode.GET_TABLE_FIELD_REFERENCE_FAIL, e);
+		}
+	}
+
+	@PostMapping("/execute/{version}")
+	@ApiVersion(1)
+	public String exportPath(HttpServletRequest request, HttpServletResponse response) {
+		try {
+
+			FieldSetEntity fse = BaseUtil.getFieldSetEntity(request);
+
+			patchExportService.export(fse, response);
+			return OK();
+
+		} catch (BaseException e) {
+			return error(e);
+		} catch (Exception e) {
+			e.printStackTrace();
+			return error(ErrorCode.EXTRACT_FAIL, e);
+		}
+
+
+	}
+}
diff --git a/src/main/java/com/product/patch/controller/PatchImportController.java b/src/main/java/com/product/patch/controller/PatchImportController.java
new file mode 100644
index 0000000..7e3c108
--- /dev/null
+++ b/src/main/java/com/product/patch/controller/PatchImportController.java
@@ -0,0 +1,65 @@
+package com.product.patch.controller;
+
+import com.product.core.config.CoreConst;
+import com.product.core.entity.FieldSetEntity;
+import com.product.core.entity.RequestParameterEntity;
+import com.product.core.exception.BaseException;
+import com.product.module.sys.version.ApiVersion;
+import com.product.patch.config.ErrorCode;
+import com.product.patch.service.idel.IPatchImportService;
+import com.product.util.BaseUtil;
+import com.product.util.support.AbstractBaseController;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.util.Map;
+
+/**
+ * @Author cheng
+ * @Date 2024/10/24 18:22
+ * @Desc 琛ヤ竵瀵煎叆
+ */
+@RestController
+@RequestMapping("/api/patch/import")
+public class PatchImportController extends AbstractBaseController {
+
+
+	@Resource
+	public IPatchImportService patchImportService;
+
+	@PostMapping("/upload/{version}")
+	@ApiVersion(1)
+	public String upload(HttpServletRequest request) {
+		try {
+
+			RequestParameterEntity rpe = null;
+			Object bean = request.getAttribute(CoreConst.API_POST_REQUEST_DATA);
+			if (bean != null) {
+				rpe = (RequestParameterEntity) bean;
+			}
+
+			FieldSetEntity fse = rpe.getFormData();
+			String fileName = fse.getString("patchFile");
+			if (rpe == null || rpe.getFormData() == null || rpe.getFiles() == null || rpe.getFiles().isEmpty() || rpe.getFiles().get(fileName) == null) {
+				throw new BaseException(ErrorCode.SYSTEM_FORM_COUNT);
+			}
+			File patchFile = rpe.getFiles().get(fileName);
+
+			IPatchImportService service = (IPatchImportService) getProxyInstance(patchImportService);
+
+			Map<String, Object> result = service.uploadPatchFile(patchFile);
+
+			return BaseUtil.success(result);
+		} catch (BaseException e) {
+			e.printStackTrace();
+			return error(e);
+		} catch (Exception e) {
+			e.printStackTrace();
+			return error(ErrorCode.EXTRACT_FAIL, e);
+		}
+	}
+}
diff --git a/src/main/java/com/product/patch/service/PatchExportService.java b/src/main/java/com/product/patch/service/PatchExportService.java
new file mode 100644
index 0000000..3276db7
--- /dev/null
+++ b/src/main/java/com/product/patch/service/PatchExportService.java
@@ -0,0 +1,372 @@
+package com.product.patch.service;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.ZipUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.product.core.cache.DataPoolCacheImpl;
+import com.product.core.config.CoreConst;
+import com.product.core.config.Global;
+import com.product.core.entity.DataTableEntity;
+import com.product.core.entity.FieldSetEntity;
+import com.product.core.service.support.AbstractBaseService;
+import com.product.file.service.FileManagerService;
+import com.product.patch.config.CmnConst;
+import com.product.patch.config.ErrorCode;
+import com.product.tool.table.enums.FieldType;
+import com.product.util.BaseUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.*;
+
+/**
+ * @Author cheng
+ * @Date 2024/10/23 10:07
+ * @Desc 琛ヤ竵瀵煎嚭
+ */
+@Service
+public class PatchExportService extends AbstractBaseService {
+
+
+	@Resource
+	private FileManagerService fileManagerService;
+
+	public void export(FieldSetEntity fse, HttpServletResponse response) throws IOException {
+		Set<String> promptNameSet = new HashSet<>();
+		Set<String> dictNameSet = new HashSet<>();
+		String checkedTable = fse.getString("checkedTable");
+		JSONArray tables = null;
+		if (!StringUtils.isEmpty(checkedTable)) {
+			tables = JSONArray.parseArray(checkedTable);
+		}
+		String exportData = fse.getString("exportData");
+		JSONObject exportDataObj = null;
+		if (!StringUtils.isEmpty(exportData)) {
+			exportDataObj = JSONArray.parseObject(exportData);
+		}
+		String exportFunction = fse.getString("exportFunction");
+		JSONArray exportFunctionArr = null;
+		if (!StringUtils.isEmpty(exportFunction)) {
+			exportFunctionArr = JSONArray.parseArray(exportFunction);
+		}
+
+		String exportFace = fse.getString("exportFace");
+		JSONArray exportFaceArr = null;
+		if (!StringUtils.isEmpty(exportFace)) {
+			exportFaceArr = JSONArray.parseArray(exportFace);
+		}
+
+		String exportFlow = fse.getString("exportFlow");
+		JSONArray exportFlowArr = null;
+		if (!StringUtils.isEmpty(exportFlow)) {
+			exportFlowArr = JSONArray.parseArray(exportFlow);
+		}
+
+		String exportReference = fse.getString("exportReference");
+		JSONObject exportReferenceObj = null;
+		if (!StringUtils.isEmpty(exportReference)) {
+			exportReferenceObj = JSONArray.parseObject(exportReference);
+		}
+
+
+		String tempDir = Global.getSystemConfig("temp.dir", "./attachment/file/temp");
+		//鐢熸垚鏈琛ヤ竵鏂囦欢澶� 鎵�鏈変骇鐢熺殑涓存椂鏂囦欢鏀惧叆璇ユ枃浠跺す涓� 鏂逛究鍒犻櫎
+		File currentDir = new File(tempDir + "/" + getDateTime());
+		File tableStructureFile = exportTable(currentDir, tables, promptNameSet, dictNameSet);
+
+		DataTableEntity attachments = new DataTableEntity();
+
+		File dataZipFile = exportBusinessData(currentDir, exportDataObj, attachments);
+
+		File functionFile = exportFunction(currentDir, exportFunctionArr);
+		File faceFile = exportFace(currentDir, exportFaceArr, promptNameSet, dictNameSet);
+		File flowFile = exportFlow(currentDir, exportFlowArr, attachments);
+		File referenceFile = exportReference(currentDir, exportReferenceObj);
+
+
+		String zipFileName = currentDir + "/lx_" + getDateTime() + ".patch";
+		List<File> fileList = new ArrayList<>();
+		if (tableStructureFile != null) {
+			fileList.add(tableStructureFile);
+		}
+		if (dataZipFile != null) {
+			fileList.add(dataZipFile);
+		}
+		if (functionFile != null) {
+			fileList.add(functionFile);
+		}
+		if (faceFile != null) {
+			fileList.add(faceFile);
+		}
+		if (flowFile != null) {
+			fileList.add(flowFile);
+		}
+		if (referenceFile != null) {
+			fileList.add(referenceFile);
+		}
+		File attachment = exportAttachment(currentDir, attachments);
+		if (attachment != null) {
+			fileList.add(attachment);
+		}
+		File zip = ZipUtil.zip(new File(zipFileName), Charset.defaultCharset(), false, fileList.toArray(new File[0]));
+
+
+		response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
+		response.setHeader("Content-Disposition", "attachment; filename=" + zip.getName());
+		response.setContentType("application/octet-stream");
+		response.setContentLengthLong(zip.length());
+		OutputStream out = response.getOutputStream();
+		try {
+			FileUtil.writeToStream(zip, out);
+		} catch (Exception e) {
+			e.printStackTrace();
+			//寮傚父鏃惰緭鍑虹被鍨嬫敼涓簀son
+			response.setContentType("application/json");
+			Map<String, Object> result = new HashMap<>();
+			result.put("code", ErrorCode.EXTRACT_FAIL.getValue());
+			result.put("msg", ErrorCode.EXTRACT_FAIL.getText());
+			result.put("status", "fail");
+			IoUtil.write(out, Charset.defaultCharset(), false, JSONObject.toJSONString(result));
+			logger.error("瀵煎嚭琛ヤ竵鏂囦欢寮傚父", e);
+		}
+		out.flush();
+		out.close();
+
+		FileUtil.del(currentDir);
+	}
+
+
+	private File writeString(DataTableEntity dte, String fileName, File dir) {
+		if (DataTableEntity.isEmpty(dte) || StringUtils.isEmpty(fileName)) {
+			return null;
+		}
+		if (!fileName.startsWith("/") && !fileName.startsWith("\\")) {
+			fileName = "/" + fileName;
+		}
+		JSONArray objects = BaseUtil.dataTableEntityToJson(dte);
+		//灏嗘暟鎹鍑哄埌鏂囦欢
+		String data = objects.toJSONString();
+		File touch = FileUtil.touch(dir, fileName);
+		FileUtil.writeString(data, touch, "UTF-8");
+		return touch;
+	}
+
+	public File exportReference(File dir, JSONObject exportReferenceObj) {
+		if (exportReferenceObj == null) {
+			return null;
+		}
+		//鍒涘缓鏂囦欢澶�
+		File referenceDir = new File(dir.getPath() + File.separator + "reference");
+		if (!referenceDir.exists()) {
+			referenceDir.mkdirs();
+		}
+
+		JSONArray prompt = exportReferenceObj.getJSONArray("prompt");
+		JSONArray dict = exportReferenceObj.getJSONArray("dict");
+		if (prompt != null && prompt.size() > 0) {
+			DataTableEntity dte = getBaseDao().listTable("product_sys_prompt", BaseUtil.buildQuestionMarkFilter("prompt_name", prompt.size(), true), prompt.toArray());
+			writeString(dte, "prompt_" + getDateTime(), referenceDir);
+		}
+		if (dict != null && dict.size() > 0) {
+			DataTableEntity dte = getBaseDao().listTable("product_sys_dict", BaseUtil.buildQuestionMarkFilter("dict_name", dict.size(), true), dict.toArray());
+			writeString(dte, "dict_" + getDateTime(), referenceDir);
+		}
+
+		if (referenceDir.list().length > 0) {
+			return ZipUtil.zip(referenceDir);
+		}
+
+
+		return null;
+	}
+
+
+	/**
+	 * 瀵煎嚭琛ㄧ粨鏋� 鍖呭惈绱㈠紩
+	 * @param dir
+	 * @param tableInfoArr
+	 * @return
+	 */
+	public File exportTable(File dir, JSONArray tableInfoArr, Set<String> promptNameSet, Set<String> dictNameSet) {
+		DataTableEntity tableDte = getBaseDao().listTable(CoreConst.PRODUCT_SYS_DATAMODEL_TABLE, BaseUtil.buildQuestionMarkFilter("table_name", tableInfoArr.size(), true), tableInfoArr.stream().toArray(),
+				new Object[]{}, null, Integer.MAX_VALUE, 1, true);
+		return writeString(tableDte, "table_" + getDateTime(), dir);
+	}
+
+	/**
+	 * 瀵煎嚭涓氬姟鏁版嵁
+	 * @param dir
+	 * @param exportDataObj
+	 * @return
+	 */
+	public File exportBusinessData(File dir, JSONObject exportDataObj, DataTableEntity attachments) {
+		if (exportDataObj == null) {
+			return null;
+		}
+		Set<String> tableNameSet = exportDataObj.keySet();
+		if (CollectionUtil.isEmpty(tableNameSet)) {
+			return null;
+		}
+		List<File> fileList = new ArrayList<>();
+		for (String tableName : tableNameSet) {
+			JSONObject conf = exportDataObj.getJSONObject(tableName);
+			// 0 蹇界暐鏁版嵁 1 瀵煎嚭鍏ㄩ儴鏁版嵁 2 瀵煎嚭鎸囧畾鏁版嵁
+			String dataExportType = conf.getString("dataExportType");
+
+			if ("0".equals(dataExportType)) {
+				continue;
+			}
+			String filter = null;
+			Object[] params = null;
+			if ("2".equals(dataExportType)) {
+				JSONArray selectionData = conf.getJSONArray("selectionData");
+				if (selectionData == null || selectionData.isEmpty()) {
+					continue;
+				}
+				filter = BaseUtil.buildQuestionMarkFilter("uuid", selectionData.size(), true);
+				params = selectionData.stream().toArray();
+			}
+			DataTableEntity dte = getBaseDao().listTable(tableName, filter, params);
+			if (DataTableEntity.isEmpty(dte)) {
+				continue;
+			}
+			DataTableEntity dt = getAttachmentData(dte);
+			if (!DataTableEntity.isEmpty(dt)) {
+				BaseUtil.dataTableMerge(attachments, dt);
+			}
+			File file = writeString(dte, "data_" + tableName + "_" + getDateTime(), dir);
+			fileList.add(file);
+		}
+
+		//鍘嬬缉鏂囦欢
+		File[] array = fileList.toArray(new File[]{});
+		File zip = new File(dir.getPath() + "/table_data" + getDateTime() + ".zip");
+		ZipUtil.zip(zip, Charset.defaultCharset(), false, array);
+		return zip;
+	}
+
+	/**
+	 * 瀵煎嚭鍔熻兘
+	 * @param dir
+	 * @param exportFunctionArr
+	 * @return
+	 */
+	public File exportFunction(File dir, JSONArray exportFunctionArr) {
+		if (exportFunctionArr == null || exportFunctionArr.isEmpty()) {
+			return null;
+		}
+		DataTableEntity functionDte = getBaseDao().listTable(CoreConst.PRODUCT_SYS_FUNCTIONS, BaseUtil.buildQuestionMarkFilter("uuid", exportFunctionArr.size(), true), exportFunctionArr.stream().toArray(),
+				new Object[]{}, null, Integer.MAX_VALUE, 1, true);
+
+		return writeString(functionDte, "function_" + getDateTime(), dir);
+	}
+
+	public File exportFlow(File dir, JSONArray exportFlowArr, DataTableEntity attachments) {
+		if (exportFlowArr == null || exportFlowArr.isEmpty()) {
+			return null;
+		}
+		DataTableEntity flowDte = getBaseDao().listTable(CmnConst.TABLE_PRODUCT_SYS_FLOW_MODEL, BaseUtil.buildQuestionMarkFilter("type_code", exportFlowArr.size(), true), exportFlowArr.stream().toArray(),
+				new Object[]{}, null, Integer.MAX_VALUE, 1, true);
+
+		return writeString(flowDte, "flow_" + getDateTime(), dir);
+	}
+
+	public File exportFace(File dir, JSONArray exportFaceArr, Set<String> promptNameSet, Set<String> dictNameSet) {
+		if (exportFaceArr == null || exportFaceArr.isEmpty()) {
+			return null;
+		}
+		DataTableEntity faceDte = getBaseDao().listTable("product_sys_face", BaseUtil.buildQuestionMarkFilter("face_number", exportFaceArr.size(), true), exportFaceArr.stream().toArray(),
+				new Object[]{}, null, Integer.MAX_VALUE, 1, true);
+		return writeString(faceDte, "face_" + getDateTime(), dir);
+	}
+
+	public File exportAttachment(File dir, DataTableEntity attachments) {
+		if (DataTableEntity.isEmpty(attachments)) {
+			return null;
+		}
+		File attachmentDir = new File(dir.getPath() + File.separator + "/attachment");
+		for (int i = 0; i < attachments.getRows(); i++) {
+			FieldSetEntity fieldSetEntity = attachments.getFieldSetEntity(i);
+			try {
+				File file = fileManagerService.getFile(fieldSetEntity);
+				if (file != null && file.isFile()) {
+					File tempFile = new File(attachmentDir.getPath() + File.separator + fieldSetEntity.getString("attachment_title"));
+					if (!tempFile.getParentFile().exists()) {
+						tempFile.getParentFile().mkdirs();
+					}
+					if (!tempFile.exists()) {
+						tempFile.createNewFile();
+					}
+					FileUtil.copy(file, tempFile, true);
+					FileUtil.del(file);
+				}
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+		JSONArray objects = BaseUtil.dataTableEntityToJson(attachments);
+		String data = objects.toJSONString();
+		File touch = FileUtil.touch(dir, "/attachment_data" + getDateTime());
+		FileUtil.writeString(data, touch, "UTF-8");
+		File zip = ZipUtil.zip(new File(dir.getPath() + "/attachment" + getDateTime() + ".zip"), Charset.defaultCharset(), true, touch, attachmentDir);
+		return zip;
+	}
+
+
+	private DataTableEntity getAttachmentData(DataTableEntity dte) {
+		if (DataTableEntity.isEmpty(dte)) {
+			return null;
+		}
+
+		String tableName = dte.getTableName().toString();
+
+		FieldSetEntity tableInfo = BaseUtil.getSingleInfoByCache("鎵�鏈夎〃淇℃伅", new String[]{tableName});
+		if (FieldSetEntity.isEmpty(tableInfo)) {
+			return null;
+		}
+		String tableUuid = tableInfo.getString("uuid");
+		DataTableEntity fieldDte = DataPoolCacheImpl.getInstance().getCacheData("鎵�鏈夊瓧娈典俊鎭苟鎸夎〃鍒嗙粍", new String[]{tableUuid});
+		//鑾峰彇鎵�鏈夐檮浠跺瓧娈�
+		Set<String> attachmentField = new HashSet<>();
+		for (int i = 0; i < fieldDte.getRows(); i++) {
+			String fieldType = fieldDte.getString(i, "field_type");
+			if (FieldType.FILE.equals(FieldType.getByDictValue(fieldType))) {
+				attachmentField.add(fieldDte.getString(i, "field_name"));
+			}
+		}
+
+		if (CollectionUtil.isEmpty(attachmentField)) {
+			return null;
+		}
+		Set<String> fileUuidSet = new HashSet<>();
+		for (int i = 0; i < dte.getRows(); i++) {
+			for (String field : attachmentField) {
+				String fileUuid = dte.getString(i, field);
+				if (StringUtils.isEmpty(fileUuid)) {
+					continue;
+				}
+				fileUuidSet.add(fileUuid);
+			}
+		}
+
+		if (CollectionUtil.isEmpty(fileUuidSet)) {
+			return null;
+		}
+
+		return getBaseDao().listTable("product_sys_attachments", BaseUtil.buildQuestionMarkFilter("uuid", fileUuidSet.size(), true), fileUuidSet.toArray());
+	}
+
+	private String getDateTime() {
+		return DateTime.now().toString("yyyyMMddHHmmss");
+	}
+}
diff --git a/src/main/java/com/product/patch/service/PatchImportService.java b/src/main/java/com/product/patch/service/PatchImportService.java
new file mode 100644
index 0000000..0f9f557
--- /dev/null
+++ b/src/main/java/com/product/patch/service/PatchImportService.java
@@ -0,0 +1,466 @@
+package com.product.patch.service;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ZipUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Sets;
+import com.product.admin.service.PublicService;
+import com.product.common.utils.StringUtils;
+import com.product.core.config.CoreConst;
+import com.product.core.config.Global;
+import com.product.core.entity.DataTableEntity;
+import com.product.core.entity.FieldSetEntity;
+import com.product.core.exception.BaseException;
+import com.product.core.service.support.AbstractBaseService;
+import com.product.core.transfer.Transactional;
+import com.product.core.util.JsonUtil;
+import com.product.patch.config.CmnConst;
+import com.product.patch.service.idel.IPatchImportService;
+import com.product.tool.table.service.DataModelService;
+import com.product.util.BaseUtil;
+import com.sun.xml.internal.bind.v2.TODO;
+import org.apache.poi.ss.formula.functions.T;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.StandardCopyOption;
+import java.util.*;
+
+/**
+ * @Author cheng
+ * @Date 2024/10/23 10:07
+ * @Desc 琛ヤ竵瀵煎嚭
+ */
+@Service
+public class PatchImportService extends AbstractBaseService implements IPatchImportService {
+
+	@Resource
+	private PublicService publicService;
+
+	@Resource
+	private DataModelService dataModelService;
+
+
+	@Override
+	@Transactional
+	public Map<String, Object> uploadPatchFile(File patchFile) throws Exception {
+
+		Map<String, Object> result = new HashMap<>();
+		File patchDir = ZipUtil.unzip(patchFile);
+		//鑾峰彇鏂囦欢澶逛笅鐨勬墍鏈夋枃浠�
+		File[] files = patchDir.listFiles();
+		//鏂囦欢鎺掑簭灏唞ip鎺掑埌鏈�鍚�
+		Arrays.sort(files, (a, v) -> {
+			if (a.getName().endsWith(".zip")) {
+				return 1;
+			} else {
+				return -1;
+			}
+		});
+		for (File file : files) {
+			if (!file.isFile()) {
+				continue;
+			}
+			String fileName = file.getName();
+			if (fileName.startsWith("face_")) {
+				//琛ㄥ崟
+				readFaceData(file);
+			} else if (fileName.startsWith("flow_")) {
+				//娴佺▼
+				readFlowData(file);
+			} else if (fileName.startsWith("function_")) {
+				//鍔熻兘
+				readFunctionData(file);
+			} else if (fileName.startsWith("structure_")) {
+				//鏁版嵁琛�
+				readTableStructure(file);
+			} else if (fileName.startsWith("attachment") && fileName.endsWith(".zip")) {
+				//闄勪欢
+				readAttachment(file);
+			} else if (fileName.startsWith("table_data") && fileName.endsWith(".zip")) {
+				//鏁版嵁
+				readTableData(file);
+			} else if (fileName.startsWith("reference") && fileName.endsWith(".zip")) {
+				//鍙傜収
+				readReference(file);
+			}
+		}
+
+		return result;
+	}
+
+
+	/**
+	 * 璇诲彇鍙傜収
+	 */
+	private Integer readReference(File file) throws Exception {
+		if (!file.isFile()) {
+			return 0;
+		}
+		File unzip = ZipUtil.unzip(file);
+		//瑙e帇鐨勬枃浠朵笅 鏈� prompt 鏂囦欢 鍜� dict 鏂囦欢 鍦ㄧ洰褰曚笅鎵惧埌杩欎袱涓枃浠�
+		File dict = new File(unzip.getPath() + File.separator + "dict");
+		File prompt = new File(unzip.getPath() + File.separator + "prompt");
+		DataTableEntity dictDte = readFileData(dict, "product_sys_dict");
+		DataTableEntity promptDte = readFileData(prompt, "product_sys_prompt");
+		return addOrUpdate(dictDte) + addOrUpdate(promptDte);
+	}
+
+	private Integer addOrUpdate(DataTableEntity dte) {
+		if (DataTableEntity.isEmpty(dte)) {
+			return 0;
+		}
+		String tableName = dte.getTableName().toString();
+		//鑾峰彇uuid
+		Object[] uuids = dte.getUuids();
+		DataTableEntity dte1 = getBaseDao().listTable(tableName, BaseUtil.buildQuestionMarkFilter("uuid", uuids.length, true), uuids);
+		Set<String> subTableNames = Sets.newHashSet();
+		for (int i = 0; i < dte.getRows(); i++) {
+			String uuid = dte1.getString(i, CoreConst.UUID);
+			FieldSetEntity ff = dte1.getFieldSetEntity(i);
+			if (ff.getSubData() != null) {
+				subTableNames.addAll(ff.getSubData().keySet());
+			}
+			List<FieldSetEntity> fieldSetEntity = dte1.getFieldSetEntity(uuid);
+			if (!CollectionUtil.isEmpty(fieldSetEntity)) {
+				continue;
+			}
+
+			FieldSetEntity fse = fieldSetEntity.get(0);
+			fse.setValue(CoreConst.SYSTEM_DATA_OPERATE_TYPE, CoreConst.SYSTEM_DATA_OPERATE_ADD);
+		}
+		for (String subTableName : subTableNames) {
+			FieldSetEntity info = BaseUtil.getSingleInfoByCache("鎵�鏈夎〃淇℃伅", new String[]{subTableName});
+			if (info == null) {
+				continue;
+			}
+			FieldSetEntity info1 = BaseUtil.getSingleInfoByCache("鎵�鏈夎〃鍏宠仈淇℃伅", new String[]{info.getUUID()});
+			if (FieldSetEntity.isEmpty(info1)) {
+				continue;
+			}
+			getBaseDao().delete(subTableName, BaseUtil.buildQuestionMarkFilter(info1.getString("field_name"), dte1.getRows(), true), uuids);
+		}
+		getBaseDao().update(dte);
+		return dte.getRows();
+	}
+
+	/**
+	 * 璇诲彇琛ㄧ粨鏋勬暟鎹�
+	 * @param file
+	 * @return
+	 * @throws Exception
+	 */
+	private DataTableEntity readTableStructure(File file) throws Exception {
+		DataTableEntity dte = readFileData(file, "product_sys_datamodel_table");
+		DataTableEntity old = getBaseDao().listTable("product_sys_datamodel_table", BaseUtil.buildQuestionMarkFilter("uuid", dte.getUuids().length, true), dte.getUuids(), null, null, Integer.MAX_VALUE, 1, true);
+		for (int i = 0; i < dte.getRows(); i++) {
+			FieldSetEntity fse = dte.getFieldSetEntity(i);
+			//鏌ヨ鍑轰笉瀛樺湪鐨勭储寮曞拰瀛楁
+			if (old != null && old.getRows() > 0) {
+				List<FieldSetEntity> oldf = old.getFieldSetEntity(fse.getString("uuid"));
+				if (CollectionUtil.isEmpty(oldf)) {
+					//璁板綍涓嶅瓨鍦� 銆佹柊琛�
+					continue;
+				}
+				FieldSetEntity oldFse = oldf.get(0);
+				//瀵规瘮绱㈠紩鍜屽瓧娈�
+				String[] table = {"product_sys_datamodel_field", "product_sys_datamodel_index"};
+				for (String t : table) {
+					DataTableEntity sub = fse.getSubDataTable(t);
+					DataTableEntity oldSub = oldFse.getSubDataTable(t);
+					if (DataTableEntity.isEmpty(oldSub)) {
+						continue;
+					}
+					// 琛ヤ竵涓瓙琛ㄤ负绌� 鍒欏叏鍒犻櫎
+					if (DataTableEntity.isEmpty(sub)) {
+						sub = old.clones();
+						//璁剧疆涓哄垹闄�
+						for (int i1 = 0; i1 < sub.getRows(); i1++) {
+							sub.setFieldValue(i1, CoreConst.SYSTEM_DATA_OPERATE_TYPE, CoreConst.SYSTEM_DATA_OPERATE_DEL);
+						}
+						continue;
+					}
+					//鍒犻櫎褰撳墠宸插瓨鍦ㄧ殑瀛楁浣嗚ˉ涓佷腑娌℃湁鐨�
+					for (int i1 = 0; i1 < oldSub.getRows(); i1++) {
+						FieldSetEntity oldFse1 = oldSub.getFieldSetEntity(i1);
+						List<FieldSetEntity> fieldSetEntity = sub.getFieldSetEntity(oldFse1.getString("uuid"));
+						if (CollectionUtil.isEmpty(fieldSetEntity)) {
+							//涓嶅瓨鍦�
+							FieldSetEntity clones = oldFse1.clones();
+							clones.setValue(CoreConst.SYSTEM_DATA_OPERATE_TYPE, CoreConst.SYSTEM_DATA_OPERATE_DEL);
+							sub.addFieldSetEntity(clones);
+						}
+					}
+				}
+			}
+
+			//璋冪敤鏁版嵁寤烘ā缁熶竴鎿嶄綔鏂规硶
+			dataModelService.dataModelOperation(fse);
+		}
+
+		return null;
+	}
+
+	/**
+	 * 璇诲彇娴佺▼閰嶇疆
+	 * @param file
+	 * @return
+	 * @throws Exception
+	 */
+	private Integer readFlowData(File file) throws Exception {
+		DataTableEntity dataTableEntity = readFileData(file, "product_sys_flow");
+		return addOrUpdate(dataTableEntity);
+	}
+
+	/**
+	 * 璇诲彇鍔熻兘閰嶇疆
+	 * @param file
+	 * @return
+	 * @throws Exception
+	 */
+	private int readFunctionData(File file) throws Exception {
+		DataTableEntity dte = readFileData(file, "product_sys_functions");
+		//鍒ゆ柇鏄惁宸茬粡瀛樺湪 涓� tricode 涓嶄竴鑷�
+		if (DataTableEntity.isEmpty(dte)) {
+			return 0;
+		}
+		String tableName = dte.getTableName().toString();
+		//鑾峰彇uuid
+		Object[] uuids = dte.getUuids();
+		DataTableEntity dte1 = getBaseDao().listTable(tableName, BaseUtil.buildQuestionMarkFilter("uuid", uuids.length, true), uuids);
+		Set<String> subTableNames = Sets.newHashSet();
+		for (int i = 0; i < dte.getRows(); i++) {
+			String uuid = dte1.getString(i, CoreConst.UUID);
+			FieldSetEntity ff = dte1.getFieldSetEntity(i);
+			if (ff.getSubData() != null) {
+				subTableNames.addAll(ff.getSubData().keySet());
+			}
+			List<FieldSetEntity> fieldSetEntity = dte1.getFieldSetEntity(uuid);
+			if (!CollectionUtil.isEmpty(fieldSetEntity)) {
+				//鍒ゆ柇tricode 鏄惁涓�鑷�
+				FieldSetEntity fieldSetEntity1 = fieldSetEntity.get(0);
+				String tricode = fieldSetEntity1.getString("tricode");
+				String tricode1 = dte.getString(i, "tricode");
+				if (StringUtils.isNotEmpty(tricode) && !tricode.equals(tricode1)) {
+					//涓嶄竴鑷�
+					String triCodeParent = fieldSetEntity1.getString("tricode_parent");
+					String triCodeParent1 = dte.getString(i, "tricode_parent");
+					if (StringUtils.isNotEmpty(triCodeParent) && !triCodeParent.equals(triCodeParent1)) {
+						//鎷垮埌宸插瓨鍦ㄧ殑tricode 鏇挎崲
+						dte.setFieldValue(i, "tricode", tricode);
+						dte.setFieldValue(i, "tricode_parent", triCodeParent);
+						continue;
+					} else {
+						//閲嶆柊鐢熸垚
+						dte.setFieldValue(i, "tricode", null);
+						publicService.createdCode(dte.getFieldSetEntity(i), "product_sys_functions", "tricode", "tricode_parent");
+					}
+					continue;
+				}
+				continue;
+			}
+			for (String subTableName : subTableNames) {
+				FieldSetEntity info = BaseUtil.getSingleInfoByCache("鎵�鏈夎〃淇℃伅", new String[]{subTableName});
+				if (info == null) {
+					continue;
+				}
+				FieldSetEntity info1 = BaseUtil.getSingleInfoByCache("鎵�鏈夎〃鍏宠仈淇℃伅", new String[]{info.getUUID()});
+				if (FieldSetEntity.isEmpty(info1)) {
+					continue;
+				}
+				getBaseDao().delete(subTableName, BaseUtil.buildQuestionMarkFilter(info1.getString("field_name"), dte1.getRows(), true), uuids);
+			}
+			FieldSetEntity fse = fieldSetEntity.get(0);
+			fse.setValue(CoreConst.SYSTEM_DATA_OPERATE_TYPE, CoreConst.SYSTEM_DATA_OPERATE_ADD);
+		}
+		getBaseDao().update(dte);
+		return dte.getRows();
+	}
+
+	/**
+	 * 璇诲彇琛ㄥ崟閰嶇疆
+	 * @param file
+	 * @return
+	 * @throws Exception
+	 */
+	private int readFaceData(File file) throws Exception {
+		DataTableEntity dte = readFileData(file, "product_sys_form");
+		return addOrUpdate(dte);
+	}
+
+
+	/**
+	 * 鏁版嵁涓氬姟琛ㄦ暟鎹�
+	 * @param file
+	 * @return
+	 * @throws Exception
+	 */
+	private int readTableData(File file) throws Exception {
+		if (!file.isFile()) {
+			return 0;
+		}
+		File fileDir = ZipUtil.unzip(file);
+		int result = 0;
+		for (File file1 : fileDir.listFiles()) {
+			if (!file1.isFile()) {
+				continue;
+			}
+			String fileName = file1.getName();
+			//鍒ゆ柇鏂囦欢鍚嶆槸鍚︿互data_寮�澶� 涓棿浠绘剰瀛楁瘝+涓嬪垝绾� 缁撳熬鏄� _ + 16浣嶆暟瀛�
+			String regex = "^data_.*_[0-9]{14}$";
+			if (!fileName.matches(regex)) {
+				continue;
+			}
+			String tableName = fileName.substring(5, fileName.length() - 15);
+			DataTableEntity res = readFileData(file1, tableName);
+			if (DataTableEntity.isEmpty(res)) {
+				continue;
+			}
+			result += addOrUpdate(res);
+		}
+		return result;
+	}
+
+	/**
+	 * 璇诲彇闄勪欢鏁版嵁骞朵繚瀛�
+	 * @param file
+	 * @throws Exception
+	 */
+	private void readAttachment(File file) throws Exception {
+		File unzip = ZipUtil.unzip(file);
+		//鍘昏鏂囦欢澶逛腑鐨勬枃浠�
+		File[] files = unzip.listFiles((v) -> v.isFile());
+		if (files.length == 0) {
+			return;
+		}
+		File attachmentFile = files[0];
+		String fileName = attachmentFile.getName();
+		JSONArray data = null;
+		if (fileName.startsWith("attachment_data")) {
+			//闄勪欢鏁版嵁
+			data = readFileString(attachmentFile);
+		} else {
+			return;
+		}
+		if (data == null || data.isEmpty()) {
+			return;
+		}
+		DataTableEntity attachmentDte = toDataTable(data, "product_sys_attachments");
+		//鍘昏闄勪欢鏂囦欢
+		File attachmentDir = new File(unzip.getPath() + File.separator + "attachment");
+
+		Object[] uuids = attachmentDte.getUuids();
+		DataTableEntity dte = getBaseDao().listTable("product_sys_attachments", BaseUtil.buildQuestionMarkFilter("uuid", uuids.length, true), uuids);
+
+
+		for (int i = 0; i < attachmentDte.getRows(); i++) {
+			FieldSetEntity fse = attachmentDte.getFieldSetEntity(i);
+
+			//鑾峰彇鏁版嵁瀵瑰簲鐨勯檮浠�
+			String attachmentTitle = fse.getString("attachment_title");
+
+			File file1 = new File(attachmentDir + File.separator + attachmentTitle);
+			if (!file1.isFile()) {
+				continue;
+			}
+			//绉诲姩鍒伴檮浠跺搴旂殑鐩綍
+
+			String path = fse.getString("attachment_url");
+			String dir = Global.getSystemConfig("local.dir", "./attachment/file");
+			File targetDir = new File(dir + File.separator + path);
+			if (!targetDir.exists()) {
+				targetDir.mkdirs();
+			}
+			//澶嶅埗鏂囦欢鍒扮洿鎺ユ枃浠跺す 瀛樺湪鏇挎崲
+			FileUtil.copyFile(file1, targetDir, StandardCopyOption.REPLACE_EXISTING);
+
+			List<FieldSetEntity> fieldSetEntity = dte.getFieldSetEntity(fse.getUUID());
+			if (fieldSetEntity == null || fieldSetEntity.isEmpty()) {
+				//鏂版暟鎹�
+				fse.setValue(CoreConst.SYSTEM_DATA_OPERATE_TYPE, CoreConst.SYSTEM_DATA_OPERATE_ADD);
+			}
+		}
+		getBaseDao().update(attachmentDte);
+
+
+	}
+
+	/**
+	 * 璇诲彇鏂囦欢涓殑鏁版嵁骞惰浆涓篋ataTable
+	 * @param file
+	 * @param tableName
+	 * @return
+	 * @throws Exception
+	 */
+	private DataTableEntity readFileData(File file, String tableName) throws Exception {
+		if (!file.isFile()) {
+			return null;
+		}
+		JSONArray objects = readFileString(file);
+		if (objects == null || objects.isEmpty()) {
+			return null;
+		}
+		return toDataTable(objects, tableName);
+	}
+
+	/**
+	 * json鏁扮粍杞珼ataTable
+	 * @param arr
+	 * @param tableName
+	 * @return
+	 */
+	private DataTableEntity toDataTable(JSONArray arr, String tableName) throws BaseException {
+		if (arr == null || arr.isEmpty()) {
+			return null;
+		}
+		DataTableEntity result = new DataTableEntity();
+		//閬嶅巻json鏁扮粍
+		for (int i = 0; i < arr.size(); i++) {
+			FieldSetEntity fse = new FieldSetEntity(tableName);
+			JSONObject jsonObject = arr.getJSONObject(i);
+			fse.setValues((Map) jsonObject.clone());
+			//灏唈son涓杞界殑json瀵硅薄杞垚DataTableEntity锛岄亶鍘唈son涓殑鍐呭
+
+			for (String key : jsonObject.keySet()) {
+				Object o = jsonObject.get(key);
+				if (o instanceof JSONArray) {
+					fse.remove(key);
+					fse.addSubDataTable(toDataTable(jsonObject.getJSONArray(key), key));
+				}
+			}
+			result.addFieldSetEntity(fse);
+		}
+		return result;
+	}
+
+	/**
+	 * 璇诲彇鏂囦欢涓殑鍐呭
+	 * @param file
+	 * @return
+	 */
+	private JSONArray readFileString(File file) throws Exception {
+		if (!file.isFile()) {
+			return null;
+		}
+		try (InputStream in = new FileInputStream(file)) {
+			String str = IoUtil.read(in, "UTF-8");
+			if (StringUtils.isEmpty(str)) {
+				return null;
+			}
+			return JSONArray.parseArray(str);
+		}
+	}
+
+	private String getDateTime() {
+		return DateTime.now().toString("yyyyMMddHHmmss");
+	}
+}
diff --git a/src/main/java/com/product/patch/service/idel/IPatchImportService.java b/src/main/java/com/product/patch/service/idel/IPatchImportService.java
new file mode 100644
index 0000000..a1cbffe
--- /dev/null
+++ b/src/main/java/com/product/patch/service/idel/IPatchImportService.java
@@ -0,0 +1,17 @@
+package com.product.patch.service.idel;
+
+
+import java.io.File;
+import java.util.Map;
+
+/**
+ * @Author cheng
+ * @Date 2024/10/23 10:07
+ * @Desc 琛ヤ竵瀵煎嚭
+ */
+public interface IPatchImportService {
+
+
+	Map<String, Object> uploadPatchFile(File patchFile) throws Exception;
+
+}

--
Gitblit v1.9.2