Commit 311685bf authored by wenmo's avatar wenmo

集群管理

parent e4247651
...@@ -5,10 +5,7 @@ import com.dlink.model.Task; ...@@ -5,10 +5,7 @@ import com.dlink.model.Task;
import com.dlink.model.User; import com.dlink.model.User;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** /**
* AdminController * AdminController
...@@ -18,7 +15,7 @@ import org.springframework.web.bind.annotation.RestController; ...@@ -18,7 +15,7 @@ import org.springframework.web.bind.annotation.RestController;
**/ **/
@Slf4j @Slf4j
@RestController @RestController
@RequestMapping("/user") @RequestMapping("/api")
public class AdminController { public class AdminController {
@Value("${dlink.login.username}") @Value("${dlink.login.username}")
...@@ -26,14 +23,30 @@ public class AdminController { ...@@ -26,14 +23,30 @@ public class AdminController {
@Value("${dlink.login.password}") @Value("${dlink.login.password}")
private String password; private String password;
/** /**
* 获取指定ID的信息 * 登录
*/ */
@PostMapping("/login") @PostMapping("/login")
public Result getOneById(@RequestBody User user) throws Exception { public Result login(@RequestBody User user) throws Exception {
if(username.equals(user.getUsername())&&password.equals(user.getPassword())) { if(username.equals(user.getUsername())&&password.equals(user.getPassword())) {
return Result.succeed(username, "登录成功"); return Result.succeed(username, "登录成功");
}else{ }else{
return Result.failed("验证失败"); return Result.failed("验证失败");
} }
} }
/**
* 退出
*/
@DeleteMapping("/outLogin")
public Result outLogin() throws Exception {
return Result.succeed("退出成功");
}
/**
* 获取当前用户信息
*/
@GetMapping("/current")
public Result current() throws Exception {
return Result.succeed(username, "获取成功");
}
} }
...@@ -25,7 +25,7 @@ import java.util.List; ...@@ -25,7 +25,7 @@ import java.util.List;
**/ **/
@Slf4j @Slf4j
@RestController @RestController
@RequestMapping("/catalogue") @RequestMapping("/api/catalogue")
public class CatalogueController { public class CatalogueController {
@Autowired @Autowired
private CatalogueService catalogueService; private CatalogueService catalogueService;
......
...@@ -8,12 +8,7 @@ import com.dlink.service.ClusterService; ...@@ -8,12 +8,7 @@ import com.dlink.service.ClusterService;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.*;
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.ArrayList;
import java.util.List; import java.util.List;
...@@ -26,7 +21,7 @@ import java.util.List; ...@@ -26,7 +21,7 @@ import java.util.List;
**/ **/
@Slf4j @Slf4j
@RestController @RestController
@RequestMapping("/cluster") @RequestMapping("/api/cluster")
public class ClusterController { public class ClusterController {
@Autowired @Autowired
private ClusterService clusterService; private ClusterService clusterService;
...@@ -36,6 +31,7 @@ public class ClusterController { ...@@ -36,6 +31,7 @@ public class ClusterController {
*/ */
@PutMapping @PutMapping
public Result saveOrUpdate(@RequestBody Cluster cluster) throws Exception { public Result saveOrUpdate(@RequestBody Cluster cluster) throws Exception {
checkHealth(cluster);
if(clusterService.saveOrUpdate(cluster)){ if(clusterService.saveOrUpdate(cluster)){
return Result.succeed("新增成功"); return Result.succeed("新增成功");
}else { }else {
...@@ -92,6 +88,13 @@ public class ClusterController { ...@@ -92,6 +88,13 @@ public class ClusterController {
List<Cluster> clusters = clusterService.listEnabledAll(); List<Cluster> clusters = clusterService.listEnabledAll();
for (int i = 0; i < clusters.size(); i++) { for (int i = 0; i < clusters.size(); i++) {
Cluster cluster = clusters.get(i); Cluster cluster = clusters.get(i);
checkHealth(cluster);
clusterService.updateById(cluster);
}
return Result.succeed("状态刷新完成");
}
private void checkHealth(Cluster cluster){
String jobManagerHost = clusterService.checkHeartBeat(cluster.getHosts(), cluster.getJobManagerHost()); String jobManagerHost = clusterService.checkHeartBeat(cluster.getHosts(), cluster.getJobManagerHost());
if(jobManagerHost==null){ if(jobManagerHost==null){
cluster.setJobManagerHost(""); cluster.setJobManagerHost("");
...@@ -100,8 +103,5 @@ public class ClusterController { ...@@ -100,8 +103,5 @@ public class ClusterController {
cluster.setJobManagerHost(jobManagerHost); cluster.setJobManagerHost(jobManagerHost);
cluster.setStatus(1); cluster.setStatus(1);
} }
clusterService.updateById(cluster);
}
return Result.succeed("状态刷新完成");
} }
} }
...@@ -26,7 +26,7 @@ import java.util.List; ...@@ -26,7 +26,7 @@ import java.util.List;
**/ **/
@Slf4j @Slf4j
@RestController @RestController
@RequestMapping("/statement") @RequestMapping("/api/statement")
public class StatementController { public class StatementController {
@Autowired @Autowired
private StatementService statementService; private StatementService statementService;
......
...@@ -26,7 +26,7 @@ import java.util.List; ...@@ -26,7 +26,7 @@ import java.util.List;
*/ */
@Slf4j @Slf4j
@RestController @RestController
@RequestMapping("/task") @RequestMapping("/api/task")
public class TaskController { public class TaskController {
@Autowired @Autowired
private TaskService taskService; private TaskService taskService;
......
org.springframework.context.ApplicationContextInitializer=\ org.springframework.context.ApplicationContextInitializer=\
com.dlink.common.banner.BannerInitializer com.dlink.common.banner.BannerInitializer
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.dlink.db.config.MybatisPlusConfigure
\ No newline at end of file
########################## 统一变量配置 ##########################
##### 数据库配置
dlink.datasource.ip=10.1.51.25
dlink.datasource.username=dlink
dlink.datasource.password=dlink
##### Flink 集群配置
dlink.flink.host=10.1.51.24,10.1.51.25,10.1.51.26
dlink.flink.port=8081
##### 登录用户配置
dlink.login.username=admin
dlink.login.password=dlink
##### mybatis-plus打印完整sql(只适用于开发环境)
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
\ No newline at end of file
spring: spring:
datasource: datasource:
url: jdbc:mysql://10.1.51.25:3306/dlink?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true url: jdbc:mysql://127.0.0.1:3306/dlink?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: dfly username: dlink
password: Dareway@2020 password: dlink
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
application: application:
name: dlink name: dlink
...@@ -24,10 +24,7 @@ mybatis-plus: ...@@ -24,10 +24,7 @@ mybatis-plus:
##### Flink 集群配置 ##### Flink 集群配置
dlink: dlink:
flink:
host: 10.1.51.24,10.1.51.25,10.1.51.26
port: 8081
##### 登录用户配置 ##### 登录用户配置
login: login:
username: admin username: admin
password: dlink password: admin
\ No newline at end of file \ No newline at end of file
########################## bootstrap级别通用配置 ##########################
# 默认开发环境
spring.profiles.active=dev
server.port=8888
spring.application.name=Dlink
\ No newline at end of file
server:
port: 8004
spring:
application:
name: datalink-task
\ No newline at end of file
...@@ -22,181 +22,22 @@ export default [ ...@@ -22,181 +22,22 @@ export default [
component: './Welcome', component: './Welcome',
}, },
{ {
path: '/dbase', path: '/studio',
name: 'dbase',
access: 'canAdmin',
routes: [
{
path: '/dbase/user-center',
name: 'user-center',
icon: 'user',
routes: [
{
path: '/dbase/user-center/user',
name: 'user',
icon: 'user',
component: './Dbase/User',
},
{
path: '/dbase/user-center/role',
name: 'role',
icon: 'smile',
component: './Common/Build',
},
{
path: '/dbase/user-center/menu',
name: 'menu',
icon: 'smile',
component: './Common/Build',
},
{
path: '/dbase/user-center/client',
name: 'client',
icon: 'smile',
component: './Common/Build',
},
{
path: '/dbase/user-center/token',
name: 'token',
icon: 'smile',
component: './Common/Build',
},
],
},
{
path: '/dbase/springcloud',
name: 'springcloud',
icon: 'cloud',
routes: [
{
path: '/dbase/springcloud/nacos',
name: 'nacos',
component: './Common/Build',
},
],
},
{
path: '/dbase/database',
name: 'database',
icon: 'database',
routes: [
{
path: '/dbase/database/manager',
name: 'manager',
component: './Common/Build',
},
],
},
{
path: '/dbase/moitor',
name: 'moitor',
icon: 'desktop',
routes: [
{
path: '/dbase/moitor/log',
name: 'log',
component: './Common/Build',
},
],
},
{
path: '/dbase/cluster',
name: 'cluster',
icon: 'cluster',
routes: [
{
path: '/dbase/cluster/node',
name: 'node',
component: './Common/Build',
},
],
},
{
path: '/dbase/schedule',
name: 'schedule',
icon: 'fieldTime',
routes: [
{
path: '/dbase/schedule/job',
name: 'job',
component: './Common/Build',
},
],
},
],
},
{
path: '/dbus',
name: 'dbus',
component: './Common/Build',
},
{
path: '/dlink',
name: 'dlink',
access: 'canAdmin',
routes: [
{
path: '/dlink/flink',
name: 'flink',
icon: 'crown',
routes: [
{
path: '/dlink/flink/studio',
name: 'studio', name: 'studio',
component: './Dlink/Studio', icon: 'consoleSql',
}, component: './Studio',
],
}, },
{ {
path: '/dlink/task', path: '/task',
name: 'task', name: 'task',
icon: 'crown', icon: 'partition',
routes: [ component: './Task',
{
path: '/dlink/task/list',
name: 'list',
component: './Dlink/Task',
},
{
path: '/dlink/task/create',
name: 'create',
component: './Common/Build',
},
{
path: '/dlink/task/flinksql',
name: 'flinksql',
component: './Dlink/FlinkSql',
},
],
},
{
path: '/dlink/warehouse',
name: 'warehouse',
icon: 'deploymentUnit',
routes: [
{
path: '/dlink/warehouse/metadata',
name: 'metadata',
component: './Common/Build',
},
],
},
],
}, },
{ {
path: '/dsink', path: '/cluster',
name: 'dsink', name: 'cluster',
component: './Common/Build', icon: 'cluster',
}, component: './Cluster',
{
path: '/dview',
name: 'dview',
component: './Common/Build',
},
{
path: '/dai',
name: 'dai',
component: './Common/Build',
}, },
{ {
path: '/dev', path: '/dev',
...@@ -279,7 +120,7 @@ export default [ ...@@ -279,7 +120,7 @@ export default [
name: 'advanced-form', name: 'advanced-form',
icon: 'smile', icon: 'smile',
path: '/demo/form/formadvancedform', path: '/demo/form/formadvancedform',
component: './FormAdvancedForm', component: './Demo/FormAdvancedForm',
}, },
{ {
name: '分步表单', name: '分步表单',
......
...@@ -8,28 +8,10 @@ import Footer from '@/components/Footer'; ...@@ -8,28 +8,10 @@ import Footer from '@/components/Footer';
import type { ResponseError } from 'umi-request'; import type { ResponseError } from 'umi-request';
import { currentUser as queryCurrentUser } from './services/ant-design-pro/api'; import { currentUser as queryCurrentUser } from './services/ant-design-pro/api';
import { BookOutlined, LinkOutlined } from '@ant-design/icons'; import { BookOutlined, LinkOutlined } from '@ant-design/icons';
import {RequestOptionsInit} from "umi-request";
const isDev = process.env.NODE_ENV === 'development'; const isDev = process.env.NODE_ENV === 'development';
const loginPath = '/user/login'; const loginPath = '/user/login';
const authHeaderInterceptor = (url: string, options: RequestOptionsInit) => {
if(url === '/api-uaa/oauth/token'){
const authorization = Buffer.from('webApp:webApp').toString('base64');
const authHeader = { Authorization: `Basic ${authorization}` };
return {
url: `${url}`,
options: {...options, interceptors: true, headers: authHeader},
};
}else {
const authHeader = {Authorization: `Bearer ${localStorage.getItem('token')}`};
return {
url: `${url}`,
options: {...options, interceptors: true, headers: authHeader},
};
}
};
/** 获取用户信息比较慢的时候会展示一个 loading */ /** 获取用户信息比较慢的时候会展示一个 loading */
export const initialStateConfig = { export const initialStateConfig = {
loading: <PageLoading />, loading: <PageLoading />,
...@@ -47,9 +29,9 @@ export async function getInitialState(): Promise<{ ...@@ -47,9 +29,9 @@ export async function getInitialState(): Promise<{
try { try {
const result = await queryCurrentUser(); const result = await queryCurrentUser();
const currentUser:API.CurrentUser = { const currentUser:API.CurrentUser = {
name: result.datas.nickname, name: '超级管理员',
avatar: result.datas.avatar, avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
userid: result.datas.id, userid: '1',
email: 'antdesign@alipay.com', email: 'antdesign@alipay.com',
signature: '海纳百川,有容乃大', signature: '海纳百川,有容乃大',
title: '交互专家啊', title: '交互专家啊',
...@@ -168,8 +150,7 @@ export const request: RequestConfig = { ...@@ -168,8 +150,7 @@ export const request: RequestConfig = {
throw error; throw error;
} }
}, },
// 新增自动添加AccessToken的请求前拦截器
requestInterceptors: [authHeaderInterceptor],
}; };
// ProLayout 支持的api https://procomponents.ant.design/components/layout // ProLayout 支持的api https://procomponents.ant.design/components/layout
......
...@@ -39,6 +39,15 @@ export async function postDataArray(url:string,params: number[]) { ...@@ -39,6 +39,15 @@ export async function postDataArray(url:string,params: number[]) {
}); });
} }
export async function postAll(url:string,params?: any) {
return request(url, {
method: 'POST',
data: {
...params,
},
});
}
export const handleAddOrUpdate = async (url:string,fields: any) => { export const handleAddOrUpdate = async (url:string,fields: any) => {
const tipsTitle = fields.id ? "修改" : "添加"; const tipsTitle = fields.id ? "修改" : "添加";
const hide = message.loading(`正在${tipsTitle}`); const hide = message.loading(`正在${tipsTitle}`);
...@@ -90,3 +99,16 @@ export const updateEnabled = (url:string,selectedRows: [], enabled: boolean) => ...@@ -90,3 +99,16 @@ export const updateEnabled = (url:string,selectedRows: [], enabled: boolean) =>
}) })
}; };
export const handleOption = async (url:string,title:string,param:any) => {
const hide = message.loading('正在'+title);
try {
const {msg} = await postAll(url,param);
hide();
message.success(msg);
return true;
} catch (error) {
hide();
message.error(title+'失败,请重试');
return false;
}
};
...@@ -50,35 +50,9 @@ export default { ...@@ -50,35 +50,9 @@ export default {
'menu.editor.mind': '脑图编辑器', 'menu.editor.mind': '脑图编辑器',
'menu.editor.koni': '拓扑编辑器', 'menu.editor.koni': '拓扑编辑器',
'menu.demo': 'Demo 开发模板', 'menu.demo': 'Demo 开发模板',
'menu.dbase': 'Dbase 资源管理', 'menu.cluster': '集群中心',
'menu.dbase.user-center': '用户中心', 'menu.studio': 'FlinkSql IDE',
'menu.dbase.user-center.user': '用户管理', 'menu.task': '作业中心',
'menu.dbase.user-center.role': '角色管理',
'menu.dbase.user-center.menu': '菜单管理',
'menu.dbase.user-center.client': '租户管理',
'menu.dbase.user-center.token': 'Token管理',
'menu.dbase.springcloud': '微服务中心',
'menu.dbase.springcloud.nacos': 'Nacos 中心',
'menu.dbase.database': '数据源中心',
'menu.dbase.database.manager': '数据源管理',
'menu.dbase.moitor': '监控中心',
'menu.dbase.moitor.log': '业务日志',
'menu.dbase.cluster': '集群中心',
'menu.dbase.cluster.node': '节点管理',
'menu.dbase.schedule': '调度中心',
'menu.dbase.schedule.job': '任务管理',
'menu.dbus': 'Dbus 数据总线',
'menu.dlink': 'Dlink 数据治理',
'menu.dlink.flink': 'Flink 中心',
'menu.dlink.flink.studio': 'FlinkSql 编辑器',
'menu.dlink.task': '作业中心',
'menu.dlink.task.list': '作业管理',
'menu.dlink.task.create': '构建作业',
'menu.dlink.task.flinksql': 'FlinkSql管理',
'menu.dlink.warehouse': '数仓中心',
'menu.dlink.warehouse.metadata': '元数据管理',
'menu.dsink': 'Dsink 数据资产',
'menu.dview': 'Dview 数据可视',
'menu.dai': 'Dai 人工智能', 'menu.dai': 'Dai 人工智能',
'menu.dev': 'Dev 开发者工具', 'menu.dev': 'Dev 开发者工具',
'menu.dev.flink': 'Flink 计算框架', 'menu.dev.flink': 'Flink 计算框架',
......
export default { export default {
'pages.layouts.userLayout.title': 'DataLink 是一款开源的创新型数据中台解决方案', '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': '登录失败,请重试!',
......
import React, {useEffect, useState} from 'react';
import { Form, Button, Input, Modal,Select } from 'antd';
import type { TableListItem } from '../data.d';
import Switch from "antd/es/switch";
import TextArea from "antd/es/input/TextArea";
export type UpdateFormProps = {
onCancel: (flag?: boolean, formVals?: Partial<TableListItem>) => void;
onSubmit: (values: Partial<TableListItem>) => void;
updateModalVisible: boolean;
values: Partial<TableListItem>;
};
const FormItem = Form.Item;
const formLayout = {
labelCol: { span: 7 },
wrapperCol: { span: 13 },
};
const UpdateForm: React.FC<UpdateFormProps> = (props) => {
const [formVals, setFormVals] = useState<Partial<TableListItem>>({
id: props.values.id,
name: props.values.name,
alias: props.values.alias,
type: props.values.type,
hosts: props.values.hosts,
note: props.values.note,
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="alias"
label="别名"
>
<Input placeholder="请输入" />
</FormItem>
<FormItem
name="type"
label="类型"
>
<Select defaultValue="Yarn" allowClear>
<Option value="Standalone">Standalone</Option>
<Option value="Yarn">Yarn</Option>
<Option value="Others">Others</Option>
</Select>
</FormItem>
<FormItem
name="hosts"
label="Hosts"
>
<TextArea placeholder="添加 Flink Hosts...例如:127.0.0.1:8081,127.0.0.1:8091" allowClear autoSize={{ minRows: 3, maxRows: 10 }}/>
</FormItem>
<FormItem
name="note"
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,
alias: formVals.alias,
type: formVals.type,
hosts: formVals.hosts,
note: formVals.note,
enabled: formVals.enabled,
}}
>
{renderContent(formVals)}
</Form>
</Modal>
);
};
export default UpdateForm;
export type ClusterTableListItem = {
id: number,
name: string,
alias: string,
type: string,
checkPoint: number,
savePointPath: string,
parallelism: number,
fragment: boolean,
clusterId: number,
note: string,
enabled: boolean,
createTime: Date,
updateTime: Date,
};
export type TableListPagination = {
total: number;
pageSize: number;
current: number;
};
export type TableListData = {
list: TableListItem[];
pagination: Partial<TableListPagination>;
};
export type TableListParams = {
status?: string;
name?: string;
desc?: string;
key?: number;
pageSize?: number;
currentPage?: number;
filter?: Record<string, any[]>;
sorter?: Record<string, any>;
};
This diff is collapsed.
import request from 'umi-request';
import type { TableListParams } from './data.d';
import {ClusterTableListItem} from "./data.d";
export async function queryCluster(params?: TableListParams) {
return request('/api/task', {
method: 'POST',
data: {
...params,
},
});
}
export async function removeCluster(params: number[]) {
return request('/api/task', {
method: 'DELETE',
data: {
...params,
},
});
}
export async function submitCluster(params: number[]) {
return request('/api/cluster/submit', {
method: 'POST',
data: {
...params,
},
});
}
export async function addOrUpdateCluster(params: ClusterTableListItem) {
return request('/api/task', {
method: 'PUT',
data: {
...params,
},
});
}
import React, {useEffect, useRef, useState} from 'react';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
function FlinkEditor(props:any) {
const {
style = { // dom节点样式
height: '300px',
width: '95%',
border: '1px solid #eee',
},
value = 'select * from ', // 代码文本
onChange = () => { // 改变的事件
},
fontSize = 14, // 代码字体大小
monacoOptions = {}, // monaco 自定义属性
language = 'sql', // 语言 支持 js ts sql css json html等
} = props;
const editOrRef = useRef();
const ThisEditor = useRef();
useEffect(() => {
ThisEditor.current = monaco.editor.create(editOrRef.current, {
value: value || '',
language,
theme: "vs",
fontSize: fontSize + 'px',
minimap: { // 关闭代码缩略图
enabled: true,
},
...monacoOptions,
});
ThisEditor.current.onDidChangeModelContent((e) => {
let newValue = ThisEditor.current.getValue();
onChange(newValue);
});
return () => {
ThisEditor.current.dispose();
ThisEditor.current = undefined; // 清除编辑器对象
}
}, []);
useEffect(() => {
if (ThisEditor.current) {
ThisEditor.current.updateOptions({
fontSize: fontSize + 'px',
})
}
}, [fontSize]);
return (
<div style={style}
ref={editOrRef}
>
</div>
);
}
export default FlinkEditor;
import React, { useRef, useEffect, forwardRef, useImperativeHandle } from 'react';
import MonacoEditor from 'react-monaco-editor';
import * as _monaco from 'monaco-editor';
// import styles from './index.less';
let provider = {
dispose: () => {},
};
interface IRightContent {
currentRecord: any; // fixme
handleCheck: () => Promise<boolean>;
secondRightData: (model.dataSource.BaseDataSourceField | model.dataSource.BaseDataSourceHeader)[];
}
export default forwardRef(
({ currentRecord, handleCheck, secondRightData = [] }: IRightContent, ref) => {
// 编辑器实例
const editorInstance = useRef<any>();
// 真实数据
const code: any = useRef(currentRecord ? currentRecord.formulaContent : '');
// 缓存数据
const cache: any = useRef(code.current);
// 输入引号触发页面刷新
const [refresh, setRefresh] = React.useState<boolean>(false);
const monacoInstance: any = useRef();
const options = {
selectOnLineNumbers: true,
renderSideBySide: false,
};
useImperativeHandle(ref, () => ({
handleSetEditorVal,
getEditorData: () => cache.current,
}));
useEffect(
() => () => {
provider.dispose(); // 弹窗关闭后 销毁编辑器实例
},
[]
);
/**
* 给编辑器设置值
* @param value 需要设置的值
*/
const handleSetEditorVal = (value: string): void => {
if (!value) return;
// 为所选取的值赋值到编辑器中
if (editorInstance.current && value) {
const selection = editorInstance?.current?.getSelection?.();
const range = new _monaco.Range(
selection.startLineNumber,
selection.startColumn,
selection.endLineNumber,
selection.endColumn
);
const id = { major: 1, minor: 1 };
const op = { identifier: id, range, text: value, forceMoveMarkers: true };
editorInstance.current.executeEdits('', [op]);
editorInstance.current.focus();
}
};
/**
* 编辑器change回调
* @param {String} val 当前编辑器的值
*/
const onChangeHandle = (val: string, event: { changes: { text: any }[] }) => {
const curWord = event.changes[0].text;
if (curWord === '"') {
cache.current = val + curWord;
setRefresh(!refresh); // 刷新页面
return;
}
cache.current = val;
};
/**
* 初始化编辑器
* @param {*} editor 编辑器实例
* @param {*} monaco
*/
interface ISuggestions {
label: string;
kind: string;
insertText: string;
detail?: string;
}
const editorDidMountHandle = (editor: any, monaco: any) => {
monacoInstance.current = monaco;
editorInstance.current = editor;
const newSecondRightFields: model.dataSource.BaseDataSourceHeader[] = [];
(secondRightData as model.dataSource.BaseDataSourceHeader[]).forEach((record) => {
if (record.fields && Array.isArray(record.fields)) {
record.fields.forEach((item: any) => {
// fixme
newSecondRightFields.push(item);
});
}
code.current = newSecondRightFields; // 数组长度永远为1
});
// 提示项设值
provider = monaco.languages.registerCompletionItemProvider('sql', {
provideCompletionItems() {
const suggestions: ISuggestions[] = [];
if (code && code.current) {
code.current.forEach((record) => {
suggestions.push({
// label未写错 中间加空格为了隐藏大写字段名称 大写字段名称用于规避自定义提示不匹配小写的bug
label:
record.label ||
`${record.displayName} (${
record.aliasName
}) ${''}(${record.aliasName.toUpperCase()})`, // 显示名称
kind: record.kind || monaco.languages.CompletionItemKind.Field, // 这里Function也可以是别的值,主要用来显示不同的图标
insertText: record.insertText || record.aliasName, // 实际粘贴上的值
detail: record.detail || `(property) ${record.aliasName}: String`,
});
});
}
[
'CASEWHEN(expression1, value1, expression2, value2, ..., else_value)',
'CONCAT(str1, str2, ...)',
'ISNULL (expression, defaultValue)',
'DATEDIFF_YEAR(startdate,enddate)',
'DATEDIFF_MONTH(startdate,enddate)',
'DATEDIFF_DAY(startdate,enddate)',
'SUM(expression)',
'AVG(expression)',
'MAX(expression)',
'MIN(expression)',
'COUNT(expression)',
'DISTINCTCOUNT(expression)',
'DISTINCTAVG(expression)',
'DISTINCTSUM(expression)',
'NOW()',
].forEach((item) => {
suggestions.push(
// 添加contact()函数
{
label: item, // 显示名称
kind: monaco.languages.CompletionItemKind.Function, // 这里Function也可以是别的值,主要用来显示不同的图标
insertText: item, // 实际粘贴上的值
}
);
});
return {
suggestions, // 必须使用深拷贝
};
},
quickSuggestions: false, // 默认提示关闭
triggerCharacters: ['$', '.', '='], // 触发提示的字符,可以写多个
});
editor.focus();
};
return (
<React.Fragment>
<MonacoEditor
width="100%"
height="400px"
language="sql"
value={cache.current}
options={options}
onChange={onChangeHandle}
editorDidMount={editorDidMountHandle}
/>
</React.Fragment>
);
}
);
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="添加任务"
visible={modalVisible}
onCancel={() => onCancel()}
footer={null}
>
{props.children}
</Modal>
);
};
export default CreateForm;
...@@ -3,11 +3,14 @@ export type TaskTableListItem = { ...@@ -3,11 +3,14 @@ export type TaskTableListItem = {
name: string, name: string,
alias: string, alias: string,
type: string, type: string,
checkPoint: number,
savePointPath: string,
parallelism: number,
fragment: boolean,
clusterId: number,
note: string, note: string,
enabled: boolean, enabled: boolean,
createUser: number,
createTime: Date, createTime: Date,
updateUser: number,
updateTime: Date, updateTime: Date,
}; };
......
...@@ -3,7 +3,7 @@ import type { TableListParams } from './data.d'; ...@@ -3,7 +3,7 @@ import type { TableListParams } from './data.d';
import {TaskTableListItem} from "./data.d"; import {TaskTableListItem} from "./data.d";
export async function queryTask(params?: TableListParams) { export async function queryTask(params?: TableListParams) {
return request('/api-dlink/task', { return request('/api/task', {
method: 'POST', method: 'POST',
data: { data: {
...params, ...params,
...@@ -12,7 +12,7 @@ export async function queryTask(params?: TableListParams) { ...@@ -12,7 +12,7 @@ export async function queryTask(params?: TableListParams) {
} }
export async function removeTask(params: number[]) { export async function removeTask(params: number[]) {
return request('/api-dlink/task', { return request('/api/task', {
method: 'DELETE', method: 'DELETE',
data: { data: {
...params, ...params,
...@@ -21,7 +21,7 @@ export async function removeTask(params: number[]) { ...@@ -21,7 +21,7 @@ export async function removeTask(params: number[]) {
} }
export async function submitTask(params: number[]) { export async function submitTask(params: number[]) {
return request('/api-dlink/task/submit', { return request('/api/task/submit', {
method: 'POST', method: 'POST',
data: { data: {
...params, ...params,
...@@ -30,7 +30,7 @@ export async function submitTask(params: number[]) { ...@@ -30,7 +30,7 @@ export async function submitTask(params: number[]) {
} }
export async function addOrUpdateTask(params: TaskTableListItem) { export async function addOrUpdateTask(params: TaskTableListItem) {
return request('/api-dlink/task', { return request('/api/task', {
method: 'PUT', method: 'PUT',
data: { data: {
...params, ...params,
......
...@@ -63,11 +63,7 @@ const Login: React.FC = () => { ...@@ -63,11 +63,7 @@ const Login: React.FC = () => {
try { try {
// 登录 // 登录
const msg = await login({ ...values, type }); const msg = await login({ ...values, type });
if (msg.code === 0 && msg.datas!=undefined && msg.datas.access_token != undefined ) { if (msg.code === 0 && msg.datas!=undefined ) {
if(localStorage.getItem('token')==null||localStorage.getItem('token')==undefined){
localStorage.setItem('token','');
}
localStorage.setItem('token',msg.datas.access_token);
const defaultloginSuccessMessage = intl.formatMessage({ const defaultloginSuccessMessage = intl.formatMessage({
id: 'pages.login.success', id: 'pages.login.success',
defaultMessage: '登录成功!', defaultMessage: '登录成功!',
...@@ -89,7 +85,7 @@ const Login: React.FC = () => { ...@@ -89,7 +85,7 @@ const Login: React.FC = () => {
} }
setSubmitting(false); setSubmitting(false);
}; };
const {code } = userLoginState; //const {code } = userLoginState;
return ( return (
<div className={styles.container}> <div className={styles.container}>
......
...@@ -6,7 +6,7 @@ import { request } from 'umi'; ...@@ -6,7 +6,7 @@ import { request } from 'umi';
/** 获取当前的用户 GET /api/currentUser */ /** 获取当前的用户 GET /api/currentUser */
export async function currentUser(options?: { [key: string]: any }) { export async function currentUser(options?: { [key: string]: any }) {
return request<API.Result>('/api-user/users/current', { return request<API.Result>('/api/current', {
method: 'GET', method: 'GET',
...(options || {}), ...(options || {}),
}); });
...@@ -14,7 +14,7 @@ export async function currentUser(options?: { [key: string]: any }) { ...@@ -14,7 +14,7 @@ export async function currentUser(options?: { [key: string]: any }) {
/** 退出登录接口 POST /api-uaa/oauth/remove/token?token= */ /** 退出登录接口 POST /api-uaa/oauth/remove/token?token= */
export async function outLogin(options?: { [key: string]: any }) { export async function outLogin(options?: { [key: string]: any }) {
return request<Record<string, any>>(`/api-uaa/oauth/remove/token?token=?token=${localStorage.getItem('token')}`, { return request<Record<string, any>>('/api/outLogin', {
method: 'DELETE', method: 'DELETE',
...(options || {}), ...(options || {}),
}); });
...@@ -22,12 +22,9 @@ export async function outLogin(options?: { [key: string]: any }) { ...@@ -22,12 +22,9 @@ export async function outLogin(options?: { [key: string]: any }) {
/** 登录接口 POST /api-uaa/oauth/token */ /** 登录接口 POST /api-uaa/oauth/token */
export async function login(body: API.LoginParams, options?: { [key: string]: any }) { export async function login(body: API.LoginParams, options?: { [key: string]: any }) {
return request<API.Result>('/api-uaa/oauth/token', { return request<API.Result>('/api/login', {
method: 'POST', method: 'POST',
headers: { data: body,
'Content-Type': 'application/x-www-form-urlencoded',
},
params: body,
...(options || {}), ...(options || {}),
}); });
} }
...@@ -39,47 +36,3 @@ export async function getNotices(options?: { [key: string]: any }) { ...@@ -39,47 +36,3 @@ export async function getNotices(options?: { [key: string]: any }) {
...(options || {}), ...(options || {}),
}); });
} }
/** 获取规则列表 GET /api/rule */
export async function rule(
params: {
// query
/** 当前的页码 */
current?: number;
/** 页面的容量 */
pageSize?: number;
},
options?: { [key: string]: any },
) {
return request<API.RuleList>('/api/rule', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 新建规则 PUT /api/rule */
export async function updateRule(options?: { [key: string]: any }) {
return request<API.RuleListItem>('/api/rule', {
method: 'PUT',
...(options || {}),
});
}
/** 新建规则 POST /api/rule */
export async function addRule(options?: { [key: string]: any }) {
return request<API.RuleListItem>('/api/rule', {
method: 'POST',
...(options || {}),
});
}
/** 删除规则 DELETE /api/rule */
export async function removeRule(options?: { [key: string]: any }) {
return request<Record<string, any>>('/api/rule', {
method: 'DELETE',
...(options || {}),
});
}
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