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>
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
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,
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user