首页 > 其他分享 >Vue+Ant Design实现CRUD

Vue+Ant Design实现CRUD

时间:2024-05-19 16:09:19浏览次数:26  
标签:Vue const CRUD value 学生 Ant student import id

vite.config.ts

import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'

//配置Vite开发环境
export default defineConfig({
    //使用vue插件
    plugins: [vue()],
    //服务器配置
    server: {
        //指定服务器端口
        port: 9090,
        //配置代理,用于将本地服务器的请求转发到其他服务器
        proxy: {
            //触发代理的路径前缀
            '/api': {
                //指定请求转发的目标服务器地址
                target: 'http://localhost:8080',
                //改变请求的源,允许跨域请求
                changeOrigin: true
            }
        }
    }
})

Model8080.ts

//学生的基本信息数据结构
export interface Student {
    id: number,
    name: string,
    sex: string,
    birthday: string
}

//新增和修改学生时需要传入的数据结构
export interface StudentSave {
    name: string,
    sex: string,
    birthday: string
}

//查询学生时需要传入的查询条件
export interface StudentQuery {
    name?: string,
    sex?: string | null,
    pageNum: number,
    pageSize: number
}

//Spring框架返回的分页结果数据结构
export interface SpringPage<T> {
    code: number,
    data: { records: T[], total: number },
    message?: string
}

//Spring框架返回的字符串结果数据结构
export interface SpringString {
    data: string,
    message?: string,
    code: number
}

//导入Axios库中的AxiosResponse类型
import {AxiosResponse} from 'axios'

//Axios库返回的分页结果数据结构,继承AxiosResponse,将SpringPage作为其响应体类型
export interface AxiosRespPage<T> extends AxiosResponse<SpringPage<T>> {
}

//Axios库返回的字符串结果数据结构,继承AxiosResponse,将SpringString作为其响应体类型
export interface AxiosRespString extends AxiosResponse<SpringString> {
}

Student.vue

<template>
  <a-row class="button-container">
    <!-- 新增按钮:点击触发onAdd()函数,打开新增学生信息的模态框 -->
    <a-button type="primary" @click="onAdd">新增</a-button>
    <!-- 删除选中按钮:点击触发onBatchRemove()函数,批量删除选中的学生信息 -->
    <a-popconfirm title="确认要删除选中学生吗?" ok-text="确定" cancel-text="取消"
                  @confirm="onBatchRemove" @visibleChange="onVisibleChange" :visible="visible">
      <a-button type="primary">删除选中</a-button>
    </a-popconfirm>
    <!-- 姓名搜索框 -->
    <div class="input-container">
      <a-input v-model:value="student.name" placeholder="姓名" :allowClear="true"></a-input>
    </div>
    <!-- 性别选择框 -->
    <div class="select-container">
      <a-select v-model:value="student.sex" placeholder="性别" :allowClear="true">
        <a-select-option value="男">男</a-select-option>
        <a-select-option value="女">女</a-select-option>
      </a-select>
    </div>
    <!-- 搜索按钮:点击触发query()函数,在分页、排序、筛选等操作后重新搜索学生信息 -->
    <a-button class="search-button" @click="query" type="primary">搜索</a-button>
  </a-row>
  <hr>
  <!-- 学生信息表格:columns属性设置列配置,data-source属性设置数据源,row-key属性设置行唯一标识,
       pagination属性设置分页配置,@change事件绑定查询函数query,:row-selection属性设置行选择配置 -->
  <a-table :columns="columns" :data-source="students" row-key="id" :pagination="pagination"
           @change="query" :row-selection="{selectedRowKeys:ids,onChange:onSelectChange}">
    <!-- 在bodyCell列模板中,根据列的dataIndex判断是否为"operation"列,如果是,则渲染修改和删除按钮 -->
    <template #bodyCell="{column, record}">
      <template v-if="column.dataIndex==='operation'">
        <!-- 修改按钮:点击触发onEdit()函数,打开修改学生信息的模态框,并将选中的学生信息传递给模态框 -->
        <a @click="onEdit(record)">修改</a>
        <a-divider type="vertical"></a-divider>
        <!-- 删除按钮:点击触发onRemove()函数,并传递要删除的学生ID -->
        <a-popconfirm title="确认要删除该学生吗?" ok-text="确定" cancel-text="取消" @confirm="onRemove(record.id)">
          <a>删除</a>
        </a-popconfirm>
      </template>
    </template>
  </a-table>
  <!-- Save组件,用于显示和编辑学生信息的模态框,通过属性和数据模型与父组件进行交互,并通过@saved事件触发onSaved()方法 -->
  <Save :id="id" :save="save" v-model:visible="saveVisible" @saved="onSaved"></Save>
