Compare commits
No commits in common. 'main' and 'liheng_branch' have entirely different histories.
main
...
liheng_bra
@ -1,18 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
||||
[docker-compose.yml]
|
||||
indent_size = 4
|
@ -1,52 +0,0 @@
|
||||
APP_NAME=moon-shop
|
||||
APP_ENV=product
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_LOG_LEVEL=debug
|
||||
# 请务必修改此项为自己的 URL
|
||||
APP_URL=http://shop.shiguopeng.cn
|
||||
|
||||
# 数据库设置
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=
|
||||
DB_USERNAME=
|
||||
DB_PASSWORD=
|
||||
|
||||
|
||||
# 缓存, session, 队列驱动设置
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
QUEUE_DRIVER=database
|
||||
|
||||
# redis 数据库配置
|
||||
REDIS_HOST=
|
||||
REDIS_PASSWORD=
|
||||
REDIS_PORT=6379
|
||||
|
||||
# 邮箱设置
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_HOST=smtp.qq.com
|
||||
MAIL_PORT=465
|
||||
MAIL_USERNAME=
|
||||
MAIL_PASSWORD=
|
||||
MAIL_FROM_ADDRESS=
|
||||
MAIL_FROM_NAME=MondayShop
|
||||
MAIL_ENCRYPTION=ssl
|
||||
|
||||
# 第三方互联登录
|
||||
OAUTH_GITHUB_ID=
|
||||
OAUTH_GITHUB_SECRET=
|
||||
OAUTH_QQ_ID=
|
||||
OAUTH_WEIBO_ID=
|
||||
|
||||
# 支付宝支付
|
||||
ALIAPY_APP_ID=
|
||||
|
||||
|
||||
JWT_SECRET=
|
||||
|
||||
# Docker 运行必须是 0.0.0.0
|
||||
LARAVELS_LISTEN_IP=0.0.0.0
|
@ -1,11 +0,0 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
*.blade.php diff=html
|
||||
*.css diff=css
|
||||
*.html diff=html
|
||||
*.md diff=markdown
|
||||
*.php diff=php
|
||||
|
||||
/.github export-ignore
|
||||
CHANGELOG.md export-ignore
|
||||
.styleci.yml export-ignore
|
@ -1,20 +0,0 @@
|
||||
/.phpunit.cache
|
||||
/node_modules
|
||||
/public/build
|
||||
/public/hot
|
||||
/public/storage
|
||||
/storage/*.key
|
||||
/vendor
|
||||
.env
|
||||
.env.backup
|
||||
.env.production
|
||||
.phpunit.result.cache
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
auth.json
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
/.fleet
|
||||
/.idea
|
||||
/.vscode
|
||||
rr
|
@ -1,21 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Use this section to tell people about which versions of your project are
|
||||
currently being supported with security updates.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 5.1.x | :white_check_mark: |
|
||||
| 5.0.x | :x: |
|
||||
| 4.0.x | :white_check_mark: |
|
||||
| < 4.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Use this section to tell people how to report a vulnerability.
|
||||
|
||||
Tell them where to go, how often they can expect to get an update on a
|
||||
reported vulnerability, what to expect if the vulnerability is accepted or
|
||||
declined, etc.
|
@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Actions\Post;
|
||||
|
||||
use App\Models\Product;
|
||||
use Encore\Admin\Actions\RowAction;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ForceDeleteProductAction extends RowAction
|
||||
{
|
||||
// 动作名称,显示在界面上的按钮文本
|
||||
public $name = '删除';
|
||||
|
||||
/**
|
||||
* 处理强制删除产品的逻辑
|
||||
*
|
||||
* @param Product $product 被删除的产品模型
|
||||
* @return \Encore\Admin\Actions\Response 返回操作结果的响应
|
||||
*/
|
||||
public function handle(Product $product)
|
||||
{
|
||||
// 调用模型的 forceDelete 方法,永久删除产品
|
||||
$product->forceDelete();
|
||||
|
||||
// 返回成功响应并刷新页面
|
||||
return $this->response()->success('操作成功.')->refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从请求中检索产品模型
|
||||
*
|
||||
* @param Request $request 当前请求实例
|
||||
* @return Product|false 返回找到的产品模型或 false
|
||||
*/
|
||||
public function retrieveModel(Request $request)
|
||||
{
|
||||
// 从请求中获取 '_key' 参数
|
||||
if (!$key = $request->get('_key')) {
|
||||
return false; // 如果没有找到 '_key',返回 false
|
||||
}
|
||||
|
||||
// 使用 withTrashed 方法查询包括已删除的产品,并根据找到的键查找产品
|
||||
return Product::query()->withTrashed()->findOrFail($key);
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Actions\Post;
|
||||
|
||||
use App\Enums\OrderShipStatusEnum;
|
||||
use App\Enums\OrderStatusEnum;
|
||||
use App\Models\Order;
|
||||
use Encore\Admin\Actions\RowAction;
|
||||
|
||||
class OrderReceivedAction extends RowAction
|
||||
{
|
||||
// 动作名称,显示在界面上的按钮文本
|
||||
public $name = '确认收货';
|
||||
|
||||
/**
|
||||
* 处理确认收货的逻辑
|
||||
*
|
||||
* @param Order $order 当前订单模型实例
|
||||
* @return \Encore\Admin\Actions\Response 返回操作结果的响应
|
||||
*/
|
||||
public function handle(Order $order)
|
||||
{
|
||||
// 检查订单状态是否为已付款
|
||||
if ($order->status != OrderStatusEnum::PAID) {
|
||||
// 如果未付款,返回错误信息
|
||||
return back()->withErrors('订单未付款', 'error');
|
||||
}
|
||||
|
||||
// 检查订单的发货状态是否为已发货
|
||||
if ($order->ship_status != OrderShipStatusEnum::DELIVERED) {
|
||||
// 如果未发货,返回错误信息
|
||||
return back()->withErrors('订单未发货', 'error');
|
||||
}
|
||||
|
||||
// 更新订单的发货状态为已收货
|
||||
$order->ship_status = OrderShipStatusEnum::RECEIVED;
|
||||
// 保存订单的更改
|
||||
$order->save();
|
||||
|
||||
// 返回成功响应并刷新页面
|
||||
return $this->response()->success('确认收货成功.')->refresh();
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Actions\Post;
|
||||
|
||||
use App\Enums\OrderShipStatusEnum;
|
||||
use App\Enums\OrderStatusEnum;
|
||||
use App\Models\Order;
|
||||
use Encore\Admin\Actions\RowAction;
|
||||
use Illuminate\Http\Request;
|
||||
use Yansongda\Pay\Pay;
|
||||
|
||||
class OrderRefundAction extends RowAction
|
||||
{
|
||||
// 动作名称,显示在界面上的按钮文本
|
||||
public $name = '退款';
|
||||
|
||||
/**
|
||||
* 处理订单退款的逻辑
|
||||
*
|
||||
* @param Order $order 当前订单模型实例
|
||||
* @param Request $request 当前请求实例
|
||||
* @return \Encore\Admin\Actions\Response 返回操作结果的响应
|
||||
*/
|
||||
public function handle(Order $order, Request $request)
|
||||
{
|
||||
// 检查订单状态是否为申请退款
|
||||
if ($order->status != OrderStatusEnum::APPLY_REFUND) {
|
||||
// 如果当前状态不允许退款,返回错误信息
|
||||
return $this->response()->error('订单当前状态禁止退款');
|
||||
}
|
||||
|
||||
// 创建支付宝支付实例
|
||||
$pay = Pay::alipay(config('pay.ali'));
|
||||
|
||||
// 准备退款数据
|
||||
$refundData = [
|
||||
'out_trade_no' => $order->no, // 订单号
|
||||
'trade_no' => $order->pay_no, // 支付交易号
|
||||
'refund_amount' => $order->pay_amount, // 退款金额
|
||||
'refund_reason' => '正常退款', // 退款原因
|
||||
];
|
||||
|
||||
try {
|
||||
// 发起退款请求
|
||||
$response = $pay->refund($refundData);
|
||||
|
||||
// 更新订单的退款信息
|
||||
$order->pay_refund_fee = $response->get('refund_fee'); // 设置退款金额
|
||||
$order->pay_trade_no = $response->get('trade_no'); // 设置退款交易号
|
||||
$order->status = OrderStatusEnum::REFUND; // 更新订单状态为退款
|
||||
$order->save(); // 保存订单的更改
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// 处理异常情况
|
||||
// abort(500, $e->getMessage()); // 可选:抛出异常
|
||||
return $this->response()->error('服务器异常,请稍后再试'); // 返回错误信息
|
||||
}
|
||||
|
||||
// 返回成功响应并刷新页面
|
||||
return $this->response()->success('退款成功.')->refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示退款确认对话框
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dialog()
|
||||
{
|
||||
// 确认退款操作
|
||||
$this->confirm('退款会直接把钱退回到支付账户,是否继续');
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Actions\Post;
|
||||
|
||||
use App\Enums\OrderShipStatusEnum;
|
||||
use App\Enums\OrderStatusEnum;
|
||||
use App\Models\Order;
|
||||
use Encore\Admin\Actions\RowAction;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class OrderShipAction extends RowAction
|
||||
{
|
||||
// 动作名称,显示在界面上的按钮文本
|
||||
public $name = '发货';
|
||||
|
||||
/**
|
||||
* 处理订单发货的逻辑
|
||||
*
|
||||
* @param Order $order 当前订单模型实例
|
||||
* @param Request $request 当前请求实例
|
||||
* @return \Encore\Admin\Actions\Response 返回操作结果的响应
|
||||
*/
|
||||
public function handle(Order $order, Request $request)
|
||||
{
|
||||
// 检查订单状态是否为已付款
|
||||
if ($order->status != OrderStatusEnum::PAID) {
|
||||
// 如果未付款,返回错误信息
|
||||
return $this->response()->error('订单未付款');
|
||||
}
|
||||
|
||||
// 获取物流公司和物流单号
|
||||
$company = $request->input('company'); // 物流公司
|
||||
$no = $request->input('no'); // 物流单号
|
||||
|
||||
// 检查物流公司和物流单号是否为空
|
||||
if (empty($company) || empty($no)) {
|
||||
// 如果有必填项为空,返回错误信息
|
||||
return $this->response()->error('必填项不能为空');
|
||||
}
|
||||
|
||||
// 更新订单的发货状态和物流信息
|
||||
$order->ship_status = OrderShipStatusEnum::DELIVERED; // 设置发货状态为已发货
|
||||
$order->express_company = $company; // 设置物流公司
|
||||
$order->express_no = $no; // 设置物流单号
|
||||
$order->save(); // 保存订单的更改
|
||||
|
||||
// 返回成功响应并刷新页面
|
||||
return $this->response()->success('发货成功.')->refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义发货表单
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function form()
|
||||
{
|
||||
// 定义物流公司输入框,设置为必填项
|
||||
$this->text('company', '物流公司')->required();
|
||||
// 定义物流单号输入框,设置为必填项
|
||||
$this->text('no', '物流单号')->required();
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Actions\Post;
|
||||
|
||||
use App\Models\Product;
|
||||
use Encore\Admin\Actions\RowAction;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProductStatusAction extends RowAction
|
||||
{
|
||||
// 动作名称,显示在界面上的按钮文本
|
||||
public $name = '';
|
||||
|
||||
/**
|
||||
* 设置动作名称
|
||||
*
|
||||
* @param string $name 动作名称
|
||||
* @return $this 返回当前实例,以便链式调用
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name; // 设置动作名称
|
||||
|
||||
return $this; // 返回当前实例
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理商品状态的逻辑
|
||||
*
|
||||
* @param Product $product 当前商品模型实例
|
||||
* @return \Encore\Admin\Actions\Response 返回操作结果的响应
|
||||
*/
|
||||
public function handle(Product $product)
|
||||
{
|
||||
// 检查商品是否已下架
|
||||
if ($product->trashed()) {
|
||||
// 如果商品已下架,则重新上架
|
||||
$product->restore();
|
||||
} else {
|
||||
// 如果商品未下架,则进行下架操作
|
||||
$product->delete();
|
||||
}
|
||||
|
||||
// 返回成功响应并刷新页面
|
||||
return $this->response()->success('操作成功.')->refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从请求中检索商品模型
|
||||
*
|
||||
* @param Request $request 当前请求实例
|
||||
* @return Product|false 返回找到的商品模型实例,或返回 false
|
||||
*/
|
||||
public function retrieveModel(Request $request)
|
||||
{
|
||||
// 从请求中获取商品的唯一键
|
||||
if (!$key = $request->get('_key')) {
|
||||
return false; // 如果没有提供键,则返回 false
|
||||
}
|
||||
|
||||
// 查找并返回商品模型,包括已删除的商品
|
||||
return Product::query()->withTrashed()->findOrFail($key);
|
||||
}
|
||||
}
|
@ -1,146 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use Encore\Admin\Auth\Database\Administrator;
|
||||
use Encore\Admin\Auth\Database\OperationLog;
|
||||
use Encore\Admin\Controllers\AuthController as BaseAuthController;
|
||||
use Encore\Admin\Grid;
|
||||
use Encore\Admin\Layout\Content;
|
||||
use Encore\Admin\Widgets\Box;
|
||||
use Encore\Admin\Widgets\InfoBox;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class AdminController extends BaseAuthController
|
||||
{
|
||||
/**
|
||||
* 显示管理员列表页面
|
||||
*
|
||||
* @param Content $content 内容区域
|
||||
* @return Content 返回构建好的内容
|
||||
*/
|
||||
public function index(Content $content)
|
||||
{
|
||||
return $content
|
||||
->header(trans('admin.administrator')) // 设置页面标题
|
||||
->description(trans('admin.list')) // 设置页面描述
|
||||
->body($this->adminGrid()->render()); // 渲染管理员网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建管理员网格
|
||||
*
|
||||
* @return Grid 返回管理员网格实例
|
||||
*/
|
||||
protected function adminGrid()
|
||||
{
|
||||
// 获取用户模型
|
||||
$userModel = config('admin.database.users_model');
|
||||
|
||||
// 创建新的网格实例
|
||||
$grid = new Grid(new $userModel());
|
||||
|
||||
// 定义网格的列
|
||||
$grid->column('id', 'ID')->sortable(); // ID 列,支持排序
|
||||
$grid->column('username', trans('admin.username')); // 用户名列
|
||||
$grid->column('name', trans('admin.name')); // 姓名列
|
||||
$grid->column('login_ip', '登录ip'); // 登录 IP 列
|
||||
$grid->roles(trans('admin.roles'))->pluck('name')->label(); // 角色列,显示角色名称
|
||||
$grid->column('created_at', trans('admin.created_at')); // 创建时间列
|
||||
$grid->column('updated_at', trans('admin.updated_at')); // 更新时间列
|
||||
|
||||
// 自定义操作按钮
|
||||
$grid->actions(function (Grid\Displayers\DropdownActions $actions) {
|
||||
// 禁用 ID 为 1 的管理员的删除操作
|
||||
if ($actions->getKey() == 1) {
|
||||
$actions->disableDelete();
|
||||
}
|
||||
});
|
||||
|
||||
// 自定义工具栏
|
||||
$grid->tools(function (Grid\Tools $tools) {
|
||||
$tools->batch(function (Grid\Tools\BatchActions $actions) {
|
||||
// 禁用批量删除操作
|
||||
$actions->disableDelete();
|
||||
});
|
||||
});
|
||||
|
||||
return $grid; // 返回创建的网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示操作日志页面
|
||||
*
|
||||
* @param Content $content 内容区域
|
||||
* @return Content 返回构建好的内容
|
||||
*/
|
||||
public function indexLogs(Content $content)
|
||||
{
|
||||
return $content
|
||||
->header(trans('admin.operation_log')) // 设置页面标题
|
||||
->description(trans('admin.list')) // 设置页面描述
|
||||
->body($this->logGrid()); // 渲染操作日志网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建操作日志网格
|
||||
*
|
||||
* @return Grid 返回操作日志网格实例
|
||||
*/
|
||||
protected function logGrid()
|
||||
{
|
||||
// 创建新的操作日志网格实例
|
||||
$grid = new Grid(new OperationLog());
|
||||
|
||||
// 按照 ID 降序排列
|
||||
$grid->model()->orderBy('id', 'DESC');
|
||||
|
||||
// 定义网格的列
|
||||
$grid->column('id', 'ID')->sortable(); // ID 列,支持排序
|
||||
$grid->column('user.name', '用户'); // 用户列,显示用户名
|
||||
$grid->column('method', '方法')->display(function ($method) {
|
||||
// 根据方法类型设置颜色
|
||||
$color = array_get(OperationLog::$methodColors, $method, 'grey');
|
||||
return "<span class=\"badge bg-$color\">$method</span>"; // 返回带颜色的标签
|
||||
});
|
||||
$grid->column('path', '路径')->label('info'); // 路径列
|
||||
$grid->column('ip', '地址')->label('primary'); // IP 地址列
|
||||
$grid->column('description', '描述')->limit(20)->modal(function ($model) {
|
||||
// 描述列,点击可弹出详细信息
|
||||
return new Box('详情', $model->description ?: ' ');
|
||||
});
|
||||
$grid->column('input', '输入数据')->limit(20)->expand(function ($model) {
|
||||
// 输入数据列,点击可展开显示详细信息
|
||||
$input = json_decode($model->input, true);
|
||||
$input = array_except($input, ['_pjax', '_token', '_method', '_previous_']);
|
||||
$codes = empty($input) ?
|
||||
'<code>{}</code>' :
|
||||
'<pre>' . json_encode($input, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . '</pre>';
|
||||
return new Box('详情', $codes); // 返回输入数据的详细信息
|
||||
});
|
||||
|
||||
$grid->column('created_at', trans('admin.created_at')); // 创建时间列
|
||||
|
||||
// 自定义操作按钮
|
||||
$grid->actions(function (Grid\Displayers\Actions $actions) {
|
||||
$actions->disableEdit(); // 禁用编辑操作
|
||||
$actions->disableView(); // 禁用查看操作
|
||||
});
|
||||
|
||||
$grid->disableCreateButton(); // 禁用创建按钮
|
||||
|
||||
// 自定义过滤器
|
||||
$grid->filter(function (Grid\Filter $filter) {
|
||||
$userModel = config('admin.database.users_model');
|
||||
|
||||
// 添加过滤选项
|
||||
$filter->equal('user_id', 'User')->select($userModel::all()->pluck('name', 'id')); // 按用户过滤
|
||||
$filter->equal('method')->select(array_combine(OperationLog::$methods, OperationLog::$methods)); // 按方法过滤
|
||||
$filter->like('path'); // 按路径过滤
|
||||
$filter->equal('ip'); // 按 IP 过滤
|
||||
});
|
||||
|
||||
return $grid; // 返回创建的操作日志网格
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Models\ArticleNotification;
|
||||
use Encore\Admin\Controllers\AdminController;
|
||||
use Encore\Admin\Form;
|
||||
use Encore\Admin\Grid;
|
||||
use Encore\Admin\Show;
|
||||
|
||||
class ArticleNotificationController extends AdminController
|
||||
{
|
||||
/**
|
||||
* 当前资源的标题
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = '通知文章';
|
||||
|
||||
/**
|
||||
* 创建网格构建器
|
||||
*
|
||||
* @return Grid 返回网格实例
|
||||
*/
|
||||
protected function grid()
|
||||
{
|
||||
// 创建新的网格实例
|
||||
$grid = new Grid(new ArticleNotification);
|
||||
|
||||
// 按照最新的通知排序
|
||||
$grid->model()->latest();
|
||||
|
||||
// 定义网格的列
|
||||
$grid->column('id', __('Id')); // ID 列
|
||||
$grid->column('title', __('Title')); // 标题列
|
||||
$grid->column('created_at', __('Created at')); // 创建时间列
|
||||
|
||||
// 定义过滤器
|
||||
$grid->filter(function (Grid\Filter $filter) {
|
||||
$filter->like('id', __('Id')); // 按 ID 过滤
|
||||
$filter->like('title', __('Title')); // 按标题过滤
|
||||
});
|
||||
|
||||
// 自定义操作按钮
|
||||
$grid->actions(function (Grid\Displayers\DropdownActions $actions) {
|
||||
$actions->disableEdit(); // 禁用编辑操作
|
||||
});
|
||||
|
||||
return $grid; // 返回创建的网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建详情展示构建器
|
||||
*
|
||||
* @param mixed $id 通知文章的 ID
|
||||
* @return Show 返回详情展示实例
|
||||
*/
|
||||
protected function detail($id)
|
||||
{
|
||||
// 创建新的详情展示实例
|
||||
$show = new Show(ArticleNotification::findOrFail($id));
|
||||
|
||||
// 定义展示的字段
|
||||
$show->field('id', __('Id')); // ID 字段
|
||||
$show->field('title', __('Title')); // 标题字段
|
||||
$show->field('content', __('Content'))->unescape(); // 内容字段,允许 HTML 解码
|
||||
$show->field('created_at', __('Created at')); // 创建时间字段
|
||||
|
||||
return $show; // 返回创建的详情展示
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表单构建器
|
||||
*
|
||||
* @return Form 返回表单实例
|
||||
*/
|
||||
protected function form()
|
||||
{
|
||||
// 创建新的表单实例
|
||||
$form = new Form(new ArticleNotification);
|
||||
|
||||
// 定义表单字段
|
||||
$form->text('title', __('Title'))->help('请再三确认再发布,不可修改'); // 标题字段,带帮助信息
|
||||
$form->kindeditor('content', __('Content')); // 内容字段,使用富文本编辑器
|
||||
|
||||
// 保存事件
|
||||
$form->saving(function (Form $form) {
|
||||
// 检查当前环境是否为开发环境
|
||||
if (app()->environment('dev')) {
|
||||
admin_toastr('开发环境不允许操作', 'error'); // 提示用户
|
||||
return back()->withInput(); // 返回到表单
|
||||
}
|
||||
});
|
||||
|
||||
// 删除事件
|
||||
$form->deleting(function (Form $form) {
|
||||
// 检查当前环境是否为开发环境
|
||||
if (app()->environment('dev')) {
|
||||
admin_toastr('开发环境不允许操作', 'error'); // 提示用户
|
||||
return back()->withInput(); // 返回到表单
|
||||
}
|
||||
});
|
||||
|
||||
return $form; // 返回创建的表单
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use Encore\Admin\Auth\Database\Administrator; // 引入管理员模型
|
||||
use Encore\Admin\Controllers\AuthController as BaseAuthController; // 继承 Encore\Admin 的 AuthController
|
||||
use Encore\Admin\Facades\Admin; // 引入 Admin 门面
|
||||
use Encore\Admin\Form; // 引入表单处理类
|
||||
use Encore\Admin\Grid; // 引入 Grid 类
|
||||
use Encore\Admin\Layout\Content; // 引入布局类
|
||||
use Illuminate\Http\Request; // 引入请求类
|
||||
use Illuminate\Support\Facades\Validator; // 引入验证器
|
||||
|
||||
class AuthController extends BaseAuthController
|
||||
{
|
||||
/**
|
||||
* 覆盖默认的登录方法
|
||||
*
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function postLogin(Request $request)
|
||||
{
|
||||
// 获取用户名和密码
|
||||
$credentials = $request->only([$this->username(), 'password']);
|
||||
|
||||
/** @var \Illuminate\Validation\Validator $validator */
|
||||
// 对输入的凭证进行验证
|
||||
$validator = Validator::make($credentials, [
|
||||
$this->username() => 'required', // 用户名为必填
|
||||
'password' => 'required', // 密码为必填
|
||||
]);
|
||||
|
||||
// 如果验证失败,返回错误信息
|
||||
if ($validator->fails()) {
|
||||
return back()->withInput()->withErrors($validator);
|
||||
}
|
||||
|
||||
// 如果验证通过,尝试进行身份验证
|
||||
if ($this->guard()->attempt($credentials)) {
|
||||
// 登录成功后,执行身份验证后的操作(比如记录 IP 地址)
|
||||
$this->authenticated($this->guard()->user());
|
||||
|
||||
// 记录登录日期并返回成功响应
|
||||
return $this->sendLoginResponse($request);
|
||||
}
|
||||
|
||||
// 如果身份验证失败,返回失败信息
|
||||
return back()->withInput()->withErrors([
|
||||
$this->username() => $this->getFailedLoginMessage(), // 获取失败的登录信息
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录之后提示 IP 地址
|
||||
*
|
||||
* @param Administrator $user
|
||||
*/
|
||||
protected function authenticated(Administrator $user)
|
||||
{
|
||||
$ip = request()->getClientIp(); // 获取当前登录用户的 IP 地址
|
||||
|
||||
// 如果当前登录 IP 与上次登录的 IP 不一致,提示风险
|
||||
if (! is_null($user->login_ip) && $ip != $user->login_ip) {
|
||||
admin_info('上一次登录的地址与本次不同,如果不是本人操作,建议及时修改密码');
|
||||
}
|
||||
|
||||
// 更新用户的登录 IP 地址
|
||||
$user->login_ip = $ip;
|
||||
$user->save(); // 保存更新后的 IP 地址
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置更新操作
|
||||
*/
|
||||
public function putSetting()
|
||||
{
|
||||
$form = $this->settingForm(); // 获取设置表单
|
||||
|
||||
// 表单提交时的处理逻辑
|
||||
$form->submitted(function (Form $form) {
|
||||
// 如果是开发环境,则禁止操作
|
||||
if (app()->environment('dev')) {
|
||||
admin_toastr('开发环境不允许操作', 'error'); // 显示错误提示
|
||||
return back()->withInput(); // 返回上一页面并保留输入
|
||||
}
|
||||
});
|
||||
|
||||
// 执行设置更新
|
||||
return $form->update(Admin::user()->id); // 更新当前登录用户的设置
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Comment;
|
||||
use App\Models\Product;
|
||||
use App\Models\User;
|
||||
use Encore\Admin\Controllers\HasResourceActions;
|
||||
use Encore\Admin\Grid;
|
||||
use Encore\Admin\Layout\Content;
|
||||
|
||||
class CommentController extends Controller
|
||||
{
|
||||
use HasResourceActions; // 引入资源操作的特性
|
||||
|
||||
/**
|
||||
* 显示评论列表的界面
|
||||
*
|
||||
* @param Content $content
|
||||
* @return Content 返回构建好的内容
|
||||
*/
|
||||
public function index(Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('评论列表') // 设置页面标题
|
||||
->description('') // 页面描述
|
||||
->body($this->grid()); // 显示评论列表
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建评论列表的网格构建器
|
||||
*
|
||||
* @return Grid 返回网格实例
|
||||
*/
|
||||
protected function grid()
|
||||
{
|
||||
$grid = new Grid(new Comment); // 创建新的网格实例,基于 Comment 模型
|
||||
|
||||
$grid->model()->latest(); // 按照创建时间降序排列评论
|
||||
|
||||
// 定义网格列
|
||||
$grid->column('id'); // 评论ID
|
||||
$grid->column('order_id', '订单'); // 关联的订单ID
|
||||
$grid->column('product.name', '商品'); // 关联商品的名称
|
||||
$grid->column('user.name', '用户'); // 关联用户的名称
|
||||
$grid->column('content', '评论内容'); // 评论内容
|
||||
$grid->column('score', '评分'); // 评分
|
||||
$grid->column('created_at', '创建时间'); // 创建时间
|
||||
$grid->column('updated_at', '修改时间'); // 修改时间
|
||||
|
||||
// 定义过滤器
|
||||
$grid->filter(function (Grid\Filter $filter) {
|
||||
$filter->disableIdFilter(); // 禁用ID过滤器
|
||||
|
||||
// 用户过滤器
|
||||
$filter->where(function ($query) {
|
||||
// 根据用户名称模糊查询用户ID
|
||||
$collections = User::query()
|
||||
->where('name', 'like', "%{$this->input}%")
|
||||
->pluck('id');
|
||||
// 根据用户ID过滤评论
|
||||
$query->whereIn('user_id', $collections->all());
|
||||
}, '用户');
|
||||
|
||||
// 商品过滤器
|
||||
$filter->where(function ($query) {
|
||||
// 根据商品名称模糊查询商品ID
|
||||
$collections = Product::query()
|
||||
->where('name', 'like', "%{$this->input}%")
|
||||
->pluck('id');
|
||||
// 根据商品ID过滤评论
|
||||
$query->whereIn('product_id', $collections->all());
|
||||
}, '商品');
|
||||
});
|
||||
|
||||
return $grid; // 返回构建好的网格
|
||||
}
|
||||
}
|
@ -1,192 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Enums\UserSexEnum; // 用户性别枚举
|
||||
use App\Enums\UserSourceEnum; // 用户来源枚举
|
||||
use App\Models\CouponCode; // 优惠券兑换码模型
|
||||
use App\Models\CouponTemplate; // 优惠券模板模型
|
||||
use App\Models\User; // 用户模型
|
||||
use App\Notifications\CouponCodeNotification; // 优惠券通知
|
||||
use Carbon\Carbon; // 日期时间处理库
|
||||
use Encore\Admin\Controllers\AdminController; // 管理员控制器基类
|
||||
use Encore\Admin\Form; // 表单构建器
|
||||
use Encore\Admin\Grid; // 网格构建器
|
||||
use Encore\Admin\Show; // 展示构建器
|
||||
use Illuminate\Http\Request; // 请求处理
|
||||
use Illuminate\Notifications\DatabaseNotification; // 数据库通知模型
|
||||
use Ramsey\Uuid\Uuid; // UUID生成库
|
||||
|
||||
class CouponCodeController extends AdminController
|
||||
{
|
||||
/**
|
||||
* 当前资源的标题.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = '优惠券兑换码'; // 控制器标题
|
||||
|
||||
/**
|
||||
* 创建网格构建器.
|
||||
*
|
||||
* @return Grid 返回网格实例
|
||||
*/
|
||||
protected function grid()
|
||||
{
|
||||
$grid = new Grid(new CouponCode); // 创建新的网格实例,基于 CouponCode 模型
|
||||
|
||||
$grid->model()->latest(); // 按照创建时间降序排列优惠券兑换码
|
||||
|
||||
// 定义网格列
|
||||
$grid->column('id', __('Id')); // 显示ID
|
||||
$grid->column('code', '兑换码'); // 显示兑换码
|
||||
$grid->column('user_id', __('User id')); // 显示用户ID
|
||||
$grid->column('template_id', '优惠券ID'); // 显示优惠券模板ID
|
||||
|
||||
// 关联显示用户和优惠券模板的名称
|
||||
$grid->column('user.name', '会员名'); // 显示会员名称
|
||||
$grid->column('template.title', '优惠券名'); // 显示优惠券名称
|
||||
|
||||
// 显示使用时间和通知时间
|
||||
$grid->column('used_at', __('Used at')); // 显示使用时间
|
||||
$grid->column('notification_at', '上一次发送通知时间'); // 显示上一次发送通知的时间
|
||||
$grid->column('created_at', __('Created at')); // 显示创建时间
|
||||
|
||||
// 定义过滤器
|
||||
$grid->filter(function (Grid\Filter $filter) {
|
||||
$filter->equal('code', '兑换码'); // 兑换码过滤
|
||||
$filter->like('user.name', '会员名'); // 会员名模糊查询
|
||||
$filter->equal('template.title', '优惠券名'); // 优惠券名过滤
|
||||
$filter->between('used_at')->datetime(); // 使用时间范围过滤
|
||||
});
|
||||
|
||||
// 禁用编辑和查看操作
|
||||
$grid->actions(function (Grid\Displayers\Actions $actions) {
|
||||
$actions->disableEdit(); // 禁用编辑按钮
|
||||
$actions->disableView(); // 禁用查看按钮
|
||||
});
|
||||
|
||||
return $grid; // 返回构建好的网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储新的优惠券兑换码.
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store()
|
||||
{
|
||||
$request = request(); // 获取请求实例
|
||||
|
||||
/**
|
||||
* 发放的优惠券不能为空
|
||||
* @var $template CouponTemplate
|
||||
*/
|
||||
// 根据模板ID查找优惠券模板
|
||||
$template = CouponTemplate::query()->findOrFail($request->input('template_id'));
|
||||
$today = Carbon::today(); // 获取今天的日期
|
||||
|
||||
// 检查优惠券是否过期
|
||||
if ($today->gt(Carbon::make($template->end_date))) {
|
||||
admin_error('优惠券已过期'); // 显示错误信息
|
||||
return back()->withInput(); // 返回上一个页面并保留输入
|
||||
}
|
||||
|
||||
// 如果会员 ID 不为空,则代表是指定会员发放
|
||||
if ($userIds = $request->input('user_ids')) {
|
||||
// 使用空格拆分 ID
|
||||
$ids = array_values(array_filter(explode(' ', $userIds))); // 过滤空值并重建索引
|
||||
$users = User::query()->findMany($ids); // 查找指定的用户
|
||||
} else {
|
||||
// 否则则是条件范围发放
|
||||
$query = User::query(); // 创建用户查询
|
||||
|
||||
// 获取过滤条件
|
||||
$sex = array_filter($request->input('user_sex')); // 性别
|
||||
$sources = array_filter($request->input('user_source')); // 会员来源
|
||||
$loginCount = (int)$request->input('login_count'); // 登录次数
|
||||
$scoreAll = (int)$request->input('user_score'); // 总积分
|
||||
|
||||
// 应用过滤条件
|
||||
$query->whereIn('sex', $sex)
|
||||
->whereIn('source', $sources)
|
||||
->where('login_count', '>=', $loginCount)
|
||||
->where('score_all', '>=', $scoreAll);
|
||||
$users = $query->get(); // 获取符合条件的用户
|
||||
}
|
||||
|
||||
// 开始根据用户发放优惠券
|
||||
$now = Carbon::now()->toDateTimeString(); // 获取当前时间
|
||||
$notifications = collect(); // 创建通知集合
|
||||
$codes = $users->map(function (User $user) use ($template, $notifications, $now) {
|
||||
$code = strtoupper(str_random(16)); // 生成随机兑换码
|
||||
|
||||
// 创建通知数据
|
||||
$notification = [
|
||||
'id' => Uuid::uuid4()->toString(), // 生成唯一ID
|
||||
'type' => CouponCodeNotification::class, // 通知类型
|
||||
'notifiable_id' => $user->id, // 可通知的用户ID
|
||||
'notifiable_type' => get_class($user), // 用户类型
|
||||
'data' => json_encode((new CouponCodeNotification($template, $code))->toArray($user), JSON_UNESCAPED_UNICODE), // 通知数据
|
||||
'created_at' => $now, // 创建时间
|
||||
'updated_at' => $now, // 更新时间
|
||||
];
|
||||
$notifications->push($notification); // 将通知添加到集合
|
||||
|
||||
return [
|
||||
'code' => $code, // 兑换码
|
||||
'user_id' => $user->id, // 用户ID
|
||||
'template_id' => $template->id, // 模板ID
|
||||
'notification_at' => $now, // 通知时间
|
||||
'created_at' => $now, // 创建时间
|
||||
'updated_at' => $now, // 更新时间
|
||||
];
|
||||
});
|
||||
|
||||
$size = 1000; // 每次插入的数量
|
||||
foreach (array_chunk($codes->all(), $size, true) as $chunk) {
|
||||
// 批量插入优惠券码
|
||||
CouponCode::query()->insert($chunk);
|
||||
}
|
||||
foreach (array_chunk($notifications->all(), $size, true) as $chunk) {
|
||||
// 批量插入通知
|
||||
DatabaseNotification::query()->insert($chunk);
|
||||
}
|
||||
|
||||
admin_toastr("发布成功,总共有{$users->count()}位会员符合发放条件"); // 显示成功提示
|
||||
return response()->redirectTo(admin_url('/coupon_codes')); // 重定向到优惠券兑换码列表
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表单构建器.
|
||||
*
|
||||
* @return Form 返回表单实例
|
||||
*/
|
||||
protected function form()
|
||||
{
|
||||
$form = new Form(new CouponCode); // 创建新的表单实例,基于 CouponCode 模型
|
||||
|
||||
$today = Carbon::today()->toDateString(); // 获取今天的日期
|
||||
|
||||
$form->divider('指定会员发放'); // 分隔符
|
||||
$form->text('user_ids', '会员')->help('请输入会员的ID, 多个会员用空格隔开,如果为空则代表是范围发放'); // 会员ID输入框
|
||||
|
||||
$form->divider('范围发放'); // 分隔符
|
||||
// 获取有效的优惠券模板
|
||||
$templates = CouponTemplate::query()->where('end_date', '>=', $today)->pluck('title', 'id');
|
||||
$form->checkbox('user_sex', '会员性别')->options([UserSexEnum::MAN => '男', UserSexEnum::WOMAN => '女'])->canCheckAll(); // 性别选择框
|
||||
$form->checkbox('user_source', '会员来源')->options([
|
||||
UserSourceEnum::MOON => '前台注册',
|
||||
UserSourceEnum::GITHUB => 'Github',
|
||||
UserSourceEnum::QQ => 'QQ',
|
||||
UserSourceEnum::WEIBO => '微博',
|
||||
])->canCheckAll(); // 来源选择框
|
||||
$form->number('login_count', '会员登录次数')->default(0)->help('会员登录次数大于等于给定的次数'); // 登录次数输入框
|
||||
$form->number('user_score', '会员总积分')->default(0)->help('会员给定的积分大于等于总积分'); // 总积分输入框
|
||||
|
||||
$form->divider('优惠券'); // 分隔符
|
||||
$form->select('template_id', '优惠券')->help('发放的优惠券')->options($templates)->required(); // 优惠券选择框
|
||||
|
||||
return $form; // 返回构建好的表单
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Admin\Transforms\YesNoTransform; // 引入 YesNoTransform 类,用于转换布尔值
|
||||
use App\Models\UserHasCoupon; // 引入用户优惠券记录模型
|
||||
use Encore\Admin\Controllers\AdminController; // 引入管理员控制器基类
|
||||
use Encore\Admin\Form; // 引入表单构建器
|
||||
use Encore\Admin\Grid; // 引入网格构建器
|
||||
use Encore\Admin\Show; // 引入展示构建器
|
||||
|
||||
class CouponLogController extends AdminController
|
||||
{
|
||||
/**
|
||||
* 当前资源的标题.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = '会员领取记录'; // 控制器标题
|
||||
|
||||
/**
|
||||
* 创建网格构建器.
|
||||
*
|
||||
* @return Grid 返回网格实例
|
||||
*/
|
||||
protected function grid()
|
||||
{
|
||||
$grid = new Grid(new UserHasCoupon); // 创建新的网格实例,基于 UserHasCoupon 模型
|
||||
|
||||
$grid->model()->latest(); // 按照记录创建时间降序排列
|
||||
|
||||
// 定义网格列
|
||||
$grid->column('id', __('Id')); // 显示记录ID
|
||||
$grid->column('user_id', '用户 ID'); // 显示用户ID
|
||||
$grid->column('user.name', '用户昵称'); // 显示用户昵称
|
||||
$grid->column('title', __('Title')); // 显示优惠券标题
|
||||
$grid->column('amount', '满减金额'); // 显示满减金额
|
||||
$grid->column('full_amount', __('Full amount')); // 显示满额金额
|
||||
$grid->column('start_date', __('Start date')); // 显示优惠券开始日期
|
||||
$grid->column('end_date', __('End date')); // 显示优惠券结束日期
|
||||
|
||||
// 显示是否使用的状态,使用 YesNoTransform 转换
|
||||
$grid->column('is_used', '是否使用')->display(function () {
|
||||
return YesNoTransform::trans(! is_null($this->used_at)); // 如果 used_at 不为空,则表示已使用
|
||||
});
|
||||
|
||||
$grid->column('used_at', '使用时间'); // 显示使用时间
|
||||
$grid->column('created_at', __('Created at')); // 显示创建时间
|
||||
|
||||
// 禁用操作按钮和创建按钮
|
||||
$grid->disableActions(); // 禁用操作按钮
|
||||
$grid->disableCreateButton(); // 禁用创建按钮
|
||||
|
||||
// 定义过滤器
|
||||
$grid->filter(function (Grid\Filter $filter) {
|
||||
$filter->like('title', __('Title')); // 允许通过优惠券标题进行模糊查询
|
||||
});
|
||||
|
||||
return $grid; // 返回构建好的网格
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Admin\Transforms\YesNoTransform; // 引入 YesNoTransform 类,用于转换布尔值
|
||||
use App\Models\CouponTemplate; // 引入优惠券模板模型
|
||||
use Carbon\Carbon; // 引入 Carbon 日期时间处理库
|
||||
use Encore\Admin\Controllers\AdminController; // 引入管理员控制器基类
|
||||
use Encore\Admin\Form; // 引入表单构建器
|
||||
use Encore\Admin\Grid; // 引入网格构建器
|
||||
use Encore\Admin\Show; // 引入展示构建器
|
||||
|
||||
class CouponTemplateController extends AdminController
|
||||
{
|
||||
/**
|
||||
* 当前资源的标题.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = '优惠券'; // 控制器标题
|
||||
|
||||
/**
|
||||
* 创建网格构建器.
|
||||
*
|
||||
* @return Grid 返回网格实例
|
||||
*/
|
||||
protected function grid()
|
||||
{
|
||||
$grid = new Grid(new CouponTemplate); // 创建新的网格实例,基于 CouponTemplate 模型
|
||||
|
||||
$grid->model()->latest('start_date'); // 按照开始日期降序排列优惠券模板
|
||||
|
||||
// 定义网格列
|
||||
$grid->column('id', __('Id')); // 显示记录ID
|
||||
$grid->column('title', __('Title')); // 显示优惠券标题
|
||||
$grid->column('amount', '优惠金额'); // 显示优惠金额
|
||||
$grid->column('full_amount', __('Full amount')); // 显示满额金额
|
||||
$grid->column('score', '需兑换积分'); // 显示需兑换的积分
|
||||
|
||||
// 显示有效日期范围
|
||||
$grid->column('exp_date', '有效日期')->display(function () {
|
||||
return $this->start_date . ' ~ ' . $this->end_date; // 显示开始日期和结束日期
|
||||
});
|
||||
|
||||
$today = Carbon::today(); // 获取今天的日期
|
||||
|
||||
// 显示优惠券是否有效(未过期)
|
||||
$grid->column('overtime', '是否有效(未过期)')->display(function () use ($today) {
|
||||
$endDate = Carbon::make($this->end_date); // 将结束日期转换为 Carbon 实例
|
||||
$startDate = Carbon::make($this->start_date); // 将开始日期转换为 Carbon 实例
|
||||
|
||||
// 检查是否有结束日期和开始日期
|
||||
if (is_null($endDate) || is_null($startDate)) {
|
||||
$isOver = true; // 如果没有结束日期,代表永远不过期
|
||||
} else {
|
||||
// 检查今天的日期是否在有效日期范围内
|
||||
$isOver = $today->gte($startDate) && $today->lte($endDate);
|
||||
}
|
||||
|
||||
return YesNoTransform::trans($isOver); // 使用 YesNoTransform 转换布尔值为可读格式
|
||||
});
|
||||
|
||||
$grid->column('created_at', __('Created at')); // 显示创建时间
|
||||
|
||||
// 定义过滤器
|
||||
$grid->filter(function (Grid\Filter $filter) {
|
||||
$filter->like('title', __('Title')); // 允许通过优惠券标题进行模糊查询
|
||||
});
|
||||
|
||||
return $grid; // 返回构建好的网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表单构建器.
|
||||
*
|
||||
* @return Form 返回表单实例
|
||||
*/
|
||||
protected function form()
|
||||
{
|
||||
$form = new Form(new CouponTemplate); // 创建新的表单实例,基于 CouponTemplate 模型
|
||||
|
||||
$form->text('title', __('Title')); // 输入优惠券标题
|
||||
$form->decimal('amount', '优惠金额'); // 输入优惠金额
|
||||
$form->decimal('full_amount', __('Full amount')); // 输入满额金额
|
||||
$form->number('score', __('Score')) // 输入需兑换积分
|
||||
->default(0) // 默认值为 0
|
||||
->help('设置为 0 代表无需积分即可兑换优惠券'); // 帮助提示
|
||||
$form->date('start_date', __('Start date')) // 输入开始日期
|
||||
->default(date('Y-m-d')); // 默认设置为今天
|
||||
$form->date('end_date', __('End date')) // 输入结束日期
|
||||
->default(Carbon::today()->addMonth()); // 默认设置为一个月后
|
||||
|
||||
return $form; // 返回构建好的表单
|
||||
}
|
||||
}
|
@ -1,192 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Models\Level; // 引入 Level 模型
|
||||
use App\Http\Controllers\Controller; // 引入基础控制器
|
||||
use Encore\Admin\Controllers\HasResourceActions; // 引入资源控制器特性
|
||||
use Encore\Admin\Form; // 引入表单构建器
|
||||
use Encore\Admin\Grid; // 引入网格构建器
|
||||
use Encore\Admin\Layout\Content; // 引入内容布局
|
||||
use Encore\Admin\Show; // 引入展示构建器
|
||||
|
||||
class LevelController extends Controller
|
||||
{
|
||||
use HasResourceActions; // 使用资源控制器特性,使得该控制器支持资源操作
|
||||
|
||||
/**
|
||||
* 显示列表页面.
|
||||
*
|
||||
* @param Content $content 内容布局实例
|
||||
* @return Content 返回内容布局
|
||||
*/
|
||||
public function index(Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('列表') // 设置页面标题
|
||||
->description('') // 设置页面描述(可选)
|
||||
->body($this->grid()); // 渲染网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示详情页面.
|
||||
*
|
||||
* @param mixed $id 资源 ID
|
||||
* @param Content $content 内容布局实例
|
||||
* @return Content 返回内容布局
|
||||
*/
|
||||
public function show($id, Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('详情') // 设置页面标题
|
||||
->description('') // 设置页面描述(可选)
|
||||
->body($this->detail($id)); // 渲染详情视图
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示编辑页面.
|
||||
*
|
||||
* @param mixed $id 资源 ID
|
||||
* @param Content $content 内容布局实例
|
||||
* @return Content 返回内容布局
|
||||
*/
|
||||
public function edit($id, Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('编辑') // 设置页面标题
|
||||
->description('') // 设置页面描述(可选)
|
||||
->body($this->form()->edit($id)); // 渲染编辑表单
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示创建页面.
|
||||
*
|
||||
* @param Content $content 内容布局实例
|
||||
* @return Content 返回内容布局
|
||||
*/
|
||||
public function create(Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('新建') // 设置页面标题
|
||||
->description('') // 设置页面描述(可选)
|
||||
->body($this->form()); // 渲染创建表单
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建网格构建器.
|
||||
*
|
||||
* @return Grid 返回网格实例
|
||||
*/
|
||||
protected function grid()
|
||||
{
|
||||
$grid = new Grid(new Level); // 创建新的网格实例,基于 Level 模型
|
||||
|
||||
$grid->model()->orderBy('min_score', 'desc'); // 按 min_score 降序排列
|
||||
|
||||
// 定义网格的列
|
||||
$grid->column('id', 'ID'); // 显示 ID 列
|
||||
$grid->column('icon', '图标')->image('', 90, 90); // 显示图标列,设置图像大小
|
||||
$grid->column('name', '名字')->editable(); // 显示名字列,可编辑
|
||||
$grid->column('level', '等级'); // 显示等级列
|
||||
$grid->column('min_score', '分阶'); // 显示分阶列
|
||||
$grid->column('created_at', '创建时间'); // 显示创建时间列
|
||||
$grid->column('updated_at', '更新时间'); // 显示更新时间列
|
||||
|
||||
// 自定义操作按钮
|
||||
$grid->actions(function (Grid\Displayers\Actions $actions) {
|
||||
$level = $actions->row; // 获取当前行的数据
|
||||
if (!$level->can_delete) { // 检查是否可以删除
|
||||
$actions->disableDelete(); // 禁用删除按钮
|
||||
}
|
||||
});
|
||||
|
||||
return $grid; // 返回构建好的网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建详情构建器.
|
||||
*
|
||||
* @param mixed $id 资源 ID
|
||||
* @return Show 返回展示实例
|
||||
*/
|
||||
protected function detail($id)
|
||||
{
|
||||
$show = new Show(Level::findOrFail($id)); // 查找并显示指定 ID 的 Level 记录
|
||||
|
||||
// 定义详情展示的字段
|
||||
$show->field('id', 'ID'); // 显示 ID
|
||||
$show->field('icon', '图标')->image(); // 显示图标
|
||||
$show->field('name', '名字'); // 显示名字
|
||||
$show->field('level', '等级'); // 显示等级
|
||||
$show->field('min_score', '分阶'); // 显示分阶
|
||||
$show->field('created_at', '创建时间'); // 显示创建时间
|
||||
$show->field('updated_at', '更新时间'); // 显示更新时间
|
||||
|
||||
return $show; // 返回构建好的详情视图
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表单构建器.
|
||||
*
|
||||
* @return Form 返回表单实例
|
||||
*/
|
||||
protected function form()
|
||||
{
|
||||
$form = new Form(new Level); // 创建新的表单实例,基于 Level 模型
|
||||
|
||||
// 添加图标字段,设置唯一名称
|
||||
$icon = $form->image('icon', '图标')->uniqueName();
|
||||
if (!windows_os()) { // 如果不是 Windows 系统
|
||||
$icon->resize(160, 160); // 调整图标大小
|
||||
}
|
||||
|
||||
// 添加其他字段
|
||||
$form->text('name', '名字'); // 添加名字字段
|
||||
$form->number('level', '等级'); // 添加等级字段
|
||||
$form->number('min_score', '积分'); // 添加积分字段
|
||||
|
||||
// 添加保存前的钩子
|
||||
$form->saving(function (Form $form) {
|
||||
if (app()->environment('dev')) { // 如果当前环境是开发环境
|
||||
admin_toastr('开发环境不允许操作', 'error'); // 显示错误提示
|
||||
return back()->withInput(); // 返回并保留输入
|
||||
}
|
||||
});
|
||||
|
||||
return $form; // 返回构建好的表单
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定资源.
|
||||
*
|
||||
* @param int $id 资源 ID
|
||||
* @return \Illuminate\Http\Response 返回响应
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
$level = Level::query()->findOrFail($id); // 查找指定 ID 的 Level 记录
|
||||
|
||||
if (!$level->can_delete) { // 检查是否可以删除
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => '这个等级不允许删除', // 返回错误消息
|
||||
]);
|
||||
}
|
||||
|
||||
// 尝试删除记录
|
||||
if ($level->delete()) {
|
||||
$data = [
|
||||
'status' => true,
|
||||
'message' => trans('admin.delete_succeeded'), // 返回成功消息
|
||||
];
|
||||
} else {
|
||||
$data = [
|
||||
'status' => false,
|
||||
'message' => trans('admin.delete_failed'), // 返回失败消息
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json($data); // 返回 JSON 响应
|
||||
}
|
||||
}
|
@ -1,243 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Admin\Actions\Post\OrderReceivedAction; // 引入订单已收货操作
|
||||
use App\Admin\Actions\Post\OrderRefundAction; // 引入订单退款操作
|
||||
use App\Admin\Actions\Post\OrderShipAction; // 引入订单发货操作
|
||||
use App\Admin\Extensions\ReceivedButton; // 引入收货按钮扩展
|
||||
use App\Admin\Extensions\ShipButton; // 引入发货按钮扩展
|
||||
use App\Admin\Transforms\OrderDetailTransform; // 引入订单详情转换器
|
||||
use App\Admin\Transforms\OrderPayTypeTransform; // 引入订单支付方式转换器
|
||||
use App\Admin\Transforms\OrderShipStatusTransform; // 引入订单物流状态转换器
|
||||
use App\Admin\Transforms\OrderStatusTransform; // 引入订单状态转换器
|
||||
use App\Admin\Transforms\OrderTypeTransform; // 引入订单类型转换器
|
||||
use App\Admin\Transforms\YesNoTransform; // 引入是/否转换器
|
||||
use App\Enums\OrderShipStatusEnum; // 引入订单物流状态枚举
|
||||
use App\Enums\OrderStatusEnum; // 引入订单状态枚举
|
||||
use App\Http\Controllers\Controller; // 引入基础控制器
|
||||
use App\Models\Order; // 引入订单模型
|
||||
use App\Models\User; // 引入用户模型
|
||||
use Encore\Admin\Controllers\HasResourceActions; // 引入资源控制器特性
|
||||
use Encore\Admin\Facades\Admin; // 引入 Admin 门面
|
||||
use Encore\Admin\Grid; // 引入网格构建器
|
||||
use Encore\Admin\Grid\Displayers\Actions; // 引入操作显示器
|
||||
use Encore\Admin\Grid\Filter; // 引入过滤器
|
||||
use Encore\Admin\Layout\Content; // 引入内容布局
|
||||
use Encore\Admin\Show; // 引入展示构建器
|
||||
use Encore\Admin\Widgets\Form; // 引入表单构建器
|
||||
use Illuminate\Http\Request; // 引入请求类
|
||||
use Illuminate\Support\Facades\DB; // 引入数据库门面
|
||||
use Yansongda\Pay\Pay; // 引入支付处理类
|
||||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
use HasResourceActions; // 使用资源控制器特性,使该控制器支持资源操作
|
||||
|
||||
/**
|
||||
* 显示订单列表页面.
|
||||
*
|
||||
* @param Content $content 内容布局实例
|
||||
* @return Content 返回内容布局
|
||||
*/
|
||||
public function index(Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('订单列表') // 设置页面标题
|
||||
->description('') // 设置页面描述(可选)
|
||||
->body($this->grid()); // 渲染网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示订单详情页面.
|
||||
*
|
||||
* @param mixed $id 订单 ID
|
||||
* @param Content $content 内容布局实例
|
||||
* @return Content 返回内容布局
|
||||
*/
|
||||
public function show($id, Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('详情') // 设置页面标题
|
||||
->description('') // 设置页面描述(可选)
|
||||
->body($this->detail($id)); // 渲染订单详情
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建网格构建器.
|
||||
*
|
||||
* @return Grid 返回网格实例
|
||||
*/
|
||||
protected function grid()
|
||||
{
|
||||
$grid = new Grid(new Order); // 创建新的网格实例,基于 Order 模型
|
||||
|
||||
$grid->model()->withTrashed()->latest(); // 显示软删除的记录,并按创建时间降序排列
|
||||
|
||||
// 定义网格的列
|
||||
$grid->column('id'); // 显示订单 ID
|
||||
$grid->column('no', '流水号'); // 显示订单流水号
|
||||
$grid->column('user.name', '用户'); // 显示用户名称
|
||||
$grid->column('origin_amount', '订单原价'); // 显示订单原价
|
||||
$grid->column('post_amount', '邮费'); // 显示邮费
|
||||
$grid->column('coupon_amount', '优惠'); // 显示优惠金额
|
||||
$grid->column('amount', '总价'); // 显示总价
|
||||
$grid->column('status', '状态')->display(function ($status) {
|
||||
// 如果订单已付款,显示物流状态
|
||||
if ($status == OrderStatusEnum::PAID) {
|
||||
return OrderShipStatusTransform::trans($this->ship_status); // 转换并显示物流状态
|
||||
}
|
||||
return OrderStatusTransform::trans($status); // 转换并显示订单状态
|
||||
});
|
||||
$grid->column('type', '订单类型')->display(function ($type) {
|
||||
return OrderTypeTransform::trans($type); // 转换并显示订单类型
|
||||
});
|
||||
$grid->column('pay_type', '支付方式')->display(function ($type) {
|
||||
return OrderPayTypeTransform::trans($type); // 转换并显示支付方式
|
||||
});
|
||||
$grid->column('pay_no', '支付流水号'); // 显示支付流水号
|
||||
$grid->column('paid_at', '支付时间'); // 显示支付时间
|
||||
$grid->column('consignee_name', '收货人姓名'); // 显示收货人姓名
|
||||
$grid->column('consignee_phone', '收货人手机'); // 显示收货人手机
|
||||
$grid->column('created_at', '创建时间'); // 显示创建时间
|
||||
|
||||
// 禁用行选择器和创建按钮
|
||||
$grid->disableRowSelector();
|
||||
$grid->disableCreateButton();
|
||||
|
||||
// 自定义操作按钮
|
||||
$grid->actions(function (Grid\Displayers\DropdownActions $actions) {
|
||||
$order = $actions->row; // 获取当前行的订单数据
|
||||
|
||||
// 根据订单状态添加相应的操作按钮
|
||||
if ($order->status == OrderStatusEnum::APPLY_REFUND) {
|
||||
$actions->add(new OrderRefundAction()); // 添加退款操作按钮
|
||||
} elseif ($order->status == OrderStatusEnum::PAID) {
|
||||
if ($order->ship_status == OrderShipStatusEnum::PENDING) {
|
||||
$actions->add(new OrderShipAction()); // 添加发货操作按钮
|
||||
} elseif ($order->ship_status == OrderShipStatusEnum::DELIVERED) {
|
||||
$actions->add(new OrderReceivedAction()); // 添加确认收货操作按钮
|
||||
}
|
||||
}
|
||||
|
||||
$actions->disableEdit(); // 禁用编辑按钮
|
||||
});
|
||||
|
||||
// 添加过滤器
|
||||
$grid->filter(function (Filter $filter) {
|
||||
$filter->disableIdFilter(); // 禁用 ID 过滤
|
||||
$filter->like('no', '流水号'); // 添加流水号模糊查询
|
||||
$filter->where(function ($query) {
|
||||
// 根据用户名称查询用户 ID
|
||||
$users = User::query()->where('name', 'like', "%{$this->input}%")->pluck('id');
|
||||
$query->whereIn('user_id', $users->all()); // 根据用户 ID 查询订单
|
||||
}, '用户');
|
||||
});
|
||||
|
||||
return $grid; // 返回构建好的网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建订单详情展示构建器.
|
||||
*
|
||||
* @param mixed $id 订单 ID
|
||||
* @return Show 返回展示实例
|
||||
*/
|
||||
protected function detail($id)
|
||||
{
|
||||
$show = new Show(Order::query()->withTrashed()->findOrFail($id)); // 查找并显示指定 ID 的订单记录
|
||||
|
||||
// 定义详情展示的字段
|
||||
$show->field('id'); // 显示订单 ID
|
||||
$show->field('no', '流水号'); // 显示订单流水号
|
||||
$show->field('user', '用户')->as(function ($user) {
|
||||
return optional($user)->name; // 显示用户名称
|
||||
});
|
||||
|
||||
$show->divider(); // 添加分隔线
|
||||
|
||||
$show->field('amount', '总计'); // 显示订单总计
|
||||
$show->field('status', '状态')->as(function ($status) {
|
||||
// 如果订单已付款,显示物流状态
|
||||
if ($status == OrderStatusEnum::PAID) {
|
||||
return OrderShipStatusTransform::trans($this->ship_status); // 转换并显示物流状态
|
||||
}
|
||||
return OrderStatusTransform::trans($status); // 转换并显示订单状态
|
||||
});
|
||||
$show->field('type', '订单类型')->as(function ($type) {
|
||||
return OrderTypeTransform::trans($type); // 转换并显示订单类型
|
||||
});
|
||||
|
||||
$show->divider(); // 添加分隔线
|
||||
|
||||
$show->field('express_company', '物流公司'); // 显示物流公司
|
||||
$show->field('express_no', '物流单号'); // 显示物流单号
|
||||
|
||||
$show->divider(); // 添加分隔线
|
||||
|
||||
$show->field('consignee_name', '收货人'); // 显示收货人姓名
|
||||
$show->field('consignee_phone', '收货人手机'); // 显示收货人手机
|
||||
$show->field('consignee_address', '收货地址'); // 显示收货地址
|
||||
|
||||
$show->divider(); // 添加分隔线
|
||||
|
||||
$show->field('pay_type', '支付类型')->as(function ($type) {
|
||||
return OrderPayTypeTransform::trans($type); // 转换并显示支付类型
|
||||
});
|
||||
$show->field('refund_reason', '退款理由'); // 显示退款理由
|
||||
$show->field('pay_trade_no', '退款单号'); // 显示退款单号
|
||||
$show->field('pay_no', '支付单号'); // 显示支付单号
|
||||
$show->field('paid_at', '支付时间'); // 显示支付时间
|
||||
$show->field('created_at', '创建时间'); // 显示创建时间
|
||||
$show->field('updated_at', '修改时间'); // 显示修改时间
|
||||
|
||||
// 显示订单详情
|
||||
$show->details('详情', function (Grid $details) {
|
||||
$details->column('id'); // 显示订单详情 ID
|
||||
$details->column('product.name', '商品名字'); // 显示商品名称
|
||||
$details->column('price', '单价'); // 显示单价
|
||||
$details->column('number', '数量'); // 显示数量
|
||||
$details->column('is_commented', '是否评论')->display(function ($is) {
|
||||
return YesNoTransform::trans($is); // 转换并显示是否评论
|
||||
});
|
||||
$details->column('total', '小计'); // 显示小计
|
||||
|
||||
// 禁用行选择器、创建按钮、过滤器和操作按钮
|
||||
$details->disableRowSelector();
|
||||
$details->disableCreateButton();
|
||||
$details->disableFilter();
|
||||
$details->disableActions();
|
||||
});
|
||||
|
||||
return $show; // 返回构建好的详情视图
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定订单.
|
||||
*
|
||||
* @param mixed $id 订单 ID
|
||||
* @return \Illuminate\Http\JsonResponse 返回 JSON 响应
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
try {
|
||||
DB::transaction(function () use ($id) {
|
||||
$order = Order::withTrashed()->findOrFail($id); // 查找指定 ID 的订单
|
||||
$order->details()->delete(); // 删除订单详情
|
||||
$order->forceDelete(); // 强制删除订单
|
||||
});
|
||||
|
||||
$data = [
|
||||
'status' => true,
|
||||
'message' => trans('admin.delete_succeeded'), // 返回成功消息
|
||||
];
|
||||
} catch (\Throwable $e) {
|
||||
$data = [
|
||||
'status' => false,
|
||||
'message' => trans('admin.delete_failed') . $e->getMessage(), // 返回失败消息及错误信息
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json($data); // 返回 JSON 响应
|
||||
}
|
||||
}
|
@ -1,242 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Admin\Actions\Post\DividerAction; // 引入分隔符操作
|
||||
use App\Admin\Actions\Post\ForceDeleteProductAction; // 引入强制删除商品操作
|
||||
use App\Admin\Actions\Post\ProductStatusAction; // 引入商品状态操作
|
||||
use App\Admin\Transforms\YesNoTransform; // 引入是/否转换器
|
||||
use App\Http\Controllers\Controller; // 引入基础控制器
|
||||
use App\Models\Category; // 引入分类模型
|
||||
use App\Models\Product; // 引入商品模型
|
||||
use Encore\Admin\Controllers\HasResourceActions; // 引入资源控制器特性
|
||||
use Encore\Admin\Form; // 引入表单构建器
|
||||
use Encore\Admin\Grid; // 引入网格构建器
|
||||
use Encore\Admin\Layout\Content; // 引入内容布局
|
||||
use Encore\Admin\Show; // 引入展示构建器
|
||||
|
||||
class ProductController extends Controller
|
||||
{
|
||||
use HasResourceActions; // 使用资源控制器特性,使该控制器支持资源操作
|
||||
|
||||
/**
|
||||
* 显示商品列表界面.
|
||||
*
|
||||
* @param Content $content 内容布局实例
|
||||
* @return Content 返回内容布局
|
||||
*/
|
||||
public function index(Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('商品列表') // 设置页面标题
|
||||
->description('') // 设置页面描述(可选)
|
||||
->body($this->grid()); // 渲染商品网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示商品详情界面.
|
||||
*
|
||||
* @param mixed $id 商品 ID
|
||||
* @param Content $content 内容布局实例
|
||||
* @return Content 返回内容布局
|
||||
*/
|
||||
public function show($id, Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('详情') // 设置页面标题
|
||||
->description('') // 设置页面描述(可选)
|
||||
->body($this->detail($id)); // 渲染商品详情
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示编辑商品界面.
|
||||
*
|
||||
* @param mixed $id 商品 ID
|
||||
* @param Content $content 内容布局实例
|
||||
* @return Content 返回内容布局
|
||||
*/
|
||||
public function edit($id, Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('编辑') // 设置页面标题
|
||||
->description('') // 设置页面描述(可选)
|
||||
->body($this->form()->edit($id)); // 渲染编辑表单
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示添加商品界面.
|
||||
*
|
||||
* @param Content $content 内容布局实例
|
||||
* @return Content 返回内容布局
|
||||
*/
|
||||
public function create(Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('添加商品') // 设置页面标题
|
||||
->description('为你的商城添加一个商品') // 设置页面描述
|
||||
->body($this->form()); // 渲染添加商品表单
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建商品网格构建器.
|
||||
*
|
||||
* @return Grid 返回网格实例
|
||||
*/
|
||||
protected function grid()
|
||||
{
|
||||
$grid = new Grid(new Product); // 创建新的网格实例,基于 Product 模型
|
||||
|
||||
$grid->model()->withTrashed()->latest(); // 显示软删除的记录,并按创建时间降序排列
|
||||
|
||||
// 定义网格的列
|
||||
$grid->column('id'); // 显示商品 ID
|
||||
$grid->column('category.title', '商品类别'); // 显示商品类别
|
||||
$grid->column('name', '商品名')->display(function ($name) {
|
||||
return str_limit($name, 30); // 显示商品名,限制字符数为 30
|
||||
});
|
||||
$grid->column('thumb', '首图')->image('', 50, 50); // 显示商品缩略图
|
||||
$grid->column('price', '价格')->display(function ($price) {
|
||||
return $price . '/' . $this->original_price; // 显示销售价和原价
|
||||
});
|
||||
$grid->column('view_count', '浏览次数')->sortable(); // 显示并支持排序的浏览次数
|
||||
$grid->column('sale_count', '售出数量')->sortable(); // 显示并支持排序的售出数量
|
||||
$grid->column('count', '库存量')->sortable(); // 显示并支持排序的库存量
|
||||
$grid->column('deleted_at', '是否上架')->display(function ($isAlive) {
|
||||
return YesNoTransform::trans(is_null($isAlive)); // 转换并显示是否上架
|
||||
});
|
||||
$grid->column('created_at', '创建时间'); // 显示创建时间
|
||||
$grid->column('updated_at', '修改时间'); // 显示修改时间
|
||||
|
||||
// 查询过滤
|
||||
$grid->filter(function (Grid\Filter $filter) {
|
||||
$categories = Category::query()
|
||||
->orderBy('order')
|
||||
->latest()
|
||||
->pluck('title', 'id')
|
||||
->all(); // 获取分类列表
|
||||
|
||||
$filter->disableIdFilter(); // 禁用 ID 过滤
|
||||
$filter->equal('category_id', '分类')->select($categories); // 分类过滤
|
||||
$filter->equal('id', 'ID'); // ID 过滤
|
||||
$filter->equal('uuid', 'UUID'); // UUID 过滤
|
||||
$filter->like('name', '商品名字'); // 商品名字模糊查询
|
||||
});
|
||||
|
||||
// 增加一个上架/下架功能
|
||||
$grid->actions(function (Grid\Displayers\DropdownActions $actions) {
|
||||
$actions->disableDelete(); // 禁用删除按钮
|
||||
$actions->add(new ForceDeleteProductAction()); // 添加强制删除商品操作
|
||||
$actions->add(new DividerAction()); // 添加分隔符
|
||||
|
||||
// 根据商品是否上架设置操作按钮名称
|
||||
$name = is_null($actions->row->deleted_at) ? "下架" : "上架";
|
||||
$statusAction = new ProductStatusAction(); // 创建商品状态操作
|
||||
$statusAction->setName($name); // 设置操作按钮名称
|
||||
|
||||
$actions->add($statusAction); // 添加状态操作按钮
|
||||
});
|
||||
|
||||
return $grid; // 返回构建好的网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建商品详情展示构建器.
|
||||
*
|
||||
* @param mixed $id 商品 ID
|
||||
* @return Show 返回展示实例
|
||||
*/
|
||||
protected function detail($id)
|
||||
{
|
||||
$show = new Show(Product::query()->withTrashed()->findOrFail($id)); // 查找并显示指定 ID 的商品记录
|
||||
|
||||
// 定义详情展示的字段
|
||||
$show->field('id'); // 显示商品 ID
|
||||
$show->field('category.title', '商品类别'); // 显示商品类别
|
||||
$show->field('name', '商品名'); // 显示商品名
|
||||
$show->field('title', '卖点'); // 显示商品卖点
|
||||
$show->field('thumb', '缩略图')->image(); // 显示商品缩略图
|
||||
$show->field('price', '价格')->as(function ($price) {
|
||||
return $price . '/' . $this->original_price; // 显示销售价和原价
|
||||
});
|
||||
$show->field('view_count', '浏览次数'); // 显示浏览次数
|
||||
$show->field('sale_count', '售出数量'); // 显示售出数量
|
||||
$show->field('count', '库存量'); // 显示库存量
|
||||
$show->field('deleted_at', '是否上架')->as(function ($isAlive) {
|
||||
return is_null($isAlive) ? '上架' : '下架'; // 显示商品是否上架
|
||||
});
|
||||
$show->field('created_at', '创建时间'); // 显示创建时间
|
||||
$show->field('updated_at', '修改时间'); // 显示修改时间
|
||||
|
||||
return $show; // 返回构建好的详情视图
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建商品表单构建器.
|
||||
*
|
||||
* @return Form 返回表单实例
|
||||
*/
|
||||
protected function form()
|
||||
{
|
||||
$form = new Form(new Product); // 创建新的表单实例,基于 Product 模型
|
||||
|
||||
// 定义表单字段
|
||||
$form->select('category_id', '类别')->options(Category::selectOrderAll())->rules('required|exists:categories,id'); // 选择商品类别
|
||||
$form->text('name', '商品名字')->rules(function (Form $form) {
|
||||
$rules = 'required|max:50|unique:products,name'; // 商品名字的验证规则
|
||||
if ($id = $form->model()->id) {
|
||||
$rules .= ',' . $id; // 在编辑时排除当前商品
|
||||
}
|
||||
return $rules; // 返回验证规则
|
||||
});
|
||||
$form->textarea('title', '卖点')->rules('required|max:199'); // 商品卖点
|
||||
$form->currency('price', '销售价')->symbol('¥')->rules('required|numeric'); // 商品销售价
|
||||
$form->currency('original_price', '原价')->symbol('¥')->rules('required|numeric'); // 商品原价
|
||||
$form->number('count', '库存量')->rules('required|integer|min:0'); // 商品库存量
|
||||
|
||||
$form->image('thumb', '缩略图')->uniqueName()->move('products/thumb')->rules('required'); // 商品缩略图
|
||||
$form->multipleImage('pictures', '轮播图')->uniqueName()->move('products/lists'); // 商品轮播图
|
||||
|
||||
$form->editor('detail.content', '详情')->rules('required'); // 商品详情
|
||||
|
||||
// 保存前的钩子
|
||||
$form->saving(function (Form $form) {
|
||||
if (app()->environment('dev')) { // 在开发环境中禁止操作
|
||||
admin_toastr('开发环境不允许操作', 'error'); // 显示错误提示
|
||||
return back()->withInput(); // 返回输入
|
||||
}
|
||||
});
|
||||
|
||||
return $form; // 返回构建好的表单
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定商品.
|
||||
*
|
||||
* @param mixed $id 商品 ID
|
||||
* @return \Illuminate\Http\JsonResponse 返回 JSON 响应
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
$product = Product::query()->withTrashed()->findOrFail($id); // 查找指定 ID 的商品
|
||||
|
||||
if (app()->environment('dev')) { // 在开发环境中禁止操作
|
||||
admin_toastr('开发环境不允许操作', 'error'); // 显示错误提示
|
||||
return back()->withInput(); // 返回输入
|
||||
}
|
||||
|
||||
// 尝试强制删除商品
|
||||
if ($product->forceDelete()) {
|
||||
$data = [
|
||||
'status' => true,
|
||||
'message' => trans('admin.delete_succeeded'), // 返回成功消息
|
||||
];
|
||||
} else {
|
||||
$data = [
|
||||
'status' => false,
|
||||
'message' => trans('admin.delete_failed'), // 返回失败消息
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json($data); // 返回 JSON 响应
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Models\ProductHasUser; // 引入用户与商品关联模型
|
||||
use Encore\Admin\Controllers\AdminController; // 引入管理控制器基类
|
||||
use Encore\Admin\Form; // 引入表单构建器
|
||||
use Encore\Admin\Grid; // 引入网格构建器
|
||||
use Encore\Admin\Show; // 引入展示构建器
|
||||
|
||||
class ProductLikeController extends AdminController
|
||||
{
|
||||
/**
|
||||
* 当前资源的标题.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = '商品喜好'; // 设置资源的标题为“商品喜好”
|
||||
|
||||
/**
|
||||
* 创建网格构建器.
|
||||
*
|
||||
* @return Grid 返回网格实例
|
||||
*/
|
||||
protected function grid()
|
||||
{
|
||||
$grid = new Grid(new ProductHasUser); // 创建新的网格实例,基于 ProductHasUser 模型
|
||||
|
||||
$grid->model()->latest(); // 按照创建时间降序排列数据
|
||||
|
||||
// 定义网格的列
|
||||
$grid->column('user_id', __('User id')); // 显示用户 ID
|
||||
$grid->column('product_id', __('Product id')); // 显示商品 ID
|
||||
|
||||
$grid->column('user.name', '用户'); // 显示用户姓名
|
||||
$grid->column('created_at', '收藏时间'); // 显示商品收藏的时间
|
||||
$grid->column('product.name', '商品'); // 显示商品名称
|
||||
$grid->column('product.price', '价格')->display(function ($price) {
|
||||
// 显示商品价格,并附加原价
|
||||
return $price . '/' . $this->product['original_price']; // 返回格式化的价格
|
||||
});
|
||||
$grid->column('product.thumb', '首图')->image('', 50, 50); // 显示商品缩略图,设置显示大小
|
||||
|
||||
// 禁用某些操作
|
||||
$grid->disableActions(); // 禁用行操作按钮
|
||||
$grid->disableCreateButton(); // 禁用创建按钮
|
||||
$grid->disableBatchActions(); // 禁用批量操作按钮
|
||||
|
||||
// 定义过滤器
|
||||
$grid->filter(function (Grid\Filter $filter) {
|
||||
$filter->disableIdFilter(); // 禁用 ID 过滤器
|
||||
$filter->like('user_id', '用户ID'); // 用户 ID 模糊查询
|
||||
$filter->like('product_id', '商品ID'); // 商品 ID 模糊查询
|
||||
$filter->like('user.name', '用户名'); // 用户名模糊查询
|
||||
$filter->equal('product.name', '商品'); // 商品名称精确查询
|
||||
});
|
||||
|
||||
return $grid; // 返回构建好的网格
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Models\ScoreLog; // 引入积分日志模型
|
||||
use Encore\Admin\Controllers\AdminController; // 引入管理控制器基类
|
||||
use Encore\Admin\Form; // 引入表单构建器
|
||||
use Encore\Admin\Grid; // 引入网格构建器
|
||||
use Encore\Admin\Show; // 引入展示构建器
|
||||
|
||||
class ScoreLogController extends AdminController
|
||||
{
|
||||
/**
|
||||
* 当前资源的标题.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title = '积分日志'; // 设置资源的标题为“积分日志”
|
||||
|
||||
/**
|
||||
* 创建网格构建器.
|
||||
*
|
||||
* @return Grid 返回网格实例
|
||||
*/
|
||||
protected function grid()
|
||||
{
|
||||
$grid = new Grid(new ScoreLog); // 创建新的网格实例,基于 ScoreLog 模型
|
||||
|
||||
$grid->model()->latest(); // 按照创建时间降序排列数据
|
||||
|
||||
// 定义网格的列
|
||||
$grid->column('id', __('Id')); // 显示日志 ID
|
||||
$grid->column('user_id', __('User id')); // 显示用户 ID
|
||||
$grid->column('user.name', '用户名'); // 显示用户名
|
||||
$grid->column('description', __('Description')); // 显示日志描述
|
||||
$grid->column('score', __('Score')); // 显示积分
|
||||
$grid->column('created_at', __('Created at')); // 显示创建时间
|
||||
$grid->column('updated_at', __('Updated at')); // 显示更新时间
|
||||
|
||||
// 禁用某些操作
|
||||
$grid->disableActions(); // 禁用行操作按钮
|
||||
$grid->disableCreateButton(); // 禁用创建按钮
|
||||
|
||||
// 定义过滤器
|
||||
$grid->filter(function (Grid\Filter $filter) {
|
||||
$filter->like('user.name', '用户名'); // 用户名模糊查询
|
||||
$filter->equal('score', '积分'); // 积分精确查询
|
||||
});
|
||||
|
||||
return $grid; // 返回构建好的网格
|
||||
}
|
||||
}
|
@ -1,222 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Enums\ScoreRuleIndexEnum; // 引入积分规则索引枚举
|
||||
use App\Models\ScoreRule; // 引入积分规则模型
|
||||
use App\Http\Controllers\Controller; // 引入控制器基类
|
||||
use Encore\Admin\Controllers\HasResourceActions; // 引入资源操作特性
|
||||
use Encore\Admin\Form; // 引入表单构建器
|
||||
use Encore\Admin\Grid; // 引入网格构建器
|
||||
use Encore\Admin\Layout\Content; // 引入内容布局
|
||||
use Encore\Admin\Show; // 引入展示构建器
|
||||
use Illuminate\Http\Request; // 引入请求处理
|
||||
|
||||
class ScoreRuleController extends Controller
|
||||
{
|
||||
use HasResourceActions; // 使用资源操作特性,提供 CRUD 操作
|
||||
|
||||
/**
|
||||
* 列表界面.
|
||||
*
|
||||
* @param Content $content
|
||||
* @return Content
|
||||
*/
|
||||
public function index(Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('列表') // 设置页面标题
|
||||
->description(':xxx 是变量模板,建议不要操作') // 设置页面描述
|
||||
->body($this->grid()); // 设置页面主体为网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示详细信息界面.
|
||||
*
|
||||
* @param mixed $id
|
||||
* @param Content $content
|
||||
* @return Content
|
||||
*/
|
||||
public function show($id, Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('详情') // 设置页面标题
|
||||
->description('') // 设置页面描述
|
||||
->body($this->detail($id)); // 设置页面主体为详细信息
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑界面.
|
||||
*
|
||||
* @param mixed $id
|
||||
* @param Content $content
|
||||
* @return Content
|
||||
*/
|
||||
public function edit($id, Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('Edit') // 设置页面标题
|
||||
->description('') // 设置页面描述
|
||||
->body($this->form($id)->edit($id)); // 设置页面主体为编辑表单
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建界面.
|
||||
*
|
||||
* @param Content $content
|
||||
* @return Content
|
||||
*/
|
||||
public function create(Content $content)
|
||||
{
|
||||
return $content
|
||||
->header('新建') // 设置页面标题
|
||||
->description('') // 设置页面描述
|
||||
->body($this->form()); // 设置页面主体为创建表单
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建网格构建器.
|
||||
*
|
||||
* @return Grid
|
||||
*/
|
||||
protected function grid()
|
||||
{
|
||||
$grid = new Grid(new ScoreRule); // 创建新的网格实例,基于 ScoreRule 模型
|
||||
|
||||
$grid->model()->latest(); // 按照创建时间降序排列数据
|
||||
|
||||
// 定义网格的列
|
||||
$grid->column('id', 'id'); // 显示日志 ID
|
||||
$grid->column('description', '描述'); // 显示描述
|
||||
$grid->column('replace_text', '替换文本'); // 显示替换文本
|
||||
$grid->column('score', '积分'); // 显示积分
|
||||
$grid->column('times', '次数')->display(function ($times) {
|
||||
// 显示次数,如果没有则返回空
|
||||
return $times ? $times : '';
|
||||
});
|
||||
|
||||
$grid->column('created_at', '创建时间'); // 显示创建时间
|
||||
$grid->column('updated_at', '修改时间'); // 显示修改时间
|
||||
|
||||
// 定义行操作
|
||||
$grid->actions(function (Grid\Displayers\Actions $actions) {
|
||||
$rule = $actions->row; // 获取当前行数据
|
||||
if (! $rule->can_delete) { // 如果该规则不可删除
|
||||
$actions->disableDelete(); // 禁用删除按钮
|
||||
}
|
||||
});
|
||||
|
||||
return $grid; // 返回构建好的网格
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建展示构建器.
|
||||
*
|
||||
* @param mixed $id
|
||||
* @return Show
|
||||
*/
|
||||
protected function detail($id)
|
||||
{
|
||||
$show = new Show(ScoreRule::findOrFail($id)); // 创建展示实例,查找指定 ID 的记录
|
||||
|
||||
// 定义展示的字段
|
||||
$show->field('id', 'id'); // 显示 ID
|
||||
$show->field('description', '描述'); // 显示描述
|
||||
$show->field('replace_text', '替换文本'); // 显示替换文本
|
||||
$show->field('score', '积分'); // 显示积分
|
||||
$show->field('times', '次数')->as(function ($times) {
|
||||
// 显示次数,如果没有则返回空
|
||||
return $times ? $times : '';
|
||||
});
|
||||
$show->field('created_at', '创建时间'); // 显示创建时间
|
||||
$show->field('updated_at', '修改时间'); // 显示修改时间
|
||||
|
||||
return $show; // 返回展示实例
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表单构建器.
|
||||
*
|
||||
* @param null $id
|
||||
* @return Form
|
||||
*/
|
||||
protected function form($id = null)
|
||||
{
|
||||
$form = new Form(new ScoreRule); // 创建新的表单实例,基于 ScoreRule 模型
|
||||
|
||||
// 定义可选的积分规则类型
|
||||
$options = [
|
||||
ScoreRuleIndexEnum::CONTINUE_LOGIN => '连续登录',
|
||||
ScoreRuleIndexEnum::VISITED_PRODUCT => '每日浏览商品'
|
||||
];
|
||||
|
||||
if (is_null($id)) { // 如果是创建新记录
|
||||
$form->select('index_code', '类型')->options($options)->rules('required'); // 选择积分类型,必填
|
||||
}
|
||||
$form->number('score', '积分'); // 输入积分
|
||||
|
||||
if (! is_null($id)) { // 如果是编辑现有记录
|
||||
// 只有当是连续登录和修改的才有次数
|
||||
$scoreRule = ScoreRule::query()->findOrFail($id); // 查找指定 ID 的规则
|
||||
$form->textarea('replace_text', '替换文本'); // 输入替换文本
|
||||
$form->textarea('description', '描述'); // 输入描述
|
||||
|
||||
if (array_key_exists($scoreRule->index_code, $options)) { // 如果规则类型在选项中
|
||||
$form->number('times', '次数'); // 输入次数
|
||||
}
|
||||
} else {
|
||||
$form->number('times', '次数'); // 输入次数
|
||||
}
|
||||
|
||||
// 表单保存前的处理
|
||||
$form->saving(function (Form $form) {
|
||||
// 如果是新建记录,复制模板
|
||||
if (! $form->model()->exists) {
|
||||
$rule = ScoreRule::query()
|
||||
->where('can_delete', 0) // 查找不可删除的规则
|
||||
->where('index_code', $form->index_code) // 根据类型查找
|
||||
->firstOrFail(); // 查找失败则抛出异常
|
||||
|
||||
// 复制规则的描述和替换文本
|
||||
$form->model()->description = $rule->description;
|
||||
$form->model()->replace_text = $rule->replace_text;
|
||||
}
|
||||
});
|
||||
|
||||
return $form; // 返回构建好的表单
|
||||
}
|
||||
|
||||
/**
|
||||
* 从存储中删除指定资源.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
$rule = ScoreRule::query()->findOrFail($id); // 查找指定 ID 的规则
|
||||
|
||||
if (! $rule->can_delete) { // 如果该规则不可删除
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => '这个等级不允许删除', // 返回错误信息
|
||||
]);
|
||||
}
|
||||
|
||||
// 尝试删除规则
|
||||
if ($rule->delete()) {
|
||||
$data = [
|
||||
'status' => true,
|
||||
'message' => trans('admin.delete_succeeded'), // 返回成功信息
|
||||
];
|
||||
} else {
|
||||
$data = [
|
||||
'status' => false,
|
||||
'message' => trans('admin.delete_failed'), // 返回失败信息
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json($data); // 返回 JSON 响应
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Exceptions\UploadException; // 引入自定义上传异常类
|
||||
use App\Http\Controllers\Controller; // 引入控制器基类
|
||||
use App\Services\UploadServe; // 引入上传服务类
|
||||
use Illuminate\Support\Facades\Storage; // 引入存储门面,便于文件存储操作
|
||||
|
||||
class UploadController extends Controller
|
||||
{
|
||||
/**
|
||||
* 通过编辑器上传文件.
|
||||
*
|
||||
* @param UploadServe $uploadServe 上传服务实例
|
||||
* @return array 返回上传结果数组
|
||||
*/
|
||||
public function uploadByEditor(UploadServe $uploadServe)
|
||||
{
|
||||
$disk = 'public'; // 定义使用的存储磁盘
|
||||
|
||||
try {
|
||||
// 设置文件输入名称、最大文件大小和允许的文件扩展名,并进行验证和存储
|
||||
$files = $uploadServe->setFileInput('pictures') // 设置文件输入名称为 'pictures'
|
||||
->setMaxSize('10M') // 设置最大文件大小为 10MB
|
||||
->setExtensions(['jpg', 'jpeg', 'png', 'bmp', 'gif']) // 设置允许的文件扩展名
|
||||
->validate() // 验证上传的文件
|
||||
->storeMulti('upload/editor', compact('disk')); // 存储文件,路径为 'upload/editor'
|
||||
|
||||
// 将存储的文件路径转换为可访问的 URL
|
||||
$files = collect($files)->map(function ($file) use ($disk) {
|
||||
return Storage::disk($disk)->url($file); // 获取文件的 URL
|
||||
})->all(); // 转换为数组
|
||||
|
||||
} catch (UploadException $e) {
|
||||
// 捕获上传异常并返回错误信息
|
||||
return ['errno' => 1, 'msg' => $e->getMessage()]; // 返回错误代码和消息
|
||||
}
|
||||
|
||||
// 返回成功的上传结果
|
||||
return ['errno' => 0, 'data' => $files]; // 返回成功代码和文件 URL 列表
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Extensions;
|
||||
|
||||
use Illuminate\Contracts\Support\Renderable; // 引入 Renderable 接口
|
||||
|
||||
class Div implements Renderable
|
||||
{
|
||||
protected $id; // div 元素的 ID
|
||||
protected $width = '100%'; // div 元素的宽度,默认值为 100%
|
||||
protected $height = '300px'; // div 元素的高度,默认值为 300px
|
||||
|
||||
/**
|
||||
* Div constructor.
|
||||
*
|
||||
* @param string $id div 元素的 ID
|
||||
* @param string|null $width div 元素的宽度,默认为 null
|
||||
* @param string|null $height div 元素的高度,默认为 null
|
||||
*/
|
||||
public function __construct($id, $width = null, $height = null)
|
||||
{
|
||||
$this->id = $id; // 设置 div 的 ID
|
||||
|
||||
// 如果提供了宽度,则设置宽度
|
||||
if (!is_null($width)) {
|
||||
$this->width = $width; // 更新 div 的宽度
|
||||
}
|
||||
|
||||
// 如果提供了高度,则设置高度
|
||||
if (!is_null($height)) {
|
||||
$this->height = $height; // 更新 div 的高度
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染 div 元素的 HTML.
|
||||
*
|
||||
* @return string 返回包含 div 的 HTML 字符串
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
// 使用 heredoc 语法返回包含 div 的 HTML 代码
|
||||
return <<<div
|
||||
<div id="{$this->id}" style="width: {$this->width}; height: {$this->height}"></div>
|
||||
div;
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Extensions;
|
||||
|
||||
use Illuminate\Support\Collection; // 引入集合类
|
||||
use Encore\Admin\Form\Field; // 引入表单字段基类
|
||||
|
||||
class WangEditor extends Field
|
||||
{
|
||||
protected $view = 'admin.wang-editor'; // 定义视图文件路径
|
||||
|
||||
// 引入 WangEditor 的 CSS 文件
|
||||
protected static $css = [
|
||||
'/vendor/wangEditor-3.1.1/release/wangEditor.css',
|
||||
];
|
||||
|
||||
// 引入 WangEditor 的 JS 文件
|
||||
protected static $js = [
|
||||
'/vendor/wangEditor-3.1.1/release/wangEditor.js',
|
||||
];
|
||||
|
||||
/**
|
||||
* 渲染 WangEditor 编辑器.
|
||||
*
|
||||
* @return string 返回渲染后的 HTML
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
// 格式化字段名称
|
||||
$name = $this->formatName($this->column);
|
||||
// 获取 CSRF 令牌
|
||||
$token = csrf_token();
|
||||
// 定义上传图片的服务器地址
|
||||
$url = admin_base_path('upload/editor');
|
||||
|
||||
// 定义 JavaScript 代码,初始化 WangEditor
|
||||
$this->script = <<<EOT
|
||||
|
||||
var E = window.wangEditor; // 获取 WangEditor 对象
|
||||
var editor = new E('#{$this->id}'); // 创建编辑器实例,绑定到指定的 HTML 元素
|
||||
editor.customConfig.zIndex = 0; // 设置编辑器的 z-index
|
||||
editor.customConfig.uploadFileName = 'pictures[]'; // 设置上传文件的名称
|
||||
|
||||
// 配置服务器端地址
|
||||
editor.customConfig.uploadImgServer = '{$url}'; // 设置图片上传的服务器地址
|
||||
editor.customConfig.uploadImgParams = {
|
||||
_token: '{$token}' // 设置上传参数,包括 CSRF 令牌
|
||||
};
|
||||
|
||||
// 文件改变时,将 HTML 内容添加到隐藏域
|
||||
editor.customConfig.onchange = function (html) {
|
||||
$('input[name=\'$name\']').val(html); // 更新隐藏域的值为编辑器内容
|
||||
}
|
||||
|
||||
// 监听上传错误
|
||||
editor.customConfig.uploadImgHooks = {
|
||||
fail: function (xhr, editor) {
|
||||
var response = $.parseJSON(xhr.response); // 解析服务器返回的 JSON
|
||||
alert(response.msg); // 弹出错误信息
|
||||
}
|
||||
};
|
||||
|
||||
editor.create(); // 创建编辑器实例
|
||||
|
||||
EOT;
|
||||
|
||||
return parent::render(); // 调用父类的 render 方法,返回最终的 HTML
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Transforms; // 定义命名空间
|
||||
|
||||
use App\Enums\OrderPayTypeEnum; // 引入订单支付类型枚举类
|
||||
use App\Enums\OrderShipStatusEnum; // 引入订单发货状态枚举类(未使用)
|
||||
use App\Enums\OrderStatusEnum; // 引入订单状态枚举类(未使用)
|
||||
use App\Enums\OrderTypeEnum; // 引入订单类型枚举类(未使用)
|
||||
use App\Models\Order; // 引入订单模型(未使用)
|
||||
|
||||
/**
|
||||
* 订单支付类型转换类
|
||||
*
|
||||
* 该类用于将订单支付类型的枚举值转换为可读的字符串形式。
|
||||
*/
|
||||
class OrderPayTypeTransform implements Transform
|
||||
{
|
||||
/**
|
||||
* 将支付类型转换为对应的可读字符串
|
||||
*
|
||||
* @param mixed $type 支付类型的枚举值
|
||||
* @return string 返回对应的支付方式名称
|
||||
*/
|
||||
public static function trans($type)
|
||||
{
|
||||
$text = ''; // 初始化返回的字符串
|
||||
|
||||
// 根据支付类型的枚举值进行判断并设置对应的字符串
|
||||
if ($type == OrderPayTypeEnum::ALI) {
|
||||
$text = '支付宝'; // 支付宝支付
|
||||
} elseif ($type == OrderPayTypeEnum::WECHAT) {
|
||||
$text = '微信'; // 微信支付
|
||||
}
|
||||
|
||||
return $text; // 返回转换后的支付方式名称
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Transforms; // 定义命名空间
|
||||
|
||||
use App\Enums\OrderShipStatusEnum; // 引入订单发货状态枚举类
|
||||
use App\Enums\OrderStatusEnum; // 引入订单状态枚举类(未使用)
|
||||
use App\Enums\OrderTypeEnum; // 引入订单类型枚举类(未使用)
|
||||
use App\Models\Order; // 引入订单模型(未使用)
|
||||
|
||||
/**
|
||||
* 订单发货状态转换类
|
||||
*
|
||||
* 该类用于将订单发货状态的枚举值转换为可读的字符串形式。
|
||||
*/
|
||||
class OrderShipStatusTransform implements Transform
|
||||
{
|
||||
/**
|
||||
* 将发货状态转换为对应的可读字符串
|
||||
*
|
||||
* @param mixed $status 发货状态的枚举值
|
||||
* @return string 返回对应的发货状态名称
|
||||
*/
|
||||
public static function trans($status)
|
||||
{
|
||||
// 根据发货状态的枚举值进行判断并设置对应的字符串
|
||||
switch ($status) {
|
||||
case OrderShipStatusEnum::PENDING:
|
||||
$text = '未发货'; // 订单尚未发货
|
||||
break;
|
||||
case OrderShipStatusEnum::DELIVERED:
|
||||
$text = '待收货'; // 订单已发货,等待用户收货
|
||||
break;
|
||||
case OrderShipStatusEnum::RECEIVED:
|
||||
$text = '已收货'; // 用户已确认收货
|
||||
break;
|
||||
default:
|
||||
$text = '未知状态'; // 未知的发货状态
|
||||
break;
|
||||
}
|
||||
|
||||
return $text; // 返回转换后的发货状态名称
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Transforms; // 定义命名空间
|
||||
|
||||
use App\Enums\OrderShipStatusEnum; // 引入订单发货状态枚举类(未使用)
|
||||
use App\Enums\OrderStatusEnum; // 引入订单状态枚举类
|
||||
use App\Enums\OrderTypeEnum; // 引入订单类型枚举类(未使用)
|
||||
use App\Models\Order; // 引入订单模型(未使用)
|
||||
|
||||
/**
|
||||
* 订单状态转换类
|
||||
*
|
||||
* 该类用于将订单状态的枚举值转换为可读的字符串形式。
|
||||
*/
|
||||
class OrderStatusTransform implements Transform
|
||||
{
|
||||
/**
|
||||
* 将订单状态转换为对应的可读字符串
|
||||
*
|
||||
* @param mixed $status 订单状态的枚举值
|
||||
* @return string 返回对应的订单状态名称
|
||||
*/
|
||||
public static function trans($status)
|
||||
{
|
||||
// 根据订单状态的枚举值进行判断并设置对应的字符串
|
||||
switch ($status) {
|
||||
case OrderStatusEnum::UN_PAY_CANCEL:
|
||||
$text = '取消'; // 订单已被取消
|
||||
break;
|
||||
case OrderStatusEnum::REFUND:
|
||||
$text = '退款'; // 订单已退款
|
||||
break;
|
||||
case OrderStatusEnum::APPLY_REFUND:
|
||||
$text = '申请退款'; // 用户已申请退款
|
||||
break;
|
||||
case OrderStatusEnum::UN_PAY:
|
||||
$text = '未支付'; // 订单尚未支付
|
||||
break;
|
||||
case OrderStatusEnum::PAID:
|
||||
$text = '已支付'; // 订单已成功支付
|
||||
break;
|
||||
case OrderStatusEnum::TIMEOUT_CANCEL:
|
||||
$text = '超时未付款系统自动取消'; // 订单因超时未付款被系统自动取消
|
||||
break;
|
||||
case OrderStatusEnum::COMPLETED:
|
||||
$text = '完成'; // 订单已完成
|
||||
break;
|
||||
default:
|
||||
$text = '未知状态'; // 未知的订单状态
|
||||
break;
|
||||
}
|
||||
|
||||
return $text; // 返回转换后的订单状态名称
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Transforms; // 定义命名空间
|
||||
|
||||
use App\Enums\OrderShipStatusEnum; // 引入订单发货状态枚举类(未使用)
|
||||
use App\Enums\OrderStatusEnum; // 引入订单状态枚举类(未使用)
|
||||
use App\Enums\OrderTypeEnum; // 引入订单类型枚举类
|
||||
use App\Models\Order; // 引入订单模型(未使用)
|
||||
|
||||
/**
|
||||
* 订单类型转换类
|
||||
*
|
||||
* 该类用于将订单类型的枚举值转换为可读的字符串形式。
|
||||
*/
|
||||
class OrderTypeTransform implements Transform
|
||||
{
|
||||
/**
|
||||
* 将订单类型转换为对应的可读字符串
|
||||
*
|
||||
* @param mixed $type 订单类型的枚举值
|
||||
* @return string 返回对应的订单类型名称
|
||||
*/
|
||||
public static function trans($type)
|
||||
{
|
||||
// 默认状态为'未知'
|
||||
$text = '未知';
|
||||
|
||||
// 根据订单类型的枚举值进行判断并设置对应的字符串
|
||||
if ($type == OrderTypeEnum::COMMON) {
|
||||
$text = '普通订单'; // 订单类型为普通订单
|
||||
} elseif ($type == OrderTypeEnum::SEC_KILL) {
|
||||
$text = '秒杀订单'; // 订单类型为秒杀订单
|
||||
}
|
||||
|
||||
return $text; // 返回转换后的订单类型名称
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Transforms; // 定义命名空间
|
||||
|
||||
/**
|
||||
* 转换接口
|
||||
*
|
||||
* 该接口定义了一个转换方法,所有实现此接口的类都需提供具体的转换逻辑。
|
||||
*/
|
||||
interface Transform
|
||||
{
|
||||
/**
|
||||
* 转换方法
|
||||
*
|
||||
* @param mixed $trans 需要转换的值,可以是任何类型
|
||||
* @return mixed 返回转换后的值,类型可以根据具体实现而定
|
||||
*/
|
||||
public static function trans($trans);
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Transforms; // 定义命名空间
|
||||
|
||||
use App\Enums\UserSexEnum; // 引入用户性别枚举类
|
||||
use App\Enums\UserStatusEnum; // 引入用户状态枚举类(未使用)
|
||||
use App\Models\User; // 引入用户模型(未使用)
|
||||
|
||||
/**
|
||||
* 用户性别转换类
|
||||
*
|
||||
* 该类用于将用户性别的枚举值转换为可读的字符串形式。
|
||||
*/
|
||||
class UserSexTransform implements Transform
|
||||
{
|
||||
/**
|
||||
* 将用户性别转换为对应的可读字符串
|
||||
*
|
||||
* @param mixed $sex 用户性别的枚举值
|
||||
* @return string 返回对应的用户性别名称
|
||||
*/
|
||||
public static function trans($sex)
|
||||
{
|
||||
// 默认状态为'未知'
|
||||
$text = '未知';
|
||||
|
||||
// 根据用户性别的枚举值进行判断并设置对应的字符串
|
||||
if ($sex == UserSexEnum::MAN) {
|
||||
$text = '男'; // 用户性别为男性
|
||||
} elseif ($sex == UserSexEnum::WOMAN) {
|
||||
$text = '女'; // 用户性别为女性
|
||||
}
|
||||
|
||||
return $text; // 返回转换后的用户性别名称
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Transforms; // 定义命名空间
|
||||
|
||||
use App\Enums\UserStatusEnum; // 引入用户状态枚举类(未使用)
|
||||
|
||||
/**
|
||||
* 是/否转换类
|
||||
*
|
||||
* 该类用于将布尔值转换为相应的图标表示形式。
|
||||
*/
|
||||
class YesNoTransform implements Transform
|
||||
{
|
||||
/**
|
||||
* 将布尔值转换为对应的图标表示
|
||||
*
|
||||
* @param bool $is 布尔值,用于表示是或否
|
||||
* @return string 返回相应的 HTML 图标字符串
|
||||
*/
|
||||
public static function trans($is)
|
||||
{
|
||||
// 返回对应的图标,绿色勾表示“是”,红色叉表示“否”
|
||||
return $is
|
||||
? "<i style='color: green;' class=\"fa fa-check-circle\" aria-hidden=\"true\"></i>" // 当 $is 为 true 时,返回绿色勾图标
|
||||
: "<i style='color: red;' class=\"fa fa-times\" aria-hidden=\"true\"></i>"; // 当 $is 为 false 时,返回红色叉图标
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
// 引入 WangEditor 扩展类
|
||||
use App\Admin\Extensions\WangEditor;
|
||||
// 引入 Encore\Admin\Form 类
|
||||
use Encore\Admin\Form;
|
||||
|
||||
// 忘记默认的 'map' 和 'editor' 字段,以便自定义处理
|
||||
Form::forget(['map', 'editor']);
|
||||
|
||||
// 扩展表单功能,注册 WangEditor 作为一个新的表单字段类型
|
||||
Form::extend('editor', WangEditor::class);
|
@ -1,83 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Admin\Controllers\CouponLogController; // 引入优惠券日志控制器
|
||||
use Illuminate\Routing\Router; // 引入路由器类
|
||||
|
||||
// 注册管理后台的认证路由
|
||||
Admin::registerAuthRoutes();
|
||||
|
||||
// 定义路由组
|
||||
Route::group([
|
||||
'prefix' => config('admin.route.prefix'), // 路由前缀
|
||||
'namespace' => config('admin.route.namespace'), // 控制器命名空间
|
||||
'middleware' => config('admin.route.middleware'), // 中间件
|
||||
], function (Router $router) {
|
||||
|
||||
// 设置默认的 404 错误页面
|
||||
$router->fallback('HomeController@noFound');
|
||||
// 首页路由
|
||||
$router->get('/', 'HomeController@index');
|
||||
|
||||
// 覆盖默认的用户管理路由
|
||||
$router->get('auth/users', 'AdminController@index');
|
||||
// 覆盖默认的操作日志路由
|
||||
$router->get('auth/logs', 'AdminController@indexLogs');
|
||||
|
||||
// 系统配置相关路由
|
||||
$router->resource('settings', 'SettingController')->only('index', 'store');
|
||||
|
||||
// 商品上架和下架操作
|
||||
$router->get('products/{id}/push', 'ProductController@pushProduct');
|
||||
|
||||
// 分类管理
|
||||
// 商品管理
|
||||
// 秒杀商品管理
|
||||
$router->resource('categories', 'CategoryController'); // 分类资源路由
|
||||
$router->resource('products', 'ProductController'); // 商品资源路由
|
||||
$router->resource('seckills', 'SeckillController')->only('index', 'create', 'store', 'destroy'); // 秒杀活动的资源路由
|
||||
|
||||
// 订单发货相关路由
|
||||
// 管理员确认订单发货
|
||||
$router->post('orders/{order}/ship', 'OrderController@ship');
|
||||
// 确认发货状态
|
||||
$router->patch('orders/{order}/shipped', 'OrderController@confirmShip');
|
||||
|
||||
// 退款相关路由
|
||||
// 订单相关路由
|
||||
// 评论管理路由
|
||||
$router->get('orders/{order}/refund', 'OrderController@refund'); // 退款请求
|
||||
$router->resource('orders', 'OrderController'); // 订单资源路由
|
||||
$router->resource('comments', 'CommentController'); // 评论资源路由
|
||||
|
||||
// 会员管理相关路由
|
||||
$router->resource('users', 'UserController'); // 用户资源路由
|
||||
|
||||
// 积分日志
|
||||
$router->get('score_logs', 'ScoreLogController@index'); // 积分日志查看
|
||||
|
||||
// 用户购物车数据
|
||||
$router->get('cars', 'CarController@index'); // 购物车数据查看
|
||||
|
||||
// 用户收藏数据
|
||||
$router->get('user_like_products', 'ProductLikeController@index'); // 用户收藏的产品
|
||||
|
||||
// 积分规则和积分等级管理
|
||||
$router->resource('score_rules', 'ScoreRuleController'); // 积分规则资源路由
|
||||
$router->resource('levels', 'LevelController'); // 积分等级资源路由
|
||||
|
||||
// 优惠券管理
|
||||
$router->resource('coupon_templates', 'CouponTemplateController'); // 优惠券模板资源路由
|
||||
// 优惠券日志
|
||||
$router->resource('coupon_logs', 'CouponLogController')->only('index'); // 优惠券日志查看
|
||||
// 优惠券兑换码管理
|
||||
$router->resource('coupon_codes', 'CouponCodeController')->only('index', 'create', 'store', 'destroy'); // 兑换码资源路由
|
||||
|
||||
// 文章通知管理
|
||||
$router->resource('article_notifications', 'ArticleNotificationController')->only('index', 'create', 'store', 'show', 'destroy'); // 文章通知资源路由
|
||||
|
||||
// 富文本编辑器图片上传
|
||||
$router->post('upload/editor', 'UploadController@uploadByEditor'); // 图片上传路由
|
||||
|
||||
// 通过分类异步加载商品下拉列表
|
||||
$router->get('api/products', 'CategoryController@getProducts'); // 获取产品列表的 API 路由
|
||||
});
|
@ -1,98 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
use App\Models\Product; // 引入商品模型
|
||||
use App\Models\SearchAble\ElasticSearchTrait; // 引入 Elasticsearch 特性
|
||||
use Elasticsearch\ClientBuilder; // 引入 Elasticsearch 客户端构建器
|
||||
use Illuminate\Console\Command; // 引入 Laravel 命令基类
|
||||
use Illuminate\Database\Eloquent\Collection; // 引入 Eloquent 集合类
|
||||
|
||||
/**
|
||||
* 将商品添加到 Elasticsearch 搜索的控制台命令
|
||||
*
|
||||
* 该命令用于将商品数据添加到 Elasticsearch 的全文索引中。
|
||||
*/
|
||||
class AddShopToEsSearchCommand extends Command
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'add:shop-to-search';
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '把商品添加到全文索引';
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行控制台命令.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
try {
|
||||
// 检查 Elasticsearch 服务器是否可用
|
||||
ElasticSearchTrait::client()->ping([
|
||||
'client' => [
|
||||
'timeout' => 5, // 设置请求超时时间
|
||||
'connect_timeout' => 5 // 设置连接超时时间
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $exception) {
|
||||
// 捕获连接异常并输出错误信息
|
||||
$this->info($exception->getMessage());
|
||||
$this->info('无法连接到 Elasticsearch 服务器,请配置 config/elasticsearch.php 文件');
|
||||
$this->info('默认使用 MySQL 的模糊搜索');
|
||||
$this->info('配置完毕后可运行: php artisan add:shop-to-search 添加索引');
|
||||
return; // 退出命令
|
||||
}
|
||||
|
||||
// 新建商品索引
|
||||
if (Product::indexExists()) {
|
||||
// 如果索引已存在,则删除索引
|
||||
Product::deleteIndex();
|
||||
$this->info('删除索引');
|
||||
}
|
||||
|
||||
// 创建新的索引
|
||||
Product::createIndex();
|
||||
$this->info('新建索引成功');
|
||||
|
||||
// 开始导入数据
|
||||
$query = Product::query(); // 创建商品查询
|
||||
|
||||
$count = $query->count(); // 获取商品总数
|
||||
$handle = 0; // 初始化处理计数
|
||||
|
||||
// 使用 chunk 方法分批处理商品数据
|
||||
$query->with('category')->chunk(1000, function (Collection $models) use ($count, &$handle) {
|
||||
// 遍历每个商品模型
|
||||
$models->map(function (Product $product) use ($count, &$handle) {
|
||||
// 将商品添加到索引
|
||||
$product->addToIndex($product->getSearchData());
|
||||
++$handle; // 处理计数加一
|
||||
echo "\r {$handle}/$count"; // 输出当前处理进度
|
||||
});
|
||||
});
|
||||
|
||||
echo PHP_EOL; // 换行
|
||||
|
||||
$this->info('索引生成完毕'); // 输出完成信息
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
use Illuminate\Console\Command; // 引入 Laravel 命令基类
|
||||
|
||||
/**
|
||||
* 基础控制台命令类
|
||||
*
|
||||
* 该类提供了一个基础命令实现,包含执行 shell 命令并打印输出的功能。
|
||||
*/
|
||||
class BaseCommand extends Command
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'moon:base'; // 定义命令的名称和签名
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'don`t use'; // 描述该命令的用途,当前设置为“不建议使用”
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行 shell 命令并打印输出
|
||||
*
|
||||
* @param string $command 要执行的 shell 命令
|
||||
* @return void
|
||||
*/
|
||||
public function execShellWithPrint($command)
|
||||
{
|
||||
$this->info('----------'); // 打印分隔线
|
||||
$this->info($command); // 打印要执行的命令
|
||||
|
||||
// 执行 shell 命令并获取输出
|
||||
$output = shell_exec($command);
|
||||
|
||||
$this->info($output); // 打印命令的输出结果
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
/**
|
||||
* 缓存优化控制台命令
|
||||
*
|
||||
* 该命令用于优化配置和路由缓存,以提高网站的运行速度。
|
||||
*/
|
||||
class CacheOptimize extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'moon:cache'; // 定义命令的名称和签名
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Cache routing, configure information, to speed up the website running speed'; // 描述该命令的用途
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行缓存命令
|
||||
*
|
||||
* 该方法用于处理缓存优化的逻辑,包括优化配置和路由缓存。
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// 优化配置并缓存配置文件
|
||||
$this->call('config:cache'); // 调用 Laravel 的 config:cache 命令
|
||||
|
||||
// 优化路由并缓存路由信息
|
||||
$this->call('route:cache'); // 调用 Laravel 的 route:cache 命令
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
/**
|
||||
* 清除缓存控制台命令
|
||||
*
|
||||
* 该命令用于清除应用程序中的缓存信息,包括配置缓存、路由缓存和视图缓存。
|
||||
*/
|
||||
class ClearCache extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'moon:clear'; // 定义命令的名称和签名
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'clear moon:cache cache information'; // 描述该命令的用途
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有缓存
|
||||
*
|
||||
* 该方法用于处理缓存清除的逻辑,包括清除配置缓存、路由缓存和视图缓存。
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// 清除配置缓存
|
||||
$this->call('config:clear'); // 调用 Laravel 的 config:clear 命令
|
||||
|
||||
// 清除路由缓存
|
||||
$this->call('route:clear'); // 调用 Laravel 的 route:clear 命令
|
||||
|
||||
// 清除视图缓存
|
||||
$this->call('view:clear'); // 调用 Laravel 的 view:clear 命令
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
use Illuminate\Filesystem\Filesystem; // 引入 Filesystem 类
|
||||
use Illuminate\Support\Facades\Storage; // 引入 Storage 门面(未使用,可以考虑移除)
|
||||
|
||||
/**
|
||||
* 复制文件控制台命令
|
||||
*
|
||||
* 该命令用于将所有上传的静态资源复制到公共存储目录。
|
||||
*/
|
||||
class CopyFile extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'moon:copy'; // 定义命令的名称和签名
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Copy all upload static resources'; // 描述该命令的用途
|
||||
|
||||
/**
|
||||
* 文件系统实例
|
||||
*
|
||||
* @var Filesystem
|
||||
*/
|
||||
protected $filesystem; // 声明文件系统实例变量
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @param Filesystem $filesystem 文件系统实例
|
||||
*/
|
||||
public function __construct(Filesystem $filesystem)
|
||||
{
|
||||
$this->filesystem = $filesystem; // 注入 Filesystem 实例
|
||||
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 把静态资源发布到 public/storage 目录
|
||||
*
|
||||
* 该方法执行复制静态资源的逻辑,包括产品图片、默认头像和其他静态图片。
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// 定义图片的静态目录及目标目录
|
||||
$from = storage_path('app/resources/products'); // 源目录:产品图片
|
||||
$to = storage_path('app/public/products'); // 目标目录:公共产品图片
|
||||
$this->filesystem->copyDirectory($from, $to); // 复制产品图片目录
|
||||
|
||||
// 复制默认头像
|
||||
$from = storage_path('app/resources/avatars'); // 源目录:默认头像
|
||||
$to = storage_path('app/public/avatars'); // 目标目录:公共头像
|
||||
$this->filesystem->copyDirectory($from, $to); // 复制默认头像目录
|
||||
|
||||
// 复制其他静态图片
|
||||
$from = storage_path('app/resources/images'); // 源目录:其他静态图片
|
||||
$to = storage_path('app/public/images'); // 目标目录:公共静态图片
|
||||
$this->filesystem->copyDirectory($from, $to); // 复制其他静态图片目录
|
||||
|
||||
// 输出成功信息
|
||||
$this->info('copy file success'); // 命令执行成功后的提示信息
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
use App\Models\SiteCount; // 引入 SiteCount 模型
|
||||
use App\Services\SiteCountService; // 引入 SiteCountService 服务
|
||||
use Carbon\Carbon; // 引入 Carbon 日期处理库
|
||||
use Illuminate\Console\Command; // 引入 Laravel 的 Command 基类
|
||||
use Illuminate\Support\Facades\Cache; // 引入 Cache 门面(未使用,可以考虑移除)
|
||||
|
||||
/**
|
||||
* 统计站点数据控制台命令
|
||||
*
|
||||
* 该命令用于统计站点数据,执行时会将统计数据记录到前一天。
|
||||
*/
|
||||
class CountSite extends Command
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'moon:count-site'; // 定义命令的名称和签名
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '统计数据,直接执行会统计到昨天'; // 描述该命令的用途
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行控制台命令
|
||||
*
|
||||
* 该方法执行统计逻辑,统计前一天的数据并保存到数据库。
|
||||
*
|
||||
* @param SiteCountService $service 站点统计服务实例
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(SiteCountService $service)
|
||||
{
|
||||
// 获取昨天的日期
|
||||
$date = Carbon::now()->subDay(1)->toDateString(); // 获取当前日期并减去一天
|
||||
|
||||
/**
|
||||
* 防止一天运行多次,所以采用增加
|
||||
*
|
||||
* @var $site SiteCount
|
||||
*/
|
||||
// 查找或创建一个新的 SiteCount 实例,基于日期
|
||||
$site = SiteCount::query()->firstOrNew(compact('date')); // 如果没有记录则创建新记录
|
||||
|
||||
// 使用服务同步数据并保存
|
||||
$site = $service->syncByCache($site, true); // 同步数据,传入 $site 实例和强制更新标志
|
||||
$site->save(); // 保存统计数据到数据库
|
||||
|
||||
// 记录系统日志
|
||||
createSystemLog('系统统计站点数据', $site->toArray()); // 记录操作日志,包含统计的数据
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
use App\Services\ScoreLogServe; // 引入 ScoreLogServe 服务
|
||||
use Carbon\Carbon; // 引入 Carbon 日期处理库
|
||||
use Illuminate\Console\Command; // 引入 Laravel 的 Command 基类
|
||||
use Illuminate\Support\Facades\Cache; // 引入 Cache 门面
|
||||
|
||||
/**
|
||||
* 删除过期积分数据控制台命令
|
||||
*
|
||||
* 该命令用于删除昨天过期的积分统计数据。
|
||||
*/
|
||||
class DelExpireScoreData extends Command
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'moon:del-score-data'; // 定义命令的名称和签名
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Delete expired score data from the previous day'; // 描述该命令的用途
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行控制台命令
|
||||
*
|
||||
* 该方法执行删除过期积分数据的逻辑。
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// 获取昨天的日期
|
||||
$yesterday = Carbon::today()->subDay()->toDateString(); // 获取昨天的日期字符串
|
||||
|
||||
// 创建 ScoreLogServe 实例
|
||||
$serve = new ScoreLogServe(); // 实例化服务以处理积分日志
|
||||
|
||||
// 删除缓存中的过期积分数据
|
||||
Cache::delete($serve->loginKey($yesterday)); // 根据昨天的日期生成键并删除对应的缓存数据
|
||||
|
||||
// 记录系统日志
|
||||
createSystemLog("系统删除{$yesterday}过期积分统计数据", ['date' => $yesterday]); // 记录删除操作的日志
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
use App\Models\Seckill; // 引入 Seckill 模型
|
||||
use Carbon\Carbon; // 引入 Carbon 日期处理库
|
||||
use Illuminate\Console\Command; // 引入 Laravel 的 Command 基类
|
||||
use Illuminate\Support\Facades\Redis; // 引入 Redis 门面
|
||||
|
||||
/**
|
||||
* 删除过期秒杀数据控制台命令
|
||||
*
|
||||
* 该命令用于删除过期的秒杀数据,并将相关库存数量回滚到商品中。
|
||||
*/
|
||||
class DelExpireSecKill extends Command
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'moon:del-seckills'; // 定义命令的名称和签名
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'delete expire seckills'; // 描述该命令的用途
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行控制台命令
|
||||
*
|
||||
* 该方法执行删除过期秒杀数据的逻辑,并回滚相关库存。
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$rollbacks = collect(); // 创建一个集合,用于存储回滚的秒杀记录
|
||||
|
||||
// 查出已经过期且没有回滚过的秒杀
|
||||
Seckill::query()
|
||||
->where('is_rollback', 0) // 选择未回滚的秒杀
|
||||
->where('end_at', '<', Carbon::now()->toDateTimeString()) // 选择已过期的秒杀
|
||||
->get() // 获取符合条件的秒杀记录
|
||||
->map(function (Seckill $seckill) use ($rollbacks) {
|
||||
|
||||
// 1. 回滚数量到商品
|
||||
// 2. 设置为过期
|
||||
$product = $seckill->product()->first(); // 获取与秒杀相关联的商品
|
||||
|
||||
// 获取 Redis 中的秒杀数量
|
||||
$jsonSeckill = Redis::get($seckill->getRedisModelKey()); // 从 Redis 获取秒杀数据
|
||||
$redisSeckill = json_decode($jsonSeckill, true); // 将 JSON 数据解码为数组
|
||||
// 获取剩余的秒杀量
|
||||
$surplus = Redis::llen($seckill->getRedisQueueKey()); // 从 Redis 获取剩余秒杀量
|
||||
|
||||
// 恢复剩余的库存量
|
||||
// 恢复库存数量
|
||||
if ($redisSeckill['sale_count'] != 0) { // 如果 Redis 中的销售数量不为零
|
||||
$product->increment('sale_count', $redisSeckill['sale_count']); // 增加商品的销售数量
|
||||
}
|
||||
|
||||
if ($surplus != 0) { // 如果剩余秒杀量不为零
|
||||
$product->increment('count', $surplus); // 增加商品的总库存数量
|
||||
}
|
||||
|
||||
// 同步 Redis 数据到数据库中
|
||||
$seckill->sale_count += $redisSeckill['sale_count']; // 更新秒杀的销售数量
|
||||
$seckill->rollback_count += $surplus; // 更新秒杀的回滚数量
|
||||
$seckill->is_rollback = 1; // 标记为已回滚
|
||||
$seckill->save(); // 保存更新后的秒杀记录
|
||||
|
||||
$rollbacks->push($seckill); // 将已回滚的秒杀记录添加到集合中
|
||||
|
||||
// 删除掉秒杀数据
|
||||
$ids = Redis::connection()->keys("seckills:{$seckill->id}:*"); // 获取与秒杀相关的所有 Redis 键
|
||||
Redis::del($ids); // 删除这些 Redis 键
|
||||
});
|
||||
|
||||
if ($rollbacks->isNotEmpty()) { // 如果有回滚的秒杀记录
|
||||
createSystemLog('系统回滚秒杀数据', $rollbacks->toArray()); // 记录系统回滚操作的日志
|
||||
}
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
use Illuminate\Support\Facades\Storage; // 引入 Storage 门面
|
||||
|
||||
/**
|
||||
* 删除文件控制台命令
|
||||
*
|
||||
* 该命令用于删除所有上传的静态资源文件。
|
||||
*/
|
||||
class DeleteFile extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'moon:delete'; // 定义命令的名称和签名
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Delete all upload static resources'; // 描述该命令的用途
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除静态资源文件
|
||||
*
|
||||
* 该方法执行删除操作,删除指定的静态资源目录及其内容。
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// 删除上传列表目录
|
||||
Storage::deleteDirectory('public' . DIRECTORY_SEPARATOR . config('web.upload.list')); // 根据配置删除上传列表目录
|
||||
|
||||
// 删除上传详情目录
|
||||
Storage::deleteDirectory('public' . DIRECTORY_SEPARATOR . config('web.upload.detail')); // 根据配置删除上传详情目录
|
||||
|
||||
// 输出成功信息
|
||||
$this->info('delete file success'); // 命令执行成功后的提示信息
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
use App\Models\User; // 引入 User 模型
|
||||
use Illuminate\Console\Command; // 引入 Laravel 的 Command 基类
|
||||
use Illuminate\Database\Eloquent\Model; // 引入 Eloquent 模型基类
|
||||
use Illuminate\Support\Collection; // 引入 Collection 类
|
||||
|
||||
/**
|
||||
* 导出数据库命令
|
||||
*
|
||||
* 该命令用于将用户数据导出到 JSON 文件中。
|
||||
*/
|
||||
class ExportDatabaseCommand extends Command
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'moon:export'; // 定义命令的名称和签名
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '导出数据到 json 文件'; // 描述该命令的用途
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行控制台命令
|
||||
*
|
||||
* 该方法执行导出用户数据的逻辑,将数据保存为 JSON 格式。
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// 查询所有用户并按创建时间升序排列
|
||||
$users = User::query()
|
||||
->oldest() // 按照创建时间升序排列
|
||||
->get() // 获取所有用户记录
|
||||
->transform(function (User $user) {
|
||||
// 先排除自身主键
|
||||
$user->offsetUnset($user->getKeyName()); // 从用户模型中移除主键字段
|
||||
|
||||
return $user; // 返回处理后的用户对象
|
||||
});
|
||||
|
||||
// 将用户数据转换为 JSON 格式并写入指定文件
|
||||
file_put_contents(\UsersTableSeeder::DATA_PATH, $users->toJson(JSON_UNESCAPED_UNICODE)); // 保存 JSON 数据到文件
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
use App\Models\Product; // 引入 Product 模型
|
||||
|
||||
/**
|
||||
* 安装商城命令
|
||||
*
|
||||
* 该命令用于初始化商城项目,包括数据库迁移、数据填充和资源复制等操作。
|
||||
*/
|
||||
class InstallShop extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'moon:install'; // 定义命令的名称和签名
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '初始化商城项目'; // 描述该命令的用途
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行商城安装命令
|
||||
*
|
||||
* 该方法执行初始化商城项目的逻辑,包括数据库迁移、数据填充和静态资源处理等。
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// 生成应用的加密密钥
|
||||
$this->call('key:generate');
|
||||
|
||||
// 删除上一次保留的数据表
|
||||
$this->call('migrate:reset'); // 重置数据库迁移,删除所有表
|
||||
|
||||
// 删除上一次保留的文件
|
||||
$this->call('moon:delete'); // 删除之前的文件或数据
|
||||
|
||||
// 禁止在安装过程中将产品添加到搜索索引
|
||||
Product::$addToSearch = false;
|
||||
|
||||
/****************************************
|
||||
* 1. 迁移数据表
|
||||
* 2. 数据库迁移
|
||||
* 3. 复制静态资源
|
||||
* 4. 创建软链接
|
||||
****************************************/
|
||||
$this->call('migrate'); // 执行数据库迁移,创建所需的数据表
|
||||
$this->call('db:seed'); // 填充数据库,插入初始数据
|
||||
$this->call('moon:copy'); // 复制静态资源到公共目录
|
||||
$this->call('storage:link'); // 创建存储目录的软链接,以便访问存储的文件
|
||||
|
||||
// 更新首页数据,防止上一次遗留数据的影响
|
||||
$this->call('moon:update-home'); // 更新首页相关数据
|
||||
|
||||
// 生成全文索引
|
||||
$this->call('add:shop-to-search'); // 为商城产品生成搜索索引
|
||||
|
||||
// 直接开启监听队列
|
||||
// $this->info('queue starting please don`t close cmd windows!!!');
|
||||
// $this->call('queue:work', ['--tries' => '3']); // 启动队列工作进程,处理队列任务
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
use App\Mail\SubscribesNotice; // 引入订阅通知邮件类
|
||||
use App\Models\Subscribe; // 引入订阅模型
|
||||
use Illuminate\Console\Command; // 引入 Laravel 的 Command 基类
|
||||
use Mail; // 引入 Mail 门面
|
||||
|
||||
/**
|
||||
* 发送订阅邮件命令
|
||||
*
|
||||
* 该命令用于向所有已订阅用户发送通知邮件。
|
||||
*/
|
||||
class SendSubscribeEmail extends Command
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'moon:send-subscribes'; // 定义命令的名称和签名
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '发送订阅通知邮件'; // 描述该命令的用途
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行控制台命令
|
||||
*
|
||||
* 该方法执行发送订阅邮件的逻辑,包括查询订阅用户和发送邮件。
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// 查询所有已订阅的用户邮箱
|
||||
$mails = Subscribe::query()
|
||||
->where('is_subscribe', 1) // 只选择已订阅的用户
|
||||
->pluck('email'); // 获取邮箱地址列表
|
||||
|
||||
// 遍历每个邮箱并发送通知邮件
|
||||
$mails->map(function ($realMail) {
|
||||
// 对邮箱进行加密处理
|
||||
$email = encrypt($realMail);
|
||||
// 生成包含加密邮箱的邮件链接
|
||||
$url = route('site.email', compact('email'));
|
||||
|
||||
// 发送邮件给当前用户
|
||||
// 不要一次发送给多个用户,以免暴露其他人的邮箱
|
||||
Mail::to($realMail)->send(new SubscribesNotice($url));
|
||||
});
|
||||
|
||||
// 记录系统日志,记录发送的用户信息
|
||||
createSystemLog('系统发送订阅消息, 发送的用户:' . $mails->implode(', '), $mails->toArray());
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
use App\Models\Product; // 引入 Product 模型
|
||||
use Carbon\Carbon; // 引入 Carbon 日期处理库
|
||||
use Illuminate\Console\Command; // 引入 Laravel 的 Command 基类
|
||||
use Illuminate\Support\Facades\Cache; // 引入 Cache 门面
|
||||
|
||||
/**
|
||||
* 同步商品浏览量命令
|
||||
*
|
||||
* 该命令用于同步前一天的商品浏览量,并更新数据库中的相关记录。
|
||||
*/
|
||||
class SyncProductViewCommand extends Command
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'moon:sync-product_view'; // 定义命令的名称和签名
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '同步商品浏览量'; // 描述该命令的用途
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行控制台命令
|
||||
*
|
||||
* 该方法执行同步商品浏览量的逻辑,包括获取前一天的浏览量并更新数据库。
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// 获取昨天的日期字符串
|
||||
$yesterday = Carbon::yesterday()->toDateString(); // 获取昨天的日期,格式为 YYYY-MM-DD
|
||||
|
||||
// 查询所有今天有浏览量记录的商品
|
||||
$products = Product::query()->where('today_has_view', 1)->get(); // 获取所有今天有浏览量的商品
|
||||
|
||||
// 遍历每个商品并更新浏览量
|
||||
$products->map(function (Product $product) use ($yesterday) {
|
||||
// 从缓存中取出前一天的浏览量,默认值为 0
|
||||
$viewCount = Cache::pull($product->getViewCountKey($yesterday), 0);
|
||||
// 更新商品的浏览量
|
||||
$product->view_count += $viewCount; // 累加前一天的浏览量
|
||||
$product->today_has_view = 0; // 重置今天的浏览量标记
|
||||
$product->save(); // 保存更新后的商品信息
|
||||
});
|
||||
|
||||
// 记录系统日志,记录同步操作的信息
|
||||
createSystemLog("系统同步{$yesterday}商品浏览量", ['date' => $yesterday]); // 记录同步的日期
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands; // 定义命名空间
|
||||
|
||||
/**
|
||||
* 卸载商城项目命令
|
||||
*
|
||||
* 该命令用于卸载商城项目,包括清理缓存、重置数据库迁移和删除上传的静态资源。
|
||||
*/
|
||||
class UninstallShop extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* 控制台命令的名称和签名
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'moon:uninstall'; // 定义命令的名称和签名
|
||||
|
||||
/**
|
||||
* 控制台命令的描述
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '卸载商城项目'; // 描述该命令的用途
|
||||
|
||||
/**
|
||||
* 创建一个新的命令实例.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(); // 调用父类构造函数
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行控制台命令
|
||||
*
|
||||
* 该方法执行卸载商城项目的逻辑,依次调用其他命令来完成任务。
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// 调用清理命令,清除缓存
|
||||
$this->call('moon:clear');
|
||||
|
||||
// 调用迁移重置命令,重置数据库迁移
|
||||
$this->call('migrate:reset');
|
||||
|
||||
// 删除所有上传的静态资源
|
||||
$this->call('moon:delete');
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console; // 定义命名空间
|
||||
|
||||
// 引入需要的控制台命令类
|
||||
use App\Console\Commands\CountSite; // 引入 CountSite 命令
|
||||
use App\Console\Commands\DelExpireScoreData; // 引入 DelExpireScoreData 命令
|
||||
use App\Console\Commands\DelExpireSecKill; // 引入 DelExpireSecKill 命令
|
||||
use App\Console\Commands\SendSubscribeEmail; // 引入 SendSubscribeEmail 命令
|
||||
use App\Console\Commands\SyncProducViewCommand; // 引入 SyncProducViewCommand 命令
|
||||
use App\Console\Commands\UpdateCacheHomeData; // 引入 UpdateCacheHomeData 命令
|
||||
use Illuminate\Console\Scheduling\Schedule; // 引入 Schedule 类
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel; // 引入 ConsoleKernel 基类
|
||||
|
||||
/**
|
||||
* 控制台命令调度内核
|
||||
*
|
||||
* 该类负责注册和调度应用程序的 Artisan 命令。
|
||||
*/
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
/**
|
||||
* 应用程序提供的 Artisan 命令
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $commands = [
|
||||
// 注册的命令列表
|
||||
];
|
||||
|
||||
/**
|
||||
* 定义应用程序的命令调度
|
||||
*
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
* @return void
|
||||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
// 每周六早上 8 点发送订阅邮件
|
||||
$schedule->command(SendSubscribeEmail::class)->saturdays()->at('8:00');
|
||||
|
||||
// 每天凌晨 1 点统计注册人数和销售数量
|
||||
$schedule->command(CountSite::class)->dailyAt('01:00');
|
||||
|
||||
// 每小时执行一次,回滚秒杀过期的数据
|
||||
$schedule->command(DelExpireSecKill::class)->hourly();
|
||||
|
||||
// 每天午夜 12 点删除昨天过期的积分数据
|
||||
$schedule->command(DelExpireScoreData::class)->dailyAt('00:00');
|
||||
|
||||
// 每天午夜 12 点 10 分同步商品浏览量
|
||||
$schedule->command(SyncProducViewCommand::class)->dailyAt('00:10');
|
||||
|
||||
// 每分钟更新一次首页数据
|
||||
$schedule->command(UpdateCacheHomeData::class)->everyMinute();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册应用程序的命令
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function commands()
|
||||
{
|
||||
// 加载命令目录下的所有命令
|
||||
$this->load(__DIR__.'/Commands');
|
||||
|
||||
// 引入控制台路由文件
|
||||
require base_path('routes/console.php');
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
|
||||
use MyCLabs\Enum\Enum;
|
||||
|
||||
class HomeCacheEnum extends Enum
|
||||
{
|
||||
// CHANGE: 修改 kye 名,防止旧版本 key 永久缓存不修改
|
||||
const SEC_KILL_DATA = 'home_page:sec_kill_data';
|
||||
const CATEGORIES = 'home_page:categories';
|
||||
const HOTTEST = 'home_page:hottest';
|
||||
const LATEST = 'home_page:latest';
|
||||
const USERS = 'home_page:users';
|
||||
const COUPON_TEMPLATES = 'home_page:templates';
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
|
||||
use MyCLabs\Enum\Enum;
|
||||
|
||||
class OrderPayTypeEnum extends Enum
|
||||
{
|
||||
const ALI = 'ali';
|
||||
const WECHAT = 'wechat';
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
|
||||
use MyCLabs\Enum\Enum;
|
||||
|
||||
class OrderShipStatusEnum extends Enum
|
||||
{
|
||||
// 未发货
|
||||
const PENDING = 1;
|
||||
// 待收货
|
||||
const DELIVERED = 2;
|
||||
// 已收货
|
||||
const RECEIVED = 3;
|
||||
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
|
||||
use MyCLabs\Enum\Enum;
|
||||
|
||||
class OrderStatusEnum extends Enum
|
||||
{
|
||||
|
||||
const UN_PAY_CANCEL = 0;
|
||||
// 未支付
|
||||
const UN_PAY = 1;
|
||||
// 已经支付
|
||||
const PAID = 2;
|
||||
// 订单完成
|
||||
const COMPLETED = 3;
|
||||
|
||||
// 超时未支付
|
||||
const TIMEOUT_CANCEL = 4;
|
||||
// 申请退款
|
||||
const APPLY_REFUND = 5;
|
||||
// 退款
|
||||
const REFUND = 6;
|
||||
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
|
||||
use MyCLabs\Enum\Enum;
|
||||
|
||||
class OrderTypeEnum extends Enum
|
||||
{
|
||||
const COMMON = 1;
|
||||
const SEC_KILL = 2;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
|
||||
use MyCLabs\Enum\Enum;
|
||||
|
||||
class ScoreRuleIndexEnum extends Enum
|
||||
{
|
||||
const CONTINUE_LOGIN = 'continue_login';
|
||||
const VISITED_PRODUCT = 'visited_product';
|
||||
const COMPLETE_ORDER = 'complete_order';
|
||||
const LOGIN = 'login';
|
||||
const REGISTER = 'register';
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
|
||||
use MyCLabs\Enum\Enum;
|
||||
|
||||
class SettingKeyEnum extends Enum
|
||||
{
|
||||
const USER_INIT_PASSWORD = 'user_init_password';
|
||||
const IS_OPEN_SECKILL = 'is_open_seckill';
|
||||
const UN_PAY_CANCEL_TIME = 'order_un_pay_auto_cancel_time';
|
||||
const POST_AMOUNT = 'post_amount';
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
|
||||
use MyCLabs\Enum\Enum;
|
||||
|
||||
class SiteCountCacheEnum extends Enum
|
||||
{
|
||||
// 注册的 key
|
||||
const REGISTERED_COUNT = 'site_counts:registered_count';
|
||||
const GITHUB_REGISTERED_COUNT = 'site_counts:github_registered_count';
|
||||
const QQ_REGISTER_COUNT = 'site_counts:qq_registered_count';
|
||||
const WEIBO_REGISTER_COUNT = 'site_counts:weibo_registered_count';
|
||||
const MOON_REGISTER_COUNT = 'site_counts:moon_registered_count';
|
||||
|
||||
// 订单的 key 统计
|
||||
const ORDER_COUNT = 'site_counts:order_count';
|
||||
// 成功支付的订单
|
||||
const PAY_ORDER_COUNT = 'site_counts:order_pay_count';
|
||||
// 退款订单量
|
||||
const REFUND_ORDER_COUNT = 'site_counts:refund_pay_count';
|
||||
// 销售金额
|
||||
const SALE_ORDER_COUNT = 'site_counts:sale_money_count';
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
|
||||
use MyCLabs\Enum\Enum;
|
||||
|
||||
class UserSexEnum extends Enum
|
||||
{
|
||||
const MAN = 1;
|
||||
const WOMAN = 2;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
|
||||
use MyCLabs\Enum\Enum;
|
||||
|
||||
class UserSourceEnum extends Enum
|
||||
{
|
||||
// 默认上城创建
|
||||
const MOON = 1;
|
||||
const GITHUB = 2;
|
||||
const QQ = 3;
|
||||
const WEIBO = 4;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
|
||||
use MyCLabs\Enum\Enum;
|
||||
|
||||
class UserStatusEnum extends Enum
|
||||
{
|
||||
const ACTIVE = 1;
|
||||
const UN_ACTIVE = 0;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
|
||||
class Event
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return \Illuminate\Broadcasting\Channel|array
|
||||
*/
|
||||
public function broadcastOn()
|
||||
{
|
||||
return new PrivateChannel('channel-name');
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class BadRequestException extends Exception
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
|
@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Throwable;
|
||||
use Tymon\JWTAuth\Exceptions\JWTException;
|
||||
use Tymon\JWTAuth\Exceptions\TokenBlacklistedException;
|
||||
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
/**
|
||||
* The list of the inputs that are never flashed to the session on validation exceptions.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $dontFlash = [
|
||||
'current_password',
|
||||
'password',
|
||||
'password_confirmation',
|
||||
];
|
||||
/**
|
||||
* Register the exception handling callbacks for the application.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
// 处理可报告的异常
|
||||
$this->reportable(function (Throwable $e) {
|
||||
// 可以在这里记录异常或执行其他操作
|
||||
});
|
||||
// 处理可渲染的异常
|
||||
$this->renderable(function (\Exception $exception, Request $request) {
|
||||
// 检查请求是否为 API 请求
|
||||
if ($request->is('api*')) {
|
||||
// 处理 JWT 相关的异常
|
||||
if ($exception instanceof JWTException) {
|
||||
// 映射 JWT 异常到用户友好的消息
|
||||
$mapExceptions = [
|
||||
TokenInvalidException::class => '无效的token',
|
||||
TokenBlacklistedException::class => 'token 已被加入黑名单,请重新登录'
|
||||
];
|
||||
// 获取对应的错误消息
|
||||
$msg = $mapExceptions[get_class($exception)] ?? $exception->getMessage();
|
||||
return responseJsonAsUnAuthorized($msg); // 返回未授权的 JSON 响应
|
||||
}
|
||||
// 拦截表单验证错误抛出的异常
|
||||
elseif ($exception instanceof ValidationException) {
|
||||
return responseJsonAsBadRequest($exception->validator->errors()->first()); // 返回验证错误的 JSON 响应
|
||||
}
|
||||
// 处理其他服务器错误
|
||||
return responseJsonAsServerError($exception->getMessage());
|
||||
}
|
||||
// 对于非 API 请求,返回服务器错误信息
|
||||
return responseJsonAsServerError($exception->getMessage(), null);
|
||||
});
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: David
|
||||
* Date: 2018/10/19
|
||||
* Time: 22:04
|
||||
*/
|
||||
namespace App\Exceptions;
|
||||
class OrderException extends \Exception
|
||||
{
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: David
|
||||
* Date: 2018/10/19
|
||||
* Time: 22:04
|
||||
*/
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
|
||||
class UploadException extends \Exception
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Enums\UserSexEnum;
|
||||
use App\Enums\UserStatusEnum;
|
||||
use App\Exceptions\BadRequestException;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\LoginRequest;
|
||||
use App\Http\Requests\RegisterUserRequest;
|
||||
use App\Http\Resources\OwnResource;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
/**
|
||||
* 登录的接口
|
||||
*
|
||||
* @param LoginRequest $request 登录请求数据
|
||||
* @return \Illuminate\Http\JsonResponse 返回登录结果的 JSON 响应
|
||||
*/
|
||||
public function login(LoginRequest $request)
|
||||
{
|
||||
// 获取用户名和密码
|
||||
$username = $request->input('username');
|
||||
$password = $request->input('password');
|
||||
|
||||
// 查询用户
|
||||
$user = User::query()
|
||||
->whereNotNull('name')
|
||||
->where('name', $username)
|
||||
->first();
|
||||
|
||||
// 检查用户是否存在
|
||||
if (is_null($user)) {
|
||||
return responseJsonAsBadRequest('用户名或者密码错误');
|
||||
}
|
||||
|
||||
// 验证密码是否正确
|
||||
if (! Hash::check($password, $user->getAuthPassword())) {
|
||||
return responseJsonAsBadRequest('用户名或者密码错误');
|
||||
}
|
||||
|
||||
// 返回成功响应和 token
|
||||
return responseJson(200, '登录成功', $this->getToken($user));
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销的接口
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse 返回注销结果的 JSON 响应
|
||||
*/
|
||||
public function logout()
|
||||
{
|
||||
// 注销用户
|
||||
auth('api')->logout();
|
||||
|
||||
return responseJsonAsDeleted('注销成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册的接口
|
||||
*
|
||||
* @param RegisterUserRequest $request 注册请求数据
|
||||
* @return \Illuminate\Http\JsonResponse 返回注册结果的 JSON 响应
|
||||
*/
|
||||
public function register(RegisterUserRequest $request)
|
||||
{
|
||||
// 获取用户名和密码
|
||||
$username = $request->input('username');
|
||||
$password = $request->input('password');
|
||||
|
||||
// 检查用户名是否已存在
|
||||
if (User::query()->where('name', $username)->exists()) {
|
||||
return responseJsonAsBadRequest('用户名已经存在, 请换一个用户名');
|
||||
}
|
||||
|
||||
// 创建新用户
|
||||
$user = new User();
|
||||
$user->name = $username;
|
||||
$user->password = Hash::make($password); // 确保密码被哈希处理
|
||||
$user->sex = UserSexEnum::MAN; // 默认性别
|
||||
$user->is_init_email = 1; // 初始化邮箱状态
|
||||
$user->is_active = UserStatusEnum::ACTIVE; // 默认激活状态
|
||||
$user->save(); // 保存用户信息
|
||||
|
||||
// 返回成功响应和 token
|
||||
return responseJson(201, '注册成功', $this->getToken($user));
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接 token
|
||||
*
|
||||
* @param User $user 用户模型
|
||||
* @return array 返回包含 token 的数组
|
||||
*/
|
||||
protected function getToken(User $user)
|
||||
{
|
||||
// 生成 token
|
||||
$prefix = 'Bearer';
|
||||
$token = auth('api')->login($user); // 登录并获取 token
|
||||
$me = new OwnResource($user); // 创建用户资源
|
||||
|
||||
return compact('prefix', 'token', 'me'); // 返回 token 和用户信息
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Resources\CategoreResource;
|
||||
use App\Http\Resources\ProductResource;
|
||||
use App\Models\Category;
|
||||
use App\Services\PageServe;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
/**
|
||||
* 获取分类列表
|
||||
*
|
||||
* @param PageServe $serve 分页服务
|
||||
* @return \Illuminate\Http\JsonResponse 返回分类列表的 JSON 响应
|
||||
*/
|
||||
public function index(PageServe $serve)
|
||||
{
|
||||
// 获取分页参数
|
||||
list($limit, $offset) = $serve->getPageParameters();
|
||||
|
||||
// 构建分类查询
|
||||
$query = Category::query();
|
||||
|
||||
// 根据名称过滤分类
|
||||
if ($title = $serve->input('name')) {
|
||||
$query->where('title', 'like', "%{$title}%");
|
||||
}
|
||||
|
||||
// 获取总数和分类数据
|
||||
$count = $query->count();
|
||||
$categories = $query->orderBy('order')->limit($limit)->offset($offset)->get();
|
||||
$categories = CategoreResource::collection($categories); // 转换为资源集合
|
||||
|
||||
return responseJson(200, 'success', $categories, compact('count')); // 返回成功响应
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定分类下的产品
|
||||
*
|
||||
* @param PageServe $serve 分页服务
|
||||
* @param int $category 分类 ID
|
||||
* @return \Illuminate\Http\JsonResponse 返回产品列表的 JSON 响应
|
||||
*/
|
||||
public function getProducts(PageServe $serve, $category)
|
||||
{
|
||||
// 获取分页参数
|
||||
list($limit, $offset) = $serve->getPageParameters();
|
||||
|
||||
// 排序的字段和排序的值
|
||||
$orderField = $serve->input('order_field');
|
||||
$orderValue = $serve->input('order_value');
|
||||
|
||||
// 查找指定分类
|
||||
/**
|
||||
* @var $category Category
|
||||
*/
|
||||
$category = Category::query()->findOrFail($category);
|
||||
|
||||
// 获取该分类下的产品查询
|
||||
$query = $category->products();
|
||||
|
||||
// 根据名称过滤产品
|
||||
if ($name = $serve->input('name')) {
|
||||
$query->where('name', 'like', "%{$name}%");
|
||||
}
|
||||
|
||||
// 获取排序的字段
|
||||
$allFields = ['created_at', 'sale_count', 'view_count'];
|
||||
$orderField = in_array($orderField, $allFields) ?
|
||||
$orderField :
|
||||
array_first($allFields); // 默认排序字段
|
||||
$orderValue = $orderValue === 'asc' ? 'asc' : 'desc'; // 默认排序方式
|
||||
|
||||
// 获取数据
|
||||
$count = $query->count(); // 获取产品总数
|
||||
$products = $query->orderBy($orderField, $orderValue)
|
||||
->limit($limit)
|
||||
->offset($offset)
|
||||
->get();
|
||||
$products = ProductResource::collection($products); // 转换为资源集合
|
||||
|
||||
return responseJson(200, 'success', $products, compact('count')); // 返回成功响应
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
public function ping()
|
||||
{
|
||||
return responseJsonAsUnAuthorized();
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Resources\OwnResource;
|
||||
use App\Http\Resources\ScoreLogResource;
|
||||
use App\Models\User;
|
||||
use App\Services\PageServe;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class OwnController extends Controller
|
||||
{
|
||||
/**
|
||||
* 获取当前用户的信息
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse 返回当前用户信息的 JSON 响应
|
||||
*/
|
||||
public function me()
|
||||
{
|
||||
// 获取当前认证用户
|
||||
$me = auth()->user();
|
||||
|
||||
// 返回成功响应和用户信息
|
||||
return responseJson(200, 'success', new OwnResource($me));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的积分日志
|
||||
*
|
||||
* @param PageServe $serve 分页服务
|
||||
* @return \Illuminate\Http\JsonResponse 返回积分日志的 JSON 响应
|
||||
*/
|
||||
public function scoreLogs(PageServe $serve)
|
||||
{
|
||||
// 获取分页参数
|
||||
list($limit, $offset) = $serve->getPageParameters();
|
||||
|
||||
/**
|
||||
* @var $me User
|
||||
*/
|
||||
// 获取当前认证用户
|
||||
$me = auth()->user();
|
||||
|
||||
// 获取用户的积分日志查询
|
||||
$query = $me->scoreLogs();
|
||||
|
||||
// 获取积分日志总数
|
||||
$count = $query->count();
|
||||
|
||||
// 获取分页后的积分日志数据
|
||||
$scoreLogs = $me->scoreLogs()
|
||||
->latest() // 按时间降序排列
|
||||
->offset($offset) // 设置偏移量
|
||||
->limit($limit) // 设置限制
|
||||
->get();
|
||||
|
||||
// 返回成功响应和积分日志
|
||||
return responseJson(200, 'success', ScoreLogResource::collection($scoreLogs), compact('count'));
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Resources\ProductResource;
|
||||
use App\Models\Product;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class ProductController extends Controller
|
||||
{
|
||||
public function show($uuid)
|
||||
{
|
||||
$product = Product::query()->where('uuid', $uuid)->firstOrFail();
|
||||
$product->load('detail');
|
||||
|
||||
// 直接使用缓存
|
||||
$today = Carbon::today()->toDateString();
|
||||
Cache::increment($product->getViewCountKey($today));
|
||||
|
||||
return responseJson(200, 'success', new ProductResource($product));
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ForgotPasswordController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling password reset emails and
|
||||
| includes a trait which assists in sending these notifications from
|
||||
| your application to your users. Feel free to explore this trait.
|
||||
|
|
||||
*/
|
||||
|
||||
use SendsPasswordResetEmails;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest');
|
||||
}
|
||||
|
||||
protected function guard()
|
||||
{
|
||||
return auth()->guard();
|
||||
}
|
||||
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Enums\UserSexEnum;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Mail\UserRegister;
|
||||
use App\Models\User;
|
||||
use Gregwar\Captcha\CaptchaBuilder;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Foundation\Auth\RegistersUsers;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class RegisterController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Register Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller handles the registration of new users as well as their
|
||||
| validation and creation. By default this controller uses a trait to
|
||||
| provide this functionality without requiring any additional code.
|
||||
|
|
||||
*/
|
||||
|
||||
use RegistersUsers;
|
||||
|
||||
/**
|
||||
* Where to redirect users after registration.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/home';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 核心注册方法
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function register(Request $request)
|
||||
{
|
||||
$this->validator($request->all())->validate();
|
||||
|
||||
if (strtolower($request->input('captcha')) != strtolower(session('captcha'))) {
|
||||
|
||||
return redirect('/register')->withErrors(['captcha' => '验证码不正确']);
|
||||
}
|
||||
|
||||
|
||||
event(new Registered($user = $this->create($request->all())));
|
||||
|
||||
$this->registered($request, $user);
|
||||
return redirect('/login')->with('status', '注册成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* registered event (send email)
|
||||
* @param Request $request
|
||||
* @param $user
|
||||
*/
|
||||
protected function registered(Request $request, $user)
|
||||
{
|
||||
Mail::to($user->email)
|
||||
->queue(new UserRegister($user));
|
||||
}
|
||||
|
||||
|
||||
protected function validator(array $data)
|
||||
{
|
||||
return Validator::make($data, [
|
||||
'name' => 'required|string|max:50|unique:users',
|
||||
'email' => 'required|string|email|max:50|unique:users',
|
||||
'password' => 'required|string|min:5|confirmed',
|
||||
'sex' => ['required', Rule::in([UserSexEnum::MAN, UserSexEnum::WOMAN])],
|
||||
'captcha' => 'required',
|
||||
], [
|
||||
'name.required' => '用户名不能为空',
|
||||
'name.max' => '用户名不能超过50个字符',
|
||||
'name.unique' => '用户名已经被占用',
|
||||
'email.unique' => '邮箱已经被占用',
|
||||
'email.required' => '邮箱不能为空',
|
||||
'email.email' => '邮箱格式不正确',
|
||||
'password.min' => '密码最少六位数',
|
||||
'password.required' => '密码不能为空',
|
||||
'password.confirmed' => '两次密码不一致',
|
||||
'captcha.required' => '验证码不能为空',
|
||||
'sex.in' => '性别错误',
|
||||
]);
|
||||
}
|
||||
|
||||
protected function create(array $data)
|
||||
{
|
||||
// email_active,
|
||||
return User::query()->create([
|
||||
'name' => $data['name'],
|
||||
'email' => $data['email'],
|
||||
'sex' => $data['sex'],
|
||||
'password' => bcrypt($data['password']),
|
||||
'active_token' => str_random(60),
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
protected function redirectTo()
|
||||
{
|
||||
return 'register';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function captcha()
|
||||
{
|
||||
$builder = (new CaptchaBuilder(4))->build(150, 46);
|
||||
|
||||
session()->put('captcha', $builder->getPhrase());
|
||||
|
||||
return $builder->get();
|
||||
}
|
||||
|
||||
protected function guard()
|
||||
{
|
||||
return auth()->guard();
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ResetPasswordController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling password reset requests
|
||||
| and uses a simple trait to include this behavior. You're free to
|
||||
| explore this trait and override any methods you wish to tweak.
|
||||
|
|
||||
*/
|
||||
|
||||
use ResetsPasswords;
|
||||
|
||||
/**
|
||||
* Where to redirect users after resetting their password.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/home';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest');
|
||||
}
|
||||
|
||||
public function validationErrorMessages()
|
||||
{
|
||||
return [
|
||||
'token.required' => '重置密码的token不是对应这个邮箱',
|
||||
'email.required' => '邮件地址不正确',
|
||||
'email.email' => '邮件地址不正确',
|
||||
'password.required' => '密码不能为空',
|
||||
'password.confirmed' => '两次密码不一致',
|
||||
'password.min' => '密码不能少于六位数',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* rewrite Illuminate\Foundation\Auth\ResetsPasswords::resetPassword not login
|
||||
* @param $user
|
||||
* @param $password
|
||||
*/
|
||||
public function resetPassword($user, $password)
|
||||
{
|
||||
$user->password = Hash::make($password);
|
||||
$user->setRememberToken(Str::random(60));
|
||||
$user->save();
|
||||
|
||||
// event(new PasswordReset($user));
|
||||
// $this->guard()->login($user);
|
||||
}
|
||||
|
||||
public function redirectTo()
|
||||
{
|
||||
return 'password/reset';
|
||||
}
|
||||
|
||||
protected function guard()
|
||||
{
|
||||
return auth()->guard();
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Mail\UserRegister;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function activeAccount($token)
|
||||
{
|
||||
if ($user = User::query()->where('active_token', $token)->first()) {
|
||||
$user->is_active = 1;
|
||||
// 重新生成激活token
|
||||
$user->active_token = str_random(60);
|
||||
$user->save();
|
||||
|
||||
return view('hint.success', ['status' => "{$user->name} 账户激活成功!", 'url' => url('login')]);
|
||||
} else {
|
||||
return view('hint.error', ['status' => '无效的token']);
|
||||
}
|
||||
}
|
||||
|
||||
public function sendActiveMail($id)
|
||||
{
|
||||
if ($user = User::query()->find($id)) {
|
||||
// again send active link, join queue
|
||||
Mail::to($user->email)
|
||||
->queue(new UserRegister($user));
|
||||
|
||||
return view('hint.success', ['status' => '发送邮件成功', 'url' => route('login')]);
|
||||
|
||||
}
|
||||
|
||||
return view('hint.error', ['status' => '用户名或者密码错误']);
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Car;
|
||||
use App\Models\Product;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CarController extends Controller
|
||||
{
|
||||
// 构造函数,设置中间件
|
||||
public function __construct()
|
||||
{
|
||||
// 仅对 store 和 destroy 方法应用用户身份验证中间件
|
||||
$this->middleware('user.auth')->only('store', 'destroy');
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示购物车列表
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View 返回购物车视图
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$cars = collect(); // 初始化购物车集合
|
||||
|
||||
/**
|
||||
* @var $user User
|
||||
*/
|
||||
// 获取当前登录用户的购物车
|
||||
if ($user = \auth()->user()) {
|
||||
// 直接获取当前用户的购物车及其关联的产品
|
||||
$cars = $user->cars()->with('product')->get();
|
||||
}
|
||||
|
||||
// 返回购物车视图,并传递购物车数据
|
||||
return view('cars.index', compact('cars'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加商品到购物车
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return array 返回操作结果
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
/**
|
||||
* @var $car Car
|
||||
* @var $product Product
|
||||
* @var $user User
|
||||
*/
|
||||
// 根据产品 UUID 查找产品
|
||||
$product = Product::query()->where('uuid', $request->input('product_id'))->firstOrFail();
|
||||
|
||||
// 获取当前用户
|
||||
$user = auth()->user();
|
||||
// 查找或新建购物车记录
|
||||
$car = $user->cars()->firstOrNew([
|
||||
'user_id' => \auth()->id(),
|
||||
'product_id' => $product->id
|
||||
]);
|
||||
|
||||
// 处理购物车数量变化
|
||||
$change = 0; // 数量变化
|
||||
$number = $request->input('number', 1); // 获取请求中的数量,默认为 1
|
||||
|
||||
if ($request->input('action') == 'sync') {
|
||||
// 如果是同步操作,直接设置数量
|
||||
$change = $number - $car->number;
|
||||
$car->number = $number;
|
||||
} else {
|
||||
// 否则,增加数量
|
||||
$car->number += $number;
|
||||
}
|
||||
|
||||
// 检查库存是否足够
|
||||
if ($car->number > $product->count) {
|
||||
return responseJson(403, '库存不足'); // 返回库存不足的响应
|
||||
}
|
||||
|
||||
// 保存购物车记录
|
||||
$car->save();
|
||||
|
||||
// 返回成功响应
|
||||
return responseJson(200, '加入购物车成功', compact('change'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从购物车中删除商品
|
||||
*
|
||||
* @param $id 购物车项的 ID
|
||||
* @return array 返回操作结果
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
try {
|
||||
/**
|
||||
* @var $user User
|
||||
*/
|
||||
// 获取当前用户
|
||||
$user = auth()->user();
|
||||
// 查找购物车项并删除
|
||||
$car = $user->cars()->whereKey($id)->firstOrFail();
|
||||
$car->delete();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// 捕获异常并返回错误响应
|
||||
dd($e); // 可选:调试输出异常信息
|
||||
return responseJson(500, '服务器异常,请稍后再试');
|
||||
}
|
||||
|
||||
// 返回成功响应
|
||||
return responseJson(200, '删除成功');
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Category;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
/**
|
||||
* 显示前台分类列表
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View 返回分类列表视图
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
// 获取最新的分类,分页显示,每页 30 条
|
||||
$categories = Category::query()->latest()->paginate(30);
|
||||
|
||||
// 返回分类列表视图,并传递分类数据
|
||||
return view('categories.index', compact('categories'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示分类详情
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @param Category $category 分类模型实例
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View 返回分类详情视图
|
||||
*/
|
||||
public function show(Request $request, Category $category)
|
||||
{
|
||||
// 获取排序字段,默认为 'created_at'
|
||||
$orderBy = $request->input('orderBy', 'created_at');
|
||||
|
||||
// 获取该分类下的产品,并按指定字段排序,分页显示,每页 10 条
|
||||
$categoryProducts = $category->products()
|
||||
->withCount('users') // 计算每个产品的用户数量
|
||||
->orderBy($orderBy, 'desc')
|
||||
->paginate(10);
|
||||
|
||||
// 返回分类详情视图,并传递分类及其产品数据
|
||||
return view('categories.show', compact('category', 'categoryProducts'));
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
// 使用 Laravel 的授权请求、任务调度和请求验证功能
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
|
||||
// 此类作为所有控制器的基类,提供通用功能
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\CouponTemplate;
|
||||
use App\Models\ScoreLog;
|
||||
use App\Models\User;
|
||||
use App\Models\UserHasCoupon;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class CouponController extends Controller
|
||||
{
|
||||
/**
|
||||
* 处理用户领取优惠券的请求
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return \Illuminate\Http\JsonResponse 返回 JSON 响应
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
// 获取请求中的优惠券模板 ID
|
||||
$templateId = $request->input('template_id');
|
||||
|
||||
/**
|
||||
* @var $user User
|
||||
*/
|
||||
// 获取当前登录用户
|
||||
$user = auth()->user();
|
||||
// 如果用户未登录,返回未授权响应
|
||||
if (is_null($user)) {
|
||||
return responseJsonAsUnAuthorized('请先登录再领取优惠券');
|
||||
}
|
||||
|
||||
// 查找优惠券模板
|
||||
$template = CouponTemplate::query()->find($templateId);
|
||||
// 如果模板不存在,返回无效优惠券响应
|
||||
if (is_null($template)) {
|
||||
return responseJsonAsBadRequest('无效的优惠券');
|
||||
}
|
||||
|
||||
// 判断优惠券是否过期
|
||||
$today = Carbon::today();
|
||||
$endDate = Carbon::make($template->end_date);
|
||||
// 如果当前日期大于优惠券结束日期,返回过期响应
|
||||
if ($today->gt($endDate)) {
|
||||
return responseJsonAsBadRequest('优惠券已过期');
|
||||
}
|
||||
|
||||
// 检查用户积分是否足够
|
||||
if ($user->score_now < $template->score) {
|
||||
return responseJsonAsBadRequest("积分不足{$template->score},请先去获取积分");
|
||||
}
|
||||
|
||||
// 确保每个用户只能领取一张优惠券
|
||||
if ($user->coupons()->where('template_id', $templateId)->exists()) {
|
||||
return responseJsonAsBadRequest('你已经领取过优惠券了');
|
||||
}
|
||||
|
||||
// 开始数据库事务
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
// 用户减少积分
|
||||
if ($template->score > 0) {
|
||||
$user->score_now -= $template->score;
|
||||
$user->save();
|
||||
|
||||
// 生成积分日志
|
||||
$log = new ScoreLog();
|
||||
$log->user_id = $user->getKey();
|
||||
$log->description = "领取优惠券";
|
||||
$log->score = -1 * $template->score; // 记录减少的积分
|
||||
$log->save();
|
||||
}
|
||||
|
||||
// 创建用户优惠券记录
|
||||
$coupon = new UserHasCoupon();
|
||||
$coupon->template_id = $template->getKey();
|
||||
$coupon->user_id = $user->getKey();
|
||||
$coupon->title = $template->title;
|
||||
$coupon->amount = $template->amount;
|
||||
$coupon->full_amount = $template->full_amount;
|
||||
$coupon->start_date = $template->start_date;
|
||||
$coupon->end_date = $template->end_date;
|
||||
$coupon->save();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// 如果发生异常,回滚事务
|
||||
DB::rollBack();
|
||||
return responseJsonAsServerError('服务器异常,请稍后再试');
|
||||
}
|
||||
|
||||
// 提交事务
|
||||
DB::commit();
|
||||
|
||||
// 返回成功响应
|
||||
return responseJson(200, '领取成功');
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\CouponTemplate;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CouponTemplateController extends Controller
|
||||
{
|
||||
/**
|
||||
* 显示可用的优惠券模板
|
||||
*
|
||||
* @return \Illuminate\View\View 返回包含优惠券模板的视图
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
// 获取今天的日期,格式为 YYYY-MM-DD
|
||||
$today = Carbon::today()->toDateString();
|
||||
|
||||
// 查询未过期的优惠券模板,并标记用户已领取的优惠券
|
||||
$templates = CouponTemplate::query()
|
||||
->withCount(['coupons' => function ($query) {
|
||||
// 统计当前用户已领取的优惠券数量
|
||||
$query->where('user_id', auth()->id());
|
||||
}])
|
||||
->where('end_date', '>=', $today) // 只选择未过期的优惠券模板
|
||||
->get(); // 执行查询并获取结果
|
||||
|
||||
// 返回包含优惠券模板的视图
|
||||
return view('coupons.templates', compact('templates'));
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Admin\Transforms\OrderPayTypeTransform;
|
||||
use App\Enums\OrderPayTypeEnum;
|
||||
use App\Enums\OrderStatusEnum;
|
||||
use App\Http\Controllers\User\PaymentController;
|
||||
use App\Models\Order;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Yansongda\Pay\Pay;
|
||||
|
||||
class PaymentNotificationController extends Controller
|
||||
{
|
||||
protected $config;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// 从配置文件中加载支付宝支付配置
|
||||
$this->config = config('pay.ali');
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理支付宝后台通知的接口
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\Response 返回支付宝的成功响应
|
||||
*/
|
||||
public function payNotify(Request $request)
|
||||
{
|
||||
$alipay = Pay::alipay($this->config);
|
||||
|
||||
// TODO: 加入轮询接口以配合后台通知修改订单状态
|
||||
// 后台异步通知接口可能因网络问题而未能接收
|
||||
// 使用轮询检查订单状态,如果支付成功则停止轮询
|
||||
try {
|
||||
$data = $alipay->verify(); // 验签操作
|
||||
|
||||
// 验证 app_id
|
||||
// 可判断 total_amount 是否为该订单的实际金额
|
||||
if ($data->get('app_id') == $this->config['app_id']) {
|
||||
|
||||
// 支付成功
|
||||
if ($data->get('trade_status') == 'TRADE_SUCCESS') {
|
||||
|
||||
// 更新订单信息
|
||||
$order = Order::query()->where('no', $data->get('out_trade_no'))->firstOrFail();
|
||||
$order->paid_at = $data->get('notify_time'); // 支付时间
|
||||
$order->pay_no = $data->get('trade_no'); // 支付交易号
|
||||
$order->pay_amount = $data->get('receipt_amount'); // 实际支付金额
|
||||
$order->status = OrderStatusEnum::PAID; // 更新订单状态为已支付
|
||||
$order->pay_type = OrderPayTypeEnum::ALI; // 支付类型
|
||||
$order->save(); // 保存订单信息
|
||||
}
|
||||
}
|
||||
|
||||
// 记录支付宝通知日志
|
||||
Log::debug('Alipay notify', $data->all());
|
||||
} catch (\Exception $e) {
|
||||
// 记录异常日志
|
||||
Log::debug('Alipay notify', $e->getMessage());
|
||||
}
|
||||
|
||||
// 返回支付宝的成功响应
|
||||
return $alipay->success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理前台跳转的接口
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View 返回支付结果视图
|
||||
*/
|
||||
public function payReturn()
|
||||
{
|
||||
// 获取最新的 9 个产品
|
||||
$latestProducts = Product::query()->latest()->take(9)->get();
|
||||
|
||||
$order = null;
|
||||
|
||||
try {
|
||||
// 验证支付数据
|
||||
$data = Pay::alipay($this->config)->verify();
|
||||
|
||||
// 根据订单号查询订单
|
||||
$order = Order::query()->where('no', $data->get('out_trade_no'))->firstOrFail();
|
||||
} catch (\Exception $e) {
|
||||
// 处理异常(可以记录日志或返回错误视图)
|
||||
}
|
||||
|
||||
// 返回支付结果视图,并传递订单和最新产品数据
|
||||
return view('user.payments.result', compact('order', 'latestProducts'));
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\User; // 定义命名空间
|
||||
|
||||
use App\Models\Product; // 引入产品模型
|
||||
use App\Models\User; // 引入用户模型
|
||||
use Auth; // 引入认证类
|
||||
use Illuminate\Http\Request; // 引入请求类
|
||||
use App\Http\Controllers\Controller; // 引入基础控制器类
|
||||
|
||||
/**
|
||||
* 用户收藏控制器
|
||||
*
|
||||
* 该控制器处理用户对产品的收藏(点赞)功能。
|
||||
*/
|
||||
class LikesController extends Controller
|
||||
{
|
||||
/**
|
||||
* 默认响应信息
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $response = [
|
||||
'code' => 1,
|
||||
'msg' => '服务器异常,请稍后再试',
|
||||
];
|
||||
|
||||
/**
|
||||
* 显示用户收藏的产品列表
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
/**
|
||||
* @var $user User
|
||||
*/
|
||||
$user = auth()->user(); // 获取当前用户
|
||||
|
||||
// 获取用户收藏的产品,按最新排序并分页
|
||||
$likesProducts = $user->products()
|
||||
->where('user_id', auth()->id())
|
||||
->withCount('users') // 统计每个产品的收藏用户数
|
||||
->latest() // 按照创建时间降序排列
|
||||
->paginate(10); // 每页显示10个产品
|
||||
|
||||
// 返回用户收藏产品的视图
|
||||
return view('user.products.likes', compact('likesProducts'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换产品的收藏状态
|
||||
*
|
||||
* @param string $uuid 产品的唯一标识符
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function toggle($uuid)
|
||||
{
|
||||
/**
|
||||
* @var $product Product
|
||||
*/
|
||||
$product = Product::query()
|
||||
->where('uuid', $uuid) // 根据 UUID 查找产品
|
||||
->firstOrFail(); // 如果未找到,抛出 404 异常
|
||||
|
||||
$user = auth()->id(); // 获取当前用户的 ID
|
||||
|
||||
// 检查当前用户是否已经收藏该产品
|
||||
if ($product->users()->where('user_id', $user)->exists()) {
|
||||
// 如果已收藏,则取消收藏
|
||||
$product->users()->detach($user);
|
||||
|
||||
// 返回 JSON 响应,表示已取消收藏
|
||||
return response()->json([
|
||||
'code' => 200,
|
||||
'msg' => '欢迎下次收藏'
|
||||
]);
|
||||
}
|
||||
|
||||
// 如果未收藏,则添加收藏
|
||||
$product->users()->attach($user);
|
||||
|
||||
// 返回 JSON 响应,表示已成功收藏
|
||||
return response()->json([
|
||||
'code' => 201,
|
||||
'msg' => '收藏成功'
|
||||
]);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue