From 089bf5d2378b3c4a61d795b2a92bede2c193b771 Mon Sep 17 00:00:00 2001
From: admin <344137771@qq.com>
Date: Tue, 06 Jan 2026 11:22:58 +0800
Subject: [PATCH] 1

---
 src/components/chat/messaege/VoteMessage.vue |  308 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 308 insertions(+), 0 deletions(-)

diff --git a/src/components/chat/messaege/VoteMessage.vue b/src/components/chat/messaege/VoteMessage.vue
new file mode 100644
index 0000000..b04b918
--- /dev/null
+++ b/src/components/chat/messaege/VoteMessage.vue
@@ -0,0 +1,308 @@
+<template>
+  <div>
+    <div class="vote-message">
+      <div class="vote-from">
+        <div class="vheader">
+          <p>
+            {{ answer_mode == 1 ? '[多选投票]' : '[单选投票]' }}
+            <i
+              v-show="is_vote"
+              class="pointer"
+              :class="{
+                'el-icon-loading': refresh,
+                'el-icon-refresh': !refresh,
+              }"
+              title="刷新投票结果"
+              @click="loadRefresh"
+            ></i>
+          </p>
+          <p>{{ title }}</p>
+        </div>
+
+        <template v-if="is_vote">
+          <div class="vbody">
+            <div class="vote-view" v-for="(option, index) in options">
+              <p class="vote-option">{{ option.value }}. {{ option.text }}</p>
+              <p class="vote-census">
+                {{ option.num }} 票 {{ option.progress }}%
+              </p>
+              <p class="vote-progress">
+                <el-progress
+                  :show-text="false"
+                  :percentage="parseInt(option.progress)"
+                />
+              </p>
+            </div>
+          </div>
+          <div class="vfooter vote-view">
+            <p>应参与人数:{{ answer_num }} 人</p>
+            <p>实际参与人数:{{ answered_num }} 人</p>
+          </div>
+        </template>
+        <template v-else>
+          <div class="vbody" >
+            <p class="option" :class="{ 'option-radio': answer_mode == 0 }" v-for="(option, index) in options">
+              <el-checkbox
+                v-model="option.is_checked"
+                @change="toSelect2(option)"
+              />
+              <span @click="toSelect(option, index)" style="margin-left: 10px;">
+                {{ option.value }} 、{{ option.text }}
+              </span>
+            </p>
+          </div>
+          <div class="vfooter">
+            <el-button plain round @click="toVote">
+              {{ isUserVote ? '立即投票' : '请选择进行投票' }}
+            </el-button>
+          </div>
+        </template>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { ServeConfirmVoteHandle } from '@/api/chat'
+
+export default {
+  name: 'VoteMessage',
+  props: {
+    vote: {
+      type: Object,
+      required: true,
+    },
+    record_id: {
+      type: Number,
+      required: true,
+    },
+  },
+  data() {
+    return {
+      answer_mode: 0,
+      title: '',
+      radio_value: '',
+      options: [],
+      is_vote: false,
+      answer_num: 0,
+      answered_num: 0,
+      refresh: false,
+    }
+  },
+  computed: {
+    isUserVote() {
+      return this.options.some(iten => {
+        return iten.is_checked
+      })
+    },
+  },
+  created() {
+    let user_id = this.$store.state.user.uid
+    let { detail, statistics, vote_users } = this.vote
+
+    this.answer_mode = detail.answer_mode
+    this.answer_num = detail.answer_num
+    this.answered_num = detail.answered_num
+    this.title = detail.title
+
+    detail.answer_option.forEach(item => {
+      this.options.push({
+        value: item.key,
+        text: item.value,
+        is_checked: false,
+        num: 0,
+        progress: '00.0',
+      })
+    })
+
+    this.is_vote = vote_users.some(value => {
+      return value == user_id
+    })
+
+    this.updateStatistics(statistics)
+  },
+  methods: {
+    loadRefresh() {
+      this.refresh = true
+
+      let timer = setTimeout(() => {
+        clearTimeout(timer);
+        this.refresh = false
+      }, 500)
+    },
+    updateStatistics(data) {
+      let count = data.count
+      this.options.forEach(option => {
+        option.num = data.options[option.value]
+
+        if (count > 0) {
+          option.progress = (data.options[option.value] / count) * 100
+        }
+      })
+    },
+
+    toSelect(option, index) {
+      if (this.answer_mode == 0) {
+        this.options.forEach(option => {
+          option.is_checked = false
+        })
+      }
+
+      this.options[index].is_checked = !option.is_checked
+    },
+    toSelect2(option) {
+      if (this.answer_mode == 0) {
+        this.options.forEach(item => {
+          if (option.value == item.value) {
+            item.is_checked = option.is_checked
+          } else {
+            item.is_checked = false
+          }
+        })
+      }
+    },
+    toVote() {
+      if (this.isUserVote == false) {
+        return false
+      }
+
+      let items = []
+      this.options.forEach(item => {
+        if (item.is_checked) {
+          items.push(item.value)
+        }
+      })
+
+      ServeConfirmVoteHandle({
+        record_id: this.record_id,
+        options: items.join(','),
+      }).then(res => {
+        if (res.code == 200) {
+          this.is_vote = true
+          this.updateStatistics(res.data)
+        }
+      })
+    },
+  },
+}
+</script>
+<style lang="less" scoped>
+.vote-message {
+  width: 300px;
+  min-height: 150px;
+  border: 1px solid #eceff1;
+  box-sizing: border-box;
+  border-radius: 5px;
+  overflow: hidden;
+
+  .vote-from {
+    width: 100%;
+
+    .vheader {
+      min-height: 50px;
+      background: #4e83fd;
+      padding: 8px;
+      position: relative;
+      p {
+        margin: 3px 0;
+        &:first-child {
+          color: rgb(245, 237, 237);
+          font-size: 13px;
+          margin-bottom: 8px;
+        }
+
+        &:last-child {
+          color: white;
+        }
+      }
+
+      &::before {
+        content: '投票';
+        position: absolute;
+        font-size: 60px;
+        color: white;
+        opacity: 0.1;
+        top: -5px;
+        right: 10px;
+      }
+    }
+
+    .vbody {
+      min-height: 80px;
+      width: 100%;
+      padding: 5px 15px;
+      box-sizing: border-box;
+
+      .option-radio {
+        /deep/.el-checkbox__inner {
+          border-radius: 50%;
+        }
+      }
+
+      .option {
+        margin: 14px 0px;
+        font-size: 13px;
+        span {
+          cursor: pointer;
+          user-select: none;
+          line-height: 22px;
+        }
+
+        .el-radio {
+          margin-right: 0;
+          .el-radio__label {
+            padding-left: 5px;
+          }
+        }
+      }
+      margin-bottom: 10px;
+    }
+
+    .vfooter {
+      height: 55px;
+      text-align: center;
+      box-sizing: border-box;
+
+      .el-button {
+        width: 80%;
+        font-weight: 400;
+      }
+
+      &.vote-view {
+        display: flex;
+        flex-direction: column;
+        justify-content: flex-start;
+        align-items: flex-start;
+        padding-left: 15px;
+
+        p {
+          border-left: 2px solid #2196f3;
+          padding-left: 5px;
+        }
+      }
+    }
+  }
+
+  .vote-view {
+    width: 100%;
+    min-height: 30px;
+    margin: 15px 0;
+    box-sizing: border-box;
+
+    > p {
+      margin: 6px 0px;
+      font-size: 13px;
+    }
+
+    .vote-option {
+      min-height: 20px;
+      line-height: 20px;
+    }
+
+    .vote-census {
+      height: 20px;
+      line-height: 20px;
+    }
+  }
+}
+</style>

--
Gitblit v1.9.3