commit
4ac653bc58
65 changed files with 9126 additions and 0 deletions
@ -0,0 +1,7 @@ |
|||||||
|
/.classpath |
||||||
|
/.project |
||||||
|
/.settings |
||||||
|
/bin/ |
||||||
|
/logs |
||||||
|
/target |
||||||
|
/src/main/resources/static |
@ -0,0 +1,9 @@ |
|||||||
|
server.port=80 |
||||||
|
server.servlet.context-path=/ |
||||||
|
|
||||||
|
dev=on |
||||||
|
|
||||||
|
# mysql数据源配置 |
||||||
|
spring.datasource.url=jdbc:mysql://cluster3.xumy.vip:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true |
||||||
|
spring.datasource.username=root |
||||||
|
spring.datasource.password=123456 |
@ -0,0 +1,46 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<configuration debug="false"> |
||||||
|
|
||||||
|
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径--> |
||||||
|
<property name="LOG_HOME" value="D:/logs/cube" /> |
||||||
|
|
||||||
|
<!--控制台日志, 控制台输出 --> |
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> |
||||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
||||||
|
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符--> |
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> |
||||||
|
</encoder> |
||||||
|
</appender> |
||||||
|
|
||||||
|
<!--文件日志, 按照每天生成日志文件 --> |
||||||
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
||||||
|
<!--日志文件输出的文件名--> |
||||||
|
<FileNamePattern>${LOG_HOME}/admin-%d{yyyy-MM-dd}.log</FileNamePattern> |
||||||
|
<!--日志文件保留天数--> |
||||||
|
<MaxHistory>30</MaxHistory> |
||||||
|
</rollingPolicy> |
||||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
||||||
|
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> |
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> |
||||||
|
</encoder> |
||||||
|
<!--日志文件最大的大小--> |
||||||
|
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> |
||||||
|
<MaxFileSize>10MB</MaxFileSize> |
||||||
|
</triggeringPolicy> |
||||||
|
</appender> |
||||||
|
|
||||||
|
<logger name="vip.xumy" level="DEBUG"/> |
||||||
|
|
||||||
|
<!--myibatis log configure--> |
||||||
|
<logger name="com.apache.ibatis" level="TRACE"/> |
||||||
|
<logger name="java.sql.Connection" level="DEBUG"/> |
||||||
|
<logger name="java.sql.Statement" level="DEBUG"/> |
||||||
|
<logger name="java.sql.PreparedStatement" level="DEBUG"/> |
||||||
|
|
||||||
|
<!-- 日志输出级别 --> |
||||||
|
<root level="INFO"> |
||||||
|
<appender-ref ref="STDOUT" /> |
||||||
|
<appender-ref ref="FILE"/> |
||||||
|
</root> |
||||||
|
</configuration> |
@ -0,0 +1,99 @@ |
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
<parent> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-starter-parent</artifactId> |
||||||
|
<version>2.7.1</version> |
||||||
|
</parent> |
||||||
|
<groupId>vip.xumy.cube</groupId> |
||||||
|
<artifactId>xumy_cube</artifactId> |
||||||
|
<version>1.0.0</version> |
||||||
|
<name>xumy_cube</name> |
||||||
|
<description>data cube</description> |
||||||
|
<packaging>jar</packaging> |
||||||
|
|
||||||
|
<properties> |
||||||
|
<java.version>17</java.version> |
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> |
||||||
|
|
||||||
|
<core.version>1.0.0</core.version> |
||||||
|
<log4j.version>1.2.17</log4j.version> |
||||||
|
<fastjson.version>1.2.46</fastjson.version> |
||||||
|
<druid.version>1.1.9</druid.version> |
||||||
|
<mybatis-plus.version>3.5.1</mybatis-plus.version> |
||||||
|
<mybatis.pagehelper.version>1.4.6</mybatis.pagehelper.version> |
||||||
|
</properties> |
||||||
|
|
||||||
|
<dependencies> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>vip.xumy.core</groupId> |
||||||
|
<artifactId>xumy_core</artifactId> |
||||||
|
<version>${core.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<!-- 代码修改之后可以实时生效,该模块在完整的打包环境下运行的时候会被禁用 --> |
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-devtools</artifactId> |
||||||
|
<optional>true</optional> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> |
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-starter-web</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<!--junit 测试包--> |
||||||
|
<dependency> |
||||||
|
<groupId>org.junit.jupiter</groupId> |
||||||
|
<artifactId>junit-jupiter-api</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<!-- mysql驱动 --> |
||||||
|
<dependency> |
||||||
|
<groupId>mysql</groupId> |
||||||
|
<artifactId>mysql-connector-java</artifactId> |
||||||
|
<scope>runtime</scope> |
||||||
|
</dependency> |
||||||
|
<!-- alibaba的druid数据库连接池 --> |
||||||
|
<dependency> |
||||||
|
<groupId>com.alibaba</groupId> |
||||||
|
<artifactId>druid-spring-boot-starter</artifactId> |
||||||
|
<version>${druid.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<!-- mybatis plus--> |
||||||
|
<dependency> |
||||||
|
<groupId>com.baomidou</groupId> |
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId> |
||||||
|
<version>${mybatis-plus.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<!-- mybatis的pagehelper --> |
||||||
|
<dependency> |
||||||
|
<groupId>com.github.pagehelper</groupId> |
||||||
|
<artifactId>pagehelper-spring-boot-starter</artifactId> |
||||||
|
<version>${mybatis.pagehelper.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
</dependencies> |
||||||
|
|
||||||
|
<!-- Package as an executable jar --> |
||||||
|
<build> |
||||||
|
<finalName>dataCube</finalName> |
||||||
|
<plugins> |
||||||
|
<plugin> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId> |
||||||
|
<configuration> |
||||||
|
<executable>true</executable> |
||||||
|
</configuration> |
||||||
|
</plugin> |
||||||
|
</plugins> |
||||||
|
</build> |
||||||
|
|
||||||
|
</project> |
@ -0,0 +1,35 @@ |
|||||||
|
package vip.xumy.cube; |
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication; |
||||||
|
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.DbType; |
||||||
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; |
||||||
|
|
||||||
|
import vip.xumy.cube.conf.CubeRescueInitializer; |
||||||
|
|
||||||
|
|
||||||
|
public class CubeRescueApplocation extends SpringBootServletInitializer { |
||||||
|
|
||||||
|
public static void main(String[] args) { |
||||||
|
Class<?>[] arr = new Class<?>[] {CubeRescueInitializer.class}; |
||||||
|
SpringApplication.run(arr,args); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 分页插件 |
||||||
|
*/ |
||||||
|
@Bean |
||||||
|
public MybatisPlusInterceptor mybatisPlusInterceptor() { |
||||||
|
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); |
||||||
|
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); |
||||||
|
return interceptor; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,20 @@ |
|||||||
|
package vip.xumy.cube.conf; |
||||||
|
|
||||||
|
import org.mybatis.spring.annotation.MapperScan; |
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; |
||||||
|
import org.springframework.boot.builder.SpringApplicationBuilder; |
||||||
|
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
||||||
|
import org.springframework.context.annotation.ComponentScan; |
||||||
|
|
||||||
|
@EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class) |
||||||
|
@ComponentScan(value = "vip.xumy.cube, vip.xumy.core") |
||||||
|
@MapperScan({"vip.xumy.cube.mapper"}) |
||||||
|
public class CubeRescueInitializer extends SpringBootServletInitializer { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { |
||||||
|
return builder.sources(CubeRescueInitializer.class); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,91 @@ |
|||||||
|
package vip.xumy.cube.ctrl; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping; |
||||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||||
|
import org.springframework.web.bind.annotation.PathVariable; |
||||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||||
|
import org.springframework.web.bind.annotation.PutMapping; |
||||||
|
import org.springframework.web.bind.annotation.RequestBody; |
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
import com.github.pagehelper.Page; |
||||||
|
|
||||||
|
import vip.xumy.core.pojo.com.BaseResponse; |
||||||
|
import vip.xumy.core.pojo.com.PageResponse; |
||||||
|
import vip.xumy.cube.pojo.Cube4Mysql; |
||||||
|
import vip.xumy.cube.pojo.Dimension; |
||||||
|
import vip.xumy.cube.service.DataCubeService; |
||||||
|
|
||||||
|
/** |
||||||
|
* Ownership belongs to the company |
||||||
|
* |
||||||
|
* @author:mengyxu |
||||||
|
* @date:2023年3月10日 |
||||||
|
*/ |
||||||
|
|
||||||
|
@RestController |
||||||
|
@RequestMapping("cube") |
||||||
|
public class CubeController { |
||||||
|
@Autowired |
||||||
|
private DataCubeService cubeService; |
||||||
|
|
||||||
|
@GetMapping |
||||||
|
public BaseResponse list(Cube4Mysql example) { |
||||||
|
return new BaseResponse(cubeService.list(example)); |
||||||
|
} |
||||||
|
|
||||||
|
@GetMapping("{name}") |
||||||
|
public BaseResponse getCube(@PathVariable("name") String name) { |
||||||
|
return new BaseResponse(cubeService.get(name)); |
||||||
|
} |
||||||
|
|
||||||
|
@PostMapping |
||||||
|
public BaseResponse save(@RequestBody Cube4Mysql cube) { |
||||||
|
cubeService.save(cube); |
||||||
|
return new BaseResponse(true, "添加立方体成功!"); |
||||||
|
} |
||||||
|
|
||||||
|
@PostMapping("dimension") |
||||||
|
public BaseResponse saveDimesion(@RequestBody Dimension dimension) { |
||||||
|
cubeService.save(dimension); |
||||||
|
return new BaseResponse(true, "添加纬度成功!"); |
||||||
|
} |
||||||
|
|
||||||
|
@PutMapping("init") |
||||||
|
public BaseResponse initCube(@RequestBody String name) { |
||||||
|
cubeService.init(name); |
||||||
|
return new BaseResponse(true, "初始化立方体成功!"); |
||||||
|
} |
||||||
|
|
||||||
|
@PostMapping("assemble") |
||||||
|
public BaseResponse assembleCube(@RequestBody String name) { |
||||||
|
cubeService.assemble(name); |
||||||
|
return new BaseResponse(true, "构建任务提交成功!"); |
||||||
|
} |
||||||
|
|
||||||
|
@DeleteMapping |
||||||
|
public BaseResponse delete(String name) { |
||||||
|
cubeService.delete(name); |
||||||
|
return new BaseResponse(true, "删除立方体成功!"); |
||||||
|
} |
||||||
|
|
||||||
|
@DeleteMapping("dimension") |
||||||
|
public BaseResponse delete(Dimension dimension) { |
||||||
|
cubeService.delete(dimension); |
||||||
|
return new BaseResponse(true, "删除维度成功!"); |
||||||
|
} |
||||||
|
|
||||||
|
@PutMapping("select") |
||||||
|
public BaseResponse selectCube(@RequestBody Cube4Mysql cube) { |
||||||
|
Page<Object> page = cube.startPage(); |
||||||
|
List<Map<String, Object>> list = cubeService.select(cube); |
||||||
|
PageResponse<Map<String, Object>> result = new PageResponse<>(list, page.getTotal()); |
||||||
|
return new BaseResponse(result); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,79 @@ |
|||||||
|
package vip.xumy.cube.mapper; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Delete; |
||||||
|
import org.apache.ibatis.annotations.Insert; |
||||||
|
import org.apache.ibatis.annotations.Mapper; |
||||||
|
import org.apache.ibatis.annotations.Param; |
||||||
|
import org.apache.ibatis.annotations.Select; |
||||||
|
import org.apache.ibatis.annotations.Update; |
||||||
|
|
||||||
|
import vip.xumy.cube.pojo.Cube4Mysql; |
||||||
|
import vip.xumy.cube.pojo.Dimension; |
||||||
|
|
||||||
|
/** |
||||||
|
* Ownership belongs to the company |
||||||
|
* |
||||||
|
* @author:mengyxu |
||||||
|
* @date:2023年3月10日 |
||||||
|
*/ |
||||||
|
|
||||||
|
@Mapper |
||||||
|
public interface DataCubeMapper { |
||||||
|
|
||||||
|
@Select(""" |
||||||
|
<script> |
||||||
|
SELECT * FROM cube |
||||||
|
<where> |
||||||
|
<if test="name != null"> AND name = #{name} </if> |
||||||
|
<if test="source != null"> AND source = #{source} </if> |
||||||
|
<if test="status != null"> AND status = #{status} </if> |
||||||
|
</where> |
||||||
|
ORDER BY create_time DESC |
||||||
|
</script> |
||||||
|
""") |
||||||
|
List<Cube4Mysql> list(Cube4Mysql example); |
||||||
|
|
||||||
|
@Select(""" |
||||||
|
<script> |
||||||
|
SELECT * FROM cube_dimession |
||||||
|
<where> |
||||||
|
<if test="cubeName != null"> AND cube_name = #{cubeName} </if> |
||||||
|
<if test="type != null"> AND type = #{type} </if> |
||||||
|
</where> |
||||||
|
</script> |
||||||
|
""") |
||||||
|
List<Dimension> dimesions(@Param("cubeName") String cubeName, @Param("type") Integer type); |
||||||
|
|
||||||
|
@Update(""" |
||||||
|
<script> |
||||||
|
UPDATE cube |
||||||
|
<set> |
||||||
|
<if test="status != null"> status = #{status}, </if> |
||||||
|
assemble_time = #{assembleTime}, |
||||||
|
<if test="total != null"> total = #{total}, </if> |
||||||
|
</set> |
||||||
|
WHERE name = #{name} |
||||||
|
</script> |
||||||
|
""") |
||||||
|
void update(Cube4Mysql cube); |
||||||
|
|
||||||
|
@Insert("INSERT INTO cube VALUES (#{name}, #{source}, #{sourceTimer}, #{remark}, #{status}, #{createTime}, #{assembleTime}, #{total})") |
||||||
|
void insert(Cube4Mysql cube); |
||||||
|
|
||||||
|
@Insert("INSERT INTO cube_dimession VALUES (#{cubeName}, #{column}, #{dimesion}, #{remark}, #{type}, #{dataType}, #{length})") |
||||||
|
void insertDimession(Dimension dimesion); |
||||||
|
|
||||||
|
@Delete(""" |
||||||
|
DELETE FROM cube WHERE name = #{name}; |
||||||
|
DELETE FROM cube_dimession WHERE cubeName = #{name}; |
||||||
|
""") |
||||||
|
void delete(String name); |
||||||
|
|
||||||
|
@Delete(""" |
||||||
|
DELETE FROM cube_dimession WHERE cubeName = #{name} AND column = #{column}; |
||||||
|
""") |
||||||
|
void deleteDimension(Dimension dimension); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package vip.xumy.cube.mapper; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Insert; |
||||||
|
import org.apache.ibatis.annotations.Mapper; |
||||||
|
import org.apache.ibatis.annotations.Select; |
||||||
|
|
||||||
|
/** |
||||||
|
* Ownership belongs to the company |
||||||
|
* |
||||||
|
* @author:mengyxu |
||||||
|
* @date:2023年3月10日 |
||||||
|
*/ |
||||||
|
|
||||||
|
@Mapper |
||||||
|
public interface SqlExcuter { |
||||||
|
|
||||||
|
@Insert("${sql}") |
||||||
|
int excute(String sql); |
||||||
|
|
||||||
|
@Select("${sql}") |
||||||
|
List<Map<String, Object>> select(String sql); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,125 @@ |
|||||||
|
package vip.xumy.cube.pojo; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.List; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
import java.util.stream.Stream; |
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField; |
||||||
|
|
||||||
|
import lombok.Getter; |
||||||
|
import lombok.Setter; |
||||||
|
import vip.xumy.core.utils.CombineUtil; |
||||||
|
import vip.xumy.core.utils.DateUtil; |
||||||
|
import vip.xumy.core.utils.StringUtil; |
||||||
|
|
||||||
|
/** |
||||||
|
* Ownership belongs to the company |
||||||
|
* |
||||||
|
* @author:mengyxu |
||||||
|
* @date:2023年3月9日 |
||||||
|
*/ |
||||||
|
|
||||||
|
@Setter |
||||||
|
@Getter |
||||||
|
public class Cube4Mysql extends PageParam { |
||||||
|
private String scheme = "cube"; |
||||||
|
|
||||||
|
private List<Dimension> dimensions; |
||||||
|
private List<Dimension> data; |
||||||
|
private String name; |
||||||
|
private String source; |
||||||
|
private String sourceTimer; |
||||||
|
private String remark; |
||||||
|
private Integer status; |
||||||
|
private String createTime; |
||||||
|
private String assembleTime; |
||||||
|
private Integer total; |
||||||
|
|
||||||
|
@JSONField(serialize = false) |
||||||
|
private String curTime; |
||||||
|
|
||||||
|
public String destorySql() { |
||||||
|
StringBuilder sb = new StringBuilder("DROP TABLE IF EXISTS ").append("`").append(name).append("`;"); |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
public String initSql() { |
||||||
|
StringBuilder sb = new StringBuilder(destorySql()).append(" CREATE TABLE ").append("`").append(name) |
||||||
|
.append("` (`id` int(11) NOT NULL AUTO_INCREMENT"); |
||||||
|
for (Dimension dimesion : dimensions) { |
||||||
|
sb.append(", `").append(dimesion.getColumn()).append("` "); |
||||||
|
switch (dimesion.getDataType()) { |
||||||
|
case 0: |
||||||
|
sb.append("varchar(").append(dimesion.getLength()).append(") "); |
||||||
|
break; |
||||||
|
case 1: |
||||||
|
sb.append("int(11) "); |
||||||
|
break; |
||||||
|
case 2: |
||||||
|
sb.append("datetime "); |
||||||
|
break; |
||||||
|
} |
||||||
|
sb.append("DEFAULT NULL"); |
||||||
|
} |
||||||
|
for (Dimension dimesion : data) { |
||||||
|
sb.append(", `").append(dimesion.getColumn()).append("` int(11) NOT NULL"); |
||||||
|
} |
||||||
|
sb.append(", PRIMARY KEY (`id`), UNIQUE KEY `base_index` (`"); |
||||||
|
List<String> columns = dimensions.stream().map(x -> x.getColumn()).collect(Collectors.toList()); |
||||||
|
sb.append(StringUtil.join(columns, "`,`")).append("`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;"); |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
public String assembleSql() { |
||||||
|
curTime = DateUtil.format(new Date(), DateUtil.FORMAT19_LINE_YYYYMMDDHHMMSS); |
||||||
|
List<String> columns = Stream.of(dimensions, data).flatMap(x -> x.stream()).map(x -> "`" + x.getColumn() + "`") |
||||||
|
.collect(Collectors.toList()); |
||||||
|
StringBuilder sb = new StringBuilder("INSERT INTO `").append(name).append("` (") |
||||||
|
.append(StringUtil.join(columns)).append(") "); |
||||||
|
new ArrayList<>(dimensions).addAll(data); |
||||||
|
List<List<Integer>> combine = CombineUtil.combine(dimensions.size()); |
||||||
|
List<String> combineSql = combine.stream().map(x -> assembleOneCombination(x)).collect(Collectors.toList()); |
||||||
|
sb.append(StringUtil.join(combineSql.toArray(new String[0]), " UNION ")).append(";"); |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
public String assembleOneCombination(List<Integer> list) { |
||||||
|
StringBuilder sb = new StringBuilder("SELECT "); |
||||||
|
for (int i = 0; i < dimensions.size(); i++) { |
||||||
|
if (list.contains(i + 1)) { |
||||||
|
sb.append(dimensions.get(i).getDimesion()); |
||||||
|
} else { |
||||||
|
sb.append("null"); |
||||||
|
} |
||||||
|
sb.append(","); |
||||||
|
} |
||||||
|
List<String> sumArr = data.stream().map(x -> x.getDimesion()).collect(Collectors.toList()); |
||||||
|
List<String> array = list.stream().map(x -> dimensions.get(x - 1).getDimesion()).collect(Collectors.toList()); |
||||||
|
sb.append(StringUtil.join(sumArr)).append(" FROM `").append(source).append("`"); |
||||||
|
if (!StringUtil.isEmpty(sourceTimer)) { |
||||||
|
sb.append(" WHERE `").append(sourceTimer).append("` <= '").append(curTime).append("'"); |
||||||
|
if (assembleTime != null) { |
||||||
|
sb.append(" AND `").append(sourceTimer).append("` > '").append(assembleTime).append("'"); |
||||||
|
} |
||||||
|
} |
||||||
|
sb.append(" GROUP BY ").append(StringUtil.join(array)); |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
public String selectSql() { |
||||||
|
StringBuilder sb = new StringBuilder("SELECT * FROM `").append(name).append("` WHERE 1=1"); |
||||||
|
for (Dimension dimesion : dimensions) { |
||||||
|
if (!dimesion.isChecked()) { |
||||||
|
sb.append(" AND `").append(dimesion.getColumn()).append("` IS NULL"); |
||||||
|
} else if (StringUtil.isEmpty(dimesion.getValue())) { |
||||||
|
sb.append(" AND `").append(dimesion.getColumn()).append("` IS NOT NULL"); |
||||||
|
} else { |
||||||
|
sb.append(" AND `").append(dimesion.getColumn()).append("` = ").append(dimesion.getValue()); |
||||||
|
} |
||||||
|
} |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
package vip.xumy.cube.pojo; |
||||||
|
|
||||||
|
import lombok.Getter; |
||||||
|
import lombok.Setter; |
||||||
|
|
||||||
|
/** |
||||||
|
* Ownership belongs to the company |
||||||
|
* |
||||||
|
* @author:mengyxu |
||||||
|
* @date:2023年3月10日 |
||||||
|
*/ |
||||||
|
|
||||||
|
@Setter |
||||||
|
@Getter |
||||||
|
public class Dimension { |
||||||
|
private String scheme = "dimension"; |
||||||
|
|
||||||
|
private String cubeName; |
||||||
|
private String column; |
||||||
|
private String dimesion; |
||||||
|
private String remark; |
||||||
|
private Integer type; |
||||||
|
private Integer dataType; |
||||||
|
private Integer length; |
||||||
|
|
||||||
|
private boolean checked = true; |
||||||
|
private String value; |
||||||
|
|
||||||
|
public Dimension(String srouce, String column) { |
||||||
|
super(); |
||||||
|
this.dimesion = srouce; |
||||||
|
this.column = column; |
||||||
|
this.dataType = 1; |
||||||
|
} |
||||||
|
|
||||||
|
public Dimension(String srouce, String column, Integer dataType, Integer length) { |
||||||
|
super(); |
||||||
|
this.dimesion = srouce; |
||||||
|
this.column = column; |
||||||
|
this.dataType = dataType; |
||||||
|
this.length = length; |
||||||
|
} |
||||||
|
|
||||||
|
public Dimension() { |
||||||
|
super(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
package vip.xumy.cube.pojo; |
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField; |
||||||
|
import com.baomidou.mybatisplus.annotation.TableField; |
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||||
|
import com.github.pagehelper.PageHelper; |
||||||
|
|
||||||
|
import lombok.Setter; |
||||||
|
import vip.xumy.core.golbal.GlobalConstant; |
||||||
|
|
||||||
|
/** |
||||||
|
* Ownership belongs to the company |
||||||
|
* |
||||||
|
* @author:mengyxu |
||||||
|
* @date:2022年7月21日 |
||||||
|
*/ |
||||||
|
|
||||||
|
@Setter |
||||||
|
public class PageParam { |
||||||
|
|
||||||
|
@TableField(exist = false) |
||||||
|
private Integer page; |
||||||
|
@TableField(exist = false) |
||||||
|
private Integer size; |
||||||
|
|
||||||
|
@JSONField(serialize = false) |
||||||
|
public <T> Page<T> getPage() { |
||||||
|
if (page == null) { |
||||||
|
page = 1; |
||||||
|
} |
||||||
|
if (size == null) { |
||||||
|
size = GlobalConstant.DEF_SIZE; |
||||||
|
} else if (size > GlobalConstant.MAX_SIZE) { |
||||||
|
size = GlobalConstant.MAX_SIZE; |
||||||
|
} |
||||||
|
return new Page<>(page, size); |
||||||
|
} |
||||||
|
|
||||||
|
@JSONField(serialize = false) |
||||||
|
public <T> com.github.pagehelper.Page<T> startPage() { |
||||||
|
if (page == null) { |
||||||
|
page = 1; |
||||||
|
} |
||||||
|
if (size == null) { |
||||||
|
size = GlobalConstant.DEF_SIZE; |
||||||
|
} else if (size > GlobalConstant.MAX_SIZE) { |
||||||
|
size = GlobalConstant.MAX_SIZE; |
||||||
|
} |
||||||
|
return PageHelper.startPage(page, size); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,140 @@ |
|||||||
|
package vip.xumy.cube.service; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
import org.springframework.transaction.annotation.Transactional; |
||||||
|
|
||||||
|
import lombok.extern.log4j.Log4j2; |
||||||
|
import vip.xumy.core.exception.CoreException; |
||||||
|
import vip.xumy.core.utils.DateUtil; |
||||||
|
import vip.xumy.core.utils.StringUtil; |
||||||
|
import vip.xumy.cube.mapper.DataCubeMapper; |
||||||
|
import vip.xumy.cube.mapper.SqlExcuter; |
||||||
|
import vip.xumy.cube.pojo.Cube4Mysql; |
||||||
|
import vip.xumy.cube.pojo.Dimension; |
||||||
|
|
||||||
|
/** |
||||||
|
* Ownership belongs to the company |
||||||
|
* |
||||||
|
* @author:mengyxu |
||||||
|
* @date:2023年3月10日 |
||||||
|
*/ |
||||||
|
|
||||||
|
@Log4j2 |
||||||
|
@Service |
||||||
|
@Transactional |
||||||
|
public class DataCubeService { |
||||||
|
@Autowired |
||||||
|
private DataCubeMapper cubeMapper; |
||||||
|
@Autowired |
||||||
|
private SqlExcuter sqlExcuter; |
||||||
|
|
||||||
|
public List<Cube4Mysql> list(Cube4Mysql example) { |
||||||
|
return cubeMapper.list(example); |
||||||
|
} |
||||||
|
|
||||||
|
public void save(Cube4Mysql cube) { |
||||||
|
if (StringUtil.isEmpty(cube.getName(), cube.getSource())) { |
||||||
|
throw new CoreException("立方体表名称和立方体数据源表名称不能为空"); |
||||||
|
} |
||||||
|
cube.setStatus(0); |
||||||
|
cube.setCreateTime(DateUtil.format(new Date(), DateUtil.FORMAT19_LINE_YYYYMMDDHHMMSS)); |
||||||
|
cube.setAssembleTime(null); |
||||||
|
cube.setTotal(0); |
||||||
|
cubeMapper.insert(cube); |
||||||
|
} |
||||||
|
|
||||||
|
public void save(Dimension dimension) { |
||||||
|
if (StringUtil.isEmpty(dimension.getCubeName(), dimension.getColumn(), dimension.getDimesion())) { |
||||||
|
throw new CoreException("立方体表名,维度字段名和数据源表字段名均不能为空"); |
||||||
|
} |
||||||
|
if (dimension.getType() == null || dimension.getDataType() == null) { |
||||||
|
throw new CoreException("纬度类型和数据类型均不能为空"); |
||||||
|
} |
||||||
|
cubeMapper.insertDimession(dimension); |
||||||
|
reset(dimension.getCubeName()); |
||||||
|
} |
||||||
|
|
||||||
|
public void init(String cubeName) { |
||||||
|
Cube4Mysql cube = get(cubeName); |
||||||
|
if (cube.getDimensions() == null || cube.getDimensions().isEmpty()) { |
||||||
|
throw new CoreException("该立方体未添加任何维度,无法完成初始化"); |
||||||
|
} |
||||||
|
String initSql = cube.initSql(); |
||||||
|
cube.setStatus(1); |
||||||
|
cube.setTotal(0); |
||||||
|
cube.setAssembleTime(null); |
||||||
|
sqlExcuter.excute(initSql); |
||||||
|
cubeMapper.update(cube); |
||||||
|
} |
||||||
|
|
||||||
|
public void assemble(String name) { |
||||||
|
Cube4Mysql cube = get(name); |
||||||
|
if (cube.getStatus() == 0) { |
||||||
|
throw new CoreException("该立方体尚未初始化"); |
||||||
|
} |
||||||
|
if (cube.getStatus() == 2) { |
||||||
|
throw new CoreException("该立方体正在构建中"); |
||||||
|
} |
||||||
|
cube.setStatus(2); |
||||||
|
cubeMapper.update(cube); |
||||||
|
new Thread(() -> { |
||||||
|
try { |
||||||
|
String assembleSql = cube.assembleSql(); |
||||||
|
int total = sqlExcuter.excute(assembleSql); |
||||||
|
cube.setAssembleTime(cube.getCurTime()); |
||||||
|
cube.setTotal(cube.getTotal() + total); |
||||||
|
cube.setStatus(1); |
||||||
|
} catch (Exception e) { |
||||||
|
log.error("立方体:" + name + "构建失败", e); |
||||||
|
cube.setStatus(3); |
||||||
|
} |
||||||
|
cubeMapper.update(cube); |
||||||
|
}).start(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public Cube4Mysql get(String name) { |
||||||
|
Cube4Mysql example = new Cube4Mysql(); |
||||||
|
example.setName(name); |
||||||
|
List<Cube4Mysql> list = cubeMapper.list(example); |
||||||
|
if (list == null || list.isEmpty()) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
Cube4Mysql cube = list.get(0); |
||||||
|
cube.setDimensions(cubeMapper.dimesions(name, 0)); |
||||||
|
cube.setData(cubeMapper.dimesions(name, 1)); |
||||||
|
return cube; |
||||||
|
} |
||||||
|
|
||||||
|
public void delete(String name) { |
||||||
|
Cube4Mysql cube = get(name); |
||||||
|
cubeMapper.delete(name); |
||||||
|
String destorySql = cube.destorySql(); |
||||||
|
sqlExcuter.excute(destorySql); |
||||||
|
} |
||||||
|
|
||||||
|
public List<Map<String, Object>> select(Cube4Mysql cube) { |
||||||
|
String selectSql = cube.selectSql(); |
||||||
|
return sqlExcuter.select(selectSql); |
||||||
|
} |
||||||
|
|
||||||
|
public void delete(Dimension dimension) { |
||||||
|
cubeMapper.deleteDimension(dimension); |
||||||
|
reset(dimension.getCubeName()); |
||||||
|
} |
||||||
|
|
||||||
|
private void reset(String name) { |
||||||
|
Cube4Mysql cube = get(name); |
||||||
|
if (cube == null) { |
||||||
|
throw new CoreException("立方体不存在"); |
||||||
|
} |
||||||
|
cube.setStatus(0); |
||||||
|
cubeMapper.update(cube); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
logging.config:logback.xml |
||||||
|
|
||||||
|
spring.main.banner-mode=off |
||||||
|
|
||||||
|
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource |
||||||
|
spring.datasource.driver-class-name=com.mysql.jdbc.Driver |
||||||
|
spring.datasource.initialSize=1 |
||||||
|
spring.datasource.minIdle=1 |
||||||
|
spring.datasource.maxActive=20 |
||||||
|
spring.datasource.maxWait=60000 |
||||||
|
spring.datasource.timeBetweenEvictionRunsMillis=60000 |
||||||
|
spring.datasource.minEvictableIdleTimeMillis=300000 |
||||||
|
spring.datasource.validationQuery=SELECT 1 FROM DUAL |
||||||
|
spring.datasource.keepAlive=true |
||||||
|
spring.datasource.testWhileIdle=true |
||||||
|
spring.datasource.testOnBorrow=false |
||||||
|
spring.datasource.testOnReturn=false |
||||||
|
spring.datasource.poolPreparedStatements=false |
||||||
|
|
||||||
|
mybatis.configuration.map-underscore-to-camel-case=true |
||||||
|
|
||||||
|
quartz.cron.clean.global=0 */10 * * * ? |
||||||
|
|
||||||
|
pagehelper.helperDialect=mysql |
||||||
|
pagehelper.reasonable=true |
||||||
|
pagehelper.supportMethodsArguments=true |
||||||
|
pagehelper.params=count=countSql |
||||||
|
pagehelper.returnPageInfo=check |
||||||
|
|
||||||
|
|
||||||
|
#springdoc.swagger-ui.path=/swagger-ui.html |
||||||
|
#springdoc.swagger-ui.enabled=true |
||||||
|
#springdoc.api-docs.path=/api-docs |
||||||
|
#springdoc.api-docs.enabled=true |
||||||
|
#springdoc.packages-to-scand=com.sprt |
@ -0,0 +1,53 @@ |
|||||||
|
package com.sprt.g5s.test; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
|
||||||
|
import vip.xumy.core.utils.CombineUtil; |
||||||
|
import vip.xumy.cube.pojo.Cube4Mysql; |
||||||
|
import vip.xumy.cube.pojo.Dimension; |
||||||
|
|
||||||
|
/** |
||||||
|
* Ownership belongs to the company |
||||||
|
* |
||||||
|
* @author:mengyxu |
||||||
|
* @date:2023年3月9日 |
||||||
|
*/ |
||||||
|
|
||||||
|
public class CubeUtilTester { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void combineTester() { |
||||||
|
List<List<Integer>> combine = CombineUtil.combine(4, 2); |
||||||
|
System.out.println(combine); |
||||||
|
|
||||||
|
List<List<Integer>> combine1 = CombineUtil.combine(4); |
||||||
|
System.out.println(combine1); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void CubeTester() { |
||||||
|
List<Dimension> dimensions = new ArrayList<>(); |
||||||
|
dimensions.add(new Dimension("imsi", "imsi", 0, 15)); |
||||||
|
dimensions.add(new Dimension("app", "app", 0, 32)); |
||||||
|
dimensions.add(new Dimension("apptype", "app_type", 0, 32)); |
||||||
|
dimensions.add(new Dimension("taskid", "task", 1, 11)); |
||||||
|
dimensions.add(new Dimension("FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(timestamp)/300)*300)", "time", 0, 20)); |
||||||
|
List<Dimension> sums = new ArrayList<>(); |
||||||
|
sums.add(new Dimension("SUM(toptraffic)", "up")); |
||||||
|
sums.add(new Dimension("SUM(downtraffic)", "down")); |
||||||
|
String srcTable = "trafficstatisticslog"; |
||||||
|
String desTable = "trafficstatisticslog_loap"; |
||||||
|
Cube4Mysql cube = new Cube4Mysql(); |
||||||
|
cube.setName(desTable); |
||||||
|
cube.setSource(srcTable); |
||||||
|
cube.setSourceTimer("timestamp"); |
||||||
|
cube.setDimensions(dimensions); |
||||||
|
cube.setData(sums); |
||||||
|
System.out.println(cube.initSql()); |
||||||
|
System.out.println(cube.assembleSql()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
NODE_ENV="preview" |
||||||
|
VUE_APP_BASE_URL="http://localhost" |
@ -0,0 +1,23 @@ |
|||||||
|
.DS_Store |
||||||
|
node_modules |
||||||
|
/dist |
||||||
|
|
||||||
|
|
||||||
|
# local env files |
||||||
|
.env.local |
||||||
|
.env.*.local |
||||||
|
|
||||||
|
# Log files |
||||||
|
npm-debug.log* |
||||||
|
yarn-debug.log* |
||||||
|
yarn-error.log* |
||||||
|
pnpm-debug.log* |
||||||
|
|
||||||
|
# Editor directories and files |
||||||
|
.idea |
||||||
|
.vscode |
||||||
|
*.suo |
||||||
|
*.ntvs* |
||||||
|
*.njsproj |
||||||
|
*.sln |
||||||
|
*.sw? |
@ -0,0 +1,24 @@ |
|||||||
|
# lz_vue |
||||||
|
|
||||||
|
## Project setup |
||||||
|
``` |
||||||
|
yarn install |
||||||
|
``` |
||||||
|
|
||||||
|
### Compiles and hot-reloads for development |
||||||
|
``` |
||||||
|
yarn serve |
||||||
|
``` |
||||||
|
|
||||||
|
### Compiles and minifies for production |
||||||
|
``` |
||||||
|
yarn build |
||||||
|
``` |
||||||
|
|
||||||
|
### Lints and fixes files |
||||||
|
``` |
||||||
|
yarn lint |
||||||
|
``` |
||||||
|
|
||||||
|
### Customize configuration |
||||||
|
See [Configuration Reference](https://cli.vuejs.org/config/). |
@ -0,0 +1,5 @@ |
|||||||
|
module.exports = { |
||||||
|
presets: [ |
||||||
|
'@vue/cli-plugin-babel/preset' |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,50 @@ |
|||||||
|
{ |
||||||
|
"name": "lz_vue", |
||||||
|
"version": "0.1.0", |
||||||
|
"private": true, |
||||||
|
"scripts": { |
||||||
|
"dev": "vue-cli-service serve", |
||||||
|
"build": "vue-cli-service build", |
||||||
|
"lint": "vue-cli-service lint" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"axios": "^0.19.2", |
||||||
|
"core-js": "^3.8.3", |
||||||
|
"element-plus": "2.2.10", |
||||||
|
"js-md5": "^0.7.3", |
||||||
|
"vue": "^3.2.13", |
||||||
|
"vue-class-component": "^8.0.0-0", |
||||||
|
"vue-router": "^4.0.3", |
||||||
|
"vuex": "^4.0.0" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"@vue/cli-plugin-babel": "~5.0.0", |
||||||
|
"@vue/cli-plugin-router": "~5.0.0", |
||||||
|
"@vue/cli-plugin-typescript": "~5.0.0", |
||||||
|
"@vue/cli-plugin-vuex": "~5.0.0", |
||||||
|
"@vue/cli-service": "~5.0.0", |
||||||
|
"sass": "^1.32.7", |
||||||
|
"sass-loader": "^12.0.0", |
||||||
|
"typescript": "~4.5.5" |
||||||
|
}, |
||||||
|
"eslintConfig": { |
||||||
|
"root": true, |
||||||
|
"env": { |
||||||
|
"node": true |
||||||
|
}, |
||||||
|
"extends": [ |
||||||
|
"plugin:vue/vue3-essential", |
||||||
|
"@vue/typescript/recommended" |
||||||
|
], |
||||||
|
"parserOptions": { |
||||||
|
"ecmaVersion": 2020 |
||||||
|
}, |
||||||
|
"rules": {} |
||||||
|
}, |
||||||
|
"browserslist": [ |
||||||
|
"> 1%", |
||||||
|
"last 2 versions", |
||||||
|
"not dead", |
||||||
|
"not ie 11" |
||||||
|
] |
||||||
|
} |
After Width: | Height: | Size: 479 KiB |
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,17 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang=""> |
||||||
|
<head> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0"> |
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> |
||||||
|
<title></title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<noscript> |
||||||
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> |
||||||
|
</noscript> |
||||||
|
<div id="app"></div> |
||||||
|
<!-- built files will be auto injected --> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,10 @@ |
|||||||
|
{ |
||||||
|
"web_title_": "系统统一标题", |
||||||
|
"web_title": "LTE无线系统", |
||||||
|
"login_form_logo_show_": "登录页面是否显示logo标志", |
||||||
|
"login_form_logo_show": false, |
||||||
|
"home_logo_type_": "主页logo类型,1-标题文字,!1-图片", |
||||||
|
"home_logo_type": 1, |
||||||
|
"web_version_": "", |
||||||
|
"web_version": "3.0.0" |
||||||
|
} |
@ -0,0 +1,102 @@ |
|||||||
|
<template> |
||||||
|
<el-container :style="appMain"> |
||||||
|
<el-header class="app-head" :height="$store.state.sizes.headHeight"> |
||||||
|
<Header v-show="$store.state.showHeader" ref="header" /> |
||||||
|
</el-header> |
||||||
|
<el-container :style="{ height: $store.state.sizes.mainHeight }"> |
||||||
|
<el-aside :width="$store.state.sizes.asideWidth"> |
||||||
|
<Aside v-show="$store.state.showAside"></Aside> |
||||||
|
</el-aside> |
||||||
|
<el-main class="app-main"> |
||||||
|
<router-view /> |
||||||
|
</el-main> |
||||||
|
</el-container> |
||||||
|
</el-container> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
// <script lang="ts" steup> |
||||||
|
// import { reactive, onMounted } from "vue"; |
||||||
|
// import { useStore } from "vuex"; |
||||||
|
import Header from "@/components/main/header"; |
||||||
|
import Aside from "@/components/main/aside"; |
||||||
|
import { publik } from "@/config/apiUrl"; |
||||||
|
|
||||||
|
// const store = useStore(); |
||||||
|
// const appMain = reactive({ |
||||||
|
// height: "", |
||||||
|
// backgroundImage: "url(" + publik.background + ")", |
||||||
|
// }); |
||||||
|
|
||||||
|
// onMounted(() => { |
||||||
|
// store.commit("updateState", { prop: "showHeader", value: false }); |
||||||
|
// store.commit("updateState", { prop: "showAside", value: false }); |
||||||
|
// store.commit("initSizes"); |
||||||
|
// store.dispatch("getWebConfig"); |
||||||
|
// appMain.height = store.state.sizes.height; |
||||||
|
|
||||||
|
// }); |
||||||
|
|
||||||
|
import { Options, Vue } from "vue-class-component"; |
||||||
|
|
||||||
|
@Options({ |
||||||
|
components: { |
||||||
|
Header, |
||||||
|
Aside |
||||||
|
}, |
||||||
|
}) |
||||||
|
export default class app extends Vue { |
||||||
|
appMain = { |
||||||
|
// backgroundImage: "url(" + publik.background + ")" |
||||||
|
} |
||||||
|
|
||||||
|
init () { |
||||||
|
this.$store.commit("setUserInfo", { type: 4 }); |
||||||
|
this.$store.commit("initSizes"); |
||||||
|
// this.$store.dispatch("getWebConfig"); |
||||||
|
// this.$router.push("/") |
||||||
|
} |
||||||
|
created () { |
||||||
|
//生命周期 - 创建完成(可以访问当前this实例) |
||||||
|
this.init(); |
||||||
|
this.appMain = { |
||||||
|
height: this.$store.state.sizes.height, |
||||||
|
// backgroundImage: "url(" + publik.background + ")" |
||||||
|
}; |
||||||
|
} |
||||||
|
mounted () { |
||||||
|
//生命周期 - 挂载完成(可以访问DOM元素) |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang='scss'> |
||||||
|
@charset "UTF-8"; |
||||||
|
// @import "./assets/style/element.scss"; |
||||||
|
@import "./assets/style/base.scss"; |
||||||
|
@import "./assets/style/dark.scss"; |
||||||
|
|
||||||
|
.app-main { |
||||||
|
background-size: cover; |
||||||
|
background-position: center; |
||||||
|
background-repeat: no-repeat; |
||||||
|
} |
||||||
|
|
||||||
|
.el-header, |
||||||
|
.main-head, |
||||||
|
.main-table { |
||||||
|
padding: 0; |
||||||
|
} |
||||||
|
|
||||||
|
#app { |
||||||
|
background-color: #edf2f7; |
||||||
|
} |
||||||
|
|
||||||
|
.app-head { |
||||||
|
padding: 0px !important; |
||||||
|
} |
||||||
|
|
||||||
|
.app-main { |
||||||
|
padding: 0px !important; |
||||||
|
} |
||||||
|
</style> |
After Width: | Height: | Size: 6.7 KiB |
@ -0,0 +1,172 @@ |
|||||||
|
* { |
||||||
|
margin: 0; |
||||||
|
padding: 0; |
||||||
|
} |
||||||
|
|
||||||
|
html, |
||||||
|
body { |
||||||
|
min-width: 1200px; |
||||||
|
font-size: 14px; |
||||||
|
font-family: 'Microsoft YaHei'; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
input { |
||||||
|
font-family: 'Microsoft YaHei'; |
||||||
|
} |
||||||
|
|
||||||
|
.clearfix { |
||||||
|
&:before, |
||||||
|
&:after { |
||||||
|
display: table; |
||||||
|
content: ''; |
||||||
|
} |
||||||
|
&:after { |
||||||
|
clear: both; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
a { |
||||||
|
&:link, |
||||||
|
&:visited { |
||||||
|
all: inherit; |
||||||
|
} |
||||||
|
&:hover { |
||||||
|
all: inherit; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* 侦码侦听设备红绿灯显示 |
||||||
|
*/ |
||||||
|
|
||||||
|
.grid-code-dev { |
||||||
|
border-radius: 4px; |
||||||
|
height: 4em; |
||||||
|
} |
||||||
|
.code-dev { |
||||||
|
margin-right: 3%; |
||||||
|
height: 100%; |
||||||
|
float: right; |
||||||
|
} |
||||||
|
|
||||||
|
// 公共样式文件 |
||||||
|
// 带阴影的表格外的div |
||||||
|
div.table-warpper { |
||||||
|
padding: 0px; |
||||||
|
margin: 0px; |
||||||
|
border: 1px solid #20a0ff; |
||||||
|
overflow: hidden; |
||||||
|
// box-shadow: |
||||||
|
// -10px 0 10px #C1C1C1, /*左边阴影*/ |
||||||
|
// 10px 0 10px #C1C1C1, /*右边阴影*/ |
||||||
|
// 0 -10px 10px #C1C1C1, /*顶部阴影*/ |
||||||
|
// 0 10px 10px #C1C1C1; /*底边阴影*/ |
||||||
|
} |
||||||
|
|
||||||
|
.tabs-header { |
||||||
|
margin-left: 1em; |
||||||
|
} |
||||||
|
|
||||||
|
.cur-table-warpper { |
||||||
|
margin-left: -1em; |
||||||
|
} |
||||||
|
|
||||||
|
// input[type=number]在ff和chrome中会出现上下的小三角箭头 |
||||||
|
input::-webkit-outer-spin-button, |
||||||
|
input::-webkit-inner-spin-button { |
||||||
|
-webkit-appearance: none !important; |
||||||
|
} |
||||||
|
|
||||||
|
input[type='number'] { |
||||||
|
-moz-appearance: textfield; |
||||||
|
} |
||||||
|
|
||||||
|
// 修改element |
||||||
|
.el-picker-panel__link-btn { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
.el-pagination__editor { |
||||||
|
width: 55px !important; |
||||||
|
} |
||||||
|
|
||||||
|
.search-row { |
||||||
|
padding-bottom: 0.2em; |
||||||
|
} |
||||||
|
|
||||||
|
.form-item-btn { |
||||||
|
float: right; |
||||||
|
width: 130px; |
||||||
|
} |
||||||
|
|
||||||
|
.full-item-form .el-select, |
||||||
|
.full-item-form .el-date-editor, |
||||||
|
.full-item-form .el-autocomplete { |
||||||
|
width: 100% !important; |
||||||
|
} |
||||||
|
|
||||||
|
.search-row { |
||||||
|
height: 40px; |
||||||
|
// background-color: $main-color; |
||||||
|
padding: 5px 15px; |
||||||
|
} |
||||||
|
|
||||||
|
.query-mini { |
||||||
|
width: 100px !important; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.query-smart { |
||||||
|
width: 120px !important; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.query-short { |
||||||
|
width: 150px !important; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.query-medium { |
||||||
|
width: 200px !important; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.query-long { |
||||||
|
width: 250px !important; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.query-tree { |
||||||
|
width: 300px !important; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.query-longest { |
||||||
|
width: 350px !important; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.query-400 { |
||||||
|
width: 400px !important; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.query-450 { |
||||||
|
width: 450px !important; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.query-500 { |
||||||
|
width: 500px !important; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.auto-height { |
||||||
|
height: 78vh; |
||||||
|
overflow-x: hidden; |
||||||
|
overflow-y: scroll; |
||||||
|
} |
||||||
|
|
@ -0,0 +1,24 @@ |
|||||||
|
// 定义一些全局变量样式 |
||||||
|
|
||||||
|
/* 文字相关 */ |
||||||
|
$text-color-grey: rgba($color: #ffffff, $alpha: .7); |
||||||
|
|
||||||
|
/* 边框 */ |
||||||
|
$border-color: #414A7A; |
||||||
|
$border: 1px solid $border-color; |
||||||
|
|
||||||
|
/* 高亮背景色 */ |
||||||
|
$active-background-color: #1D3B8A; |
||||||
|
$active-background-color1: #3A7BFF; |
||||||
|
$highlight-color: #8493E3; |
||||||
|
|
||||||
|
/* 主要颜色 */ |
||||||
|
$main-color: #18295E; |
||||||
|
$sec-color: #3E4583; |
||||||
|
$email-background-color: rgba(0, 24, 106, 0.3); |
||||||
|
|
||||||
|
$success-color: #67C23A; |
||||||
|
$warning-color: #E6A23C; |
||||||
|
$danger-color: #F56C6C; |
||||||
|
|
||||||
|
// @import '_common.scss'; |
@ -0,0 +1,13 @@ |
|||||||
|
.style-dark .el-table *, .style-dark .el-tabs *, |
||||||
|
.style-dark .el-input__inner, |
||||||
|
.style-dark h1, .style-dark h2, .style-dark small, .style-dark span, .style-dark div *{ |
||||||
|
color: white; |
||||||
|
} |
||||||
|
|
||||||
|
.style-dark .el-input__inner * { |
||||||
|
background: none !important; |
||||||
|
} |
||||||
|
|
||||||
|
.style-dark .el-dialog *{ |
||||||
|
color: white !important; |
||||||
|
} |
@ -0,0 +1,197 @@ |
|||||||
|
@import 'conf.scss'; |
||||||
|
|
||||||
|
.el-input__wrapper { |
||||||
|
padding: 0px !important; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.el-input__inner { |
||||||
|
padding: 0px 15px !important; |
||||||
|
} |
||||||
|
|
||||||
|
.el-input__suffix { |
||||||
|
padding-right: 15px !important; |
||||||
|
} |
||||||
|
.el-input__prefix { |
||||||
|
padding-left: 15px !important; |
||||||
|
} |
||||||
|
|
||||||
|
.el-input__inner, |
||||||
|
.el-input__wrapper { |
||||||
|
background: transparent !important; |
||||||
|
color: rgba(17, 17, 17, 0.747) !important; |
||||||
|
} |
||||||
|
|
||||||
|
.el-dialog { |
||||||
|
background-color: transparent !important; |
||||||
|
// background-image: url('~@/assets/img/background.png') !important; |
||||||
|
background-size: cover !important; |
||||||
|
background-position: center !important; |
||||||
|
background-repeat: no-repeat !important; |
||||||
|
.el-dialog__title { |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* 针对table组件的修改 */ |
||||||
|
.my-table { |
||||||
|
.el-table { |
||||||
|
font-size: 12px; |
||||||
|
background-color: transparent; |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
thead { |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
.cell { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
} |
||||||
|
td, |
||||||
|
th { |
||||||
|
padding: 6px 0; |
||||||
|
} |
||||||
|
th, |
||||||
|
tr { |
||||||
|
background-color: transparent; |
||||||
|
} |
||||||
|
th.is-leaf { |
||||||
|
// border-bottom: $border; |
||||||
|
} |
||||||
|
td { |
||||||
|
// border-bottom: $border; |
||||||
|
} |
||||||
|
&::before { |
||||||
|
// background-color: $border-color; |
||||||
|
} |
||||||
|
.el-table__body tr.current-row > td { |
||||||
|
background: $active-background-color; |
||||||
|
} |
||||||
|
} |
||||||
|
.el-table--enable-row-hover .el-table__body tr:hover > td { |
||||||
|
background: rgba(226, 226, 226, 0.705); |
||||||
|
} |
||||||
|
.el-table .el-table__body tr.current-row > td { |
||||||
|
background: rgba(226, 226, 226, 0.705); |
||||||
|
} |
||||||
|
.el-table__expand-icon { |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
} |
||||||
|
.el-table__body tr.hover-row > td { |
||||||
|
background: rgba(226, 226, 226, 0.705); |
||||||
|
} |
||||||
|
} |
||||||
|
.el-table--striped .el-table__body tr.el-table__row--striped td { |
||||||
|
background: rgba($color: #9b9eb8, $alpha: 0.2); |
||||||
|
} |
||||||
|
|
||||||
|
/* 针对表单组件的修改 */ |
||||||
|
.my-form { |
||||||
|
// display: inline-block; |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
.el-input__inner, |
||||||
|
.el-textarea__inner { |
||||||
|
background: transparent; |
||||||
|
// border-color: $border-color; |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
} |
||||||
|
.el-form-item__label { |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
} |
||||||
|
.el-checkbox { |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
margin-right: 15px !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* 时间选取组件 */ |
||||||
|
.my-date-picker { |
||||||
|
display: inline-block; |
||||||
|
.el-input__inner { |
||||||
|
// border: $border; |
||||||
|
.el-range-input { |
||||||
|
background-color: transparent !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.el-range-input { |
||||||
|
background: $main-color; |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
} |
||||||
|
.el-range-separator, |
||||||
|
.el-input__inner, |
||||||
|
.el-range__icon { |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* 针对tab组件修改 */ |
||||||
|
.my-tabs { |
||||||
|
.el-tabs__item { |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
} |
||||||
|
.el-tabs__nav-wrap::after { |
||||||
|
height: 0px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// /* 分页 */ |
||||||
|
// .el-pagination { |
||||||
|
// .el-pagination__total { |
||||||
|
// color: rgba(17, 17, 17, 0.747); |
||||||
|
// } |
||||||
|
// } |
||||||
|
|
||||||
|
.my-pagination { |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
.el-input__inner, |
||||||
|
.el-textarea__inner { |
||||||
|
background: transparent; |
||||||
|
// border-color: $border-color; |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
} |
||||||
|
.el-form-item__label { |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
} |
||||||
|
.el-pagination { |
||||||
|
.btn-next { |
||||||
|
background-color: transparent !important; |
||||||
|
.el-icon-arrow-right { |
||||||
|
color: #50a3f7; |
||||||
|
&:hover { |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.btn-prev { |
||||||
|
background-color: transparent !important; |
||||||
|
.el-icon-arrow-left { |
||||||
|
color: #50a3f7; |
||||||
|
&:hover { |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.el-pager { |
||||||
|
li { |
||||||
|
background: transparent; |
||||||
|
} |
||||||
|
.number { |
||||||
|
color: #50a3f7 !important; |
||||||
|
} |
||||||
|
.is-active { |
||||||
|
color: rgba(17, 17, 17, 0.747) !important; |
||||||
|
} |
||||||
|
.el-icon-more { |
||||||
|
color: #50a3f7 !important; |
||||||
|
} |
||||||
|
.el-icon-d-arrow-left { |
||||||
|
border-radius: 10px; |
||||||
|
} |
||||||
|
.el-icon-d-arrow-right { |
||||||
|
border-radius: 10px; |
||||||
|
} |
||||||
|
} |
||||||
|
.el-pagination__jump { |
||||||
|
color: rgba(17, 17, 17, 0.747); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
<template> |
||||||
|
<el-row> |
||||||
|
<el-button v-if="slice.length < 8" type="success" icon="el-icon-plus" size="small" class="form-item-btn" |
||||||
|
@click="add">FLOW |
||||||
|
</el-button> |
||||||
|
</el-row> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script lang="ts" setup> |
||||||
|
import { useStore } from "vuex"; |
||||||
|
import { get, post, put, delate } from "@/config/axios"; |
||||||
|
import { reactive, onMounted, ref, defineProps } from "vue"; |
||||||
|
|
||||||
|
const store = useStore(); |
||||||
|
const prop = defineProps({ |
||||||
|
slice: { |
||||||
|
type: Array, |
||||||
|
default: [] |
||||||
|
}, |
||||||
|
prefix: { |
||||||
|
type: String, |
||||||
|
defaul: null |
||||||
|
} |
||||||
|
}); |
||||||
|
const add = () => { |
||||||
|
prop.slice.push({}); |
||||||
|
} |
||||||
|
|
||||||
|
onMounted(() => { }); |
||||||
|
</script> |
||||||
|
<style lang="scss" scoped> |
||||||
|
//@import url(); 引入公共css类 |
||||||
|
</style> |
@ -0,0 +1,15 @@ |
|||||||
|
<template> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script lang="ts" setup> |
||||||
|
import { useStore } from "vuex"; |
||||||
|
import { get, post, put, delate } from "@/config/axios"; |
||||||
|
import { reactive, onMounted, ref } from "vue"; |
||||||
|
|
||||||
|
const { state, commit, dispatch } = useStore(); |
||||||
|
|
||||||
|
onMounted(() => {}); |
||||||
|
</script> |
||||||
|
<style lang="scss" scoped> |
||||||
|
//@import url(); 引入公共css类 |
||||||
|
</style> |
@ -0,0 +1,15 @@ |
|||||||
|
<template> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script lang="ts" setup> |
||||||
|
import { useStore } from "vuex"; |
||||||
|
import { get, post, put, delate } from "@/config/axios"; |
||||||
|
import { reactive, onMounted, ref } from "vue"; |
||||||
|
|
||||||
|
const { state, commit, dispatch } = useStore(); |
||||||
|
|
||||||
|
onMounted(() => {}); |
||||||
|
</script> |
||||||
|
<style lang="scss" scoped> |
||||||
|
//@import url(); 引入公共css类 |
||||||
|
</style> |
@ -0,0 +1,5 @@ |
|||||||
|
import ListTable from './listTable.vue'; |
||||||
|
import ModifyForm from './modifyForm.vue'; |
||||||
|
import SearchRow from './searchRow.vue'; |
||||||
|
|
||||||
|
export { ListTable, ModifyForm, SearchRow }; |
@ -0,0 +1,76 @@ |
|||||||
|
<template> |
||||||
|
<div class="my-table"> |
||||||
|
<el-table :data="page ? data.data : data" |
||||||
|
:height="height ? height : (page ? state.sizes.pTableHei : state.sizes.tableHei)" highlight-current-row> |
||||||
|
<el-table-column v-for="item in props" :key="item.code" :prop="item.code" :label="item.name" |
||||||
|
:min-width="item.width" :width="item.type ? item.width : ''" :align="item.align ? item.align : 'center'" |
||||||
|
show-overflow-tooltip :formatter="formatter"> |
||||||
|
<template v-if="item.slot" #default="scope"> |
||||||
|
<slot :name="item.code" :row="scope.row"></slot> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column v-if="prop.actionWidth" label="操作" :min-width="prop.actionWidth" align="center"> |
||||||
|
<template #default="scope"> |
||||||
|
<slot v-bind:row="scope.row" v-bind:$index="scope.$index"></slot> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
</el-table> |
||||||
|
</div> |
||||||
|
<div v-if="page" class="my-pagination"> |
||||||
|
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" |
||||||
|
:current-page="example.page" :page-sizes="[10, 20, 50, 100, 200]" :page-size="example.size" |
||||||
|
layout="total, sizes, prev, pager, next, jumper" :total="data.total"> |
||||||
|
</el-pagination> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script lang="ts" setup> |
||||||
|
import { useStore } from "vuex"; |
||||||
|
import { get, post, put, delate } from "@/config/axios"; |
||||||
|
import { reactive, onMounted, ref, defineEmits, defineProps } from "vue"; |
||||||
|
import { formatter } from "@/plugs/formatter"; |
||||||
|
const prop = defineProps({ |
||||||
|
data: { |
||||||
|
type: Object, |
||||||
|
default: null |
||||||
|
}, |
||||||
|
props: { |
||||||
|
type: Array<any>(), |
||||||
|
default: [], |
||||||
|
}, |
||||||
|
page: { |
||||||
|
type: Boolean, |
||||||
|
default: false, |
||||||
|
}, |
||||||
|
actionWidth: { |
||||||
|
type: Number, |
||||||
|
default: null, |
||||||
|
}, |
||||||
|
height: { |
||||||
|
type: Number, |
||||||
|
default: null, |
||||||
|
}, |
||||||
|
example: { |
||||||
|
type: Object, |
||||||
|
default: null, |
||||||
|
}, |
||||||
|
}); |
||||||
|
const { state } = useStore(); |
||||||
|
|
||||||
|
const emit = defineEmits(["query"]); |
||||||
|
|
||||||
|
const handleSizeChange = (val) => { |
||||||
|
prop.example.size = val; |
||||||
|
emit("query"); |
||||||
|
}; |
||||||
|
|
||||||
|
const handleCurrentChange = (val) => { |
||||||
|
prop.example.page = val; |
||||||
|
emit("query"); |
||||||
|
}; |
||||||
|
|
||||||
|
onMounted(() => { }); |
||||||
|
</script> |
||||||
|
<style lang="scss" scoped> |
||||||
|
//@import url(); 引入公共css类 |
||||||
|
</style> |
@ -0,0 +1,69 @@ |
|||||||
|
<template> |
||||||
|
<div class="modify-form"> |
||||||
|
<el-form label-position="right" :class="class" :label-width="width ? width + 'px' : ''" :model="param" |
||||||
|
ref="modifyForm" :rules="rules"> |
||||||
|
<slot></slot> |
||||||
|
<el-form-item class="form-btns"> |
||||||
|
<el-button type="primary" @click="formConfirm">确定</el-button> |
||||||
|
<el-button type="primary" @click="emit('cancel')">取消</el-button> |
||||||
|
</el-form-item> |
||||||
|
</el-form> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script lang="ts" setup> |
||||||
|
import { useStore } from "vuex"; |
||||||
|
import { get, post, put, delate } from "@/config/axios"; |
||||||
|
import { reactive, onMounted, ref, watch } from "vue"; |
||||||
|
import { FormInstance } from "element-plus"; |
||||||
|
|
||||||
|
const store = useStore(); |
||||||
|
const prop = defineProps({ |
||||||
|
width: { |
||||||
|
type: Number, |
||||||
|
default: 80, |
||||||
|
}, |
||||||
|
param: { |
||||||
|
type: Object, |
||||||
|
default: {}, |
||||||
|
}, |
||||||
|
rules: { |
||||||
|
type: Object, |
||||||
|
default: {}, |
||||||
|
}, |
||||||
|
class: { |
||||||
|
type: String, |
||||||
|
default: '', |
||||||
|
}, |
||||||
|
}); |
||||||
|
const emit = defineEmits(["confirm", "cancel"]); |
||||||
|
const modifyForm = ref<FormInstance>(); |
||||||
|
|
||||||
|
const formConfirm = () => { |
||||||
|
if (!modifyForm.value) return; |
||||||
|
modifyForm.value?.validate((valid, fields) => { |
||||||
|
if (valid) { |
||||||
|
emit("confirm"); |
||||||
|
} |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
const clearValidate = () => { |
||||||
|
modifyForm.value?.clearValidate(); |
||||||
|
} |
||||||
|
|
||||||
|
watch(() => prop.param, () => { |
||||||
|
modifyForm.value?.clearValidate(); |
||||||
|
}); |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
}); |
||||||
|
</script> |
||||||
|
<style lang="scss"> |
||||||
|
//@import url(); 引入公共css类 |
||||||
|
.modify-form { |
||||||
|
.el-select { |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,70 @@ |
|||||||
|
<template> |
||||||
|
<div class="search-row"> |
||||||
|
<div class="left"> |
||||||
|
<span class="title" v-if="title">{{ title }}</span> |
||||||
|
<el-button v-if="fresh" type="info" icon="Refresh" @click="emit('query')"> </el-button> |
||||||
|
<el-button v-if="add" type="primary" icon="Plus" @click="emit('add')"> 添加 </el-button> |
||||||
|
<el-button v-if="del" type="danger" icon="Delete" @click="emit('delete')"> 删除 </el-button> |
||||||
|
<slot name="left"></slot> |
||||||
|
</div> |
||||||
|
<div class="query"> |
||||||
|
<slot></slot> |
||||||
|
<el-button v-if="query" type="primary" icon="Search" @click="emit('query')"> 查询 </el-button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script lang="ts" setup> |
||||||
|
import { useStore } from "vuex"; |
||||||
|
import { get, post, put, delate } from "@/config/axios"; |
||||||
|
import { reactive, onMounted, ref } from "vue"; |
||||||
|
import { defineProps, defineEmits } from "vue"; |
||||||
|
// import { Refresh, Plus, Delete, Search } from "@element-plus/icons-vue"; |
||||||
|
|
||||||
|
const store = useStore(); |
||||||
|
|
||||||
|
const prop = defineProps({ |
||||||
|
title: { |
||||||
|
type: String, |
||||||
|
default: null |
||||||
|
}, |
||||||
|
fresh: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
add: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
del: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
query: { |
||||||
|
type: Boolean, |
||||||
|
default: true, |
||||||
|
}, |
||||||
|
}); |
||||||
|
|
||||||
|
const emit = defineEmits(["query", "add", "delete"]); |
||||||
|
|
||||||
|
onMounted(() => { }); |
||||||
|
</script> |
||||||
|
<style lang="scss" scoped> |
||||||
|
//@import url(); 引入公共css类 |
||||||
|
.query { |
||||||
|
text-align: right; |
||||||
|
float: right; |
||||||
|
} |
||||||
|
|
||||||
|
.left { |
||||||
|
float: left; |
||||||
|
} |
||||||
|
|
||||||
|
.title { |
||||||
|
font-weight: bold; |
||||||
|
padding-right: 15px; |
||||||
|
font-size: 20px; |
||||||
|
min-width: 20px; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,29 @@ |
|||||||
|
export const publik = { |
||||||
|
background: '/background.jpg', |
||||||
|
webConfig: '/webConfig.json', |
||||||
|
login: '/public/login', |
||||||
|
logout: '/public/logout', |
||||||
|
info: '/public/info', |
||||||
|
updatePassword: 'public/password', |
||||||
|
}; |
||||||
|
|
||||||
|
export const user = { |
||||||
|
root: '/sys/user', |
||||||
|
lock: '/sys//user/lock', |
||||||
|
reset: '/sys//user/reset', |
||||||
|
clean: '/sys//user/data', |
||||||
|
}; |
||||||
|
|
||||||
|
export const log = { |
||||||
|
sys: '/sys/log', |
||||||
|
service: '/sys//log/service', |
||||||
|
export: '/sys//log/service/export', |
||||||
|
}; |
||||||
|
|
||||||
|
export const cube = { |
||||||
|
root: '/cube', |
||||||
|
init: '/cube/init', |
||||||
|
assemble: '/cube/assemble', |
||||||
|
select: '/cube/select', |
||||||
|
dimension: '/cube/dimension' |
||||||
|
}; |
@ -0,0 +1,257 @@ |
|||||||
|
/* eslint-disable */ |
||||||
|
import axios from 'axios'; |
||||||
|
import store from '@/store'; |
||||||
|
import { loading, close, showMessage } from './element'; |
||||||
|
|
||||||
|
const config = { |
||||||
|
baseURL: process.env.VUE_APP_BASE_URL ? '/api' : '', |
||||||
|
timeout: 60 * 1000, |
||||||
|
withCredentials: true, // Check cross-site Access-Control
|
||||||
|
}; |
||||||
|
|
||||||
|
const _axios = axios.create(config); |
||||||
|
_axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'; |
||||||
|
_axios.defaults.headers.put['Content-Type'] = 'application/json;charset=UTF-8'; |
||||||
|
_axios.defaults.headers.delete['Content-Type'] = |
||||||
|
'application/json;charset=UTF-8'; |
||||||
|
|
||||||
|
let curMsg: any; |
||||||
|
|
||||||
|
// Add a request interceptor
|
||||||
|
_axios.interceptors.request.use( |
||||||
|
function (config) { |
||||||
|
const time = new Date().getTime().toString(); |
||||||
|
const params = config.params; |
||||||
|
if (params) { |
||||||
|
delEmpty(params); |
||||||
|
params.t = time; |
||||||
|
} |
||||||
|
const data = config.data; |
||||||
|
if (data != null && typeof data === 'object') { |
||||||
|
delEmpty(data); |
||||||
|
data.t = time; |
||||||
|
} |
||||||
|
return config; |
||||||
|
}, |
||||||
|
function (error) { |
||||||
|
return Promise.reject(error); |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
function delEmpty(data) { |
||||||
|
if (data) { |
||||||
|
for (const item in data) { |
||||||
|
if (data.hasOwnProperty(item)) { |
||||||
|
const val = data[item]; |
||||||
|
if ((val == null || val == 'null' || val == '') && val !== 0) { |
||||||
|
delete data[item]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Add a response interceptor
|
||||||
|
_axios.interceptors.response.use( |
||||||
|
function (response) { |
||||||
|
return response.data; |
||||||
|
}, |
||||||
|
function (error) { |
||||||
|
return Promise.reject(error); |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
export function post(url, data?, noMsg?, noLoading?) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
if (!noLoading) { |
||||||
|
loading(); |
||||||
|
} |
||||||
|
_axios.post(url, data).then( |
||||||
|
(response: any) => { |
||||||
|
handResponse(response, resolve, noMsg, noLoading); |
||||||
|
}, |
||||||
|
(err) => { |
||||||
|
handError(err, reject, noMsg, noLoading); |
||||||
|
} |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export function get(url, data?, noMsg?, noLoading?) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
if (!noLoading) { |
||||||
|
loading(); |
||||||
|
} |
||||||
|
_axios.get(url, { params: data }).then( |
||||||
|
(response: any) => { |
||||||
|
handResponse(response, resolve, noMsg, noLoading); |
||||||
|
}, |
||||||
|
(err) => { |
||||||
|
handError(err, reject, noMsg, noLoading); |
||||||
|
} |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export function put(url, data?, noMsg?, noLoading?) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
if (!noLoading) { |
||||||
|
loading(); |
||||||
|
} |
||||||
|
_axios.put(url, data).then( |
||||||
|
(response: any) => { |
||||||
|
handResponse(response, resolve, noMsg, noLoading); |
||||||
|
}, |
||||||
|
(err) => { |
||||||
|
handError(err, reject, noMsg, noLoading); |
||||||
|
} |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export function delate(url, data?, noMsg?, noLoading?) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
if (!noLoading) { |
||||||
|
loading(); |
||||||
|
} |
||||||
|
// _axios.delete(url, data).then(
|
||||||
|
// (response: any) => {
|
||||||
|
// handResponse(response, resolve, noMsg, noLoading);
|
||||||
|
// },
|
||||||
|
// (err) => {
|
||||||
|
// handError(err, reject, noMsg, noLoading);
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
_axios({ |
||||||
|
method: 'delete', |
||||||
|
url: url, |
||||||
|
data: data, |
||||||
|
}).then( |
||||||
|
(response: any) => { |
||||||
|
handResponse(response, resolve, noMsg, noLoading); |
||||||
|
}, |
||||||
|
(err) => { |
||||||
|
handError(err, reject, noMsg, noLoading); |
||||||
|
} |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
function handResponse(response, resolve, noMsg, noLoading) { |
||||||
|
if (!noLoading) { |
||||||
|
close(); |
||||||
|
} |
||||||
|
if (response.success) { |
||||||
|
if (response.message) { |
||||||
|
if (!noMsg) { |
||||||
|
showMessage('success', response.message, false); |
||||||
|
} |
||||||
|
resolve(true); |
||||||
|
} else if (response.data) { |
||||||
|
resolve(response.data); |
||||||
|
} else { |
||||||
|
resolve(true); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (response.message == 'session timeout') { |
||||||
|
store.dispatch('logout'); |
||||||
|
} |
||||||
|
if (response.message == 'no permission') { |
||||||
|
response.message = '您暂无权访问,请联系管理员添加'; |
||||||
|
} |
||||||
|
if (response.message?.indexOf('no permission for ') == 0) { |
||||||
|
response.message = '此权限尚未开放,请勿越权访问'; |
||||||
|
} |
||||||
|
if (!noMsg) { |
||||||
|
showMessage('error', response.message, false); |
||||||
|
} |
||||||
|
response.error && console.log(response.error); |
||||||
|
resolve(false); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function handError(err, reject, noMsg, noLoading) { |
||||||
|
if (!noLoading) { |
||||||
|
close(); |
||||||
|
} |
||||||
|
if (!noMsg) { |
||||||
|
showMessage('error', '网络错误', false); |
||||||
|
} |
||||||
|
reject(err); |
||||||
|
} |
||||||
|
|
||||||
|
export function upload(file, url, data) { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
let param = new FormData(); // 创建form对象
|
||||||
|
param.append('file', file); // 通过append向form对象添加数据
|
||||||
|
if (data) { |
||||||
|
for (const item in data) { |
||||||
|
if (data.hasOwnProperty(item)) { |
||||||
|
param.append(item, data[item]); // 添加form表单中其他数据
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
let config = { |
||||||
|
headers: { 'Content-Type': 'multipart/form-data' }, |
||||||
|
}; |
||||||
|
_axios.post(url, param, config).then( |
||||||
|
(response) => { |
||||||
|
handResponse(response, resolve, false, false); |
||||||
|
}, |
||||||
|
(err) => { |
||||||
|
handError(err, reject, false, false); |
||||||
|
} |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export function download(fileName, url, data = {}, callBack?) { |
||||||
|
loading(); |
||||||
|
_axios({ |
||||||
|
method: 'get', |
||||||
|
url: url, // 请求地址
|
||||||
|
params: data, // 参数
|
||||||
|
responseType: 'blob', // 表明返回服务器返回的数据类型
|
||||||
|
}).then( |
||||||
|
(response: any) => { |
||||||
|
close(); |
||||||
|
const reader = new FileReader() as any; |
||||||
|
reader.readAsText(response); |
||||||
|
reader.onload = function () { |
||||||
|
try { |
||||||
|
const result = JSON.parse(reader.result); |
||||||
|
if (typeof result === 'object') { |
||||||
|
showMessage('error', result.message, false); |
||||||
|
if (callBack != null) { |
||||||
|
callBack(false); |
||||||
|
} |
||||||
|
return; |
||||||
|
} |
||||||
|
} catch (err) {} |
||||||
|
const blob = new Blob([response], { |
||||||
|
type: 'application/vnd.ms-excel', |
||||||
|
}); |
||||||
|
const navigator = window.navigator as any; |
||||||
|
if (navigator.msSaveOrOpenBlob) { |
||||||
|
navigator.msSaveBlob(blob, fileName); |
||||||
|
} else { |
||||||
|
const link = document.createElement('a'); |
||||||
|
link.href = window.URL.createObjectURL(blob); |
||||||
|
link.download = fileName; |
||||||
|
link.click(); |
||||||
|
window.URL.revokeObjectURL(link.href); |
||||||
|
} |
||||||
|
if (callBack != null) { |
||||||
|
callBack(true); |
||||||
|
} |
||||||
|
}; |
||||||
|
}, |
||||||
|
(err) => { |
||||||
|
close(); |
||||||
|
showMessage('error', '下载失败,网络异常!', false); |
||||||
|
if (callBack != null) { |
||||||
|
callBack(false); |
||||||
|
} |
||||||
|
} |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,88 @@ |
|||||||
|
import { |
||||||
|
ElLoading, |
||||||
|
ElMessage, |
||||||
|
ElNotification, |
||||||
|
ElMessageBox, |
||||||
|
Action, |
||||||
|
} from 'element-plus'; |
||||||
|
let curMsg; |
||||||
|
let count = 0; |
||||||
|
let instance; |
||||||
|
|
||||||
|
export function loading() { |
||||||
|
if (count === 0) { |
||||||
|
instance = ElLoading.service({ |
||||||
|
lock: true, |
||||||
|
text: '加载中...', |
||||||
|
spinner: 'el-icon-loading', |
||||||
|
background: 'rgba(0, 0, 0, 0.3)', |
||||||
|
}); |
||||||
|
} |
||||||
|
count++; |
||||||
|
} |
||||||
|
|
||||||
|
export function close() { |
||||||
|
if (count <= 0) { |
||||||
|
return; |
||||||
|
} |
||||||
|
if (--count === 0) { |
||||||
|
instance.close(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export function showMessage(type, info, unClose) { |
||||||
|
if (curMsg != null) { |
||||||
|
curMsg.close(); |
||||||
|
} |
||||||
|
const tmp = ElMessage({ |
||||||
|
type: type, |
||||||
|
showClose: true, |
||||||
|
message: info, |
||||||
|
duration: 3000, |
||||||
|
offset: 50, |
||||||
|
}); |
||||||
|
if (!unClose) { |
||||||
|
curMsg = tmp; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export function showNotify(type, title, message, position) { |
||||||
|
if (position == null) { |
||||||
|
position = 'top-right'; |
||||||
|
} |
||||||
|
ElNotification({ |
||||||
|
title: title, |
||||||
|
type: type, |
||||||
|
message: message, |
||||||
|
position: position, |
||||||
|
duration: 0, |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
export function warning(msg) { |
||||||
|
showMessage('warning', msg, false); |
||||||
|
} |
||||||
|
|
||||||
|
export function error(msg) { |
||||||
|
showMessage('error', msg, false); |
||||||
|
} |
||||||
|
|
||||||
|
export function success(msg) { |
||||||
|
showMessage('success', msg, false); |
||||||
|
} |
||||||
|
|
||||||
|
export const confirm = (msg: string, title: string) => { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
ElMessageBox.confirm(msg, title, { |
||||||
|
confirmButtonText: '确定', |
||||||
|
cancelButtonText: '取消', |
||||||
|
buttonSize: 'default', |
||||||
|
confirmButtonClass:'el-button--info', |
||||||
|
type: 'warning', |
||||||
|
}) |
||||||
|
.then(resolve) |
||||||
|
.catch(() => { |
||||||
|
//do nothing
|
||||||
|
}); |
||||||
|
}); |
||||||
|
}; |
@ -0,0 +1,90 @@ |
|||||||
|
export const menu = [ |
||||||
|
{ |
||||||
|
user: { |
||||||
|
name: '账号管理', |
||||||
|
active: true, |
||||||
|
}, |
||||||
|
log: { |
||||||
|
name: '日志管理', |
||||||
|
active: false, |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
user: { |
||||||
|
name: '账号管理', |
||||||
|
active: true, |
||||||
|
}, |
||||||
|
case: { |
||||||
|
name: '案件管理', |
||||||
|
active: false, |
||||||
|
}, |
||||||
|
log: { |
||||||
|
name: '日志管理', |
||||||
|
active: false, |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
target: { |
||||||
|
name: '目标管理', |
||||||
|
active: true, |
||||||
|
}, |
||||||
|
reconnCode: { |
||||||
|
name: '侦码动态', |
||||||
|
active: false, |
||||||
|
unread: 0, |
||||||
|
}, |
||||||
|
reconnDynamic: { |
||||||
|
name: '侦听动态', |
||||||
|
active: false, |
||||||
|
}, |
||||||
|
reconnListen: { |
||||||
|
name: '侦听详情', |
||||||
|
active: false, |
||||||
|
unread: 0, |
||||||
|
}, |
||||||
|
analysis: { |
||||||
|
name: '人群分析', |
||||||
|
active: false, |
||||||
|
}, |
||||||
|
flux: { |
||||||
|
name: '流量管理', |
||||||
|
active: false, |
||||||
|
}, |
||||||
|
history: { |
||||||
|
name: '历史记录', |
||||||
|
active: false, |
||||||
|
}, |
||||||
|
device: { |
||||||
|
name: '设备管理', |
||||||
|
active: true, |
||||||
|
}, |
||||||
|
log: { |
||||||
|
name: '日志管理', |
||||||
|
active: false, |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
profile: { |
||||||
|
name: '开户模版', |
||||||
|
active: true, |
||||||
|
}, |
||||||
|
Subscriber: { |
||||||
|
name: '开户', |
||||||
|
active: false, |
||||||
|
unread: 0, |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
cube: { |
||||||
|
name: '数据立方', |
||||||
|
active: true, |
||||||
|
}, |
||||||
|
}, |
||||||
|
]; |
||||||
|
export const homes = [ |
||||||
|
{ path: 'user', show: true }, |
||||||
|
{ path: 'user', show: true }, |
||||||
|
{ path: 'task', show: false }, |
||||||
|
{ path: 'profile', show: true }, |
||||||
|
{ path: 'cube', show: false }, |
||||||
|
]; |
@ -0,0 +1,18 @@ |
|||||||
|
import { createApp } from 'vue'; |
||||||
|
import App from './App.vue'; |
||||||
|
import router from './router'; |
||||||
|
import store from './store'; |
||||||
|
|
||||||
|
import ElementPlus from 'element-plus'; |
||||||
|
import 'element-plus/dist/index.css'; |
||||||
|
import zhCn from 'element-plus/es/locale/lang/zh-cn'; |
||||||
|
import * as ElementPlusIconsVue from '@element-plus/icons-vue' |
||||||
|
|
||||||
|
const app = createApp(App); |
||||||
|
|
||||||
|
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { |
||||||
|
app.component(key, component); |
||||||
|
} |
||||||
|
|
||||||
|
app.use(ElementPlus, { size: 'default', locale: zhCn }); |
||||||
|
app.use(store).use(router).mount('#app'); |
@ -0,0 +1,31 @@ |
|||||||
|
export const units = { |
||||||
|
0: 'bps', |
||||||
|
1: 'Kbps', |
||||||
|
2: 'Mbps', |
||||||
|
3: 'Gbps', |
||||||
|
4: 'Tbps', |
||||||
|
}; |
||||||
|
export const context = { |
||||||
|
1: '主叫', |
||||||
|
2: '被叫', |
||||||
|
3: '主动', |
||||||
|
}; |
||||||
|
export const extens = { |
||||||
|
'_X.': '_X.', |
||||||
|
}; |
||||||
|
export const appData = { |
||||||
|
Dial: 'PJSIP/${EXTEN},60', |
||||||
|
Macro: 'DIAL,${EXTEN}', |
||||||
|
}; |
||||||
|
export const activeStatus = { |
||||||
|
A: '已启用', |
||||||
|
I: '已禁用', |
||||||
|
}; |
||||||
|
export const smsType = { |
||||||
|
R: '被叫', |
||||||
|
S: '主叫', |
||||||
|
}; |
||||||
|
export const smsAction = { |
||||||
|
Y: '拦截', |
||||||
|
N: '放行', |
||||||
|
}; |
@ -0,0 +1,11 @@ |
|||||||
|
export const cube_status = { |
||||||
|
0: '未初始化', |
||||||
|
1: '空闲', |
||||||
|
2: '执行构建中', |
||||||
|
3: '构建失败', |
||||||
|
}; |
||||||
|
export const dimension_dataType = { |
||||||
|
0: '字符', |
||||||
|
1: '数字', |
||||||
|
2: '时间', |
||||||
|
}; |
@ -0,0 +1,94 @@ |
|||||||
|
export const device_Status = { |
||||||
|
0: '自适应中', |
||||||
|
1: '工作状态', |
||||||
|
2: '告警', |
||||||
|
3: '故障', |
||||||
|
4: '启动中', |
||||||
|
}; |
||||||
|
export const device_cardTotalStatus = { |
||||||
|
0: '初始状态', |
||||||
|
1: '切换角色中', |
||||||
|
2: '手动重启', |
||||||
|
3: '禁用状态', |
||||||
|
4: '异常', |
||||||
|
5: '在线', |
||||||
|
}; |
||||||
|
export const device_cardCurrentStatus = { |
||||||
|
0: '离线', |
||||||
|
1: '小区未建立', |
||||||
|
2: '小区建立中', |
||||||
|
3: '小区建立成功', |
||||||
|
4: '切换角色失败', |
||||||
|
5: '查询配置失败', |
||||||
|
6: '工作模式', |
||||||
|
7: '功放查询配置失败', |
||||||
|
}; |
||||||
|
export const device_syncMode = { |
||||||
|
0: '宏站同步', |
||||||
|
1: 'GPS同步', |
||||||
|
4: '自适应', |
||||||
|
5: '无同步模式', |
||||||
|
}; |
||||||
|
export const powerMeasure = { |
||||||
|
46: '40W', |
||||||
|
42: '16W', |
||||||
|
40: '10W', |
||||||
|
37: '5W', |
||||||
|
33: '2W', |
||||||
|
30: '1W', |
||||||
|
27: '0.5W', |
||||||
|
24: '0.25W', |
||||||
|
23: '0.2W', |
||||||
|
20: '0.1W', |
||||||
|
17: '0.05W', |
||||||
|
10: '10MW', |
||||||
|
0: '1MW', |
||||||
|
}; |
||||||
|
|
||||||
|
const arr1 = [24, 42]; |
||||||
|
const arr2 = [24, 46]; |
||||||
|
const arr3 = [24, 33]; |
||||||
|
const arr4 = [0, 23]; |
||||||
|
export const powerRange = { |
||||||
|
0: arr1, |
||||||
|
1: arr1, |
||||||
|
2: arr1, |
||||||
|
3: arr1, |
||||||
|
4: arr1, |
||||||
|
5: arr2, |
||||||
|
6: arr2, |
||||||
|
7: arr3, |
||||||
|
8: arr4, |
||||||
|
}; |
||||||
|
|
||||||
|
export const device_interdict = { |
||||||
|
1: '上网', |
||||||
|
2: '短信', |
||||||
|
4: 'volte通话', |
||||||
|
8: '上行短信', |
||||||
|
16: '下行短信', |
||||||
|
}; |
||||||
|
export const device_soldierNum = { |
||||||
|
'-1': '侦模块', |
||||||
|
1: '听模块', |
||||||
|
}; |
||||||
|
export const device_powerSwitch = { |
||||||
|
0: '关', |
||||||
|
1: '开', |
||||||
|
}; |
||||||
|
export const auto_conf_model = { |
||||||
|
1: '普通机型', |
||||||
|
2: '小米12', |
||||||
|
}; |
||||||
|
export const standards = { |
||||||
|
0: 'GSM', |
||||||
|
1: 'WCDMA', |
||||||
|
}; |
||||||
|
export const tac_cycle = { |
||||||
|
0: '不自动更新', |
||||||
|
1: '1分钟', |
||||||
|
2: '2分钟', |
||||||
|
5: '5分钟', |
||||||
|
10: '10分钟', |
||||||
|
30: '30分钟', |
||||||
|
}; |
@ -0,0 +1,6 @@ |
|||||||
|
export * from './device'; |
||||||
|
// import * as device from './device';
|
||||||
|
// import * as base from './base';
|
||||||
|
// export * from "./user";
|
||||||
|
export * from "./5gs"; |
||||||
|
export * from './base'; |
@ -0,0 +1,45 @@ |
|||||||
|
import * as dict from './dict'; |
||||||
|
|
||||||
|
export const getValue = ( |
||||||
|
row: any, |
||||||
|
column: string, |
||||||
|
value: any, |
||||||
|
index?: number |
||||||
|
) => { |
||||||
|
if ((value == null || value == '') && value !== 0) { |
||||||
|
return ''; |
||||||
|
} |
||||||
|
return value; |
||||||
|
}; |
||||||
|
|
||||||
|
export const formatter = (row: any, column: any, value: any, index: number) => { |
||||||
|
return formatterByDist(row.scheme + '_' + column.property, value); |
||||||
|
}; |
||||||
|
|
||||||
|
export const formatterByDist = (dictKey, value) => { |
||||||
|
if (!dictKey) { |
||||||
|
return getValue(null, '', value); |
||||||
|
} |
||||||
|
const mapping = dict[dictKey]; |
||||||
|
if (mapping == null) { |
||||||
|
return getValue(null, '', value); |
||||||
|
} |
||||||
|
return mapping[value] == null ? value : mapping[value]; |
||||||
|
}; |
||||||
|
|
||||||
|
export const formartLink = (row) => { |
||||||
|
const up = row.ambr.uplink; |
||||||
|
const down = row.ambr.downlink; |
||||||
|
return ( |
||||||
|
down.value + dict.units[down.unit] + '/' + up.value + dict.units[up.unit] |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export const formartApn = (row, index) => { |
||||||
|
const session = row.slice[0].session[index]; |
||||||
|
if (session) { |
||||||
|
return session.name + '-' + session.qos.index; |
||||||
|
} else { |
||||||
|
return ''; |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,119 @@ |
|||||||
|
import { useStore } from 'vuex'; |
||||||
|
import { warning } from '@/config/element'; |
||||||
|
const store = useStore(); |
||||||
|
export const fddFreqs = [ |
||||||
|
[ |
||||||
|
//B38/41
|
||||||
|
[37750, 38249], |
||||||
|
[39650, 41589], |
||||||
|
], |
||||||
|
[ |
||||||
|
//B39/34
|
||||||
|
[38250, 38649], |
||||||
|
[36200, 36349], |
||||||
|
], |
||||||
|
[ |
||||||
|
//B40
|
||||||
|
[38650, 39649], |
||||||
|
], |
||||||
|
]; |
||||||
|
|
||||||
|
export function repeat(arr) { |
||||||
|
arr = JSON.parse(JSON.stringify(arr)); |
||||||
|
arr.sort(); |
||||||
|
for (let i = 1; i < arr.length; i++) { |
||||||
|
if (arr[i - 1] == arr[i]) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
export function getIndex(freq) { |
||||||
|
freq = parseInt(freq); |
||||||
|
for (let i = 0; i < fddFreqs.length; i++) { |
||||||
|
for (let j = 0; j < fddFreqs[i].length; j++) { |
||||||
|
const arr = fddFreqs[i][j]; |
||||||
|
if (arr[0] <= freq && freq <= arr[1]) { |
||||||
|
return i; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
export function getUsedFreqs(device) { |
||||||
|
const arr: number[] = []; |
||||||
|
store.state.devCode.forEach((item) => { |
||||||
|
if (item.deviceId != device.deviceId && item.sModType == 'TDD') { |
||||||
|
const freqs = [item.devFreq].concat(item.defaultFreq.split(',')); |
||||||
|
for (let i = 0; i < freqs.length; i++) { |
||||||
|
const freq = freqs[i]; |
||||||
|
const index = getIndex(freq); |
||||||
|
if (index > -1) { |
||||||
|
arr.push(index); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
return arr; |
||||||
|
} |
||||||
|
|
||||||
|
export function enable(device, freq) { |
||||||
|
let enable = false; |
||||||
|
freq = parseInt(freq); |
||||||
|
const freqs = device.uarfcnband.split(','); |
||||||
|
for (let i = 0; i < freqs.length; i++) { |
||||||
|
const arr = freqs[i].split('-'); |
||||||
|
if (freq >= parseInt(arr[0]) && freq <= parseInt(arr[1])) { |
||||||
|
enable = true; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
return enable; |
||||||
|
} |
||||||
|
|
||||||
|
export function checkFreq(device, freq) { |
||||||
|
if (!enable(device, freq)) { |
||||||
|
warning('配置的频点不在可配范围内,请确认后重新配置'); |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (device.sModType != 'TDD') { |
||||||
|
return true; |
||||||
|
} |
||||||
|
const arr = getUsedFreqs(device); |
||||||
|
const index = getIndex(freq); |
||||||
|
if (index > -1 && arr.indexOf(index) > -1) { |
||||||
|
warning('频点不能配置在其他TDD模块已配置频段内'); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
export function checkFreqs(device, freqs) { |
||||||
|
if (repeat(freqs)) { |
||||||
|
warning('轮询频点不可重复,请确认后重新配置'); |
||||||
|
return false; |
||||||
|
} |
||||||
|
const arr = getUsedFreqs(device); |
||||||
|
for (let i = 0; i < freqs.length; i++) { |
||||||
|
if (!enable(device, freqs[i])) { |
||||||
|
warning('第' + (i + 1) + '个轮询频点不在可配范围内,请确认后重新配置'); |
||||||
|
return false; |
||||||
|
} |
||||||
|
const index = getIndex(freqs[i]); |
||||||
|
if (index > -1 && arr.indexOf(index) > -1) { |
||||||
|
warning('第' + (i + 1) + '个轮询频点不能配置在其他TDD模块已配置频段内'); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
export function checkCycle(device) { |
||||||
|
if (device.freqSwitchCycle < 10 || device.freqSwitchCycle > 120) { |
||||||
|
warning('轮询周期必须为10-120之间的整数!'); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
export * from "./device"; |
||||||
|
export * from "./user"; |
@ -0,0 +1,11 @@ |
|||||||
|
export const validatePass = (rule: any, value: any, callback: any) => { |
||||||
|
if (value === '') { |
||||||
|
callback(new Error('请输入密码')); |
||||||
|
} else { |
||||||
|
const pwtest = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&_])[A-Za-z\d$@$!%*?&_]{6,}$/; |
||||||
|
if (pwtest.test(value) == false) { |
||||||
|
callback(new Error('密码格式有误')); |
||||||
|
} |
||||||
|
callback(); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,26 @@ |
|||||||
|
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'; |
||||||
|
import Login from '../views/main/login.vue'; |
||||||
|
|
||||||
|
const routes: Array<RouteRecordRaw> = [ |
||||||
|
{ |
||||||
|
path: '/', |
||||||
|
redirect: '/cube', |
||||||
|
}, |
||||||
|
{ |
||||||
|
path: '/login', |
||||||
|
name: 'login', |
||||||
|
component: () => import('../views/main/login.vue') |
||||||
|
}, |
||||||
|
{ |
||||||
|
path: '/cube', |
||||||
|
name: 'user', |
||||||
|
component: () => import('../views/admin/cube.vue') |
||||||
|
} |
||||||
|
]; |
||||||
|
|
||||||
|
const router = createRouter({ |
||||||
|
history: createWebHashHistory(), |
||||||
|
routes, |
||||||
|
}); |
||||||
|
|
||||||
|
export default router; |
@ -0,0 +1,6 @@ |
|||||||
|
/* eslint-disable */ |
||||||
|
declare module '*.vue' { |
||||||
|
import type { DefineComponent } from 'vue' |
||||||
|
const component: DefineComponent<{}, {}, any> |
||||||
|
export default component |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
import axios from 'axios'; |
||||||
|
import { publik } from '@/config/apiUrl'; |
||||||
|
import router from '@/router'; |
||||||
|
import {post, get, put, delate} from '@/config/axios'; |
||||||
|
|
||||||
|
export default { |
||||||
|
getWebConfig({ commit }) { |
||||||
|
axios.get(publik.webConfig).then((rsp) => { |
||||||
|
commit('updateState', { prop: 'webConf', value: rsp.data }); |
||||||
|
document.title = rsp.data.web_title; |
||||||
|
}); |
||||||
|
}, |
||||||
|
logout({ commit }) { |
||||||
|
put(publik.logout).then((rsp) => { |
||||||
|
commit('updateState', { prop: 'user', value: {} }); |
||||||
|
router.push('/'); |
||||||
|
}); |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,12 @@ |
|||||||
|
import { createStore } from 'vuex'; |
||||||
|
import state from './state'; |
||||||
|
import mutations from './mutations'; |
||||||
|
import actions from './actions'; |
||||||
|
|
||||||
|
export default createStore({ |
||||||
|
state, |
||||||
|
getters: {}, |
||||||
|
mutations, |
||||||
|
actions, |
||||||
|
modules: {}, |
||||||
|
}); |
@ -0,0 +1,47 @@ |
|||||||
|
import { menu, homes } from '@/config/menu'; |
||||||
|
import router from "@/router"; |
||||||
|
|
||||||
|
export default { |
||||||
|
updateState(state, param) { |
||||||
|
state[param.prop] = param.value; |
||||||
|
}, |
||||||
|
initSizes(state) { |
||||||
|
const height = window.innerHeight; |
||||||
|
const width = window.innerWidth; |
||||||
|
state.widescreen = width > 1800; |
||||||
|
const loginHeight = 350; |
||||||
|
const loginWidth = 450; |
||||||
|
const navHead = state.showHeader ? 60 : 0; |
||||||
|
const aside = state.showAside ? 250 : 0; |
||||||
|
const map = { |
||||||
|
medium: 50, |
||||||
|
small: 42, |
||||||
|
mini: 35, |
||||||
|
}; |
||||||
|
const head = 40; |
||||||
|
const pd = 15; |
||||||
|
const page = 37; |
||||||
|
state.sizes.height = height; |
||||||
|
state.sizes.width = width; |
||||||
|
state.sizes.fullHeight = height + 'px'; |
||||||
|
state.sizes.loginHeight = loginHeight + 'px'; |
||||||
|
state.sizes.loginWidth = loginWidth + 'px'; |
||||||
|
state.sizes.loginTop = (height - loginHeight) * 0.4 + 'px'; |
||||||
|
state.sizes.loginLeft = (width - loginWidth) * 0.49 + 'px'; |
||||||
|
state.sizes.headHeight = navHead + 'px'; |
||||||
|
state.sizes.asideWidth = aside + 'px'; |
||||||
|
state.sizes.mainHead = head + 'px'; |
||||||
|
state.sizes.mainHeight = height - navHead + 'px'; |
||||||
|
state.sizes.tableHei = height - navHead - head - pd; |
||||||
|
state.sizes.pTableHei = state.sizes.tableHei - page; |
||||||
|
}, |
||||||
|
setUserInfo(state, user) { |
||||||
|
state.user = user; |
||||||
|
const home = homes[user.type]; |
||||||
|
state.showHeader = home.show; |
||||||
|
state.showAside = home.show; |
||||||
|
router.push(home.path); |
||||||
|
state.curPath = home.path; |
||||||
|
state.menu = JSON.parse(JSON.stringify(menu[user.type])); |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,15 @@ |
|||||||
|
export default { |
||||||
|
sizes: {}, |
||||||
|
webConf: {}, |
||||||
|
showHeader: false, |
||||||
|
showAside: false, |
||||||
|
widescreen: true, |
||||||
|
size: 'large', |
||||||
|
user: {}, |
||||||
|
menu: [], |
||||||
|
curPath: '', |
||||||
|
unread: { |
||||||
|
msg: 0, |
||||||
|
call: 0, |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,139 @@ |
|||||||
|
<template> |
||||||
|
<div id="cube"> |
||||||
|
<SearchRow :example="example" @query="queryCube" :query="false" :del="false" title="数据立方" |
||||||
|
@add="param = {}; flag.add = true;"></SearchRow> |
||||||
|
<ListTable :data="list" :props="props" :actionWidth="220" :height="state.sizes.height - 90"> |
||||||
|
<template #default="{ row: { name, status } }"> |
||||||
|
<el-button type="primary" @click="showDetail(name)">管理</el-button> |
||||||
|
<el-button v-if="status > 0" type="primary" @click="select(name)">查询</el-button> |
||||||
|
<el-button type="danger" @click="delCube(name)">删除</el-button> |
||||||
|
</template> |
||||||
|
</ListTable> |
||||||
|
</div> |
||||||
|
|
||||||
|
<el-dialog :title="selectTitle" v-model="flag.select" :close-on-click-modal="false" width="95%" top="2%"> |
||||||
|
<CubeData :cube="cube"></CubeData> |
||||||
|
</el-dialog> |
||||||
|
|
||||||
|
<el-dialog title="新增立方体" v-model="flag.add" width="50%" :close-on-click-modal="false"> |
||||||
|
<ModifyForm :param="param" :rules="rules" @confirm="addCube" @cancel="flag.add = false" :width="100"> |
||||||
|
<el-form-item label="立方体表名" prop="name"> |
||||||
|
<el-input type="text" v-model="param.name" auto-complete="off" :maxlength="100"></el-input> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="数据源表名" prop="source"> |
||||||
|
<el-input type="text" v-model="param.source" auto-complete="off" :maxlength="100"></el-input> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="源表时间字段" prop="sourceTimer"> |
||||||
|
<el-input type="text" v-model="param.sourceTimer" auto-complete="off" :maxlength="64"></el-input> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="备注(名称)" prop="remark"> |
||||||
|
<el-input type="text" v-model="param.remark" auto-complete="off" :maxlength="64"></el-input> |
||||||
|
</el-form-item> |
||||||
|
</ModifyForm> |
||||||
|
</el-dialog> |
||||||
|
|
||||||
|
<el-dialog title="立方体管理" v-model="flag.detail" width="98%" top="1%" :close-on-click-modal="false"> |
||||||
|
<CubeDetail :name="cubeName" @fresh="select(cube.name)"></CubeDetail> |
||||||
|
</el-dialog> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script lang="ts" setup> |
||||||
|
import { useStore } from "vuex"; |
||||||
|
import { get, post, put, delate } from "@/config/axios"; |
||||||
|
import { reactive, onMounted, ref } from "vue"; |
||||||
|
import { cube as urls } from "@/config/apiUrl"; |
||||||
|
import { ListTable, SearchRow, ModifyForm } from "@/components/template"; |
||||||
|
import { confirm } from "@/config/element"; |
||||||
|
import CubeData from "./cubeData.vue"; |
||||||
|
import CubeDetail from "./cubeDetail.vue" |
||||||
|
|
||||||
|
const { state, commit, dispatch } = useStore(); |
||||||
|
|
||||||
|
const example = reactive<any>({ |
||||||
|
}) |
||||||
|
const list = ref<any>([]); |
||||||
|
const flag = reactive({ |
||||||
|
select: false, |
||||||
|
add: false, |
||||||
|
detail: false |
||||||
|
}); |
||||||
|
const selectTitle = ref<string>(""); |
||||||
|
const cube = ref<any>({}); |
||||||
|
const cubeName = ref<any>({}); |
||||||
|
const param = ref<any>({}); |
||||||
|
const rules = reactive({ |
||||||
|
|
||||||
|
}) |
||||||
|
|
||||||
|
const props = [ |
||||||
|
{ code: 'name', name: '立方体表名', width: '180' }, |
||||||
|
{ code: 'source', name: '数据源表', width: '180' }, |
||||||
|
{ code: 'remark', name: '备注', width: '150' }, |
||||||
|
{ code: 'status', name: '状态', width: '100' }, |
||||||
|
{ code: 'total', name: '数据量', width: '120' }, |
||||||
|
{ code: 'createTime', name: '创建时间', width: '170' }, |
||||||
|
{ code: 'assembleTime', name: '最近构建成功时间', width: '170' }, |
||||||
|
] |
||||||
|
|
||||||
|
const queryCube = () => { |
||||||
|
get(urls.root, example).then(rsp => { |
||||||
|
if (rsp) list.value = rsp; |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
const addCube = () => { |
||||||
|
post(urls.root, param.value).then(rsp => { |
||||||
|
rsp && queryCube; |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
const showDetail = name => { |
||||||
|
cubeName.value = name; |
||||||
|
flag.detail = true; |
||||||
|
} |
||||||
|
|
||||||
|
const select = name => { |
||||||
|
if (name == cube.value.name) { |
||||||
|
flag.select = true; |
||||||
|
return; |
||||||
|
} |
||||||
|
get(urls.root + '/' + name).then((rsp: any) => { |
||||||
|
if (rsp) { |
||||||
|
rsp.title = '立方体:' + rsp.name; |
||||||
|
if (rsp.remark) rsp.title += ('(' + rsp.remark + ')'); |
||||||
|
rsp.title += ' 数据查询'; |
||||||
|
cube.value = rsp; |
||||||
|
cube.value.page = 1; |
||||||
|
cube.value.size = 20; |
||||||
|
flag.select = true; |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
const delCube = name => { |
||||||
|
confirm('确认要删除立方体' + name + '吗?', '提示').then(() => { |
||||||
|
delate(urls.root, name).then(rsp => { |
||||||
|
rsp && queryCube() |
||||||
|
}) |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
queryCube(); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
<style lang="scss" scoped> |
||||||
|
//@import url(); 引入公共css类 |
||||||
|
#cube { |
||||||
|
padding: 20px; |
||||||
|
} |
||||||
|
|
||||||
|
.cell-item { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.cube-item { |
||||||
|
margin: 20px 50px; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,67 @@ |
|||||||
|
<template> |
||||||
|
<SearchRow :del="false" :add="false" :fresh="false" title="选择维度:" @query="selectData"> |
||||||
|
<template v-slot:left> |
||||||
|
<el-checkbox v-for="item in cube.dimensions" size="default" v-model="item.checked" :label="item.remark" /> |
||||||
|
</template> |
||||||
|
<template #default> |
||||||
|
<el-input v-for="item in cube.dimensions" v-show="item.checked" v-model="item.value" class="query-medium" |
||||||
|
clearable :placeholder="'输入' + item.remark" /> |
||||||
|
</template> |
||||||
|
</SearchRow> |
||||||
|
<ListTable :example="cube" :data="data" :props="props" :height="state.sizes.height - 290" page @query="selectData"> |
||||||
|
</ListTable> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script lang="ts" setup> |
||||||
|
import { useStore } from "vuex"; |
||||||
|
import { get, post, put, delate } from "@/config/axios"; |
||||||
|
import { cube as urls } from "@/config/apiUrl"; |
||||||
|
import { reactive, onMounted, ref, watch } from "vue"; |
||||||
|
import { ListTable, SearchRow } from "@/components/template"; |
||||||
|
|
||||||
|
const { state, commit, dispatch } = useStore(); |
||||||
|
const prop = defineProps({ |
||||||
|
cube: { |
||||||
|
type: Object, |
||||||
|
default: {}, |
||||||
|
} |
||||||
|
}); |
||||||
|
const data = ref<any>({ |
||||||
|
total: 0, |
||||||
|
data: [] |
||||||
|
}); |
||||||
|
const props = ref<any>([]); |
||||||
|
|
||||||
|
const selectData = () => { |
||||||
|
init(prop.cube); |
||||||
|
put(urls.select, prop.cube).then(rsp => { |
||||||
|
data.value = rsp ? rsp : []; |
||||||
|
}) |
||||||
|
} |
||||||
|
const init = (cube) => { |
||||||
|
props.value = []; |
||||||
|
if (cube && cube.dimensions) { |
||||||
|
cube.dimensions.forEach(i => { |
||||||
|
if (i.checked) |
||||||
|
props.value.push({ code: i.column, name: i.remark, width: 150 }); |
||||||
|
}); |
||||||
|
} |
||||||
|
if (cube && cube.data) { |
||||||
|
cube.data.forEach(i => { |
||||||
|
props.value.push({ code: i.column, name: i.remark, width: 150 }); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// watch(() => prop.cube, (n, o) => { |
||||||
|
// init(n); |
||||||
|
// }); |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
init(prop.cube); |
||||||
|
}); |
||||||
|
|
||||||
|
</script> |
||||||
|
<style lang="scss" scoped> |
||||||
|
//@import url(); 引入公共css类 |
||||||
|
</style> |
@ -0,0 +1,150 @@ |
|||||||
|
<template> |
||||||
|
<el-descriptions class="margin-top" title="" :column="3" size="large" border> |
||||||
|
<template #title> |
||||||
|
<el-button type="warning" @click="initCube(name)">初始化</el-button> |
||||||
|
<el-button :disabled="cube.status == 0" type="primary" @click="assemble(name)">构建</el-button> |
||||||
|
<el-button type="primary" icon="Plus" @click="showAdd(0)"> 添加维度 </el-button> |
||||||
|
<el-button type="primary" icon="Plus" @click="showAdd(1)"> 添加统计 </el-button> |
||||||
|
</template> |
||||||
|
<el-descriptions-item label="立方体表名">{{ cube.name }}</el-descriptions-item> |
||||||
|
<el-descriptions-item label="数据源表名">{{ cube.source }}</el-descriptions-item> |
||||||
|
<el-descriptions-item label="数据源时间字段">{{ cube.sourceTimer }}</el-descriptions-item> |
||||||
|
<el-descriptions-item label="创建时间">{{ cube.createTime }}</el-descriptions-item> |
||||||
|
<el-descriptions-item label="状态">{{ formatterByDist('cube_status', cube.status) }}</el-descriptions-item> |
||||||
|
<el-descriptions-item label="数据量">{{ cube.total }}</el-descriptions-item> |
||||||
|
<el-descriptions-item label="最近一次构建成功时间">{{ cube.assembleTime }}</el-descriptions-item> |
||||||
|
</el-descriptions> <br> |
||||||
|
<h2>维度信息</h2> |
||||||
|
<ListTable :data="cube.dimensions" :props="props" :actionWidth="220" :height="state.sizes.height - 600"> |
||||||
|
<template #default="{ row }"> |
||||||
|
<!-- <el-button type="primary" @click="modify(row)">修改</el-button> --> |
||||||
|
<el-button type="danger" @click="delDimension(row)">删除</el-button> |
||||||
|
</template> |
||||||
|
</ListTable> |
||||||
|
<h2>统计信息</h2> |
||||||
|
<ListTable :data="cube.data" :props="props" :actionWidth="220" :height="150"> |
||||||
|
<template #default="{ row }"> |
||||||
|
<!-- <el-button type="primary" @click="modify(row)">修改</el-button> --> |
||||||
|
<el-button type="danger" @click="delDimension(row)">删除</el-button> |
||||||
|
</template> |
||||||
|
</ListTable> |
||||||
|
|
||||||
|
<el-dialog title="新增维度" v-model="flag.add" width="50%" :close-on-click-modal="false"> |
||||||
|
<ModifyForm :param="dimension" :rules="rules" @confirm="addDimension" @cancel="flag.add = false" :width="100"> |
||||||
|
<el-form-item label="维度表字段" prop="column"> |
||||||
|
<el-input type="text" v-model="dimension.column" auto-complete="off" :maxlength="64"></el-input> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="维度数据源" prop="dimesion"> |
||||||
|
<el-input type="text" v-model="dimension.dimesion" auto-complete="off" :maxlength="255"></el-input> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="备注(名称)" prop="remark"> |
||||||
|
<el-input type="text" v-model="dimension.remark" auto-complete="off" :maxlength="64"></el-input> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="字段数据类型" prop="dataType"> |
||||||
|
<el-select v-model="dimension.dataType"> |
||||||
|
<el-option v-for="(val, key, i) in dimension_dataType" :label="val" :value="Number(key)" |
||||||
|
:key="key"></el-option> |
||||||
|
</el-select> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item v-if="dimension.dataType == 0" label="字段长度" prop="length"> |
||||||
|
<el-input type="number" v-model="dimension.length" auto-complete="off" :max="255"></el-input> |
||||||
|
</el-form-item> |
||||||
|
</ModifyForm> |
||||||
|
</el-dialog> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script lang="ts" setup> |
||||||
|
import { useStore } from "vuex"; |
||||||
|
import { cube as urls } from "@/config/apiUrl"; |
||||||
|
import { get, post, put, delate } from "@/config/axios"; |
||||||
|
import { reactive, onMounted, ref, watch } from "vue"; |
||||||
|
import { confirm } from "@/config/element"; |
||||||
|
import { formatterByDist } from "@/plugs/formatter"; |
||||||
|
import { dimension_dataType } from "@/plugs/dict"; |
||||||
|
import { ListTable, ModifyForm } from "@/components/template"; |
||||||
|
|
||||||
|
|
||||||
|
const { state, commit, dispatch } = useStore(); |
||||||
|
const prop = defineProps({ |
||||||
|
name: { |
||||||
|
type: String, |
||||||
|
default: null, |
||||||
|
} |
||||||
|
}); |
||||||
|
const cube = ref<any>({}); |
||||||
|
const dimension = ref<any>({}); |
||||||
|
const flag = reactive({ |
||||||
|
add: false |
||||||
|
}) |
||||||
|
const rules = [ |
||||||
|
|
||||||
|
] |
||||||
|
const props = [ |
||||||
|
{ code: "column", name: '维度表字段', width: 150 }, |
||||||
|
{ code: "dimesion", name: '维度数据源', width: 150 }, |
||||||
|
{ code: "remark", name: '备注', width: 150 }, |
||||||
|
{ code: "dataType", name: '数据类型', width: 120 }, |
||||||
|
{ code: "length", name: '字段长度', width: 100 }, |
||||||
|
] |
||||||
|
|
||||||
|
const getCube = () => { |
||||||
|
get(urls.root + '/' + prop.name).then((rsp: any) => { |
||||||
|
if (rsp) { |
||||||
|
cube.value = rsp; |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
const showAdd = type => { |
||||||
|
dimension.value = { cubeName: cube.value.name, type: type }; |
||||||
|
flag.add = true; |
||||||
|
} |
||||||
|
|
||||||
|
const addDimension = () => { |
||||||
|
post(urls.dimension, dimension.value).then(rsp => { |
||||||
|
if (rsp) { |
||||||
|
getCube(); |
||||||
|
flag.add = false; |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
const modify = row => { } |
||||||
|
|
||||||
|
const delDimension = row => { |
||||||
|
confirm('初始化后的立方体删除维度后需重新初始化,是否确认删除?', '提示').then(() => { |
||||||
|
delate(urls.dimension, row).then(rsp => { |
||||||
|
rsp && getCube() |
||||||
|
}) |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
const initCube = name => { |
||||||
|
confirm('初始化操作将清空立方体数据,请确认是否继续?', '提示').then(() => { |
||||||
|
put(urls.init, name).then(rsp => { |
||||||
|
if (rsp) { |
||||||
|
getCube(); |
||||||
|
} |
||||||
|
}) |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
const assemble = name => { |
||||||
|
confirm('是否确认提交构建任务?', '提示').then(() => { |
||||||
|
post(urls.assemble, name).then(rsp => { |
||||||
|
rsp && getCube() |
||||||
|
}) |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
watch(() => prop.name, (n, o) => { |
||||||
|
getCube(); |
||||||
|
}) |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
getCube(); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
<style lang="scss" scoped> |
||||||
|
//@import url(); 引入公共css类 |
||||||
|
</style> |
@ -0,0 +1,129 @@ |
|||||||
|
<template> |
||||||
|
<el-row class="content"> |
||||||
|
<el-col :span="state.widescreen ? 4 : 6" :offset="state.widescreen ? 10 : 9"> |
||||||
|
<el-form :model="user" :rules="rules" ref="loginform" label-width="0px" :style="{ |
||||||
|
'height': state.sizes.loginHeight, |
||||||
|
'margin-top': state.sizes.loginTop |
||||||
|
}" size="large"> |
||||||
|
<!-- <img v-if="$store.state.webConf.login_form_logo_show" class="logo" src="../../assets/img/logo.png"> --> |
||||||
|
<el-form-item> |
||||||
|
<div class="lte-title"> {{ state.webConf.web_title }} </div> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item prop="userId"> |
||||||
|
<el-input v-model="user.userId" placeholder="用户名"></el-input> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item prop="password"> |
||||||
|
<el-input v-model="user.password" type="password" placeholder="密码"></el-input> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item> |
||||||
|
<el-button @click="login(loginform)">登 录</el-button> |
||||||
|
</el-form-item> |
||||||
|
</el-form> |
||||||
|
</el-col> |
||||||
|
</el-row> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script lang="ts" setup> |
||||||
|
import { onBeforeMount, reactive, ref } from "vue"; |
||||||
|
import { useStore } from "vuex"; |
||||||
|
|
||||||
|
import type { FormInstance } from "element-plus"; |
||||||
|
import md5 from "js-md5"; |
||||||
|
import { post } from "@/config/axios"; |
||||||
|
import { publik } from "@/config/apiUrl"; |
||||||
|
|
||||||
|
const { state, commit } = useStore(); |
||||||
|
|
||||||
|
const loginform = ref<FormInstance>(); |
||||||
|
const user = reactive({ |
||||||
|
userId: "", |
||||||
|
password: "", |
||||||
|
}); |
||||||
|
const rules = reactive({ |
||||||
|
userId: [ |
||||||
|
{ required: true, message: "请输入用户名", trigger: "blur" }, |
||||||
|
{ min: 3, max: 8, message: "请输入3-8位的用户名", trigger: "blur" }, |
||||||
|
], |
||||||
|
password: [ |
||||||
|
{ required: true, message: "请输入密码", trigger: "change" }, |
||||||
|
{ min: 6, max: 16, message: "请输入6-16位的密码", trigger: "blur" }, |
||||||
|
], |
||||||
|
}); |
||||||
|
const homes = ["user", "case", "task"]; |
||||||
|
|
||||||
|
onBeforeMount(() => { |
||||||
|
commit("updateState", { prop: "showHeader", value: false }); |
||||||
|
commit("updateState", { prop: "showAside", value: false }); |
||||||
|
commit("initSizes"); |
||||||
|
}); |
||||||
|
|
||||||
|
const login = async (formEl: FormInstance | undefined) => { |
||||||
|
if (!formEl) return; |
||||||
|
await formEl.validate((valid, fields) => { |
||||||
|
if (valid) { |
||||||
|
const param = JSON.parse(JSON.stringify(user)); |
||||||
|
param.password = md5(param.password); |
||||||
|
post(publik.login, param).then((response: any) => { |
||||||
|
if (response) { |
||||||
|
commit("setUserInfo", response); |
||||||
|
commit("initSizes"); |
||||||
|
// router.push(homes[response.type]); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
}); |
||||||
|
}; |
||||||
|
</script> |
||||||
|
<style lang='scss' scoped> |
||||||
|
//@import url(); 引入公共css类 |
||||||
|
.el-row.content { |
||||||
|
padding: 16px; |
||||||
|
z-index: 2; |
||||||
|
} |
||||||
|
|
||||||
|
.lte-title { |
||||||
|
font-size: 1.5em; |
||||||
|
font-weight: bold; |
||||||
|
text-align: center; |
||||||
|
width: 100%; |
||||||
|
color: rgb(49, 89, 143); |
||||||
|
} |
||||||
|
|
||||||
|
.el-input { |
||||||
|
margin: 12px 0; |
||||||
|
} |
||||||
|
|
||||||
|
.el-button { |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
.el-row { |
||||||
|
margin-bottom: 20px; |
||||||
|
|
||||||
|
&:last-child { |
||||||
|
margin-bottom: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.el-col { |
||||||
|
border-radius: 4px; |
||||||
|
} |
||||||
|
|
||||||
|
#home { |
||||||
|
position: relative; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
overflow-x: hidden; |
||||||
|
background: rgba(255, 255, 255, 0); |
||||||
|
} |
||||||
|
|
||||||
|
.canvas { |
||||||
|
position: fixed; |
||||||
|
z-index: -1; // background-color: black; |
||||||
|
} |
||||||
|
|
||||||
|
.logo { |
||||||
|
width: 300px; |
||||||
|
height: 90px; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,42 @@ |
|||||||
|
{ |
||||||
|
"compilerOptions": { |
||||||
|
"target": "esnext", |
||||||
|
"module": "esnext", |
||||||
|
"strict": true, |
||||||
|
"jsx": "preserve", |
||||||
|
"moduleResolution": "node", |
||||||
|
"experimentalDecorators": true, |
||||||
|
"skipLibCheck": true, |
||||||
|
"esModuleInterop": true, |
||||||
|
"allowSyntheticDefaultImports": true, |
||||||
|
"forceConsistentCasingInFileNames": true, |
||||||
|
"useDefineForClassFields": true, |
||||||
|
"noImplicitAny": false, |
||||||
|
"sourceMap": true, |
||||||
|
"baseUrl": ".", |
||||||
|
"types": [ |
||||||
|
"webpack-env" |
||||||
|
], |
||||||
|
"paths": { |
||||||
|
"@/*": [ |
||||||
|
"src/*" |
||||||
|
] |
||||||
|
}, |
||||||
|
"lib": [ |
||||||
|
"esnext", |
||||||
|
"dom", |
||||||
|
"dom.iterable", |
||||||
|
"scripthost" |
||||||
|
] |
||||||
|
}, |
||||||
|
"include": [ |
||||||
|
"src/**/*.ts", |
||||||
|
"src/**/*.tsx", |
||||||
|
"src/**/*.vue", |
||||||
|
"tests/**/*.ts", |
||||||
|
"tests/**/*.tsx" |
||||||
|
], |
||||||
|
"exclude": [ |
||||||
|
"node_modules" |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
const { defineConfig } = require('@vue/cli-service'); |
||||||
|
module.exports = defineConfig({ |
||||||
|
transpileDependencies: true, |
||||||
|
devServer: { |
||||||
|
proxy: { |
||||||
|
'/api': { |
||||||
|
target: process.env.VUE_APP_BASE_URL, |
||||||
|
// 允许跨域
|
||||||
|
changeOrigin: true, |
||||||
|
ws: true, |
||||||
|
pathRewrite: { |
||||||
|
'^/api': '', |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}); |
Loading…
Reference in new issue