Commit 31384a46 authored by wenmo's avatar wenmo

删除无用文件

parent 046ffb48
#!/bin/bash
# 定义变量
# 要运行的jar包路径,加不加引号都行。 注意:等号两边 不能 有空格,否则会提示command找不到
JAR_NAME="./dlink-admin.jar"
LIB_PATH="./lib"
# 如果输入格式不对,给出提示!
tips() {
echo ""
echo "WARNING!!!......Tips, please use command: sh auto.sh [start|stop|restart|status]. For example: sh auto.sh start "
echo ""
exit 1
}
# 启动方法
start() {
# 重新获取一下pid,因为其它操作如stop会导致pid的状态更新
pid=`ps -ef | grep $JAR_NAME | grep -v grep | awk '{print $2}'`
# -z 表示如果$pid为空时执行
if [ -z $pid ]; then
nohup java -Djava.ext.dirs=$LIB_PATH -Doracle.jdbc.thinLogonCapability=o3 -jar -Xms512M -Xmx2048M -XX:PermSize=512M -XX:MaxPermSize=1024M $JAR_NAME > /dev/null 2>&1 &
pid=`ps -ef | grep $JAR_NAME | grep -v grep | awk '{print $2}'`
echo ""
echo "Service ${JAR_NAME} is starting!pid=${pid}"
echo "........................Start successfully!........................."
else
echo ""
echo "Service ${JAR_NAME} is already running,it's pid = ${pid}. If necessary, please use command: sh auto.sh restart."
echo ""
fi
}
# 停止方法
stop() {
# 重新获取一下pid,因为其它操作如start会导致pid的状态更新
pid=`ps -ef | grep $JAR_NAME | grep -v grep | awk '{print $2}'`
# -z 表示如果$pid为空时执行。 注意:每个命令和变量之间一定要前后加空格,否则会提示command找不到
if [ -z $pid ]; then
echo ""
echo "Service ${JAR_NAME} is not running! It's not necessary to stop it!"
echo ""
else
kill -9 $pid
echo ""
echo "Service stop successfully!pid:${pid} which has been killed forcibly!"
echo ""
fi
}
# 输出运行状态方法
status() {
# 重新获取一下pid,因为其它操作如stop、restart、start等会导致pid的状态更新
pid=`ps -ef | grep $JAR_NAME | grep -v grep | awk '{print $2}'`
# -z 表示如果$pid为空时执行。注意:每个命令和变量之间一定要前后加空格,否则会提示command找不到
if [ -z $pid ];then
echo ""
echo "Service ${JAR_NAME} is not running!"
echo ""
else
echo ""
echo "Service ${JAR_NAME} is running. It's pid=${pid}"
echo ""
fi
}
# 重启方法
restart() {
echo ""
echo ".............................Restarting.............................."
echo "....................................................................."
# 重新获取一下pid,因为其它操作如start会导致pid的状态更新
pid=`ps -ef | grep $JAR_NAME | grep -v grep | awk '{print $2}'`
# -z 表示如果$pid为空时执行。 注意:每个命令和变量之间一定要前后加空格,否则会提示command找不到
if [ ! -z $pid ]; then
kill -9 $pid
fi
start
echo "....................Restart successfully!..........................."
}
# 根据输入参数执行对应方法,不输入则执行tips提示方法
case "$1" in
"start")
start
;;
"stop")
stop
;;
"status")
status
;;
"restart")
restart
;;
*)
tips
;;
esac
\ No newline at end of file
......@@ -21,15 +21,9 @@ export default [
icon: 'home',
component: './Welcome',
},
/*{
path: '/studio',
name: 'studio',
icon: 'consoleSql',
component: './Studio',
},*/
{
path: '/flinksqlstudio',
name: 'flinsqlstudio',
name: 'flinksqlstudio',
icon: 'consoleSql',
component: './FlinkSqlStudio',
},
......@@ -45,6 +39,12 @@ export default [
icon: 'cluster',
component: './Cluster',
},
{
path: '/document',
name: 'document',
icon: 'cluster',
component: './Document',
},
/*{
path: '/dev',
name: 'dev',
......
export const executeSql = (url:string, selectedRows: [], enabled: boolean) => {
};
import * as monaco from "monaco-editor";
const Completion =[
/** * 内置函数 */
{
label: 'SUM(number)',
kind: monaco.languages.CompletionItemKind.Function,
insertText: 'SUM(${1:})',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
detail: '返回指定参数的求和'
}
];
export default Completion;
import { Tabs } from 'antd';
import React from 'react';
import FlinkSqlEditor from "@/components/FlinkSqlEditor";
const { TabPane } = Tabs;
const initialPanes = [
{ title: '未命名', key: '0' ,value:'select * from ',closable: false,},
];
class EditorTabs extends React.Component {
newTabIndex = 1;
state = {
activeKey: initialPanes[0].key,
panes: initialPanes,
};
onChange = (activeKey: any) => {
this.setState({ activeKey });
};
onEdit = (targetKey: any, action: any) => {
this[action](targetKey);
};
updateValue = (targetKey: any, val: string)=>{
const { panes, activeKey } = this.state;
panes.forEach((pane, i) => {
if (pane.key === targetKey) {
pane.value = val;
return;
}
});
/*debugger;
this.setState({
panes:panes,
activeKey: activeKey,
});*/
};
add = () => {
const { panes } = this.state;
const activeKey = this.newTabIndex++;
const newPanes = [...panes];
newPanes.push({ title: `未命名${activeKey}`,value:'', key: `${activeKey}` });
this.setState({
panes: newPanes,
activeKey: activeKey,
});
};
remove = (targetKey:any) => {
const { panes, activeKey } = this.state;
let newActiveKey = activeKey;
let lastIndex = 1;
panes.forEach((pane, i) => {
if (pane.key === targetKey) {
lastIndex = i - 1;
}
});
const newPanes = panes.filter(pane => pane.key !== targetKey);
if (newPanes.length && newActiveKey === targetKey) {
if (lastIndex >= 0) {
newActiveKey = newPanes[lastIndex].key;
} else {
newActiveKey = newPanes[0].key;
}
}
this.setState({
panes: newPanes,
activeKey: newActiveKey,
});
};
render() {
const { panes, activeKey } = this.state;
return (
<Tabs
type="editable-card"
onChange={this.onChange}
activeKey={activeKey}
onEdit={this.onEdit}
>
{panes.map(pane => (
<TabPane tab={pane.title} key={pane.key} closable={pane.closable}>
<FlinkSqlEditor value={{formulaContent:pane.value}} onChange={
(val: string)=>{
this.updateValue(pane.key,val);
}} />
</TabPane>
))}
</Tabs>
);
}
}
export default EditorTabs;
export type BaseDataSourceField ={
fields:[{
label?:string,
displayName?:string,
aliasName?:string,
kind?:any,
insertText?:string,
insertTextRules?:any,
detail?:string,
}]
}
export type BaseDataSourceHeader ={
fields:[{
label?:string,
displayName?:string,
aliasName?:string,
kind?:any,
insertText?:string,
insertTextRules?:any,
detail?:string,
}]
}
export type CompletionItem ={
label?:string,
kind?:any,
insertText?:string,
insertTextRules?:any,
detail?:string,
}
export type StudioParam = {
statement:string,
}
import React, {useEffect, useImperativeHandle, useRef} from 'react';
import * as _monaco from "monaco-editor";
import MonacoEditor from "react-monaco-editor/lib/editor";
import {BaseDataSourceField, BaseDataSourceHeader, CompletionItem} from "@/components/FlinkSqlEditor/data";
import Completion from "@/components/FlinkSqlEditor/completion";
import {connect} from "umi";
import {StateType} from "@/components/FlinkSqlEditor/model";
import {executeSql} from "@/components/FlinkSqlEditor/service";
let provider = {
dispose: () => {},
};
interface IRightContent {
value: any;
handleCheck: () => Promise<boolean>;
secondRightData: (BaseDataSourceField|BaseDataSourceHeader)[];
}
const FlinkSqlEditor = (props:any) => {
const {
height = '300px',
width = '100%',
language = 'sql',
onChange=(val: string, event: { changes: { text: any }[] })=>{},
options = {
selectOnLineNumbers: true,
renderSideBySide: false,
},
} = props
;
const { value, handleCheck, secondRightData = [] }: IRightContent = props;
const editorInstance:any = useRef<any>();
const monacoInstance: any = useRef();
const code: any = useRef(value ? value.formulaContent : '');
const cache: any = useRef(code.current);
const [refresh, setRefresh] = React.useState<boolean>(false);
useEffect(
() => () => {
provider.dispose();
},
[]
);
useImperativeHandle(editorInstance, () => ({
handleSetEditorVal,
getEditorData: () => cache.current,
}));
const submit = async () => {
await executeSql({statement:cache.current});
};
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();
}
};
const onChangeHandle = (val: string, event: { changes: { text: any }[] }) => {
onChange(val,event);
/*const curWord = event.changes[0].text;
if (curWord === ';') {
cache.current = val +'\r\n';
setRefresh(!refresh); // 刷新页面
return;
}
cache.current = val;*/
};
interface ISuggestions {
label: string;
kind: string;
insertText: string;
detail?: string;
}
const editorDidMountHandle = (editor: any, monaco: any) => {
monacoInstance.current = monaco;
editorInstance.current = editor;
const newSecondRightFields: BaseDataSourceHeader[] = [];
(secondRightData as BaseDataSourceHeader[]).forEach((record) => {
if (record.fields && Array.isArray(record.fields)) {
record.fields.forEach((item: any) => {
newSecondRightFields.push(item);
});
}
});
code.current = newSecondRightFields; // 数组长度永远为1
// 提示项设值
provider = monaco.languages.registerCompletionItemProvider('sql', {
provideCompletionItems() {
const suggestions: ISuggestions[] = [];
if (code && code.current) {
code.current.forEach((record:any) => {
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`,
});
});
}
Completion.forEach((item:CompletionItem) => {
suggestions.push(item);
});
return {
suggestions,
};
},
quickSuggestions: true,
triggerCharacters: ['$', '.', '='],
});
editor.focus();
};
return (
<React.Fragment>
<MonacoEditor
width={width}
height={height}
language={language}
value={cache.current}
options={options}
onChange={onChangeHandle}
editorDidMount={editorDidMountHandle}
/>
</React.Fragment>
);
};
export default FlinkSqlEditor;
import type { Effect, Reducer } from 'umi';
export type StateType = {
value?: string;
};
export type ModelType = {
namespace: string;
state: StateType;
effects: {
updateSql: Effect;
};
reducers: {
saveValue: Reducer<StateType>;
};
};
const Model: ModelType = {
namespace: 'sqlEditorValue',
state: {
value: 'select ',
},
effects: {
*updateSql({ payload }, { call, put }) {
yield put({
type: 'saveValue',
payload,
});
},
},
reducers: {
saveValue(state, { payload }) {
return {
...state,
value: payload,
};
},
},
};
export default Model;
import request from 'umi-request';
import {StudioParam} from "@/components/FlinkSqlEditor/data";
export async function executeSql(params: StudioParam) {
return request('/api-dlink/studio/executeSql', {
method: 'POST',
data: {
...params,
},
});
}
......@@ -113,7 +113,8 @@ const StudioConnector = (props:any) => {
let newTableData = tableData;
for (let i=0; i<newTableData.length; i++) {
if (newTableData[i].tablename == item.tablename) {
newTableData.splice(i, 1);
// newTableData.splice(i, 1);
delete newTableData[i];
setTableData(newTableData);
break;
}
......
......@@ -52,9 +52,9 @@ export default {
'menu.demo': 'Demo 开发模板',
'menu.cluster': '集群中心',
'menu.studio': 'FlinkSql IDE',
'menu.flinsqlstudio': 'FlinkSql Studio',
'menu.flinksqlstudio': 'FlinkSql Studio',
'menu.task': '作业中心',
'menu.dai': 'Dai 人工智能',
'menu.document': '文档中心',
'menu.dev': 'Dev 开发者工具',
'menu.dev.flink': 'Flink 计算框架',
'menu.dev.flink.docs': '官方文档',
......
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;
import React, {useEffect, useState} from 'react';
import { Form, Button, Input, Modal, InputNumber, 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,
sqlIndex: props.values.sqlIndex,
statement: props.values.statement,
note: props.values.note,
enabled: props.values.enabled,
taskId: props.values.taskId,
});
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="名称"
>
<Input placeholder="请输入" />
</FormItem>
<FormItem
name="alias"
label="表名"
>
<Input placeholder="请输入" />
</FormItem>
<FormItem
name="type"
label="类型"
>
<Select defaultValue="CREATE TABLE" allowClear>
<Option value="CREATE TABLE">CREATE TABLE</Option>
<Option value="INSERT INTO">INSERT INTO</Option>
<Option value="CREATE VIEW">CREATE VIEW</Option>
<Option value="CREATE AGGTABLE">CREATE AGGTABLE</Option>
</Select>
</FormItem>
<FormItem
name="sqlIndex"
label="次序"
>
<InputNumber min={0} max={100}/>
</FormItem>
<FormItem
name="statement"
label="语句"
>
<TextArea placeholder="添加 Flink Sql..." allowClear autoSize={{ minRows: 3, maxRows: 10 }}/>
</FormItem>
<FormItem
name="note"
label="备注"
>
<TextArea placeholder="添加备注" allowClear />
</FormItem>
<FormItem
name="enabled"
label="是否启用"
rules={[{ required: true, message: '请输入是否启用!' }]} >
<Switch checkedChildren="启用" unCheckedChildren="禁用"
defaultChecked={formVals.enabled}/>
</FormItem>
<FormItem
name="taskId"
label="任务ID"
rules={[{ required: true, message: '请输入任务ID!' }]} >
<Input placeholder="请输入" />
</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="编辑FlinkSql"
visible={updateModalVisible}
footer={renderFooter()}
onCancel={() => handleUpdateModalVisible()}
>
<Form
{...formLayout}
form={form}
initialValues={{
id: formVals.id,
name: formVals.name,
alias: formVals.alias,
type: formVals.type,
sqlIndex: formVals.sqlIndex,
statement: formVals.statement,
note: formVals.note,
enabled: formVals.enabled,
taskId: formVals.taskId,
}}
>
{renderContent(formVals)}
</Form>
</Modal>
);
};
export default UpdateForm;
export type FlinkSqlTableListItem = {
id: number,
name: string,
alias: string,
type: string,
sqlIndex: number,
statement: string,
note: string,
enabled: boolean,
createUser: number,
createNickName: string,
createTime: Date,
updateUser: number,
updateNickName: string,
updateTime: Date,
taskId: number,
};
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>;
};
import {DownOutlined, 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 { FlinkSqlTableListItem } from './data.d';
import styles from './index.less';
import Dropdown from "antd/es/dropdown/dropdown";
import Menu from "antd/es/menu";
import {handleAddOrUpdate, handleRemove, handleSubmit, queryData, updateEnabled} from "@/components/Common/crud";
const url = '/api-dlink/flinkSql';
const FlinkSqlTableList: 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<FlinkSqlTableListItem>();
const [selectedRowsState, setSelectedRows] = useState<FlinkSqlTableListItem[]>([]);
const editAndDelete = (key: string | number, currentItem: FlinkSqlTableListItem) => {
if (key === 'edit') {
handleUpdateModalVisible(true);
setFormValues(currentItem);
} else if (key === 'delete') {
Modal.confirm({
title: '删除FlinkSql',
content: '确定删除该FlinkSql吗?',
okText: '确认',
cancelText: '取消',
onOk:async () => {
await handleRemove(url,[currentItem]);
actionRef.current?.reloadAndRest?.();
}
});
}
};
const MoreBtn: React.FC<{
item: FlinkSqlTableListItem;
}> = ({ 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<FlinkSqlTableListItem>[] = [
{
title: '名称',
dataIndex: 'name',
tip: 'name是唯一的',
sorter: true,
formItemProps: {
rules: [
{
required: true,
message: 'name为必填项',
},
],
},
render: (dom, entity) => {
return <a onClick={() => setRow(entity)}>{dom}</a>;
},
},
{
title: '表名',
sorter: true,
dataIndex: 'alias',
hideInForm: false,
hideInTable:false,
},
{
title: '类型',
sorter: true,
dataIndex: 'type',
hideInForm: false,
hideInSearch:true,
hideInTable:false,
filters: [
{
text: 'CREATE TABLE',
value: 'CREATE TABLE',
},
{
text: 'INSERT INTO',
value: 'INSERT INTO',
},
{
text: 'CREATE VIEW',
value: 'CREATE VIEW',
},
{
text: 'CREATE AGGTABLE',
value: 'CREATE AGGTABLE',
},
],
filterMultiple: false,
valueEnum: {
'CREATE TABLE': { text: 'CREATE TABLE'},
'INSERT INTO': { text: 'INSERT INTO'},
'CREATE VIEW': { text: 'CREATE VIEW' },
'CREATE AGGTABLE': { text: 'CREATE AGGTABLE' },
},
},
{
title: '次序',
sorter: true,
dataIndex: 'sqlIndex',
hideInForm: false,
hideInSearch:true,
hideInTable:false,
},
{
title: '语句',
sorter: true,
valueType: 'textarea',
dataIndex: 'statement',
hideInForm: false,
hideInSearch:true,
hideInTable:true,
},
{
title: '备注',
sorter: true,
dataIndex: 'note',
valueType: 'textarea',
hideInForm: false,
hideInSearch:true,
hideInTable:true,
},
{
title: '是否启用',
sorter: true,
dataIndex: 'enabled',
hideInForm: false,
hideInSearch:true,
hideInTable:false,
filters: [
{
text: '正常',
value: 1,
},
{
text: '禁用',
value: 0,
},
],
filterMultiple: false,
valueEnum: {
true: { text: '正常', status: 'Success' },
false: { text: '禁用', status: 'Error' },
},
},
{
title: '创建人ID',
sorter: true,
dataIndex: 'createUser',
hideInForm: true,
hideInSearch:true,
hideInTable:true,
hideInDescriptions:true,
},
{
title: '创建人',
sorter: true,
dataIndex: 'createNickName',
hideInForm: true,
hideInSearch: true,
hideInTable:true,
},
{
title: '创建时间',
sorter: true,
dataIndex: 'createTime',
hideInForm: true,
hideInTable:true,
valueType: 'dateTime',
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: '更新人ID',
sorter: true,
dataIndex: 'updateUser',
hideInForm: true,
hideInSearch:true,
hideInTable:true,
hideInDescriptions:true,
},
{
title: '更新人',
sorter: true,
dataIndex: 'updateNickName',
hideInForm: true,
hideInSearch: true,
hideInTable: false,
},
{
title: '更新时间',
sorter: true,
dataIndex: 'updateTime',
hideInForm: true,
hideInTable:false,
valueType: 'dateTime',
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: '任务ID',
sorter: true,
dataIndex: 'taskId',
hideInForm: false,
hideInSearch:true,
hideInTable:false,
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => [
<a
onClick={() => {
handleUpdateModalVisible(true);
setFormValues(record);
}}
>
配置
</a>,
<MoreBtn key="more" item={record} />,
],
},
];
return (
<PageContainer>
<ProTable<FlinkSqlTableListItem>
headerTitle="FlinkSql管理"
actionRef={actionRef}
rowKey="id"
search={{
labelWidth: 120,
}}
toolBarRender={() => [
<Button type="primary" onClick={() => handleModalVisible(true)}>
<PlusOutlined /> 新建
</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>
被禁用的FlinkSql共 {selectedRowsState.length - selectedRowsState.reduce((pre, item) => pre + (item.enabled?1:0), 0)}
</span>
</div>
}
>
<Button type="primary" danger
onClick ={()=>{
Modal.confirm({
title: '禁用FlinkSql',
content: '确定禁用选中的FlinkSql吗?',
okText: '确认',
cancelText: '取消',
onOk:async () => {
await handleRemove(url,selectedRowsState);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>
批量删除
</Button>
<Button type="primary"
onClick ={()=>{
Modal.confirm({
title: '禁用FlinkSql',
content: '确定禁用选中的FlinkSql吗?',
okText: '确认',
cancelText: '取消',
onOk:async () => {
await updateEnabled(url,selectedRowsState,true);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量启用</Button>
<Button danger
onClick ={()=>{
Modal.confirm({
title: '禁用FlinkSql',
content: '确定禁用选中的FlinkSql吗?',
okText: '确认',
cancelText: '取消',
onOk:async () => {
await updateEnabled(url,selectedRowsState, false);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量禁用</Button>
</FooterToolbar>
)}
<CreateForm onCancel={() => handleModalVisible(false)} modalVisible={createModalVisible}>
<ProTable<FlinkSqlTableListItem, FlinkSqlTableListItem>
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<FlinkSqlTableListItem>
column={2}
title={row?.name}
request={async () => ({
data: row || {},
})}
params={{
id: row?.name,
}}
columns={columns}
/>
)}
</Drawer>
</PageContainer>
);
};
export default FlinkSqlTableList;
import request from 'umi-request';
import type { TableListParams } from './data.d';
import {FlinkSqlTableListItem} from "./data.d";
export async function queryFlinkSql(params?: TableListParams) {
return request('/api-dlink/flinkSql', {
method: 'POST',
data: {
...params,
},
});
}
export async function removeFlinkSql(params: number[]) {
return request('/api-dlink/flinkSql', {
method: 'DELETE',
data: {
...params,
},
});
}
export async function addOrUpdateFlinkSql(params: FlinkSqlTableListItem) {
return request('/api-dlink/flinkSql', {
method: 'PUT',
data: {
...params,
},
});
}
.container {
:global {
#components-dropdown-demo-placement .ant-btn {
margin-right: 8px;
margin-bottom: 8px;
}
}
}
import React from "react";
import styles from "./index.less";
import { Menu, Dropdown, Button, Row, Col } from "antd";
const menu = (
<Menu>
<Menu.Item>
<a
target="_blank"
rel="noopener noreferrer"
href="http://www.alipay.com/"
>
1st menu item
</a>
</Menu.Item>
<Menu.Item>
<a
target="_blank"
rel="noopener noreferrer"
href="http://www.taobao.com/"
>
2nd menu item
</a>
</Menu.Item>
<Menu.Item>
<a target="_blank" rel="noopener noreferrer" href="http://www.tmall.com/">
3rd menu item
</a>
</Menu.Item>
</Menu>
);
export default () => (
<Row>
<Col span={24}>
<div className={styles.container}>
<div id="components-dropdown-demo-placement">
<div>
<Dropdown overlay={menu}>
<Button>文件</Button>
</Dropdown>
<Dropdown overlay={menu}>
<Button>编辑</Button>
</Dropdown>
<Dropdown overlay={menu}>
<Button>运行</Button>
</Dropdown>
<Dropdown overlay={menu}>
<Button>帮助</Button>
</Dropdown>
</div>
</div>
</div>
</Col>
</Row>
);
@import '~antd/lib/style/themes/default.less';
.container{
background: #fafafa;
border: 1px solid #e6f7ff;
}
.ant-divider-horizontal-0 {
margin: 0!important;
}
.dw-path{
margin-left: 10px;
line-height: 32px;
}
import React from "react";
import styles from "./index.less";
import { Menu, Dropdown, Typography, Row, Col } from "antd";
import {CaretRightOutlined, DownOutlined, PlayCircleOutlined } from "@ant-design/icons";
import Space from "antd/es/space";
import Divider from "antd/es/divider";
import Button from "antd/es/button/button";
import Breadcrumb from "antd/es/breadcrumb/Breadcrumb";
const { SubMenu } = Menu;
//<Button shape="circle" icon={<CaretRightOutlined />} />
const menu = (
<Menu>
<Menu.Item>1st 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>
);
export default () => (
<Row className={styles.container}>
<Col span={24}>
<div>
<Space>
<Dropdown overlay={menu}>
<Button type="text" onClick={e => e.preventDefault()}>
文件
</Button>
</Dropdown>
<Dropdown overlay={menu}>
<Button type="text" onClick={e => e.preventDefault()}>
编辑
</Button>
</Dropdown>
<Dropdown overlay={menu}>
<Button type="text" onClick={e => e.preventDefault()}>
执行
</Button>
</Dropdown>
<Dropdown overlay={menu}>
<Button type="text" onClick={e => e.preventDefault()}>
帮助
</Button>
</Dropdown>
</Space>
</div>
</Col>
<Divider className={styles["ant-divider-horizontal-0"]}/>
<Col span={24}>
<Breadcrumb className={styles["dw-path"]}>
<Breadcrumb.Item>数据仓库</Breadcrumb.Item>
<Breadcrumb.Item>维度</Breadcrumb.Item>
<Breadcrumb.Item>用户</Breadcrumb.Item>
</Breadcrumb>
</Col>
</Row>
);
.container {
:global {
#components-tabs-demo-card-top .code-box-demo {
background: #f5f5f5;
overflow: hidden;
padding: 24px;
}
[data-theme="dark"]
.card-container
> .ant-tabs-card
> .ant-tabs-bar
.ant-tabs-tab {
border-color: transparent;
background: transparent;
}
[data-theme="dark"] #components-tabs-demo-card-top .code-box-demo {
background: #000;
}
[data-theme="dark"]
.card-container
> .ant-tabs-card
> .ant-tabs-content
> .ant-tabs-tabpane {
background: #141414;
}
[data-theme="dark"] .card-container > .ant-tabs-card > .ant-tabs-bar {
border-color: #141414;
}
[data-theme="dark"]
.card-container
> .ant-tabs-card
> .ant-tabs-bar
.ant-tabs-tab-active {
border-color: #141414;
background: #141414;
}
}
}
import React from "react";
import styles from "./index.less";
import { Tabs } from "antd";
const { TabPane } = Tabs;
export default () => (
<div className={styles.container}>
<div id="components-tabs-demo-card-top">
<div className="card-container">
<Tabs type="card">
<TabPane tab="Tab Title 1" key="1">
<p>Content of Tab Pane 1</p>
<p>Content of Tab Pane 1</p>
<p>Content of Tab Pane 1</p>
</TabPane>
<TabPane tab="Tab Title 2" key="2">
<p>Content of Tab Pane 2</p>
<p>Content of Tab Pane 2</p>
<p>Content of Tab Pane 2</p>
</TabPane>
<TabPane tab="Tab Title 3" key="3">
<p>Content of Tab Pane 3</p>
<p>Content of Tab Pane 3</p>
<p>Content of Tab Pane 3</p>
</TabPane>
</Tabs>
</div>
</div>
</div>
);
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 '~antd/es/style/themes/default.less';
.main {
width: 100%;
//background: @component-background;
}
.card {
margin-bottom: 24px;
:global {
.ant-legacy-form-item .ant-legacy-form-item-control-wrapper {
width: 100%;
}
}
}
.card{
background-color: #ffffff;
}
import { PageContainer } from '@ant-design/pro-layout';
import React, { useState, useEffect } from 'react';
import { Spin } from 'antd';
import styles from './index.less';
import FlinkSqlEditor from '@/components/FlinkSqlEditor';
import * as monaco from 'monaco-editor';
import Card from 'antd/es/card';
import DropdownSubMenu from './DropdownSubMenu';
import EditorTabs from "@/components/FlinkSqlEditor/components/EditorTabs";
export default () => {
const code: string = 'select count(1) from ';
const value: any = {
formulaContent: code,
};
const secondRightData = [
{
fields: [
{
label: 'name1',
displayName: 'name2',
aliasName: 'name3',
kind: monaco.languages.CompletionItemKind.Field,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
insertText: 'name:string',
detail: '详情',
},
],
},
];
const callbackTab = () => {};
return (
<PageContainer
content="这是一个 FlinkSql 在线编辑器(测试版),请从这里进行开发!"
className={styles.main}
>
<Card bordered={false} className={styles.card}>
<DropdownSubMenu />
<div
style={{
height: 300,
}}
>
<FlinkSqlEditor value={value} secondRightData={secondRightData} />
</div>
</Card>
</PageContainer>
);
};
@import '~antd/lib/style/themes/default.less';
.container{
background: #fafafa;
border: 1px solid #e6f7ff;
}
.ant-divider-horizontal-0 {
margin: 0!important;
}
.dw-path{
margin-left: 10px;
line-height: 32px;
}
import React from "react";
import styles from "./index.less";
import { Menu, Dropdown, Typography, Row, Col } from "antd";
import {CaretRightOutlined, DownOutlined, PlayCircleOutlined } from "@ant-design/icons";
import Space from "antd/es/space";
import Divider from "antd/es/divider";
import Button from "antd/es/button/button";
import Breadcrumb from "antd/es/breadcrumb/Breadcrumb";
import FlinkSqlEditor from "@/components/FlinkSqlEditor";
import {Simulate} from "react-dom/test-utils";
const { SubMenu } = Menu;
//<Button shape="circle" icon={<CaretRightOutlined />} />
const menu = (
<Menu>
<Menu.Item>1st 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>
);
const runMenu = (
<Menu>
<Menu.Item onClick={()=>{
FlinkSqlEditor.call('submit');
}}>远程执行</Menu.Item>
</Menu>
);
export default () => (
<Row className={styles.container}>
<Col span={24}>
<div>
<Space>
<Dropdown overlay={menu}>
<Button type="text" onClick={e => e.preventDefault()}>
文件
</Button>
</Dropdown>
<Dropdown overlay={menu}>
<Button type="text" onClick={e => e.preventDefault()}>
编辑
</Button>
</Dropdown>
<Dropdown overlay={runMenu}>
<Button type="text" onClick={e => e.preventDefault()}>
执行
</Button>
</Dropdown>
<Dropdown overlay={menu}>
<Button type="text" onClick={e => e.preventDefault()}>
帮助
</Button>
</Dropdown>
</Space>
</div>
</Col>
<Divider className={styles["ant-divider-horizontal-0"]}/>
<Col span={24}>
<Breadcrumb className={styles["dw-path"]}>
<Breadcrumb.Item>数据仓库</Breadcrumb.Item>
<Breadcrumb.Item>维度</Breadcrumb.Item>
<Breadcrumb.Item>用户</Breadcrumb.Item>
</Breadcrumb>
</Col>
</Row>
);
import {handleAddOrUpdate} from "@/components/Common/crud";
export const updateEnabled = (url:string, selectedRows: [], enabled: boolean) => {
selectedRows.forEach((item) => {
handleAddOrUpdate(url,{id: item.id, enabled: enabled})
})
};
@import '~antd/es/style/themes/default.less';
.main {
width: 100%;
//background: @component-background;
}
.card {
margin-bottom: 24px;
:global {
.ant-legacy-form-item .ant-legacy-form-item-control-wrapper {
width: 100%;
}
}
}
.card{
background-color: #ffffff;
}
import { PageContainer } from '@ant-design/pro-layout';
import React, { useState, useEffect } from 'react';
import { Spin } from 'antd';
import styles from './index.less';
import * as monaco from 'monaco-editor';
import Card from 'antd/es/card';
import DropdownSubMenu from './DropdownSubMenu';
import EditorTabs from "@/components/FlinkSqlEditor/components/EditorTabs";
export default () => {
const code: string = 'select count(1) from ';
const value: any = {
formulaContent: code,
};
const secondRightData = [
{
fields: [
{
label: 'name1',
displayName: 'name2',
aliasName: 'name3',
kind: monaco.languages.CompletionItemKind.Field,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
insertText: 'name:string',
detail: '详情',
},
],
},
];
const callbackTab = () => {};
return (
<PageContainer
content="这是一个 FlinkSql 在线编辑器(测试版),请从这里进行开发!"
className={styles.main}
>
<Card bordered={false} className={styles.card}>
<DropdownSubMenu />
<div
style={{
height: 300,
}}
>
<EditorTabs value={value} secondRightData={secondRightData} />
</div>
</Card>
</PageContainer>
);
};
......@@ -90,7 +90,7 @@ export default (): React.ReactNode => {
</li>
</ul>
</Paragraph></>} reverse={true}>
<Timeline.Item><Text code>0.1.0</Text> <Text type="secondary">2021-06-04</Text>
<Timeline.Item><Text code>0.1.0</Text> <Text type="secondary">2021-06-06</Text>
<p> </p>
<Paragraph>
<ul>
......
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