Files
leaudit-platform-frontend/auth_doc/交叉评查接口文档(1).md
T
LiangShiyong d8bba607fc fix: 1. 重新对齐交叉评查的接口。
2. 确认评查结果的接口对接。 3. 新增评查点适配省级创建的响应数据和其他用户创建的单条响应数据。  4. 文档列表的文档类型通过通用的查询接口查询文档类型。优化加载状态的时机。
2025-12-11 11:16:50 +08:00

28 KiB
Raw Blame History

交叉评查接口文档

本文档描述交叉评查模块的所有API接口,供前端直接对接使用。

基础信息

  • 基础路径: /api/v2/cross_review (推荐)
  • 备用路径: /admin/v2/cross_review (兼容,功能相同)
  • 认证方式: JWT Token (Header: Authorization: Bearer <token>)
  • Content-Type: application/json

说明: /api/v2/admin/v2 两个前缀指向同一套接口,功能完全相同。建议前端统一使用 /api/v2/cross_review


接口总览

提案管理

方法 路径 接口名称 权限
POST /proposals 发起评分提案 cross_review:proposal:create
DELETE /proposals/{proposal_id} 撤销评分提案 cross_review:proposal:delete
POST /proposals/{proposal_id}/votes 对提案投票 cross_review:proposal:vote
POST /proposals/details 获取提案列表及详情 cross_review:proposal:read
POST /proposals/document 获取指定文档的提案列表 cross_review:proposal:read
POST /proposals/document/check_pending_votes 检查未投票用户 cross_review:task:read

任务管理

方法 路径 接口名称 权限
POST /tasks/user_tasks 获取用户参与的任务列表 cross_review:task:read
GET /tasks/{task_id}/progress 获取评查任务进度 cross_review:progress:view
POST /tasks/{task_id}/documents 获取任务下文档列表 cross_review:task:read
POST /tasks/{task_id}/documents/{document_id}/complete 确认完成文档评查 cross_review:document:complete

接口详细说明


1. 发起评分提案

POST /api/v2/cross_review/proposals

为某个评查结果创建一个新的评分提案(加分或扣分)。

权限: cross_review:proposal:create

请求参数

字段 类型 必填 说明
document_id int 文档ID
evaluation_point_id int 评查点ID
proposed_score float 建议加/减分数(正数加分,负数扣分,不能为0)
reason string 理由说明(不能为空)
proposer_id int 提案人ID
evaluation_result_id int 评查结果ID(必填!)

请求示例

{
  "document_id": 123,
  "evaluation_point_id": 456,
  "proposed_score": -5,
  "reason": "该评查点存在明显问题,应扣5分",
  "proposer_id": 1,
  "evaluation_result_id": 789
}

业务逻辑

  1. 权限验证

    • 验证用户是否有权限访问该文档
    • 验证 evaluation_result_id 是否真正属于 document_id(防止IDOR攻击)
  2. 任务参与者验证

    • 查找文档关联的最新交叉评查任务
    • 验证提案人是否是任务的参与者(在 user_ids 中)
  3. 重复提案检查

    • 同一用户不能对同一评查点重复创建提案
  4. 分数校验

    • 不能创建 0 分的提案
    • 当前分数为 0 时,不能发起扣分提案(proposed_score < 0
    • 当前分数已满分时,不能发起加分提案(proposed_score > 0
  5. 自动投票

    • 创建提案后,系统自动为提案人创建一条"同意"的投票记录
  6. 状态检查

    • 检查是否达到通过/否决条件,自动更新提案状态

响应示例

成功 (201):

{
  "code": 0,
  "success": true,
  "message": "评分提案创建成功",
  "proposal": {
    "id": 1,
    "document_id": 123,
    "evaluation_point_id": 456,
    "proposed_score": -5,
    "reason": "该评查点存在明显问题,应扣5分",
    "proposer_id": 1,
    "status": "pending",
    "evaluation_result_id": 789,
    "created_at": "2024-01-01T10:00:00"
  }
}

错误码

状态码 错误信息 说明
400 评查结果ID不能为空 evaluation_result_id 未提供
400 不能创建0分的提案 proposed_score 为 0
400 当前分数为0,不能再发起扣分提案 当前评查结果分数已经是0
400 当前已满分,不能再加分 当前评查结果已达到满分
400 您已经为该评查点创建过提案 重复创建提案
400 文档未分配任何评查任务 文档不在交叉评查任务中
400 用户无权为该文档创建提案 用户不是任务参与者
403 无权访问此文档 文档权限验证失败
403 评查结果与文档不匹配 IDOR攻击防护触发
404 评查结果不存在 evaluation_result_id 无效

2. 对提案投票

POST /api/v2/cross_review/proposals/{proposal_id}/votes

对指定的评分提案进行投票(同意/反对/取消)。

权限: cross_review:proposal:vote

路径参数

参数 类型 说明
proposal_id int 提案ID(必须大于0

请求参数

字段 类型 必填 说明
vote_type string 投票类型:agree(同意) / disagree(反对) / cancel(取消投票)
voter_id int 投票人的用户ID

请求示例

{
  "vote_type": "agree",
  "voter_id": 2
}

业务逻辑

  1. 提案状态检查

    • 提案必须存在且未被删除
    • 只能对 pending 状态的提案投票
    • approvedrejected 的提案无法投票
  2. 任务参与者验证

    • 根据提案关联的文档找到对应任务
    • 验证投票人是否是任务参与者
  3. 分数校验(投票前再次校验)

    • 不能投 0 分的提案
    • 当前分数为 0 时,不能投赞成扣分提案
    • 当前已满分时,不能投赞成加分提案
  4. 投票处理

    • 新投票: 创建新的投票记录
    • 更新投票: 如果已投票,更新投票类型
    • 恢复投票: 如果之前取消过投票,恢复并更新
    • 取消投票: 软删除投票记录(设置 deleted_at
  5. 自动状态更新

    • 投票后自动检查提案是否达到通过/否决条件
    • 通过条件: 同意票数 >= (参与人数/2 + 1)
    • 否决条件: 反对票数 >= (参与人数/2 + 1) 或 剩余票数不足以达到通过条件
    • 提案通过后自动更新评查结果的 final_score
  6. 文档完成检查

    • 提案状态变更后,检查文档下所有提案是否都已完成
    • 如果都完成,自动将文档标记为已完成(audit_status=1

响应示例

成功 (201):

{
  "code": 0,
  "success": true,
  "message": "投票成功",
  "proposal_status": "approved"
}

取消投票成功:

{
  "code": 0,
  "success": true,
  "message": "投票已撤销",
  "proposal_status": "pending"
}

错误码

状态码 错误信息 说明
400 提案不存在或已被删除 无效的提案ID
400 提案状态为 approved/rejected,无法投票 提案已结束
400 不能投0分的提案 提案分数为0
400 当前分数为0,不能再扣分 评查结果分数已是0
400 当前已满分,不能再加分 评查结果已满分
400 用户无权对该提案投票 用户不是任务参与者

3. 撤销评分提案

DELETE /api/v2/cross_review/proposals/{proposal_id}

撤销一个评分提案。仅提案人本人可以撤销。

权限: cross_review:proposal:delete

路径参数

参数 类型 说明
proposal_id int 提案ID(必须大于0

请求体

无需请求体。

业务逻辑

  1. 提案存在性验证

    • 验证提案存在且未被删除
  2. 权限验证

    • 只有提案人本人才能撤销自己的提案
  3. 状态验证

    • 只能撤销 pending 状态的提案
    • approvedrejected 的提案无法撤销
  4. 软删除

    • 将提案的 deleted_at 设置为当前时间
    • 同时软删除所有关联的投票记录

响应示例

成功 (200):

{
  "code": 0,
  "success": true,
  "message": "提案已成功撤销"
}

错误码

状态码 错误信息 说明
400 提案不存在 无效的提案ID
400 提案状态为 approved/rejected,无法撤销 提案已结束
403 只有提案人才能撤销自己的提案 权限不足

4. 获取提案列表及详情

POST /api/v2/cross_review/proposals/details

获取当前用户需要处理的所有待投票提案列表(排除自己创建的提案和已投票的提案)。

权限: cross_review:proposal:read

请求参数

字段 类型 必填 默认值 说明
document_id int null 按文档ID过滤(不传则查所有)
page int 1 页码(从1开始)
page_size int 20 每页数量

请求示例

{
  "document_id": 123,
  "page": 1,
  "page_size": 20
}

业务逻辑

  1. 任务范围确定

    • 查找当前用户参与的所有交叉评查任务
    • 获取这些任务下的所有文档ID
  2. 提案过滤

    • 只返回 pending 状态的提案
    • 排除当前用户自己创建的提案
    • 如果指定了 document_id,只返回该文档的提案
  3. 关联信息查询

    • 评查点名称
    • 提案人昵称
    • 所有投票人及投票类型
    • 同意者列表、反对者列表
    • 待投票者列表
    • 发现问题(evaluation_result 的 message
  4. 投票状态判断

    • 判断当前用户是否已对该提案投票
    • 返回 can_vote 字段

响应示例

{
  "data": [
    {
      "proposal_id": 1,
      "evaluation_point_name": "当事人签名检查",
      "proposed_score": -5,
      "reason": "缺少当事人签名",
      "proposer": "张三",
      "votes": [
        {"voter": "张三", "vote_type": "agree"},
        {"voter": "李四", "vote_type": "disagree"}
      ],
      "agree_voters": ["张三"],
      "disagree_voters": ["李四"],
      "can_vote": true,
      "problem_message": "文档中未找到当事人签名",
      "pending_voters": ["王五", "赵六"],
      "status": "pending"
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 20,
    "total": 5,
    "total_pages": 1
  }
}

返回字段说明

字段 类型 说明
proposal_id int 提案ID
evaluation_point_name string 评查点名称
proposed_score float 提议的加/减分数
reason string 提案理由
proposer string 提案人昵称
votes array 所有投票记录(含投票人和投票类型)
agree_voters array 同意者昵称列表
disagree_voters array 反对者昵称列表
can_vote boolean 当前用户是否可以投票
problem_message string 评查结果发现的问题描述
pending_voters array 待投票者昵称列表
status string 提案状态(pending/approved/rejected

5. 获取指定文档的提案列表

POST /api/v2/cross_review/proposals/document

获取指定文档下的所有评分提案及其详细信息(包含所有状态的提案)。

权限: cross_review:proposal:read

请求参数

字段 类型 必填 默认值 说明
document_id int - 文档ID
page int 1 页码(从1开始)
page_size int 10 每页数量

请求示例

{
  "document_id": 123,
  "page": 1,
  "page_size": 10
}

业务逻辑

  1. 权限验证

    • 验证当前用户是否有权限访问该文档
  2. 提案查询

    • 获取该文档下所有未删除的提案(包括 pending/approved/rejected
  3. 关联信息查询

    • 评查点名称
    • 提案人昵称和ID
    • 所有投票人及投票类型
    • 同意者列表、反对者列表
    • 待投票者列表
    • 发现问题
    • 创建时间
  4. 投票状态判断

    • 判断当前用户是否可以投票
    • 条件:未投票 + 不是提案人 + 是任务参与者

响应示例

{
  "data": [
    {
      "proposal_id": 1,
      "evaluation_point_name": "当事人签名检查",
      "proposed_score": -5,
      "reason": "缺少当事人签名",
      "proposer": "张三",
      "proposer_id": 1,
      "votes": [
        {"voter": "张三", "vote_type": "agree"},
        {"voter": "李四", "vote_type": "agree"},
        {"voter": "王五", "vote_type": "agree"}
      ],
      "agree_voters": ["张三", "李四", "王五"],
      "disagree_voters": [],
      "problem_message": "文档中未找到当事人签名",
      "pending_voters": [],
      "created_at": "2024-01-01 10:00:00",
      "can_vote": false,
      "status": "approved"
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 10,
    "total": 3,
    "total_pages": 1
  }
}

返回字段说明

字段 类型 说明
proposal_id int 提案ID
evaluation_point_name string 评查点名称
proposed_score float 提议的加/减分数
reason string 提案理由
proposer string 提案人昵称
proposer_id int 提案人ID
votes array 所有投票记录
agree_voters array 同意者昵称列表
disagree_voters array 反对者昵称列表
problem_message string 评查结果发现的问题描述
pending_voters array 待投票者昵称列表
created_at string 创建时间(格式:yyyy-MM-dd HH:mm:ss
can_vote boolean 当前用户是否可以投票
status string 提案状态

错误码

状态码 错误信息 说明
403 无权访问此文档 用户无权限访问该文档

6. 检查未投票用户

POST /api/v2/cross_review/proposals/document/check_pending_votes

检查指定文档下所有提案是否存在未投票的用户。仅任务创建人可调用

权限: cross_review:task:read

请求参数

字段 类型 必填 说明
document_id int 文档ID

请求示例

{
  "document_id": 123
}

业务逻辑

  1. 任务查找

    • 根据文档ID查找关联的最新任务
  2. 权限验证

    • 验证当前用户是否是任务的创建人(assigner_id
    • 只有任务创建人才能调用此接口
  3. 投票统计

    • 查找文档下所有提案
    • 统计每个提案的已投票用户
    • 计算待投票用户(任务参与者 - 已投票用户 - 提案人)

响应示例

有未投票用户:

{
  "has_pending_votes": true,
  "pending_proposals": [
    {
      "proposal_id": 1,
      "pending_voters_num": 2,
      "pending_voters": ["王五", "赵六"],
      "evaluation_point_name": "当事人签名检查"
    },
    {
      "proposal_id": 2,
      "pending_voters_num": 1,
      "pending_voters": ["赵六"],
      "evaluation_point_name": "日期格式检查"
    }
  ]
}

无未投票用户:

{
  "has_pending_votes": false,
  "pending_proposals": []
}

错误码

状态码 错误信息 说明
400 未找到该文档的任务 文档不在任何任务中
403 只有任务创建人可以执行此操作 当前用户不是任务创建人

7. 获取用户参与的任务列表

POST /api/v2/cross_review/tasks/user_tasks

获取当前用户参与的所有交叉评查任务列表(分页)。

权限: cross_review:task:read

请求参数

字段 类型 必填 默认值 说明
page int 1 页码(从1开始)
page_size int 10 每页数量

请求示例

{
  "page": 1,
  "page_size": 10
}

业务逻辑

  1. 任务查询

    • 查询当前用户参与的所有任务(用户ID在任务的 user_ids 数组中)
  2. 进度计算

    • 统计每个任务下的文档总数
    • 统计已完成文档数(cross_task_document_mapping.audit_status = 1
    • 计算完成百分比
  3. 文档类型解析

    • doc_type 代码转换为可读名称
  4. 地区信息聚合

    • 获取任务参与者的地区列表

响应示例

{
  "total": 5,
  "page": 1,
  "page_size": 10,
  "items": [
    {
      "task_id": 1,
      "task_name": "2024年度交叉评查任务",
      "task_status": "in_progress",
      "doc_type": "行政处罚",
      "task_type": "CITY",
      "task_created_at": "2024-01-01T10:00:00",
      "progress": 75,
      "total_documents": 20,
      "evaluation_region": ["梅州", "云浮"]
    },
    {
      "task_id": 2,
      "task_name": "2024年Q1评查",
      "task_status": "completed",
      "doc_type": "行政许可",
      "task_type": "DISTRICT",
      "task_created_at": "2024-02-01T10:00:00",
      "progress": 100,
      "total_documents": 15,
      "evaluation_region": ["揭阳"]
    }
  ]
}

返回字段说明

字段 类型 说明
task_id int 任务ID
task_name string 任务名称
task_status string 任务状态(in_progress/completed
doc_type string 文档类型名称
task_type string 任务类型(CITY/DISTRICT等)
task_created_at datetime 任务创建时间
progress int 完成进度百分比 (0-100)
total_documents int 任务包含的文档总数
evaluation_region array 参与评查的地区列表

8. 获取评查任务进度

GET /api/v2/cross_review/tasks/{task_id}/progress

根据任务ID获取评查进度详情。仅任务参与者可访问

权限: cross_review:progress:view

路径参数

参数 类型 说明
task_id int 任务ID(必须大于0

请求体

无需请求体。

业务逻辑

  1. 权限验证

    • 验证当前用户是否是任务的参与者(在 user_ids 中)
  2. 进度计算

    • 获取任务关联的所有文档映射(排除已删除的)
    • 统计已完成文档数(audit_status = 1
    • 计算完成百分比

响应示例

{
  "code": 0,
  "task_id": 1,
  "total_documents": 20,
  "completed_documents": 15,
  "progress": 75.0
}

返回字段说明

字段 类型 说明
code int 状态码(0表示成功)
task_id int 任务ID
total_documents int 文档总数
completed_documents int 已完成文档数
progress float 完成百分比(保留2位小数)

错误码

状态码 错误信息 说明
403 无权访问任务:您不是该任务的参与者 用户不是任务参与者
404 任务不存在 无效的任务ID

9. 获取任务下文档列表

POST /api/v2/cross_review/tasks/{task_id}/documents

获取指定任务下的文档列表,支持多种筛选条件和排序。仅任务参与者可访问

权限: cross_review:task:read

路径参数

参数 类型 说明
task_id int 任务ID(必须大于0

请求参数

字段 类型 必填 默认值 说明
page int 1 页码(从1开始)
page_size int 10 每页数量
file_type_ids array[int] null 文件类型ID列表(不传查所有类型)
date_from string null 起始日期 (yyyy-MM-dd)
date_to string null 结束日期 (yyyy-MM-dd)
keyword string null 搜索关键字(匹配文件名或文书号)
order string upload_time_desc 排序方式

排序方式

说明
upload_time_desc 上传时间降序(默认,最新的在前)
upload_time_asc 上传时间升序(最早的在前)

请求示例

{
  "page": 1,
  "page_size": 10,
  "file_type_ids": [1, 2],
  "date_from": "2024-01-01",
  "date_to": "2024-12-31",
  "keyword": "处罚",
  "order": "upload_time_desc"
}

业务逻辑

  1. 权限验证

    • 验证当前用户是否是任务的参与者
  2. 文档查询

    • cross_task_document_mapping 获取任务关联的文档
    • 应用各种筛选条件
    • 关联 documentsdocument_types
  3. 评查统计

    • 统计每个文档的评查结果
    • 计算通过/警告/失败/人工审核数量
    • 计算最终得分和满分
    • 获取问题摘要(最多5条)

响应示例

{
  "total": 100,
  "page": 1,
  "page_size": 10,
  "items": [
    {
      "document_id": 123,
      "file_name": "行政处罚决定书_001.pdf",
      "status": "completed",
      "path": "/documents/2024/01/123.pdf",
      "file_code": "穗市监罚字[2024]001号",
      "file_type_name": "行政处罚",
      "file_type_id": 1,
      "file_size": 1024000,
      "upload_time": "2024-01-01T10:00:00",
      "created_at": "2024-01-01T10:00:00",
      "evaluations_status": "completed",
      "audit_status": 1,
      "created_by_user_id": 1,
      "final_score": 85.5,
      "full_score": 100,
      "score_summary": "85.5/100",
      "score_percent": 85.5,
      "pass_count": 18,
      "warning_count": 2,
      "fail_count": 1,
      "manual_count": 3,
      "issues": [
        {
          "severity": "error",
          "message": "缺少当事人签名"
        },
        {
          "severity": "warning",
          "message": "日期格式不规范"
        }
      ]
    }
  ]
}

返回字段说明

字段 类型 说明
document_id int 文档ID
file_name string 文件名
status string 文档处理状态
path string 文件存储路径
file_code string 文书号
file_type_name string 文件类型名称
file_type_id int 文件类型ID
file_size int 文件大小(字节)
upload_time datetime 上传时间
created_at datetime 创建时间
evaluations_status string 评查状态
audit_status int 审核状态 (0:待审核, 1:已完成)
created_by_user_id int 创建用户ID
final_score float 最终得分
full_score float 满分
score_summary string 得分摘要(如 "85.5/100"
score_percent float 得分百分比
pass_count int 通过的评查点数量
warning_count int 警告的评查点数量(severity=warning或info
fail_count int 失败的评查点数量(severity=error
manual_count int 需人工审核的评查点数量(post_action=manual
issues array 问题列表(最多5条,包含severity和message

错误码

状态码 错误信息 说明
403 无权访问任务:您不是该任务的参与者 用户不是任务参与者

10. 确认完成文档评查

POST /api/v2/cross_review/tasks/{task_id}/documents/{document_id}/complete

确认完成对指定文档的评查,更新任务进度。

权限: cross_review:document:complete

路径参数

参数 类型 说明
task_id int 任务ID(必须大于0
document_id int 文档ID(必须大于0

请求体

无需请求体。

业务逻辑

  1. 任务存在性验证

    • 验证任务存在
  2. 权限验证

    • 验证当前用户是否是任务的参与者
  3. 文档归属验证

    • 验证文档确实属于该任务(在 cross_task_document_mapping 中)
  4. 状态更新

    • cross_task_document_mapping.audit_status 设置为 1(已完成)

响应示例

{
  "code": 0,
  "success": true,
  "message": "文档评查已完成",
  "task_id": 1,
  "document_id": 123
}

错误码

状态码 错误信息 说明
400 任务不存在 无效的任务ID
400 文档不在任务中 文档不属于该任务
403 用户不是任务的参与者 权限不足

核心业务规则

提案投票机制

  1. 投票通过条件: 同意票数 >= ⌊参与人数/2⌋ + 1

  2. 投票否决条件:

    • 反对票数 >= ⌊参与人数/2⌋ + 1
    • 或剩余可投票数不足以达到通过条件
  3. 提案人自动投票: 创建提案时,系统自动为提案人投一票"同意"

  4. 分数自动更新: 提案通过后,自动将 proposed_score 累加到评查结果的 final_score

分数校验规则

场景 限制
创建0分提案 禁止
当前分数为0时扣分 禁止
当前分数已满分时加分 禁止
分数计算后超过满分 自动截断为满分
分数计算后小于0 自动截断为0

文档完成自动标记

当文档下所有提案都达到终态(approved 或 rejected)时,系统自动将该文档在任务中的状态标记为已完成(audit_status=1)。


权限列表

权限 Key 说明
cross_review:proposal:create 创建提案
cross_review:proposal:read 查看提案
cross_review:proposal:delete 撤销提案
cross_review:proposal:vote 提案投票
cross_review:task:read 查看任务
cross_review:progress:view 查看进度
cross_review:document:complete 完成文档评查

枚举值说明

VoteType 投票类型

说明
agree 同意
disagree 反对
cancel 取消投票

ProposalStatus 提案状态

说明
pending 待处理(投票中)
approved 已通过(分数已更新)
rejected 已否决

DocType 文档类型

说明
XZCF 行政处罚
XZXK 行政许可

audit_status 任务内文档审核状态

说明
0 待审核/进行中
1 已完成

task_status 任务状态

说明
in_progress 进行中
completed 已完成

数据库表关系

cross_examination_tasks (交叉评查任务)
├── id: 任务ID
├── assigner_id: 创建人ID
├── user_ids: 参与者ID数组
├── task_name: 任务名称
├── task_status: 任务状态
├── doc_type: 文档类型
└── task_type: 任务类型

cross_task_document_mapping (任务-文档映射)
├── task_id: 任务ID
├── document_id: 文档ID
├── audit_status: 文档审核状态
└── deleted_at: 软删除标记

cross_scoring_proposals (评分提案)
├── id: 提案ID
├── document_id: 文档ID
├── evaluation_point_id: 评查点ID
├── evaluation_result_id: 评查结果ID
├── proposed_score: 提议分数
├── reason: 理由
├── proposer_id: 提案人ID
├── status: 提案状态
└── deleted_at: 软删除标记

cross_opinion_votes (投票记录)
├── proposal_id: 提案ID
├── voter_id: 投票人ID
├── vote_type: 投票类型
└── deleted_at: 软删除标记

通用错误响应格式

{
  "detail": "错误信息描述"
}

HTTP 状态码:

  • 400 Bad Request: 请求参数错误/业务规则校验失败
  • 403 Forbidden: 权限不足
  • 404 Not Found: 资源不存在
  • 500 Internal Server Error: 服务器内部错误

前端对接注意事项

  1. 所有接口都需要认证: 必须在 Header 中携带有效的 JWT Token

  2. evaluation_result_id 必填: 创建提案时必须提供评查结果ID

  3. 任务权限检查: 大部分任务相关接口会校验当前用户是否为任务参与者

  4. 分页参数: 分页从第1页开始,不是第0页

  5. 日期格式: 使用 yyyy-MM-dd 格式(如 2024-01-01

  6. 投票后刷新: 投票后应刷新提案列表,因为提案状态可能已自动更新

  7. proposed_score 含义:

    • 正数表示加分
    • 负数表示扣分
    • 0 不允许
  8. can_vote 字段: 前端应根据此字段决定是否显示投票按钮