分享一套锋哥原创的基于Python的通讯录管理系统(FastAPI+Vue3)
大家好我是Java1234_小锋老师分享一套锋哥原创的基于Python的通讯录管理系统(FastAPIVue3)项目介绍随着移动互联网与数字化办公的快速发展个人与企业在日常工作中需要对大量联系人信息进行统一管理。传统纸质通讯录或分散存储于手机、表格中的联系方式存在检索不便、备份困难、多人协作能力弱、权限控制不足等问题。针对上述需求本文设计并实现了一套基于Python的通讯录管理系统。系统采用前后端分离的B/S架构后端使用Python语言与FastAPI框架构建高性能RESTful API结合SQLAlchemy完成对象关系映射数据持久化采用MySQL数据库前端采用Vue3、Vite、Pinia、Vue Router与Element Plus构建管理端界面并使用ECharts实现首页数据可视化统计。系统围绕用户认证、个人中心、联系人管理、分组管理、Excel导入导出、操作日志与后台用户管理等核心业务展开通过JWT实现无状态身份认证并通过角色区分管理员与普通用户保证数据隔离与访问控制。论文完成了需求分析、总体设计、数据库E-R建模、详细表结构设计、关键模块实现与系统测试等工作。测试结果表明系统功能完整、运行稳定能够满足本科毕业设计对工程实践能力的训练要求同时为后续扩展移动端接入、密码加密存储与更细粒度权限控制提供了良好基础。源码下载链接: https://pan.baidu.com/s/1INXE-TJiN7qTRTklTAPC-Q?pwd1234提取码: 1234系统展示核心代码 用户服务 from sqlalchemy import or_ from sqlalchemy.orm import Session from app.common.deps import CurrentUser from app.common.exceptions import BusinessException from app.common.jwt_util import JwtUtil from app.common.utils import build_page_result from app.models.user import User from app.schemas.serializers import user_to_dict from app.schemas.user import LoginDTO, ProfileUpdateDTO, RegisterDTO, UserSaveDTO class UserService: 用户服务类 staticmethod def login(db: Session, dto: LoginDTO) - dict: 用户登录 user db.query(User).filter(User.username dto.username).first() if not user: raise BusinessException(用户名不存在) if user.password ! dto.password: raise BusinessException(密码错误) if user.status ! 1: raise BusinessException(账号已被禁用) token JwtUtil.generate_token(user.id, user.username, user.role) return {token: token, user: user_to_dict(user)} staticmethod def register(db: Session, dto: RegisterDTO) - None: 用户注册 if dto.confirmPassword is not None and dto.password ! dto.confirmPassword: raise BusinessException(两次输入的密码不一致) exists db.query(User).filter(User.username dto.username).count() if exists 0: raise BusinessException(用户名已存在) user User( usernamedto.username, passworddto.password, nicknamedto.nickname or dto.username, phonedto.phone, emaildto.email, gender0, role1, status1, ) db.add(user) db.commit() staticmethod def get_by_id(db: Session, user_id: int) - User | None: 根据ID获取用户 return db.query(User).filter(User.id user_id).first() staticmethod def page_users(db: Session, page_num: int, page_size: int, keyword: str | None) - dict: 分页查询用户 query db.query(User) if keyword: like f%{keyword}% query query.filter( or_(User.username.like(like), User.nickname.like(like), User.phone.like(like)) ) total query.count() records ( query.order_by(User.create_time.desc()) .offset((page_num - 1) * page_size) .limit(page_size) .all() ) return build_page_result( [user_to_dict(item) for item in records], total, page_num, page_size ) staticmethod def save_user(db: Session, dto: UserSaveDTO) - None: 管理员新增用户 exists db.query(User).filter(User.username dto.username).count() if exists 0: raise BusinessException(用户名已存在) user User( usernamedto.username, passworddto.password or 123456, nicknamedto.nickname, phonedto.phone, emaildto.email, genderdto.gender or 0, roledto.role if dto.role is not None else 1, statusdto.status if dto.status is not None else 1, avatardto.avatar, ) db.add(user) db.commit() staticmethod def update_user(db: Session, dto: UserSaveDTO) - None: 管理员修改用户 user db.query(User).filter(User.id dto.id).first() if not user: raise BusinessException(用户不存在) user.nickname dto.nickname user.phone dto.phone user.email dto.email user.gender dto.gender if dto.gender is not None else user.gender user.role dto.role if dto.role is not None else user.role user.status dto.status if dto.status is not None else user.status if dto.password: user.password dto.password db.commit() staticmethod def delete_user(db: Session, user_id: int) - None: 管理员删除用户 if user_id 1: raise BusinessException(不能删除超级管理员) user db.query(User).filter(User.id user_id).first() if user: db.delete(user) db.commit() staticmethod def update_profile(db: Session, user_id: int, dto: ProfileUpdateDTO) - None: 更新个人资料 user db.query(User).filter(User.id user_id).first() if not user: raise BusinessException(用户不存在) if dto.nickname is not None: user.nickname dto.nickname if dto.phone is not None: user.phone dto.phone if dto.email is not None: user.email dto.email if dto.gender is not None: user.gender dto.gender if dto.avatar: user.avatar dto.avatar db.commit() staticmethod def change_password(db: Session, user_id: int, old_password: str, new_password: str) - None: 修改密码 user db.query(User).filter(User.id user_id).first() if not user: raise BusinessException(用户不存在) if user.password ! old_password: raise BusinessException(旧密码错误) user.password new_password db.commit() staticmethod def count_all(db: Session) - int: 统计用户总数 return db.query(User).count()template div classpage-container div classsearch-bar el-form :inlinetrue el-form-item label分组名称 el-input v-modelquery.keyword placeholder搜索分组名称 clearable keyup.enterloadData / /el-form-item el-form-item el-button typeprimary clickloadDatael-iconSearch //el-icon 搜索/el-button el-button clickquery.keyword;query.pageNum1;loadData()el-iconRefresh //el-icon 重置/el-button /el-form-item /el-form /div div classtable-card div stylemargin-bottom:16px el-button typeprimary clickopenDialog()el-iconPlus //el-icon 新增分组/el-button /div el-table :datatableData stripe border stylewidth:100% el-table-column propgroupName label分组名称 min-width160 / el-table-column propcontactCount label联系人数量 min-width120 aligncenter / el-table-column propsort label排序 min-width80 aligncenter / el-table-column v-ifuserStore.isAdmin propownerName label所属用户 min-width120 / el-table-column label创建时间 min-width170 template #default{ row }{{ formatDateTime(row.createTime) }}/template /el-table-column el-table-column label操作 width160 fixedright aligncenter template #default{ row } el-button typeprimary link clickopenDialog(row)编辑/el-button el-button typedanger link clickhandleDelete(row)删除/el-button /template /el-table-column /el-table div classpagination-wrap el-pagination v-model:current-pagequery.pageNum v-model:page-sizequery.pageSize :totaltotal :page-sizes[10, 20, 50] layouttotal, sizes, prev, pager, next, jumper size-changeloadData current-changeloadData / /div /div el-dialog v-modeldialogVisible :titleform.id ? 编辑分组 : 新增分组 width480px destroy-on-close el-form refformRef :modelform :rulesformRules label-width80px el-form-item label分组名称 propgroupName el-input v-modelform.groupName placeholder请输入分组名称 / /el-form-item el-form-item label排序 el-input-number v-modelform.sort :min0 :max999 / /el-form-item /el-form template #footer el-button clickdialogVisible false取消/el-button el-button typeprimary clickhandleSubmit确定/el-button /template /el-dialog /div /template script setup import { ref, reactive, onMounted } from vue import dayjs from dayjs import { ElMessage, ElMessageBox } from element-plus import { useUserStore } from /store/user import { getGroupPage, addGroup, updateGroup, deleteGroup } from /api const userStore useUserStore() const tableData ref([]) const total ref(0) const dialogVisible ref(false) const formRef ref() const query reactive({ pageNum: 1, pageSize: 10, keyword: }) const form reactive({ id: null, groupName: , sort: 0 }) const formRules { groupName: [{ required: true, message: 请输入分组名称, trigger: blur }] } function formatDateTime(d) { return d ? dayjs(d).format(YYYY-MM-DD HH:mm:ss) : } async function loadData() { const res await getGroupPage(query) tableData.value res.data.records total.value res.data.total } function openDialog(row) { if (row) { Object.assign(form, { id: row.id, groupName: row.groupName, sort: row.sort }) } else { Object.assign(form, { id: null, groupName: , sort: 0 }) } dialogVisible.value true } async function handleSubmit() { await formRef.value.validate() if (form.id) { await updateGroup(form) ElMessage.success(修改成功) } else { await addGroup(form) ElMessage.success(新增成功) } dialogVisible.value false loadData() } async function handleDelete(row) { await ElMessageBox.confirm(确定删除分组「${row.groupName}」吗, 提示, { type: warning }) await deleteGroup(row.id) ElMessage.success(删除成功) loadData() } onMounted(loadData) /script

