新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于Flask与uni-app的班级事务管理系统开发实战

发布时间:2026/9/24 23:14:35来源:尧图网络
基于Flask与uni-app的班级事务管理系统开发实战
说实话班级里的那点事看起来小真正做起来能烦死人。班长要发通知、统计活动报名、安排值日、记录考勤学习委员要收作业、登记成绩文体委员要组织活动所有信息都挤在微信群聊天记录里翻起来全是“收到”和表情包。我最初做这个项目是因为一个班委朋友实在受不了每天手工整理Excel让我帮他用Python Flask和uni-app搭了一套班级事务管理系统小程序端就是微信小程序班委和同学各干各的事后再也不用在群里刷屏接龙了。做完以后我发现这套系统的架构并不复杂但踩坑点非常多尤其是Flask接口联调和微信小程序真机调试的部分特别适合作为毕业设计、课程设计或者个人练手项目于是把完整过程整理出来。这套系统能做什么给班长和班委一个简洁的后台负责发布班级公告、派发任务、组织活动报名、打卡签到、收集同学反馈给普通同学一个清爽的微信小程序入口查公告、参加活动、查看任务、提建议。角色分班委和同学权限清晰数据统一存在MySQL里。如果你正好要用Python做毕设又不想选烂大街的商城系统这个“班级事务管理系统”是个非常接地气的方向如果你想入门Flask和uni-app联合开发这篇文章也可以当第一份实践地图。1. 项目整体设计与技术选型思路1.1 痛点分析班级事务到底乱在哪我自己在学生阶段做过班委最深的感受是“事务零碎、信息分散”。今天的通知发在微信群明天报名用问卷收集后天收作业直接让室友催最后统计表散落在几个人的电脑里。真正到了评优评先的时候负责的班委要花一晚上翻聊天记录还经常漏掉关键消息。这个系统的第一目标不是搞出一堆炫酷功能而是把零散的“班级事务”归拢到一条清晰的流程里谁发起、谁处理、谁能看到、完成后存到哪里。从需求边界上看班级事务管理系统不需要做成OA级别的复杂系统。核心对象有两个一个是有管理权限的班委一个是需要被通知和配合的同学。围绕这两个对象自然能拆出公告发布、任务分配、活动报名、考勤签到、意见反馈几大块。像请假审批、课表查询这类功能虽然很好但如果一开始就铺开做很容易失控。所以我当时的策略是先把信息流跑通再加入高频功能最后再考虑通知触达等进阶能力。1.2 架构选择Flask给后端减负uni-app给前端留后路后端框架其实可以在Django和Flask之间选。Django自带Admin和ORM适合功能繁重的系统但对于班级管理这种业务量级反而是Flask更灵活。Flask核心只做路由和视图数据库、登录、跨域都可以按需集成项目结构自己说了算调试时打开日志看请求问题定位非常直接。对毕设和课程设计来说Flask还有一个隐藏优势代码量少答辩时能把每一行讲清楚。小程序端我选了uni-app而不是原生微信小程序原因更实际将来想把这套系统打包成H5或者Android Appuniapp换编译目标就行不用重写页面。它的Vue语法比较容易上手组件库生态也丰富而且开发时用HBuilderX运行到微信开发者工具可以一边改代码一边看效果调试体验比纯原生小程序的wxml流畅不少。项目中的所有页面、路由、状态管理都沿用Vue的习惯即使你以前只写过Vue没有接触过微信小程序也能在一天内开始干活。1.3 系统整体架构与信息流我用一张表来展示这个系统的分层结构层次技术组件职责客户端uni-app微信小程序用户登录、展示数据、提交表单、扫码签到接口层Flask RESTful API接收前端请求、校验身份、返回JSON业务层Flask蓝图 业务函数公告、任务、活动、签到、反馈处理数据层MySQL SQLAlchemy用户、班级、业务数据持久化文件存储服务器本地上传目录头像、公告封面、活动图片小程序发起请求后先经过Flask的before_request钩子统一做CORS和登录态检查再路由到对应蓝图最后通过SQLAlchemy访问MySQL并返回统一结构的JSON。这里有一点需要注意前后端分离后所有状态都通过token传递前端不要依赖Cookie后端也不要尝试读写session否则在微信小程序里会遇到各种奇奇怪怪的问题。2. 功能边界与数据模型怎么定2.1 角色权限班委能做什么同学能做什么权限设计要平衡“简单”和“可用”。我的方案是设置三个角色admin班主任或辅导员、leader班长/班委、student普通同学。但为了让系统不复杂控制权限不细粒度到每个班委管谁而是分成两层leader可以管理班级公告和事务student只能查看和报名。具体如下角色可操作功能admin管理所有班级、超级浏览、删除违规内容leader发布公告、创建任务、发起活动、查看签到统计、导出数据student查看公告、报名活动、扫码签到、提交反馈、查看个人任务为什么要给admin角色因为实际使用时班主任或辅导员需要查看整个班级的动态如果只开放给班长一个入口数据容易变成“黑盒”。但admin不需要参与日常琐事所以不需要操作业务只给只读权限就行。2.2 核心业务表和字段设计附示例数据库设计是整个项目的底座。我在MySQL里一共建了8张表user用户、class_info班级、class_member班级成员关系、notice公告、task任务、activity活动、activity_sign活动签到、feedback反馈。这里我挑几张关键表说。用户表user核心字段字段类型说明idint主键openidvarchar(64)微信openid唯一nicknamevarchar(50)昵称avatarvarchar(255)头像地址rolevarchar(20)admin/leader/studentclass_idint所属班级班级成员表class_member用于处理“一个同学可能有多个班级”的情况比如转专业、双学位。不过大多数场景只有一个班级所以这个表属于增强设计。公告表notice字段类型说明idint主键class_idint所属班级titlevarchar(100)标题contenttext内容publisher_idint发布者idattachmentvarchar(255)附件地址created_atdatetime创建时间任务表task包括title、content、assignee_id、publisher_id、deadline、status待办/已完成。活动表activity包括title、location、start_time、end_time、max_people、cover_image。签到表activity_sign包括activity_id、user_id、sign_time、latitude、longitude。SQLAlchemy建模时可以这样定义比如class User(db.Model): __tablename__ user id db.Column(db.Integer, primary_keyTrue) openid db.Column(db.String(64), uniqueTrue, nullableFalse) nickname db.Column(db.String(50), default) avatar db.Column(db.String(255), default) role db.Column(db.String(20), defaultstudent) class_id db.Column(db.Integer, db.ForeignKey(class_info.id))这里把class_id做外键方便联表查询。2.3 关键接口路径与权限控制策略接口设计要保持语义清晰我把业务接口都放在 /api 前缀下并划分不同蓝图方法路径功能权限POST/api/auth/login微信登录交换token无GET/api/notices获取公告列表student及以上POST/api/notices发布公告leader及以上GET/api/tasks查看任务列表student及以上POST/api/tasks创建任务leader及以上POST/api/activities创建活动leader及以上POST/api/activities/ /sign活动扫码签到student及以上GET/api/feedbacks查看反馈leader及以上POST/api/feedbacks提交反馈student及以上权限控制我推荐用一个装饰器统一处理而不是在视图函数里反复写if判断。装饰器里读token解析出用户角色再和接口要求对比。下面第3部分会给出代码。3. 后端API开发从登录到业务闭环3.1 Flask工程结构和数据库配置写Flask项目不一定要用一整套“工厂模式”但至少要分蓝图。我的目录结构是这样的course-manage-backend/ app.py config.py extensions.py models/ __init__.py user.py notice.py task.py activity.py feedback.py api/ __init__.py auth.py notice.py task.py activity.py feedback.py utils/ jwt_utils.py decorators.py uploads.py uploads/app.py负责创建app、注册蓝图、启动服务器config.py放数据库连接和上传目录配置extensions.py统一初始化SQLAlchemy和CORS。这样做的最大好处是业务代码之间不互相import顶层app避免循环导入。配置示例import os class Config: SECRET_KEY os.getenv(SECRET_KEY, dev-secret-key) SQLALCHEMY_DATABASE_URI os.getenv( DATABASE_URL, mysqlpymysql://root:passwordlocalhost/class_assistant?charsetutf8mb4 ) SQLALCHEMY_TRACK_MODIFICATIONS False UPLOAD_FOLDER os.path.join(os.getcwd(), uploads) MAX_CONTENT_LENGTH 10 * 1024 * 1024数据库字符集一定要用utf8mb4不然后端存emoji表情会报错我就是被这个坑过一次。MAX_CONTENT_LENGTH限制上传大小为10MB避免同学传视频把服务器打满。3.2 微信登录换openid签发JWT微信小程序的登录逻辑是wx.login拿到临时code把code传给后端后端用code向微信接口换取openid。这里要注意code只能用一次而且有效期短所以要拿到后立刻请求。在auth蓝图里import requests from flask import Blueprint, request, jsonify, current_app from models import User, db from utils.jwt_utils import generate_token bp Blueprint(auth, __name__, url_prefix/api/auth) bp.route(/login, methods[POST]) def login(): data request.get_json() code data.get(code) if not code: return jsonify({code: 1, message: 缺少code}), 400 appid current_app.config[WECHAT_APPID] secret current_app.config[WECHAT_SECRET] resp requests.get( https://api.weixin.qq.com/sns/jscode2session, params{ appid: appid, secret: secret, js_code: code, grant_type: authorization_code }, timeout5 ) wechat_data resp.json() openid wechat_data.get(openid) if not openid: return jsonify({code: 1, message: 登录失败}), 401 user User.query.filter_by(openidopenid).first() if not user: user User(openidopenid, nickname新同学, rolestudent) db.session.add(user) db.session.commit() token generate_token(user.id, user.role) return jsonify({code: 0, data: {token: token, user: user.to_dict()}})generate_token我用PyJWT实现加入过期时间import jwt import datetime SECRET_KEY your-secret def generate_token(user_id, role): payload { user_id: user_id, role: role, exp: datetime.datetime.utcnow() datetime.timedelta(days7) } return jwt.encode(payload, SECRET_KEY, algorithmHS256)这里的设计要点是token里存user_id和role后续接口拿到token就能知道谁在调用不必每次都查数据库。当然如果对权限实时性要求高可以再做一个token过期检验。3.3 权限装饰器和公告/任务接口实现装饰器的作用是把“校验token、拿当前用户、检查角色”这三件事封装起来。我写的简化版from functools import wraps from flask import request, jsonify import jwt from utils.jwt_utils import SECRET_KEY def require_role(*roles): def decorator(fn): wraps(fn) def wrapper(*args, **kwargs): auth request.headers.get(Authorization, ) if not auth.startswith(Bearer ): return jsonify({code: 401, message: 未登录}), 401 token auth[7:] try: payload jwt.decode(token, SECRET_KEY, algorithms[HS256]) except jwt.ExpiredSignatureError: return jsonify({code: 401, message: token过期}), 401 except jwt.InvalidTokenError: return jsonify({code: 401, message: 无效token}), 401 if payload.get(role) not in roles: return jsonify({code: 403, message: 没有权限}), 403 request.user_id payload.get(user_id) request.user_role payload.get(role) return fn(*args, **kwargs) return wrapper return decorator发布公告接口用起来就很简洁bp.route(/notices, methods[POST]) require_role(leader, admin) def create_notice(): data request.get_json() notice Notice( class_iddata[class_id], titledata[title], contentdata.get(content, ), publisher_idrequest.user_id ) db.session.add(notice) db.session.commit() return jsonify({code: 0, data: notice.to_dict()})注意require_role要放在路由装饰器下面一层否则app注册路由时会找不到函数对象。这个问题我第一次写的时候纠结了很久后来发现是装饰器顺序错了。任务分派接口也类似只不过多了一个assignee_id字段。创建任务时我建议同时生成一条“未读/待办”状态方便同学端显示红点。这里不铺开写核心就是多表写入时用db.session.add_all保证原子性。3.4 上传图片时最容易踩的两个坑文件上传是班级相册、活动封面、用户头像的刚需也是Flask项目里问题高发区。核心代码其实非常简单import os import uuid from flask import request, current_app from werkzeug.utils import secure_filename def allowed_file(filename): return . in filename and filename.rsplit(., 1)[1].lower() in {jpg, jpeg, png, gif} bp.route(/upload, methods[POST]) require_role(student, leader, admin) def upload(): file request.files.get(file) if not file or not allowed_file(file.filename): return jsonify({code: 1, message: 不支持的格式}), 400 ext os.path.splitext(file.filename)[1] new_name uuid.uuid4().hex ext save_path os.path.join(current_app.config[UPLOAD_FOLDER], new_name) file.save(save_path) return jsonify({code: 0, data: {url: /uploads/ new_name}})这代码看起来没问题但实际部署后我至少遇到两个坑。第一个坑是文件名。secure_filename会把中文文件名过滤掉导致“活动海报.jpg”变成“jpg”甚至空字符串。我的处理是使用uuid重命名不再调用secure_filename然后自己用后缀白名单校验格式。第二个坑是访问路径。Flask返回的相对路径“/uploads/xxx.jpg”在小程序里只有当后端域名也开着同一个Flask服务才有效。后面前端如果走了Nginx反向代理要保证静态文件由Nginx直接服务或者Flask正确挂了static_url_path。最简单的做法是上传接口返回一个完整的URL从数据库里读出来直接拼上域名这样不管前端怎么改baseURL都不会错。不过要注意如果以后迁移域名历史数据的URL会失效所以更稳妥的是返回相对路径前端统一拼BASE_URL。4. 小程序端uni-app把管理后台装进口袋4.1 从HBuilderX创建项目到微信开发者工具第一步是用HBuilderX新建uni-app项目模板选“默认模板”就行千万不要选复杂模板否则里面自带的一堆示例页面后期要删半天。创建后在manifest.json里配置小程序部分{ mp-weixin: { appid: 你的微信小程序AppID, setting: { urlCheck: false }, usingComponents: true } }这里urlCheck就是“关闭合法域名校验”的开关开发阶段可以设为false方便本地联调。但上线前必须改回true否则开发者工具会一直提示“不在以下合法域名列表中”。开发阶段最省事的方式是HBuilderX菜单栏选“运行 - 运行到小程序模拟器 - 微信开发者工具”。前提是微信开发者工具已经打开并设置了安全设置里的服务端口。这个流程比“发行”快得多因为每次改代码都会自动触发编译微信开发者工具里直接刷新即可。4.2 自定义导航栏与主要页面搭建小程序页面顶部导航栏在不同机型上高度不一样如果直接用默认导航栏返回键、胶囊按钮会挡住自定义按钮。我的做法是在pages.json里给需要定制的页面设置“navigationStyle”: “custom”然后在页面组件里用uni.getSystemInfoSync()获取状态栏高度再动态设置头部padding-top。比如首页公告列表页面布局大概是这样template view classpage view classcustom-nav :style{ paddingTop: statusBarHeight px } text classnav-title班级公告/text /view view classnotice-card v-foritem in notices :keyitem.id clickgoDetail(item.id) view classtitle{{ item.title }}/view view classtime{{ item.created_at }}/view /view /view /template状态栏高度可以用uni.getSystemInfoSync().statusBarHeight获取不同机型的值不一样所以必须在onLoad里动态赋值。另外扫码签到我用的uni.scanCodeuni.scanCode({ success: (res) { const activityId res.result.split(activity_id)[1]; this.signActivity(activityId); } });签到二维码可以做成活动详情页里的一张图片由后端生成包含activity_id参数的二维码。这里的重点是扫描结果里的参数格式要提前约定好我统一用URL参数形式方便以后扩展其他扫码场景。4.3 request封装、token存储与自动登录小程序端最核心的封装就是request。我的utils/request.js长这样const BASE_URL https://api.yourdomain.com; export function request(path, method GET, data {}) { return new Promise((resolve, reject) { const token uni.getStorageSync(token); uni.request({ url: BASE_URL path, method, data, header: { Content-Type: application/json, Authorization: token ? Bearer ${token} : }, success: (res) { if (res.statusCode 401) { // token过期触发重新登录 login().then(() { resolve(request(path, method, data)); }); return; } if (res.data.code 0) { resolve(res.data.data); } else { uni.showToast({ title: res.data.message, icon: none }); reject(res.data); } }, fail: (err) { uni.showToast({ title: 网络异常, icon: none }); reject(err); } }); }); }登录逻辑我放在App.vue的onLaunch里先读本地token如果有就直接进首页如果没有就调uni.login拿code再请求后端login接口换取token并存储。这样用户第一次打开小程序时只需要授权昵称和头像不需要手输账号密码。存储时需要注意uni.setStorageSync不支持复杂对象序列化但普通JSON没问题把用户信息完整存一份方便个人中心直接用。还有小程序的storage默认是同步的如果在请求里需要读取直接getStorageSync很安全。4.4 联调常见问题跨域、域名校验、白屏本地联调阶段后端在电脑上跑小程序在开发者工具里跑网络环境是互通的。但如果你拿真机扫码调试手机和电脑不在同一个WiFi下请求会失败。我一般在开发者工具里开启“不校验合法域名”同时确保后端Flask配置了CORSfrom flask_cors import CORS CORS(app, resources{r/api/*: {origins: *}})不过CORS只解决浏览器环境下的跨域限制微信小程序的网络请求本质上不受浏览器的CORS约束它只校验域名白名单。所以小程序端最常见的问题反而是request的url写成了http://localhost:5000在开发者工具里能跑一到真机就网络失败。这个没有别的办法要么后端绑定局域网IP要么直接把后端代码部署到云服务器用公网域名联调。白屏问题大多是请求失败后页面没有处理异常导致的。比如未登录时去请求详情页接口返回401页面没有捕获错误数据是空的页面自然白屏。建议在每个页面的onLoad里统一加上loading状态请求完成后无论成功失败都关闭loading并且对空的列表显示“暂无数据”。这样即使用户断网也不会直接看到白屏。5. 上线部署与后续扩展5.1 用gunicorn Nginx把Flask项目跑起来本地开发时Flask自带的开发服务器够用但性能很差并发一高就卡。部署到云服务器时我习惯用gunicorn当作WSGI服务器。安装并运行pip install gunicorn gunicorn -w 4 -b 127.0.0.1:5000 app:app如果项目入口是app.py里的app对象就写“app:app”如果用的是工厂函数create_app要改成“app:create_app()”。再用Nginx做反向代理把外部请求转发到5000端口server { listen 80; server_name api.yourdomain.com; location / { proxy_pass http://127.0.0.1:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /uploads/ { alias /你的项目路径/uploads/; } }这里把/uploads/静态目录单独交给Nginx处理既能分担Flask压力也避免出现“静态文件加载不出来”的问题。注意alias路径末尾一定要加/这是Nginx配置里最常见的坑。另外生产环境的合法域名必须是HTTPS不能带端口不能是IP地址。证书配置完成后在微信公众平台的开发设置里把request合法域名加进去这一步很容易被漏掉漏掉的结果就是开发工具一切正常手机一扫码全挂。5.2 高频问题排查速查表项目做久了常见的报错基本都遇到过。我把高频问题整理成了表格方便排查问题可能原因解决办法小程序请求失败合法域名未配置或未关闭校验开发时勾选“不校验合法域名”上线时在mp后台配置request域名接口返回跨域错误Flask未配置CORS安装flask-cors并设置CORS(app)上传图片404静态目录没有映射或权限不足Nginx配置/uploads/目录确认uploads目录有写权限登录报“code无效”code被重复使用确保前端每次uni.login都重新获取code后端只消费一次token过期JWT过期时间太短检查generate_token的exp字段前端做401自动续登录中文文件名上传失败secure_filename过滤中文用uuid重命名文件后保存列表数据为空后端返回结构不是{code,data,message}前后端约定统一JSON结构避免前端解错字段小程序分享没有图onShareAppMessage未配置imageUrl自定义分享标题和图片路径这个速查表在实际售后阶段特别有用因为毕设答辩前夕经常有人遇到一模一样的问题。5.3 这套系统还能怎么扩展班级事务管理系统做到这里已经可以正常交付了但如果你想拿它做更完整的毕设作品还有几个很自然的扩展方向。第一加入消息订阅。微信小程序有订阅消息功能同学报名活动成功后可以给他发送一条“报名成功”的通知。这个功能需要在用户授权后收集一次性订阅消息有一定门槛但对“班级事务提醒”场景非常合适。第二加入数据可视化。班委后台可以加一个统计面板用ECharts画任务完成率、活动参加人数的柱状图或饼图。后端只需要多提供几个统计接口前端用canvas渲染效果很好。第三做Web管理端。现在班委只能在小程序里管理页面受限。如果增加一个Vue或React的PC后台批量导入同学名单、导出Excel表格都会方便很多。后端只需要继续复用同一套API前端用uni-app的H5形态也能快速搭出来。这个扩展方案对毕设来说非常加分相当于一套代码解决了小程序和H5两个终端。第四把任务模块升级成“值日排班”。班级值日生是最常见的高频事务可以做成自动排班表每周轮换同学们在日历视图里看到自己哪天值日。这功能看起来简单但算法上要处理“节假日跳过”“补班调整”等细节非常有磨头。整个项目做完我有一个特别深的体会技术选型真的不需要花里胡哨。Flask加uni-app这套组合非常适合中小型管理类系统写起来快改起来也方便。班级事务管理看起来是个小题目但它把用户权限、业务流、文件上传、前后端联调、小程序发布这些环节全都串起来了做完一遍能打下一个特别扎实的基础。后来我又用同一套架构改过几个内部管理项目每次回来补班委系统的代码都还会发现一些可以优化的细节。如果让我给后来者一句实在话那就是别指望一次写对先跑通最小闭环再一页一页把“能用的功能”变好用。踩坑本身不可怕可怕的是不知道去哪里排查希望这份实战记录能让你少走几趟弯路。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

汽车电子底层软件开发:AUTOSAR与CAN总线实战解析 2026/9/24 23:59:54

汽车电子底层软件开发:AUTOSAR与CAN总线实战解析

1. 这门“汽车电子底层软件开发就业课”到底在教什么?——不是写个LED闪烁就能上岗的很多人看到“汽车电子底层软件开发就业课”这个标题,第一反应是:不就是嵌入式C语言单片机CAN通信?刷几道LeetCode、调通一个STM32 CAN收发例程&…

阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战 2026/9/24 23:59:54

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署 2026/9/24 23:59:54

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

阅读更多 →
AI元人文:从工具使用到思维重构的深度探索 2026/9/24 23:59:54

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

阅读更多 →
《AI Agent 场景应用 - MobileOpenClaw》第5-9节:会话上下文细化处理实战指南 2026/9/24 23:59:47

《AI Agent 场景应用 - MobileOpenClaw》第5-9节:会话上下文细化处理实战指南

文档教程后端 【免费下载链接】CodeGuide :books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总,旨在为大家提供一个清晰详细的学习教程,侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助,请给予支持(关注、…

阅读更多 →
写出来的,和没写的——七个模块,一副骨头 2026/9/24 23:59:47

写出来的,和没写的——七个模块,一副骨头

「合金日记」第 85 篇 「小艾说」第 34 期 幕后弧(换弧开篇) 从「写谁」转向「怎么写」 专栏连载中 前篇:《听漏了,还是听深了——一个 a,一句禅》 模块 骨架 沉默 对位 骨头 没看过前篇也能读 没看过前八十…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