first version

This commit is contained in:
liu
2026-07-23 20:41:25 +08:00
parent 00a0938a1b
commit 10cff754a4
211 changed files with 11577 additions and 842 deletions
@@ -0,0 +1,219 @@
<?php
namespace App\Http\Controllers\Mini;
use App\Exceptions\RepositoryException;
use App\Http\Requests\Mini\MiniOrderRequest;
use App\Models\ProductModel;
use App\Models\ProductPriceModel;
use App\Models\StoreOrderItemModel;
use App\Models\StoreOrderModel;
use App\Services\BillNumberService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Modules\AnnoRoute\Attribute\GetRoute;
use Modules\AnnoRoute\Attribute\PostRoute;
use Modules\AnnoRoute\Attribute\PutRoute;
use Modules\AnnoRoute\Attribute\RequestAttribute;
/**
* 小程序门店订单(下单 / 历史 / 详情 / 取消 / 周期汇总)
*/
#[RequestAttribute('/mini', 'mini', authGuard: 'users')]
class OrderController extends BaseMiniController
{
/**
* 下单:逐行取当前门店等级价快照,服务端重算 amount 与 total(不接受前端金额)
*/
#[PostRoute('/order', authorize: true)]
public function store(MiniOrderRequest $request): JsonResponse
{
$user = $this->currentUser($request);
$store = $this->ensureStoreBound($user);
if ($store->level_id <= 0) {
throw new RepositoryException('门店未设置客户等级,无法下单,请联系客服');
}
$items = $request->validated('items');
$remark = (string) ($request->validated('remark') ?? '');
$order = DB::transaction(function () use ($store, $items, $remark) {
$productIds = array_map(static fn ($row) => (int) $row['product_id'], $items);
$products = ProductModel::query()
->where('status', ProductModel::STATUS_ON)
->whereIn('id', $productIds)
->get()
->keyBy('id');
$prices = ProductPriceModel::query()
->where('level_id', $store->level_id)
->whereIn('product_id', $productIds)
->pluck('price', 'product_id');
$totalQuantity = '0';
$totalAmount = '0';
$now = now();
$rows = [];
foreach ($items as $row) {
$productId = (int) $row['product_id'];
$product = $products->get($productId);
if ($product === null) {
throw new RepositoryException('存在已下架或不存在的商品,请刷新后重试');
}
if (! isset($prices[$productId])) {
throw new RepositoryException('商品「' . $product->name . '」未设置您所在等级的价格,无法下单');
}
$price = (string) $prices[$productId];
$quantity = (string) $row['quantity'];
$amount = bcmul($price, $quantity, 2);
$totalQuantity = bcadd($totalQuantity, $quantity, 2);
$totalAmount = bcadd($totalAmount, $amount, 2);
$rows[] = [
'store_id' => $store->id,
'product_id' => $productId,
'product_name' => $product->name,
'product_spec' => $product->spec,
'price' => $price,
'quantity' => $quantity,
'weight' => 0,
'amount' => $amount,
'remark' => '',
'created_at' => $now,
'updated_at' => $now,
];
}
$order = StoreOrderModel::create([
'order_no' => app(BillNumberService::class)->make('SO'),
'store_id' => $store->id,
'order_date' => $now->toDateString(),
'total_quantity' => $totalQuantity,
'total_weight' => 0,
'total_amount' => $totalAmount,
'status' => StoreOrderModel::STATUS_PENDING,
'remark' => $remark,
]);
foreach ($rows as &$itemRow) {
$itemRow['order_id'] = $order->id;
}
StoreOrderItemModel::insert($rows);
return $order;
});
return $this->success([
'id' => $order->id,
'order_no' => $order->order_no,
'total_amount' => $order->total_amount,
], '下单成功');
}
/** 历史订单:当前门店强制过滤,?status=&page=&pageSize= */
#[GetRoute('/order', authorize: true)]
public function index(Request $request): JsonResponse
{
$user = $this->currentUser($request);
$store = $this->ensureStoreBound($user);
$query = StoreOrderModel::query()->where('store_id', $store->id);
if ($request->filled('status')) {
$query->where('status', (int) $request->input('status'));
}
$data = $query->orderBy('order_date', 'desc')
->orderBy('id', 'desc')
->paginate((int) $request->input('pageSize', 10))
->toArray();
return $this->success($data);
}
/**
* 按周期聚合金额/数量:?period=day|week|month(分组列表,period_label 可作下钻查询参数)
*/
#[GetRoute('/order/summary', authorize: true)]
public function summary(Request $request): JsonResponse
{
$period = (string) $request->query('period', 'month');
if (! in_array($period, ['day', 'week', 'month'], true)) {
throw new RepositoryException('period 参数只能是 day/week/month');
}
$user = $this->currentUser($request);
$store = $this->ensureStoreBound($user);
// 按数据库方言选择周期分组表达式(生产 MySQL / 测试 SQLite
$driver = DB::connection()->getDriverName();
if ($driver === 'sqlite') {
$format = match ($period) {
'day' => '%Y-%m-%d',
'week' => '%Y-W%W',
default => '%Y-%m',
};
$labelExpr = "strftime('{$format}', order_date)";
} else {
$format = match ($period) {
'day' => '%Y-%m-%d',
'week' => '%x-W%v',
default => '%Y-%m',
};
$labelExpr = "DATE_FORMAT(order_date, '{$format}')";
}
$rows = StoreOrderModel::query()
->where('store_id', $store->id)
->where('status', '<>', StoreOrderModel::STATUS_CANCELLED)
->selectRaw("{$labelExpr} as period_label")
->selectRaw('SUM(total_amount) as total_amount, SUM(total_quantity) as total_quantity, COUNT(*) as order_count')
->groupBy('period_label')
->orderByDesc('period_label')
->limit(50)
->get()
->toArray();
return $this->success(['period' => $period, 'groups' => $rows]);
}
/** 订单详情(校验归属:仅能查看本店订单) */
#[GetRoute('/order/{id}', authorize: true, where: ['id' => '[0-9]+'])]
public function detail(int $id, Request $request): JsonResponse
{
$user = $this->currentUser($request);
$store = $this->ensureStoreBound($user);
$order = StoreOrderModel::with('items')
->where('store_id', $store->id)
->find($id);
if ($order === null) {
throw new RepositoryException('订单不存在');
}
return $this->success($order->toArray());
}
/** 取消订单(仅待汇总可取消) */
#[PutRoute('/order/{id}/cancel', authorize: true, where: ['id' => '[0-9]+'])]
public function cancel(int $id, Request $request): JsonResponse
{
$user = $this->currentUser($request);
$store = $this->ensureStoreBound($user);
$order = StoreOrderModel::where('store_id', $store->id)->find($id);
if ($order === null) {
throw new RepositoryException('订单不存在');
}
if ($order->status !== StoreOrderModel::STATUS_PENDING) {
throw new RepositoryException('仅待汇总的订单可以取消');
}
$order->status = StoreOrderModel::STATUS_CANCELLED;
$order->save();
return $this->success([], '订单已取消');
}
}