Merge branch 'dev-v2' of github.com:dataease/dataease into dev-v2

 Conflicts:
	core/core-frontend/src/views/template-market/component/CategoryTemplateV2.vue
	core/core-frontend/src/views/template-market/index.vue
This commit is contained in:
wangjiahao 2023-12-04 11:53:40 +08:00
commit d2522886cb
25 changed files with 116 additions and 46 deletions

View File

@ -16,7 +16,7 @@
DataEase 是开源的数据可视化分析工具帮助用户快速分析数据并洞察业务趋势从而实现业务的改进与优化。DataEase 支持丰富的数据源连接,能够通过拖拉拽方式快速制作图表,并可以方便的与他人分享。
<p align="center">
<img src="https://github.com/dataease/dataease/assets/41712985/ce8db032-227a-41e2-b45c-279007bd4ae3" alt="DataEase 概览图" border="0" />
<img src="https://github.com/dataease/dataease/assets/41712985/f951e258-a328-43a9-aa37-ee470d37ed63" alt="DataEase 概览图" border="0" />
</p>
**DataEase 的优势:**

View File

@ -1106,11 +1106,11 @@ public class ChartDataBuild {
break;
}
if (originStr.length() >= columnPermissionItem.getDesensitizationRule().getM() && originStr.length() >= columnPermissionItem.getDesensitizationRule().getN()) {
desensitizationStr = "***" + StringUtils.substring(originStr, columnPermissionItem.getDesensitizationRule().getM() - 1, columnPermissionItem.getDesensitizationRule().getN()) + "***";
desensitizationStr = StringUtils.substring(originStr, columnPermissionItem.getDesensitizationRule().getM() - 1, columnPermissionItem.getDesensitizationRule().getN()) + "***";
break;
}
if (originStr.length() >= columnPermissionItem.getDesensitizationRule().getM() && originStr.length() < columnPermissionItem.getDesensitizationRule().getN()) {
desensitizationStr = "***" + StringUtils.substring(originStr, columnPermissionItem.getDesensitizationRule().getM() - 1, originStr.length());
desensitizationStr = StringUtils.substring(originStr, columnPermissionItem.getDesensitizationRule().getM() - 1, originStr.length());
}
break;
default:

View File

