news 2026/6/4 16:00:09

后端使用 AI 开发前端速成:第六期:管理后台核心页面 —— 表单与 CRUD

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
后端使用 AI 开发前端速成:第六期:管理后台核心页面 —— 表单与 CRUD

📌发布状态:未发布

第六期:管理后台核心页面 —— 表单与 CRUD

本期目标:完成从"只看列表"到"能写完整 CRUD"的跨越
核心理念:管理后台 = 列表页(查)+ 表单页(增改)+ 弹窗(删)+ 详情页(看)


目录

  • 第一章:管理后台页面类型
  • 第二章:表单页设计
  • 第三章:弹窗 vs 新页面
  • 第四章:文件上传
  • 第五章:实战——完整 CRUD 用户管理
  • 第六章:AI Prompt 模板
  • 第七章:课后作业

第一章:管理后台页面类型

1.1 四大页面类型

类型用途对应操作典型组件
列表页数据展示、搜索筛选查(R)Table + Pagination
表单页新增/编辑数据增/改(C/U)Form + Input
详情页查看单条数据详情查(R)Descriptions + Card
弹窗快捷操作、二次确认删/改(D/U)Dialog/Modal

1.2 CRUD 闭环

列表页(查) → 点击"新增" → 表单页/弹窗(增) → 提交 → 回到列表页 → 点击"编辑" → 表单页/弹窗(改) → 提交 → 回到列表页 → 点击"删除" → 确认弹窗(删) → 删除 → 刷新列表

第二章:表单页设计

2.1 表单字段设计原则

后端工程师视角:表单字段 ≈ DTO 字段

// 后端 DTOinterfaceCreateUserRequest{name:string// 必填email:string// 必填,邮箱格式phone?:string// 可选role:string// 必填,下拉选择status:string// 必填,默认 activeavatar?:string// 可选,文件上传}

2.2 Vue 表单页(Element Plus)

<template> <el-form ref="formRef" :model="form" :rules="rules" label-width="80px" > <el-form-item label="用户名" prop="name"> <el-input v-model="form.name" placeholder="请输入用户名" /> </el-form-item> <el-form-item label="邮箱" prop="email"> <el-input v-model="form.email" placeholder="请输入邮箱" /> </el-form-item> <el-form-item label="角色" prop="role"> <el-select v-model="form.role" placeholder="请选择角色"> <el-option label="管理员" value="admin" /> <el-option label="普通用户" value="user" /> </el-select> </el-form-item> <el-form-item label="状态" prop="status"> <el-radio-group v-model="form.status"> <el-radio label="active">启用</el-radio> <el-radio label="inactive">禁用</el-radio> </el-radio-group> </el-form-item> <el-form-item> <el-button type="primary" :loading="submitting" @click="handleSubmit"> 提交 </el-button> <el-button @click="handleCancel">取消</el-button> </el-form-item> </el-form> </template> <script setup lang="ts"> import { ref, reactive } from 'vue' import { ElMessage } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus' import request from '@/utils/request' const props = defineProps<{ userId?: number // 有值=编辑,无值=新增 }>() const emit = defineEmits<['success', 'cancel']>() const formRef = ref<FormInstance>() const submitting = ref(false) const form = reactive({ name: '', email: '', role: '', status: 'active' }) // 表单校验规则 const rules: FormRules = { name: [ { required: true, message: '请输入用户名', trigger: 'blur' }, { min: 2, max: 20, message: '长度 2-20 个字符', trigger: 'blur' } ], email: [ { required: true, message: '请输入邮箱', trigger: 'blur' }, { type: 'email', message: '邮箱格式不正确', trigger: 'blur' } ], role: [ { required: true, message: '请选择角色', trigger: 'change' } ] } // 编辑时回显数据 const fetchDetail = async () => { if (!props.userId) return const { data } = await request.get(`/api/users/${props.userId}`) Object.assign(form, data) } const handleSubmit = async () => { const valid = await formRef.value?.validate() if (!valid) return submitting.value = true try { if (props.userId) { await request.put(`/api/users/${props.userId}`, form) ElMessage.success('修改成功') } else { await request.post('/api/users', form) ElMessage.success('新增成功') } emit('success') } finally { submitting.value = false } } const handleCancel = () => { emit('cancel') } // 初始化 fetchDetail() </script>

2.3 React 表单页(Ant Design)

