feat: 新增文章分类增/删/改/查接口
This commit is contained in:
@@ -13,3 +13,8 @@ DEFAULT_LANG = zh-cn
|
||||
|
||||
[JWT]
|
||||
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
||||
|
||||
# 后台不需要登录的接口
|
||||
[ADMIN_AUTH]
|
||||
WHITE_LIST[] = v1/user/login
|
||||
WHITE_LIST[] = v1/user/captcha
|
||||
|
||||
22
app/admin/config/apiret.php
Normal file
22
app/admin/config/apiret.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | api 返回状态配置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
'status_var' => 'code',
|
||||
'message_var' => 'msg',
|
||||
'data_var' => 'data',
|
||||
'states' => [
|
||||
'success' => [
|
||||
'code' => 0,
|
||||
'msg' => '操作成功!',
|
||||
'data' => []
|
||||
],
|
||||
'error' => [
|
||||
'code' => 1,
|
||||
'msg' => '操作错误!',
|
||||
'data' => []
|
||||
],
|
||||
]
|
||||
];
|
||||
9
app/admin/config/auth.php
Normal file
9
app/admin/config/auth.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 登录验证设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 不需要登录验证的接口
|
||||
'white_list' => env('ADMIN_AUTH.WHITE_LIST', ['v1/user/login','1/user/captcha']),
|
||||
];
|
||||
9
app/admin/controller/v1/Article.php
Normal file
9
app/admin/controller/v1/Article.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\controller\v1;
|
||||
|
||||
class Article
|
||||
{
|
||||
//
|
||||
}
|
||||
116
app/admin/controller/v1/ArticleCategory.php
Normal file
116
app/admin/controller/v1/ArticleCategory.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\controller\v1;
|
||||
|
||||
use app\admin\model\v1\ArticleCategoryModel;
|
||||
use app\admin\validate\v1\ArticleCategoryValidate;
|
||||
|
||||
class ArticleCategory
|
||||
{
|
||||
// 分类列表
|
||||
public function index()
|
||||
{
|
||||
$param = request()->param([
|
||||
'name',
|
||||
'page/d' => 1,
|
||||
'limit/d' => 10,
|
||||
]);
|
||||
|
||||
$category = ArticleCategoryModel::withoutField([
|
||||
'language_id',
|
||||
'deleted_at',
|
||||
'seo_title',
|
||||
'seo_keywords',
|
||||
'seo_desc',
|
||||
])
|
||||
->withSearch(['name'], ['name' => $param['name']])
|
||||
->order('sort', 'asc')
|
||||
->page($param['page'], $param['limit'])
|
||||
->select();
|
||||
|
||||
return success('获取成功', $category);
|
||||
}
|
||||
|
||||
// 分类详情
|
||||
public function read()
|
||||
{
|
||||
$id = request()->param('id');
|
||||
$category = ArticleCategoryModel::where('id', '=', $id)
|
||||
->withoutField(['language_id', 'deleted_at'])
|
||||
->find();
|
||||
if (is_null($category)) {
|
||||
return error('文章分类不存在');
|
||||
}
|
||||
return success('获取成功', $category);
|
||||
}
|
||||
|
||||
// 添加分类
|
||||
public function save()
|
||||
{
|
||||
$post = request()->post([
|
||||
'name',
|
||||
'sort' => 0,
|
||||
'is_show' => 1,
|
||||
'seo_title',
|
||||
'seo_keywords',
|
||||
'seo_desc',
|
||||
]);
|
||||
|
||||
$data = array_merge($post, ['language_id' => request()->lang_id]);
|
||||
$valiate = new ArticleCategoryValidate;
|
||||
if (!$valiate->check($data)) {
|
||||
return error($valiate->getError());
|
||||
}
|
||||
|
||||
$category = new ArticleCategoryModel();
|
||||
if (!$category->save($data)) {
|
||||
return error('操作失败');
|
||||
}
|
||||
return success('操作成功');
|
||||
}
|
||||
|
||||
// 更新分类
|
||||
public function update()
|
||||
{
|
||||
$id = request()->param('id');
|
||||
$put = request()->put([
|
||||
'name',
|
||||
'sort',
|
||||
'is_show',
|
||||
'seo_title',
|
||||
'seo_keywords',
|
||||
'seo_desc',
|
||||
]);
|
||||
$data = array_merge($put, ['language_id' => request()->lang_id]);
|
||||
|
||||
$valiate = new ArticleCategoryValidate;
|
||||
if (!$valiate->check(array_merge($data, ['id' => $id]))) {
|
||||
return error($valiate->getError());
|
||||
}
|
||||
|
||||
$category = ArticleCategoryModel::where('id', '=', $id)->find();
|
||||
if (is_null($category)) {
|
||||
return error('请确认操作对象是否存在');
|
||||
}
|
||||
if (!$category->save($data)) {
|
||||
return error('操作失败');
|
||||
}
|
||||
|
||||
return success('操作成功');
|
||||
}
|
||||
|
||||
// 删除分类
|
||||
public function delete()
|
||||
{
|
||||
$id = request()->param('id');
|
||||
$category = ArticleCategoryModel::where('id', '=', $id)->find();
|
||||
if (is_null($category)) {
|
||||
return error('请确认操作对象是否存在');
|
||||
}
|
||||
if (!$category->useSoftDelete('deleted_at', date('Y-m-d H:m:s', time()))->delete()) {
|
||||
return error('操作失败');
|
||||
}
|
||||
return success('操作成功');
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
// 这是系统自动生成的middleware定义文件
|
||||
return [
|
||||
|
||||
// 登录验证
|
||||
app\admin\middleware\v1\Auth::class,
|
||||
];
|
||||
|
||||
77
app/admin/middleware/v1/Auth.php
Normal file
77
app/admin/middleware/v1/Auth.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\middleware\v1;
|
||||
|
||||
use app\admin\model\v1\LanguageModel;
|
||||
class Auth extends \thans\jwt\middleware\BaseMiddleware
|
||||
{
|
||||
// 获取语言信息
|
||||
private function setLanguage($request)
|
||||
{
|
||||
$code = $request->cookie('lang', 'zh_cn');
|
||||
$lang = LanguageModel::cache('lang:code.' . $code, 3600, 'lang')
|
||||
->field(['id', 'name', 'code', 'icon', 'url'])
|
||||
->withJoin(['country' => ['id', 'name', 'code', 'icon']])
|
||||
->where('language_model.code', '=', $code)
|
||||
->find();
|
||||
if (!is_null($lang)) {
|
||||
$request->lang_id = $lang['id'];
|
||||
$request->country_id = $lang->country['id'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理请求
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param \Closure $next
|
||||
* @return Response
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
// options 请求过滤
|
||||
if ($request->isOptions()) {
|
||||
return response();
|
||||
}
|
||||
|
||||
// 白名单
|
||||
if (in_array($request->pathinfo(), config('auth.white_list'))) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
try {
|
||||
// 验证 token
|
||||
$payload = $this->auth->auth();
|
||||
|
||||
// 将用户信息存入请求
|
||||
$request->uid = $payload['uid'];
|
||||
|
||||
// 语言信息
|
||||
$this->setLanguage($request);
|
||||
} catch (\thans\jwt\exception\TokenExpiredException $e) {
|
||||
try {
|
||||
// 尝试刷新 token
|
||||
$this->auth->setRefresh();
|
||||
|
||||
// 刷新 token
|
||||
$token = $this->auth->refresh();
|
||||
|
||||
$payload = $this->auth->auth(false);
|
||||
$request->uid = $payload['uid'];
|
||||
|
||||
// 语言信息
|
||||
$this->setLanguage($request);
|
||||
|
||||
$response = $next($request);
|
||||
return $this->setAuthentication($response, $token);
|
||||
} catch (\thans\jwt\exception\TokenBlacklistGracePeriodException $e) {
|
||||
return error('登录已过期', [], 401);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
return error('请先登录', [], 401);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
50
app/admin/model/v1/ArticleCategoryModel.php
Normal file
50
app/admin/model/v1/ArticleCategoryModel.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\model\v1;
|
||||
|
||||
use think\Model;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class ArticleCategoryModel extends Model
|
||||
{
|
||||
// 启动软删除
|
||||
use SoftDelete;
|
||||
// 软删除标记数据字段
|
||||
protected $deleteTime = 'deleted_at';
|
||||
|
||||
// 表名
|
||||
protected $name = 'article_category';
|
||||
|
||||
// 主键
|
||||
protected $pk = 'id';
|
||||
|
||||
// 字段信息
|
||||
protected $schema = [
|
||||
'id' => 'int',
|
||||
'language_id' => 'int',
|
||||
'pid' => 'int',
|
||||
'name' => 'string',
|
||||
'short_name' => 'string',
|
||||
'icon' => 'string',
|
||||
'desc' => 'string',
|
||||
'sort' => 'int',
|
||||
'level' => 'int',
|
||||
'is_show' => 'int',
|
||||
'seo_title' => 'string',
|
||||
'seo_keywords' => 'string',
|
||||
'seo_desc' => 'string',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
'deleted_at' => 'datetime',
|
||||
];
|
||||
|
||||
// 搜索分类名
|
||||
public function searchNameAttr($query, $value, $data)
|
||||
{
|
||||
$query->where('name', 'like', '%' . $value . '%');
|
||||
}
|
||||
}
|
||||
43
app/admin/model/v1/ArticleModel.php
Normal file
43
app/admin/model/v1/ArticleModel.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\model\v1;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class ArticleModel extends Model
|
||||
{
|
||||
// 表名
|
||||
protected $name = 'article';
|
||||
|
||||
// 主键
|
||||
protected $pk = 'id';
|
||||
|
||||
// 字段信息
|
||||
protected $schema = [
|
||||
'id' => 'int',
|
||||
'languge_id' => 'int',
|
||||
'category_id' => 'int',
|
||||
'title' => 'string',
|
||||
'author' => 'string',
|
||||
'source' => 'string',
|
||||
'image' => 'string',
|
||||
'desc' => 'string',
|
||||
'recommend' => 'int',
|
||||
'release_time' => 'int',
|
||||
'sort' => 'int',
|
||||
'link' => 'string',
|
||||
'content' => 'string',
|
||||
'view_count' => 'int',
|
||||
'praise_count' => 'int',
|
||||
'seo_title' => 'string',
|
||||
'seo_keywords' => 'string',
|
||||
'seo_desc' => 'string',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
'deleted_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
30
app/admin/model/v1/CountryModel.php
Normal file
30
app/admin/model/v1/CountryModel.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\model\v1;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class CountryModel extends Model
|
||||
{
|
||||
// 表名
|
||||
protected $name = 'sys_country';
|
||||
|
||||
// 主键
|
||||
protected $pk = 'id';
|
||||
|
||||
// 字段信息
|
||||
protected $schema = [
|
||||
'id' => 'int',
|
||||
'name' => 'string',
|
||||
'code' => 'string',
|
||||
'icon' => 'string',
|
||||
'status' => 'int',
|
||||
'sort' => 'int',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
39
app/admin/model/v1/LanguageModel.php
Normal file
39
app/admin/model/v1/LanguageModel.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\model\v1;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class LanguageModel extends Model
|
||||
{
|
||||
// 表名
|
||||
protected $name = 'sys_language';
|
||||
|
||||
// 主键
|
||||
protected $pk = 'id';
|
||||
|
||||
// 字段信息
|
||||
protected $schema = [
|
||||
'id' => 'int',
|
||||
'country_id' => 'int',
|
||||
'name' => 'string',
|
||||
'code' => 'string',
|
||||
'icon' => 'string',
|
||||
'url' => 'string',
|
||||
'status' => 'int',
|
||||
'is_default' => 'int',
|
||||
'sort' => 'int',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
];
|
||||
|
||||
// 关联国家
|
||||
public function country()
|
||||
{
|
||||
return $this->belongsTo(CountryModel::class, 'country_id', 'id');
|
||||
}
|
||||
}
|
||||
@@ -10,13 +10,13 @@ use think\Model;
|
||||
*/
|
||||
class UserLoginLogModel extends Model
|
||||
{
|
||||
// 设置表名
|
||||
// 表名
|
||||
protected $name = 'sys_user_login_log';
|
||||
|
||||
// 设置主键
|
||||
// 主键
|
||||
protected $pk = 'id';
|
||||
|
||||
// 设置字段信息
|
||||
// 字段信息
|
||||
protected $schema = [
|
||||
'id' => 'int',
|
||||
'user_id' => 'int',
|
||||
|
||||
@@ -25,6 +25,27 @@ Route::group('v1', function () {
|
||||
// 登录接口
|
||||
Route::post('login', 'Login/index');
|
||||
});
|
||||
|
||||
// 文章模块
|
||||
Route::group('article', function () {
|
||||
// 文章分类
|
||||
Route::group('category', function () {
|
||||
// 分类列表
|
||||
Route::get('index', 'ArticleCategory/index');
|
||||
|
||||
// 分类详情
|
||||
Route::get('read/:id', 'ArticleCategory/read');
|
||||
|
||||
// 分类新增
|
||||
Route::post('save', 'ArticleCategory/save');
|
||||
|
||||
// 分类更新
|
||||
Route::put('update/:id', 'ArticleCategory/update');
|
||||
|
||||
// 分类删除
|
||||
Route::delete('delete/:id', 'ArticleCategory/delete');
|
||||
});
|
||||
});
|
||||
})->prefix('v1.');
|
||||
|
||||
Route::miss(function() {
|
||||
|
||||
46
app/admin/validate/v1/ArticleCategoryValidate.php
Normal file
46
app/admin/validate/v1/ArticleCategoryValidate.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\admin\validate\v1;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class ArticleCategoryValidate extends Validate
|
||||
{
|
||||
/**
|
||||
* 定义验证规则
|
||||
* 格式:'字段名' => ['规则1','规则2'...]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rule = [
|
||||
'language_id' => 'require|integer',
|
||||
'name' => 'require|unique:article_category,name^language_id|max:64',
|
||||
'sort' => 'require|integer',
|
||||
'is_show' => 'require|in:0,1',
|
||||
'seo_title' => 'max:255',
|
||||
'seo_keywords' => 'max:255',
|
||||
'seo_desc' => 'max:255',
|
||||
];
|
||||
|
||||
/**
|
||||
* 定义错误信息
|
||||
* 格式:'字段名.规则名' => '错误信息'
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $message = [
|
||||
'language_id.require' => '语言ID不能为空',
|
||||
'language_id.integer' => '语言ID必须为整数',
|
||||
'name.require' => '分类名称不能为空',
|
||||
'name.unique' => '分类名称已存在',
|
||||
'name.max' => '分类名称最多64个字符',
|
||||
'sort.require' => '排序不能为空',
|
||||
'sort.integer' => '排序必须为整数',
|
||||
'is_show.require' => '是否显示不能为空',
|
||||
'is_show.in' => '是否显示值必须为0或1',
|
||||
'seo_title.max' => 'SEO标题最多255个字符',
|
||||
'seo_keywords.max' => 'SEO关键词最多255个字符',
|
||||
'seo_desc.max' => 'SEO描述最多255个字符',
|
||||
];
|
||||
}
|
||||
@@ -8,7 +8,7 @@ return [
|
||||
'private_key' => env('JWT_PRIVATE_KEY'),
|
||||
'password' => env('JWT_PASSWORD'),
|
||||
//JWT time to live
|
||||
'ttl' => env('JWT_TTL', 60),
|
||||
'ttl' => env('JWT_TTL', 3600),
|
||||
//Refresh time to live
|
||||
'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
|
||||
//JWT hashing algorithm
|
||||
|
||||
Reference in New Issue
Block a user