mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 07:25:54 +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)
|
||||
*/
|
||||
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
|
||||
* @return
|
||||
*/
|
||||
public JSONArray getReports(Entity entity, int type, ID user) {
|
||||
public JSONArray getReportTemplates(Entity entity, int type, ID user) {
|
||||
JSONArray alist = new JSONArray();
|
||||
for (ConfigBean e : getReportsRaw(entity)) {
|
||||
if (e.getBoolean("disabled")) continue;
|
||||
|
@ -66,7 +66,8 @@ public class DataReportManager implements ConfigManager {
|
|||
if (type == DataReportManager.TYPE_LIST) {
|
||||
can = aType == type;
|
||||
} 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) {
|
||||
|
@ -210,10 +211,12 @@ public class DataReportManager implements ConfigManager {
|
|||
name = ContentWithFieldVars.replaceWithRecord(name, (ID) idOrEntity);
|
||||
}
|
||||
|
||||
// suffix
|
||||
// Suffix
|
||||
if (fileName.endsWith(".pdf")) name += ".pdf";
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import com.alibaba.excel.EasyExcel;
|
|||
import com.alibaba.excel.ExcelWriter;
|
||||
import com.alibaba.excel.write.metadata.WriteSheet;
|
||||
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.JSONArray;
|
||||
import com.rebuild.core.Application;
|
||||
|
@ -55,7 +56,6 @@ import java.math.RoundingMode;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
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__NUMBER;
|
||||
import static com.rebuild.core.service.datareport.TemplateExtractor.PLACEHOLDER;
|
||||
import static com.rebuild.core.service.datareport.TemplateExtractor33.NROW_PREFIX2;
|
||||
|
||||
/**
|
||||
* 报表生成 easyexcel
|
||||
|
@ -80,11 +81,12 @@ import static com.rebuild.core.service.datareport.TemplateExtractor.PLACEHOLDER;
|
|||
@Slf4j
|
||||
public class EasyExcelGenerator extends SetUser {
|
||||
|
||||
final protected static String MDATA_KEY = ".";
|
||||
|
||||
protected File templateFile;
|
||||
protected Integer writeSheetAt = null;
|
||||
protected ID recordId;
|
||||
|
||||
protected boolean hasMain = false;
|
||||
protected int phNumber = 1;
|
||||
protected Map<String, Object> phValues = new HashMap<>();
|
||||
|
||||
|
@ -93,7 +95,7 @@ public class EasyExcelGenerator extends SetUser {
|
|||
* @param recordId
|
||||
*/
|
||||
protected EasyExcelGenerator(File template, ID recordId) {
|
||||
this.templateFile = getFixTemplate(template);
|
||||
this.templateFile = template;
|
||||
this.recordId = recordId;
|
||||
}
|
||||
|
||||
|
@ -105,14 +107,13 @@ public class EasyExcelGenerator extends SetUser {
|
|||
public File generate() {
|
||||
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("暂无数据"));
|
||||
|
||||
Map<String, Object> main = null;
|
||||
if (this.hasMain) {
|
||||
Iterator<Map<String, Object>> iter = datas.iterator();
|
||||
main = iter.next();
|
||||
iter.remove();
|
||||
if (datas.containsKey(MDATA_KEY)) {
|
||||
main = datas.get(MDATA_KEY).get(0);
|
||||
datas.remove(MDATA_KEY);
|
||||
}
|
||||
|
||||
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
|
||||
|
@ -123,10 +124,29 @@ public class EasyExcelGenerator extends SetUser {
|
|||
.registerWriteHandler(new FormulaCellWriteHandler())
|
||||
.build();
|
||||
|
||||
// 有明细记录
|
||||
if (!datas.isEmpty()) {
|
||||
// 有引用记录
|
||||
if (datas.size() == 1) {
|
||||
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) {
|
||||
|
@ -153,9 +173,9 @@ public class EasyExcelGenerator extends SetUser {
|
|||
protected File getTargetFile() {
|
||||
String suffix = "xls";
|
||||
if (templateFile.getName().endsWith(".xlsx")) suffix = "xlsx";
|
||||
if (templateFile.getName().endsWith(".html")) suffix = "html";
|
||||
if (templateFile.getName().endsWith(".docx")) suffix = "docx";
|
||||
if (templateFile.getName().endsWith(".doc")) suffix = "doc";
|
||||
else if (templateFile.getName().endsWith(".html")) suffix = "html";
|
||||
else if (templateFile.getName().endsWith(".docx")) suffix = "docx";
|
||||
else if (templateFile.getName().endsWith(".doc")) suffix = "doc";
|
||||
|
||||
return RebuildConfiguration.getFileOfTemp(String.format("RBREPORT-%d.%s", System.currentTimeMillis(), suffix));
|
||||
}
|
||||
|
@ -165,7 +185,7 @@ public class EasyExcelGenerator extends SetUser {
|
|||
*
|
||||
* @return 第一个为主记录(若有)
|
||||
*/
|
||||
protected List<Map<String, Object>> buildData() {
|
||||
protected Map<String, List<Map<String, Object>>> buildData() {
|
||||
Entity entity = MetadataHelper.getEntity(recordId.getEntityCode());
|
||||
|
||||
TemplateExtractor templateExtractor = new TemplateExtractor(templateFile);
|
||||
|
@ -213,10 +233,10 @@ public class EasyExcelGenerator extends SetUser {
|
|||
}
|
||||
|
||||
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 = ?";
|
||||
|
||||
if (!fieldsOfMain.isEmpty()) {
|
||||
|
@ -229,8 +249,8 @@ public class EasyExcelGenerator extends SetUser {
|
|||
.record();
|
||||
Assert.notNull(record, "No record found : " + recordId);
|
||||
|
||||
datas.add(buildData(record, varsMapOfMain));
|
||||
this.hasMain = true;
|
||||
Map<String, Object> d = buildData(record, varsMapOfMain);
|
||||
datas.put(MDATA_KEY, Collections.singletonList(d));
|
||||
}
|
||||
|
||||
// 明细
|
||||
|
@ -246,10 +266,12 @@ public class EasyExcelGenerator extends SetUser {
|
|||
.list();
|
||||
|
||||
phNumber = 1;
|
||||
List<Map<String, Object>> detailList = new ArrayList<>();
|
||||
for (Record c : list) {
|
||||
datas.add(buildData(c, varsMapOfDetail));
|
||||
detailList.add(buildData(c, varsMapOfDetail));
|
||||
phNumber++;
|
||||
}
|
||||
datas.put(MDATA_KEY + "detail", detailList);
|
||||
}
|
||||
|
||||
// 审批
|
||||
|
@ -263,10 +285,12 @@ public class EasyExcelGenerator extends SetUser {
|
|||
.list();
|
||||
|
||||
phNumber = 1;
|
||||
List<Map<String, Object>> approvalList = new ArrayList<>();
|
||||
for (Record c : list) {
|
||||
datas.add(buildData(c, varsMapOfApproval));
|
||||
approvalList.add(buildData(c, varsMapOfApproval));
|
||||
phNumber++;
|
||||
}
|
||||
datas.put(MDATA_KEY + "approval", approvalList);
|
||||
}
|
||||
|
||||
return datas;
|
||||
|
@ -465,62 +489,6 @@ public class EasyExcelGenerator extends SetUser {
|
|||
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.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_PREFIX2;
|
||||
import static com.rebuild.core.service.datareport.TemplateExtractor33.NROW_PREFIX2;
|
||||
|
||||
/**
|
||||
* V33
|
||||
|
@ -65,7 +68,7 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected List<Map<String, Object>> buildData() {
|
||||
protected Map<String, List<Map<String, Object>>> buildData() {
|
||||
final Entity entity = MetadataHelper.getEntity(recordId.getEntityCode());
|
||||
|
||||
final TemplateExtractor33 templateExtractor33 = this.buildTemplateExtractor33();
|
||||
|
@ -82,25 +85,25 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
|||
final String varName = e.getKey();
|
||||
final String fieldName = e.getValue();
|
||||
|
||||
String refName = null;
|
||||
if (varName.startsWith(NROW_PREFIX)) {
|
||||
if (varName.startsWith(APPROVAL_PREFIX)) {
|
||||
refName = APPROVAL_PREFIX;
|
||||
} else if (varName.startsWith(DETAIL_PREFIX)) {
|
||||
refName = DETAIL_PREFIX;
|
||||
String refKey = null;
|
||||
if (varName.startsWith(NROW_PREFIX) || varName.startsWith(NROW_PREFIX2)) {
|
||||
if (varName.startsWith(APPROVAL_PREFIX) || varName.startsWith(APPROVAL_PREFIX2)) {
|
||||
refKey = APPROVAL_PREFIX;
|
||||
} else if (varName.startsWith(DETAIL_PREFIX) || varName.startsWith(DETAIL_PREFIX2)) {
|
||||
refKey = DETAIL_PREFIX;
|
||||
} else {
|
||||
// 在客户中导出订单(下列 AccountId 为订单中引用客户的引用字段)
|
||||
// .AccountId.SalesOrder.SalesOrderName
|
||||
String[] split = varName.substring(1).split("\\.");
|
||||
// .AccountId.SalesOrder.SalesOrderName or $AccountId$SalesOrder$SalesOrderName
|
||||
String[] split = varName.substring(1).split("[.$]");
|
||||
if (split.length < 2) throw new ReportsException("Bad REF (Miss .detail prefix?) : " + varName);
|
||||
|
||||
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);
|
||||
varsMapOfRefs.put(refName, varsMapOfRef);
|
||||
varsMapOfRefs.put(refKey, varsMapOfRef);
|
||||
|
||||
} else {
|
||||
varsMapOfMain.put(varName, fieldName);
|
||||
|
@ -114,22 +117,23 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (varName.startsWith(NROW_PREFIX)) {
|
||||
List<String> fieldsOfRef = fieldsOfRefs.getOrDefault(refName, new ArrayList<>());
|
||||
if (varName.startsWith(NROW_PREFIX) || varName.startsWith(NROW_PREFIX2)) {
|
||||
List<String> fieldsOfRef = fieldsOfRefs.getOrDefault(refKey, new ArrayList<>());
|
||||
fieldsOfRef.add(fieldName);
|
||||
fieldsOfRefs.put(refName, fieldsOfRef);
|
||||
fieldsOfRefs.put(refKey, fieldsOfRef);
|
||||
} else {
|
||||
fieldsOfMain.add(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
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 = ?";
|
||||
|
||||
// 主记录
|
||||
if (!fieldsOfMain.isEmpty()) {
|
||||
String sql = String.format(baseSql,
|
||||
StringUtils.join(fieldsOfMain, ","),
|
||||
|
@ -140,13 +144,14 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
|||
.record();
|
||||
Assert.notNull(record, "No record found : " + recordId);
|
||||
|
||||
this.hasMain = true;
|
||||
datas.add(buildData(record, varsMapOfMain));
|
||||
Map<String, Object> d = buildData(record, varsMapOfMain);
|
||||
datas.put(MDATA_KEY, Collections.singletonList(d));
|
||||
}
|
||||
|
||||
// 相关记录(含明细、审批)
|
||||
for (Map.Entry<String, List<String>> e : fieldsOfRefs.entrySet()) {
|
||||
final String refName = e.getKey();
|
||||
final boolean isApproval = refName.startsWith(APPROVAL_PREFIX);
|
||||
final String refKey = e.getKey();
|
||||
final boolean isApproval = refKey.startsWith(APPROVAL_PREFIX);
|
||||
|
||||
String querySql = baseSql;
|
||||
if (isApproval) {
|
||||
|
@ -154,7 +159,7 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
|||
querySql = String.format(querySql, StringUtils.join(e.getValue(), ","),
|
||||
"createdOn,recordId,state,stepId", "RobotApprovalStep", "recordId");
|
||||
|
||||
} else if (refName.startsWith(DETAIL_PREFIX)) {
|
||||
} else if (refKey.startsWith(DETAIL_PREFIX)) {
|
||||
Entity de = entity.getDetailEntity();
|
||||
|
||||
String sortField = templateExtractor33.getSortField(DETAIL_PREFIX);
|
||||
|
@ -164,11 +169,11 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
|||
de.getPrimaryField().getName(), de.getName(), MetadataHelper.getDetailToMainField(de).getName());
|
||||
|
||||
} else {
|
||||
String[] split = refName.substring(1).split("\\.");
|
||||
String[] split = refKey.substring(1).split("[.$]");
|
||||
Field ref2Field = MetadataHelper.getField(split[1], split[0]);
|
||||
Entity ref2Entity = ref2Field.getOwnEntity();
|
||||
|
||||
String sortField = templateExtractor33.getSortField(refName);
|
||||
String sortField = templateExtractor33.getSortField(refKey);
|
||||
querySql += " order by " + StringUtils.defaultIfBlank(sortField, "createdOn asc");
|
||||
|
||||
String relatedExpr = split[1] + "." + split[0];
|
||||
|
@ -193,13 +198,14 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
|||
.add("state", 0)
|
||||
.build(UserService.SYSTEM_USER);
|
||||
|
||||
List<Record> list2 = new ArrayList<>();
|
||||
list2.add(submit);
|
||||
list2.addAll(list);
|
||||
list = list2;
|
||||
List<Record> listReplace = new ArrayList<>();
|
||||
listReplace.add(submit);
|
||||
listReplace.addAll(list);
|
||||
list = listReplace;
|
||||
}
|
||||
|
||||
phNumber = 1;
|
||||
List<Map<String, Object>> refDatas = new ArrayList<>();
|
||||
for (Record c : list) {
|
||||
// 特殊处理
|
||||
if (isApproval) {
|
||||
|
@ -207,10 +213,10 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
|||
Date approvedTime = c.getDate("approvedTime");
|
||||
if (approvedTime == null && state > 1) c.setDate("approvedTime", c.getDate("createdOn"));
|
||||
}
|
||||
|
||||
datas.add(buildData(c, varsMapOfRefs.get(refName)));
|
||||
refDatas.add(buildData(c, varsMapOfRefs.get(refKey)));
|
||||
phNumber++;
|
||||
}
|
||||
datas.put(refKey, refDatas);
|
||||
}
|
||||
|
||||
return datas;
|
||||
|
@ -273,7 +279,6 @@ public class EasyExcelGenerator33 extends EasyExcelGenerator {
|
|||
this.templateFile = targetFile;
|
||||
this.writeSheetAt = newSheetAt;
|
||||
this.recordId = recordId;
|
||||
this.hasMain = false;
|
||||
this.phNumber = 1;
|
||||
this.phValues.clear();
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ public class EasyExcelListGenerator extends EasyExcelGenerator {
|
|||
* @see DataListBuilderImpl#getJSONResult()
|
||||
*/
|
||||
@Override
|
||||
protected List<Map<String, Object>> buildData() {
|
||||
protected Map<String, List<Map<String, Object>>> buildData() {
|
||||
Entity entity = MetadataHelper.getEntity(queryData.getString("entity"));
|
||||
TemplateExtractor varsExtractor = new TemplateExtractor(templateFile, Boolean.TRUE);
|
||||
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); // 使用模板字段
|
||||
|
||||
|
@ -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__CURRENTDATETIME)) phValues.put(PH__CURRENTDATETIME, getPhValue(PH__CURRENTDATETIME));
|
||||
|
||||
return datas;
|
||||
return Collections.singletonMap(MDATA_KEY, datas);
|
||||
}
|
||||
|
||||
public int getExportCount() {
|
||||
|
|
|
@ -20,7 +20,7 @@ import org.apache.commons.lang.StringUtils;
|
|||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -38,7 +38,7 @@ public class TemplateExtractor {
|
|||
// 列表(即多条记录)
|
||||
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 = "__";
|
||||
|
@ -137,7 +137,7 @@ public class TemplateExtractor {
|
|||
protected Set<String> extractVars() {
|
||||
List<Cell[]> rows = ExcelUtils.readExcel(templateFile);
|
||||
|
||||
Set<String> vars = new HashSet<>();
|
||||
Set<String> vars = new LinkedHashSet<>();
|
||||
for (Cell[] row : rows) {
|
||||
for (Cell cell : row) {
|
||||
if (cell.isEmpty()) continue;
|
||||
|
|
|
@ -26,7 +26,11 @@ import java.util.Set;
|
|||
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";
|
||||
|
@ -56,14 +60,15 @@ public class TemplateExtractor33 extends TemplateExtractor {
|
|||
Map<String, String> map = new HashMap<>();
|
||||
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("$", ".");
|
||||
|
||||
// 占位
|
||||
if (isPlaceholder(listField)) {
|
||||
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());
|
||||
if (approvalEntity != null && MetadataHelper.getLastJoinField(approvalEntity, stepNodeField) != null) {
|
||||
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());
|
||||
detailField = getFieldNameWithSort(DETAIL_PREFIX, detailField);
|
||||
|
||||
|
@ -124,6 +129,7 @@ public class TemplateExtractor33 extends TemplateExtractor {
|
|||
hasSort = varFieldName + " desc";
|
||||
}
|
||||
|
||||
// 有多个字段排序的,其排序顺序取决于字段出现在模板中的位置
|
||||
if (hasSort != null) {
|
||||
String useSorts = sortFields.get(refName);
|
||||
if (useSorts != null) useSorts += "," + hasSort;
|
||||
|
@ -151,6 +157,8 @@ public class TemplateExtractor33 extends TemplateExtractor {
|
|||
* @return
|
||||
*/
|
||||
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),
|
||||
DingtalkSyncUsersRole,
|
||||
DingtalkRobotCode,
|
||||
DingtalkSyncUsersMatch("ID"),
|
||||
// WxWork
|
||||
WxworkCorpid, WxworkAgentid, WxworkSecret,
|
||||
WxworkRxToken, WxworkRxEncodingAESKey,
|
||||
WxworkAuthFile,
|
||||
WxworkSyncUsers(false),
|
||||
WxworkSyncUsersRole,
|
||||
WxworkSyncUsersMatch("ID"),
|
||||
|
||||
// PORTALs
|
||||
PortalBaiduMapAk,
|
||||
|
|
|
@ -223,17 +223,16 @@ public class QueryParser {
|
|||
|
||||
// 排序
|
||||
|
||||
StringBuilder sqlSort = new StringBuilder(" order by ");
|
||||
|
||||
String sortNode = queryExpr.getString("sort");
|
||||
String sortSql = null;
|
||||
if (StringUtils.isNotBlank(sortNode)) {
|
||||
sqlSort.append(StringUtils.defaultString(parseSort(sortNode), ""));
|
||||
sortSql = parseSort(sortNode);
|
||||
} else if (entity.containsField(EntityHelper.ModifiedOn)) {
|
||||
sqlSort.append(EntityHelper.ModifiedOn + " desc");
|
||||
sortSql = EntityHelper.ModifiedOn + " desc";
|
||||
} 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.countSql = this.buildCountSql(pkName) + sqlWhere;
|
||||
|
|
|
@ -37,6 +37,7 @@ import com.rebuild.web.EntityParam;
|
|||
import com.rebuild.web.IdParam;
|
||||
import com.rebuild.web.admin.ConfigCommons;
|
||||
import com.rebuild.web.commons.FileDownloader;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -47,6 +48,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -164,7 +166,7 @@ public class ReportTemplateController extends BaseController {
|
|||
}
|
||||
|
||||
@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 {
|
||||
final TemplateFile tt;
|
||||
// 新建时
|
||||
|
@ -183,7 +185,7 @@ public class ReportTemplateController extends BaseController {
|
|||
Object[] random = Application.createQueryNoFilter(sql).unique();
|
||||
if (random == null) {
|
||||
response.sendError(400, Language.L("未找到可供预览的记录"));
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
File output;
|
||||
|
@ -201,6 +203,12 @@ public class ReportTemplateController extends BaseController {
|
|||
"com.rebuild.rbv.data.WordReportGenerator#create", tt.templateFile, random[0]);
|
||||
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
|
||||
else {
|
||||
output = EasyExcelGenerator.create(tt.templateFile, (ID) random[0], tt.isV33).generate();
|
||||
|
@ -208,13 +216,19 @@ public class ReportTemplateController extends BaseController {
|
|||
|
||||
} catch (ConfigurationException ex) {
|
||||
response.sendError(500, ex.getLocalizedMessage());
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
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");
|
||||
if (PdfConverter.TYPE_PDF.equalsIgnoreCase(typeOutput) || PdfConverter.TYPE_HTML.equalsIgnoreCase(typeOutput)) {
|
||||
output = PdfConverter.convert(output.toPath(), typeOutput).toFile();
|
||||
|
@ -222,6 +236,7 @@ public class ReportTemplateController extends BaseController {
|
|||
}
|
||||
|
||||
FileDownloader.downloadTempFile(response, output, attname);
|
||||
return null;
|
||||
}
|
||||
|
||||
@GetMapping("/report-templates/download")
|
||||
|
@ -232,4 +247,18 @@ public class ReportTemplateController extends BaseController {
|
|||
FileDownloader.setDownloadHeaders(request, response, attname, false);
|
||||
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.web.BaseController;
|
||||
import com.rebuild.web.IdParam;
|
||||
import com.rebuild.web.admin.data.ReportTemplateController;
|
||||
import com.rebuild.web.commons.FileDownloader;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 报表/导出
|
||||
|
@ -67,10 +69,10 @@ public class ReportsController extends BaseController {
|
|||
|
||||
// 报表模板
|
||||
|
||||
@RequestMapping("report/available")
|
||||
@GetMapping("report/available")
|
||||
public JSON availableReports(@PathVariable String entity, HttpServletRequest request) {
|
||||
final ID user = getRequestUser(request);
|
||||
JSONArray res = DataReportManager.instance.getReports(
|
||||
JSONArray res = DataReportManager.instance.getReportTemplates(
|
||||
MetadataHelper.getEntity(entity),
|
||||
getIntParameter(request, "type", DataReportManager.TYPE_RECORD), user);
|
||||
|
||||
|
@ -84,16 +86,11 @@ public class ReportsController extends BaseController {
|
|||
}
|
||||
|
||||
@RequestMapping({"report/generate", "report/export"})
|
||||
public void reportGenerate(@PathVariable String entity,
|
||||
public ModelAndView reportGenerate(@PathVariable String entity,
|
||||
@IdParam(name = "report") ID reportId,
|
||||
HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
String record = getParameterNotNull(request, "record");
|
||||
List<ID> recordIds = new ArrayList<>();
|
||||
for (String id : record.split(",")) {
|
||||
if (ID.isId(id)) recordIds.add(ID.valueOf(id));
|
||||
}
|
||||
|
||||
final ID recordId = recordIds.get(0);
|
||||
final ID[] recordIds = getIdArrayParameterNotNull(request, "record");
|
||||
final ID recordId = recordIds[0];
|
||||
final TemplateFile tt = DataReportManager.instance.getTemplateFile(reportId);
|
||||
|
||||
File output = null;
|
||||
|
@ -102,9 +99,15 @@ public class ReportsController extends BaseController {
|
|||
EasyExcelGenerator33 word = (EasyExcelGenerator33) CommonsUtils.invokeMethod(
|
||||
"com.rebuild.rbv.data.WordReportGenerator#create", reportId, recordId);
|
||||
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 {
|
||||
// 支持多个
|
||||
output = EasyExcelGenerator.create(reportId, recordIds).generate();
|
||||
output = EasyExcelGenerator.create(reportId, Arrays.asList(recordIds)).generate();
|
||||
}
|
||||
|
||||
} catch (ExcelRuntimeException ex) {
|
||||
|
@ -113,6 +116,13 @@ public class ReportsController extends BaseController {
|
|||
|
||||
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 boolean isHtml = "HTML".equalsIgnoreCase(typeOutput);
|
||||
final boolean isPdf = "PDF".equalsIgnoreCase(typeOutput);
|
||||
|
@ -122,8 +132,6 @@ public class ReportsController extends BaseController {
|
|||
output = PdfConverter.convertHtml(output.toPath()).toFile();
|
||||
}
|
||||
|
||||
final String fileName = DataReportManager.getReportName(reportId, recordId, output.getName());
|
||||
|
||||
if (ServletUtils.isAjaxRequest(request)) {
|
||||
JSONObject data = JSONUtils.toJSONObject(
|
||||
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");
|
||||
FileDownloader.downloadTempFile(response, output, forcePreview ? FileDownloader.INLINE_FORCE : fileName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 列表数据导出
|
||||
|
|
|
@ -454,7 +454,6 @@
|
|||
"sudo",
|
||||
"super",
|
||||
"superuser",
|
||||
"support",
|
||||
"survey",
|
||||
"sync",
|
||||
"sysadmin",
|
||||
|
@ -503,7 +502,6 @@
|
|||
"void",
|
||||
"vote",
|
||||
"webmail",
|
||||
"webmaster",
|
||||
"website",
|
||||
"widget",
|
||||
"widgets",
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
.badge.badge-info.word {
|
||||
background-color: #307cf1;
|
||||
}
|
||||
.badge.badge-info.html5 {
|
||||
background-color: #f16529;
|
||||
background-color: #e44d26;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<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>
|
||||
</td>
|
||||
</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>
|
||||
<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('无')}]]
|
||||
</td>
|
||||
</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>
|
||||
</td>
|
||||
</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>
|
||||
<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('无')}]]
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -54,33 +54,38 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
display: none;
|
||||
}
|
||||
|
||||
.chart-box .chart-head .chart-oper a {
|
||||
.chart-box .chart-head .chart-oper > a {
|
||||
color: #000;
|
||||
opacity: 0.4;
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
margin-left: 10px;
|
||||
padding-left: 3px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.chart-box .chart-head .chart-oper a:hover {
|
||||
.chart-box .chart-head .chart-oper > a:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.chart-box .chart-head .chart-oper a .zmdi {
|
||||
.chart-box .chart-head .chart-oper > a .zmdi {
|
||||
font-size: 1.3rem;
|
||||
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;
|
||||
}
|
||||
|
||||
.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,
|
||||
.chart-box .chart-head .chart-oper > a .zmdi-fullscreen-exit {
|
||||
font-size: 1.43rem;
|
||||
}
|
||||
|
||||
.chart-box .chart-head .chart-oper .dropdown-menu {
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
.chart-undata {
|
||||
margin: 0;
|
||||
color: #999;
|
||||
|
@ -271,6 +276,10 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
top: 0;
|
||||
}
|
||||
|
||||
.chart-box.ApprovalList .progress-wrap .progress-bar {
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
.chart-box.ApprovalList .progress-wrap .progress-bar:hover {
|
||||
cursor: pointer;
|
||||
opacity: 0.8;
|
||||
|
|
|
@ -147,9 +147,9 @@ code {
|
|||
border-color: transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 0 5px 5px;
|
||||
border-left-color: #ddd;
|
||||
border-left-color: #ccc;
|
||||
margin-top: 4px;
|
||||
margin-right: -10px;
|
||||
margin-right: -8px;
|
||||
}
|
||||
|
||||
.dropdown-submenu:hover > a::after {
|
||||
|
|
|
@ -27,7 +27,7 @@ class ConfigFormDlg extends RbFormHandler {
|
|||
<div className="form-group row footer">
|
||||
<div className="col-sm-7 offset-sm-3" ref={(c) => (this._btns = c)}>
|
||||
<button className="btn btn-primary" type="button" onClick={this.confirm}>
|
||||
{$L('确定')}
|
||||
{this.confirmText || $L('确定')}
|
||||
</button>
|
||||
<a className="btn btn-link" onClick={this.hide}>
|
||||
{$L('取消')}
|
||||
|
|
|
@ -8,7 +8,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
|
||||
$(document).ready(function () {
|
||||
$('.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')
|
||||
})
|
||||
|
@ -31,7 +31,7 @@ class ReportList extends ConfigList {
|
|||
<tr key={item[0]}>
|
||||
<td>
|
||||
{isHtml5 ? (
|
||||
<a title={$L('在线模板编辑器')} href={`report-template/design?id=${item[0]}`}>
|
||||
<a title={$L('在线模板编辑')} href={`report-template/design?id=${item[0]}`}>
|
||||
{item[3]}
|
||||
</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] === 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>}
|
||||
|
||||
{outputType.includes('pdf') && <span className="badge badge-secondary badge-sm ml-1">PDF</span>}
|
||||
|
@ -97,6 +97,7 @@ class ReportEditor extends ConfigFormDlg {
|
|||
constructor(props) {
|
||||
super(props)
|
||||
this.subtitle = $L('报表模板')
|
||||
this.confirmText = this.props.isHtml5 && !this.props.id ? $L('下一步') : null
|
||||
this.hasDetail = true
|
||||
}
|
||||
|
||||
|
|
|
@ -19,26 +19,35 @@ class BaseChart extends React.Component {
|
|||
const opActions = (
|
||||
<div className="chart-oper">
|
||||
{!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" />
|
||||
</a>
|
||||
)}
|
||||
<a title={$L('刷新')} onClick={() => this.loadChartData()}>
|
||||
<i className="zmdi zmdi-refresh" />
|
||||
</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'}`} />
|
||||
</a>
|
||||
{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}`}>
|
||||
<i className="zmdi zmdi-edit" />
|
||||
|
||||
<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 && (
|
||||
<a className="dropdown-item J_chart-edit" title={$L('编辑')} href={`${rb.baseUrl}/dashboard/chart-design?id=${this.props.id}`}>
|
||||
{$L('编辑')}
|
||||
</a>
|
||||
)}
|
||||
{this.props.editable && (
|
||||
<a className="dropdown-item" title={$L('移除')} onClick={() => this.remove()}>
|
||||
{$L('移除')}
|
||||
</a>
|
||||
)}
|
||||
<a className="dropdown-item" title={$L('导出')} onClick={() => this.export()}>
|
||||
{$L('导出')}
|
||||
</a>
|
||||
)}
|
||||
{this.props.editable && (
|
||||
<a title={$L('移除')} onClick={() => this.remove()}>
|
||||
<i className="zmdi zmdi-close" />
|
||||
</a>
|
||||
)}
|
||||
</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) {
|
||||
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)
|
||||
.perfectScrollbar()
|
||||
|
||||
// let tdActive = null
|
||||
// const $els = $tb.find('tbody td').on('mousedown', function () {
|
||||
// if (tdActive === this) {
|
||||
// $(this).toggleClass('highlight')
|
||||
// return
|
||||
// }
|
||||
// tdActive = this
|
||||
// $els.removeClass('highlight')
|
||||
// $(this).addClass('highlight')
|
||||
// })
|
||||
// selected
|
||||
$tb.find('table').tableCellsSelection()
|
||||
|
||||
if (window.render_preview_chart) {
|
||||
|
|
|
@ -1091,7 +1091,7 @@ class RbList extends React.Component {
|
|||
}, 400)
|
||||
|
||||
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) => {
|
||||
|
|
|
@ -8,7 +8,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
/* !!! KEEP IT ES5 COMPATIBLE !!! */
|
||||
|
||||
// GA
|
||||
(function () {
|
||||
;(function () {
|
||||
var gaScript = document.createElement('script')
|
||||
gaScript.src = 'https://www.googletagmanager.com/gtag/js?id=G-ZCZHJPMEG7'
|
||||
gaScript.async = true
|
||||
|
@ -207,18 +207,18 @@ $(function () {
|
|||
// }
|
||||
})
|
||||
|
||||
var $addResizeHandler__calls = []
|
||||
var $addResizeHandler__cbs = []
|
||||
/**
|
||||
* 窗口 RESIZE 回调
|
||||
*/
|
||||
var $addResizeHandler = function (call) {
|
||||
typeof call === 'function' && $addResizeHandler__calls && $addResizeHandler__calls.push(call)
|
||||
var $addResizeHandler = function (callback) {
|
||||
typeof callback === 'function' && $addResizeHandler__cbs && $addResizeHandler__cbs.push(callback)
|
||||
return function () {
|
||||
if (!$addResizeHandler__calls || $addResizeHandler__calls.length === 0) return
|
||||
if (!$addResizeHandler__cbs || $addResizeHandler__cbs.length === 0) return
|
||||
// eslint-disable-next-line no-console
|
||||
if (rb.env === 'dev') console.log('Calls ' + $addResizeHandler__calls.length + ' handlers of resize ...')
|
||||
$addResizeHandler__calls.forEach(function (call) {
|
||||
call()
|
||||
if (rb.env === 'dev') console.log('Callbacks ' + $addResizeHandler__cbs.length + ' handlers of resize ...')
|
||||
$addResizeHandler__cbs.forEach(function (cb) {
|
||||
cb()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1019,7 +1019,7 @@ var $useMap = function (onLoad) {
|
|||
}
|
||||
|
||||
// 自动定位(有误差)
|
||||
var $autoLocation = function (call) {
|
||||
var $autoLocation = function (callback) {
|
||||
$useMap(function () {
|
||||
var geo = new window.BMapGL.Geolocation()
|
||||
geo.enableSDKLocation()
|
||||
|
@ -1032,7 +1032,7 @@ var $autoLocation = function (call) {
|
|||
lng: e.longitude,
|
||||
text: r ? r.address : null,
|
||||
}
|
||||
typeof call === 'function' && call(v)
|
||||
typeof callback === 'function' && callback(v)
|
||||
})
|
||||
} else {
|
||||
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/echarts.min.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>
|
||||
<th:block th:replace="~{/_include/forms}" />
|
||||
<script th:src="@{/assets/js/charts/dashboard.js}" type="text/babel"></script>
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
</script>
|
||||
<script type="text/babel">
|
||||
// clear
|
||||
window.$addResizeHandler__calls = []
|
||||
window.$addResizeHandler__cbs = []
|
||||
|
||||
$(document).ready(function () {
|
||||
// 无关闭按钮
|
||||
|
|
Loading…
Reference in a new issue