Files
gamegroup2/frontend/src/views/Changelog.vue
T

235 lines
8.4 KiB
Vue
Raw Normal View History

<!-- src/views/Changelog.vue -->
<script setup lang="ts">
import { ref } from 'vue'
interface LogEntry {
version: string
date: string
title: string
items: { type: 'feat' | 'fix' | 'refactor' | 'style'; text: string }[]
}
const logs = ref<LogEntry[]>([
{
version: 'v0.1.1',
date: '2026-04-18',
title: '二期功能优化',
items: [
{ type: 'feat', text: '投票编辑:发起人可修改标题、选项、截止时间,已投票选项不可删除' },
{ type: 'feat', text: '通知面板展示站内消息通知,支持投票/组队/群组通知跳转' },
{ type: 'feat', text: '创建投票后自动通知同群组成员' },
{ type: 'feat', text: '邀请被拒绝/接受后通知邀请发起人' },
{ type: 'feat', text: '通知点击跳转到对应群组并切换到相关 Tab' },
{ type: 'fix', text: '修复通知 createRule 权限限制导致无法给他人发送通知' },
{ type: 'fix', text: '修复截止时间时区偏差,统一 ISO 格式存储' },
{ type: 'fix', text: '修复投票列表 auto-cancel 竞态和选项 order=0 校验失败' },
{ type: 'fix', text: '修复 nginx 静态缓存误拦截 API 文件请求和上传大小限制' },
{ type: 'fix', text: '修复回忆 Tab 图片不展示和视频无法播放问题' },
{ type: 'fix', text: '修复切换 Tab 数据不加载的时序问题' },
]
},
{
version: 'v0.1.0',
date: '2026-04-18',
title: '二期功能:投票、回忆、统计',
items: [
{ type: 'feat', text: '群组投票:支持选项投票和接龙报名两种模式,可设置截止时间、匿名投票' },
{ type: 'feat', text: '投票编辑:发起人可修改标题、选项、截止时间,已投票选项不可删除' },
{ type: 'feat', text: '投票结算:到达截止时间自动结算,发起人也可手动结束投票' },
{ type: 'feat', text: '多媒体回忆:群组内上传图片/视频/音频/文档,缩略图预览和弹窗播放' },
{ type: 'feat', text: '数据统计:群组内展示本周组队次数、投票参与率、积分排行' },
{ type: 'feat', text: '站内通知:新增投票、组队、入群等场景通知,铃铛图标显示未读数' },
{ type: 'feat', text: '积分体系:参与投票/组队/上传获取积分,群组内展示排行' },
{ type: 'feat', text: '群组详情页 Tab 重构:动态/投票/回忆/统计四个 Tab,带图标醒目展示' },
{ type: 'fix', text: '修复 nginx 代理文件上传 413 问题和静态资源误拦截 API 文件请求' },
{ type: 'fix', text: '修复投票列表 auto-cancel 竞态问题和选项排序 0 值校验失败' },
{ type: 'fix', text: '修复截止时间时区偏差,统一使用 ISO 格式存储' },
]
},
2026-04-18 13:36:02 +08:00
{
version: 'v0.0.3',
date: '2026-04-18',
title: '优化登录和注册',
items: [
{ type: 'feat', text: '支持中文昵称登录:输入昵称即可登录,无需记忆邮箱' },
{ type: 'feat', text: '注册时昵称唯一性检查:失焦自动检测,实时反馈是否可用' },
{ type: 'feat', text: '注册支持中文昵称,自动生成系统用户名' },
{ type: 'fix', text: '密码规则清晰展示:四项规则标签 + 密码强度指示条' },
]
},
{
version: 'v0.0.2',
date: '2026-04-18',
title: '优化页面元素和游戏库筛选',
items: [
{ type: 'style', text: '统一色彩体系,将混用的蓝/紫色调全部替换为绿色主题' },
{ type: 'feat', text: '侧边栏「创建群组」「加入群组」按钮添加文字标签,提升可发现性' },
{ type: 'feat', text: '顶部 Header 增加快捷操作入口(创建群组、加入群组、通知)' },
{ type: 'feat', text: '移动端适配:添加汉堡菜单,侧边栏滑动展开' },
{ type: 'feat', text: '首页欢迎条增加 CTA 按钮,无群组时显示引导卡片' },
{ type: 'feat', text: '加入群组弹窗新增按名称搜索模式,保留 ID 查找作为备选' },
{ type: 'feat', text: '游戏库页面内置群组下拉选择,不再依赖外部选择' },
{ type: 'fix', text: '热门游戏空状态优化提示文案' },
{ type: 'refactor', text: '首页无临时小组时自动折叠空闲成员区域' },
]
},
{
version: 'v0.0.1',
date: '2026-04-17',
title: '项目初始化',
items: [
{ type: 'feat', text: '搭建项目基础架构:Vue 3 + TypeScript + Pinia + Element Plus + Tailwind CSS' },
{ type: 'feat', text: '集成 PocketBase 后端服务,完成用户认证(注册/登录/Cookie 持久化)' },
{ type: 'feat', text: '实现群组管理:创建群组、加入群组(ID 查找)、解散群组' },
{ type: 'feat', text: '实现入群审批流程:审核开关、提交申请、群主审批' },
{ type: 'feat', text: '实现临时小组:创建小队、邀请成员、开始游戏、结束解散' },
{ type: 'feat', text: '实现组队邀请:发送邀请、接受/拒绝、实时通知' },
{ type: 'feat', text: '实现游戏库:添加游戏、导入导出、评论收藏、热门排行' },
{ type: 'feat', text: '用户状态管理:空闲/工作中/组队中/离开,工作时间自动切换' },
{ type: 'feat', text: '实时数据同步:PocketBase Realtime 订阅群组、成员、邀请变更' },
{ type: 'feat', text: 'Docker 部署方案:Dev/UAT 环境分离,独立 PocketBase 实例' },
]
}
])
const typeMap: Record<string, { label: string; color: string }> = {
feat: { label: '新功能', color: 'var(--gg-primary)' },
fix: { label: '修复', color: 'var(--gg-warning)' },
refactor: { label: '优化', color: 'var(--gg-info)' },
style: { label: '样式', color: 'var(--gg-accent)' },
}
</script>
<template>
<div class="changelog-page">
<h1 class="page-title">更新日志</h1>
<div class="timeline">
<section v-for="log in logs" :key="log.version" class="version-block">
<div class="version-header">
<span class="version-tag">{{ log.version }}</span>
<span class="version-date">{{ log.date }}</span>
</div>
<h2 class="version-title">{{ log.title }}</h2>
<ul class="change-list">
<li v-for="(item, i) in log.items" :key="i" class="change-item">
<span class="change-type" :style="{ background: typeMap[item.type].color + '18', color: typeMap[item.type].color }">
{{ typeMap[item.type].label }}
</span>
<span class="change-text">{{ item.text }}</span>
</li>
</ul>
</section>
</div>
</div>
</template>
<style scoped>
.changelog-page {
max-width: 680px;
margin: 0 auto;
}
.page-title {
font-size: 28px;
font-weight: 700;
margin: 0 0 28px;
background: var(--gg-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.timeline {
display: flex;
flex-direction: column;
gap: 28px;
padding-left: 20px;
border-left: 3px solid var(--gg-border);
}
.version-block {
position: relative;
padding: 20px 24px;
background: var(--gg-bg-card);
border: 1px solid var(--gg-border);
border-radius: var(--gg-radius-lg);
transition: border-color 0.2s;
}
.version-block:hover {
border-color: var(--gg-primary);
}
.version-block::before {
content: '';
position: absolute;
left: -29px;
top: 28px;
width: 13px;
height: 13px;
border-radius: 50%;
background: var(--gg-primary);
border: 3px solid var(--gg-bg);
}
.version-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 8px;
}
.version-tag {
display: inline-block;
padding: 3px 12px;
border-radius: 20px;
background: var(--gg-gradient-green);
color: white;
font-size: 13px;
font-weight: 600;
}
.version-date {
font-size: 13px;
color: var(--gg-text-muted);
}
.version-title {
font-size: 18px;
font-weight: 600;
margin: 0 0 16px;
color: var(--gg-text);
}
.change-list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 10px;
}
.change-item {
display: flex;
align-items: flex-start;
gap: 10px;
font-size: 14px;
line-height: 1.5;
}
.change-type {
flex-shrink: 0;
padding: 2px 8px;
border-radius: 4px;
font-size: 11px;
font-weight: 600;
line-height: 1.6;
}
.change-text {
color: var(--gg-text-secondary);
}
</style>