公式编辑器组件封装

This commit is contained in:
黎永顺 2023-04-13 10:00:24 +08:00
parent cbf784a2e9
commit 644113efcb
6 changed files with 703 additions and 0 deletions

View File

@ -0,0 +1,16 @@
export const keyboardBaseBtns=[
{ key:"1", label: "+" },
{ key:"2", label: "-" },
{ key:"3", label: ">" },
{ key:"4", label: ">=" },
{ key:"5", label: "=" },
{ key:"6", label: "*" },
{ key:"7", label: "/" },
{ key:"8", label: "<" },
{ key:"9", label: "<=" },
{ key:"10", label: "!=" },
{ key:"11", label: "(" },
{ key:"12", label: ")" },
{ key:"13", label: "%" },
{ key:"space", label: "space" },
]

View File

@ -0,0 +1,111 @@
// extendCodeMirror.js
/* eslint-disable */
import * as CodeMirror from 'codemirror';
CodeMirror.extendMode("css", {
commentStart: "/*",
commentEnd: "*/",
newlineAfterToken: function(type, content) {
return /^[;{}]$/.test(content);
}
});
CodeMirror.extendMode("javascript", {
commentStart: "/*",
commentEnd: "*/",
// FIXME semicolons inside of for
newlineAfterToken: function(type, content, textAfter, state) {
if (this.jsonMode) {
return /^[\[,{]$/.test(content) || /^}/.test(textAfter)|| /^]/.test(textAfter);
} else {
if (content == ";" && state.lexical && state.lexical.type == ")") return false;
return /^[;{}]$/.test(content) && !/^;/.test(textAfter);
}
}
});
CodeMirror.extendMode("xml", {
commentStart: "<!--",
commentEnd: "-->",
newlineAfterToken: function(type, content, textAfter) {
return type == "tag" && />$/.test(content) || /^</.test(textAfter);
}
});
// Comment/uncomment the specified range
CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
var cm = this, curMode = CodeMirror.innerMode(cm.getMode(), cm.getTokenAt(from).state).mode;
cm.operation(function() {
if (isComment) { // Comment range
cm.replaceRange(curMode.commentEnd, to);
cm.replaceRange(curMode.commentStart, from);
if (from.line == to.line && from.ch == to.ch) // An empty comment inserted - put cursor inside
cm.setCursor(from.line, from.ch + curMode.commentStart.length);
} else { // Uncomment range
var selText = cm.getRange(from, to);
var startIndex = selText.indexOf(curMode.commentStart);
var endIndex = selText.lastIndexOf(curMode.commentEnd);
if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
// Take string till comment start
selText = selText.substr(0, startIndex)
// From comment start till comment end
+ selText.substring(startIndex + curMode.commentStart.length, endIndex)
// From comment end till string end
+ selText.substr(endIndex + curMode.commentEnd.length);
}
cm.replaceRange(selText, from, to);
}
});
});
// Applies automatic mode-aware indentation to the specified range
CodeMirror.defineExtension("autoIndentRange", function (from, to) {
var cmInstance = this;
this.operation(function () {
for (var i = from.line; i <= to.line; i++) {
cmInstance.indentLine(i, "smart");
}
});
});
// Applies automatic formatting to the specified range
CodeMirror.defineExtension("autoFormatRange", function (from, to) {
var cm = this;
var outer = cm.getMode(), text = cm.getRange(from, to).split("\n");
var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state);
var tabSize = cm.getOption("tabSize");
var out = "", lines = 0, atSol = from.ch == 0;
function newline() {
out += "\n";
atSol = true;
++lines;
}
for (var i = 0; i < text.length; ++i) {
var stream = new CodeMirror.StringStream(text[i], tabSize);
while (!stream.eol()) {
var inner = CodeMirror.innerMode(outer, state);
var style = outer.token(stream, state), cur = stream.current();
stream.start = stream.pos;
if (!atSol || /\S/.test(cur)) {
out += cur;
atSol = false;
}
if (!atSol && inner.mode.newlineAfterToken &&
inner.mode.newlineAfterToken(style, cur, stream.string.slice(stream.pos) || text[i+1] || "", inner.state))
newline();
}
if (!stream.pos && outer.blankLine) outer.blankLine(state);
if (!atSol) newline();
}
cm.operation(function () {
cm.replaceRange(out, from, to);
for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur)
cm.indentLine(cur, "smart");
cm.setSelection(from, cm.getCursor(false));
});
});
// console.log("初始化CodeMirror完成");
export default CodeMirror;

