提交 5327d517 authored 作者: fit2cloud-chenyw's avatar fit2cloud-chenyw

Merge remote-tracking branch 'origin/main' into main

......@@ -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<String, Object> datasetDetail(@PathVariable String id) {
return dataSetTableService.getDatasetDetail(id);
}
@PostMapping("excel/upload")
public Map<String, Object> excelUpload(@RequestParam("file") MultipartFile file) throws Exception {
return dataSetTableService.excelSaveAndParse(file);
}
}
......@@ -31,9 +31,9 @@ public class PanelTemplateController {
return panelTemplateService.save(request);
}
@PostMapping("/deleteCircle/{id}")
public void deleteCircle(@PathVariable String id) {
panelTemplateService.deleteCircle(id);
@PostMapping("/delete/{id}")
public void delete(@PathVariable String id) {
panelTemplateService.delete(id);
}
@GetMapping("/findOne/{id}")
......
......@@ -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> datasetTable) throws Exception {
for (DatasetTable table : datasetTable) {
......@@ -434,4 +452,120 @@ public class DataSetTableService {
}
return map;
}
public Map<String, Object> excelSaveAndParse(MultipartFile file) throws Exception {
String filename = file.getOriginalFilename();
String suffix = filename.substring(filename.lastIndexOf(".") + 1);
List<TableFiled> fields = new ArrayList<>();
List<String[]> data = new ArrayList<>();
List<Map<String, Object>> 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<String, Object> 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<String, Object> 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 "";
}
}
}
......@@ -69,9 +69,9 @@ public class PanelTemplateService {
}
public void deleteCircle(String id){
public void delete(String id){
Assert.notNull(id, "id cannot be null");
extPanelTemplateMapper.deleteCircle(id);
panelTemplateMapper.deleteByPrimaryKey(id);
}
......
<template>
<div @click="handleClick">
<component
class="component"
:is="config.component"
:style="getStyle(config.style)"
:propValue="config.propValue"
:element="config"
/>
</div>
<div @click="handleClick">
<component
:is="config.component"
class="component"
:style="getStyle(config.style)"
:prop-value="config.propValue"
:element="config"
:filter="filter"
/>
</div>
</template>
<script>
......@@ -16,26 +17,30 @@ import runAnimation from '@/components/canvas/utils/runAnimation'
import { mixins } from '@/components/canvas/utils/events'
export default {
props: {
config: {
type: Object,
require: true,
},
mixins: [mixins],
props: {
config: {
type: Object,
require: true
},
mounted() {
runAnimation(this.$el, this.config.animations)
},
mixins: [mixins],
methods: {
getStyle,
filter: {
type: Object,
require: false
}
},
mounted() {
runAnimation(this.$el, this.config.animations)
},
methods: {
getStyle,
handleClick() {
const events = this.config.events
Object.keys(events).forEach(event => {
this[event](events[event])
})
},
},
handleClick() {
const events = this.config.events
Object.keys(events).forEach(event => {
this[event](events[event])
})
}
}
}
</script>
......
......@@ -43,6 +43,7 @@
:style="getComponentStyle(item.style)"
:prop-value="item.propValue"
:element="item"
:filter="filter"
/>
<!-- <component
:is="item.component"
......@@ -84,6 +85,10 @@ export default {
isEdit: {
type: Boolean,
default: true
},
filter: {
type: Object,
require: false
}
},
data() {
......
......@@ -15,6 +15,20 @@ export default {
props: {
element: {
type: Object
},
filter: {
type: Object,
required: false,
default: function() {
return {
filter: []
}
}
}
},
watch: {
filter(val) {
this.getData(this.element.propValue.viewId)
}
},
data() {
......@@ -31,7 +45,7 @@ export default {
methods: {
getData(id) {
if (id) {
post('/chart/view/getData/' + id, {}).then(response => {
post('/chart/view/getData/' + id, this.filter).then(response => {
// 将视图传入echart组件
this.chart = response.data
})
......
......@@ -783,7 +783,8 @@ export default {
detail: '详情',
type: '类型',
create_by: '创建者',
create_time: '创建时间'
create_time: '创建时间',
preview_100_data: '预览前100行数据'
},
datasource: {
datasource: '数据源',
......
......@@ -20,7 +20,11 @@ export default {
chart: {
type: Object,
required: true
}
},
filter: {
type: Object,
required: false
}
},
data() {
return {
......
......@@ -9,7 +9,7 @@
<el-button size="mini" @click="cancel">
{{ $t('dataset.cancel') }}
</el-button>
<el-button size="mini" type="primary" @click="save">
<el-button :disabled="!form.name || fileList.length === 0" size="mini" type="primary" @click="save">
{{ $t('dataset.confirm') }}
</el-button>
</el-row>
......@@ -24,11 +24,14 @@
</el-form-item>
<el-form-item>
<el-upload
action="/posts/"
:action="baseUrl+'dataset/table/excel/upload'"
:multiple="false"
:show-file-list="false"
:file-list="fileList"
accept=".xls,.xlsx,.csv"
:on-success="uploadSuccess"
name="file"
:headers="headers"
>
<el-button size="mini" type="primary">{{ $t('dataset.upload_file') }}</el-button>
</el-upload>
......@@ -42,6 +45,7 @@
<el-card class="box-card dataPreview" shadow="never">
<div slot="header" class="clearfix">
<span>{{ $t('dataset.data_preview') }}</span>
<span style="font-size: 12px;color: #3d4d66;">{{ $t('dataset.preview_100_data') }}</span>
</div>
<div class="text item">
<ux-grid
......@@ -70,6 +74,9 @@
<script>
import { post } from '@/api/dataset/dataset'
import { getToken } from '@/utils/auth'
const token = getToken()
export default {
name: 'AddExcel',
......@@ -85,8 +92,12 @@ export default {
name: ''
},
fields: [],
data: [],
mode: '1',
height: 600
height: 600,
fileList: [],
headers: { Authorization: token },
baseUrl: process.env.VUE_APP_BASE_API
}
},
watch: {
......@@ -120,6 +131,18 @@ export default {
// },
uploadSuccess(response, file, fileList) {
console.log(response)
console.log(file)
console.log(fileList)
this.fields = response.data.fields
this.data = response.data.data
const datas = this.data
this.$refs.plxTable.reloadData(datas)
if (file.name.lastIndexOf('.') > 0) {
this.form.name = file.name.substring(0, file.name.lastIndexOf('.'))
}
this.fileList = fileList
},
save() {
......
......@@ -38,7 +38,7 @@
:visible.sync="templateSaveShow"
custom-class="de-dialog"
>
<save-to-template />
<save-to-template :template-info="templateInfo" @closeSaveDialog="closeSaveDialog" />
</el-dialog>
</el-row>
</template>
......@@ -87,12 +87,16 @@ export default {
this.templateSaveShow = true
html2canvas(this.$refs.imageWrapper).then(canvas => {
debugger
const snapShot = canvas.toDataURL('image/jpeg', 0.2) // 0.2是图片质量
if (snapShot !== '') {
const snapshot = canvas.toDataURL('image/jpeg', 0.2) // 0.2是图片质量
if (snapshot !== '') {
this.templateInfo = {
snapShot: snapShot,
panelStyle: JSON.stringify(this.canvasStyleData),
panelData: JSON.stringify(this.componentData),
name: this.$store.state.panel.panelInfo.name,
snapshot: snapshot,
templateStyle: JSON.stringify(this.canvasStyleData),
templateData: JSON.stringify(this.componentData),
templateType: 'self',
level: 1,
pid: null,
dynamicData: ''
}
}
......@@ -104,6 +108,8 @@ export default {
const snapShot = canvas.toDataURL('image/jpeg', 0.2) // 0.2是图片质量
if (snapShot !== '') {
this.templateInfo = {
name: this.$store.state.panel.panelInfo.name,
templateType: 'self',
snapShot: snapShot,
panelStyle: JSON.stringify(this.canvasStyleData),
panelData: JSON.stringify(this.componentData),
......@@ -128,6 +134,9 @@ export default {
}
}
})
},
closeSaveDialog() {
this.templateSaveShow = false
}
}
......
<template>
<el-row>
<el-row>
<el-input v-model="name" placeholder="名称" />
<el-col span="4">模板名称</el-col>
<el-col span="20">
<el-input v-model="templateInfo.name" clearable size="mini" />
</el-col>
</el-row>
<el-row class="de-tab">
<div class="my_table">
......@@ -15,9 +18,9 @@
>
<el-table-column :label="columnLabel" :column-key="fieldName" :prop="fieldName" />
<el-table-column align="right">
<template slot="header">
<el-input v-model="keyWordSearch" size="mini" placeholder="输入关键字搜索" />
</template>
<!-- <template slot="header">-->
<!-- <el-input v-model="keyWordSearch" size="mini" placeholder="输入关键字搜索" />-->
<!-- </template>-->
<template slot-scope="scope">
<el-radio v-model="tableRadio" :label="scope.row"><i /></el-radio>
</template>
......@@ -26,8 +29,8 @@
</div>
</el-row>
<el-row class="root-class">
<el-button @click="cancel">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
<el-button @click="cancel()">取 消</el-button>
<el-button type="primary" @click="save()">确 定</el-button>
</el-row>
</el-row>
</template>
......@@ -37,10 +40,15 @@ import { post } from '@/api/panel/panel'
export default {
name: 'SaveToTemplate',
props: {
templateInfo: {
type: Object,
require: true
}
},
data() {
return {
data: [],
name: '',
fieldName: 'name',
tableRadio: null,
keyWordSearch: '',
......@@ -53,26 +61,37 @@ export default {
methods: {
search() {
const param = {
template_type: 'self',
templateType: 'self',
level: '0'
}
post('/template/templateList', param).then(response => {
this.data = response.data
})
},
setCheckNodes() {
this.data.forEach(node => {
const nodeId = node.userId
this.shares.includes(nodeId) && this.$refs.table.toggleRowSelection(node, true)
})
},
clickChange(item) {
this.tableRadio = item
this.templateInfo.pid = item.id
},
cancel() {
this.$refs[this.activeName].cancel()
this.$emit('close-grant', 0)
this.$emit('closeSaveDialog')
},
save() {
if (!this.templateInfo.pid) {
this.$warning('请选择所属类别')
return false
}
if (!this.templateInfo.name) {
this.$warning('模板名称不能为空')
return false
}
post('/template/save', this.templateInfo).then(response => {
this.$message({
message: '保存成功',
type: 'success',
showClose: true
})
this.$emit('closeSaveDialog')
})
}
}
......
<template xmlns:el-col="http://www.w3.org/1999/html">
<el-col>
<el-row>
<div class="block">
<el-form>
<el-form-item class="form-item">
<el-input
v-model="systemTemplateFilterText"
placeholder="输入关键字进行过滤"
size="mini"
clearable
prefix-icon="el-icon-search"
/>
</el-form-item>
</el-form>
<el-button icon="el-icon-folder-add" type="primary" size="mini" @click="add()">
添加分类
</el-button>
</el-row>
<el-row style="margin-top: 5px">
<el-row>
<el-input
v-model="systemTemplateFilterText"
placeholder="输入关键字进行过滤"
size="mini"
clearable
prefix-icon="el-icon-search"
/>
</el-row>
<el-row style="margin-top: 5px">
<el-tree
ref="systemTemplateTree"
:default-expanded-keys="defaultExpandedKeys"
......@@ -27,7 +30,7 @@
<span>
<span>
<el-button
icon="el-icon-picture-outline"
icon="el-icon-collection"
type="text"
/>
</span>
......@@ -35,22 +38,27 @@
</span>
</span>
</el-tree>
</div>
</el-row>
</el-row>
</el-col>
</template>
<script>
import { get, post } from '@/api/panel/panel'
export default {
name: 'SystemTemplateList',
components: { },
props: {
systemTemplateList: {
type: Array,
default: function() {
return []
}
}
},
data() {
return {
systemTemplateFilterText: '',
defaultExpandedKeys: [],
systemTemplateList: [],
currentTemplateShowList: []
}
},
......@@ -62,33 +70,18 @@ export default {
this.$refs.systemTemplateTree.filter(val)
}
},
mounted() {
this.getTree()
},
methods: {
filterNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
},
getTree() {
const request = {
templateType: 'system',
level: '0'
}
post('/template/templateList', request).then(res => {
this.systemTemplateList = res.data
if (this.systemTemplateList && this.systemTemplateList.length > 0) {
const id = this.systemTemplateList[0].id
// this.currentNodeKey = id
// this.$refs['systemTemplateTree'].setCurrentKey(id)
this.$emit('showCurrentTemplate', id)
}
})
},
nodeClick(data, node) {
console.log('nodeClick')
debugger
this.$emit('showCurrentTemplate', data.id)
},
add() {
this.$emit('showTemplateEditDialog', 'new')
}
}
}
......
<template>
<div class="testcase-template">
<div :style="classBackground" class="template-img">
<div class="template-img" :style="classBackground">
<i class="el-icon-error" @click.stop="templateDelete" />
</div>
<span class="demonstration">{{ template.name }}</span>
......@@ -23,13 +23,23 @@ export default {
classBackground() {
return {
background: `url(${this.template.snapshot}) no-repeat`,
'background-size': '100%,100%'
'background-size': `100% 100%`
}
}
},
methods: {
templateDelete() {
console.log('templateDelete')
this.$alert('是否删除模板:' + this.template.name + '?', '', {
confirmButtonText: '确认',
callback: (action) => {
if (action === 'confirm') {
this.$emit('templateDelete', this.template.id)
}
}
})
},
templateEdit() {
this.$emit('templateEdit', this.template)
},
handleDelete() {
console.log('handleDelete')
......@@ -57,14 +67,13 @@ export default {
}
.template-img {
height: 150px;
height: 130px;
width: 200px;
margin: 0 auto;
box-shadow: 0 0 2px 0 rgba(31,31,31,0.15), 0 1px 2px 0 rgba(31,31,31,0.15);
border: solid 2px #fff;
box-sizing: border-box;
border-radius: 3px;
background-size: 100%,100%;
}
.template-img:hover {
......
<template>
<de-container>
<de-aside-container>
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane name="SystemTemplate">
<el-tabs v-model="currentTemplateType" @tab-click="handleClick">
<el-tab-pane name="system">
<span slot="label"><i class="el-icon-document" />系统模板</span>
<system-template-list @showCurrentTemplate="showCurrentTemplate" />
<system-template-list :system-template-list="systemTemplateList" @showTemplateEditDialog="showTemplateEditDialog" />
</el-tab-pane>
<el-tab-pane name="UserTemplate">
<el-tab-pane name="self">
<span slot="label"><i class="el-icon-star-off" />用户模板</span>
开发中...
</el-tab-pane>
</el-tabs>
</de-aside-container>
<de-main-container>
<!-- <el-card class="el-card-template">-->
<template-item
v-for="item in currentTemplateShowList"
:key="item.id"
:template="item"
@templateDelete="templateDelete"
@templateEdit="templateEdit"
/>
<!-- </el-card>-->
</de-main-container>
<el-dialog :title="dialogTitle" :visible="editTemplate" :show-close="false" width="30%">
<el-form ref="templateEditForm" :model="templateEditForm" :rules="templateEditFormRules">
<el-form-item label="名称" prop="name">
<el-input v-model="templateEditForm.name" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="mini" @click="close()">{{ $t('panel.cancel') }}</el-button>
<el-button type="primary" size="mini" @click="saveTemplateEdit(templateEditForm)">{{ $t('panel.confirm') }}
</el-button>
</div>
</el-dialog>
</de-container>
</template>
......@@ -31,38 +43,106 @@ import DeAsideContainer from '@/components/dataease/DeAsideContainer'
import SystemTemplateList from './component/SystemTemplateList'
import TemplateItem from './component/TemplateItem'
import { get, post } from '@/api/panel/panel'
import { deepCopy } from '../../../components/canvas/utils/utils'
export default {
name: 'PanelMain',
components: { DeMainContainer, DeContainer, DeAsideContainer, SystemTemplateList, TemplateItem },
data() {
return {
activeName: 'SystemTemplate',
showShare: false,
currentTemplateShowList: []
currentTemplateShowList: [],
currentPid: '',
currentTemplateType: 'system',
templateEditFormRules: {
name: [
{ required: true, message: this.$t('commons.input_content'), trigger: 'change' }
]
},
templateEditForm: {},
editTemplate: false,
dialogTitle: '',
systemTemplateList: []
}
},
mounted() {
this.getTree()
},
methods: {
handleClick(tab, event) {
// 点击分析面板需要刷新分享内容
if (tab.name === 'panels_share') {
this.refreshShare()
},
showCurrentTemplate(pid) {
this.currentPid = pid
if (this.currentPid) {
post('/template/templateList', { pid: this.currentPid }).then(response => {
this.currentTemplateShowList = response.data
})
}
},
refreshShare() {
this.showShare = false
this.$nextTick(() => (this.showShare = true))
templateDelete(id) {
if (id) {
post('/template/delete/' + id, null).then(response => {
this.$message({
message: '删除成功',
type: 'success',
showClose: true
})
this.showCurrentTemplate(this.currentPid)
})
}
},
get() {
this.showShare = false
this.$nextTick(() => (this.showShare = true))
saveTemplate(templateEditForm) {
if (templateEditForm) {
post('/template/save', templateEditForm).then(response => {
this.$message({
message: '删除成功',
type: 'success',
showClose: true
})
this.showCurrentTemplate(this.currentPid)
})
}
},
showCurrentTemplate(currentPid) {
if (currentPid) {
post('/template/templateList', { pid: currentPid }).then(response => {
this.currentTemplateShowList = response.data
showTemplateEditDialog(type, templateInfo) {
if (type === 'edit') {
this.dialogTitle = '编辑'
this.templateEditForm = deepCopy(templateInfo)
} else {
this.dialogTitle = '新建'
this.templateEditForm = { name: '', templateType: this.currentTemplateType, level: 0 }
}
this.editTemplate = true
},
templateEdit(templateInfo) {
this.showTemplateEditDialog('edit', templateInfo)
},
saveTemplateEdit(templateEditForm) {
debugger
post('/template/save', templateEditForm).then(response => {
this.$message({
message: '保存成功',
type: 'success',
showClose: true
})
this.editTemplate = false
this.getTree()
})
},
close() {
this.editTemplate = false
},
getTree() {
const request = {
templateType: this.currentTemplateType,
level: '0'
}
post('/template/templateList', request).then(res => {
this.systemTemplateList = res.data
if (this.systemTemplateList && this.systemTemplateList.length > 0) {
this.showCurrentTemplate(this.systemTemplateList[0].id)
}
})
}
}
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论