localhost18comic.vip的无限可能
背景问题需要理解代码生成器的
实现原理。
方案思考实现一个简单的代码生成器。
具体实现代码生成器// utils/code-generator.js// 代码生成器类exportclassCodeGenerator{constructor(options{}){this.options{templateDir:options.templateDir||./templates,outputDir:options.outputDir||./output,...options}}// 生成Vue组件staticgenerateVueComponent(config){const{name,props,template,script,style}configreturntemplate div class${toKebabCase(name)}${template||}/div /template script setup${script||import { ref } from \vue\}${props?defineProps({\n ${props.map(prop${prop.name}:${prop.type}).join(,\n )}\n}):}/scriptstyle scoped${style||.${toKebabCase(name)}{\n /* 样式 */\n}}/style} // 生成API文件 static generateApiFile(config) { const { moduleName, baseUrl, methods } config const apiMethods methods.map(method { const { name, url, method: httpMethod, params } method returnexportfunction${name}(${params?params:}){returnrequest({url:${url},method:${httpMethod.toLowerCase()},${params?${httpMethod.toLowerCase()get?params:data}: params:}})}}).join(\n\n) returnimportrequestfrom/utils/request${apiMethods}} // 生成Store static generateStore(config) { const { name, state, actions, getters } config returnimport{defineStore}frompiniaimport{ref,computed}fromvueexportconstuse${capitalize(name)}StoredefineStore(${name},(){// State${Object.entries(state).map(([key,value])const${key} ref(${JSON.stringify(value)})).join(\n )}// Getters${getters?Object.entries(getters).map(([key,fn])const${key} computed(() ${fn})).join(\n ):}// Actions${actions?Object.entries(actions).map(([key,fn])const${key}${fn.toString()}).join(\n ):}return{${[...Object.keys(state),...Object.keys(getters||{}),...Object.keys(actions||{})].join(,\n )}}})} // 生成路由 static generateRoute(config) { const { path, name, component, meta } config return{path:${path},name:${name},component:()import(/views/${component}.vue),meta:${JSON.stringify(meta,null,
}}} } // 辅助函数 function toKebabCase(str) { return str.replace(/[A-Z]/g, match -${match.toLowerCase()})}functioncapitalize(str){returnstr.charAt(
.toUpperCase()str.slice(
}代码生成工具// utils/generator-tools.jsimport{CodeGenerator}from./code-generator// 项目生成器exportclassProjectGenerator{// 生成CRUD页面staticgenerateCRUD(config){const{moduleName,fields,hasPaginationtrue}config// 生成列表页面constlistPagethis.generateListPage(config)// 生成表单页面constformPagethis.generateFormPage(config)// 生成APIconstapiFileCodeGenerator.generateApiFile({moduleName,baseUrl:/api/${moduleName},methods:[{name:${moduleName}List,url:/${moduleName}/list,method:GET,params:true},{name:get${capitalize(moduleName)}Info,url:/${moduleName}/info,method:GET,params:true},{name:create${capitalize(moduleName)},url:/${moduleName},method:POST,params:true},{name:update${capitalize(moduleName)},url:/${moduleName},method:PUT,params:true},{name:delete${capitalize(moduleName)},url:/${moduleName},method:DELETE,params:true}]})// 生成StoreconststoreCodeGenerator.generateStore({name:moduleName,state:{list:[],total:0,loading:false},actions:{getList:async function(params) { this.loading true try { const response await${moduleName}List(params) this.list response.data.list this.total response.data.total } finally { this.loading false } }}})return{listPage,formPage,apiFile,store}}// 生成列表页面staticgenerateListPage(config){const{moduleName,fields}configconsttableColumnsfields.map(fieldel-table-column prop${field.name} label${field.label} /).join(\n )returntemplate div class${toKebabCase(moduleName)}-list div classsearch-form el-form :modelqueryParams inline${fields.filter(ff.searchable).map(fieldel-form-item label${field.label} el-input v-modelqueryParams.${field.name} placeholder请输入${field.label} / /el-form-item).join(\n )}el-form-item el-button typeprimary clickhandleSearch搜索/el-button el-button clickhandleReset重置/el-button /el-form-item /el-form /div div classtable-actions el-button typeprimary clickhandleAdd新增/el-button el-button clickhandleDeleteBatch批量删除/el-button /div el-table :datalist v-loadingloading selection-changehandleSelectionChange el-table-column typeselection width55 /${tableColumns}el-table-column label操作 width200 template #default{ row } el-button sizesmall clickhandleEdit(row)编辑/el-button el-button sizesmall typedanger clickhandleDelete(row.id)删除/el-button /template /el-table-column /el-table Pagination v-model:pagequeryParams.pageNum v-model:limitqueryParams.pageSize :totaltotal paginationgetList / /div /template script setup import { ref, onMounted } from vue import {${moduleName}List, delete${capitalize(moduleName)}} from /api/${moduleName} import Pagination from /components/Pagination.vue const list ref([]) const total ref(
const loading ref(false) const queryParams ref({ pageNum: 1, pageSize: 10,${fields.filter(ff.searchable).map(f${f.name}: ).join(,\n )}}) const selectedRows ref([]) const getList async () { loading.value true try { const response await${moduleName}List(queryParams.value) list.value response.data.list total.value response.data.total } finally { loading.value false } } const handleSearch () { queryParams.value.pageNum 1 getList() } const handleReset () { queryParams.value { pageNum: 1, pageSize: 10,${fields.filter(ff.searchable).map(f${f.name}: ).join(,\n )}} getList() } const handleAdd () { // 跳转到新增页面 } const handleEdit (row) { // 跳转到编辑页面 } const handleDelete async (id) { try { await delete${capitalize(moduleName)}(id) ElMessage.success(删除成功) getList() } catch (error) { ElMessage.error(删除失败) } } const handleSelectionChange (selection) { selectedRows.value selection } onMounted(() { getList() }) /script}// 生成表单页面staticgenerateFormPage(config){const{moduleName,fields}configconstformItemsfields.filter(ff.formField).map(fieldel-form-item label${field.label} prop${field.name} el-input v-modelformData.${field.name} placeholder请输入${field.label} / /el-form-item).join(\n )returntemplate div class${toKebabCase(moduleName)}-form el-card template #header span${config.title||capitalize(moduleName)}表单/span /template el-form :modelformData :rulesformRules refformRef label-width100px ${formItems}el-form-item el-button typeprimary clickhandleSubmit提交/el-button el-button clickhandleCancel取消/el-button /el-form-item /el-form /el-card /div /template script setup import { ref, reactive } from vue import { useRoute, useRouter } from vue-router import { get${capitalize(moduleName)}Info, create${capitalize(moduleName)}, update${capitalize(moduleName)}} from /api/${moduleName} const route useRoute() const router useRouter() const formRef ref() const formData reactive({${fields.filter(ff.formField).map(f${f.name}:${f.typenumber?0:f.typeboolean?false:}).join(,\n )}}) const formRules {${fields.filter(ff.required).map(f${f.name}: [{ required: true, message: 请输入${f.label}, trigger: blur }]).join(,\n )}} const handleSubmit async () { try { await formRef.value.validate() if (formData.id) { // 更新 await update${capitalize(moduleName)}(formData) ElMessage.success(更新成功) } else { // 创建 await create${capitalize(moduleName)}(formData) ElMessage.success(创建成功) } router.back() } catch (error) { ElMessage.error(提交失败) } } const handleCancel () { router.back() } // 如果是编辑模式加载数据 if (route.query.id) { const loadDetail async () { const response await get${capitalize(moduleName)}Info({ id: route.query.id }) Object.assign(formData, response.data) } loadDetail() } /script}}functiontoKebabCase(str){returnstr.replace(/[A-Z]/g,match-${match.toLowerCase()})}functioncapitalize(str){returnstr.charAt(
.toUpperCase()str.slice(
}
小小小蜜桃8免费观看电视剧高清-小小小蜜桃8免费观看电视剧高清应用