sku完成,订单、商品上下架管理正在搞

This commit is contained in:
2025-05-21 17:04:10 +08:00
parent 035ab1105c
commit fc503cb95a
18 changed files with 239579 additions and 22 deletions

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Enum\order;
/**
* 状态码定义
*/
enum OrderStatusEnum: int
{
// 状态 0待支付 1待发货 2待收货 3已收货 4待评价 5已评价 6申请退款 7同意退款 8拒绝退款 9异常订单 10投诉订单 11已取消 12已过期
case WAIT_PAY = 0;
case WAIT_SHIP = 1;
case WAIT_RECEIVE = 2;
case WAIT_COMMENT = 3;
case WAIT_REFUND = 4;
case REFUND_APPLY = 5;
case REFUND_AGREE = 6;
case REFUND_REFUSE = 7;
case REFUND_SUCCESS = 8;
case EXCEPTION = 9;
case COMPLAIN = 10;
case CANCEL = 11;
case EXPIRED = 12;
public function description(): string
{
return match ($this) {
self::WAIT_PAY => '待支付',
self::WAIT_SHIP => '待发货',
self::WAIT_RECEIVE => '待收货',
self::WAIT_COMMENT => '待评价',
self::WAIT_REFUND => '待退款',
self::REFUND_APPLY => '申请退款',
self::REFUND_AGREE => '同意退款',
self::REFUND_REFUSE => '拒绝退款',
self::REFUND_SUCCESS => '退款成功',
self::EXCEPTION => '异常订单',
self::COMPLAIN => '投诉订单',
self::CANCEL => '取消订单',
self::EXPIRED => '订单过期',
default => '未知状态',
};
}
public function getColor()
{
return match ($this) {
self::WAIT_PAY => 'primary', // 蓝色:代表等待行动的状态
self::WAIT_SHIP => 'success', // 绿色:代表正常流程中的积极状态
self::WAIT_RECEIVE => 'warning', // 橙色:代表进行中的过渡状态
self::WAIT_COMMENT => 'info', // 浅蓝色:代表可操作但非紧急的状态
self::WAIT_REFUND => 'warning', // 橙色:代表需要关注的状态
self::REFUND_APPLY => 'danger', // 红色:代表需要紧急处理的状态
self::REFUND_AGREE => 'warning', // 橙色:代表处理中的过渡状态
self::REFUND_REFUSE => 'dark', // 深灰色:代表已处理的负面状态
self::REFUND_SUCCESS => 'success', // 绿色:代表成功完成的状态
self::EXCEPTION => 'danger', // 红色:代表需要紧急处理的异常情况
self::COMPLAIN => 'danger', // 红色:代表需要紧急处理的投诉情况
self::CANCEL => 'secondary', // 浅灰色:代表已取消的中性状态
self::EXPIRED => 'secondary', // 浅灰色:代表已过期的中性状态
default => 'secondary', // 浅灰色:代表未知状态
};
}
}

View File

