qianlishi 2 жил өмнө
parent
commit
8348691e28

+ 132 - 0
report-ui/src/components/MonacoEditor/index.vue

@@ -0,0 +1,132 @@
+<template>
+  <div ref="editor" class="main"></div>
+</template>
+
+<script>
+import * as monaco from "monaco-editor";
+import createSqlCompleter from "./util/sql-completion";
+import createJavascriptCompleter from "./util/javascript-completion";
+import registerLanguage from "./util/log-language";
+const global = {};
+
+const getHints = model => {
+  let id = model.id.substring(6);
+  return (global[id] && global[id].hints) || [];
+};
+monaco.languages.registerCompletionItemProvider(
+  "sql",
+  createSqlCompleter(getHints)
+);
+monaco.languages.registerCompletionItemProvider(
+  "javascript",
+  createJavascriptCompleter(getHints)
+);
+registerLanguage(monaco);
+/**
+ * monaco options
+ * https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.istandaloneeditorconstructionoptions.html
+ */
+export default {
+  props: {
+    options: {
+      type: Object,
+      default() {
+        return {};
+      }
+    },
+    value: {
+      type: String,
+      required: false
+    },
+    language: {
+      type: String
+    },
+    hints: {
+      type: Array,
+      default() {
+        return [];
+      }
+    }
+  },
+  name: "MonacoEditor",
+  data() {
+    return {
+      editorInstance: null,
+      defaultOptions: {
+        theme: "vs-dark",
+        fontSize: 14
+      }
+    };
+  },
+  watch: {
+    value() {
+      if (this.value !== this.editorInstance.getValue()) {
+        this.editorInstance.setValue(this.value);
+      }
+    }
+  },
+  mounted() {
+    this.initEditor();
+    global[this.editorInstance._id] = this;
+    window.addEventListener("resize", this.layout);
+  },
+  destroyed() {
+    this.editorInstance.dispose();
+    global[this.editorInstance._id] = null;
+    window.removeEventListener("resize", this.layout);
+  },
+  methods: {
+    layout() {
+      this.editorInstance.layout();
+    },
+    undo() {
+      this.editorInstance.trigger("anyString", "undo");
+      this.onValueChange();
+    },
+    redo() {
+      this.editorInstance.trigger("anyString", "redo");
+      this.onValueChange();
+    },
+    getOptions() {
+      let props = { value: this.value };
+      this.language !== undefined && (props.language = this.language);
+      let options = Object.assign({}, this.defaultOptions, this.options, props);
+      return options;
+    },
+    onValueChange() {
+      this.$emit("input", this.editorInstance.getValue());
+      this.$emit("change", this.editorInstance.getValue());
+    },
+    initEditor() {
+      this.MonacoEnvironment = {
+        getWorkerUrl: function() {
+          return "./editor.worker.bundle.js";
+        }
+      };
+
+      this.editorInstance = monaco.editor.create(
+        this.$refs.editor,
+        this.getOptions()
+      );
+      this.editorInstance.onContextMenu(e => {
+        this.$emit("contextmenu", e);
+      });
+      this.editorInstance.onDidChangeModelContent(() => {
+        this.onValueChange();
+      });
+      this.editorInstance.addCommand(
+        monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S,
+        () => {
+          this.$emit("save", this.editorInstance.getValue());
+        }
+      );
+    }
+  }
+};
+</script>
+
+<style scoped>
+.main /deep/ .view-lines * {
+  font-family: Consolas, "Courier New", monospace !important;
+}
+</style>

+ 38 - 0
report-ui/src/components/MonacoEditor/util/javascript-completion.js

