评审描述与合并模板

为了提高代码评审(Code Review, CR)的效率和质量,云效提供了一系列Code Review模板功能。这些模板旨在标准化审核流程、减少人为错误,并确保代码的质量。下面将详细介绍如何使用这些模板,以及如何创建和应用自定义模板以适应您的开发流程。

合并请求模板

云效支持以下两种类型的CR模板:

  • 代码评审详情模板:用于描述代码变更的详细信息,帮助评审者了解变更的上下文、目的和效果。

  • 代码评审合并模板:用于标准化合并请求的信息,确保合并过程的清晰和规范。

代码评审详情模板

内置模板

Codeup提供了五种内置的代码评审详情模板,分别适用于不同的评审场景:

标准模板

适用于一般的代码变更审查。该模板的示例如下:

评审的动机和背景
<!--
详细描述您的代码评审的作用及其原因。
请随时更新此描述以进行任何讨论,以便 以便评审者能够理解你的意图。
保持描述的更新对于没有参与讨论的评审者来说尤为重要。
-->
效果展示(支持屏幕截图或者录屏)
如果存在UI上的改动,推荐上传截图或者录屏
之前
之后


如何进行配置和测试验证?
<!--- 
详细描述运行测试环境、配置、测试过程、结果等信息。
-->
验收清单(Checklist)
该清单鼓励我们确认所有变更均已进行分析,以降低质量、性能、可靠性、安全性和可维护性方面的风险。
<!--
● [ ] 我已经评估了该代码仓库需要遵循的评审规范
-->
关联的工作项以及资料等
<!--- 关联的任务链接 --><!--- 相关文档链接 -->

详细模板

包含更多的细节,用于需要更深入审查的复杂代码变更。该模板的示例如下:

评审的动机和背景
<!--
详细描述您的代码评审的作用及其原因。
请随时更新此描述以进行任何讨论,以便 以便评审者能够理解你的意图。
保持描述的更新对于没有参与讨论的评审者来说尤为重要。
-->
效果展示(支持屏幕截图或者录屏)
如果存在UI上的改动,推荐上传截图或者录屏
之前
之后
如何进行配置和测试验证?
<!--- 
详细描述运行测试环境、配置、测试过程、结果等信息。
-->
验收清单(Checklist)
该清单鼓励我们确认所有变更均已进行分析,以降低质量、性能、可靠性、安全性和可维护性方面的风险。
<!--
● [ ] 我已经评估了该代码仓库需要遵循的评审规范
-->
关联的工作项以及资料等
<!--- 关联的任务链接 --><!--- 相关文档链接 -->
评审的动机和背景
<!--
详细描述您的代码评审的作用及其原因。
请随时更新此描述以进行任何讨论,以便 以便评审者能够理解你的意图。
保持描述的更新对于没有参与讨论的评审者来说尤为重要。
-->
评审类型
<!-- 可按需删除不相关的选项或新增类型:-->
● [ ] 缺陷修复(非破坏性改动的方式进行缺陷修复)
● [ ] 特性开发(非破坏性改动的方式进行特性功能开发)
● [ ] 破坏性改动(可能会导致现有功能产生非预期的结果)
评审的测试情况
<!--
请描述为了验证此更改而运行的测试情况,必要时请提供对应的说明。
例如测试的配置和参数等详细信息,以便可以进行重现。
-->
● [ ] UT(单元测试)
● [ ] SIT(集成测试)
● [ ] PT(性能测试)
<!--
测试配置情况,可按需删除不相关的选项或新增类型。
-->
● 测试版本:
● 测试环境:
● 测试工具链:
● 测试SDK版本:
验收清单(Checklist)
该清单鼓励我们确认所有变更均已进行分析,以降低质量、性能、可靠性、安全性和可维护性方面的风险。
<!--
例如:
● [ ] 我已经评估了该代码仓库需要遵循的评审规范
下列选项,可按需删除或新增:
-->
● [ ] 我的代码遵循该项目的代码风格
● [ ] 我已经对我的代码进行了自我审查
● [ ] 我对我的代码进行了注释,特别是在难以理解的区域
● [ ] 我对文档做了相应的修改
● [ ] 我添加了单元测试来证明改动有效
● [ ] 新的和现有的单元测试在我本地可以运行通过

缺陷描述模板

