From e003db40641845a3bec85131554962ec44ca6a2c Mon Sep 17 00:00:00 2001 From: 16th-admin Date: Sat, 29 Aug 2026 20:40:40 +0800 Subject: [PATCH 01/10] feat: add democracy wall MVP --- scripts/tests/democracy-wall.spec.ts | 141 +++++++ scripts/tests/navigation.spec.ts | 2 +- .../democracy/AnonymousVoteCard.vue | 267 +++++++++++++ .../democracy/DemocracyEntryCard.vue | 215 ++++++++++ src/components/utils/Footer.vue | 16 + src/i18n/de.ts | 51 ++- src/i18n/en.ts | 51 +++ src/i18n/fr.ts | 51 ++- src/i18n/ja.ts | 48 ++- src/i18n/zh.ts | 53 ++- src/router/index.ts | 7 + src/services/democracyWall.ts | 109 +++++ src/views/DemocracyWall.vue | 377 ++++++++++++++++++ 13 files changed, 1380 insertions(+), 8 deletions(-) create mode 100644 scripts/tests/democracy-wall.spec.ts create mode 100644 src/components/democracy/AnonymousVoteCard.vue create mode 100644 src/components/democracy/DemocracyEntryCard.vue create mode 100644 src/services/democracyWall.ts create mode 100644 src/views/DemocracyWall.vue diff --git a/scripts/tests/democracy-wall.spec.ts b/scripts/tests/democracy-wall.spec.ts new file mode 100644 index 00000000..bc255c3e --- /dev/null +++ b/scripts/tests/democracy-wall.spec.ts @@ -0,0 +1,141 @@ +import { test, expect } from './fixtures' +import { injectLoginStateWithoutNavigation, waitForPageReady } from './test-helpers' + +const statistic = { + ID: '6666ff550b5f97d6e49d12d7', + Activities: [ + { + ActivityID: '7777ff550b5f97d6e49d12d7', + Avails: [0, 1], + Counters: [0, 0], + Expiration: '2026-09-30T00:00:00Z', + Finished: false, + Gains: [], + LastModified: '2026-08-29T00:00:00Z', + }, + ], +} + +const entriesResponse = { + Status: 200, + Message: '', + Data: { + $values: [ + { + $type: 'Summary', + ID: '66a84559744ed757b46f8917', + Tags: ['民主墙', '公开卷宗'], + Type: 0, + User: { + ID: '6666ff550b5f97d6e49d12d7', + Nickname: '调查员', + Avatar: 0, + AvatarRegion: 0, + Signature: '', + Decoration: 0, + Verification: 'Editor', + }, + Image: 1, + ImageRegion: 1, + Price: 0, + Stars: 12, + Editor: null, + Visits: 88, + ModelID: null, + Remixes: 0, + Subject: '关于公开指控处理流程的卷宗', + Version: 1, + Category: 'Discussion', + Comments: 7, + Language: 'Chinese', + Supports: 0, + Coauthors: [], + Popularity: 0, + UpdateDate: 0, + Visibility: 0, + SortingDate: 0, + CreationDate: 0, + Multilingual: false, + Description: ['公开事实、规则依据和处理记录。'], + }, + ], + }, +} + +const activitiesResponse = { + Status: 200, + Message: '', + Data: { + Statistic: statistic, + Activities: [ + { + Contents: [{ Chinese: '对条例模糊部分进行社区决议。' }], + FinishDate: '2026-09-30T00:00:00Z', + ID: '7777ff550b5f97d6e49d12d7', + InterfaceModel: 'Vote-Single', + InternalLink: null, + IsAttendance: false, + IsDaily: false, + IsDevelopment: false, + IsTutorial: false, + Items: [ + { + Bonuses: {}, + Condition: '', + Counter: 20, + Counters: {}, + Description: '同意修订', + Local: false, + }, + { + Bonuses: {}, + Condition: '', + Counter: 10, + Counters: {}, + Description: '维持原文', + Local: false, + }, + ], + Languages: [], + Platforms: [], + Priority: 1, + StartDate: '2026-08-01T00:00:00Z', + Subject: { Chinese: '条例修订投票' }, + TargetLink: {}, + TargetText: {}, + Version: 1, + }, + ], + }, +} + +test.describe('民主墙', () => { + test.beforeEach(async ({ page }) => { + await injectLoginStateWithoutNavigation(page) + await page.route('**/api/Contents/QueryExperiments', async (route) => { + await route.fulfill({ + contentType: 'application/json', + body: JSON.stringify(entriesResponse), + }) + }) + await page.route('**/api/Users/Authenticate', async (route) => { + await route.fulfill({ + contentType: 'application/json', + body: JSON.stringify(activitiesResponse), + }) + }) + }) + + test('展示卷宗、身份标签和现有匿名投票', async ({ page }) => { + await page.goto('/#/d') + await waitForPageReady(page) + + await expect(page.getByRole('heading', { name: '民主墙' })).toBeVisible() + await expect(page.getByText('关于公开指控处理流程的卷宗')).toBeVisible() + await expect(page.getByText('Editor')).toBeVisible() + + await page.getByText('匿名投票 1', { exact: true }).click() + await expect(page.getByText('条例修订投票')).toBeVisible() + await expect(page.getByRole('button', { name: /同意修订/ })).toBeVisible() + }) +}) diff --git a/scripts/tests/navigation.spec.ts b/scripts/tests/navigation.spec.ts index 53f64f6d..2fcb4df1 100644 --- a/scripts/tests/navigation.spec.ts +++ b/scripts/tests/navigation.spec.ts @@ -25,6 +25,7 @@ test.describe('路由与导航', () => { { path: '/', name: '首页' }, { path: '/b', name: '黑洞' }, { path: '/n', name: '通知' }, + { path: '/d', name: '民主墙' }, { path: '/p/Discussion/66a84559744ed757b46f8917', name: '作品详情' }, { path: '/c/Discussion/66a84559744ed757b46f8917/test', name: '评论' }, { path: '/u/6666ff550b5f97d6e49d12d7', name: '用户资料' }, @@ -80,5 +81,4 @@ test.describe('路由与导航', () => { // 应回到首页 await assertNoWhiteScreen(page) }) - }) diff --git a/src/components/democracy/AnonymousVoteCard.vue b/src/components/democracy/AnonymousVoteCard.vue new file mode 100644 index 00000000..688f835c --- /dev/null +++ b/src/components/democracy/AnonymousVoteCard.vue @@ -0,0 +1,267 @@ + + + + + diff --git a/src/components/democracy/DemocracyEntryCard.vue b/src/components/democracy/DemocracyEntryCard.vue new file mode 100644 index 00000000..aea6214b --- /dev/null +++ b/src/components/democracy/DemocracyEntryCard.vue @@ -0,0 +1,215 @@ + + + + + diff --git a/src/components/utils/Footer.vue b/src/components/utils/Footer.vue index 92b82ece..34d55edd 100644 --- a/src/components/utils/Footer.vue +++ b/src/components/utils/Footer.vue @@ -33,6 +33,22 @@ {{ $t('footer.blackHole') }} + + + + + {{ $t('footer.democracy') }} +