import { useState, useEffect } from 'react' import { Form, Input, Select, Radio, Button, message } from 'antd' import request from '@/utils/request' interface UserFormProps { userId?: number onSuccess: () => void onCancel: () => void } function UserForm({ userId, onSuccess, onCancel }: UserFormProps) { const [form] = Form.useForm() const [submitting, setSubmitting] = useState(false) // 编辑时回显 useEffect(() => { if (userId) { request.get(`/api/users/${userId}`).then(({ data }) => { form.setFieldsValue(data) }) } }, [userId, form]) const handleSubmit = async () => { try { const values = await form.validateFields() setSubmitting(true) if (userId) { await request.put(`/api/users/${userId}`, values) message.success('修改成功') } else { await request.post('/api/users', values) message.success('新增成功') } onSuccess() } catch (error) { console.error(error) } finally { setSubmitting(false) } } return ( <Form form={form} layout="vertical"> <Form.Item name="name" label="用户名" rules={[ { required: true, message: '请输入用户名' }, { min: 2, max: 20, message: '长度 2-20 个字符' } ]}> <Input placeholder="请输入用户名" /> </Form.Item> <Form.Item name="email" label="邮箱" rules={[ { required: true, message: '请输入邮箱' }, { type: 'email', message: '邮箱格式不正确' } ]}> <Input placeholder="请输入邮箱" /> </Form.Item> <Form.Item name="role" label="角色" rules={[{ required: true }]}> <Select placeholder="请选择角色"> <Select.Option value="admin">管理员</Select.Option> <Select.Option value="user">普通用户</Select.Option> </Select> </Form.Item> <Form.Item name="status" label="状态" initialValue="active"> <Radio.Group> <Radio value="active">启用</Radio> <Radio value="inactive">禁用</Radio> </Radio.Group> </Form.Item> <Form.Item> <Button type="primary" loading={submitting} onClick={handleSubmit}> 提交 </Button> <Button onClick={onCancel} style={{ marginLeft: 8 }> 取消 </Button> </Form.Item> </Form> ) } export default UserForm

第三章:弹窗 vs 新页面

3.1 选择原则

场景推荐原因
字段 < 8 个弹窗不需要跳转,操作连贯
字段 >= 8 个新页面空间充裕,用户体验好
复杂交互(富文本、地图)新页面需要更多空间
快速操作弹窗保持上下文
需要多步骤新页面流程清晰

3.2 Vue 弹窗实现

<template> <div> <!-- 列表页内容 --> ... <el-button type="primary" @click="openDialog()">新增用户</el-button> <!-- 新增/编辑弹窗 --> <el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px" destroy-on-close > <UserForm :user-id="editingId" @success="handleSuccess" @cancel="dialogVisible = false" /> </el-dialog> </div> </template> <script setup> import { ref, computed } from 'vue' import UserForm from './UserForm.vue' const dialogVisible = ref(false) const editingId = ref() const dialogTitle = computed(() => editingId.value ? '编辑用户' : '新增用户') const openDialog = (id) => { editingId.value = id dialogVisible.value = true } const handleSuccess = () => { dialogVisible.value = false fetchData() // 刷新列表 } </script>

3.3 React 弹窗实现

import { useState } from 'react' import { Button, Modal } from 'antd' import UserForm from './UserForm' function UserList() { const [modalVisible, setModalVisible] = useState(false) const [editingId, setEditingId] = useState<number | undefined>() const modalTitle = editingId ? '编辑用户' : '新增用户' const openModal = (id?: number) => { setEditingId(id) setModalVisible(true) } return ( <div> <Button type="primary" onClick={() => openModal()}>新增用户</Button> <Modal title={modalTitle} open={modalVisible} onCancel={() => setModalVisible(false)} footer={null} destroyOnClose > <UserForm userId={editingId} onSuccess={() => { setModalVisible(false) fetchData() }} onCancel={() => setModalVisible(false)} /> </Modal> </div> ) }

第四章:文件上传

4.1 基本上传

Vue + Element Plus

<el-upload action="/api/upload" :headers="{ Authorization: `Bearer ${token}` }" :on-success="handleUploadSuccess" :on-error="handleUploadError" accept=".jpg,.png" :limit="1" > <el-button type="primary">上传头像</el-button> </el-upload>

React + Ant Design

import { Upload, Button, message } from 'antd' import { UploadOutlined } from '@ant-design/icons' <Upload action="/api/upload" headers={{ Authorization: `Bearer ${token}` }} onChange={(info) => { if (info.file.status === 'done') { message.success('上传成功') form.setFieldsValue({ avatar: info.file.response.url }) } }} accept=".jpg,.png" maxCount={1} > <Button icon={<UploadOutlined />}>上传头像</Button> </Upload>

4.2 上传前校验

// 校验文件大小和类型constbeforeUpload=(file:File)=>{constisJpgOrPng=file.type==='image/jpeg'||file.type==='image/png'if(!isJpgOrPng){message.error('只支持 JPG/PNG 格式')}constisLt2M=file.size/1024/1024<2if(!isLt2M){message.error('图片大小不能超过 2MB')}returnisJpgOrPng&&isLt2M}

第五章:实战——完整 CRUD 用户管理

5.1 需求

基于第三期的用户列表页,扩展为完整的 CRUD:

  1. 列表页增加"新增"、“编辑”、"删除"按钮
  2. 新增/编辑使用弹窗
  3. 删除需要二次确认
  4. 新增/编辑成功后刷新列表

5.2 给 AI 的 Prompt

请帮我将现有的用户列表页扩展为完整的 CRUD 功能。 当前代码: [粘贴已有的列表页代码] 新增需求: 1. 列表页操作列增加"编辑"和"删除"按钮 2. 列表页顶部增加"新增用户"按钮 3. 新增/编辑使用弹窗(字段少于 8 个,适合弹窗) 4. 弹窗包含字段:用户名、邮箱、角色(下拉)、状态(单选) 5. 表单需要完整的校验规则 6. 删除操作需要二次确认 7. 提交按钮有 loading 状态 8. 新增/编辑成功后自动刷新列表 技术栈: - Vue 3 + TypeScript + Element Plus - 使用现有的 request 封装 输出要求: - 提供完整的列表页代码(含弹窗逻辑) - 提供独立的表单组件 - 严格 TypeScript,禁止 any

第六章:AI Prompt 模板

6.1 表单页生成模板

请用 [技术栈] 写一个 [模块名] [新增/编辑] 表单。 表单字段: 1. [字段名]:[类型],[是否必填],[校验规则] 2. ... 接口: POST [接口地址](新增) PUT [接口地址]/:id(编辑) GET [接口地址]/:id(编辑时回显) 输出要求: - 表单校验规则完整 - 提交按钮 loading 状态 - 提交成功返回上一页/关闭弹窗 - 编辑时自动回显数据 - 严格 TypeScript

6.2 弹窗组件模板

请帮我把 [表单组件] 封装到弹窗中。 要求: - 弹窗宽度 600px - 弹窗标题根据是否有 id 显示"新增"或"编辑" - destroy-on-close / destroyOnClose - 提交成功后关闭弹窗并通知父组件刷新 - 使用现有 [技术栈] 的 Dialog/Modal 组件

第七章:实战

7.1 必做实战

实战 1:为列表页增加完整 CRUD

在第三期的用户列表页基础上:

  1. 增加新增/编辑弹窗
  2. 增加删除确认
  3. 实现表单校验
  4. 提交成功后刷新列表

实战 2:添加文件上传功能

在用户表单中增加头像上传功能:

  1. 限制文件类型(jpg/png)
  2. 限制文件大小(2MB)
  3. 上传成功后显示预览

7.2 FAQ

Q:表单校验规则怎么设计?

参考后端校验规则,前端做一层用户友好的校验。必填、长度、格式(邮箱/手机号)、范围(数字)是最常见的。

Q:弹窗还是新页面怎么选?

字段少于 8 个用弹窗,多于 8 个用新页面。特殊情况:需要富文本编辑器、地图选择等复杂交互时用新页面。


下一期预告:路由、权限与页面骨架 —— 登录、路由守卫、菜单、Axios 封装

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/4 15:56:50

Python教学:编码测试及格式等

s"abcd1234ABCD" #方法1: sList[s[i:i2] for i in range(0,len(s),2)] print(sList) newS .join(sList) print(newS)text "A€" # 欧元符号 encodings [utf-8, utf-16, gbk, latin-1]for enc in encodings:try:encoded text.encode(enc)print(f"…

作者头像 李华
网站建设 2026/6/4 15:56:14

Loft复式自建房楼道电梯太窄床垫进不来?环保可拆洗床垫这样选不踩坑

在装修选购床垫的过程中&#xff0c;loft复式、狭窄楼道电梯户型与农村自建房&#xff0c;是普遍公认的床垫入户与适配难题户型。这类户型不同于常规大平层宽敞的入户条件与规整的空间格局&#xff0c;普遍存在入户通道狭窄、楼梯转角刁钻、室内层高受限等硬性短板&#xff0c;…

作者头像 李华
网站建设 2026/6/4 15:54:18

3步掌握My-TODOs:让桌面待办清单成为你的效率伙伴

3步掌握My-TODOs&#xff1a;让桌面待办清单成为你的效率伙伴 【免费下载链接】My-TODOs A cross-platform desktop To-Do list. 跨平台桌面待办小工具 项目地址: https://gitcode.com/gh_mirrors/my/My-TODOs 开篇故事&#xff1a;当你的大脑需要外置硬盘 每天早上9点…

作者头像 李华
网站建设 2026/6/4 15:52:04

四旋翼无人机物理定律与数据算法

第一章&#xff1a;飞行的物理基础1.1 升力的产生一只四旋翼无人机能飞起来&#xff0c;全靠四个旋翼产生的升力。升力是什么&#xff1f;从哪里来&#xff1f;大小由什么决定&#xff1f;本节我们从流体力学的三个经典理论出发&#xff0c;一步步拆解升力的物理本质。1.1.1 伯…

作者头像 李华
网站建设 2026/6/4 15:52:03

3步掌握专业缠论分析:ChanlunX通达信插件完全指南

3步掌握专业缠论分析&#xff1a;ChanlunX通达信插件完全指南 【免费下载链接】ChanlunX 缠中说禅炒股缠论可视化插件 项目地址: https://gitcode.com/gh_mirrors/ch/ChanlunX 你是否曾在股市中感到迷茫&#xff0c;看着复杂的K线图不知从何下手&#xff1f;你是否听说过…

作者头像 李华