专门为bug修复和问题追踪的评审设计。该模板的示例如下:

评审的动机和背景
<!--
详细描述您的代码评审的作用及其原因。
请随时更新此描述以进行任何讨论,以便 以便评审者能够理解你的意图。
保持描述的更新对于没有参与讨论的评审者来说尤为重要。
-->
效果展示(支持屏幕截图或者录屏)
如果存在UI上的改动,推荐上传截图或者录屏
之前
之后
如何进行配置和测试验证?
<!--- 
详细描述运行测试环境、配置、测试过程、结果等信息。
-->
验收清单(Checklist)
该清单鼓励我们确认所有变更均已进行分析,以降低质量、性能、可靠性、安全性和可维护性方面的风险。
<!--
● [ ] 我已经评估了该代码仓库需要遵循的评审规范
-->
关联的工作项以及资料等
<!--- 关联的任务链接 --><!--- 相关文档链接 -->
评审的动机和背景
<!--
详细描述您的代码评审的作用及其原因。
请随时更新此描述以进行任何讨论,以便 以便评审者能够理解你的意图。
保持描述的更新对于没有参与讨论的评审者来说尤为重要。
-->
评审类型
<!-- 可按需删除不相关的选项或新增类型:-->
● [ ] 缺陷修复(非破坏性改动的方式进行缺陷修复)
● [ ] 特性开发(非破坏性改动的方式进行特性功能开发)
● [ ] 破坏性改动(可能会导致现有功能产生非预期的结果)
评审的测试情况
<!--
请描述为了验证此更改而运行的测试情况,必要时请提供对应的说明。
例如测试的配置和参数等详细信息,以便可以进行重现。
-->
● [ ] UT(单元测试)
● [ ] SIT(集成测试)
● [ ] PT(性能测试)
<!--
测试配置情况,可按需删除不相关的选项或新增类型。
-->
● 测试版本:
● 测试环境:
● 测试工具链:
● 测试SDK版本:
验收清单(Checklist)
该清单鼓励我们确认所有变更均已进行分析,以降低质量、性能、可靠性、安全性和可维护性方面的风险。
<!--
例如:
● [ ] 我已经评估了该代码仓库需要遵循的评审规范
下列选项,可按需删除或新增:
-->
● [ ] 我的代码遵循该项目的代码风格
● [ ] 我已经对我的代码进行了自我审查
● [ ] 我对我的代码进行了注释,特别是在难以理解的区域
● [ ] 我对文档做了相应的修改
● [ ] 我添加了单元测试来证明改动有效
● [ ] 新的和现有的单元测试在我本地可以运行通过
缺陷描述
<!--- 缺陷的影响面和严重程度 -->
● [ ] Critical(严重缺陷:可能导致系统崩溃或损坏,需要立即修复)
● [ ] Major(一般缺陷:影响产品功能,需要进行排期修复)
● [ ] Minor(轻微缺陷:对功能影响较小,但是仍然存在隐患,需要进行排期修复)
预期结果
<!--- 预期的行为是什么? -->
实际结果
<!--- 实际发生了什么? -->
重现步骤
<!--- 如何重现该问题? -->
修复前后效果(支持屏幕截图或者录屏)
如果存在UI上的改动,推荐上传截图或者录屏
修复前
修复后


