diff --git a/backend/src/main/java/io/dataease/controller/dataset/DataSetTableController.java b/backend/src/main/java/io/dataease/controller/dataset/DataSetTableController.java index 91e8d5a3dc..3d491518ba 100644 --- a/backend/src/main/java/io/dataease/controller/dataset/DataSetTableController.java +++ b/backend/src/main/java/io/dataease/controller/dataset/DataSetTableController.java @@ -7,6 +7,7 @@ import io.dataease.controller.request.dataset.DataSetTableRequest; import io.dataease.datasource.dto.TableFiled; import io.dataease.service.dataset.DataSetTableService; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import java.util.List; @@ -86,4 +87,9 @@ public class DataSetTableController { public Map datasetDetail(@PathVariable String id) { return dataSetTableService.getDatasetDetail(id); } + + @PostMapping("excel/upload") + public Map excelUpload(@RequestParam("file") MultipartFile file) throws Exception { + return dataSetTableService.excelSaveAndParse(file); + } } diff --git a/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java b/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java index 0ca76754fe..2851e3cc9e 100644 --- a/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java +++ b/backend/src/main/java/io/dataease/service/dataset/DataSetTableService.java @@ -18,10 +18,26 @@ import io.dataease.dto.dataset.DataTableInfoDTO; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import java.io.*; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; import java.sql.ResultSet; +import java.text.DecimalFormat; import java.text.MessageFormat; import java.util.*; import java.util.stream.Collectors; @@ -42,6 +58,8 @@ public class DataSetTableService { private DataSetTableTaskService dataSetTableTaskService; @Resource private DatasetTableIncrementalConfigMapper datasetTableIncrementalConfigMapper; + @Value("${upload.file.path}") + private String path; public void batchInsert(List datasetTable) throws Exception { for (DatasetTable table : datasetTable) { @@ -434,4 +452,120 @@ public class DataSetTableService { } return map; } + + public Map excelSaveAndParse(MultipartFile file) throws Exception { + String filename = file.getOriginalFilename(); + String suffix = filename.substring(filename.lastIndexOf(".") + 1); + + List fields = new ArrayList<>(); + List data = new ArrayList<>(); + List> jsonArray = new ArrayList<>(); + + InputStream inputStream = file.getInputStream(); + if (StringUtils.equalsIgnoreCase(suffix, "xls")) { + HSSFWorkbook workbook = new HSSFWorkbook(inputStream); + HSSFSheet sheet0 = workbook.getSheetAt(0); + if (sheet0.getNumMergedRegions() > 0) { + throw new RuntimeException("Sheet have merged regions."); + } + int rows = Math.min(sheet0.getPhysicalNumberOfRows(), 100); + for (int i = 0; i < rows; i++) { + HSSFRow row = sheet0.getRow(i); + String[] r = new String[row.getPhysicalNumberOfCells()]; + for (int j = 0; j < row.getPhysicalNumberOfCells(); j++) { + if (i == 0) { + TableFiled tableFiled = new TableFiled(); + tableFiled.setFieldName(readCell(row.getCell(j))); + tableFiled.setRemarks(readCell(row.getCell(j))); + fields.add(tableFiled); + } else { + r[j] = readCell(row.getCell(j)); + } + } + if (i > 0) { + data.add(r); + } + } + } else if (StringUtils.equalsIgnoreCase(suffix, "xlsx")) { + XSSFWorkbook xssfWorkbook = new XSSFWorkbook(inputStream); + XSSFSheet sheet0 = xssfWorkbook.getSheetAt(0); + if (sheet0.getNumMergedRegions() > 0) { + throw new RuntimeException("Sheet have merged regions."); + } + int rows = Math.min(sheet0.getPhysicalNumberOfRows(), 100); + for (int i = 0; i < rows; i++) { + XSSFRow row = sheet0.getRow(i); + String[] r = new String[row.getPhysicalNumberOfCells()]; + for (int j = 0; j < row.getPhysicalNumberOfCells(); j++) { + if (i == 0) { + TableFiled tableFiled = new TableFiled(); + tableFiled.setFieldName(readCell(row.getCell(j))); + tableFiled.setRemarks(readCell(row.getCell(j))); + fields.add(tableFiled); + } else { + r[j] = readCell(row.getCell(j)); + } + } + if (i > 0) { + data.add(r); + } + } + } else if (StringUtils.equalsIgnoreCase(suffix, "csv")) { + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + String s = reader.readLine();// first line + String[] split = s.split(","); + for (String s1 : split) { + TableFiled tableFiled = new TableFiled(); + tableFiled.setFieldName(s1); + tableFiled.setRemarks(s1); + fields.add(tableFiled); + } + int num = 1; + String line = null; + while ((line = reader.readLine()) != null) { + if (num > 100) { + break; + } + data.add(line.split(",")); + num++; + } + } + + String[] fieldArray = fields.stream().map(TableFiled::getFieldName).toArray(String[]::new); + if (CollectionUtils.isNotEmpty(data)) { + jsonArray = data.stream().map(ele -> { + Map map = new HashMap<>(); + for (int i = 0; i < ele.length; i++) { + map.put(fieldArray[i], ele[i]); + } + return map; + }).collect(Collectors.toList()); + } + inputStream.close(); + + Map map = new HashMap<>(); + map.put("fields", fields); + map.put("data", jsonArray); + + return map; + } + + private String readCell(Cell cell) { + CellType cellTypeEnum = cell.getCellTypeEnum(); + if (cellTypeEnum.equals(CellType.STRING)) { + return cell.getStringCellValue(); + } else if (cellTypeEnum.equals(CellType.NUMERIC)) { + double d = cell.getNumericCellValue(); + try { + return new Double(d).longValue() + ""; + } catch (Exception e) { + BigDecimal b = new BigDecimal(d); + return b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue() + ""; + } + } else if (cellTypeEnum.equals(CellType.BOOLEAN)) { + return cell.getBooleanCellValue() ? "1" : "0"; + } else { + return ""; + } + } } diff --git a/frontend/src/api/link/index.js b/frontend/src/api/link/index.js index 5c16783800..57b5e1933d 100644 --- a/frontend/src/api/link/index.js +++ b/frontend/src/api/link/index.js @@ -48,3 +48,10 @@ export function loadGenerate(resourceId) { method: 'post' }) } + +export function loadResource(resourceId) { + return request({ + url: 'panel/group/findOne/' + resourceId, + method: 'get' + }) +} diff --git a/frontend/src/components/canvas/components/Editor/index.vue b/frontend/src/components/canvas/components/Editor/index.vue index 1767d5438f..b209b4d560 100644 --- a/frontend/src/components/canvas/components/Editor/index.vue +++ b/frontend/src/components/canvas/components/Editor/index.vue @@ -324,7 +324,15 @@ export default { this.addCondition(condition) }, addCondition(condition) { - this.conditions.push(condition) + let conditionExist = false + for (let index = 0; index < this.conditions.length; index++) { + const element = this.conditions[index] + if (condition.componentId === element.componentId) { + this.conditions[index] = condition + conditionExist = true + } + } + !conditionExist && this.conditions.push(condition) this.executeSearch() }, deleteCondition(condition) { diff --git a/frontend/src/lang/zh.js b/frontend/src/lang/zh.js index 017ac5e402..be3033c3a0 100644 --- a/frontend/src/lang/zh.js +++ b/frontend/src/lang/zh.js @@ -783,7 +783,8 @@ export default { detail: '详情', type: '类型', create_by: '创建者', - create_time: '创建时间' + create_time: '创建时间', + preview_100_data: '预览前100行数据' }, datasource: { datasource: '数据源', diff --git a/frontend/src/link/Link.vue b/frontend/src/link/Link.vue index e00d2fd5d5..7ee67c92eb 100644 --- a/frontend/src/link/Link.vue +++ b/frontend/src/link/Link.vue @@ -1,5 +1,5 @@ + + diff --git a/frontend/src/views/panel/filter/filterDialog.vue b/frontend/src/views/panel/filter/filterDialog.vue index d818777bf5..38b2b33039 100644 --- a/frontend/src/views/panel/filter/filterDialog.vue +++ b/frontend/src/views/panel/filter/filterDialog.vue @@ -12,12 +12,12 @@ - - 按组件选择 + +
+ + + {{ bread.label }} + {{ bread.label }} + + +
+ +
+ + + + + + +
+ + +
+ + {{ item.name }} +
+
+
+
+
+
@@ -200,12 +254,18 @@ export default { return { activeName: 'dataset', showDomType: 'tree', + comShowDomType: 'view', dataSetBreads: [ { label: '数据列表', link: false, type: 'root' } ], + componentSetBreads: [ + { label: '组件列表', link: false, type: 'root' } + ], data: [], sceneDatas: [], + // viewDatas: [], fieldDatas: [], + comFieldDatas: [], defaultProps: { children: 'children', label: 'label' @@ -319,15 +379,28 @@ export default { tail.type = node.type tail.link = true }, + comSetTailLink(node) { + const tail = this.componentSetBreads[this.componentSetBreads.length - 1] + tail.type = node.type + tail.link = true + }, addTail(node) { const tail = { link: false, label: node.label || node.name, type: node.type } this.dataSetBreads.push(tail) }, + comAddTail(node) { + const tail = { link: false, label: node.label || node.name, type: node.type } + this.componentSetBreads.push(tail) + }, removeTail() { this.dataSetBreads = this.dataSetBreads.slice(0, this.dataSetBreads.length - 1) this.dataSetBreads[this.dataSetBreads.length - 1]['link'] = false }, + comRemoveTail() { + this.componentSetBreads = this.componentSetBreads.slice(0, this.componentSetBreads.length - 1) + this.componentSetBreads[this.componentSetBreads.length - 1]['link'] = false + }, backToLink(bread) { if (bread.type === 'db') { this.showDomType = 'db' @@ -337,6 +410,10 @@ export default { this.removeTail() }, + comBackLink(bread) { + this.comShowDomType = 'view' + this.comRemoveTail() + }, loadTable(sceneId) { loadTable({ sceneId: sceneId, sort: 'type asc,create_time desc,name asc' }).then(res => { this.sceneDatas = res.data @@ -352,13 +429,27 @@ export default { this.fieldDatas = datas }) }, + comLoadField(tableId) { + fieldList(tableId).then(res => { + let datas = res.data + if (this.widget && this.widget.filterFieldMethod) { + datas = this.widget.filterFieldMethod(datas) + } + this.comFieldDatas = datas + }) + }, showFieldDatas(row) { this.showDomType = 'field' this.setTailLink(row) this.addTail(row) this.loadField(row.id) }, - test(row) {}, + comShowFieldDatas(row) { + this.comShowDomType = 'field' + this.comSetTailLink(row) + this.comAddTail(row) + this.comLoadField(row.tableId) + }, onMove(e, originalEvent) { this.moveId = e.draggedContext.element.id return true