@@ -15,4 +15,35 @@ class OrderController extends BaseController
$this->updateField = ["id","user_id","order_no","order_status","total_amount"];
$this->service = OrderService::getInstance();
}
public function generateOrder()
{
// $this->insertField = [
// 'products',
// 'address_id'
// ];
// $params = $this->checkRequiredFields(request()->post());
$params = [
'products' => [
[
'id' => 3,
'sku_id' => 1,
'number' => 2
],
[
'id' => 3,
'sku_id' => 7,
'number' => 10
],
],
'address_id' => 2,
'user_remarks' => '测试订单'
];
return jok(
$this->service->generateOrder($params),
'生成订单成功',
);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Http\Controllers\Api\CodeGeneration;
use App\BaseApp\BaseController;
use App\Service\CodeGeneration\RegionService;
class RegionController extends BaseController
{
//
public function __construct()
{
parent::__construct();
$this->insertField = ["name","pid", 'price'];
$this->updateField = ["id","name","pid", 'price'];
$this->service = RegionService::getInstance();
}
}

View File

@@ -4,6 +4,9 @@ namespace App\Http\Controllers\Api\CodeGeneration;
use App\BaseApp\BaseController;
use App\Service\CodeGeneration\SkuService;
use Illuminate\Http\JsonResponse;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class SkuController extends BaseController
{
@@ -15,4 +18,20 @@ class SkuController extends BaseController
$this->updateField = ["id","product_id","cover", "name","inventory","price"];
$this->service = SkuService::getInstance();
}
/**
* 获取sku列表根据商品id
* @Method GET
* @return JsonResponse
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function getSkuByProductId()
{
$id = request()->get('id');
if (!$id) {
return jerr('参数错误');
}
return jok($this->service->getSkuByProductId($id));
}
}

View File

@@ -11,8 +11,8 @@ class UserReceivingAddressController extends BaseController
public function __construct()
{
parent::__construct();
$this->insertField = ["user_id","province","city","district","detailed_address","complete_address"];
$this->updateField = ["id","user_id","province","city","district","detailed_address","complete_address"];
$this->insertField = ["user_id", "total_address","detailed_address", "name", "phone", "is_default",];
$this->updateField = ["id","user_id", "total_address","detailed_address", "name", "phone", "is_default",];
$this->service = UserReceivingAddressService::getInstance();
}
}

View File

@@ -14,4 +14,14 @@ class OrderModel extends BaseModel
* @var list<string>
*/
protected $guarded = [];
public function user()
{
return $this->hasOne(UserModel::class, 'id', 'user_id');
}
public function detail()
{
return $this->hasMany(OrderDetailModel::class, 'order_id', 'id');
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Models;
use App\BaseApp\BaseModel;
class RegionModel extends BaseModel
{
protected $table = 'region';
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $guarded = [];
}

View File

@@ -19,4 +19,19 @@ class UserReceivingAddressModel extends BaseModel
{
return $this->hasOne(UserModel::class, 'id', 'user_id');
}
public function provinceInfo()
{
return $this->hasOne(RegionModel::class, 'id', 'province');
}
public function cityInfo()
{
return $this->hasOne(RegionModel::class, 'id', 'city');
}
public function districtInfo()
{
return $this->hasOne(RegionModel::class, 'id', 'district');
}
}

View File

@@ -3,8 +3,15 @@
namespace App\Service\CodeGeneration;
use App\BaseApp\BaseService;
use App\Enum\order\OrderStatusEnum;
use App\Models\OrderDetailModel;
use App\Models\OrderModel;
use App\Models\ProductModel;
use App\Models\SkuModel;
use App\Models\UserModel;
use App\Models\UserReceivingAddressModel;
use Exception;
use Illuminate\Support\Facades\DB;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
@@ -16,6 +23,9 @@ class OrderService extends BaseService
$this->selectField = ["id", "user_id", "order_no", "order_status", "total_amount", "status", "created_at", "updated_at", "deleted_at"];
$this->queryField = ['user_id' => '=','order_no' => 'like','order_status' => '=,status='];
$this->model = OrderModel::class;
$this->with = [
'user:id,nick_name,avatar'
];
}
/**
@@ -26,7 +36,12 @@ class OrderService extends BaseService
*/
public function list(): array
{
return $this->getPageList();
$result = $this->getPageList();
foreach ($result['items'] as &$v) {
$v['status_text'] = OrderStatusEnum::from($v['status'])->description();
$v['status_color'] = OrderStatusEnum::from($v['status'])->getColor();
}
return $result;
}
/**
@@ -37,7 +52,16 @@ class OrderService extends BaseService
*/
public function detail($id)
{
return $this->getDetail($id);
$this->selectField[] = 'recipient';
$this->with[] = 'detail:id,order_id,product_id,sku_id,price,quantity,subtotal,snapshot';
$result = $this->getDetail($id);
$result['status_text'] = OrderStatusEnum::from($result['status'])->description();
$result['status_color'] = OrderStatusEnum::from($result['status'])->getColor();
$result['recipient'] = json_decode($result['recipient'], true);
foreach ($result['detail'] as &$v) {
$v['snapshot'] = !empty($v['snapshot']) ? json_decode($v['snapshot'], true) : [];
}
return $result;
}
/**
@@ -84,4 +108,97 @@ class OrderService extends BaseService
return $this->del($ids);
}
public function generateOrder($params)
{
$userIds = UserModel::pluck('id');
$userId = $userIds->random();
$skuIds = array_column($params['products'], 'sku_id');
$skuQuantity = array_column($params['products'], 'number', 'sku_id');
$skus = SkuModel::with('product')->whereIn('id', $skuIds)->get();
if (empty($skus)) {
$this->utils->errorThrow('商品sku不存在');
}
$skus = $skus->toArray();
$skuGetIds = array_column($skus, 'id');
// 对比skuIds和skuGetIds如果传入的skuId不存在于skuGetIds中则抛出异常
$diffSkuIds = array_diff($skuIds, $skuGetIds);
if ($diffSkuIds) {
$this->utils->errorThrow('商品sku不存在SkuId'. implode(',', $diffSkuIds));
}
// 获取收件人地址
$recipient = $this->getRecipientInfo($params['address_id']?? 0);
// 生成订单号
$orderNo = $this->utils->genOrderNo();
$orderInsertData = [
'user_id' => $userId,
'order_no' => $orderNo,
'total_amount' => 0,
'recipient' => $recipient,
'user_remarks' => $params['user_remarks'] ?? '',
'status' => 0,
];
DB::beginTransaction();
try {
$totalAmount = 0;
$orderId = $this->insert($orderInsertData);
if (!$orderId) {
$this->utils->errorThrow('订单生成失败!');
}
$orderProducts = [];
foreach ($skus as $v) {
$subtotal = bcmul($v['price'], $skuQuantity[$v['id']], 2);
$orderProducts[] = [
'order_id' => $orderId,
'product_id' => $v['product_id'],
'sku_id' => $v['id'],
'price' => $v['price'],
'quantity' => $skuQuantity[$v['id']],
'subtotal' => $subtotal,
'snapshot' => json_encode($v),
];
$totalAmount = bcadd($totalAmount, $subtotal, 2);
}
$orderDetailInsertModel = OrderDetailModel::insert($orderProducts);
if (!$orderDetailInsertModel) {
$this->utils->errorThrow('订单商品生成失败!');
}
$orderUpdateModel = $this->update($orderId, [
'total_amount' => $totalAmount,
]);
if (!$orderUpdateModel) {
$this->utils->errorThrow('订单生成失败!');
}
DB::commit();
} catch (Exception $e) {
DB::rollBack();
$this->utils->errorThrow($e->getMessage());
}
return $orderId;
}
public function getRecipientInfo($id = null)
{
if (empty($id)) {
$this->utils->errorThrow('请选择收件人!');
}
$recipientInfo = UserReceivingAddressModel::where('id', $id)->first();
$recipientInfo['copy_text'] = "{$recipientInfo['name']} {$recipientInfo['phone']} {$recipientInfo['complete_address']}";
return json_encode($recipientInfo);
}
}

View File

@@ -37,6 +37,14 @@ class ProductService extends BaseService
*/
public function list(): array
{
$this->with = [
'images:id,product_id,url',
'mall:id,name,avatar',
'user:id,nick_name,avatar',
'labels',
'classification',
'skus:id,product_id,name,cover,price,inventory',
];
$result = $this->getPageList();
foreach ($result['items'] as &$v) {
$v['images'] = array_column($v['images'], 'url');

View File

@@ -0,0 +1,87 @@
<?php
namespace App\Service\CodeGeneration;
use App\BaseApp\BaseService;
use App\Models\RegionModel;
use Exception;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
class RegionService extends BaseService
{
public function __construct()
{
parent::__construct();
$this->selectField = ["id", "name", "pid", "status", "price", "created_at", "updated_at", "deleted_at"];
$this->queryField = ['name' => '=','pid' => '=,status='];
$this->model = RegionModel::class;
}
/**
* 获取地区列表
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function list(): array
{
return $this->getPageList();
}
/**
* 获取地区详情
* @param $id
* @return mixed
* @throws Exception
*/
public function detail($id)
{
return $this->getDetail($id);
}
/**
* 地区下拉列表
* @return mixed
*/
public function option()
{
$this->optionField = ['id', 'name'];
return $this->getOption();
}
/**
* 创建地区
* @param $params
* @return mixed
* @throws Exception
*/
public function create($params): mixed
{
return $this->insert($params);
}
/**
* 编辑地区
* @param $id
* @param $params
* @return mixed
* @throws Exception
*/
public function update($id, $params): mixed
{
return $this->save($id, $params);
}
/**
* 删除地区
* @param $ids
* @return mixed|true
* @throws Exception
*/
public function delete($ids): mixed
{
return $this->del($ids);
}
}

View File

@@ -21,6 +21,11 @@ class SkuService extends BaseService
];
}
public function getSkuByProductId($id)
{
return $this->model::where('product_id', $id)->orderBy('id', 'desc')->get();
}
/**
* 获取sku管理列表
* @return array

View File

@@ -3,6 +3,7 @@
namespace App\Service\CodeGeneration;
use App\BaseApp\BaseService;
use App\Models\RegionModel;
use App\Models\UserReceivingAddressModel;
use Exception;
use Psr\Container\ContainerExceptionInterface;
@@ -13,9 +14,15 @@ class UserReceivingAddressService extends BaseService
public function __construct()
{
parent::__construct();
$this->selectField = ["id", "user_id", "province", "city", "district", "detailed_address", "complete_address", "status", "created_at", "updated_at", "deleted_at"];
$this->selectField = ["id", "user_id", "province", "total_address", "city", "district", "name", "phone", "is_default", "detailed_address", "complete_address", "status", "created_at", "updated_at", "deleted_at"];
$this->queryField = ['user_id' => '=','province' => '=','city' => '=','district' => '=','detailed_address' => '=','complete_address' => '=,status='];
$this->model = UserReceivingAddressModel::class;
$this->with = [
'user:id,nick_name',
'provinceInfo:id,name',
'cityInfo:id,name',
'districtInfo:id,name',
];
}
/**
@@ -26,7 +33,11 @@ class UserReceivingAddressService extends BaseService
*/
public function list(): array
{
return $this->getPageList();
$result = $this->getPageList();
foreach ($result['items'] as &$v) {
$v['total_address'] = json_decode($v['total_address']);
}
return $result;
}
/**
@@ -58,6 +69,7 @@ class UserReceivingAddressService extends BaseService
*/
public function create($params): mixed
{
$params = $this->checkAddress($params);
return $this->insert($params);
}
@@ -70,6 +82,7 @@ class UserReceivingAddressService extends BaseService
*/
public function update($id, $params): mixed
{
$params = $this->checkAddress($params);
return $this->save($id, $params);
}
@@ -84,4 +97,15 @@ class UserReceivingAddressService extends BaseService
return $this->del($ids);
}
public function checkAddress($params)
{
$data = RegionModel::whereIn('id', $params['total_address'])->get(['id', 'name']);
$regionName = array_column($data->toArray(), 'name');
$params['complete_address'] = implode('', $regionName). ' '. $params['detailed_address'];
$params['province'] = $params['total_address'][0];
$params['city'] = $params['total_address'][1];
$params['district'] = $params['total_address'][2];
$params['total_address'] = json_encode($params['total_address']);
return $params;
}
}

