mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-13 12:02:51 +00:00
perf: 优化消息组件
This commit is contained in:
parent
e956a03098
commit
ae587950b9
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div :class="`content-file ${msg.type}`">
|
||||
<div class="dialog-file">
|
||||
<img v-if="msg.type === 'img'" class="file-img" :style="imageStyle(msg)" :src="msg.thumb" @click="viewFile"/>
|
||||
<div v-else-if="isVideoFile(msg)" class="file-video" :style="imageStyle(msg)" @click="viewFile">
|
||||
<img v-if="msg.thumb" :src="msg.thumb">
|
||||
<video v-else :width="imageStyle(msg, 'width')" :height="imageStyle(msg, 'height')">
|
||||
<source :src="msg.path" type="video/mp4">
|
||||
</video>
|
||||
<div class="file-play">
|
||||
<div class="play-icon">
|
||||
<i class="taskfont"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="file-box" @click="downFile">
|
||||
<img class="file-thumb" :src="msg.thumb"/>
|
||||
<div class="file-info">
|
||||
<div class="file-name">{{ msg.name }}</div>
|
||||
<div class="file-size">{{ $A.bytesToSize(msg.size) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="msg.percentage" class="file-percentage">
|
||||
<span :style="fileStyle(msg.percentage)"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
props: {
|
||||
msg: Object,
|
||||
},
|
||||
methods: {
|
||||
viewFile() {
|
||||
this.$emit('viewFile');
|
||||
},
|
||||
downFile() {
|
||||
this.$emit('downFile');
|
||||
},
|
||||
|
||||
fileStyle(percentage) {
|
||||
if (percentage) {
|
||||
return {
|
||||
width: `${percentage}%`
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
||||
imageStyle(info, type = 'style') {
|
||||
const {width, height} = info;
|
||||
if (width && height) {
|
||||
let maxW = 220,
|
||||
maxH = 220,
|
||||
tempW = width,
|
||||
tempH = height;
|
||||
if (width > maxW || height > maxH) {
|
||||
if (width > height) {
|
||||
tempW = maxW;
|
||||
tempH = height * (maxW / width);
|
||||
} else {
|
||||
tempW = width * (maxH / height);
|
||||
tempH = maxH;
|
||||
}
|
||||
}
|
||||
if (type === 'width') {
|
||||
return tempW
|
||||
}
|
||||
if (type === 'height') {
|
||||
return tempH
|
||||
}
|
||||
return {
|
||||
width: tempW + 'px',
|
||||
height: tempH + 'px',
|
||||
};
|
||||
}
|
||||
if (type === 'width' || type === 'height') {
|
||||
return 0
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
||||
isVideoFile(msg) {
|
||||
return msg.type === 'file'
|
||||
&& msg.ext === 'mp4'
|
||||
&& msg.width > 0
|
||||
&& msg.height > 0;
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -26,148 +26,21 @@
|
||||
<!--详情-->
|
||||
<div ref="content" class="dialog-content" :class="contentClass">
|
||||
<!--文本-->
|
||||
<div v-if="msgData.type === 'text'" class="content-text no-dark-content">
|
||||
<DialogMarkdown v-if="msgData.msg.type === 'md'" @click="viewText" :text="msgData.msg.text"/>
|
||||
<pre v-else @click="viewText" v-html="$A.formatTextMsg(msgData.msg.text, userId)"></pre>
|
||||
</div>
|
||||
<TextMsg v-if="msgData.type === 'text'" :msg="msgData.msg" @click="viewText"/>
|
||||
<!--文件-->
|
||||
<div v-else-if="msgData.type === 'file'" :class="`content-file ${msgData.msg.type}`">
|
||||
<div class="dialog-file">
|
||||
<img v-if="msgData.msg.type === 'img'" class="file-img" :style="imageStyle(msgData.msg)" :src="msgData.msg.thumb" @click="viewFile"/>
|
||||
<div v-else-if="isVideoFile(msgData.msg)" class="file-video" :style="imageStyle(msgData.msg)" @click="viewFile">
|
||||
<img v-if="msgData.msg.thumb" :src="msgData.msg.thumb">
|
||||
<video v-else :width="imageStyle(msgData.msg, 'width')" :height="imageStyle(msgData.msg, 'height')">
|
||||
<source :src="msgData.msg.path" type="video/mp4">
|
||||
</video>
|
||||
<div class="file-play">
|
||||
<div class="play-icon">
|
||||
<i class="taskfont"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="file-box" @click="downFile">
|
||||
<img class="file-thumb" :src="msgData.msg.thumb"/>
|
||||
<div class="file-info">
|
||||
<div class="file-name">{{msgData.msg.name}}</div>
|
||||
<div class="file-size">{{$A.bytesToSize(msgData.msg.size)}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="msgData.msg.percentage" class="file-percentage">
|
||||
<span :style="fileStyle(msgData.msg.percentage)"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<FileMsg v-else-if="msgData.type === 'file'" :msg="msgData.msg" @viewFile="viewFile" @downFile="downFile"/>
|
||||
<!--录音-->
|
||||
<div v-else-if="msgData.type === 'record'" class="content-record no-dark-content">
|
||||
<div class="dialog-record" :class="{playing: audioPlaying === msgData.msg.path}" :style="recordStyle(msgData.msg)" @click="playRecord">
|
||||
<div class="record-time">{{recordDuration(msgData.msg.duration)}}</div>
|
||||
<div class="record-icon taskfont"></div>
|
||||
</div>
|
||||
<div v-if="msgData.msg.text" class="dialog-record-text">
|
||||
{{msgData.msg.text}}
|
||||
</div>
|
||||
</div>
|
||||
<RecordMsg v-else-if="msgData.type === 'record'" :msg="msgData.msg" @playRecord="playRecord"/>
|
||||
<!--会议-->
|
||||
<div v-else-if="msgData.type === 'meeting'" class="content-meeting no-dark-content">
|
||||
<ul class="dialog-meeting" :class="{'meeting-end':!!msgData.msg.end_at}">
|
||||
<li>
|
||||
<em>{{$L('会议主题')}}</em>
|
||||
{{msgData.msg.name}}
|
||||
</li>
|
||||
<li>
|
||||
<em>{{$L('会议创建人')}}</em>
|
||||
<UserAvatar :userid="msgData.msg.userid" :show-icon="false" :show-name="true"/>
|
||||
</li>
|
||||
<li>
|
||||
<em>{{$L('频道ID')}}</em>
|
||||
{{msgData.msg.meetingid.replace(/^(.{3})(.{3})(.*)$/, '$1 $2 $3')}}
|
||||
</li>
|
||||
<li v-if="msgData.msg.end_at" class="meeting-operation">
|
||||
{{$L('会议已结束')}}
|
||||
</li>
|
||||
<li v-else class="meeting-operation" @click="openMeeting">
|
||||
{{$L('点击加入会议')}}
|
||||
<i class="taskfont"></i>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<MeetingMsg v-else-if="msgData.type === 'meeting'" :msg="msgData.msg" @openMeeting="openMeeting"/>
|
||||
<!--接龙-->
|
||||
<div v-else-if="msgData.type === 'word-chain'" class="content-text content-word-chain no-dark-content">
|
||||
<pre v-html="$A.formatTextMsg(msgData.msg.text, userId)"></pre>
|
||||
<ul :class="{'expand': unfoldWordChainData.indexOf(msgData.id) !== -1 }">
|
||||
<li v-for="(item) in (msgData.msg.list || []).filter(h=>h.type == 'case')">
|
||||
{{ $L('例') }} {{ item.text }}
|
||||
</li>
|
||||
<li v-for="(item,index) in (msgData.msg.list || []).filter(h=>h.type != 'case' && h.text)">
|
||||
<span class="expand" v-if="index == 2 && msgData.msg.list.length > 4" @click="unfoldWordChain(msgData)">
|
||||
...{{$L('展开')}}...
|
||||
</span>
|
||||
<span :class="{'shrink': index >= 2 && msgData.msg.list.length > 4 } ">
|
||||
{{index + 1}}. {{item.text}}
|
||||
</span>
|
||||
</li>
|
||||
<li @click="onWordChain" class="participate">
|
||||
{{ $L('参与接龙') }}
|
||||
<i class="taskfont"></i>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<WordChainMsg v-else-if="msgData.type === 'word-chain'" :msg="msgData.msg" :msgId="msgData.id" :unfoldWordChainData="unfoldWordChainData" @unfoldWordChain="unfoldWordChain(msgData)" @onWordChain="onWordChain"/>
|
||||
<!--投票-->
|
||||
<div v-else-if="msgData.type === 'vote'" class="content-text content-word-vote no-dark-content">
|
||||
<div class="vote-msg-head">
|
||||
<i class="taskfont"></i>
|
||||
<em>{{ $L('投票') }}</em>
|
||||
<span>{{ msgData.msg.multiple == 1 ? $L('多选') : $L('单选')}}</span>
|
||||
<span>{{ msgData.msg.anonymous == 1 ? $L('匿名') : $L('实名')}}</span>
|
||||
</div>
|
||||
<pre v-html="$A.formatTextMsg(msgData.msg.text, userId)"></pre>
|
||||
<template v-if="(msgData.msg.votes || []).filter(h=>h.userid == userId).length == 0">
|
||||
<RadioGroup v-if="msgData.msg.multiple == 0" v-model="voteData[msgData.msg.uuid]" vertical>
|
||||
<Radio v-for="(item,index) in (msgData.msg.list || [])" :label="item.id" :key="index">
|
||||
{{item.text}}
|
||||
</Radio>
|
||||
</RadioGroup>
|
||||
<CheckboxGroup v-else v-model="voteData[msgData.msg.uuid]">
|
||||
<Checkbox v-for="(item,index) in (msgData.msg.list || [])" :label="item.id" :key="index">
|
||||
{{item.text}}
|
||||
</Checkbox>
|
||||
</CheckboxGroup>
|
||||
<div class="btn-row">
|
||||
<Button v-if="(voteData[msgData.msg.uuid] || []).length == 0" class="ivu-btn-grey" disabled>{{$L("请选择后投票")}}</Button>
|
||||
<Button v-else type="warning" :loading="msgData.msg._loadIng > 0" class="no-dark-content" @click="onVote('vote',msgData)">{{$L("立即投票")}}</Button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="vote-result-body">
|
||||
<ul>
|
||||
<li v-for="item in (msgData.msg.list || [])">
|
||||
<div class="vote-option-title">{{ item.text }}</div>
|
||||
<div class="ticket-num">
|
||||
<span>{{ getVoteProgress(msgData.msg,item.id).num }}{{$L('票')}}</span>
|
||||
<span>{{ getVoteProgress(msgData.msg,item.id).progress + '%' }}</span>
|
||||
</div>
|
||||
<Progress :percent="Number(getVoteProgress(msgData.msg,item.id).progress)" :stroke-width="5" hide-info/>
|
||||
<div v-if="msgData.msg.anonymous == 0" class="avatar-row">
|
||||
<template v-for="votes in (msgData.msg.votes || []).filter(h=>h.votes.indexOf(item.id) != -1)">
|
||||
<UserAvatar :userid="votes.userid" :size="18" />
|
||||
</template>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-row" v-if="msgData.msg.state == 1 && msgData.msg.userid == userId">
|
||||
<Button type="warning" :loading="msgData.msg._loadIng > 0" @click="onVote('again',msgData)">{{$L("再次发送")}}</Button>
|
||||
<Button type="warning" :loading="msgData.msg._loadIng > 0" @click="onVote('finish',msgData)">{{$L("结束投票")}}</Button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<VoteMsg v-else-if="msgData.type === 'vote'" :msg="msgData.msg" :voteData="voteData" @onVote="onVote($event, msgData)"/>
|
||||
<!--等待-->
|
||||
<div v-else-if="msgData.type === 'loading'" class="content-loading">
|
||||
<Icon v-if="msgData.error === true" type="ios-alert-outline" />
|
||||
<Loading v-else/>
|
||||
</div>
|
||||
<LoadMsg v-else-if="isLoading" :error="msgData.error"/>
|
||||
<!--未知-->
|
||||
<div v-else class="content-unknown">{{$L("未知的消息类型")}}</div>
|
||||
<UnknownMsg v-else/>
|
||||
</div>
|
||||
<!--emoji-->
|
||||
<ul v-if="$A.arrayLength(msgData.emoji) > 0" class="dialog-emoji">
|
||||
@ -295,15 +168,33 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WCircle from "../../../components/WCircle";
|
||||
import WCircle from "../../../../components/WCircle";
|
||||
import {mapGetters, mapState} from "vuex";
|
||||
import {Store} from "le5le-store";
|
||||
import longpress from "../../../directives/longpress";
|
||||
import DialogMarkdown from "./DialogMarkdown.vue";
|
||||
import longpress from "../../../../directives/longpress";
|
||||
|
||||
import TextMsg from "./text.vue";
|
||||
import FileMsg from "./file.vue";
|
||||
import RecordMsg from "./record.vue";
|
||||
import MeetingMsg from "./meet.vue";
|
||||
import WordChainMsg from "./word-chain.vue";
|
||||
import VoteMsg from "./vote.vue";
|
||||
import LoadMsg from "./load.vue";
|
||||
import UnknownMsg from "./unknown.vue";
|
||||
|
||||
export default {
|
||||
name: "DialogView",
|
||||
components: {DialogMarkdown, WCircle},
|
||||
components: {
|
||||
UnknownMsg,
|
||||
LoadMsg,
|
||||
VoteMsg,
|
||||
WordChainMsg,
|
||||
MeetingMsg,
|
||||
RecordMsg,
|
||||
TextMsg,
|
||||
FileMsg,
|
||||
WCircle
|
||||
},
|
||||
directives: {longpress},
|
||||
props: {
|
||||
msgData: {
|
||||
@ -382,7 +273,7 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['loads', 'audioPlaying']),
|
||||
...mapState(['loads']),
|
||||
...mapGetters(['isLoad']),
|
||||
|
||||
isLoading() {
|
||||
@ -557,72 +448,6 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
recordStyle(info) {
|
||||
const {duration} = info;
|
||||
const width = 50 + Math.min(180, Math.floor(duration / 200));
|
||||
return {
|
||||
width: width + 'px',
|
||||
};
|
||||
},
|
||||
|
||||
recordDuration(duration) {
|
||||
const minute = Math.floor(duration / 60000),
|
||||
seconds = Math.floor(duration / 1000) % 60;
|
||||
if (minute > 0) {
|
||||
return `${minute}:${seconds}″`
|
||||
}
|
||||
return `${Math.max(1, seconds)}″`
|
||||
},
|
||||
|
||||
fileStyle(percentage) {
|
||||
if (percentage) {
|
||||
return {
|
||||
width: `${percentage}%`
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
||||
imageStyle(info, type = 'style') {
|
||||
const {width, height} = info;
|
||||
if (width && height) {
|
||||
let maxW = 220,
|
||||
maxH = 220,
|
||||
tempW = width,
|
||||
tempH = height;
|
||||
if (width > maxW || height > maxH) {
|
||||
if (width > height) {
|
||||
tempW = maxW;
|
||||
tempH = height * (maxW / width);
|
||||
} else {
|
||||
tempW = width * (maxH / height);
|
||||
tempH = maxH;
|
||||
}
|
||||
}
|
||||
if (type === 'width') {
|
||||
return tempW
|
||||
}
|
||||
if (type === 'height') {
|
||||
return tempH
|
||||
}
|
||||
return {
|
||||
width: tempW + 'px',
|
||||
height: tempH + 'px',
|
||||
};
|
||||
}
|
||||
if (type === 'width' || type === 'height') {
|
||||
return 0
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
||||
isVideoFile(msg) {
|
||||
return msg.type === 'file'
|
||||
&& msg.ext === 'mp4'
|
||||
&& msg.width > 0
|
||||
&& msg.height > 0;
|
||||
},
|
||||
|
||||
playRecord() {
|
||||
if (this.operateVisible) {
|
||||
return
|
||||
@ -737,15 +562,15 @@ export default {
|
||||
cancelText: '取消',
|
||||
okText: '确定',
|
||||
onOk: () => {
|
||||
this.vote(type, msgData);
|
||||
this.submitVote(type, msgData);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.vote(type, msgData);
|
||||
this.submitVote(type, msgData);
|
||||
},
|
||||
|
||||
vote(type, msgData) {
|
||||
submitVote(type, msgData) {
|
||||
this.$set(msgData.msg, '_loadIng', 1)
|
||||
this.$store.dispatch("call", {
|
||||
url: 'dialog/msg/vote',
|
||||
@ -769,12 +594,6 @@ export default {
|
||||
this.$set(msgData.msg, '_loadIng', 0)
|
||||
});
|
||||
},
|
||||
|
||||
getVoteProgress(msgData, id) {
|
||||
const num = msgData.votes.filter(h => (h.votes || '').indexOf(id) != -1).length
|
||||
const progress = !num ? '0.00' : (num / msgData.votes.length * 100).toFixed(2);
|
||||
return { num, progress };
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div class="content-loading">
|
||||
<Icon v-if="error === true" type="ios-alert-outline" />
|
||||
<Loading v-else/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
props: {
|
||||
error: Boolean,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div class="content-meeting no-dark-content">
|
||||
<ul class="dialog-meeting" :class="{'meeting-end':!!msg.end_at}">
|
||||
<li>
|
||||
<em>{{ $L('会议主题') }}</em>
|
||||
{{ msg.name }}
|
||||
</li>
|
||||
<li>
|
||||
<em>{{ $L('会议创建人') }}</em>
|
||||
<UserAvatar :userid="msg.userid" :show-icon="false" :show-name="true"/>
|
||||
</li>
|
||||
<li>
|
||||
<em>{{ $L('频道ID') }}</em>
|
||||
{{ channelID(msg.meetingid) }}
|
||||
</li>
|
||||
<li v-if="msg.end_at" class="meeting-operation">
|
||||
{{ $L('会议已结束') }}
|
||||
</li>
|
||||
<li v-else class="meeting-operation" @click="openMeeting">
|
||||
{{ $L('点击加入会议') }}
|
||||
<i class="taskfont"></i>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
props: {
|
||||
msg: Object,
|
||||
},
|
||||
methods: {
|
||||
openMeeting() {
|
||||
this.$emit('openMeeting');
|
||||
},
|
||||
channelID(meetingid: string) {
|
||||
return meetingid.replace(/^(.{3})(.{3})(.*)$/, '$1 $2 $3');
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div class="content-record no-dark-content">
|
||||
<div class="dialog-record" :class="{playing: audioPlaying === msg.path}" :style="recordStyle(msg)" @click="playRecord">
|
||||
<div class="record-time">{{recordDuration(msg.duration)}}</div>
|
||||
<div class="record-icon taskfont"></div>
|
||||
</div>
|
||||
<div v-if="msg.text" class="dialog-record-text">
|
||||
{{msg.text}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
msg: Object,
|
||||
},
|
||||
computed: {
|
||||
...mapState(['audioPlaying']),
|
||||
},
|
||||
methods: {
|
||||
playRecord() {
|
||||
this.$emit('playRecord');
|
||||
},
|
||||
recordStyle(info) {
|
||||
const {duration} = info;
|
||||
const width = 50 + Math.min(180, Math.floor(duration / 200));
|
||||
return {
|
||||
width: width + 'px',
|
||||
};
|
||||
},
|
||||
recordDuration(duration) {
|
||||
const minute = Math.floor(duration / 60000),
|
||||
seconds = Math.floor(duration / 1000) % 60;
|
||||
if (minute > 0) {
|
||||
return `${minute}:${seconds}″`
|
||||
}
|
||||
return `${Math.max(1, seconds)}″`
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div class="content-text no-dark-content">
|
||||
<DialogMarkdown v-if="msg.type === 'md'" @click="viewText" :text="msg.text"/>
|
||||
<pre v-else @click="viewText" v-html="$A.formatTextMsg(msg.text, userId)"></pre>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import DialogMarkdown from "../DialogMarkdown.vue";
|
||||
|
||||
export default {
|
||||
components: {DialogMarkdown},
|
||||
props: {
|
||||
msg: Object,
|
||||
},
|
||||
methods: {
|
||||
viewText() {
|
||||
this.$emit('viewText');
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div class="content-unknown">{{$L("未知的消息类型")}}</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div class="content-text content-word-vote no-dark-content">
|
||||
<div class="vote-msg-head">
|
||||
<i class="taskfont"></i>
|
||||
<em>{{ $L('投票') }}</em>
|
||||
<span>{{ msg.multiple == 1 ? $L('多选') : $L('单选') }}</span>
|
||||
<span>{{ msg.anonymous == 1 ? $L('匿名') : $L('实名') }}</span>
|
||||
</div>
|
||||
<pre v-html="$A.formatTextMsg(msg.text, userId)"></pre>
|
||||
<template v-if="(msg.votes || []).filter(h=>h.userid == userId).length == 0">
|
||||
<RadioGroup v-if="msg.multiple == 0" v-model="voteData[msg.uuid]" vertical>
|
||||
<Radio v-for="(item,index) in (msg.list || [])" :label="item.id" :key="index">
|
||||
{{ item.text }}
|
||||
</Radio>
|
||||
</RadioGroup>
|
||||
<CheckboxGroup v-else v-model="voteData[msg.uuid]">
|
||||
<Checkbox v-for="(item,index) in (msg.list || [])" :label="item.id" :key="index">
|
||||
{{ item.text }}
|
||||
</Checkbox>
|
||||
</CheckboxGroup>
|
||||
<div class="btn-row">
|
||||
<Button v-if="(voteData[msg.uuid] || []).length == 0" class="ivu-btn-grey" disabled>{{ $L("请选择后投票") }}</Button>
|
||||
<Button v-else type="warning" :loading="msg._loadIng > 0" class="no-dark-content" @click="onVote('vote')">{{ $L("立即投票") }}</Button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="vote-result-body">
|
||||
<ul>
|
||||
<li v-for="item in (msg.list || [])">
|
||||
<div class="vote-option-title">{{ item.text }}</div>
|
||||
<div class="ticket-num">
|
||||
<span>{{ getVoteProgress(msg, item.id).num }}{{ $L('票') }}</span>
|
||||
<span>{{ getVoteProgress(msg, item.id).progress + '%' }}</span>
|
||||
</div>
|
||||
<Progress :percent="Number(getVoteProgress(msg,item.id).progress)" :stroke-width="5" hide-info/>
|
||||
<div v-if="msg.anonymous == 0" class="avatar-row">
|
||||
<template v-for="votes in (msg.votes || []).filter(h=>h.votes.indexOf(item.id) != -1)">
|
||||
<UserAvatar :userid="votes.userid" :size="18"/>
|
||||
</template>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-row" v-if="msg.state == 1 && msg.userid == userId">
|
||||
<Button type="warning" :loading="msg._loadIng > 0" @click="onVote('again')">{{ $L("再次发送") }}</Button>
|
||||
<Button type="warning" :loading="msg._loadIng > 0" @click="onVote('finish')">{{ $L("结束投票") }}</Button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
props: {
|
||||
msg: Object,
|
||||
voteData: Object,
|
||||
},
|
||||
methods: {
|
||||
getVoteProgress(data, id) {
|
||||
const num = data.votes.filter(h => (h.votes || '').indexOf(id) != -1).length
|
||||
const progress = !num ? '0.00' : (num / data.votes.length * 100).toFixed(2);
|
||||
return {num, progress};
|
||||
},
|
||||
onVote(type) {
|
||||
this.$emit('onVote', type);
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div class="content-text content-word-chain no-dark-content">
|
||||
<pre v-html="$A.formatTextMsg(msg.text, userId)"></pre>
|
||||
<ul :class="{'expand': unfoldWordChainData.indexOf(msgId) !== -1 }">
|
||||
<li v-for="(item) in (msg.list || []).filter(h=>h.type == 'case')">
|
||||
{{ $L('例') }} {{ item.text }}
|
||||
</li>
|
||||
<li v-for="(item, index) in (msg.list || []).filter(h=>h.type != 'case' && h.text)">
|
||||
<span class="expand" v-if="index == 2 && msg.list.length > 4" @click="unfoldWordChain">
|
||||
...{{ $L('展开') }}...
|
||||
</span>
|
||||
<span :class="{'shrink': index >= 2 && msg.list.length > 4 } ">
|
||||
{{ index + 1 }}. {{ item.text }}
|
||||
</span>
|
||||
</li>
|
||||
<li @click="onWordChain" class="participate">
|
||||
{{ $L('参与接龙') }}
|
||||
<i class="taskfont"></i>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
props: {
|
||||
msg: Object,
|
||||
msgId: Number,
|
||||
unfoldWordChainData: Array,
|
||||
},
|
||||
methods: {
|
||||
unfoldWordChain() {
|
||||
this.$emit('unfoldWordChain');
|
||||
},
|
||||
onWordChain() {
|
||||
this.$emit('onWordChain');
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -655,7 +655,8 @@
|
||||
position: relative;
|
||||
|
||||
&.text,
|
||||
&.record {
|
||||
&.record,
|
||||
&.word-chain {
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
@ -1317,7 +1318,7 @@
|
||||
|
||||
.content-word-vote {
|
||||
min-width: 200px;
|
||||
max-width: 260px;
|
||||
max-width: 300px;
|
||||
|
||||
.vote-msg-head {
|
||||
display: flex;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user