Merge branch 'dev-v2' into pr@dev-v2_dzz

This commit is contained in:
dataeaseShu 2024-01-24 10:53:43 +08:00
commit 714a19cf1f
25 changed files with 206 additions and 67 deletions

View File

@ -59,7 +59,7 @@
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.4.0</version>
<version>[2.9.0, )</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>

View File

@ -311,6 +311,7 @@ public class DatasetDataManage {
Map<String, Object> previewData = buildPreviewData(data, fields, new HashMap<>());
Map<String, Object> map = new LinkedHashMap<>();
map.put("data", previewData);
map.put("sql", Base64.getEncoder().encodeToString(sql.getBytes()));
return map;
}

View File

@ -16,8 +16,8 @@ import io.dataease.utils.CommonBeanFactory;
import io.dataease.utils.HttpClientConfig;
import io.dataease.utils.HttpClientUtil;
import io.dataease.utils.JsonUtil;
import net.minidev.json.JSONArray;
import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONArray;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

View File

@ -7,8 +7,8 @@ export const sourceDsPageApi = (page: number, limit: number, data) => {
export const targetDsPageApi = (page: number, limit: number, data) => {
return request.post({ url: `/sync/datasource/target/pager/${page}/${limit}`, data })
}
export const latestUseApi = () => {
return request.post({ url: '/sync/datasource/latestUse', data: {} })
export const latestUseApi = (sourceType: string) => {
return request.post({ url: `/sync/datasource/latestUse/${sourceType}`, data: {} })
}
export const validateApi = data => {

View File

@ -41,8 +41,29 @@ const reposition = () => {
// wheel
let lastWheelNum = 0
//
const checkDialog = () => {
let haveDialog = false
document.querySelectorAll('.ed-overlay').forEach(element => {
if (window.getComputedStyle(element).getPropertyValue('display') != 'none') {
haveDialog = true
}
})
document.querySelectorAll('.ed-popover').forEach(element => {
if (window.getComputedStyle(element).getPropertyValue('display') != 'none') {
haveDialog = true
}
})
//
if (document.querySelector('.tox-dialog-wrap')) {
haveDialog = true
}
return haveDialog
}
const handleMouseWheel = e => {
if (editMode.value === 'preview') {
if (editMode.value === 'preview' || checkDialog()) {
return
}
let dvMain = document.getElementById('dv-main-center')

View File

@ -206,7 +206,9 @@ watch(
watch(
() => canvasStyleData.value,
() => {
initWatermark()
nextTick(() => {
initWatermark()
})
},
{ deep: true }
)
@ -1383,7 +1385,7 @@ defineExpose({
:id="mainDomId"
ref="container"
class="editor"
:class="{ edit: isEdit }"
:class="{ edit: isEdit, 'dashboard-editor': dashboardActive }"
:style="editStyle"
@contextmenu="handleContextMenu"
>
@ -1480,6 +1482,9 @@ defineExpose({
</template>
<style lang="less" scoped>
.dashboard-editor {
min-height: 100%;
}
.editor {
position: relative;
margin: auto;

View File

@ -2,7 +2,8 @@
import { propTypes } from '@/utils/propTypes'
import { ElSelect, ElOption } from 'element-plus-secondary'
import { computed, reactive } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n()
const props = defineProps({
optionList: propTypes.arrayOf(
propTypes.shape({
@ -10,7 +11,13 @@ const props = defineProps({
name: propTypes.string
})
),
title: propTypes.string
title: propTypes.string,
property: {
type: Object,
default: () => {
placeholder: ''
}
}
})
const state = reactive({
@ -21,7 +28,7 @@ const emits = defineEmits(['filter-change'])
const selectStatus = ids => {
emits(
'filter-change',
ids.map(item => item.label)
ids.map(item => item.id || item.value)
)
}
@ -46,6 +53,7 @@ defineExpose({
v-model="state.activeStatus"
value-key="id"
filterable
:placeholder="t('common.please_select') + props.property.placeholder"
multiple
@change="selectStatus"
>

View File

@ -1,8 +1,15 @@
<script setup lang="ts">
import { propTypes } from '@/utils/propTypes'
import { ElTreeSelect } from 'element-plus-secondary'
import { computed, reactive, ref } from 'vue'
import { computed, reactive, ref, PropType, toRefs } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n()
interface TreeConfig {
checkStrictly: boolean
showCheckbox: boolean
checkOnClickNode: boolean
placeholder: string
}
const props = defineProps({
optionList: propTypes.arrayOf(
propTypes.shape({
@ -12,7 +19,22 @@ const props = defineProps({
disabled: Boolean
})
),
title: propTypes.string
title: propTypes.string,
property: Object as PropType<TreeConfig>
})
const { property } = toRefs(props)
const treeConfig = computed(() => {
let obj = Object.assign(
{
checkStrictly: false,
showCheckbox: true,
checkOnClickNode: true,
placeholder: t('user.role')
},
property.value
)
return obj
})
const state = reactive({
@ -58,9 +80,10 @@ defineExpose({
:highlight-current="true"
multiple
:render-after-expand="false"
:placeholder="$t('common.please_select') + $t('user.role')"
show-checkbox
check-on-click-node
:placeholder="$t('common.please_select') + treeConfig.placeholder"
:show-checkbox="treeConfig.showCheckbox"
:check-strictly="treeConfig.checkStrictly"
:check-on-click-node="treeConfig.checkOnClickNode"
/>
</div>
</div>

View File

@ -107,6 +107,7 @@ defineExpose({
v-if="component.type === 'tree-select'"
:option-list="component.option"
:title="component.title"
:property="component.property"
@filter-change="v => filterChange(v, component.field, 'in')"
/>
<drawer-filter
@ -114,6 +115,7 @@ defineExpose({
v-if="component.type === 'select'"
:option-list="component.option"
:title="component.title"
:property="component.property"
@filter-change="v => filterChange(v, component.field, 'in')"
/>
<drawer-enum-filter

View File

@ -25,6 +25,12 @@ const valueTextFormTree = (val, options) => {
}
return result || val
}
const timestampFormatDate = value => {
if (!value) {
return '-'
}
return new Date(value)['format']()
}
const valueText = (field, val, options) => {
for (let index = 0; index < options.length; index++) {
const element = options[index]
@ -41,6 +47,9 @@ const valueText = (field, val, options) => {
return item.name || item.label
}
}
if (element.type === 'time') {
return timestampFormatDate(val)
}
if (isTree) {
return valueTextFormTree(val, selectOption)
}

View File

@ -27,6 +27,7 @@ import { storeToRefs } from 'pinia'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import _ from 'lodash'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import { groupSizeStyleAdaptor } from '@/utils/style'
const snapshotStore = snapshotStoreWithOut()
const dvMainStore = dvMainStoreWithOut()
@ -73,6 +74,13 @@ const onPositionChange = key => {
curComponent.value.style[key] = Math.round(
(positionMounted.value[key] * canvasStyleData.value.scale) / 100
)
if (curComponent.value.component === 'Group') {
//Group
const parentNode = document.querySelector('#editor-canvas-main')
groupSizeStyleAdaptor(curComponent.value)
}
snapshotStore.recordSnapshotCache()
}

View File

@ -41,17 +41,17 @@ export function watermark(settings, domId) {
// 如果将水印列数设置为0或水印列数设置过大超过页面最大宽度则重新计算水印列数和水印x轴间隔
if (
defaultSettings.watermark_cols === 0 ||
parseInt(
Math.floor(
defaultSettings.watermark_x +
defaultSettings.watermark_width * defaultSettings.watermark_cols +
defaultSettings.watermark_x_space * (defaultSettings.watermark_cols - 1)
) > page_width
) {
defaultSettings.watermark_cols = parseInt(
defaultSettings.watermark_cols = Math.floor(
(page_width - defaultSettings.watermark_x + defaultSettings.watermark_x_space) /
(defaultSettings.watermark_width + defaultSettings.watermark_x_space)
)
defaultSettings.watermark_x_space = parseInt(
defaultSettings.watermark_x_space = Math.floor(
(page_width -
defaultSettings.watermark_x -
defaultSettings.watermark_width * defaultSettings.watermark_cols) /
@ -61,17 +61,17 @@ export function watermark(settings, domId) {
// 如果将水印行数设置为0或水印行数设置过大超过页面最大长度则重新计算水印行数和水印y轴间隔
if (
defaultSettings.watermark_rows === 0 ||
parseInt(
Math.floor(
defaultSettings.watermark_y +
defaultSettings.watermark_height * defaultSettings.watermark_rows +
defaultSettings.watermark_y_space * (defaultSettings.watermark_rows - 1)
) > page_height
) {
defaultSettings.watermark_rows = parseInt(
defaultSettings.watermark_rows = Math.floor(
(defaultSettings.watermark_y_space + page_height - defaultSettings.watermark_y) /
(defaultSettings.watermark_height + defaultSettings.watermark_y_space)
)
defaultSettings.watermark_y_space = parseInt(
defaultSettings.watermark_y_space = Math.floor(
(page_height -
defaultSettings.watermark_y -
defaultSettings.watermark_height * defaultSettings.watermark_rows) /

View File

@ -108,6 +108,9 @@ export const copyStore = defineStore('copy', {
// -新ID映射关系
const idMap = {}
const newComponent = deepCopyHelper(data, idMap)
if (newComponent.canvasId.includes('Group')) {
newComponent.canvasId = 'canvas-main'
}
dvMainStore.addCopyComponent(newComponent, idMap, copyDataTemp.copyCanvasViewInfo)
if (dvInfo.value.type === 'dashboard') {
if (dvMainStore.multiplexingStyleAdapt && copyDataTemp.copyFrom === 'multiplexing') {
@ -115,6 +118,7 @@ export const copyStore = defineStore('copy', {
}
eventBus.emit('addDashboardItem-' + newComponent.canvasId, newComponent)
}
i++
}
}, moveTime)

View File

@ -221,7 +221,17 @@ export const dvMainStore = defineStore('dataVisualization', {
})
}
}
if (!this.curComponent) {
this.componentData.forEach(componentItem => {
componentItem['canvasActive'] = false
})
}
if (component) {
this.componentData.forEach(componentItem => {
if (!component.canvasId.includes(componentItem.id)) {
componentItem['canvasActive'] = false
}
})
// Is the current component in editing status
if (!this.curComponent) {
component['editing'] = false
@ -559,7 +569,10 @@ export const dvMainStore = defineStore('dataVisualization', {
mixPropertiesTemp = deepCopy(componentInfo.properties)
mixPropertyInnerTemp = deepCopy(componentInfo.propertyInner)
}
batchAttachInfo.type = componentInfo.value
batchAttachInfo.type =
batchAttachInfo.type === null || batchAttachInfo.type === componentInfo.value
? componentInfo.value
: 'mix'
}
mixPropertiesTemp.forEach(property => {
if (mixPropertyInnerTemp[property]) {

View File

@ -1,7 +1,7 @@
export const positionData = [
{ key: 'left', label: 'X', min: -1000, max: 20000, step: 10 },
{ key: 'top', label: 'Y', min: -1000, max: 20000, step: 10 },
{ key: 'width', label: 'W', min: 10, max: 20000, step: 10 },
{ key: 'top', label: 'Y', min: -1000, max: 20000, step: 10 },
{ key: 'height', label: 'H', min: 10, max: 20000, step: 10 }
]

View File

@ -271,12 +271,12 @@ watch(
</collapse-switch-item>
<el-collapse-item
:effect="themes"
v-if="showProperties('misc-selector')"
v-if="showProperties('misc-selector') && !chart.type.includes('mix')"
name="size"
title="大小"
>
<misc-selector
:property-inner="propertyInnerAll['size-selector']"
:property-inner="propertyInnerAll['misc-selector']"
:themes="themes"
class="attr-selector"
:chart="chart"

View File

@ -25,6 +25,8 @@
@onTableCellChange="onTableCellChange"
@onTableTotalChange="onTableTotalChange"
@onChangeMiscStyleForm="onChangeMiscStyleForm"
@onIndicatorChange="onIndicatorChange"
@onIndicatorNameChange="onIndicatorNameChange"
/>
<common-attr
v-else-if="mixProperties && batchOptComponentInfo && batchOptComponentType !== 'UserView'"
@ -77,6 +79,14 @@ const onChangeYAxisForm = (val, prop) => {
batchOptChange('customStyle', 'yAxis', val, prop)
}
const onIndicatorChange = (val, prop) => {
batchOptChange('customAttr', 'indicator', val, prop)
}
const onIndicatorNameChange = (val, prop) => {
batchOptChange('customAttr', 'indicatorName', val, prop)
}
const onChangeMiscStyleForm = (val, prop) => {
batchOptChange('customStyle', 'misc', val, prop)
}

View File

@ -17,7 +17,7 @@
<el-icon class="custom-back-icon hover-icon" @click="previewModel = 'full'"
><ArrowLeft
/></el-icon>
<span>{{ state.curTemplate.title }} </span>
<span>{{ state.curTemplate.title }}1 </span>
<el-row class="head-right">
<el-button :disabled="state.curTemplateIndex === 0" style="float: right" @click="preOne"
>上一个</el-button
@ -480,8 +480,10 @@ const templatePreview = previewId => {
} else {
state.curTemplateShowFilter =
state.marketActiveTab === '推荐'
? state.currentMarketTemplateShowList
: state.currentMarketTemplateShowList.filter(ele => ele.showFlag)
? state.currentMarketTemplateShowList.filter(ele => ele.showFlag)
: state.currentMarketTemplateShowList.filter(
ele => ele.showFlag && ele.categoryNames?.includes(state.marketActiveTab)
)
state.curTemplateIndex = state.curTemplateShowFilter.findIndex(temp => temp.id === previewId)
state.curTemplate = state.curTemplateShowFilter[state.curTemplateIndex]
previewModel.value = 'createPreview'

@ -1 +1 @@
Subproject commit 19d1cc14aaa7ff5297ebe8f3b8ea3c706f164cc3
Subproject commit 62f9e14297af537ce48f32571d97e3e90ba60796

View File

@ -7,7 +7,7 @@ DE_RUNNING_BASE=${DE_BASE}/dataease2.0
need_init_apisix=false
compose_files="-f docker-compose.yml"
compose_cmd="docker-compose"
server_url="github.com"
server_url=""
current_version=""
latest_version=""
@ -28,12 +28,6 @@ if [[ ! ${DE_EXTERNAL_MYSQL} ]] || [ "${DE_EXTERNAL_MYSQL}" = "false" ]; then
compose_files="${compose_files} -f docker-compose-mysql.yml"
fi
if [[ -x "$(command -v python)" ]]; then
py_cmd='python'
elif [[ -x "$(command -v python3)" ]]; then
py_cmd='python3'
fi
function usage() {
echo "DATAEASE 控制脚本"
echo
@ -125,34 +119,33 @@ function _get_current_version() {
function _get_available_server() {
git_urls=('github.com')
for git_url in ${git_urls[*]}; do
success="true"
for git_url in ${git_urls[*]}; do
echo -ne "检测 ${git_url} ... "
curl -m 5 -kIs https://${git_url} >/dev/null
if [ $? != 0 ]; then
echo "failed"
success="false"
else
echo "ok"
fi
if [[ ${success} == "true" ]]; then
server_url=${git_url}
break
else
unset server_url
fi
done
if [[ "x${server_url}" == "x" ]]; then
echo "没有找到稳定的下载服务器,请访问 https://community.fit2cloud.com/#/products/dataease/downloads 下载离线安装包"
exit 1
fi
}
function _get_latest_version() {
rm -f /tmp/de_latest_release
_get_available_server
if [[ "x${server_url}" == "x" ]];then
echo "无法连接版本服务器,请稍候重试"
exit 1
fi
if [[ -x "$(command -v python)" ]]; then
py_cmd='python'
elif [[ -x "$(command -v python3)" ]]; then
py_cmd='python3'
fi
$py_cmd - <<EOF
# -*- coding: UTF-8 -*-
import os
@ -185,8 +178,6 @@ while (page <= 3):
if latest_release == None or latest_release == "":
print("Failed to obtain latest version, please try again.")
exit(1)
else:
print("latest version is %s" % (latest_release))
# 记录最新版本号
os.popen("echo "+latest_release+" > /tmp/de_latest_release")
@ -253,15 +244,12 @@ function reload() {
function version() {
echo
_get_current_version
_get_latest_version
echo "current version is $current_version"
_get_latest_version
echo "latest version is $latest_version"
}
function upgrade() {
echo
_get_current_version
echo "检测当前版本为${current_version}"
_get_available_server
_get_latest_version
version
if [ "${latest_version}" = "" ]; then
echo "未获取到最新版本"
@ -270,7 +258,12 @@ function upgrade() {
echo "最新版本与当前版本一致,退出升级过程"
exit 0
else
echo "检测到 ${server_url} 上最新版本为 ${latest_version} 即将执行在线升级..."
if [[ ! "$latest_version" =~ ^v2.* ]];then
echo "获取到的最新版本与当前版本不匹配,请访问 https://community.fit2cloud.com/#/products/dataease/downloads 下载离线安装包"
exit 1
else
echo "检测到 ${server_url} 上最新版本为 ${latest_version} 即将执行在线升级..."
fi
fi
sleep 2

View File

@ -20,7 +20,7 @@ if [ -f /usr/bin/dectl ]; then
dectl stop
INSTALL_TYPE='upgrade'
v2_version=$(dectl version |grep "^v2.")
v2_version=$(dectl version | head -n 2 | grep "v2.")
if [[ -z $v2_version ]];then
echo "系统当前版本不是 DataEase v2 版本系列,不支持升级到 v2请检查离线包版本。"
exit 1;
@ -48,6 +48,14 @@ DE_RUN_BASE=$DE_BASE/dataease2.0
conf_folder=${DE_RUN_BASE}/conf
templates_folder=${DE_RUN_BASE}/templates
if [[ $DE_RUN_BASE ]];then
for image in $(grep "image: " $DE_RUN_BASE/docker*.yml | awk -F 'image:' '{print $2}'); do
image_path=$(eval echo $image)
image_name=$(echo $image_path | awk -F "[/]" '{print $3}')
current_images[${#current_images[@]}]=$image_name
done
fi
function prop {
[ -f "$1" ] | grep -P "^\s*[^#]?${2}=.*$" $1 | cut -d'=' -f2
}
@ -183,7 +191,11 @@ cd ${CURRENT_DIR}
if [[ -d images ]]; then
log "加载镜像"
for i in $(ls images); do
docker load -i images/$i 2>&1 | tee -a ${CURRENT_DIR}/install.log
if [[ "${current_images[@]}" =~ "${i%.tar.gz}" ]]; then
echo "ignore image $i"
else
docker load -i images/$i 2>&1 | tee -a ${CURRENT_DIR}/install.log
fi
done
else
DEVERSION=$(cat ${CURRENT_DIR}/dataease/templates/version)

View File

@ -11,11 +11,13 @@ import java.util.List;
@Data
public class LogGridRequest extends KeywordRequest implements Serializable {
private String op;
private List<String> op;
private Long uid;
private List<Long> uid;
private Long oid;
private List<Long> oid;
private List<Long> time;
private Boolean timeDesc = true;
}

View File

@ -156,4 +156,8 @@ public interface UserApi {
@Hidden
@GetMapping("/queryByAccount")
CurUserVO queryByAccount(String account);
@Hidden
@PostMapping("/all")
List<UserItem> allUser(@RequestBody KeywordRequest request);
}

View File

@ -56,8 +56,8 @@ public interface SyncDatasourceApi {
@GetMapping("/validate/{datasourceId}")
SyncDatasourceDTO validate(@PathVariable("datasourceId") String datasourceId) throws DEException;
@PostMapping("/latestUse")
List<String> latestUse();
@PostMapping("/latestUse/{sourceType}")
List<String> latestUse(@PathVariable("sourceType") String sourceType);
@GetMapping("/get/{datasourceId}")
SyncDatasourceDTO get(@PathVariable("datasourceId") String datasourceId) throws DEException;

View File

@ -0,0 +1,22 @@
package io.dataease.utils;
import org.apache.commons.lang3.StringUtils;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
public class DateUtils {
public static String time2String(Long time, String pattern) {
if (StringUtils.isBlank(pattern)) pattern = "yyyy-MM-dd HH:mm:ss";
DateTimeFormatter format = DateTimeFormatter.ofPattern(pattern);
LocalDateTime timeByMilli = Instant.ofEpochMilli(time).atZone(ZoneId.of("Asia/Shanghai")).toLocalDateTime();
return format.format(timeByMilli);
}
public static String time2String(Long time) {
String pattern = "yyyy-MM-dd HH:mm:ss";
return time2String(time, pattern);
}
}