Commit 9bd1618c authored by godkaikai's avatar godkaikai

预览数据

parent 9cb959f9
...@@ -53,7 +53,6 @@ public class ClusterController { ...@@ -53,7 +53,6 @@ public class ClusterController {
@DeleteMapping @DeleteMapping
public Result deleteMul(@RequestBody JsonNode para) { public Result deleteMul(@RequestBody JsonNode para) {
if (para.size()>0){ if (para.size()>0){
boolean isAdmin = false;
List<Integer> error = new ArrayList<>(); List<Integer> error = new ArrayList<>();
for (final JsonNode item : para){ for (final JsonNode item : para){
Integer id = item.asInt(); Integer id = item.asInt();
...@@ -61,7 +60,7 @@ public class ClusterController { ...@@ -61,7 +60,7 @@ public class ClusterController {
error.add(id); error.add(id);
} }
} }
if(error.size()==0&&!isAdmin) { if(error.size()==0) {
return Result.succeed("删除成功"); return Result.succeed("删除成功");
}else { }else {
return Result.succeed("删除部分成功,但"+error.toString()+"删除失败,共"+error.size()+"次失败。"); return Result.succeed("删除部分成功,但"+error.toString()+"删除失败,共"+error.size()+"次失败。");
......
package com.dlink.controller;
import com.dlink.common.result.ProTableResult;
import com.dlink.common.result.Result;
import com.dlink.model.Document;
import com.dlink.service.DocumentService;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
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 java.util.ArrayList;
import java.util.List;
/**
* DocumentController
*
* @author wenmo
* @since 2021/6/3
**/
@Slf4j
@RestController
@RequestMapping("/api/document")
public class DocumentController {
@Autowired
private DocumentService documentService;
/**
* 新增或者更新
*/
@PutMapping
public Result saveOrUpdate(@RequestBody Document document) throws Exception {
if(documentService.saveOrUpdate(document)){
return Result.succeed("新增成功");
}else {
return Result.failed("新增失败");
}
}
/**
* 动态查询列表
*/
@PostMapping
public ProTableResult<Document> listDocuments(@RequestBody JsonNode para) {
return documentService.selectForProTable(para);
}
/**
* 批量删除
*/
@DeleteMapping
public Result deleteMul(@RequestBody JsonNode para) {
if (para.size()>0){
List<Integer> error = new ArrayList<>();
for (final JsonNode item : para){
Integer id = item.asInt();
if(!documentService.removeById(id)){
error.add(id);
}
}
if(error.size()==0) {
return Result.succeed("删除成功");
}else {
return Result.succeed("删除部分成功,但"+error.toString()+"删除失败,共"+error.size()+"次失败。");
}
}else{
return Result.failed("请选择要删除的记录");
}
}
/**
* 获取指定ID的信息
*/
@PostMapping("/getOneById")
public Result getOneById(@RequestBody Document document) throws Exception {
document = documentService.getById(document.getId());
return Result.succeed(document,"获取成功");
}
}
package com.dlink.controller; package com.dlink.controller;
import com.dlink.common.result.Result; import com.dlink.common.result.Result;
import com.dlink.dto.StudioDDLDTO;
import com.dlink.dto.StudioExecuteDTO; import com.dlink.dto.StudioExecuteDTO;
import com.dlink.model.Task; import com.dlink.model.Task;
import com.dlink.result.RunResult; import com.dlink.result.RunResult;
...@@ -34,4 +35,13 @@ public class StudioController { ...@@ -34,4 +35,13 @@ public class StudioController {
RunResult runResult = studioService.executeSql(studioExecuteDTO); RunResult runResult = studioService.executeSql(studioExecuteDTO);
return Result.succeed(runResult,"执行成功"); return Result.succeed(runResult,"执行成功");
} }
/**
* 进行DDL操作
*/
@PostMapping("/executeDDL")
public Result executeDDL(@RequestBody StudioDDLDTO studioDDLDTO) throws Exception {
RunResult runResult = studioService.executeDDL(studioDDLDTO);
return Result.succeed(runResult,"执行成功");
}
} }
package com.dlink.dto;
import lombok.Getter;
import lombok.Setter;
/**
* StudioDDLDTO
*
* @author wenmo
* @since 2021/6/3
*/
@Getter
@Setter
public class StudioDDLDTO {
private String session;
private String statement;
private Integer clusterId=0;
}
package com.dlink.mapper;
import com.dlink.db.mapper.SuperMapper;
import com.dlink.model.Document;
import org.apache.ibatis.annotations.Mapper;
/**
* DocumentMapper
*
* @author wenmo
* @since 2021/6/3 14:31
**/
@Mapper
public interface DocumentMapper extends SuperMapper<Document> {
}
package com.dlink.model;
import com.baomidou.mybatisplus.annotation.TableName;
import com.dlink.db.model.SuperEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* Document
*
* @author wenmo
* @since 2021/6/3 14:27
**/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("dlink_flink_document")
public class Document extends SuperEntity {
private static final long serialVersionUID = -6340080980759236641L;
private String category;
private String type;
private String subtype;
private String description;
private String version;
private String likeNum;
}
package com.dlink.service;
import com.dlink.db.service.ISuperService;
import com.dlink.model.Document;
/**
* DocumentService
*
* @author wenmo
* @since 2021/6/3 14:35
**/
public interface DocumentService extends ISuperService<Document> {
}
package com.dlink.service; package com.dlink.service;
import com.dlink.dto.StudioDDLDTO;
import com.dlink.dto.StudioExecuteDTO; import com.dlink.dto.StudioExecuteDTO;
import com.dlink.result.RunResult; import com.dlink.result.RunResult;
...@@ -11,4 +12,6 @@ import com.dlink.result.RunResult; ...@@ -11,4 +12,6 @@ import com.dlink.result.RunResult;
*/ */
public interface StudioService { public interface StudioService {
RunResult executeSql(StudioExecuteDTO studioExecuteDTO); RunResult executeSql(StudioExecuteDTO studioExecuteDTO);
RunResult executeDDL(StudioDDLDTO studioDDLDTO);
} }
package com.dlink.service.impl;
import com.dlink.db.service.impl.SuperServiceImpl;
import com.dlink.mapper.DocumentMapper;
import com.dlink.model.Document;
import com.dlink.service.DocumentService;
import org.springframework.stereotype.Service;
/**
* DocumentServiceImpl
*
* @author wenmo
* @since 2021/6/3 14:36
**/
@Service
public class DocumentServiceImpl extends SuperServiceImpl<DocumentMapper, Document> implements DocumentService {
}
...@@ -2,6 +2,7 @@ package com.dlink.service.impl; ...@@ -2,6 +2,7 @@ package com.dlink.service.impl;
import com.dlink.assertion.Assert; import com.dlink.assertion.Assert;
import com.dlink.cluster.FlinkCluster; import com.dlink.cluster.FlinkCluster;
import com.dlink.dto.StudioDDLDTO;
import com.dlink.dto.StudioExecuteDTO; import com.dlink.dto.StudioExecuteDTO;
import com.dlink.executor.Executor; import com.dlink.executor.Executor;
import com.dlink.executor.ExecutorSetting; import com.dlink.executor.ExecutorSetting;
...@@ -27,13 +28,38 @@ public class StudioServiceImpl implements StudioService { ...@@ -27,13 +28,38 @@ public class StudioServiceImpl implements StudioService {
@Override @Override
public RunResult executeSql(StudioExecuteDTO studioExecuteDTO) { public RunResult executeSql(StudioExecuteDTO studioExecuteDTO) {
studioExecuteDTO.setSession(studioExecuteDTO.getClusterId()+"_"+studioExecuteDTO.getSession());
String ExecuteType = Executor.REMOTE;
String host =null;
Cluster cluster = clusterService.getById(studioExecuteDTO.getClusterId()); Cluster cluster = clusterService.getById(studioExecuteDTO.getClusterId());
if(studioExecuteDTO.getClusterId()==0&&cluster==null){
ExecuteType = Executor.LOCAL;
}else {
Assert.check(cluster); Assert.check(cluster);
String host = FlinkCluster.testFlinkJobManagerIP(cluster.getHosts(), cluster.getJobManagerHost()); host = FlinkCluster.testFlinkJobManagerIP(cluster.getHosts(), cluster.getJobManagerHost());
Assert.checkHost(host); Assert.checkHost(host);
}
JobManager jobManager = new JobManager(host,studioExecuteDTO.getSession(),studioExecuteDTO.getMaxRowNum()); JobManager jobManager = new JobManager(host,studioExecuteDTO.getSession(),studioExecuteDTO.getMaxRowNum());
return jobManager.execute(studioExecuteDTO.getStatement(), new ExecutorSetting( return jobManager.execute(studioExecuteDTO.getStatement(), new ExecutorSetting(
Executor.REMOTE,studioExecuteDTO.getCheckPoint(),studioExecuteDTO.getParallelism(), ExecuteType,studioExecuteDTO.getCheckPoint(),studioExecuteDTO.getParallelism(),
studioExecuteDTO.isFragment(),studioExecuteDTO.getSavePointPath())); studioExecuteDTO.isFragment(),studioExecuteDTO.getSavePointPath()));
} }
@Override
public RunResult executeDDL(StudioDDLDTO studioDDLDTO) {
studioDDLDTO.setSession(studioDDLDTO.getClusterId()+"_"+studioDDLDTO.getSession());
String ExecuteType = Executor.REMOTE;
String host =null;
Cluster cluster = clusterService.getById(studioDDLDTO.getClusterId());
if(studioDDLDTO.getClusterId()==0&&cluster==null){
ExecuteType = Executor.LOCAL;
}else {
Assert.check(cluster);
host = FlinkCluster.testFlinkJobManagerIP(cluster.getHosts(), cluster.getJobManagerHost());
Assert.checkHost(host);
}
JobManager jobManager = new JobManager(host,studioDDLDTO.getSession(),1000);
return jobManager.execute(studioDDLDTO.getStatement(), new ExecutorSetting(
ExecuteType));
}
} }
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dlink.mapper.DocumentMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.dlink.model.Document">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="category" property="category" />
<result column="type" property="type" />
<result column="subtype" property="subtype" />
<result column="description" property="description" />
<result column="version" property="version" />
<result column="like_num" property="likeNum" />
<result column="enabled" property="enabled" />
<result column="create_time" property="createTime" />
<result column="update_time" property="updateTime" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, name, category, type,subtype,description, version,like_num, enabled, create_time, update_time
</sql>
<select id="selectForProTable" resultType="com.dlink.model.Document">
select
a.*
from
dlink_flink_document a
<where>
1=1
<if test='param.name!=null and param.name!=""'>
and a.name like "%${param.name}%"
</if>
<if test='param.description!=null and param.description!=""'>
and a.description like "%${param.description}%"
</if>
<if test='param.type!=null and param.type!=""'>
and a.type = #{param.type}
</if>
<if test='param.subtype!=null and param.subtype!=""'>
and a.subtype = #{param.subtype}
</if>
<if test='param.version!=null and param.version!=""'>
and a.version = #{param.version}
</if>
<if test='param.createTime!=null and param.createTime!=""'>
and a.create_time <![CDATA[>=]]> str_to_date( #{param.createTime},'%Y-%m-%d %H:%i:%s')
</if>
<if test='param.updateTime!=null and param.updateTime!=""'>
and a.update_time <![CDATA[>=]]> str_to_date( #{param.updateTime},'%Y-%m-%d %H:%i:%s')
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!="" and !ew.sqlSegment.startsWith(" ORDER BY")'>
and
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!=""'>
${ew.sqlSegment}
</if>
</where>
</select>
</mapper>
...@@ -36,6 +36,10 @@ public class ExecutorSetting { ...@@ -36,6 +36,10 @@ public class ExecutorSetting {
this.savePointPath = savePointPath; this.savePointPath = savePointPath;
} }
public boolean isRemote(){
return type.equals(Executor.REMOTE);
}
public String getType() { public String getType() {
return type; return type;
} }
......
...@@ -26,6 +26,12 @@ public class LocalStreamExecutor extends Executor { ...@@ -26,6 +26,12 @@ public class LocalStreamExecutor extends Executor {
public LocalStreamExecutor(ExecutorSetting executorSetting) { public LocalStreamExecutor(ExecutorSetting executorSetting) {
this.executorSetting = executorSetting; this.executorSetting = executorSetting;
this.environment = StreamExecutionEnvironment.createLocalEnvironment(); this.environment = StreamExecutionEnvironment.createLocalEnvironment();
if(executorSetting.getCheckpoint()!=null&&executorSetting.getCheckpoint()>0){
environment.enableCheckpointing(executorSetting.getCheckpoint());
}
if(executorSetting.getParallelism()!=null&&executorSetting.getParallelism()>0){
environment.setParallelism(executorSetting.getParallelism());
}
stEnvironment = CustomTableEnvironmentImpl.create(environment); stEnvironment = CustomTableEnvironmentImpl.create(environment);
if(executorSetting.isUseSqlFragment()){ if(executorSetting.isUseSqlFragment()){
stEnvironment.useSqlFragment(); stEnvironment.useSqlFragment();
......
...@@ -30,6 +30,12 @@ public class RemoteStreamExecutor extends Executor { ...@@ -30,6 +30,12 @@ public class RemoteStreamExecutor extends Executor {
this.executorSetting = executorSetting; this.executorSetting = executorSetting;
synchronized (RemoteStreamExecutor.class){ synchronized (RemoteStreamExecutor.class){
this.environment = StreamExecutionEnvironment.createRemoteEnvironment(environmentSetting.getHost(), environmentSetting.getPort()); this.environment = StreamExecutionEnvironment.createRemoteEnvironment(environmentSetting.getHost(), environmentSetting.getPort());
if(executorSetting.getCheckpoint()!=null&&executorSetting.getCheckpoint()>0){
environment.enableCheckpointing(executorSetting.getCheckpoint());
}
if(executorSetting.getParallelism()!=null&&executorSetting.getParallelism()>0){
environment.setParallelism(executorSetting.getParallelism());
}
if(stEnvironment == null){ if(stEnvironment == null){
stEnvironment = CustomTableEnvironmentImpl.create(environment); stEnvironment = CustomTableEnvironmentImpl.create(environment);
} }
......
...@@ -78,7 +78,11 @@ public class JobManager { ...@@ -78,7 +78,11 @@ public class JobManager {
if (executorEntity != null) { if (executorEntity != null) {
executor = executorEntity.getExecutor(); executor = executorEntity.getExecutor();
} else { } else {
if(executorSetting.isRemote()) {
executor = Executor.build(new EnvironmentSetting(flinkHost, FlinkConstant.PORT), executorSetting); executor = Executor.build(new EnvironmentSetting(flinkHost, FlinkConstant.PORT), executorSetting);
}else{
executor = Executor.build(null, executorSetting);
}
SessionPool.push(new ExecutorEntity(sessionId, executor)); SessionPool.push(new ExecutorEntity(sessionId, executor));
} }
String[] Statements = statement.split(";"); String[] Statements = statement.split(";");
...@@ -99,18 +103,23 @@ public class JobManager { ...@@ -99,18 +103,23 @@ public class JobManager {
runResult.setResult(result); runResult.setResult(result);
runResult.setTime(timeElapsed); runResult.setTime(timeElapsed);
runResult.setFinishDate(LocalDateTime.now()); runResult.setFinishDate(LocalDateTime.now());
if(tableResult.getJobClient().isPresent()) {
runResult.setJobId(tableResult.getJobClient().get().getJobID().toString());
runResult.setSuccess(tableResult.getJobClient().get().getJobStatus().isDone());
}else{
runResult.setSuccess(true); runResult.setSuccess(true);
} }
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
StackTraceElement[] trace = e.getStackTrace(); StackTraceElement[] trace = e.getStackTrace();
StringBuffer resMsg = new StringBuffer(""); StringBuffer resMsg = new StringBuffer("");
for (StackTraceElement s : trace) { for (StackTraceElement s : trace) {
resMsg.append(" </br> " + s + " "); resMsg.append(" \n " + s + " ");
} }
runResult.setFinishDate(LocalDateTime.now()); runResult.setFinishDate(LocalDateTime.now());
runResult.setSuccess(false); runResult.setSuccess(false);
runResult.setError(LocalDateTime.now().toString() + ":" + "运行第" + currentIndex + "行sql时出现异常:" + e.getMessage() + "</br> >>>堆栈信息<<<" + resMsg.toString()); runResult.setError(LocalDateTime.now().toString() + ":" + "运行第" + currentIndex + "行sql时出现异常:" + e.getMessage() + " \n >>>堆栈信息<<<" + resMsg.toString());
return runResult; return runResult;
} }
return runResult; return runResult;
......
...@@ -12,6 +12,7 @@ import java.time.LocalDateTime; ...@@ -12,6 +12,7 @@ import java.time.LocalDateTime;
**/ **/
public class RunResult { public class RunResult {
private String sessionId; private String sessionId;
private String jobId;
private String statement; private String statement;
private String flinkHost; private String flinkHost;
private Integer flinkPort; private Integer flinkPort;
...@@ -34,6 +35,14 @@ public class RunResult { ...@@ -34,6 +35,14 @@ public class RunResult {
this.setting = setting; this.setting = setting;
} }
public String getJobId() {
return jobId;
}
public void setJobId(String jobId) {
this.jobId = jobId;
}
public ExecutorSetting getSetting() { public ExecutorSetting getSetting() {
return setting; return setting;
} }
......
...@@ -87,4 +87,219 @@ CREATE TABLE `dlink_task_statement` ( ...@@ -87,4 +87,219 @@ CREATE TABLE `dlink_task_statement` (
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '语句' ROW_FORMAT = Dynamic; ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '语句' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for dlink_flink_document
-- ----------------------------
DROP TABLE IF EXISTS `dlink_flink_document`;
CREATE TABLE `dlink_flink_document` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`category` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文档类型',
`type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '类型',
`subtype` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '子类型',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '信息',
`description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',
`version` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '版本号',
`like_num` int(255) NULL DEFAULT 0 COMMENT '喜爱值',
`enabled` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否启用',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 263 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '文档管理' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of dlink_flink_document
-- ----------------------------
INSERT INTO `dlink_flink_document` VALUES (1, 'function', '内置函数', '比较函数', 'value1 = value2', '如果value1等于value2 返回true; 如果value1或value2为NULL,则返回UNKNOWN 。', '1.12', 9, 1, '2021-02-22 10:06:49', '2021-02-24 09:40:30');
INSERT INTO `dlink_flink_document` VALUES (3, 'function', '内置函数', '比较函数', 'value1 <> value2', '如果value1不等于value2 返回true; 如果value1或value2为NULL,则返回UNKNOWN 。', '1.12', 4, 1, '2021-02-22 10:05:38', '2021-03-11 09:58:48');
INSERT INTO `dlink_flink_document` VALUES (22, 'function', '内置函数', '比较函数', 'value1 > value2', '如果value1大于value2 返回true; 如果value1或value2为NULL,则返回UNKNOWN 。', '1.12', 2, 1, '2021-02-22 14:37:58', '2021-03-10 11:58:06');
INSERT INTO `dlink_flink_document` VALUES (23, 'function', '内置函数', '比较函数', 'value1 >= value2', '如果value1大于或等于value2 返回true; 如果value1或value2为NULL,则返回UNKNOWN 。', '1.12', 2, 1, '2021-02-22 14:38:52', '2021-03-10 11:57:57');
INSERT INTO `dlink_flink_document` VALUES (24, 'function', '内置函数', '比较函数', 'value1 < value2', '如果value1小于value2 返回true; 如果value1或value2为NULL,则返回UNKNOWN 。', '1.12', 0, 1, '2021-02-22 14:39:15', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (25, 'function', '内置函数', '比较函数', 'value1 <= value2', '如果value1小于或等于value2 返回true; 如果value1或value2为NULL,则返回UNKNOWN 。', '1.12', 0, 1, '2021-02-22 14:39:40', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (26, 'function', '内置函数', '比较函数', 'value IS NULL', '如果value为NULL,则返回TRUE 。', '1.12', 2, 1, '2021-02-22 14:40:39', '2021-03-10 11:57:51');
INSERT INTO `dlink_flink_document` VALUES (27, 'function', '内置函数', '比较函数', 'value IS NOT NULL', '如果value不为NULL,则返回TRUE 。', '1.12', 0, 1, '2021-02-22 14:41:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (28, 'function', '内置函数', '比较函数', 'value1 IS DISTINCT FROM value2', '如果两个值不相等则返回TRUE。NULL值在这里被视为相同的值。', '1.12', 0, 1, '2021-02-22 14:42:39', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (29, 'function', '内置函数', '比较函数', 'value1 IS NOT DISTINCT FROM value2', '如果两个值相等则返回TRUE。NULL值在这里被视为相同的值。', '1.12', 0, 1, '2021-02-22 14:43:23', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (30, 'function', '内置函数', '比较函数', 'value1 BETWEEN [ ASYMMETRIC | SYMMETRIC ] value2 AND value3', '如果value1大于或等于value2和小于或等于value3 返回true', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (31, 'function', '内置函数', '比较函数', 'value1 NOT BETWEEN [ ASYMMETRIC | SYMMETRIC ] value2 AND value3', '如果value1小于value2或大于value3 返回true', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (32, 'function', '内置函数', '比较函数', 'string1 LIKE string2 [ ESCAPE char ]', '如果STRING1匹配模式STRING2,则返回TRUE ;如果STRING1或STRING2为NULL,则返回UNKNOWN 。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (33, 'function', '内置函数', '比较函数', 'string1 NOT LIKE string2 [ ESCAPE char ]', '如果STRING1不匹配模式STRING2,则返回TRUE ;如果STRING1或STRING2为NULL,则返回UNKNOWN 。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (34, 'function', '内置函数', '比较函数', 'string1 SIMILAR TO string2 [ ESCAPE char ]', '如果STRING1与SQL正则表达式STRING2匹配,则返回TRUE ;如果STRING1或STRING2为NULL,则返回UNKNOWN 。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-03-10 11:57:28');
INSERT INTO `dlink_flink_document` VALUES (35, 'function', '内置函数', '比较函数', 'string1 NOT SIMILAR TO string2 [ ESCAPE char ]', '如果STRING1与SQL正则表达式STRING2不匹配,则返回TRUE ;如果STRING1或STRING2为NULL,则返回UNKNOWN 。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (36, 'function', '内置函数', '比较函数', 'value1 IN (value2 [, value3]* )', '如果value1存在于给定列表(value2,value3,...)中,则返回TRUE 。\r\n\r\n当(value2,value3,...)包含NULL,如果可以找到该元素,则返回TRUE,否则返回UNKNOWN。\r\n\r\n如果value1为NULL,则始终返回UNKNOWN 。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (37, 'function', '内置函数', '比较函数', 'value1 NOT IN (value2 [, value3]* )', '如果value1不存在于给定列表(value2,value3,...)中,则返回TRUE 。\r\n\r\n当(value2,value3,...)包含NULL,如果可以找到该元素,则返回TRUE,否则返回UNKNOWN。\r\n\r\n如果value1为NULL,则始终返回UNKNOWN 。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (38, 'function', '内置函数', '比较函数', 'EXISTS (sub-query)', '如果value存在于子查询中,则返回TRUE。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (39, 'function', '内置函数', '比较函数', 'value IN (sub-query)', '如果value存在于子查询中,则返回TRUE。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (40, 'function', '内置函数', '比较函数', 'value NOT IN (sub-query)', '如果value不存在于子查询中,则返回TRUE。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (41, 'function', '内置函数', '逻辑函数', 'boolean1 OR boolean2', '如果BOOLEAN1为TRUE或BOOLEAN2为TRUE,则返回TRUE。支持三值逻辑。\r\n\r\n例如,true || Null(Types.BOOLEAN)返回TRUE。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (42, 'function', '内置函数', '逻辑函数', 'boolean1 AND boolean2', '如果BOOLEAN1和BOOLEAN2均为TRUE,则返回TRUE。支持三值逻辑。\r\n\r\n例如,true && Null(Types.BOOLEAN)返回未知。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (43, 'function', '内置函数', '逻辑函数', 'NOT boolean', '如果BOOLEAN为FALSE,则返回TRUE ;如果BOOLEAN为TRUE,则返回FALSE 。\r\n\r\n如果BOOLEAN为UNKNOWN,则返回UNKNOWN。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (44, 'function', '内置函数', '逻辑函数', 'boolean IS FALSE', ' \r\n如果BOOLEAN为FALSE,则返回TRUE ;如果BOOLEAN为TRUE或UNKNOWN,则返回FALSE 。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (45, 'function', '内置函数', '逻辑函数', 'boolean IS NOT FALSE', '如果BOOLEAN为TRUE或UNKNOWN,则返回TRUE ;如果BOOLEAN为FALSE,则返回FALSE。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (46, 'function', '内置函数', '逻辑函数', 'boolean IS TRUE', '如果BOOLEAN为TRUE,则返回TRUE;如果BOOLEAN为FALSE或UNKNOWN,则返回FALSE 。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (47, 'function', '内置函数', '逻辑函数', 'boolean IS NOT TRUE', '如果BOOLEAN为FALSE或UNKNOWN,则返回TRUE ;如果BOOLEAN为TRUE,则返回FALSE 。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (48, 'function', '内置函数', '逻辑函数', 'boolean IS UNKNOWN', '如果BOOLEAN为UNKNOWN,则返回TRUE ;如果BOOLEAN为TRUE或FALSE,则返回FALSE 。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (49, 'function', '内置函数', '逻辑函数', 'boolean IS NOT UNKNOWN', '如果BOOLEAN为TRUE或FALSE,则返回TRUE ;如果BOOLEAN为UNKNOWN,则返回FALSE 。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (50, 'function', '内置函数', '算术函数', '+ numeric', '返回NUMERIC。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (51, 'function', '内置函数', '算术函数', '- numeric', '返回负数NUMERIC。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (52, 'function', '内置函数', '算术函数', 'numeric1 + numeric2', '返回NUMERIC1加NUMERIC2。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (53, 'function', '内置函数', '算术函数', 'numeric1 - numeric2', '返回NUMERIC1减去NUMERIC2。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (54, 'function', '内置函数', '算术函数', 'numeric1 * numeric2', '返回NUMERIC1乘以NUMERIC2。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (55, 'function', '内置函数', '算术函数', 'numeric1 / numeric2', '返回NUMERIC1除以NUMERIC2。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (56, 'function', '内置函数', '算术函数', 'numeric1 % numeric2', '返回NUMERIC1除以NUMERIC2的余数(模)。仅当numeric1为负数时,结果为负数。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (57, 'function', '内置函数', '算术函数', 'POWER(numeric1, numeric2)', '返回NUMERIC1的NUMERIC2 次幂。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (58, 'function', '内置函数', '算术函数', 'ABS(numeric)', '返回NUMERIC的绝对值。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (59, 'function', '内置函数', '算术函数', 'MOD(numeric1, numeric2)', '返回numeric1除以numeric2的余数(模)。只有当numeric1为负数时,结果才为负数', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (60, 'function', '内置函数', '算术函数', 'SQRT(numeric)', '返回NUMERIC的平方根。', '1.12', 0, 1, '2021-02-22 14:44:26', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (61, 'function', '内置函数', '算术函数', 'LN(numeric)', '返回NUMERIC的自然对数(以e为底)。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (62, 'function', '内置函数', '算术函数', 'LOG10(numeric)', '返回NUMERIC的以10为底的对数。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (63, 'function', '内置函数', '算术函数', 'LOG2(numeric)', '返回NUMERIC的以2为底的对数。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (64, 'function', '内置函数', '算术函数', 'LOG(numeric2)\r\nLOG(numeric1, numeric2)', '如果不带参数调用,则返回NUMERIC1的自然对数。当使用参数调用时,将NUMERIC1的对数返回到基数NUMERIC2。\r\n\r\n注意:当前,NUMERIC1必须大于0,而NUMERIC2必须大于1。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (65, 'function', '内置函数', '算术函数', 'EXP(numeric)', '返回e 的 NUMERIC 次幂。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (66, 'function', '内置函数', '算术函数', 'CEIL(numeric)\r\nCEILING(numeric)', '将NUMERIC向上舍入,并返回大于或等于NUMERIC的最小整数。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (67, 'function', '内置函数', '算术函数', 'FLOOR(numeric)', ' \r\n向下舍入NUMERIC,并返回小于或等于NUMERIC的最大整数。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (68, 'function', '内置函数', '算术函数', 'SIN(numeric)', '返回NUMERIC的正弦值。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (69, 'function', '内置函数', '算术函数', 'SINH(numeric)', '返回NUMERIC的双曲正弦值。\r\n\r\n返回类型为DOUBLE。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (70, 'function', '内置函数', '算术函数', 'COS(numeric)', '返回NUMERIC的余弦值。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (71, 'function', '内置函数', '算术函数', 'TAN(numeric)', '返回NUMERIC的正切。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (72, 'function', '内置函数', '算术函数', 'TANH(numeric)', '返回NUMERIC的双曲正切值。\r\n\r\n返回类型为DOUBLE。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (73, 'function', '内置函数', '算术函数', 'COT(numeric)', '返回NUMERIC的余切。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (74, 'function', '内置函数', '算术函数', 'ASIN(numeric)', '返回NUMERIC的反正弦值。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (75, 'function', '内置函数', '算术函数', 'ACOS(numeric)', '返回NUMERIC的反余弦值。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (76, 'function', '内置函数', '算术函数', 'ATAN(numeric)', '返回NUMERIC的反正切。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (77, 'function', '内置函数', '算术函数', 'ATAN2(numeric1, numeric2)', '返回坐标的反正切(NUMERIC1,NUMERIC2)。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (78, 'function', '内置函数', '算术函数', 'COSH(numeric)', '返回NUMERIC的双曲余弦值。\r\n\r\n返回值类型为DOUBLE。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (79, 'function', '内置函数', '算术函数', 'DEGREES(numeric)', '返回弧度NUMERIC的度数表示形式', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (80, 'function', '内置函数', '算术函数', 'RADIANS(numeric)', '返回度数NUMERIC的弧度表示。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (81, 'function', '内置函数', '算术函数', 'SIGN(numeric)', '返回NUMERIC的符号。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (82, 'function', '内置函数', '算术函数', 'ROUND(numeric, integer)', '返回一个数字,四舍五入为NUMERIC的INT小数位。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (83, 'function', '内置函数', '算术函数', 'PI', '返回一个比任何其他值都更接近圆周率的值。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (84, 'function', '内置函数', '算术函数', 'E()', '返回一个比任何其他值都更接近e的值。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (85, 'function', '内置函数', '算术函数', 'RAND()', '返回介于0.0(含)和1.0(不含)之间的伪随机双精度值。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (86, 'function', '内置函数', '算术函数', 'RAND(integer)', ' \r\n返回带有初始种子INTEGER的介于0.0(含)和1.0(不含)之间的伪随机双精度值。\r\n\r\n如果两个RAND函数具有相同的初始种子,它们将返回相同的数字序列。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (87, 'function', '内置函数', '算术函数', 'RAND_INTEGER(integer)', '返回介于0(含)和INTEGER(不含)之间的伪随机整数值。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (88, 'function', '内置函数', '算术函数', 'RAND_INTEGER(integer1, integer2)', '返回介于0(含)和INTEGER2(不含)之间的伪随机整数值,其初始种子为INTEGER1。\r\n\r\n如果两个randInteger函数具有相同的初始种子和边界,它们将返回相同的数字序列。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (89, 'function', '内置函数', '算术函数', 'UUID()', '根据RFC 4122 type 4(伪随机生成)UUID返回UUID(通用唯一标识符)字符串\r\n\r\n(例如,“ 3d3c68f7-f608-473f-b60c-b0c44ad4cc4e”)。使用加密强度高的伪随机数生成器生成UUID。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (90, 'function', '内置函数', '算术函数', 'BIN(integer)', '以二进制格式返回INTEGER的字符串表示形式。如果INTEGER为NULL,则返回NULL。\r\n\r\n例如,4.bin()返回“ 100”并12.bin()返回“ 1100”。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (91, 'function', '内置函数', '算术函数', 'HEX(numeric)\r\nHEX(string)', '以十六进制格式返回整数NUMERIC值或STRING的字符串表示形式。如果参数为NULL,则返回NULL。\r\n\r\n例如,数字20导致“ 14”,数字100导致“ 64”,字符串“ hello,world”导致“ 68656C6C6F2C776F726C64”。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (92, 'function', '内置函数', '算术函数', 'TRUNCATE(numeric1, integer2)', '返回一个小数点后被截断为integer2位的数字。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (93, 'function', '内置函数', '算术函数', 'PI()', '返回π (pi)的值。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (94, 'function', '内置函数', '字符串函数', 'string1 || string2', '返回string1和string2的连接。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (95, 'function', '内置函数', '字符串函数', 'CHAR_LENGTH(string)\r\nCHARACTER_LENGTH(string)', '返回STRING中的字符数。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (96, 'function', '内置函数', '字符串函数', 'UPPER(string)', '以大写形式返回STRING。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (97, 'function', '内置函数', '字符串函数', 'LOWER(string)', '以小写形式返回STRING。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (98, 'function', '内置函数', '字符串函数', 'POSITION(string1 IN string2)', '返回STRING1在STRING2中第一次出现的位置(从1开始);\r\n\r\n如果在STRING2中找不到STRING1,则返回0 。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (99, 'function', '内置函数', '字符串函数', 'TRIM([ BOTH | LEADING | TRAILING ] string1 FROM string2)', '返回一个字符串,该字符串从STRING中删除前导和/或结尾字符。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (100, 'function', '内置函数', '字符串函数', 'LTRIM(string)', '返回一个字符串,该字符串从STRING除去左空格。\r\n\r\n例如,\" This is a test String.\".ltrim()返回“This is a test String.”。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (101, 'function', '内置函数', '字符串函数', 'RTRIM(string)', '返回一个字符串,该字符串从STRING中删除正确的空格。\r\n\r\n例如,\"This is a test String. \".rtrim()返回“This is a test String.”。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (102, 'function', '内置函数', '字符串函数', 'REPEAT(string, integer)', '返回一个字符串,该字符串重复基本STRING INT次。\r\n\r\n例如,\"This is a test String.\".repeat(2)返回“This is a test String.This is a test String.”。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (103, 'function', '内置函数', '字符串函数', 'REGEXP_REPLACE(string1, string2, string3)', '返回字符串STRING1所有匹配正则表达式的子串STRING2连续被替换STRING3。\r\n\r\n例如,\"foobar\".regexpReplace(\"oo|ar\", \"\")返回“ fb”。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (104, 'function', '内置函数', '字符串函数', 'OVERLAY(string1 PLACING string2 FROM integer1 [ FOR integer2 ])', '从位置INT1返回一个字符串,该字符串将STRING1的INT2(默认为STRING2的长度)字符替换为STRING2', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (105, 'function', '内置函数', '字符串函数', 'SUBSTRING(string FROM integer1 [ FOR integer2 ])', '返回字符串STRING的子字符串,从位置INT1开始,长度为INT2(默认为结尾)。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (106, 'function', '内置函数', '字符串函数', 'REPLACE(string1, string2, string3)', '返回一个新字符串替换其中出现的所有STRING2与STRING3(非重叠)从STRING1。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (107, 'function', '内置函数', '字符串函数', 'REGEXP_EXTRACT(string1, string2[, integer])', '从STRING1返回一个字符串,该字符串使用指定的正则表达式STRING2和正则表达式匹配组索引INTEGER1提取。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (108, 'function', '内置函数', '字符串函数', 'INITCAP(string)', '返回一种新形式的STRING,其中每个单词的第一个字符转换为大写,其余字符转换为小写。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (109, 'function', '内置函数', '字符串函数', 'CONCAT(string1, string2,...)', '返回连接STRING1,STRING2,...的字符串。如果任何参数为NULL,则返回NULL。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (110, 'function', '内置函数', '字符串函数', 'CONCAT_WS(string1, string2, string3,...)', '返回一个字符串,会连接STRING2,STRING3,......与分离STRING1。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (111, 'function', '内置函数', '字符串函数', 'LPAD(string1, integer, string2)', '返回一个新字符串,该字符串从STRING1的左侧填充STRING2,长度为INT个字符。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (112, 'function', '内置函数', '字符串函数', 'RPAD(string1, integer, string2)', '返回一个新字符串,该字符串从STRING1右侧填充STRING2,长度为INT个字符。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (113, 'function', '内置函数', '字符串函数', 'FROM_BASE64(string)', '返回来自STRING的base64解码结果;如果STRING为NULL,则返回null 。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (114, 'function', '内置函数', '字符串函数', 'TO_BASE64(string)', '从STRING返回base64编码的结果;如果STRING为NULL,则返回NULL。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (115, 'function', '内置函数', '字符串函数', 'ASCII(string)', '返回字符串的第一个字符的数值。如果字符串为NULL,则返回NULL。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (116, 'function', '内置函数', '字符串函数', 'CHR(integer)', '返回与integer在二进制上等价的ASCII字符。如果integer大于255,我们将首先得到integer的模数除以255,并返回模数的CHR。如果integer为NULL,则返回NULL。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (117, 'function', '内置函数', '字符串函数', 'DECODE(binary, string)', '使用提供的字符集(\'US-ASCII\'\'ISO-8859-1\'\'UTF-8\'\'UTF-16BE\'\'UTF-16LE\'\'UTF-16\'之一)将第一个参数解码为字符串。如果任意一个参数为空,结果也将为空。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (118, 'function', '内置函数', '字符串函数', 'ENCODE(string1, string2)', '使用提供的string2字符集(\'US-ASCII\'\'ISO-8859-1\'\'UTF-8\'\'UTF-16BE\'\'UTF-16LE\'\'UTF-16\'之一)将string1编码为二进制。如果任意一个参数为空,结果也将为空。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (119, 'function', '内置函数', '字符串函数', 'INSTR(string1, string2)', '返回string2在string1中第一次出现的位置。如果任何参数为空,则返回NULL。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (120, 'function', '内置函数', '字符串函数', 'LEFT(string, integer)', '返回字符串中最左边的整数字符。如果整数为负,则返回空字符串。如果任何参数为NULL,则返回NULL。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (121, 'function', '内置函数', '字符串函数', 'RIGHT(string, integer)', '返回字符串中最右边的整数字符。如果整数为负,则返回空字符串。如果任何参数为NULL,则返回NULL。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (122, 'function', '内置函数', '字符串函数', 'LOCATE(string1, string2[, integer])', '返回string1在string2中的位置整数之后第一次出现的位置。如果没有找到,返回0。如果任何参数为NULL,则返回NULL仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (123, 'function', '内置函数', '字符串函数', 'PARSE_URL(string1, string2[, string3])', '从URL返回指定的部分。string2的有效值包括\'HOST\'\'PATH\'\'QUERY\'\'REF\'\'PROTOCOL\'\'AUTHORITY\'\'FILE\'\'USERINFO\'。如果任何参数为NULL,则返回NULL。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (124, 'function', '内置函数', '字符串函数', 'REGEXP(string1, string2)', '如果string1的任何子字符串(可能为空)与Java正则表达式string2匹配,则返回TRUE,否则返回FALSE。如果任何参数为NULL,则返回NULL。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (125, 'function', '内置函数', '字符串函数', 'REVERSE(string)', '返回反向字符串。如果字符串为NULL,则返回NULL仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (126, 'function', '内置函数', '字符串函数', 'SPLIT_INDEX(string1, string2, integer1)', '通过分隔符string2拆分string1,返回拆分字符串的整数(从零开始)字符串。如果整数为负,返回NULL。如果任何参数为NULL,则返回NULL。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (127, 'function', '内置函数', '字符串函数', 'STR_TO_MAP(string1[, string2, string3]])', '使用分隔符将string1分割成键/值对后返回一个映射。string2是pair分隔符,默认为\'\'。string3是键值分隔符,默认为\'=\'。仅在blink planner中支持。', '1.12', 4, 1, '2021-02-22 15:29:35', '2021-05-20 19:59:50');
INSERT INTO `dlink_flink_document` VALUES (128, 'function', '内置函数', '字符串函数', 'SUBSTR(string[, integer1[, integer2]])', '返回一个字符串的子字符串,从位置integer1开始,长度为integer2(默认到末尾)。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (129, 'function', '内置函数', '时间函数', 'DATE string', '返回以“ yyyy-MM-dd”形式从STRING解析的SQL日期。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (130, 'function', '内置函数', '时间函数', 'TIME string', '返回以“ HH:mm:ss”的形式从STRING解析的SQL时间。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (131, 'function', '内置函数', '时间函数', 'TIMESTAMP string', '返回从STRING解析的SQL时间戳,格式为“ yyyy-MM-dd HH:mm:ss [.SSS]”', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (132, 'function', '内置函数', '时间函数', 'INTERVAL string range', '解析“dd hh:mm:ss”形式的区间字符串。fff表示毫秒间隔,yyyy-mm表示月间隔。间隔范围可以是天、分钟、天到小时或天到秒,以毫秒为间隔;年或年到月的间隔。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (133, 'function', '内置函数', '时间函数', 'CURRENT_DATE', '返回UTC时区中的当前SQL日期。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (134, 'function', '内置函数', '时间函数', 'CURRENT_TIME', '返回UTC时区的当前SQL时间。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (135, 'function', '内置函数', '时间函数', 'CURRENT_TIMESTAMP', '返回UTC时区内的当前SQL时间戳。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (136, 'function', '内置函数', '时间函数', 'LOCALTIME', '返回本地时区的当前SQL时间。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (137, 'function', '内置函数', '时间函数', 'LOCALTIMESTAMP', '返回本地时区的当前SQL时间戳。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (138, 'function', '内置函数', '时间函数', 'EXTRACT(timeintervalunit FROM temporal)', '返回从时域的timeintervalunit部分提取的长值。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (139, 'function', '内置函数', '时间函数', 'YEAR(date)', '返回SQL date日期的年份。等价于EXTRACT(YEAR FROM date)。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (140, 'function', '内置函数', '时间函数', 'QUARTER(date)', '从SQL date date返回一年中的季度(1到4之间的整数)。相当于EXTRACT(从日期起四分之一)。', '1.12', 0, 1, '2021-02-22 15:29:35', '2021-02-22 15:28:47');
INSERT INTO `dlink_flink_document` VALUES (141, 'function', '内置函数', '时间函数', 'MONTH(date)', '返回SQL date date中的某月(1到12之间的整数)。等价于EXTRACT(MONTH FROM date)。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (142, 'function', '内置函数', '时间函数', 'WEEK(date)', '从SQL date date返回一年中的某个星期(1到53之间的整数)。相当于EXTRACT(从日期开始的星期)。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (143, 'function', '内置函数', '时间函数', 'DAYOFYEAR(date)', '返回SQL date date中的某一天(1到366之间的整数)。相当于EXTRACT(DOY FROM date)。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (144, 'function', '内置函数', '时间函数', 'DAYOFMONTH(date)', '从SQL date date返回一个月的哪一天(1到31之间的整数)。相当于EXTRACT(DAY FROM date)。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (145, 'function', '内置函数', '时间函数', 'DAYOFWEEK(date)', '返回星期几(1到7之间的整数;星期日= 1)从SQL日期日期。相当于提取(道指从日期)。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (146, 'function', '内置函数', '时间函数', 'HOUR(timestamp)', '从SQL timestamp timestamp返回一天中的小时(0到23之间的整数)。相当于EXTRACT(HOUR FROM timestamp)。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (147, 'function', '内置函数', '时间函数', 'MINUTE(timestamp)', '从SQL timestamp timestamp返回一小时的分钟(0到59之间的整数)。相当于EXTRACT(分钟从时间戳)。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (148, 'function', '内置函数', '时间函数', 'SECOND(timestamp)', '从SQL时间戳返回一分钟中的秒(0到59之间的整数)。等价于EXTRACT(从时间戳开始倒数第二)。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (149, 'function', '内置函数', '时间函数', 'FLOOR(timepoint TO timeintervalunit)', '返回一个将timepoint舍入到时间单位timeintervalunit的值。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (150, 'function', '内置函数', '时间函数', 'CEIL(timepoint TO timeintervalunit)', '返回一个将timepoint舍入到时间单位timeintervalunit的值。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (151, 'function', '内置函数', '时间函数', '(timepoint1, temporal1) OVERLAPS (timepoint2, temporal2)', '如果(timepoint1, temporal1)和(timepoint2, temporal2)定义的两个时间间隔重叠,则返回TRUE。时间值可以是时间点或时间间隔。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (152, 'function', '内置函数', '时间函数', 'DATE_FORMAT(timestamp, string)', '注意这个功能有严重的错误,现在不应该使用。请实现一个自定义的UDF,或者使用EXTRACT作为解决方案。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (153, 'function', '内置函数', '时间函数', 'TIMESTAMPADD(timeintervalunit, interval, timepoint)', '返回一个新的时间值,该值将一个(带符号的)整数间隔添加到时间点。间隔的单位由unit参数给出,它应该是以下值之一:秒、分、小时、日、周、月、季度或年。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (154, 'function', '内置函数', '时间函数', 'TIMESTAMPDIFF(timepointunit, timepoint1, timepoint2)', '返回timepointunit在timepoint1和timepoint2之间的(带符号)数。间隔的单位由第一个参数给出,它应该是以下值之一:秒、分、小时、日、月或年。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (155, 'function', '内置函数', '时间函数', 'CONVERT_TZ(string1, string2, string3)', '将时区string2中的datetime string1(默认ISO时间戳格式\'yyyy-MM-dd HH:mm:ss\')转换为时区string3。时区的格式可以是缩写,如“PST”;可以是全名,如“America/Los_Angeles”;或者是自定义ID,如“GMT-8:00”。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (156, 'function', '内置函数', '时间函数', 'FROM_UNIXTIME(numeric[, string])', '以字符串格式返回数值参数的表示形式(默认为\'yyyy-MM-dd HH:mm:ss\')。numeric是一个内部时间戳值,表示从UTC \'1970-01-01 00:00:00\'开始的秒数,例如UNIX_TIMESTAMP()函数生成的时间戳。返回值用会话时区表示(在TableConfig中指定)。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (157, 'function', '内置函数', '时间函数', 'UNIX_TIMESTAMP()', '获取当前Unix时间戳(以秒为单位)。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (158, 'function', '内置函数', '时间函数', 'UNIX_TIMESTAMP(string1[, string2])', '转换日期时间字符串string1,格式为string2(缺省为yyyy-MM-dd HH:mm:ss,如果没有指定)为Unix时间戳(以秒为单位),使用表配置中指定的时区。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (159, 'function', '内置函数', '时间函数', 'TO_DATE(string1[, string2])', '将格式为string2的日期字符串string1(默认为\'yyyy-MM-dd\')转换为日期。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (160, 'function', '内置函数', '时间函数', 'TO_TIMESTAMP(string1[, string2])', '将会话时区(由TableConfig指定)下的日期时间字符串string1转换为时间戳,格式为string2(默认为\'yyyy-MM-dd HH:mm:ss\')。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (161, 'function', '内置函数', '时间函数', 'NOW()', '返回UTC时区内的当前SQL时间戳。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (162, 'function', '内置函数', '条件函数', 'CASE value\r\nWHEN value1_1 [, value1_2 ]* THEN result1\r\n[ WHEN value2_1 [, value2_2 ]* THEN result2 ]*\r\n[ ELSE resultZ ]\r\nEND', '当第一个时间值包含在(valueX_1, valueX_2,…)中时,返回resultX。如果没有匹配的值,则返回resultZ,否则返回NULL。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (163, 'function', '内置函数', '条件函数', 'CASE\r\nWHEN condition1 THEN result1\r\n[ WHEN condition2 THEN result2 ]*\r\n[ ELSE resultZ ]\r\nEND', '当第一个条件满足时返回resultX。当不满足任何条件时,如果提供了resultZ则返回resultZ,否则返回NULL。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (164, 'function', '内置函数', '条件函数', 'NULLIF(value1, value2)', '如果value1等于value2,则返回NULL;否则返回value1。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (165, 'function', '内置函数', '条件函数', 'COALESCE(value1, value2 [, value3 ]* )', '返回value1, value2, ....中的第一个非空值', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (166, 'function', '内置函数', '条件函数', 'IF(condition, true_value, false_value)', '如果条件满足则返回true值,否则返回false值。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (167, 'function', '内置函数', '条件函数', 'IS_ALPHA(string)', '如果字符串中所有字符都是字母则返回true,否则返回false。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (168, 'function', '内置函数', '条件函数', 'IS_DECIMAL(string)', '如果字符串可以被解析为有效的数字则返回true,否则返回false。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (169, 'function', '内置函数', '条件函数', 'IS_DIGIT(string)', '如果字符串中所有字符都是数字则返回true,否则返回false。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (170, 'function', '内置函数', '类型转换函数功能', 'CAST(value AS type)', '返回一个要转换为type类型的新值。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (171, 'function', '内置函数', 'Collection 函数', 'CARDINALITY(array)', '返回数组中元素的数量。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (172, 'function', '内置函数', 'Collection 函数', 'array ‘[’ integer ‘]’', '返回数组中位于整数位置的元素。索引从1开始。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (173, 'function', '内置函数', 'Collection 函数', 'ELEMENT(array)', '返回数组的唯一元素(其基数应为1);如果数组为空,则返回NULL。如果数组有多个元素,则抛出异常。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (174, 'function', '内置函数', 'Collection 函数', 'CARDINALITY(map)', '返回map中的条目数。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (175, 'function', '内置函数', 'Collection 函数', 'map ‘[’ value ‘]’', '返回map中key value指定的值。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (176, 'function', '内置函数', 'Value Construction函数', '-- implicit constructor with parenthesis\r\n(value1 [, value2]*)\r\n\r\n-- explicit ROW constructor\r\nROW(value1 [, value2]*)', '返回从值列表(value1, value2,…)创建的行。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (177, 'function', '内置函数', 'Value Construction函数', 'ARRAY ‘[’ value1 [, value2 ]* ‘]’', '返回一个由一系列值(value1, value2,…)创建的数组。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (178, 'function', '内置函数', 'Value Construction函数', 'MAP ‘[’ value1, value2 [, value3, value4 ]* ‘]’', '返回一个从键值对列表((value1, value2), (value3, value4),…)创建的映射。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (179, 'function', '内置函数', 'Value Access函数', 'tableName.compositeType.field', '按名称从Flink复合类型(例如,Tuple, POJO)中返回一个字段的值。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (180, 'function', '内置函数', 'Value Access函数', 'tableName.compositeType.*', '返回Flink复合类型(例如,Tuple, POJO)的平面表示,它将每个直接子类型转换为一个单独的字段。在大多数情况下,平面表示的字段的名称与原始字段类似,但使用了$分隔符(例如,mypojo$mytuple$f0)。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (181, 'function', '内置函数', '分组函数', 'GROUP_ID()', '返回唯一标识分组键组合的整数', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (182, 'function', '内置函数', '分组函数', 'GROUPING(expression1 [, expression2]* )\r\nGROUPING_ID(expression1 [, expression2]* )', '返回给定分组表达式的位向量。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (183, 'function', '内置函数', 'hash函数', 'MD5(string)', '以32位十六进制数字的字符串形式返回string的MD5哈希值;如果字符串为NULL,则返回NULL。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (184, 'function', '内置函数', 'hash函数', 'SHA1(string)', '返回字符串的SHA-1散列,作为一个由40个十六进制数字组成的字符串;如果字符串为NULL,则返回NULL', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (185, 'function', '内置函数', 'hash函数', 'SHA224(string)', '以56位十六进制数字的字符串形式返回字符串的SHA-224散列;如果字符串为NULL,则返回NULL。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (186, 'function', '内置函数', 'hash函数', 'SHA256(string)', '以64位十六进制数字的字符串形式返回字符串的SHA-256散列;如果字符串为NULL,则返回NULL。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (187, 'function', '内置函数', 'hash函数', 'SHA384(string)', '以96个十六进制数字的字符串形式返回string的SHA-384散列;如果字符串为NULL,则返回NULL。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (188, 'function', '内置函数', 'hash函数', 'SHA512(string)', '以128位十六进制数字的字符串形式返回字符串的SHA-512散列;如果字符串为NULL,则返回NULL。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (189, 'function', '内置函数', 'hash函数', 'SHA2(string, hashLength)', '使用SHA-2哈希函数族(SHA-224、SHA-256、SHA-384或SHA-512)返回哈希值。第一个参数string是要散列的字符串,第二个参数hashLength是结果的位长度(224、256、384或512)。如果string或hashLength为NULL,则返回NULL。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (190, 'function', '内置函数', '聚合函数', 'COUNT([ ALL ] expression | DISTINCT expression1 [, expression2]*)', '默认情况下或使用ALL时,返回表达式不为空的输入行数。对每个值的唯一实例使用DISTINCT。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (191, 'function', '内置函数', '聚合函数', 'COUNT(*)\r\nCOUNT(1)', '返回输入行数。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (192, 'function', '内置函数', '聚合函数', 'AVG([ ALL | DISTINCT ] expression)', '默认情况下,或使用关键字ALL,返回表达式在所有输入行中的平均值(算术平均值)。对每个值的唯一实例使用DISTINCT。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (193, 'function', '内置函数', '聚合函数', 'SUM([ ALL | DISTINCT ] expression)', '默认情况下,或使用关键字ALL,返回所有输入行表达式的和。对每个值的唯一实例使用DISTINCT。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (194, 'function', '内置函数', '聚合函数', 'MAX([ ALL | DISTINCT ] expression)', '默认情况下或使用关键字ALL,返回表达式在所有输入行中的最大值。对每个值的唯一实例使用DISTINCT。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (195, 'function', '内置函数', '聚合函数', 'MIN([ ALL | DISTINCT ] expression)', '默认情况下,或使用关键字ALL,返回表达式在所有输入行中的最小值。对每个值的唯一实例使用DISTINCT。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (196, 'function', '内置函数', '聚合函数', 'STDDEV_POP([ ALL | DISTINCT ] expression)', '默认情况下,或使用关键字ALL,返回表达式在所有输入行中的总体标准差。对每个值的唯一实例使用DISTINCT。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (197, 'function', '内置函数', '聚合函数', 'STDDEV_SAMP([ ALL | DISTINCT ] expression)', '默认情况下或使用关键字ALL时,返回表达式在所有输入行中的样本标准差。对每个值的唯一实例使用DISTINCT。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (198, 'function', '内置函数', '聚合函数', 'VAR_POP([ ALL | DISTINCT ] expression)', '默认情况下,或使用关键字ALL,返回表达式在所有输入行中的总体方差(总体标准差的平方)。对每个值的唯一实例使用DISTINCT。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (199, 'function', '内置函数', '聚合函数', 'VAR_SAMP([ ALL | DISTINCT ] expression)', '默认情况下,或使用关键字ALL,返回表达式在所有输入行中的样本方差(样本标准差的平方)。对每个值的唯一实例使用DISTINCT。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (200, 'function', '内置函数', '聚合函数', 'COLLECT([ ALL | DISTINCT ] expression)', '默认情况下,或使用关键字ALL,跨所有输入行返回表达式的多集。空值将被忽略。对每个值的唯一实例使用DISTINCT。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (201, 'function', '内置函数', '聚合函数', 'VARIANCE([ ALL | DISTINCT ] expression)', 'VAR_SAMP的同义词。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (202, 'function', '内置函数', '聚合函数', 'RANK()', '返回值在一组值中的秩。结果是1加上分区顺序中位于当前行之前或等于当前行的行数。这些值将在序列中产生空白。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (203, 'function', '内置函数', '聚合函数', 'DENSE_RANK()', '返回值在一组值中的秩。结果是1加上前面分配的秩值。与函数rank不同,dense_rank不会在排序序列中产生空隙。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (204, 'function', '内置函数', '聚合函数', 'ROW_NUMBER()', '根据窗口分区中的行顺序,为每一行分配一个惟一的连续数字,从1开始。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (205, 'function', '内置函数', '聚合函数', 'LEAD(expression [, offset] [, default] )', '返回表达式在窗口中当前行之前的偏移行上的值。offset的默认值是1,default的默认值是NULL。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (206, 'function', '内置函数', '聚合函数', 'LAG(expression [, offset] [, default])', '返回表达式的值,该值位于窗口中当前行之后的偏移行。offset的默认值是1,default的默认值是NULL。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (207, 'function', '内置函数', '聚合函数', 'FIRST_VALUE(expression)', '返回一组有序值中的第一个值。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (208, 'function', '内置函数', '聚合函数', 'LAST_VALUE(expression)', '返回一组有序值中的最后一个值。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (209, 'function', '内置函数', '聚合函数', 'LISTAGG(expression [, separator])', '连接字符串表达式的值,并在它们之间放置分隔符值。分隔符没有添加在字符串的末尾。分隔符的默认值是\'\'。仅在blink planner中支持。', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (210, 'function', '内置函数', '列函数', 'withColumns(…)', '选择的列', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (211, 'function', '内置函数', '列函数', 'withoutColumns(…)', '不选择的列', '1.12', 0, 1, '2021-02-22 15:46:48', '2021-02-22 15:47:21');
INSERT INTO `dlink_flink_document` VALUES (262, 'function', 'UDF', '表值聚合函数', 'TO_MAP(string1,object2[, string3])', '将非规则一维表转化为规则二维表,string1是key。string2是value。string3为非必填项,表示key的值域(维度),用英文逗号分割。', '1.12', 8, 1, '2021-05-20 19:59:22', '2021-05-20 20:00:54');
SET FOREIGN_KEY_CHECKS = 1; SET FOREIGN_KEY_CHECKS = 1;
...@@ -45,7 +45,7 @@ export default [ ...@@ -45,7 +45,7 @@ export default [
icon: 'cluster', icon: 'cluster',
component: './Cluster', component: './Cluster',
}, },
{ /*{
path: '/dev', path: '/dev',
name: 'dev', name: 'dev',
icon: 'crown', icon: 'crown',
...@@ -78,7 +78,7 @@ export default [ ...@@ -78,7 +78,7 @@ export default [
], ],
}, },
], ],
}, },*/
/*{ /*{
path: '/admin', path: '/admin',
name: 'admin', name: 'admin',
...@@ -94,7 +94,7 @@ export default [ ...@@ -94,7 +94,7 @@ export default [
}, },
], ],
},*/ },*/
{ /*{
path: '/demo', path: '/demo',
name: 'demo', name: 'demo',
icon: 'crown', icon: 'crown',
...@@ -139,7 +139,7 @@ export default [ ...@@ -139,7 +139,7 @@ export default [
], ],
}, },
], ],
}, },*/
{ {
path: '/', path: '/',
redirect: '/welcome', redirect: '/welcome',
......
import {message, Input, Button, Space, Table, Dropdown, Menu, Empty,Divider} from "antd";
import {StateType} from "@/pages/FlinkSqlStudio/model";
import {connect} from "umi";
import {useState} from "react";
// import Highlighter from 'react-highlight-words';
import { SearchOutlined,DownOutlined,TableOutlined } from '@ant-design/icons';
import React from "react";
import {executeDDL} from "@/pages/FlinkSqlStudio/service";
const StudioConnector = (props:any) => {
const {current} = props;
const [tableData,setTableData] = useState<[]>([]);
const [loadings,setLoadings] = useState<boolean[]>([]);
const [searchText,setSearchText] = useState<string>('');
const [searchedColumn,setSearchedColumn] = useState<string>('');
const getColumnSearchProps = (dIndex) => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}>
<Input
placeholder={`Search ${dIndex}`}
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => handleSearch(selectedKeys, confirm, dIndex)}
style={{ marginBottom: 8, display: 'block' }}
/>
<Space>
<Button
type="primary"
onClick={() => handleSearch(selectedKeys, confirm, dIndex)}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
搜索
</Button>
<Button onClick={() => handleReset(clearFilters)} size="small" style={{ width: 90 }}>
重置
</Button>
<Button
type="link"
size="small"
onClick={() => {
setSearchText(selectedKeys[0]);
setSearchedColumn(dIndex);
}}
>
过滤
</Button>
</Space>
</div>
),
filterIcon: filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />,
onFilter: (value, record) =>
record[dIndex]
? record[dIndex].toString().toLowerCase().includes(value.toLowerCase())
: '',
/*render: text =>
searchedColumn === dIndex ? (
<Highlighter
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
searchWords={[searchText]}
autoEscape
textToHighlight={text ? text.toString() : ''}
/>
) : (
text
),*/
});
const handleSearch = (selectedKeys, confirm, dIndex) => {
confirm();
setSearchText(selectedKeys[0]);
setSearchedColumn(dIndex);
};
const handleReset = (clearFilters) => {
clearFilters();
setSearchText('');
};
const MoreBtn: React.FC<{
item:any
}> = ({item}) => (
<Dropdown
overlay={
<Menu onClick={({key}) => keyEvent(key, item)}>
<Menu.Item key="desc">描述</Menu.Item>
<Menu.Item key="delete">删除</Menu.Item>
</Menu>
}
>
<a>
更多 <DownOutlined/>
</a>
</Dropdown>
);
const keyEvent=(key, item)=>{
if(key=='delete'){
let newLoadings = [...loadings];
newLoadings[1] = true;
setLoadings(newLoadings);
const res = executeDDL({
statement:"drop table "+item.tablename,
clusterId: current.task.clusterId,
session:current.task.session,
});
res.then((result)=>{
if(result.datas.success){
let newTableData = tableData;
for (let i=0; i<newTableData.length; i++) {
if (newTableData[i].tablename == item.tablename) {
newTableData.splice(i, 1);
setTableData(newTableData);
break;
}
}
}
let newLoadings = [...loadings];
newLoadings[1] = false;
setLoadings(newLoadings);
});
}else{
message.warn("敬请期待");
}
};
const getTables = () => {
let newLoadings = [...loadings];
newLoadings[0] = true;
setLoadings(newLoadings);
const res = executeDDL({
statement:"show tables",
clusterId: current.task.clusterId,
session:current.task.session,
});
res.then((result)=>{
if(result.datas.result.rowData.length>0){
setTableData(result.datas.result.rowData);
}else {
setTableData([]);
}
let newLoadings = [...loadings];
newLoadings[0] = false;
setLoadings(newLoadings);
});
};
const getColumns=()=>{
let columns:any=[{
title: "表名",
dataIndex: "tablename",
key: "tablename",
sorter: true,
...getColumnSearchProps("tablename"),
},{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => [
<a
onClick={() => {
message.warn('敬请期待');
}}
>
描述
</a>,<Divider type="vertical" />,<a
onClick={() => {
keyEvent('delete',record);
}}
>
删除
</a>
],
},];
return columns;
};
return (
<>
<Button
type="primary"
icon={<TableOutlined />}
loading={loadings[0]}
onClick={() => getTables()}
>
获取Connectors
</Button>
{tableData.length>0?(<Table dataSource={tableData} columns={getColumns()} />):(<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />)}
</>
);
};
export default connect(({ Studio }: { Studio: StateType }) => ({
current: Studio.current,
}))(StudioConnector);
import {DownOutlined, HeartOutlined, PlusOutlined, UserOutlined} from '@ant-design/icons';
import {Button, message, Input, Drawer, Modal} from 'antd';
import React, {useState, useRef} from 'react';
import {PageContainer, FooterToolbar} from '@ant-design/pro-layout';
import type {ProColumns, ActionType} from '@ant-design/pro-table';
import ProTable from '@ant-design/pro-table';
import ProDescriptions from '@ant-design/pro-descriptions';
import type {DocumentTableListItem} from '@/pages/Document/data.d';
import { queryData,} from "@/components/Common/crud";
import {connect} from "umi";
import {StateType} from "@/pages/FlinkSqlStudio/model";
const url = '/api/document';
const StudioDocument = () => {
const actionRef = useRef<ActionType>();
const [row, setRow] = useState<DocumentTableListItem>();
const columns: ProColumns<DocumentTableListItem>[] = [
{
title: '名称',
dataIndex: 'name',
tip: '名称是唯一的',
sorter: true,
width:'400px',
formItemProps: {
rules: [
{
required: true,
message: '名称为必填项',
},
],
},
render: (dom, entity) => {
return <a onClick={() => setRow(entity)}>{dom}</a>;
},
},
{
title: '文档ID',
dataIndex: 'id',
hideInTable: true,
hideInForm: true,
hideInSearch: true,
},
{
title: '文档类型',
sorter: true,
dataIndex: 'category',
hideInForm: false,
hideInSearch: true,
hideInTable: true,
filters: [
{
text: '函数',
value: 'function',
}
],
filterMultiple: false,
valueEnum: {
'function': { text: '函数'},
},
},
{
title: '类型',
sorter: true,
dataIndex: 'type',
hideInForm: false,
hideInSearch: true,
hideInTable: false,
filters: [
{
text: '内置函数',
value: '内置函数',
},
{
text: 'UDF',
value: 'UDF',
},
],
filterMultiple: false,
valueEnum: {
'内置函数': { text: '内置函数'},
'UDF': { text: 'UDF'},
},
},
{
title: '子类型',
sorter: true,
dataIndex: 'subtype',
hideInForm: false,
hideInSearch: true,
hideInTable: false,
filters: [
{
text: '比较函数',
value: '比较函数',
},
{
text: '逻辑函数',
value: '逻辑函数',
},{
text: '算术函数',
value: '算术函数',
},{
text: '字符串函数',
value: '字符串函数',
},{
text: '时间函数',
value: '时间函数',
},{
text: '条件函数',
value: '条件函数',
},{
text: '类型转换函数',
value: '类型转换函数',
},{
text: 'Collection 函数',
value: 'Collection 函数',
},{
text: 'Value Collection 函数',
value: 'Value Collection 函数',
},{
text: 'Value Access 函数',
value: 'Value Access 函数',
},{
text: '分组函数',
value: '分组函数',
},{
text: 'hash函数',
value: 'hash函数',
},{
text: '聚合函数',
value: '聚合函数',
},{
text: '列函数',
value: '列函数',
},{
text: '表值聚合函数',
value: '表值聚合函数',
},{
text: '其他函数',
value: '其他函数',
},
],
filterMultiple: false,
valueEnum: {
'比较函数': { text: '比较函数'},
'逻辑函数': { text: '逻辑函数'},
'算术函数': { text: '算术函数'},
'字符串函数': { text: '字符串函数'},
'时间函数': { text: '时间函数'},
'条件函数': { text: '条件函数'},
'类型转换函数': { text: '类型转换函数'},
'Collection 函数': { text: 'Collection 函数'},
'Value Collection 函数': { text: 'Value Collection 函数'},
'Value Access 函数': { text: 'Value Access 函数'},
'分组函数': { text: '分组函数'},
'hash函数': { text: 'hash函数'},
'聚合函数': { text: '聚合函数'},
'列函数': { text: '列函数'},
'表值聚合函数': { text: '表值聚合函数'},
'其他函数': { text: '其他函数'},
},
},
{
title: '描述',
sorter: true,
dataIndex: 'description',
valueType: 'textarea',
hideInForm: false,
hideInSearch: false,
hideInTable: false,
width:'400px',
},
{
title: '版本',
sorter: true,
dataIndex: 'version',
hideInForm: true,
hideInSearch: true,
hideInTable: true,
},{
title: '赞',
sorter: true,
dataIndex: 'likeNum',
hideInForm: true,
hideInSearch: true,
hideInTable: false,
},
{
title: '是否启用',
dataIndex: 'enabled',
hideInForm: true,
hideInSearch: true,
hideInTable: true,
filters: [
{
text: '已启用',
value: 1,
},
{
text: '已禁用',
value: 0,
},
],
filterMultiple: false,
valueEnum: {
true: { text: '已启用', status: 'Success' },
false: { text: '已禁用', status: 'Error' },
},
},
{
title: '创建时间',
dataIndex: 'createTime',
sorter: true,
valueType: 'dateTime',
hideInForm: true,
hideInTable:true,
hideInSearch:true,
renderFormItem: (item, { defaultRender, ...rest }, form) => {
const status = form.getFieldValue('status');
if (`${status}` === '0') {
return false;
}
if (`${status}` === '3') {
return <Input {...rest} placeholder="请输入异常原因!" />;
}
return defaultRender(item);
},
},
{
title: '最近更新时间',
dataIndex: 'updateTime',
sorter: true,
valueType: 'dateTime',
hideInForm: true,
hideInTable:true,
hideInSearch:true,
renderFormItem: (item, { defaultRender, ...rest }, form) => {
const status = form.getFieldValue('status');
if (`${status}` === '0') {
return false;
}
if (`${status}` === '3') {
return <Input {...rest} placeholder="请输入异常原因!" />;
}
return defaultRender(item);
},
},
];
return (
<>
<ProTable<DocumentTableListItem>
headerTitle="文档管理"
actionRef={actionRef}
rowKey="id"
search={{
labelWidth: 120,
}}
request={(params, sorter, filter) => queryData(url,{...params, sorter, filter})}
columns={columns}
/>
<Drawer
width={600}
visible={!!row}
onClose={() => {
setRow(undefined);
}}
closable={false}
>
{row?.name && (
<ProDescriptions<DocumentTableListItem>
column={2}
title={row?.name}
request={async () => ({
data: row || {},
})}
params={{
id: row?.name,
}}
columns={columns}
/>
)}
</Drawer>
</>);
};
export default connect(({ Studio }: { Studio: StateType }) => ({
current: Studio.current,
}))(StudioDocument);
import {Typography, Divider, Badge, Empty} from "antd";
import {StateType} from "@/pages/FlinkSqlStudio/model";
import {connect} from "umi";
const { Title, Paragraph, Text, Link } = Typography;
const StudioHistory = (props:any) => {
const {current} = props;
return (
<Typography>
{current.console.result.map((item)=> {
return (<Paragraph>
<blockquote><Link href={`http://${item.flinkHost}:${item.flinkPort}`} target="_blank">
[{item.sessionId}:{item.flinkHost}:{item.flinkPort}]
</Link> <Divider type="vertical" />{item.finishDate}
<Divider type="vertical" />
{!item.success ? <><Badge status="error"/><Text type="danger">Error</Text></> :
<><Badge status="success"/><Text type="success">Success</Text></>}
<Divider type="vertical" />
{item.jobId&&<Text code>{item.jobId}</Text>}
<Text keyboard>{item.time}ms</Text></blockquote>
{item.statement && (<pre style={{height:'40px'}}>{item.statement}</pre>)}
{item.msg ? item.msg : ''}
{item.error && (<pre style={{height:'100px'}}>{item.error}</pre>)}
</Paragraph>)
})}
{current.console.result.length==0?<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />:''}
</Typography>
);
};
export default connect(({ Studio }: { Studio: StateType }) => ({
current: Studio.current,
}))(StudioHistory);
import { Typography,Divider,Badge } from "antd"; import {Typography, Divider, Badge, Empty} from "antd";
import {StateType} from "@/pages/FlinkSqlStudio/model"; import {StateType} from "@/pages/FlinkSqlStudio/model";
import {connect} from "umi"; import {connect} from "umi";
...@@ -10,21 +10,27 @@ const StudioMsg = (props:any) => { ...@@ -10,21 +10,27 @@ const StudioMsg = (props:any) => {
return ( return (
<Typography> <Typography>
{current.console.result.map((item)=> { {current.console.result.map((item,index)=> {
if(index==0) {
return (<Paragraph> return (<Paragraph>
<blockquote><Link href={`http://${item.flinkHost}:${item.flinkPort}`} target="_blank"> <blockquote><Link href={`http://${item.flinkHost}:${item.flinkPort}`} target="_blank">
[{item.sessionId}:{item.flinkHost}:{item.flinkPort}] [{item.sessionId}:{item.flinkHost}:{item.flinkPort}]
</Link> <Divider type="vertical" />{item.finishDate} </Link> <Divider type="vertical"/>{item.finishDate}
<Divider type="vertical" /> <Divider type="vertical"/>
{!item.success ? <><Badge status="error"/><Text type="danger">Error</Text></> : {!item.success ? <><Badge status="error"/><Text type="danger">Error</Text></> :
<><Badge status="success"/><Text type="success">Success</Text></>} <><Badge status="success"/><Text type="success">Success</Text></>}
<Divider type="vertical" /> <Divider type="vertical"/>
{item.jobId&&<Text code>{item.jobId}</Text>}
<Text keyboard>{item.time}ms</Text></blockquote> <Text keyboard>{item.time}ms</Text></blockquote>
{item.statement && (<pre style={{height:'40px'}}>{item.statement}</pre>)} {item.statement && (<pre style={{height: '100px'}}>{item.statement}</pre>)}
{item.msg ? item.msg : ''} {item.msg ? item.msg : ''}
{item.error && (<pre style={{height:'100px'}}>{item.error}</pre>)} {item.error && (<pre style={{height: '100px'}}>{item.error}</pre>)}
</Paragraph>) </Paragraph>)
}else{
return '';
}
})} })}
{current.console.result.length==0?<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />:''}
</Typography> </Typography>
); );
}; };
......
import { Typography,Divider,Badge,Select,Tag,Form} from "antd"; import {Typography, Input, Button, Space, Table, Select, Tag, Form, Empty} from "antd";
import {StateType} from "@/pages/FlinkSqlStudio/model"; import {StateType} from "@/pages/FlinkSqlStudio/model";
import {connect} from "umi"; import {connect} from "umi";
import {useState} from "react";
// import Highlighter from 'react-highlight-words';
import { SearchOutlined } from '@ant-design/icons';
const { Option } = Select; const { Option } = Select;
const { Title, Paragraph, Text, Link } = Typography; const { Title, Paragraph, Text, Link } = Typography;
...@@ -9,16 +12,101 @@ const { Title, Paragraph, Text, Link } = Typography; ...@@ -9,16 +12,101 @@ const { Title, Paragraph, Text, Link } = Typography;
const StudioTable = (props:any) => { const StudioTable = (props:any) => {
const {current} = props; const {current} = props;
const [dataIndex,setDataIndex] = useState<number>(0);
const [searchText,setSearchText] = useState<string>('');
const [searchedColumn,setSearchedColumn] = useState<string>('');
const getColumnSearchProps = (dIndex) => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}>
<Input
placeholder={`Search ${dIndex}`}
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => handleSearch(selectedKeys, confirm, dIndex)}
style={{ marginBottom: 8, display: 'block' }}
/>
<Space>
<Button
type="primary"
onClick={() => handleSearch(selectedKeys, confirm, dIndex)}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
搜索
</Button>
<Button onClick={() => handleReset(clearFilters)} size="small" style={{ width: 90 }}>
重置
</Button>
<Button
type="link"
size="small"
onClick={() => {
setSearchText(selectedKeys[0]);
setSearchedColumn(dIndex);
}}
>
过滤
</Button>
</Space>
</div>
),
filterIcon: filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />,
onFilter: (value, record) =>
record[dIndex]
? record[dIndex].toString().toLowerCase().includes(value.toLowerCase())
: '',
/*render: text =>
searchedColumn === dIndex ? (
<Highlighter
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
searchWords={[searchText]}
autoEscape
textToHighlight={text ? text.toString() : ''}
/>
) : (
text
),*/
});
const handleSearch = (selectedKeys, confirm, dIndex) => {
confirm();
setSearchText(selectedKeys[0]);
setSearchedColumn(dIndex);
};
const handleReset = (clearFilters) => {
clearFilters();
setSearchText('');
};
const getColumns=(columns:[])=>{
let datas:any=[];
columns.map((item)=> {
datas.push({
title: item,
dataIndex: item,
key: item,
sorter: true,
...getColumnSearchProps(item),
});
});
return datas;
};
const onChange=(val:number)=>{
setDataIndex(val);
};
return ( return (
<Typography> <Typography>
<Form.Item label="当前执行记录" tooltip="选择最近的执行记录,仅包含成功的记录"> <Form.Item label="当前执行记录" tooltip="选择最近的执行记录,仅包含成功的记录">
<Select <Select
//mode="multiple"
style={{ width: '100%' }} style={{ width: '100%' }}
placeholder="选择最近的执行记录" placeholder="选择最近的执行记录"
defaultValue={[0]}
optionLabelProp="label" optionLabelProp="label"
onChange={onChange}
> >
{current.console.result.map((item,index)=> { {current.console.result.map((item,index)=> {
if(item.success) { if(item.success) {
...@@ -33,6 +121,7 @@ const StudioTable = (props:any) => { ...@@ -33,6 +121,7 @@ const StudioTable = (props:any) => {
})} })}
</Select> </Select>
</Form.Item> </Form.Item>
{current.console.result[dataIndex]&&current.console.result[dataIndex].result?(<Table dataSource={current.console.result[dataIndex].result.rowData} columns={getColumns(current.console.result[dataIndex].result.columns)} />):(<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />)}
</Typography> </Typography>
); );
}; };
......
...@@ -6,6 +6,8 @@ import {connect} from "umi"; ...@@ -6,6 +6,8 @@ import {connect} from "umi";
import styles from "./index.less"; import styles from "./index.less";
import StudioMsg from "./StudioMsg"; import StudioMsg from "./StudioMsg";
import StudioTable from "./StudioTable"; import StudioTable from "./StudioTable";
import StudioHistory from "./StudioHistory";
import StudioDocument from "./StudioDocument";
const { TabPane } = Tabs; const { TabPane } = Tabs;
...@@ -68,7 +70,7 @@ const StudioConsole = (props:any) => { ...@@ -68,7 +70,7 @@ const StudioConsole = (props:any) => {
} }
key="5" key="5"
> >
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> <StudioHistory />
</TabPane> </TabPane>
<TabPane <TabPane
tab={ tab={
...@@ -79,7 +81,7 @@ const StudioConsole = (props:any) => { ...@@ -79,7 +81,7 @@ const StudioConsole = (props:any) => {
} }
key="6" key="6"
> >
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> <StudioDocument />
</TabPane> </TabPane>
<TabPane <TabPane
tab={ tab={
......
...@@ -8,7 +8,42 @@ const Completion =[ ...@@ -8,7 +8,42 @@ const Completion =[
insertText: 'SUM(${1:})', insertText: 'SUM(${1:})',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
detail: '返回指定参数的求和' detail: '返回指定参数的求和'
} },
{
label: 'SQRT(number)',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'SQRT(${1:})',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
detail: '返回指定参数的平方根'
},
{
label: 'SIN(number)',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'SIN(${1:})',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
detail: '返回指定参数的正弦值'
},
{
label: 'SINH(number)',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'SINH(${1:})',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
detail: '返回指定参数的双曲正弦值'
},
{
label: 'SIGN(number)',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'SIGN(${1:})',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
detail: '返回指定参数的符合'
},
{
label: 'SUBSTRING(string,integer1,integer2)',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'SUBSTRING(${1:})',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
detail: '返回指定字符串的子字符串'
},
]; ];
export default Completion; export default Completion;
...@@ -31,4 +31,11 @@ export type CompletionItem ={ ...@@ -31,4 +31,11 @@ export type CompletionItem ={
} }
export type StudioParam = { export type StudioParam = {
statement:string, statement:string,
checkPoint?: number,
savePointPath?: string,
parallelism?: number,
fragment?: boolean,
clusterId: number,
session:string,
maxRowNum?: number,
} }
...@@ -29,10 +29,9 @@ const FlinkSqlEditor = (props:any) => { ...@@ -29,10 +29,9 @@ const FlinkSqlEditor = (props:any) => {
selectOnLineNumbers: true, selectOnLineNumbers: true,
renderSideBySide: false, renderSideBySide: false,
}, },
sql=props.current.value,
current=props.current, current=props.current,
// sql,
dispatch, dispatch,
monaco,
} = props } = props
; ;
...@@ -48,6 +47,7 @@ const FlinkSqlEditor = (props:any) => { ...@@ -48,6 +47,7 @@ const FlinkSqlEditor = (props:any) => {
const cache: any = useRef(code.current); const cache: any = useRef(code.current);
const [refresh, setRefresh] = React.useState<boolean>(false); const [refresh, setRefresh] = React.useState<boolean>(false);
const [selectValue, setSelectValue] = React.useState<string>("");
useEffect( useEffect(
() => () => { () => () => {
...@@ -113,7 +113,6 @@ const FlinkSqlEditor = (props:any) => { ...@@ -113,7 +113,6 @@ const FlinkSqlEditor = (props:any) => {
} }
}); });
code.current = newSecondRightFields; // 数组长度永远为1 code.current = newSecondRightFields; // 数组长度永远为1
// 提示项设值 // 提示项设值
provider = monaco.languages.registerCompletionItemProvider('sql', { provider = monaco.languages.registerCompletionItemProvider('sql', {
provideCompletionItems() { provideCompletionItems() {
...@@ -149,6 +148,7 @@ const FlinkSqlEditor = (props:any) => { ...@@ -149,6 +148,7 @@ const FlinkSqlEditor = (props:any) => {
return ( return (
<React.Fragment> <React.Fragment>
<MonacoEditor <MonacoEditor
ref={monaco}
width={width} width={width}
height={height} height={height}
language={language} language={language}
...@@ -158,6 +158,7 @@ return ( ...@@ -158,6 +158,7 @@ return (
theme="vs-dark" theme="vs-dark"
editorDidMount={editorDidMountHandle} editorDidMount={editorDidMountHandle}
/> />
{selectValue}
</React.Fragment> </React.Fragment>
); );
}; };
...@@ -166,4 +167,5 @@ export default connect(({ Studio }: { Studio: StateType }) => ({ ...@@ -166,4 +167,5 @@ export default connect(({ Studio }: { Studio: StateType }) => ({
current: Studio.current, current: Studio.current,
sql: Studio.sql, sql: Studio.sql,
tabs: Studio.tabs, tabs: Studio.tabs,
monaco: Studio.monaco,
}))(FlinkSqlEditor); }))(FlinkSqlEditor);
import {message, Input, Button, Space, Table, Dropdown, Menu, Empty,Divider} from "antd";
import {StateType} from "@/pages/FlinkSqlStudio/model";
import {connect} from "umi";
import {useState} from "react";
// import Highlighter from 'react-highlight-words';
import { SearchOutlined,DownOutlined,TableOutlined } from '@ant-design/icons';
import React from "react";
import {executeDDL} from "@/pages/FlinkSqlStudio/service";
const StudioConnector = (props:any) => {
const {current} = props;
const [tableData,setTableData] = useState<[]>([]);
const [loadings,setLoadings] = useState<boolean[]>([]);
const [searchText,setSearchText] = useState<string>('');
const [searchedColumn,setSearchedColumn] = useState<string>('');
const getColumnSearchProps = (dIndex) => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}>
<Input
placeholder={`Search ${dIndex}`}
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => handleSearch(selectedKeys, confirm, dIndex)}
style={{ marginBottom: 8, display: 'block' }}
/>
<Space>
<Button
type="primary"
onClick={() => handleSearch(selectedKeys, confirm, dIndex)}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
搜索
</Button>
<Button onClick={() => handleReset(clearFilters)} size="small" style={{ width: 90 }}>
重置
</Button>
<Button
type="link"
size="small"
onClick={() => {
setSearchText(selectedKeys[0]);
setSearchedColumn(dIndex);
}}
>
过滤
</Button>
</Space>
</div>
),
filterIcon: filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />,
onFilter: (value, record) =>
record[dIndex]
? record[dIndex].toString().toLowerCase().includes(value.toLowerCase())
: '',
/*render: text =>
searchedColumn === dIndex ? (
<Highlighter
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
searchWords={[searchText]}
autoEscape
textToHighlight={text ? text.toString() : ''}
/>
) : (
text
),*/
});
const handleSearch = (selectedKeys, confirm, dIndex) => {
confirm();
setSearchText(selectedKeys[0]);
setSearchedColumn(dIndex);
};
const handleReset = (clearFilters) => {
clearFilters();
setSearchText('');
};
const MoreBtn: React.FC<{
item:any
}> = ({item}) => (
<Dropdown
overlay={
<Menu onClick={({key}) => keyEvent(key, item)}>
<Menu.Item key="desc">描述</Menu.Item>
<Menu.Item key="delete">删除</Menu.Item>
</Menu>
}
>
<a>
更多 <DownOutlined/>
</a>
</Dropdown>
);
const keyEvent=(key, item)=>{
if(key=='delete'){
let newLoadings = [...loadings];
newLoadings[1] = true;
setLoadings(newLoadings);
const res = executeDDL({
statement:"drop table "+item.tablename,
clusterId: current.task.clusterId,
session:current.task.session,
});
res.then((result)=>{
if(result.datas.success){
let newTableData = tableData;
for (let i=0; i<newTableData.length; i++) {
if (newTableData[i].tablename == item.tablename) {
newTableData.splice(i, 1);
setTableData(newTableData);
break;
}
}
}
let newLoadings = [...loadings];
newLoadings[1] = false;
setLoadings(newLoadings);
});
}else{
message.warn("敬请期待");
}
};
const getTables = () => {
let newLoadings = [...loadings];
newLoadings[0] = true;
setLoadings(newLoadings);
const res = executeDDL({
statement:"show tables",
clusterId: current.task.clusterId,
session:current.task.session,
});
res.then((result)=>{
if(result.datas.result.rowData.length>0){
setTableData(result.datas.result.rowData);
}else {
setTableData([]);
}
let newLoadings = [...loadings];
newLoadings[0] = false;
setLoadings(newLoadings);
});
};
const getColumns=()=>{
let columns:any=[{
title: "表名",
dataIndex: "tablename",
key: "tablename",
sorter: true,
...getColumnSearchProps("tablename"),
},{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => [
<a
onClick={() => {
message.warn('敬请期待');
}}
>
描述
</a>,<Divider type="vertical" />,<a
onClick={() => {
keyEvent('delete',record);
}}
>
删除
</a>
],
},];
return columns;
};
return (
<>
<Button
type="primary"
icon={<TableOutlined />}
loading={loadings[0]}
onClick={() => getTables()}
>
获取Connectors
</Button>
{tableData.length>0?(<Table dataSource={tableData} columns={getColumns()} />):(<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />)}
</>
);
};
export default connect(({ Studio }: { Studio: StateType }) => ({
current: Studio.current,
}))(StudioConnector);
import styles from "./index.less"; import styles from "./index.less";
import {Menu, Dropdown, Tooltip, Row, Col,Popconfirm,Badge} from "antd"; import {Menu, Dropdown, Tooltip, Row, Col,Popconfirm,notification} from "antd";
import {PauseCircleTwoTone, CopyTwoTone, DeleteTwoTone,PlayCircleTwoTone,DiffTwoTone, import {PauseCircleTwoTone, CopyTwoTone, DeleteTwoTone,PlayCircleTwoTone,DiffTwoTone,
FileAddTwoTone,FolderOpenTwoTone,SafetyCertificateTwoTone,SaveTwoTone,FlagTwoTone,EnvironmentOutlined} from "@ant-design/icons"; FileAddTwoTone,FolderOpenTwoTone,SafetyCertificateTwoTone,SaveTwoTone,FlagTwoTone,
EnvironmentOutlined,SmileOutlined} from "@ant-design/icons";
import Space from "antd/es/space"; import Space from "antd/es/space";
import Divider from "antd/es/divider"; import Divider from "antd/es/divider";
import Button from "antd/es/button/button"; import Button from "antd/es/button/button";
import Breadcrumb from "antd/es/breadcrumb/Breadcrumb"; import Breadcrumb from "antd/es/breadcrumb/Breadcrumb";
import {StateType} from "@/pages/FlinkSqlStudio/model"; import {StateType} from "@/pages/FlinkSqlStudio/model";
import {connect} from "umi"; import {connect} from "umi";
import {useEffect, useState} from "react"; import { postAll} from "@/components/Common/crud";
import {handleAddOrUpdate, postAll} from "@/components/Common/crud"; import {executeSql} from "@/pages/FlinkSqlStudio/service";
const {SubMenu} = Menu;
//<Button shape="circle" icon={<CaretRightOutlined />} />
const menu = ( const menu = (
<Menu> <Menu>
<Menu.Item>1st menu item</Menu.Item> <Menu.Item>敬请期待</Menu.Item>
<Menu.Item>2nd menu item</Menu.Item>
<SubMenu title="sub menu">
<Menu.Item>3rd menu item</Menu.Item>
<Menu.Item>4th menu item</Menu.Item>
</SubMenu>
<SubMenu title="disabled sub menu" disabled>
<Menu.Item>5d menu item</Menu.Item>
<Menu.Item>6th menu item</Menu.Item>
</SubMenu>
</Menu> </Menu>
); );
const StudioMenu = (props: any) => { const StudioMenu = (props: any) => {
const {tabs,current,currentPath,form,dispatch} = props; const {tabs,current,currentPath,form,dispatch,monaco} = props;
const [pathItem, setPathItem] = useState<[]>();
const executeSql = () => { const execute = () => {
let selection = monaco.current.editor.getSelection();
let selectsql = monaco.current.editor.getModel().getValueInRange(selection);
if(selectsql==null||selectsql==''){
selectsql=current.value;
}
let param ={ let param ={
session:current.task.session, session:current.task.session,
statement:current.value, statement:selectsql,
clusterId:current.task.clusterId, clusterId:current.task.clusterId,
checkPoint:current.task.checkPoint, checkPoint:current.task.checkPoint,
parallelism:current.task.parallelism, parallelism:current.task.parallelism,
...@@ -46,8 +40,17 @@ const StudioMenu = (props: any) => { ...@@ -46,8 +40,17 @@ const StudioMenu = (props: any) => {
savePointPath:current.task.savePointPath, savePointPath:current.task.savePointPath,
}; };
const key = current.key; const key = current.key;
const result = postAll('api/studio/executeSql',param); const taskKey = (Math.random()*1000)+'';
notification.success({
message: `${param.clusterId+"_"+param.session} 新任务正在执行`,
description: param.statement,
duration:null,
key:taskKey,
icon: <SmileOutlined style={{ color: '#108ee9' }} />,
});
const result = executeSql(param);
result.then(res=>{ result.then(res=>{
notification.close(taskKey);
let newTabs = tabs; let newTabs = tabs;
for(let i=0;i<newTabs.panes.length;i++){ for(let i=0;i<newTabs.panes.length;i++){
if(newTabs.panes[i].key==key){ if(newTabs.panes[i].key==key){
...@@ -59,7 +62,6 @@ const StudioMenu = (props: any) => { ...@@ -59,7 +62,6 @@ const StudioMenu = (props: any) => {
break; break;
} }
} }
console.log(newTabs);
dispatch&&dispatch({ dispatch&&dispatch({
type: "Studio/saveTabs", type: "Studio/saveTabs",
payload: newTabs, payload: newTabs,
...@@ -67,14 +69,6 @@ const StudioMenu = (props: any) => { ...@@ -67,14 +69,6 @@ const StudioMenu = (props: any) => {
}) })
}; };
const buildMsg=(res)=>{
const result = res.datas;
let msg=`[${result.sessionId}:${result.flinkHost}:${result.flinkPort}] ${result.finishDate} ${result.success?'Success':'Error'}
[${result.time}ms] ${result.msg?result.msg:''} ${result.error?result.error:''} \r\n
Statement: ${result.statement}`;
return msg;
};
const saveSqlAndSettingToTask = async() => { const saveSqlAndSettingToTask = async() => {
const fieldsValue = await form.validateFields(); const fieldsValue = await form.validateFields();
if(current.task){ if(current.task){
...@@ -97,7 +91,7 @@ const StudioMenu = (props: any) => { ...@@ -97,7 +91,7 @@ const StudioMenu = (props: any) => {
const runMenu = ( const runMenu = (
<Menu> <Menu>
<Menu.Item onClick={executeSql}>执行</Menu.Item> <Menu.Item onClick={execute}>执行</Menu.Item>
</Menu> </Menu>
); );
...@@ -177,7 +171,7 @@ const StudioMenu = (props: any) => { ...@@ -177,7 +171,7 @@ const StudioMenu = (props: any) => {
type="text" type="text"
icon={<PlayCircleTwoTone />} icon={<PlayCircleTwoTone />}
//loading={loadings[2]} //loading={loadings[2]}
onClick={executeSql} onClick={execute}
/> />
</Tooltip> </Tooltip>
<Popconfirm <Popconfirm
...@@ -188,12 +182,12 @@ const StudioMenu = (props: any) => { ...@@ -188,12 +182,12 @@ const StudioMenu = (props: any) => {
cancelText="取消" cancelText="取消"
> >
<Tooltip title="停止所有的 FlinkSql 任务"> <Tooltip title="停止所有的 FlinkSql 任务">
<Badge size="small" count={1} offset={[-5, 5]}> {/*<Badge size="small" count={1} offset={[-5, 5]}>*/}
<Button <Button
type="text" type="text"
icon={<PauseCircleTwoTone />} icon={<PauseCircleTwoTone />}
/> />
</Badge> {/*</Badge>*/}
</Tooltip> </Tooltip>
</Popconfirm> </Popconfirm>
<Divider type="vertical" /> <Divider type="vertical" />
...@@ -220,4 +214,5 @@ export default connect(({Studio}: { Studio: StateType }) => ({ ...@@ -220,4 +214,5 @@ export default connect(({Studio}: { Studio: StateType }) => ({
current: Studio.current, current: Studio.current,
currentPath: Studio.currentPath, currentPath: Studio.currentPath,
tabs: Studio.tabs, tabs: Studio.tabs,
monaco: Studio.monaco,
}))(StudioMenu); }))(StudioMenu);
...@@ -15,7 +15,7 @@ const StudioSetting = (props: any) => { ...@@ -15,7 +15,7 @@ const StudioSetting = (props: any) => {
const getCluster = ()=>{ const getCluster = ()=>{
cluster.then(value=>{ cluster&&cluster.then(value=>{
let itemList = []; let itemList = [];
for(let item of value){ for(let item of value){
let tag =(<><Tag color={item.enabled?"processing":"error"}>{item.type}</Tag>{item.alias}</>); let tag =(<><Tag color={item.enabled?"processing":"error"}>{item.type}</Tag>{item.alias}</>);
...@@ -134,6 +134,7 @@ const StudioSetting = (props: any) => { ...@@ -134,6 +134,7 @@ const StudioSetting = (props: any) => {
className={styles.form_item}> className={styles.form_item}>
<Select <Select
placeholder="选择会话" placeholder="选择会话"
defaultValue='admin'
dropdownRender={menu => ( dropdownRender={menu => (
<div> <div>
{menu} {menu}
......
...@@ -34,40 +34,3 @@ export function convertToTreeData(data:TreeDataNode[], pid:number,path?:string[] ...@@ -34,40 +34,3 @@ export function convertToTreeData(data:TreeDataNode[], pid:number,path?:string[]
} }
return result return result
} }
export function getLeafFromTree(data:DataType[], arr:DataType[]) {
if (typeof arr == 'undefined') {
arr = [];
}
for (let i = 0; i < data.length; i++) {
let sonList = data[i].children;
if (sonList) {
if (sonList.length == 0) {
arr.push(data[i]);
} else {
getLeafFromTree(sonList, arr);
}
} else {
arr.push(data[i]);
}
}
return arr;
}
export function getChildFromTree(data:DataType[], arr:DataType[]) {
if (typeof arr == 'undefined') {
arr = [];
}
for (let i = 0; i < data.length; i++) {
if (data[i].isParent) {
let sonList = data[i].children;
if (!sonList || sonList == null || sonList.length == 0) {
} else {
getChildFromTree(sonList, arr);
}
} else {
arr.push(data[i]);
}
}
return arr;
}
...@@ -107,7 +107,11 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => { ...@@ -107,7 +107,11 @@ const StudioTree: React.FC<StudioTreeProps> = (props) => {
key: node.taskId, key: node.taskId,
value:(result.datas.statement?result.datas.statement:''), value:(result.datas.statement?result.datas.statement:''),
closable: true, closable: true,
task:result.datas, task:{
session:'admin',
maxRowNum: 100,
...result.datas
},
console:{ console:{
result:[], result:[],
} }
......
...@@ -12,6 +12,7 @@ import {StateType} from "@/pages/FlinkSqlStudio/model"; ...@@ -12,6 +12,7 @@ import {StateType} from "@/pages/FlinkSqlStudio/model";
import StudioConsole from "./StudioConsole"; import StudioConsole from "./StudioConsole";
import StudioSetting from "./StudioSetting"; import StudioSetting from "./StudioSetting";
import StudioEdit from "./StudioEdit"; import StudioEdit from "./StudioEdit";
import StudioConnector from "./StudioConnector";
const {TabPane} = Tabs; const {TabPane} = Tabs;
...@@ -62,7 +63,7 @@ const Studio: React.FC<StudioProps> = ({sql}) => { ...@@ -62,7 +63,7 @@ const Studio: React.FC<StudioProps> = ({sql}) => {
</Tabs> </Tabs>
<Tabs defaultActiveKey="1" size="small"> <Tabs defaultActiveKey="1" size="small">
<TabPane tab={<span>&nbsp;<ApiOutlined />连接器</span>} key="1" > <TabPane tab={<span>&nbsp;<ApiOutlined />连接器</span>} key="1" >
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> <StudioConnector />
</TabPane> </TabPane>
<TabPane tab={<span>&nbsp;<DashboardOutlined />总览</span>} key="2" > <TabPane tab={<span>&nbsp;<DashboardOutlined />总览</span>} key="2" >
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
......
export default { export default {
'pages.layouts.userLayout.title': 'Dlink 是一款开源的 Apache Flink 开发运维平台', 'pages.layouts.userLayout.title': 'Dlink 是一款开源的基于 Apache Flink 的实时计算平台',
'pages.login.accountLogin.tab': '账户密码登录', 'pages.login.accountLogin.tab': '账户密码登录',
'pages.login.accountLogin.errorMessage': '错误的用户名和密码(admin/ant.design)', 'pages.login.accountLogin.errorMessage': '错误的用户名和密码(admin/ant.design)',
'pages.login.failure': '登录失败,请重试!', 'pages.login.failure': '登录失败,请重试!',
...@@ -22,10 +22,12 @@ export default { ...@@ -22,10 +22,12 @@ export default {
'pages.login.submit': '登录', 'pages.login.submit': '登录',
'pages.login.loginWith': '其他登录方式 :', 'pages.login.loginWith': '其他登录方式 :',
'pages.login.registerAccount': '注册账户', 'pages.login.registerAccount': '注册账户',
'pages.welcome.advancedComponent': '高级表格', 'pages.welcome.Community': '官方社区',
'pages.welcome.link': '欢迎使用', 'pages.welcome.upgrade': '更新日志',
'pages.welcome.advancedLayout': '高级布局', 'pages.welcome.link': '欢迎加入',
'pages.welcome.alertMessage': '更快更强的重型组件,已经发布。', 'pages.welcome.star': '欢迎 Star ',
'pages.welcome.advancedLayout': 'Github',
'pages.welcome.alertMessage': '实时计算平台 Dlink & Apache Flink 即将发布,目前为体验版,版本号为 0.1.0。',
'pages.admin.subPage.title': ' 这个页面只有 admin 权限才能查看', 'pages.admin.subPage.title': ' 这个页面只有 admin 权限才能查看',
'pages.admin.subPage.alertMessage': 'umi ui 现已发布,欢迎使用 npm run ui 启动体验。', 'pages.admin.subPage.alertMessage': 'umi ui 现已发布,欢迎使用 npm run ui 启动体验。',
'pages.searchTable.createForm.newRule': '新建规则', 'pages.searchTable.createForm.newRule': '新建规则',
......
...@@ -17,7 +17,7 @@ export default (): React.ReactNode => { ...@@ -17,7 +17,7 @@ export default (): React.ReactNode => {
<Alert <Alert
message={intl.formatMessage({ message={intl.formatMessage({
id: 'pages.welcome.alertMessage', id: 'pages.welcome.alertMessage',
defaultMessage: '更快更强的重型组件,已经发布。', defaultMessage: '实时计算平台 Dlink & Apache Flink 即将发布,目前为体验版,版本号为0.1.0。',
})} })}
type="success" type="success"
showIcon showIcon
......
import React from 'react';
import { Modal } from 'antd';
type CreateFormProps = {
modalVisible: boolean;
onCancel: () => void;
};
const CreateForm: React.FC<CreateFormProps> = (props) => {
const { modalVisible, onCancel } = props;
return (
<Modal
destroyOnClose
title="添加 Flink 集群"
visible={modalVisible}
onCancel={() => onCancel()}
footer={null}
>
{props.children}
</Modal>
);
};
export default CreateForm;
import React, {useEffect, useState} from 'react';
import { Form, Button, Input, Modal,Select } from 'antd';
import Switch from "antd/es/switch";
import TextArea from "antd/es/input/TextArea";
import {DocumentTableListItem} from "@/pages/Document/data";
export type UpdateFormProps = {
onCancel: (flag?: boolean, formVals?: Partial<DocumentTableListItem>) => void;
onSubmit: (values: Partial<DocumentTableListItem>) => void;
updateModalVisible: boolean;
values: Partial<DocumentTableListItem>;
};
const FormItem = Form.Item;
const Option = Select.Option;
const formLayout = {
labelCol: { span: 7 },
wrapperCol: { span: 13 },
};
const UpdateForm: React.FC<UpdateFormProps> = (props) => {
const [formVals, setFormVals] = useState<Partial<DocumentTableListItem>>({
id: props.values.id,
name: props.values.name,
category: props.values.category,
type: props.values.type,
subtype: props.values.subtype,
description: props.values.description,
version: props.values.version,
likeNum: props.values.likeNum,
enabled: props.values.enabled,
});
const [form] = Form.useForm();
const {
onSubmit: handleUpdate,
onCancel: handleUpdateModalVisible,
updateModalVisible,
values,
} = props;
const submitForm = async () => {
const fieldsValue = await form.validateFields();
setFormVals({ ...formVals, ...fieldsValue });
handleUpdate({ ...formVals, ...fieldsValue });
};
const renderContent = (formVals) => {
return (
<>
<FormItem
name="name"
label="名称"
rules={[{ required: true, message: '请输入名称!' }]} >
<Input placeholder="请输入" />
</FormItem>
<FormItem
name="category"
label="文档类型"
>
<Select defaultValue="function" allowClear>
<Option value="function">函数</Option>
</Select>
</FormItem>
<FormItem
name="type"
label="类型"
>
<Select defaultValue="内置函数" allowClear>
<Option value="内置函数">内置函数</Option>
<Option value="UDF">UDF</Option>
</Select>
</FormItem>
<FormItem
name="subtype"
label="子类型"
>
<Select defaultValue="比较函数" allowClear>
<Option value="比较函数">比较函数</Option>
<Option value="逻辑函数">逻辑函数</Option>
<Option value="算术函数">算术函数</Option>
<Option value="字符串函数">字符串函数</Option>
<Option value="时间函数">时间函数</Option>
<Option value="条件函数">条件函数</Option>
<Option value="类型转换函数">类型转换函数</Option>
<Option value="Collection 函数">Collection 函数</Option>
<Option value="Value Collection 函数">Value Collection 函数</Option>
<Option value="Value Access 函数">Value Access 函数</Option>
<Option value="分组函数">分组函数</Option>
<Option value="hash函数">hash函数</Option>
<Option value="聚合函数">聚合函数</Option>
<Option value="列函数">列函数</Option>
<Option value="表值聚合函数">表值聚合函数</Option>
<Option value="其他函数">其他函数</Option>
</Select>
</FormItem>
<FormItem
name="description"
label="描述"
>
<TextArea placeholder="" allowClear autoSize={{ minRows: 3, maxRows: 10 }}/>
</FormItem>
<FormItem
name="version"
label="版本"
>
<Input placeholder="请输入" />
</FormItem>
<FormItem
name="enabled"
label="是否启用"
rules={[{ required: true, message: '请输入是否启用!' }]} >
<Switch checkedChildren="启用" unCheckedChildren="禁用"
defaultChecked={formVals.enabled}/>
</FormItem>
</>
);
};
const renderFooter = () => {
return (
<>
<Button onClick={() => handleUpdateModalVisible(false, values)}>取消</Button>
<Button type="primary" onClick={() => submitForm()}>
完成
</Button>
</>
);
};
return (
<Modal
width={640}
bodyStyle={{ padding: '32px 40px 48px' }}
destroyOnClose
title="编辑文档"
visible={updateModalVisible}
footer={renderFooter()}
onCancel={() => handleUpdateModalVisible()}
>
<Form
{...formLayout}
form={form}
initialValues={{
id: formVals.id,
name: formVals.name,
category: formVals.category,
type: formVals.type,
subtype: formVals.subtype,
description: formVals.description,
version: formVals.version,
likeNum: formVals.likeNum,
enabled: formVals.enabled,
}}
>
{renderContent(formVals)}
</Form>
</Modal>
);
};
export default UpdateForm;
export type DocumentTableListItem = {
id: number,
name: string,
category: string,
type: string,
subtype: string,
description: string,
version: string,
likeNum: number,
enabled: boolean,
createTime: Date,
updateTime: Date,
};
import {DownOutlined, HeartOutlined, PlusOutlined, UserOutlined} from '@ant-design/icons';
import {Button, message, Input, Drawer, Modal} from 'antd';
import React, {useState, useRef} from 'react';
import {PageContainer, FooterToolbar} from '@ant-design/pro-layout';
import type {ProColumns, ActionType} from '@ant-design/pro-table';
import ProTable from '@ant-design/pro-table';
import ProDescriptions from '@ant-design/pro-descriptions';
import CreateForm from './components/CreateForm';
import UpdateForm from './components/UpdateForm';
import type {DocumentTableListItem} from './data.d';
import styles from './index.less';
import Dropdown from "antd/es/dropdown/dropdown";
import Menu from "antd/es/menu";
import {
handleAddOrUpdate, handleOption, handleRemove, queryData,
updateEnabled
} from "@/components/Common/crud";
const url = '/api/document';
const DocumentTableList: React.FC<{}> = () => {
const [createModalVisible, handleModalVisible] = useState<boolean>(false);
const [updateModalVisible, handleUpdateModalVisible] = useState<boolean>(false);
const [formValues, setFormValues] = useState({});
const actionRef = useRef<ActionType>();
const [row, setRow] = useState<DocumentTableListItem>();
const [selectedRowsState, setSelectedRows] = useState<DocumentTableListItem[]>([]);
const editAndDelete = (key: string | number, currentItem: DocumentTableListItem) => {
if (key === 'edit') {
handleUpdateModalVisible(true);
setFormValues(currentItem);
} else if (key === 'delete') {
Modal.confirm({
title: '删除文档',
content: '确定删除该文档吗?',
okText: '确认',
cancelText: '取消',
onOk:async () => {
await handleRemove(url,[currentItem]);
actionRef.current?.reloadAndRest?.();
}
});
}
};
const checkHeartBeats = async ()=>{
await handleOption(url+'/heartbeats','心跳检测',null);
actionRef.current?.reloadAndRest?.();
};
const MoreBtn: React.FC<{
item: DocumentTableListItem;
}> = ({item}) => (
<Dropdown
overlay={
<Menu onClick={({key}) => editAndDelete(key, item)}>
<Menu.Item key="edit">编辑</Menu.Item>
<Menu.Item key="delete">删除</Menu.Item>
</Menu>
}
>
<a>
更多 <DownOutlined/>
</a>
</Dropdown>
);
const columns: ProColumns<DocumentTableListItem>[] = [
{
title: '名称',
dataIndex: 'name',
tip: '名称是唯一的',
sorter: true,
formItemProps: {
rules: [
{
required: true,
message: '名称为必填项',
},
],
},
render: (dom, entity) => {
return <a onClick={() => setRow(entity)}>{dom}</a>;
},
},
{
title: '文档ID',
dataIndex: 'id',
hideInTable: true,
hideInForm: true,
hideInSearch: true,
},
{
title: '文档类型',
sorter: true,
dataIndex: 'category',
hideInForm: false,
hideInSearch: true,
hideInTable: false,
filters: [
{
text: '函数',
value: 'function',
}
],
filterMultiple: false,
valueEnum: {
'function': { text: '函数'},
},
},
{
title: '类型',
sorter: true,
dataIndex: 'type',
hideInForm: false,
hideInSearch: true,
hideInTable: false,
filters: [
{
text: '内置函数',
value: '内置函数',
},
{
text: 'UDF',
value: 'UDF',
},
],
filterMultiple: false,
valueEnum: {
'内置函数': { text: '内置函数'},
'UDF': { text: 'UDF'},
},
},
{
title: '子类型',
sorter: true,
dataIndex: 'subtype',
hideInForm: false,
hideInSearch: true,
hideInTable: false,
filters: [
{
text: '比较函数',
value: '比较函数',
},
{
text: '逻辑函数',
value: '逻辑函数',
},{
text: '算术函数',
value: '算术函数',
},{
text: '字符串函数',
value: '字符串函数',
},{
text: '时间函数',
value: '时间函数',
},{
text: '条件函数',
value: '条件函数',
},{
text: '类型转换函数',
value: '类型转换函数',
},{
text: 'Collection 函数',
value: 'Collection 函数',
},{
text: 'Value Collection 函数',
value: 'Value Collection 函数',
},{
text: 'Value Access 函数',
value: 'Value Access 函数',
},{
text: '分组函数',
value: '分组函数',
},{
text: 'hash函数',
value: 'hash函数',
},{
text: '聚合函数',
value: '聚合函数',
},{
text: '列函数',
value: '列函数',
},{
text: '表值聚合函数',
value: '表值聚合函数',
},{
text: '其他函数',
value: '其他函数',
},
],
filterMultiple: false,
valueEnum: {
'比较函数': { text: '比较函数'},
'逻辑函数': { text: '逻辑函数'},
'算术函数': { text: '算术函数'},
'字符串函数': { text: '字符串函数'},
'时间函数': { text: '时间函数'},
'条件函数': { text: '条件函数'},
'类型转换函数': { text: '类型转换函数'},
'Collection 函数': { text: 'Collection 函数'},
'Value Collection 函数': { text: 'Value Collection 函数'},
'Value Access 函数': { text: 'Value Access 函数'},
'分组函数': { text: '分组函数'},
'hash函数': { text: 'hash函数'},
'聚合函数': { text: '聚合函数'},
'列函数': { text: '列函数'},
'表值聚合函数': { text: '表值聚合函数'},
'其他函数': { text: '其他函数'},
},
},
{
title: '描述',
sorter: true,
dataIndex: 'description',
valueType: 'textarea',
hideInForm: false,
hideInSearch: true,
hideInTable: true,
},
{
title: '版本',
sorter: true,
dataIndex: 'version',
hideInForm: true,
hideInSearch: true,
hideInTable: true,
},
{
title: '是否启用',
dataIndex: 'enabled',
hideInForm: true,
hideInSearch: true,
hideInTable: false,
filters: [
{
text: '已启用',
value: 1,
},
{
text: '已禁用',
value: 0,
},
],
filterMultiple: false,
valueEnum: {
true: { text: '已启用', status: 'Success' },
false: { text: '已禁用', status: 'Error' },
},
},
{
title: '创建时间',
dataIndex: 'createTime',
sorter: true,
valueType: 'dateTime',
hideInForm: true,
hideInTable:true,
renderFormItem: (item, { defaultRender, ...rest }, form) => {
const status = form.getFieldValue('status');
if (`${status}` === '0') {
return false;
}
if (`${status}` === '3') {
return <Input {...rest} placeholder="请输入异常原因!" />;
}
return defaultRender(item);
},
},
{
title: '最近更新时间',
dataIndex: 'updateTime',
sorter: true,
valueType: 'dateTime',
hideInForm: true,
renderFormItem: (item, { defaultRender, ...rest }, form) => {
const status = form.getFieldValue('status');
if (`${status}` === '0') {
return false;
}
if (`${status}` === '3') {
return <Input {...rest} placeholder="请输入异常原因!" />;
}
return defaultRender(item);
},
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => [
<a
onClick={() => {
handleUpdateModalVisible(true);
setFormValues(record);
}}
>
配置
</a>,
<MoreBtn key="more" item={record}/>,
],
},
];
return (
<PageContainer>
<ProTable<DocumentTableListItem>
headerTitle="文档管理"
actionRef={actionRef}
rowKey="id"
search={{
labelWidth: 120,
}}
toolBarRender={() => [
<Button type="primary" onClick={() => handleModalVisible(true)}>
<PlusOutlined/> 新建
</Button>,
<Button type="primary" onClick={() => checkHeartBeats()}>
<HeartOutlined /> 心跳
</Button>,
]}
request={(params, sorter, filter) => queryData(url,{...params, sorter, filter})}
columns={columns}
rowSelection={{
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
}}
/>
{selectedRowsState?.length > 0 && (
<FooterToolbar
extra={
<div>
已选择 <a style={{fontWeight: 600}}>{selectedRowsState.length}</a>&nbsp;&nbsp;
<span>
被禁用的文档共 {selectedRowsState.length - selectedRowsState.reduce((pre, item) => pre + (item.enabled ? 1 : 0), 0)}
</span>
</div>
}
>
<Button type="primary" danger
onClick ={()=>{
Modal.confirm({
title: '删除文档',
content: '确定删除选中的文档吗?',
okText: '确认',
cancelText: '取消',
onOk:async () => {
await handleRemove(url,selectedRowsState);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>
批量删除
</Button>
<Button type="primary"
onClick ={()=>{
Modal.confirm({
title: '启用文档',
content: '确定启用选中的文档吗?',
okText: '确认',
cancelText: '取消',
onOk:async () => {
await updateEnabled(url,selectedRowsState, true);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量启用</Button>
<Button danger
onClick ={()=>{
Modal.confirm({
title: '禁用文档',
content: '确定禁用选中的文档吗?',
okText: '确认',
cancelText: '取消',
onOk:async () => {
await updateEnabled(url,selectedRowsState, false);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量禁用</Button>
</FooterToolbar>
)}
<CreateForm onCancel={() => handleModalVisible(false)} modalVisible={createModalVisible}>
<ProTable<DocumentTableListItem, DocumentTableListItem>
onSubmit={async (value) => {
const success = await handleAddOrUpdate(url,value);
if (success) {
handleModalVisible(false);
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
rowKey="id"
type="form"
columns={columns}
/>
</CreateForm>
{formValues && Object.keys(formValues).length ? (
<UpdateForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate(url,value);
if (success) {
handleUpdateModalVisible(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
handleUpdateModalVisible(false);
setFormValues({});
}}
updateModalVisible={updateModalVisible}
values={formValues}
/>
) : null}
<Drawer
width={600}
visible={!!row}
onClose={() => {
setRow(undefined);
}}
closable={false}
>
{row?.name && (
<ProDescriptions<DocumentTableListItem>
column={2}
title={row?.name}
request={async () => ({
data: row || {},
})}
params={{
id: row?.name,
}}
columns={columns}
/>
)}
</Drawer>
</PageContainer>
);
};
export default DocumentTableList;
...@@ -60,6 +60,7 @@ export type StateType = { ...@@ -60,6 +60,7 @@ export type StateType = {
cluster?:ClusterType[]; cluster?:ClusterType[];
current: TabsItemType; current: TabsItemType;
sql?: string; sql?: string;
monaco?: any;
currentPath?: string[]; currentPath?: string[];
tabs:TabsType; tabs:TabsType;
session:string[]; session:string[];
...@@ -74,6 +75,7 @@ export type ModelType = { ...@@ -74,6 +75,7 @@ export type ModelType = {
reducers: { reducers: {
saveSql: Reducer<StateType>; saveSql: Reducer<StateType>;
saveCurrentPath: Reducer<StateType>; saveCurrentPath: Reducer<StateType>;
saveMonaco: Reducer<StateType>;
saveTabs: Reducer<StateType>; saveTabs: Reducer<StateType>;
changeActiveKey: Reducer<StateType>; changeActiveKey: Reducer<StateType>;
saveTaskData: Reducer<StateType>; saveTaskData: Reducer<StateType>;
...@@ -115,6 +117,7 @@ const Model: ModelType = { ...@@ -115,6 +117,7 @@ const Model: ModelType = {
} }
}, },
sql: '', sql: '',
monaco: {},
currentPath: [], currentPath: [],
tabs:{ tabs:{
activeKey: 0, activeKey: 0,
...@@ -177,6 +180,14 @@ const Model: ModelType = { ...@@ -177,6 +180,14 @@ const Model: ModelType = {
currentPath:payload, currentPath:payload,
}; };
}, },
saveMonaco(state, { payload }) {
return {
...state,
monaco:{
...payload
},
};
},
saveTabs(state, { payload }) { saveTabs(state, { payload }) {
let newCurrent = state.current; let newCurrent = state.current;
for(let i=0;i<payload.panes.length;i++){ for(let i=0;i<payload.panes.length;i++){
......
...@@ -10,6 +10,15 @@ export async function executeSql(params: StudioParam) { ...@@ -10,6 +10,15 @@ export async function executeSql(params: StudioParam) {
}); });
} }
export async function executeDDL(params: StudioParam) {
return request<API.Result>('/api/studio/executeDDL', {
method: 'POST',
data: {
...params,
},
});
}
export async function getCatalogueTreeData(params?: StudioParam) { export async function getCatalogueTreeData(params?: StudioParam) {
return request<API.Result>('/api/catalogue/getCatalogueTreeData', { return request<API.Result>('/api/catalogue/getCatalogueTreeData', {
method: 'POST', method: 'POST',
......
import React from 'react'; import React from 'react';
import { PageContainer } from '@ant-design/pro-layout'; import { PageContainer } from '@ant-design/pro-layout';
import { Card, Alert, Typography } from 'antd'; import { Card, Alert, Typography,Timeline } from 'antd';
import { useIntl, FormattedMessage } from 'umi'; import { useIntl, FormattedMessage } from 'umi';
import styles from './Welcome.less'; import styles from './Welcome.less';
const { Text, Link,Paragraph } = Typography;
const CodePreview: React.FC = ({ children }) => ( const CodePreview: React.FC = ({ children }) => (
<pre className={styles.pre}> <pre className={styles.pre}>
<code> <code>
...@@ -31,32 +31,49 @@ export default (): React.ReactNode => { ...@@ -31,32 +31,49 @@ export default (): React.ReactNode => {
}} }}
/> />
<Typography.Text strong> <Typography.Text strong>
<FormattedMessage id="pages.welcome.advancedComponent" defaultMessage="高级表格" />{' '} <FormattedMessage id="pages.welcome.Community" defaultMessage="官方社区" />{' '}
<a <FormattedMessage id="pages.welcome.link" defaultMessage="欢迎加入" />
href="https://procomponents.ant.design/components/table"
rel="noopener noreferrer"
target="__blank"
>
<FormattedMessage id="pages.welcome.link" defaultMessage="欢迎使用" />
</a>
</Typography.Text> </Typography.Text>
<CodePreview>yarn add @ant-design/pro-table</CodePreview> <CodePreview>微信公众号:Datalink数据中台</CodePreview>
<Typography.Text <Typography.Text
strong strong
style={{ style={{
marginBottom: 12, marginBottom: 12,
}} }}
> >
<FormattedMessage id="pages.welcome.advancedLayout" defaultMessage="高级布局" />{' '} <FormattedMessage id="pages.welcome.advancedLayout" defaultMessage="Github" />{' '}
<a <a
href="https://procomponents.ant.design/components/layout" href="https://github.com/aiwenmo/dlink"
rel="noopener noreferrer" rel="noopener noreferrer"
target="__blank" target="__blank"
> >
<FormattedMessage id="pages.welcome.link" defaultMessage="欢迎使用" /> <FormattedMessage id="pages.welcome.star" defaultMessage="欢迎 Star " />
</a> </a>
</Typography.Text> </Typography.Text>
<CodePreview>yarn add @ant-design/pro-layout</CodePreview> <Paragraph>
<Typography.Text strong>
<FormattedMessage id="pages.welcome.upgrade" defaultMessage="更新日志" />
</Typography.Text>
</Paragraph>
<p> </p>
<Timeline pending="Recording..." reverse={true}>
<Timeline.Item><Text code>0.1.0</Text> <Text type="secondary">2015-09-01</Text>
<p> </p>
<Paragraph>
<ul>
<li>
<Link href="">FlinkSql Studio</Link>
</li>
<li>
<Link href="">Flink 集群</Link>
</li>
<li>
<Link href="">Flink 任务</Link>
</li>
</ul>
</Paragraph>
</Timeline.Item>
</Timeline>
</Card> </Card>
</PageContainer> </PageContainer>
); );
......
...@@ -95,7 +95,7 @@ const Login: React.FC = () => { ...@@ -95,7 +95,7 @@ const Login: React.FC = () => {
<div className={styles.header}> <div className={styles.header}>
<Link to="/"> <Link to="/">
<img alt="logo" className={styles.logo} src="/logo.svg" /> <img alt="logo" className={styles.logo} src="/logo.svg" />
<span className={styles.title}>Dlink</span> <span className={styles.title}>Dlink & Apache Flink</span>
</Link> </Link>
</div> </div>
<div className={styles.desc}> <div className={styles.desc}>
...@@ -139,7 +139,7 @@ const Login: React.FC = () => { ...@@ -139,7 +139,7 @@ const Login: React.FC = () => {
}} }}
placeholder={intl.formatMessage({ placeholder={intl.formatMessage({
id: 'pages.login.username.placeholder', id: 'pages.login.username.placeholder',
defaultMessage: '用户名: admin or user', defaultMessage: '用户名:',
})} })}
rules={[ rules={[
{ {
...@@ -161,7 +161,7 @@ const Login: React.FC = () => { ...@@ -161,7 +161,7 @@ const Login: React.FC = () => {
}} }}
placeholder={intl.formatMessage({ placeholder={intl.formatMessage({
id: 'pages.login.password.placeholder', id: 'pages.login.password.placeholder',
defaultMessage: '密码: ant.design', defaultMessage: '密码:',
})} })}
rules={[ rules={[
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment