实现网站游戏评分与评价 (#561)
Project CI / AI game creator shell Rust crates (push) Successful in 1m43s
Project CI / AI game creator shell Rust lane 2/2 (push) Failing after 2m7s
Project CI / AI game creator shell Rust smoke (push) Successful in 2m55s
Project CI / AI game creator shell Rust lane 1/2 (push) Failing after 3m23s
Project CI / Frontend tests (push) Successful in 3m3s
Project CI / Repository checks (push) Successful in 3m42s
Project CI / AI game creator shell web tests (push) Successful in 2m3s
Project CI / Backend tests (push) Successful in 6m19s
Project CI / Native shell tests (push) Successful in 8m7s
Project CI / AI game creator shell Rust crates (push) Successful in 1m43s
Project CI / AI game creator shell Rust lane 2/2 (push) Failing after 2m7s
Project CI / AI game creator shell Rust smoke (push) Successful in 2m55s
Project CI / AI game creator shell Rust lane 1/2 (push) Failing after 3m23s
Project CI / Frontend tests (push) Successful in 3m3s
Project CI / Repository checks (push) Successful in 3m42s
Project CI / AI game creator shell web tests (push) Successful in 2m3s
Project CI / Backend tests (push) Successful in 6m19s
Project CI / Native shell tests (push) Successful in 8m7s
公开游戏详情页新增评分与评价:登录用户可提交并修改自己对每款游戏的唯一一条 1–10 分评价,评论可空且最多 4000 个 Unicode 码点;游客可分页浏览评价并查看平均分与评分人数。 - 新增私有评价表及共享 DTO/API,事务内校验游戏公开可见性、保证唯一性,并计算分页与全量评分统计;下架或封禁后关闭读写,重新公开及更新版本保留评价。 - 详情页支持编辑预填、取消、提交期间冻结输入、失败保留草稿,以及保存、翻页和账号/游戏切换时的旧响应隔离;复用现有认证与公共组件。 - 同步主规范、里程碑、实施计划、生成绑定、表目录和验收脚本。不扩展 AGC、外部 API、评论审核或评分缓存。 验证: - 本轮审查复跑前端定向测试 40 项、评价领域测试 2 项,均通过。 - 网站 typecheck、Rust/TypeScript DTO 对齐、SpacetimeDB schema、文档索引、编码与 diff 检查通过。 - 实施文档另记录本地隔离数据库/API 49 项及桌面/移动视口浏览器 smoke 通过;本轮审查未重跑这些运行时验收,也未运行完整测试套件。 发布说明:新增 SpacetimeDB 表,部署时需同步 module 与 API。尚未部署 dev/production,待用户验收。 Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/561 Co-authored-by: Linghong <ink29535@proton.me> Co-committed-by: Linghong <ink29535@proton.me>
This commit was merged in pull request #561.
This commit is contained in:
@@ -31,6 +31,7 @@ import { AdminEditorShowcaseReviewPage } from '../pages/AdminEditorShowcaseRevie
|
||||
import { AdminErrorReportsPage } from '../pages/AdminErrorReportsPage';
|
||||
import { AdminGameDistributionReviewPage } from '../pages/AdminGameDistributionReviewPage';
|
||||
import { AdminGameManagementPage } from '../pages/AdminGameManagementPage';
|
||||
import { AdminGameReviewsPage } from '../pages/AdminGameReviewsPage';
|
||||
import { AdminGrayReleaseConfigPage } from '../pages/AdminGrayReleaseConfigPage';
|
||||
import { AdminInviteCodePage } from '../pages/AdminInviteCodePage';
|
||||
import { AdminLoginPage } from '../pages/AdminLoginPage';
|
||||
@@ -141,7 +142,7 @@ export function AdminApp() {
|
||||
|
||||
setRouteId(nextRouteId);
|
||||
const nextHash = routeHash(nextRouteId);
|
||||
if (window.location.hash !== nextHash) {
|
||||
if ((window.location.hash.split('?')[0] ?? '').toLowerCase() !== nextHash) {
|
||||
window.history.replaceState(null, '', nextHash);
|
||||
}
|
||||
}, [accessibleRoutes, admin, routeId, status]);
|
||||
@@ -325,6 +326,15 @@ export function AdminApp() {
|
||||
) : null}
|
||||
{activeRouteId === 'game-management' ? (
|
||||
<AdminGameManagementPage
|
||||
token={token}
|
||||
canManageReviews={accessibleRoutes.some(
|
||||
(route) => route.id === 'game-reviews',
|
||||
)}
|
||||
onUnauthorized={handleUnauthorized}
|
||||
/>
|
||||
) : null}
|
||||
{activeRouteId === 'game-reviews' ? (
|
||||
<AdminGameReviewsPage
|
||||
token={token}
|
||||
onUnauthorized={handleUnauthorized}
|
||||
/>
|
||||
|
||||
@@ -55,6 +55,7 @@ const routeIcons = {
|
||||
'editor-showcase': Star,
|
||||
'game-distribution': Gamepad2,
|
||||
'game-management': Swords,
|
||||
'game-reviews': Star,
|
||||
'editor-assets': Images,
|
||||
'project-snapshots': FolderArchive,
|
||||
accounts: Users,
|
||||
|
||||
@@ -8,6 +8,22 @@ import {
|
||||
routeHash,
|
||||
} from './adminRoutes';
|
||||
|
||||
test('游戏评价路由独立授权并支持游戏参数', () => {
|
||||
expect(resolveAdminRoute('#game-reviews?gameId=game_1')).toBe('game-reviews');
|
||||
expect(
|
||||
getAccessibleAdminRoutes({
|
||||
accountRole: 'member',
|
||||
tabPermissions: ['game-reviews'],
|
||||
}).map((route) => route.id),
|
||||
).toEqual(['game-reviews']);
|
||||
expect(
|
||||
getAccessibleAdminRoutes({
|
||||
accountRole: 'member',
|
||||
tabPermissions: ['game-management'],
|
||||
}).some((route) => route.id === 'game-reviews'),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test('客户端埋点路由遵守成员页签权限', () => {
|
||||
expect(resolveAdminRoute('#agc-tracking')).toBe('agc-tracking');
|
||||
expect(
|
||||
|
||||
@@ -18,6 +18,7 @@ export type AdminRouteId =
|
||||
| 'editor-showcase'
|
||||
| 'game-distribution'
|
||||
| 'game-management'
|
||||
| 'game-reviews'
|
||||
| 'editor-assets'
|
||||
| 'project-snapshots'
|
||||
| 'agc-models'
|
||||
@@ -62,6 +63,7 @@ export const adminRoutes: AdminRouteDefinition[] = [
|
||||
{ id: 'editor-showcase', label: '精选审核', hash: '#editor-showcase' },
|
||||
{ id: 'game-distribution', label: '游戏审核', hash: '#game-distribution' },
|
||||
{ id: 'game-management', label: '游戏管理', hash: '#game-management' },
|
||||
{ id: 'game-reviews', label: '游戏评价', hash: '#game-reviews' },
|
||||
{ id: 'editor-assets', label: '素材查询', hash: '#editor-assets' },
|
||||
{ id: 'project-snapshots', label: '项目工程', hash: '#project-snapshots' },
|
||||
{ id: 'accounts', label: '账号管理', hash: '#accounts', ownerOnly: true },
|
||||
|
||||
Reference in New Issue
Block a user