Files
lgp-admin-plus-api/app/Service/wx/WxListService.php
LQ bcf54c2727 初始化
缺陷:主题配色需要优化整体的同风格
2026-08-14 23:21:21 +08:00

216 lines
8.0 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Service\wx;
use App\BaseApp\BaseWxService;
use App\Models\business\ListItemModel;
use App\Models\business\ListModel;
use App\Service\business\PriceService;
use App\Service\business\SerialNoService;
/**
* 小程序清单
*
* 清单是「加购物车」的语义但不含结算,下单由 WxOrderService 从清单快照生成。
* 所有写操作都必须带 user_id 条件,否则改个 id 就能删别人的清单——老项目的 deleteItem 就是这个漏洞。
*/
class WxListService extends BaseWxService
{
/**
* 我的清单,带明细数量
*
* 兼容两种返回:
* - 不传 page / pageSize老调用方返回全量扁平数组保持向后兼容
* - 传了 page / pageSize返回 { items, total, page, pageSize, has_more },供小程序真分页使用。
* 判断「是否分页模式」只看请求里有没有 page避免 pageSize 默认值造成歧义。
*/
public function list(): array
{
// 请求里带了 page 才走分页分支pageSize 缺省 20与列表页约定一致
$page = request()->get('page');
$paged = $page !== null && $page !== '';
$page = max(1, (int) $page);
$pageSize = max(1, (int) (request()->get('pageSize') ?? 20));
$base = ListModel::with([
'items' => fn ($query) => $query->where('deleted_at', 0)->select(['id', 'list_id']),
])->where('user_id', $this->userId)
->where('deleted_at', 0)
->orderBy('id', 'desc');
// 不分页:一次拿全,保持老结构
if (!$paged) {
$rows = $base->get();
if ($rows->isEmpty()) {
return [];
}
$rows = $rows->toArray();
foreach ($rows as &$row) {
$row['count'] = count($row['items'] ?? []);
}
unset($row);
return $rows;
}
// 分页:拿当前页 + 总数,前端按 has_more 决定是否继续 loadMore
$total = (clone $base)->count();
$rows = $base->forPage($page, $pageSize)->get();
$items = $rows->isEmpty() ? [] : $rows->toArray();
foreach ($items as &$row) {
$row['count'] = count($row['items'] ?? []);
}
unset($row);
return [
'items' => $items,
'total' => $total,
'page' => $page,
'pageSize' => $pageSize,
'has_more' => ($page * $pageSize) < $total,
];
}
/**
* 清单详情:带商品与规格,价格按当前用户的可见性与倍率处理
*/
public function detail(int $id): array
{
$info = ListModel::with([
'items' => fn ($query) => $query->where('deleted_at', 0),
'items.catalogue',
'items.catalogue.priceSheet' => fn ($query) => $query->where('deleted_at', 0),
])->where('id', $id)
->where('user_id', $this->userId)
->where('deleted_at', 0)
->first();
if (empty($info)) {
$this->utils->errorThrow('清单不存在');
}
$info = $info->toArray();
$price = PriceService::getInstance();
$showPrice = $this->canSeePrice();
$multiplier = $this->priceMultiplier();
foreach ($info['items'] as &$item) {
$sheet = $item['catalogue']['price_sheet'] ?? [];
if (!empty($sheet)) {
$applied = $price->applyToRows($sheet, $showPrice, $multiplier);
$item['catalogue']['price_sheet'] = $applied['rows'];
}
// 老前端读的是 product 这个键名,保留别名避免小程序改字段
$item['product'] = $item['catalogue'] ?? null;
}
unset($item);
$info['is_show_price'] = $showPrice;
return $info;
}
public function create(array $params): mixed
{
$name = trim((string) ($params['name'] ?? ''));
if ($name === '') {
$this->utils->errorThrow('请填写清单名称');
}
return ListModel::insertGetId([
'list_no' => SerialNoService::getInstance()->generate(SerialNoService::PREFIX_LIST, 'list', 'list_no'),
'user_id' => $this->userId,
'name' => $name,
'remark' => (string) ($params['remark'] ?? ''),
'created_at' => time(),
]);
}
public function update(int $id, array $params): mixed
{
return ListModel::where('id', $id)->where('user_id', $this->userId)->update([
'name' => (string) ($params['name'] ?? ''),
'remark' => (string) ($params['remark'] ?? ''),
'updated_at' => time(),
]);
}
public function delete(array|int $ids): mixed
{
return ListModel::whereIn('id', (array) $ids)
->where('user_id', $this->userId)
->update(['deleted_at' => time(), 'updated_at' => time()]);
}
/**
* 删清单明细:先确认这些明细属于当前用户的清单
*/
public function deleteItem(array|int $ids): mixed
{
$ids = (array) $ids;
$listIds = ListModel::where('user_id', $this->userId)->where('deleted_at', 0)->pluck('id');
return ListItemModel::whereIn('id', $ids)
->whereIn('list_id', $listIds)
->update(['deleted_at' => time(), 'updated_at' => time()]);
}
/**
* 加入清单;同一清单同一商品同一规格只留一条,重复则累加数量
*/
public function toCart(array $params): mixed
{
$listId = (int) ($params['list_id'] ?? 0);
$catalogueId = (int) ($params['product_id'] ?? $params['catalogue_id'] ?? 0);
if ($listId <= 0 || $catalogueId <= 0) {
$this->utils->errorThrow('参数错误');
}
$list = ListModel::where('id', $listId)->where('user_id', $this->userId)->where('deleted_at', 0)->first();
if (empty($list)) {
$this->utils->errorThrow('清单不存在');
}
$priceSheetId = (int) ($params['price_sheet_id'] ?? 0);
$quantity = max(1, (int) ($params['quantity'] ?? 1));
$exists = ListItemModel::where('list_id', $listId)
->where('catalogue_id', $catalogueId)
->where('price_sheet_id', $priceSheetId)
->where('deleted_at', 0)
->first();
if (!empty($exists)) {
return ListItemModel::where('id', $exists['id'])->update([
'quantity' => (int) $exists['quantity'] + $quantity,
'updated_at' => time(),
]);
}
return ListItemModel::insertGetId([
'list_id' => $listId,
'catalogue_id' => $catalogueId,
'price_sheet_id' => $priceSheetId,
'material_key' => (string) ($params['material_key'] ?? 'routine'),
'quantity' => $quantity,
'remark' => (string) ($params['remark'] ?? ''),
'created_at' => time(),
]);
}
/**
* 改明细的规格与数量:转订单前用户要能在清单里补齐这些信息
*/
public function updateItem(array $params): mixed
{
$itemId = (int) ($params['id'] ?? 0);
if ($itemId <= 0) {
$this->utils->errorThrow('参数错误');
}
$listIds = ListModel::where('user_id', $this->userId)->where('deleted_at', 0)->pluck('id');
$update = ['updated_at' => time()];
if (array_key_exists('quantity', $params)) {
$update['quantity'] = max(1, (int) $params['quantity']);
}
if (array_key_exists('price_sheet_id', $params)) {
$update['price_sheet_id'] = (int) $params['price_sheet_id'];
}
if (array_key_exists('material_key', $params)) {
$update['material_key'] = (string) $params['material_key'];
}
if (array_key_exists('remark', $params)) {
$update['remark'] = (string) $params['remark'];
}
return ListItemModel::where('id', $itemId)->whereIn('list_id', $listIds)->update($update);
}
}