@@ -0,0 +1,38 @@
+import * as monaco from 'monaco-editor'
+// js 有内置提示
+function createCompleter(getExtraHints) {
+    const createSuggestions = function (model, textUntilPosition) {
+        let text = model.getValue();
+        textUntilPosition = textUntilPosition.replace(/[\*\[\]@\$\(\)]/g, "").replace(/(\s+|\.)/g, " ");
+        let arr = textUntilPosition.split(/[\s;]/);
+        let activeStr = arr[arr.length - 1];
+        let len = activeStr.length;
+        let rexp = new RegExp("([^\\w]|^)" + activeStr + "\\w*", "gim");
+        let match = text.match(rexp);
+        let mergeHints = Array.from(new Set([...getExtraHints(model)]))
+            .sort()
+            .filter(ele => {
+                let rexp = new RegExp(ele.substr(0, len), "gim");
+                return (match && match.length === 1 && ele === activeStr) ||
+                    ele.length === 1 ? false : activeStr.match(rexp);
+            });
+        return mergeHints.map(ele => ({
+            label: ele,
+            kind: monaco.languages.CompletionItemKind.Text,
+            documentation: ele,
+            insertText: ele
+        }));
+    };
+    return {
+        provideCompletionItems(model, position) {
+            let textUntilPosition = model.getValueInRange({
+                startLineNumber: position.lineNumber,
+                startColumn: 1,
+                endLineNumber: position.lineNumber,
+                endColumn: position.column
+            });
+            return { suggestions: createSuggestions(model, textUntilPosition) };
+        }
+    }
+}
+export default createCompleter;

+ 58 - 0
report-ui/src/components/MonacoEditor/util/log-language.js

@@ -0,0 +1,58 @@
+function registerLanguage(monaco) {
+    monaco.languages.register({
+      id: "log"
+    });
+    monaco.languages.setMonarchTokensProvider("log", {
+      tokenizer: {
+        root: [
+          [/(^[=a-zA-Z].*|\d\s.*)/, "log-normal"],
+          [/\sERROR\s.*/, "log-error"],
+          [/\sWARN\s.*/, "log-warn"],
+          [/\sINFO\s.*/, "log-info"],
+          [
+            /^([0-9]{4}||[0-9]{2})-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{3})?/,
+            "log-date",
+          ],
+          [
+            /^[0-9]{2}\/[0-9]{2}\/[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{3})?/,
+            "log-date",
+          ],
+          [/(^\*\*Waiting queue:.*)/, "log-info"],
+          [/(^\*\*result tips:.*)/, "log-info"],
+        ],
+      },
+    });
+    monaco.editor.defineTheme("log", {
+      base: "vs",
+      inherit: true,
+      rules: [{
+          token: "log-info",
+          foreground: "4b71ca"
+        },
+        {
+          token: "log-error",
+          foreground: "ff0000",
+          fontStyle: "bold"
+        },
+        {
+          token: "log-warn",
+          foreground: "FFA500"
+        },
+        {
+          token: "log-date",
+          foreground: "008800"
+        },
+        {
+          token: "log-normal",
+          foreground: "808080"
+        },
+      ],
+      colors: {
+        "editor.lineHighlightBackground": "#ffffff",
+        "editorGutter.background": "#f7f7f7",
+      },
+    });
+  
+  }
+  
+  export default registerLanguage;

+ 82 - 0
report-ui/src/components/MonacoEditor/util/sql-completion.js