</template>

<script setup lang="ts">
import axios from "axios";
import {ref, computed, reactive} from "vue";
import {usePagination, useRequest} from "vue-request";
import {AxiosRespPage, AxiosRespString, Student, StudentQuery} from "./model/Model8080";
import {PaginationProps} from "ant-design-vue";
import Save from "./Save.vue";

//新增、修改学生信息的相关变量和函数
const saveVisible = ref(false) //定义saveVisible对象,用于存储是否显示保存学生信息的对话框的可见性状态,初始值为false
const id = ref(0) //定义id对象,用于存储要进行新增或修改的学生的ID,初始值为0
const save = reactive({name: '', sex: '', birthday: ''}) //定义save对象,用于存储要进行新增或修改的学生信息

//打开新增学生信息的模态框
function onAdd() {
  saveVisible.value = true //将saveVisible的值设为true,以显示模态框
  id.value = 0 //将id的值设为0,用于标识新增的学生信息
  Object.assign(save, {name: '', sex: '', birthday: ''}) //使用Object.assign方法初始化save对象
}

//打开修改学生信息的模态框,并将选中的学生信息传递给模态框
function onEdit(record: Student) {
  saveVisible.value = true //将saveVisible的值设为true,以显示模态框
  id.value = record.id //将id的值赋给record.id,用于标识修改的学生信息
  Object.assign(save, record) //使用Object.assign方法将record对象的属性和值复制给save对象,实现对save对象的更新
}

//在保存学生信息后调用,用于重新搜索学生信息
function onSaved() {
  search(student.value)
}

//分页、搜索学生信息的相关变量和函数
const student = ref({pageNum: 1, pageSize: 5, name: '', sex: null, birthday: null})
//调用usePagination函数实现分页
const {data, total, run: search} = usePagination<AxiosRespPage<Student>, StudentQuery[]>(
    (records) => axios.get('/api/student/findByPage', {params: records}),
    {
      defaultParams: [student.value], //指定请求分页数据时需要传递的默认参数
      pagination: {
        currentKey: "pageNum", //当前页码
        pageSizeKey: 'pageSize', //每页显示条数
        totalKey: 'data.data.totalRow' //总记录数
      }
    }
)

//在分页、排序、筛选等操作后重新搜索学生信息
function query(pagination: PaginationProps) {
  student.value.pageNum = pagination.current ?? 1 //当前页码
  student.value.pageSize = pagination.pageSize ?? 5 //每页显示条数
  search(student.value)
}

//计算分页控件的配置
const pagination = computed<PaginationProps>(() => {
  return {
    current: student.value.pageNum, //当前页码
    pageSize: student.value.pageSize, //每页显示条数
    total: total.value, //总记录数
    showSizeChanger: true, //每页显示条数的下拉列表
    pageSizeOptions: ["5", "10", "15", "20"] //自定义下拉列表内容
  }
})

//计算学生列表
const students = computed(() => {
  return data.value?.data.data.records || [] //获取数据,如果该值存在则返回,否则返回一个空数组
})

//删除学生信息的相关函数
async function onRemove(id: number) {
  await remove(id) //调用remove函数,删除指定ID的学生信息,等待其返回结果
  search(student.value)
}
//删除学生信息异步请求
const {runAsync: remove} = useRequest<AxiosRespString, number[]>(
    (id) => axios.delete(`/api/student/remove/${id}`),
    {
      manual: true //请求需要手动触发
    }
)

//批量删除选中的学生信息
const ids = ref<number[]>([]) //定义ids对象,用于存储选中的学生ID列表
//当选择的学生发生变化时,更新ids的值为新的学生ID列表
function onSelectChange(keys: number[]) {
  ids.value = keys
}

//调用batchRemove接口删除选中的学生,然后清空ids的值,并重新搜索学生
async function onBatchRemove() {
  await batchRemove(ids.value)
  ids.value = []
  search(student.value)
}

const {runAsync: batchRemove} = useRequest<AxiosRespString, number[][]>(
    (ids) => axios.delete(`/api/student/batchRemove/${ids.join(',')}`),
    {
      manual: true //请求需要手动触发
    }
)
const visible = ref(false) //关闭批量删除学生信息的模态框

