refactor: 修复冲突

This commit is contained in:
taojinlong 2022-01-17 18:05:26 +08:00
commit be5b1b07c2
128 changed files with 2072 additions and 627 deletions

View File

@ -256,6 +256,11 @@
<artifactId>selenium-java</artifactId>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.14.3</version>
</dependency>
</dependencies>
<build>
@ -415,10 +420,10 @@
</fileset>
</copy>
<copy file="../mobile/dist/build/h5/index.html" tofile="src/main/resources/templates/app.html" />
</target>
</configuration>
<goals>

View File

@ -13,31 +13,27 @@ import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Map;
@Api(tags = "权限:权限管理")
@ApiSupport(order = 10)
@RequestMapping("/api/auth")
public interface AuthApi {
@ApiOperation("登录")
@PostMapping("/login")
Object login(LoginDto loginDto) throws Exception;
@ApiOperation("获取用户信息")
@PostMapping("/userInfo")
CurrentUserDto userInfo();
@ApiOperation("是否使用初始密码")
@PostMapping("/useInitPwd")
Boolean useInitPwd();
@ApiOperation("登出")
@PostMapping("/logout")
String logout();
@ApiOperation("验证账号")
@PostMapping("/validateName")
Boolean validateName(Map<String, String> nameDto);
@ -46,7 +42,6 @@ public interface AuthApi {
@PostMapping("/isOpenLdap")
boolean isOpenLdap();
@ApiOperation("是否开启oidc")
@PostMapping("/isOpenOidc")
boolean isOpenOidc();

View File

@ -27,6 +27,7 @@ import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@ -40,6 +41,9 @@ import javax.servlet.http.HttpServletRequest;
@RestController
public class AuthServer implements AuthApi {
@Value("${dataease.init_password:DataEase123..}")
private String DEFAULT_PWD;
@Autowired
private AuthUserService authUserService;
@ -65,14 +69,19 @@ public class AuthServer implements AuthApi {
SysUserEntity user = authUserService.getLdapUserByName(username);
if (ObjectUtils.isEmpty(user) || ObjectUtils.isEmpty(user.getUserId())) {
LdapAddRequest ldapAddRequest = new LdapAddRequest();
ldapAddRequest.setUsers(new ArrayList<XpackLdapUserEntity>() {{
add(ldapUserEntity);
}});
ldapAddRequest.setUsers(new ArrayList<XpackLdapUserEntity>() {
{
add(ldapUserEntity);
}
});
ldapAddRequest.setEnabled(1L);
ldapAddRequest.setRoleIds(new ArrayList<Long>() {{
add(2L);
}});
sysUserService.validateExistUser(ldapUserEntity.getUsername(), ldapUserEntity.getNickname(), ldapUserEntity.getEmail());
ldapAddRequest.setRoleIds(new ArrayList<Long>() {
{
add(2L);
}
});
sysUserService.validateExistUser(ldapUserEntity.getUsername(), ldapUserEntity.getNickname(),
ldapUserEntity.getEmail());
sysUserService.saveLdapUsers(ldapAddRequest);
}
@ -92,9 +101,9 @@ public class AuthServer implements AuthApi {
// 普通登录需要验证密码
if (loginType == 0 || !isSupportLdap) {
//私钥解密
// 私钥解密
//md5加密
// md5加密
pwd = CodingUtil.md5(pwd);
if (!StringUtils.equals(pwd, realPwd)) {
@ -128,6 +137,16 @@ public class AuthServer implements AuthApi {
return userDto;
}
@Override
public Boolean useInitPwd() {
CurrentUserDto user = AuthUtils.getUser();
if (null == user) {
return false;
}
String md5 = CodingUtil.md5(DEFAULT_PWD);
return StringUtils.equals(AuthUtils.getUser().getPassword(), md5);
}
@Override
public String logout() {
String token = ServletUtils.getToken();
@ -158,7 +177,8 @@ public class AuthServer implements AuthApi {
@Override
public Boolean validateName(@RequestBody Map<String, String> nameDto) {
String userName = nameDto.get("userName");
if (StringUtils.isEmpty(userName)) return false;
if (StringUtils.isEmpty(userName))
return false;
SysUserEntity userEntity = authUserService.getUserByName(userName);
return !ObjectUtils.isEmpty(userEntity);
}
@ -166,29 +186,30 @@ public class AuthServer implements AuthApi {
@Override
public boolean isOpenLdap() {
Boolean licValid = PluginUtils.licValid();
if (!licValid) return false;
if (!licValid)
return false;
return authUserService.supportLdap();
}
@Override
public boolean isOpenOidc() {
Boolean licValid = PluginUtils.licValid();
if (!licValid) return false;
if (!licValid)
return false;
return authUserService.supportOidc();
}
@Override
public boolean isPluginLoaded() {
Boolean licValid = PluginUtils.licValid();
if (!licValid) return false;
if (!licValid)
return false;
return authUserService.pluginLoaded();
}
@Override
public String getPublicKey() {
return RsaProperties.publicKey;
}
}

View File

@ -7,6 +7,7 @@ import io.dataease.base.domain.SysMenu;
import io.dataease.base.domain.SysMenuExample;
import io.dataease.base.mapper.SysMenuMapper;
import io.dataease.base.mapper.ext.ExtPluginSysMenuMapper;
import io.dataease.base.mapper.ext.ExtSysMenuMapper;
import io.dataease.plugins.common.dto.PluginSysMenu;
import io.dataease.plugins.util.PluginUtils;
import org.apache.commons.collections4.CollectionUtils;
@ -30,12 +31,16 @@ public class DynamicMenuServiceImpl implements DynamicMenuService {
@Resource
private ExtPluginSysMenuMapper extPluginSysMenuMapper;
@Resource
private ExtSysMenuMapper extSysMenuMapper;
@Override
public List<DynamicMenuDto> load(String userId) {
SysMenuExample sysMenuExample = new SysMenuExample();
sysMenuExample.createCriteria().andTypeLessThanOrEqualTo(1);
sysMenuExample.setOrderByClause(" menu_sort ");
List<SysMenu> sysMenus = sysMenuMapper.selectByExample(sysMenuExample);
// SysMenuExample sysMenuExample = new SysMenuExample();
// sysMenuExample.createCriteria().andTypeLessThanOrEqualTo(1);
// sysMenuExample.setOrderByClause(" menu_sort ");
// List<SysMenu> sysMenus = sysMenuMapper.selectByExample(sysMenuExample);
List<SysMenu> sysMenus = extSysMenuMapper.querySysMenu();
List<DynamicMenuDto> dynamicMenuDtos = sysMenus.stream().map(this::convert).collect(Collectors.toList());
//增加插件中的菜单
List<PluginSysMenu> pluginSysMenus = PluginUtils.pluginMenus();

View File

@ -17,16 +17,13 @@ import org.springframework.core.env.Environment;
import java.util.Date;
public class JWTUtils {
// token过期时间1min (过期会自动刷新续命 目的是避免一直都是同一个token )
private static final long EXPIRE_TIME = 1 * 60 * 1000;
// 登录间隔时间10min 超过这个时间强制重新登录
private static long Login_Interval;
/**
* 校验token是否正确
*
@ -82,7 +79,8 @@ public class JWTUtils {
public static boolean loginExpire(String token) {
if (Login_Interval == 0) {
// 默认超时时间是8h
int minute = CommonBeanFactory.getBean(Environment.class).getProperty("dataease.login_timeout", Integer.class, 8 * 60);
Long minute = CommonBeanFactory.getBean(Environment.class).getProperty("dataease.login_timeout", Long.class,
8 * 60L);
// 分钟换算成毫秒
Login_Interval = minute * 1000 * 60;
}
@ -128,19 +126,19 @@ public class JWTUtils {
public static String signLink(String resourceId, Long userId, String secret) {
Algorithm algorithm = Algorithm.HMAC256(secret);
if(userId == null){
if (userId == null) {
return JWT.create().withClaim("resourceId", resourceId).sign(algorithm);
}else {
} else {
return JWT.create().withClaim("resourceId", resourceId).withClaim("userId", userId).sign(algorithm);
}
}
public static boolean verifyLink(String token, String resourceId, Long userId, String secret) {
public static boolean verifyLink(String token, String resourceId, Long userId, String secret) {
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier;
if(userId == null){
if (userId == null) {
verifier = JWT.require(algorithm).withClaim("resourceId", resourceId).build();
}else {
} else {
verifier = JWT.require(algorithm).withClaim("resourceId", resourceId).withClaim("userId", userId).build();
}

View File

@ -1,5 +1,6 @@
package io.dataease.base.mapper.ext;
import io.dataease.base.domain.SysMenu;
import io.dataease.base.mapper.ext.query.GridExample;
import io.dataease.controller.sys.request.SimpleTreeNode;
@ -10,4 +11,6 @@ public interface ExtSysMenuMapper {
List<SimpleTreeNode> allNodes();
List<SimpleTreeNode> nodesByExample(GridExample example);
List<SysMenu> querySysMenu();
}

View File

@ -7,6 +7,8 @@
<result property="pid" column="pid" javaType="java.lang.Long"/>
</resultMap>
<resultMap id="ExtBaseResultMap" type="io.dataease.base.domain.SysMenu" extends="io.dataease.base.mapper.SysMenuMapper.BaseResultMap"></resultMap>
<select id="allNodes" resultMap="simpleNode">
select menu_id as id, pid from sys_menu where hidden != 1
</select>
@ -19,4 +21,27 @@
</select>
<select id="querySysMenu" resultMap="ExtBaseResultMap">
SELECT
*
FROM
sys_menu
WHERE
type &lt;= 1
AND (
sys_menu.menu_id != 61
OR EXISTS (
SELECT
1
FROM
system_parameter
WHERE
param_key = 'ui.openHomePage'
AND param_value = 'true'
)
)
ORDER BY
menu_sort
</select>
</mapper>

View File

@ -0,0 +1,9 @@
package io.dataease.base.mapper.ext;
public interface ExtTaskMapper {
int runningCount(Long taskId);
void resetRunnings(Long taskId);
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="io.dataease.base.mapper.ext.ExtTaskMapper">
<select id="runningCount" resultType="java.lang.Integer">
select count(*) as count from sys_task_instance where task_id = #{taskId} and status = 0
</select>
<update id="resetRunnings">
update sys_task_instance set status = -1, info = 'System Interrupt Error' where task_id = #{taskId} and status = 0
</update>
</mapper>

View File

@ -0,0 +1,113 @@
package io.dataease.commons.pool;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import io.dataease.commons.utils.LogUtil;
public class PriorityThreadPoolExecutor extends ThreadPoolExecutor {
public static AtomicInteger globaInteger = new AtomicInteger(1);
private ThreadLocal<Integer> local = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 1;
}
};
public PriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, getWorkQueue());
}
public PriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, getWorkQueue(), threadFactory);
}
public PriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, getWorkQueue(), handler);
}
public PriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, getWorkQueue(), threadFactory, handler);
}
protected static PriorityBlockingQueue getWorkQueue() {
return new PriorityBlockingQueue();
}
@Override
public void execute(Runnable command) {
int andIncrement = globaInteger.getAndIncrement();
Integer theadInteger = local.get();
try {
if (theadInteger == 0) {
this.execute(command, 0);
} else {
this.execute(command, andIncrement);
}
} finally {
local.set(1);
}
}
public void execute(Runnable command, int priority) {
super.execute(new PriorityRunnable(command, priority));
}
public <T> Future<T> submit(Callable<T> task, int priority) {
local.set(priority);
return super.submit(task);
}
protected static class PriorityRunnable<E extends Comparable<? super E>>
implements Runnable, Comparable<PriorityRunnable<E>> {
private final static AtomicLong seq = new AtomicLong();
private final long seqNum;
Runnable run;
private int priority;
public PriorityRunnable(Runnable run, int priority) {
seqNum = seq.getAndIncrement();
this.run = run;
this.priority = priority;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public Runnable getRun() {
return run;
}
@Override
public void run() {
LogUtil.info("number " + priority + " is starting...");
this.run.run();
}
@Override
public int compareTo(PriorityRunnable<E> other) {
int res = 0;
if (this.priority == other.priority) {
if (other.run != this.run) {// ASC
res = (seqNum < other.seqNum ? -1 : 1);
}
} else {// DESC
res = this.priority > other.priority ? 1 : -1;
}
return res;
}
}
}

View File

@ -0,0 +1,17 @@
package io.dataease.commons.pool;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.Data;
@ConfigurationProperties(prefix = "detask", ignoreInvalidFields = true)
@Data
@Component
public class PriorityThreadPoolProperties {
private int corePoolSize = 2;
private int maximumPoolSize = 100;
private int keepAliveTime = 60;
}

View File

@ -1,15 +1,25 @@
package io.dataease.config;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import io.dataease.commons.pool.PriorityThreadPoolExecutor;
import io.dataease.commons.pool.PriorityThreadPoolProperties;
@EnableAsync(proxyTargetClass = true)
@Configuration
public class AsyncConfig {
@Resource
private PriorityThreadPoolProperties priorityThreadPoolProperties;
@Bean
public AsyncTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
@ -18,4 +28,18 @@ public class AsyncConfig {
executor.setMaxPoolSize(10);
return executor;
}
@Bean
public PriorityThreadPoolExecutor priorityExecutor() {
int corePoolSize = priorityThreadPoolProperties.getCorePoolSize();
int maximumPoolSize = priorityThreadPoolProperties.getMaximumPoolSize();
int keepAliveTime = priorityThreadPoolProperties.getKeepAliveTime();
PriorityThreadPoolExecutor executor = new PriorityThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, TimeUnit.SECONDS);
return executor;
}
}

View File

@ -0,0 +1,30 @@
package io.dataease.controller.wizard;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.dataease.service.wizard.ReptileService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Map;
@Api(tags = "首页")
@ApiSupport(order = 80)
@RestController
@RequestMapping("Reptile")
public class ReptileController {
@Resource
private ReptileService reptileService;
@GetMapping("lastActive")
@ApiOperation("获取官方Blog最新动态")
public Map<String, String> lastActive() {
return reptileService.lastActive();
}
}

View File

@ -28,7 +28,7 @@ public class ScheduleManager {
* @throws SchedulerException
*/
public void addSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> cls, int repeatIntervalTime,
JobDataMap jobDataMap) throws SchedulerException {
JobDataMap jobDataMap) throws SchedulerException {
JobBuilder jobBuilder = JobBuilder.newJob(cls).withIdentity(jobKey);
@ -46,7 +46,8 @@ public class ScheduleManager {
scheduler.scheduleJob(jd, trigger);
}
public void addSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> cls, int repeatIntervalTime) throws SchedulerException {
public void addSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> cls, int repeatIntervalTime)
throws SchedulerException {
addSimpleJob(jobKey, triggerKey, cls, repeatIntervalTime);
}
@ -59,7 +60,8 @@ public class ScheduleManager {
* @param cron
* @param jobDataMap
*/
public void addCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, Date startTime, Date endTime, JobDataMap jobDataMap) {
public void addCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, Date startTime,
Date endTime, JobDataMap jobDataMap) {
try {
LogUtil.info("addCronJob: " + triggerKey.getName() + "," + triggerKey.getGroup());
@ -99,7 +101,8 @@ public class ScheduleManager {
}
}
public void addCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, Date startTime, Date endTime) {
public void addCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, Date startTime,
Date endTime) {
addCronJob(jobKey, triggerKey, jobClass, cron, startTime, endTime, null);
}
@ -140,7 +143,8 @@ public class ScheduleManager {
* @param cron
* @throws SchedulerException
*/
public void modifyCronJobTime(TriggerKey triggerKey, String cron, Date startTime, Date endTime) throws SchedulerException {
public void modifyCronJobTime(TriggerKey triggerKey, String cron, Date startTime, Date endTime)
throws SchedulerException {
LogUtil.info("modifyCronJobTime: " + triggerKey.getName() + "," + triggerKey.getGroup());
@ -151,7 +155,6 @@ public class ScheduleManager {
return;
}
/** 方式一 :调用 rescheduleJob 开始 */
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();// 触发器
@ -279,7 +282,6 @@ public class ScheduleManager {
}
}
public static void startJobs(Scheduler sched) {
try {
sched.start();
@ -289,7 +291,6 @@ public class ScheduleManager {
}
}
public void shutdownJobs(Scheduler sched) {
try {
if (!sched.isShutdown()) {
@ -312,7 +313,7 @@ public class ScheduleManager {
* @throws SchedulerException
*/
public void addOrUpdateSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class clz,
int intervalTime, JobDataMap jobDataMap) throws SchedulerException {
int intervalTime, JobDataMap jobDataMap) throws SchedulerException {
if (scheduler.checkExists(triggerKey)) {
modifySimpleJobTime(triggerKey, intervalTime);
@ -323,7 +324,7 @@ public class ScheduleManager {
}
public void addOrUpdateSingleJob(JobKey jobKey, TriggerKey triggerKey, Class clz,
Date date, JobDataMap jobDataMap) throws SchedulerException {
Date date, JobDataMap jobDataMap) throws SchedulerException {
if (scheduler.checkExists(triggerKey)) {
modifySingleJobTime(triggerKey, date);
} else {
@ -333,15 +334,15 @@ public class ScheduleManager {
}
public void addOrUpdateSingleJob(JobKey jobKey, TriggerKey triggerKey, Class clz,
Date date) throws SchedulerException {
Date date) throws SchedulerException {
addOrUpdateSingleJob(jobKey, triggerKey, clz, date, null);
}
public void addOrUpdateSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class clz, int intervalTime) throws SchedulerException {
public void addOrUpdateSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class clz, int intervalTime)
throws SchedulerException {
addOrUpdateSimpleJob(jobKey, triggerKey, clz, intervalTime, null);
}
/**
* 添加或修改 cronJob
*
@ -352,7 +353,8 @@ public class ScheduleManager {
* @param jobDataMap
* @throws SchedulerException
*/
public void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, Date startTime, Date endTime, JobDataMap jobDataMap) throws SchedulerException {
public void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, Date startTime,
Date endTime, JobDataMap jobDataMap) throws SchedulerException {
LogUtil.info("AddOrUpdateCronJob: " + jobKey.getName() + "," + triggerKey.getGroup());
@ -363,7 +365,8 @@ public class ScheduleManager {
}
}
public void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, Date startTime, Date endTime) throws SchedulerException {
public void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, Date startTime,
Date endTime) throws SchedulerException {
addOrUpdateCronJob(jobKey, triggerKey, jobClass, cron, startTime, endTime, null);
}
@ -398,7 +401,8 @@ public class ScheduleManager {
if (!CronExpression.isValidExpression(cron)) {
DataEaseException.throwException("cron :" + cron + " error");
}
return TriggerBuilder.newTrigger().withIdentity("Calculate Date").withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
return TriggerBuilder.newTrigger().withIdentity("Calculate Date")
.withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
}

View File

@ -13,9 +13,6 @@ import java.util.Date;
public abstract class TaskHandler implements InitializingBean {
private static final String[] week = {"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"};
public void addTask(ScheduleManager scheduleManager, GlobalTaskEntity taskEntity) throws Exception {
// 1首先看看是否过期
Long endTime = taskEntity.getEndTime();
@ -30,12 +27,11 @@ public abstract class TaskHandler implements InitializingBean {
if (ObjectUtils.isNotEmpty(taskEntity.getEndTime())) {
new Date(taskEntity.getEndTime());
}
Class executor = this.getClass();
Class<? extends TaskHandler> executor = this.getClass();
String cron = cron(taskEntity);
scheduleManager.addOrUpdateCronJob(jobKey, triggerKey, executor, cron, start, end, jobDataMap(taskEntity));
}
protected abstract JobDataMap jobDataMap(GlobalTaskEntity taskEntity);
private String cron(GlobalTaskEntity taskEntity) {
@ -54,36 +50,34 @@ public abstract class TaskHandler implements InitializingBean {
instance.setTime(date);
if (taskEntity.getRateType() == 0) {
return
instance.get(Calendar.SECOND) + " " +
instance.get(Calendar.MINUTE) + " " +
instance.get(Calendar.HOUR_OF_DAY) + " * * ?";
return instance.get(Calendar.SECOND) + " " +
instance.get(Calendar.MINUTE) + " " +
instance.get(Calendar.HOUR_OF_DAY) + " * * ?";
}
if (taskEntity.getRateType() == 1) {
return
instance.get(Calendar.SECOND) + " " +
instance.get(Calendar.MINUTE) + " " +
instance.get(Calendar.HOUR_OF_DAY) + " ? * " +
getDayOfWeek(instance);
return instance.get(Calendar.SECOND) + " " +
instance.get(Calendar.MINUTE) + " " +
instance.get(Calendar.HOUR_OF_DAY) + " ? * " +
getDayOfWeek(instance);
}
if (taskEntity.getRateType() == 2) {
return
instance.get(Calendar.SECOND) + " " +
instance.get(Calendar.MINUTE) + " " +
instance.get(Calendar.HOUR_OF_DAY) + " " +
instance.get(Calendar.DATE) + " * ?";
return instance.get(Calendar.SECOND) + " " +
instance.get(Calendar.MINUTE) + " " +
instance.get(Calendar.HOUR_OF_DAY) + " " +
instance.get(Calendar.DATE) + " * ?";
}
return null;
}
public abstract void resetRunningInstance(Long taskId);
private String getDayOfWeek(Calendar instance) {
int index = instance.get(Calendar.DAY_OF_WEEK);
index = (index + 1) % 7;
index = (index + 1) % 7;
return String.valueOf(index);
}
public void removeTask(ScheduleManager scheduleManager, GlobalTaskEntity taskEntity) {
JobKey jobKey = new JobKey(taskEntity.getTaskId().toString());
TriggerKey triggerKey = new TriggerKey(taskEntity.getTaskId().toString());
@ -95,14 +89,16 @@ public abstract class TaskHandler implements InitializingBean {
scheduleManager.fireNow(jobKey);
}
//判断任务是否过期
// 判断任务是否过期
public Boolean taskExpire(Long endTime) {
if (ObjectUtils.isEmpty(endTime)) return false;
if (ObjectUtils.isEmpty(endTime))
return false;
Long now = System.currentTimeMillis();
return now > endTime;
}
protected abstract Boolean taskIsRunning(Long taskId);
@Override
public void afterPropertiesSet() throws Exception {
String beanName = null;

View File

@ -5,6 +5,7 @@ import io.dataease.auth.entity.TokenInfo;
import io.dataease.auth.service.AuthUserService;
import io.dataease.auth.service.impl.AuthUserServiceImpl;
import io.dataease.auth.util.JWTUtils;
import io.dataease.base.mapper.ext.ExtTaskMapper;
import io.dataease.commons.utils.CommonBeanFactory;
import io.dataease.commons.utils.LogUtil;
import io.dataease.commons.utils.ServletUtils;
@ -20,6 +21,7 @@ import io.dataease.service.system.EmailService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@ -46,6 +48,16 @@ public class EmailTaskHandler extends TaskHandler implements Job {
return jobDataMap;
}
public EmailTaskHandler proxy() {
return CommonBeanFactory.getBean(EmailTaskHandler.class);
}
@Override
protected Boolean taskIsRunning(Long taskId) {
ExtTaskMapper extTaskMapper = CommonBeanFactory.getBean(ExtTaskMapper.class);
return extTaskMapper.runningCount(taskId) > 0;
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 插件没有加载 空转
@ -54,11 +66,16 @@ public class EmailTaskHandler extends TaskHandler implements Job {
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
GlobalTaskEntity taskEntity = (GlobalTaskEntity) jobDataMap.get("taskEntity");
ScheduleManager scheduleManager = SpringContextUtil.getBean(ScheduleManager.class);
if (taskExpire(taskEntity.getEndTime())) {
ScheduleManager scheduleManager = SpringContextUtil.getBean(ScheduleManager.class);
removeTask(scheduleManager, taskEntity);
return;
}
if (taskIsRunning(taskEntity.getTaskId())) {
LogUtil.info("Skip synchronization task: {} ,due to task status is {}",
taskEntity.getTaskId(), "running");
return;
}
GlobalTaskInstance taskInstance = buildInstance(taskEntity);
Long instanceId = saveInstance(taskInstance);
@ -67,10 +84,15 @@ public class EmailTaskHandler extends TaskHandler implements Job {
XpackEmailTemplateDTO emailTemplate = (XpackEmailTemplateDTO) jobDataMap.get("emailTemplate");
SysUserEntity creator = (SysUserEntity) jobDataMap.get("creator");
LogUtil.info("start execute send panel report task...");
sendReport(taskInstance, emailTemplate, creator);
proxy().sendReport(taskInstance, emailTemplate, creator);
}
@Override
public void resetRunningInstance(Long taskId) {
ExtTaskMapper extTaskMapper = CommonBeanFactory.getBean(ExtTaskMapper.class);
extTaskMapper.resetRunnings(taskId);
}
public Long saveInstance(GlobalTaskInstance taskInstance) {
EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class);
@ -99,11 +121,12 @@ public class EmailTaskHandler extends TaskHandler implements Job {
emailXpackService.saveInstance(taskInstance);
}
@Async("priorityExecutor")
public void sendReport(GlobalTaskInstance taskInstance, XpackEmailTemplateDTO emailTemplateDTO,
SysUserEntity user) {
SysUserEntity user) {
EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class);
try {
String panelId = emailTemplateDTO.getPanelId();
String url = panelUrl(panelId);
String token = tokenByUser(user);
@ -116,11 +139,15 @@ public class EmailTaskHandler extends TaskHandler implements Job {
String recipients = emailTemplateDTO.getRecipients();
byte[] content = emailTemplateDTO.getContent();
EmailService emailService = SpringContextUtil.getBean(EmailService.class);
String contentStr = "";
if (ObjectUtils.isNotEmpty(content)) {
contentStr = new String(content, "UTF-8");
}
emailService.sendWithImage(recipients, emailTemplateDTO.getTitle(), contentStr, bytes);
emailService.sendWithImage(recipients, emailTemplateDTO.getTitle(),
contentStr, bytes);
Thread.sleep(10000);
success(taskInstance);
} catch (Exception e) {
error(taskInstance, e);

View File

@ -32,6 +32,7 @@ public class GlobalTaskStartListener implements ApplicationListener<ApplicationR
tasks.stream().forEach(task -> {
TaskHandler taskHandler = TaskStrategyFactory.getInvokeStrategy(task.getTaskType());
try {
taskHandler.resetRunningInstance(task.getTaskId());
taskHandler.addTask(scheduleManager, task);
} catch (Exception e) {
e.printStackTrace();

View File

@ -4,12 +4,13 @@ import java.util.List;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import io.dataease.commons.exception.DEException;
import io.dataease.commons.utils.LogUtil;
import io.dataease.plugins.config.SpringContextUtil;
import io.dataease.plugins.xpack.theme.dto.ThemeDto;
import io.dataease.plugins.xpack.theme.dto.ThemeItem;
@ -20,10 +21,8 @@ import io.dataease.plugins.xpack.theme.service.ThemeXpackService;
@RestController
public class ThemeServer {
@PostMapping("/themes")
public List<ThemeDto> themes(){
public List<ThemeDto> themes() {
ThemeXpackService themeXpackService = SpringContextUtil.getBean(ThemeXpackService.class);
return themeXpackService.themes();
@ -36,15 +35,22 @@ public class ThemeServer {
}
@PostMapping("/save")
public void save(@RequestPart("request") ThemeRequest request, @RequestPart(value = "file", required = false) MultipartFile bodyFile) {
public void save(@RequestPart("request") ThemeRequest request,
@RequestPart(value = "file", required = false) MultipartFile bodyFile) {
ThemeXpackService themeXpackService = SpringContextUtil.getBean(ThemeXpackService.class);
themeXpackService.save(request, bodyFile);
try {
themeXpackService.save(request, bodyFile);
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
DEException.throwException(e);
}
}
@PostMapping("/delete/{themeId}")
public void save(@PathVariable("themeId") int themeId) {
public void delete(@PathVariable("themeId") int themeId) {
ThemeXpackService themeXpackService = SpringContextUtil.getBean(ThemeXpackService.class);
themeXpackService.deleteTheme(themeId);
}
}

View File

@ -3,6 +3,7 @@ package io.dataease.plugins.server;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.dataease.commons.exception.DEException;
import io.dataease.commons.pool.PriorityThreadPoolExecutor;
import io.dataease.commons.utils.*;
import io.dataease.plugins.common.entity.GlobalTaskEntity;
import io.dataease.plugins.common.entity.GlobalTaskInstance;
@ -23,6 +24,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.concurrent.Future;
import javax.annotation.Resource;
@Api(tags = "xpack定时报告")
@RequestMapping("/plugin/task")
@ -32,6 +36,9 @@ public class XEmailTaskServer {
@Autowired
private ScheduleService scheduleService;
@Resource
private PriorityThreadPoolExecutor priorityExecutor;
@PostMapping("/queryTasks/{goPage}/{pageSize}")
public Pager<List<XpackTaskGridDTO>> queryTask(@PathVariable int goPage, @PathVariable int pageSize,
@RequestBody XpackGridRequest request) {
@ -85,7 +92,19 @@ public class XEmailTaskServer {
String token = ServletUtils.getToken();
String fileId = null;
try {
fileId = emailXpackService.print(url, token, buildPixel(request.getPixel()));
Future<?> future = priorityExecutor.submit(() -> {
try {
return emailXpackService.print(url, token, buildPixel(request.getPixel()));
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
DEException.throwException("预览失败,请联系管理员");
}
return null;
}, 0);
Object object = future.get();
if (ObjectUtils.isNotEmpty(object)) {
fileId = object.toString();
}
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
DEException.throwException("预览失败,请联系管理员");

View File

@ -0,0 +1,45 @@
package io.dataease.service.wizard;
import io.dataease.commons.utils.HttpClientUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* Author: wangjiahao
* Date: 2022/1/11
* Description:
*/
@Service
public class ReptileService {
String blogUrl = "https://blog.fit2cloud.com/?cat=321";
public Map<String, String> lastActive() {
Map<String, String> result = new HashMap();
try {
//爬取最新数据
Document doc = Jsoup.parse(HttpClientUtil.get(blogUrl, null));
Elements elementsContent = doc.getElementsByAttributeValue("rel", "bookmark");
Elements elementsTime = doc.getElementsByTag("time");
Element lastInfo = elementsContent.get(0);
result.put("title",lastInfo.attr("title"));
result.put("href",lastInfo.attr("href"));
result.put("time",elementsTime.get(0).childNode(0).outerHtml());
} catch (Exception e) {
//ignore
result.put("title","支持移动端展示数据源新增对DB2的支持DataEase开源数据可视化分析平台v1.6.0发布");
result.put("href","https://blog.fit2cloud.com/?p=3200");
result.put("time","2022年1月10日");
}
return result;
}
}

View File

@ -6,4 +6,8 @@ CREATE TABLE `dataset_column_permissions` (
`permissions` longtext DEFAULT NULL COMMENT '权限',
`update_time` bigint(13) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (61, 0, 0, 1, '首页', 'wizard', 'wizard/index', 0, '', '/wizard', b'1', b'0', b'0', NULL, NULL, NULL, NULL, 1614915491036);
INSERT INTO `system_parameter` (`param_key`, `param_value`, `type`, `sort`) VALUES ('ui.openHomePage', 'true', 'boolean', 13);

View File

@ -223,6 +223,7 @@ authsource_configuration_is_null=Authentication source configuration cannot be e
角色表单=Role Form
重置密码=Reset Password
关于=About Us
首页=Home Page
i18n_auth_view=View
i18n_auth_use=Use
i18n_auth_export=Export

View File

@ -222,6 +222,7 @@ authsource_configuration_is_null=认证源配置不能为空
角色表单=角色表单
重置密码=重置密码
关于=关于
首页=首页
i18n_auth_view=查看
i18n_auth_use=使用
i18n_auth_export=导出

View File

@ -225,6 +225,7 @@ authsource_configuration_is_null=認證源配置不能為空
角色表单=角色表單
重置密码=重置密碼
关于=關於
首页=首頁
i18n_auth_view=查看
i18n_auth_use=使用
i18n_auth_export=導出

View File

@ -22,6 +22,13 @@ export function logout() {
})
}
export function needModifyPwd() {
return request({
url: '/api/auth/useInitPwd',
method: 'post'
})
}
export function validateUserName(data) {
return request({
url: '/api/auth/validateName',

View File

@ -0,0 +1,8 @@
import request from '@/utils/request'
export function blogLastActive() {
return request({
url: 'Reptile/lastActive',
method: 'get'
})
}

BIN
frontend/src/assets/deV.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

View File

@ -535,7 +535,7 @@ export default {
return this.$store.state.curComponent
},
curGap() {
return (this.canvasStyleData.panel.gap === 'yes' && this.element.auxiliaryMatrix && this.element.type !== 'custom') ? this.componentGap : 0
return (this.canvasStyleData.panel.gap === 'yes' && this.element.auxiliaryMatrix) ? this.componentGap : 0
},
...mapState([
'editor',

View File

@ -1,5 +1,6 @@
<template>
<div class="bar-main">
<input id="input" ref="files" type="file" accept="image/*" hidden @click="e => {e.target.value = '';}" @change="handleFileChange">
<div v-if="linkageAreaShow" style="margin-right: -1px;width: 18px">
<el-checkbox v-model="linkageInfo.linkageActive" />
<linkage-field v-if="linkageInfo.linkageActive" :element="element" />
@ -25,6 +26,9 @@
<span :title="$t('panel.cancel_linkage')">
<i v-if="curComponent.type==='view'&&existLinkage" class="icon iconfont icon-quxiaoliandong" @click.stop="clearLinkage" />
</span>
<span :title="$t('panel.switch_picture')">
<i v-if="activeModel==='edit'&&curComponent&&curComponent.type==='picture-add'" class="icon iconfont icon-genghuan" @click.stop="goFile" />
</span>
</div>
</div>
</template>
@ -34,6 +38,7 @@ import { mapState } from 'vuex'
import bus from '@/utils/bus'
import SettingMenu from '@/components/canvas/components/Editor/SettingMenu'
import LinkageField from '@/components/canvas/components/Editor/LinkageField'
import toast from '@/components/canvas/utils/toast'
export default {
components: { SettingMenu, LinkageField },
@ -207,6 +212,24 @@ export default {
},
linkJumpSet() {
this.$emit('linkJumpSet')
},
goFile() {
this.$refs.files.click()
},
handleFileChange(e) {
const file = e.target.files[0]
if (!file.type.includes('image')) {
toast('只能插入图片')
return
}
const reader = new FileReader()
reader.onload = (res) => {
const fileResult = res.target.result
this.curComponent.propValue = fileResult
this.$store.commit('recordSnapshot', 'handleFileChange')
}
reader.readAsDataURL(file)
}
}
}

View File

@ -3,6 +3,10 @@ import {
HYPERLINKS
} from '@/components/canvas/custom-component/component-list'
import {
ApplicationContext
} from '@/utils/ApplicationContext'
export function deepCopy(target) {
if (typeof target === 'object') {
const result = Array.isArray(target) ? [] : {}
@ -62,28 +66,17 @@ export function mobile2MainCanvas(mainSource, mobileSource) {
export function panelInit(componentDatas) {
componentDatas.forEach(item => {
if (item.component && item.component === 'de-date') {
if (item.serviceName === 'timeDateWidget' && item.options.attrs && !item.options.attrs.default) {
item.options.attrs.default = {
isDynamic: false,
dkey: 0,
dynamicPrefix: 1,
dynamicInfill: 'day',
dynamicSuffix: 'before'
}
}
if (item.serviceName === 'timeDateRangeWidget' && item.options.attrs && !item.options.attrs.default) {
item.options.attrs.default = {
isDynamic: false,
dkey: 0,
sDynamicPrefix: 1,
sDynamicInfill: 'day',
sDynamicSuffix: 'before',
eDynamicPrefix: 1,
eDynamicInfill: 'day',
eDynamicSuffix: 'after'
if (item.options.attrs &&
(!item.options.attrs.default || (item.serviceName === 'timeYearWidget' && item.options.attrs.default.dynamicInfill !== 'year') || (item.serviceName === 'timeMonthWidget' && item.options.attrs.default.dynamicInfill !== 'month'))) {
const widget = ApplicationContext.getService(item.serviceName)
if (widget && widget.defaultSetting) {
item.options.attrs.default = widget.defaultSetting()
}
}
}
if (item.type === 'custom') {
item.options.manualModify = false
}
if (item.filters && item.filters.length > 0) {
item.filters = []
}

View File

@ -161,7 +161,7 @@ export default {
<style lang="scss" scoped>
.my-container {
position: absolute;
position: relative;
overflow: auto;
top: 0px;
right: 0px;

View File

@ -64,6 +64,9 @@ export default {
viewIds() {
if (!this.element || !this.element.options || !this.element.options.attrs.viewIds) return ''
return this.element.options.attrs.viewIds.toString()
},
manualModify() {
return !!this.element.options.manualModify
}
},
watch: {
@ -72,9 +75,7 @@ export default {
this.setCondition()
},
'defaultValueStr': function(value, old) {
if ((this.element.serviceName === 'timeDateWidget' || this.element.serviceName === 'timeDateRangeWidget') &&
this.element.options.attrs.default.isDynamic) {
//
if (this.element.options.attrs.default.isDynamic) {
return
}
if (value === old) return
@ -82,13 +83,10 @@ export default {
this.dateChange(value)
},
'defaultoptions': function(val, old) {
// console.log('default chaneg')
if (this.element.serviceName !== 'timeDateWidget' || this.element.serviceName === 'timeDateRangeWidget') {
if (!this.element.options.attrs.default.isDynamic) {
this.values = this.fillValueDerfault()
this.dateChange(this.values)
return
}
if (!this.element.options.attrs.default.isDynamic) {
this.values = this.fillValueDerfault()
this.dateChange(this.values)
return
}
if (val === old) return
const widget = ApplicationContext.getService(this.element.serviceName)
@ -97,9 +95,7 @@ export default {
}
},
created() {
if ((this.element.serviceName === 'timeDateWidget' || this.element.serviceName === 'timeDateRangeWidget') && this
.element.options.attrs.default && this.element.options
.attrs.default.isDynamic) {
if (this.element.options.attrs.default && this.element.options.attrs.default.isDynamic) {
if (this.element.options.attrs.default) {
const widget = ApplicationContext.getService(this.element.serviceName)
this.values = widget.dynamicDateFormNow(this.element)
@ -118,6 +114,18 @@ export default {
this.$refs.dateRef.hidePicker()
}
})
bus.$on('reset-default-value', id => {
if (this.inDraw && this.manualModify && this.element.id === id) {
if (!this.element.options.attrs.default.isDynamic) {
this.values = this.fillValueDerfault()
this.dateChange(this.values)
return
}
const widget = ApplicationContext.getService(this.element.serviceName)
this.values = widget.dynamicDateFormNow(this.element)
this.dateChange(this.values)
}
})
},
methods: {
onBlur() {
@ -145,6 +153,9 @@ export default {
} else {
this.element.options.value = Array.isArray(value) ? value.join() : value.toString()
}
this.element.options.manualModify = false
} else {
this.element.options.manualModify = true
}
this.setCondition()
this.styleChange()

View File

@ -17,6 +17,7 @@
</template>
<script>
import bus from '@/utils/bus'
export default {
props: {
@ -45,6 +46,9 @@ export default {
viewIds() {
if (!this.element || !this.element.options || !this.element.options.attrs.viewIds) return ''
return this.element.options.attrs.viewIds.toString()
},
manualModify() {
return !!this.element.options.manualModify
}
},
watch: {
@ -64,6 +68,14 @@ export default {
this.search()
}
},
mounted() {
bus.$on('reset-default-value', id => {
if (this.inDraw && this.manualModify && this.element.id === id) {
this.value = this.fillValueDerfault()
this.search()
}
})
},
methods: {
search() {
if (!this.inDraw) {
@ -85,6 +97,9 @@ export default {
valueChange(val) {
if (!this.inDraw) {
this.element.options.value = val
this.element.options.manualModify = false
} else {
this.element.options.manualModify = true
}
},
fillValueDerfault() {

View File

@ -17,6 +17,7 @@
<script>
const MIN_NUMBER = -2147483648
const MAX_NUMBER = 2147483647
import bus from '@/utils/bus'
export default {
props: {
@ -64,6 +65,9 @@ export default {
viewIds() {
if (!this.element || !this.element.options || !this.element.options.attrs.viewIds) return ''
return this.element.options.attrs.viewIds.toString()
},
manualModify() {
return !!this.element.options.manualModify
}
},
watch: {
@ -99,6 +103,18 @@ export default {
this.search()
}
},
mounted() {
bus.$on('reset-default-value', id => {
if (this.inDraw && this.manualModify && this.element.id === id) {
const values = this.element.options.value
this.form.min = values[0]
if (values.length > 1) {
this.form.max = values[1]
}
this.search()
}
})
},
methods: {
searchWithKey(index) {
this.timeMachine = setTimeout(() => {
@ -211,6 +227,9 @@ export default {
if (!this.inDraw) {
const values = [this.form.min, this.form.max]
this.element.options.value = values
this.element.options.manualModify = false
} else {
this.element.options.manualModify = true
}
}
}

View File

@ -28,9 +28,9 @@
</template>
<script>
import { multFieldValues, linkMultFieldValues} from '@/api/dataset/dataset'
import { multFieldValues, linkMultFieldValues } from '@/api/dataset/dataset'
import bus from '@/utils/bus'
import {getLinkToken, getToken} from "@/utils/auth";
import { getLinkToken, getToken } from '@/utils/auth'
export default {
props: {
@ -70,6 +70,9 @@ export default {
viewIds() {
if (!this.element || !this.element.options || !this.element.options.attrs.viewIds) return ''
return this.element.options.attrs.viewIds.toString()
},
manualModify() {
return !!this.element.options.manualModify
}
},
@ -87,7 +90,7 @@ export default {
if (typeof value === 'undefined' || value === old) return
this.datas = []
let method = multFieldValues
let method = multFieldValues
const token = this.$store.getters.token || getToken()
const linkToken = this.$store.getters.linkToken || getLinkToken()
if (!token && linkToken) {
@ -95,7 +98,7 @@ export default {
}
this.element.options.attrs.fieldId &&
this.element.options.attrs.fieldId.length > 0 &&
method({fieldIds: this.element.options.attrs.fieldId.split(',')}).then(res => {
method({ fieldIds: this.element.options.attrs.fieldId.split(',') }).then(res => {
this.datas = this.optionDatas(res.data)
}) || (this.element.options.value = '')
},
@ -122,6 +125,12 @@ export default {
this.$refs.deSelect.blur()
}
})
bus.$on('reset-default-value', id => {
if (this.inDraw && this.manualModify && this.element.id === id) {
this.value = this.fillValueDerfault()
this.changeValue(this.value)
}
})
},
methods: {
@ -132,13 +141,13 @@ export default {
this.value = this.fillValueDerfault()
this.datas = []
if (this.element.options.attrs.fieldId) {
let method = multFieldValues
let method = multFieldValues
const token = this.$store.getters.token || getToken()
const linkToken = this.$store.getters.linkToken || getLinkToken()
if (!token && linkToken) {
method = linkMultFieldValues
}
method({fieldIds: this.element.options.attrs.fieldId.split(',')}).then(res => {
method({ fieldIds: this.element.options.attrs.fieldId.split(',') }).then(res => {
this.datas = this.optionDatas(res.data)
})
}
@ -154,6 +163,9 @@ export default {
} else {
this.element.options.value = Array.isArray(value) ? value.join() : value
}
this.element.options.manualModify = false
} else {
this.element.options.manualModify = true
}
this.setCondition()
this.styleChange()

View File

@ -38,6 +38,7 @@
<script>
import { multFieldValues, linkMultFieldValues } from '@/api/dataset/dataset'
import { getLinkToken, getToken } from '@/utils/auth'
import bus from '@/utils/bus'
export default {
props: {
@ -89,6 +90,9 @@ export default {
viewIds() {
if (!this.element || !this.element.options || !this.element.options.attrs.viewIds) return ''
return this.element.options.attrs.viewIds.toString()
},
manualModify() {
return !!this.element.options.manualModify
}
},
watch: {
@ -137,6 +141,19 @@ export default {
created() {
this.initLoad()
},
mounted() {
bus.$on('reset-default-value', id => {
if (this.inDraw && this.manualModify && this.element.id === id) {
this.value = this.fillValueDerfault()
this.changeValue(this.value)
if (this.element.options.attrs.multiple) {
this.checkAll = this.value.length === this.datas.length
this.isIndeterminate = this.value.length > 0 && this.value.length < this.datas.length
}
}
})
},
methods: {
initLoad() {
@ -168,6 +185,9 @@ export default {
} else {
this.element.options.value = Array.isArray(value) ? value.join() : value
}
this.element.options.manualModify = false
} else {
this.element.options.manualModify = true
}
this.setCondition()
this.styleChange()

View File

@ -15,7 +15,8 @@ const dialogPanel = {
fieldId: '',
dragItems: []
},
value: ''
value: '',
manualModify: false
},
defaultClass: 'tree-filter',
component: 'de-number-range'

View File

@ -20,7 +20,8 @@ const dialogPanel = {
fieldId: '',
dragItems: []
},
value: ''
value: '',
manualModify: false
},
defaultClass: 'tree-filter',
component: 'de-select-grid'

View File

@ -20,7 +20,8 @@ const dialogPanel = {
fieldId: '',
dragItems: []
},
value: ''
value: '',
manualModify: false
},
defaultClass: 'tree-filter',
component: 'de-select'

View File

@ -15,7 +15,8 @@ const dialogPanel = {
dragItems: []
},
value: ''
value: '',
manualModify: false
},
defaultClass: 'text-filter',
component: 'de-input-search'

View File

@ -20,7 +20,8 @@ const dialogPanel = {
fieldId: '',
dragItems: []
},
value: ''
value: '',
manualModify: false
},
defaultClass: 'text-filter',
component: 'de-select-grid'

View File

@ -20,7 +20,8 @@ const dialogPanel = {
fieldId: '',
dragItems: []
},
value: ''
value: '',
manualModify: false
},
defaultClass: 'text-filter',
component: 'de-select'

View File

@ -29,7 +29,8 @@ const dialogPanel = {
eDynamicSuffix: 'after'
}
},
value: ''
value: '',
manualModify: false
},
defaultClass: 'time-filter',
component: 'de-date'
@ -80,6 +81,9 @@ class TimeDateRangeServiceImpl extends WidgetService {
return field['deType'] === 1
})
}
defaultSetting() {
return dialogPanel.options.attrs.default
}
getStartDayOfWeek() {
var now = new Date() // 当前日期
var nowDayOfWeek = now.getDay()

View File

@ -21,10 +21,27 @@ const dialogPanel = {
dkey: 0,
dynamicPrefix: 1,
dynamicInfill: 'day',
dynamicSuffix: 'before'
dynamicSuffix: 'before',
radioOptions: [{ value: false, text: 'dynamic_time.fix' }, { value: true, text: 'dynamic_time.dynamic' }],
relativeOptions: [
{ value: 0, text: 'dynamic_time.today' },
{ value: 1, text: 'dynamic_time.yesterday' },
{ value: 2, text: 'dynamic_time.firstOfMonth' },
{ value: 3, text: 'dynamic_time.custom' }
],
custom: {
unitsOptions: [
{ value: 'day', text: 'dynamic_time.date' },
{ value: 'week', text: 'dynamic_time.week' },
{ value: 'month', text: 'dynamic_time.month' },
{ value: 'year', text: 'dynamic_time.year' }
],
limits: [1, 12]
}
}
},
value: ''
value: '',
manualModify: false
},
defaultClass: 'time-filter',
component: 'de-date'
@ -75,6 +92,9 @@ class TimeDateServiceImpl extends WidgetService {
return field['deType'] === 1
})
}
defaultSetting() {
return dialogPanel.options.attrs.default
}
dynamicDateFormNow(element) {
if (element.options.attrs.default === null || typeof element.options.attrs.default === 'undefined' || !element.options.attrs.default.isDynamic) return null

View File

@ -13,9 +13,30 @@ const dialogPanel = {
placeholder: 'deyearmonth.placeholder',
viewIds: [],
fieldId: '',
dragItems: []
dragItems: [],
default: {
isDynamic: false,
dkey: 0,
dynamicPrefix: 1,
dynamicInfill: 'month',
dynamicSuffix: 'before',
radioOptions: [{ value: false, text: 'dynamic_month.fix' }, { value: true, text: 'dynamic_month.dynamic' }],
relativeOptions: [
{ value: 0, text: 'dynamic_month.current' },
{ value: 1, text: 'dynamic_month.last' },
{ value: 2, text: 'dynamic_month.firstOfYear' },
{ value: 3, text: 'dynamic_time.custom' }
],
custom: {
unitsOptions: [
{ value: 'month', text: 'dynamic_time.month' }
],
limits: [0, 10]
}
}
},
value: ''
value: '',
manualModify: false
},
defaultClass: 'time-filter',
component: 'de-date'
@ -64,6 +85,38 @@ class TimeMonthServiceImpl extends WidgetService {
return field['deType'] === 1
})
}
defaultSetting() {
return dialogPanel.options.attrs.default
}
dynamicDateFormNow(element) {
const now = new Date()
const nowMonth = now.getMonth()
const nowYear = now.getFullYear()
if (element.options.attrs.default === null || typeof element.options.attrs.default === 'undefined' || !element.options.attrs.default.isDynamic) return null
if (element.options.attrs.default.dkey === 0) {
return new Date(nowYear, nowMonth, 1).getTime()
}
if (element.options.attrs.default.dkey === 1) {
return new Date(nowYear, nowMonth - 1, 1).getTime()
}
if (element.options.attrs.default.dkey === 2) {
return new Date(nowYear, 0, 1).getTime()
}
if (element.options.attrs.default.dkey === 3) {
const dynamicPrefix = parseInt(element.options.attrs.default.dynamicPrefix)
const dynamicSuffix = element.options.attrs.default.dynamicSuffix
if (dynamicSuffix === 'before') {
return new Date(nowYear, nowMonth - dynamicPrefix, 1).getTime()
} else {
return new Date(nowYear, nowMonth + dynamicPrefix, 1).getTime()
}
}
}
}
const timeMonthServiceImpl = new TimeMonthServiceImpl()
export default timeMonthServiceImpl

View File

@ -13,9 +13,29 @@ const dialogPanel = {
placeholder: 'deyear.placeholder',
viewIds: [],
fieldId: '',
dragItems: []
dragItems: [],
default: {
isDynamic: false,
dkey: 0,
dynamicPrefix: 1,
dynamicInfill: 'year',
dynamicSuffix: 'before',
radioOptions: [{ value: false, text: 'dynamic_year.fix' }, { value: true, text: 'dynamic_year.dynamic' }],
relativeOptions: [
{ value: 0, text: 'dynamic_year.current' },
{ value: 1, text: 'dynamic_year.last' },
{ value: 2, text: 'dynamic_time.custom' }
],
custom: {
unitsOptions: [
{ value: 'year', text: 'dynamic_time.year' }
],
limits: [0, 10]
}
}
},
value: ''
value: '',
manualModify: false
},
defaultClass: 'time-filter',
component: 'de-date'
@ -65,6 +85,29 @@ class TimeYearServiceImpl extends WidgetService {
return field['deType'] === 1
})
}
defaultSetting() {
return dialogPanel.options.attrs.default
}
dynamicDateFormNow(element) {
if (element.options.attrs.default === null || typeof element.options.attrs.default === 'undefined' || !element.options.attrs.default.isDynamic) return null
const now = new Date()
const nowYear = now.getFullYear()
if (element.options.attrs.default.dkey === 0) {
return new Date(nowYear, 0, 1).getTime()
}
if (element.options.attrs.default.dkey === 1) {
return new Date(nowYear - 1, 0, 1).getTime()
}
if (element.options.attrs.default.dkey === 2) {
const dynamicPrefix = parseInt(element.options.attrs.default.dynamicPrefix)
const dynamicSuffix = element.options.attrs.default.dynamicSuffix
return new Date(dynamicSuffix === 'before' ? (nowYear - dynamicPrefix) : (nowYear + dynamicPrefix), 0, 1).getTime()
}
}
}
const timeYearServiceImpl = new TimeYearServiceImpl()
export default timeYearServiceImpl

View File

@ -131,6 +131,9 @@ export default {
default_login: 'Normal'
},
commons: {
first_login_tips: 'Please change the initial password',
roger_that: 'Roger That',
apply: 'Apply',
search: 'Search',
folder: 'Folder',
no_target_permission: 'No permission',
@ -437,7 +440,10 @@ export default {
background: 'Background color',
custom: 'Custom color',
otherSave: 'Theme Save as',
info: 'Theme info'
info: 'Theme info',
add: 'Add Theme',
please_input_name: 'Please enter a name',
name_repeat: 'Name already exists'
},
tagsView: {
refresh: 'Refresh',
@ -455,7 +461,8 @@ export default {
sysParams: {
display: 'Display Setting',
ldap: 'LDAP Setting',
oidc: 'OIDC Setting'
oidc: 'OIDC Setting',
theme: 'Theme Setting'
},
license: {
i18n_no_license_record: 'No License Record',
@ -1443,6 +1450,7 @@ export default {
linkage: 'linkage',
jump: 'Jump',
cancel_linkage: 'Cancel Linkage',
switch_picture: 'Switch Picture',
remove_all_linkage: 'Remove All Linkage',
exit_un_march_linkage_field: 'Exit Un March Linkage Field',
details: 'Details',
@ -1519,7 +1527,9 @@ export default {
themeLight: 'Light',
themeDark: 'Dark',
themeCustom: 'Custom'
themeCustom: 'Custom',
openHomePage: 'Show Home Page'
},
auth: {
authConfig: 'Auth Config',
@ -1771,6 +1781,40 @@ export default {
cweek: 'This Week',
cmonth: 'This Month',
cquarter: 'This Quarter',
cyear: 'This Year'
cyear: 'This Year',
openHomePage: 'Show Home Page'
},
dynamic_year: {
fix: 'Fixed Year',
dynamic: 'Dynamic Year',
current: 'This Year',
last: 'Last Year'
},
dynamic_month: {
fix: 'Fixed Month',
dynamic: 'Dynamic Month',
current: 'This Month',
last: 'Last Month',
firstOfYear: 'First month of this year'
},
wizard: {
welcome_title: 'Welcome To Use DataEase',
welcome_hint: 'Open source data visual analysis tool available to everyone',
demo_video: 'Demo',
online_document: 'Online',
latest_developments: 'Latest',
teaching_video: 'Teaching',
enterprise_edition: 'Enterprise',
contact_us: 'Contact Us',
demo_video_hint: 'How to make a DataEase dashboard in 3 minutes and share it with others',
online_document_hint: 'It covers the installation steps, user manuals, tutorials, solutions to common problems, and secondary development of DataEase',
teaching_video_bottom_hint: 'More videos',
enterprise_edition_hint1: 'Provide enterprise application scenario x-pack enhancement package',
enterprise_edition_hint2: 'Provide high-level original factory service support',
enterprise_edition_hint3: 'Provide dataease O & M security best practices',
open_source_community: 'Open source community',
click_show: 'Click To View',
show_more: 'Show More',
click_inner: 'Click To Enter'
}
}

View File

@ -131,6 +131,9 @@ export default {
default_login: '普通登錄'
},
commons: {
first_login_tips: '您使用的是初始密碼,記得修改密碼哦',
roger_that: '知道了',
apply: '應用',
search: '搜索',
folder: '目錄',
no_target_permission: '沒有權限',
@ -437,7 +440,10 @@ export default {
background: '背景顏色',
custom: '自定義顏色',
otherSave: '主題另存為',
info: '主題信息'
info: '主題信息',
add: '新增主題',
please_input_name: '請輸入名稱',
name_repeat: '名稱已存在'
},
tagsView: {
refresh: '刷新',
@ -455,7 +461,8 @@ export default {
sysParams: {
display: '顯示設置',
ldap: 'LDAP設置',
oidc: 'OIDC設置'
oidc: 'OIDC設置',
theme: '主题设置'
},
license: {
i18n_no_license_record: '沒有 License 記錄',
@ -1445,6 +1452,7 @@ export default {
linkage: '聯動',
jump: '跳轉',
cancel_linkage: '取消聯動',
switch_picture: '更换图片',
remove_all_linkage: '清除所有聯動',
exit_un_march_linkage_field: '存在未匹配聯動關繫的字段',
details: '詳情',
@ -1529,7 +1537,8 @@ export default {
themeLight: '淺色',
themeDark: '深色',
themeCustom: '自定義'
themeCustom: '自定義',
openHomePage: '显示首页'
},
auth: {
@ -1784,5 +1793,38 @@ export default {
cmonth: '本月',
cquarter: '本季',
cyear: '本年'
},
dynamic_year: {
fix: '固定年份',
dynamic: '動態年份',
current: '當年',
last: '去年'
},
dynamic_month: {
fix: '固定年月',
dynamic: '動態年月',
current: '本月',
last: '上月',
firstOfYear: '當年首月'
},
wizard: {
welcome_title: '歡迎使用DataEase',
welcome_hint: '人人可用的開源數據可視化分析工具',
demo_video: '演示視頻',
online_document: '在線文檔',
latest_developments: '最新動態',
teaching_video: '教學視頻',
enterprise_edition: '企業版',
contact_us: '聯系我們',
demo_video_hint: '如何3分鐘製作一個DataEase 數據看板、並分享給他人',
online_document_hint: '涵蓋DataEase的安裝步驟、用戶手冊、使用教程、常見問題的解決方案、以及二次開發等',
teaching_video_bottom_hint: '更多視頻資料',
enterprise_edition_hint1: '提供企業級應用場景X-Pack增強包',
enterprise_edition_hint2: '提供高等級原廠服務支持',
enterprise_edition_hint3: '提供DataEase 運維安全最佳實踐',
open_source_community: '開源社區',
click_show: '點擊查看',
show_more: '查看更多',
click_inner: '點擊進入'
}
}

View File

@ -131,6 +131,9 @@ export default {
default_login: '普通登录'
},
commons: {
first_login_tips: '您使用的是初始密码,记得修改密码哦',
roger_that: '知道了',
apply: '应用',
search: '搜索',
folder: '目录',
no_target_permission: '没有权限',
@ -438,7 +441,10 @@ export default {
background: '背景颜色',
custom: '自定义颜色',
otherSave: '主题另存为',
info: '主题信息'
info: '主题信息',
add: '新增主题',
please_input_name: '请输入名称',
name_repeat: '名称已存在'
},
tagsView: {
refresh: '刷新',
@ -1456,6 +1462,7 @@ export default {
linkage: '联动',
jump: '跳转',
cancel_linkage: '取消联动',
switch_picture: '更换图片',
remove_all_linkage: '清除所有联动',
exit_un_march_linkage_field: '存在未匹配联动关系的字段',
details: '详情',
@ -1539,7 +1546,8 @@ export default {
themeLight: '浅色',
themeDark: '深色',
themeCustom: '自定义'
themeCustom: '自定义',
openHomePage: '显示首页'
},
auth: {
@ -1795,5 +1803,38 @@ export default {
cmonth: '本月',
cquarter: '本季',
cyear: '本年'
},
dynamic_year: {
fix: '固定年份',
dynamic: '动态年份',
current: '当年',
last: '去年'
},
dynamic_month: {
fix: '固定年月',
dynamic: '动态年月',
current: '当月',
last: '上月',
firstOfYear: '当年首月'
},
wizard: {
welcome_title: '欢迎使用DataEase',
welcome_hint: '人人可用的开源数据可视化分析工具',
demo_video: '演示视频',
online_document: '在线文档',
latest_developments: '最新动态',
teaching_video: '教学视频',
enterprise_edition: '企业版',
contact_us: '联系我们',
demo_video_hint: '如何3分钟制作一个DataEase 数据看板、并分享给他人',
online_document_hint: '涵盖DataEase的安装步骤、用户手册、使用教程、常见问题的解决方案、以及二次开发等',
teaching_video_bottom_hint: '更多视频资料',
enterprise_edition_hint1: '提供企业级应用场景X-Pack增强包',
enterprise_edition_hint2: '提供高等级原厂服务支持',
enterprise_edition_hint3: '提供DataEase 运维安全最佳实践',
open_source_community: '开源社区',
click_show: '点击查看',
show_more: '查看更多',
click_inner: '点击进入'
}
}

View File

@ -14,10 +14,8 @@
>
<div v-for="item in permission_routes" :key="item.path" class="nav-item">
<app-link :to="resolvePath(item)">
<el-menu-item
v-if="!item.hidden"
:index="item.path"
>{{ item.meta ? item.meta.title : item.children[0].meta.title }}</el-menu-item>
<el-menu-item v-if="!item.hidden" :index="item.path">
{{ item.meta ? item.meta.title : item.children[0].meta.title }}</el-menu-item>
</app-link>
</div>
</el-menu>
@ -28,13 +26,22 @@
<notification class="right-menu-item hover-effect" />
<lang-select class="right-menu-item hover-effect" />
<div style="height: 100%;padding: 0 8px;" class="right-menu-item hover-effect">
<a href="https://dataease.io/docs/" target="_blank" style="display: flex;height: 100%;width: 100%;justify-content: center;align-items: center;">
<a
href="https://dataease.io/docs/"
target="_blank"
style="display: flex;height: 100%;width: 100%;justify-content: center;align-items: center;"
>
<svg-icon icon-class="docs" />
</a>
</div>
</template>
<el-dropdown class="top-dropdown" style="display: flex;align-items: center; width:100px;" trigger="click">
<el-dropdown
ref="my-drop"
class="top-dropdown"
style="display: flex;align-items: center; width:100px;"
trigger="click"
>
<div class="el-dropdown-link" style="display: flex;color: var(--TopTextColor);font-size: 14px; width:100%;">
<span style="max-width:80px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;">{{ name }}</span>
@ -62,21 +69,32 @@
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import {
mapGetters
} from 'vuex'
import AppLink from './Sidebar/Link'
import variables from '@/styles/variables.scss'
import { isExternal } from '@/utils/validate'
import {
isExternal
} from '@/utils/validate'
import Notification from '@/components/Notification'
import bus from '@/utils/bus'
import LangSelect from '@/components/LangSelect'
import { getSysUI } from '@/utils/auth'
import { pluginLoaded } from '@/api/user'
import { initTheme } from '@/utils/ThemeUtil'
import {
getSysUI
} from '@/utils/auth'
import {
pluginLoaded
} from '@/api/user'
import {
initTheme
} from '@/utils/ThemeUtil'
export default {
name: 'Topbar',
components: {
@ -85,6 +103,12 @@ export default {
LangSelect
},
props: {
showTips: {
type: Boolean,
default: false
}
},
data() {
return {
uiInfo: null,
@ -100,27 +124,42 @@ export default {
},
topMenuColor() {
if (this.$store.getters.uiInfo && this.$store.getters.uiInfo['ui.topMenuColor'] && this.$store.getters.uiInfo['ui.topMenuColor'].paramValue) { return this.$store.getters.uiInfo['ui.topMenuColor'].paramValue }
if (this.$store.getters.uiInfo && this.$store.getters.uiInfo['ui.topMenuColor'] && this.$store.getters.uiInfo[
'ui.topMenuColor'].paramValue) {
return this.$store.getters.uiInfo['ui.topMenuColor'].paramValue
}
return this.variables.topBarBg
},
topMenuActiveColor() {
if (this.$store.getters.uiInfo && this.$store.getters.uiInfo['ui.topMenuActiveColor'] && this.$store.getters.uiInfo['ui.topMenuActiveColor'].paramValue) { return this.$store.getters.uiInfo['ui.topMenuActiveColor'].paramValue }
if (this.$store.getters.uiInfo && this.$store.getters.uiInfo['ui.topMenuActiveColor'] && this.$store.getters
.uiInfo['ui.topMenuActiveColor'].paramValue) {
return this.$store.getters.uiInfo['ui.topMenuActiveColor'].paramValue
}
return this.variables.topBarMenuActive
},
topMenuTextColor() {
if (this.$store.getters.uiInfo && this.$store.getters.uiInfo['ui.topMenuTextColor'] && this.$store.getters.uiInfo['ui.topMenuTextColor'].paramValue) { return this.$store.getters.uiInfo['ui.topMenuTextColor'].paramValue }
if (this.$store.getters.uiInfo && this.$store.getters.uiInfo['ui.topMenuTextColor'] && this.$store.getters
.uiInfo['ui.topMenuTextColor'].paramValue) {
return this.$store.getters.uiInfo['ui.topMenuTextColor'].paramValue
}
return this.variables.topBarMenuText
},
topMenuTextActiveColor() {
if (this.$store.getters.uiInfo && this.$store.getters.uiInfo['ui.topMenuTextActiveColor'] && this.$store.getters.uiInfo['ui.topMenuTextActiveColor'].paramValue) { return this.$store.getters.uiInfo['ui.topMenuTextActiveColor'].paramValue }
if (this.$store.getters.uiInfo && this.$store.getters.uiInfo['ui.topMenuTextActiveColor'] && this.$store.getters
.uiInfo['ui.topMenuTextActiveColor'].paramValue) {
return this.$store.getters.uiInfo['ui.topMenuTextActiveColor'].paramValue
}
return this.variables.topBarMenuTextActive
},
/* topMenuColor() {
return this.$store.getters.uiInfo.topMenuColor
}, */
return this.$store.getters.uiInfo.topMenuColor
}, */
activeMenu() {
const route = this.$route
const { meta, path } = route
const {
meta,
path
} = route
// if set path, the sidebar will highlight the path you set
if (meta.activeMenu) {
// return meta.activeMenu
@ -152,6 +191,10 @@ export default {
bus.$on('set-top-menu-active-info', this.setTopMenuActiveInfo)
bus.$on('set-top-text-info', this.setTopTextInfo)
bus.$on('set-top-text-active-info', this.setTopTextActiveInfo)
this.showTips && this.$nextTick(() => {
const drop = this.$refs['my-drop']
drop && drop.show && drop.show()
})
},
created() {
this.loadUiInfo()
@ -159,13 +202,17 @@ export default {
beforeCreate() {
pluginLoaded().then(res => {
this.isPluginLoaded = res.success && res.data
if (this.isPluginLoaded) { initTheme() }
if (this.isPluginLoaded) {
initTheme()
}
})
},
methods: {
// store
initCurrentRoutes() {
const { path } = this.$route
const {
path
} = this.$route
let route = this.permission_routes.find(
item => item.path === '/' + path.split('/')[1]
)
@ -197,9 +244,9 @@ export default {
//
let path = ''
/**
* item 路由子项
* parent 路由父项
*/
* item 路由子项
* parent 路由父项
*/
const getDefaultPath = (item, parent) => {
// path
if (isExternal(item.path)) {
@ -233,7 +280,7 @@ export default {
},
//
setSidebarHide(route) {
// if (!route.children || route.children.length === 1) {
// if (!route.children || route.children.length === 1) {
if (route.name !== 'system' && (!route.children || this.showChildLength(route) === 1)) {
this.$store.dispatch('app/toggleSideBarHide', true)
} else {
@ -266,12 +313,12 @@ export default {
}
/* if (this.uiInfo['ui.themeStr'] && this.uiInfo['ui.themeStr'].paramValue) {
if (this.uiInfo['ui.themeStr'].paramValue === 'dark') {
document.body.className = 'blackTheme'
} else if (this.uiInfo['ui.themeStr'].paramValue === 'light') {
document.body.className = ''
}
} */
if (this.uiInfo['ui.themeStr'].paramValue === 'dark') {
document.body.className = 'blackTheme'
} else if (this.uiInfo['ui.themeStr'].paramValue === 'light') {
document.body.className = ''
}
} */
this.axiosFinished = true
})
},
@ -291,12 +338,14 @@ export default {
}
}
</script>
<style lang="scss" scoped>
.el-dropdown-link {
cursor: pointer;
color: #1e212a;
}
.el-icon-arrow-down {
font-size: 12px;
}
@ -312,7 +361,8 @@ export default {
}
.de-top-menu {
background-color: var(--MainBG);
background-color: var(--MainBG);
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<div :class="classObj" class="app-wrapper">
<licbar />
<topbar v-if="!fullHeightFlag" />
<topbar v-if="!fullHeightFlag && finishLoad" :show-tips="showTips" />
<de-container :style="mainStyle">
<de-aside-container v-if="!sidebar.hide" class="le-aside-container">
@ -12,6 +12,14 @@
<app-main />
</de-main-container>
</de-container>
<div v-if="showTips" class="pwd-tips">
<span>{{ $t('commons.first_login_tips') }}</span>
<div style="text-align: right; margin-bottom: 10px;">
<el-button type="primary" size="mini" @click="showTips = false">{{ $t('commons.roger_that') }}</el-button>
</div>
<div class="arrow" />
</div>
</div>
</template>
@ -23,6 +31,8 @@ import DeContainer from '@/components/dataease/DeContainer'
import DeAsideContainer from '@/components/dataease/DeAsideContainer'
import bus from '@/utils/bus'
import { needModifyPwd } from '@/api/user'
export default {
name: 'Layout',
components: {
@ -37,7 +47,9 @@ export default {
mixins: [ResizeMixin],
data() {
return {
componentName: 'PanelMain'
componentName: 'PanelMain',
showTips: false,
finishLoad: false
}
},
computed: {
@ -76,6 +88,14 @@ export default {
}
}
},
beforeCreate() {
needModifyPwd().then(res => {
this.showTips = res.success && res.data
this.finishLoad = true
}).catch(e => {
this.finishLoad = true
})
},
mounted() {
bus.$on('PanelSwitchComponent', (c) => {
this.componentName = c.name
@ -94,6 +114,8 @@ export default {
@import "~@/styles/variables.scss";
.app-wrapper {
min-width: 1000px!important;
min-height: 600px!important;
@include clearfix;
position: relative;
height: 100%;
@ -153,4 +175,29 @@ export default {
}
}
.pwd-tips {
position: absolute;
box-shadow: 0 0 0 1000em rgb(0, 0, 0, 0.3);
height: 100px;
width: 225px;
top: 105px;
right: 115px;
z-index: 9999;
border-radius: 4px;
padding: 15px;
background: #fff;
}
.arrow{
border-bottom: 7px solid #fff;
border-right: 7px solid #b5b5b7;
border-left: 7px solid #b5b5b7;
border-top: 7px solid #b5b5b7;
width: 0px;
height: 0px;
position: relative;
top:-60px;
left:210px;
transform: rotate(90deg);
}
</style>

View File

@ -16,6 +16,7 @@ import {
import {
isMobile
} from '@/utils/index'
import Layout from '@/layout/index'
// import bus from './utils/bus'
NProgress.configure({
@ -97,6 +98,23 @@ export const loadMenus = (next, to) => {
const datas = res.data
const filterDatas = filterRouter(datas)
const asyncRouter = filterAsyncRouter(filterDatas)
// 如果包含首页 则默认页面是 首页 否则默认页面是仪表板页面
if (JSON.stringify(datas).indexOf('wizard') > -1) {
asyncRouter.push({
path: '/',
component: Layout,
redirect: '/wizard/index',
hidden: true
})
} else {
asyncRouter.push({
path: '/',
component: Layout,
redirect: '/panel/index',
hidden: true
})
}
asyncRouter.push({
path: '*',
redirect: '/404',

View File

@ -91,12 +91,6 @@ export const constantRoutes = [
path: '/previewFullScreen',
component: () => import('@/components/canvas/components/Editor/PreviewFullScreen'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/panel/index',
hidden: true
}
// {

View File

@ -16,6 +16,7 @@ const getters = {
errorLogs: state => state.errorLog.logs,
sceneData: state => state.dataset.sceneData,
table: state => state.dataset.table,
chartTable: state => state.chart.table,
hideCustomDs: state => state.dataset.hideCustomDs,
loadingMap: state => state.request.loadingMap,
currentPath: state => state.permission.currentPath,

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 2459092 */
src: url('iconfont.woff2?t=1639622225820') format('woff2'),
url('iconfont.woff?t=1639622225820') format('woff'),
url('iconfont.ttf?t=1639622225820') format('truetype');
src: url('iconfont.woff2?t=1642061879222') format('woff2'),
url('iconfont.woff?t=1642061879222') format('woff'),
url('iconfont.ttf?t=1642061879222') format('truetype');
}
.iconfont {
@ -13,6 +13,22 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-genghuan:before {
content: "\e606";
}
.icon-fasongyoujian:before {
content: "\e605";
}
.icon-github:before {
content: "\e6f8";
}
.icon-dianhua:before {
content: "\e681";
}
.icon-guanbi:before {
content: "\e60d";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,34 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "12851123",
"name": "更换",
"font_class": "genghuan",
"unicode": "e606",
"unicode_decimal": 58886
},
{
"icon_id": "1286",
"name": "发送邮件",
"font_class": "fasongyoujian",
"unicode": "e605",
"unicode_decimal": 58885
},
{
"icon_id": "7239484",
"name": "github",
"font_class": "github",
"unicode": "e6f8",
"unicode_decimal": 59128
},
{
"icon_id": "11810462",
"name": "电话",
"font_class": "dianhua",
"unicode": "e681",
"unicode_decimal": 59009
},
{
"icon_id": "1367318",
"name": "关闭",

View File

@ -534,14 +534,7 @@ div:focus {
color: var(--Main) !important;
}
/* .blackTheme .el-dialog {
background: var(--ContentBG) !important;
color: var(--TextPrimary) !important;
}
*/
.blackTheme .el-dialog__title {
color: #ffffff !important;
}
.blackTheme .title-text {
color: var(--TextPrimary) !important;
@ -663,9 +656,7 @@ div:focus {
background: #38393a !important;
}
.blackTheme .el-message-box__content {
color: #F2F6FC;
}
.blackTheme .el-message-box__btns {
.el-button--default:not(.el-button--primary) {

View File

@ -13,11 +13,11 @@ export const DEFAULT_SIZE = {
barDefault: true,
barWidth: 40,
barGap: 0.4,
lineWidth: 1,
lineWidth: 2,
lineType: 'solid',
lineSymbol: 'circle',
lineSymbolSize: 4,
lineSmooth: false,
lineSmooth: true,
lineArea: false,
pieInnerRadius: 0,
pieOuterRadius: 80,

View File

@ -5,7 +5,7 @@ import { DEFAULT_SIZE } from '@/views/chart/chart/chart'
export function baseLiquid(plot, container, chart) {
let value = 0
const colors = []
let max, radius, outlineBorder, outlineDistance, waveLength, waveCount, bgColor, shape, labelContent, title
let max, radius, bgColor, shape, labelContent, title
if (chart.data) {
if (chart.data.series.length > 0) {
value = chart.data.series[0].data[0]
@ -26,10 +26,6 @@ export function baseLiquid(plot, container, chart) {
const size = JSON.parse(JSON.stringify(customAttr.size))
max = size.liquidMax ? size.liquidMax : DEFAULT_SIZE.liquidMax
radius = parseFloat((size.liquidSize ? size.liquidSize : DEFAULT_SIZE.liquidSize) / 100)
outlineBorder = parseInt(size.liquidOutlineBorder ? size.liquidOutlineBorder : DEFAULT_SIZE.liquidOutlineBorder)
outlineDistance = parseInt((size.liquidOutlineDistance || size.liquidOutlineDistance === 0) ? size.liquidOutlineDistance : DEFAULT_SIZE.liquidOutlineDistance)
waveLength = parseInt(size.liquidWaveLength ? size.liquidWaveLength : DEFAULT_SIZE.liquidWaveLength)
waveCount = parseInt(size.liquidWaveCount ? size.liquidWaveCount : DEFAULT_SIZE.liquidWaveCount)
shape = size.liquidShape ? size.liquidShape : DEFAULT_SIZE.liquidShape
}
// label
@ -86,14 +82,6 @@ export function baseLiquid(plot, container, chart) {
percent: (parseFloat(value) / parseFloat(max)),
radius: radius,
shape: shape,
outline: {
border: outlineBorder,
distance: outlineDistance
},
wave: {
length: waveLength,
count: waveCount
},
statistic: {
// title: title,
content: labelContent

View File

@ -26,7 +26,7 @@ export function baseMapOption(chart_option, chart) {
// 处理data
if (chart.data) {
chart_option.title.text = chart.title
if (chart.data.series.length > 0) {
if (chart.data.series && chart.data.series.length > 0) {
chart_option.series[0].name = chart.data.series[0].name
// label
if (customAttr.label) {

View File

@ -74,7 +74,7 @@ import {
import {
baseMixOption
} from '@/views/chart/chart/mix/mix'
// import eventBus from '@/components/canvas/utils/eventBus'
// import eventBus from '@/components/canvas/utils/eventBus'
import {
uuid
} from 'vue-uuid'
@ -130,7 +130,8 @@ export default {
pointParam: null,
dynamicAreaCode: null,
borderRadius: '0px'
borderRadius: '0px',
mapCenter: null
}
},
@ -276,6 +277,11 @@ export default {
const base_json = JSON.parse(JSON.stringify(BASE_MAP))
const chart_option = baseMapOption(base_json, chart)
this.myEcharts(chart_option)
const opt = this.myChart.getOption()
if (opt && opt.series) {
const center = opt.series[0].center
this.mapCenter = center
}
},
myEcharts(option) {
//
@ -356,6 +362,7 @@ export default {
resetZoom() {
const options = JSON.parse(JSON.stringify(this.myChart.getOption()))
options.series[0].zoom = 1
options.series[0].center = this.mapCenter
this.myChart.setOption(options)
}
}

View File

@ -6,7 +6,7 @@
id="label-content"
:style="content_class"
>
<span v-if="quotaShow" :style="label_class">
<span :style="label_class">
<p v-for="item in chart.data.series" :key="item.name" :style="label_content_class">
{{ item.data[0] }}
</p>

View File

@ -17,7 +17,7 @@
<el-form-item :label="$t('chart.text_color')" class="form-item">
<el-color-picker v-model="labelForm.color" class="color-picker-style" :predefine="predefineColors" @change="changeLabelAttr" />
</el-form-item>
<el-form-item v-show="chart.type && chart.type !== 'liquid'" :label="$t('chart.label_position')" class="form-item">
<el-form-item v-show="chart.type && chart.type !== 'liquid' && !chart.type.includes('line') && chart.type !== 'treemap'" :label="$t('chart.label_position')" class="form-item">
<el-select v-model="labelForm.position" :placeholder="$t('chart.label_position')" @change="changeLabelAttr">
<el-option v-for="option in labelPosition" :key="option.value" :label="option.name" :value="option.value" />
</el-select>
@ -84,27 +84,35 @@ export default {
labelForm: JSON.parse(JSON.stringify(DEFAULT_LABEL)),
fontSize: [],
isSetting: false,
labelPosition: [
labelPosition: [],
labelPositionPie: [
{ name: this.$t('chart.inside'), value: 'inside' },
{ name: this.$t('chart.outside'), value: 'outside' },
{ name: this.$t('chart.center'), value: 'center' },
{ name: this.$t('chart.text_pos_top'), value: 'top' },
{ name: this.$t('chart.text_pos_bottom'), value: 'bottom' },
{ name: this.$t('chart.outside'), value: 'outside' }
],
labelPositionH: [
{ name: this.$t('chart.text_pos_left'), value: 'left' },
{ name: this.$t('chart.center'), value: 'inside' },
{ name: this.$t('chart.text_pos_right'), value: 'right' }
],
labelPositionV: [
{ name: this.$t('chart.text_pos_top'), value: 'top' },
{ name: this.$t('chart.center'), value: 'inside' },
{ name: this.$t('chart.text_pos_bottom'), value: 'bottom' }
],
predefineColors: COLOR_PANEL
}
},
watch: {
'chart': {
handler: function() {
this.initOptions()
this.initData()
}
}
},
mounted() {
this.init()
this.initOptions()
this.initData()
},
methods: {
@ -140,6 +148,18 @@ export default {
this.isSetting = false
}
this.$emit('onLabelChange', this.labelForm)
},
initOptions() {
const type = this.chart.type
if (type) {
if (type.includes('horizontal') || type === 'funnel') {
this.labelPosition = this.labelPositionH
} else if (type.includes('pie')) {
this.labelPosition = this.labelPositionPie
} else {
this.labelPosition = this.labelPositionV
}
}
}
}
}

View File

@ -17,7 +17,7 @@
<el-form-item :label="$t('chart.text_color')" class="form-item">
<el-color-picker v-model="labelForm.color" class="color-picker-style" :predefine="predefineColors" @change="changeLabelAttr" />
</el-form-item>
<el-form-item v-show="chart.type && chart.type !== 'liquid' && chart.type !== 'pie-rose'" :label="$t('chart.label_position')" class="form-item">
<el-form-item v-show="chart.type && chart.type !== 'liquid' && chart.type !== 'pie-rose' && !chart.type.includes('line') && chart.type !== 'treemap'" :label="$t('chart.label_position')" class="form-item">
<el-select v-model="labelForm.position" :placeholder="$t('chart.label_position')" @change="changeLabelAttr">
<el-option v-for="option in labelPosition" :key="option.value" :label="option.name" :value="option.value" />
</el-select>
@ -62,29 +62,35 @@ export default {
labelForm: JSON.parse(JSON.stringify(DEFAULT_LABEL)),
fontSize: [],
isSetting: false,
labelPosition: [
{ name: this.$t('chart.inside'), value: 'middle' },
{ name: this.$t('chart.outside'), value: 'outside' },
{ name: this.$t('chart.center'), value: 'center' },
{ name: this.$t('chart.text_pos_top'), value: 'top' },
{ name: this.$t('chart.text_pos_bottom'), value: 'bottom' },
labelPosition: [],
labelPositionPie: [
{ name: this.$t('chart.inside'), value: 'inner' },
{ name: this.$t('chart.outside'), value: 'outer' }
],
labelPositionH: [
{ name: this.$t('chart.text_pos_left'), value: 'left' },
{ name: this.$t('chart.center'), value: 'middle' },
{ name: this.$t('chart.text_pos_right'), value: 'right' }
],
labelPositionV: [
{ name: this.$t('chart.text_pos_top'), value: 'top' },
{ name: this.$t('chart.center'), value: 'middle' },
{ name: this.$t('chart.text_pos_bottom'), value: 'bottom' }
],
predefineColors: COLOR_PANEL
}
},
watch: {
'chart': {
handler: function() {
this.initLabelPosition()
this.initOptions()
this.initData()
}
}
},
mounted() {
this.init()
this.initLabelPosition()
this.initOptions()
this.initData()
},
methods: {
@ -121,22 +127,16 @@ export default {
}
this.$emit('onLabelChange', this.labelForm)
},
initLabelPosition() {
if (this.chart && this.chart.type && this.chart.type.includes('pie')) {
this.labelPosition = [
{ name: this.$t('chart.inside'), value: 'inner' },
{ name: this.$t('chart.outside'), value: 'outer' }
]
} else {
this.labelPosition = [
{ name: this.$t('chart.inside'), value: 'middle' },
{ name: this.$t('chart.outside'), value: 'outside' },
{ name: this.$t('chart.center'), value: 'center' },
{ name: this.$t('chart.text_pos_top'), value: 'top' },
{ name: this.$t('chart.text_pos_bottom'), value: 'bottom' },
{ name: this.$t('chart.text_pos_left'), value: 'left' },
{ name: this.$t('chart.text_pos_right'), value: 'right' }
]
initOptions() {
const type = this.chart.type
if (type) {
if (type.includes('horizontal') || type === 'funnel') {
this.labelPosition = this.labelPositionH
} else if (type.includes('pie')) {
this.labelPosition = this.labelPositionPie
} else {
this.labelPosition = this.labelPositionV
}
}
}
}

View File

@ -128,9 +128,6 @@
</el-form>
<el-form v-show="chart.type && chart.type.includes('text')" ref="sizeFormPie" :disabled="param && !hasDataPermission('manage',param.privileges)" :model="sizeForm" label-width="100px" size="mini">
<el-form-item :label="$t('chart.quota_show')" class="form-item">
<el-checkbox v-model="sizeForm.quotaShow" @change="changeBarSizeCase">{{ $t('chart.show') }}</el-checkbox>
</el-form-item>
<el-form-item :label="$t('chart.quota_font_size')" class="form-item">
<el-select v-model="sizeForm.quotaFontSize" :placeholder="$t('chart.quota_font_size')" @change="changeBarSizeCase">
<el-option v-for="option in fontSize" :key="option.value" :label="option.name" :value="option.value" />

View File

@ -125,9 +125,6 @@
</el-form>
<el-form v-show="chart.type && chart.type.includes('text')" ref="sizeFormPie" :disabled="param && !hasDataPermission('manage',param.privileges)" :model="sizeForm" label-width="100px" size="mini">
<el-form-item :label="$t('chart.quota_show')" class="form-item">
<el-checkbox v-model="sizeForm.quotaShow" @change="changeBarSizeCase">{{ $t('chart.show') }}</el-checkbox>
</el-form-item>
<el-form-item :label="$t('chart.quota_font_size')" class="form-item">
<el-select v-model="sizeForm.quotaFontSize" :placeholder="$t('chart.quota_font_size')" @change="changeBarSizeCase">
<el-option v-for="option in fontSize" :key="option.value" :label="option.name" :value="option.value" />
@ -244,18 +241,6 @@
<el-form-item :label="$t('chart.radar_size')" class="form-item form-item-slider">
<el-slider v-model="sizeForm.liquidSize" show-input :show-input-controls="false" input-size="mini" :min="1" :max="100" @change="changeBarSizeCase" />
</el-form-item>
<el-form-item :label="$t('chart.liquid_outline_border')" class="form-item form-item-slider">
<el-slider v-model="sizeForm.liquidOutlineBorder" show-input :show-input-controls="false" input-size="mini" :min="1" :max="20" @change="changeBarSizeCase" />
</el-form-item>
<el-form-item :label="$t('chart.liquid_outline_distance')" class="form-item form-item-slider">
<el-slider v-model="sizeForm.liquidOutlineDistance" show-input :show-input-controls="false" input-size="mini" :min="0" :max="20" @change="changeBarSizeCase" />
</el-form-item>
<el-form-item :label="$t('chart.liquid_wave_length')" class="form-item form-item-slider">
<el-slider v-model="sizeForm.liquidWaveLength" show-input :show-input-controls="false" input-size="mini" :min="10" :max="500" @change="changeBarSizeCase" />
</el-form-item>
<el-form-item :label="$t('chart.liquid_wave_count')" class="form-item form-item-slider">
<el-slider v-model="sizeForm.liquidWaveCount" show-input :show-input-controls="false" input-size="mini" :min="2" :max="10" @change="changeBarSizeCase" />
</el-form-item>
</el-form>
</el-col>
</div>

View File

@ -196,9 +196,9 @@
:options="chartGroupTreeAvailable"
:normalizer="normalizer"
:placeholder="$t('chart.select_group')"
:noChildrenText="$t('commons.treeselect.no_children_text')"
:noOptionsText="$t('commons.treeselect.no_options_text')"
:noResultsText="$t('commons.treeselect.no_results_text')"
:no-children-text="$t('commons.treeselect.no_children_text')"
:no-options-text="$t('commons.treeselect.no_options_text')"
:no-results-text="$t('commons.treeselect.no_results_text')"
/>
</el-form-item>
</el-col>
@ -558,7 +558,7 @@ export default {
showClose: true
})
this.treeNode()
this.$store.dispatch('chart/setTable', null)
this.$store.dispatch('chart/setTable', new Date().getTime())
})
} else {
// this.$message({
@ -773,6 +773,7 @@ export default {
view.customFilter = JSON.stringify([])
view.drillFields = JSON.stringify([])
view.extBubble = JSON.stringify([])
this.setChartDefaultOptions(view)
const _this = this
post('/chart/view/save', view).then(response => {
this.closeCreateChart()
@ -788,6 +789,33 @@ export default {
})
},
setChartDefaultOptions(view) {
const type = view.type
const attr = JSON.parse(view.customAttr)
if (type.includes('pie')) {
if (view.render === 'echarts') {
attr.label.position = 'inside'
} else {
attr.label.position = 'inner'
}
} else if (type.includes('line')) {
attr.label.position = 'top'
} else if (type.includes('treemap')) {
if (view.render === 'echarts') {
attr.label.position = 'inside'
} else {
attr.label.position = 'middle'
}
} else {
if (view.render === 'echarts') {
attr.label.position = 'inside'
} else {
attr.label.position = 'middle'
}
}
view.customAttr = JSON.stringify(attr)
},
getTable(table) {
this.table = JSON.parse(JSON.stringify(table))
},

View File

@ -1,6 +1,7 @@
<template>
<el-row v-loading="loading" style="height: 100%;overflow-y: hidden;width: 100%;">
<el-row style="height: 40px;" class="padding-lr">
<span v-show="false">{{ refreshPage }}</span>
<span class="title-text" style="line-height: 40px;">{{ view.name }}</span>
<el-popover
placement="right-start"
@ -141,7 +142,7 @@
class="render-select"
style="width: 100px"
size="mini"
@change="calcData(true,'chart',true,true)"
@change="changeChartType()"
>
<el-option
v-for="item in renderOptions"
@ -158,7 +159,7 @@
v-model="view.type"
style="width: 100%"
:disabled="!hasDataPermission('manage',param.privileges)"
@change="calcData(true,'chart',true,true)"
@change="changeChartType()"
>
<chart-type :chart="view" style="height: 480px" />
</el-radio-group>
@ -1105,11 +1106,10 @@ export default {
}
},
computed: {
// vId() {
// // console.log(this.$store.state.chart.viewId);
// this.getData(this.$store.state.chart.viewId)
// return this.$store.state.chart.viewId
// }
refreshPage: function() {
this.getChart(this.param.id)
return this.$store.getters.chartTable
},
chartType() {
return this.chart.type
}
@ -2066,6 +2066,36 @@ export default {
reset() {
this.getData(this.param.id)
},
changeChartType() {
this.setChartDefaultOptions()
this.calcData(true, 'chart', true, true)
},
setChartDefaultOptions() {
const type = this.view.type
if (type.includes('pie')) {
if (this.view.render === 'echarts') {
this.view.customAttr.label.position = 'inside'
} else {
this.view.customAttr.label.position = 'inner'
}
} else if (type.includes('line')) {
this.view.customAttr.label.position = 'top'
} else if (type.includes('treemap')) {
if (this.view.render === 'echarts') {
this.view.customAttr.label.position = 'inside'
} else {
this.view.customAttr.label.position = 'middle'
}
} else {
if (this.view.render === 'echarts') {
this.view.customAttr.label.position = 'inside'
} else {
this.view.customAttr.label.position = 'middle'
}
}
}
}
}

View File

@ -1,6 +1,6 @@
<template>
<el-row style="height: 100%;overflow-y: hidden;width: 100%;">
<!-- <span v-show="false">{{ tableRefresh }}</span>-->
<span v-show="false">{{ refreshPage }}</span>
<el-row style="height: 26px;">
<span class="title-text" style="line-height: 26px;">
{{ table.name }}
@ -57,7 +57,7 @@
<update-info v-if="tabActive=='updateInfo'" :param="param" :table="table" />
</el-tab-pane>
<el-tab-pane v-if="isPluginLoaded && hasDataPermission('manage',param.privileges)" :lazy="true" :label="$t('dataset.row_permissions')" name="rowPermissions">
<plugin-com v-if="isPluginLoaded && tabActive=='rowPermissions'" ref="RowPermissions" component-name="RowPermissions" :obj="table"/>
<plugin-com v-if="isPluginLoaded && tabActive=='rowPermissions'" ref="RowPermissions" component-name="RowPermissions" :obj="table" />
</el-tab-pane>
<el-tab-pane v-if="isPluginLoaded && hasDataPermission('manage',param.privileges)" :lazy="true" :label="$t('dataset.column_permissions')" name="columnPermissions">
<plugin-com v-if="isPluginLoaded && tabActive=='columnPermissions'" ref="ColumnPermissions" component-name="ColumnPermissions" :obj="table" />
@ -78,7 +78,7 @@ import PluginCom from '@/views/system/plugin/PluginCom'
export default {
name: 'ViewTable',
components: {FieldEdit, UnionView, DatasetChartDetail, UpdateInfo, TabDataPreview, PluginCom },
components: { FieldEdit, UnionView, DatasetChartDetail, UpdateInfo, TabDataPreview, PluginCom },
props: {
param: {
type: Object,
@ -105,14 +105,13 @@ export default {
isPluginLoaded: false
}
},
beforeCreate() {
pluginLoaded().then(res => {
this.isPluginLoaded = res.success && res.data
})
},
computed: {
hideCustomDs: function() {
return this.$store.getters.hideCustomDs
},
refreshPage: function() {
this.initTable(this.param.id)
return this.$store.getters.table
}
},
watch: {
@ -121,6 +120,11 @@ export default {
this.initTable(this.param.id)
}
},
beforeCreate() {
pluginLoaded().then(res => {
this.isPluginLoaded = res.success && res.data
})
},
created() {
},

View File

@ -688,7 +688,7 @@ export default {
},
cancelFilter() {
this.closeFilter()
if(this.filterFromDrag){
if (this.filterFromDrag) {
bus.$emit('onRemoveLastItem')
}
},
@ -697,6 +697,7 @@ export default {
this.$store.commit('setComponentWithId', this.currentFilterCom)
this.$store.commit('recordSnapshot', 'sureFilter')
this.$store.commit('setCurComponent', { component: this.currentFilterCom, index: this.curComponentIndex })
bus.$emit('reset-default-value', this.currentFilterCom.id)
this.closeFilter()
},
reFreshComponent(component) {

View File

@ -4,8 +4,14 @@
<el-form-item :label="$t('dynamic_time.set_default')">
<el-radio-group v-model="element.options.attrs.default.isDynamic" @change="dynamicChange">
<el-radio :label="false">{{ $t('dynamic_time.fix') }}</el-radio>
<el-radio :label="true">{{ $t('dynamic_time.dynamic') }}</el-radio>
<el-radio
v-for="(item, index) in defaultSetting.radioOptions"
:key="index"
:label="item.value"
>
{{ $t(item.text) }}
</el-radio>
</el-radio-group>
</el-form-item>
@ -17,10 +23,13 @@
class="relative-time"
@change="dkeyChange"
>
<el-option :label="$t('dynamic_time.today')" :value="0" />
<el-option :label="$t('dynamic_time.yesterday')" :value="1" />
<el-option :label="$t('dynamic_time.firstOfMonth')" :value="2" />
<el-option :label="$t('dynamic_time.custom')" :value="3" />
<el-option
v-for="(item, index) in defaultSetting.relativeOptions"
:key="item.value + index"
:label="$t(item.text)"
:value="item.value"
/>
</el-select>
</el-form-item>
@ -28,7 +37,7 @@
<div class="inline">
<el-form-item
v-if="element.options.attrs.default.isDynamic && element.options.attrs.default.dkey === 3"
v-if="element.options.attrs.default.isDynamic && element.options.attrs.default.dkey === (defaultSetting.relativeOptions.length - 1)"
label=""
>
<el-input
@ -42,7 +51,7 @@
</el-form-item>
<el-form-item
v-if="element.options.attrs.default.isDynamic && element.options.attrs.default.dkey === 3"
v-if="element.options.attrs.default.isDynamic && element.options.attrs.default.dkey === (defaultSetting.relativeOptions.length - 1)"
label=""
class="no-label-item"
>
@ -50,17 +59,21 @@
v-model="element.options.attrs.default.dynamicInfill"
size="mini"
placeholder=""
:disabled="defaultSetting.custom && defaultSetting.custom.unitsOptions && defaultSetting.custom.unitsOptions.length === 1"
@change="dynamicInfillChange"
>
<el-option :label="$t('dynamic_time.date')" value="day" />
<el-option :label="$t('dynamic_time.week')" value="week" />
<el-option :label="$t('dynamic_time.month')" value="month" />
<el-option :label="$t('dynamic_time.year')" value="year" />
<el-option
v-for="(item, index) in defaultSetting.custom.unitsOptions"
:key="item.value + index"
:label="$t(item.text)"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="element.options.attrs.default.isDynamic && element.options.attrs.default.dkey === 3"
v-if="element.options.attrs.default.isDynamic && element.options.attrs.default.dkey === (defaultSetting.relativeOptions.length - 1)"
label=""
class="no-label-item"
>
@ -79,7 +92,13 @@
</div>
<el-form-item v-if="element.options.attrs.default.isDynamic" :label="$t('dynamic_time.preview')">
<el-date-picker v-model="dval" type="date" disabled placeholder="" class="relative-time" />
<el-date-picker
v-model="dval"
:type="element.options.attrs.type"
disabled
placeholder=""
class="relative-time"
/>
</el-form-item>
<el-form-item v-else :label="$t('dynamic_time.set')">
@ -115,6 +134,13 @@ export default {
dval: null
}
},
computed: {
defaultSetting() {
const widget = ApplicationContext.getService(this.element.serviceName)
const setting = widget.defaultSetting()
return setting
}
},
created() {
this.setDval()
},
@ -143,6 +169,7 @@ export default {
const widget = ApplicationContext.getService(this.element.serviceName)
const time = widget.dynamicDateFormNow(this.element)
this.dval = time
this.element.options.manualModify = false
}
}
}

View File

@ -213,6 +213,7 @@ export default {
const time = widget.dynamicDateFormNow(this.element)
this.dval = time
bus.$emit('valid-values-change', (!time || time.length === 0 || time[1] > time[0]))
this.element.options.manualModify = false
}
}
}

View File

@ -3,11 +3,11 @@
<el-col :span="24">
<div class="filter-content">
<el-card
v-if="element.serviceName && element.serviceName !== 'timeDateWidget' && element.serviceName !== 'timeDateRangeWidget'"
v-if="element.component && element.component !== 'de-date'"
class="box-card"
>
<div style="margin-bottom: 10px;">
<span>默认值设置</span>
<span>{{ $t('dynamic_time.set_default') }}</span>
</div>
<div class="custom-component-class">
<component
@ -22,13 +22,13 @@
</el-card>
<el-card v-if="element.serviceName && element.serviceName === 'timeDateWidget'" class="box-card">
<de-date-default v-if="element.serviceName && element.serviceName === 'timeDateWidget'" :element="element" />
<el-card v-if="element.component && element.component === 'de-date' && element.serviceName && element.serviceName !== 'timeDateRangeWidget'" class="box-card">
<de-date-default v-if="element.component === 'de-date' && element.serviceName !== 'timeDateRangeWidget'" :element="element" />
</el-card>
<el-card v-if="element.serviceName && element.serviceName === 'timeDateRangeWidget'" class="box-card">
<el-card v-if="element.component && element.component === 'de-date' && element.serviceName && element.serviceName === 'timeDateRangeWidget'" class="box-card">
<de-date-range-default
v-if="element.serviceName && element.serviceName === 'timeDateRangeWidget'"
v-if="element.component === 'de-date' && element.serviceName === 'timeDateRangeWidget'"
:element="element"
/>
</el-card>

View File

@ -13,12 +13,12 @@
<el-form-item :label="$t('commons.email')" prop="email">
<el-input v-model="form.email" />
</el-form-item>
<el-form-item v-if="formType !== 'modify'" :label="$t('commons.password')" prop="password">
<!-- <el-form-item v-if="formType !== 'modify'" :label="$t('commons.password')" prop="password">
<el-input v-model="form.password" autocomplete="off" show-password />
</el-form-item>
<el-form-item v-if="formType !== 'modify'" :label="$t('commons.confirmPassword')" prop="confirmPassword">
<el-input v-model="form.confirmPassword" autocomplete="off" show-password />
</el-form-item>
</el-form-item> -->
<el-form-item :label="$t('commons.gender')" prop="gender">
<el-radio-group v-model="form.gender" style="width: 178px">
@ -40,9 +40,9 @@
:load-options="loadDepts"
:auto-load-root-options="false"
:placeholder="$t('user.choose_org')"
:noChildrenText="$t('commons.treeselect.no_children_text')"
:noOptionsText="$t('commons.treeselect.no_options_text')"
:noResultsText="$t('commons.treeselect.no_results_text')"
:no-children-text="$t('commons.treeselect.no_children_text')"
:no-options-text="$t('commons.treeselect.no_options_text')"
:no-results-text="$t('commons.treeselect.no_results_text')"
@open="filterData"
/>
</el-form-item>

View File

@ -0,0 +1,60 @@
<template>
<el-col :span="8" class="card_main">
<el-row>
<el-col :span="8" class="card_head">
<span>{{ headInfo }}</span>
</el-col>
<el-col :span="1" class="triangle" />
</el-row>
<el-row class="card_content">
<slot />
</el-row>
</el-col>
</template>
<script>
export default {
name: 'Card',
props: {
headInfo: {
type: String,
required: false
}
},
data() {
return {}
}
}
</script>
<style lang="scss" scoped>
.card_main{
padding: 40px 30px 30px 30px;
height: 33vh;
}
.card_head{
padding-left: 15px;
color: white;
line-height: 30px;
font-weight: bold;
font-size: 18px;
background-color: var(--MenuActiveBG, #409EFF);
}
.triangle{
width: 0;
height: 0;
border-bottom: 30px solid var(--MenuActiveBG, #409EFF);
border-right: 30px solid transparent;
-webkit-transform: rotate(180deg);
transform: rotate(0deg);
}
.card_content{
border: lightgray solid 1px;
border-radius: 0px 5px 5px 5px;
height: 100%;
overflow: hidden;
}
</style>

View File

@ -0,0 +1,51 @@
<template>
<el-row class="demo_main">
<el-row style="margin-top: 5%" class="demo_content">
<span class="icon iconfont icon-fasongyoujian" />
<span style="margin-left: 10px">dataease@fit2cloud.com</span>
</el-row>
<el-row class="demo_content">
<span class="icon iconfont icon-dianhua" />
<span style="margin-left: 10px">400-052-0755</span>
</el-row>
<el-row class="demo_content">
<span class="icon iconfont icon-github" />
<span class="demo_git"><a href="https://github.com/dataease/dataease/issues" target="_blank">{{ $t('wizard.open_source_community') }}</a></span>
</el-row>
</el-row>
</template>
<script>
export default {
name: 'ContactUs',
data() {
return {}
}
}
</script>
<style lang="scss" scoped>
.demo_main{
height: 100%;
padding: 10px 20px 10px 20px;
}
.demo_content{
padding-left: 10px;
height: 30%;
}
.demo_git{
margin-left: 10px;
color: var(--MenuActiveBG, #409EFF);
}
.demo_bottom{
position: absolute;
left: 30px;
bottom: 10px;
font-weight: 500;
color: var(--MenuActiveBG, #409EFF);
}
</style>

View File

@ -0,0 +1,49 @@
<template>
<el-row class="demo_main">
<div class="demo_title" />
<div class="demo_content">
<a href="https://www.bilibili.com/video/BV1UB4y1K7jA" target="_blank">{{ $t('wizard.demo_video_hint') }}</a>
</div>
</el-row>
</template>
<script>
export default {
name: 'DemoVideo',
props: {
headInfo: {
type: String,
required: false
}
},
data() {
return {}
}
}
</script>
<style lang="scss" scoped>
.demo_main{
height: 100%;
padding: 10px 20px 10px 20px;
}
.demo_title{
float: left;
height: 100%;
width: 50%;
background-size: 100% 100% !important;
background-image: url('../../../assets/deV.png');
}
.demo_content{
margin: auto;
padding-left: 10px;
float: left;
width: 50%;
font-weight: 500;
color: var(--MenuActiveBG, #409EFF);
}
</style>

View File

@ -0,0 +1,60 @@
<template>
<el-row class="demo_main">
<el-row class="demo_content">
<span>
{{ $t('wizard.enterprise_edition_hint1') }}
</span>
<br>
<span>
{{ $t('wizard.enterprise_edition_hint2') }}
</span>
<br>
<span>
{{ $t('wizard.enterprise_edition_hint3') }}
</span>
</el-row>
<el-row class="demo_bottom">
<a href="https://jinshuju.net/f/TK5TTd" target="_blank"> {{ $t('wizard.click_inner') }}</a>
</el-row>
</el-row>
</template>
<script>
export default {
name: 'TeachingVideo',
props: {
},
data() {
return {}
}
}
</script>
<style lang="scss" scoped>
.demo_main{
height: 100%;
padding: 10px 20px 10px 20px;
}
.demo_content{
padding-left: 10px;
float: left;
font-weight: 400;
max-height: 80%;
overflow: hidden;
}
.demo_bottom{
position: absolute;
left: 30px;
bottom: 10px;
font-weight: 500;
color: var(--MenuActiveBG, #409EFF);
}
.title{
line-height: 40px;
}
</style>

View File

@ -0,0 +1,65 @@
<template>
<el-row class="demo_main">
<el-row class="demo_content">
<a :href="href" target="_blank">{{ title }}</a>
<br>
<span style="color: lightgray">{{ time }}</span>
</el-row>
<el-row class="demo_bottom">
<a href="https://blog.fit2cloud.com/?cat=321" target="_blank">{{ $t('wizard.show_more') }}</a>
</el-row>
</el-row>
</template>
<script>
import { blogLastActive } from '@/api/wizard/wizard'
export default {
name: 'LatestDevelopments',
data() {
return {
title: '',
href: '',
time: ''
}
},
mounted() {
this.init()
},
methods: {
init() {
blogLastActive().then(res => {
this.title = res.data.title
this.href = res.data.href
this.time = res.data.time
})
}
}
}
</script>
<style lang="scss" scoped>
.demo_main{
height: 100%;
padding: 10px 20px 10px 20px;
}
.demo_content{
padding-left: 10px;
float: left;
font-weight: 500;
color: var(--MenuActiveBG, #409EFF);
max-height: 80%;
overflow: hidden;
}
.demo_bottom{
position: absolute;
left: 30px;
bottom: 10px;
font-weight: 500;
color: var(--MenuActiveBG, #409EFF);
}
</style>

View File

@ -0,0 +1,50 @@
<template>
<el-row class="demo_main">
<el-row class="demo_content">
<span>{{ $t('wizard.online_document_hint') }}</span>
</el-row>
<el-row class="demo_bottom">
<a href="https://dataease.io/docs/dev_manual/dev_manual/" target="_blank">{{ $t('wizard.click_show') }}</a>
</el-row>
</el-row>
</template>
<script>
export default {
name: 'OnlineDocument',
props: {
headInfo: {
type: String,
required: false
}
},
data() {
return {}
}
}
</script>
<style lang="scss" scoped>
.demo_main{
height: 100%;
padding: 10px 20px 10px 20px;
}
.demo_content{
padding-left: 10px;
float: left;
font-weight: 400;
max-height: 80%;
overflow: hidden;
}
.demo_bottom{
position: absolute;
left: 30px;
bottom: 10px;
font-weight: 500;
color: var(--MenuActiveBG, #409EFF);
}
</style>

View File

@ -0,0 +1,59 @@
<template>
<el-row class="demo_main">
<el-row class="demo_content">
<span class="title">
<a href="https://live.vhall.com/v3/lives/subscribe/533874762" target="_blank">40分钟带你玩转 DataEase </a>
</span>
<br>
<span class="title">
<a href="https://live.vhall.com/v3/lives/subscribe/903960272" target="_blank">用DataEase开源工具可视化 ClickHouse数据 </a>
</span>
</el-row>
<el-row class="demo_bottom">
<span style="color: black">{{ $t('wizard.teaching_video_bottom_hint') }}</span><a href="https://e.vhall.com/v3/user/home/45637107" target="_blank">{{ $t('wizard.click_inner') }}</a>
</el-row>
</el-row>
</template>
<script>
export default {
name: 'OnlineDocument',
props: {
headInfo: {
type: String,
required: false
}
},
data() {
return {}
}
}
</script>
<style lang="scss" scoped>
.demo_main{
height: 100%;
padding: 10px 20px 10px 20px;
}
.demo_content{
padding-left: 10px;
float: left;
font-weight: 400;
color: var(--MenuActiveBG, #409EFF);
}
.demo_bottom{
position: absolute;
left: 30px;
bottom: 10px;
font-weight: 500;
color: var(--MenuActiveBG, #409EFF);
}
.title{
line-height: 40px;
}
</style>

View File

@ -0,0 +1,84 @@
<template>
<el-row class="main_container">
<el-row class="head">
<span class="hint_head">{{ $t('wizard.welcome_title') }}</span> <br>
<span class="hint_content">{{ $t('wizard.welcome_hint') }}</span>
</el-row>
<el-row class="card_container">
<card v-for="(cardDetail,index) in cardList" :key="index" :head-info="cardDetail.headInfo">
<component :is="cardDetail.component" />
</card>
</el-row>
</el-row>
</template>
<script>
import Card from '@/views/wizard/card'
import DemoVideo from '@/views/wizard/details/DemoVideo'
import OnlineDocument from '@/views/wizard/details/OnlineDocument'
import LatestDevelopments from '@/views/wizard/details/LatestDevelopments'
import TeachingVideo from '@/views/wizard/details/TeachingVideo'
import EnterpriseEdition from '@/views/wizard/details/EnterpriseEdition'
import ContactUs from '@/views/wizard/details/ContactUs'
export default {
name: 'Wizard',
components: { Card, DemoVideo, OnlineDocument, LatestDevelopments, TeachingVideo, EnterpriseEdition, ContactUs },
data() {
return {
cardList: [
{
headInfo: this.$t('wizard.demo_video'),
component: 'DemoVideo'
},
{
headInfo: this.$t('wizard.online_document'),
component: 'OnlineDocument'
},
{
headInfo: this.$t('wizard.latest_developments'),
component: 'LatestDevelopments'
},
{
headInfo: this.$t('wizard.teaching_video'),
component: 'TeachingVideo'
},
{
headInfo: this.$t('wizard.enterprise_edition'),
component: 'EnterpriseEdition'
},
{
headInfo: this.$t('wizard.contact_us'),
component: 'ContactUs'
}
]
}
}
}
</script>
<style lang="scss" scoped>
.main_container {
}
.head {
background-color: var(--MenuActiveBG, #409EFF);
text-align: center;
color: white;
padding: 10px;
margin-top: 25px;
}
.hint_head {
line-height: 40px;
font-weight: bold;
font-size: 25px;
}
.hint_content {
line-height: 40px;
font-size: 15px;
}
.card_container {
}
</style>

View File

@ -1,5 +0,0 @@
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title></title><script>document.addEventListener('DOMContentLoaded', function() {
document.documentElement.style.fontSize = document.documentElement.clientWidth / 20 + 'px'
})
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')</script><link rel="stylesheet" href="/de-app/static/index.a5c69d49.css"></head><body><noscript><strong>Please enable JavaScript to continue.</strong></noscript><div id="app"></div><script src="/de-app/static/js/chunk-vendors.2822c2ee.js"></script><script src="/de-app/static/js/index.12bd8b7a.js"></script></body></html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 561 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Some files were not shown because too many files have changed in this diff Show More