feat: SSR 投票帖发帖与详情投票卡

compose 支持 poll 类型与选项,详情可投票/查看结果/结束。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-30 01:18:58 +08:00
parent 7f21ffb14e
commit 4f93397ef3
10 changed files with 403 additions and 43 deletions

View File

@@ -96,6 +96,34 @@ func ParsePollOptionsJSON(raw string) ([]PollOptionInput, bool, int, *time.Time,
return payload.Options, payload.Multi, payload.MaxChoices, endsAt, nil
}
// BuildPollOptionsJSON 由 SSR 表单字段组装 poll_options JSON
func BuildPollOptionsJSON(multi bool, maxChoices int, endsAt, optionsText string) (string, error) {
var opts []PollOptionInput
for _, line := range strings.Split(optionsText, "\n") {
text := strings.TrimSpace(line)
if text == "" {
continue
}
opts = append(opts, PollOptionInput{Text: text})
}
if len(opts) < 2 || len(opts) > 10 {
return "", errors.New("投票选项需 2-10 个(每行一项)")
}
payload := struct {
Multi bool `json:"multi"`
MaxChoices int `json:"max_choices"`
EndsAt string `json:"ends_at,omitempty"`
Options []PollOptionInput `json:"options"`
}{
Multi: multi, MaxChoices: maxChoices, EndsAt: strings.TrimSpace(endsAt), Options: opts,
}
b, err := json.Marshal(payload)
if err != nil {
return "", err
}
return string(b), nil
}
func parsePollEndsAt(raw string) (*time.Time, error) {
raw = strings.TrimSpace(raw)
if raw == "" {
@@ -107,7 +135,9 @@ func parsePollEndsAt(raw string) (*time.Time, error) {
time.RFC3339Nano,
time.RFC3339,
"2006-01-02T15:04:05",
"2006-01-02T15:04",
"2006-01-02 15:04:05",
"2006-01-02 15:04",
} {
if t, err := time.Parse(layout, raw); err == nil {
parsed = t