首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PiranhaCMS中的DevExpress网络仪表板

PiranhaCMS中的DevExpress网络仪表板
EN

Stack Overflow用户
提问于 2021-07-23 20:59:29
回答 1查看 53关注 0票数 2

我目前正在开发一个基于名为PiranhaCMS的.NET框架的CMS核心应用程序。这个框架允许定义可配置的“块”,基本上是小部件,可以由用户在其页面上添加。这些块的配置页面被实现为一个Vue.js组件,然后通过gulp以标准JS格式编译代码(从.vue文件到Vue.component(...)语法)以供Piranha框架读取和呈现。Piranha的作者证实,这是定义新块的唯一方法。

在我们的一个自定义块中,我们尝试实现一个DevExpress Web Dashboard。我尝试了遵循https://docs.devexpress.com/Dashboard/401150/web-dashboard/dashboard-component-for-vue中概述的步骤,但是没有用,因为编译器抛出了一个异常,声明顶级声明应该是导出默认{ ... },而不是导入语句。

我想出了一个变通方法,我在组件的created()方法上动态加载所需的脚本和样式,然后以与经典javascript用例相同的方式定义仪表板(https://docs.devexpress.com/Dashboard/119158/web-dashboard/dashboard-control-for-javascript-applications-jquery-knockout-etc/add-web-dashboard-to-a-javascript-application);;)然而,我相信有一个更优雅的解决方案来解决这个问题。

下面是与问题相关的代码。下面是自定义块itools-dashboard.vue:

代码语言:javascript
复制
<template>
    <div class="form-group block-body">
        <div :id="'dashboard-designer-' + uid" class="dashboard-designer">
            <div :id="'dashboard_' + uid" style="height: 100%;">
            </div>
        </div>
        <div class="row">
            <div class="col-sm-6" style="padding:10px; margin-top: 0px;vertical-align: top;">
                <fieldset>
                    <legend>Dashboard</legend>
                    <div class="form-group">
                        <label>Dashboard name</label>
                        <select class="form-control small" :id="'dashboard-names-' + uid" v-model="model.dashboardName.value">
                            <option v-for="dash in dashboardNames">{{ dash }}</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label>Update time</label>
                        <input class="form-control small" type="number" v-model="model.updateTime.value">
                    </div>
                    <div class="form-group">
                        <label>Width</label>
                        <input class="form-control small" type="text" v-model="model.width.value">
                    </div>
                    <div class="form-group">
                        <label>Height</label>
                        <input class="form-control small" type="text" v-model="model.height.value">
                    </div>
                </fieldset>
            </div>
            <div class="col-sm-6" style="padding:10px; margin-top: 0px; background-color: #fcfcfc; border:1px dotted lightgray; vertical-align: top;">
                <itools-base :model="model"></itools-base>
            </div>
        </div>
    </div>
</template>
<script>
    export default {
        props: ["uid", "toolbar", "model"],
        data: function () {
            return {
                dashboardNames: [],
                dahsboardConfig: null,
                updateModes: ["period", "realtime"],
                basePath: "../../../../assets/",
                // define all the css and js files paths
                cssResources: [
                    "devextreme/dist/css/light.css",
                    "@devexpress/analytics-core/dist/css/dx-analytics.common.css",
                    "@devexpress/analytics-core/dist/css/dx-analytics.light.css",
                    "@devexpress/analytics-core/dist/css/dx-querybuilder.css",
                    "devexpress-dashboard/dist/css/dx-dashboard.light.min.css"
                ],
                jsResources: [
                    "js/jquery/jquery-3.3.1.min.js",
                    "jquery-ui-dist/jquery-ui.js",
                    "knockout/build/output/knockout-latest.js",
                    "ace-builds/src-min-noconflict/ace.js",
                    "ace-builds/src-min-noconflict/ext-language_tools.js",
                    "ace-builds/src-min-noconflict/theme-dreamweaver.js",
                    "ace-builds/src-min-noconflict/theme-ambiance.js",
                    "devextreme/dist/js/dx.all.js",
                    "devextreme/dist/js/dx.aspnet.mvc.js",
                    "devextreme-aspnet-data/js/dx.aspnet.data.js",
                    "@devexpress/analytics-core/dist/js/dx-analytics-core.min.js",
                    "@devexpress/analytics-core/dist/js/dx-querybuilder.min.js",
                    "devexpress-dashboard/dist/js/dx-dashboard.min.js"
                ]
            }
        },
        created: function () {
            // dynamically add the required css
            this.cssResources.forEach(x => {
                let link = document.createElement("link");
                link.setAttribute("href", this.basePath + x);
                link.setAttribute("rel", "stylesheet");
                document.head.appendChild(link);
            });
            // dynamically add the js files. 
            // It needs to be a synchronous ajax call so that the exports are visible in the code
            // (eg the new DevExpress call)
            this.jsResources.forEach(x => {
                $.ajax({
                    async: false,
                    url: this.basePath + x,
                    dataType: "script"
                })
            });
            this.model.width.value = this.model.width.value || "100%";
            this.model.height.value = this.model.height.value || "300";
            this.model.updateTime.value = this.model.updateTime.value || 5000;

        },
        mounted: function () {
            var h = document.getElementById("dashboard-designer-" + this.uid).clientHeight;

            DevExpress.Dashboard.ResourceManager.embedBundledResources();
            var dashboardControl = new DevExpress.Dashboard.DashboardControl(document.getElementById("dashboard_" + this.uid), {
                endpoint: "/api/dashboard",
                workingMode: "Designer",
                width: "100%",
                height: "100%",
                initialDashboardId: this.model.dashboardName.value,
            });

            dashboardControl.render();
        },
        beforeCreate: function () {
            fetch("/api/Dashboards/GetDashboardNames")
                .then(response => response.json())
                .then(data => {
                    this.dashboardNames = data;
                });
        },
    }
</script>

然后通过gulp任务进行编译以

代码语言:javascript
复制
Vue.component("itools-dashboard", {
  props: ["uid", "toolbar", "model"],
  data: function () {
    return {
      dashboardNames: [],
      dahsboardConfig: null,
      updateModes: ["period", "realtime"],
      basePath: "../../../../assets/",
      cssResources: ["devextreme/dist/css/light.css", "@devexpress/analytics-core/dist/css/dx-analytics.common.css", "@devexpress/analytics-core/dist/css/dx-analytics.light.css", "@devexpress/analytics-core/dist/css/dx-querybuilder.css", "devexpress-dashboard/dist/css/dx-dashboard.light.min.css"],
      jsResources: ["js/jquery/jquery-3.3.1.min.js", "jquery-ui-dist/jquery-ui.js", "knockout/build/output/knockout-latest.js", "ace-builds/src-min-noconflict/ace.js", "ace-builds/src-min-noconflict/ext-language_tools.js", "ace-builds/src-min-noconflict/theme-dreamweaver.js", "ace-builds/src-min-noconflict/theme-ambiance.js", "devextreme/dist/js/dx.all.js", "devextreme/dist/js/dx.aspnet.mvc.js", "devextreme-aspnet-data/js/dx.aspnet.data.js", "@devexpress/analytics-core/dist/js/dx-analytics-core.min.js", "@devexpress/analytics-core/dist/js/dx-querybuilder.min.js", "devexpress-dashboard/dist/js/dx-dashboard.min.js"]
    };
  },
  created: function () {
    this.cssResources.forEach(x => {
      let link = document.createElement("link");
      link.setAttribute("href", this.basePath + x);
      link.setAttribute("rel", "stylesheet");
      document.head.appendChild(link);
    });
    this.jsResources.forEach(x => {
      $.ajax({
        async: false,
        url: this.basePath + x,
        dataType: "script"
      });
    });
    this.model.width.value = this.model.width.value || "100%";
    this.model.height.value = this.model.height.value || "300";
    this.model.updateTime.value = this.model.updateTime.value || 5000;
  },
  mounted: function () {
    DevExpress.Dashboard.ResourceManager.embedBundledResources();
    var dashboardControl = new DevExpress.Dashboard.DashboardControl(document.getElementById("dashboard_" + this.uid), {
      endpoint: "/api/dashboard",
      workingMode: "Designer",
      width: "100%",
      height: "100%",
      initialDashboardId: this.model.dashboardName.value
    });
    dashboardControl.render();
  },
  beforeCreate: function () {
    fetch("/api/Dashboards/GetDashboardNames").then(response => response.json()).then(data => {
      this.dashboardNames = data;
    });
  },
  template: "\n<div class=\"form-group block-body\">\n    <div :id=\"'dashboard-designer-' + uid\" class=\"dashboard-designer\">\n        <div :id=\"'dashboard_' + uid\" style=\"height: 100%;\">\n        </div>\n    </div>\n    <div class=\"row\">\n        <div class=\"col-sm-6\" style=\"padding:10px; margin-top: 0px;vertical-align: top;\">\n            <fieldset>\n                <legend>Dashboard</legend>\n                <div class=\"form-group\">\n                    <label>Dashboard name</label>\n                    <select class=\"form-control small\" :id=\"'dashboard-names-' + uid\" v-model=\"model.dashboardName.value\">\n                        <option v-for=\"dash in dashboardNames\">{{ dash }}</option>\n                    </select>\n                </div>\n                <div class=\"form-group\">\n                    <label>Update time</label>\n                    <input class=\"form-control small\" type=\"number\" v-model=\"model.updateTime.value\">\n                </div>\n                <div class=\"form-group\">\n                    <label>Width</label>\n                    <input class=\"form-control small\" type=\"text\" v-model=\"model.width.value\">\n                </div>\n                <div class=\"form-group\">\n                    <label>Height</label>\n                    <input class=\"form-control small\" type=\"text\" v-model=\"model.height.value\">\n                </div>\n            </fieldset>\n        </div>\n        <div class=\"col-sm-6\" style=\"padding:10px; margin-top: 0px; background-color: #fcfcfc; border:1px dotted lightgray; vertical-align: top;\">\n            <itools-base :model=\"model\"></itools-base>\n        </div>\n    </div>\n</div>\n"
});  

Piranha定义的负责编译的gulp任务是:

代码语言:javascript
复制
var gulp = require('gulp'),
    sass = require('gulp-sass'),
    cssmin = require("gulp-cssmin"),
    uglifyes = require('uglify-es'),
    composer = require('gulp-uglify/composer'),
    uglify = composer(uglifyes, console),
    rename = require("gulp-rename"),
    concat = require("gulp-concat");

var path = require('path'),
    vueCompiler = require('vue-template-compiler'),
    babel = require("@babel/core"),
    babelTemplate = require("@babel/template").default,
    codeFrameColumns = require('@babel/code-frame').codeFrameColumns,
    babelTypes = require("@babel/types"),
    through2 = require('through2');

function vueCompile() {
    return through2.obj(function (file, _, callback) {
        var relativeFile = path.relative(file.cwd, file.path);
        console.log(relativeFile);
        var ext = path.extname(file.path);
        if (ext === '.vue') {
            var getComponent;
            getComponent = function (ast, sourceCode) {
                const ta = ast.program.body[0]
                if (!babelTypes.isExportDefaultDeclaration(ta)) {
                    var msg = 'Top level declaration in file ' + relativeFile + ' must be "export default {" \n' + codeFrameColumns(sourceCode, { start: ta.loc.start }, { highlightCode: true });
                    throw msg;
                }
                return ta.declaration;
            }

            var compile;
            compile = function (componentName, content) {
                var component = vueCompiler.parseComponent(content, []);
                if (component.styles.length > 0) {
                    component.styles.forEach(s => {
                        const linesToStyle = content.substr(0, s.start).split(/\r?\n/).length;
                        var msg = 'WARNING: <style> tag in ' + relativeFile + ' is ignored\n' + codeFrameColumns(content, { start: { line: linesToStyle } }, { highlightCode: true });
                        console.warn(msg);
                    });
                }

                var ast = babel.parse(component.script.content, {
                    parserOpts: {
                        sourceFilename: file.path
                    }
                });

                var vueComponent = getComponent(ast, component.script.content);
                vueComponent.properties.push(babelTypes.objectProperty(babelTypes.identifier('template'), babelTypes.stringLiteral(component.template.content)))

                var wrapInComponent = babelTemplate("Vue.component(NAME, COMPONENT);");
                var componentAst = wrapInComponent({
                    NAME: babelTypes.stringLiteral(componentName),
                    COMPONENT: vueComponent
                })

                ast.program.body = [componentAst]

                babel.transformFromAst(ast, null, null, function (err, result) {
                    if (err) {
                        callback(err, null)
                    }
                    else {
                        file.contents = Buffer.from(result.code);
                        callback(null, file)
                    }
                });
            }
            var componentName = path.basename(file.path, ext);
            if (file.isBuffer()) {
                compile(componentName, file.contents.toString());
            }
            else if (file.isStream()) {
                var chunks = [];
                file.contents.on('data', function (chunk) {
                    chunks.push(chunk);
                });
                file.contents.on('end', function () {
                    compile(componentName, Buffer.concat(chunks).toString());
                });
            }
        } else {
            callback(null, file);
        }
    });
}

var js = {
    name: "itools-blocks.js",
    path: "wwwroot/assets/js/blocks/*.vue"
}

//
// Compile & minimize js files
//
gulp.task("min:js", function (done) {
    gulp.src(js.path, { base: "." })
        .pipe(vueCompile())
        .pipe(concat("wwwroot/assets/js/blocks/" + js.name))
        .pipe(gulp.dest("."))
        .pipe(uglify().on('error', function (e) {
            console.log(e);
        }))
        .pipe(rename({
            suffix: ".min"
        }))
        .pipe(gulp.dest("."));
    done();
});

任何形式的帮助都是非常感谢的。

EN

回答 1

Stack Overflow用户

发布于 2021-07-25 01:42:54

您提到的带有“vueCompile”方法的suit文件是专门为满足我们在框架中提供的内部组件的需要而编写的,它绝不是所有Vue组件编译的灵丹妙药。然而,我理解你的问题,在写这段代码之前,我们拼命寻找能给我们提供所需功能的现有npm包,但这并不容易找到,因为我们只使用了Vue.js中可用特性的一个子集

我们非常乐意得到关于如何做到这一点的反馈或更多信息,所以我们将关注这个线程??

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68499598

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档