当前位置: 首页 > news >正文

分享一套锋哥原创的SpringBoot4+Vue3通讯录管理系统

大家好,我是Java1234_小锋老师,分享一套锋哥原创的SpringBoot4+Vue3通讯录管理系统

项目介绍

随着移动互联网与信息化办公的快速发展,个人与组织对联系人信息的高效管理需求日益增长。传统的纸质通讯录或分散的电子表格方式存在检索困难、数据易丢失、难以多人协同和扩展性差等问题。因此,设计并实现一套基于B/S架构的通讯录管理系统具有较强的实际应用价值。本文以Spring Boot作为后端核心框架,结合MyBatis-Plus完成持久层访问,前端采用Vue3与Element Plus构建交互界面,数据库选用MySQL,认证机制采用JWT,构建了一套功能完整的通讯录管理系统。系统实现了用户注册与登录、联系人增删改查、分组管理、收藏联系人、Excel导入导出、个人中心(头像上传、资料修改、密码修改)、管理员用户管理、首页数据统计图表以及操作日志查询等功能。在数据库设计方面,围绕用户、联系人、联系人分组和操作日志四类核心实体完成概念结构设计与逻辑结构设计,并给出详细的数据表字段说明。在系统实现方面,重点阐述了Spring Boot分层架构、MyBatis-Plus条件构造与分页、Vue3组合式API及前后端分离交互流程。测试结果表明,系统功能运行稳定,界面交互清晰,能够满足日常通讯录管理的基本业务需求。本文的研究与实现过程可为同类中小型信息管理系统的开发提供参考。

源码下载

链接: https://pan.baidu.com/s/1ylAImSIMkYUc47iTmF2nbA?pwd=1234
提取码: 1234

系统展示

核心代码

package com.java1234.addressbook.controller; import com.java1234.addressbook.common.Result; import com.java1234.addressbook.common.UserContext; import com.java1234.addressbook.dto.PasswordDTO; import com.java1234.addressbook.entity.User; import com.java1234.addressbook.service.UserService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; /** * 个人中心控制器 * * @author addressbook */ @RestController @RequestMapping("/api/profile") @RequiredArgsConstructor public class ProfileController { private final UserService userService; /** * 获取当前用户信息 */ @GetMapping public Result<User> getProfile() { User user = userService.getById(UserContext.getUserId()); if (user != null) { user.setPassword(null); } return Result.success(user); } /** * 更新个人资料 */ @PutMapping public Result<Void> updateProfile(@RequestBody User user) { user.setId(UserContext.getUserId()); userService.updateProfile(user); return Result.success("资料更新成功", null); } /** * 修改密码 */ @PutMapping("/password") public Result<Void> changePassword(@RequestBody PasswordDTO dto) { userService.changePassword(UserContext.getUserId(), dto.getOldPassword(), dto.getNewPassword()); return Result.success("密码修改成功", null); } }
<template> <div class="page-container"> <!-- 统计卡片 --> <el-row :gutter="16" class="stat-row"> <el-col :span="6"> <div class="stat-card blue"> <div class="stat-label">联系人总数</div> <div class="stat-value">{{ stats.contactCount || 0 }}</div> <el-icon :size="40" style="opacity:0.3;position:absolute;right:20px;top:20px"><User /></el-icon> </div> </el-col> <el-col :span="6"> <div class="stat-card green"> <div class="stat-label">分组数量</div> <div class="stat-value">{{ stats.groupCount || 0 }}</div> <el-icon :size="40" style="opacity:0.3;position:absolute;right:20px;top:20px"><FolderOpened /></el-icon> </div> </el-col> <el-col :span="6"> <div class="stat-card orange"> <div class="stat-label">收藏联系人</div> <div class="stat-value">{{ stats.starredCount || 0 }}</div> <el-icon :size="40" style="opacity:0.3;position:absolute;right:20px;top:20px"><Star /></el-icon> </div> </el-col> <el-col :span="6"> <div class="stat-card purple"> <div class="stat-label">{{ userStore.isAdmin ? '用户总数' : '我的联系人' }}</div> <div class="stat-value">{{ userStore.isAdmin ? (stats.userCount || 0) : (stats.contactCount || 0) }}</div> <el-icon :size="40" style="opacity:0.3;position:absolute;right:20px;top:20px"><Avatar /></el-icon> </div> </el-col> </el-row> <!-- 图表区域 --> <el-row :gutter="16" style="margin-top:16px"> <el-col :span="12"> <div class="chart-card"> <div class="chart-title">联系人分组分布</div> <div ref="pieChartRef" style="height:320px"></div> </div> </el-col> <el-col :span="12"> <div class="chart-card"> <div class="chart-title">近6个月新增趋势</div> <div ref="barChartRef" style="height:320px"></div> </div> </el-col> </el-row> <!-- 生日提醒 --> <div class="chart-card" style="margin-top:16px"> <div class="chart-title">近期生日提醒 (30天内)</div> <el-table :data="stats.birthdays || []" stripe style="width:100%"> <el-table-column prop="name" label="姓名" min-width="120" /> <el-table-column prop="mobile" label="手机号" min-width="140" /> <el-table-column prop="groupName" label="分组" min-width="100" /> <el-table-column label="生日" min-width="120"> <template #default="{ row }"> {{ formatDate(row.birthday) }} </template> </el-table-column> <el-table-column prop="company" label="公司" min-width="160" show-overflow-tooltip /> </el-table> <el-empty v-if="!stats.birthdays?.length" description="近期暂无生日提醒" /> </div> </div> </template> <script setup> import { ref, onMounted, onUnmounted } from 'vue' import * as echarts from 'echarts' import dayjs from 'dayjs' import { getDashboard } from '@/api' import { useUserStore } from '@/store/user' const userStore = useUserStore() const stats = ref({}) const pieChartRef = ref() const barChartRef = ref() let pieChart = null let barChart = null /** 格式化日期 */ function formatDate(date) { return date ? dayjs(date).format('YYYY-MM-DD') : '' } /** 加载统计数据 */ async function loadData() { const res = await getDashboard() stats.value = res.data renderPieChart(res.data.groupDistribution || []) renderBarChart(res.data.monthlyTrend || []) } /** 渲染饼图 */ function renderPieChart(data) { if (!pieChartRef.value) return pieChart = echarts.init(pieChartRef.value) pieChart.setOption({ tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' }, legend: { bottom: 0, type: 'scroll' }, color: ['#667eea', '#11998e', '#f5576c', '#4facfe', '#f093fb', '#38ef7d'], series: [{ type: 'pie', radius: ['40%', '70%'], center: ['50%', '45%'], itemStyle: { borderRadius: 8, borderColor: '#fff', borderWidth: 2 }, label: { show: true, formatter: '{b}\n{c}人' }, data: data.length ? data : [{ name: '暂无数据', value: 0 }] }] }) } /** 渲染柱状图 */ function renderBarChart(data) { if (!barChartRef.value) return barChart = echarts.init(barChartRef.value) barChart.setOption({ tooltip: { trigger: 'axis' }, grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, xAxis: { type: 'category', data: data.map(d => d.month), axisLabel: { rotate: 30 } }, yAxis: { type: 'value', minInterval: 1 }, series: [{ type: 'bar', data: data.map(d => d.count), barWidth: '40%', itemStyle: { borderRadius: [6, 6, 0, 0], color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: '#667eea' }, { offset: 1, color: '#764ba2' } ]) } }] }) } /** 窗口大小变化时重绘图表 */ function handleResize() { pieChart?.resize() barChart?.resize() } onMounted(() => { loadData() window.addEventListener('resize', handleResize) }) onUnmounted(() => { window.removeEventListener('resize', handleResize) pieChart?.dispose() barChart?.dispose() }) </script> <style scoped> .stat-row .stat-card { position: relative; overflow: hidden; } </style>
http://www.cnnetsun.cn/news/3429906.html

