Artist 自定义 Right Templates (2026-07-27)

变更概览

Artist 现在可以维护属于自己的自定义权利模板,并在多个自己的 Service 中复用。

Service 的 right_templates 现在包含两类模板:

type来源说明
platform平台模板来自平台维护的 right_templates
customArtist 自定义模板来自当前 Artist 自己维护的模板库

两类模板的数值 id 可能相同,因此前端必须使用 (type, id) 作为模板唯一标识,不能只使用 id

自定义模板可配置:

  • 多语言 name
  • 完整权益状态 right_tree

自定义模板的 summarydescription 由系统固定提供,Artist 不可编辑:

{
  "summary": {
    "zh": "画师自定义授权模板",
    "en": "Artist-defined license template",
    "ja": "アーティスト作成のライセンステンプレート"
  },
  "description": {
    "zh": "该授权模板由画师自行创建,请在选择前仔细确认具体权益范围。",
    "en": "This license template was created by the artist. Please review its rights carefully before selecting it.",
    "ja": "このライセンステンプレートはアーティストが独自に作成したものです。選択する前に、具体的な権利範囲をよくご確認ください。"
  }
}

接口变更

content

  • GET /api/content/service/info
    • 功能:获取公开 Service 详情
    • 变更:data.right_templates[] 同时返回平台模板和 Artist 自定义模板,并新增 type

user

  • POST /api/service_requests/create
    • 功能:创建 Service Request
    • 变更:新增 right_template_type,支持选择平台模板或 Artist 自定义模板
  • POST /api/service_requests/list
    • 功能:获取用户的 Service Request 列表
    • 变更:历史 service_snap.data.right_templates[] 缺少 type 时,读取结果按 platform 返回
  • POST /api/service_requests/info
    • 功能:获取用户的 Service Request 详情
    • 变更:返回带 type 的 Service 模板快照;历史快照缺少 type 时按 platform 返回
  • POST /api/work_tasks/list
    • 功能:获取用户的 Work Task 列表
    • 变更:历史 busable_snap.right_templates[] 缺少 type 时,读取结果按 platform 返回
  • GET /api/work_tasks/info
    • 功能:获取用户的 Work Task 详情
    • 变更:历史 busable_snap.right_templates[] 缺少 type 时,读取结果按 platform 返回

artist_center

admin_center

接口示例

content

GET /api/content/service/info

  • 功能说明:获取公开 Service 详情。
  • 变更说明:right_templates 统一返回平台模板和 Artist 自定义模板。

请求参数

字段类型必填说明
service_idnumberService id

请求示例

GET /api/content/service/info?service_id=12

响应示例

{
  "data": {
    "id": 12,
    "price": 10000,
    "right_templates": [
      {
        "type": "platform",
        "id": 1,
        "name": {
          "zh": "个人使用",
          "en": "Personal use"
        },
        "summary": {
          "zh": "适用于个人及非营利用途",
          "en": "Suitable for personal and non-commercial use"
        },
        "description": {
          "zh": "客户可以将作品用于头像、壁纸、个人展示和收藏。",
          "en": "Clients may use the work for avatars, wallpapers, personal display, and collection."
        },
        "markup_type": "percent",
        "markup_value": 0,
        "right_tree": []
      },
      {
        "type": "custom",
        "id": 1,
        "name": {
          "zh": "直播及视频商业授权",
          "en": "Livestream and Video Commercial License"
        },
        "summary": {
          "zh": "画师自定义授权模板",
          "en": "Artist-defined license template",
          "ja": "アーティスト作成のライセンステンプレート"
        },
        "description": {
          "zh": "该授权模板由画师自行创建,请在选择前仔细确认具体权益范围。",
          "en": "This license template was created by the artist. Please review its rights carefully before selecting it.",
          "ja": "このライセンステンプレートはアーティストが独自に作成したものです。選択する前に、具体的な権利範囲をよくご確認ください。"
        },
        "markup_type": "fixed",
        "markup_value": 500,
        "right_tree": [
          {
            "id": 10,
            "parent_id": null,
            "name": {
              "zh": "商业使用",
              "en": "Commercial use"
            },
            "state": 1,
            "children": []
          }
        ]
      }
    ]
  }
}