相关新闻

DeepSeek-OCR Client开发者指南:如何扩展PDF支持和批量处理功能

DeepSeek-OCR Client开发者指南:如何扩展PDF支持和批量处理功能

DeepSeek-OCR Client开发者指南:如何扩展PDF支持和批量处理功能 【免费下载链接】deepseek-ocr-client A real-time Electron-based desktop GUI for DeepSeek-OCR 项目地址: https://gitcode.com/gh_mirrors/de/deepseek-ocr-client DeepSeek-OCR Client是一…

2026/7/17 16:43:24阅读更多 →
HslControls:工业物联网可视化利器,让上位机开发效率提升300%

HslControls:工业物联网可视化利器,让上位机开发效率提升300%

HslControls:工业物联网可视化利器,让上位机开发效率提升300% 【免费下载链接】HslControlsDemo HslControls控件库的使用demo,HslControls是一个工业物联网的控件库,基于C#开发,配套HslCommunication组件可以实现工业…

2026/7/17 16:43:24阅读更多 →
OpenEuler/Trucker:打造高效ISO与LiveCD的终极工具套件详解

OpenEuler/Trucker:打造高效ISO与LiveCD的终极工具套件详解

OpenEuler/Trucker:打造高效ISO与LiveCD的终极工具套件详解 【免费下载链接】trucker Tools for create iso livecd and cloud image 项目地址: https://gitcode.com/openeuler/trucker 前往项目官网免费下载:https://ar.openeuler.org/ar/ Open…

