文件
yjyf/server/application/api/controller/Base.php
linda 376ce7b5c9 feat(api): 全链路后端 + 数据库设计 + E2E 测试(65 项断言全通过)
数据库:
- 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 未联系自动回流
2026-10-28 15:45:51 +08:00

156 行
4.6 KiB
PHP

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<?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);
}
}