【XIUNOX插件】帖子投票 v1.0.5

管理员组

xnx_poll 帖子投票插件

为帖子添加内嵌投票功能。支持单选/多选、倒计时、实时结果展示、用户组权限控制,htmx 无刷新投票体验。

功能

  • 发帖集成:在发布页右侧栏添加投票配置卡片(与「引用帖子」卡片同款样式)
- 开启开关、投票标题、2-20 个动态选项

- 投票类型:单选 / 多选(最多可选数) - 持续时间(小时,0=永久) - 结果可见性:投票后立即可见 / 结束后可见 - 允许修改投票、允许游客、允许参与的用户组(多选)

  • 帖子展示:在帖子正文下方显示投票卡片
- 进度条可视化(占比 + 票数)

- 倒计时实时刷新(到期自动切换为结束态) - 已投票用户高亮已选项 - 总票数 + 参与人数统计 - 作者可提前结束、管理员可强制结束

  • htmx 无刷新投票:fetch + FormData 提交,实时返回新卡片 + toast 提示
  • 管理功能
- 全局开关、允许发起的用户组、选项数范围、默认时长、允许游客、允许改票

- 后台投票列表(按状态 tab 筛选:全部/进行中/已结束/已过期) - 查看参与记录(display_name + 所选项 + 投票时间) - CSV 导出 - 强制结束、删除(含级联清理)

  • 多语言:zh-cn / zh-tw / en-us 三语言同步
  • 级联清理:删帖自动级联清理投票主表/选项/记录

安装

  1. 复制 xnx_poll 目录到 plugin/
  2. 后台 → 插件管理 → 安装并启用
  3. 后台 → 投票设置 → 配置允许发起的用户组
  4. 发帖时勾选「开启投票」配置参数即可

路由

| 路由名 | URL | 说明 | |---|---|---| | poll_vote | ?poll-vote.htm | 投票提交(POST) | | poll_end | ?poll-end-{poll_id}.htm | 提前结束(POST) | | poll_refresh | ?poll-refresh-{poll_id}.htm | 刷新卡片(GET) | | poll_admin | ?plugin-poll_admin.htm | 后台投票管理(仅管理员) |

文件结构

plugin/xnx_poll/
├── conf.json
├── install.php / uninstall.php / upgrade.php
├── setting.php + view/htm/setting.htm
├── model/PollService.php
├── route/
│   ├── poll.php            # 前台投票
│   └── admin_poll.php      # 后台管理
├── hook/
│   ├── model_inc_file.php
│   ├── model_route_table_end.php
│   ├── index_route_case_end.php
│   ├── admin_index_route_case_end.php
│   ├── thread_create_thread_end.php      # 发帖成功后创建投票
│   ├── model_thread_delete_end.php       # 删帖级联清理
│   ├── post_ref_thread_after.htm         # 桌面端发布页配置
│   ├── post_ref_thread_after_mobile.htm  # 手机端发布页配置
│   ├── post_js.htm                       # 加载 poll_post.js
│   ├── thread_message_after.htm          # 帖子正文下方投票卡
│   ├── footer_js_after.htm               # 加载 poll.js
│   ├── lang_zh_cn_bbs.php
│   ├── lang_zh_tw_bbs.php
│   └── lang_en_us_bbs.php
├── view/htm/
│   ├── poll_card.htm       # 投票卡模板(前台 + 路由共用)
│   ├── poll_admin.htm      # 后台管理页
│   └── setting.htm         # 后台设置页
├── static/js/
│   ├── poll_post.js        # 发布页交互
│   └── poll.js             # 投票卡交互(投票/结束/倒计时)
└── lang/
    ├── zh-cn.php
    ├── zh-tw.php
    └── en-us.php

数据库表

xnx_poll(主表)

| 字段 | 类型 | 说明 | |---|---|---| | id | int UNSIGNED PK | 投票 ID | | tid | int UNSIGNED | 帖子 ID | | uid | int UNSIGNED | 发起人 | | title | varchar(255) | 投票问题 | | type | tinyint | 0=单选 1=多选 | | max_choices | tinyint | 多选时最多可选数 | | duration_hours | int | 时长(0=永久) | | expire_at | int | 到期时间戳(0=永久) | | result_visibility | tinyint | 0=投票后 1=结束后 | | allow_change | tinyint | 是否允许修改 | | allow_guests | tinyint | 是否允许游客 | | allow_groups | varchar(255) | 允许的用户组(逗号分隔) | | status | tinyint | 0=进行中 1=手动结束 2=过期 3=已删 | | participants_count | int | 参与人数(原子计数) | | create_time | int | 创建时间 | | end_time | int | 结束时间 |

xnx_poll_option(选项表)

| 字段 | 类型 | 说明 | |---|---|---| | id | int UNSIGNED PK | 选项 ID | | poll_id | int | 投票 ID | | label | varchar(255) | 选项内容 | | sort | int | 排序 | | votes_count | int | 票数(原子计数) |

xnx_poll_vote(投票记录表)

| 字段 | 类型 | 说明 | |---|---|---| | id | int UNSIGNED PK | 记录 ID | | poll_id | int | 投票 ID | | option_id | int | 所选项 ID | | uid | int UNSIGNED | 投票人 | | vote_time | int | 投票时间 | | UNIQUE KEY | (poll_id, option_id, uid) | 同一用户对同一选项只能投一次 |

关键技术点

  • 版本号缓存xnx_poll_poll_{id}_v{v} + xnx_poll_poll_v_{id} 双键机制避免长键哈希
  • 原子计数UPDATE ... SET votes_count = votes_count + 1 无并发问题
  • CAS 防并发结束UPDATE xnx_poll SET status=1 WHERE id=? AND status=0 防止重复结束
  • HTMX 兼容:所有 hook 用 if 包裹(不用 return;,hook 内 return 会从宿主函数退出)
  • htmx 4 事件名:冒号分隔格式(htmx:config:request 等)
  • 显示名:用 user_find_by_uids / user_read_cachedisplay_name,不用 db_find('user')
  • CSRF:所有 POST 表单走 CsrfService::input() + CsrfService::check()
  • 多语言:双写 lang/.php + hook/lang__bbs.php(前台实际读 hook)
  • 卡片样式:统一 x-card(无 border + 阴影 + dark mode border)

已知限制

  • 倒计时依赖 JS 在前台运行(无 cron 后台扫描过期)
  • 删除投票仅清理数据库与缓存,通过消息中心通知参与者
  • 游客投票需开启 allow_guests 且未登录态可触发(按 IP 记录,故一行仅一票)

测试要点

  • 后台启用插件、配置用户组权限
  • 发帖创建单选/多选投票
  • 已登录用户参与投票(已投提示拦截)
  • 游客在开启游客权限时参与(按 IP 记录)
  • 倒计时到期自动刷新卡片
  • 作者提前结束、管理员后台强制结束
  • 后台列表筛选(tab 切换)、查看记录、CSV 导出、删除
  • 删主帖后级联清理(数据库 + 缓存)

版本 1.0.5 | 兼容 Xiuno 1.1+



版本:v1.0.5
适用版本:1.1
开发者:贰先生

请登录后查看此内容
最新回复

请先登录后再回复 登录