vue中使用amis(做管理后台渲染器)

发布于:2024-06-30 ⋅ 阅读:(19) ⋅ 点赞:(0)

1.配置amis页面和web应用菜单的关联关系

最终生成的json如下

[
    {
        "path": "/develop",//顶部导航栏
        "title": "开发中心",
        "icon": "md-code-working",
        "hideSider": false,
        "name": "develop",
        "children": [
            {
                "path": "/develop/datamodel", //侧边栏-目录
                "icon": "ios-barcode",
                "title": "数据表模型",
                "header": "develop",
                "children": [
                    {
                        "path": "/develop/modelclass",//侧边栏-菜单
                        "icon": "ios-list-box-outline",
                        "title": "表模型分类",
                        "nodeKey": 36,
                        "meta": {
                            "auth": true,
                            "mclass": "base",
                            "template": "base.modelclass", //绑定的amis页面
                            "type": "pagetpl",
                            "iframe": "",
                            "component": "",
                            "closable": true
                        },
                        "selected": true,
                        "component": "default/default.tpl",
                        "name": "develop-modelclass",
                        "auth": [
                            "admin",
                            "superadmin"
                        ],
                        "nodeClass": "sider",
                        "target": "_self",
                        "hideSider": false,
                        "headerDropdown": false,
                        "menu": {
                            "enable": true,
                            "header": true
                        },
                        "divided": false,
                        "childAddDisabled": true
                    },
                    {
                        "path": "/develop/model",
                        "icon": "md-menu",
                        "title": "表模型管理",
                        "nodeKey": 37,
                        "meta": {
                            "auth": true,
                            "mclass": "base",
                            "template": "base.modelinfo",
                            "type": "pagetpl",
                            "iframe": "",
                            "component": "",
                            "closable": true
                        },
                        "component": "default/default.tpl",
                        "selected": false,
                        "name": "develop-modelinfo",
                        "auth": [
                            "admin",
                            "superadmin"
                        ],
                        "nodeClass": "sider",
                        "target": "_self",
                        "hideSider": false,
                        "headerDropdown": false,
                        "menu": {
                            "enable": true,
                            "header": true
                        },
                        "divided": false,
                        "childAddDisabled": true
                    }
                ],
                "nodeKey": 35,
                "meta": {
                    "auth": true,
                    "type": "folder",
                    "iframe": "",
                    "component": "",
                    "closable": true
                },
                "selected": false,
                "expand": true,
                "name": "develop-model",
                "nodeClass": "folder",
                "target": "_self",
                "hideSider": false,
                "headerDropdown": false,
                "menu": {
                    "enable": true
                },
                "divided": false
            },

        ],
        "nodeKey": 34,
        "expand": true,
        "meta": {
            "auth": true,
            "mclass": "",
            "template": "",
            "type": "pagetpl",
            "iframe": "",
            "component": "",
            "closable": true
        },
        "selected": false,
        "redirect": "develop-page.pagetemplate",
        "headerDropdown": false,
        "nodeClass": "header",
        "target": "_self",
        "menu": {
            "enable": true
        }
    }
]

2.根据关联关系生成动态路由

libs/util.js:

export const getRouterByAppMenu = (list, level) => {
    let routers = [];
    forEach(list, item => {
        let r = {};
        item.meta = item.meta || {};
        // let mPath = item.path.split("/");
        item.meta.auth = (item.auth && item.auth.length>0) ? true : false; //auth为[]时,不需要权限
        r = {
            // mpath: mPath[mPath.length - 1],
            path: item.path,
            name: item.name,
            meta: item.meta,
        }
        r.meta.title = item.title || '';
        r.meta.notCache = true;
        r.meta.actions = item.actions;
        r.meta.menu = item.menu;
        if (item.redirect) {
            r.redirect = { name: item.redirect };
        }
        if (item.children && item.children.length > 0) {
            r.component = vueCompontent[level];
            r.children = getRouterByAppMenu(item.children, level + 1);
        }
        else {
            r.component = resolve => require([`@/pages/${item.component || 'default/default.tpl'}.vue`], resolve);
            // r.meta.template = r.meta.template || 'none.initpage';
        }
        routers.push(r);
    })
    return routers;
}

router/index.js(动态路由)核心代码如下:

import Vue from 'vue';
import VueRouter from 'vue-router';
import util, { getRouterByAppMenu }  from '@/libs/util'
import Setting from '@/setting';
import store from '@/store/index';
import routes from './routes';// 路由数据
import { loadApplicationMenu } from "../services/appmenu";
Vue.use(VueRouter);

const router = new VueRouter({
    routes,
    mode: Setting.routerMode,
    base: Setting.routerBase
});

