数据库: - db/schema_phase1.sql 16 张业务表(类目/服务/地址/师傅/订单/流水/取证/报价/评价/券/钱包/提现/结算/消息) - db/seed_phase1.sql 15 类目 + 32 服务项目 + 新人券(幂等) 后端 API (application/api/controller): - Base/Auth/Home/Address/Order/Master/Review - app/common/library/OrderStatus 11 状态机 + 流转矩阵 - application/api/common.php PHP 8.5 兼容垫片(E_DEPRECATED 不再升级为异常) 测试: - tests/e2e_flow.js 用户下单→支付→师傅抢单→履约→验收→结算→评价 全链路 65 项断言 - 含异常用例:越权/重复操作/非法状态流转/2h 未联系自动回流
156 行
4.6 KiB
PHP
156 行
4.6 KiB
PHP
<?php
|
||
|
||
namespace app\api\controller;
|
||
|
||
use app\common\controller\Api;
|
||
use app\common\library\OrderStatus;
|
||
use think\Db;
|
||
|
||
/**
|
||
* 业务接口基类
|
||
* 统一处理:登录用户注入 / 师傅档案 / 订单归属校验 / 状态流转 / 通知
|
||
*/
|
||
class Base extends Api
|
||
{
|
||
protected $noNeedLogin = [];
|
||
protected $noNeedRight = '*';
|
||
|
||
/** @var mixed 当前登录用户 */
|
||
protected $user = null;
|
||
|
||
/** @var array|false|null 师傅档案:null未查询 / false未入驻 / array已入驻 */
|
||
protected $master = null;
|
||
|
||
protected function _initialize()
|
||
{
|
||
parent::_initialize();
|
||
$this->user = $this->auth->getUser();
|
||
}
|
||
|
||
/**
|
||
* 当前用户ID
|
||
*/
|
||
protected function uid()
|
||
{
|
||
return (int)$this->auth->id;
|
||
}
|
||
|
||
/**
|
||
* 师傅档案
|
||
*/
|
||
protected function masterInfo($reload = false)
|
||
{
|
||
if ($this->master === null || $reload) {
|
||
$row = Db::name('master')->where('user_id', $this->uid())->find();
|
||
$this->master = $row ? $row : false;
|
||
}
|
||
return $this->master;
|
||
}
|
||
|
||
/**
|
||
* 要求是已通过审核的师傅
|
||
*/
|
||
protected function requireMaster()
|
||
{
|
||
$master = $this->masterInfo();
|
||
if (!$master) {
|
||
$this->error('请先完成师傅入驻', ['need_apply' => 1], 2001);
|
||
}
|
||
if ($master['verify_status'] === 'pending') {
|
||
$this->error('师傅资质审核中,请耐心等待', ['verify_status' => 'pending'], 2002);
|
||
}
|
||
if ($master['verify_status'] === 'reject') {
|
||
$this->error('资质未通过:' . $master['audit_msg'], ['verify_status' => 'reject'], 2003);
|
||
}
|
||
return $master;
|
||
}
|
||
|
||
/**
|
||
* 取本人订单(越权拦截)
|
||
* @param int $orderId
|
||
* @param string $side user|master
|
||
*/
|
||
protected function ownOrder($orderId, $side = 'user')
|
||
{
|
||
$orderId = (int)$orderId;
|
||
if ($orderId <= 0) {
|
||
$this->error('订单参数错误');
|
||
}
|
||
$order = Db::name('order')->where('id', $orderId)->find();
|
||
if (!$order) {
|
||
$this->error('订单不存在');
|
||
}
|
||
if ($side === 'user' && (int)$order['user_id'] !== $this->uid()) {
|
||
$this->error('无权操作该订单', null, 403);
|
||
}
|
||
if ($side === 'master') {
|
||
$master = $this->requireMaster();
|
||
if ((int)$order['master_id'] !== (int)$master['id']) {
|
||
$this->error('无权操作该订单', null, 403);
|
||
}
|
||
}
|
||
return $order;
|
||
}
|
||
|
||
/**
|
||
* 订单状态流转:校验 → 更新 → 写流水
|
||
*/
|
||
protected function transit(array $order, $to, $remark = '', $extra = [], $operatorType = 'system', $operatorId = 0)
|
||
{
|
||
$from = (int)$order['status'];
|
||
if (!OrderStatus::can($from, $to)) {
|
||
$this->error('订单状态「' . OrderStatus::label($from) . '」不允许变更为「' . OrderStatus::label($to) . '」');
|
||
}
|
||
$data = array_merge($extra, [
|
||
'status' => (int)$to,
|
||
'updatetime' => time(),
|
||
]);
|
||
Db::name('order')->where('id', (int)$order['id'])->update($data);
|
||
$this->addLog((int)$order['id'], (int)$to, $remark, $operatorType, $operatorId);
|
||
return array_merge($order, $data);
|
||
}
|
||
|
||
/**
|
||
* 写订单流水
|
||
*/
|
||
protected function addLog($orderId, $status, $remark = '', $operatorType = 'system', $operatorId = 0)
|
||
{
|
||
Db::name('order_log')->insert([
|
||
'order_id' => (int)$orderId,
|
||
'status' => (int)$status,
|
||
'remark' => mb_substr((string)$remark, 0, 255),
|
||
'operator_type' => $operatorType,
|
||
'operator_id' => (int)$operatorId,
|
||
'createtime' => time(),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 消息通知
|
||
*/
|
||
protected function notify($receiveType, $receiveId, $title, $content, $type = 'order', $orderId = 0)
|
||
{
|
||
if (!$receiveId) {
|
||
return;
|
||
}
|
||
Db::name('message')->insert([
|
||
'receive_type' => $receiveType,
|
||
'receive_id' => (int)$receiveId,
|
||
'type' => $type,
|
||
'title' => mb_substr((string)$title, 0, 100),
|
||
'content' => mb_substr((string)$content, 0, 500),
|
||
'order_id' => (int)$orderId,
|
||
'is_read' => 0,
|
||
'createtime' => time(),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 生成订单号
|
||
*/
|
||
protected function makeOrderNo()
|
||
{
|
||
return date('YmdHis') . str_pad((string)mt_rand(0, 999999), 6, '0', STR_PAD_LEFT);
|
||
}
|
||
}
|