View File

@ -0,0 +1,112 @@
import React, { Component } from "react";
import { Button } from "antd";
import { UnControlled as CodeMirror } from "react-codemirror2";
import { keyboardBaseBtns } from "./constants";
import cs from "classnames";
import "./index.less";
import "codemirror/lib/codemirror.css";
import "codemirror/lib/codemirror.js";
import "codemirror/theme/dracula.css"; //主题
//代码折叠
import "codemirror/addon/fold/foldgutter.css";
import "codemirror/addon/lint/lint.css";
import "codemirror/addon/fold/foldcode.js";
import "codemirror/addon/fold/foldgutter.js";
import "codemirror/addon/fold/brace-fold.js";
import "codemirror/addon/hint/javascript-hint.js";
import "codemirror/addon/hint/show-hint.js";
import "codemirror/addon/lint/lint.js";
import "codemirror/addon/lint/json-lint.js";
import "codemirror/addon/lint/javascript-lint.js";
import "codemirror/addon/display/placeholder.js";
import "codemirror/mode/javascript/javascript.js";
import "codemirror/mode/sql/sql.js";
// const sqlFormatter = require('sql-formatter');
class ExcelEditor extends Component {
constructor(props) {
super(props);
this.state = {
value: ""
};
}
render() {
return (
<React.Fragment>
<div className="excel-codeWrap">
<div className="excel-codeBox">
<CodeMirror
autoCursor
value={this.state.value}
onBeforeChange={(editor, data, value) => {
this.setState({ value });
}}
onChange={(editor, value) => {
console.log("controlled", { value });
}}
options={{
lineNumbers: false,
mode: { name: this.props.type === "sql" ? "text/x-sql" : "application/json" },
autofocus: false,
styleActiveLine: true,
lineWrapping: true,
foldGutter: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
lint: false,
indentUnit: 2,
cursorHeight: 0.85,
placeholder: ""
}}
/>
</div>
<div className="excel-codeBox-keyboard">
<div className="excel-codeBox-keyboard-operate">
<div className="excel-codeBox-keyboard-operate-content">
{
_.map(keyboardBaseBtns, item => {
const { key, label } = item;
return <Button
key={key} title={label} size="small"
className={cs(key === "space" ? "excel-codeBox-keyboard-space" : "excel-codeBox-keyboard-base")}
>{label}</Button>;
})
}
</div>
<div className="excel-codeBox-keyboard-operate-clear">
<Button title="←" size="small" className="excel-codeBox-keyboard-del"></Button>
<Button title="C" size="small" className="excel-codeBox-keyboard-clear">C</Button>
</div>
</div>
</div>
</div>
<div className="excel-codeAction">
<div className="excel-codeAction-item">
<div className="excel-codeAction-header">
<div className="excel-codeAction-header-title">变量</div>
</div>
<div className="excel-codeAction-content"></div>
</div>
<div className="excel-codeAction-item">
<div className="excel-codeAction-header">
<div className="excel-codeAction-header-title">函数</div>
</div>
<div className="excel-codeAction-content"></div>
</div>
<div className="excel-codeAction-item">
<div className="excel-codeAction-header">
<div className="excel-codeAction-header-title">提示</div>
</div>
<div className="excel-codeAction-content"></div>
</div>
</div>
</React.Fragment>
);
}
}
export default ExcelEditor;

View File

