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