(async () => {
    /**
     * 路由拦截,权限验证
     */

    let app = await loadApplicationMenu(appname); //调用接口获取web应用信息
    let ROUTERS = getRouterByAppMenu(app.menu, 0); //封装配置的menu为routes
    for (let i in ROUTERS) {
        let mRouter = ROUTERS[i];
        routes.push(mRouter);
        router.addRoute(mRouter);
    }
    let Router404 = {
        path: '*',
        name: '404',
        meta: {
            title: '404'
        },
        component: () => import('@/pages/system/error/404')
    };
    routes.push(Router404);
    router.addRoute(Router404);

    router.beforeResolve((to, from, next) => {
        // 判断是否需要登录才可以进入
        if (to.matched.some(_ => _.meta.auth)) {
            // 这里依据 token 判断是否登录,可视情况修改
            if (token && token !== 'undefined') {
                next();
            } else {
                // 没有登录的时候跳转到登录界面, 携带上登陆成功之后需要跳转的页面完整路径
                next({
                    name: 'login',
                    query: {
                        redirect: to.fullPath
                    }
                });
            }
        } else {
            // 不需要身份校验 直接通过
            next(); 
        }
    });

    router.afterEach(to => {
        // 多页控制 打开新的页面
        store.dispatch('admin/page/open', to);
        // 更改标题
        util.title({
            title: to.meta.title
        });
        // 返回页面顶端
        window.scrollTo(0, 0);
    });
})();
export default router;

3.渲染amis页面

pages/default/default.tpl.vue(amis页面渲染器)核心代码如下:

import axios from "axios";
import store from '@/store';
import router from '@/router';
import {Notice,Message} from 'view-design';
import { loadPageTemplate } from "./services/system";
const amis = amisRequire("amis/embed");
import Setting from "@/setting";


axios.interceptors.response.use(
  res => res, //res为axios封装后的结果,amis底层会进行.data取出接口数据
  error => {
      if (error.response.status == 401) { // token 过期
        router.app._route.name !== 'login' && store.dispatch('admin/account/logout');
      }
      return Promise.reject(error)
    });

const amisEnv =
{
    // api接口调用fetcher实现
    fetcher: ({
        url, // 接口地址
        method, // 请求方法 get、post、put、delete
        data, // 请求数据
        responseType,
        config, // 其他配置
        headers // 请求头
    }) => {
        config.withCredentials = true;
        responseType && (config.responseType = responseType);

        if (config.cancelExecutor) {
            config.cancelToken = new (axios).CancelToken(
                config.cancelExecutor
            );
        }

        config.headers = headers || {};
        config.headers["Authorization"]= `Bearer ${token}`;

        if (method !== 'post' && method !== 'put' && method !== 'patch') {
            if (data) {
                config.params = data;
            }
            return (axios)[method](url, config);
        } else if (data && data instanceof FormData) {
            // config.headers['Content-Type'] = 'multipart/form-data';
        } else if (
            data &&
            typeof data !== 'string' &&
            !(data instanceof Blob) &&
            !(data instanceof ArrayBuffer)
        ) {
            data = JSON.stringify(data);
            config.headers['Content-Type'] = 'application/json';
        }
        return (axios)[method](url, data, config);
    },
    isCancel: (value) => { (axios).isCancel(value) },
    copy: content => {
        copy(content);
        toast.success('内容已复制到粘贴板');
    },

    // 用来实现通知,不传则使用amis内置
    notify: (type, msg) => {
        if (msg != 'Response is empty!') {
            let mtype = {
                success: '成功',
                error: '错误',
                info: '信息',
                warning: '警告',
                warn: '警惕'
            }
            Notice[type](
                {
                    title: mtype[type],
                    desc: msg.toString()
                }
            );
        }
    },

    // 用来实现提示,不传则使用amis内置
    alert: content => {
        Message.info({
            content: content,
            duration: 3,
            closable: true
        });
    },
    // 用来实现确认框,不传则使用amis内置。
    // confirm: content => {}
    // 主题,默认是 default,还可以设置成 cxd 或 dark,但记得引用它们的 css,比如 sdk 目录下的 cxd.css
    theme: "ang"
}

          //tracker可以在监听到指定事件触发后,进行相关处理。
//             const tracker = (eventTrack, props) => {
//                 //tracker监听到FormItem改变后, 更新到vue中,可以用来做参数配置器
//                 if (eventTrack.eventType == 'formItemChange') {
//                  const formData = this.amisScoped.getComponentByName("mpage.mform")?.getValues();
//                 }
//             }
//          amisEnv.tracker = tracker;
//          amisEnv.session = "global"

export default {
  watch: {
    "$route.meta.template": {
      handler(template) {
        this.loadInit(template);
      },
      immediate: false,
    },
  },
  async mounted() {
    this.loadInit(this.$route.meta.template);
  },
  beforeDestroy() {
      this.amisScoped?.unmount();
  },
  methods: {
    async loadInit(id) {
      let pl = await loadPageTemplate(id); //获取amis页面信息
      const m = pl.data;
      if (m) {
        this.amisScoped?.unmount();
        const amisJSON = JSON.parse(template);
        amisJSON.data = { ...amisJSON.data, appname, user: this.userInfo }
        if(this.$refs["vnode"]){
            this.amisScoped = amis.embed(
            this.$refs["vnode"],
            amisJSON,
            { theme: "ang" },
            amisEnv
            );
        }
      }
    }
  }
}


网站公告

今日签到

点亮在社区的每一天
去签到