//控制删除选中学生的模态框的显示与隐藏
function onVisibleChange(v: boolean) {
  if (!v) { //隐藏
    visible.value = false
  } else {  //显示
    visible.value = ids.value.length > 0
  }
}

//表格列的定义
const columns = ref([
  {
    title: "编号",
    dataIndex: "id",
  },
  {
    title: "姓名",
    dataIndex: "name",
  },
  {
    title: "性别",
    dataIndex: "sex",
  },
  {
    title: "生日",
    dataIndex: "birthday",
  },
  {
    title: '操作',
    dataIndex: 'operation'
  }
]);
</script>

<style scoped> /* 样式仅应用于当前组件的元素 */
.button-container {
  display: flex;
  align-items: center;
}
.input-container {
  display: flex;
  align-items: center;
  margin-left: 15px; /* 调整与按钮的间距 */
}
.select-container {
  display: flex;
  align-items: center;
  margin-left: 15px; /* 适当调整与输入框的间距 */
}
.search-button {
  margin-left: 15px; /* 调整与选择框的间距 */
}
button {
  margin: 5px; /* 调整按钮的间距 */
}
</style>

Save.vue

<template>
  <!-- 模态框组件,用于展示和编辑用户信息 -->
  <a-modal :visible="visible" :title="title" @ok="onOk" @cancel="onCancel">
    <a-form>
      <!-- 如果存在用户ID,则显示用户ID输入框,此处仅用于展示,不可编辑 -->
      <a-form-item label="编号" v-if="id">
        <a-input v-bind:value="id" readonly></a-input>
      </a-form-item>
      <!-- 姓名输入框,带有表单验证信息 -->
      <a-form-item label="姓名" v-bind="validateInfos.name">
        <a-input v-model:value="save.name"></a-input>
      </a-form-item>
      <!-- 性别选择器,支持选择男性或女性 -->
      <a-form-item label="性别" v-bind="validateInfos.sex">
        <a-radio-group v-model:value="save.sex">
          <a-radio-button value="男">男</a-radio-button>
          <a-radio-button value="女">女</a-radio-button>
        </a-radio-group>
      </a-form-item>
      <!-- 生日选择器,支持选择日期,绑定表单验证信息 -->
      <a-form-item label="生日" v-bind="validateInfos.birthday">
        <a-date-picker v-model:value="save.birthday" value-format="YYYY-MM-DD"></a-date-picker>
      </a-form-item>
    </a-form>
  </a-modal>
</template>

<script setup lang="ts">
import axios from "axios";
import {ref, computed} from "vue";
import {useRequest} from "vue-request";
import {AxiosRespString, StudentSave} from "./model/Model8080";
import {Form} from 'ant-design-vue'

//定义组件接收的props
const props = defineProps<{ id: number, save: StudentSave, visible: boolean }>()
//通过props中的id值决定显示的标题
const title = computed(() => props.id === 0 ? '新增学生' : '修改学生')
//定义组件向父组件发送的事件
const emit = defineEmits(['update:visible', 'saved'])

//点击确认按钮时的处理逻辑
async function onOk() {
  try {
    //提交前校验
    await validate()
    //判断是新增还是编辑
    if (props.id === 0) {
      await add(props.save)
    } else {
      await edit(props.save)
    }
    //通知父组件保存成功,并关闭当前组件
    emit('saved')
    emit('update:visible', false)
  } catch (e) {
    console.error(e)
  }
}

//点击取消按钮时的逻辑:关闭当前组件
function onCancel() {
  emit('update:visible', false)
}

//新增学生信息异步请求
const {runAsync: add} = useRequest<AxiosRespString, StudentSave[]>(
    (student) => axios.post('/api/student/add', student),
    {
      manual: true //手动触发请求
    }
)

//编辑学生信息异步请求
const {runAsync: edit} = useRequest<AxiosRespString, StudentSave[]>(
    (student) => axios.put('/api/student/edit', student),
    {
      manual: true //手动触发请求
    }
)

//定义表单校验规则
const rules = ref({
  name: [
    {required: true, message: '请输入姓名'},
    {min: 2, message: '字符数至少为2'}
  ],
  sex: [
    {required: true, message: '请选择性别'}
  ],
  birthday: [
    {required: true, message: '请选择生日'}
  ]
})

