mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 15:35:55 +08:00
Dd wx sync scope (#712)
* fix: excel模板字段排序 * fix: 多列表导出 * template5 * feat: chart/table export * feat: 用户同步匹配选项
This commit is contained in:
parent
47a7335391
commit
91010899a0
2
@rbv
2
@rbv
|
@ -1 +1 @@
|
||||||
Subproject commit 1b45fde01e4b313cd65ad9f73598b3453c047227
|
Subproject commit e30741d980c3d40f31590401bcb3c4070bbe8268
|
|
@ -152,7 +152,9 @@ public class UserContextHolder {
|
||||||
* @see #replaceUser(ID)
|
* @see #replaceUser(ID)
|
||||||
*/
|
*/
|
||||||
public static ID getRestoreUser() {
|
public static ID getRestoreUser() {
|
||||||
return CALLER_PREV.get();
|
ID prev = CALLER_PREV.get();
|
||||||
|
if (prev != null) return prev;
|
||||||
|
return getUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --
|
// --
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class DataReportManager implements ConfigManager {
|
||||||
* @param user
|
* @param user
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public JSONArray getReports(Entity entity, int type, ID user) {
|
public JSONArray getReportTemplates(Entity entity, int type, ID user) {
|
||||||
JSONArray alist = new JSONArray();
|
JSONArray alist = new JSONArray();
|
||||||
for (ConfigBean e : getReportsRaw(entity)) {
|
for (ConfigBean e : getReportsRaw(entity)) {
|
||||||
if (e.getBoolean("disabled")) continue;
|
if (e.getBoolean("disabled")) continue;
|
||||||
|
@ -66,7 +66,8 @@ public class DataReportManager implements ConfigManager {
|
||||||
if (type == DataReportManager.TYPE_LIST) {
|
if (type == DataReportManager.TYPE_LIST) {
|
||||||
can = aType == type;
|
can = aType == type;
|
||||||
} else {
|
} else {
|
||||||
can = aType == DataReportManager.TYPE_RECORD || aType == DataReportManager.TYPE_WORD;
|
can = aType == DataReportManager.TYPE_RECORD
|
||||||
|
|| aType == DataReportManager.TYPE_WORD || aType == DataReportManager.TYPE_HTML5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (can) {
|
if (can) {
|
||||||
|
@ -210,10 +211,12 @@ public class DataReportManager implements ConfigManager {
|
||||||
name = ContentWithFieldVars.replaceWithRecord(name, (ID) idOrEntity);
|
name = ContentWithFieldVars.replaceWithRecord(name, (ID) idOrEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// suffix
|
// Suffix
|
||||||
if (fileName.endsWith(".pdf")) name += ".pdf";
|
if (fileName.endsWith(".pdf")) name += ".pdf";
|
||||||
else if (fileName.endsWith(".docx")) name += ".docx";
|
else if (fileName.endsWith(".docx")) name += ".docx";
|
||||||
else name += fileName.endsWith(".xlsx") ? ".xlsx" : ".xls";
|
else if (fileName.endsWith(".doc")) name += ".doc";
|
||||||
|
else if (fileName.endsWith(".xlsx")) name += ".xlsx";
|
||||||
|
else if (fileName.endsWith(".xls")) name += ".xls";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import com.alibaba.excel.EasyExcel;
|
||||||
import com.alibaba.excel.ExcelWriter;
|
import com.alibaba.excel.ExcelWriter;
|
||||||
import com.alibaba.excel.write.metadata.WriteSheet;
|
import com.alibaba.excel.write.metadata.WriteSheet;
|
||||||
import com.alibaba.excel.write.metadata.fill.FillConfig;
|
import com.alibaba.excel.write.metadata.fill.FillConfig;
|
||||||
|
import com.alibaba.excel.write.metadata.fill.FillWrapper;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.rebuild.core.Application;
|
import com.rebuild.core.Application;
|
||||||
|
@ -55,7 +56,6 @@ import java.math.RoundingMode;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -69,6 +69,7 @@ import static com.rebuild.core.service.datareport.TemplateExtractor.PH__CURRENTU
|
||||||
import static com.rebuild.core.service.datareport.TemplateExtractor.PH__KEEP;
|
import static com.rebuild.core.service.datareport.TemplateExtractor.PH__KEEP;
|
||||||
import static com.rebuild.core.service.datareport.TemplateExtractor.PH__NUMBER;
|
import static com.rebuild.core.service.datareport.TemplateExtractor.PH__NUMBER;
|
||||||
import static com.rebuild.core.service.datareport.TemplateExtractor.PLACEHOLDER;
|
import static com.rebuild.core.service.datareport.TemplateExtractor.PLACEHOLDER;
|
||||||
|
import static com.rebuild.core.service.datareport.TemplateExtractor33.NROW_PREFIX2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 报表生成 easyexcel
|
* 报表生成 easyexcel
|
||||||
|
@ -80,11 +81,12 @@ import static com.rebuild.core.service.datareport.TemplateExtractor.PLACEHOLDER;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class EasyExcelGenerator extends SetUser {
|
public class EasyExcelGenerator extends SetUser {
|
||||||
|
|
||||||
|
final protected static String MDATA_KEY = ".";
|
||||||
|
|
||||||
protected File templateFile;
|
protected File templateFile;
|
||||||
protected Integer writeSheetAt = null;
|
protected Integer writeSheetAt = null;
|
||||||
protected ID recordId;
|
protected ID recordId;
|
||||||
|
|
||||||
protected boolean hasMain = false;
|
|
||||||
protected int phNumber = 1;
|
protected int phNumber = 1;
|
||||||
protected Map<String, Object> phValues = new HashMap<>();
|
protected Map<String, Object> phValues = new HashMap<>();
|
||||||
|
|
||||||
|
@ -93,7 +95,7 @@ public class EasyExcelGenerator extends SetUser {
|
||||||
* @param recordId
|
* @param recordId
|
||||||
*/
|
*/
|
||||||
protected EasyExcelGenerator(File template, ID recordId) {
|
protected EasyExcelGenerator(File template, ID recordId) {
|
||||||
this.templateFile = getFixTemplate(template);
|
this.templateFile = template;
|
||||||
this.recordId = recordId;
|
this.recordId = recordId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,14 +107,13 @@ public class EasyExcelGenerator extends SetUser {
|
||||||
public File generate() {
|
public File generate() {
|
||||||
final File target = getTargetFile();
|
final File target = getTargetFile();
|
||||||
|
|
||||||
List<Map<String, Object>> datas = buildData();
|
Map<String, List<Map<String, Object>>> datas = buildData();
|
||||||
if (datas.isEmpty()) throw new DefinedException(Language.L("暂无数据"));
|
if (datas.isEmpty()) throw new DefinedException(Language.L("暂无数据"));
|
||||||
|
|
||||||
Map<String, Object> main = null;
|
Map<String, Object> main = null;
|
||||||
if (this.hasMain) {
|
if (datas.containsKey(MDATA_KEY)) {
|
||||||
Iterator<Map<String, Object>> iter = datas.iterator();
|
main = datas.get(MDATA_KEY).get(0);
|
||||||
main = iter.next();
|
datas.remove(MDATA_KEY);
|
||||||
iter.remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
|
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
|
||||||
|
@ -123,10 +124,29 @@ public class EasyExcelGenerator extends SetUser {
|
||||||
.registerWriteHandler(new FormulaCellWriteHandler())
|
.registerWriteHandler(new FormulaCellWriteHandler())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// 有明细记录
|
// 有引用记录
|
||||||
if (!datas.isEmpty()) {
|
if (datas.size() == 1) {
|
||||||
excelWriter.fill(datas, fillConfig, writeSheet);
|
excelWriter.fill(datas, fillConfig, writeSheet);
|
||||||
}
|
}
|
||||||
|
// fix: v3.6 有多个引用记录
|
||||||
|
else if (datas.size() > 1) {
|
||||||
|
for (Map.Entry<String, List<Map<String, Object>>> e : datas.entrySet()) {
|
||||||
|
final String refKey = NROW_PREFIX2 + e.getKey().substring(1);
|
||||||
|
final List<Map<String, Object>> refDatas = e.getValue();
|
||||||
|
|
||||||
|
List<Map<String, Object>> refDatasNew = new ArrayList<>();
|
||||||
|
for (Map<String, Object> map : refDatas) {
|
||||||
|
Map<String, Object> mapNew = new HashMap<>();
|
||||||
|
for (Map.Entry<String, Object> ee : map.entrySet()) {
|
||||||
|
String keyNew = ee.getKey().substring(refKey.length() + 1);
|
||||||
|
mapNew.put(keyNew, ee.getValue());
|
||||||
|
}
|
||||||
|
refDatasNew.add(mapNew);
|
||||||
|
}
|
||||||
|
|
||||||
|
excelWriter.fill(new FillWrapper(refKey, refDatasNew), fillConfig, writeSheet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 主记录
|
// 主记录
|
||||||
if (main != null) {
|
if (main != null) {
|
||||||
|
@ -153,9 +173,9 @@ public class EasyExcelGenerator extends SetUser {
|
||||||
protected File getTargetFile() {
|
protected File getTargetFile() {
|
||||||
String suffix = "xls";
|
String suffix = "xls";
|
||||||
if (templateFile.getName().endsWith(".xlsx")) suffix = "xlsx";
|
if (templateFile.getName().endsWith(".xlsx")) suffix = "xlsx";
|
||||||
if (templateFile.getName().endsWith(".html")) suffix = "html";
|
else if (templateFile.getName().endsWith(".html")) suffix = "html";
|
||||||
if (templateFile.getName().endsWith(".docx")) suffix = "docx";
|
else if (templateFile.getName().endsWith(".docx")) suffix = "docx";
|
||||||
if (templateFile.getName().endsWith(".doc")) suffix = "doc";
|
else if (templateFile.getName().endsWith(".doc")) suffix = "doc";
|
||||||
|
|
||||||
return RebuildConfiguration.getFileOfTemp(String.format("RBREPORT-%d.%s", System.currentTimeMillis(), suffix));
|
return RebuildConfiguration.getFileOfTemp(String.format("RBREPORT-%d.%s", System.currentTimeMillis(), suffix));
|
||||||
}
|
}
|
||||||
|
@ -165,7 +185,7 @@ public class EasyExcelGenerator extends SetUser {
|
||||||
*
|
*
|
||||||
* @return 第一个为主记录(若有)
|
* @return 第一个为主记录(若有)
|
||||||
*/
|
*/
|
||||||
protected List<Map<String, Object>> buildData() {
|
protected Map<String, List<Map<String, Object>>> buildData() {
|
||||||
Entity entity = MetadataHelper.getEntity(recordId.getEntityCode());
|
Entity entity = MetadataHelper.getEntity(recordId.getEntityCode());
|
||||||
|
|
||||||
TemplateExtractor templateExtractor = new TemplateExtractor(templateFile);
|
TemplateExtractor templateExtractor = new TemplateExtractor(templateFile);
|
||||||
|
@ -213,10 +233,10 @@ public class EasyExcelGenerator extends SetUser {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldsOfMain.isEmpty() && fieldsOfDetail.isEmpty() && fieldsOfApproval.isEmpty()) {
|
if (fieldsOfMain.isEmpty() && fieldsOfDetail.isEmpty() && fieldsOfApproval.isEmpty()) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Map<String, Object>> datas = new ArrayList<>();
|
final Map<String, List<Map<String, Object>>> datas = new HashMap<>();
|
||||||
final String baseSql = "select %s,%s from %s where %s = ?";
|
final String baseSql = "select %s,%s from %s where %s = ?";
|
||||||
|
|
||||||
if (!fieldsOfMain.isEmpty()) {
|
if (!fieldsOfMain.isEmpty()) {
|
||||||
|
@ -229,8 +249,8 @@ public class EasyExcelGenerator extends SetUser {
|
||||||
.record();
|
.record();
|
||||||
Assert.notNull(record, "No record found : " + recordId);
|
Assert.notNull(record, "No record found : " + recordId);
|
||||||
|
|
||||||
datas.add(buildData(record, varsMapOfMain));
|
Map<String, Object> d = buildData(record, varsMapOfMain);
|
||||||
this.hasMain = true;
|
datas.put(MDATA_KEY, Collections.singletonList(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 明细
|
// 明细
|
||||||
|
@ -246,10 +266,12 @@ public class EasyExcelGenerator extends SetUser {
|
||||||
.list();
|
.list();
|
||||||
|
|
||||||
phNumber = 1;
|
phNumber = 1;
|
||||||
|
List<Map<String, Object>> detailList = new ArrayList<>();
|
||||||
for (Record c : list) {
|
for (Record c : list) {
|
||||||
datas.add(buildData(c, varsMapOfDetail));
|
detailList.add(buildData(c, varsMapOfDetail));
|
||||||
phNumber++;
|
phNumber++;
|
||||||
}
|
}
|
||||||
|
datas.put(MDATA_KEY + "detail", detailList);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 审批
|
// 审批
|
||||||
|
@ -263,10 +285,12 @@ public class EasyExcelGenerator extends SetUser {
|
||||||
.list();
|
.list();
|
||||||
|
|
||||||
phNumber = 1;
|
phNumber = 1;
|
||||||
|
List<Map<String, Object>> approvalList = new ArrayList<>();
|
||||||
for (Record c : list) {
|
for (Record c : list) {
|
||||||
datas.add(buildData(c, varsMapOfApproval));
|
approvalList.add(buildData(c, varsMapOfApproval));
|
||||||
phNumber++;
|
phNumber++;
|
||||||
}
|
}
|
||||||
|
datas.put(MDATA_KEY + "approval", approvalList);
|
||||||
}
|
}
|
||||||
|
|
||||||
return datas;
|
return datas;
|
||||||
|
@ -465,62 +489,6 @@ public class EasyExcelGenerator extends SetUser {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修复模板
|
|
||||||
private File getFixTemplate(File template) {
|
|
||||||
return template;
|
|
||||||
|
|
||||||
// v34 暂不启用
|
|
||||||
// String fixName = template.getName();
|
|
||||||
// fixName = fixName.substring(0, fixName.lastIndexOf(".")) + "__FIX34" + fixName.substring(fixName.lastIndexOf("."));
|
|
||||||
// File fixTemplate = new File(template.getParent(), fixName);
|
|
||||||
// if (fixTemplate.exists()) return fixTemplate;
|
|
||||||
//
|
|
||||||
// // Use copy
|
|
||||||
// try {
|
|
||||||
// FileUtils.copyFile(template, fixTemplate);
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// throw new ReportsException(e);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // 替换 `.` > `$`
|
|
||||||
// try (Workbook wb = WorkbookFactory.create(Files.newInputStream(template.toPath()))) {
|
|
||||||
// Sheet sheet = wb.getSheetAt(0);
|
|
||||||
// for (Iterator<Row> iterRow = sheet.rowIterator(); iterRow.hasNext(); ) {
|
|
||||||
// final Row row = iterRow.next();
|
|
||||||
//
|
|
||||||
// for (Iterator<Cell> iterCell = row.cellIterator(); iterCell.hasNext(); ) {
|
|
||||||
// final Cell cell = iterCell.next();
|
|
||||||
// final String cellValue = cell.getStringCellValue();
|
|
||||||
//
|
|
||||||
// String newCellValue = cellValue;
|
|
||||||
// Matcher matcher = TemplateExtractor.PATT_V2.matcher(cellValue);
|
|
||||||
// while (matcher.find()) {
|
|
||||||
// String varName = matcher.group(1);
|
|
||||||
// if (varName.contains(".") && !varName.startsWith(".")) {
|
|
||||||
// newCellValue = newCellValue.replace(".", "$");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (!cellValue.equals(newCellValue)) {
|
|
||||||
// log.info("Replace `{}` to `{}` in : {}", cellValue, newCellValue, template);
|
|
||||||
// cell.setCellValue(newCellValue);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// try (FileOutputStream fos = new FileOutputStream(fixTemplate)) {
|
|
||||||
// wb.write(fos);
|
|
||||||
// }
|
|
||||||
// } catch (IOException ex) {
|
|
||||||
// log.error("Cannot fix template : {}", template, ex);
|
|
||||||
//
|
|
||||||
// FileUtils.deleteQuietly(fixTemplate);
|
|
||||||
// return template;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return fixTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --
|
// --
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -41,7 +41,10 @@ import java.util.Map;
|
||||||
|
|
||||||
import static com.rebuild.core.service.datareport.TemplateExtractor.APPROVAL_PREFIX;
|
import static com.rebuild.core.service.datareport.TemplateExtractor.APPROVAL_PREFIX;
|
||||||
import static com.rebuild.core.service.datareport.TemplateExtractor.NROW_PREFIX;
|
import static com.rebuild.core.service.datareport.TemplateExtractor.NROW_PREFIX;
|
||||||
|
import static com.rebuild.core.service.datareport.TemplateExtractor33.APPROVAL_PREFIX2;
|
||||||
import static com.rebuild.core.service.datareport.TemplateExtractor33.DETAIL_PREFIX;
|
import static com.rebuild.core.service.datareport.TemplateExtractor33.DETAIL_PREFIX;
|
||||||
|
import static com.rebuild.core.service.datareport.TemplateExtractor33.DETAIL_PREFIX2;
|
||||||
|
import static com.rebuild.core.service.datareport.TemplateExtractor33.NROW_PREFIX2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* V33
|
* V33
|
||||||
|
@ -65,7 +68,7 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<Map<String, Object>> buildData() {
|
protected Map<String, List<Map<String, Object>>> buildData() {
|
||||||
final Entity entity = MetadataHelper.getEntity(recordId.getEntityCode());
|
final Entity entity = MetadataHelper.getEntity(recordId.getEntityCode());
|
||||||
|
|
||||||
final TemplateExtractor33 templateExtractor33 = this.buildTemplateExtractor33();
|
final TemplateExtractor33 templateExtractor33 = this.buildTemplateExtractor33();
|
||||||
|
@ -82,25 +85,25 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
||||||
final String varName = e.getKey();
|
final String varName = e.getKey();
|
||||||
final String fieldName = e.getValue();
|
final String fieldName = e.getValue();
|
||||||
|
|
||||||
String refName = null;
|
String refKey = null;
|
||||||
if (varName.startsWith(NROW_PREFIX)) {
|
if (varName.startsWith(NROW_PREFIX) || varName.startsWith(NROW_PREFIX2)) {
|
||||||
if (varName.startsWith(APPROVAL_PREFIX)) {
|
if (varName.startsWith(APPROVAL_PREFIX) || varName.startsWith(APPROVAL_PREFIX2)) {
|
||||||
refName = APPROVAL_PREFIX;
|
refKey = APPROVAL_PREFIX;
|
||||||
} else if (varName.startsWith(DETAIL_PREFIX)) {
|
} else if (varName.startsWith(DETAIL_PREFIX) || varName.startsWith(DETAIL_PREFIX2)) {
|
||||||
refName = DETAIL_PREFIX;
|
refKey = DETAIL_PREFIX;
|
||||||
} else {
|
} else {
|
||||||
// 在客户中导出订单(下列 AccountId 为订单中引用客户的引用字段)
|
// 在客户中导出订单(下列 AccountId 为订单中引用客户的引用字段)
|
||||||
// .AccountId.SalesOrder.SalesOrderName
|
// .AccountId.SalesOrder.SalesOrderName or $AccountId$SalesOrder$SalesOrderName
|
||||||
String[] split = varName.substring(1).split("\\.");
|
String[] split = varName.substring(1).split("[.$]");
|
||||||
if (split.length < 2) throw new ReportsException("Bad REF (Miss .detail prefix?) : " + varName);
|
if (split.length < 2) throw new ReportsException("Bad REF (Miss .detail prefix?) : " + varName);
|
||||||
|
|
||||||
String refName2 = split[0] + split[1];
|
String refName2 = split[0] + split[1];
|
||||||
refName = varName.substring(0, refName2.length() + 2 /* dots */);
|
refKey = varName.substring(0, refName2.length() + 2 /* dots */);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> varsMapOfRef = varsMapOfRefs.getOrDefault(refName, new HashMap<>());
|
Map<String, String> varsMapOfRef = varsMapOfRefs.getOrDefault(refKey, new HashMap<>());
|
||||||
varsMapOfRef.put(varName, fieldName);
|
varsMapOfRef.put(varName, fieldName);
|
||||||
varsMapOfRefs.put(refName, varsMapOfRef);
|
varsMapOfRefs.put(refKey, varsMapOfRef);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
varsMapOfMain.put(varName, fieldName);
|
varsMapOfMain.put(varName, fieldName);
|
||||||
|
@ -114,22 +117,23 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (varName.startsWith(NROW_PREFIX)) {
|
if (varName.startsWith(NROW_PREFIX) || varName.startsWith(NROW_PREFIX2)) {
|
||||||
List<String> fieldsOfRef = fieldsOfRefs.getOrDefault(refName, new ArrayList<>());
|
List<String> fieldsOfRef = fieldsOfRefs.getOrDefault(refKey, new ArrayList<>());
|
||||||
fieldsOfRef.add(fieldName);
|
fieldsOfRef.add(fieldName);
|
||||||
fieldsOfRefs.put(refName, fieldsOfRef);
|
fieldsOfRefs.put(refKey, fieldsOfRef);
|
||||||
} else {
|
} else {
|
||||||
fieldsOfMain.add(fieldName);
|
fieldsOfMain.add(fieldName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldsOfMain.isEmpty() && fieldsOfRefs.isEmpty()) {
|
if (fieldsOfMain.isEmpty() && fieldsOfRefs.isEmpty()) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Map<String, Object>> datas = new ArrayList<>();
|
final Map<String, List<Map<String, Object>>> datas = new HashMap<>();
|
||||||
final String baseSql = "select %s,%s from %s where %s = ?";
|
final String baseSql = "select %s,%s from %s where %s = ?";
|
||||||
|
|
||||||
|
// 主记录
|
||||||
if (!fieldsOfMain.isEmpty()) {
|
if (!fieldsOfMain.isEmpty()) {
|
||||||
String sql = String.format(baseSql,
|
String sql = String.format(baseSql,
|
||||||
StringUtils.join(fieldsOfMain, ","),
|
StringUtils.join(fieldsOfMain, ","),
|
||||||
|
@ -140,13 +144,14 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
||||||
.record();
|
.record();
|
||||||
Assert.notNull(record, "No record found : " + recordId);
|
Assert.notNull(record, "No record found : " + recordId);
|
||||||
|
|
||||||
this.hasMain = true;
|
Map<String, Object> d = buildData(record, varsMapOfMain);
|
||||||
datas.add(buildData(record, varsMapOfMain));
|
datas.put(MDATA_KEY, Collections.singletonList(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 相关记录(含明细、审批)
|
||||||
for (Map.Entry<String, List<String>> e : fieldsOfRefs.entrySet()) {
|
for (Map.Entry<String, List<String>> e : fieldsOfRefs.entrySet()) {
|
||||||
final String refName = e.getKey();
|
final String refKey = e.getKey();
|
||||||
final boolean isApproval = refName.startsWith(APPROVAL_PREFIX);
|
final boolean isApproval = refKey.startsWith(APPROVAL_PREFIX);
|
||||||
|
|
||||||
String querySql = baseSql;
|
String querySql = baseSql;
|
||||||
if (isApproval) {
|
if (isApproval) {
|
||||||
|
@ -154,7 +159,7 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
||||||
querySql = String.format(querySql, StringUtils.join(e.getValue(), ","),
|
querySql = String.format(querySql, StringUtils.join(e.getValue(), ","),
|
||||||
"createdOn,recordId,state,stepId", "RobotApprovalStep", "recordId");
|
"createdOn,recordId,state,stepId", "RobotApprovalStep", "recordId");
|
||||||
|
|
||||||
} else if (refName.startsWith(DETAIL_PREFIX)) {
|
} else if (refKey.startsWith(DETAIL_PREFIX)) {
|
||||||
Entity de = entity.getDetailEntity();
|
Entity de = entity.getDetailEntity();
|
||||||
|
|
||||||
String sortField = templateExtractor33.getSortField(DETAIL_PREFIX);
|
String sortField = templateExtractor33.getSortField(DETAIL_PREFIX);
|
||||||
|
@ -164,11 +169,11 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
||||||
de.getPrimaryField().getName(), de.getName(), MetadataHelper.getDetailToMainField(de).getName());
|
de.getPrimaryField().getName(), de.getName(), MetadataHelper.getDetailToMainField(de).getName());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
String[] split = refName.substring(1).split("\\.");
|
String[] split = refKey.substring(1).split("[.$]");
|
||||||
Field ref2Field = MetadataHelper.getField(split[1], split[0]);
|
Field ref2Field = MetadataHelper.getField(split[1], split[0]);
|
||||||
Entity ref2Entity = ref2Field.getOwnEntity();
|
Entity ref2Entity = ref2Field.getOwnEntity();
|
||||||
|
|
||||||
String sortField = templateExtractor33.getSortField(refName);
|
String sortField = templateExtractor33.getSortField(refKey);
|
||||||
querySql += " order by " + StringUtils.defaultIfBlank(sortField, "createdOn asc");
|
querySql += " order by " + StringUtils.defaultIfBlank(sortField, "createdOn asc");
|
||||||
|
|
||||||
String relatedExpr = split[1] + "." + split[0];
|
String relatedExpr = split[1] + "." + split[0];
|
||||||
|
@ -193,13 +198,14 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
||||||
.add("state", 0)
|
.add("state", 0)
|
||||||
.build(UserService.SYSTEM_USER);
|
.build(UserService.SYSTEM_USER);
|
||||||
|
|
||||||
List<Record> list2 = new ArrayList<>();
|
List<Record> listReplace = new ArrayList<>();
|
||||||
list2.add(submit);
|
listReplace.add(submit);
|
||||||
list2.addAll(list);
|
listReplace.addAll(list);
|
||||||
list = list2;
|
list = listReplace;
|
||||||
}
|
}
|
||||||
|
|
||||||
phNumber = 1;
|
phNumber = 1;
|
||||||
|
List<Map<String, Object>> refDatas = new ArrayList<>();
|
||||||
for (Record c : list) {
|
for (Record c : list) {
|
||||||
// 特殊处理
|
// 特殊处理
|
||||||
if (isApproval) {
|
if (isApproval) {
|
||||||
|
@ -207,10 +213,10 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
||||||
Date approvedTime = c.getDate("approvedTime");
|
Date approvedTime = c.getDate("approvedTime");
|
||||||
if (approvedTime == null && state > 1) c.setDate("approvedTime", c.getDate("createdOn"));
|
if (approvedTime == null && state > 1) c.setDate("approvedTime", c.getDate("createdOn"));
|
||||||
}
|
}
|
||||||
|
refDatas.add(buildData(c, varsMapOfRefs.get(refKey)));
|
||||||
datas.add(buildData(c, varsMapOfRefs.get(refName)));
|
|
||||||
phNumber++;
|
phNumber++;
|
||||||
}
|
}
|
||||||
|
datas.put(refKey, refDatas);
|
||||||
}
|
}
|
||||||
|
|
||||||
return datas;
|
return datas;
|
||||||
|
@ -273,7 +279,6 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
||||||
this.templateFile = targetFile;
|
this.templateFile = targetFile;
|
||||||
this.writeSheetAt = newSheetAt;
|
this.writeSheetAt = newSheetAt;
|
||||||
this.recordId = recordId;
|
this.recordId = recordId;
|
||||||
this.hasMain = false;
|
|
||||||
this.phNumber = 1;
|
this.phNumber = 1;
|
||||||
this.phValues.clear();
|
this.phValues.clear();
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class EasyExcelListGenerator extends EasyExcelGenerator {
|
||||||
* @see DataListBuilderImpl#getJSONResult()
|
* @see DataListBuilderImpl#getJSONResult()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected List<Map<String, Object>> buildData() {
|
protected Map<String, List<Map<String, Object>>> buildData() {
|
||||||
Entity entity = MetadataHelper.getEntity(queryData.getString("entity"));
|
Entity entity = MetadataHelper.getEntity(queryData.getString("entity"));
|
||||||
TemplateExtractor varsExtractor = new TemplateExtractor(templateFile, Boolean.TRUE);
|
TemplateExtractor varsExtractor = new TemplateExtractor(templateFile, Boolean.TRUE);
|
||||||
Map<String, String> varsMap = varsExtractor.transformVars(entity);
|
Map<String, String> varsMap = varsExtractor.transformVars(entity);
|
||||||
|
@ -72,7 +72,7 @@ public class EasyExcelListGenerator extends EasyExcelGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validFields.isEmpty()) return Collections.emptyList();
|
if (validFields.isEmpty()) return Collections.emptyMap();
|
||||||
|
|
||||||
queryData.put("fields", validFields); // 使用模板字段
|
queryData.put("fields", validFields); // 使用模板字段
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ public class EasyExcelListGenerator extends EasyExcelGenerator {
|
||||||
if (varsMap.containsKey(PH__CURRENTDATE)) phValues.put(PH__CURRENTDATE, getPhValue(PH__CURRENTDATE));
|
if (varsMap.containsKey(PH__CURRENTDATE)) phValues.put(PH__CURRENTDATE, getPhValue(PH__CURRENTDATE));
|
||||||
if (varsMap.containsKey(PH__CURRENTDATETIME)) phValues.put(PH__CURRENTDATETIME, getPhValue(PH__CURRENTDATETIME));
|
if (varsMap.containsKey(PH__CURRENTDATETIME)) phValues.put(PH__CURRENTDATETIME, getPhValue(PH__CURRENTDATETIME));
|
||||||
|
|
||||||
return datas;
|
return Collections.singletonMap(MDATA_KEY, datas);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getExportCount() {
|
public int getExportCount() {
|
||||||
|
|
|
@ -20,7 +20,7 @@ import org.apache.commons.lang.StringUtils;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -38,7 +38,7 @@ public class TemplateExtractor {
|
||||||
// 列表(即多条记录)
|
// 列表(即多条记录)
|
||||||
public static final String NROW_PREFIX = ".";
|
public static final String NROW_PREFIX = ".";
|
||||||
// 审批节点字段
|
// 审批节点字段
|
||||||
protected static final String APPROVAL_PREFIX = NROW_PREFIX + "approval";
|
public static final String APPROVAL_PREFIX = NROW_PREFIX + "approval";
|
||||||
|
|
||||||
// 占位
|
// 占位
|
||||||
public static final String PLACEHOLDER = "__";
|
public static final String PLACEHOLDER = "__";
|
||||||
|
@ -137,7 +137,7 @@ public class TemplateExtractor {
|
||||||
protected Set<String> extractVars() {
|
protected Set<String> extractVars() {
|
||||||
List<Cell[]> rows = ExcelUtils.readExcel(templateFile);
|
List<Cell[]> rows = ExcelUtils.readExcel(templateFile);
|
||||||
|
|
||||||
Set<String> vars = new HashSet<>();
|
Set<String> vars = new LinkedHashSet<>();
|
||||||
for (Cell[] row : rows) {
|
for (Cell[] row : rows) {
|
||||||
for (Cell cell : row) {
|
for (Cell cell : row) {
|
||||||
if (cell.isEmpty()) continue;
|
if (cell.isEmpty()) continue;
|
||||||
|
|
|
@ -26,7 +26,11 @@ import java.util.Set;
|
||||||
public class TemplateExtractor33 extends TemplateExtractor {
|
public class TemplateExtractor33 extends TemplateExtractor {
|
||||||
|
|
||||||
// 明细字段
|
// 明细字段
|
||||||
protected static final String DETAIL_PREFIX = NROW_PREFIX + "detail";
|
public static final String DETAIL_PREFIX = NROW_PREFIX + "detail";
|
||||||
|
// $
|
||||||
|
public static final String NROW_PREFIX2 = "$";
|
||||||
|
public static final String DETAIL_PREFIX2 = NROW_PREFIX2 + "detail";
|
||||||
|
public static final String APPROVAL_PREFIX2 = NROW_PREFIX2 + "approval";
|
||||||
|
|
||||||
// 排序
|
// 排序
|
||||||
private static final String SORT_ASC = ":asc";
|
private static final String SORT_ASC = ":asc";
|
||||||
|
@ -56,14 +60,15 @@ public class TemplateExtractor33 extends TemplateExtractor {
|
||||||
Map<String, String> map = new HashMap<>();
|
Map<String, String> map = new HashMap<>();
|
||||||
for (final String varName : vars) {
|
for (final String varName : vars) {
|
||||||
// 列表型字段
|
// 列表型字段
|
||||||
if (varName.startsWith(NROW_PREFIX)) {
|
if (varName.startsWith(NROW_PREFIX) || varName.startsWith(NROW_PREFIX2)) {
|
||||||
final String listField = varName.substring(1).replace("$", ".");
|
final String listField = varName.substring(1).replace("$", ".");
|
||||||
|
|
||||||
|
// 占位
|
||||||
if (isPlaceholder(listField)) {
|
if (isPlaceholder(listField)) {
|
||||||
map.put(varName, null);
|
map.put(varName, null);
|
||||||
}
|
}
|
||||||
// 审批流程
|
// 审批流程
|
||||||
else if (varName.startsWith(APPROVAL_PREFIX)) {
|
else if (varName.startsWith(APPROVAL_PREFIX) || varName.startsWith(APPROVAL_PREFIX2)) {
|
||||||
String stepNodeField = listField.substring(APPROVAL_PREFIX.length());
|
String stepNodeField = listField.substring(APPROVAL_PREFIX.length());
|
||||||
if (approvalEntity != null && MetadataHelper.getLastJoinField(approvalEntity, stepNodeField) != null) {
|
if (approvalEntity != null && MetadataHelper.getLastJoinField(approvalEntity, stepNodeField) != null) {
|
||||||
map.put(varName, stepNodeField);
|
map.put(varName, stepNodeField);
|
||||||
|
@ -72,7 +77,7 @@ public class TemplateExtractor33 extends TemplateExtractor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 明细实体
|
// 明细实体
|
||||||
else if (varName.startsWith(DETAIL_PREFIX)) {
|
else if (varName.startsWith(DETAIL_PREFIX) || varName.startsWith(DETAIL_PREFIX2)) {
|
||||||
String detailField = listField.substring(DETAIL_PREFIX.length());
|
String detailField = listField.substring(DETAIL_PREFIX.length());
|
||||||
detailField = getFieldNameWithSort(DETAIL_PREFIX, detailField);
|
detailField = getFieldNameWithSort(DETAIL_PREFIX, detailField);
|
||||||
|
|
||||||
|
@ -124,6 +129,7 @@ public class TemplateExtractor33 extends TemplateExtractor {
|
||||||
hasSort = varFieldName + " desc";
|
hasSort = varFieldName + " desc";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 有多个字段排序的,其排序顺序取决于字段出现在模板中的位置
|
||||||
if (hasSort != null) {
|
if (hasSort != null) {
|
||||||
String useSorts = sortFields.get(refName);
|
String useSorts = sortFields.get(refName);
|
||||||
if (useSorts != null) useSorts += "," + hasSort;
|
if (useSorts != null) useSorts += "," + hasSort;
|
||||||
|
@ -151,6 +157,8 @@ public class TemplateExtractor33 extends TemplateExtractor {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static boolean isPlaceholder(String varName) {
|
public static boolean isPlaceholder(String varName) {
|
||||||
return varName.startsWith(PLACEHOLDER) || varName.contains(NROW_PREFIX + PLACEHOLDER);
|
return varName.startsWith(PLACEHOLDER)
|
||||||
|
|| varName.contains(NROW_PREFIX + PLACEHOLDER)
|
||||||
|
|| varName.contains(NROW_PREFIX2 + PLACEHOLDER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,12 +100,14 @@ public enum ConfigurationItem {
|
||||||
DingtalkSyncUsers(false),
|
DingtalkSyncUsers(false),
|
||||||
DingtalkSyncUsersRole,
|
DingtalkSyncUsersRole,
|
||||||
DingtalkRobotCode,
|
DingtalkRobotCode,
|
||||||
|
DingtalkSyncUsersMatch("ID"),
|
||||||
// WxWork
|
// WxWork
|
||||||
WxworkCorpid, WxworkAgentid, WxworkSecret,
|
WxworkCorpid, WxworkAgentid, WxworkSecret,
|
||||||
WxworkRxToken, WxworkRxEncodingAESKey,
|
WxworkRxToken, WxworkRxEncodingAESKey,
|
||||||
WxworkAuthFile,
|
WxworkAuthFile,
|
||||||
WxworkSyncUsers(false),
|
WxworkSyncUsers(false),
|
||||||
WxworkSyncUsersRole,
|
WxworkSyncUsersRole,
|
||||||
|
WxworkSyncUsersMatch("ID"),
|
||||||
|
|
||||||
// PORTALs
|
// PORTALs
|
||||||
PortalBaiduMapAk,
|
PortalBaiduMapAk,
|
||||||
|
|
|
@ -223,17 +223,16 @@ public class QueryParser {
|
||||||
|
|
||||||
// 排序
|
// 排序
|
||||||
|
|
||||||
StringBuilder sqlSort = new StringBuilder(" order by ");
|
|
||||||
|
|
||||||
String sortNode = queryExpr.getString("sort");
|
String sortNode = queryExpr.getString("sort");
|
||||||
|
String sortSql = null;
|
||||||
if (StringUtils.isNotBlank(sortNode)) {
|
if (StringUtils.isNotBlank(sortNode)) {
|
||||||
sqlSort.append(StringUtils.defaultString(parseSort(sortNode), ""));
|
sortSql = parseSort(sortNode);
|
||||||
} else if (entity.containsField(EntityHelper.ModifiedOn)) {
|
} else if (entity.containsField(EntityHelper.ModifiedOn)) {
|
||||||
sqlSort.append(EntityHelper.ModifiedOn + " desc");
|
sortSql = EntityHelper.ModifiedOn + " desc";
|
||||||
} else if (entity.containsField(EntityHelper.CreatedOn)) {
|
} else if (entity.containsField(EntityHelper.CreatedOn)) {
|
||||||
sqlSort.append(EntityHelper.CreatedOn + " desc");
|
sortSql = EntityHelper.CreatedOn + " desc";
|
||||||
}
|
}
|
||||||
if (sqlSort.length() >= 14) fullSql.append(sqlSort);
|
if (StringUtils.isNotBlank(sortSql)) fullSql.append(" order by ").append(sortSql);
|
||||||
|
|
||||||
this.sql = fullSql.toString();
|
this.sql = fullSql.toString();
|
||||||
this.countSql = this.buildCountSql(pkName) + sqlWhere;
|
this.countSql = this.buildCountSql(pkName) + sqlWhere;
|
||||||
|
|
|
@ -37,6 +37,7 @@ import com.rebuild.web.EntityParam;
|
||||||
import com.rebuild.web.IdParam;
|
import com.rebuild.web.IdParam;
|
||||||
import com.rebuild.web.admin.ConfigCommons;
|
import com.rebuild.web.admin.ConfigCommons;
|
||||||
import com.rebuild.web.commons.FileDownloader;
|
import com.rebuild.web.commons.FileDownloader;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
@ -47,6 +48,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -164,7 +166,7 @@ public class ReportTemplateController extends BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/report-templates/preview")
|
@GetMapping("/report-templates/preview")
|
||||||
public void preview(@IdParam(required = false) ID reportId,
|
public ModelAndView preview(@IdParam(required = false) ID reportId,
|
||||||
HttpServletRequest request, HttpServletResponse response) throws IOException {
|
HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
final TemplateFile tt;
|
final TemplateFile tt;
|
||||||
// 新建时
|
// 新建时
|
||||||
|
@ -183,7 +185,7 @@ public class ReportTemplateController extends BaseController {
|
||||||
Object[] random = Application.createQueryNoFilter(sql).unique();
|
Object[] random = Application.createQueryNoFilter(sql).unique();
|
||||||
if (random == null) {
|
if (random == null) {
|
||||||
response.sendError(400, Language.L("未找到可供预览的记录"));
|
response.sendError(400, Language.L("未找到可供预览的记录"));
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
File output;
|
File output;
|
||||||
|
@ -201,6 +203,12 @@ public class ReportTemplateController extends BaseController {
|
||||||
"com.rebuild.rbv.data.WordReportGenerator#create", tt.templateFile, random[0]);
|
"com.rebuild.rbv.data.WordReportGenerator#create", tt.templateFile, random[0]);
|
||||||
output = word.generate();
|
output = word.generate();
|
||||||
}
|
}
|
||||||
|
// HTML5
|
||||||
|
else if (tt.type == DataReportManager.TYPE_HTML5) {
|
||||||
|
EasyExcelGenerator33 html5 = (EasyExcelGenerator33) CommonsUtils.invokeMethod(
|
||||||
|
"com.rebuild.rbv.data.Html5ReportGenerator#create", tt.templateContent, random[0]);
|
||||||
|
output = html5.generate();
|
||||||
|
}
|
||||||
// EXCEL
|
// EXCEL
|
||||||
else {
|
else {
|
||||||
output = EasyExcelGenerator.create(tt.templateFile, (ID) random[0], tt.isV33).generate();
|
output = EasyExcelGenerator.create(tt.templateFile, (ID) random[0], tt.isV33).generate();
|
||||||
|
@ -208,13 +216,19 @@ public class ReportTemplateController extends BaseController {
|
||||||
|
|
||||||
} catch (ConfigurationException ex) {
|
} catch (ConfigurationException ex) {
|
||||||
response.sendError(500, ex.getLocalizedMessage());
|
response.sendError(500, ex.getLocalizedMessage());
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
RbAssert.is(output != null, Language.L("无法输出报表,请检查报表模板是否有误"));
|
RbAssert.is(output != null, Language.L("无法输出报表,请检查报表模板是否有误"));
|
||||||
|
|
||||||
String attname = "RBREPORT-PREVIEW." + FileNameUtil.getSuffix(output);
|
String attname = "RBREPORT-PREVIEW";
|
||||||
|
|
||||||
|
// v3.6
|
||||||
|
if (tt.type == DataReportManager.TYPE_HTML5) {
|
||||||
|
return buildHtml5ModelAndView(output, attname);
|
||||||
|
}
|
||||||
|
|
||||||
|
attname += "." + FileNameUtil.getSuffix(output);
|
||||||
String typeOutput = getParameter(request, "output");
|
String typeOutput = getParameter(request, "output");
|
||||||
if (PdfConverter.TYPE_PDF.equalsIgnoreCase(typeOutput) || PdfConverter.TYPE_HTML.equalsIgnoreCase(typeOutput)) {
|
if (PdfConverter.TYPE_PDF.equalsIgnoreCase(typeOutput) || PdfConverter.TYPE_HTML.equalsIgnoreCase(typeOutput)) {
|
||||||
output = PdfConverter.convert(output.toPath(), typeOutput).toFile();
|
output = PdfConverter.convert(output.toPath(), typeOutput).toFile();
|
||||||
|
@ -222,6 +236,7 @@ public class ReportTemplateController extends BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDownloader.downloadTempFile(response, output, attname);
|
FileDownloader.downloadTempFile(response, output, attname);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/report-templates/download")
|
@GetMapping("/report-templates/download")
|
||||||
|
@ -232,4 +247,18 @@ public class ReportTemplateController extends BaseController {
|
||||||
FileDownloader.setDownloadHeaders(request, response, attname, false);
|
FileDownloader.setDownloadHeaders(request, response, attname, false);
|
||||||
FileDownloader.writeLocalFile(template, response);
|
FileDownloader.writeLocalFile(template, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param html5
|
||||||
|
* @param title
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static ModelAndView buildHtml5ModelAndView(File html5, String title) throws IOException {
|
||||||
|
String content = FileUtils.readFileToString(html5, StandardCharsets.UTF_8);
|
||||||
|
ModelAndView mv = new ModelAndView("/admin/data/template5-view");
|
||||||
|
mv.getModelMap().put("reportName", title);
|
||||||
|
mv.getModelMap().put("reportContent", content);
|
||||||
|
return mv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,19 +40,21 @@ import com.rebuild.utils.PdfConverter;
|
||||||
import com.rebuild.utils.RbAssert;
|
import com.rebuild.utils.RbAssert;
|
||||||
import com.rebuild.web.BaseController;
|
import com.rebuild.web.BaseController;
|
||||||
import com.rebuild.web.IdParam;
|
import com.rebuild.web.IdParam;
|
||||||
|
import com.rebuild.web.admin.data.ReportTemplateController;
|
||||||
import com.rebuild.web.commons.FileDownloader;
|
import com.rebuild.web.commons.FileDownloader;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 报表/导出
|
* 报表/导出
|
||||||
|
@ -67,10 +69,10 @@ public class ReportsController extends BaseController {
|
||||||
|
|
||||||
// 报表模板
|
// 报表模板
|
||||||
|
|
||||||
@RequestMapping("report/available")
|
@GetMapping("report/available")
|
||||||
public JSON availableReports(@PathVariable String entity, HttpServletRequest request) {
|
public JSON availableReports(@PathVariable String entity, HttpServletRequest request) {
|
||||||
final ID user = getRequestUser(request);
|
final ID user = getRequestUser(request);
|
||||||
JSONArray res = DataReportManager.instance.getReports(
|
JSONArray res = DataReportManager.instance.getReportTemplates(
|
||||||
MetadataHelper.getEntity(entity),
|
MetadataHelper.getEntity(entity),
|
||||||
getIntParameter(request, "type", DataReportManager.TYPE_RECORD), user);
|
getIntParameter(request, "type", DataReportManager.TYPE_RECORD), user);
|
||||||
|
|
||||||
|
@ -84,16 +86,11 @@ public class ReportsController extends BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping({"report/generate", "report/export"})
|
@RequestMapping({"report/generate", "report/export"})
|
||||||
public void reportGenerate(@PathVariable String entity,
|
public ModelAndView reportGenerate(@PathVariable String entity,
|
||||||
@IdParam(name = "report") ID reportId,
|
@IdParam(name = "report") ID reportId,
|
||||||
HttpServletRequest request, HttpServletResponse response) throws IOException {
|
HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
String record = getParameterNotNull(request, "record");
|
final ID[] recordIds = getIdArrayParameterNotNull(request, "record");
|
||||||
List<ID> recordIds = new ArrayList<>();
|
final ID recordId = recordIds[0];
|
||||||
for (String id : record.split(",")) {
|
|
||||||
if (ID.isId(id)) recordIds.add(ID.valueOf(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
final ID recordId = recordIds.get(0);
|
|
||||||
final TemplateFile tt = DataReportManager.instance.getTemplateFile(reportId);
|
final TemplateFile tt = DataReportManager.instance.getTemplateFile(reportId);
|
||||||
|
|
||||||
File output = null;
|
File output = null;
|
||||||
|
@ -102,9 +99,15 @@ public class ReportsController extends BaseController {
|
||||||
EasyExcelGenerator33 word = (EasyExcelGenerator33) CommonsUtils.invokeMethod(
|
EasyExcelGenerator33 word = (EasyExcelGenerator33) CommonsUtils.invokeMethod(
|
||||||
"com.rebuild.rbv.data.WordReportGenerator#create", reportId, recordId);
|
"com.rebuild.rbv.data.WordReportGenerator#create", reportId, recordId);
|
||||||
output = word.generate();
|
output = word.generate();
|
||||||
|
|
||||||
|
} else if (tt.type == DataReportManager.TYPE_HTML5) {
|
||||||
|
EasyExcelGenerator33 html5 = (EasyExcelGenerator33) CommonsUtils.invokeMethod(
|
||||||
|
"com.rebuild.rbv.data.Html5ReportGenerator#create", reportId, recordId);
|
||||||
|
output = html5.generate();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// 支持多个
|
// 支持多个
|
||||||
output = EasyExcelGenerator.create(reportId, recordIds).generate();
|
output = EasyExcelGenerator.create(reportId, Arrays.asList(recordIds)).generate();
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (ExcelRuntimeException ex) {
|
} catch (ExcelRuntimeException ex) {
|
||||||
|
@ -113,6 +116,13 @@ public class ReportsController extends BaseController {
|
||||||
|
|
||||||
RbAssert.is(output != null, Language.L("无法输出报表,请检查报表模板是否有误"));
|
RbAssert.is(output != null, Language.L("无法输出报表,请检查报表模板是否有误"));
|
||||||
|
|
||||||
|
String fileName = DataReportManager.getReportName(reportId, recordId, output.getName());
|
||||||
|
|
||||||
|
// v3.6
|
||||||
|
if (tt.type == DataReportManager.TYPE_HTML5) {
|
||||||
|
return ReportTemplateController.buildHtml5ModelAndView(output, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
final String typeOutput = getParameter(request, "output");
|
final String typeOutput = getParameter(request, "output");
|
||||||
final boolean isHtml = "HTML".equalsIgnoreCase(typeOutput);
|
final boolean isHtml = "HTML".equalsIgnoreCase(typeOutput);
|
||||||
final boolean isPdf = "PDF".equalsIgnoreCase(typeOutput);
|
final boolean isPdf = "PDF".equalsIgnoreCase(typeOutput);
|
||||||
|
@ -122,8 +132,6 @@ public class ReportsController extends BaseController {
|
||||||
output = PdfConverter.convertHtml(output.toPath()).toFile();
|
output = PdfConverter.convertHtml(output.toPath()).toFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
final String fileName = DataReportManager.getReportName(reportId, recordId, output.getName());
|
|
||||||
|
|
||||||
if (ServletUtils.isAjaxRequest(request)) {
|
if (ServletUtils.isAjaxRequest(request)) {
|
||||||
JSONObject data = JSONUtils.toJSONObject(
|
JSONObject data = JSONUtils.toJSONObject(
|
||||||
new String[] { "fileKey", "fileName" }, new Object[] { output.getName(), fileName });
|
new String[] { "fileKey", "fileName" }, new Object[] { output.getName(), fileName });
|
||||||
|
@ -153,6 +161,7 @@ public class ReportsController extends BaseController {
|
||||||
boolean forcePreview = isHtml || isPdf || getBoolParameter(request, "preview");
|
boolean forcePreview = isHtml || isPdf || getBoolParameter(request, "preview");
|
||||||
FileDownloader.downloadTempFile(response, output, forcePreview ? FileDownloader.INLINE_FORCE : fileName);
|
FileDownloader.downloadTempFile(response, output, forcePreview ? FileDownloader.INLINE_FORCE : fileName);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 列表数据导出
|
// 列表数据导出
|
||||||
|
|
|
@ -454,7 +454,6 @@
|
||||||
"sudo",
|
"sudo",
|
||||||
"super",
|
"super",
|
||||||
"superuser",
|
"superuser",
|
||||||
"support",
|
|
||||||
"survey",
|
"survey",
|
||||||
"sync",
|
"sync",
|
||||||
"sysadmin",
|
"sysadmin",
|
||||||
|
@ -503,7 +502,6 @@
|
||||||
"void",
|
"void",
|
||||||
"vote",
|
"vote",
|
||||||
"webmail",
|
"webmail",
|
||||||
"webmaster",
|
|
||||||
"website",
|
"website",
|
||||||
"widget",
|
"widget",
|
||||||
"widgets",
|
"widgets",
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
.badge.badge-info.word {
|
.badge.badge-info.word {
|
||||||
background-color: #307cf1;
|
background-color: #307cf1;
|
||||||
}
|
}
|
||||||
|
.badge.badge-info.html5 {
|
||||||
|
background-color: #f16529;
|
||||||
|
background-color: #e44d26;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -74,9 +74,17 @@
|
||||||
<button class="btn btn-light btn-sm J_syncUsers up-1" type="button"><i class="icon zmdi zmdi-refresh up-1"></i> [[${bundle.L('立即同步')}]]</button>
|
<button class="btn btn-light btn-sm J_syncUsers up-1" type="button"><i class="icon zmdi zmdi-refresh up-1"></i> [[${bundle.L('立即同步')}]]</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>[[${bundle.L('用户匹配方式')}]]</td>
|
||||||
|
<td data-id="DingtalkSyncUsersMatch" th:data-value="${DingtalkSyncUsersMatch}" th:data-form-text="${bundle.L('针对已存在用户,采用何种方式进行匹配,如无匹配则新建')}">
|
||||||
|
<th:block th:if="${DingtalkSyncUsersMatch == 'ID'}">[[${bundle.L('默认')}]]</th:block>
|
||||||
|
<th:block th:if="${DingtalkSyncUsersMatch == 'EMAIL'}">[[${bundle.L('邮箱')}]]</th:block>
|
||||||
|
<th:block th:if="${DingtalkSyncUsersMatch == 'NAME'}">[[${bundle.L('用户名')}]]</th:block>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>[[${bundle.L('用户默认角色')}]]</td>
|
<td>[[${bundle.L('用户默认角色')}]]</td>
|
||||||
<td data-id="DingtalkSyncUsersRole" th:data-value="${DingtalkSyncUsersRole}" th:data-form-text="${bundle.L('如不指定新同步的用户将不可用,直到你为他们指定了角色')}">
|
<td data-id="DingtalkSyncUsersRole" th:data-value="${DingtalkSyncUsersRole}" th:data-form-text="${bundle.L('如不指定,新建用户将不可用,直到你为他们指定了角色')}">
|
||||||
[[${DingtalkSyncUsersRoleLabel ?:bundle.L('无')}]]
|
[[${DingtalkSyncUsersRoleLabel ?:bundle.L('无')}]]
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -74,9 +74,17 @@
|
||||||
<button class="btn btn-light btn-sm J_syncUsers up-1" type="button"><i class="icon zmdi zmdi-refresh up-1"></i> [[${bundle.L('立即同步')}]]</button>
|
<button class="btn btn-light btn-sm J_syncUsers up-1" type="button"><i class="icon zmdi zmdi-refresh up-1"></i> [[${bundle.L('立即同步')}]]</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>[[${bundle.L('用户匹配方式')}]]</td>
|
||||||
|
<td data-id="WxworkSyncUsersMatch" th:data-value="${WxworkSyncUsersMatch}" th:data-form-text="${bundle.L('针对已存在用户,采用何种方式进行匹配,如无匹配则新建')}">
|
||||||
|
<th:block th:if="${WxworkSyncUsersMatch == 'ID'}">[[${bundle.L('默认')}]]</th:block>
|
||||||
|
<th:block th:if="${WxworkSyncUsersMatch == 'EMAIL'}">[[${bundle.L('邮箱')}]]</th:block>
|
||||||
|
<th:block th:if="${WxworkSyncUsersMatch == 'NAME'}">[[${bundle.L('用户名')}]]</th:block>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>[[${bundle.L('用户默认角色')}]]</td>
|
<td>[[${bundle.L('用户默认角色')}]]</td>
|
||||||
<td data-id="WxworkSyncUsersRole" th:data-value="${WxworkSyncUsersRole}" th:data-form-text="${bundle.L('如不指定新同步的用户将不可用,直到你为他们指定了角色')}">
|
<td data-id="WxworkSyncUsersRole" th:data-value="${WxworkSyncUsersRole}" th:data-form-text="${bundle.L('如不指定,新建用户将不可用,直到你为他们指定了角色')}">
|
||||||
[[${WxworkSyncUsersRoleLabel ?:bundle.L('无')}]]
|
[[${WxworkSyncUsersRoleLabel ?:bundle.L('无')}]]
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -54,33 +54,38 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-box .chart-head .chart-oper a {
|
.chart-box .chart-head .chart-oper > a {
|
||||||
color: #000;
|
color: #000;
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
margin-left: 10px;
|
margin-left: 5px;
|
||||||
padding-left: 3px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-box .chart-head .chart-oper a:hover {
|
.chart-box .chart-head .chart-oper > a:hover {
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-box .chart-head .chart-oper a .zmdi {
|
.chart-box .chart-head .chart-oper > a .zmdi {
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
width: 20px;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-box .chart-head .chart-oper a .zmdi-close {
|
.chart-box .chart-head .chart-oper > a .zmdi-close {
|
||||||
font-size: 1.45rem;
|
font-size: 1.45rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-box .chart-head .chart-oper a .zmdi-fullscreen,
|
.chart-box .chart-head .chart-oper > a .zmdi-fullscreen,
|
||||||
.chart-box .chart-head .chart-oper a .zmdi-fullscreen-exit {
|
.chart-box .chart-head .chart-oper > a .zmdi-fullscreen-exit {
|
||||||
font-size: 1.43rem;
|
font-size: 1.43rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chart-box .chart-head .chart-oper .dropdown-menu {
|
||||||
|
min-width: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
.chart-undata {
|
.chart-undata {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: #999;
|
color: #999;
|
||||||
|
@ -271,6 +276,10 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chart-box.ApprovalList .progress-wrap .progress-bar {
|
||||||
|
min-width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.chart-box.ApprovalList .progress-wrap .progress-bar:hover {
|
.chart-box.ApprovalList .progress-wrap .progress-bar:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
|
|
|
@ -147,9 +147,9 @@ code {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: 5px 0 5px 5px;
|
border-width: 5px 0 5px 5px;
|
||||||
border-left-color: #ddd;
|
border-left-color: #ccc;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
margin-right: -10px;
|
margin-right: -8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-submenu:hover > a::after {
|
.dropdown-submenu:hover > a::after {
|
||||||
|
|
|
@ -27,7 +27,7 @@ class ConfigFormDlg extends RbFormHandler {
|
||||||
<div className="form-group row footer">
|
<div className="form-group row footer">
|
||||||
<div className="col-sm-7 offset-sm-3" ref={(c) => (this._btns = c)}>
|
<div className="col-sm-7 offset-sm-3" ref={(c) => (this._btns = c)}>
|
||||||
<button className="btn btn-primary" type="button" onClick={this.confirm}>
|
<button className="btn btn-primary" type="button" onClick={this.confirm}>
|
||||||
{$L('确定')}
|
{this.confirmText || $L('确定')}
|
||||||
</button>
|
</button>
|
||||||
<a className="btn btn-link" onClick={this.hide}>
|
<a className="btn btn-link" onClick={this.hide}>
|
||||||
{$L('取消')}
|
{$L('取消')}
|
||||||
|
|
|
@ -8,7 +8,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('.J_add').on('click', () => renderRbcomp(<ReportEditor />))
|
$('.J_add').on('click', () => renderRbcomp(<ReportEditor />))
|
||||||
// $('.J_add-html5').on('click', () => renderRbcomp(<ReportEditor isHtml5 />))
|
$('.J_add-html5').on('click', () => renderRbcomp(<ReportEditor isHtml5 />))
|
||||||
|
|
||||||
renderRbcomp(<ReportList />, 'dataList')
|
renderRbcomp(<ReportList />, 'dataList')
|
||||||
})
|
})
|
||||||
|
@ -31,7 +31,7 @@ class ReportList extends ConfigList {
|
||||||
<tr key={item[0]}>
|
<tr key={item[0]}>
|
||||||
<td>
|
<td>
|
||||||
{isHtml5 ? (
|
{isHtml5 ? (
|
||||||
<a title={$L('在线模板编辑器')} href={`report-template/design?id=${item[0]}`}>
|
<a title={$L('在线模板编辑')} href={`report-template/design?id=${item[0]}`}>
|
||||||
{item[3]}
|
{item[3]}
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
|
@ -39,7 +39,7 @@ class ReportList extends ConfigList {
|
||||||
)}
|
)}
|
||||||
{item[6] === 1 && <span className="badge badge-info badge-arrow3 badge-sm ml-1 excel">EXCEL</span>}
|
{item[6] === 1 && <span className="badge badge-info badge-arrow3 badge-sm ml-1 excel">EXCEL</span>}
|
||||||
{item[6] === 2 && <span className="badge badge-info badge-arrow3 badge-sm ml-1 excel">{$L('EXCEL 列表')}</span>}
|
{item[6] === 2 && <span className="badge badge-info badge-arrow3 badge-sm ml-1 excel">{$L('EXCEL 列表')}</span>}
|
||||||
{isHtml5 && <span className="badge badge-info badge-arrow3 badge-sm ml-1">{$L('在线模板')}</span>}
|
{isHtml5 && <span className="badge badge-info badge-arrow3 badge-sm ml-1 html5">{$L('在线模板')}</span>}
|
||||||
{item[6] === 4 && <span className="badge badge-info badge-arrow3 badge-sm ml-1 word">WORD</span>}
|
{item[6] === 4 && <span className="badge badge-info badge-arrow3 badge-sm ml-1 word">WORD</span>}
|
||||||
|
|
||||||
{outputType.includes('pdf') && <span className="badge badge-secondary badge-sm ml-1">PDF</span>}
|
{outputType.includes('pdf') && <span className="badge badge-secondary badge-sm ml-1">PDF</span>}
|
||||||
|
@ -97,6 +97,7 @@ class ReportEditor extends ConfigFormDlg {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.subtitle = $L('报表模板')
|
this.subtitle = $L('报表模板')
|
||||||
|
this.confirmText = this.props.isHtml5 && !this.props.id ? $L('下一步') : null
|
||||||
this.hasDetail = true
|
this.hasDetail = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,26 +19,35 @@ class BaseChart extends React.Component {
|
||||||
const opActions = (
|
const opActions = (
|
||||||
<div className="chart-oper">
|
<div className="chart-oper">
|
||||||
{!this.props.builtin && (
|
{!this.props.builtin && (
|
||||||
<a className="J_view-source" title={$L('查看来源数据')} href={`${rb.baseUrl}/dashboard/view-chart-source?id=${this.props.id}`} target="_blank">
|
<a title={$L('查看来源数据')} href={`${rb.baseUrl}/dashboard/view-chart-source?id=${this.props.id}`} target="_blank">
|
||||||
<i className="zmdi zmdi-rss" />
|
<i className="zmdi zmdi-rss" />
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
<a title={$L('刷新')} onClick={() => this.loadChartData()}>
|
<a title={$L('刷新')} onClick={() => this.loadChartData()}>
|
||||||
<i className="zmdi zmdi-refresh" />
|
<i className="zmdi zmdi-refresh" />
|
||||||
</a>
|
</a>
|
||||||
<a className="J_fullscreen d-none d-md-inline-block" title={$L('全屏')} onClick={() => this.toggleFullscreen()}>
|
<a className="d-none d-md-inline-block" title={$L('全屏')} onClick={() => this.toggleFullscreen()}>
|
||||||
<i className={`zmdi zmdi-${this.state.fullscreen ? 'fullscreen-exit' : 'fullscreen'}`} />
|
<i className={`zmdi zmdi-${this.state.fullscreen ? 'fullscreen-exit' : 'fullscreen'}`} />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<a className="d-none d-md-inline-block" data-toggle="dropdown">
|
||||||
|
<i className="icon zmdi zmdi-more-vert" style={{ width: 16 }} />
|
||||||
|
</a>
|
||||||
|
<div className="dropdown-menu dropdown-menu-right">
|
||||||
{this.props.isManageable && !this.props.builtin && (
|
{this.props.isManageable && !this.props.builtin && (
|
||||||
<a className="J_chart-edit d-none d-md-inline-block" title={$L('编辑')} href={`${rb.baseUrl}/dashboard/chart-design?id=${this.props.id}`}>
|
<a className="dropdown-item J_chart-edit" title={$L('编辑')} href={`${rb.baseUrl}/dashboard/chart-design?id=${this.props.id}`}>
|
||||||
<i className="zmdi zmdi-edit" />
|
{$L('编辑')}
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
{this.props.editable && (
|
{this.props.editable && (
|
||||||
<a title={$L('移除')} onClick={() => this.remove()}>
|
<a className="dropdown-item" title={$L('移除')} onClick={() => this.remove()}>
|
||||||
<i className="zmdi zmdi-close" />
|
{$L('移除')}
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
|
<a className="dropdown-item" title={$L('导出')} onClick={() => this.export()}>
|
||||||
|
{$L('导出')}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -119,6 +128,51 @@ class BaseChart extends React.Component {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export() {
|
||||||
|
if (this._echarts) {
|
||||||
|
const base64 = this._echarts.getDataURL({
|
||||||
|
type: 'png',
|
||||||
|
pixelRatio: 2,
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
})
|
||||||
|
|
||||||
|
const $a = document.createElement('a')
|
||||||
|
$a.href = base64
|
||||||
|
$a.download = `${this.state.title}.png`
|
||||||
|
$a.click()
|
||||||
|
} else {
|
||||||
|
const table = $(this._$body).find('table.table')[0]
|
||||||
|
if (table) {
|
||||||
|
this._exportTable(table)
|
||||||
|
} else {
|
||||||
|
RbHighbar.createl('该图表暂不支持导出')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_exportTable(table) {
|
||||||
|
function reLinks(table, a, b) {
|
||||||
|
$(table)
|
||||||
|
.find('a')
|
||||||
|
.each(function () {
|
||||||
|
$(this)
|
||||||
|
.attr(a, `${$(this).attr(b)}`)
|
||||||
|
.removeAttr(b)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove
|
||||||
|
reLinks(table, '__href', 'href')
|
||||||
|
|
||||||
|
// https://docs.sheetjs.com/docs/api/utilities/html#html-table-input
|
||||||
|
// https://docs.sheetjs.com/docs/api/write-options
|
||||||
|
const wb = window.XLSX.utils.table_to_book(table, { raw: true })
|
||||||
|
window.XLSX.writeFile(wb, `${this.state.title}.xls`)
|
||||||
|
|
||||||
|
// Add
|
||||||
|
setTimeout(() => reLinks(table, 'href', '__href'), 500)
|
||||||
|
}
|
||||||
|
|
||||||
renderError(msg, cb) {
|
renderError(msg, cb) {
|
||||||
this.setState({ chartdata: <div className="chart-undata must-center">{msg || $L('加载失败')}</div> }, cb)
|
this.setState({ chartdata: <div className="chart-undata must-center">{msg || $L('加载失败')}</div> }, cb)
|
||||||
}
|
}
|
||||||
|
@ -195,16 +249,7 @@ class ChartTable extends BaseChart {
|
||||||
.css('height', $tb.height() - 20)
|
.css('height', $tb.height() - 20)
|
||||||
.perfectScrollbar()
|
.perfectScrollbar()
|
||||||
|
|
||||||
// let tdActive = null
|
// selected
|
||||||
// const $els = $tb.find('tbody td').on('mousedown', function () {
|
|
||||||
// if (tdActive === this) {
|
|
||||||
// $(this).toggleClass('highlight')
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// tdActive = this
|
|
||||||
// $els.removeClass('highlight')
|
|
||||||
// $(this).addClass('highlight')
|
|
||||||
// })
|
|
||||||
$tb.find('table').tableCellsSelection()
|
$tb.find('table').tableCellsSelection()
|
||||||
|
|
||||||
if (window.render_preview_chart) {
|
if (window.render_preview_chart) {
|
||||||
|
|
|
@ -1091,7 +1091,7 @@ class RbList extends React.Component {
|
||||||
}, 400)
|
}, 400)
|
||||||
|
|
||||||
if (query.filter && (query.filter.items || []).length > 0) {
|
if (query.filter && (query.filter.items || []).length > 0) {
|
||||||
console.log('API Filter <Body> :\n', JSON.stringify(query.filter))
|
console.log(`API Filter <Body> :\n %c${JSON.stringify(query.filter)}`, 'color:#e83e8c;font-size:16px')
|
||||||
}
|
}
|
||||||
|
|
||||||
$.post(`/app/${this._entity}/data-list`, JSON.stringify(RbList.queryBefore(query)), (res) => {
|
$.post(`/app/${this._entity}/data-list`, JSON.stringify(RbList.queryBefore(query)), (res) => {
|
||||||
|
|
|
@ -8,7 +8,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
||||||
/* !!! KEEP IT ES5 COMPATIBLE !!! */
|
/* !!! KEEP IT ES5 COMPATIBLE !!! */
|
||||||
|
|
||||||
// GA
|
// GA
|
||||||
(function () {
|
;(function () {
|
||||||
var gaScript = document.createElement('script')
|
var gaScript = document.createElement('script')
|
||||||
gaScript.src = 'https://www.googletagmanager.com/gtag/js?id=G-ZCZHJPMEG7'
|
gaScript.src = 'https://www.googletagmanager.com/gtag/js?id=G-ZCZHJPMEG7'
|
||||||
gaScript.async = true
|
gaScript.async = true
|
||||||
|
@ -207,18 +207,18 @@ $(function () {
|
||||||
// }
|
// }
|
||||||
})
|
})
|
||||||
|
|
||||||
var $addResizeHandler__calls = []
|
var $addResizeHandler__cbs = []
|
||||||
/**
|
/**
|
||||||
* 窗口 RESIZE 回调
|
* 窗口 RESIZE 回调
|
||||||
*/
|
*/
|
||||||
var $addResizeHandler = function (call) {
|
var $addResizeHandler = function (callback) {
|
||||||
typeof call === 'function' && $addResizeHandler__calls && $addResizeHandler__calls.push(call)
|
typeof callback === 'function' && $addResizeHandler__cbs && $addResizeHandler__cbs.push(callback)
|
||||||
return function () {
|
return function () {
|
||||||
if (!$addResizeHandler__calls || $addResizeHandler__calls.length === 0) return
|
if (!$addResizeHandler__cbs || $addResizeHandler__cbs.length === 0) return
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
if (rb.env === 'dev') console.log('Calls ' + $addResizeHandler__calls.length + ' handlers of resize ...')
|
if (rb.env === 'dev') console.log('Callbacks ' + $addResizeHandler__cbs.length + ' handlers of resize ...')
|
||||||
$addResizeHandler__calls.forEach(function (call) {
|
$addResizeHandler__cbs.forEach(function (cb) {
|
||||||
call()
|
cb()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1019,7 +1019,7 @@ var $useMap = function (onLoad) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自动定位(有误差)
|
// 自动定位(有误差)
|
||||||
var $autoLocation = function (call) {
|
var $autoLocation = function (callback) {
|
||||||
$useMap(function () {
|
$useMap(function () {
|
||||||
var geo = new window.BMapGL.Geolocation()
|
var geo = new window.BMapGL.Geolocation()
|
||||||
geo.enableSDKLocation()
|
geo.enableSDKLocation()
|
||||||
|
@ -1032,7 +1032,7 @@ var $autoLocation = function (call) {
|
||||||
lng: e.longitude,
|
lng: e.longitude,
|
||||||
text: r ? r.address : null,
|
text: r ? r.address : null,
|
||||||
}
|
}
|
||||||
typeof call === 'function' && call(v)
|
typeof callback === 'function' && callback(v)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
console.log('Geolocation failed :', this.getStatus())
|
console.log('Geolocation failed :', this.getStatus())
|
||||||
|
|
24
src/main/resources/web/assets/lib/charts/xlsx.full.min.js
vendored
Normal file
24
src/main/resources/web/assets/lib/charts/xlsx.full.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -73,6 +73,7 @@
|
||||||
<script th:src="@{/assets/lib/charts/gridstack.all.js}"></script>
|
<script th:src="@{/assets/lib/charts/gridstack.all.js}"></script>
|
||||||
<script th:src="@{/assets/lib/charts/echarts.min.js}"></script>
|
<script th:src="@{/assets/lib/charts/echarts.min.js}"></script>
|
||||||
<script th:src="@{/assets/lib/charts/tablecellsselection.js}"></script>
|
<script th:src="@{/assets/lib/charts/tablecellsselection.js}"></script>
|
||||||
|
<script th:src="@{/assets/lib/charts/xlsx.full.min.js}"></script>
|
||||||
<script th:src="@{/assets/js/charts/charts.js}" type="text/babel"></script>
|
<script th:src="@{/assets/js/charts/charts.js}" type="text/babel"></script>
|
||||||
<th:block th:replace="~{/_include/forms}" />
|
<th:block th:replace="~{/_include/forms}" />
|
||||||
<script th:src="@{/assets/js/charts/dashboard.js}" type="text/babel"></script>
|
<script th:src="@{/assets/js/charts/dashboard.js}" type="text/babel"></script>
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
</script>
|
</script>
|
||||||
<script type="text/babel">
|
<script type="text/babel">
|
||||||
// clear
|
// clear
|
||||||
window.$addResizeHandler__calls = []
|
window.$addResizeHandler__cbs = []
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
// 无关闭按钮
|
// 无关闭按钮
|
||||||
|
|
Loading…
Reference in a new issue