fix: 解决冲突

This commit is contained in:
taojinlong 2024-04-28 17:35:38 +08:00
commit 554e119025
27 changed files with 361 additions and 109 deletions

View File

@ -129,6 +129,10 @@ public class XAuthServer {
if (StringUtils.equals("panel", sourceType)) {
return SysLogConstants.SOURCE_TYPE.PANEL;
}
if (StringUtils.equals("data_fill", sourceType)) {
return SysLogConstants.SOURCE_TYPE.DATA_FILL_FORM;
}
return null;
}

View File

@ -39,9 +39,9 @@ public class MysqlExtDDLProvider extends DefaultExtDDLProvider {
@Override
public String createTableSql(String table, List<ExtTableField> formFields) {
//check inject
if (checkSqlInjection(table)) {
/*if (checkSqlInjection(table)) {
throw new RuntimeException("包含SQL注入的参数请检查参数");
}
}*/
List<ExtTableField.TableField> fields = convertTableFields(true, formFields);
String fieldSql = convertTableFieldsString(table, fields);
@ -249,9 +249,9 @@ public class MysqlExtDDLProvider extends DefaultExtDDLProvider {
}
//check inject
if (checkSqlInjection(field.getColumnName())) {
/*if (checkSqlInjection(field.getColumnName())) {
throw new RuntimeException("包含SQL注入的参数请检查参数");
}
}*/
//column name
str.append("`").append(field.getColumnName()).append("` ");
@ -345,9 +345,9 @@ public class MysqlExtDDLProvider extends DefaultExtDDLProvider {
}
//check inject
if (checkSqlInjection(table) || checkSqlInjection(indexField.getName())) {
/*if (checkSqlInjection(table) || checkSqlInjection(indexField.getName())) {
throw new RuntimeException("包含SQL注入的参数请检查参数");
}
}*/
int count = 0;
for (ExtIndexField.ColumnSetting indexFieldColumn : indexField.getColumns()) {

View File

@ -41,6 +41,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
@ -171,7 +172,15 @@ public class DataFillDataService {
List<String[]> countData = datasourceProvider.getData(datasourceRequest);
long count = NumberUtils.toLong(countData.get(0)[0]);
String searchSql = extDDLProvider.searchSql(dataFillForm.getTableName(), searchFields, whereSql, searchRequest.getPageSize(), (searchRequest.getCurrentPage() - 1) * searchRequest.getPageSize());
long totalPage = new BigDecimal(count).divide(new BigDecimal(searchRequest.getPageSize()), 0, RoundingMode.CEILING).longValue();
long currentPage = totalPage < searchRequest.getCurrentPage() ? totalPage - 1 : searchRequest.getCurrentPage();
if (currentPage < 1) {
currentPage = 1;
}
String searchSql = extDDLProvider.searchSql(dataFillForm.getTableName(), searchFields, whereSql, searchRequest.getPageSize(), (currentPage - 1) * searchRequest.getPageSize());
datasourceRequest.setQuery(searchSql);
List<String[]> data2 = datasourceProvider.getData(datasourceRequest);
@ -241,7 +250,7 @@ public class DataFillDataService {
.setFields(fields)
.setTotal(count)
.setPageSize(searchRequest.getPageSize())
.setCurrentPage(searchRequest.getCurrentPage());
.setCurrentPage(currentPage);
}
@ -378,7 +387,7 @@ public class DataFillDataService {
uniqueMap.putIfAbsent(name, new ArrayList<>());
if (uniqueMap.get(name).contains(data.get(name).toString())) {
//提前判断录入的数据有没有unique字段重复的
DataEaseException.throwException(extTableFields.get(name).getSettings().getName() + " 值不能重复");
DataEaseException.throwException("[" + extTableFields.get(name).getSettings().getName() + "]: " + data.get(name) + " 不能重复");
} else {
uniqueMap.get(name).add(data.get(name).toString());
}
@ -416,7 +425,7 @@ public class DataFillDataService {
long count = NumberUtils.toLong(countData.get(0)[0]);
if (count > 0) {
DataEaseException.throwException(extTableFields.get(uniqueField.getFiledName()).getSettings().getName() + " 值不能重复");
DataEaseException.throwException("[" + extTableFields.get(uniqueField.getFiledName()).getSettings().getName() + "]: " + data.get(name) + " 在数据库中已存在, 不能重复");
}
}
@ -684,14 +693,10 @@ public class DataFillDataService {
if (i < excelDatum.size()) {
excelRowData = excelDatum.get(i);
}
if (StringUtils.isBlank(excelRowData)) { //处理必填这里如果是字符串格式的强制改成空字符串防止报错其他类型都直接报错
if (StringUtils.isBlank(excelRowData)) { //处理必填
excelRowData = null;
if (field.getSettings().isRequired()) {
if (field.getSettings().getMapping().getType().equals(ExtTableField.BaseType.nvarchar) ||
field.getSettings().getMapping().getType().equals(ExtTableField.BaseType.text)) {
excelRowData = StringUtils.EMPTY;
} else {
DataEaseException.throwException(field.getSettings().getName() + "不能为空");
}
DataEaseException.throwException("[" + field.getSettings().getName() + "] 不能为空");
}
}
if (excelRowData == null) {
@ -709,10 +714,26 @@ public class DataFillDataService {
break;
case datetime:
Date date = getDate(field, excelRowData);
rowData.put(field.getSettings().getMapping().getColumnName(), date.getTime());
Long time = date == null ? null : date.getTime();
if (time != null && time < 0) {
throw new Exception("时间不能小于1970/01/01");
}
rowData.put(field.getSettings().getMapping().getColumnName(), time);
break;
default:
if (StringUtils.equalsIgnoreCase(field.getType(), "checkbox") ||
if (StringUtils.equalsIgnoreCase(field.getType(), "select") && !field.getSettings().isMultiple()) {
boolean has = false;
for (ExtTableField.Option option : field.getSettings().getOptions()) {
if (StringUtils.equals((String) option.getValue(), excelRowData)) {
has = true;
break;
}
}
if (!has) {
DataEaseException.throwException("[" + field.getSettings().getName() + "] 值: " + excelRowData + " 不在范围内");
}
rowData.put(field.getSettings().getMapping().getColumnName(), excelRowData);
} else if (StringUtils.equalsIgnoreCase(field.getType(), "checkbox") ||
StringUtils.equalsIgnoreCase(field.getType(), "select") && field.getSettings().isMultiple()) {
List<String> list = new ArrayList<>();
String[] strArr = excelRowData.split(";");
@ -723,11 +744,43 @@ public class DataFillDataService {
}
if (field.getSettings().isRequired()) {
if (CollectionUtils.isEmpty(list)) {
DataEaseException.throwException(field.getSettings().getName() + "不能为空");
DataEaseException.throwException("[" + field.getSettings().getName() + "] 不能为空");
}
}
rowData.put(field.getSettings().getMapping().getColumnName(), gson.toJson(list));
List<String> result = new ArrayList<>();
if (CollectionUtils.isNotEmpty(list)) {
for (String str : list) {
boolean has = false;
for (ExtTableField.Option option : field.getSettings().getOptions()) {
if (StringUtils.equals((String) option.getValue(), str)) {
has = true;
break;
}
}
if (has) {
result.add(str);
}
}
if (CollectionUtils.isEmpty(result)) {
DataEaseException.throwException("[" + field.getSettings().getName() + "] 输入值不在范围内");
}
}
rowData.put(field.getSettings().getMapping().getColumnName(), gson.toJson(result));
} else {
//校验手机号校验邮箱格式
if (StringUtils.equalsAnyIgnoreCase(field.getSettings().getInputType(), "tel")) {
if (!excelRowData.matches("^1[3|4|5|7|8][0-9]{9}$")) {
throw new Exception(Translator.get("i18n_wrong_tel"));
}
}
if (StringUtils.equalsAnyIgnoreCase(field.getSettings().getInputType(), "email")) {
if (!excelRowData.matches("^[a-zA-Z0-9_._-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")) {
throw new Exception(Translator.get("i18n_wrong_email"));
}
}
rowData.put(field.getSettings().getMapping().getColumnName(), excelRowData);
}
}
@ -735,7 +788,7 @@ public class DataFillDataService {
} catch (DataEaseException e) {
DataEaseException.throwException(e.getMessage());
} catch (Exception e) {
DataEaseException.throwException(field.getSettings().getName() + "格式错误");
DataEaseException.throwException("[" + field.getSettings().getName() + "] 值: " + excelRowData + " 格式解析错误: " + e.getMessage());
}
}
@ -755,6 +808,9 @@ public class DataFillDataService {
}
private static Date getDate(ExtTableField field, String excelRowData) throws ParseException {
if (StringUtils.isBlank(excelRowData)) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //默认会拿到这种格式的
if (field.getSettings().isEnableTime()) {
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

View File

@ -387,7 +387,7 @@ public class DataFillService {
break;
case text:
case nvarchar:
if (StringUtils.equalsIgnoreCase("select", formField.getType()) || StringUtils.equalsIgnoreCase("checkbox", formField.getType())) {
if (StringUtils.equalsIgnoreCase("select", formField.getType()) && formField.getSettings().isMultiple() || StringUtils.equalsIgnoreCase("checkbox", formField.getType())) {
example = "\n(多个值使用分号\";\"分割)";
} else if (StringUtils.equalsIgnoreCase("email", formField.getSettings().getInputType())) {
example = "\n(邮箱格式)";

View File

@ -290,7 +290,7 @@ public class ExportCenterService {
// with DataType
if ((excelTypes[j].equals(DeTypeConstants.DE_INT) || excelTypes[j].equals(DeTypeConstants.DE_FLOAT)) && rowData[j] != null) {
cell.setCellValue(Double.valueOf(rowData[j].toString()));
} else {
} else if(rowData[j] != null){
cell.setCellValue(String.valueOf(rowData[j]));
}
} catch (Exception e) {
@ -496,7 +496,7 @@ public class ExportCenterService {
// with DataType
if ((excelTypes[j].equals(DeTypeConstants.DE_INT) || excelTypes[j].equals(DeTypeConstants.DE_FLOAT)) && StringUtils.isNotEmpty(cellValObj.toString())) {
cell.setCellValue(Double.valueOf(cellValObj.toString()));
} else {
} else if(cellValObj != null){
cell.setCellValue(cellValObj.toString());
}
} catch (Exception e) {

View File

@ -664,15 +664,17 @@ public class PanelGroupService {
CacheUtils.removeAll(AuthConstants.DEPT_PANEL_NAME);
}
public DataSetExportRequest composeDatasetExportRequest(PanelViewDetailsRequest request){
public DataSetExportRequest composeDatasetExportRequest(PanelViewDetailsRequest request) {
ChartExtRequest extRequest = request.getComponentFilterInfo();
List<ChartExtFilterRequest> filter = new ArrayList();
if(extRequest != null){
if(CollectionUtils.isNotEmpty(extRequest.getFilter())){
if (extRequest != null) {
if (CollectionUtils.isNotEmpty(extRequest.getFilter())) {
filter.addAll(extRequest.getFilter());
}if(CollectionUtils.isNotEmpty(extRequest.getLinkageFilters())){
}
if (CollectionUtils.isNotEmpty(extRequest.getLinkageFilters())) {
filter.addAll(extRequest.getLinkageFilters());
}if(CollectionUtils.isNotEmpty(extRequest.getOuterParamsFilters())){
}
if (CollectionUtils.isNotEmpty(extRequest.getOuterParamsFilters())) {
filter.addAll(extRequest.getOuterParamsFilters());
}
}
@ -681,23 +683,23 @@ public class PanelGroupService {
permissionsTreeObjFilter.setLogic("and");
List<DatasetRowPermissionsTreeItem> composePermission = new ArrayList<>();
permissionsTreeObjFilter.setItems(composePermission);
if(CollectionUtils.isNotEmpty(filter)){
filter.forEach(filterInfo ->{
if (CollectionUtils.isNotEmpty(filter)) {
filter.forEach(filterInfo -> {
DatasetRowPermissionsTreeItem filterPermission = new DatasetRowPermissionsTreeItem();
List<String> values = filterInfo.getValue();
String operator = filterInfo.getOperator();
String dataSetFilterType = "logic";
String term = operator;
if("eq".equals(operator) && values.size()>1){
if ("eq".equals(operator) && values.size() > 1) {
dataSetFilterType = "enum";
}
String fieldId = filterInfo.getFieldId();
filterPermission.setFieldId(fieldId);
filterPermission.setFilterType(dataSetFilterType);
filterPermission.setType("item");
if(dataSetFilterType.equals("enum")){
if (dataSetFilterType.equals("enum")) {
filterPermission.setEnumValue(values);
}else{
} else {
filterPermission.setTerm(term);
filterPermission.setValue(values.get(0));
}
@ -708,17 +710,19 @@ public class PanelGroupService {
ChartViewWithBLOBs chartInfo = chartViewMapper.selectByPrimaryKey(request.getViewId());
String customFilter = chartInfo.getCustomFilter();
DatasetTable datasetTable = datasetTableMapper.selectByPrimaryKey(chartInfo.getTableId());
DatasetTable datasetTable = datasetTableMapper.selectByPrimaryKey(chartInfo.getTableId());
DataSetExportRequest dataSetExportRequest = new DataSetExportRequest();
BeanUtils.copyBean(dataSetExportRequest,datasetTable);
if(CollectionUtils.isNotEmpty(composePermission)){
DatasetRowPermissionsTreeObj permissionsTreeObjCustomsFilter = gson.fromJson(customFilter,DatasetRowPermissionsTreeObj.class);
DatasetRowPermissionsTreeItem customFilterPermission = new DatasetRowPermissionsTreeItem();
customFilterPermission.setType("tree");
customFilterPermission.setSubTree(permissionsTreeObjCustomsFilter);
composePermission.add(customFilterPermission);
BeanUtils.copyBean(dataSetExportRequest, datasetTable);
DatasetRowPermissionsTreeObj permissionsTreeObjCustomsFilter = gson.fromJson(customFilter, DatasetRowPermissionsTreeObj.class);
if (CollectionUtils.isNotEmpty(composePermission)) {
if (StringUtils.isNotEmpty(permissionsTreeObjCustomsFilter.getLogic())) {
DatasetRowPermissionsTreeItem customFilterPermission = new DatasetRowPermissionsTreeItem();
customFilterPermission.setType("tree");
customFilterPermission.setSubTree(permissionsTreeObjCustomsFilter);
composePermission.add(customFilterPermission);
}
dataSetExportRequest.setExpressionTree(gson.toJson(permissionsTreeObjFilter));
}else{
} else if(StringUtils.isNotEmpty(permissionsTreeObjCustomsFilter.getLogic())){
dataSetExportRequest.setExpressionTree(customFilter);
}
dataSetExportRequest.setFilename(dataSetExportRequest.getName());
@ -727,7 +731,7 @@ public class PanelGroupService {
}
public void exportDatasetDetails(PanelViewDetailsRequest request, HttpServletResponse response) throws Exception {
dataSetTableService.exportDataset(composeDatasetExportRequest(request),response);
dataSetTableService.exportDataset(composeDatasetExportRequest(request), response);
}

View File

@ -104,6 +104,9 @@ public class LogManager {
case 11:
typeValue = "menu";
break;
case 13:
typeValue = "data_fill";
break;
default:
break;
}

View File

@ -1,6 +1,9 @@
spring.profiles.active=@profiles.active@
spring.application.name=dataease
server.port=8081
# spring.jackson.serialization.fail-on-empty-beans=true
# spring.jackson.deserialization.fail-on-unknown-properties=true
# Hikari
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.minimum-idle=5

View File

@ -127,7 +127,7 @@
>
<span v-if="showChartInfoType==='enlarge' && hasDataPermission('export',panelInfo.privileges)&& showChartInfo && showChartInfo.type !== 'symbol-map'">
<span style="font-size: 12px">
导出分辨率
{{ $t('panel.export_pixel') }}
</span>
<el-select
v-model="pixel"
@ -833,7 +833,10 @@ export default {
const componentData = deepCopy(this.componentData)
componentData.forEach(component => {
if (component.type === 'custom') {
component.style = deepCopy(this.findSourceComponent(component.id).style)
const sourceComponent = this.findSourceComponent(component.id)
if (sourceComponent?.style) {
component.style = deepCopy(this.findSourceComponent(component.id).style)
}
}
Object.keys(component.style).forEach(key => {
if (this.needToChangeHeight.includes(key)) {

View File

@ -160,7 +160,7 @@
>
<span v-if="showChartInfoType==='enlarge' && hasDataPermission('export',panelInfo.privileges)&& showChartInfo && !equalsAny(showChartInfo.type, 'symbol-map', 'flow-map')">
<span style="font-size: 12px">
导出分辨率
{{ $t('panel.export_pixel') }}
</span>
<el-select
v-model="pixel"
@ -993,14 +993,11 @@ export default {
if (this.chart.type === 'map' && this.scaleCoefficientType === 'mobile') {
customAttrChart.label.show = false
}
const data = this.chart.data
delete this.chart.data
this.chart = {
...this.chart,
customAttr: JSON.stringify(customAttrChart),
customStyle: JSON.stringify(customStyleChart)
}
this.chart.data = data
},
getData(id, cache = true, dataBroadcast = false) {
if (this.requestStatus === 'waiting') {
@ -1060,12 +1057,8 @@ export default {
try {
// echart
if (response.success) {
const data = response.data.data
delete response.data.data
this.chart = response.data
this.view = response.data
this.chart.data = data
this.view.data = data
this.$store.commit('setLastViewRequestInfo', { viewId: id, requestInfo: requestInfo })
this.buildInnerRefreshTimer(this.chart.refreshViewEnable, this.chart.refreshUnit, this.chart.refreshTime)
this.$emit('fill-chart-2-parent', this.chart)

View File

@ -282,19 +282,7 @@ export default {
}
},
exportExcel(callBack) {
const _this = this
if (this.isOnlyDetails) {
_this.exportExcelDownload(null, null, null, callBack)
} else {
if (this.showChartCanvas) {
html2canvas(document.getElementById('chartCanvas')).then(canvas => {
const snapshot = canvas.toDataURL('image/jpeg', 1)
_this.exportExcelDownload(snapshot, canvas.width, canvas.height, callBack)
})
} else {
_this.exportExcelDownload(null, null, null, callBack)
}
}
this.exportExcelDownload(null, null, null, callBack)
},
exportSourceDetails(callBack) {
const loadingWrapper = { val: this.linkLoading }

View File

@ -469,10 +469,11 @@ export function getCacheTree(treeName) {
}
export function exportExcelDownload(chart, snapshot, width, height, loadingWrapper, downloadParams, callBack) {
if (chart.render === 'antv' && !chart.data?.data?.length) {
if ((chart.render === 'echarts' || ['text', 'label'].includes(chart.type)) && !(chart.data?.series?.length && chart.data?.series[0].data?.length)) {
callBack()
return
}
if (chart.type === 'echarts' && !(chart.data?.series?.length && chart.data?.series[0].data?.length)) {
} else if ((chart.render === 'antv' && !['text', 'label'].includes(chart.type)) && !chart.data?.data?.length) {
callBack()
return
}
const fields = JSON.parse(JSON.stringify(chart.data.fields))
@ -504,6 +505,19 @@ export function exportExcelDownload(chart, snapshot, width, height, loadingWrapp
})
})
}
if (chart.render === 'echarts' && chart.type === 'table-normal') {
const initTotal = fields.map(i => [2, 3].includes(i.deType) ? 0 : undefined)
initTotal[0] = '合计'
tableRow.reduce((p, n) => {
p.forEach((v, i) => {
if (!isNaN(v)) {
p[i] = v + n[excelHeaderKeys[i]]
}
})
return p
}, initTotal)
excelData.push(initTotal)
}
const request = {
proxy: null,
viewId: chart.id,

View File

@ -173,6 +173,7 @@ export default {
default_login: 'Normal'
},
commons: {
pwd_will_expired: 'The password will expire in %s days. To avoid any disruption to your normal use, please update it promptly!',
component: {
input: 'Input',
textarea: 'Textarea',
@ -2275,6 +2276,7 @@ export default {
back_parent: 'Back to previous'
},
panel: {
export_pixel: 'Export pixel',
app_export_tips: 'In the current dashboard, [{0}] belongs to a template view and cannot be exported. Please set up the dataset first!',
required_tips: 'Cannot be empty!',
filter_no_select: 'Filter components do not need to be selected',
@ -2409,7 +2411,7 @@ export default {
link_share: 'Share Link',
over_time: 'Over time',
link_expire: 'Link is expire',
link_share_desc: 'After opening the link, anyone can access the dashboard through this link.',
link_share_desc: 'Anyone can access the dashboard through this link.',
share: 'Share',
remove_share_confirm: 'Sure removel All share ?',
share_in: 'Share With Me',
@ -3226,5 +3228,11 @@ export default {
export_from: 'Export source',
export_obj: 'Export object',
export_time: 'Export time'
},
link_ticket: {
require: 'Require',
back: 'Back to link',
refresh: 'Refresh',
time_tips: 'Unit: Minutes, Range: [0-1440], 0 represents no expiration, starting from the first use of the ticket'
}
}

View File

@ -39,7 +39,10 @@ export function getLanguage() {
if (chooseLanguage) return chooseLanguage
// if has not choose language
const language = (navigator.language || navigator.browserLanguage).toLowerCase()
let language = (navigator.language || navigator.browserLanguage).toLowerCase()
if (language && language === 'en') {
language = 'en_US'
}
const locales = Object.keys(messages)
for (const locale of locales) {
if (language.indexOf(locale) > -1) {

View File

@ -173,6 +173,7 @@ export default {
default_login: '普通登錄'
},
commons: {
pwd_will_expired: '密碼將於%s天後過期為了不影響正常使用請及時進行修改',
component: {
input: '單行輸入',
textarea: '多行輸入',
@ -662,8 +663,8 @@ export default {
add_index: '新增索引',
index_name: '索引名稱',
index_column: '索引字段',
order_asc: '序',
order_desc: '序',
order_asc: '序',
order_desc: '序',
order_none: '默認排序',
add_column: '新增字段',
please_insert_start: '請輸入開始時間',
@ -2268,6 +2269,7 @@ export default {
back_parent: '返回上一級'
},
panel: {
export_pixel: '導出分辨率',
app_export_tips: '當前儀表板中[{0}]屬於模板視圖,無法導出,請先設置數據集!',
required_tips: '必填項不能爲空!',
filter_no_select: '過濾組件無需選擇',
@ -3218,5 +3220,11 @@ export default {
export_from: '匯出來源',
export_obj: '匯出對象',
export_time: '匯出時間'
},
link_ticket: {
require: '必選',
back: '返回公共鏈接設置頁面',
refresh: '刷新',
time_tips: '單位: 分鐘,範圍: [0-1440],0代表無期限自首次使用ticket訪問開始'
}
}

View File

@ -173,6 +173,7 @@ export default {
default_login: '普通登录'
},
commons: {
pwd_will_expired: '密码将于%s天后过期为了不影响正常使用请及时进行修改',
component: {
input: '单行输入',
textarea: '多行输入',
@ -660,8 +661,8 @@ export default {
add_index: '新增索引',
index_name: '索引名称',
index_column: '索引字段',
order_asc: '序',
order_desc: '序',
order_asc: '序',
order_desc: '序',
order_none: '默认排序',
add_column: '新增字段',
please_insert_start: '请输入开始时间',
@ -2269,6 +2270,7 @@ export default {
back_parent: '返回上一级'
},
panel: {
export_pixel: '导出分辨率',
app_export_tips: '当前仪表板中[{0}]属于模版视图,无法导出,请先设置数据集!',
required_tips: '必填项不能为空!',
filter_no_select: '过滤组件无需选择',
@ -3224,5 +3226,11 @@ export default {
no_failed_file: '暂无失败文件',
no_file: '暂无文件',
no_task: '暂无任务'
},
link_ticket: {
require: '必选',
back: '返回公共链接设置页面',
refresh: '刷新',
time_tips: '单位: 分钟,范围: [0-1440],0代表无期限自首次使用ticket访问开始'
}
}

View File

@ -89,7 +89,8 @@ export default {
}
}
.ai-main-active {
border: 1px solid #d9d9d9;
border: 1px solid rgba(239, 240, 241, 1);
box-shadow: 0px 6px 24px 0px #1f232914;
}
.ai-main-active-min {
min-width: 350px;

View File

@ -0,0 +1,95 @@
<script>
export default {
name: 'AiTips',
data() {
return {
visible: true
}
},
mounted() {
},
methods: {
confirm() {
this.$emit('confirm')
}
}
}
</script>
<template>
<el-popover
v-model="visible"
placement="bottom"
:width="288"
show-arrow
>
<div class="ai-popper-tips-content">
<p class="title">DataEase 智能客服</p>
<p class="constant">
你好我是 DataEase 智能客服<br />点击一下开启高效解答模式~<br />&nbsp;
</p>
<div class="bottom">
<el-button size="middle" @click="confirm"> 我知道了 </el-button>
</div>
</div>
<div slot="reference">
<div
style="height: 100%;padding: 0 8px;"
class="right-menu-item hover-effect"
>
<a style="font-size:24px;display: flex;height: 100%;width: 100%;justify-content: center;align-items: center;">
<svg-icon
icon-class="dv-ai"
/>
</a>
</div>
</div>
</el-popover>
</template>
<style lang="less">
.ai-popper-tips {
z-index: 10001 !important;
padding: 24px !important;
box-shadow: none !important;
background: var(--ed-color-primary) !important;
.ed-popper__arrow::before {
border: 1px solid var(--ed-color-primary) !important;
background: var(--ed-color-primary) !important;
}
}
.ai-popper-tips-content {
color: rgba(255, 255, 255, 1);
.title {
font-family: PingFang SC;
font-size: 20px;
font-weight: 500;
line-height: 28px;
}
.content {
font-family: PingFang SC;
font-size: 14px;
font-weight: 500;
line-height: 22px;
text-align: left;
}
.bottom {
line-height: 22px;
text-align: right;
button {
border-color: #ffffff !important;
font-weight: 500;
color: rgba(51, 112, 255, 1) !important;
}
}
}
.ai-popper-tips-icon {
margin: 0 8px;
z-index: 10003;
border-radius: 50%;
background: #ffffff;
width: 28px;
height: 28px;
}
</style>

View File

@ -29,11 +29,21 @@ export default {
},
computed: {
pwdPeriodWarn() {
if (localStorage.getItem('pwd-period-warn')) {
return true
}
return this.$store.state.user.validityPeriod > 0 && this.$store.state.user.validityPeriod < 8
},
warnMsg() {
if (localStorage.getItem('pwd-period-warn')) {
const timeText = localStorage.getItem('pwd-period-warn')
const temp = this.$t('commons.pwd_will_expired')
return temp.replace('%s', timeText)
}
if (this.$store.state.user.validityPeriod > 0 && this.$store.state.user.validityPeriod < 8) {
return `密码将于${this.$store.state.user.validityPeriod}后过期,为了不影响正常使用,请及时进行修改!`
localStorage.setItem('pwd-period-warn', this.$store.state.user.validityPeriod)
const temp = this.$t('commons.pwd_will_expired')
return temp.replace('%s', this.$store.state.user.validityPeriod)
}
return null
}

View File

@ -125,6 +125,8 @@
</div>
<ExportExcel ref="ExportExcelRef" />
<ai-tips @confirm="aiTipsConfirm" v-if="showOverlay" class="ai-icon-tips"></ai-tips>
<div v-if="showOverlay" class="overlay"></div>
<ai-component
v-if="aiBaseUrl"
@ -165,9 +167,11 @@ import TemplateMarket from '@/views/panel/templateMarket'
import { changeFavicon, inOtherPlatform } from '@/utils/index'
import AiComponent from '@/layout/components/AiComponent'
import { findBaseParams } from '@/api/ai/aiComponent'
import AiTips from "@/layout/components/AiTips.vue";
export default {
name: 'Topbar',
components: {
AiTips,
AiComponent,
TemplateMarket,
AppLink,
@ -183,6 +187,7 @@ export default {
},
data() {
return {
showOverlay: false,
aiBaseUrl: null,
uiInfo: null,
logoUrl: null,
@ -308,10 +313,15 @@ export default {
})
},
methods: {
aiTipsConfirm(){
localStorage.setItem('DE1.0-AI-TIPS-CHECK', 'CHECKED')
this.showOverlay = false
},
dataExportCenter() {
this.downloadClick()
},
async initAiBase() {
const aiTipsCheck = localStorage.getItem('DE1.0-AI-TIPS-CHECK')
await findBaseParams().then(rsp => {
const params = rsp.data
if (params && params['ai.baseUrl']) {
@ -529,4 +539,19 @@ export default {
display: none;
}
.ai-icon-tips {
font-size: 24px !important;
z-index: 10001;
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5); /* 半透明黑色 */
z-index: 10000;
}
</style>

View File

@ -98,6 +98,7 @@ const actions = {
commit('SET_PASSWORD_MODIFIED', passwordModified)
localStorage.setItem('passwordModified', passwordModified)
commit('SET_VALIDITY_PERIOD', data.validityPeriod)
localStorage.removeItem('pwd-period-warn')
resolve()
}).catch(error => {
error?.response?.data?.message?.startsWith('pwdValidityPeriod') && commit('SET_LOGIN_MSG', '密码已过期,请联系管理员进行密码重置!')
@ -174,6 +175,7 @@ const actions = {
commit('RESET_STATE')
resolve(customLogoutUrl || res.data)
localStorage.removeItem('passwordModified')
localStorage.removeItem('pwd-period-warn')
}).catch(error => {
reject(error)
if (error?.response?.data?.message) {

View File

@ -4,7 +4,6 @@
top: 0;
left: 0;
z-index: 1001;
overflow: hidden;
border-bottom: 1px solid var(--TopBG, #E6E6E6);
background-color: var(--TopBG, #f1f3f8);
.log {

View File

@ -77,7 +77,12 @@ export default {
name: this.$t('data_fill.form.email'),
rules: [{ pattern: EMAIL_REGEX, message: this.$t('user.email_format_is_incorrect'), trigger: ['blur', 'change'] }]
}
]
],
pickerOptions: {
disabledDate: (time) => {
return time.getTime() < new Date(0).getTime()
}
}
}
},
watch: {},
@ -259,7 +264,7 @@ export default {
:readonly="readonly"
:placeholder="item.settings.placeholder"
size="small"
:show-word-limit="item.value !== undefined && item.value.length > 250"
:show-word-limit="item.value !== undefined && item.value !== null && item.value.length > 250"
maxlength="255"
/>
<el-input-number
@ -343,6 +348,7 @@ export default {
:placeholder="item.settings.placeholder"
style="width: 100%"
size="small"
:picker-options="pickerOptions"
/>
<el-date-picker
v-else-if="item.type === 'date' && item.settings.enableTime"
@ -353,6 +359,7 @@ export default {
:placeholder="item.settings.placeholder"
style="width: 100%"
size="small"
:picker-options="pickerOptions"
/>
<el-date-picker
v-else-if="item.type === 'dateRange' && !item.settings.enableTime"
@ -365,6 +372,7 @@ export default {
:end-placeholder="item.settings.endPlaceholder"
style="width: 100%"
size="small"
:picker-options="pickerOptions"
/>
<el-date-picker
v-else-if="item.type === 'dateRange' && item.settings.enableTime"
@ -377,6 +385,7 @@ export default {
:end-placeholder="item.settings.endPlaceholder"
style="width: 100%"
size="small"
:picker-options="pickerOptions"
/>
</el-form-item>

View File

@ -1,5 +1,8 @@
<template>
<div class="view-table">
<div
v-if="hasDataPermission('use', param.privileges)"
class="view-table"
>
<el-row>
<el-col
class="de-dataset-name"
@ -87,6 +90,7 @@
name="record"
/>
<el-tab-pane
v-if="hasDataPermission('grant', param.privileges)"
:label="$t('data_fill.form.task_manage')"
:lazy="true"
name="task"
@ -108,11 +112,13 @@
@click="addData"
>{{ $t('data_fill.data.add_data') }}</el-button>
<el-button
v-if="hasDataPermission('write', param.privileges)"
icon="el-icon-download"
size="small"
@click="downloadTemplate"
>{{ $t('data_fill.data.download_template') }}</el-button>
<el-upload
v-if="hasDataPermission('write', param.privileges)"
:action="`${baseUrl}dataFilling/form/${param.id}/excel/upload`"
:multiple="false"
:show-file-list="false"
@ -136,7 +142,8 @@
</div>
<div style="flex: 1">
<grid-table
v-if="columns.length > 0"
v-if="columns.length > 0 && dataTableShow"
ref="dataTable"
v-loading="$store.getters.loadingMap[$store.getters.currentPath]"
style="width: 100%; height: 100%"
border
@ -212,6 +219,7 @@
>
<template slot-scope="scope">
<el-button
v-if="hasDataPermission('write', param.privileges)"
type="text"
@click="updateRow(scope.row.data)"
>
@ -224,6 +232,7 @@
{{ $t('data_fill.form.show') }}
</el-button>
<el-button
v-if="hasDataPermission('write', param.privileges)"
type="text"
@click="deleteRow(scope.row.data[paginationConfig.key])"
>
@ -547,6 +556,7 @@ export default {
Authorization: token,
'Accept-Language': i18n.locale.replace('_', '-')
},
dataTableShow: true,
fileList: [],
uploading: false,
operateName: '',
@ -642,6 +652,10 @@ export default {
this.data = []
this.records = []
this.tasks = []
this.dataTableShow = false
this.$nextTick(() => {
this.dataTableShow = true
})
}
this.initTable(this.param.id)
},
@ -731,6 +745,7 @@ export default {
if (res.data) {
this.paginationConfig.key = res.data.key
this.paginationConfig.total = res.data.total
this.paginationConfig.currentPage = res.data.currentPage
const _data = []
forEach(res.data.data, d => {
const obj = {}
@ -911,7 +926,7 @@ export default {
const link = document.createElement('a')
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
link.download = 'test.xlsx' //
link.download = this.param.name + '.xlsx' //
document.body.appendChild(link)
link.click()
document.body.removeChild(link)

View File

@ -664,6 +664,7 @@ export default {
</div>
</div>
<el-button
v-if="scope.row.columns.length < 5"
type="text"
@click="addColumn(scope.row.columns)"
>+ {{ $t('data_fill.form.add_column') }}

View File

@ -19,13 +19,13 @@
:model="form"
size="small"
:rules="rules"
label-width="80px"
label-width="90px"
>
<el-form-item :label="$t('panel.link_share')">
<el-switch
v-model="valid"
style="width: 370px;"
style="width: 360px;"
:active-value="true"
:inactive-value="false"
@change="onChange"
@ -34,7 +34,7 @@
<el-form-item label=" ">
<el-link
class="de-link"
style="width: 370px;"
style="width: 360px;"
disabled
>{{ $t('panel.link_share_desc') }}</el-link>
</el-form-item>
@ -45,7 +45,7 @@
<el-input
v-model.number="form.uri"
disabled
style="width: 370px;"
style="width: 360px;"
/>
</el-form-item>
@ -102,7 +102,7 @@
plain
size="mini"
@click="openTicket"
>Ticket 设置</el-button>
>{{ 'Ticket ' + $t('commons.setting') }}</el-button>
<el-button
v-if="!form.enablePwd"
v-clipboard:copy="form.uri"
@ -136,7 +136,7 @@
<el-tooltip
class="item"
effect="dark"
content="返回公共链接设置页面"
:content="$t('link_ticket.back')"
placement="top"
>
<span class="back-tips">
@ -146,14 +146,14 @@
/>
</span>
</el-tooltip>
<span class="ticket-title">Ticket 设置</span>
<span class="ticket-title">{{ 'Ticket ' + $t('commons.setting') }}</span>
</div>
<div class="ticket-model-end">
<el-checkbox
v-model="requireTicket"
@change="requireTicketChange"
/>
<span>必选</span>
<span>{{ $t('link_ticket.require') }}</span>
</div>
</div>
@ -185,7 +185,7 @@
<el-tooltip
class="item"
effect="dark"
content="复制"
:content="$t('commons.copy')"
placement="top"
>
<span
@ -202,7 +202,7 @@
<el-tooltip
class="item"
effect="dark"
content="刷新ticket"
:content="`${$t('link_ticket.refresh')} ticket`"
placement="top"
>
<span class="refresh-i">
@ -218,15 +218,15 @@
<el-table-column
prop="exp"
label="有效期"
:label="$t('panel.over_time')"
width="100"
>
<template slot="header">
<span>有效期</span>
<span>{{ $t('panel.over_time') }}</span>
<el-tooltip
class="item"
effect="dark"
content="单位: 分钟,范围: [0-1440],0代表无期限自首次使用ticket访问开始"
:content="$t('link_ticket.time_tips')"
placement="top"
>
<span class="check-tips">
@ -243,7 +243,7 @@
:ref="setExpRef(scope.$index)"
v-model="scope.row.exp"
type="number"
placeholder="请输入内容"
:placeholder="$t('commons.input_content')"
min="0"
max="1440"
size="mini"
@ -256,7 +256,7 @@
</el-table-column>
<el-table-column
prop="args"
label="参数"
:label="$t('dataset.param')"
>
<template slot-scope="scope">
<el-input
@ -264,7 +264,7 @@
:ref="setArgRef(scope.$index)"
v-model="scope.row.args"
type="text"
placeholder="请输入内容"
:placeholder="$t('commons.input_content')"
maxlength="200"
size="mini"
@change="val => validateArgs(val, scope.$index)"
@ -275,15 +275,15 @@
</template>
</el-table-column>
<el-table-column
label="操作"
width="60"
:label="$t('commons.operating')"
width="80"
>
<template slot-scope="scope">
<div class="ticket-op">
<el-tooltip
class="item"
effect="dark"
content="删除"
:content="$t('commons.delete')"
placement="top"
>
<span>
@ -296,7 +296,7 @@
<el-tooltip
class="item"
effect="dark"
:content="scope.row.isEdit ? '保存' : '编辑'"
:content="scope.row.isEdit ? $t('commons.save') : $t('commons.edit')"
placement="top"
>
<span>
@ -349,7 +349,7 @@ export default {
requireTicket: false,
uuid: '',
tabList: [
{ name: 'link', 'label': '链接分享' }
{ name: 'link', 'label': this.$t('panel.link_share') }
],
activeName: 'link',
tableData: [],

View File

@ -505,7 +505,7 @@ export default {
},
{
paramKey: 'loginlimit.openModifyPwd',
paramValue: this.formInline.open,
paramValue: this.formInline.openModifyPwd,
type: 'text',
sort: 5
},