2026/7/17 16:43:24阅读更多 →
电磁场与电磁波:本质区别与工程应用解析

电磁场与电磁波:本质区别与工程应用解析

1. 电磁场与电磁波的物理本质差异当我们在大学物理课本上第一次看到"电磁场"和"电磁波"这两个术语时,很多人会下意识地认为它们是同一种物理现象的不同表述。但当我真正开始研究天线设计时,才深刻理解到它们的本质区别就像"蓄水…

2026/7/17 17:59:10阅读更多 →
Spring Boot应用代码保护实战:XJar加密原理与部署指南

Spring Boot应用代码保护实战:XJar加密原理与部署指南

1. 项目概述:为什么你的Spring Boot应用需要“加密盔甲”?最近在跟几个做企业级应用开发的朋友聊天,发现大家普遍有个痛点:辛辛苦苦开发的Spring Boot应用,一旦打包成JAR或WAR交付出去,里面的核心业务逻辑、…

2026/7/17 17:59:10阅读更多 →
云呼叫中心一体化架构手册(系统+线路):从底层协议、调度算法到生产级落地部署

云呼叫中心一体化架构手册(系统+线路):从底层协议、调度算法到生产级落地部署

企业级云呼叫中心系统线路一体化技术落地手册,可用于研发集成、运维部署、架构选型、项目交付、内部技术培训。区别于通用功能科普,本文聚焦软硬协同底层原理、通信协议规范、线路调度机制、高并发容灾、生产级代码配置、故障排错体系,具备完…

