import{_ as i,o as a,c as t,a2 as h}from"./chunks/framework.BbmSSMjL.js";const y=JSON.parse('{"title":"6.7 文章管理","description":"","frontmatter":{},"headers":[],"relativePath":"zh/modules/article.md","filePath":"zh/modules/article.md"}'),n={name:"zh/modules/article.md"};function l(k,s,p,e,d,r){return a(),t("div",null,[...s[0]||(s[0]=[h(`

6.7 文章管理 ​

概述

文章管理模块支持封面图上传、图集多图、分类关联。ArticleService 继承 BaseTenantService 实现租户隔离,use HasFileProcessing 启用文件字段自动处理,并配置了数据权限(按创建人过滤)。

模块特点 ​

特性说明
基类BaseTenantService(租户隔离 + 数据权限由基类提供)
Trait 组合HasCrudOperations, HasFileProcessing, HasQueryScopes, HasSerializeMaps
文件字段cover(封面图,保存到 article 目录)
多文件字段images(图集,逗号分隔多 URL 逐个处理)
枚举映射status → article_status 字典
数据权限dataScopeUserField='create_user',按创建人过滤
模糊搜索title、author
精确匹配category_id、status
关联钩子afterDetail 补充分类名称等关联数据

API 接口 ​

方法路径权限码说明
GET/api/article/pagesys:article:page分页列表
GET/api/article/list—全量列表
GET/api/article/detail/{id}sys:article:detail详情
POST/api/article/addsys:article:add新增
PUT/api/article/updatesys:article:update修改
DELETE/api/article/delete/{id}sys:article:delete删除
DELETE/api/article/batchDeletesys:article:batchDelete批量删除

Service 配置(来自项目实际代码) ​

php
class ArticleService extends BaseTenantService
{
    // 文件字段处理由 HasFileProcessing 提供;HasDataScope 由基类提供
    use HasCrudOperations, HasFileProcessing, HasQueryScopes, HasSerializeMaps;

    protected string $modelClass = Article::class;

    // 需要自动处理的文件上传字段
    protected array $fileFields = ['cover'];

    // 多文件字段(逗号分隔的多个 URL,逐个迁移/补全)
    protected array $multiFileFields = ['images'];

    // 富文本字段:保存时迁移媒体并替换为 [IMG_URL] 占位,读取时替换回域名
    protected array $contentFields = ['content'];

    // 文件保存的子目录
    protected string $fileSaveDir = 'article';

    // LIKE 模糊匹配字段
    protected array $pageLikeFields = ['title', 'author'];

    // 精确匹配字段
    protected array $pageEqFields = ['category_id', 'status'];

    // 默认排序(租户内按排序值)
    protected array $pageOrderBy = [
        ['field' => 'tenant_id', 'type' => 'asc'],
        ['field' => 'sort', 'type' => 'asc'],
    ];

    // 字典翻译
    protected array $serializeMaps = [
        'status' => 'article_status',
    ];

    // 数据权限:归属字段(按创建人过滤)
    protected string $dataScopeUserField = 'create_user';

    // 详情后处理:补充分类名称等关联数据
    protected function afterDetail(int $id, array &$data): void
    {
        // 补充关联显示字段...
    }
}

Controller 代码 ​

php
// app/Http/Controllers/Api/ArticleController.php(形态示例)

#[OperationLog('文章管理-查询分页', OperationLog::TYPE_QUERY)]
#[Permission('sys:article:page', '文章分页')]
public function page(): JsonResponse
{
    return $this->_page($this->articleService);
}

#[OperationLog('文章管理-新增', OperationLog::TYPE_ADD, '新增文章:{title}')]
#[Permission('sys:article:add', '添加文章')]
public function add(ArticleRequest $request): JsonResponse
{
    return $this->_add($this->articleService, $request->validated());
}

#[OperationLog('文章管理-删除', OperationLog::TYPE_DELETE, '删除文章ID:{id}')]
#[Permission('sys:article:delete', '删除文章')]
public function delete(int $id): JsonResponse
{
    return $this->_delete($this->articleService, $id);
}

数据权限

文章模块配置了 dataScopeUserField = 'create_user'(服务由 BaseTenantService 提供 HasDataScope)——数据范围解析为 3(仅本人)时,普通用户只能看到自己创建的文章;当前角色一律解析为 1(全部数据),见 5.9 数据权限。

文件字段处理依赖 Trait

fileFields / multiFileFields 声明后必须 use HasFileProcessing(本模块已启用),否则 BaseService 中的占位实现会直接跳过处理——封面图将停留在临时路径。详见 4.7 横切机制。

文件处理流程 ​

text
封面 cover(单文件字段):
  传入临时 URL → processFileFieldsOnSave 迁移到 article/ 存相对路径
  读取 → processFileFieldsOnRead 补全 FILE_DOMAIN_URL 域名

图集 images(多文件字段):
  传入 "url1,url2" → 逐个迁移、去域名 → 逗号拼接入库
  读取 → 逐个补全域名 → 逗号拼接返回
`,14)])])}const g=i(n,[["render",l]]);export{y as __pageData,g as default};