c5d3ac01ca
- 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>
162 lines
3.9 KiB
TypeScript
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,
|
|
}
|
|
})
|