Compare commits
5 Commits
Author | SHA1 | Date |
---|---|---|
|
5f0e1c86e5 | 3 months ago |
|
1937923cd0 | 3 months ago |
|
eae6afc139 | 3 months ago |
|
1c6fa53351 | 3 months ago |
|
fa6bbf212c | 3 months ago |
@ -1,62 +0,0 @@
|
|||||||
version: 2
|
|
||||||
name: feng
|
|
||||||
description: ""
|
|
||||||
global:
|
|
||||||
concurrent: 1
|
|
||||||
trigger:
|
|
||||||
webhook: gitlink@1.0.0
|
|
||||||
event:
|
|
||||||
- ref: push
|
|
||||||
ruleset-operator: AND
|
|
||||||
workflow:
|
|
||||||
- ref: start
|
|
||||||
name: 开始
|
|
||||||
task: start
|
|
||||||
- ref: git_clone_0
|
|
||||||
name: git clone
|
|
||||||
task: git_clone@1.2.9
|
|
||||||
input:
|
|
||||||
username: ((user.name))
|
|
||||||
password: ((mima.mima))
|
|
||||||
remote_url: '"https://gitlink.org.cn/fengyujue/gitlink_help_center.git"'
|
|
||||||
ref: '"refs/heads/master"'
|
|
||||||
commit_id: '""'
|
|
||||||
depth: 1
|
|
||||||
needs:
|
|
||||||
- start
|
|
||||||
- ref: end
|
|
||||||
name: 结束
|
|
||||||
task: end
|
|
||||||
needs:
|
|
||||||
- ssh_cmd_0
|
|
||||||
- ref: docker_image_build_0
|
|
||||||
name: docker镜像构建
|
|
||||||
task: docker_image_build@1.6.0
|
|
||||||
input:
|
|
||||||
docker_username: ((docker.name))
|
|
||||||
docker_password: ((docker.mima))
|
|
||||||
image_name: '"crpi-ybi767umyzh9owc0.cn-hangzhou.personal.cr.aliyuncs.com/help-center-gitlink/gitlink_help_gitlink"'
|
|
||||||
image_tag: '"latest"'
|
|
||||||
registry_address: '"crpi-ybi767umyzh9owc0.cn-hangzhou.personal.cr.aliyuncs.com"'
|
|
||||||
docker_file: '"Dockerfile"'
|
|
||||||
docker_build_path: '"."'
|
|
||||||
workspace: git_clone_0.git_path
|
|
||||||
image_push: true
|
|
||||||
build_args: '""'
|
|
||||||
needs:
|
|
||||||
- git_clone_0
|
|
||||||
- ref: ssh_cmd_0
|
|
||||||
name: ssh执行命令
|
|
||||||
task: ssh_cmd@1.1.1
|
|
||||||
input:
|
|
||||||
ssh_pass: ((ssh.password))
|
|
||||||
ssh_ip: '"120.27.137.186"'
|
|
||||||
ssh_port: '"22"'
|
|
||||||
ssh_user: '"root"'
|
|
||||||
ssh_cmd: '"docker stop group8 || true && docker rm group8 || true && docker pull
|
|
||||||
crpi-ybi767umyzh9owc0.cn-hangzhou.personal.cr.aliyuncs.com/help-center-gitlink/gitlink_help_gitlink:latest
|
|
||||||
&& docker run -d -p 3000:3000 --name group8
|
|
||||||
crpi-ybi767umyzh9owc0.cn-hangzhou.personal.cr.aliyuncs.com/help-center-gitlink/gitlink_help_gitlink:latest"'
|
|
||||||
needs:
|
|
||||||
- docker_image_build_0
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
|||||||
version: 2
|
|
||||||
name: 流水线
|
|
||||||
description: ""
|
|
||||||
global:
|
|
||||||
concurrent: 1
|
|
||||||
trigger:
|
|
||||||
webhook: gitlink@1.0.0
|
|
||||||
event:
|
|
||||||
- ref: push
|
|
||||||
ruleset-operator: AND
|
|
||||||
workflow:
|
|
||||||
- ref: start
|
|
||||||
name: 开始
|
|
||||||
task: start
|
|
||||||
- ref: git_clone_0
|
|
||||||
name: git clone
|
|
||||||
task: git_clone@1.2.9
|
|
||||||
input:
|
|
||||||
username: ((user.name))
|
|
||||||
password: ((mima.mima))
|
|
||||||
remote_url: '"https://gitlink.org.cn/fengyujue/gitlink_help_center.git"'
|
|
||||||
ref: '"refs/heads/wangfengzhi"'
|
|
||||||
commit_id: '""'
|
|
||||||
depth: 1
|
|
||||||
needs:
|
|
||||||
- start
|
|
||||||
- ref: end
|
|
||||||
name: 结束
|
|
||||||
task: end
|
|
||||||
needs:
|
|
||||||
- ssh_cmd_0
|
|
||||||
- ref: docker_image_build_0
|
|
||||||
name: docker镜像构建
|
|
||||||
task: docker_image_build@1.6.0
|
|
||||||
input:
|
|
||||||
docker_username: ((docker.name))
|
|
||||||
docker_password: ((docker.mima))
|
|
||||||
image_name: '"crpi-ybi767umyzh9owc0.cn-hangzhou.personal.cr.aliyuncs.com/help-center-gitlink/gitlink_help_gitlink"'
|
|
||||||
image_tag: '"latest"'
|
|
||||||
registry_address: '"crpi-ybi767umyzh9owc0.cn-hangzhou.personal.cr.aliyuncs.com"'
|
|
||||||
docker_file: '"Dockerfile"'
|
|
||||||
docker_build_path: '"."'
|
|
||||||
workspace: git_clone_0.git_path
|
|
||||||
image_push: true
|
|
||||||
build_args: '""'
|
|
||||||
needs:
|
|
||||||
- git_clone_0
|
|
||||||
- ref: ssh_cmd_0
|
|
||||||
name: ssh执行命令
|
|
||||||
task: ssh_cmd@1.1.1
|
|
||||||
input:
|
|
||||||
ssh_pass: ((ssh.password))
|
|
||||||
ssh_ip: '"120.27.137.186"'
|
|
||||||
ssh_port: '"22"'
|
|
||||||
ssh_user: '"root"'
|
|
||||||
ssh_cmd: docker stop gitlink_help_center || true && docker rm
|
|
||||||
gitlink_help_center || true && docker pull
|
|
||||||
crpi-ybi767umyzh9owc0.cn-hangzhou.personal.cr.aliyuncs.com/help-center-gitlink/gitlink_help_gitlink:latest;
|
|
||||||
docker run -d -p 3000:3000 --name gitlink_help_center
|
|
||||||
crpi-ybi767umyzh9owc0.cn-hangzhou.personal.cr.aliyuncs.com/help-center-gitlink/gitlink_help_gitlink:latest
|
|
||||||
needs:
|
|
||||||
- docker_image_build_0
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"label": "合并请求",
|
"label": "合并请求(PR)",
|
||||||
"position": 2,
|
"position": 5
|
||||||
"className": "merge-request"
|
|
||||||
}
|
}
|
||||||
|
@ -1,67 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: merge-request-issue
|
sidebar_label: '合并请求关联疑修'
|
||||||
title: 合并请求关联疑修
|
sidebar_position: 5
|
||||||
sidebar_label: '合并请求关联疑修'
|
|
||||||
sidebar_position: 5
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 合并请求关联疑修
|
# 合并请求关联疑修
|
||||||
|
|
||||||
## 功能介绍
|
|
||||||
|
|
||||||
合并请求关联疑修功能允许您在创建或编辑合并请求时,将相关的疑修与合并请求建立关联。这样可以帮助团队成员更好地追踪代码变更与疑修之间的关系,提高开发效率。
|
|
||||||
|
|
||||||
## 如何关联疑修
|
|
||||||
|
|
||||||
### 方法一:在合并请求描述中引用
|
|
||||||
|
|
||||||
1. 在创建或编辑合并请求时,在描述中使用 `#` 符号引用疑修编号
|
|
||||||
2. 例如:`修复 #123 中提到的登录问题`
|
|
||||||
3. 系统会自动识别并建立关联
|
|
||||||
|
|
||||||
### 方法二:在疑修详情页关联
|
|
||||||
|
|
||||||
1. 打开疑修详情页面
|
|
||||||
2. 点击"关联合并请求"按钮
|
|
||||||
3. 选择要关联的合并请求
|
|
||||||
4. 确认关联
|
|
||||||
|
|
||||||
## 关联后的效果
|
|
||||||
|
|
||||||
1. 在疑修详情页面可以看到关联的合并请求列表
|
|
||||||
2. 在合并请求详情页面可以看到关联的疑修信息
|
|
||||||
3. 当合并请求被合并时,系统会自动更新疑修状态
|
|
||||||
4. 可以通过关联关系快速追踪代码变更
|
|
||||||
|
|
||||||
## 管理关联关系
|
|
||||||
|
|
||||||
### 查看关联
|
|
||||||
|
|
||||||
1. 在疑修详情页面的"关联合并请求"部分查看
|
|
||||||
2. 在合并请求详情页面的"关联疑修"部分查看
|
|
||||||
|
|
||||||
### 解除关联
|
|
||||||
|
|
||||||
1. 在疑修详情页面:
|
|
||||||
- 找到要解除关联的合并请求
|
|
||||||
- 点击"解除关联"按钮
|
|
||||||
- 确认操作
|
|
||||||
|
|
||||||
2. 在合并请求详情页面:
|
|
||||||
- 找到要解除关联的疑修
|
|
||||||
- 点击"解除关联"按钮
|
|
||||||
- 确认操作
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
1. 在创建合并请求时,及时关联相关的疑修
|
|
||||||
2. 使用清晰的描述说明合并请求与疑修的关系
|
|
||||||
3. 定期检查关联关系,确保其准确性
|
|
||||||
4. 在合并请求被合并后,及时确认疑修状态
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
1. 一个合并请求可以关联多个疑修
|
|
||||||
2. 一个疑修可以关联多个合并请求
|
|
||||||
3. 关联关系建立后可以随时修改
|
|
||||||
4. 解除关联不会影响已合并的代码变更
|
|
@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"label": "平台公告",
|
"label": "平台公告",
|
||||||
"position": 1,
|
"position": 99
|
||||||
"className": "platform-announcement"
|
|
||||||
}
|
}
|
||||||
|
@ -1,87 +1,4 @@
|
|||||||
---
|
---
|
||||||
id: platform-announcement
|
sidebar_label: '平台公告'
|
||||||
title: 平台公告
|
sidebar_position: 1
|
||||||
sidebar_label: '平台公告'
|
---
|
||||||
sidebar_position: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
# 平台公告
|
|
||||||
|
|
||||||
## 功能介绍
|
|
||||||
|
|
||||||
平台公告功能允许管理员发布和管理平台相关的通知、更新和重要信息。通过平台公告,可以及时向用户传达重要信息,确保用户了解平台的最新动态。
|
|
||||||
|
|
||||||
## 创建平台公告
|
|
||||||
|
|
||||||
1. 进入平台公告管理页面
|
|
||||||
2. 点击"新建公告"按钮
|
|
||||||
3. 填写公告标题和内容
|
|
||||||
4. 设置公告类型和优先级
|
|
||||||
5. 选择发布范围
|
|
||||||
6. 点击"发布"按钮
|
|
||||||
|
|
||||||
## 公告类型
|
|
||||||
|
|
||||||
平台公告支持以下类型:
|
|
||||||
|
|
||||||
- 系统更新:平台功能更新和系统维护通知
|
|
||||||
- 功能发布:新功能发布和功能介绍
|
|
||||||
- 活动通知:平台活动、比赛和培训通知
|
|
||||||
- 重要提醒:安全提醒和重要政策变更
|
|
||||||
- 其他通知:其他类型的平台通知
|
|
||||||
|
|
||||||
## 公告管理
|
|
||||||
|
|
||||||
### 编辑公告
|
|
||||||
|
|
||||||
1. 在公告列表中找到要编辑的公告
|
|
||||||
2. 点击"编辑"按钮
|
|
||||||
3. 修改公告内容
|
|
||||||
4. 点击"保存"按钮
|
|
||||||
|
|
||||||
### 删除公告
|
|
||||||
|
|
||||||
1. 在公告列表中找到要删除的公告
|
|
||||||
2. 点击"删除"按钮
|
|
||||||
3. 确认删除操作
|
|
||||||
|
|
||||||
### 公告状态
|
|
||||||
|
|
||||||
公告可能处于以下状态:
|
|
||||||
|
|
||||||
- 草稿:未发布的公告
|
|
||||||
- 已发布:正在显示的公告
|
|
||||||
- 已过期:超过显示期限的公告
|
|
||||||
- 已归档:已归档的公告
|
|
||||||
|
|
||||||
## 公告显示
|
|
||||||
|
|
||||||
### 显示位置
|
|
||||||
|
|
||||||
1. 平台首页公告栏
|
|
||||||
2. 用户个人中心
|
|
||||||
3. 相关功能页面
|
|
||||||
|
|
||||||
### 显示规则
|
|
||||||
|
|
||||||
1. 按优先级排序显示
|
|
||||||
2. 按发布时间倒序排列
|
|
||||||
3. 支持置顶显示
|
|
||||||
4. 支持定时发布和自动过期
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
1. 公告标题要简洁明了
|
|
||||||
2. 内容要清晰易懂
|
|
||||||
3. 重要信息要突出显示
|
|
||||||
4. 及时更新和删除过期公告
|
|
||||||
5. 合理设置公告优先级
|
|
||||||
6. 注意公告的时效性
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
1. 公告内容要符合平台规范
|
|
||||||
2. 避免发布重复或过时的信息
|
|
||||||
3. 重要公告要及时通知用户
|
|
||||||
4. 定期清理过期公告
|
|
||||||
5. 注意公告的权限管理
|
|
@ -1 +0,0 @@
|
|||||||
<center>该功能无法使用</center><br/>
|
|
File diff suppressed because it is too large
Load Diff
@ -1,56 +0,0 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
import styles from './styles.module.css';
|
|
||||||
|
|
||||||
export default function BackToTop() {
|
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
|
||||||
|
|
||||||
// 监听滚动事件
|
|
||||||
useEffect(() => {
|
|
||||||
const toggleVisibility = () => {
|
|
||||||
if (window.pageYOffset > 300) {
|
|
||||||
setIsVisible(true);
|
|
||||||
} else {
|
|
||||||
setIsVisible(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('scroll', toggleVisibility);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('scroll', toggleVisibility);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 滚动到顶部
|
|
||||||
const scrollToTop = () => {
|
|
||||||
window.scrollTo({
|
|
||||||
top: 0,
|
|
||||||
behavior: 'smooth',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{isVisible && (
|
|
||||||
<button
|
|
||||||
onClick={scrollToTop}
|
|
||||||
className={styles.backToTop}
|
|
||||||
aria-label="返回顶部"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
fill="none"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
>
|
|
||||||
<path d="M12 19V5M5 12l7-7 7 7" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
.backToTop {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 20px;
|
|
||||||
right: 20px;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: var(--ifm-color-primary);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.backToTop:hover {
|
|
||||||
background-color: var(--ifm-color-primary-darker);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.backToTop:active {
|
|
||||||
transform: translateY(0);
|
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 996px) {
|
|
||||||
.backToTop {
|
|
||||||
bottom: 15px;
|
|
||||||
right: 15px;
|
|
||||||
width: 35px;
|
|
||||||
height: 35px;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
import styles from './styles.module.css';
|
|
||||||
|
|
||||||
export default function Bookmark({ docId }) {
|
|
||||||
const [isBookmarked, setIsBookmarked] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// 从localStorage中读取标记状态
|
|
||||||
const bookmarks = JSON.parse(localStorage.getItem('docBookmarks') || '{}');
|
|
||||||
setIsBookmarked(bookmarks[docId] || false);
|
|
||||||
}, [docId]);
|
|
||||||
|
|
||||||
const toggleBookmark = (e) => {
|
|
||||||
e.stopPropagation(); // 阻止事件冒泡
|
|
||||||
const bookmarks = JSON.parse(localStorage.getItem('docBookmarks') || '{}');
|
|
||||||
const newState = !isBookmarked;
|
|
||||||
bookmarks[docId] = newState;
|
|
||||||
localStorage.setItem('docBookmarks', JSON.stringify(bookmarks));
|
|
||||||
setIsBookmarked(newState);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
onClick={toggleBookmark}
|
|
||||||
className={`${styles.bookmarkButton} ${isBookmarked ? styles.bookmarked : ''}`}
|
|
||||||
aria-label={isBookmarked ? '取消标记' : '添加标记'}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
fill={isBookmarked ? 'currentColor' : 'none'}
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
>
|
|
||||||
<path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
.bookmarkButton {
|
|
||||||
position: absolute;
|
|
||||||
left: -20px;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 4px;
|
|
||||||
color: var(--ifm-color-emphasis-600);
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
opacity: 0;
|
|
||||||
z-index: 100;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmarkButton:hover {
|
|
||||||
color: var(--ifm-color-primary);
|
|
||||||
transform: translateY(-50%) scale(1.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmarked {
|
|
||||||
color: var(--ifm-color-primary);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 当鼠标悬停在侧边栏项目上时显示标记按钮 */
|
|
||||||
:global(.menu__link-wrapper:hover) .bookmarkButton {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 已标记的项目始终显示标记按钮 */
|
|
||||||
:global(.menu__link-wrapper) .bookmarked {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 确保侧边栏项目有足够的空间显示标记按钮 */
|
|
||||||
:global(.menu__link-wrapper) {
|
|
||||||
padding-left: 25px !important;
|
|
||||||
position: relative !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 调整列表项样式 */
|
|
||||||
:global(.menu__list-item) {
|
|
||||||
position: relative !important;
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
import styles from './styles.module.css';
|
|
||||||
|
|
||||||
export default function DocBookmark({ docId }) {
|
|
||||||
const [isBookmarked, setIsBookmarked] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// 从localStorage中读取标记状态
|
|
||||||
const bookmarks = JSON.parse(localStorage.getItem('docBookmarks') || '{}');
|
|
||||||
setIsBookmarked(bookmarks[docId] || false);
|
|
||||||
}, [docId]);
|
|
||||||
|
|
||||||
const toggleBookmark = () => {
|
|
||||||
const bookmarks = JSON.parse(localStorage.getItem('docBookmarks') || '{}');
|
|
||||||
const newState = !isBookmarked;
|
|
||||||
bookmarks[docId] = newState;
|
|
||||||
localStorage.setItem('docBookmarks', JSON.stringify(bookmarks));
|
|
||||||
setIsBookmarked(newState);
|
|
||||||
|
|
||||||
// 触发自定义事件,通知侧边栏更新
|
|
||||||
const event = new CustomEvent('bookmarkChanged', {
|
|
||||||
detail: { docId, isBookmarked: newState }
|
|
||||||
});
|
|
||||||
window.dispatchEvent(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.bookmarkContainer}>
|
|
||||||
<button
|
|
||||||
onClick={toggleBookmark}
|
|
||||||
className={`${styles.bookmarkButton} ${isBookmarked ? styles.bookmarked : ''}`}
|
|
||||||
aria-label={isBookmarked ? '取消标记' : '添加标记'}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
fill={isBookmarked ? 'currentColor' : 'none'}
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
>
|
|
||||||
<path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z" />
|
|
||||||
</svg>
|
|
||||||
<span className={styles.bookmarkText}>
|
|
||||||
{isBookmarked ? '取消标记' : '添加标记'}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
.bookmarkContainer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
padding: 0.5rem;
|
|
||||||
border-bottom: 1px solid var(--ifm-color-emphasis-200);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmarkButton {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.5rem;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
border: 1px solid var(--ifm-color-emphasis-300);
|
|
||||||
border-radius: 4px;
|
|
||||||
background: var(--ifm-background-color);
|
|
||||||
color: var(--ifm-color-emphasis-700);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmarkButton:hover {
|
|
||||||
background: var(--ifm-color-emphasis-100);
|
|
||||||
border-color: var(--ifm-color-primary);
|
|
||||||
color: var(--ifm-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmarked {
|
|
||||||
background: var(--ifm-color-primary);
|
|
||||||
color: white;
|
|
||||||
border-color: var(--ifm-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmarked:hover {
|
|
||||||
background: var(--ifm-color-primary-darker);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmarkText {
|
|
||||||
font-size: 0.9rem;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
.commentSection {
|
|
||||||
margin-top: 3rem;
|
|
||||||
padding-top: 2rem;
|
|
||||||
border-top: 1px solid var(--ifm-color-emphasis-200);
|
|
||||||
}
|
|
||||||
|
|
||||||
.commentTitle {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
color: var(--ifm-color-emphasis-800);
|
|
||||||
}
|
|
||||||
|
|
||||||
.commentList {
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.commentItem {
|
|
||||||
padding: 1rem;
|
|
||||||
border: 1px solid var(--ifm-color-emphasis-200);
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
background-color: var(--ifm-background-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.commentHeader {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.commentAuthor {
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--ifm-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.commentTime {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: var(--ifm-color-emphasis-600);
|
|
||||||
}
|
|
||||||
|
|
||||||
.deleteButton {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: var(--ifm-color-emphasis-600);
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0 4px;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.deleteButton:hover {
|
|
||||||
color: var(--ifm-color-danger);
|
|
||||||
}
|
|
||||||
|
|
||||||
.commentText {
|
|
||||||
font-size: 1rem;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: var(--ifm-color-emphasis-800);
|
|
||||||
}
|
|
||||||
|
|
||||||
.commentInput {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.commentInput textarea {
|
|
||||||
width: 100%;
|
|
||||||
padding: 0.75rem;
|
|
||||||
border: 1px solid var(--ifm-color-emphasis-200);
|
|
||||||
border-radius: 8px;
|
|
||||||
resize: vertical;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: 1rem;
|
|
||||||
min-height: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.commentInput textarea:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: var(--ifm-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.submitButton {
|
|
||||||
align-self: flex-end;
|
|
||||||
padding: 0.5rem 1.5rem;
|
|
||||||
background-color: var(--ifm-color-primary);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 1rem;
|
|
||||||
transition: background-color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submitButton:hover {
|
|
||||||
background-color: var(--ifm-color-primary-darker);
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import styles from './styles.module.css';
|
|
||||||
|
|
||||||
export default function DocRating({ docId }) {
|
|
||||||
const [hasRated, setHasRated] = useState(false);
|
|
||||||
const [showMessage, setShowMessage] = useState(false);
|
|
||||||
const [message, setMessage] = useState('');
|
|
||||||
|
|
||||||
const handleRating = (isPositive) => {
|
|
||||||
// 保存评级到localStorage
|
|
||||||
const ratings = JSON.parse(localStorage.getItem('docRatings') || '{}');
|
|
||||||
ratings[docId] = isPositive;
|
|
||||||
localStorage.setItem('docRatings', JSON.stringify(ratings));
|
|
||||||
|
|
||||||
// 显示相应的消息
|
|
||||||
setMessage(isPositive
|
|
||||||
? '感谢您的评价,祝您使用愉快'
|
|
||||||
: '不好意思,给您带来不好的体验,我们一定会积极改进'
|
|
||||||
);
|
|
||||||
setShowMessage(true);
|
|
||||||
setHasRated(true);
|
|
||||||
|
|
||||||
// 5秒后隐藏消息
|
|
||||||
setTimeout(() => {
|
|
||||||
setShowMessage(false);
|
|
||||||
}, 5000);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (hasRated) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={styles.ratingSection}>
|
|
||||||
<p className={styles.ratingText}>请您对本文档做出评价</p>
|
|
||||||
<div className={styles.ratingButtons}>
|
|
||||||
<button
|
|
||||||
onClick={() => handleRating(true)}
|
|
||||||
className={`${styles.ratingButton} ${styles.positiveButton}`}
|
|
||||||
>
|
|
||||||
好
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => handleRating(false)}
|
|
||||||
className={`${styles.ratingButton} ${styles.negativeButton}`}
|
|
||||||
>
|
|
||||||
不好
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{showMessage && (
|
|
||||||
<>
|
|
||||||
<div className={styles.messageOverlay} />
|
|
||||||
<div className={styles.message}>
|
|
||||||
{message}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
.ratingSection {
|
|
||||||
margin-top: 2rem;
|
|
||||||
padding: 1.5rem;
|
|
||||||
border: 1px solid var(--ifm-color-emphasis-200);
|
|
||||||
border-radius: 8px;
|
|
||||||
background-color: var(--ifm-background-color);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ratingText {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
color: var(--ifm-color-emphasis-800);
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ratingButtons {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ratingButton {
|
|
||||||
padding: 0.5rem 2rem;
|
|
||||||
border: none;
|
|
||||||
border-radius: 6px;
|
|
||||||
font-size: 1rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.positiveButton {
|
|
||||||
background-color: var(--ifm-color-success);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.positiveButton:hover {
|
|
||||||
background-color: var(--ifm-color-success-darker);
|
|
||||||
transform: translateY(-1px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.negativeButton {
|
|
||||||
background-color: var(--ifm-color-danger);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.negativeButton:hover {
|
|
||||||
background-color: var(--ifm-color-danger-darker);
|
|
||||||
transform: translateY(-1px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.messageOverlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
z-index: 999;
|
|
||||||
animation: fadeIn 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message {
|
|
||||||
position: fixed;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
padding: 1.5rem 2rem;
|
|
||||||
border-radius: 8px;
|
|
||||||
background-color: var(--ifm-background-color);
|
|
||||||
color: var(--ifm-color-emphasis-800);
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
||||||
z-index: 1000;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
text-align: center;
|
|
||||||
min-width: 300px;
|
|
||||||
border: 1px solid var(--ifm-color-emphasis-200);
|
|
||||||
animation: fadeIn 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeIn {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translate(-50%, -40%);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import DocItem from '@theme-original/DocItem';
|
|
||||||
import DocComment from '@site/src/components/DocComment';
|
|
||||||
import DocRating from '@site/src/components/DocRating';
|
|
||||||
|
|
||||||
export default function DocItemWrapper(props) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<DocItem {...props} />
|
|
||||||
<DocRating docId={props.content.metadata.id} />
|
|
||||||
<DocComment docId={props.content.metadata.id} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import DocPage from '@theme-original/DocPage';
|
|
||||||
import DocBookmark from '@site/src/components/DocBookmark';
|
|
||||||
import {useLocation} from '@docusaurus/router';
|
|
||||||
|
|
||||||
export default function DocPageWrapper(props) {
|
|
||||||
const {content} = props;
|
|
||||||
const location = useLocation();
|
|
||||||
const docId = location.pathname;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<DocBookmark docId={docId} />
|
|
||||||
<DocPage {...props} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import DocSidebarItem from '@theme-original/DocSidebarItem';
|
|
||||||
import styles from './styles.module.css';
|
|
||||||
|
|
||||||
export default function DocSidebarItemWrapper(props) {
|
|
||||||
const { item } = props;
|
|
||||||
const [isBookmarked, setIsBookmarked] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (item.type === 'doc') {
|
|
||||||
const bookmarks = JSON.parse(localStorage.getItem('docBookmarks') || '{}');
|
|
||||||
setIsBookmarked(bookmarks[item.docId] || false);
|
|
||||||
|
|
||||||
// 监听标记变化事件
|
|
||||||
const handleBookmarkChange = (event) => {
|
|
||||||
const { docId, isBookmarked: newState } = event.detail;
|
|
||||||
if (docId === item.docId) {
|
|
||||||
setIsBookmarked(newState);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('bookmarkChanged', handleBookmarkChange);
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('bookmarkChanged', handleBookmarkChange);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}, [item]);
|
|
||||||
|
|
||||||
if (item.type === 'doc') {
|
|
||||||
return (
|
|
||||||
<li className={`menu__list-item ${isBookmarked ? styles.bookmarkedItem : ''}`}>
|
|
||||||
<div className={styles.menuLinkWrapper}>
|
|
||||||
<DocSidebarItem {...props} />
|
|
||||||
<div className={styles.actionButtons}>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
const bookmarks = JSON.parse(localStorage.getItem('docBookmarks') || '{}');
|
|
||||||
const newState = !isBookmarked;
|
|
||||||
bookmarks[item.docId] = newState;
|
|
||||||
localStorage.setItem('docBookmarks', JSON.stringify(bookmarks));
|
|
||||||
setIsBookmarked(newState);
|
|
||||||
window.dispatchEvent(new CustomEvent('bookmarkChanged', {
|
|
||||||
detail: { docId: item.docId, isBookmarked: newState }
|
|
||||||
}));
|
|
||||||
}}
|
|
||||||
className={`${styles.bookmarkButton} ${isBookmarked ? styles.bookmarked : ''}`}
|
|
||||||
aria-label={isBookmarked ? '取消标记' : '添加标记'}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
fill={isBookmarked ? 'currentColor' : 'none'}
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
>
|
|
||||||
<path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <DocSidebarItem {...props} />;
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
.menuLinkWrapper {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actionButtons {
|
|
||||||
position: absolute;
|
|
||||||
right: 8px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4px;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmarkButton {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 4px;
|
|
||||||
color: var(--ifm-color-emphasis-600);
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmarkButton:hover {
|
|
||||||
color: var(--ifm-color-primary);
|
|
||||||
transform: scale(1.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmarked {
|
|
||||||
color: var(--ifm-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmarkedItem {
|
|
||||||
background-color: var(--ifm-color-emphasis-100);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmarkedItem :global(.menu__link) {
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--ifm-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 确保侧边栏项目有足够的空间显示按钮 */
|
|
||||||
:global(.menu__link-wrapper) {
|
|
||||||
padding-right: 80px !important;
|
|
||||||
position: relative !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 调整列表项样式 */
|
|
||||||
:global(.menu__list-item) {
|
|
||||||
position: relative !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bookmarkedItem :global(.menu__link:hover) {
|
|
||||||
background-color: var(--ifm-color-emphasis-200) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 确保样式在深色模式下也生效 */
|
|
||||||
[data-theme='dark'] .bookmarkedItem :global(.menu__link) {
|
|
||||||
background-color: var(--ifm-color-emphasis-200) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme='dark'] .bookmarkedItem :global(.menu__link:hover) {
|
|
||||||
background-color: var(--ifm-color-emphasis-300) !important;
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import Layout from '@theme-original/Layout';
|
|
||||||
import BackToTop from '@site/src/components/BackToTop';
|
|
||||||
|
|
||||||
export default function LayoutWrapper(props) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Layout {...props} />
|
|
||||||
<BackToTop />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
After Width: | Height: | Size: 9.3 KiB |
@ -1,67 +1,6 @@
|
|||||||
---
|
---
|
||||||
id: merge-request-issue
|
sidebar_label: '合并请求关联疑修'
|
||||||
title: 合并请求关联疑修
|
sidebar_position: 5
|
||||||
sidebar_label: '合并请求关联疑修'
|
|
||||||
sidebar_position: 5
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 合并请求关联疑修
|
# 合并请求关联疑修
|
||||||
|
|
||||||
## 功能介绍
|
|
||||||
|
|
||||||
合并请求关联疑修功能允许您在创建或编辑合并请求时,将相关的疑修与合并请求建立关联。这样可以帮助团队成员更好地追踪代码变更与疑修之间的关系,提高开发效率。
|
|
||||||
|
|
||||||
## 如何关联疑修
|
|
||||||
|
|
||||||
### 方法一:在合并请求描述中引用
|
|
||||||
|
|
||||||
1. 在创建或编辑合并请求时,在描述中使用 `#` 符号引用疑修编号
|
|
||||||
2. 例如:`修复 #123 中提到的登录问题`
|
|
||||||
3. 系统会自动识别并建立关联
|
|
||||||
|
|
||||||
### 方法二:在疑修详情页关联
|
|
||||||
|
|
||||||
1. 打开疑修详情页面
|
|
||||||
2. 点击"关联合并请求"按钮
|
|
||||||
3. 选择要关联的合并请求
|
|
||||||
4. 确认关联
|
|
||||||
|
|
||||||
## 关联后的效果
|
|
||||||
|
|
||||||
1. 在疑修详情页面可以看到关联的合并请求列表
|
|
||||||
2. 在合并请求详情页面可以看到关联的疑修信息
|
|
||||||
3. 当合并请求被合并时,系统会自动更新疑修状态
|
|
||||||
4. 可以通过关联关系快速追踪代码变更
|
|
||||||
|
|
||||||
## 管理关联关系
|
|
||||||
|
|
||||||
### 查看关联
|
|
||||||
|
|
||||||
1. 在疑修详情页面的"关联合并请求"部分查看
|
|
||||||
2. 在合并请求详情页面的"关联疑修"部分查看
|
|
||||||
|
|
||||||
### 解除关联
|
|
||||||
|
|
||||||
1. 在疑修详情页面:
|
|
||||||
- 找到要解除关联的合并请求
|
|
||||||
- 点击"解除关联"按钮
|
|
||||||
- 确认操作
|
|
||||||
|
|
||||||
2. 在合并请求详情页面:
|
|
||||||
- 找到要解除关联的疑修
|
|
||||||
- 点击"解除关联"按钮
|
|
||||||
- 确认操作
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
1. 在创建合并请求时,及时关联相关的疑修
|
|
||||||
2. 使用清晰的描述说明合并请求与疑修的关系
|
|
||||||
3. 定期检查关联关系,确保其准确性
|
|
||||||
4. 在合并请求被合并后,及时确认疑修状态
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
1. 一个合并请求可以关联多个疑修
|
|
||||||
2. 一个疑修可以关联多个合并请求
|
|
||||||
3. 关联关系建立后可以随时修改
|
|
||||||
4. 解除关联不会影响已合并的代码变更
|
|
@ -1,87 +1,4 @@
|
|||||||
---
|
---
|
||||||
id: platform-announcement
|
sidebar_label: '平台公告'
|
||||||
title: 平台公告
|
sidebar_position: 1
|
||||||
sidebar_label: '平台公告'
|
---
|
||||||
sidebar_position: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
# 平台公告
|
|
||||||
|
|
||||||
## 功能介绍
|
|
||||||
|
|
||||||
平台公告功能允许管理员发布和管理平台相关的通知、更新和重要信息。通过平台公告,可以及时向用户传达重要信息,确保用户了解平台的最新动态。
|
|
||||||
|
|
||||||
## 创建平台公告
|
|
||||||
|
|
||||||
1. 进入平台公告管理页面
|
|
||||||
2. 点击"新建公告"按钮
|
|
||||||
3. 填写公告标题和内容
|
|
||||||
4. 设置公告类型和优先级
|
|
||||||
5. 选择发布范围
|
|
||||||
6. 点击"发布"按钮
|
|
||||||
|
|
||||||
## 公告类型
|
|
||||||
|
|
||||||
平台公告支持以下类型:
|
|
||||||
|
|
||||||
- 系统更新:平台功能更新和系统维护通知
|
|
||||||
- 功能发布:新功能发布和功能介绍
|
|
||||||
- 活动通知:平台活动、比赛和培训通知
|
|
||||||
- 重要提醒:安全提醒和重要政策变更
|
|
||||||
- 其他通知:其他类型的平台通知
|
|
||||||
|
|
||||||
## 公告管理
|
|
||||||
|
|
||||||
### 编辑公告
|
|
||||||
|
|
||||||
1. 在公告列表中找到要编辑的公告
|
|
||||||
2. 点击"编辑"按钮
|
|
||||||
3. 修改公告内容
|
|
||||||
4. 点击"保存"按钮
|
|
||||||
|
|
||||||
### 删除公告
|
|
||||||
|
|
||||||
1. 在公告列表中找到要删除的公告
|
|
||||||
2. 点击"删除"按钮
|
|
||||||
3. 确认删除操作
|
|
||||||
|
|
||||||
### 公告状态
|
|
||||||
|
|
||||||
公告可能处于以下状态:
|
|
||||||
|
|
||||||
- 草稿:未发布的公告
|
|
||||||
- 已发布:正在显示的公告
|
|
||||||
- 已过期:超过显示期限的公告
|
|
||||||
- 已归档:已归档的公告
|
|
||||||
|
|
||||||
## 公告显示
|
|
||||||
|
|
||||||
### 显示位置
|
|
||||||
|
|
||||||
1. 平台首页公告栏
|
|
||||||
2. 用户个人中心
|
|
||||||
3. 相关功能页面
|
|
||||||
|
|
||||||
### 显示规则
|
|
||||||
|
|
||||||
1. 按优先级排序显示
|
|
||||||
2. 按发布时间倒序排列
|
|
||||||
3. 支持置顶显示
|
|
||||||
4. 支持定时发布和自动过期
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
1. 公告标题要简洁明了
|
|
||||||
2. 内容要清晰易懂
|
|
||||||
3. 重要信息要突出显示
|
|
||||||
4. 及时更新和删除过期公告
|
|
||||||
5. 合理设置公告优先级
|
|
||||||
6. 注意公告的时效性
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
1. 公告内容要符合平台规范
|
|
||||||
2. 避免发布重复或过时的信息
|
|
||||||
3. 重要公告要及时通知用户
|
|
||||||
4. 定期清理过期公告
|
|
||||||
5. 注意公告的权限管理
|
|
Loading…
Reference in new issue