购物车
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Mini;
|
||||
|
||||
use App\Exceptions\RepositoryException;
|
||||
use App\Http\Requests\Mini\MiniCartRequest;
|
||||
use App\Models\CartModel;
|
||||
use App\Models\ProductModel;
|
||||
use App\Models\ProductPriceModel;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\AnnoRoute\Attribute\DeleteRoute;
|
||||
use Modules\AnnoRoute\Attribute\GetRoute;
|
||||
use Modules\AnnoRoute\Attribute\PostRoute;
|
||||
use Modules\AnnoRoute\Attribute\PutRoute;
|
||||
use Modules\AnnoRoute\Attribute\RequestAttribute;
|
||||
use Modules\SystemTool\Models\SysFileModel;
|
||||
|
||||
/**
|
||||
* 小程序购物车(门店订货车:加购 / 列表 / 改数量 / 删项 / 清空)
|
||||
* 提交订货单复用 POST /mini/order,购物车仅作前置编辑容器
|
||||
*/
|
||||
#[RequestAttribute('/mini', 'mini', authGuard: 'users')]
|
||||
class CartController extends BaseMiniController
|
||||
{
|
||||
/** decimal(10,2) 上限 */
|
||||
private const MAX_QUANTITY = '99999999.99';
|
||||
|
||||
/**
|
||||
* 加购:商品上架 + 门店有等级价(与下单一致 fail-fast),同商品合并累加
|
||||
*/
|
||||
#[PostRoute('/cart', authorize: true)]
|
||||
public function store(MiniCartRequest $request): JsonResponse
|
||||
{
|
||||
$user = $this->currentUser($request);
|
||||
$store = $this->ensureStoreBound($user);
|
||||
if ($store->level_id <= 0) {
|
||||
throw new RepositoryException('门店未设置客户等级,无法加购,请联系客服');
|
||||
}
|
||||
|
||||
$productId = (int) $request->validated('product_id');
|
||||
// Eloquent 查询自带 SoftDeletes 全局作用域:软删除/下架一并在内
|
||||
$product = ProductModel::where('status', ProductModel::STATUS_ON)->find($productId);
|
||||
if ($product === null) {
|
||||
throw new RepositoryException('商品不存在或已下架,请刷新后重试');
|
||||
}
|
||||
$price = ProductPriceModel::query()
|
||||
->where('product_id', $productId)
|
||||
->where('level_id', $store->level_id)
|
||||
->value('price');
|
||||
if ($price === null) {
|
||||
throw new RepositoryException('商品「' . $product->name . '」未设置您所在等级的价格,无法加购');
|
||||
}
|
||||
|
||||
$quantity = (string) $request->validated('quantity');
|
||||
|
||||
$cart = DB::transaction(function () use ($user, $productId, $quantity) {
|
||||
$row = CartModel::query()
|
||||
->where('user_id', $user->id)
|
||||
->where('product_id', $productId)
|
||||
->lockForUpdate()
|
||||
->first();
|
||||
|
||||
if ($row !== null) {
|
||||
$merged = bcadd((string) $row->quantity, $quantity, 2);
|
||||
if (bccomp($merged, self::MAX_QUANTITY, 2) > 0) {
|
||||
throw new RepositoryException('该商品在购物车中的数量已达上限');
|
||||
}
|
||||
$row->quantity = $merged;
|
||||
$row->save();
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
return CartModel::create([
|
||||
'user_id' => $user->id,
|
||||
'product_id' => $productId,
|
||||
'quantity' => $quantity,
|
||||
]);
|
||||
});
|
||||
|
||||
return $this->success([
|
||||
'id' => $cart->id,
|
||||
'quantity' => $cart->quantity,
|
||||
], '已加入购物车');
|
||||
}
|
||||
|
||||
/**
|
||||
* 购物车列表:当前用户全部项 + 实时等级价,逐项服务端 bcmul 算金额;
|
||||
* status=1 可购 / 0 商品下架、缺失或未设等级价;汇总只统计可购项
|
||||
*/
|
||||
#[GetRoute('/cart', authorize: true)]
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$user = $this->currentUser($request);
|
||||
$store = $this->ensureStoreBound($user);
|
||||
|
||||
$rows = CartModel::query()
|
||||
->where('user_id', $user->id)
|
||||
->orderBy('id', 'desc')
|
||||
->get();
|
||||
|
||||
if ($rows->isEmpty()) {
|
||||
return $this->success([
|
||||
'items' => [],
|
||||
'total_count' => 0,
|
||||
'total_quantity' => '0.00',
|
||||
'total_amount' => '0.00',
|
||||
]);
|
||||
}
|
||||
|
||||
$productIds = $rows->pluck('product_id')
|
||||
->map(static fn ($id) => (int) $id)
|
||||
->unique()->values()->all();
|
||||
|
||||
$products = ProductModel::withTrashed()->whereIn('id', $productIds)->get()->keyBy('id');
|
||||
$prices = ProductPriceModel::query()
|
||||
->where('level_id', $store->level_id)
|
||||
->whereIn('product_id', $productIds)
|
||||
->pluck('price', 'product_id');
|
||||
|
||||
// 图片一次查回(避免 ProductModel::$appends images_arr 的 N+1)。
|
||||
// 注意:image_ids 有 imageIds Attribute 访问器(get 返回数组),需取原始值
|
||||
$allFileIds = [];
|
||||
foreach ($products as $product) {
|
||||
foreach (explode(',', (string) $product->getRawOriginal('image_ids')) as $fileId) {
|
||||
if ($fileId !== '') {
|
||||
$allFileIds[] = (int) $fileId;
|
||||
}
|
||||
}
|
||||
}
|
||||
$fileMap = SysFileModel::query()
|
||||
->whereIn('id', $allFileIds)
|
||||
->get()->keyBy('id');
|
||||
|
||||
$items = [];
|
||||
$totalQuantity = '0.00';
|
||||
$totalAmount = '0.00';
|
||||
foreach ($rows as $row) {
|
||||
$product = $products->get($row->product_id);
|
||||
$productOn = $product !== null && $product->status === ProductModel::STATUS_ON;
|
||||
$price = $prices->get($row->product_id); // string|null
|
||||
$buyable = $productOn && $price !== null;
|
||||
$quantity = (string) $row->quantity;
|
||||
|
||||
$firstFileId = (int) (explode(',', (string) $product->getRawOriginal('image_ids'))[0] ?? 0);
|
||||
$firstFile = $firstFileId > 0 ? $fileMap->get($firstFileId) : null;
|
||||
|
||||
$item = [
|
||||
'id' => $row->id,
|
||||
'product_id' => $row->product_id,
|
||||
'name' => $product->name ?? '',
|
||||
'spec' => $product->spec ?? '',
|
||||
'unit' => $product->unit ?? '',
|
||||
'image' => $firstFile?->file_url ?? '',
|
||||
'price' => $price,
|
||||
'quantity' => $quantity,
|
||||
'amount' => $buyable ? bcmul($price, $quantity, 2) : null,
|
||||
'status' => $buyable ? 1 : 0,
|
||||
];
|
||||
$items[] = $item;
|
||||
|
||||
if ($buyable) {
|
||||
$totalQuantity = bcadd($totalQuantity, $quantity, 2);
|
||||
$totalAmount = bcadd($totalAmount, $item['amount'], 2);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'items' => $items,
|
||||
'total_count' => count($items),
|
||||
'total_quantity' => $totalQuantity,
|
||||
'total_amount' => $totalAmount,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改数量(校验归属)
|
||||
*/
|
||||
#[PutRoute('/cart/{id}', authorize: true, where: ['id' => '[0-9]+'])]
|
||||
public function update(int $id, MiniCartRequest $request): JsonResponse
|
||||
{
|
||||
$user = $this->currentUser($request);
|
||||
$this->ensureStoreBound($user);
|
||||
|
||||
$row = CartModel::query()
|
||||
->where('id', $id)
|
||||
->where('user_id', $user->id)
|
||||
->first();
|
||||
if ($row === null) {
|
||||
throw new RepositoryException('购物车项不存在');
|
||||
}
|
||||
|
||||
$row->quantity = (string) $request->validated('quantity');
|
||||
$row->save();
|
||||
|
||||
return $this->success(['id' => $row->id, 'quantity' => $row->quantity], '已修改数量');
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单项(校验归属)
|
||||
*/
|
||||
#[DeleteRoute('/cart/{id}', authorize: true, where: ['id' => '[0-9]+'])]
|
||||
public function destroy(int $id, Request $request): JsonResponse
|
||||
{
|
||||
$user = $this->currentUser($request);
|
||||
$this->ensureStoreBound($user);
|
||||
|
||||
$deleted = CartModel::query()
|
||||
->where('id', $id)
|
||||
->where('user_id', $user->id)
|
||||
->delete();
|
||||
if ($deleted === 0) {
|
||||
throw new RepositoryException('购物车项不存在');
|
||||
}
|
||||
|
||||
return $this->success([], '已删除');
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空购物车(仅当前用户)
|
||||
*/
|
||||
#[DeleteRoute('/cart', authorize: true)]
|
||||
public function clear(Request $request): JsonResponse
|
||||
{
|
||||
$user = $this->currentUser($request);
|
||||
$this->ensureStoreBound($user);
|
||||
|
||||
CartModel::query()->where('user_id', $user->id)->delete();
|
||||
|
||||
return $this->success([], '购物车已清空');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Mini;
|
||||
|
||||
use Modules\Common\Http\Requests\BaseFormRequest;
|
||||
|
||||
/**
|
||||
* 小程序购物车 验证(product_id 仅加购时必填;PUT 只改数量)
|
||||
*/
|
||||
class MiniCartRequest extends BaseFormRequest
|
||||
{
|
||||
protected $stopOnFirstFailure = true;
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [
|
||||
'quantity' => 'required|numeric|min:0.01|max:99999999.99',
|
||||
];
|
||||
|
||||
if (! $this->isUpdate()) {
|
||||
$rules['product_id'] = 'required|integer|exists:product,id';
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'product_id.required' => '请选择商品',
|
||||
'product_id.integer' => '商品参数错误',
|
||||
'product_id.exists' => '商品不存在',
|
||||
'quantity.required' => '订货数量不能为空',
|
||||
'quantity.numeric' => '订货数量必须为数字',
|
||||
'quantity.min' => '订货数量必须大于 0',
|
||||
'quantity.max' => '订货数量超出上限',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
/**
|
||||
* 小程序购物车模型(门店订货车:按用户归属,同商品唯一行、加购合并数量)
|
||||
*/
|
||||
class CartModel extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'cart';
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'product_id',
|
||||
'quantity',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'user_id' => 'integer',
|
||||
'product_id' => 'integer',
|
||||
'quantity' => 'decimal:2',
|
||||
];
|
||||
|
||||
/**
|
||||
* 归属用户
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(UserModel::class, 'user_id', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 购物车商品(软删除后为 null;列表接口需 withTrashed 自行判断状态)
|
||||
*/
|
||||
public function product(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ProductModel::class, 'product_id', 'id');
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
/**
|
||||
* 微信小程序服务(基于 EasyWeChat 6.x)
|
||||
*
|
||||
* 封装 code2Session / 手机号解密;配置读取 config('services.wechat.mini')
|
||||
* (env:WECHAT_MINI_APPID / WECHAT_MINI_SECRET,需业务方提供)。
|
||||
* 封装 code2Session / 手机号解密;配置读取 site_config('wechatMini')
|
||||
* (后台「小程序设置」面板维护,存 sys_site_config 表)。
|
||||
*
|
||||
* 测试策略:通过 setHttpClient() 注入 Symfony MockHttpClient 拦截微信 HTTP 调用。
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\CartModel;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* 购物车工厂(user_id / product_id 需调用方指定;无需 Faker)
|
||||
*
|
||||
* @extends Factory<CartModel>
|
||||
*/
|
||||
class CartModelFactory extends Factory
|
||||
{
|
||||
protected $model = CartModel::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'user_id' => 0,
|
||||
'product_id' => 0,
|
||||
'quantity' => number_format(random_int(100, 10000) / 100, 2, '.', ''),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\CustomerLevelModel;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* 客户等级工厂(确定性序列数据,无需 Faker)
|
||||
*
|
||||
* @extends Factory<CustomerLevelModel>
|
||||
*/
|
||||
class CustomerLevelModelFactory extends Factory
|
||||
{
|
||||
protected $model = CustomerLevelModel::class;
|
||||
|
||||
private static int $sequence = 0;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
$seq = ++self::$sequence;
|
||||
|
||||
return [
|
||||
'name' => '客户等级' . $seq,
|
||||
'sort' => $seq,
|
||||
'status' => CustomerLevelModel::STATUS_NORMAL,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\ProductModel;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* 商品工厂(确定性序列数据,无需 Faker)
|
||||
*
|
||||
* @extends Factory<ProductModel>
|
||||
*/
|
||||
class ProductModelFactory extends Factory
|
||||
{
|
||||
protected $model = ProductModel::class;
|
||||
|
||||
private const NAMES = ['大白菜', '土豆', '西红柿', '黄瓜', '苹果', '香蕉'];
|
||||
private const SPECS = ['500g/袋', '10斤/箱', '散装', '25斤/袋'];
|
||||
private const UNITS = ['斤', '箱', '袋'];
|
||||
|
||||
private static int $sequence = 0;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
$seq = ++self::$sequence;
|
||||
|
||||
return [
|
||||
'category_id' => 0,
|
||||
'supplier_id' => 0,
|
||||
'name' => self::NAMES[$seq % count(self::NAMES)] . $seq,
|
||||
'spec' => self::SPECS[$seq % count(self::SPECS)],
|
||||
'unit' => self::UNITS[$seq % count(self::UNITS)],
|
||||
'image_ids' => '',
|
||||
'content' => '',
|
||||
'sort' => $seq,
|
||||
'shelf_life' => 0,
|
||||
'stock' => 0,
|
||||
'status' => ProductModel::STATUS_ON,
|
||||
'remark' => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 下架商品
|
||||
*/
|
||||
public function off(): static
|
||||
{
|
||||
return $this->state(fn () => ['status' => ProductModel::STATUS_OFF]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\ProductPriceModel;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* 商品等级价格工厂(product_id / level_id 需调用方指定;无需 Faker)
|
||||
*
|
||||
* @extends Factory<ProductPriceModel>
|
||||
*/
|
||||
class ProductPriceModelFactory extends Factory
|
||||
{
|
||||
protected $model = ProductPriceModel::class;
|
||||
|
||||
private static int $sequence = 0;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
$seq = ++self::$sequence;
|
||||
|
||||
return [
|
||||
'product_id' => 0,
|
||||
'level_id' => 0,
|
||||
'price' => number_format(random_int(100, 10000) / 100 + $seq * 0.01, 2, '.', ''),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\PurchaseOrderModel;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* 采购单工厂(无需 Faker)
|
||||
*
|
||||
* @extends Factory<PurchaseOrderModel>
|
||||
*/
|
||||
class PurchaseOrderModelFactory extends Factory
|
||||
{
|
||||
protected $model = PurchaseOrderModel::class;
|
||||
|
||||
private static int $sequence = 0;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
$seq = ++self::$sequence;
|
||||
|
||||
return [
|
||||
'purchase_no' => 'PO' . str_pad((string) $seq, 12, '0', STR_PAD_LEFT),
|
||||
'purchase_date' => now()->toDateString(),
|
||||
'status' => PurchaseOrderModel::STATUS_PENDING,
|
||||
'total_quantity' => 0,
|
||||
'total_weight' => 0,
|
||||
'estimate_amount' => 0,
|
||||
'actual_amount' => 0,
|
||||
'operator_id' => 0,
|
||||
'remark' => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定采购日期
|
||||
*/
|
||||
public function onDate(string $date): static
|
||||
{
|
||||
return $this->state(fn () => ['purchase_date' => $date]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\StoreModel;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* 门店工厂(确定性序列数据,无需 Faker)
|
||||
*
|
||||
* @extends Factory<StoreModel>
|
||||
*/
|
||||
class StoreModelFactory extends Factory
|
||||
{
|
||||
protected $model = StoreModel::class;
|
||||
|
||||
private static int $sequence = 0;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
$seq = ++self::$sequence;
|
||||
|
||||
return [
|
||||
'name' => '测试门店' . $seq,
|
||||
'code' => 'S' . str_pad((string) $seq, 6, '0', STR_PAD_LEFT),
|
||||
'level_id' => 0,
|
||||
'contact' => '联系人' . $seq,
|
||||
'phone' => '138' . str_pad((string) $seq, 8, '0', STR_PAD_LEFT),
|
||||
'address' => '测试地址' . $seq . '号',
|
||||
'payment_cycle_days' => $seq % 8,
|
||||
'status' => StoreModel::STATUS_NORMAL,
|
||||
'remark' => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 停用门店
|
||||
*/
|
||||
public function disabled(): static
|
||||
{
|
||||
return $this->state(fn () => ['status' => StoreModel::STATUS_DISABLED]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定回款周期(天)
|
||||
*/
|
||||
public function paymentCycle(int $days): static
|
||||
{
|
||||
return $this->state(fn () => ['payment_cycle_days' => $days]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\StoreOrderItemModel;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* 门店订单明细工厂(order_id / store_id / product_id 需调用方指定;
|
||||
* amount 未显式指定时按 price × quantity 自动计算;无需 Faker)
|
||||
*
|
||||
* @extends Factory<StoreOrderItemModel>
|
||||
*/
|
||||
class StoreOrderItemModelFactory extends Factory
|
||||
{
|
||||
protected $model = StoreOrderItemModel::class;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'order_id' => 0,
|
||||
'store_id' => 0,
|
||||
'product_id' => 0,
|
||||
'product_name' => '测试商品',
|
||||
'product_spec' => '500g/袋',
|
||||
'price' => number_format(random_int(100, 5000) / 100, 2, '.', ''),
|
||||
'quantity' => number_format(random_int(100, 10000) / 100, 2, '.', ''),
|
||||
'weight' => 0,
|
||||
'amount' => 0,
|
||||
'remark' => '',
|
||||
];
|
||||
}
|
||||
|
||||
public function configure(): static
|
||||
{
|
||||
return $this->afterMaking(function (StoreOrderItemModel $item): void {
|
||||
if ((float) $item->amount === 0.0 && (float) $item->price > 0 && (float) $item->quantity > 0) {
|
||||
$item->amount = bcmul((string) $item->price, (string) $item->quantity, 2);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\StoreOrderModel;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* 门店订单工厂(store_id 需调用方指定;无需 Faker)
|
||||
*
|
||||
* @extends Factory<StoreOrderModel>
|
||||
*/
|
||||
class StoreOrderModelFactory extends Factory
|
||||
{
|
||||
protected $model = StoreOrderModel::class;
|
||||
|
||||
private static int $sequence = 0;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
$seq = ++self::$sequence;
|
||||
|
||||
return [
|
||||
'order_no' => 'SO' . str_pad((string) $seq, 12, '0', STR_PAD_LEFT),
|
||||
'store_id' => 0,
|
||||
'order_date' => now()->toDateString(),
|
||||
'total_quantity' => 0,
|
||||
'total_weight' => 0,
|
||||
'total_amount' => 0,
|
||||
'status' => StoreOrderModel::STATUS_PENDING,
|
||||
'remark' => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定订货日期
|
||||
*/
|
||||
public function onDate(string $date): static
|
||||
{
|
||||
return $this->state(fn () => ['order_date' => $date]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 已汇总(已被采购单归集)
|
||||
*/
|
||||
public function summarized(): static
|
||||
{
|
||||
return $this->state(fn () => ['status' => StoreOrderModel::STATUS_SUMMARIZED]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\SupplierModel;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* 供应商工厂(确定性序列数据,无需 Faker)
|
||||
*
|
||||
* @extends Factory<SupplierModel>
|
||||
*/
|
||||
class SupplierModelFactory extends Factory
|
||||
{
|
||||
protected $model = SupplierModel::class;
|
||||
|
||||
private const MAIN_PRODUCTS = ['蔬菜', '水果', '蔬菜/水果', '肉禽蛋'];
|
||||
|
||||
private static int $sequence = 0;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
$seq = ++self::$sequence;
|
||||
|
||||
return [
|
||||
'name' => '测试供应商' . $seq,
|
||||
'contact' => '联系人' . $seq,
|
||||
'phone' => '139' . str_pad((string) $seq, 8, '0', STR_PAD_LEFT),
|
||||
'address' => '供应商地址' . $seq . '号',
|
||||
'main_products' => self::MAIN_PRODUCTS[$seq % count(self::MAIN_PRODUCTS)],
|
||||
'status' => SupplierModel::STATUS_NORMAL,
|
||||
'remark' => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 停用供应商
|
||||
*/
|
||||
public function disabled(): static
|
||||
{
|
||||
return $this->state(fn () => ['status' => SupplierModel::STATUS_DISABLED]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\UserModel;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* 小程序用户工厂(微信登录自动生成,供测试使用;无需 Faker)
|
||||
*
|
||||
* @extends Factory<UserModel>
|
||||
*/
|
||||
class UserModelFactory extends Factory
|
||||
{
|
||||
protected $model = UserModel::class;
|
||||
|
||||
private static int $sequence = 0;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
$seq = ++self::$sequence;
|
||||
|
||||
return [
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
'nickname' => '微信用户' . $seq,
|
||||
'email' => '',
|
||||
'openid' => 'openid_' . str_pad((string) $seq, 16, '0', STR_PAD_LEFT),
|
||||
'unionid' => '',
|
||||
'phone' => '',
|
||||
'avatar' => '',
|
||||
'type' => UserModel::TYPE_PENDING,
|
||||
'store_id' => 0,
|
||||
'supplier_id' => 0,
|
||||
'status' => UserModel::STATUS_NORMAL,
|
||||
'last_login_at' => null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 已绑定门店的门店用户
|
||||
*/
|
||||
public function forStore(int $storeId): static
|
||||
{
|
||||
return $this->state(fn () => [
|
||||
'type' => UserModel::TYPE_STORE,
|
||||
'store_id' => $storeId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 已绑定供应商的供应商用户
|
||||
*/
|
||||
public function forSupplier(int $supplierId): static
|
||||
{
|
||||
return $this->state(fn () => [
|
||||
'type' => UserModel::TYPE_SUPPLIER,
|
||||
'supplier_id' => $supplierId,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停用账号
|
||||
*/
|
||||
public function disabled(): static
|
||||
{
|
||||
return $this->state(fn () => ['status' => UserModel::STATUS_DISABLED]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
* 小程序购物车(门店订货车):按用户归属,同商品唯一行、加购合并累加
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('cart')) {
|
||||
Schema::create('cart', function (Blueprint $table) {
|
||||
$table->increments('id')->comment('购物车项ID');
|
||||
$table->integer('user_id')->comment('用户ID(购物车归属者)');
|
||||
$table->integer('product_id')->comment('商品ID');
|
||||
$table->decimal('quantity', 10, 2)->default(0)->comment('订货量');
|
||||
$table->timestamps();
|
||||
$table->unique(['user_id', 'product_id'], 'cart_user_product_unique');
|
||||
$table->index(['user_id', 'created_at'], 'cart_user_created_index');
|
||||
$table->comment('小程序购物车表(门店订货车)');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('cart');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,331 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\CartModel;
|
||||
use App\Models\CustomerLevelModel;
|
||||
use App\Models\ProductModel;
|
||||
use App\Models\ProductPriceModel;
|
||||
use App\Models\StoreModel;
|
||||
use App\Models\UserModel;
|
||||
|
||||
/**
|
||||
* 小程序购物车:加购合并、等级价/金额服务端计算、归属校验、数据隔离、清空
|
||||
*/
|
||||
class CartTest extends ProcurementTestCase
|
||||
{
|
||||
/**
|
||||
* 造一家门店 + 一个上架商品(含等级价)+ 该店用户
|
||||
*
|
||||
* @return array{0: StoreModel, 1: ProductModel, 2: UserModel}
|
||||
*/
|
||||
private function makeStoreWithProduct(string $price = '5.00'): array
|
||||
{
|
||||
$level = CustomerLevelModel::factory()->create();
|
||||
$store = StoreModel::factory()->create(['level_id' => $level->id]);
|
||||
$product = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
|
||||
ProductPriceModel::factory()->create([
|
||||
'product_id' => $product->id,
|
||||
'level_id' => $level->id,
|
||||
'price' => $price,
|
||||
]);
|
||||
|
||||
return [$store, $product, UserModel::factory()->forStore($store->id)->create()];
|
||||
}
|
||||
|
||||
/** 加购成功:数量入库、返回购物车项 */
|
||||
public function test_add_to_cart_succeeds(): void
|
||||
{
|
||||
[, $product, $user] = $this->makeStoreWithProduct('5.50');
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$this->postJson('/mini/cart', [
|
||||
'product_id' => $product->id,
|
||||
'quantity' => 2.5,
|
||||
])->assertOk()
|
||||
->assertJsonPath('success', true)
|
||||
->assertJsonPath('data.quantity', '2.50')
|
||||
->assertJsonStructure(['data' => ['id', 'quantity']]);
|
||||
|
||||
$cart = CartModel::first();
|
||||
$this->assertNotNull($cart);
|
||||
$this->assertSame($user->id, $cart->user_id);
|
||||
$this->assertSame('2.50', (string) $cart->quantity);
|
||||
}
|
||||
|
||||
/** 重复加购同一商品合并累加(同商品唯一行) */
|
||||
public function test_duplicate_add_merges_quantity(): void
|
||||
{
|
||||
[, $product, $user] = $this->makeStoreWithProduct();
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 2]);
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 3])
|
||||
->assertJsonPath('data.quantity', '5.00');
|
||||
|
||||
$this->assertSame(1, CartModel::count());
|
||||
$this->assertSame('5.00', (string) CartModel::first()->quantity);
|
||||
}
|
||||
|
||||
/** 已下架商品拒绝加购 */
|
||||
public function test_off_shelf_product_rejected(): void
|
||||
{
|
||||
[, $product, $user] = $this->makeStoreWithProduct();
|
||||
$product->update(['status' => ProductModel::STATUS_OFF]);
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 1])
|
||||
->assertOk()
|
||||
->assertJsonPath('success', false);
|
||||
|
||||
$this->assertSame(0, CartModel::count());
|
||||
}
|
||||
|
||||
/** 已软删除商品拒绝加购 */
|
||||
public function test_soft_deleted_product_rejected(): void
|
||||
{
|
||||
[, $product, $user] = $this->makeStoreWithProduct();
|
||||
$product->delete();
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 1])
|
||||
->assertJsonPath('success', false);
|
||||
|
||||
$this->assertSame(0, CartModel::count());
|
||||
}
|
||||
|
||||
/** 商品未设置门店等级价时拒绝加购 */
|
||||
public function test_product_without_level_price_rejected(): void
|
||||
{
|
||||
[, $product, $user] = $this->makeStoreWithProduct();
|
||||
ProductPriceModel::where('product_id', $product->id)->delete();
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 1])
|
||||
->assertJsonPath('success', false);
|
||||
|
||||
$this->assertSame(0, CartModel::count());
|
||||
}
|
||||
|
||||
/** 未绑定门店的用户拒绝加购 */
|
||||
public function test_unbound_user_rejected(): void
|
||||
{
|
||||
[, $product] = $this->makeStoreWithProduct();
|
||||
$this->actingAsMiniUser(UserModel::factory()->create());
|
||||
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 1])
|
||||
->assertJsonPath('success', false)
|
||||
->assertJsonPath('msg', '尚未绑定门店,请联系客服处理');
|
||||
}
|
||||
|
||||
/** 门店未设置客户等级时拒绝加购 */
|
||||
public function test_store_without_level_rejected(): void
|
||||
{
|
||||
[, $product] = $this->makeStoreWithProduct();
|
||||
$store = StoreModel::factory()->create(['level_id' => 0]);
|
||||
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
|
||||
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 1])
|
||||
->assertJsonPath('success', false);
|
||||
}
|
||||
|
||||
/** 列表:实时等级价、服务端金额、汇总(同店两商品,新加入在前) */
|
||||
public function test_list_with_prices_amounts_and_totals(): void
|
||||
{
|
||||
$level = CustomerLevelModel::factory()->create();
|
||||
$store = StoreModel::factory()->create(['level_id' => $level->id]);
|
||||
$p1 = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
|
||||
$p2 = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
|
||||
ProductPriceModel::factory()->create(['product_id' => $p1->id, 'level_id' => $level->id, 'price' => '5.50']);
|
||||
ProductPriceModel::factory()->create(['product_id' => $p2->id, 'level_id' => $level->id, 'price' => '3.00']);
|
||||
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
|
||||
|
||||
$this->postJson('/mini/cart', ['product_id' => $p1->id, 'quantity' => 3]);
|
||||
$this->postJson('/mini/cart', ['product_id' => $p2->id, 'quantity' => 2]);
|
||||
|
||||
$this->getJson('/mini/cart')->assertOk()
|
||||
->assertJsonPath('success', true)
|
||||
// items 按 id 倒序:后加入的 p2 在前
|
||||
->assertJsonPath('data.items.0.product_id', $p2->id)
|
||||
->assertJsonPath('data.items.0.price', '3.00')
|
||||
->assertJsonPath('data.items.0.quantity', '2.00')
|
||||
->assertJsonPath('data.items.0.amount', '6.00')
|
||||
->assertJsonPath('data.items.0.status', 1)
|
||||
->assertJsonPath('data.items.1.product_id', $p1->id)
|
||||
->assertJsonPath('data.items.1.price', '5.50')
|
||||
->assertJsonPath('data.items.1.amount', '16.50')
|
||||
->assertJsonPath('data.items.1.status', 1)
|
||||
->assertJsonPath('data.total_count', 2)
|
||||
->assertJsonPath('data.total_quantity', '5.00')
|
||||
->assertJsonPath('data.total_amount', '22.50');
|
||||
}
|
||||
|
||||
/** 列表:下架商品标记不可购,不计入汇总 */
|
||||
public function test_list_marks_off_shelf_item_unbuyable(): void
|
||||
{
|
||||
$level = CustomerLevelModel::factory()->create();
|
||||
$store = StoreModel::factory()->create(['level_id' => $level->id]);
|
||||
$p1 = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
|
||||
$p2 = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
|
||||
ProductPriceModel::factory()->create(['product_id' => $p1->id, 'level_id' => $level->id, 'price' => '5.50']);
|
||||
ProductPriceModel::factory()->create(['product_id' => $p2->id, 'level_id' => $level->id, 'price' => '3.00']);
|
||||
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
|
||||
|
||||
$this->postJson('/mini/cart', ['product_id' => $p1->id, 'quantity' => 3]);
|
||||
$this->postJson('/mini/cart', ['product_id' => $p2->id, 'quantity' => 2]);
|
||||
$p1->update(['status' => ProductModel::STATUS_OFF]);
|
||||
|
||||
$this->getJson('/mini/cart')->assertOk()
|
||||
->assertJsonPath('data.items.1.status', 0)
|
||||
->assertJsonPath('data.items.1.amount', null)
|
||||
->assertJsonPath('data.total_count', 2)
|
||||
->assertJsonPath('data.total_quantity', '2.00')
|
||||
->assertJsonPath('data.total_amount', '6.00');
|
||||
}
|
||||
|
||||
/** 空购物车返回空列表 */
|
||||
public function test_empty_cart_returns_empty_items(): void
|
||||
{
|
||||
$store = StoreModel::factory()->create(['level_id' => CustomerLevelModel::factory()->create()->id]);
|
||||
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
|
||||
|
||||
$this->getJson('/mini/cart')->assertOk()
|
||||
->assertJsonPath('data.items', [])
|
||||
->assertJsonPath('data.total_count', 0)
|
||||
->assertJsonPath('data.total_amount', '0.00');
|
||||
}
|
||||
|
||||
/** 修改数量 */
|
||||
public function test_update_quantity(): void
|
||||
{
|
||||
[, $product, $user] = $this->makeStoreWithProduct();
|
||||
$this->actingAsMiniUser($user);
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 1]);
|
||||
$cart = CartModel::first();
|
||||
|
||||
$this->putJson("/mini/cart/{$cart->id}", ['quantity' => 7])
|
||||
->assertJsonPath('success', true)
|
||||
->assertJsonPath('data.quantity', '7.00');
|
||||
|
||||
$this->assertSame('7.00', (string) $cart->fresh()->quantity);
|
||||
}
|
||||
|
||||
/** 修改他人购物车项拒绝(同店另一用户) */
|
||||
public function test_update_other_users_item_rejected(): void
|
||||
{
|
||||
[$store, $product, $userA] = $this->makeStoreWithProduct();
|
||||
$this->actingAsMiniUser($userA);
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 1]);
|
||||
$cart = CartModel::first();
|
||||
|
||||
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
|
||||
$this->putJson("/mini/cart/{$cart->id}", ['quantity' => 9])
|
||||
->assertJsonPath('success', false)
|
||||
->assertJsonPath('msg', '购物车项不存在');
|
||||
|
||||
$this->assertSame('1.00', (string) $cart->fresh()->quantity, '他人改数量不应生效');
|
||||
}
|
||||
|
||||
/** 修改不存在的购物车项拒绝 */
|
||||
public function test_update_missing_item_rejected(): void
|
||||
{
|
||||
[$store, $product, $user] = $this->makeStoreWithProduct();
|
||||
$this->actingAsMiniUser($user);
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 1]);
|
||||
|
||||
$this->putJson('/mini/cart/999999', ['quantity' => 1])->assertJsonPath('success', false);
|
||||
}
|
||||
|
||||
/** 数量校验:0 与负值拒绝 */
|
||||
public function test_invalid_quantity_rejected(): void
|
||||
{
|
||||
[, $product, $user] = $this->makeStoreWithProduct();
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 0])
|
||||
->assertOk()
|
||||
->assertJsonPath('success', false)
|
||||
->assertJsonPath('msg', '订货数量必须大于 0');
|
||||
|
||||
$this->assertSame(0, CartModel::count());
|
||||
}
|
||||
|
||||
/** 删除单项 */
|
||||
public function test_delete_item(): void
|
||||
{
|
||||
[, $product, $user] = $this->makeStoreWithProduct();
|
||||
$this->actingAsMiniUser($user);
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 1]);
|
||||
$cart = CartModel::first();
|
||||
|
||||
$this->deleteJson("/mini/cart/{$cart->id}")->assertJsonPath('success', true);
|
||||
$this->assertSame(0, CartModel::count());
|
||||
}
|
||||
|
||||
/** 删除他人购物车项拒绝 */
|
||||
public function test_delete_other_users_item_rejected(): void
|
||||
{
|
||||
[$store, $product, $userA] = $this->makeStoreWithProduct();
|
||||
$this->actingAsMiniUser($userA);
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 1]);
|
||||
$cart = CartModel::first();
|
||||
|
||||
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
|
||||
$this->deleteJson("/mini/cart/{$cart->id}")
|
||||
->assertJsonPath('success', false)
|
||||
->assertJsonPath('msg', '购物车项不存在');
|
||||
|
||||
$this->assertSame(1, CartModel::count());
|
||||
}
|
||||
|
||||
/** 清空购物车仅影响当前用户 */
|
||||
public function test_clear_only_own_cart(): void
|
||||
{
|
||||
$level = CustomerLevelModel::factory()->create();
|
||||
$store = StoreModel::factory()->create(['level_id' => $level->id]);
|
||||
$p1 = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
|
||||
$p2 = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
|
||||
ProductPriceModel::factory()->create(['product_id' => $p1->id, 'level_id' => $level->id, 'price' => '5.00']);
|
||||
ProductPriceModel::factory()->create(['product_id' => $p2->id, 'level_id' => $level->id, 'price' => '5.00']);
|
||||
$userA = UserModel::factory()->forStore($store->id)->create();
|
||||
$userB = UserModel::factory()->forStore($store->id)->create();
|
||||
|
||||
$this->actingAsMiniUser($userA);
|
||||
$this->postJson('/mini/cart', ['product_id' => $p1->id, 'quantity' => 1]);
|
||||
$this->postJson('/mini/cart', ['product_id' => $p2->id, 'quantity' => 1]);
|
||||
|
||||
$this->actingAsMiniUser($userB);
|
||||
$this->postJson('/mini/cart', ['product_id' => $p1->id, 'quantity' => 1]);
|
||||
|
||||
$this->actingAsMiniUser($userA);
|
||||
$this->deleteJson('/mini/cart')->assertJsonPath('success', true);
|
||||
|
||||
$this->assertSame(0, CartModel::where('user_id', $userA->id)->count());
|
||||
$this->assertSame(1, CartModel::where('user_id', $userB->id)->count(), '他人购物车不受影响');
|
||||
}
|
||||
|
||||
/** 未登录访问购物车 → 401 */
|
||||
public function test_unauthenticated_returns_401(): void
|
||||
{
|
||||
$this->getJson('/mini/cart')->assertStatus(401);
|
||||
}
|
||||
|
||||
/** 跨用户列表隔离:B 看不到 A 的购物车 */
|
||||
public function test_cart_isolated_between_users(): void
|
||||
{
|
||||
$level = CustomerLevelModel::factory()->create();
|
||||
$store = StoreModel::factory()->create(['level_id' => $level->id]);
|
||||
$product = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
|
||||
ProductPriceModel::factory()->create(['product_id' => $product->id, 'level_id' => $level->id, 'price' => '5.00']);
|
||||
$userA = UserModel::factory()->forStore($store->id)->create();
|
||||
$userB = UserModel::factory()->forStore($store->id)->create();
|
||||
|
||||
$this->actingAsMiniUser($userA);
|
||||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 1]);
|
||||
|
||||
$this->actingAsMiniUser($userB);
|
||||
$this->getJson('/mini/cart')->assertOk()
|
||||
->assertJsonPath('data.items', [])
|
||||
->assertJsonPath('data.total_count', 0);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ namespace Tests\Feature;
|
||||
use App\Models\StoreModel;
|
||||
use App\Models\UserModel;
|
||||
use App\Services\WechatService;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\SystemTool\Services\SysSiteConfigService;
|
||||
use Symfony\Component\HttpClient\MockHttpClient;
|
||||
use Symfony\Component\HttpClient\Response\MockResponse;
|
||||
|
||||
@@ -17,8 +19,29 @@ class MiniAuthTest extends ProcurementTestCase
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
// 测试环境注入微信配置(生产由 WECHAT_MINI_APPID/SECRET 提供)
|
||||
config(['services.wechat.mini' => ['appid' => 'test_appid', 'secret' => 'test_secret']]);
|
||||
// 微信配置为 DB 驱动(后台「小程序设置」→ sys_site_config,WechatService 经
|
||||
// site_config('wechatMini') 读取):测试落库并刷新配置缓存
|
||||
DB::table('sys_site_config_group')->insert([
|
||||
'id' => 100,
|
||||
'title' => '小程序设置',
|
||||
'key' => 'wechatMini',
|
||||
'remark' => '',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
DB::table('sys_site_config_items')->insert([
|
||||
[
|
||||
'group_id' => 100, 'key' => 'appid', 'title' => 'APPID', 'describe' => '',
|
||||
'values' => 'test_appid', 'type' => 'Input', 'options' => null, 'props' => null, 'sort' => 0,
|
||||
'created_at' => now(), 'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'group_id' => 100, 'key' => 'secret', 'title' => 'SecretKey', 'describe' => '',
|
||||
'values' => 'test_secret', 'type' => 'Input', 'options' => null, 'props' => null, 'sort' => 1,
|
||||
'created_at' => now(), 'updated_at' => now(),
|
||||
],
|
||||
]);
|
||||
SysSiteConfigService::refreshSiteConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user