错误响应

404:Service 不存在或不可访问。


user

POST /api/service_requests/create

  • 功能说明:创建 Service Request,并选择该 Service 中的一个权利模板。
  • 变更说明:新增 right_template_typeright_template_id 必须属于指定 Service 在对应类型下关联的模板。

请求参数

字段类型必填说明
service_idnumberService id
right_template_type"platform" | "custom" | null模板类型;省略但传入 right_template_id 时默认为 platform
right_template_idnumber | null条件必填选择的模板 id;传入 right_template_type 时必填
deadlinestring原有字段
detailstring原有字段
budgetnumber原有字段
currency_idnumber原有字段
filesobject[]原有字段

其他校验规则

  • right_template_type 仅允许 platformcustom
  • type = custom 时,只能选择该 Service 已关联的 Artist 自定义模板。
  • 同一个数值 id 可能同时存在于两种类型中,选择结果由 right_template_type + right_template_id 共同确定。

请求示例

{
  "service_id": 12,
  "right_template_type": "custom",
  "right_template_id": 1,
  "deadline": "2026-08-10 12:00:00",
  "detail": "用于直播间宣传图",
  "budget": 10000,
  "currency_id": 1,
  "files": []
}

响应示例

{
  "data": {
    "id": 1001,
    "service_id": 12,
    "right_template_type": "custom",
    "right_template_id": 1,
    "status": "pending"
  }
}

错误响应

422:类型不合法,或模板不属于当前 Service。

{
  "message": "The selected right template is invalid for this service.",
  "errors": {
    "right_template_id": [
      "The selected right template is invalid for this service."
    ]
  }
}

POST /api/service_requests/list

  • 功能说明:获取当前用户的 Service Request 列表。
  • 变更说明:返回的 service_snap.data.right_templates[] 均按新类型语义读取。

请求参数

无新增。

响应示例

{
  "data": [
    {
      "id": 1001,
      "right_template_type": "platform",
      "right_template_id": 1,
      "service_snap": {
        "data": {
          "right_templates": [
            {
              "type": "platform",
              "id": 1
            }
          ]
        }
      }
    }
  ],
  "total": 1
}

错误响应

无新增,沿用原有错误语义。


POST /api/service_requests/info

  • 功能说明:获取当前用户的 Service Request 详情。
  • 变更说明:新快照会完整保存平台模板和自定义模板;历史快照缺少 type 时,API 读取结果补为 platform

请求参数

字段类型必填说明
idnumberService Request id

请求示例

{
  "id": 1001
}

响应示例

{
  "data": {
    "id": 1001,
    "right_template_type": "custom",
    "right_template_id": 1,
    "service_snap": {
      "data": {
        "id": 12,
        "right_templates": [
          {
            "type": "custom",
            "id": 1,
            "name": {
              "zh": "直播及视频商业授权",
              "en": "Livestream and Video Commercial License"
            },
            "summary": {
              "zh": "画师自定义授权模板",
              "en": "Artist-defined license template",
              "ja": "アーティスト作成のライセンステンプレート"
            },
            "description": {
              "zh": "该授权模板由画师自行创建,请在选择前仔细确认具体权益范围。",
              "en": "This license template was created by the artist. Please review its rights carefully before selecting it.",
              "ja": "このライセンステンプレートはアーティストが独自に作成したものです。選択する前に、具体的な権利範囲をよくご確認ください。"
            },
            "markup_type": "fixed",
            "markup_value": 500,
            "right_tree": []
          }
        ]
      }
    }
  }
}

错误响应

无新增,沿用原有错误语义。