@@ -0,0 +1,82 @@
+import * as monaco from 'monaco-editor'
+const hints = [
+    "SELECT",
+    "INSERT",
+    "DELETE",
+    "UPDATE",
+    "CREATE TABLE",
+    "DROP TABLE",
+    "ALTER TABLE",
+    "CREATE VIEW",
+    "DROP VIEW",
+    "CREATE INDEX",
+    "DROP INDEX",
+    "CREATE PROCEDURE",
+    "DROP PROCEDURE",
+    "CREATE TRIGGER",
+    "DROP TRIGGER",
+    "CREATE SCHEMA",
+    "DROP SCHEMA",
+    "CREATE DOMAIN",
+    "ALTER DOMAIN",
+    "DROP DOMAIN",
+    "GRANT",
+    "DENY",
+    "REVOKE",
+    "COMMIT",
+    "ROLLBACK",
+    "SET TRANSACTION",
+    "DECLARE",
+    "EXPLAN",
+    "OPEN",
+    "FETCH",
+    "CLOSE",
+    "PREPARE",
+    "EXECUTE",
+    "DESCRIBE",
+    "FROM",
+    "ORDER BY"]
+function createCompleter(getExtraHints) {
+    const createSuggestions = function (model, textUntilPosition) {
+        let text = model.getValue();
+        textUntilPosition = textUntilPosition.replace(/[\*\[\]@\$\(\)]/g, "").replace(/(\s+|\.)/g, " ");
+        let arr = textUntilPosition.split(/[\s;]/);
+        let activeStr = arr[arr.length - 1];
+        let len = activeStr.length;
+        let rexp = new RegExp("([^\\w]|^)" + activeStr + "\\w*", "gim");
+        let match = text.match(rexp);
+        let textHints = !match ? [] :
+            match.map(ele => {
+                let rexp = new RegExp(activeStr, "gim");
+                let search = ele.search(rexp);
+                return ele.substr(search);
+            });
+        let mergeHints = Array.from(new Set([...hints, ...textHints, ...getExtraHints(model)]))
+            .sort()
+            .filter(ele => {
+                let rexp = new RegExp(ele.substr(0, len), "gim");
+                return (match && match.length === 1 && ele === activeStr) ||
+                    ele.length === 1 ? false : activeStr.match(rexp);
+            });
+        return mergeHints.map(ele => ({
+            label: ele,
+            kind: hints.indexOf(ele) > -1 ?
+                monaco.languages.CompletionItemKind.Keyword :
+                monaco.languages.CompletionItemKind.Text,
+            documentation: ele,
+            insertText: ele
+        }));
+    };
+    return {
+        provideCompletionItems(model, position) {
+            let textUntilPosition = model.getValueInRange({
+                startLineNumber: position.lineNumber,
+                startColumn: 1,
+                endLineNumber: position.lineNumber,
+                endColumn: position.column
+            });
+            return { suggestions: createSuggestions(model, textUntilPosition) };
+        }
+    }
+}
+export default createCompleter;

+ 56 - 25
report-ui/src/views/bigscreenDesigner/designer/components/dynamicForm.vue

@@ -12,8 +12,8 @@
           <el-form-item
             v-if="
               inputShow[item.name] &&
-                item.type != 'dycustComponents' &&
-                item.type != 'dynamic-add-table'
+              item.type != 'dycustComponents' &&
+              item.type != 'dynamic-add-table'
             "
             :label="item.label"
             :prop="item.name"
@@ -22,7 +22,7 @@
             <el-input-number
               v-if="item.type == 'el-input-number'"
               size="mini"
-              style="width:100%"
+              style="width: 100%"
               v-model.trim="formData[item.name]"
               controls-position="right"
               @change="changed($event, item.name)"
@@ -58,7 +58,7 @@
             <ColorPicker
               v-if="item.type == 'vue-color'"
               v-model="formData[item.name]"
-              @change="val => changed(val, item.name)"
+              @change="(val) => changed(val, item.name)"
             />
             <customUpload
               v-if="item.type == 'custom-upload'"
@@ -69,7 +69,7 @@
             <el-radio-group
               v-if="item.type == 'el-radio-group'"
               v-model="formData[item.name]"
-              @change="val => changed(val, item.name)"
+              @change="(val) => changed(val, item.name)"
             >
               <el-radio
                 v-for="itemChild in item.selectOptions"
@@ -85,7 +85,7 @@
               v-model="formData[item.name]"
               clearable
               placeholder="请选择"
-              @change="val => changed(val, item.name)"
+              @change="(val) => changed(val, item.name)"
             >
               <el-option
                 v-for="itemChild in item.selectOptions"
@@ -98,7 +98,7 @@
             <el-slider
               v-if="item.type == 'el-slider'"
               v-model="formData[item.name]"
-              @change="val => changed(val, item.name)"
+              @change="(val) => changed(val, item.name)"
             />
 
             <el-button
@@ -110,6 +110,14 @@
               >编辑</el-button
             >
 
+            <el-button
+              v-if="item.type == 'methods'"
+              type="primary"
+              size="mini"
+              @click="methodsVisible = true"
+              >添加事件</el-button
+            >
+
             <!-- 弹窗 -->
             <el-dialog
               title="代码编辑"
