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