POST /api/work_tasks/list /GET /api/work_tasks/info

  • 功能说明:获取用户的 Work Task 列表或详情。
  • 变更说明:Service Work Task 的 busable_snap.right_templates[] 返回结构与 Service Request 快照一致;历史项缺少 type 时按 platform 返回。

请求参数

无新增。

响应示例

{
  "data": {
    "busable_snap": {
      "right_templates": [
        {
          "type": "platform",
          "id": 1
        }
      ]
    }
  }
}

错误响应

无新增,沿用原有错误语义。

artist_center

GET /api/artist_center/right_templates/custom/list

  • 功能说明:分页获取当前 Artist 的自定义权利模板。
  • 变更说明:仅返回当前登录 Artist 自己创建且未删除的模板。

请求参数

字段类型必填说明
pagenumber页码,默认 1
sizenumber每页数量,默认 15,范围 1-50

请求示例

GET /api/artist_center/right_templates/custom/list?page=1&size=15

响应示例

{
  "data": [
    {
      "type": "custom",
      "id": 1,
      "name": {
        "zh": "直播及视频商业授权",
        "en": "Livestream and Video Commercial License"
      },
      "summary": {
        "zh": "画师自定义授权模板",
        "en": "Artist-defined license template",
        "ja": "アーティスト作成のライセンステンプレート"
      },
      "description": {
        "zh": "该授权模板由画师自行创建,请在选择前仔细确认具体权益范围。",
        "en": "This license template was created by the artist. Please review its rights carefully before selecting it.",
        "ja": "このライセンステンプレートはアーティストが独自に作成したものです。選択する前に、具体的な権利範囲をよくご確認ください。"
      },
      "services_count": 2,
      "right_tree": []
    }
  ],
  "total": 1
}

错误响应

422:分页参数不合法。


GET /api/artist_center/right_templates/custom/info

  • 功能说明:获取当前 Artist 的单个自定义模板。
  • 变更说明:返回完整权益树和使用该模板的 Service 数量。

请求参数

字段类型必填说明
idnumber自定义模板 id

请求示例

GET /api/artist_center/right_templates/custom/info?id=1

响应示例

与列表项结构一致。

错误响应

  • 404:模板不存在、已删除或不属于当前 Artist。
  • 422:参数校验失败。

POST /api/artist_center/right_templates/custom/create

  • 功能说明:创建当前 Artist 的自定义权利模板。
  • 变更说明:name 为多语言对象;权益状态使用扁平的 right_states 数组提交。

请求参数

字段类型必填说明
nameRecord<string, string>多语言模板名称,至少包含一项,每个值最长 255 字符
right_statesobject[]权益状态列表,创建时至少包含一项
right_states[].right_idnumberRights 表中的权益 id,不可重复
right_states[].statenumber权益状态整数

summarydescription 不允许提交,始终由系统固定返回。

请求示例

{
  "name": {
    "zh": "直播及视频商业授权",
    "en": "Livestream and Video Commercial License"
  },
  "right_states": [
    {
      "right_id": 10,
      "state": 1
    },
    {
      "right_id": 11,
      "state": 0
    }
  ]
}

响应示例

{
  "data": {
    "type": "custom",
    "id": 1,
    "name": {
      "zh": "直播及视频商业授权",
      "en": "Livestream and Video Commercial License"
    },
    "summary": {
      "zh": "画师自定义授权模板",
      "en": "Artist-defined license template",
      "ja": "アーティスト作成のライセンステンプレート"
    },
    "description": {
      "zh": "该授权模板由画师自行创建,请在选择前仔细确认具体权益范围。",
      "en": "This license template was created by the artist. Please review its rights carefully before selecting it.",
      "ja": "このライセンステンプレートはアーティストが独自に作成したものです。選択する前に、具体的な権利範囲をよくご確認ください。"
    },
    "right_tree": [
      {
        "id": 10,
        "state": 1,
        "children": []
      }
    ]
  }
}

错误响应

422:名称、Rights id 或权益状态参数不合法。


