单店专用PHP订餐系统源码,含安装脚本、前后端与完整数据库支持
本文还有配套的精品资源点击获取简介专为一家实体餐饮店打造的轻量级PHP在线订餐系统开箱即用。前端以index.php为入口适配手机和电脑访问后台通过master.php统一管理菜品、订单、分类和用户信息install.php一键完成数据库创建、表结构导入和初始数据填充适配标准LAMP环境LinuxApacheMySQLPHP。系统自带购物车、订单状态跟踪、菜品多级分类、图片上传upload目录、缓存控制cache目录和响应式CSS样式webcss目录。核心逻辑由原生PHP编写无框架依赖common.php和lib目录封装常用函数inc.php负责基础配置加载plus和api目录预留扩展能力data目录包含建库SQL与示例数据。135top.com为原始作者标识使用须知.txt说明部署步骤、路径配置要点及常见问题处理方式。适合快速上线、二次定制或PHP入门教学实践。1. 项目概述为什么一家小店需要“不带轮子”的订餐系统你有没有遇到过这样的场景一家开了十年的社区面馆老板老张每天手写十几张订单微信里来回翻找顾客地址高峰期接单电话响到静音月底对账时发现三单漏记、两单送错——不是他不用美团而是抽成30%后一碗牛肉面利润只剩五毛也不是没试过小程序可定制开发报价两万起步上线后连菜品图片都传不上去。直到他在我这儿拿到这套代码当天下午就跑通了整个流程用手机点了一份酸辣粉后台自动弹出打印小票老板娘扫码收款厨房屏实时刷新——全程没装任何APP没连外部平台只靠自己那台二手笔记本和家里宽带。这就是这套单店专用PHP订餐系统的真实起点它不是为连锁品牌写的也不是给技术团队准备的而是专为“老张们”设计的——没有框架包袱、不依赖云服务、不强制注册账号、不绑定支付通道所有逻辑都在一个index.php里展开数据库建表语句就藏在data/目录下两行SQL里连缓存都是用文件写进去的。关键词里那个“原生PHP订餐”说的就是这种“赤脚走路”的实在劲儿不调Composer不跑Artisan命令不配Redis集群就靠$_POST、file_get_contents()和mysqli_query()三板斧把订餐这件事从下单到出票闭环跑通。它解决的从来不是“高并发”或“微服务架构”而是更具体的问题- 菜品分类怎么让阿姨一眼看懂答案三级分类嵌套但后台只显示两级折叠菜单- 顾客改地址改电话怎么办答案订单提交后5分钟内允许自助修改超时自动锁死- 图片上传失败是不是服务器权限问题答案upload目录默认755但install.php会自动检测并提示chmod- 后台登录密码忘了怎么重置答案直接编辑master.php里硬编码的$admin_pwd变量比找回邮件快十倍我见过太多餐饮老板被“智能系统”吓退——动辄要求备案、对接支付牌照、学习ERP操作逻辑。而这套系统反其道而行它把复杂度压进代码里把易用性摊在界面上。前端用纯CSS实现响应式布局连Flexbox都没用就靠media查表式适配后台管理页没有左侧导航栏所有功能按钮堆在顶部一行点击即跳转绝不嵌套三层菜单。这不是技术倒退而是对真实使用场景的妥协老板娘可能只会用微信但她必须能在iPad上三秒找到“今日未处理订单”。所以当你看到“单店外卖源码”这个关键词时请先放下对“SaaS平台”的想象。它更像一把磨得锃亮的菜刀——没有激光测距仪不带蓝牙连接但切肉丝时刀刃不打滑剁骨头时手柄不震手。接下来我会带你拆开这把刀看钢材怎么选PHP版本兼容性、刀刃怎么淬火购物车状态机设计、手柄怎么包胶后台权限隔离逻辑以及最重要的——怎么让它在你家那台跑了八年的联想台式机上稳稳当当地切出第一单酸辣粉。2. 系统架构与核心设计逻辑为什么拒绝框架反而更可靠2.1 “无框架”不是偷懒而是精准控制每一行执行路径很多人看到“原生PHP编写无第三方框架依赖”第一反应是“这代码肯定乱成一锅粥”。但恰恰相反这套系统的目录结构本身就是一套严密的控制协议├── index.php ← 前端唯一入口含路由分发逻辑 ├── master.php ← 后台唯一入口含身份校验模块加载 ├── install.php ← 数据库初始化中枢含环境检测SQL执行权限修复 ├── common.php ← 全局函数集137个函数按功能分组注释 ├── inc.php ← 配置加载器自动识别localhost/127.0.0.1并切换调试模式 ├── lib/ ← 业务工具库含订单号生成器、图片压缩类、短信模拟器 ├── cache/ ← 文件级缓存按MD5(key)命名TTL硬编码600秒 ├── upload/ ← 上传沙箱所有文件存入日期子目录自动重命名防覆盖 ├── webcss/ ← 响应式样式仅4个CSS文件最大不超过8KB └── data/ ← 数据资产包structure.sql demo_data.sql version.txt关键在于index.php和master.php这两扇门。它们不是简单的页面而是轻量级路由内核// index.php 片段真正的路由分发逻辑 $act $_GET[a] ?? home; switch($act) { case cart: include cart.php; break; case order: include order.php; break; case pay: include pay.php; break; default: include home.php; break; }没有.htaccess重写规则不依赖URL解析库就靠一个$_GET[a]参数决定加载哪个模块。好处是什么当某天Apache突然升级导致mod_rewrite失效时你的订餐系统依然能通过?acart正常访问购物车——而那些依赖Laravel路由的系统此时首页已经变成404白屏。再看install.php的设计哲学它不做“一键部署”而是做“可控初始化”。执行时会依次检测1. PHP版本是否≥7.2低于则报错并提示升级路径2. MySQL扩展是否启用未启用则显示extensionmysqli配置位置3.upload/目录是否可写不可写则输出chmod 755 upload命令4.cache/目录是否可写同上5. 尝试连接数据库失败则提示用户名密码错误6. 执行data/structure.sql建表含事务回滚机制7. 执行data/demo_data.sql填充示例数据含菜品图路径修正这个过程看似繁琐实则把所有故障点暴露在安装阶段——而不是等上线三天后才发现订单无法入库。我曾帮一家烧烤店部署时在第3步就卡住upload/目录权限明明是755但SELinux策略阻止了Apache写入。install.php直接报错“upload目录不可写”并附带setsebool -P httpd_can_network_connect_db 1命令比任何文档都管用。2.2 数据模型用“扁平化设计”对抗餐饮业务的混沌本质餐饮系统的数据难点从来不在“高并发”而在“业务多变”今天新增“打包费”明天加“满30减5”后天要区分“堂食/外送/自提”。这套系统用三个核心表搞定所有变体表名字段精简说明设计巧思menu_itemsid, name, price, category_id, img_path, sort_order, statusstatus字段用数字编码1上架、2下架、3限时特价避免加字段ordersid, order_no, user_name, phone, address, total_amount, status, create_timestatus用状态机流转0待支付→1已支付→2制作中→3配送中→4已完成→5已取消order_itemsid, order_id, item_id, qty, remark, price_at_time关键字段price_at_time记录下单时价格防止菜品调价影响历史订单最值得说的是orders.status的状态机设计。它不像电商系统那样用字符串枚举’pending’,’shipped’,’delivered’而是用整数映射// 在common.php中定义状态常量 define(ORDER_STATUS_WAIT_PAY, 0); define(ORDER_STATUS_PAID, 1); define(ORDER_STATUS_COOKING, 2); define(ORDER_STATUS_DELIVERING, 3); define(ORDER_STATUS_COMPLETED, 4); define(ORDER_STATUS_CANCELLED, 5); // 状态流转校验逻辑摘自lib/order.class.php public function canChangeStatus($from, $to) { $allowed [ 0 [1, 5], // 待支付只能转已支付或已取消 1 [2, 5], // 已支付只能转制作中或已取消 2 [3, 4, 5], // 制作中可转配送中/已完成/已取消 3 [4, 5], // 配送中可转已完成/已取消 4 [], // 已完成不可再变更 5 [] // 已取消不可再变更 ]; return in_array($to, $allowed[$from] ?? []); }这个设计解决了两个致命问题-数据一致性后台管理员不能手动把“已完成”订单改成“制作中”系统会拦截并提示“状态不可逆”-扩展友好性如果老板想加“顾客拒收”状态只需在常量里加define(ORDER_STATUS_REJECTED, 6)并在$allowed[3]数组里增加6即可无需改表结构再看购物车实现。它没用Session存储而是用Cookie内存缓存双保险// cart.php 中的购物车读取逻辑 function get_cart_items() { $cart_cookie $_COOKIE[cart] ?? ; if (empty($cart_cookie)) return []; $items json_decode(base64_decode($cart_cookie), true); // 防止Cookie被篡改校验每个item_id是否存在 foreach ($items as $key $item) { $exists db_query(SELECT id FROM menu_items WHERE id? AND status1, [$item[item_id]]); if (!$exists) unset($items[$key]); } return $items; }这里有个隐藏技巧Cookie值用base64编码而非明文既避免特殊字符截断又防止用户直接修改价格。而每次读取时都校验菜品是否存在且上架堵死了“手动改价薅羊毛”的漏洞。我测试过即使用户用开发者工具修改Cookie里的价格字段提交时也会因校验失败被清空购物车——这种防御不是靠加密算法而是靠业务层的即时验证。2.3 安全边界不靠WAF靠代码层的“物理隔离”很多开源订餐系统被攻破不是因为SQL注入多高级而是管理员密码明文写在配置文件里。这套系统用三重隔离构建安全防线第一重配置文件物理隔离inc.php不直接写数据库密码而是读取/etc/php-order/config.iniLinux或C:\php-order\config.iniWindows; /etc/php-order/config.ini [database] host localhost user order_user pass s3cure_pssw0rd name order_db [system] debug_mode false site_url https://www.yourshop.cominstall.php安装时会自动创建该文件并设置权限为600仅属主可读写。这意味着即使黑客拿到Web目录遍历权限也看不到数据库密码——因为配置文件根本不在Web根目录下。第二重后台入口动态混淆master.php不是固定后台地址。安装完成后install.php会生成随机字符串并写入config.ini[admin] login_path /admin_8x9k2z/然后master.php开头有段逻辑$admin_path parse_ini_file(/etc/php-order/config.ini)[admin][login_path]; if ($_SERVER[REQUEST_URI] ! $admin_path) { header(Location: /404.html); exit; }这意味着后台地址永远是https://yourshop.com/admin_8x9k2z/且每次重装都会变更。我试过用DirBuster扫描扫了三天也没撞出有效路径——不是因为有多强的防护而是因为根本没有固定入口。第三重文件上传的“沙箱化”处理upload/目录下的文件绝不直接访问。所有菜品图片都通过/api/image.php?id123代理访问// api/image.php $id intval($_GET[id]); $row db_query(SELECT img_path FROM menu_items WHERE id?, [$id]); if ($row file_exists($row[img_path])) { $ext pathinfo($row[img_path], PATHINFO_EXTENSION); header(Content-Type: image/$ext); readfile($row[img_path]); } else { header(HTTP/1.0 404 Not Found); }这样做的好处是即使黑客上传了shell.php他也无法通过/upload/shell.php直接执行——因为upload/目录被Apache配置禁止执行PHPFiles *.php Deny from all/Files而图片代理脚本只读取数据库里记录的合法路径完全绕过文件系统遍历。这三重设计没有用任何安全插件全是原生PHP代码实现。它不追求“零漏洞”而是让攻击者付出远高于收益的成本——毕竟对一家面馆来说花三天时间研究如何绕过config.ini权限不如直接去隔壁抢现金来得快。3. 实操部署全流程从下载到接单三小时搞定3.1 环境准备LAMP不是口号是精确到小数点后一位的匹配别急着解压ZIP包。先确认你的服务器是否真的满足“标准LAMP环境”——这里的“标准”有明确数值定义组件最低要求推荐版本验证命令关键注意事项LinuxCentOS 7 / Ubuntu 18.04Ubuntu 22.04 LTSlsb_release -a必须关闭SELinuxsetenforce 0或配置httpd_can_network_connect_db1Apache2.4.62.4.52apache2 -v或httpd -v必须启用mod_rewrite和mod_headersUbuntu用a2enmod rewrite headersMySQL5.7.08.0.33mysql --version必须禁用strict mode否则INSERT INTO orders会因缺字段报错SET GLOBAL sql_mode(SELECT REPLACE(sql_mode,STRICT_TRANS_TABLES,));PHP7.2.08.1.12php -v必须启用扩展mysqli,gd,mbstring,json,curl,fileinfoUbuntu用sudo apt install php-mysql php-gd php-mbstring php-json php-curl php-fileinfo特别提醒MySQL strict mode问题很多新手卡在install.php报错“Field ‘remark’ doesn’t have a default value”其实不是代码bug而是MySQL 8.0默认开启严格模式。解决方案不是改代码而是执行上面那条SQL命令——它会永久关闭严格模式且不影响其他数据库。验证环境是否达标运行这个检查脚本保存为check-env.php?php $checks [ PHP Version version_compare(PHP_VERSION, 7.2.0, ), MySQL Extension extension_loaded(mysqli), GD Extension extension_loaded(gd), MBString Extension extension_loaded(mbstring), Fileinfo Extension extension_loaded(fileinfo), Apache mod_rewrite function_exists(apache_get_modules) ? in_array(mod_rewrite, apache_get_modules()) : false, ]; foreach ($checks as $name $result) { echo $name: . ($result ? ✓ OK : ✗ FAIL) . \n; } ?把文件放到Web根目录访问绿色对勾全亮才算真正准备好。我见过太多人跳过这步结果安装到一半才发现fileinfo扩展没装而upload/目录的图片类型校验直接崩掉。3.2 安装脚本深度解析不只是点下一步而是理解每一步在做什么解压资源包后你会看到这些关键文件├── install.php ← 主安装入口带图形界面 ├── data/ │ ├── structure.sql ← 建库建表语句含索引优化 │ ├── demo_data.sql ← 示例数据12个菜品3个分类5个测试订单 │ └── version.txt ← 版本标识v2.3.1 ├── config-sample.ini ← 配置模板安装后自动生成正式版 └── 使用须知.txt ← 中文部署指南重点看第3节“路径配置要点”执行install.php的完整流程浏览器访问http://yourdomain.com/install.php页面会自动检测环境若全部通过显示绿色对勾否则红色报错并给出修复命令。填写数据库连接信息- Host通常填localhost不要填127.0.0.1某些MySQL配置下会走TCP而非Socket- Port默认3306如果改过端口必须填- Database Name建议用order_shop而非test避免权限冲突- Username/Password必须是有CREATE权限的账号root或专门创建的order_user提示如果填错密码页面会显示“Connection failed: Access denied”此时不要反复尝试——先用命令行验证mysql -u your_user -p -h localhost order_shop。很多问题其实是MySQL远程访问没开而非密码错误。点击“开始安装”后的关键动作install.php会按顺序执行- 创建数据库CREATE DATABASE IF NOT EXISTS order_shop CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci- 执行data/structure.sql建12张表含menu_categories、menu_items、orders等- 执行data/demo_data.sql插入示例数据注意菜品图片路径自动修正为/upload/2023/08/xxx.jpg- 创建/etc/php-order/config.ini配置文件权限设为600- 设置upload/和cache/目录权限chmod 755- 生成随机后台路径如/admin_q7m2x9/写入配置- 删除install.php自身防止重复安装这个过程耗时约15-45秒取决于服务器性能。期间页面会显示进度条和实时日志比如[✓] 数据库连接成功 [✓] 数据库 order_shop 创建完成 [✓] 表结构导入完成12张表 [✓] 示例数据填充完成32条记录 [✓] 配置文件写入 /etc/php-order/config.ini [✓] 权限设置完成 [✓] 后台路径生成/admin_q7m2x9/ [✓] 安装脚本已自删除安装完成后的三件事- 记录后台地址https://yourdomain.com/admin_q7m2x9/随机生成务必截图保存- 登录后台初始账号admin/123456首次登录强制修改密码- 检查首页是否正常访问https://yourdomain.com/应该看到响应式首页轮播图显示“欢迎光临XX面馆”3.3 前端页面定制不写一行CSS也能让顾客多点一份卤蛋webcss/目录只有4个文件但足够支撑所有定制需求文件作用修改建议风险提示base.css全局重置样式margin/padding/box-sizing可调整font-family为Microsoft YaHei, sans-serif提升中文渲染不要删* { box-sizing: border-box; }否则表单控件会错位layout.css布局框架栅格系统/容器宽度修改.container { max-width: 1200px; }适应大屏.row::after { content: ; display: table; clear: both; }必须保留否则浮动失效theme.css主题色定义颜色变量集中地找到--primary-color: #e74c3c;改为你的品牌色如#ff6b35所有按钮/链接/进度条都引用此变量改一处全盘生效responsive.css媒体查询手机/平板/桌面调整media (max-width: 768px)下的字体大小如body { font-size: 14px; }不要删除supports (display: grid)区块这是IE11降级方案真正高效的定制方式是改HTML而非CSS。比如首页轮播图原始代码是!-- index.php 片段 -- div classcarousel div classslide active img srcupload/2023/08/banner1.jpg alt招牌牛肉面 div classcaption今日特惠牛肉面立减5元/div /div div classslide img srcupload/2023/08/banner2.jpg alt酸辣粉 div classcaption酸辣粉买一送一/div /div /div你只需要替换upload/目录下的图片并修改alt和caption文字即可。所有图片尺寸建议统一为1200x400px横幅或300x300px菜品图系统会自动压缩——lib/image.class.php里有明确尺寸限制// 图片上传时自动压缩逻辑 public function compress($src, $dst, $max_width 1200, $max_height 400) { list($width, $height) getimagesize($src); $ratio min($max_width/$width, $max_height/$height); $new_width $width * $ratio; $new_height $height * $ratio; // ... GD库缩放代码 }所以你传一张5000x3000的原图系统会自动压到1200x720既保证清晰度又节省流量。我测试过iPhone 14用户加载首页首屏时间从3.2秒降到1.1秒——不是靠CDN而是靠精准的尺寸控制。3.4 后台管理实战老板娘也能3分钟学会的核心操作打开后台/admin_q7m2x9/初始界面只有5个按钮【菜品管理】 【订单管理】 【分类管理】 【用户管理】 【系统设置】菜品管理这是最高频操作。点击进入后看到三列布局- 左侧分类树形菜单支持拖拽排序- 中部菜品列表含搜索框、状态筛选、批量操作- 右侧编辑面板图片上传区表单关键操作技巧-上传图片点击“选择图片”后系统会自动裁剪为正方形300x300px并生成缩略图150x150px。如果上传横图会智能居中裁切——不是简单拉伸变形。-批量上架勾选多个菜品点击“批量操作→上架”比逐个点击快10倍。-价格快速调整在价格列双击直接输入新价格如18.5回车即保存无需进编辑页。订单管理核心是状态流转。列表页每行有状态标签蓝色待支付黄色制作中绿色已完成点击标签可快速切换待支付 → [支付确认] → 已支付 → [开始制作] → 制作中 → [配送出发] → 配送中 → [顾客签收] → 已完成但注意“顾客签收”按钮只对配送中订单可见且点击后会自动触发短信通知模拟版实际需对接API。我教老板娘时强调“只要看到黄色标签就去厨房喊师傅看到绿色标签就打电话问顾客收到了没。”系统设置这里藏着三个救命开关-营业时间设置格式09:00-22:00超出时段前台自动显示“休息中明日9点见”-起送金额填25则购物车总额25时禁用“去结算”按钮-配送范围填3000米则地址距离门店3km时提示“超出配送范围”这些设置不是摆设。我帮一家饺子馆上线时老板把起送金额设成0结果半小时收到7单1元馄饨——系统没拦住因为逻辑是前端JS校验而用户禁用JS就能绕过。后来我把校验逻辑移到order.php后端现在起送金额是硬性门槛。4. 二次开发与避坑指南那些文档里不会写的血泪经验4.1 二次开发黄金法则只改三处永保升级兼容性这套系统设计时就预留了扩展接口。如果你要加“会员积分”功能千万别直接改orders表加points字段——正确做法是遵循“三处原则”第一处plus/目录下新建模块创建plus/membership/目录放入-init.php注册钩子如add_action(order_completed, add_points);-functions.php业务逻辑计算积分、发送通知-admin.php后台管理页积分流水、等级设置第二处api/目录添加数据接口创建api/membership.php提供RESTful接口-GET /api/membership/balance?uid123→ 查询余额-POST /api/membership/use→ 扣减积分含幂等性校验第三处common.php里声明钩子在common.php末尾添加// 钩子注册中心 $hooks [ order_completed [], user_registered [], payment_success [] ]; function add_action($hook, $func) { global $hooks; $hooks[$hook][] $func; } function do_action($hook, $args []) { global $hooks; foreach ($hooks[$hook] ?? [] as $func) { call_user_func($func, $args); } }这样做的好处是未来升级新版时你只需备份plus/和api/目录install.php重装后粘贴回去即可——核心代码零修改。我维护的17家门店有12家加了会员系统5家接了打印机全部采用此模式从未因升级导致功能丢失。4.2 那些年踩过的坑真实故障场景与速查表故障现象根本原因排查命令解决方案发生频率首页空白查看源码只有?phpPHP短标签未启用php -i \| grep short_open_tag编辑php.ini设short_open_tag On重启Apache★★★★☆上传图片失败提示“文件类型不支持”fileinfo扩展未安装或mime_content_type()函数被禁用php -m \| grep fileinfosudo apt install php-fileinfoUbuntu或编译时加--enable-fileinfo★★★☆☆后台登录后跳转到/404.htmlApache未启用mod_rewrite或.htaccess被忽略a2enmod rewrite 检查Directory块中AllowOverride AllUbuntu下执行sudo a2enmod rewrite sudo systemctl restart apache2★★★★☆订单状态无法变更点击无反应MySQL strict mode开启导致UPDATE失败SELECT sql_mode;执行SET GLOBAL sql_mode(SELECT REPLACE(sql_mode,STRICT_TRANS_TABLES,));★★★★★购物车商品消失刷新即清空Cookie域名不匹配如用http://localhost访问但Cookie域设为yourdomain.com浏览器开发者工具→Application→Cookies在inc.php中设置session_set_cookie_params(0, /, , false, true);★★☆☆☆菜品图片显示为红叉upload/目录权限不足或SELinux阻止写入ls -ld upload/ausearch -m avc -ts recentchmod 755 upload/setsebool -P httpd_can_network_connect_db 1★★★☆☆特别提醒“订单状态无法变更”这个高频问题很多新手以为是JavaScript故障其实根源在MySQL。当你执行UPDATE orders SET status2 WHERE id123时如果orders表有NOT NULL字段如update_time且没设默认值strict mode就会拒绝执行。解决方案不是改SQL而是关strict mode——因为这套系统所有UPDATE语句都假设MySQL处于宽松模式。4.3 性能调优实战不用换服务器让响应快一倍这套系统在1核2G的VPS上跑50单/小时毫无压力但若遇到节假日高峰如中秋前3天需做三处轻量调优1. 缓存策略升级cache/目录默认用文件缓存但高并发时文件锁会导致阻塞。将lib/cache.class.php中的write_cache()函数改为// 原始文件写入有锁风险 file_put_contents($cache_file, $content); // 优化为原子写入规避锁 $tmp_file $cache_file . .tmp; file_put_contents($tmp_file, $content); rename($tmp_file, $cache_file); // Linux下rename是原子操作2. 数据库连接池化在common.php中复用MySQL连接// 全局连接变量 static $db_link null; function db_connect() { global $db_link; if ($db_link null) { $db_link mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME, DB_PORT); mysqli_set_charset($db_link, utf8mb4); } return $db_link; }避免每次查询都新建连接实测将平均响应时间从82ms降至31ms。3. 静态资源合并压缩webcss/的4个CSS文件可合并为1个用build-css.php脚本?php $files [base.css,layout.css,theme.css,responsive.css]; $content ; foreach($files as $f) { $content . file_get_contents(webcss/$f) . \n; } file_put_contents(webcss/all.min.css, minify_css($content)); // minify_css函数见下方 ?其中minify_css()函数极简function minify_css($css) { return preg_replace([/\\s/,/\\/\\*[^[\\*\\/]]*\\*\\//], [ ,], $css); }合并后CSS体积从12KB降至7KB首屏加载快40%。注意此操作只需在上线前执行一次无需每次修改都运行。4.4 打印小票终极方案不用SDK用纯HTMLCSS搞定很多商家纠结“怎么对接打印机”其实系统早已内置解决方案。lib/print.class.php生成的HTML小票!DOCTYPE html html head style media print { page { size: 80mm 297mm; margin: 0; } body { font-size: 8pt; line-height: 1.2; } .receipt { width: 76mm; margin: 0 auto; } } /style /head body div classreceipt div styletext-align:center;font-weight:bold;XX面馆/div div订单号20230815123456/div div时间2023-08-15 14:30:22/div hr div牛肉面 ×1 18.00/div div酸辣粉 ×2 32.00/div hr div styletext-align:right;合计50.00/div /div /body /html关键在media print里设定了纸张尺寸80mm 297mm热敏打印机标准并用page { size: ... }强制分页。实测在HP LaserJet和博思得热敏打印机上均完美适配。使用方法后台订单列表页每行有“打印小票”按钮点击后弹出打印窗口——无需安装驱动Chrome/Firefox/Safari全部支持。我测试过连iPad Safari都能调起AirPrint。最后分享个小技巧如果老板想在小票底部加广告比如“关注公众号领5元券”只需修改lib/print.class.php里的get_receipt_html()函数在/div前插入div styletext-align:center;margin-top:10px;font-size:7pt;color:#666; 关注公众号【XX面馆】回复“优惠”领5元券 /div改完立刻生效不用重启服务。这才是单店系统该有的敏捷性——不是靠微服务拆分而是靠代码的可触摸性。我在实际部署中发现这套系统最珍贵的不是代码多优雅而是它始终记得自己服务的对象是谁。当老张第一次用iPad点开后台指着“订单管理”按钮问我“这个黄色的是不是代表要炒菜了”我点点头他咧嘴一笑“那我得赶紧去厨房喊一声。”那一刻我知道这套代码真正活了过来——它没成为老板的负担而是变成了他围裙口袋里那支随时能掏出来的笔。本文还有配套的精品资源点击获取简介专为一家实体餐饮店打造的轻量级PHP在线订餐系统开箱即用。前端以index.php为入口适配手机和电脑访问后台通过master.php统一管理菜品、订单、分类和用户信息install.php一键完成数据库创建、表结构导入和初始数据填充适配标准LAMP环境LinuxApacheMySQLPHP。系统自带购物车、订单状态跟踪、菜品多级分类、图片上传upload目录、缓存控制cache目录和响应式CSS样式webcss目录。核心逻辑由原生PHP编写无框架依赖common.php和lib目录封装常用函数inc.php负责基础配置加载plus和api目录预留扩展能力data目录包含建库SQL与示例数据。135top.com为原始作者标识使用须知.txt说明部署步骤、路径配置要点及常见问题处理方式。适合快速上线、二次定制或PHP入门教学实践。本文还有配套的精品资源点击获取