Files
gamegroup2/frontend/src/stores/poll.ts
T
congsh c5d3ac01ca feat: phase 2 - polls, memories, notifications, stats v0.1.0
- Group polls with option/rollcall modes, edit by creator, auto-settle
- Multimedia memories with upload, preview, inline video playback
- In-app notifications for poll/team/group events
- Points system and group stats dashboard
- Group detail tabs with icons (activity/polls/memories/stats)
- Fix: nginx file upload size, static cache blocking API, timezone, auto-cancel

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-18 18:19:46 +08:00

162 lines
3.9 KiB
TypeScript

import { defineStore } from 'pinia'
import { ref } from 'vue'
import type { Poll, PollOption, PollVote } from '@/types'
import {
listPolls,
getPoll,
getPollOptions,
getPollVotes,
getUserVote,
votePoll,
cancelVote,
settlePoll,
updatePoll as apiUpdatePoll,
addPollOption as apiAddPollOption,
updatePollOption as apiUpdatePollOption,
deletePollOption as apiDeletePollOption,
} from '@/api/polls'
export const usePollStore = defineStore('poll', () => {
// 状态
const activePolls = ref<Poll[]>([])
const settledPolls = ref<Poll[]>([])
const currentPoll = ref<Poll | null>(null)
const currentOptions = ref<PollOption[]>([])
const currentVotes = ref<PollVote[]>([])
const currentUserVote = ref<PollVote | null>(null)
const loading = ref(false)
// 加载群组投票列表
async function loadPolls(groupId: string) {
try {
loading.value = true
const [active, settled] = await Promise.all([
listPolls(groupId, 'active'),
listPolls(groupId, 'settled'),
])
activePolls.value = active
settledPolls.value = settled
} catch (error) {
console.error('加载投票列表失败:', error)
} finally {
loading.value = false
}
}
// 加载投票详情(含选项、投票记录、当前用户投票)
async function loadPollDetail(pollId: string) {
try {
loading.value = true
const [poll, options, votes, userVote] = await Promise.all([
getPoll(pollId),
getPollOptions(pollId),
getPollVotes(pollId),
getUserVote(pollId),
])
currentPoll.value = poll
currentOptions.value = options
currentVotes.value = votes
currentUserVote.value = userVote
} catch (error) {
console.error('加载投票详情失败:', error)
throw error
} finally {
loading.value = false
}
}
// 投票
async function vote(pollId: string, optionId: string) {
try {
await votePoll(pollId, optionId)
// 重新加载详情以获取最新数据
await loadPollDetail(pollId)
} catch (error) {
console.error('投票失败:', error)
throw error
}
}
// 取消投票
async function unvote(pollId: string) {
try {
await cancelVote(pollId)
// 重新加载详情以获取最新数据
await loadPollDetail(pollId)
} catch (error) {
console.error('取消投票失败:', error)
throw error
}
}
// 关闭投票
async function settle(pollId: string) {
try {
await settlePoll(pollId)
await loadPollDetail(pollId)
} catch (error) {
console.error('关闭投票失败:', error)
throw error
}
}
// 编辑投票
async function edit(pollId: string, data: {
title: string
deadline: string
maxParticipants: number | null
options: { id?: string; content: string; hasVotes?: boolean }[]
deletedOptionIds: string[]
}) {
try {
await apiUpdatePoll(pollId, {
title: data.title,
deadline: data.deadline,
maxParticipants: data.maxParticipants,
})
for (const opt of data.options) {
if (opt.id && opt.content) {
await apiUpdatePollOption(opt.id, opt.content)
} else if (!opt.id && opt.content) {
await apiAddPollOption(pollId, opt.content)
}
}
for (const id of data.deletedOptionIds) {
await apiDeletePollOption(id)
}
await loadPollDetail(pollId)
} catch (error) {
console.error('编辑投票失败:', error)
throw error
}
}
// 清除当前投票详情
function clearCurrent() {
currentPoll.value = null
currentOptions.value = []
currentVotes.value = []
currentUserVote.value = null
}
return {
activePolls,
settledPolls,
currentPoll,
currentOptions,
currentVotes,
currentUserVote,
loading,
loadPolls,
loadPollDetail,
vote,
unvote,
settle,
edit,
clearCurrent,
}
})