@ -267,7 +267,7 @@ public class DatasourceServer implements DatasourceApi {
try {
datasourceSyncManage.createEngineTable(datasourceRequest.getTable(), tableFields);
} catch (Exception e) {
DEException.throwException("Failed to create table " + datasourceRequest.getTable());
DEException.throwException("Failed to create table " + datasourceRequest.getTable() + ", " + e.getMessage());
}
}
commonThreadPool.addTask(() -> {
@ -409,7 +409,7 @@ public class DatasourceServer implements DatasourceApi {
try {
datasourceSyncManage.createEngineTable(toCreateTable, ApiUtils.getTableFields(datasourceRequest));
} catch (Exception e) {
DEException.throwException("Failed to create table " + toCreateTable);
DEException.throwException("Failed to create table " + toCreateTable + ", " + e.getMessage());
}
}
datasourceSyncManage.deleteSchedule(datasourceTaskServer.selectByDSId(dataSourceDTO.getId()));
@ -425,7 +425,7 @@ public class DatasourceServer implements DatasourceApi {
try {
datasourceSyncManage.dropEngineTable(deleteTable);
} catch (Exception e) {
DEException.throwException("Failed to drop table " + deleteTable);
DEException.throwException("Failed to drop table " + deleteTable + ", " + e.getMessage());
}
}
for (String toCreateTable : toCreateTables) {
@ -433,7 +433,7 @@ public class DatasourceServer implements DatasourceApi {
try {
datasourceSyncManage.createEngineTable(toCreateTable, ExcelUtils.getTableFields(datasourceRequest));
} catch (Exception e) {
DEException.throwException("Failed to create table " + toCreateTable);
DEException.throwException("Failed to create table " + toCreateTable + ", " + e.getMessage());
}
}
datasourceSyncManage.extractExcelData(requestDatasource, "all_scope");

View File

@ -4,7 +4,7 @@ spring:
username: root
password: 123456
messages:
basename: i18n/core,i18n/permissions
basename: i18n/lic,i18n/core,i18n/permissions
flyway:
enabled: true
table: de_standalone_version

View File

@ -22,7 +22,9 @@ BEGIN;
INSERT INTO `core_menu`
VALUES (19, 0, 2, 'template-market', 'template-market', 4, NULL, '/template-market', 1, 1, 0);
INSERT INTO `core_menu`
VALUES (20, 15, 2, 'template-setting', 'system/template-setting', 4, 'icon_template', '/template-setting', 0, 1, 1);
VALUES (30, 0, 1, 'toolbox', null, 7, 'icon_template', '/toolbox', 1, 1, 0);
INSERT INTO `core_menu`
VALUES (31, 30, 2, 'template-setting', 'toolbox/template-setting', 1, 'icon_template', '/template-setting', 0, 1, 1);
COMMIT;
DROP TABLE IF EXISTS `visualization_template_extend_data`;
@ -52,8 +54,10 @@ CREATE TABLE `core_area_custom`
);
BEGIN;
INSERT INTO `core_sys_setting` VALUES (1, 'basic.dsIntervalTime', '6', 'text', 2);
INSERT INTO `core_sys_setting` VALUES (2, 'basic.dsExecuteTime', 'minute', 'text', 3);
INSERT INTO `core_sys_setting`
VALUES (1, 'basic.dsIntervalTime', '6', 'text', 2);
INSERT INTO `core_sys_setting`
VALUES (2, 'basic.dsExecuteTime', 'minute', 'text', 3);
INSERT INTO `core_sys_setting` (`id`, `pkey`, `pval`, `type`, `sort`) VALUES (7, 'template.url', 'https://templates-de.fit2cloud.com', 'text', 0);
INSERT INTO `core_sys_setting` (`id`, `pkey`, `pval`, `type`, `sort`) VALUES (8, 'template.accessKey', 'dataease', 'text', 1);
COMMIT;
COMMIT;

View File

@ -83,6 +83,11 @@
<value-type>java.lang.Integer</value-type>
</cache>
<cache alias="user_echelon" uses-template="common-cache">
<key-type>java.lang.String</key-type>
<value-type>java.util.List</value-type>
</cache>
<cache alias="role_busi_pers_interactive" uses-template="common-cache">
<key-type>java.lang.String</key-type>
<value-type>java.util.List</value-type>
@ -130,17 +135,17 @@
</resources>
</cache>
<cache alias="core_menu_cache">
<cache alias="core_menu_cache" uses-template="common-cache">
<key-type>java.lang.String</key-type>
<value-type>java.util.List</value-type>
<expiry>
<!--<expiry>
<none/>
</expiry>
<resources>
<heap unit="entries">20</heap>
<offheap unit="MB">2</offheap>
<disk unit="MB" persistent="true">5</disk>
</resources>
</resources>-->
</cache>
</config>

View File

@ -116,10 +116,10 @@ service.interceptors.response.use(
response: AxiosResponse<any> & { config: InternalAxiosRequestConfig & { loading?: boolean } }
) => {
executeVersionHandler(response)
if (response.headers['x-de-refresh-token']) {
/* if (response.headers['x-de-refresh-token']) {
wsCache.set('user.token', response.headers['x-de-refresh-token'])
wsCache.set('user.exp', new Date().getTime() + 90000)
}
} */
if (response.headers['x-de-link-token']) {
linkStore.setLinkToken(response.headers['x-de-link-token'])
}

View File

@ -2,6 +2,7 @@
import { ref, reactive, nextTick, computed, shallowRef, toRefs, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import { useI18n } from '@/hooks/web/useI18n'
import { fieldType } from '@/utils/attr'
import { ElMessage } from 'element-plus-secondary'
@ -55,6 +56,7 @@ const activeConditionForRename = reactive({
visible: false
})
const datasetMap = {}
const snapshotStore = snapshotStoreWithOut()
const dfsComponentData = () => {
const isMain = componentData.value.some(ele => ele.id === queryElement.value.id)
@ -308,6 +310,7 @@ const confirmClick = () => {
)
})
queryElement.value.propValue = cloneDeep(conditions.value)
snapshotStore.recordSnapshotCache()
}
const cancelValueSource = () => {

View File

@ -7,6 +7,7 @@ import HeaderMenuItem from './HeaderMenuItem.vue'
import { Icon } from '@/components/icon-custom'
import { ElHeader, ElMenu } from 'element-plus-secondary'
import SystemCfg from './SystemCfg.vue'
import ToolboxCfg from './ToolboxCfg.vue'
import { useRouter, useRoute } from 'vue-router'
import TopDoc from '@/layout/components/TopDoc.vue'
import AccountOperator from '@/layout/components/AccountOperator.vue'
@ -26,6 +27,7 @@ const permissionStore = usePermissionStore()
const routers: any[] = formatRoute(permissionStore.getRoutersNotHidden as AppCustomRouteRecordRaw[])
const showSystem = ref(false)
const showToolbox = ref(false)
const handleSelect = (index: string) => {
//
if (isExternal(index)) {
@ -37,8 +39,12 @@ const handleSelect = (index: string) => {
const initShowSystem = () => {
showSystem.value = permissionStore.getRouters.some(route => route.path === '/system')
}
const initShowToolbox = () => {
showToolbox.value = permissionStore.getRouters.some(route => route.path === '/toolbox')
}
onMounted(() => {
initShowSystem()
initShowToolbox()
})
</script>
@ -56,6 +62,7 @@ onMounted(() => {
</el-menu>
<div class="operate-setting" v-if="!desktop">
<XpackComponent jsname="c3dpdGNoZXI=" />
<ToolboxCfg v-if="showToolbox" />
<TopDoc />
<SystemCfg v-if="showSystem" />
<AccountOperator />

View File

@ -2,7 +2,11 @@
import { ElHeader } from 'element-plus-secondary'
import { useRouter } from 'vue-router'
import AccountOperator from '@/layout/components/AccountOperator.vue'
import { propTypes } from '@/utils/propTypes'
const { push } = useRouter()
const props = defineProps({
title: propTypes.string.def('系统设置')
})
const backToMain = () => {
push('/workbranch/index')
}
@ -12,7 +16,7 @@ const backToMain = () => {
<el-header class="header-flex system-header">
<Icon className="logo" name="logo"></Icon>
<el-divider direction="vertical" />
<span class="system">系统设置</span>
<span class="system">{{ props.title || '系统设置' }}</span>
<div class="operate-setting">
<span @click="backToMain" class="work-bar flex-align-center">
<el-icon>

View File

@ -0,0 +1,34 @@
<script lang="ts" setup>
import { useRouter } from 'vue-router'
const { push, resolve } = useRouter()
const redirectUser = () => {
const toolboxMenu = resolve('/toolbox')
const kidPath = toolboxMenu.matched[0].children[0].path
push(`${toolboxMenu.path}/${kidPath}`)
}
</script>
<template>
<el-tooltip class="box-item" effect="dark" content="工具箱" placement="top">
<div class="sys-setting">
<el-icon @click="redirectUser">
<Icon class="icon-setting" name="sys-tools" />
</el-icon>
</div>
</el-tooltip>
</template>
<style lang="less" scoped>
.sys-setting {
margin: 0 0 0 10px;
padding: 5px;
height: 28px;
width: 28px;
border-radius: 4px;
overflow: hidden;
cursor: pointer;
&:hover {
background-color: #1e2738;
}
}
</style>

View File

@ -7,23 +7,28 @@ import Menu from './components/Menu.vue'
import Main from './components/Main.vue'
import { ElContainer } from 'element-plus-secondary'
import { useRoute } from 'vue-router'
import HeaderTemplateMarket from '@/layout/components/HeaderTemplateMarket.vue'
const route = useRoute()
const systemMenu = computed(() => route.path.includes('system'))
const settingMenu = computed(() => route.path.includes('sys-setting'))
const templateMarketMenu = computed(() => route.path.includes('template-market'))
const marketMenu = computed(() => route.path.includes('template-market'))
const toolboxMenu = computed(() => route.path.includes('toolbox'))
</script>
<template>
<div class="common-layout">
<header-template-market v-if="templateMarketMenu"></header-template-market>
<HeaderSystem v-else-if="settingMenu"></HeaderSystem>
<HeaderSystem
v-if="settingMenu || marketMenu || toolboxMenu"
:title="toolboxMenu ? '工具箱' : marketMenu ? '模板中心' : ''"
/>
<Header v-else></Header>
<el-container class="layout-container">
<Sidebar v-if="systemMenu || settingMenu" class="layout-sidebar">
<Sidebar v-if="systemMenu || settingMenu || toolboxMenu" class="layout-sidebar">
<Menu style="height: 100%"></Menu>
</Sidebar>
<Main class="layout-main" :class="{ 'with-sider': systemMenu || settingMenu }"></Main>
<Main
class="layout-main"
:class="{ 'with-sider': systemMenu || settingMenu || toolboxMenu }"
></Main>
</el-container>
</div>
</template>

View File

@ -1,4 +1,4 @@
import { deepCopy } from '@/utils/utils'
import { cloneDeep } from 'lodash-es'
import componentList, {
COMMON_COMPONENT_BACKGROUND_DARK,
COMMON_COMPONENT_BACKGROUND_LIGHT
@ -17,12 +17,12 @@ const { curBatchOptComponents, dvInfo, canvasStyleData, componentData, canvasVie
const snapshotStore = snapshotStoreWithOut()
export function chartTransStr2Object(targetIn, copy) {
const target = copy === 'Y' ? deepCopy(targetIn) : targetIn
const target = copy === 'Y' ? cloneDeep(targetIn) : targetIn
return target
}
export function chartTransObject2Str(targetIn, copy) {
const target = copy === 'Y' ? deepCopy(targetIn) : targetIn
const target = copy === 'Y' ? cloneDeep(targetIn) : targetIn
return target
}
@ -37,7 +37,7 @@ export function findNewComponent(componentName, innerType) {
let newComponent
componentList.forEach(comp => {
if (comp.component === componentName) {
newComponent = deepCopy(comp)
newComponent = cloneDeep(comp)
newComponent.innerType = innerType
if (newComponent.innerType === 'richText') {
newComponent.propValue = {
@ -45,9 +45,9 @@ export function findNewComponent(componentName, innerType) {
}
}
if (dvMainStore.curOriginThemes === 'light') {
newComponent['commonBackground'] = deepCopy(COMMON_COMPONENT_BACKGROUND_LIGHT)
newComponent['commonBackground'] = cloneDeep(COMMON_COMPONENT_BACKGROUND_LIGHT)
} else {
newComponent['commonBackground'] = deepCopy(COMMON_COMPONENT_BACKGROUND_DARK)
newComponent['commonBackground'] = cloneDeep(COMMON_COMPONENT_BACKGROUND_DARK)
}
}
})
@ -130,7 +130,7 @@ export function checkIsBatchOptView(viewId) {
}
export function canvasSave(callBack) {
const componentDataToSave = deepCopy(componentData.value)
const componentDataToSave = cloneDeep(componentData.value)
componentDataToSave.forEach(item => {
if (item.component === 'UserView') {
item.linkageFilters = []
@ -152,6 +152,7 @@ export function canvasSave(callBack) {
canvasViewInfo: canvasViewInfo.value,
...dvInfo.value
}
const method = dvInfo.value.id ? updateCanvas : saveCanvas
method(canvasInfo).then(res => {
if (res && res.data) {

View File

@ -42,6 +42,9 @@ const searchResult = computed(
)
const showFlagCheck = template => {
if (!template.categoryNames) {
console.log('===templateTest' + JSON.stringify(template))
}
return template.showFlag && template.categoryNames?.includes(props.label)
}

View File

@ -273,6 +273,7 @@ const categoriesComputed = computed(() => {
category => category.source === 'public' || category.source === state.templateSourceType
)
}
console.log('categoriesComputed=' + JSON.stringify(result))
return result
})

View File

@ -336,9 +336,8 @@ const getEmptyDesc = (): string => {
padding: 8px 24px 0 24px;
background: #fff;
border-radius: 4px;
// height: calc(100% - 280px);
// margin-top: 16px;
height: 100%;
height: calc(100% - 280px);
margin-top: 16px;
.select-type-list {
width: 104px;

@ -1 +1 @@
Subproject commit 31d53d9a7650f4902ba93269d20912b3bb08bfac
Subproject commit 438f36fc4b459721ae0d88e365e4982f35fa1600

View File

@ -9,6 +9,7 @@ import io.dataease.auth.DePermit;
import io.dataease.auth.vo.TokenVO;
import io.dataease.model.KeywordRequest;
import io.dataease.request.BaseGridRequest;
import io.swagger.v3.oas.annotations.Hidden;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@ -66,6 +67,7 @@ public interface UserApi {
@PostMapping("/byCurOrg")
List<UserItem> byCurOrg(@RequestBody KeywordRequest request);
@Hidden
@GetMapping("/userCount")
int userCount();
@ -100,5 +102,7 @@ public interface UserApi {
@PostMapping("/modifyPwd")
void modifyPwd(@RequestBody ModifyPwdRequest request);
@Hidden
@GetMapping("/firstEchelon/{limit}")
List<Long> firstEchelon(@PathVariable("limit") Long limit);
}

View File

@ -9,6 +9,7 @@ import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.Objects;
public class TokenFilter implements Filter {
@ -35,13 +36,13 @@ public class TokenFilter implements Filter {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
String refreshToken = null;
/*String refreshToken = null;
if (StringUtils.isNotBlank(refreshToken = ServletUtils.request().getHeader(AuthConstant.REFRESH_TOKEN_KEY))) {
ServletUtils.response().addHeader(AuthConstant.REFRESH_TOKEN_KEY, refreshToken);
}
}*/
String executeVersion = null;
if (StringUtils.isNotBlank(executeVersion = VersionUtil.getRandomVersion())) {
ServletUtils.response().addHeader(AuthConstant.DE_EXECUTE_VERSION, executeVersion);
Objects.requireNonNull(ServletUtils.response()).addHeader(AuthConstant.DE_EXECUTE_VERSION, executeVersion);
}
String linkToken = ServletUtils.getHead(AuthConstant.LINK_TOKEN_KEY);
if (StringUtils.isNotBlank(linkToken)) {

View File

@ -37,6 +37,7 @@ public class CorsInterceptor implements HandlerInterceptor {
public void addOriginList() {
busiOriginList.clear();
String className = "io.dataease.api.permissions.embedded.api.EmbeddedApi";
String methodName = "domainList";
if (ObjectUtils.isEmpty(aClass)) {
@ -54,10 +55,8 @@ public class CorsInterceptor implements HandlerInterceptor {
if (ObjectUtils.isNotEmpty(result)) {
List<String> list = (List<String>) result;
if (CollectionUtils.isNotEmpty(list)) {
List<String> strings = list.stream().filter(item -> !busiOriginList.contains(item)).toList();
busiOriginList.addAll(strings);
busiOriginList.addAll(list.stream().distinct().toList());
}
}
}
}

View File

@ -13,7 +13,7 @@ public class AuthConstant {
public final static String DE_API_PREFIX = "/de2api";
public final static String REFRESH_TOKEN_KEY = "X-DE-REFRESH-TOKEN";
// public final static String REFRESH_TOKEN_KEY = "X-DE-REFRESH-TOKEN";
public final static String USER_IMPORT_ERROR_KEY = "USER-IMPORT-ERROR-KEY";

View File

@ -3,6 +3,7 @@ package io.dataease.constant;
public class CacheConstant {
public static class UserCacheConstant {
public static final String USER_COUNT_CACHE = "user_count";
public static final String USER_ECHELON_CACHE = "user_echelon";
public static final String LOGIN_USER_CACHE = "login_user_cache";
public static final String USER_ROLES_CACHE = "user_roles";
public static final String USER_BUSI_PERS_CACHE = "user_busi_pers";

View File

@ -29,7 +29,7 @@ public class AuthUtils {
}
public static boolean isSysAdmin(Long userId) {
return userId == SYS_ADMIN_UID;
return userId.equals(SYS_ADMIN_UID);
}

View File

@ -28,8 +28,7 @@ public class TokenUtils {
if (StringUtils.length(token) < 100) {
DEException.throwException("token is invalid");
}
TokenUserBO tokenUserBO = userBOByToken(token);
return tokenUserBO;
return userBOByToken(token);
}
public static TokenUserBO validateLinkToken(String linkToken) {