1. 项目背景与需求分析
中医药行业作为传统医疗体系的重要组成部分,近年来随着互联网+医疗的快速发展,线上中医药商城呈现出爆发式增长。这类商城与传统电商平台相比具有显著差异:
- 商品属性复杂:中药材涉及产地、年份、炮制工艺等多维度属性
- 法规要求严格:需符合药品管理相关法规,如处方药销售限制
- 专业内容需求:需要配套中医知识库和用药指导
- 客户群体特殊:既有专业医疗机构采购,也有普通消费者
在这样的背景下,我们选择了PHP领域两大主流框架ThinkPHP和Laravel来实现中医药商城销售管理系统。这两个框架各有特点:
ThinkPHP(6.0版本)优势:
- 中文文档完善,国内开发者社区活跃
- 内置丰富的中国本土化功能(如支付接口、短信服务等)
- MVC架构清晰,适合快速开发业务系统
- 对传统PHP开发模式兼容性好
Laravel(9.x版本)优势:
- 现代化开发理念(依赖注入、服务容器等)
- 强大的ORM(Eloquent)和数据库迁移工具
- 完善的队列系统和任务调度
- 丰富的扩展包生态系统
实际选型中发现:中小型项目团队更倾向ThinkPHP的快速上手,而有复杂业务需求的大型项目则偏好Laravel的扩展性。我们最终决定采用双框架并行开发模式,核心业务用Laravel实现,前台展示层用ThinkPHP构建。
2. 系统架构设计
2.1 整体技术架构
系统采用前后端分离设计,后端提供RESTful API,前端使用Vue.js构建管理后台和微信小程序端。核心架构如下:
[客户端层] ├── 微信小程序(消费者端) ├── PC管理后台(运营端) └── 商家管理后台 [API网关层] ├── 身份认证 ├── 请求路由 └── 限流防护 [业务服务层] ├── 商品服务(Laravel) ├── 订单服务(Laravel) ├── 支付服务(ThinkPHP) └── 会员服务(ThinkPHP) [数据层] ├── MySQL主从集群 ├── Redis缓存 └── Elasticsearch搜索2.2 数据库设计要点
针对中医药商品特性,我们设计了扩展性强的ER模型:
// 药材核心表结构示例(Laravel迁移文件) Schema::create('herbs', function (Blueprint $table) { $table->id(); $table->string('name')->comment('药材名称'); $table->string('pinyin')->comment('拼音名')->index(); $table->foreignId('category_id')->constrained(); $table->string('origin')->comment('产地'); $table->string('harvest_year')->comment('采收年份'); $table->decimal('price', 10, 2)->comment('单价(元/克)'); $table->json('properties')->comment('扩展属性'); $table->timestamps(); }); // 处方关联表 Schema::create('prescription_items', function (Blueprint $table) { $table->foreignId('prescription_id')->constrained(); $table->foreignId('herb_id')->constrained(); $table->decimal('dosage')->comment('用量(克)'); $table->string('processing')->comment('炮制要求'); });2.3 混合框架集成方案
双框架协同工作的关键技术点:
统一认证方案:
- 采用JWT标准,两个框架共用签名密钥
- 用户数据存储在中央Redis,避免重复登录
数据交互方式:
// ThinkPHP调用Laravel服务示例 public function getHerbDetail($id) { $client = new \GuzzleHttp\Client(); $response = $client->get('http://laravel-service/api/herbs/'.$id, [ 'headers' => ['Authorization' => 'Bearer '.session('token')] ]); return json_decode($response->getBody(), true); }任务队列整合:
- Laravel队列处理耗时任务(如生成报表)
- ThinkPHP通过Redis发布任务消息
3. 核心功能实现
3.1 智能药材搜索
结合Elasticsearch实现多维度搜索:
// Laravel中的搜索服务 class HerbSearchService { public function search($params) { return Herb::search($params['keyword']) ->where('category_id', $params['category_id']) ->whereBetween('price', [$params['min_price'], $params['max_price']]) ->orderBy('_score', 'desc') ->paginate(15); } }前端实现搜索建议组件:
// Vue组件示例 <template> <div class="search-box"> <input v-model="keyword" @input="fetchSuggestions"/> <ul v-show="suggestions.length"> <li v-for="item in suggestions" @click="selectSuggestion(item)"> {{ item.name }} <small>{{ item.pinyin }}</small> </li> </ul> </div> </template>3.2 处方配伍禁忌检查
基于药典数据实现实时校验:
// ThinkPHP中的禁忌检查服务 class CompatibilityCheck { public function check($herbIds) { $incompatible = Db::name('herb_incompatible') ->where('herb_a', 'in', $herbIds) ->where('herb_b', 'in', $herbIds) ->select(); if (!empty($incompatible)) { throw new \Exception('存在配伍禁忌:'. implode(',', array_column($incompatible, 'reason'))); } } }3.3 订单处理流水线
Laravel队列系统的典型应用:
// 订单处理任务类 class ProcessOrder implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public function handle() { // 1. 库存预扣减 $this->reserveStock(); // 2. 支付超时检查 if ($this->order->isExpired()) { $this->release(30); // 30秒后重试 return; } // 3. 物流单生成 $this->createShipping(); // 4. 电子处方审核(如需) if ($this->order->hasPrescription()) { $this->dispatch(new AuditPrescription($this->order)); } } }4. 性能优化实践
4.1 缓存策略设计
中医药商品数据特点:
- 基础信息变化频率低
- 价格和库存实时性要求高
- 关联数据复杂(如功效、禁忌等)
对应的缓存方案:
// ThinkPHP中的缓存封装 class HerbCache { const TTL = 86400; // 24小时 public static function get($id) { $key = "herb:{$id}"; $data = Cache::get($key); if (!$data) { $data = Db::name('herb') ->with(['category','properties']) ->find($id); Cache::set($key, $data, self::TTL); } // 实时数据覆盖 $data['stock'] = Redis::hget('herb_stock', $id); $data['price'] = Redis::hget('herb_price', $id); return $data; } }4.2 高并发订单处理
秒杀场景下的解决方案:
库存预热:
// Laravel命令预处理库存 Artisan::command('stock:preheat', function () { $herbs = Herb::where('is_hot', true)->get(); $herbs->each(function ($herb) { Redis::set("stock_{$herb->id}", $herb->stock); }); });Redis原子操作:
// 扣减库存Lua脚本 $script = <<<LUA local stock = tonumber(redis.call('GET', KEYS[1])) if stock >= tonumber(ARGV[1]) then return redis.call('DECRBY', KEYS[1], ARGV[1]) else return -1 end LUA; Redis::eval($script, 1, "stock_123", 1);订单异步处理:
// 使用Laravel Horizon管理队列 'order' => [ 'connection' => 'redis', 'queue' => ['order_process'], 'balance' => 'auto', 'processes' => 10, 'tries' => 3 ]
5. 安全防护措施
5.1 处方药销售合规
实现要点:
- 医生资质验证(对接卫健委API)
- 处方图片OCR识别
- 审核流程日志
// ThinkPHP中的审核服务 class PrescriptionAudit { public function submit($orderId) { $prescription = OrderPrescription::where('order_id', $orderId)->find(); // 1. 基础校验 if (empty($prescription->doctor_license)) { throw new \Exception('缺少医师执业证书'); } // 2. 调用OCR服务 $ocr = new OcrService(); $result = $ocr->analyze($prescription->image_url); // 3. 人工审核队列 if ($this->needManualCheck($result)) { Dispatch::queue('audit')->send(new ManualAuditJob($prescription)); } // 4. 更新状态 $prescription->status = 'processing'; $prescription->save(); } }5.2 支付安全方案
双框架下的统一支付处理:
// 支付网关抽象层 interface PaymentGateway { public function createOrder($amount, $metadata); public function verifyNotification($data); } // 微信支付实现(ThinkPHP) class WechatPayment implements PaymentGateway { public function createOrder($amount, $metadata) { $app = Factory::payment(config('wechat')); $result = $app->order->unify([ 'body' => $metadata['title'], 'out_trade_no' => $metadata['sn'], 'total_fee' => $amount, 'notify_url' => url('/pay/notify') ]); if ($result['return_code'] === 'FAIL') { throw new \Exception($result['return_msg']); } return $result; } }6. 部署与运维实践
6.1 混合环境部署方案
服务器架构:
- Nginx作为前端代理
- PHP-FPM运行双框架
- 服务发现通过Consul实现
Nginx关键配置:
# ThinkPHP伪静态规则 location / { if (!-e $request_filename) { rewrite ^/(.*)$ /index.php/$1 last; } } # Laravel路由处理 location /api/ { try_files $uri $uri/ /index.php?$query_string; } # 静态资源缓存 location ~* \.(js|css|png|jpg)$ { expires 30d; add_header Cache-Control "public"; }6.2 监控体系建设
核心监控指标:
- 药材搜索响应时间(Elasticsearch性能)
- 订单创建成功率(事务处理能力)
- 支付回调延迟(第三方接口稳定性)
使用Prometheus+Granafa实现:
# Laravel暴露的指标示例 - name: order_created_total type: counter help: "Total number of created orders" labels: ["status"] - name: api_response_time type: histogram help: "API response time in milliseconds" buckets: [50, 100, 200, 500, 1000]7. 开发经验总结
在实际开发中,我们积累了几个关键经验:
框架选型不是非此即彼:
- 简单CRUD用ThinkPHP开发效率更高
- 复杂业务逻辑用Laravel更易维护
- 通过服务拆分可以实现优势互补
中医药数据特殊性处理:
// 药材别名搜索实现 public function searchByAlias($name) { return Herb::where(function ($query) use ($name) { $query->where('name', 'like', "%{$name}%") ->orWhereHas('aliases', function ($q) use ($name) { $q->where('name', 'like', "%{$name}%"); }); })->get(); }性能优化平衡点:
- 药材基础信息缓存24小时
- 价格库存信息实时更新
- 搜索服务单独部署ES集群
合规性设计要点:
- 处方审核日志保留5年
- 敏感操作二次验证
- 数据修改留有审计痕迹
这个项目让我们深刻体会到,传统行业与互联网技术的结合既充满挑战也蕴含巨大价值。中医药电商系统不仅需要技术实现,更需要深入理解行业特性,在系统设计中体现专业性和安全性。