相关文章:

  • TTKWidgetTools与Qt Designer集成指南:可视化拖拽布局技巧
  • 图像分割技术:从传统算法到深度学习的演进与应用
  • 百度网盘Mac版性能优化:开源工具实现SVIP级下载体验
  • 单卡RTX 3090实现LLaMA-3 8B全参微调技术解析
  • 3种方法彻底解决Windows 10 PL2303驱动问题:让老旧串口设备重获新生
  • OpenCode安装与使用深度指南:终端智能代理层部署详解
  • VS Code浏览器预览插件:重新定义前端开发的沉浸式体验
  • GB/T 2423.56-2023 详解|宽带随机振动国标,电子产品抗振测试全指南
  • AXI-Stream数据流中的“哨兵”:TKEEP与TSTRB在稀疏流与位宽转换中的协同作战
  • 3分钟解决魔兽世界字体乱码:终极字体合并补全指南
  • CANN/asc-devkit SIMD Or操作
  • 专业系统稳定性测试实战:stress-ng深度解析与高效应用
  • 从零构建AI原生智能体:Hello-Agents实战指南
  • 视频直播点播/云点播/云直播EasyDSS一体化云平台助力数字赛事直播全新升级
  • 计算机小程序毕设实战-公司食堂订餐管理系统的设计与实现 基于 Django + 微信小程序的企业线上订餐服务平台【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 5分钟掌握BDSup2Sub:解决蓝光字幕转换难题的终极方案
  • C++条件变量wait_for:低延迟高响应系统的核心同步机制
  • FreeRTOS任务通知:解锁轻量级进程间通信的实战指南
  • C/C++指针从入门到精通:多级指针、动态内存与实战技巧
  • 机器人奇异点:从原理到实战避坑指南
  • 3步解决音乐加密困境:开源浏览器解密工具完全指南
  • 免费Java字节码反编译工具JD-GUI:3个实用技巧帮你快速分析第三方库
  • C++ this指针深度解析:从内存模型到实战应用
  • Windows安卓应用安装指南:APK Installer让跨平台体验触手可及
  • 如何快速实现7-Zip-zstd自动化部署:完整实践指南
  • BilibiliDown:你的B站视频离线观看助手,3步完成视频下载
  • C++实现水准网平差:从数据结构到高性能算法实践
  • 告别复杂命令行:在Mac上制作Windows启动盘的终极解决方案
  • Moonlight主题用户反馈与社区贡献:如何参与主题改进
  • RK3566开发板IDO-SBC2D06-V1B-12W开箱与开发环境搭建指南