尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于FastAPI+Vue3的问卷调查管理平台:从Excel导入到可视化统计全流程解析

基于FastAPI+Vue3的问卷调查管理平台:从Excel导入到可视化统计全流程解析 基于FastAPI+Vue3的问卷调查管理平台:从Excel导入到可视化统计全流程解析项目地址:https://github.com/hosjoywzx123/survey_manage.git一、项目简介在数字化办公场景下,问卷调查已成为收集反馈、调研需求的高效工具。本文将带你深入解析一个基于FastAPI + Vue 3的全栈问卷调查管理平台,该项目支持从 Excel 文件一键导入问卷、自动生成微信分享二维码、多人实时填写、后台可视化数据统计等核心功能。无论你是想学习现代 Web 全栈开发,还是需要一个轻量级的问卷管理工具,这个项目都值得深入研究。二、技术栈概览层级技术选型版本后端FastAPI + SQLAlchemy (async) + Celery + RedisFastAPI 0.111, SQLAlchemy 2.0前端Vue 3 + Element Plus + Pinia + EChartsVue 3.x, Vite 5.x数据库MySQL 8.0 / SQLite (开发环境)-存储MinIO (对象存储)-容器化Docker Compose-三、架构设计┌─────────────────────────────────────────────────────────┐ │ Nginx (反向代理) │ │ 前端静态资源 + API 代理 │ └─────────────────────────────────────────────────────────┘ │ ┌───────────────────┼───────────────────┐ ▼ ▼ ▼ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ Frontend │ │ Backend │ │ Celery │ │ Vue 3 SPA │ │ FastAPI │ │ Worker │ │ :80 │ │ :8000 │ │ (异步任务) │ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ │ │ │ └──────────────────┼───────────────────┘ ▼ ┌────────────────────────┐ │ MySQL / Redis / │ │ MinIO (存储服务) │ └────────────────────────┘四、核心功能代码精讲4.1 Excel 问卷导入解析亮点:支持从 Excel 模板批量导入问卷结构和题目,极大提升创建效率。# app/utils/excel_parser.pyimportiofromtypingimportDict,Listfromopenpyxlimportload_workbookfromapp.schemas.questionimportQuestionCreate,OptionCreate VALID_TYPES={"text","textarea","number","date","single_choice","multi_choice","dropdown"}defparse_excel_survey(file_bytes:bytes)-Dict:""" 解析 Excel 问卷模板。 必须包含 Survey 表头工作表,至少包含 Questions 工作表。 Questions 工作表列: A: 题号, B: 题目类型, C: 题目文本, D: 是否必填(是/否), E: 排序, F: 配置(JSON), G+: 选项 """wb=load_workbook(io.BytesIO(file_bytes),data_only=True)if"Survey"notinwb.sheetnames:raiseValueError("Excel 必须包含 'Survey' 工作表")if"Questions"notinwb.sheetnames:raiseValueError("Excel 必须包含 'Questions' 工作表")survey_ws=wb["Survey"]meta={}forrowinsurvey_ws.iter_rows(min_row=2,values_only=True):key,value=row[0],row[1]ifkey:meta[str(key)]=str(value)ifvalueisnotNoneelse""questions_ws=wb["Questions"]questions:List[QuestionCreate]=[]forrowinquestions_ws.iter_rows(min_row=2,values_only=True):ifnotrow[0]:continueq_type=str(row[1]).strip().lower()ifq_typenotinVALID_TYPES:raiseValueError(f"不支持的题目类型:{q_type}")options=[]ifq_typein("single_choice","multi_choice","dropdown"):foridx,optinenumerate(row[6:],start=1):ifoptisNoneorstr(opt).strip()=="":continueval=str(opt).strip()options.append(OptionCreate(label=val,value=val,sort_order=idx))ifnotoptions:raiseValueError(f"选择题必须至少有一个选项:{row[2]}")extra=str(row[5]).strip()ifrow[5]elseNonequestions.append(QuestionCreate(title=str(row[2])
返回列表