Express 前端起一个后端服务 实现低代码生成自定义模板页面

Express 是一个基于 Node.js 的 轻量级 Web 服务框架

让你快速启动一个本地 HTTP 服务(比如 POST/GET 接口),响应浏览器或其他前端发来的请求。

①下载wxpress

npm install express

下不了就-D -W

 根目录下就是src同目录,创建一个js 或者cjs的node脚本文件

crud-generator-server.cjs

②执行脚本:node crud-generator-server.cjs

F:\vue3\ZRKJvue3\zrkj-aigov-city-web>node crud-generator-server.cjs
✅ CRUD 页面生成服务已启动:http://localhost:3001

// crud-generator-server.js
const fs = require('fs');
const path = require('path');
const express = require('express');
const app = express();

app.use(express.json());

app.post('/generate-page', (req, res) => {
  const { tableName } = req.body;

  if (!tableName) {
    return res.status(400).json({ message: 'Missing tableName' });
  }

  const targetDir = path.resolve(__dirname, 'src/views/systemTools/addPages');
  const filePath = path.join(targetDir, `${tableName}.vue`);

  if (!fs.existsSync(targetDir)) fs.mkdirSync(targetDir, { recursive: true });

  const template = `
<template>
  <div class="common-warp-pages">
    <BasicTable @register="registerTable">
      <template #toolbar>
        <a-button type="primary" @click="handleAdd('add')">新增</a-button>
      </template>
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'action'">
          <TableAction :actions="[
            { label: '查看', onClick: () => handleView(record) },
            { label: '修改', onClick: () => openAddDrawer(true, { isUpdate: true, record, formSchema }) },
            { label: '删除', onClick: () => handleDelete(record.id) }
          ]" />
        </template>
      </template>
    </BasicTable>
    <AddDrawer @register="registerDrawer" @success="handleSuccess" />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { BasicTable, useTable, BasicColumn } from '@/components/Table';
import { FormSchema } from '@/components/Form/src/types/form';
import { TableAction } from '@/components/Table';
import { useDrawer } from '@/components/Drawer';
import AddDrawer from '@/views/systemTools/components/AddDrawer.vue';

const [registerDrawer, { openDrawer: openAddDrawer }] = useDrawer();

interface RowItem {
  id: number;
  name: string;
  age: number;
  address: string;
  userId?: number;
  status?: string;
}

const allData = ref<RowItem[]>([
  { id: 1, name: '张三', age: 18, address: '北京', userId: 1, status: '0' },
  { id: 2, name: '李四', age: 25, address: '上海', userId: 2, status: '1' },
  { id: 3, name: '王五', age: 30, address: '广州', userId: 3, status: '0' },
]);

const filteredData = ref<RowItem[]>([...allData.value]);

const searchSchemas: FormSchema[] = [
  { field: 'name', label: '姓名', component: 'Input' },
];

const formSchema: FormSchema[] = [
  { field: 'content', label: '描述', component: 'InputTextArea' },
  { field: 'name', label: '姓名', component: 'Input', required: true },
  { field: 'age', label: '年龄', component: 'InputNumber', required: true },
  { field: 'address', label: '地址', component: 'Input', required: true },
];

const columns: BasicColumn[] = [
  { title: '姓名', dataIndex: 'name' },
  { title: '年龄', dataIndex: 'age' },
  { title: '地址', dataIndex: 'address' },
];

const [registerTable] = useTable({
  columns,
  dataSource: filteredData,
  useSearchForm: true,
  formConfig: {
    labelWidth: 100,
    schemas: searchSchemas,
  },
  rowKey: 'id',
  showIndexColumn: true,
  actionColumn: {
    width: 150,
    title: '操作',
    dataIndex: 'action',
    fixed: 'right',
    align: 'center',
  },
});

const handleAdd = () => {
  openAddDrawer(true, { isUpdate: false, formSchema });
};
const handleView = (record: RowItem) => {
  openAddDrawer(true, { isUpdate: true, record });
};
const handleDelete = (id: number) => {
  allData.value = allData.value.filter((item) => item.id !== id);
  handleSearch();
};
const handleSearch = () => {
  filteredData.value = [...allData.value];
};
const handleSuccess = (val: RowItem) => {
  const idx = allData.value.findIndex((i) => i.id === val.id);
  if (idx > -1) {
    allData.value[idx] = { ...val };
  } else {
    const newId = allData.value.length ? Math.max(...allData.value.map((i) => i.id)) + 1 : 1;
    allData.value.unshift({ ...val, id: newId });
  }
  handleSearch();
};
</script>
  `;

  fs.writeFileSync(filePath, template.trim(), 'utf-8');
  res.json({ message: `${tableName}.vue 页面已生成` });
});

app.listen(3001, () => {
  console.log('✅ CRUD 页面生成服务已启动:http://localhost:3001');
});

③跨域后端cors这里自己起的太麻烦了就proxy代理替换一下

在config.ts文件里面

      proxy: {

          '/generate-page': {
         target: 'http://localhost:3001',
              changeOrigin: true,
              rewrite: (path) => path.replace(/^\/generate-page/, '/generate-page'),
  },



}

④生成页面 一个页面按钮点击方法用fetch

// 生成页面
const pageCreate = async () => {
  try {
    const res = await fetch('/generate-page', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ tableName: 'DemoTable3' }),
    });
    if (!res.ok) {
      throw new Error(`请求失败,状态码:${res.status}`);
    }
    createMessage.success('页面生成成功!');
  } catch (error) {
    console.error(error);
    createMessage.error('页面生成失败,请稍后重试');
  }
};

效果出来然后需要自己去对应文件路径配置路由

⑤最终页面效果

还有很多方面需要完善只是简单的实现了一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值