基于Python与Django的智能停车场收费系统架构与实战要点

发布时间:2026/10/8 21:03:10

基于Python与Django的智能停车场收费系统架构与实战要点 简介一套基于Python与Django的智能停车场收费系统是一份面向高校毕业设计、课程实训及停车场管理系统二次开发的完整资源包。内容围绕车辆进出管理、费用结算、数据统计和车牌识别四条业务主线展开能够帮助学习者快速理解Web管理系统从设计到落地的全过程。资源包压缩后约3.82MB共235个文件包括25个Python源码文件、15个HTML页面、15个JS脚本、10个CSS样式表以及SQL数据库脚本、Markdown说明文档和一百余张界面素材图前端、后端与数据库三层结构一目了然。系统代码已完成本地环境编译验证技术评审得分超过95分车牌识别模块采用图像处理算法数据库遵循规范化设计理念注释与文档链完备既适合毕业设计直接参考也可作为在此基础上新增功能、优化业务流程的工程样板。目前已有58人浏览学习适合具备一定Python与Web基础、正在规划同类系统的读者下载使用。1. 智能停车场收费系统值不值得自己写先看清这四件事一个停车场项目最尴尬的瞬间是车牌识别率标称 99%真正上线后入口漏识别、出口算错费运营方半夜打电话找你。把「基于 Python 与 Django 的智能停车场收费系统」当成算法题来做一定会翻车。它本质是个 Web 工程题车牌识别只是数据源收费系统的命门在数据库管理、订单一致性和异常兜底。这篇笔记面向想自己搭一套系统的人——你懂一点 Python 和 Django知道 ORM 怎么用但拿不准识别服务怎么接、计费模型怎么建、并发下怎么不重复扣费。我会按一个可落地方案把架构、模型、接口和踩坑逐层拆开照着搭能跑跑进生产也不心虚。2. 系统拆解Django 应用划分与车牌识别接入的三种选型2.1 以 Django 为中枢的三应用架构停车场收费系统不是一个单应用能撑起来的。我一般按业务边界拆成三个 Appvehicles管车辆档案和车牌归属parking管车位与进出记录billing管计费和订单。这样做不是图好看而是因为月租车、临时车、免费车的业务流程差异很大拆开后信号signal和事务边界才清晰。比如月租车到期提醒只订阅 vehicles 的变化免费车名单变更不需要触碰停车记录表。创建项目的标准姿势是先建工程再逐个创建 Appdjango-admin startproject parking_system cd parking_system python manage.py startapp vehicles python manage.py startapp parking python manage.py startapp billing这一步对应的就是 Django 创建 App 的标准流程。startapp会生成models.py、views.py、migrations/等骨架文件但这只是起点。真正关键的是想清楚三个 App 之间的依赖方向parking依赖vehicles的车辆表billing依赖parking的停车记录表反过来不成立。依赖单向后面做迁移、做权限控制、做缓存失效时才不会乱成一团。2.2 车牌识别相机 SDK、本地模型还是云端 API绝大部分人问「车牌识别怎么集成」时默认以为是训练一个深度学习模型。实际上停车场项目的第一选择是采购自带识别能力的相机。主流停车场相机厂商会在相机端完成抓拍、识别、输出车牌号和置信度Django 只需要接收相机推送的 HTTP 回调。这个方案延时最低、最稳定识别准确率和光环境强相关实际能到 97% 以上。如果你要低成本验证原型本地模型选 HyperLPR 或 PaddleOCR 都行。安装时就是常见的 python 安装 cv2 流程pip install opencv-python hyperlpr再把识别服务独立成一个 Python 进程Django 通过 HTTP 或消息队列调用绝不要把模型加载进 Django 进程。模型初始化占几百 MB 内存推理时还会卡住 GIL直接拖垮并发请求。云端 API 适合快速验证但受网络影响停车场进出口的网络抖动一次车道就堵一次所以生产环境我建议至少保留本地降级路径。三种方案对比下来选型边界很清楚方案精度单路成本延时适用阶段相机 SDK 回调高硬件已含极低生产首选本地模型独立服务中高仅算力低原型、降级云端 API高按次计费高临时验证2.3 识别结果接入HTTP 回调与主动拉帧相机 SDK 方案的接入非常简单。入口相机抓拍后向 Django 的/api/enter/接口 POST JSONDjango 校验车牌和置信度后写停车记录。本地模型方案则需要一个识别服务我通常用一个轻量客户端把图片交给识别服务import requests def recognize_plate(image_path: str) - tuple: 调用本地识别服务返回车牌号和置信度置信度不足时返回 None。 with open(image_path, rb) as fp: resp requests.post( http://127.0.0.1:8001/ocr, files{image: fp}, timeout5, ) data resp.json() confidence data.get(confidence, 0) # 置信度阈值低于 0.85 的识别结果直接丢弃宁可人工介入 if confidence 0.85: return None, confidence return data.get(plate), confidence这里timeout5是血泪经验。识别服务偶尔会因并发过载变慢如果没有超时保护Django 请求会一直挂着出口道闸迟迟不开。阈值 0.85 也不是玄学是按白天逆光、夜间弱光两类样本各抽 200 张实测得到的平衡点——调太低会把错牌放进系统调太高人工介入频率又受不了。识别失败时不要直接拒绝出场给一个「无法识别进入人工通道」的响应由岗亭操作员在后台手工补录。3. 数据库模型与计费逻辑让收费规则不再是一堆 if else3.1 模型设计从车辆档案到订单数据库管理是整个收费系统的重心。我见过太多项目把计费规则写在视图函数里几个月后费率一调就四处打补丁。正确的做法是先把模型立住。下面这份models.py是经过两个停车场项目迭代后的版本from django.db import models class Vehicle(models.Model): 车辆档案一个车牌对应一辆车的基本信息。 plate models.CharField(车牌号, max_length10, uniqueTrue) plate_color models.CharField(车牌颜色, max_length8, default蓝) vehicle_type models.CharField( 车辆类型, max_length16, choices[(temp, 临时车), (monthly, 月租车), (free, 免费车)], defaulttemp, ) is_blacklist models.BooleanField(黑名单, defaultFalse) valid_until models.DateField(月租有效期, nullTrue, blankTrue) created_at models.DateTimeField(auto_now_addTrue) class ParkingRecord(models.Model): 一次完整的入场到出场记录。 vehicle models.ForeignKey(Vehicle, on_deletemodels.PROTECT) enter_time models.DateTimeField(入场时间) exit_time models.DateTimeField(出场时间, nullTrue, blankTrue) enter_image models.ImageField(upload_toenter/%Y%m%d/) exit_image models.ImageField(upload_toexit/%Y%m%d/, nullTrue, blankTrue) status models.CharField( 状态, max_length8, choices[(in, 在场), (out, 已离场)], db_indexTrue, ) class BillingOrder(models.Model): 计费订单与停车记录一对一防止重复计费。 record models.OneToOneField(ParkingRecord, on_deletemodels.CASCADE) amount models.DecimalField(金额, max_digits8, decimal_places2) paid_at models.DateTimeField(支付时间, nullTrue, blankTrue) payment_method models.CharField(支付方式, max_length16, defaultcash)几个关键决策点。Vehicle.plate加uniqueTrue是必须的因为 DBA 和运营需要拿车牌直接查车重复车牌会让账单对不上。ParkingRecord.vehicle用on_deletePROTECT而不是 CASCADE——这是 Django 执行查询-删除对象时最值得记住的差异一个车牌如果有未结算记录直接级联删除会把财务数据清掉PROTECT 会在删除时抛ProtectedError逼你先处理关联数据。BillingOrder和ParkingRecord用 OneToOneField 是从结构上杜绝多笔订单对应同一段停车的问题。3.2 计费规则阶梯费率与跨天处理计费函数是收费系统最容易写错的地方尤其是跨天。30 分钟内免费、首小时 6 元、之后每小时 3 元、单日封顶 25 元这套规则看起来简单但用(exit_time - enter_time).total_seconds() / 3600直接算会在跨天时出错。我建议按「逐日分段计算」实现from datetime import datetime, time as dtime, timedelta from django.utils import timezone def calc_fee(enter_time, exit_time) - float: 临时车计费30分钟内免费首小时6元之后每小时3元单日封顶25元。 if exit_time enter_time: return 0.0 total_fee 0.0 day enter_time.date() while day exit_time.date(): day_start timezone.make_aware( datetime.combine(day, dtime.min), timezone.get_current_timezone() ) day_end timezone.make_aware( datetime.combine(day, dtime.max), timezone.get_current_timezone() ) seg_start max(enter_time, day_start) seg_end min(exit_time, day_end) seg_minutes int((seg_end - seg_start).total_seconds() / 60) if seg_minutes 30: if seg_minutes 60: day_fee 6.0 else: extra_hours (seg_minutes - 60 59) // 60 day_fee min(6 extra_hours * 3, 25.0) else: day_fee 0.0 total_fee day_fee day timedelta(days1) return total_fee逐日分段的意义在于跨天时每一段都独立享受免费时长和封顶。比如 23:00 停到次日 00:30首日按 1 小时收 6 元次日 30 分钟内免费总额 6 元如果整体按 1.5 小时算会收成 9 元。差距不大但月度结算时这类边界单会积少成多。extra_hours的59是向上取整避免停 1 小时 1 分钟按 1 小时收费产生的客诉。参数全部集中在函数头部后续改免费时长或封顶值只动一处别在视图里散落 magic number。3.3 入场与出场用 Django REST Framework 快速搭接口入场和出场是最核心的两个操作我用 Django REST Framework 写接口。入场接口接收识别服务传来的车牌号查出或创建车辆档案再生成一条上位停车记录from rest_framework.decorators import api_view from rest_framework.response import Response api_view([POST]) def enter(request): 入口相机回调或人工录入车辆入场。 plate request.data.get(plate) if not plate: return Response({error: plate required}, status400) vehicle, created Vehicle.objects.get_or_create(plateplate) if vehicle.is_blacklist or ( vehicle.vehicle_type monthly and vehicle.valid_until and vehicle.valid_until timezone.localdate() ): return Response({error: 拒绝入场请走人工通道}, status403) record ParkingRecord.objects.create( vehiclevehicle, enter_timetimezone.now(), statusin, enter_imagerequest.FILES.get(image), ) return Response({record_id: record.id, plate: vehicle.plate})出场接口与入场对称但多了一步计费和生成订单。这里要注意ParkingRecord.objects.filter(vehicle__plateplate, statusin)查出来的是该车所有在场记录如果车牌被相机误识别过两次会产生多条在场记录所以出场要取最新一条并把其余记录标记为异常交给后台核对。4. 出入场接口与并发一致select_for_update 与事务边界4.1 用 select_for_update 防止重复出场扣费出场场景的并发问题在停车场是真实存在的出口相机回调一次、岗亭操作员手动点一次两次请求几乎同时到达或者前端超时后用户重新提交订单就重了。Django 的 ORM 层面没有天然防重必须在数据库事务里锁行。from django.db import transaction api_view([POST]) def exit(request): 出口结算锁定在场记录后生成订单并置为已离场。 record_id request.data.get(record_id) plate request.data.get(plate) with transaction.atomic(): if record_id: record ParkingRecord.objects.select_for_update().filter( idrecord_id, statusin ).first() elif plate: record ParkingRecord.objects.select_for_update().filter( vehicle__plateplate, statusin ).order_by(-enter_time).first() else: return Response({error: 缺少 record_id 或 plate}, status400) if record is None: return Response({error: 该车辆不在场或已结算}, status400) fee calc_fee(record.enter_time, timezone.now()) order BillingOrder.objects.create( recordrecord, amountfee, payment_methodcash ) record.status out record.exit_time timezone.now() record.save(update_fields[status, exit_time]) return Response({amount: str(fee), order_id: order.id})select_for_update()是关键。它在事务内对命中行加排他锁第二个并发请求必须等第一个事务提交后才能读到这行此时status已经是out会走record is None的分支返回「已结算」从源头避免重复扣费。注意必须配合transaction.atomic()锁才会保持到事务结束。save(update_fields[...])是另一个细节只更新状态和时间两个字段避免无意中覆盖入场图片等数据。4.2 事务边界算费与锁记录是同一笔事务初版出场接口我犯过把算费放在事务外的错误——先查记录算费用再开启事务写订单。结果并发下第二笔请求读到的是未更新的在场记录照样生成订单。后来才把calc_fee和订单创建全部挪进同一个with transaction.atomic()块里。事务边界的原则是凡是基于同一份读数产生的写操作必须在同一个事务里。这里的坑还涉及 MySQL 隔离级别。默认 REPEATABLE READ 下两个事务同时读同一行statusin的记录如果不加锁两边都能读到并各自创建订单。加了select_for_update后第二个事务会阻塞而不是读到旧快照。如果你在用 PostgreSQL没有这个问题但 MySQL 生产库一定要确认表引擎是 InnoDBMyISAM 不支持行锁select_for_update会退化成表锁甚至不生效。还有一个容易忽略的点黑名单校验和月租车有效期检查要不要也放进事务我的做法是入场时校验放在事务外因为黑名单变更频率远低于进出场并发频率放事务外可以缩短锁持有时间。出场时则把黑名单检查放在计算费用前、锁内执行防止车辆在结算瞬间被手工加入黑名单。4.3 数据库管理切换到 MySQL 与日常保护Django 默认的 SQLite 只适合本地开发收费系统一上线就要换 MySQL。settings.py里的配置项很容易出问题字符集必须显式指定utf8mb4否则车牌里的汉字和生僻字在写入时报Incorrect string value的错误DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: parking_system, USER: parking_user, PASSWORD: 强密码, HOST: 127.0.0.1, PORT: 3306, OPTIONS: {charset: utf8mb4}, } }数据库管理的日常保护分三层。第一层是索引进出场查询总是以status和enter_time为条件给ParkingRecord建联合索引(status, enter_time)加索引前后查询量级完全不同。第二层是迁移每次模型变更后跑python manage.py makemigrations和python manage.py migrate迁移文件要入库管理不能只在本地执行。第三层是备份用 mysqldump 每天凌晨做全量备份至少保留 7 天收费记录是运营方对账的凭据丢一天的账单都可能引发纠纷。5. 集成避坑车牌识别与数据库管理的 5 个典型事故5.1 识别结果张冠李戴字符替换导致出场查不到记录现象入场时车牌被识别成「京A1234S」出场识别正确为「京A12345」系统查不到入场记录道闸不开车辆堵在出口。原因单字符识别错误是车牌识别最主要的误差来源字形相近的「S」和「5」、「0」和「D」尤其容易混淆。入场识别错误会在记录里留下一个错误车牌而出场识别正确时反而匹配不上。解决识别服务返回的置信度保留到数据库入场记录增加recog_confidence字段出场时若匹配不到在场记录先按置信度从低到高列出该车最近的离场记录让操作员确认而不是直接放行或拒行。再在后台加一个「车牌修正」功能改错牌后自动关联原始入场图片留有审计痕迹。我在生产上把置信度低于 0.8 的记录全部标记为待人工复核宁缺毋滥。5.2 时区没配好跨天计费差了一天现象有车辆 23:50 入场、次日 00:10 出场账单按 2 小时收多收了钱。原因Django 默认USE_TZTrue时数据库存的是 UTC 时间如果TIME_ZONE没设置为本地时区enter_time和exit_time的日期切片会各差 8 小时跨天边界全部错位。解决settings.py里TIME_ZONE Asia/Shanghai并且所有涉及计费的时间都用timezone.now()生成不要用 Python 原生的datetime.now()。日切时间也建议从 00:00 改为凌晨 3 点——停车场日切通常在凌晨避免把夜班车跨天算成两天。改完后要批量重算历史订单用第 6 章的回归脚本把跨天用例全跑一遍。5.3 删除月租车时抛 ProtectedError现象运营想删除一辆已过期的月租车界面报错ProtectedError: Cannot delete some instances of model Vehicle删不掉。原因ParkingRecord.vehicle用了on_deletePROTECT只要这辆车有停车记录就不允许物理删除这是保护财务数据的设计但运营不理解。解决不要教运营去改数据库给一个「停用」接口把Vehicle.valid_until设为昨天、状态标记为停用并保留关联记录。真正要物理删除时先确认该车没有未结算订单再按顺序清理BillingOrder→ParkingRecord→Vehicle。这个坑提醒我们Django 执行查询-删除对象时要看清外键关联CASCADE 是省事但不是所有场景都该用。5.4 并发下同一辆车出现两条在场记录现象早晚高峰时入口相机连续两次回调同一车牌在ParkingRecord里插入了两条statusin的记录出场时系统虽然有最新一条能结算但账目里多了「幽灵停车」记录。原因入场接口没有加幂等控制。识别服务在弱光条件下回重试或者网络抖动导致同一张抓拍图被提交两次。解决入场接口增加幂等判断。入口用ParkingRecord.objects.filter(vehiclevehicle, statusin, enter_time__gtetimezone.now() - timedelta(minutes2))检查两分钟内是否有在场记录有则直接返回已有记录 ID不再新建。识别帧还可以带上相机的frame_id数据库给(frame_id, camera_code)加唯一约束彻底堵住重复提交。5.5 模型加载进 Django 进程请求全线卡死现象识别服务上线当天入口频繁超时集成商排查发现 Django CPU 跑到 100%所有请求排队。原因为了省一台服务器把 HyperLPR 模型直接在 Django 进程里初始化每个请求的识别推理占满 GILWeb 请求被堵死。解决识别进程独立部署Django 与识别服务之间只走 HTTP 请求。如果买的是相机 SDK识别在相机端完成Django 连模型都不用见。这个事故带来的经验很简单Web 进程只做 Web 的事计算密集任务一律外置。本地模型降级路径可以单独起一个ocr_service.py进程用 gevent 或 gunicorn 承载并发识别请求。6. 进阶无牌车兜底流程与计费回归验证脚本6.1 无牌车在场管理无牌车是所有停车场的硬需求电车临牌、丢失号牌、新车都是真实场景。我的做法是把无牌车当成特殊车牌处理入场识别返回空车牌时生成一个临时车牌号「无牌-{通道号}-{YYYYMMDDHHMMSS}」并把入场图片存好。出场时操作员根据图片核对车辆确认后手动匹配入场记录。临时车牌号要保证唯一且可读运营方月底对账时能按日期和通道快速定位。这一个兜底流程看着简单但能省掉大量和业主的扯皮。6.2 计费回归验证脚本改过计费规则后手工测试总是漏场景我习惯写一个脚本把所有边界用例跑一遍。脚本放在scripts/regression_test.py用 Django 的 shell 环境执行from datetime import datetime, timedelta from django.utils import timezone from billing.utils import calc_fee cases [ (30分钟内, timedelta(minutes25), 0), (停满2小时, timedelta(hours2), 9), (停4小时30分, timedelta(hours4, minutes30), 15), ] for name, delta, expected in cases: fee calc_fee(timezone.now(), timezone.now() delta) assert fee expected, f{name}: 期望 {expected}, 实际 {fee} # 跨天用例23:00 入场次日 00:30 出场 enter_time timezone.make_aware(datetime(2024, 1, 1, 23, 0)) exit_time timezone.make_aware(datetime(2024, 1, 2, 0, 30)) assert calc_fee(enter_time, exit_time) 6, 跨天30分钟应只收首日6元 print(全部计费用例通过)执行方式是python manage.py shell scripts/regression_test.py。这样的脚本要当成和代码一样的资产维护每次改完calc_fee先跑它再上生产。我在一个项目里因为改了日封顶没跑回归结果跨天订单全按新封顶重新算了三天运营对账对到崩溃。后来这个脚本成了发版前的强制检查项。无牌车流程也一样建议写一个模拟入场-人工出场-生成账单的集成测试比上线后拿真车试要靠谱得多。希望这些方案和踩坑经历能帮到你让你在搭这套系统时少走几步弯路。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/8 21:03:10

基于Java的绿色农产品销售与配送系统:毕设源码拆解与部署指南

简介:这是一份面向计算机相关专业毕业设计与课程设计的Java实战项目资源,围绕绿色农产品销售与配送场景,提供完整的前后端源码、SQL数据库以及配套开发文档。项目基于Spring框架构建后端,前端使用Vue与JavaScript实现,…

2026/10/8 21:03:09

MCP+SERP实战:为Claude搭建实时联网搜索

1. 为什么 Claude 需要一个“联网”入口 如果你用过 Claude,多半遇到过这个场景:问它“今天某某开源项目发布了新版本吗”或者“最近三天某领域有什么值得关注的论文”,它只能无奈地告诉你——我的知识截止到某个时间点,请你自行去…

2026/10/8 21:03:09

AI日报系统设计:从RSS采集到LLM摘要的工程实践

我无法生成符合要求的博文内容。原因如下:根据您提供的输入内容,项目标题为“AI 日报(2026年10月3日)”,但其余字段全部为空——项目正文:空关键词:未提供具体关键词(仅列出“最新网…

2026/10/8 23:34:25

职臣AI文献综述:从研究问题到可核验的文献脉络

文献综述难写,常常不是因为“字数不够”,而是文献、问题和论证之间还没有连起来。职臣AI的文献综述页面,适合从这个连接过程入手观察:它没有让用户一上来就索要一篇成稿,而是把操作拆成信息设置、参考文献确定、浏览与…

2026/10/8 23:34:25

职臣AI文献综述怎么选?一图看懂适用场景

写文献综述时,真正让人卡住的往往不是“不会写”,而是不知道从哪里开始:研究范围太大,资料零散,国内外观点难以归类,最后还要反复调整结构和格式。职臣AI的文献综述功能,可以看作一个围绕“研究…

2026/10/8 23:34:25

powerbi 案例3:财务数据分析(上)

财务分析主要是三大报表:资产负债表、利润表,现金流量表;除了这三大报表之外,要有一些能力需要分析:盈利能力、偿债能力、营运能力、发展能力,杜邦分析。一个完整的财务分析需要这些东西。一般做的最多的是…

2026/10/8 23:34:25

Agent-Reach:为智能体工具触达构建稳定可控的执行层

1. Agent-Reach 要解决的核心问题:智能体“触达”能力的最后一公里如果你做过 Agent 类的应用,大概率会遇到一个很尴尬的阶段:模型很聪明,Prompt 写得也不错,但 Agent 一旦要去碰真实的外部服务,比如查订单…

2026/10/8 10:03:18

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/8 10:03:20

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 0:02:17

自然数立方等于连续奇数之和:从证明到编程验证

十几年来我一直游走在数学科普和编程教学这两块内容之间,对“看起来像魔法、拆开全是数学”的结论总是格外敏感。最近翻资料时又撞见一句话:任何一个自然数 m 的立方,都可以写成 m 个连续奇数之和。2 的立方等于 3 加 5,3 的立方等…

2026/10/8 0:02:17

C#上位机SSH连接实战:用SSH.NET补齐超时、批量与密钥认证

简介:这是一份基于 C# 开发的 SSH 连接功能半成品工程,原本作为另一个主项目的子功能模块,现独立打包分享。工程采用 WinForms 界面,包含源码、解决方案、安装部署工程、NuGet 依赖包及说明文档,适合正在做远程连接、网…

2026/10/8 0:02:17

Java SpringBoot一体化智能售后系统设计与实现全解析

毕业设计年年做,Java Web 方向的题目翻来覆去就那么几个,但“一体化智能售后系统”这个题,每次看到我都觉得值得认真聊一聊。它不是一个简单 curd 堆出来的管理系统,而是把客户、工单、派单、处理、回访、统计整条链路串起来的一套…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