@ -0,0 +1,450 @@
.excel-codeWrap {
width: 100%;
display: flex;
justify-content: space-around;
padding: 0 0 8px;
.excel-codeBox {
flex: 1;
overflow: auto;
background: #fff;
box-sizing: content-box;
border: 1px solid #e5e5e5;
.esb-algorithm-sourceContent {
.CodeMirror {
}
}
}
.excel-codeBox-keyboard {
width: 272px;
min-height: 232px;
padding: 20px;
background: #fff;
border: 1px solid #e5e5e5;
border-left: none;
.excel-codeBox-keyboard-operate {
display: flex;
.excel-codeBox-keyboard-operate-content {
display: flex;
flex-wrap: wrap;
flex: 1;
.excel-codeBox-keyboard-base {
width: 30px;
height: 30px;
text-align: center;
margin: 0 10px 10px 0;
}
.excel-codeBox-keyboard-space {
width: 70px;
height: 30px;
}
}
.excel-codeBox-keyboard-operate-clear {
width: 30px;
.excel-codeBox-keyboard-del {
width: 30px;
height: 70px;
}
.excel-codeBox-keyboard-clear {
width: 30px;
height: 30px;
margin-top: 10px;
}
}
}
}
}
.excel-codeAction {
width: 100%;
display: flex;
justify-content: space-between;
.excel-codeAction-item:last-child {
margin-right: 0;
.excel-codeAction-header-title {
color: rgb(217, 82, 189);
}
}
.excel-codeAction-item {
width: 33%;
min-height: 317px;
flex: 1;
background: #fff;
border: 1px solid #e5e5e5;
margin-right: 16px;
.excel-codeAction-header {
display: flex;
padding: 10px 16px;
border-bottom: 1px solid #e5e5e5;
.excel-codeAction-header-title {
flex: 1;
font-weight: 600;
}
}
}
}
//
///* BASICS */
//
//.CodeMirror {
// /* Set height, width, borders, and global font properties here */
// font-family: monospace;
// height: 300px;
// color: black;
// direction: ltr;
//}
//
///* PADDING */
//
//.CodeMirror-lines {
// padding: 4px 0; /* Vertical padding around content */
//}
//.CodeMirror pre.CodeMirror-line,
//.CodeMirror pre.CodeMirror-line-like {
// padding: 0 4px; /* Horizontal padding of content */
//}
//
//.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
// background-color: white; /* The little square between H and V scrollbars */
//}
//
///* GUTTER */
//
//.CodeMirror-gutters {
// border-right: 1px solid #ddd;
// background-color: #f7f7f7;
// white-space: nowrap;
//}
//.CodeMirror-linenumbers {}
//.CodeMirror-linenumber {
// padding: 0 3px 0 5px;
// min-width: 20px;
// text-align: right;
// color: #999;
// white-space: nowrap;
//}
//
//.CodeMirror-guttermarker { color: black; }
//.CodeMirror-guttermarker-subtle { color: #999; }
//
///* CURSOR */
//
//.CodeMirror-cursor {
// border-left: 1px solid black;
// border-right: none;
// width: 0;
//}
///* Shown when moving in bi-directional text */
//.CodeMirror div.CodeMirror-secondarycursor {
// border-left: 1px solid silver;
//}
//.cm-fat-cursor .CodeMirror-cursor {
// width: auto;
// border: 0 !important;
// background: #7e7;
//}
//.cm-fat-cursor div.CodeMirror-cursors {
// z-index: 1;
//}
//.cm-fat-cursor-mark {
// background-color: rgba(20, 255, 20, 0.5);
// -webkit-animation: blink 1.06s steps(1) infinite;
// -moz-animation: blink 1.06s steps(1) infinite;
// animation: blink 1.06s steps(1) infinite;
//}
//.cm-animate-fat-cursor {
// width: auto;
// border: 0;
// -webkit-animation: blink 1.06s steps(1) infinite;
// -moz-animation: blink 1.06s steps(1) infinite;
// animation: blink 1.06s steps(1) infinite;
// background-color: #7e7;
//}
//@-moz-keyframes blink {
// 0% {}
// 50% { background-color: transparent; }
// 100% {}
//}
//@-webkit-keyframes blink {
// 0% {}
// 50% { background-color: transparent; }
// 100% {}
//}
//@keyframes blink {
// 0% {}
// 50% { background-color: transparent; }
// 100% {}
//}
//
///* Can style cursor different in overwrite (non-insert) mode */
//.CodeMirror-overwrite .CodeMirror-cursor {}
//
//.cm-tab { display: inline-block; text-decoration: inherit; }
//
//.CodeMirror-rulers {
// position: absolute;
// left: 0; right: 0; top: -50px; bottom: 0;
// overflow: hidden;
//}
//.CodeMirror-ruler {
// border-left: 1px solid #ccc;
// top: 0; bottom: 0;
// position: absolute;
//}
//
///* DEFAULT THEME */
//
//.cm-s-default .cm-header {color: blue;}
//.cm-s-default .cm-quote {color: #090;}
//.cm-negative {color: #d44;}
//.cm-positive {color: #292;}
//.cm-header, .cm-strong {font-weight: bold;}
//.cm-em {font-style: italic;}
//.cm-link {text-decoration: underline;}
//.cm-strikethrough {text-decoration: line-through;}
//
//.cm-s-default .cm-keyword {color: #708;}
//.cm-s-default .cm-atom {color: #219;}
//.cm-s-default .cm-number {color: #164;}
//.cm-s-default .cm-def {color: #00f;}
//.cm-s-default .cm-variable,
//.cm-s-default .cm-punctuation,
//.cm-s-default .cm-property,
//.cm-s-default .cm-operator {}
//.cm-s-default .cm-variable-2 {color: #05a;}
//.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
//.cm-s-default .cm-comment {color: #a50;}
//.cm-s-default .cm-string {color: #a11;}
//.cm-s-default .cm-string-2 {color: #f50;}
//.cm-s-default .cm-meta {color: #555;}
//.cm-s-default .cm-qualifier {color: #555;}
//.cm-s-default .cm-builtin {color: #30a;}
//.cm-s-default .cm-bracket {color: #997;}
//.cm-s-default .cm-tag {color: #170;}
//.cm-s-default .cm-attribute {color: #00c;}
//.cm-s-default .cm-hr {color: #999;}
//.cm-s-default .cm-link {color: #00c;}
//
//.cm-s-default .cm-error {color: #f00;}
//.cm-invalidchar {color: #f00;}
//
//.CodeMirror-composing { border-bottom: 2px solid; }
//
///* Default styles for common addons */
//
//div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
//div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
//.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
//.CodeMirror-activeline-background {background: #e8f2ff;}
//
///* STOP */
//
///* The rest of this file contains styles related to the mechanics of
// the editor. You probably shouldn't touch them. */
//
//.CodeMirror {
// position: relative;
// overflow: hidden;
// background: white;
//}
//
//.CodeMirror-scroll {
// overflow: scroll !important; /* Things will break if this is overridden */
// /* 50px is the magic margin used to hide the element's real scrollbars */
// /* See overflow: hidden in .CodeMirror */
// margin-bottom: -50px; margin-right: -50px;
// padding-bottom: 50px;
// height: 100%;
// outline: none; /* Prevent dragging from highlighting the element */
// position: relative;
//}
//.CodeMirror-sizer {
// position: relative;
// border-right: 50px solid transparent;
//}
//
///* The fake, visible scrollbars. Used to force redraw during scrolling
// before actual scrolling happens, thus preventing shaking and
// flickering artifacts. */
//.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
// position: absolute;
// z-index: 6;
// display: none;
// outline: none;
//}
//.CodeMirror-vscrollbar {
// right: 0; top: 0;
// overflow-x: hidden;
// overflow-y: scroll;
//}
//.CodeMirror-hscrollbar {
// bottom: 0; left: 0;
// overflow-y: hidden;
// overflow-x: scroll;
//}
//.CodeMirror-scrollbar-filler {
// right: 0; bottom: 0;
//}
//.CodeMirror-gutter-filler {
// left: 0; bottom: 0;
//}
//
//.CodeMirror-gutters {
// position: absolute; left: 0; top: 0;
// min-height: 100%;
// z-index: 3;
//}
//.CodeMirror-gutter {
// white-space: normal;
// height: 100%;
// display: inline-block;
// vertical-align: top;
// margin-bottom: -50px;
//}
//.CodeMirror-gutter-wrapper {
// position: absolute;
// z-index: 4;
// background: none !important;
// border: none !important;
//}
//.CodeMirror-gutter-background {
// position: absolute;
// top: 0; bottom: 0;
// z-index: 4;
//}
//.CodeMirror-gutter-elt {
// position: absolute;
// cursor: default;
// z-index: 4;
//}
//.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
//.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
//
//.CodeMirror-lines {
// cursor: text;
// min-height: 1px; /* prevents collapsing before first draw */
//}
//.CodeMirror pre.CodeMirror-line,
//.CodeMirror pre.CodeMirror-line-like {
// /* Reset some styles that the rest of the page might have set */
// -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
// border-width: 0;
// background: transparent;
// font-family: inherit;
// font-size: inherit;
// margin: 0;
// white-space: pre;
// word-wrap: normal;
// line-height: inherit;
// color: inherit;
// z-index: 2;
// position: relative;
// overflow: visible;
// -webkit-tap-highlight-color: transparent;
// -webkit-font-variant-ligatures: contextual;
// font-variant-ligatures: contextual;
//}
//.CodeMirror-wrap pre.CodeMirror-line,
//.CodeMirror-wrap pre.CodeMirror-line-like {
// word-wrap: break-word;
// white-space: pre-wrap;
// word-break: normal;
//}
//
//.CodeMirror-linebackground {
// position: absolute;
// left: 0; right: 0; top: 0; bottom: 0;
// z-index: 0;
//}
//
//.CodeMirror-linewidget {
// position: relative;
// z-index: 2;
// padding: 0.1px; /* Force widget margins to stay inside of the container */
//}
//
//.CodeMirror-widget {}
//
//.CodeMirror-rtl pre { direction: rtl; }
//
//.CodeMirror-code {
// outline: none;
//}
//
///* Force content-box sizing for the elements where we expect it */
//.CodeMirror-scroll,
//.CodeMirror-sizer,
//.CodeMirror-gutter,
//.CodeMirror-gutters,
//.CodeMirror-linenumber {
// -moz-box-sizing: content-box;
// box-sizing: content-box;
//}
//
//.CodeMirror-measure {
// position: absolute;
// width: 100%;
// height: 0;
// overflow: hidden;
// visibility: hidden;
//}
//
//.CodeMirror-cursor {
// position: absolute;
// pointer-events: none;
//}
//.CodeMirror-measure pre { position: static; }
//
//div.CodeMirror-cursors {
// visibility: hidden;
// position: relative;
// z-index: 3;
//}
//div.CodeMirror-dragcursors {
// visibility: visible;
//}
//
//.CodeMirror-focused div.CodeMirror-cursors {
// visibility: visible;
//}
//
//.CodeMirror-selected { background: #d9d9d9; }
//.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
//.CodeMirror-crosshair { cursor: crosshair; }
//.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
//.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
//
//.cm-searching {
// background-color: #ffa;
// background-color: rgba(255, 255, 0, .4);
//}
//
///* Used to force a border model for a node */
//.cm-force-border { padding-right: .1px; }
//
//@media print {
// /* Hide the cursor when printing */
// .CodeMirror div.CodeMirror-cursors {
// visibility: hidden;
// }
//}
//
///* See issue #2901 */
//.cm-tab-wrap-hack:after { content: ''; }
//
///* Help users use markselection to safely style text background */
//span.CodeMirror-selectedtext { background: none; }

View File

@ -32,6 +32,7 @@ import SysConfig from "./pages/sysConfig";
import RuleConfig from "./pages/ruleConfig";
import Appconfig from "./pages/appConfig";
import FieldManagement from "./pages/fieldManagement";
import EquationEditor from "./pages/equationEditor";
import stores from "./stores";
import "./style/index";
@ -150,6 +151,7 @@ const Routes = (
<Route key="sysconfig-1" path="sysconfig-1" component={RuleConfig}/>
<Route key="appconfig" path="appconfig" component={Appconfig}/>
<Route key="fieldManagement" path="fieldManagement" component={FieldManagement}/>
<Route key="equationEditor" path="equationEditor" component={EquationEditor}/>
</Route>
);

View File

@ -0,0 +1,12 @@
import React, { Component } from "react";
import ExcelEditor from "../../components/excelEditor";
class Index extends Component {
render() {
return (
<ExcelEditor/>
);
}
}
export default Index;