大家好我是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
分享一套锋哥原创的基于Python的通讯录管理系统(FastAPI+Vue3)
发布时间:2026/7/17 16:43:14
大家好我是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