feat: 新增文章分类增/删/改/查接口
This commit is contained in:
@@ -13,3 +13,8 @@ DEFAULT_LANG = zh-cn
|
|||||||
|
|
||||||
[JWT]
|
[JWT]
|
||||||
SECRET=b43e6276644ed60e65c50d1b324ba10b
|
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
|
<?php
|
||||||
// 这是系统自动生成的middleware定义文件
|
// 这是系统自动生成的middleware定义文件
|
||||||
return [
|
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
|
class UserLoginLogModel extends Model
|
||||||
{
|
{
|
||||||
// 设置表名
|
// 表名
|
||||||
protected $name = 'sys_user_login_log';
|
protected $name = 'sys_user_login_log';
|
||||||
|
|
||||||
// 设置主键
|
// 主键
|
||||||
protected $pk = 'id';
|
protected $pk = 'id';
|
||||||
|
|
||||||
// 设置字段信息
|
// 字段信息
|
||||||
protected $schema = [
|
protected $schema = [
|
||||||
'id' => 'int',
|
'id' => 'int',
|
||||||
'user_id' => 'int',
|
'user_id' => 'int',
|
||||||
|
|||||||
@@ -25,6 +25,27 @@ Route::group('v1', function () {
|
|||||||
// 登录接口
|
// 登录接口
|
||||||
Route::post('login', 'Login/index');
|
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.');
|
})->prefix('v1.');
|
||||||
|
|
||||||
Route::miss(function() {
|
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'),
|
'private_key' => env('JWT_PRIVATE_KEY'),
|
||||||
'password' => env('JWT_PASSWORD'),
|
'password' => env('JWT_PASSWORD'),
|
||||||
//JWT time to live
|
//JWT time to live
|
||||||
'ttl' => env('JWT_TTL', 60),
|
'ttl' => env('JWT_TTL', 3600),
|
||||||
//Refresh time to live
|
//Refresh time to live
|
||||||
'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
|
'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
|
||||||
//JWT hashing algorithm
|
//JWT hashing algorithm
|
||||||
|
|||||||
Reference in New Issue
Block a user