const { uid, str, has } = require('./http') const { isAdmin } = require('./auth') const STATUSES = ['current', 'past', 'draft'] const DEFAULT_BRAND = '卓米会 ZHUOMI' function publicActivity(activity, posters) { const poster = (posters || []) .filter((item) => item.activityId === activity.id && item.enabled && item.image) .sort((a, b) => a.sort - b.sort)[0] return { id: activity.id, title: activity.title, brandName: activity.brandName || DEFAULT_BRAND, brandDesc: activity.brandDesc || '', startAt: activity.startAt || '', address: activity.address || '', latitude: activity.latitude, longitude: activity.longitude, status: activity.status, isCurrent: !!activity.isCurrent, pinned: !!activity.pinned, pinnedAt: activity.pinnedAt || '', theme: activity.theme || 0, cover: activity.cover || '', video: activity.video || '', // Activity cover wins over linked posters so admin “封面图片” updates show immediately. poster: activity.cover || (poster && poster.image) || '', createdAt: activity.createdAt } } function currentActivity(data) { return ( data.activities.find((item) => item.isCurrent && item.status !== 'draft') || data.activities.find((item) => item.status === 'current') || null ) } function byPinnedThenNewest(a, b) { const ap = a.pinned ? 1 : 0 const bp = b.pinned ? 1 : 0 if (ap !== bp) return bp - ap if (ap) return String(b.pinnedAt || '').localeCompare(String(a.pinnedAt || '')) return String(b.createdAt).localeCompare(String(a.createdAt)) } function pastActivities(data) { return data.activities.filter((item) => item.status === 'past').sort(byPinnedThenNewest) } function nextPastTheme(data) { return data.activities.filter((item) => item.status === 'past').length % 2 } function setPinned(activity, pinned) { const now = new Date().toISOString() activity.pinned = !!pinned activity.pinnedAt = pinned ? now : '' activity.updatedAt = now return activity } const PROFILE_FIELDS = ['nickName', 'avatarUrl', 'name', 'phone', 'company', 'position'] function publicProfile(user, data) { const profile = { openid: user.openid } PROFILE_FIELDS.forEach((key) => { profile[key] = user[key] || '' }) profile.isAdmin = isAdmin(user.openid, data) return profile } function coordinate(value) { if (value === '' || value == null) return null const num = Number(value) return Number.isFinite(num) ? num : null } function activityPayload(body, prev, data) { const now = new Date().toISOString() const status = STATUSES.includes(body.status) ? body.status : 'draft' const keep = (key, fallback) => (has(body, key) ? str(body[key]) : prev ? prev[key] || fallback : fallback) let pinned = prev ? !!prev.pinned : false let pinnedAt = prev ? prev.pinnedAt || '' : '' if (status !== 'past') { pinned = false pinnedAt = '' } else if (has(body, 'pinned')) { const requested = body.pinned === true || body.pinned === 'on' || body.pinned === 'true' if (requested !== pinned) pinnedAt = requested ? now : '' pinned = requested } let theme = Number(body.theme) if (!has(body, 'theme') || !Number.isFinite(theme)) { theme = prev ? prev.theme || 0 : status === 'past' ? nextPastTheme(data) : 0 } return { id: prev ? prev.id : uid('a'), title: str(body.title, 60), brandName: str(body.brandName) || DEFAULT_BRAND, brandDesc: str(body.brandDesc, 300), cover: keep('cover', ''), video: keep('video', ''), startAt: str(body.startAt, 32), address: str(body.address, 120), latitude: coordinate(body.latitude), longitude: coordinate(body.longitude), status, isCurrent: !!body.isCurrent, pinned, pinnedAt, theme, createdAt: prev ? prev.createdAt : now, updatedAt: now } } module.exports = { publicActivity, currentActivity, pastActivities, nextPastTheme, setPinned, publicProfile, activityPayload, DEFAULT_BRAND }