View File

@@ -185,15 +185,53 @@ class UtilsService
*/
public function genOrderNo(int $type = 0): string
{
$len = 9999999999;
switch ($type) {
case 0:
return 'DK' . date('Ymd') . str_pad(mt_rand(1, $len), 11, '0', STR_PAD_LEFT);
case 1:
return 'DD' . date('Ymd') . str_pad(mt_rand(1, $len), 11, '0', STR_PAD_LEFT);
default:
return '';
$prefix = ['NL', 'TX', 'TK'];
$datePart = date('Ymd');
// 确保len不超过PHP_INT_MAX避免整数溢出
$maxLen = PHP_INT_MAX;
// 使用bcmath扩展生成安全的大数随机数
if (function_exists('bcadd') && function_exists('bcmul')) {
// 生成一个10位的随机字符串作为基础
$randomBase = '';
for ($i = 0; $i < 10; $i++) {
$randomBase .= mt_rand(0, 9);
}
// 使用bcmath计算一个大数随机数
$randomPart = bcadd(
'1', // 确保最小值为1
bcmul(
$randomBase,
bcdiv((string)$maxLen, '10000000000', 0),
0
)
);
// 截取前11位数字
$randomStr = substr($randomPart, 0, 11);
} else {
// 备用方案使用mt_rand并处理溢出
$randomNum = mt_rand(1, $maxLen);
$randomStr = (string)$randomNum;
// 如果长度不足11位左侧补0
if (strlen($randomStr) < 11) {
$randomStr = str_pad($randomStr, 11, '0', STR_PAD_LEFT);
} else {
// 如果长度超过11位截取前11位
$randomStr = substr($randomStr, 0, 11);
}
}
// 确保随机部分长度为11
$paddedRandom = str_pad($randomStr, 11, '0', STR_PAD_LEFT);
$paddedRandom = substr($paddedRandom, -11); // 确保最终长度为11
// 返回格式化后的代码
return isset($prefix[$type]) ? $prefix[$type] . $datePart . $paddedRandom : '';
}
/**

View File

@@ -10,7 +10,8 @@
"ext-zip": "*",
"firebase/php-jwt": "^6.11",
"laravel/framework": "^12.0",
"laravel/tinker": "^2.10.1"
"laravel/tinker": "^2.10.1",
"ext-bcmath": "*"
},
"require-dev": {
"fakerphp/faker": "^1.23",

239103
public/address.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
<div class="container mx-auto px-4 py-8">
<div class="bg-white rounded-xl shadow-lg p-6 mb-8">
<h1 class="text-3xl font-bold text-gray-800 mb-4 flex items-center">
<i class="fa fa-road mr-3 text-primary"></i>应用路由信息
<i class="fa fa-road mr-3 text-primary"></i>应用路由信息 {{ count($routes) }}
</h1>
<p class="text-gray-600 mb-6">这里展示了应用中所有已注册的路由信息包括请求方法、URI、名称、控制器和中间件。</p>
@@ -14,7 +14,7 @@
<div class="mb-6 flex flex-col md:flex-row justify-between items-start md:items-center space-y-4 md:space-y-0">
<div class="flex flex-wrap gap-2">
<button class="view-toggle-btn active px-4 py-2 rounded-lg bg-primary text-white font-medium transition-all duration-200" data-view="all">
<i class="fa fa-list-ul mr-1"></i>全部路由 {{ count($routes) }}
<i class="fa fa-list-ul mr-1"></i>全部路由
</button>
<button class="view-toggle-btn px-4 py-2 rounded-lg bg-gray-100 text-gray-700 font-medium transition-all duration-200 hover:bg-gray-200" data-view="groups">
<i class="fa fa-th-large mr-1"></i>分组视图

View File

@@ -42,9 +42,8 @@ Route::group([], function () {
'product-label-relations' => \App\Http\Controllers\Api\CodeGeneration\ProductLabelRelationsController::class, // 商品标签关联
'order' => \App\Http\Controllers\Api\CodeGeneration\OrderController::class, // 订单管理
'order-detail' => \App\Http\Controllers\Api\CodeGeneration\OrderDetailController::class, // 订单详情
'order-detail' => \App\Http\Controllers\Api\CodeGeneration\OrderDetailController::class, // 订单详情
'order-detail' => \App\Http\Controllers\Api\CodeGeneration\OrderDetailController::class, // 订单详情
'sku' => \App\Http\Controllers\Api\CodeGeneration\SkuController::class, // sku管理
'region' => \App\Http\Controllers\Api\CodeGeneration\RegionController::class, // 地区
// 需要登录的路由生成地址
]);
});