//使用Ant Design Vue的Form.useForm方法将表单和校验规则进行绑定,获取校验信息和校验函数
const {validateInfos, validate} = Form.useForm(props.save, rules)
</script>

标签:Vue,const,CRUD,value,学生,Ant,student,import,id
From: https://www.cnblogs.com/javasm1214/p/18200415

相关文章

  • React+Ant Design实现CRUD
    Student.ts//学生对象exportinterfaceStudent{id:number,name:string,sex?:string,birthday?:string}//服务器返回的数据exportinterfaceResult<T>{code:number,msg?:string,data:T}//分页响应exportinterfacePageRe......
  • 挑战程序设计竞赛 2.1章习题 poj 3046 Ant Counting
    https://vjudge.net.cn/problem/POJ-3046#author=GPT_zh有一天,贝西在蚂蚁山里探头探脑,看着蚂蚁们来来回回地觅食。她发现很多蚂蚁都是兄弟姐妹,彼此无法区分。她还发现,有时只有一只蚂蚁去觅食,有时几只,有时全部。这就产生了大量不同组合的蚂蚁!有点数学天赋的贝茜开始琢磨起来......
  • Vue3报错:已声明“upperName”,但从未读取其值。ts-plugin(6133)
    Vue3报错:已声明“upperName”,但从未读取其值。ts-plugin(6133)报错显示:类型“StoreToRefs<Store<"count",{sum:number;name:string;address:string;},{},{increment(value:number):void;}>>”上不存在属性“upperName”。ts-plugin(2339)相关代码:vue文件:con......
  • 关于学习VUE源码的感受! 学习VUE源码最好的方式 !!!
    仓库地址仓库whoelse666mini-vue崔学社mini-vue文章导航Vue3源码实战课|构建你自己的Vue3|掌握源码最有效的学习方法就是手写一遍!Vue3源码实战课阮一峰推荐最佳学习vue3源码的利器-mini-vue学习源码经历过程vue从出来到现在也有好些年了,相信几乎所所有从事......
  • VUE速通(10)Vue3核心语法(2)setup
    1setup概述setup是Vue3中一个新的配置项,值是一个函数,它是CompositionAPI“表演的舞台”,组件中所用到的:数据、方法、计算属性、监视......等等,均配置在setup中。特点如下:setup函数返回的对象中的内容,可直接在模板中使用。setup中访问this是undefined。setup函数会......
  • 『手撕Vue-CLI』添加帮助和版本号
    前言经过上一篇『手撕Vue-CLI』编码规范检查之后,手撕Vue-CLI已经进阶到了代码规范检查这一步,已经将基本的工程搭建好了,然后代码规范约束也已经加入了,并且将nue-cli指令绑定到了全局当中,可以在任何地方使用了。正文接下来这篇文章呢,就要来实现一下大多数的命令行工具都会有......
  • VSCode安装vue3插件
    1.以前的volar已经弃用了。2.最近vue插件 3.安装好插件后,在vscode中创建项目可能会报错。解决方法:1.使用window+r调出cmd,运行node-v,npm-v都没问题。那么尝试以管理员方式运行vscode,如果还是不行,重启一下电脑。2.网络原因,网络波动或者网比较差的时候导致下载丢包,把node......
  • ctflearn-writeup(Exclusive Santa)
    https://ctflearn.com/challenge/851在完成这题前最好先下载foremost,unrar,stegsolve等工具首先拿到题目后,先解压得到两个图片文件1.png和3.png两张图片用exiftool,strings,binwalk试过后发现无解于是用关键命令foremost3.png-T(修复破损文件)发现有一个output的文件夹......
  • 基于uniapp+vue3自定义增强版table表格组件「兼容H5+小程序+App端」
    vue3+uniapp多端自定义table组件|uniapp加强版综合表格组件uv3-table:一款基于uniapp+vue3跨端自定义手机端增强版表格组件。支持固定表头/列、边框、斑马纹、单选/多选,自定义表头/表体插槽、左右固定列阴影高亮显示。支持编译兼容H5+小程序端+App端。如下图:H5+小程序+App端,多端......
  • 安装vue/cli报错问题解决
    在管理员终端中输入命令:npmi-g@vue/cli错误原因证书已过期,需要安装淘宝镜像npmconfigsetregistryhttps://registry.npmmirror.com使用cnpm安装脚手架报错cnpmi-g@vue/cli 这个错误表明你尝试执行的 cnpm 命令无法加载,因为PowerShell策略不允许执......