POST /api/artist_center/right_templates/custom/update

  • 功能说明:更新当前 Artist 的自定义权利模板。
  • 变更说明:nameright_states 均为可选;传入 right_states 时会替换模板的完整权益状态集合。

请求参数

字段类型必填说明
idnumber自定义模板 id
nameRecord<string, string>新的多语言名称
right_statesobject[]新的完整权益状态列表
right_states[].right_idnumber条件必填传入 right_states 时必填
right_states[].statenumber条件必填传入 right_states 时必填

请求示例

{
  "id": 1,
  "name": {
    "zh": "直播、视频及宣传授权",
    "en": "Livestream, Video and Promotion License"
  },
  "right_states": [
    {
      "right_id": 10,
      "state": 1
    }
  ]
}

响应示例

与创建接口响应结构一致。

错误响应

  • 404:模板不存在、已删除或不属于当前 Artist。
  • 422:参数校验失败。

POST /api/artist_center/right_templates/custom/delete

  • 功能说明:软删除当前 Artist 的自定义模板。
  • 变更说明:模板仍被 Service 使用时,默认返回业务错误码 81001;传入 force: true 后解除 Service 关联并删除。

请求参数

字段类型必填说明
idnumber自定义模板 id
forceboolean是否强制解除所有 Service 关联并删除,默认 false

请求示例

{
  "id": 1,
  "force": true
}

响应示例

{
  "ok": true
}

错误响应

400:模板仍被 Service 使用,业务错误码为 81001ArtistRightTemplateUsedByService)。前端应使用 code 判断是否展示强制删除确认,不要依赖 message 文案。

{
  "code": 81001,
  "message": "Template is used by services"
}

404:模板不存在、已删除或不属于当前 Artist。


GET /api/artist_center/services/meta

  • 功能说明:获取 Service 编辑所需元数据。
  • 变更说明:平台模板新增 type: "platform";该接口不混入 Artist 自定义模板,自定义模板通过 /right_templates/custom/list 获取。

请求参数

无。

响应示例

{
  "data": {
    "right_templates": [
      {
        "type": "platform",
        "id": 1,
        "name": {
          "zh": "个人使用",
          "en": "Personal use"
        }
      }
    ],
    "rights": []
  }
}

错误响应

无新增,沿用原有错误语义。


GET /api/artist_center/services/info

  • 功能说明:获取当前 Artist 的 Service 详情。
  • 变更说明:data.right_templates[] 统一返回平台模板和自定义模板,并包含各自的 type

请求参数

字段类型必填说明
idnumberService id

响应示例

right_templates 结构与 GET /api/content/service/info 一致。

错误响应

无新增,沿用原有错误语义。


POST /api/artist_center/services/create /POST /api/artist_center/services/update

  • 功能说明:创建或更新 Service。
  • 变更说明:right_templates[] 使用 type 区分平台模板与自定义模板。

请求参数

字段类型必填说明
right_templatesobject[]Service 关联的完整模板列表
right_templates[].type"platform" | "custom"模板类型;省略时兼容为 platform
right_templates[].idnumber对应类型下的模板 id
right_templates[].markup_type"percent" | "fixed"加价类型,默认 percent
right_templates[].markup_valuenumber非负整数,默认 0

其他校验规则

  • type = platform:模板必须存在于平台 right_templates
  • type = custom:模板必须属于当前 Artist,不能关联其他 Artist 的自定义模板。
  • (type, id) 不可重复。
  • 更新时传入的 right_templates 是完整集合;空数组表示解除全部平台和自定义模板关联。

请求示例

{
  "id": 12,
  "right_templates": [
    {
      "type": "platform",
      "id": 1,
      "markup_type": "percent",
      "markup_value": 10
    },
    {
      "type": "custom",
      "id": 1,
      "markup_type": "fixed",
      "markup_value": 500
    }
  ]
}

更新接口响应:

{
  "ok": true
}

错误响应

422:模板不存在、重复,或自定义模板不属于当前 Artist。