报错日志
<!--- 推荐使用代码块 (```) 格式化控制台输出内容、日志或缺陷代码-->
问题定位
<!--- 问题代码行链接等信息 -->
修复方案
<!--- 你是如何修复该问题的? -->

功能开发模板

适用于新功能开发的代码评审。该模板的示例如下:

评审的动机和背景
<!--
详细描述您的代码评审的作用及其原因。
请随时更新此描述以进行任何讨论,以便 以便评审者能够理解你的意图。
保持描述的更新对于没有参与讨论的评审者来说尤为重要。
-->
效果展示(支持屏幕截图或者录屏)
如果存在UI上的改动,推荐上传截图或者录屏
之前
之后
如何进行配置和测试验证?
<!--- 
详细描述运行测试环境、配置、测试过程、结果等信息。
-->
验收清单(Checklist)
该清单鼓励我们确认所有变更均已进行分析,以降低质量、性能、可靠性、安全性和可维护性方面的风险。
<!--
● [ ] 我已经评估了该代码仓库需要遵循的评审规范
-->
关联的工作项以及资料等
<!--- 关联的任务链接 --><!--- 相关文档链接 -->
评审的动机和背景
<!--
详细描述您的代码评审的作用及其原因。
请随时更新此描述以进行任何讨论,以便 以便评审者能够理解你的意图。
保持描述的更新对于没有参与讨论的评审者来说尤为重要。
-->
评审类型
<!-- 可按需删除不相关的选项或新增类型:-->
● [ ] 缺陷修复(非破坏性改动的方式进行缺陷修复)
● [ ] 特性开发(非破坏性改动的方式进行特性功能开发)
● [ ] 破坏性改动(可能会导致现有功能产生非预期的结果)
评审的测试情况
<!--
请描述为了验证此更改而运行的测试情况,必要时请提供对应的说明。
例如测试的配置和参数等详细信息,以便可以进行重现。
-->
● [ ] UT(单元测试)
● [ ] SIT(集成测试)
● [ ] PT(性能测试)
<!--
测试配置情况,可按需删除不相关的选项或新增类型。
-->
● 测试版本:
● 测试环境:
● 测试工具链:
● 测试SDK版本:
验收清单(Checklist)
该清单鼓励我们确认所有变更均已进行分析,以降低质量、性能、可靠性、安全性和可维护性方面的风险。
<!--
例如:
● [ ] 我已经评估了该代码仓库需要遵循的评审规范
下列选项,可按需删除或新增:
-->
● [ ] 我的代码遵循该项目的代码风格
● [ ] 我已经对我的代码进行了自我审查
● [ ] 我对我的代码进行了注释,特别是在难以理解的区域
● [ ] 我对文档做了相应的修改
● [ ] 我添加了单元测试来证明改动有效
● [ ] 新的和现有的单元测试在我本地可以运行通过
缺陷描述
<!--- 缺陷的影响面和严重程度 -->
● [ ] Critical(严重缺陷:可能导致系统崩溃或损坏,需要立即修复)
● [ ] Major(一般缺陷:影响产品功能,需要进行排期修复)
● [ ] Minor(轻微缺陷:对功能影响较小,但是仍然存在隐患,需要进行排期修复)
预期结果
<!--- 预期的行为是什么? -->
实际结果
<!--- 实际发生了什么? -->
重现步骤
<!--- 如何重现该问题? -->
修复前后效果(支持屏幕截图或者录屏)
如果存在UI上的改动,推荐上传截图或者录屏
修复前
修复后
报错日志
<!--- 推荐使用代码块 (```) 格式化控制台输出内容、日志或缺陷代码-->
问题定位
<!--- 问题代码行链接等信息 -->
修复方案
<!--- 你是如何修复该问题的? -->
需求概括
<!--- 简洁总结该需求功能 -->
需求来源和功能描述
<!--- 该需求和功能主要解决什么问题? -->
需求功能的实现方案是什么?
<!--- 如何实现该需求功能? -->
新功能的测试用例是否补齐?
<!--- 涉及了哪些测试用例,在评审中是否涵盖? -->
需求概括
<!--- 简洁总结该需求功能 -->
需求来源和功能描述
<!--- 该需求和功能主要解决什么问题? -->
需求功能的实现方案是什么?
<!--- 如何实现该需求功能? -->
新功能的测试用例是否补齐?
<!--- 涉及了哪些测试用例,在评审中是否涵盖? -->

优化改进模板

针对性能优化和代码改进的评审。该模板的示例如下:

