数据库实训Day004上午

1 添加删除和编辑按钮

element官网

https://element.eleme.cn/#/zh-CN

修改User.vue

删除需确认窗口

修改user_api.js

在user_api.js中新增一个删除接口

javascript 复制代码
userDelete:function(id){
        return http({
            url:'/api/user/'+id,
            method:'delete'
        });
    },

在User.vue中增加组件

java 复制代码
<script setup>
import {ref,onMounted} from 'vue'
import user_api from '@/api/user_api.js'
import { ElMessageBox,ElMessage } from 'element-plus'


const tableData = ref([]);


onMounted(function(){
  showTableData();
});

const showTableData=async()=>{
  const result = await  user_api.userList({current:1,size:10});
  tableData.value=result.data.records;
}



//执行删除按钮执行的代码
const handleDelete = (index, row) => {
//row就是当前行的数据
//index就是当前数据的下表
  ElMessageBox.confirm('是否要删除该行数据?')
      .then(async() => {
        //点击执行删除操作
        const result = await user_api.userDelete(row.id);
        showTableData();
        if(result.code==200 && result.message){
          ElMessage({
            message: result.message,
            type: 'success',
          })
        }
        if(result.code!=200){
          ElMessage({
            message: '系统异常',
            type: 'warning',
          })
        }

      }).catch(()=>{
    ElMessage.error('服务端出现异常')
  });

};

</script>

<template>
  <el-table :data="tableData" border style="width: 100%">
    <el-table-column prop="username" label="账号" width="180" />
    <el-table-column prop="nickname" label="昵称" width="180" />
    <el-table-column  label="状态" >
      <template #default="scope">
        <el-switch
            v-model="scope.row.status"
            inline-prompt
            style="--el-switch-on-color:#13ce66; --el-switch-off-color: #ff4949"
            active-text="正常"
            inactive-text="封号"
            :active-value="0"
            :inactive-value="1"
        />
      </template>
    </el-table-column>
    <el-table-column prop="last_login_time" label="最近登录时间" />
    <el-table-column label="操作">
      <template #default="scope">
        <el-button
            size="small"
            @click="handleEdit(scope.$index, scope.row)"
        >
          修改
        </el-button>
        <el-button
            size="small"
            type="danger"
            @click="handleDelete(scope.$index, scope.row)"
        >
          删除
        </el-button>
      </template>
    </el-table-column>

  </el-table>
</template>

<style scoped></style>

2 添加"新增"按钮,并实现点击"新增"按钮,弹出"新增窗口"

2.1 在user_api.js中添加新增接口

java 复制代码
// 新增:用户新增接口
    userAdd:function(obj){
        return http({
            url:'/api/user/',
            method:'post',
            data: obj,
            headers: {
                'Content-Type': 'application/json'
            }
        });
    },

在User.vue中添加"新增方法"

2.2 创建UserAdd.vue文件

java 复制代码
<template>
  <el-dialog
      v-model="localVisible"
      title="新增用户"
      width="400px"
      @close="handleClose"
  >
    <el-form
        ref="formRef"
        :model="form"
        :rules="rules"
        label-width="80px"
        style="max-width: 360px"
    >
      <el-form-item label="账号" prop="username">
        <el-input v-model="form.username" placeholder="请输入用户账号" />
      </el-form-item>
      <el-form-item label="昵称" prop="nickname">
        <el-input v-model="form.nickname" placeholder="请输入用户昵称" />
      </el-form-item>

      <el-form-item label="密码" prop="password">
        <el-input
            v-model="form.password"
            type="password"
            placeholder="请输入6-20位密码"
            show-password
        />
      </el-form-item>

      <el-form-item label="状态">
        <el-switch
            v-model="form.status"
            inline-prompt
            style="--el-switch-on-color:#13ce66; --el-switch-off-color: #ff4949"
            active-text="正常"
            inactive-text="封号"
            :active-value="0"
            :inactive-value="1"
        />
      </el-form-item>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="handleClose">取消</el-button>
        <!-- 新增:加载状态,防止重复提交 -->
        <el-button type="primary" @click="handleSubmit" :loading="loading">确定</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<script setup>
import { ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import user_api from '@/api/user_api.js'

// 接收父组件传参(弹窗显隐)
const props = defineProps({
  visible: { type: Boolean, default: false }
})
// 向父组件传递事件
const emit = defineEmits(['close', 'refreshList'])

// 本地中转弹窗状态(避免直接修改props)
const localVisible = ref(props.visible)
watch(() => props.visible, (newVal) => {
  localVisible.value = newVal
})

// 表单实例 + 加载状态 + 表单数据
const formRef = ref(null)
const loading = ref(false) // 新增:防止重复提交
const form = ref({
  username: '',
  nickname: '',
  password: '', // 修复:补充密码字段,与表单v-model绑定对应
  status: 0 // 默认正常
})

// 表单验证规则
const rules = ref({
  // 保留原有账号、昵称的规则,新增密码规则
  password: [
    { required: true, message: '请输入密码', trigger: 'blur' },
    { min: 6, max: 20, message: '密码长度需在6-20位之间', trigger: 'blur' }
  ],
  username: [
    { required: true, message: '请输入用户账号', trigger: 'blur' },
    { min: 3, max: 20, message: '账号长度3-20字符', trigger: 'blur' }
  ],
  nickname: [
    { required: true, message: '请输入用户昵称', trigger: 'blur' },
    { min: 2, max: 30, message: '昵称长度2-30字符', trigger: 'blur' }
  ]
})

// 提交新增(核心逻辑)
const handleSubmit = async () => {
  // 1. 防止重复提交
  if (loading.value) return;
  // 2. 表单验证
  if (!formRef.value) return;
  try {
    await formRef.value.validate()
  } catch (err) {
    ElMessage.warning('请完善必填项');
    return;
  }

  // 3. 调用接口写入数据库
  try {
    loading.value = true; // 开启加载
    const res = await user_api.userAdd(form.value);
    // 新增成功判断:严格校验返回值,确保提示准确性
    if (res?.code === 200) {
      // 优化:优先使用后端返回消息,无消息则兜底友好提示
      const successMsg = res.message || '新增用户成功!'
      ElMessage.success(successMsg)
      emit('refreshList'); // 通知父组件刷新列表
      handleClose(); // 关闭弹窗
    } else {
      ElMessage.warning(res?.message || '新增用户失败,请重试')
    }
  } catch (err) {
    ElMessage.error(`服务端异常:${err.message || '未知错误,新增失败'}`);
    console.error('新增用户报错:', err);
  } finally {
    loading.value = false; // 关闭加载,无论成功失败都重置
  }
}

// 关闭弹窗(重置表单)
const handleClose = () => {
  if (formRef.value) formRef.value.resetFields(); // 重置验证状态
  form.value = {
    username: '',
    nickname: '',
    password: '', // 修复:清空密码字段
    status: 0
  }; // 清空数据
  emit('close'); // 通知父组件关闭弹窗
  localVisible.value = false;
}
</script>

<style scoped>
.dialog-footer { text-align: right; }
</style>

2.3 修改User.vue

1

2

3

4

新增成功

3 编辑功能

3.1 创建UserEdit.vue文件

java 复制代码
<template>
  <el-dialog
      v-model="localVisible"
      title="编辑用户"
      width="400px"
      @close="handleClose"
  >
    <el-form
        ref="formRef"
        :model="form"
        :rules="rules"
        label-width="80px"
        style="max-width: 360px"
    >
      <!-- 账号通常不允许修改,disabled 可以设置为禁用 -->
      <el-form-item label="账号" prop="username">
        <el-input v-model="form.username" placeholder="请输入用户账号" />
      </el-form-item>
      <el-form-item label="昵称" prop="nickname">
        <el-input v-model="form.nickname" placeholder="请输入用户昵称" />
      </el-form-item>
      <el-form-item label="状态">
        <el-switch
            v-model="form.status"
            inline-prompt
            style="--el-switch-on-color:#13ce66; --el-switch-off-color: #ff4949"
            active-text="正常"
            inactive-text="封号"
            :active-value="0"
            :inactive-value="1"
        />
      </el-form-item>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="handleClose">取消</el-button>
        <el-button type="primary" @click="handleSubmit">保存</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<script setup>
import { ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import user_api from '@/api/user_api.js'

// 接收父组件传递的参数:弹窗显隐、编辑行数据
const props = defineProps({
  visible: {
    type: Boolean,
    default: false
  },
  editData: { // 编辑的用户数据
    type: Object,
    default: () => ({})
  }
})

// 向父组件传递事件:关闭弹窗、刷新列表
const emit = defineEmits(['close', 'refreshList'])

// 本地维护弹窗显隐状态(避免直接修改props)
const localVisible = ref(props.visible)
watch(() => props.visible, (newVal) => {
  localVisible.value = newVal
})

// 表单实例
const formRef = ref(null)
// 表单数据(编辑时从父组件回显)
const form = ref({
  id: '',      // 新增id字段,用于后端定位编辑对象
  username: '',
  nickname: '',
  status: 0
})

// 监听编辑数据变化,自动回显到表单
watch(() => props.editData, (newVal) => {
  if (newVal && newVal.id) {
    form.value = { ...newVal } // 深拷贝,避免修改原数据
  }
}, { immediate: true })

// 表单验证规则(和新增保持一致)
const rules = ref({
  username: [
    { required: true, message: '请输入用户账号', trigger: 'blur' },
    { min: 3, max: 20, message: '账号长度在 3 到 20 个字符', trigger: 'blur' }
  ],
  nickname: [
    { required: true, message: '请输入用户昵称', trigger: 'blur' },
    { min: 2, max: 30, message: '昵称长度在 2 到 30 个字符', trigger: 'blur' }
  ]
})

// 提交编辑
const handleSubmit = async () => {
  // 表单验证
  try {
    await formRef.value.validate()
  } catch (error) {
    ElMessage.warning('请完善表单必填项')
    return
  }

  // 调用编辑接口
  try {
    const result = await user_api.userEdit(form.value)
    // 编辑成功判断:优先判断接口返回码,保障提示准确性
    if (result.code === 200) {
      // 弹窗成功提示:优先使用接口返回的消息,无消息则使用兜底默认提示
      const successMsg = result.message || '编辑用户成功!'
      ElMessage.success(successMsg)

      emit('refreshList') // 通知父组件刷新列表
      handleClose()       // 关闭编辑弹窗
    } else {
      // 接口返回非成功码,弹出失败提示
      ElMessage.warning(result.message || '编辑用户失败,请重试')
    }
  } catch (error) {
    // 网络异常/服务端报错,弹出错误提示
    ElMessage.error('服务端异常,编辑用户失败')
    console.error('编辑用户报错:', error)
  }
}

// 关闭弹窗(重置表单+通知父组件)
const handleClose = () => {
  formRef.value?.resetFields() // 重置表单验证状态
  form.value = { id: '', username: '', nickname: '', status: 0 } // 清空表单
  emit('close') // 通知父组件关闭弹窗
  localVisible.value = false
}
</script>

<style scoped>
.dialog-footer {
  text-align: right;
}
</style>

3.2 相应的修改User.vue代码

编辑成功

4 搜索框(实现模糊搜索)

4.1 创建UserSearch.vue文件

java 复制代码
<template>
  <el-form
      ref="searchFormRef"
      :model="searchForm"
      inline
      style="margin-bottom: 0"
  >
    <!-- 昵称搜索框 -->
    <el-form-item label="昵称" prop="nickname">
      <el-input
          v-model="searchForm.nickname"
          placeholder="请输入用户昵称"
          clearable
          style="width: 200px"
          @keyup.enter="handleSearch"
      />
    </el-form-item>
    <!-- 操作按钮 -->
    <el-form-item>
      <el-button type="primary" @click="handleSearch">搜索</el-button>
      <el-button @click="handleReset">重置</el-button>
    </el-form-item>
  </el-form>
</template>

<script setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'

// 定义事件:向父组件传递搜索/重置指令
const emit = defineEmits(['search', 'reset'])

// 搜索表单数据
const searchForm = ref({
  nickname: ''  // 昵称关键词
})

// 表单实例(用于重置)
const searchFormRef = ref(null)

// 搜索按钮/回车触发
const handleSearch = () => {
  // 传递搜索参数(深拷贝避免引用问题)
  emit('search', { ...searchForm.value })

  // 添加查询成功的提示消息
  ElMessage({
    type: 'success',
    message: '查询成功!',
    duration: 2000 // 可选:设置提示自动关闭时间,默认3000毫秒
  })

  // 简化写法(若无需自定义配置,可直接使用)
  // ElMessage.success('查询成功!')
}

// 重置按钮触发
const handleReset = () => {
  // 重置表单状态+清空数据
  searchFormRef.value?.resetFields()
  searchForm.value = { nickname: '' }
  // 通知父组件重置搜索
  emit('reset')
}
</script>

<style scoped>
/* 调整表单间距,避免和页面其他元素冲突 */
.el-form-item {
  margin-bottom: 0;
  margin-right: 10px;
}
</style>

4.2 修改后端 Controller 查询逻辑(核心)

代码调整

1、替换原有的 searchtext 参数为 nickname,精准接收前端传递的昵称关键词;

2、增加分页参数 current/size 的默认值,避免分页异常;

3、仅针对 nickname 执行模糊查询(like),且做空值校验,避免无效查询。

前后端参数对齐

1、前端 UserSearch 组件传递 nickname 参数 → 父组件 User.vue 接收后拼接分页参数 → user_api.js 传递到后端;

2、后端接收 nickname 参数后,通过 MyBatis Plus 的 LambdaQueryWrapper.like 实现模糊搜索。

java 复制代码
package com.easy.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easy.service.UserService;
import com.easy.bean.User;
import com.easy.util.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

//允许跨域访问
@CrossOrigin
@RestController
@RequestMapping("user")
public class UserController {
    @Autowired
    UserService userService;

    @PostMapping("/")
    public Result add(@RequestBody User user) {
        userService.save(user);
        user = userService.getById(user.getId());
        return Result.success("新增数据成功", user);
    }

    @PutMapping("/")
    public Result edit(@RequestBody User user) {
        userService.updateById(user);
        user = userService.getById(user.getId());
        return Result.success("编辑数据成功", user);
    }

    @DeleteMapping("/{id}")
    public Result delete(@PathVariable int id) {
        userService.removeById(id);
        return Result.success("删除数据成功");
    }

    @GetMapping("/{id}")
    public Result getById(@PathVariable int id) {
        User user = userService.getById(id);
        return Result.success("", user);
    }

    /**
     * 分页查询 + 昵称模糊搜索
     * @param page MyBatis Plus分页对象
     * @param nickname 昵称搜索关键词(非必传)
     * @param current 当前页(默认1)
     * @param size 每页条数(默认10)
     * @return 分页结果
     */
    @GetMapping("/")
    public Result getPage(Page page,
                         @RequestParam(value = "nickname", required = false) String nickname,
                         @RequestParam(value = "current", defaultValue = "1") Long current,
                         @RequestParam(value = "size", defaultValue = "10") Long size) {
        // 设置分页参数
        page.setCurrent(current);
        page.setSize(size);

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        // 昵称非空时,执行模糊查询
        if (nickname != null && !nickname.trim().isEmpty()) {
            queryWrapper.like(User::getNickname, nickname.trim());
        }

        // 执行分页查询
        userService.page(page, queryWrapper);
        return Result.success("", page);
    }
}

支持模糊查询

5 最新的User.vue文件

java 复制代码
<script setup>
import {ref,onMounted} from 'vue'
import user_api from '@/api/user_api.js'
import { ElMessageBox,ElMessage } from 'element-plus'

// 引入新增用户组件
import UserAdd from './UserAdd.vue'

import UserEdit from './UserEdit.vue' // 新增:引入编辑组件

// 1. 引入搜索组件
import UserSearch from './UserSearch.vue'


const tableData = ref([]);

// 控制新增弹窗显隐
const addDialogVisible = ref(false);
const editDialogVisible = ref(false); // 新增:编辑弹窗显隐
const editRowData = ref({});          // 新增:存储要编辑的行数据

// 2. 新增:存储搜索参数
const searchParams = ref({
  username: '',
  nickname: ''
})


onMounted(function(){
  showTableData();
});


// 3. 改造:支持传入搜索参数
const showTableData=async(searchParams = {})=>{
  try {
    // 合并分页参数 + 搜索参数
    const params = {
      current:1, // 可扩展分页,此处先固定
      size:10,
      ...searchParams
    };
    const result = await  user_api.userList(params);
    tableData.value=result.data.records;
  } catch (error) {
    ElMessage.error('加载数据失败:' + error.message)
    console.error('加载用户列表报错:', error)
  }
}

// 4. 新增:处理搜索事件(接收子组件参数)
const handleSearch = (params) => {
  searchParams.value = params;
  showTableData(params);
}

// 5. 新增:处理重置事件
const handleReset = () => {
  searchParams.value = { username: '', nickname: '' };
  showTableData();
}

// 打开新增弹窗
const openAddDialog = () => {
  addDialogVisible.value = true
}

// 新增:打开编辑弹窗(传递行数据)
const handleEdit = (index, row) => {
  editRowData.value = { ...row }; // 深拷贝行数据,避免直接修改表格
  editDialogVisible.value = true;
};

//执行删除按钮执行的代码
const handleDelete = (index, row) => {
//row就是当前行的数据
//index就是当前数据的下表
  ElMessageBox.confirm('是否要删除该行数据?')
      .then(async() => {
        //点击执行删除操作
        const result = await user_api.userDelete(row.id);
        showTableData();
        if(result.code==200 && result.message){
          ElMessage({
            message: result.message,
            type: 'success',
          })
        }
        if(result.code!=200){
          ElMessage({
            message: '系统异常',
            type: 'warning',
          })
        }

      }).catch(()=>{
    ElMessage.error('服务端出现异常')
  });

};
</script>

<template>

  <!-- 调整布局:新增按钮 + 搜索组件 同行展示 -->
  <div style="margin-bottom: 10px; display: flex; align-items: center; gap: 20px;">
    <el-button type="primary" @click="openAddDialog">新增用户</el-button>
    <!-- 2. 挂载搜索组件,绑定事件 -->
    <UserSearch
        @search="handleSearch"
        @reset="handleReset"
    />
  </div>

  <el-table :data="tableData" border style="width: 100%">
    <el-table-column prop="username" label="账号" width="180" />
    <el-table-column prop="nickname" label="昵称" width="180" />
    <el-table-column  label="状态" >
      <template #default="scope">
        <el-switch
            v-model="scope.row.status"
            inline-prompt
            style="--el-switch-on-color:#13ce66; --el-switch-off-color: #ff4949"
            active-text="正常"
            inactive-text="封号"
            :active-value="0"
            :inactive-value="1"
        />
      </template>
    </el-table-column>
    <el-table-column prop="last_login_time" label="最近登录时间" />
    <el-table-column label="操作">
      <template #default="scope">
        <el-button
            size="small"
            @click="handleEdit(scope.$index, scope.row)"
        >
          修改
        </el-button>
        <el-button
            size="small"
            type="danger"
            @click="handleDelete(scope.$index, scope.row)"
        >
          删除
        </el-button>
      </template>
    </el-table-column>
  </el-table>

  <!-- 用户弹窗组件 -->
  <UserAdd
      :visible="addDialogVisible"
      @close="addDialogVisible = false"
      @refreshList="showTableData"
  />

  <!-- 编辑用户弹窗组件 -->
  <UserEdit
      :visible="editDialogVisible"
      :edit-data="editRowData"
      @close="editDialogVisible = false"
      @refreshList="showTableData"
  />

</template>


<style scoped></style>
相关推荐
2501_9418059331 分钟前
在大阪智能零售场景中构建支付实时处理与高并发顾客行为分析平台的工程设计实践经验分享
数据库
李慕婉学姐39 分钟前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
珠海西格电力1 小时前
零碳园区有哪些政策支持?
大数据·数据库·人工智能·物联网·能源
数据大魔方1 小时前
【期货量化实战】日内动量策略:顺势而为的短线交易法(Python源码)
开发语言·数据库·python·mysql·算法·github·程序员创富
Chasing Aurora2 小时前
数据库连接+查询优化
数据库·sql·mysql·prompt·约束
倔强的石头_2 小时前
【金仓数据库】ksql 指南(六)—— 创建与管理用户和权限(KingbaseES 安全控制核心)
数据库
小熊officer3 小时前
Python字符串
开发语言·数据库·python
渐暖°3 小时前
JDBC直连ORACLE进行查询
数据库·oracle
萧曵 丶3 小时前
Next-Key Lock、记录锁、间隙锁浅谈
数据库·sql·mysql·mvcc·可重复读·幻读
做cv的小昊4 小时前
【TJU】信息检索与分析课程笔记和练习(7)数据库检索—Ei
数据库·笔记·学习·全文检索