{
  "message": "Invalid custom right template ids: 9.",
  "errors": {
    "right_templates": ["Invalid custom right template ids: 9."]
  }
}

GET /api/artist_center/service_requests/list /GET /api/artist_center/service_requests/info

  • 功能说明:获取 Artist 的 Service Request 列表或详情。
  • 变更说明:Service 模板快照返回类型与 user 侧一致;历史模板缺少 type 时按 platform 返回。

请求参数

无新增。

响应示例

快照中的 right_templates 结构与 POST /api/service_requests/info 一致。

错误响应

无新增,沿用原有错误语义。


POST /api/artist_center/work_tasks/list /GET /api/artist_center/work_tasks/info

  • 功能说明:获取 Artist 的 Work Task 列表或详情。
  • 变更说明:Service Work Task 的 busable_snap.right_templates[] 历史项缺少 type 时按 platform 返回。

请求参数

无新增。

响应示例

busable_snap.right_templates 结构与 user Work Task 接口一致。

错误响应

无新增,沿用原有错误语义。

admin_center

POST /api/admin_center/service_request/list /POST /api/admin_center/service_request/info

  • 功能说明:获取管理端 Service Request 列表或详情。
  • 变更说明:Service 模板快照返回类型与 user、artist_center 侧一致;历史模板缺少 type 时按 platform 返回。

请求参数

无新增。

响应示例

快照中的 right_templates 结构与 POST /api/service_requests/info 一致。

错误响应

无新增,沿用原有错误语义。


POST /api/admin_center/work_task/list /POST /api/admin_center/work_task/info

  • 功能说明:获取管理端 Work Task 列表或详情。
  • 变更说明:Service Work Task 的 busable_snap.right_templates[] 历史项缺少 type 时按 platform 返回。

请求参数

无新增。

响应示例

busable_snap.right_templates 结构与 user Work Task 接口一致。

错误响应

无新增,沿用原有错误语义。

快照与历史追溯

  • 创建 Service Request 时,service_snap.data.right_templates 会保存当时 Service 的全部平台模板和自定义模板。
  • 每个快照模板包含:
    • type
    • id
    • name
    • summary
    • description
    • markup_type
    • markup_value
    • right_tree
  • Service Request 本体通过 right_template_type + right_template_id 记录用户选择的模板。
  • 自定义模板后续改名、修改权益或删除,不会改变已经创建的 Service Request / Work Task 快照。
  • 强制删除自定义模板只解除实时 Service 关联,不删除历史快照。

兼容性说明

后端兼容

  • Service 创建/更新请求中,right_templates[].type 缺失时默认为 platform
  • Service Request 创建请求中,传入 right_template_id 但省略 right_template_type 时默认为 platform
  • 旧 Service Request 数据中已有 right_template_id 的记录会按 platform 处理。
  • 读取旧 service_snap.data.right_templates[]work_tasks.busable_snap.right_templates[] 时:
    • 如果某一项缺少 type,API 返回结果会补为 platform
    • 仅规范化读取结果,不修改原始历史 JSON

前端必须保留的兼容规则

前端仍必须对缺失的 type 做相同回退,不能只依赖后端:

const templateType = template.type ?? 'platform';
const templateKey = `${templateType}:${template.id}`;

匹配 Service Request 已选模板时:

const selectedType = serviceRequest.right_template_type ?? 'platform';

const selectedTemplate = serviceSnap.right_templates.find((template) => {
  const templateType = template.type ?? 'platform';

  return (
    templateType === selectedType &&
    template.id === serviceRequest.right_template_id
  );
});

不要使用以下方式:

// 错误:platform:1 和 custom:1 是两个不同模板
const selectedTemplate = templates.find(
  (template) => template.id === serviceRequest.right_template_id,
);

性能说明

  • 返回多个模板时,后端会复用同一次 Rights 基础树查询,再分别填充每个模板的权益状态。
  • 该优化不改变 API 字段、排序或状态语义。
ON THIS PAGE