评审的动机和背景
<!--
详细描述您的代码评审的作用及其原因。
请随时更新此描述以进行任何讨论,以便 以便评审者能够理解你的意图。
保持描述的更新对于没有参与讨论的评审者来说尤为重要。
-->
效果展示(支持屏幕截图或者录屏)
如果存在UI上的改动,推荐上传截图或者录屏
之前
之后
如何进行配置和测试验证?
<!--- 
详细描述运行测试环境、配置、测试过程、结果等信息。
-->
验收清单(Checklist)
该清单鼓励我们确认所有变更均已进行分析,以降低质量、性能、可靠性、安全性和可维护性方面的风险。
<!--
● [ ] 我已经评估了该代码仓库需要遵循的评审规范
-->
关联的工作项以及资料等
<!--- 关联的任务链接 --><!--- 相关文档链接 -->
评审的动机和背景
<!--
详细描述您的代码评审的作用及其原因。
请随时更新此描述以进行任何讨论,以便 以便评审者能够理解你的意图。
保持描述的更新对于没有参与讨论的评审者来说尤为重要。
-->
评审类型
<!-- 可按需删除不相关的选项或新增类型:-->
● [ ] 缺陷修复(非破坏性改动的方式进行缺陷修复)
● [ ] 特性开发(非破坏性改动的方式进行特性功能开发)
● [ ] 破坏性改动(可能会导致现有功能产生非预期的结果)
评审的测试情况
<!--
请描述为了验证此更改而运行的测试情况,必要时请提供对应的说明。
例如测试的配置和参数等详细信息,以便可以进行重现。
-->
● [ ] UT(单元测试)
● [ ] SIT(集成测试)
● [ ] PT(性能测试)
<!--
测试配置情况,可按需删除不相关的选项或新增类型。
-->
● 测试版本:
● 测试环境:
● 测试工具链:
● 测试SDK版本:
验收清单(Checklist)
该清单鼓励我们确认所有变更均已进行分析,以降低质量、性能、可靠性、安全性和可维护性方面的风险。
<!--
例如:
● [ ] 我已经评估了该代码仓库需要遵循的评审规范
下列选项,可按需删除或新增:
-->
● [ ] 我的代码遵循该项目的代码风格
● [ ] 我已经对我的代码进行了自我审查
● [ ] 我对我的代码进行了注释,特别是在难以理解的区域
● [ ] 我对文档做了相应的修改
● [ ] 我添加了单元测试来证明改动有效
● [ ] 新的和现有的单元测试在我本地可以运行通过
缺陷描述
<!--- 缺陷的影响面和严重程度 -->
● [ ] Critical(严重缺陷:可能导致系统崩溃或损坏,需要立即修复)
● [ ] Major(一般缺陷:影响产品功能,需要进行排期修复)
● [ ] Minor(轻微缺陷:对功能影响较小,但是仍然存在隐患,需要进行排期修复)
预期结果
<!--- 预期的行为是什么? -->
实际结果
<!--- 实际发生了什么? -->
重现步骤
<!--- 如何重现该问题? -->
修复前后效果(支持屏幕截图或者录屏)
如果存在UI上的改动,推荐上传截图或者录屏
修复前
修复后
报错日志
<!--- 推荐使用代码块 (```) 格式化控制台输出内容、日志或缺陷代码-->
问题定位
<!--- 问题代码行链接等信息 -->
修复方案
<!--- 你是如何修复该问题的? -->
需求概括
<!--- 简洁总结该需求功能 -->
需求来源和功能描述
<!--- 该需求和功能主要解决什么问题? -->
需求功能的实现方案是什么?
<!--- 如何实现该需求功能? -->
新功能的测试用例是否补齐?
<!--- 涉及了哪些测试用例,在评审中是否涵盖? -->
需求概括
<!--- 简洁总结该需求功能 -->
需求来源和功能描述
<!--- 该需求和功能主要解决什么问题? -->
需求功能的实现方案是什么?
<!--- 如何实现该需求功能? -->
新功能的测试用例是否补齐?
<!--- 涉及了哪些测试用例,在评审中是否涵盖? -->
优化目标
<!--- 简洁总结优化目标和效果 -->
优化类型
<!--- 选择本次优化的类型 -->
● [ ] 代码重构
● [ ] 体验优化
● [ ] 性能优化
优化改进描述
<!--- 本次优化解决什么问题? 目标和效果是什么? -->
优化改进方案
<!--- 如何实现本次优化? -->
优化改进效果
<!--- 优化改进效果对比 -->

自定义模板

如果内置模板不能满足您的需求,您可以创建自定义的代码评审详情模板。自定义模板的识别基于以下规则:

  • 条件1:在默认分支的仓库根路径下的.aliyun.github.gitee目录创建名为pull_request_template.md的文件。

  • 条件2:在默认分支的仓库根路径下的.aliyun/PULL_REQUEST_TEMPLATE.github/PULL_REQUEST_TEMPLATE.gitee/PULL_REQUEST_TEMPLATE目录创建任何.md后缀的文件。

  • 条件3:在默认分支的仓库根路径下的.gitlab/merge_request_templates目录创建名为default.md的文件。

这些文件路径和模板名称不区分大小写。

如何使用代码评审详情模板

创建合并请求

  1. 合并请求页面,单击新建合并请求按钮。

  2. 在描述区域下方,系统将展示可用的代码评审详情模板,包括内置模板和您的自定义模板。您也可以从描述区域的右上方的下拉菜单描述模板,选择您想要使用的代码评审详情模板。

    高的 (67)

  3. 选择相应的模板后,模板内容将自动填充到合并请求的详细信息中,您可以根据需要进一步进行编辑。

    高的 (68)

浏览,编辑,创建模板文件

为了简化您的工作流程,Codeup提供了智能模板识别功能,在您与模板文件交互时自动提供帮助和指引。 当您在浏览文件时,如果系统检测到文件是一个模板文件,它将在浏览器界面上显示一个明显的提示。这样,您可以轻松地辨识出当前文件是否为模板,并按照模板格式进行相关操作。

高的 (69)

当您在编辑文件时,如果系统检测到文件是一个模板文件,它将在浏览器界面上显示一个明显的提示,确保您在修改时可以遵循模板的规范。

高的 (70)

当您在创建新文件时,如果您的文件命名和结构符合模板文件的规则,系统也将提示您该文件是模板文件。这有助于您在创建时即刻了解文件的模板性质,从而正确使用模板。此外,为了进一步提高您的效率,允许您在创建自定义模板时直接使用云效提供的五种内置代码评审详情模板。您可以选择一个内置模板作为起点,然后根据您的具体需求进行自定义和扩展。

高的 (71)

创建代码库时选择合并请求模板

在创建新的代码库时,您现在可以轻松启用默认的合并请求模板。操作方法如下:

  1. 在创建代码库过程中,勾选创建合并请求模板选项。

  2. 从下拉菜单中选择一种云效提供的内置代码评审详情模板。

  3. 系统会自动在默认分支的.aliyun文件夹下创建一个名为pull_request_template.md的模板文件。

依靠这些功能,您可以保证您的工作流程更加高效,并且与您的团队成员在提交和审查代码时保持一致性。

高的 (72)

代码评审合并模板

内置模板

Codeup提供了两种内置的合并模板,用于标准化合并请求信息:

默认普通合并模板

用于普通的代码合并操作。该模板的示例如下:

Merge {{cr_id}} into {{cr_target}} from {{cr_source}}

{{cr_title}}

* {{cr_source}}: ({{cr_commits_count}} commits)
{{cr_commits_oneline}}

{{cr_author}}
{{cr_commentators}}
{{cr_reviewers}}
{{cr_submitter}}

{{cr_link}}

默认压缩合并模板

用于在合并时压缩多个提交。该模板的示例如下:

Merge {{cr_id}} into {{cr_target}} from {{cr_source}}

{{cr_title}}

* {{cr_source}}: ({{cr_commits_count}} commits)
{{cr_commits_full}}

{{cr_author}}
{{cr_commentators}}
{{cr_reviewers}}
{{cr_submitter}}

{{cr_link}}

自定义模板

如果内置模板不能满足您的需求,您可以创建自定义的代码评审合并模板。自定义模板的识别基于以下规则:

  • 普通合并模板:在 .aliyun/PULL_REQUEST_TEMPLATE/MERGE_TEMPLATE 目录下创建名为 normal_merge_message.txt 的文件表示普通合并模板。

  • 压缩合并模板:在 .aliyun/PULL_REQUEST_TEMPLATE/MERGE_TEMPLATE 目录下创建名为 squash_merge_message.txt 的文件表示压缩合并模板。

文件路径和模板名称不区分大小写。

模板渲染

代码评审合并模板利用Mustache模板引擎进行变量渲染,以便快速且灵活地生成合并信息。接下来,将介绍支持的模板变量以及Mustache语法的基本规则。

支持的模板变量

在您的代码评审合并模板中,您可以使用以下变量来自动填充信息:

字段名

说明

示例

cr_id

评审ID

#1

cr_source

来源分支

feature/support_mysql

cr_target

目标分支

master

cr_title

cr标题

一个cr的标题

cr_description

cr描述

一段cr的描述

cr_author

作者

Signed-off-by: 名字 <邮箱>

cr_reviewers

评审者(所有评审人,包括通过、未通过、未表态)

Reviewed-by: 名字1 <邮箱1>

Reviewed-by: 名字2 <邮箱2>

Reviewed-by: 名字3 <邮箱3>

cr_approved_by

评审通过人

Approved-by: 名字1 <邮箱1>

Approved-by: 名字2 <邮箱2>

cr_submitter

合并人

Merged-by: 名字 <邮箱>

cr_commentators

评论人

Commented-by: 名字1 <邮箱1>

Commented-by: 名字2 <邮箱2>

Commented-by: 名字3 <邮箱3>

cr_link

评审链接

CR-link: 评审浏览器访问地址

cr_commits_count

评审提交数

25

cr_commits_oneline

提交信息(简略版)

* <commit-1 subject>

* <commit-2 subject>

* <commit-3 subject>

cr_commits_full

提交信息(详细版)

包含提交标题与提交描述的完整提交信息格式

Mustache模板引擎语法简介

Mustache是一个逻辑简单的模板系统,通常称为“无逻辑”模板。它可以使用于HTML、配置文件、源代码等。模板标签使用双花括号({{ 和 }})包围。以下是Mustache基本语法:

变量渲染

变量是Mustache模板中的基本插值类型。当模板中的标签与视图中的属性匹配时,它将被替换为对应的值。

Hello, {{name}}!

如果视图对象是 { “name”: “John” },那么输出将是:

Hello, John!
列表渲染

假设您的变量是一个列表,比如你有一个代表人员列表的数组。

{
 "people": [{"name": "Alice"},
 {"name": "Bob"},
 {"name": "Charlie"}]
}

Mustache模板可以设计为:

People:
{{#people}}
- {{name}}
{{/people}}

在这个例子中,{{#people}}开始了一个Section,该Section对应视图对象的 people 数组。Mustache将为列表中的每个条目渲染- {{name}}。当所有条目都被渲染后,{{/people}}表示Section的结束。渲染后的文本将是:

People:
- Alice
- Bob
- Charlie
转义与注释

Mustache默认会转义HTML字符,避免XSS攻击。如果您不想输出的变量被转义,可以使用三花括号:

Hello, {{{name}}}!

如果name的值是 “John”,那么输出将是:

Hello, <b>John</b>!

而不是转义后的:Hello, <b>John</b>!。

Mustache中的注释使用 {{! comment}}。这些注释不会出现在最终的输出中。

如何使用代码评审合并模板

当您准备合并一个合并请求时,您可以选择合并方式。根据您的选择(普通合并或压缩合并),系统将使用相应的合并模板来填充合并信息。

将合并请求进行合并

在合并请求详情页面,找到并单击合并按钮。

高的 (73)

方式1:选择创建一个合并节点。当选择这种方式进行合并时,所有的提交会以独立节点的形式加入到目标分支中。系统将会根据自定义代码评审合并模板规则检查您的仓库,以确定是否有自定义的普通合并模板:

  • 如果发现自定义普通合并模板,系统将使用该模板来渲染合并信息。

  • 如果没有自定义普通合并模板,系统将使用内置的普通合并模板。

高的 (74)

方式2:选择Squash合并。所有的提交会被压缩成一个单一的提交再合并到目标分支。系统将会根据自定义代码评审合并模板规则检查您的仓库,以确定是否有自定义的压缩合并模板:

  • 如果发现自定义压缩合并模板,系统将使用该模板来渲染合并信息。

  • 如果没有自定义压缩合并模板,系统将使用内置的压缩合并模板。

高的 (75)

浏览,编辑,创建模板文件

当您在浏览文件时,如果系统检测到文件是一个模板文件,它将在浏览器界面上显示一个明显的提示。这样,您可以轻松地辨识出当前文件是否为模板,并按照模板格式进行相关操作。

高的 (76)

当您在编辑文件时,如果系统检测到文件是一个模板文件,它将在浏览器界面上显示一个明显的提示,确保您在修改时可以遵循模板的规范。

高的 (77)

当您在创建新文件时,如果您的文件命名和结构符合模板文件的规则,系统也将提示您该文件是模板文件。这有助于您在创建时实时了解文件的模板性质,从而正确使用模板。

此外,为了进一步提高您的效率,允许您在创建自定义模板时直接使用云效提供的两种内置代码评审合并模板。您可以选择一个内置模板作为起点,然后根据您的具体需求进行自定义和扩展。

高的 (78)