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

View File

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

View File

@ -27,6 +27,7 @@ import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired; 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.RequestBody;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -40,6 +41,9 @@ import javax.servlet.http.HttpServletRequest;
@RestController @RestController
public class AuthServer implements AuthApi { public class AuthServer implements AuthApi {
@Value("${dataease.init_password:DataEase123..}")
private String DEFAULT_PWD;
@Autowired @Autowired
private AuthUserService authUserService; private AuthUserService authUserService;
@ -65,14 +69,19 @@ public class AuthServer implements AuthApi {
SysUserEntity user = authUserService.getLdapUserByName(username); SysUserEntity user = authUserService.getLdapUserByName(username);
if (ObjectUtils.isEmpty(user) || ObjectUtils.isEmpty(user.getUserId())) { if (ObjectUtils.isEmpty(user) || ObjectUtils.isEmpty(user.getUserId())) {
LdapAddRequest ldapAddRequest = new LdapAddRequest(); LdapAddRequest ldapAddRequest = new LdapAddRequest();
ldapAddRequest.setUsers(new ArrayList<XpackLdapUserEntity>() {{ ldapAddRequest.setUsers(new ArrayList<XpackLdapUserEntity>() {
add(ldapUserEntity); {
}}); add(ldapUserEntity);
}
});
ldapAddRequest.setEnabled(1L); ldapAddRequest.setEnabled(1L);
ldapAddRequest.setRoleIds(new ArrayList<Long>() {{ ldapAddRequest.setRoleIds(new ArrayList<Long>() {
add(2L); {
}}); add(2L);
sysUserService.validateExistUser(ldapUserEntity.getUsername(), ldapUserEntity.getNickname(), ldapUserEntity.getEmail()); }
});
sysUserService.validateExistUser(ldapUserEntity.getUsername(), ldapUserEntity.getNickname(),
ldapUserEntity.getEmail());
sysUserService.saveLdapUsers(ldapAddRequest); sysUserService.saveLdapUsers(ldapAddRequest);
} }
@ -92,9 +101,9 @@ public class AuthServer implements AuthApi {
// 普通登录需要验证密码 // 普通登录需要验证密码
if (loginType == 0 || !isSupportLdap) { if (loginType == 0 || !isSupportLdap) {
//私钥解密 // 私钥解密
//md5加密 // md5加密
pwd = CodingUtil.md5(pwd); pwd = CodingUtil.md5(pwd);
if (!StringUtils.equals(pwd, realPwd)) { if (!StringUtils.equals(pwd, realPwd)) {
@ -128,6 +137,16 @@ public class AuthServer implements AuthApi {
return userDto; 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 @Override
public String logout() { public String logout() {
String token = ServletUtils.getToken(); String token = ServletUtils.getToken();
@ -158,7 +177,8 @@ public class AuthServer implements AuthApi {
@Override @Override
public Boolean validateName(@RequestBody Map<String, String> nameDto) { public Boolean validateName(@RequestBody Map<String, String> nameDto) {
String userName = nameDto.get("userName"); String userName = nameDto.get("userName");
if (StringUtils.isEmpty(userName)) return false; if (StringUtils.isEmpty(userName))
return false;
SysUserEntity userEntity = authUserService.getUserByName(userName); SysUserEntity userEntity = authUserService.getUserByName(userName);
return !ObjectUtils.isEmpty(userEntity); return !ObjectUtils.isEmpty(userEntity);
} }
@ -166,29 +186,30 @@ public class AuthServer implements AuthApi {
@Override @Override
public boolean isOpenLdap() { public boolean isOpenLdap() {
Boolean licValid = PluginUtils.licValid(); Boolean licValid = PluginUtils.licValid();
if (!licValid) return false; if (!licValid)
return false;
return authUserService.supportLdap(); return authUserService.supportLdap();
} }
@Override @Override
public boolean isOpenOidc() { public boolean isOpenOidc() {
Boolean licValid = PluginUtils.licValid(); Boolean licValid = PluginUtils.licValid();
if (!licValid) return false; if (!licValid)
return false;
return authUserService.supportOidc(); return authUserService.supportOidc();
} }
@Override @Override
public boolean isPluginLoaded() { public boolean isPluginLoaded() {
Boolean licValid = PluginUtils.licValid(); Boolean licValid = PluginUtils.licValid();
if (!licValid) return false; if (!licValid)
return false;
return authUserService.pluginLoaded(); return authUserService.pluginLoaded();
} }
@Override @Override
public String getPublicKey() { public String getPublicKey() {
return RsaProperties.publicKey; 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.domain.SysMenuExample;
import io.dataease.base.mapper.SysMenuMapper; import io.dataease.base.mapper.SysMenuMapper;
import io.dataease.base.mapper.ext.ExtPluginSysMenuMapper; 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.common.dto.PluginSysMenu;
import io.dataease.plugins.util.PluginUtils; import io.dataease.plugins.util.PluginUtils;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
@ -30,12 +31,16 @@ public class DynamicMenuServiceImpl implements DynamicMenuService {
@Resource @Resource
private ExtPluginSysMenuMapper extPluginSysMenuMapper; private ExtPluginSysMenuMapper extPluginSysMenuMapper;
@Resource
private ExtSysMenuMapper extSysMenuMapper;
@Override @Override
public List<DynamicMenuDto> load(String userId) { public List<DynamicMenuDto> load(String userId) {
SysMenuExample sysMenuExample = new SysMenuExample(); // SysMenuExample sysMenuExample = new SysMenuExample();
sysMenuExample.createCriteria().andTypeLessThanOrEqualTo(1); // sysMenuExample.createCriteria().andTypeLessThanOrEqualTo(1);
sysMenuExample.setOrderByClause(" menu_sort "); // sysMenuExample.setOrderByClause(" menu_sort ");
List<SysMenu> sysMenus = sysMenuMapper.selectByExample(sysMenuExample); // List<SysMenu> sysMenus = sysMenuMapper.selectByExample(sysMenuExample);
List<SysMenu> sysMenus = extSysMenuMapper.querySysMenu();
List<DynamicMenuDto> dynamicMenuDtos = sysMenus.stream().map(this::convert).collect(Collectors.toList()); List<DynamicMenuDto> dynamicMenuDtos = sysMenus.stream().map(this::convert).collect(Collectors.toList());
//增加插件中的菜单 //增加插件中的菜单
List<PluginSysMenu> pluginSysMenus = PluginUtils.pluginMenus(); List<PluginSysMenu> pluginSysMenus = PluginUtils.pluginMenus();

View File

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

View File

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

View File

@ -7,6 +7,8 @@
<result property="pid" column="pid" javaType="java.lang.Long"/> <result property="pid" column="pid" javaType="java.lang.Long"/>
</resultMap> </resultMap>
<resultMap id="ExtBaseResultMap" type="io.dataease.base.domain.SysMenu" extends="io.dataease.base.mapper.SysMenuMapper.BaseResultMap"></resultMap>
<select id="allNodes" resultMap="simpleNode"> <select id="allNodes" resultMap="simpleNode">
select menu_id as id, pid from sys_menu where hidden != 1 select menu_id as id, pid from sys_menu where hidden != 1
</select> </select>
@ -19,4 +21,27 @@
</select> </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> </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; package io.dataease.config;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import io.dataease.commons.pool.PriorityThreadPoolExecutor;
import io.dataease.commons.pool.PriorityThreadPoolProperties;
@EnableAsync(proxyTargetClass = true) @EnableAsync(proxyTargetClass = true)
@Configuration @Configuration
public class AsyncConfig { public class AsyncConfig {
@Resource
private PriorityThreadPoolProperties priorityThreadPoolProperties;
@Bean @Bean
public AsyncTaskExecutor taskExecutor() { public AsyncTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
@ -18,4 +28,18 @@ public class AsyncConfig {
executor.setMaxPoolSize(10); executor.setMaxPoolSize(10);
return executor; 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 * @throws SchedulerException
*/ */
public void addSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> cls, int repeatIntervalTime, 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); JobBuilder jobBuilder = JobBuilder.newJob(cls).withIdentity(jobKey);
@ -46,7 +46,8 @@ public class ScheduleManager {
scheduler.scheduleJob(jd, trigger); 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); addSimpleJob(jobKey, triggerKey, cls, repeatIntervalTime);
} }
@ -59,7 +60,8 @@ public class ScheduleManager {
* @param cron * @param cron
* @param jobDataMap * @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 { try {
LogUtil.info("addCronJob: " + triggerKey.getName() + "," + triggerKey.getGroup()); 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); addCronJob(jobKey, triggerKey, jobClass, cron, startTime, endTime, null);
} }
@ -140,7 +143,8 @@ public class ScheduleManager {
* @param cron * @param cron
* @throws SchedulerException * @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()); LogUtil.info("modifyCronJobTime: " + triggerKey.getName() + "," + triggerKey.getGroup());
@ -151,7 +155,6 @@ public class ScheduleManager {
return; return;
} }
/** 方式一 :调用 rescheduleJob 开始 */ /** 方式一 :调用 rescheduleJob 开始 */
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();// 触发器 TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();// 触发器
@ -279,7 +282,6 @@ public class ScheduleManager {
} }
} }
public static void startJobs(Scheduler sched) { public static void startJobs(Scheduler sched) {
try { try {
sched.start(); sched.start();
@ -289,7 +291,6 @@ public class ScheduleManager {
} }
} }
public void shutdownJobs(Scheduler sched) { public void shutdownJobs(Scheduler sched) {
try { try {
if (!sched.isShutdown()) { if (!sched.isShutdown()) {
@ -312,7 +313,7 @@ public class ScheduleManager {
* @throws SchedulerException * @throws SchedulerException
*/ */
public void addOrUpdateSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class clz, 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)) { if (scheduler.checkExists(triggerKey)) {
modifySimpleJobTime(triggerKey, intervalTime); modifySimpleJobTime(triggerKey, intervalTime);
@ -323,7 +324,7 @@ public class ScheduleManager {
} }
public void addOrUpdateSingleJob(JobKey jobKey, TriggerKey triggerKey, Class clz, 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)) { if (scheduler.checkExists(triggerKey)) {
modifySingleJobTime(triggerKey, date); modifySingleJobTime(triggerKey, date);
} else { } else {
@ -333,15 +334,15 @@ public class ScheduleManager {
} }
public void addOrUpdateSingleJob(JobKey jobKey, TriggerKey triggerKey, Class clz, public void addOrUpdateSingleJob(JobKey jobKey, TriggerKey triggerKey, Class clz,
Date date) throws SchedulerException { Date date) throws SchedulerException {
addOrUpdateSingleJob(jobKey, triggerKey, clz, date, null); 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); addOrUpdateSimpleJob(jobKey, triggerKey, clz, intervalTime, null);
} }
/** /**
* 添加或修改 cronJob * 添加或修改 cronJob
* *
@ -352,7 +353,8 @@ public class ScheduleManager {
* @param jobDataMap * @param jobDataMap
* @throws SchedulerException * @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()); 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); addOrUpdateCronJob(jobKey, triggerKey, jobClass, cron, startTime, endTime, null);
} }
@ -398,7 +401,8 @@ public class ScheduleManager {
if (!CronExpression.isValidExpression(cron)) { if (!CronExpression.isValidExpression(cron)) {
DataEaseException.throwException("cron :" + cron + " error"); 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 { 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 { public void addTask(ScheduleManager scheduleManager, GlobalTaskEntity taskEntity) throws Exception {
// 1首先看看是否过期 // 1首先看看是否过期
Long endTime = taskEntity.getEndTime(); Long endTime = taskEntity.getEndTime();
@ -30,12 +27,11 @@ public abstract class TaskHandler implements InitializingBean {
if (ObjectUtils.isNotEmpty(taskEntity.getEndTime())) { if (ObjectUtils.isNotEmpty(taskEntity.getEndTime())) {
new Date(taskEntity.getEndTime()); new Date(taskEntity.getEndTime());
} }
Class executor = this.getClass(); Class<? extends TaskHandler> executor = this.getClass();
String cron = cron(taskEntity); String cron = cron(taskEntity);
scheduleManager.addOrUpdateCronJob(jobKey, triggerKey, executor, cron, start, end, jobDataMap(taskEntity)); scheduleManager.addOrUpdateCronJob(jobKey, triggerKey, executor, cron, start, end, jobDataMap(taskEntity));
} }
protected abstract JobDataMap jobDataMap(GlobalTaskEntity taskEntity); protected abstract JobDataMap jobDataMap(GlobalTaskEntity taskEntity);
private String cron(GlobalTaskEntity taskEntity) { private String cron(GlobalTaskEntity taskEntity) {
@ -54,36 +50,34 @@ public abstract class TaskHandler implements InitializingBean {
instance.setTime(date); instance.setTime(date);
if (taskEntity.getRateType() == 0) { if (taskEntity.getRateType() == 0) {
return return instance.get(Calendar.SECOND) + " " +
instance.get(Calendar.SECOND) + " " + instance.get(Calendar.MINUTE) + " " +
instance.get(Calendar.MINUTE) + " " + instance.get(Calendar.HOUR_OF_DAY) + " * * ?";
instance.get(Calendar.HOUR_OF_DAY) + " * * ?";
} }
if (taskEntity.getRateType() == 1) { if (taskEntity.getRateType() == 1) {
return return instance.get(Calendar.SECOND) + " " +
instance.get(Calendar.SECOND) + " " + instance.get(Calendar.MINUTE) + " " +
instance.get(Calendar.MINUTE) + " " + instance.get(Calendar.HOUR_OF_DAY) + " ? * " +
instance.get(Calendar.HOUR_OF_DAY) + " ? * " + getDayOfWeek(instance);
getDayOfWeek(instance);
} }
if (taskEntity.getRateType() == 2) { if (taskEntity.getRateType() == 2) {
return return instance.get(Calendar.SECOND) + " " +
instance.get(Calendar.SECOND) + " " + instance.get(Calendar.MINUTE) + " " +
instance.get(Calendar.MINUTE) + " " + instance.get(Calendar.HOUR_OF_DAY) + " " +
instance.get(Calendar.HOUR_OF_DAY) + " " + instance.get(Calendar.DATE) + " * ?";
instance.get(Calendar.DATE) + " * ?";
} }
return null; return null;
} }
public abstract void resetRunningInstance(Long taskId);
private String getDayOfWeek(Calendar instance) { private String getDayOfWeek(Calendar instance) {
int index = instance.get(Calendar.DAY_OF_WEEK); int index = instance.get(Calendar.DAY_OF_WEEK);
index = (index + 1) % 7; index = (index + 1) % 7;
return String.valueOf(index); return String.valueOf(index);
} }
public void removeTask(ScheduleManager scheduleManager, GlobalTaskEntity taskEntity) { public void removeTask(ScheduleManager scheduleManager, GlobalTaskEntity taskEntity) {
JobKey jobKey = new JobKey(taskEntity.getTaskId().toString()); JobKey jobKey = new JobKey(taskEntity.getTaskId().toString());
TriggerKey triggerKey = new TriggerKey(taskEntity.getTaskId().toString()); TriggerKey triggerKey = new TriggerKey(taskEntity.getTaskId().toString());
@ -95,14 +89,16 @@ public abstract class TaskHandler implements InitializingBean {
scheduleManager.fireNow(jobKey); scheduleManager.fireNow(jobKey);
} }
// 判断任务是否过期
//判断任务是否过期
public Boolean taskExpire(Long endTime) { public Boolean taskExpire(Long endTime) {
if (ObjectUtils.isEmpty(endTime)) return false; if (ObjectUtils.isEmpty(endTime))
return false;
Long now = System.currentTimeMillis(); Long now = System.currentTimeMillis();
return now > endTime; return now > endTime;
} }
protected abstract Boolean taskIsRunning(Long taskId);
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
String beanName = null; 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.AuthUserService;
import io.dataease.auth.service.impl.AuthUserServiceImpl; import io.dataease.auth.service.impl.AuthUserServiceImpl;
import io.dataease.auth.util.JWTUtils; import io.dataease.auth.util.JWTUtils;
import io.dataease.base.mapper.ext.ExtTaskMapper;
import io.dataease.commons.utils.CommonBeanFactory; import io.dataease.commons.utils.CommonBeanFactory;
import io.dataease.commons.utils.LogUtil; import io.dataease.commons.utils.LogUtil;
import io.dataease.commons.utils.ServletUtils; 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.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.quartz.*; import org.quartz.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -46,6 +48,16 @@ public class EmailTaskHandler extends TaskHandler implements Job {
return jobDataMap; 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 @Override
public void execute(JobExecutionContext context) throws JobExecutionException { public void execute(JobExecutionContext context) throws JobExecutionException {
// 插件没有加载 空转 // 插件没有加载 空转
@ -54,11 +66,16 @@ public class EmailTaskHandler extends TaskHandler implements Job {
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
GlobalTaskEntity taskEntity = (GlobalTaskEntity) jobDataMap.get("taskEntity"); GlobalTaskEntity taskEntity = (GlobalTaskEntity) jobDataMap.get("taskEntity");
ScheduleManager scheduleManager = SpringContextUtil.getBean(ScheduleManager.class);
if (taskExpire(taskEntity.getEndTime())) { if (taskExpire(taskEntity.getEndTime())) {
ScheduleManager scheduleManager = SpringContextUtil.getBean(ScheduleManager.class);
removeTask(scheduleManager, taskEntity); removeTask(scheduleManager, taskEntity);
return; return;
} }
if (taskIsRunning(taskEntity.getTaskId())) {
LogUtil.info("Skip synchronization task: {} ,due to task status is {}",
taskEntity.getTaskId(), "running");
return;
}
GlobalTaskInstance taskInstance = buildInstance(taskEntity); GlobalTaskInstance taskInstance = buildInstance(taskEntity);
Long instanceId = saveInstance(taskInstance); Long instanceId = saveInstance(taskInstance);
@ -67,10 +84,15 @@ public class EmailTaskHandler extends TaskHandler implements Job {
XpackEmailTemplateDTO emailTemplate = (XpackEmailTemplateDTO) jobDataMap.get("emailTemplate"); XpackEmailTemplateDTO emailTemplate = (XpackEmailTemplateDTO) jobDataMap.get("emailTemplate");
SysUserEntity creator = (SysUserEntity) jobDataMap.get("creator"); SysUserEntity creator = (SysUserEntity) jobDataMap.get("creator");
LogUtil.info("start execute send panel report task..."); 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) { public Long saveInstance(GlobalTaskInstance taskInstance) {
EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class); EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class);
@ -99,11 +121,12 @@ public class EmailTaskHandler extends TaskHandler implements Job {
emailXpackService.saveInstance(taskInstance); emailXpackService.saveInstance(taskInstance);
} }
@Async("priorityExecutor")
public void sendReport(GlobalTaskInstance taskInstance, XpackEmailTemplateDTO emailTemplateDTO, public void sendReport(GlobalTaskInstance taskInstance, XpackEmailTemplateDTO emailTemplateDTO,
SysUserEntity user) { SysUserEntity user) {
EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class); EmailXpackService emailXpackService = SpringContextUtil.getBean(EmailXpackService.class);
try { try {
String panelId = emailTemplateDTO.getPanelId(); String panelId = emailTemplateDTO.getPanelId();
String url = panelUrl(panelId); String url = panelUrl(panelId);
String token = tokenByUser(user); String token = tokenByUser(user);
@ -116,11 +139,15 @@ public class EmailTaskHandler extends TaskHandler implements Job {
String recipients = emailTemplateDTO.getRecipients(); String recipients = emailTemplateDTO.getRecipients();
byte[] content = emailTemplateDTO.getContent(); byte[] content = emailTemplateDTO.getContent();
EmailService emailService = SpringContextUtil.getBean(EmailService.class); EmailService emailService = SpringContextUtil.getBean(EmailService.class);
String contentStr = ""; String contentStr = "";
if (ObjectUtils.isNotEmpty(content)) { if (ObjectUtils.isNotEmpty(content)) {
contentStr = new String(content, "UTF-8"); 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); success(taskInstance);
} catch (Exception e) { } catch (Exception e) {
error(taskInstance, e); error(taskInstance, e);

View File

@ -32,6 +32,7 @@ public class GlobalTaskStartListener implements ApplicationListener<ApplicationR
tasks.stream().forEach(task -> { tasks.stream().forEach(task -> {
TaskHandler taskHandler = TaskStrategyFactory.getInvokeStrategy(task.getTaskType()); TaskHandler taskHandler = TaskStrategyFactory.getInvokeStrategy(task.getTaskType());
try { try {
taskHandler.resetRunningInstance(task.getTaskId());
taskHandler.addTask(scheduleManager, task); taskHandler.addTask(scheduleManager, task);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); 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.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; 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.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; 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.config.SpringContextUtil;
import io.dataease.plugins.xpack.theme.dto.ThemeDto; import io.dataease.plugins.xpack.theme.dto.ThemeDto;
import io.dataease.plugins.xpack.theme.dto.ThemeItem; import io.dataease.plugins.xpack.theme.dto.ThemeItem;
@ -20,10 +21,8 @@ import io.dataease.plugins.xpack.theme.service.ThemeXpackService;
@RestController @RestController
public class ThemeServer { public class ThemeServer {
@PostMapping("/themes") @PostMapping("/themes")
public List<ThemeDto> themes(){ public List<ThemeDto> themes() {
ThemeXpackService themeXpackService = SpringContextUtil.getBean(ThemeXpackService.class); ThemeXpackService themeXpackService = SpringContextUtil.getBean(ThemeXpackService.class);
return themeXpackService.themes(); return themeXpackService.themes();
@ -36,15 +35,22 @@ public class ThemeServer {
} }
@PostMapping("/save") @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 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}") @PostMapping("/delete/{themeId}")
public void save(@PathVariable("themeId") int themeId) { public void delete(@PathVariable("themeId") int themeId) {
ThemeXpackService themeXpackService = SpringContextUtil.getBean(ThemeXpackService.class); ThemeXpackService themeXpackService = SpringContextUtil.getBean(ThemeXpackService.class);
themeXpackService.deleteTheme(themeId); themeXpackService.deleteTheme(themeId);
} }
} }

View File

@ -3,6 +3,7 @@ package io.dataease.plugins.server;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import io.dataease.commons.exception.DEException; import io.dataease.commons.exception.DEException;
import io.dataease.commons.pool.PriorityThreadPoolExecutor;
import io.dataease.commons.utils.*; import io.dataease.commons.utils.*;
import io.dataease.plugins.common.entity.GlobalTaskEntity; import io.dataease.plugins.common.entity.GlobalTaskEntity;
import io.dataease.plugins.common.entity.GlobalTaskInstance; 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 org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
import java.util.concurrent.Future;
import javax.annotation.Resource;
@Api(tags = "xpack定时报告") @Api(tags = "xpack定时报告")
@RequestMapping("/plugin/task") @RequestMapping("/plugin/task")
@ -32,6 +36,9 @@ public class XEmailTaskServer {
@Autowired @Autowired
private ScheduleService scheduleService; private ScheduleService scheduleService;
@Resource
private PriorityThreadPoolExecutor priorityExecutor;
@PostMapping("/queryTasks/{goPage}/{pageSize}") @PostMapping("/queryTasks/{goPage}/{pageSize}")
public Pager<List<XpackTaskGridDTO>> queryTask(@PathVariable int goPage, @PathVariable int pageSize, public Pager<List<XpackTaskGridDTO>> queryTask(@PathVariable int goPage, @PathVariable int pageSize,
@RequestBody XpackGridRequest request) { @RequestBody XpackGridRequest request) {
@ -85,7 +92,19 @@ public class XEmailTaskServer {
String token = ServletUtils.getToken(); String token = ServletUtils.getToken();
String fileId = null; String fileId = null;
try { 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) { } catch (Exception e) {
LogUtil.error(e.getMessage(), e); LogUtil.error(e.getMessage(), e);
DEException.throwException("预览失败,请联系管理员"); 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 '权限', `permissions` longtext DEFAULT NULL COMMENT '权限',
`update_time` bigint(13) NULL DEFAULT NULL, `update_time` bigint(13) NULL DEFAULT NULL,
PRIMARY KEY (`id`) 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 角色表单=Role Form
重置密码=Reset Password 重置密码=Reset Password
关于=About Us 关于=About Us
首页=Home Page
i18n_auth_view=View i18n_auth_view=View
i18n_auth_use=Use i18n_auth_use=Use
i18n_auth_export=Export i18n_auth_export=Export

View File

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

View File

@ -225,6 +225,7 @@ authsource_configuration_is_null=認證源配置不能為空
角色表单=角色表單 角色表单=角色表單
重置密码=重置密碼 重置密码=重置密碼
关于=關於 关于=關於
首页=首頁
i18n_auth_view=查看 i18n_auth_view=查看
i18n_auth_use=使用 i18n_auth_use=使用
i18n_auth_export=導出 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) { export function validateUserName(data) {
return request({ return request({
url: '/api/auth/validateName', 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 return this.$store.state.curComponent
}, },
curGap() { 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([ ...mapState([
'editor', 'editor',

View File

@ -1,5 +1,6 @@
<template> <template>
<div class="bar-main"> <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"> <div v-if="linkageAreaShow" style="margin-right: -1px;width: 18px">
<el-checkbox v-model="linkageInfo.linkageActive" /> <el-checkbox v-model="linkageInfo.linkageActive" />
<linkage-field v-if="linkageInfo.linkageActive" :element="element" /> <linkage-field v-if="linkageInfo.linkageActive" :element="element" />
@ -25,6 +26,9 @@
<span :title="$t('panel.cancel_linkage')"> <span :title="$t('panel.cancel_linkage')">
<i v-if="curComponent.type==='view'&&existLinkage" class="icon iconfont icon-quxiaoliandong" @click.stop="clearLinkage" /> <i v-if="curComponent.type==='view'&&existLinkage" class="icon iconfont icon-quxiaoliandong" @click.stop="clearLinkage" />
</span> </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>
</div> </div>
</template> </template>
@ -34,6 +38,7 @@ import { mapState } from 'vuex'
import bus from '@/utils/bus' import bus from '@/utils/bus'
import SettingMenu from '@/components/canvas/components/Editor/SettingMenu' import SettingMenu from '@/components/canvas/components/Editor/SettingMenu'
import LinkageField from '@/components/canvas/components/Editor/LinkageField' import LinkageField from '@/components/canvas/components/Editor/LinkageField'
import toast from '@/components/canvas/utils/toast'
export default { export default {
components: { SettingMenu, LinkageField }, components: { SettingMenu, LinkageField },
@ -207,6 +212,24 @@ export default {
}, },
linkJumpSet() { linkJumpSet() {
this.$emit('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 HYPERLINKS
} from '@/components/canvas/custom-component/component-list' } from '@/components/canvas/custom-component/component-list'
import {
ApplicationContext
} from '@/utils/ApplicationContext'
export function deepCopy(target) { export function deepCopy(target) {
if (typeof target === 'object') { if (typeof target === 'object') {
const result = Array.isArray(target) ? [] : {} const result = Array.isArray(target) ? [] : {}
@ -62,28 +66,17 @@ export function mobile2MainCanvas(mainSource, mobileSource) {
export function panelInit(componentDatas) { export function panelInit(componentDatas) {
componentDatas.forEach(item => { componentDatas.forEach(item => {
if (item.component && item.component === 'de-date') { if (item.component && item.component === 'de-date') {
if (item.serviceName === 'timeDateWidget' && item.options.attrs && !item.options.attrs.default) { if (item.options.attrs &&
item.options.attrs.default = { (!item.options.attrs.default || (item.serviceName === 'timeYearWidget' && item.options.attrs.default.dynamicInfill !== 'year') || (item.serviceName === 'timeMonthWidget' && item.options.attrs.default.dynamicInfill !== 'month'))) {
isDynamic: false, const widget = ApplicationContext.getService(item.serviceName)
dkey: 0, if (widget && widget.defaultSetting) {
dynamicPrefix: 1, item.options.attrs.default = widget.defaultSetting()
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.type === 'custom') {
item.options.manualModify = false
}
if (item.filters && item.filters.length > 0) { if (item.filters && item.filters.length > 0) {
item.filters = [] item.filters = []
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -38,6 +38,7 @@
<script> <script>
import { multFieldValues, linkMultFieldValues } from '@/api/dataset/dataset' import { multFieldValues, linkMultFieldValues } from '@/api/dataset/dataset'
import { getLinkToken, getToken } from '@/utils/auth' import { getLinkToken, getToken } from '@/utils/auth'
import bus from '@/utils/bus'
export default { export default {
props: { props: {
@ -89,6 +90,9 @@ export default {
viewIds() { viewIds() {
if (!this.element || !this.element.options || !this.element.options.attrs.viewIds) return '' if (!this.element || !this.element.options || !this.element.options.attrs.viewIds) return ''
return this.element.options.attrs.viewIds.toString() return this.element.options.attrs.viewIds.toString()
},
manualModify() {
return !!this.element.options.manualModify
} }
}, },
watch: { watch: {
@ -137,6 +141,19 @@ export default {
created() { created() {
this.initLoad() 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: { methods: {
initLoad() { initLoad() {
@ -168,6 +185,9 @@ export default {
} else { } else {
this.element.options.value = Array.isArray(value) ? value.join() : value this.element.options.value = Array.isArray(value) ? value.join() : value
} }
this.element.options.manualModify = false
} else {
this.element.options.manualModify = true
} }
this.setCondition() this.setCondition()
this.styleChange() this.styleChange()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,10 +21,27 @@ const dialogPanel = {
dkey: 0, dkey: 0,
dynamicPrefix: 1, dynamicPrefix: 1,
dynamicInfill: 'day', 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', defaultClass: 'time-filter',
component: 'de-date' component: 'de-date'
@ -75,6 +92,9 @@ class TimeDateServiceImpl extends WidgetService {
return field['deType'] === 1 return field['deType'] === 1
}) })
} }
defaultSetting() {
return dialogPanel.options.attrs.default
}
dynamicDateFormNow(element) { dynamicDateFormNow(element) {
if (element.options.attrs.default === null || typeof element.options.attrs.default === 'undefined' || !element.options.attrs.default.isDynamic) return null 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', placeholder: 'deyearmonth.placeholder',
viewIds: [], viewIds: [],
fieldId: '', 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', defaultClass: 'time-filter',
component: 'de-date' component: 'de-date'
@ -64,6 +85,38 @@ class TimeMonthServiceImpl extends WidgetService {
return field['deType'] === 1 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() const timeMonthServiceImpl = new TimeMonthServiceImpl()
export default timeMonthServiceImpl export default timeMonthServiceImpl

View File

@ -13,9 +13,29 @@ const dialogPanel = {
placeholder: 'deyear.placeholder', placeholder: 'deyear.placeholder',
viewIds: [], viewIds: [],
fieldId: '', 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', defaultClass: 'time-filter',
component: 'de-date' component: 'de-date'
@ -65,6 +85,29 @@ class TimeYearServiceImpl extends WidgetService {
return field['deType'] === 1 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() const timeYearServiceImpl = new TimeYearServiceImpl()
export default timeYearServiceImpl export default timeYearServiceImpl

View File

@ -131,6 +131,9 @@ export default {
default_login: 'Normal' default_login: 'Normal'
}, },
commons: { commons: {
first_login_tips: 'Please change the initial password',
roger_that: 'Roger That',
apply: 'Apply',
search: 'Search', search: 'Search',
folder: 'Folder', folder: 'Folder',
no_target_permission: 'No permission', no_target_permission: 'No permission',
@ -437,7 +440,10 @@ export default {
background: 'Background color', background: 'Background color',
custom: 'Custom color', custom: 'Custom color',
otherSave: 'Theme Save as', 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: { tagsView: {
refresh: 'Refresh', refresh: 'Refresh',
@ -455,7 +461,8 @@ export default {
sysParams: { sysParams: {
display: 'Display Setting', display: 'Display Setting',
ldap: 'LDAP Setting', ldap: 'LDAP Setting',
oidc: 'OIDC Setting' oidc: 'OIDC Setting',
theme: 'Theme Setting'
}, },
license: { license: {
i18n_no_license_record: 'No License Record', i18n_no_license_record: 'No License Record',
@ -1443,6 +1450,7 @@ export default {
linkage: 'linkage', linkage: 'linkage',
jump: 'Jump', jump: 'Jump',
cancel_linkage: 'Cancel Linkage', cancel_linkage: 'Cancel Linkage',
switch_picture: 'Switch Picture',
remove_all_linkage: 'Remove All Linkage', remove_all_linkage: 'Remove All Linkage',
exit_un_march_linkage_field: 'Exit Un March Linkage Field', exit_un_march_linkage_field: 'Exit Un March Linkage Field',
details: 'Details', details: 'Details',
@ -1519,7 +1527,9 @@ export default {
themeLight: 'Light', themeLight: 'Light',
themeDark: 'Dark', themeDark: 'Dark',
themeCustom: 'Custom' themeCustom: 'Custom',
openHomePage: 'Show Home Page'
}, },
auth: { auth: {
authConfig: 'Auth Config', authConfig: 'Auth Config',
@ -1771,6 +1781,40 @@ export default {
cweek: 'This Week', cweek: 'This Week',
cmonth: 'This Month', cmonth: 'This Month',
cquarter: 'This Quarter', 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: '普通登錄' default_login: '普通登錄'
}, },
commons: { commons: {
first_login_tips: '您使用的是初始密碼,記得修改密碼哦',
roger_that: '知道了',
apply: '應用',
search: '搜索', search: '搜索',
folder: '目錄', folder: '目錄',
no_target_permission: '沒有權限', no_target_permission: '沒有權限',
@ -437,7 +440,10 @@ export default {
background: '背景顏色', background: '背景顏色',
custom: '自定義顏色', custom: '自定義顏色',
otherSave: '主題另存為', otherSave: '主題另存為',
info: '主題信息' info: '主題信息',
add: '新增主題',
please_input_name: '請輸入名稱',
name_repeat: '名稱已存在'
}, },
tagsView: { tagsView: {
refresh: '刷新', refresh: '刷新',
@ -455,7 +461,8 @@ export default {
sysParams: { sysParams: {
display: '顯示設置', display: '顯示設置',
ldap: 'LDAP設置', ldap: 'LDAP設置',
oidc: 'OIDC設置' oidc: 'OIDC設置',
theme: '主题设置'
}, },
license: { license: {
i18n_no_license_record: '沒有 License 記錄', i18n_no_license_record: '沒有 License 記錄',
@ -1445,6 +1452,7 @@ export default {
linkage: '聯動', linkage: '聯動',
jump: '跳轉', jump: '跳轉',
cancel_linkage: '取消聯動', cancel_linkage: '取消聯動',
switch_picture: '更换图片',
remove_all_linkage: '清除所有聯動', remove_all_linkage: '清除所有聯動',
exit_un_march_linkage_field: '存在未匹配聯動關繫的字段', exit_un_march_linkage_field: '存在未匹配聯動關繫的字段',
details: '詳情', details: '詳情',
@ -1529,7 +1537,8 @@ export default {
themeLight: '淺色', themeLight: '淺色',
themeDark: '深色', themeDark: '深色',
themeCustom: '自定義' themeCustom: '自定義',
openHomePage: '显示首页'
}, },
auth: { auth: {
@ -1784,5 +1793,38 @@ export default {
cmonth: '本月', cmonth: '本月',
cquarter: '本季', cquarter: '本季',
cyear: '本年' 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: '普通登录' default_login: '普通登录'
}, },
commons: { commons: {
first_login_tips: '您使用的是初始密码,记得修改密码哦',
roger_that: '知道了',
apply: '应用',
search: '搜索', search: '搜索',
folder: '目录', folder: '目录',
no_target_permission: '没有权限', no_target_permission: '没有权限',
@ -438,7 +441,10 @@ export default {
background: '背景颜色', background: '背景颜色',
custom: '自定义颜色', custom: '自定义颜色',
otherSave: '主题另存为', otherSave: '主题另存为',
info: '主题信息' info: '主题信息',
add: '新增主题',
please_input_name: '请输入名称',
name_repeat: '名称已存在'
}, },
tagsView: { tagsView: {
refresh: '刷新', refresh: '刷新',
@ -1456,6 +1462,7 @@ export default {
linkage: '联动', linkage: '联动',
jump: '跳转', jump: '跳转',
cancel_linkage: '取消联动', cancel_linkage: '取消联动',
switch_picture: '更换图片',
remove_all_linkage: '清除所有联动', remove_all_linkage: '清除所有联动',
exit_un_march_linkage_field: '存在未匹配联动关系的字段', exit_un_march_linkage_field: '存在未匹配联动关系的字段',
details: '详情', details: '详情',
@ -1539,7 +1546,8 @@ export default {
themeLight: '浅色', themeLight: '浅色',
themeDark: '深色', themeDark: '深色',
themeCustom: '自定义' themeCustom: '自定义',
openHomePage: '显示首页'
}, },
auth: { auth: {
@ -1795,5 +1803,38 @@ export default {
cmonth: '本月', cmonth: '本月',
cquarter: '本季', cquarter: '本季',
cyear: '本年' 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"> <div v-for="item in permission_routes" :key="item.path" class="nav-item">
<app-link :to="resolvePath(item)"> <app-link :to="resolvePath(item)">
<el-menu-item <el-menu-item v-if="!item.hidden" :index="item.path">
v-if="!item.hidden" {{ item.meta ? item.meta.title : item.children[0].meta.title }}</el-menu-item>
:index="item.path"
>{{ item.meta ? item.meta.title : item.children[0].meta.title }}</el-menu-item>
</app-link> </app-link>
</div> </div>
</el-menu> </el-menu>
@ -28,13 +26,22 @@
<notification class="right-menu-item hover-effect" /> <notification class="right-menu-item hover-effect" />
<lang-select 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"> <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" /> <svg-icon icon-class="docs" />
</a> </a>
</div> </div>
</template> </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%;"> <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> <span style="max-width:80px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;">{{ name }}</span>
@ -62,21 +69,32 @@
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { mapGetters } from 'vuex' import {
mapGetters
} from 'vuex'
import AppLink from './Sidebar/Link' import AppLink from './Sidebar/Link'
import variables from '@/styles/variables.scss' import variables from '@/styles/variables.scss'
import { isExternal } from '@/utils/validate' import {
isExternal
} from '@/utils/validate'
import Notification from '@/components/Notification' import Notification from '@/components/Notification'
import bus from '@/utils/bus' import bus from '@/utils/bus'
import LangSelect from '@/components/LangSelect' import LangSelect from '@/components/LangSelect'
import { getSysUI } from '@/utils/auth' import {
import { pluginLoaded } from '@/api/user' getSysUI
import { initTheme } from '@/utils/ThemeUtil' } from '@/utils/auth'
import {
pluginLoaded
} from '@/api/user'
import {
initTheme
} from '@/utils/ThemeUtil'
export default { export default {
name: 'Topbar', name: 'Topbar',
components: { components: {
@ -85,6 +103,12 @@ export default {
LangSelect LangSelect
}, },
props: {
showTips: {
type: Boolean,
default: false
}
},
data() { data() {
return { return {
uiInfo: null, uiInfo: null,
@ -100,27 +124,42 @@ export default {
}, },
topMenuColor() { 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 return this.variables.topBarBg
}, },
topMenuActiveColor() { 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 return this.variables.topBarMenuActive
}, },
topMenuTextColor() { 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 return this.variables.topBarMenuText
}, },
topMenuTextActiveColor() { 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 return this.variables.topBarMenuTextActive
}, },
/* topMenuColor() { /* topMenuColor() {
return this.$store.getters.uiInfo.topMenuColor return this.$store.getters.uiInfo.topMenuColor
}, */ }, */
activeMenu() { activeMenu() {
const route = this.$route const route = this.$route
const { meta, path } = route const {
meta,
path
} = route
// if set path, the sidebar will highlight the path you set // if set path, the sidebar will highlight the path you set
if (meta.activeMenu) { if (meta.activeMenu) {
// return meta.activeMenu // return meta.activeMenu
@ -152,6 +191,10 @@ export default {
bus.$on('set-top-menu-active-info', this.setTopMenuActiveInfo) bus.$on('set-top-menu-active-info', this.setTopMenuActiveInfo)
bus.$on('set-top-text-info', this.setTopTextInfo) bus.$on('set-top-text-info', this.setTopTextInfo)
bus.$on('set-top-text-active-info', this.setTopTextActiveInfo) 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() { created() {
this.loadUiInfo() this.loadUiInfo()
@ -159,13 +202,17 @@ export default {
beforeCreate() { beforeCreate() {
pluginLoaded().then(res => { pluginLoaded().then(res => {
this.isPluginLoaded = res.success && res.data this.isPluginLoaded = res.success && res.data
if (this.isPluginLoaded) { initTheme() } if (this.isPluginLoaded) {
initTheme()
}
}) })
}, },
methods: { methods: {
// store // store
initCurrentRoutes() { initCurrentRoutes() {
const { path } = this.$route const {
path
} = this.$route
let route = this.permission_routes.find( let route = this.permission_routes.find(
item => item.path === '/' + path.split('/')[1] item => item.path === '/' + path.split('/')[1]
) )
@ -197,9 +244,9 @@ export default {
// //
let path = '' let path = ''
/** /**
* item 路由子项 * item 路由子项
* parent 路由父项 * parent 路由父项
*/ */
const getDefaultPath = (item, parent) => { const getDefaultPath = (item, parent) => {
// path // path
if (isExternal(item.path)) { if (isExternal(item.path)) {
@ -233,7 +280,7 @@ export default {
}, },
// //
setSidebarHide(route) { 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)) { if (route.name !== 'system' && (!route.children || this.showChildLength(route) === 1)) {
this.$store.dispatch('app/toggleSideBarHide', true) this.$store.dispatch('app/toggleSideBarHide', true)
} else { } else {
@ -266,12 +313,12 @@ export default {
} }
/* if (this.uiInfo['ui.themeStr'] && this.uiInfo['ui.themeStr'].paramValue) { /* if (this.uiInfo['ui.themeStr'] && this.uiInfo['ui.themeStr'].paramValue) {
if (this.uiInfo['ui.themeStr'].paramValue === 'dark') { if (this.uiInfo['ui.themeStr'].paramValue === 'dark') {
document.body.className = 'blackTheme' document.body.className = 'blackTheme'
} else if (this.uiInfo['ui.themeStr'].paramValue === 'light') { } else if (this.uiInfo['ui.themeStr'].paramValue === 'light') {
document.body.className = '' document.body.className = ''
} }
} */ } */
this.axiosFinished = true this.axiosFinished = true
}) })
}, },
@ -291,12 +338,14 @@ export default {
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.el-dropdown-link { .el-dropdown-link {
cursor: pointer; cursor: pointer;
color: #1e212a; color: #1e212a;
} }
.el-icon-arrow-down { .el-icon-arrow-down {
font-size: 12px; font-size: 12px;
} }
@ -312,7 +361,8 @@ export default {
} }
.de-top-menu { .de-top-menu {
background-color: var(--MainBG); background-color: var(--MainBG);
} }
</style> </style>

View File

@ -1,7 +1,7 @@
<template> <template>
<div :class="classObj" class="app-wrapper"> <div :class="classObj" class="app-wrapper">
<licbar /> <licbar />
<topbar v-if="!fullHeightFlag" /> <topbar v-if="!fullHeightFlag && finishLoad" :show-tips="showTips" />
<de-container :style="mainStyle"> <de-container :style="mainStyle">
<de-aside-container v-if="!sidebar.hide" class="le-aside-container"> <de-aside-container v-if="!sidebar.hide" class="le-aside-container">
@ -12,6 +12,14 @@
<app-main /> <app-main />
</de-main-container> </de-main-container>
</de-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> </div>
</template> </template>
@ -23,6 +31,8 @@ import DeContainer from '@/components/dataease/DeContainer'
import DeAsideContainer from '@/components/dataease/DeAsideContainer' import DeAsideContainer from '@/components/dataease/DeAsideContainer'
import bus from '@/utils/bus' import bus from '@/utils/bus'
import { needModifyPwd } from '@/api/user'
export default { export default {
name: 'Layout', name: 'Layout',
components: { components: {
@ -37,7 +47,9 @@ export default {
mixins: [ResizeMixin], mixins: [ResizeMixin],
data() { data() {
return { return {
componentName: 'PanelMain' componentName: 'PanelMain',
showTips: false,
finishLoad: false
} }
}, },
computed: { 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() { mounted() {
bus.$on('PanelSwitchComponent', (c) => { bus.$on('PanelSwitchComponent', (c) => {
this.componentName = c.name this.componentName = c.name
@ -94,6 +114,8 @@ export default {
@import "~@/styles/variables.scss"; @import "~@/styles/variables.scss";
.app-wrapper { .app-wrapper {
min-width: 1000px!important;
min-height: 600px!important;
@include clearfix; @include clearfix;
position: relative; position: relative;
height: 100%; 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> </style>

View File

@ -16,6 +16,7 @@ import {
import { import {
isMobile isMobile
} from '@/utils/index' } from '@/utils/index'
import Layout from '@/layout/index'
// import bus from './utils/bus' // import bus from './utils/bus'
NProgress.configure({ NProgress.configure({
@ -97,6 +98,23 @@ export const loadMenus = (next, to) => {
const datas = res.data const datas = res.data
const filterDatas = filterRouter(datas) const filterDatas = filterRouter(datas)
const asyncRouter = filterAsyncRouter(filterDatas) 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({ asyncRouter.push({
path: '*', path: '*',
redirect: '/404', redirect: '/404',

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 2459092 */ font-family: "iconfont"; /* Project id 2459092 */
src: url('iconfont.woff2?t=1639622225820') format('woff2'), src: url('iconfont.woff2?t=1642061879222') format('woff2'),
url('iconfont.woff?t=1639622225820') format('woff'), url('iconfont.woff?t=1642061879222') format('woff'),
url('iconfont.ttf?t=1639622225820') format('truetype'); url('iconfont.ttf?t=1642061879222') format('truetype');
} }
.iconfont { .iconfont {
@ -13,6 +13,22 @@
-moz-osx-font-smoothing: grayscale; -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 { .icon-guanbi:before {
content: "\e60d"; content: "\e60d";
} }

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,34 @@
"css_prefix_text": "icon-", "css_prefix_text": "icon-",
"description": "", "description": "",
"glyphs": [ "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", "icon_id": "1367318",
"name": "关闭", "name": "关闭",

View File

@ -534,14 +534,7 @@ div:focus {
color: var(--Main) !important; 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 { .blackTheme .title-text {
color: var(--TextPrimary) !important; color: var(--TextPrimary) !important;
@ -663,9 +656,7 @@ div:focus {
background: #38393a !important; background: #38393a !important;
} }
.blackTheme .el-message-box__content {
color: #F2F6FC;
}
.blackTheme .el-message-box__btns { .blackTheme .el-message-box__btns {
.el-button--default:not(.el-button--primary) { .el-button--default:not(.el-button--primary) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -128,9 +128,6 @@
</el-form> </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 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-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-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" /> <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>
<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 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-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-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" /> <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-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-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>
<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-form>
</el-col> </el-col>
</div> </div>

View File

@ -196,9 +196,9 @@
:options="chartGroupTreeAvailable" :options="chartGroupTreeAvailable"
:normalizer="normalizer" :normalizer="normalizer"
:placeholder="$t('chart.select_group')" :placeholder="$t('chart.select_group')"
:noChildrenText="$t('commons.treeselect.no_children_text')" :no-children-text="$t('commons.treeselect.no_children_text')"
:noOptionsText="$t('commons.treeselect.no_options_text')" :no-options-text="$t('commons.treeselect.no_options_text')"
:noResultsText="$t('commons.treeselect.no_results_text')" :no-results-text="$t('commons.treeselect.no_results_text')"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -558,7 +558,7 @@ export default {
showClose: true showClose: true
}) })
this.treeNode() this.treeNode()
this.$store.dispatch('chart/setTable', null) this.$store.dispatch('chart/setTable', new Date().getTime())
}) })
} else { } else {
// this.$message({ // this.$message({
@ -773,6 +773,7 @@ export default {
view.customFilter = JSON.stringify([]) view.customFilter = JSON.stringify([])
view.drillFields = JSON.stringify([]) view.drillFields = JSON.stringify([])
view.extBubble = JSON.stringify([]) view.extBubble = JSON.stringify([])
this.setChartDefaultOptions(view)
const _this = this const _this = this
post('/chart/view/save', view).then(response => { post('/chart/view/save', view).then(response => {
this.closeCreateChart() 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) { getTable(table) {
this.table = JSON.parse(JSON.stringify(table)) this.table = JSON.parse(JSON.stringify(table))
}, },

View File

@ -1,6 +1,7 @@
<template> <template>
<el-row v-loading="loading" style="height: 100%;overflow-y: hidden;width: 100%;"> <el-row v-loading="loading" style="height: 100%;overflow-y: hidden;width: 100%;">
<el-row style="height: 40px;" class="padding-lr"> <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> <span class="title-text" style="line-height: 40px;">{{ view.name }}</span>
<el-popover <el-popover
placement="right-start" placement="right-start"
@ -141,7 +142,7 @@
class="render-select" class="render-select"
style="width: 100px" style="width: 100px"
size="mini" size="mini"
@change="calcData(true,'chart',true,true)" @change="changeChartType()"
> >
<el-option <el-option
v-for="item in renderOptions" v-for="item in renderOptions"
@ -158,7 +159,7 @@
v-model="view.type" v-model="view.type"
style="width: 100%" style="width: 100%"
:disabled="!hasDataPermission('manage',param.privileges)" :disabled="!hasDataPermission('manage',param.privileges)"
@change="calcData(true,'chart',true,true)" @change="changeChartType()"
> >
<chart-type :chart="view" style="height: 480px" /> <chart-type :chart="view" style="height: 480px" />
</el-radio-group> </el-radio-group>
@ -1105,11 +1106,10 @@ export default {
} }
}, },
computed: { computed: {
// vId() { refreshPage: function() {
// // console.log(this.$store.state.chart.viewId); this.getChart(this.param.id)
// this.getData(this.$store.state.chart.viewId) return this.$store.getters.chartTable
// return this.$store.state.chart.viewId },
// }
chartType() { chartType() {
return this.chart.type return this.chart.type
} }
@ -2066,6 +2066,36 @@ export default {
reset() { reset() {
this.getData(this.param.id) 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> <template>
<el-row style="height: 100%;overflow-y: hidden;width: 100%;"> <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;"> <el-row style="height: 26px;">
<span class="title-text" style="line-height: 26px;"> <span class="title-text" style="line-height: 26px;">
{{ table.name }} {{ table.name }}
@ -57,7 +57,7 @@
<update-info v-if="tabActive=='updateInfo'" :param="param" :table="table" /> <update-info v-if="tabActive=='updateInfo'" :param="param" :table="table" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane v-if="isPluginLoaded && hasDataPermission('manage',param.privileges)" :lazy="true" :label="$t('dataset.row_permissions')" name="rowPermissions"> <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>
<el-tab-pane v-if="isPluginLoaded && hasDataPermission('manage',param.privileges)" :lazy="true" :label="$t('dataset.column_permissions')" name="columnPermissions"> <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" /> <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 { export default {
name: 'ViewTable', name: 'ViewTable',
components: {FieldEdit, UnionView, DatasetChartDetail, UpdateInfo, TabDataPreview, PluginCom }, components: { FieldEdit, UnionView, DatasetChartDetail, UpdateInfo, TabDataPreview, PluginCom },
props: { props: {
param: { param: {
type: Object, type: Object,
@ -105,14 +105,13 @@ export default {
isPluginLoaded: false isPluginLoaded: false
} }
}, },
beforeCreate() {
pluginLoaded().then(res => {
this.isPluginLoaded = res.success && res.data
})
},
computed: { computed: {
hideCustomDs: function() { hideCustomDs: function() {
return this.$store.getters.hideCustomDs return this.$store.getters.hideCustomDs
},
refreshPage: function() {
this.initTable(this.param.id)
return this.$store.getters.table
} }
}, },
watch: { watch: {
@ -121,6 +120,11 @@ export default {
this.initTable(this.param.id) this.initTable(this.param.id)
} }
}, },
beforeCreate() {
pluginLoaded().then(res => {
this.isPluginLoaded = res.success && res.data
})
},
created() { created() {
}, },

View File

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

View File

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

View File

@ -213,6 +213,7 @@ export default {
const time = widget.dynamicDateFormNow(this.element) const time = widget.dynamicDateFormNow(this.element)
this.dval = time this.dval = time
bus.$emit('valid-values-change', (!time || time.length === 0 || time[1] > time[0])) 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"> <el-col :span="24">
<div class="filter-content"> <div class="filter-content">
<el-card <el-card
v-if="element.serviceName && element.serviceName !== 'timeDateWidget' && element.serviceName !== 'timeDateRangeWidget'" v-if="element.component && element.component !== 'de-date'"
class="box-card" class="box-card"
> >
<div style="margin-bottom: 10px;"> <div style="margin-bottom: 10px;">
<span>默认值设置</span> <span>{{ $t('dynamic_time.set_default') }}</span>
</div> </div>
<div class="custom-component-class"> <div class="custom-component-class">
<component <component
@ -22,13 +22,13 @@
</el-card> </el-card>
<el-card v-if="element.serviceName && element.serviceName === 'timeDateWidget'" class="box-card"> <el-card v-if="element.component && element.component === 'de-date' && element.serviceName && element.serviceName !== 'timeDateRangeWidget'" class="box-card">
<de-date-default v-if="element.serviceName && element.serviceName === 'timeDateWidget'" :element="element" /> <de-date-default v-if="element.component === 'de-date' && element.serviceName !== 'timeDateRangeWidget'" :element="element" />
</el-card> </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 <de-date-range-default
v-if="element.serviceName && element.serviceName === 'timeDateRangeWidget'" v-if="element.component === 'de-date' && element.serviceName === 'timeDateRangeWidget'"
:element="element" :element="element"
/> />
</el-card> </el-card>

View File

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