Merge pull request #10463 from dataease/dev

merge 1.18.22
This commit is contained in:
fit2cloudrd 2024-06-24 14:24:38 +08:00 committed by GitHub
commit ccbc5079e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 706 additions and 110 deletions

View File

@ -3,6 +3,7 @@ package io.dataease.controller.datafill;
import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.gson.Gson;
import io.dataease.commons.utils.AuthUtils;
import io.dataease.commons.utils.PageUtils;
import io.dataease.commons.utils.Pager;
@ -25,10 +26,7 @@ import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;
@ApiIgnore
@RequestMapping("dataFilling")
@ -193,20 +191,33 @@ public class DataFillController {
@ApiIgnore
@PostMapping("/form/{formId}/excel/template")
public void getExcelTemplate(@PathVariable String formId, HttpServletResponse response) throws Exception {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码
String fileName = URLEncoder.encode("template", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 这里需要设置不关闭流
EasyExcel.write(response.getOutputStream())
.head(dataFillService.getExcelHead(formId))
.automaticMergeHead(false)
.inMemory(true)
.registerWriteHandler(dataFillService.getCommentWriteHandler(formId))
.autoCloseStream(Boolean.FALSE)
.sheet("模板")
.doWrite(new ArrayList());
try {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码
String fileName = URLEncoder.encode("template", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 这里需要设置不关闭流
EasyExcel.write(response.getOutputStream())
.head(dataFillService.getExcelHead(formId))
.automaticMergeHead(false)
.inMemory(true)
.registerWriteHandler(dataFillService.getCommentWriteHandler(formId))
.autoCloseStream(Boolean.FALSE)
.sheet("模板")
.doWrite(new ArrayList());
} catch (Exception e) {
e.printStackTrace();
// 重置response
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.setStatus(500);
Map<String, Object> map = new HashMap<>();
map.put("success", false);
map.put("message", e.getMessage());
response.getWriter().println(new Gson().toJson(map));
}
}
@ApiIgnore
@ -216,4 +227,10 @@ public class DataFillController {
dataFillDataService.importExcelData(file, formId);
}
@ApiIgnore
@PostMapping("/form/{optionDatasource}/{optionTable}/{optionColumn}/options/{optionOrder}")
public List<ExtTableField.Option> listColumnData(@PathVariable String optionDatasource, @PathVariable String optionTable, @PathVariable String optionColumn, @PathVariable String optionOrder) throws Exception {
return dataFillDataService.listColumnData(optionDatasource, optionTable, optionColumn, optionOrder);
}
}

View File

@ -575,6 +575,7 @@ public class JdbcProvider extends DefaultJdbcProvider {
if (StringUtils.isNotEmpty(hiveConfiguration.getAuthMethod()) && hiveConfiguration.getAuthMethod().equalsIgnoreCase("kerberos")) {
System.setProperty("java.security.krb5.conf", "/opt/dataease/conf/krb5.conf");
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
ExtendedJdbcClassLoader classLoader;
if (isDefaultClassLoader(customDriver)) {
classLoader = extendedJdbcClassLoader;

View File

@ -89,6 +89,18 @@ public class MysqlExtDDLProvider extends DefaultExtDDLProvider {
return baseSql;
}
@Override
public String searchColumnData(String table, String column, String order) {
String baseSql = "SELECT DISTINCT `$Column_Field$` FROM `$TABLE_NAME$` ORDER BY `$Column_Field$` $Column_Order$;";
baseSql = baseSql.replace("$TABLE_NAME$", table).replace("$Column_Field$", column).replace("$Column_Field$", column);
if (StringUtils.equalsIgnoreCase(order, "desc")) {
baseSql = baseSql.replace("$Column_Order$", "DESC");
} else {
baseSql = baseSql.replace("$Column_Order$", "ASC");
}
return baseSql;
}
@Override
public String whereSql(String tableName, List<TableField> searchFields) {
StringBuilder builder = new StringBuilder("WHERE 1 = 1 ");

View File

@ -689,6 +689,35 @@ public class DataFillDataService {
return rowId;
}
public List<ExtTableField.Option> listColumnData(String optionDatasource, String optionTable, String optionColumn, String optionOrder) throws Exception {
Datasource ds = datasource.get(optionDatasource);
Provider datasourceProvider = ProviderFactory.getProvider(ds.getType());
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setDatasource(ds);
ExtDDLProvider extDDLProvider = ProviderFactory.gerExtDDLProvider(ds.getType());
String sql = extDDLProvider.searchColumnData(optionTable, optionColumn, optionOrder);
datasourceRequest.setQuery(sql);
List<String[]> data = datasourceProvider.getData(datasourceRequest);
List<ExtTableField.Option> result = new ArrayList<>();
for (String[] datum : data) {
ExtTableField.Option option = new ExtTableField.Option();
if (StringUtils.isBlank(datum[0])) {
continue;
}
option.setName(datum[0]);
option.setValue(datum[0]);
result.add(option);
}
return result;
}
@Data
public static class ExcelDataListener extends AnalysisEventListener<Map<Integer, String>> {
private List<List<String>> data = new ArrayList<>();
@ -840,7 +869,16 @@ public class DataFillDataService {
default:
if (StringUtils.equalsIgnoreCase(field.getType(), "select") && !field.getSettings().isMultiple() || StringUtils.equalsIgnoreCase(field.getType(), "radio")) {
boolean has = false;
for (ExtTableField.Option option : field.getSettings().getOptions()) {
List<ExtTableField.Option> options = field.getSettings().getOptions();
if (field.getSettings().getOptionSourceType() == 2
&& StringUtils.isNotBlank(field.getSettings().getOptionDatasource())
&& StringUtils.isNotBlank(field.getSettings().getOptionTable())
&& StringUtils.isNotBlank(field.getSettings().getOptionColumn())
) {
options = listColumnData(field.getSettings().getOptionDatasource(), field.getSettings().getOptionTable(), field.getSettings().getOptionColumn(), field.getSettings().getOptionOrder());
}
for (ExtTableField.Option option : options) {
if (StringUtils.equals((String) option.getValue(), excelRowData)) {
has = true;
break;
@ -867,9 +905,19 @@ public class DataFillDataService {
List<String> result = new ArrayList<>();
if (CollectionUtils.isNotEmpty(list)) {
List<ExtTableField.Option> options = field.getSettings().getOptions();
if (field.getSettings().getOptionSourceType() == 2
&& StringUtils.isNotBlank(field.getSettings().getOptionDatasource())
&& StringUtils.isNotBlank(field.getSettings().getOptionTable())
&& StringUtils.isNotBlank(field.getSettings().getOptionColumn())
) {
options = listColumnData(field.getSettings().getOptionDatasource(), field.getSettings().getOptionTable(), field.getSettings().getOptionColumn(), field.getSettings().getOptionOrder());
}
for (String str : list) {
boolean has = false;
for (ExtTableField.Option option : field.getSettings().getOptions()) {
for (ExtTableField.Option option : options) {
if (StringUtils.equals((String) option.getValue(), str)) {
has = true;
break;
@ -877,6 +925,8 @@ public class DataFillDataService {
}
if (has) {
result.add(str);
} else {
DataEaseException.throwException("[" + field.getSettings().getName() + "] 输入值[" + str + "]不在范围内");
}
}
if (CollectionUtils.isEmpty(result)) {

View File

@ -527,6 +527,21 @@ public class DataFillService {
ExtTableField end = gson.fromJson(gson.toJson(field), ExtTableField.class);
end.getSettings().getMapping().setColumnName(end.getSettings().getMapping().getColumnName2());
fields.add(end);
} else if (StringUtils.equalsIgnoreCase(field.getType(), "select") || StringUtils.equalsIgnoreCase(field.getType(), "radio") || StringUtils.equalsIgnoreCase(field.getType(), "checkbox")) {
if (field.getSettings().getOptionSourceType() == 2
&& StringUtils.isNotBlank(field.getSettings().getOptionDatasource())
&& StringUtils.isNotBlank(field.getSettings().getOptionTable())
&& StringUtils.isNotBlank(field.getSettings().getOptionColumn())
) {
List<ExtTableField.Option> columnData = new ArrayList<>();
try {
columnData = dataFillDataService.listColumnData(field.getSettings().getOptionDatasource(), field.getSettings().getOptionTable(), field.getSettings().getOptionColumn(), field.getSettings().getOptionOrder());
} catch (Exception e) {
e.printStackTrace();
}
field.getSettings().setOptions(columnData);
}
fields.add(field);
} else {
fields.add(field);
}

View File

@ -2,6 +2,7 @@ package io.dataease.service.exportCenter;
import com.google.gson.Gson;
import io.dataease.auth.api.dto.CurrentUserDto;
import io.dataease.auth.service.AuthUserService;
import io.dataease.commons.constants.ParamConstants;
import io.dataease.commons.constants.SysLogConstants;
import io.dataease.commons.utils.*;
@ -124,7 +125,8 @@ public class ExportCenterService {
private int corePoolSize = 10;
private int keepAliveSeconds = 600;
private Map<String, Future> Running_Task = new HashMap<>();
@Resource
private AuthUserService authUserService;
@Autowired
private WsService wsService;
@ -394,11 +396,10 @@ public class ExportCenterService {
}
private void startViewTask(ExportTask exportTask, PanelViewDetailsRequest request) {
String dataPath = exportData_path + exportTask.getId();
File directory = new File(dataPath);
boolean isCreated = directory.mkdir();
CurrentUserDto currentUserDto = AuthUtils.getUser();
CurrentUserDto currentUserDto = (CurrentUserDto) authUserService.getUserById(exportTask.getUserId());
Future future = scheduledThreadPoolExecutor.submit(() -> {
AuthUtils.setUser(currentUserDto);
try {
@ -597,7 +598,9 @@ public class ExportCenterService {
String dataPath = exportData_path + exportTask.getId();
File directory = new File(dataPath);
boolean isCreated = directory.mkdir();
CurrentUserDto user = (CurrentUserDto) authUserService.getUserById(exportTask.getUserId());
Future future = scheduledThreadPoolExecutor.submit(() -> {
AuthUtils.setUser(user);
try {
exportTask.setExportStatus("IN_PROGRESS");
exportTaskMapper.updateByPrimaryKey(exportTask);

View File

@ -303,4 +303,13 @@ export function downloadFile(id) {
})
}
export default { loadTable, getScene, addGroup, delGroup, addTable, delTable, groupTree, checkCustomDs, exportDataset }
export function getColumnList(datasource, table) {
return request({
url: 'dataset/table/getFields',
method: 'post',
loading: true,
data: { dataSourceId: datasource, info: JSON.stringify({ table: table }) }
})
}
export default { loadTable, getScene, addGroup, delGroup, addTable, delTable, groupTree, checkCustomDs, exportDataset, getColumnList }

View File

@ -163,4 +163,14 @@ export function getDatasourceDetail(id) {
method: 'post'
})
}
export default { getDatasourceDetail, dsGrid, addDs, editDs, delDs, validateDs, listDatasource, getSchema }
export function getTableList(datasource) {
return request({
url: 'datasource/getTables/' + datasource,
method: 'post',
loading: true,
data: {}
})
}
export default { getDatasourceDetail, dsGrid, addDs, editDs, delDs, validateDs, listDatasource, getSchema, getTableList }

View File

@ -322,6 +322,7 @@ export default {
'letterSpacing'
],
scaleWidth: '100',
scaleWidthLay: '100',
scaleHeight: '100',
timer: null,
componentDataShow: [],
@ -451,7 +452,7 @@ export default {
if (this.backScreenShot) {
style.height = this.mainHeight
} else {
style.padding = '5px'
style.padding = '0px'
}
return style
},
@ -806,7 +807,7 @@ export default {
restore() {
const canvasHeight = document.getElementById(this.previewDomId).offsetHeight
const canvasWidth = document.getElementById(this.previewDomId).offsetWidth
this.scaleWidth = (canvasWidth) * 100 / this.canvasStyleData.width //
this.scaleWidth = (canvasWidth) * 100 / (this.canvasStyleData.width - 8) //
// 使
if (this.backScreenShot) {
this.scaleHeight = this.scaleWidth

View File

@ -1002,7 +1002,7 @@ export default {
},
getData(id, cache = true, dataBroadcast = false) {
// Err1001
if (this.requestStatus === 'waiting' || (this.message && this.message.indexOf('Err1001'))) {
if (this.requestStatus === 'waiting' || (this.message && this.message.indexOf('Err1001')> -1)) {
return
}
if (id) {
@ -1444,7 +1444,7 @@ export default {
let mappingName = null
if (this.chart.senior) {
const senior = JSON.parse(this.chart.senior)
if (senior?.mapMapping[currentNode.code]) {
if (senior?.mapMapping?.[currentNode.code]) {
const mapping = senior.mapMapping[currentNode.code]
if (mapping[name]) {
mappingName = mapping[name]

View File

@ -655,6 +655,9 @@ export default {
set_multiple: 'Set Multiple',
use_datetime: 'Use Datetime',
custom: 'Custom',
use_datasource: 'Bind Datasource',
bind_column: 'Bind Column',
bind_complete: 'Bind',
option_value: 'Options',
add_option: 'Add Option',
form_name_cannot_none: 'Form name cannot be null',
@ -670,6 +673,7 @@ export default {
index_name: 'Index Name',
create_index_hint: 'MySQL versions earlier than 8.0 or MariaDB versions earlier than 10.8.0 do not support Descending indexes',
index_column: 'Index Column',
order: 'Sort',
order_asc: 'Asc',
order_desc: 'Desc',
order_none: 'Default Order',

View File

@ -655,6 +655,9 @@ export default {
set_multiple: '允許多選',
use_datetime: '使用日期時間',
custom: '自定義',
use_datasource: '綁定數據源',
bind_column: '綁定字段',
bind_complete: '已綁定',
option_value: '選項值',
add_option: '添加選項值',
form_name_cannot_none: '表單名稱不能為空',
@ -670,6 +673,7 @@ export default {
index_name: '索引名稱',
create_index_hint: 'MySQL 8.0 或 MariaDB 10.8.0 以下版本不支持索引降序排序',
index_column: '索引字段',
order: '排序',
order_asc: '升序',
order_desc: '降序',
order_none: '默認排序',

View File

@ -653,6 +653,9 @@ export default {
set_multiple: '允许多选',
use_datetime: '使用日期时间',
custom: '自定义',
use_datasource: '绑定数据源',
bind_column: '绑定字段',
bind_complete: '已绑定',
option_value: '选项值',
add_option: '添加选项值',
form_name_cannot_none: '表单名称不能为空',
@ -668,6 +671,7 @@ export default {
index_name: '索引名称',
create_index_hint: 'MySQL 8.0 或 MariaDB 10.8.0 以下版本不支持索引降序排序',
index_column: '索引字段',
order: '排序',
order_asc: '升序',
order_desc: '降序',
order_none: '默认排序',

View File

@ -300,7 +300,7 @@
v-model="curComponent.style.showNum"
:min="1"
step-strictly
:max="10"
:max="50"
controls-position="right"
size="small"
/>

View File

@ -1,7 +1,12 @@
<script>
import { forEach, find, concat, cloneDeep, floor, map, filter, includes } from 'lodash-es'
import { PHONE_REGEX, EMAIL_REGEX } from '@/utils/validate'
import { newFormRowData, saveFormRowData, userFillFormData } from '@/views/dataFilling/form/dataFilling'
import {
getTableColumnData,
newFormRowData,
saveFormRowData,
userFillFormData
} from '@/views/dataFilling/form/dataFilling'
export default {
name: 'EditFormData',
@ -61,6 +66,7 @@ export default {
}
return {
loading: false,
asyncOptions: {},
formData: {},
requiredRule: { required: true, message: this.$t('commons.required'), trigger: ['blur', 'change'] },
dateRangeRequiredRule: { validator: checkDateRangeRequireValidator, message: this.$t('commons.required'), trigger: ['blur', 'change'] },
@ -87,7 +93,9 @@ export default {
},
watch: {},
mounted() {
const _tempForms = []
this.formData = []
this.asyncOptions = {}
forEach(this.forms, v => {
if (!v.removed) {
const f = cloneDeep(v)
@ -102,6 +110,19 @@ export default {
const _end = this.data[f.settings.mapping.columnName2]
f.value = [_start, _end]
} else {
const _value = this.data[f.settings.mapping.columnName]
//
f.value = _value
}
_tempForms.push(f)
}
})
this.loading = true
this.initFormOptionsData(_tempForms, () => {
//
_tempForms.forEach(f => {
if (f.type !== 'dateRange') {
const _value = this.data[f.settings.mapping.columnName]
if (f.type === 'select' && f.settings.multiple || f.type === 'checkbox') {
if (_value) {
@ -109,7 +130,8 @@ export default {
if (this.readonly) {
f.value = JSON.parse(_value)
} else {
const options = map(f.settings.options, f => f.value)
const tempId = f.settings.optionDatasource + '_' + f.settings.optionTable + '_' + f.settings.optionColumn + '_' + f.settings.optionOrder
const options = map(f.settings.optionSourceType === 1 ? f.settings.options : (this.asyncOptions[tempId] ? this.asyncOptions[tempId] : []), f => f.value)
f.value = filter(JSON.parse(_value), v => includes(options, v))
}
} else {
@ -118,7 +140,8 @@ export default {
} else if (f.type === 'select' && !f.settings.multiple || f.type === 'radio') {
if (_value) {
if (!this.readonly) {
const options = map(f.settings.options, f => f.value)
const tempId = f.settings.optionDatasource + '_' + f.settings.optionTable + '_' + f.settings.optionColumn + '_' + f.settings.optionOrder
const options = map(f.settings.optionSourceType === 1 ? f.settings.options : (this.asyncOptions[tempId] ? this.asyncOptions[tempId] : []), f => f.value)
if (!includes(options, _value)) {
f.value = undefined
} else {
@ -128,15 +151,47 @@ export default {
f.value = _value
}
}
} else {
f.value = _value
}
}
this.formData.push(f)
}
})
//
this.formData = _tempForms
this.loading = false
})
},
methods: {
initFormOptionsData(forms, callback) {
const queries = []
const queryIds = []
forEach(forms, f => {
if (f.type === 'checkbox' || f.type === 'select' || f.type === 'radio') {
if (f.settings && f.settings.optionSourceType === 2 && f.settings.optionDatasource && f.settings.optionTable && f.settings.optionColumn && f.settings.optionOrder) {
const id = f.settings.optionDatasource + '_' + f.settings.optionTable + '_' + f.settings.optionColumn + '_' + f.settings.optionOrder
const p = getTableColumnData(f.settings.optionDatasource, f.settings.optionTable, f.settings.optionColumn, f.settings.optionOrder)
queries.push(p)
queryIds.push(id)
}
}
})
if (queries.length > 0) {
Promise.all(queries).then((val) => {
for (let i = 0; i < queryIds.length; i++) {
const id = queryIds[i]
this.asyncOptions[id] = val[i].data
}
}).finally(() => {
if (callback) {
callback()
}
})
} else {
if (callback) {
callback()
}
}
},
getRules(item) {
let rules = []
if (item.settings.required) {
@ -266,6 +321,7 @@ export default {
<div
v-for="(item, $index) in formData"
:key="item.id"
:data-var="tempId = item.settings ? item.settings.optionDatasource + '_' + item.settings.optionTable + '_' + item.settings.optionColumn + '_' + item.settings.optionOrder : 'unset'"
class="m-item m-form-item"
>
@ -332,7 +388,7 @@ export default {
clearable
>
<el-option
v-for="(x, $index) in item.settings.options"
v-for="(x, $index) in item.settings.optionSourceType === 1 ? item.settings.options : (asyncOptions[tempId] ? asyncOptions[tempId] : [])"
:key="$index"
:label="x.name"
:value="x.value"
@ -347,7 +403,7 @@ export default {
size="small"
>
<el-radio
v-for="(x, $index) in item.settings.options"
v-for="(x, $index) in item.settings.optionSourceType === 1 ? item.settings.options : (asyncOptions[tempId] ? asyncOptions[tempId] : [])"
:key="$index"
:label="x.value"
>{{ x.name }}
@ -361,7 +417,7 @@ export default {
size="small"
>
<el-checkbox
v-for="(x, $index) in item.settings.options"
v-for="(x, $index) in item.settings.optionSourceType === 1 ? item.settings.options : (asyncOptions[tempId] ? asyncOptions[tempId] : [])"
:key="$index"
:label="x.value"
>{{ x.name }}

View File

@ -2,10 +2,12 @@
import DeContainer from '@/components/dataease/DeContainer.vue'
import DataFillingFormSave from './save.vue'
import clickoutside from 'element-ui/src/utils/clickoutside.js'
import { filter, cloneDeep, find, concat, forEach } from 'lodash-es'
import { filter, cloneDeep, find, concat, forEach, groupBy, keys } from 'lodash-es'
import { v4 as uuidv4 } from 'uuid'
import { EMAIL_REGEX, PHONE_REGEX } from '@/utils/validate'
import { getWithPrivileges } from '@/views/dataFilling/form/dataFilling'
import { getTableColumnData, getWithPrivileges } from '@/views/dataFilling/form/dataFilling'
import { getColumnList, listDatasource } from '@/api/dataset/dataset'
import { getTableList } from '@/api/system/datasource'
export default {
name: 'DataFillingFormCreate',
@ -25,6 +27,12 @@ export default {
callback()
}
return {
baseLoading: false,
loading: false,
allDatasourceList: [],
tableList: [],
columnList: [],
optionFormData: {},
showDrawer: false,
isEdit: false,
disableCreateIndex: false,
@ -47,14 +55,24 @@ export default {
{
type: 'tel',
name: this.$t('data_fill.form.tel'),
rules: [{ pattern: PHONE_REGEX, message: this.$t('user.mobile_number_format_is_incorrect'), trigger: ['blur', 'change'] }]
rules: [{
pattern: PHONE_REGEX,
message: this.$t('user.mobile_number_format_is_incorrect'),
trigger: ['blur', 'change']
}]
},
{
type: 'email',
name: this.$t('data_fill.form.email'),
rules: [{ pattern: EMAIL_REGEX, message: this.$t('user.email_format_is_incorrect'), trigger: ['blur', 'change'] }]
rules: [{
pattern: EMAIL_REGEX,
message: this.$t('user.email_format_is_incorrect'),
trigger: ['blur', 'change']
}]
}
],
showEditBindColumn: false,
asyncOptions: {},
componentList: [
{
type: 'input',
@ -104,6 +122,10 @@ export default {
options: [{ name: this.$t('data_fill.form.option') + ' 1', value: this.$t('data_fill.form.option') + ' 1' },
{ name: this.$t('data_fill.form.option') + ' 2', value: this.$t('data_fill.form.option') + ' 2' }],
optionSourceType: 1,
optionDatasource: undefined,
optionTable: undefined,
optionColumn: undefined,
optionOrder: 'asc',
placeholder: '',
multiple: false, required: false,
mapping: {
@ -124,6 +146,10 @@ export default {
options: [{ name: this.$t('data_fill.form.option') + ' 1', value: this.$t('data_fill.form.option') + ' 1' },
{ name: this.$t('data_fill.form.option') + ' 2', value: this.$t('data_fill.form.option') + ' 2' }],
optionSourceType: 1,
optionDatasource: undefined,
optionTable: undefined,
optionColumn: undefined,
optionOrder: 'asc',
required: false,
mapping: {
@ -144,6 +170,10 @@ export default {
options: [{ name: this.$t('data_fill.form.option') + ' 1', value: this.$t('data_fill.form.option') + ' 1' },
{ name: this.$t('data_fill.form.option') + ' 2', value: this.$t('data_fill.form.option') + ' 2' }],
optionSourceType: 1,
optionDatasource: undefined,
optionTable: undefined,
optionColumn: undefined,
optionOrder: 'asc',
required: false,
mapping: {
@ -225,6 +255,22 @@ export default {
}
},
computed: {
datasourceList() {
const dsMap = groupBy(this.allDatasourceList, d => d.type)
const _types = []
if (dsMap) {
forEach(keys(dsMap), type => {
if (type === 'mysql' || type === 'mariadb') {
_types.push({
name: dsMap[type][0]?.typeDesc,
type: type,
options: dsMap[type]
})
}
})
}
return _types
},
componentList1() {
return filter(this.componentList, c => c.order % 2 === 0)
},
@ -268,7 +314,10 @@ export default {
const tempData = res.data
this.formSettings.folder = tempData.pid
this.formSettings.level = tempData.level
this.formSettings.forms = JSON.parse(tempData.forms)
this.baseLoading = true
this.initData(tempData, () => {
this.baseLoading = false
})
})
} else if (this.$route.query.id !== undefined) {
const id = this.$route.query.id
@ -278,37 +327,84 @@ export default {
this.formSettings = tempData
this.formSettings.table = tempData.tableName
this.formSettings.folder = tempData.pid
const tempForms = filter(JSON.parse(res.data.forms), f => !f.removed)
forEach(tempForms, f => {
f.old = true
if (f.type === 'checkbox' || f.type === 'select' && f.settings.multiple) {
f.value = []
}
if (f.type === 'date' && f.settings.dateType === undefined) { //
f.settings.dateType = f.settings.enableTime ? 'datetime' : 'date'
}
if (f.type === 'dateRange' && f.settings.dateType === undefined) { //
f.settings.dateType = f.settings.enableTime ? 'datetimerange' : 'daterange'
this.baseLoading = true
this.initData(res.data, () => {
if (res.data.createIndex) {
forEach(this.formSettings.tableIndexes, f => {
f.old = true
})
this.formSettings.oldTableIndexes = JSON.parse(res.data.tableIndexes)
} else {
this.formSettings.oldTableIndexes = []
}
this.disableCreateIndex = res.data.createIndex
this.baseLoading = false
})
this.formSettings.forms = tempForms
this.formSettings.oldForms = JSON.parse(res.data.forms)
this.formSettings.tableIndexes = JSON.parse(res.data.tableIndexes)
if (res.data.createIndex) {
forEach(this.formSettings.tableIndexes, f => {
f.old = true
})
this.formSettings.oldTableIndexes = JSON.parse(res.data.tableIndexes)
} else {
this.formSettings.oldTableIndexes = []
}
this.disableCreateIndex = res.data.createIndex
})
}
//
listDatasource().then(data => {
this.allDatasourceList = data.data
})
},
methods: {
initData(data, callback) {
const tempForms = filter(JSON.parse(data.forms), f => !f.removed)
forEach(tempForms, f => {
f.old = true
if (f.type === 'checkbox' || f.type === 'select' && f.settings.multiple) {
f.value = []
}
if (f.type === 'date' && f.settings.dateType === undefined) { //
f.settings.dateType = f.settings.enableTime ? 'datetime' : 'date'
}
if (f.type === 'dateRange' && f.settings.dateType === undefined) { //
f.settings.dateType = f.settings.enableTime ? 'datetimerange' : 'daterange'
}
})
this.initFormOptionsData(tempForms, () => {
this.formSettings.forms = tempForms
this.formSettings.oldForms = JSON.parse(data.forms)
this.formSettings.tableIndexes = JSON.parse(data.tableIndexes)
if (callback) {
callback()
}
})
},
initFormOptionsData(forms, callback) {
const queries = []
const queryIds = []
forEach(forms, f => {
if (f.type === 'checkbox' || f.type === 'select' || f.type === 'radio') {
if (f.settings && f.settings.optionSourceType === 2 && f.settings.optionDatasource && f.settings.optionTable && f.settings.optionColumn && f.settings.optionOrder) {
const id = f.settings.optionDatasource + '_' + f.settings.optionTable + '_' + f.settings.optionColumn + '_' + f.settings.optionOrder
const p = getTableColumnData(f.settings.optionDatasource, f.settings.optionTable, f.settings.optionColumn, f.settings.optionOrder)
queries.push(p)
queryIds.push(id)
}
}
})
if (queries.length > 0) {
Promise.all(queries).then((val) => {
for (let i = 0; i < queryIds.length; i++) {
const id = queryIds[i]
this.asyncOptions[id] = val[i].data
}
}).finally(() => {
if (callback) {
callback()
}
})
} else {
if (callback) {
callback()
}
}
},
closeCreate: function() {
// back to forms list
if (this.$route.query.copy) {
@ -417,6 +513,133 @@ export default {
return rules
},
onOptionSourceTypeChange(type, itemSettings) {
if (type === 2) {
this.getAsyncOption({
optionSourceType: type,
optionDatasource: itemSettings.optionDatasource,
optionTable: itemSettings.optionTable,
optionColumn: itemSettings.optionColumn,
optionOrder: itemSettings.optionOrder
})
}
},
getAsyncOption(itemSettings, callback) {
if (itemSettings.optionSourceType === 2 && itemSettings.optionDatasource && itemSettings.optionTable && itemSettings.optionColumn && itemSettings.optionOrder) {
const id = itemSettings.optionDatasource + '_' + itemSettings.optionTable + '_' + itemSettings.optionColumn + '_' + itemSettings.optionOrder
if (this.asyncOptions[id] === undefined || this.asyncOptions[id].length === 0) {
getTableColumnData(itemSettings.optionDatasource, itemSettings.optionTable, itemSettings.optionColumn, itemSettings.optionOrder).then(data => {
this.asyncOptions[id] = data.data
}).finally(() => {
if (callback) {
callback()
}
})
} else {
if (callback) {
callback()
}
}
}
},
openEditBindColumn(settings) {
this.tableList = []
this.columnList = []
this.optionFormData = cloneDeep({
optionSourceType: 2,
optionDatasource: settings.optionDatasource,
optionTable: settings.optionTable,
optionColumn: settings.optionColumn,
optionOrder: settings.optionOrder ?? 'asc'
})
const p1 = settings.optionDatasource ? getTableList(settings.optionDatasource) : undefined
const p2 = settings.optionDatasource && settings.optionTable ? getColumnList(settings.optionDatasource, settings.optionTable) : undefined
const promiseList = []
if (p1) {
promiseList.push(p1)
if (p2) {
promiseList.push(p2)
}
}
if (promiseList.length > 1) {
this.loading = true
Promise.all(promiseList).then((val) => {
this.tableList = val[0].data
if (find(this.tableList, t => t.name === this.optionFormData.optionTable)) {
if (promiseList.length > 1) {
this.columnList = val[1].data
if (!find(this.columnList, t => t.fieldName === this.optionFormData.optionColumn)) {
this.optionFormData.optionColumn = undefined
}
}
} else {
this.optionFormData.optionTable = undefined
this.optionFormData.optionColumn = undefined
}
}).finally(() => {
this.loading = false
})
}
this.showEditBindColumn = true
},
onDataSourceChange(datasource) {
this.tableList = []
this.columnList = []
if (datasource) {
this.loading = true
getTableList(datasource).then(res => {
this.tableList = res.data
if (this.optionFormData.optionTable) {
if (find(this.tableList, t => t.name === this.optionFormData.optionTable)) {
this.onTableChange(datasource, this.optionFormData.optionTable)
} else {
this.optionFormData.optionTable = undefined
this.optionFormData.optionColumn = undefined
}
}
}).finally(() => {
this.loading = false
})
}
},
onTableChange(datasource, table) {
this.columnList = []
if (datasource && table) {
this.loading = true
getColumnList(datasource, table).then(res => {
this.columnList = res.data
if (this.optionFormData.optionColumn) {
if (!find(this.columnList, t => t.fieldName === this.optionFormData.optionColumn)) {
this.optionFormData.optionColumn = undefined
}
}
}).finally(() => {
this.loading = false
})
}
},
closeEditBindColumn() {
this.showEditBindColumn = false
},
doEditBindColumn() {
this.$refs['optionForm'].validate((valid, invalidFields) => {
if (valid) {
this.loading = true
this.getAsyncOption(this.optionFormData, () => {
this.selectedComponentItem.settings.optionSourceType = this.optionFormData.optionSourceType
this.selectedComponentItem.settings.optionDatasource = this.optionFormData.optionDatasource
this.selectedComponentItem.settings.optionTable = this.optionFormData.optionTable
this.selectedComponentItem.settings.optionColumn = this.optionFormData.optionColumn
this.selectedComponentItem.settings.optionOrder = this.optionFormData.optionOrder
this.loading = false
this.closeEditBindColumn()
})
}
})
},
addOption(list) {
list.push({ name: '', value: '' })
},
@ -488,7 +711,10 @@ export default {
</script>
<template>
<div class="data-filling-form">
<div
v-loading="baseLoading"
class="data-filling-form"
>
<el-header class="de-header">
<div class="panel-info-area">
<!--back to panelList-->
@ -520,7 +746,8 @@ export default {
<el-button
style="margin-right: 20px"
@click="toSave"
>{{ $t('commons.save') }}</el-button>
>{{ $t('commons.save') }}
</el-button>
</el-header>
<de-container class="form-main-container">
<div class="tools-window-left">
@ -617,9 +844,9 @@ export default {
:key="item.id"
class="m-item m-form-item"
:class="{'selectedClass': item.id === selectedItemId}"
:data-var="tempId = item.settings ? item.settings.optionDatasource + '_' + item.settings.optionTable + '_' + item.settings.optionColumn + '_' + item.settings.optionOrder : 'unset'"
@click.stop="selectItem(item.id)"
>
<div class="m-label-container">
<span style="width: unset">
{{ item.settings.name }}
@ -699,7 +926,7 @@ export default {
clearable
>
<el-option
v-for="(x, $index) in item.settings.options"
v-for="(x, $index) in item.settings.optionSourceType === 1 ? item.settings.options : (asyncOptions[tempId] ? asyncOptions[tempId] : [])"
:key="$index"
:label="x.name"
:value="x.value"
@ -714,7 +941,7 @@ export default {
size="small"
>
<el-radio
v-for="(x, $index) in item.settings.options"
v-for="(x, $index) in item.settings.optionSourceType === 1 ? item.settings.options : (asyncOptions[tempId] ? asyncOptions[tempId] : [])"
:key="$index"
:label="x.value"
>{{ x.name }}
@ -728,7 +955,7 @@ export default {
size="small"
>
<el-checkbox
v-for="(x, $index) in item.settings.options"
v-for="(x, $index) in item.settings.optionSourceType === 1 ? item.settings.options : (asyncOptions[tempId] ? asyncOptions[tempId] : [])"
:key="$index"
:label="x.value"
>{{ x.name }}
@ -990,47 +1217,78 @@ export default {
<el-radio-group
v-model="selectedComponentItem.settings.optionSourceType"
size="small"
@change="onOptionSourceTypeChange(selectedComponentItem.settings.optionSourceType, selectedComponentItem.settings)"
>
<el-radio :label="1">
{{ $t('data_fill.form.custom') }}
</el-radio>
<el-radio :label="2">
{{ $t('data_fill.form.use_datasource') }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-button
type="text"
@click="addOption(selectedComponentItem.settings.options)"
>+ {{ $t('data_fill.form.add_option') }}
</el-button>
<template v-if="selectedComponentItem.settings.optionSourceType === 1">
<el-button
type="text"
@click="addOption(selectedComponentItem.settings.options)"
>+ {{ $t('data_fill.form.add_option') }}
</el-button>
<div
v-for="(x,$index) in selectedComponentItem.settings.options"
:key="$index"
class="option-list-div"
>
<el-form-item
:prop="'options['+$index+'].value'"
class="form-item no-margin-bottom"
style="width: 100%"
:rules="[requiredRule, duplicateOptionRule]"
>
<el-input
v-model="x.value"
required
size="small"
minlength="1"
maxlength="50"
show-word-limit
@change="onOptionValueChange(x, x.value)"
/>
</el-form-item>
<div
class="btn-item"
@click.prevent.stop="removeOption(selectedComponentItem.settings.options, $index)"
v-for="(x,$index) in selectedComponentItem.settings.options"
:key="$index"
class="option-list-div"
>
<svg-icon icon-class="icon_delete-trash_outlined" />
<el-form-item
:prop="'options['+$index+'].value'"
class="form-item no-margin-bottom"
style="width: 100%"
:rules="[requiredRule, duplicateOptionRule]"
>
<el-input
v-model="x.value"
required
size="small"
minlength="1"
maxlength="50"
show-word-limit
@change="onOptionValueChange(x, x.value)"
/>
</el-form-item>
<div
class="btn-item"
@click.prevent.stop="removeOption(selectedComponentItem.settings.options, $index)"
>
<svg-icon icon-class="icon_delete-trash_outlined" />
</div>
</div>
</div>
</template>
<template v-else>
<el-button
v-if="!selectedComponentItem.settings.optionColumn"
type="text"
@click="openEditBindColumn({})"
>+ {{ $t('data_fill.form.bind_column') }}
</el-button>
<div
v-else
style="display: flex; flex-direction: row; align-items: center; font-size: 14px;"
>
<div style="width: 28px;" />
<div style="flex:2">{{ selectedComponentItem.settings.optionTable }}
({{ selectedComponentItem.settings.optionColumn }})
</div>
<div style="flex:1; color: #8F959E;">{{ $t('data_fill.form.bind_complete') }}</div>
<el-button
:title="$t('chart.edit')"
icon="el-icon-edit"
type="text"
@click="openEditBindColumn(selectedComponentItem.settings)"
/>
</div>
</template>
</div>
@ -1091,10 +1349,137 @@ export default {
/>
</el-drawer>
<el-dialog
v-dialogDrag
append-to-body
:title="$t('data_fill.form.use_datasource')"
:visible.sync="showEditBindColumn"
:show-close="true"
width="600px"
class="m-dialog"
>
<el-container
v-loading="loading"
style="width: 100%"
direction="vertical"
>
<el-form
ref="optionForm"
class="m-form"
:model="optionFormData"
label-position="right"
label-width="140px"
hide-required-asterisk
@submit.native.prevent
>
<el-main>
<el-form-item
prop="optionDatasource"
class="form-item"
:label="$t('data_fill.form.datasource')"
:rules="[requiredRule]"
>
<el-select
v-model="optionFormData.optionDatasource"
required
style="width: 100%"
size="small"
filterable
@change="onDataSourceChange"
>
<el-option-group
v-for="(x, $index) in datasourceList"
:key="$index"
:label="x.name"
>
<el-option
v-for="d in x.options"
:key="d.id"
:value="d.id"
:label="d.name"
>{{ d.name }}
</el-option>
</el-option-group>
</el-select>
</el-form-item>
<el-form-item
prop="optionTable"
class="form-item"
:label="$t('data_fill.form.table')"
:rules="[requiredRule]"
>
<el-select
v-model="optionFormData.optionTable"
required
style="width: 100%"
size="small"
filterable
@change="onTableChange(optionFormData.optionDatasource, optionFormData.optionTable)"
>
<el-option
v-for="d in tableList"
:key="d.name"
:value="d.name"
:label="d.name"
>{{ d.name }}
</el-option>
</el-select>
</el-form-item>
<el-form-item
prop="optionColumn"
class="form-item"
:label="$t('data_fill.form.column_name')"
:rules="[requiredRule]"
>
<el-select
v-model="optionFormData.optionColumn"
required
style="width: 100%"
size="small"
filterable
>
<el-option
v-for="d in columnList"
:key="d.fieldName"
:value="d.fieldName"
:label="d.fieldName"
>{{ d.fieldName }}
</el-option>
</el-select>
</el-form-item>
<el-form-item
prop="optionOrder"
class="form-item"
:label="$t('data_fill.form.order')"
:rules="[requiredRule]"
>
<el-radio-group
v-model="optionFormData.optionOrder"
required
style="width: 100%"
size="small"
>
<el-radio label="asc">{{ $t('data_fill.form.order_asc') }}</el-radio>
<el-radio label="desc">{{ $t('data_fill.form.order_desc') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-main>
</el-form>
<el-footer class="de-footer">
<el-button @click="closeEditBindColumn">{{ $t("commons.cancel") }}</el-button>
<el-button
type="primary"
@click="doEditBindColumn"
>{{ $t("commons.confirm") }}
</el-button>
</el-footer>
</el-container>
</el-dialog>
</div>
</template>
<style lang="scss" scoped>
<style lang="scss" scoped>
.data-filling-form {
::v-deep .el-form-item__error {
position: relative;
@ -1208,7 +1593,7 @@ export default {
flex-direction: row;
align-items: center;
//styleName: Title 3 / 16px; font-family: PingFang SC; font-size: 16px; font-weight: 500; line-height: 24px; text-align: left;
//styleName: Title 3 / 16px; font-family: PingFang SC; font-size: 16px; font-weight: 500; line-height: 24px; text-align: left;
}
@ -1462,6 +1847,11 @@ export default {
}
}
}
.de-footer {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end
}
</style>

View File

@ -168,3 +168,11 @@ export function userFillFormData(userTaskId, data) {
data
})
}
export function getTableColumnData(optionDatasource, optionTable, optionColumn, optionOrder) {
return request({
url: `dataFilling/form/${optionDatasource}/${optionTable}/${optionColumn}/options/${optionOrder}`,
method: 'post',
loading: true
})
}

View File

@ -932,7 +932,7 @@ export default {
height: calc(100% - 56px);
overflow-x: hidden;
overflow-y: auto;
/*padding: 5px;*/
padding: 5px;
}
.custom-position {

View File

@ -56,6 +56,11 @@ public class ExtTableField implements Serializable {
private Integer optionSourceType;
private String optionDatasource;
private String optionTable;
private String optionColumn;
private String optionOrder;
private boolean multiple;
private List<Option> options;

View File

@ -52,6 +52,11 @@ public class DefaultExtDDLProvider extends ExtDDLProvider {
return null;
}
@Override
public String searchColumnData(String table, String column, String order) {
return null;
}
@Override
public String countSql(String table, List<TableField> formFields, String whereSql) {
return null;

View File

@ -21,6 +21,8 @@ public abstract class ExtDDLProvider {
public abstract String searchSql(String table, List<TableField> formFields, String whereSql, long limit, long offset);
public abstract String searchColumnData(String table, String column, String order);
public abstract String countSql(String table, List<TableField> formFields, String whereSql);
public abstract String dropTableSql(String table);