2026/7/17 17:59:10阅读更多 →
7分钟高效瘦手臂训练:零器械自重动作详解与科学计划

7分钟高效瘦手臂训练:零器械自重动作详解与科学计划

这次我们来看一个健身训练项目——超模Nina Dapper的7分钟瘦手臂训练。这个训练视频在网络上热度很高,号称"已练100次,超级有用",特别适合想要针对性瘦手臂、改善手臂线条的人群。 这个训练的核心特点是时间短、效率高&#xff0c…

2026/7/17 17:59:10阅读更多 →
开发者必看:diffusiongemma-26B-A4B-it-4bit配置文件详解与参数调优

开发者必看:diffusiongemma-26B-A4B-it-4bit配置文件详解与参数调优

开发者必看:diffusiongemma-26B-A4B-it-4bit配置文件详解与参数调优 【免费下载链接】diffusiongemma-26B-A4B-it-4bit 项目地址: https://ai.gitcode.com/hf_mirrors/mlx-community/diffusiongemma-26B-A4B-it-4bit 想要充分发挥diffusiongemma-26B-A4B-it…

2026/7/17 17:59:10阅读更多 →
股票交易记录系统构建:从数据采集到风险控制的Python实现

股票交易记录系统构建:从数据采集到风险控制的Python实现

这次我们来看一个股票交易策略跟踪项目,标题虽然带有情绪化表达,但核心是一个实盘交易记录系统。这类项目对技术人来说,重点不在于预测准确性,而在于如何构建可靠的交易记录、风险控制和数据分析框架。 从技术角度看,…

2026/7/17 17:54:09阅读更多 →
VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异当你在VSCode中启动一个新的TypeScript项目时,第一个技术决策往往从安装方式开始。这个看似简单的选择——全局安装还是项目本地安装——实际上会深刻影响你的开发流程、团队协作和…

2026/7/17 10:42:55阅读更多 →
智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 智慧树刷课插件是一款专为智慧树在线教育平台设计的Chrome浏…

2026/7/17 8:31:03阅读更多 →
Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在GOG或Epic Games Store购买了心仪的游戏…

2026/7/17 13:22:23阅读更多 →
VS Code 高效配置与个性化定制全攻略

VS Code 高效配置与个性化定制全攻略

1. VS Code 高效配置基础作为一款轻量级但功能强大的代码编辑器,VS Code 的默认配置已经能满足基本需求,但通过合理调整设置可以大幅提升编码效率。我使用 VS Code 已经有五年多时间,期间尝试过各种配置方案,总结出这套适合大多数…

2026/7/17 0:00:01阅读更多 →
从竞赛代码到桌面工具:让 SuperADD 与 SubspaceAD 真正跑进自己的图像

从竞赛代码到桌面工具:让 SuperADD 与 SubspaceAD 真正跑进自己的图像

在异常检测领域,很多优秀算法最初都是以研究代码的形式发布的。它们能够在固定测试集上复现实验结果,却不一定能被普通用户直接拿来测试自己的图片。尤其是最近很多算法仅提供在固定测试集的测试环境,而gradio的demo演示也不会提供。 对工程应用和在自己的图片上进行测试来…

2026/7/17 0:00:01阅读更多 →
WinRAR高效配置指南:从基础安装到高级压缩实战

WinRAR高效配置指南:从基础安装到高级压缩实战

前几天帮同事处理一个客户发来的压缩包,解压时系统自带的工具弹出一串乱码,换用 WinRAR 却顺利打开了。这种看似简单的场景,恰恰暴露了不同压缩工具在处理非标准编码、分卷压缩或加密文件时的差异。WinRAR 作为一款老牌工具,真正价…

2026/7/17 0:00:01阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/16 20:13:14阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/17 13:22:38阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/17 17:26:50阅读更多 →