6
0
Fork 0

解决冲突

release
vine_liutk 2021-12-13 20:56:42 +08:00
parent 0bc4cfd837
commit f9fc7a9271
23 changed files with 658 additions and 6 deletions

View File

@ -29,6 +29,8 @@ class ArticleController extends AdminController
// $grid->column('author_name');
$grid->column('subtitle')->limit(20);
$grid->column('cover')->image(100, 100);
$grid->column('points');
$grid->column('likes');
$grid->column('jump_type')->using([
'0'=>__('admin_message.article.jump_type.radio.0'),
'1'=>__('admin_message.article.jump_type.radio.1'),
@ -127,7 +129,37 @@ class ArticleController extends AdminController
->saveFullUrl()
->removable(false)
->autoUpload();
$form->radio('media_type')
->when(1, function (Form $form) {
$form->multipleImage('media_content1')
->move('articles/'.Carbon::now()->toDateString())
->saveFullUrl()
->removable(false)
->autoUpload()->autoSave(false)->customFormat(function ($v) {
$v = [];
if ($this->model()->media_type == 1) {
$v = json_decode($this->model()->media_content, true);
}
return $v;
});
})->when([2, 3], function (Form $form) {
$form->file('media_content2')->chunked()
->accept('mp4', 'mp4/*', 'mp3', 'mp3/*')
->move('articles/media/'.Carbon::now()->toDateString())
->saveFullUrl()
->removable(false)
->autoUpload()->autoSave(false)->customFormat(function ($v) {
if ($this->model()->media_type == 2) {
$v = json_decode($this->model()->media_content, true)[0];
}
return $v;
});
})
->options([
'0'=>'无', '1'=>'轮播图', '2'=>'音频', '3'=>'视频',
])->default(1);
$form->editor('content');
$form->number('points');
$form->radio('jump_type')->options([
'0'=>__('admin_message.article.jump_type.radio.0'),
'1'=>__('admin_message.article.jump_type.radio.1'),
@ -137,6 +169,29 @@ class ArticleController extends AdminController
$form->switch('is_show');
$form->switch('is_recommend');
$form->number('sort')->min(0)->default(0);
$form->hidden('media_content');
$form->saving(function (Form $form) {
if (!is_null($form->media_type)) {
switch ($form->media_type) {
case 1:
dd(1);
$form->media_content = json_encode($form->media_content1);
break;
case 2:
$form->media_content = json_encode([$form->media_content2]);
break;
case 3:
$form->media_content = json_encode([$form->media_content2]);
break;
default:
$form->media_content = null;
break;
}
$form->deleteInput('media_content1');
$form->deleteInput('media_content2');
}
});
$form->display('created_at');
$form->display('updated_at');

View File

@ -0,0 +1,124 @@
<?php
namespace App\Endpoint\Api\Http\Controllers;
use App\Endpoint\Api\Http\Resources\ArticleResource;
use App\Endpoint\Api\Http\Resources\ArticleSimpleResource;
use App\Exceptions\BizException;
use App\Helpers\Paginator as PaginatorHelper;
use App\Models\Article;
use App\Models\ArticleLikesLog;
use App\Models\ArticlePointsLog;
use App\Models\PointsLog;
use App\Services\PointsService;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Throwable;
class ArticleController extends Controller
{
/**
*
*
* @param \Illuminate\Http\Request $request
* @return void
*/
public function index(Request $request)
{
$cate = (string) $request->query('cate');
$key = (string) $request->query('key');
$categoryId = Arr::get(Article::$cateMap, $cate);
$query = Article::query()->with(['likesInfo'=>function ($q) use ($request) {
return $q->where('user_id', $request->user()->id);
}])->where('is_show', 1);
if ($categoryId) {
$query->where('category_id', $categoryId);
}
if ($key) {
$query->where('title', 'like', '%'.$key.'%');
}
$query->orderBy('is_recommend', 'desc');
$query->orderBy('sort', 'desc');
$query->orderBy('created_at', 'desc');
$list = $query->simplePaginate(PaginatorHelper::resolvePerPage('per_page', 20, 50));
return ArticleSimpleResource::collection($list);
}
/**
* 文章详情
*
* @param [type] $id
* @return void
*/
public function show($id, Request $request)
{
$article = Article::with(['likesInfo'=>function ($q) use ($request) {
return $q->where('user_id', $request->user()->id);
}])->where('is_show', 1)->findOrFail($id);
return ArticleResource::make($article);
}
/**
* 文章点赞
*
* @param [type] $id
* @param Request $request
* @return void
*/
public function like($id, Request $request)
{
$article = Article::where('is_show', 1)->findOrFail($id);
if (ArticleLikesLog::where('user_id', $request->user()->id)->where('article_id', $article->id)->exists()) {
throw new BizException('您已点赞过这篇文章');
}
try {
DB::beginTransaction();
ArticleLikesLog::create([
'article_id' => $article->id,
'user_id' => $request->user()->id,
]);
$article->increment('likes');
DB::commit();
} catch (Throwable $th) {
DB::rollBack();
report($th);
throw new BizException('系统繁忙,请稍后再试');
}
return response()->noContent();
}
/**
* 阅读加积分接口
*
* @param [type] $id
* @return void
*/
public function read($id, Request $request, PointsService $pointsService)
{
$article = Article::where('is_show', 1)->findOrFail($id);
if ($article->points > 0) {
if (ArticlePointsLog::where('user_id', $request->user()->id)->whereDate('created_at', now())->exists()) {
throw new BizException('您今天已拿过积分了,请明天再来');
}
try {
DB::beginTransaction();
ArticlePointsLog::create([
'user_id' => $request->user()->id,
'article_id' => $article->id,
]);
$pointsService->sendPoints(PointsLog::TYPE_READ, $request->user(), $article->points, '阅读文章送积分');
DB::commit();
} catch (Throwable $th) {
DB::rollBack();
report($th);
throw new BizException('系统繁忙,请稍后再试');
}
}
return response()->json([
'points'=>$article->points,
]);
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Endpoint\Api\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ArticleResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'title' => $this->title,
'cover' => $this->cover,
'subtitle' => $this->subtitle,
'content'=>$this->content,
'points'=> $this->points,
'likes' => $this->likes,
'like_status' => $this->whenLoaded('likesInfo', $this->likesInfo->count() > 0),
'media_type'=> $this->media_type,
'media_content'=> json_decode($this->media_content, true),
'created_at' => $this->created_at->toDateTimeString(),
];
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Endpoint\Api\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ArticleSimpleResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'title' => $this->title,
'subtitle' => $this->subtitle,
'cover' => $this->cover,
'points'=> $this->points,
'likes' => $this->likes,
'like_status' => $this->whenLoaded('likesInfo', $this->likesInfo->count() > 0),
'jump_type' => $this->jump_type,
'jump_link' => (string) $this->jump_link,
'created_at' => $this->created_at->toDateTimeString(),
];
}
}

View File

@ -4,6 +4,7 @@ use App\Endpoint\Api\Http\Controllers\Account\ChangePasswordController;
use App\Endpoint\Api\Http\Controllers\Account\UserController;
use App\Endpoint\Api\Http\Controllers\AdController;
use App\Endpoint\Api\Http\Controllers\AfterSaleController;
use App\Endpoint\Api\Http\Controllers\ArticleController;
use App\Endpoint\Api\Http\Controllers\Auth\LoginController;
use App\Endpoint\Api\Http\Controllers\Auth\LogoutController;
use App\Endpoint\Api\Http\Controllers\Auth\RegisterController;
@ -78,10 +79,10 @@ Route::group([
//售后订单
Route::get('after-sales', [AfterSaleController::class, 'index']);
Route::post('after-sales', [AfterSaleController::class, 'store']);
Route::get('after-sales/{after_sales}', [AfterSaleController::class, 'show']);
Route::put('after-sales/{after_sales}', [AfterSaleController::class, 'update']);
Route::put('after-sales/{after_sales}/agree', [AfterSaleController::class, 'agree']);
Route::delete('after-sales/{after_sales}', [AfterSaleController::class, 'cancel']);
Route::get('after-sales/{after_sale}', [AfterSaleController::class, 'show']);
Route::put('after-sales/{after_sale}', [AfterSaleController::class, 'update']);
Route::put('after-sales/{after_sale}/agree', [AfterSaleController::class, 'agree']);
Route::delete('after-sales/{after_sale}', [AfterSaleController::class, 'cancel']);
//消息
Route::get('messages', [MessageController::class, 'index']);
@ -91,5 +92,11 @@ Route::group([
// 我的优惠券
Route::get('coupons', [CouponController::class, 'index']);
//文章
Route::get('articles', [ArticleController::class, 'index']);
Route::get('articles/{article}', [ArticleController::class, 'show']);
Route::post('articles/{article}/read', [ArticleController::class, 'read']);
Route::post('articles/{article}/like', [ArticleController::class, 'like']);
});
});

View File

@ -10,6 +10,16 @@ class Article extends Model
{
use HasDateTimeFormatter;
protected const CATE_HELP = 1;
protected const CATE_AGREEMENT = 2;
protected const CATE_HEALTH = 3;
public static $cateMap = [
'help'=> self::CATE_HELP,
'agreement'=> self::CATE_AGREEMENT,
'health'=> self::CATE_HEALTH,
];
protected $casts = [
'is_show' => 'boolean',
'is_recommend' => 'boolean',
@ -19,4 +29,9 @@ class Article extends Model
{
return $this->belongsTo(ArticleCategory::class, 'category_id');
}
public function likesInfo()
{
return $this->hasMany(ArticleLikesLog::class, 'article_id');
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ArticleLikesLog extends Model
{
use HasFactory;
protected $fillable = [
'user_id', 'article_id',
];
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ArticlePointsLog extends Model
{
use HasFactory;
protected $fillable = [
'user_id', 'article_id',
];
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Click extends Model
{
use HasFactory;
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ClickLog extends Model
{
use HasFactory;
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class PointsLog extends Model
{
use HasFactory;
public const TYPE_CLICK = 1;//签到
public const TYPE_READ = 2;//阅读文章
protected $fillable = [
'type', 'user_id', 'old_points', 'desc',
];
}

View File

@ -37,7 +37,10 @@ class AfterSaleService
}
switch ($type) {
case in_array($type, [3, 4])://换货漏发退款金额为0
case 3:
$amount = 0;
break;
case 4:
$amount = 0;
break;
default:

View File

@ -0,0 +1,40 @@
<?php
namespace App\Services;
use App\Models\PointsLog;
use App\Models\User;
class PointsService
{
/**
* 发放积分
*
* @param integer $type
* @param User $user
* @param integer $points
* @param string $desc
* @return bool
*/
public function sendPoints(int $type, User $user, int $points, string $desc)
{
$res = false;
if ($points != 0) {
PointsLog::create([
'type' => $type,
'user_id' => $user->id,
'points' => $points,
'old_points'=> $user->userInfo->points,
'desc' => $desc,
]);
if ($points > 0) {
$user->userInfo()->increment('points', abs($points));
} else {
$user->userInfo()->decrement('points', abs($points));
}
$res = true;
}
return $res;
}
}

View File

@ -18,7 +18,7 @@ class CreateCouponsTable extends Migration
$table->string('name')->comment('优惠券名称');
$table->text('description')->nullable()->comment('优惠券说明');
$table->tinyInteger('type')->default(0)->unsigned()->comment('优惠券类型:1抵扣券2折扣券');
$table->unsignedInteger('amount')->default(0)->comment('抵扣金额:分/折扣(100)');
$table->unsignedBigInteger('amount')->default(0)->comment('抵扣金额:分/折扣(100)');
$table->unsignedBigInteger('threshold')->default(0)->comment('使用门槛金额:分');
$table->unsignedInteger('limit')->default(0)->comment('限量');
$table->unsignedInteger('sent')->default(0)->comment('已送数量');

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateClicksTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('clicks', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->comment('用户ID');
$table->integer('continue_click_times')->default(0)->comment('连续签到次数');
$table->timestamp('last_click_at')->nullable()->comment('上次签到时间');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('clicks');
}
}

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateClickLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('click_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->comment('用户ID');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('click_logs');
}
}

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePointsLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('points_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->comment('用户ID');
$table->unsignedTinyInteger('type')->default(0)->comment('类别1签到2阅读');
$table->bigInteger('points')->default(0)->comment('积分:可以为负数');
$table->unsignedBigInteger('old_points')->default(0)->comment('变动前');
$table->string('desc')->nullable()->comment('备注');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('points_logs');
}
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddPointsToUserInfosTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('user_infos', function (Blueprint $table) {
//
$table->unsignedBigInteger('points')->default(0)->comment('积分');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('user_infos', function (Blueprint $table) {
//
$table->dropColumn('points');
});
}
}

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddPointsAndLikesToArticlesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('articles', function (Blueprint $table) {
//
$table->unsignedBigInteger('points')->default(0)->comment('积分');
$table->unsignedBigInteger('likes')->default(0)->comment('点赞数');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('articles', function (Blueprint $table) {
//
$table->dropColumn('points');
$table->dropColumn('likes');
});
}
}

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateArticleLikesLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('article_likes_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('article_id')->column('文章');
$table->unsignedBigInteger('user_id')->column('用户');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('article_likes_logs');
}
}

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateArticlePointsLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('article_points_logs', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('article_id')->column('文章');
$table->unsignedBigInteger('user_id')->column('用户');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('article_points_logs');
}
}

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddMediaToArticlesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('articles', function (Blueprint $table) {
//
$table->unsignedTinyInteger('media_type')->default(0)->comment('媒体类型1轮播图2音频3视频');
$table->json('media_content')->nullable()->comment('媒体内容');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('articles', function (Blueprint $table) {
//
$table->dropColumn('media_type');
$table->dropColumn('media_content');
});
}
}

View File

@ -20,6 +20,11 @@ return [
'category' => [
'name' => '分类',
],
'points' => '积分',
'likes' => '点赞',
'media_type'=>'媒体类型',
'media_content1'=>'轮播图',
'media_content2'=>'音视频文件',
],
'options' => [
],