@@ -131,6 +139,23 @@
                 <el-button type="primary" @click="saveData">确 定</el-button>
               </span>
             </el-dialog>
+
+            <el-dialog
+              title="代码编辑"
+              :visible.sync="methodsVisible"
+              width="50%"
+              :before-close="handleClose"
+            >
+              <monaco-editor
+                v-model.trim="formData[item.name]"
+                language="javascript"
+                style="height: 500px"
+              />
+              <span slot="footer" class="dialog-footer">
+                <el-button @click="methodsVisible = false">取 消</el-button>
+                <el-button type="primary" @click="saveData">确 定</el-button>
+              </span>
+            </el-dialog>
           </el-form-item>
           <dynamicComponents
             v-if="item.type == 'dycustComponents' && inputShow[item.name]"
@@ -149,7 +174,8 @@
             v-if="item.type == 'dynamic-add-radar' && inputShow[item.name]"
             v-model="formData[item.name]"
             :chart-type="item.chartType"
-            @change="changed($event, item.name)"/>
+            @change="changed($event, item.name)"
+          />
         </div>
         <div v-else-if="isShowForm(item, '[object Array]')" :key="'a-' + index">
           <el-collapse accordion>
@@ -169,7 +195,7 @@
                   <el-input-number
                     v-if="itemChildList.type == 'el-input-number'"
                     size="mini"
-                    style="width:100%"
+                    style="width: 100%"
                     v-model="formData[itemChildList.name]"
                     controls-position="right"
                     :placeholder="itemChildList.placeholder"
@@ -207,7 +233,7 @@
                   <ColorPicker
                     v-if="itemChildList.type == 'vue-color'"
                     v-model="formData[itemChildList.name]"
-                    @change="val => changed(val, itemChildList.name)"
+                    @change="(val) => changed(val, itemChildList.name)"
                   />
 
                   <el-upload
@@ -220,7 +246,7 @@
                   <el-radio-group
                     v-if="itemChildList.type == 'el-radio-group'"
                     v-model="formData[itemChildList.name]"
-                    @change="val => changed(val, itemChildList.name)"
+                    @change="(val) => changed(val, itemChildList.name)"
                   >
                     <el-radio
                       v-for="it in itemChildList.selectOptions"
@@ -236,7 +262,7 @@
                     v-model="formData[itemChildList.name]"
                     clearable
                     placeholder="请选择"
-                    @change="val => changed(val, itemChildList.name)"
+                    @change="(val) => changed(val, itemChildList.name)"
                   >
                     <el-option
                       v-for="it in itemChildList.selectOptions"
@@ -249,7 +275,7 @@
                   <el-slider
                     v-if="itemChildList.type == 'el-slider'"
                     v-model="formData[itemChildList.name]"
-                    @change="val => changed(val, itemChildList.name)"
+                    @change="(val) => changed(val, itemChildList.name)"
                   />
                 </el-form-item>
                 <customColorComponents
@@ -282,6 +308,7 @@ import customColorComponents from "./customColorComponents";
 import dynamicAddTable from "./dynamicAddTable.vue";
 import customUpload from "./customUpload.vue";
 import dynamicAddRadar from "./dynamicAddRadar";
+import MonacoEditor from "@/components/MonacoEditor/index";
 export default {
   name: "DynamicForm",
   components: {
@@ -291,24 +318,26 @@ export default {
     customColorComponents,
     dynamicAddTable,
     customUpload,
-    dynamicAddRadar
+    dynamicAddRadar,
+    MonacoEditor,
   },
   model: {
     prop: "value",
-    event: "input"
+    event: "input",
   },
   props: {
     options: Array,
     value: {
       type: [Object],
-      default: () => {}
-    }
+      default: () => {},
+    },
   },
   data() {
     return {
       formData: {},
       inputShow: {}, // 控制表单是否显示
       dialogVisibleStaticData: false,
+      methodsVisible: false,
       validationRules: "",
       optionsJavascript: {
         mode: "text/javascript",
@@ -318,9 +347,9 @@ export default {
         styleActiveLine: true, // 高亮选中行
 
         hintOptions: {
-          completeSingle: true // 当匹配只有一项的时候是否自动补全
-        }
-      }
+          completeSingle: true, // 当匹配只有一项的时候是否自动补全
+        },
+      },
     };
   },
   watch: {
@@ -330,7 +359,7 @@ export default {
     options(val) {
       this.setDefaultValue();
       this.isShowData();
-    }
+    },
   },
   created() {
     this.isShowData();
@@ -365,6 +394,7 @@ export default {
     saveData() {
       this.$emit("onChanged", this.formData);
       this.dialogVisibleStaticData = false;
+      this.methodsVisible = false;
     },
     // 静态数据
     addStaticData() {
@@ -372,6 +402,7 @@ export default {
     },
     handleClose() {
       this.dialogVisibleStaticData = false;
+      this.methodsVisible = false;
     },
     // 组件属性 数据是否展示动态还是静态数据
     isShowData() {
@@ -386,7 +417,7 @@ export default {
           data.push(this.options[i]);
         }
       }
-      data.forEach(el => {
+      data.forEach((el) => {
         if (el.relactiveDomValue != currentData.value) {
           this.inputShow[el.name] = false;
         }
@@ -404,7 +435,7 @@ export default {
           } else if (Object.prototype.toString.call(obj) == "[object Array]") {
             for (let j = 0; j < obj.length; j++) {
               const list = obj[j].list;
-              list.forEach(el => {
+              list.forEach((el) => {
                 this.formData[el.name] = el.value;
               });
             }
@@ -416,8 +447,8 @@ export default {
     // 是否显示 那种格式
     isShowForm(val, type) {
       return Object.prototype.toString.call(val) == type;
-    }
-  }
+    },
+  },
 };
 </script>
 

+ 12 - 0
report-ui/src/views/bigscreenDesigner/designer/index.vue

@@ -270,6 +270,17 @@
             @onChanged="(val) => widgetValueChanged('position', val)"
           />
         </el-tab-pane>
+        <el-tab-pane
+          v-if="isNotNull(widgetOptions.methods)"
+          name="four"
+          label="方法"
+        >
+          <dynamicForm
+            ref="formData"
+            :options="widgetOptions.methods"
+            @onChanged="(val) => widgetValueChanged('methods', val)"
+          />
+        </el-tab-pane>
       </el-tabs>
     </div>
 
@@ -360,6 +371,7 @@ export default {
               top: 0,
               zIndex: 0,
             },
+            methods: {},
           },
           // options属性是从工具栏中拿到的tools中拿到
           options: [],

+ 44 - 29
report-ui/src/views/bigscreenDesigner/designer/tools/configure/barCharts/widget-barchart.js

@@ -3,8 +3,8 @@
  * @version:
  * @Author: qianlishi
  * @Date: 2021-08-29 07:21:45
- * @LastEditors: qianlishi
- * @LastEditTime: 2021-09-28 14:08:29
+ * @LastEditors: qianlishi qianlishi@anji-plus.com
+ * @LastEditTime: 2023-01-09 09:53:31
  */
 export const widgetBarchart = {
   code: 'widget-barchart',
@@ -111,10 +111,10 @@ export const widgetBarchart = {
               required: false,
               placeholder: '',
               selectOptions: [
-                {code: 'normal', name: '正常'},
-                {code: 'bold', name: '粗体'},
-                {code: 'bolder', name: '特粗体'},
-                {code: 'lighter', name: '细体'}
+                { code: 'normal', name: '正常' },
+                { code: 'bold', name: '粗体' },
+                { code: 'bolder', name: '特粗体' },
+                { code: 'lighter', name: '细体' }
               ],
               value: 'normal'
             },
@@ -125,9 +125,9 @@ export const widgetBarchart = {
               required: false,
               placeholder: '',
               selectOptions: [
-                {code: 'normal', name: '正常'},
-                {code: 'italic', name: 'italic斜体'},
-                {code: 'oblique', name: 'oblique斜体'},
+                { code: 'normal', name: '正常' },
+                { code: 'italic', name: 'italic斜体' },
+                { code: 'oblique', name: 'oblique斜体' },
               ],
               value: 'normal'
             },
@@ -138,9 +138,9 @@ export const widgetBarchart = {
               required: false,
               placeholder: '',
               selectOptions: [
-                {code: 'center', name: '居中'},
-                {code: 'left', name: '左对齐'},
-                {code: 'right', name: '右对齐'},
+                { code: 'center', name: '居中' },
+                { code: 'left', name: '左对齐' },
+                { code: 'right', name: '右对齐' },
               ],
               value: 'center'
             },
@@ -175,10 +175,10 @@ export const widgetBarchart = {
               required: false,
               placeholder: '',
               selectOptions: [
-                {code: 'normal', name: '正常'},
-                {code: 'bold', name: '粗体'},
-                {code: 'bolder', name: '特粗体'},
-                {code: 'lighter', name: '细体'}
+                { code: 'normal', name: '正常' },
+                { code: 'bold', name: '粗体' },
+                { code: 'bolder', name: '特粗体' },
+                { code: 'lighter', name: '细体' }
               ],
               value: 'normal'
             },
@@ -189,9 +189,9 @@ export const widgetBarchart = {
               required: false,
               placeholder: '',
               selectOptions: [
-                {code: 'normal', name: '正常'},
-                {code: 'italic', name: 'italic斜体'},
-                {code: 'oblique', name: 'oblique斜体'},
+                { code: 'normal', name: '正常' },
+                { code: 'italic', name: 'italic斜体' },
+                { code: 'oblique', name: 'oblique斜体' },
               ],
               value: 'normal'
             },
@@ -481,10 +481,10 @@ export const widgetBarchart = {
               required: false,
               placeholder: '',
               selectOptions: [
-                {code: 'normal', name: '正常'},
-                {code: 'bold', name: '粗体'},
-                {code: 'bolder', name: '特粗体'},
-                {code: 'lighter', name: '细体'}
+                { code: 'normal', name: '正常' },
+                { code: 'bold', name: '粗体' },
+                { code: 'bolder', name: '特粗体' },
+                { code: 'lighter', name: '细体' }
               ],
               value: 'normal'
             },
@@ -553,7 +553,7 @@ export const widgetBarchart = {
               label: '',
               name: 'customColor',
               required: false,
-              value: [{color: '#ff7f50'}, {color: '#87cefa'}, {color: '#da70d6'}, {color: '#32cd32'}, {color: '#6495ed'}],
+              value: [{ color: '#ff7f50' }, { color: '#87cefa' }, { color: '#da70d6' }, { color: '#32cd32' }, { color: '#6495ed' }],
             },
           ],
         },
@@ -597,11 +597,11 @@ export const widgetBarchart = {
         relactiveDom: 'dataType',
         relactiveDomValue: 'staticData',
         value: [
-          {"axis": "苹果", "data": 1000},
-          {"axis": "三星", "data": 2229},
-          {"axis": "小米", "data": 3879},
-          {"axis": "oppo", "data": 2379},
-          {"axis": "vivo", "data": 4079},
+          { "axis": "苹果", "data": 1000 },
+          { "axis": "三星", "data": 2229 },
+          { "axis": "小米", "data": 3879 },
+          { "axis": "oppo", "data": 2379 },
+          { "axis": "vivo", "data": 4079 },
         ],
       },
       {
@@ -652,5 +652,20 @@ export const widgetBarchart = {
         value: 200,
       },
     ],
+    // 事件
+    methods: [
+      {
+        type: 'methods',
+        label: '前置钩子',
+        name: 'beforeMethods',
+        value: 'function beforeMethods(data){\n\t//自定义脚本内容1\n\treturn data;\n}',
+      },
+      {
+        type: 'methods',
+        label: '后置钩子',
+        name: 'afterMethods',
+        value: 'function afterMethods(data){\n\t//自定义脚本内容2\n\treturn data;\n}',
+      },
+    ]
   }
 }