|
|
@@ -444,6 +444,45 @@ public class WbsTreeContractController extends BladeController {
|
|
|
if (ObjectUtil.isEmpty(formList)) {
|
|
|
throw new ServiceException("该节点下没有找到对应的表单数据");
|
|
|
}
|
|
|
+ // 对formList进行排序:主表优先,复制表按数字顺序排列
|
|
|
+ formList.sort((contract1, contract2) -> {
|
|
|
+ String name1 = contract1.getNodeName().replaceAll("\\s+", "");
|
|
|
+ String name2 = contract2.getNodeName().replaceAll("\\s+", "");
|
|
|
+
|
|
|
+ boolean isCopy1 = name1.contains("__");
|
|
|
+ boolean isCopy2 = name2.contains("__");
|
|
|
+
|
|
|
+ // 如果一个是主表,一个是复制表,主表排在前面
|
|
|
+ if (isCopy1 != isCopy2) {
|
|
|
+ return isCopy1 ? 1 : -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果都是主表或都是复制表
|
|
|
+ if (!isCopy1 && !isCopy2) {
|
|
|
+ // 都是主表,按字母顺序排序
|
|
|
+ return name1.compareTo(name2);
|
|
|
+ } else {
|
|
|
+ // 都是复制表,按主表名称和数字排序
|
|
|
+ String[] parts1 = name1.split("__", 2);
|
|
|
+ String[] parts2 = name2.split("__", 2);
|
|
|
+
|
|
|
+ // 先比较主表名称
|
|
|
+ int mainNameCompare = parts1[0].compareTo(parts2[0]);
|
|
|
+ if (mainNameCompare != 0) {
|
|
|
+ return mainNameCompare;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 主表名称相同,比较数字部分
|
|
|
+ try {
|
|
|
+ int num1 = Integer.parseInt(parts1[1]);
|
|
|
+ int num2 = Integer.parseInt(parts2[1]);
|
|
|
+ return Integer.compare(num1, num2);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ // 如果解析数字失败,按字符串比较
|
|
|
+ return parts1[1].compareTo(parts2[1]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
// 获取节点及祖先节点信息用于构建文件名
|
|
|
WbsTreeContract node = wbsTreeContractServiceImpl.getById(nodeId);
|
|
|
@@ -514,11 +553,21 @@ public class WbsTreeContractController extends BladeController {
|
|
|
throw new ServiceException("所有表单均无法生成有效Excel内容");
|
|
|
}
|
|
|
|
|
|
- // 设置响应头
|
|
|
- String encodedFileName = URLEncoder.encode(excelName + ".xlsx", "UTF-8")
|
|
|
- .replaceAll("\\+", " ")
|
|
|
- .replaceAll("%2B", "+");
|
|
|
- response.setHeader("Content-Disposition", "attachment; filename=" + encodedFileName);
|
|
|
+ // 处理包含特殊符号的文件名(如#、空格、中文等)
|
|
|
+ String originalFileName = excelName + ".xlsx";
|
|
|
+ // 使用UTF-8编码,并替换特殊字符(符合RFC 5987标准)
|
|
|
+ String encodedFileName = URLEncoder.encode(originalFileName, StandardCharsets.UTF_8.name())
|
|
|
+ .replaceAll("\\+", "%20") // 空格编码为%20(而非+)
|
|
|
+ .replaceAll("%23", "#")
|
|
|
+ .replaceAll("%26", "&"); // 保留#不编码(或根据需求调整)
|
|
|
+
|
|
|
+ // 设置响应头,采用RFC 5987标准格式(指定字符集)
|
|
|
+ // 双格式响应头:同时支持旧版和新版浏览器
|
|
|
+ response.setHeader("Content-Disposition",
|
|
|
+ "attachment; " +
|
|
|
+ "filename=\"" + encodedFileName + "\"; " + // 旧格式(部分浏览器依赖)
|
|
|
+ "filename*=UTF-8''" + encodedFileName // 新标准格式
|
|
|
+ );
|
|
|
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
|
|
|
|
// 写入输出流
|
|
|
@@ -780,6 +829,15 @@ public class WbsTreeContractController extends BladeController {
|
|
|
continue;
|
|
|
}
|
|
|
Map<String, String> dataMap = getDataMap(sheetResult);
|
|
|
+ // 对所有value中的单引号进行转义处理
|
|
|
+ for (Map.Entry<String, String> entry : dataMap.entrySet()) {
|
|
|
+ String value = entry.getValue();
|
|
|
+ if (value != null && value.contains("'")) {
|
|
|
+ // 将单引号转义为 \'
|
|
|
+ value = value.replace("'", "\\'");
|
|
|
+ entry.setValue(value);
|
|
|
+ }
|
|
|
+ }
|
|
|
String delSql = "delete from " + matchedContract.getInitTableName() + " where p_key_id=" + matchedContract.getPKeyId();
|
|
|
dataMap.put("p_key_id", matchedContract.getPKeyId()+"");
|
|
|
String sqlInfo = buildMTableInsertSql(matchedContract.getInitTableName(), dataMap, SnowFlakeUtil.getId(), null, null).toString();
|
|
|
@@ -901,7 +959,7 @@ public class WbsTreeContractController extends BladeController {
|
|
|
} catch (Exception e) {
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
- valSql.append(", '").append(data).append("'");
|
|
|
+ valSql.append(", ").append(data).append("'");
|
|
|
}
|
|
|
sql.append("(").append(keySql).append(")").append(" values(").append(valSql).append(")");
|
|
|
return sql;
|