前言
之前要写管理后台的一个菜单,首先要手动在菜单表创建一条记录,然后在创建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;
}
});
}
四、创建一个菜单
创建主菜单
创建子菜单
完成
本篇文章并非全部流程,只是提供一个思路,写的不好,望轻喷