使用plop快速生成菜单模板文件

前言

之前要写管理后台的一个菜单,首先要手动在菜单表创建一条记录,然后在创建view文件和router文件,同时还有其他类似的模板文件要一个个手动创建。当菜单多的时候,真的是要写麻了

今天,咱们通过plop快速生成文件模板,在创建菜单记录的同时生成其他文件模板。

一、首先编写plop指令生成模板文件

1、创建plopfile.js
js 复制代码
const viewGenerator = require('./plop-templates/view/prompt')

module.exports = function(plop) {
  plop.setGenerator('view', viewGenerator)
}
2、编写模板指令文件
js 复制代码
const { notEmpty } = require("../utils.js");

module.exports = {
  description: "generate a view",
  prompts: [
    {
      type: "input",
      name: "rootDir",
      message: "输入根模块路径",
      validate: notEmpty("rootDir")
    },
    {
      type: "input",
      name: "dir",
      message: "输入模块路径",
      validate: notEmpty("dir")
    },
    {
      type: "input",
      name: "name",
      message: "输入模块名称",
      validate: notEmpty("name")
    },
    {
      type: "input",
      name: "menuName",
      message: "输入模块中文名称",
      validate: notEmpty("menuName")
    },
    {
      type: "input",
      name: "rootName",
      message: "输入根模块名称",
      validate: notEmpty("rootName")
    },
    {
      type: "input",
      name: "rootMenuName",
      message: "输入根模块中文名称",
      validate: notEmpty("rootMenuName")
    },
    {
      type: "checkbox",
      name: "blocks",
      message: "Blocks:",
      choices: [{
        name: "<template>",
        value: "template",
        checked: true
      },
        {
          name: "<script>",
          value: "script",
          checked: true
        },
        {
          name: "style",
          value: "style",
          checked: true
        }
      ],
      validate(value) {
        if (value.indexOf("script") === -1 && value.indexOf("template") === -1) {
          return "View require at least a <script> or <template> tag.";
        }
        return true;
      }
    }
  ],
  actions: data => {
    const dir = "{{dir}}";
    const rootDir = "{{rootDir}}";
    const rootName = "{{rootName}}";
    const rootMenuName = "{{rootMenuName}}";
    const name = "{{name}}";
    const menuName = "{{menuName}}";
    const actions = [{
      type: "add",
      path: `src/views/${rootDir}/${dir}/index.vue`,
      templateFile: "plop-templates/view/index.hbs",
      data: {
        dir: dir,
        rootDir: rootDir,
        rootName: rootName,
        rootMenuName: rootMenuName,
        name: name,
        menuName: menuName,
        template: data.blocks.includes("template"),
        script: data.blocks.includes("script"),
        style: data.blocks.includes("style")
      }
    },
      {
        type: "add",
        path: `src/api/${rootDir}/${dir}.js`,
        templateFile: "plop-templates/view/api.hbs",
        data: {
          name: name
        }
      },
      {
        type: "add",
        path: `src/views/${rootDir}/${dir}/data.ts`,
        templateFile: "plop-templates/view/data.hbs"
      },
      {
        type: "add",
        path: `src/views/${rootDir}/${dir}/modal-form.vue`,
        templateFile: "plop-templates/view/form.hbs",
        data:{
          template: data.blocks.includes("template"),
          script: data.blocks.includes("script"),
          style: data.blocks.includes("style")
        }
      }
    ];

    return actions;
  }
};
3、最后编写模板hbs文件(以其中的index.vue为例)
hbs 复制代码
{{#if template}}
  <template>
    <div class="container">
      <Breadcrumb :items="['{{rootMenuName}}','{{menuName}}']" />
      <a-card class="general-card" :title="$t('common.dataList')">
        <search-bar v-model:condition="searchParams" :search-items="searchItems" @search="getDataList"></search-bar>
        <div class="data-handle" style="margin-bottom: 16px">
          <a-button type="primary" @click="addItem">
            <template #icon>
              <icon-plus />
            </template>
            \{{$t('common.add')}}
          </a-button>
        </div>

        <a-table
          row-key="id"
          :loading="loading"
          :bordered="false"
          :columns="columns" :data="data">
          <template #optional="{ record }">
            <a-button type="text" @click="editItem(record)">
              <template #icon>
                <icon-edit />
              </template>
              \{{$t('common.edit')}}
            </a-button>
            <a-button type="text" status="danger" @click="deleteItem(record)">
              <template #icon>
                <icon-delete />
              </template>
              \{{$t('common.delete')}}
            </a-button>
          </template>
        </a-table>
      </a-card>

      <modalForm v-model:show="show" :form-data="form" @confirm="confirmSubmit" title="{{menuName}}" />

    </div>
  </template>
{{/if}}

{{#if script}}
<script setup lang="ts">
import { reactive, ref, getCurrentInstance } from "vue";
import {{name}}Api from "@/api/{{rootDir}}/{{dir}}";
import { cloneDeep } from "lodash";
import { Modal } from '@arco-design/web-vue';
import { useI18n } from "vue-i18n";
import modalForm from "./modal-form.vue";
import useData from "./data";

const { t } = useI18n();
const {proxy} = getCurrentInstance();
const loading = ref(false);
const show = ref(false);
const form = ref(null);
const data = ref([]);
const { searchParams, searchItems, columns } = useData();

const addItem = () => {
  show.value = true;
  form.value = null
};

const editItem = (record: any) => {
  show.value = true
  form.value = cloneDeep(record)
};

const getDataList = () => {
  loading.value = true
  {{name}}Api.{{name}}List().then((res: any) => {
    if (res.code === 200) {
      loading.value = false
      data.value = res.data || [];
    }
  });
};

const confirmSubmit = (formData: any) => {
  {{name}}Api.update{{ properCase name }}({
    op: formData.id ? 1 : 0,
    ...formData
  }).then((res: any) => {
    if (res.code === 200) {
      show.value = false;
      getDataList();
      proxy.$notification.success(t("common.updateSuccess"));
    }
  });
};

const deleteItem = (record: any) => {
  Modal.warning({
    title: t("common.deleteRecord"),
    content: t("common.deleteRecordTip"),
    okText:t("common.confirm"),
    cancelText:t("common.cancel"),
    hideCancel: false,
    onOk:() => {
      {{name}}Api.update{{ properCase name }}({
        op:2,
        id:record.id
      }).then((res: any) => {
        if (res.code === 200) {
          getDataList();
          proxy.$notification.success(t("common.deleteSuccess"));
        }
      });
    }
  });
}


getDataList();

</script>
{{/if}}

{{#if style}}
<style scoped>
.container {
  padding: 0 20px 20px 20px;
}

.data-handle button {
  margin-right: 16px;
}
</style>
{{/if}}

上面只是以view文件为例,router文件同样可以按上面的流程编写

二、编写shell文件执行plop模板命令

bash 复制代码
#!/bin/bash
echo "开始生成..."

# 返回上一级目录
#cd ..


if [[ $7 == "root" ]]; then
  # 根菜单生成路由
  ./node_modules/.bin/plop parentRouter $1 $2 $3 $4 $8
  echo '根菜单生成路由完成 >>>>'
  git add ./src/router/routes/modules/$1.ts
  git add ./src/views/$1
  echo "git add ./src/router/routes/modules/$1.ts"
  echo "git add ./src/views/$1"
else
  # 生成文件
    echo "view $5 $1 $3 $2 $7 $6 template,script,style >>>>"
    ./node_modules/.bin/plop view $5 $1 $3 $2 $7 $6 template,script,style
    echo "view 文件生成完毕"
  # 生成路由
    echo "childRouter $5 $1 $7 $3 $2 $8 >>>>"
    ./node_modules/.bin/plop childRouter $5 $1 $7 $3 $2 $8
    echo "childRouter 路由生成完毕"
    git add ./src/api/$5
    git add ./src/views/$5/$1
    echo "git add ./src/api/$5"
    echo "git add ./src/views/$5/$1"
fi

echo "代码生成完毕!"

三、编写node执行shell脚本

js 复制代码
router.post("/create/menu", async ctx => {
  const data = ctx.request.body; 

  createFileShell(data);
  const response = await axios.post('http://*.*.*.*:9527/menu/list_op',data)

  ctx.body = response.data;
  // ctx.body = "success";
});


function createFileShell(data) {
  const options = {
    encoding: "utf8", // 设置输出编码为utf8
    stdio: "inherit"// 继承stdin和stdout,stderr通过pipe捕获
  };
  let nameCode = data.name;
  let menuName = data.menu_name;
  let icon = data.menu_icon;
  let path = data.path;
  let rootDir = data.path;
  let rootName = data.menu_name;
  if (data.parent) {
    rootDir = data.parent.path;
    rootName = data.parent.menu_name;
  }
  const sort = data.sort;
  const parent = data.parent_code;
  execFile("/bin/bash", [__dirname + "/create.sh", path, menuName, nameCode, icon, rootDir, rootName, parent,sort], options, (error, stdout, stderr) => {
    console.log(`stdout: ${stdout}`);
    if (error) {
      console.error(`执行脚本出错: ${error}`);
      return;
    }

  });
}

四、创建一个菜单

创建主菜单
创建子菜单
完成

本篇文章并非全部流程,只是提供一个思路,写的不好,望轻喷

相关推荐
花花鱼几秒前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui
k09334 分钟前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
EricWang135825 分钟前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
September_ning25 分钟前
React.lazy() 懒加载
前端·react.js·前端框架
web行路人35 分钟前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架
超雄代码狂1 小时前
ajax关于axios库的运用小案例
前端·javascript·ajax
长弓三石1 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙
小马哥编程1 小时前
【前端基础】CSS基础
前端·css
嚣张农民1 小时前
推荐3个实用的760°全景框架
前端·vue.js·程序员
周亚鑫2 小时前
vue3 pdf base64转成文件流打开
前端·javascript·pdf