瀏覽代碼

fix: 修复投票多选BUG

小莫唐尼 7 月之前
父節點
當前提交
5606e8c59f

+ 23 - 1
components/article-vote/article-vote.vue

@@ -151,6 +151,10 @@
 			index: {
 				type: Number,
 				default: 0
+			},
+			article: {
+				type: Object,
+				default: () => ({})
 			}
 		},
 		data() {
@@ -236,6 +240,12 @@
 			formatJsonStr(jsonStr) {
 				return jsonStr ? JSON.parse(jsonStr) : {}
 			},
+			handleSubmitTip() {
+				uni.showToast({
+					icon: "none",
+					title: "请选择选项后继续"
+				})
+			},
 			handleSubmit() {
 				if (!this.vote.spec.canAnonymously) {
 					uni.showModal({
@@ -247,7 +257,8 @@
 						confirmText: "复制地址",
 						success: (res) => {
 							if (res.confirm) {
-								this.$utils.copyText(this.$baseApiUrl, "复制成功")
+								const articleUrl = this.$baseApiUrl + (this.article?.status?.permalink ?? "")
+								this.$utils.copyText(articleUrl, "原文地址复制成功")
 							}
 						}
 					})
@@ -296,6 +307,17 @@
 
 			handleSelectCheckboxOption(option) {
 				if (this.vote.spec.disabled) return
+
+				const checkedList = this.vote.spec.options.filter(x => x.checked && x.id != option.id)
+
+				if (this.vote.spec.type === 'multiple' && checkedList.length >= this.vote.spec.maxVotes) {
+					uni.showToast({
+						icon: "none",
+						title: `最多选择 ${this.vote.spec.maxVotes} 项`
+					})
+					return
+				}
+
 				this.vote.spec.options.map(item => {
 					if (option.id == item.id) {
 						item.checked = !item.checked

+ 2 - 2
components/vote-card/vote-card.vue

@@ -173,7 +173,7 @@
 		padding: 24rpx;
 		border-radius: 12rpx;
 		background-color: #ffff;
-		box-shadow: 0rpx 2rpx 24rpx rgba(0, 0, 0, 0.075);
+		box-shadow: 0rpx 2rpx 12rpx rgba(0, 0, 0, 0.035);
 		overflow: hidden;
 		margin-bottom: 24rpx;
 		// border: 1px solid #eee;
@@ -207,7 +207,7 @@
 		box-sizing: border-box;
 		padding-top: 6px;
 		margin-top: 6px;
-		border-top: 2rpx solid #eee;
+		border-top: 2rpx solid #F7F7F7;
 		
 		.left{
 			

+ 41 - 30
pagesA/article-detail/article-detail.vue

@@ -106,24 +106,32 @@
 				</view>
 
 				<!-- 投票 -->
-				<view v-if="!calcAuditModeEnabled && result._voteIds.length!==0" class="vote-wrap copyright-wrap bg-white mt-24 pa-24 round-4">
-					<PluginUnavailable v-if="!uniHaloPluginAvailable" :pluginId="uniHaloPluginId"
-						:error-text="uniHaloPluginAvailableError" />
-					<template v-else>
-						<view class="copyright-title text-weight-b flex items-center justify-between">
-							<text>相关投票</text>
-							<text class="vote-opra" @click="voteIsOpen=!voteIsOpen">
-								{{ voteIsOpen?'收起':'展开'  }}
-							</text>
-						</view>
-						<view v-show="voteIsOpen" class="flex flex-col uh-gap-8 uh-mt-8">
-							<ArticleVote v-for="(voteId,voteIdIndex) in result._voteIds" :key="voteId" :voteId="voteId" :index="voteIdIndex">
+				<view v-if="!calcAuditModeEnabled && result._voteIds.length!==0"
+					class="vote-wrap copyright-wrap bg-white mt-24 pa-24 round-4">
+
+					<view class="copyright-title text-weight-b flex items-center justify-between">
+						<text>相关投票</text>
+						<text class="vote-opra" @click="voteIsOpen=!voteIsOpen">
+							{{ voteIsOpen?'收起':'展开'  }}
+						</text>
+					</view>
+					<view v-show="voteIsOpen" class="flex flex-col uh-gap-8 uh-mt-8">
+						<PluginUnavailable v-if="!uniHaloPluginAvailable" :article="result" :pluginId="uniHaloPluginId"
+							:error-text="uniHaloPluginAvailableError" :useDecoration="false" :customStyle="{
+								width:'100%',borderRadius:'16rpx' }" />
+						<template v-else>
+							<ArticleVote v-for="(voteId,voteIdIndex) in result._voteIds" :key="voteId" :voteId="voteId"
+								:index="voteIdIndex">
 							</ArticleVote>
-						</view>
-						<view v-show="!voteIsOpen" class="vote-tip" @click="voteIsOpen=!voteIsOpen">
-							投票已收起,点击展开 {{result._voteIds.length}} 个投票项
-						</view>
-					</template>
+							<view v-show="!voteIsOpen" class="vote-tip" @click="voteIsOpen=!voteIsOpen">
+								投票已收起,点击展开 {{result._voteIds.length}} 个投票项
+							</view>
+						</template>
+					</view>
+					<view v-show="!uniHaloPluginAvailable && !voteIsOpen" class="vote-tip"
+						@click="voteIsOpen=!voteIsOpen">
+						提示区域已收起,点击显示
+					</view>
 				</view>
 
 				<!-- 版权声明 -->
@@ -325,11 +333,12 @@
 	import RestrictReadSkeleton from "@/components/restrict-read-skeleton/restrict-read-skeleton.vue";
 	import TmImages from "@/tm-vuetify/components/tm-images/tm-images.vue";
 	import TmInput from "@/tm-vuetify/components/tm-input/tm-input.vue";
-	import pluginAvailable from "@/common/mixins/pluginAvailable.js"
+	import pluginAvailableMixin from "@/common/mixins/pluginAvailable.js"
+	import PluginUnavailable from '@/components/plugin-unavailable/plugin-unavailable.vue'
 
 	let videoAd = null;
 	export default {
-		mixins:[pluginAvailable],
+		mixins: [pluginAvailableMixin],
 		components: {
 			TmInput,
 			TmImages,
@@ -347,7 +356,8 @@
 			rCanvas,
 			barrage,
 			commentModal,
-			ArticleVote
+			ArticleVote,
+			PluginUnavailable
 		},
 		data() {
 			return {
@@ -454,7 +464,7 @@
 			this.setPluginId(this.NeedPluginIds.PluginVote)
 			this.setPluginError("阿偶,检测到当前插件没有安装或者启用,无法使用投票功能,请联系管理员")
 			await this.checkPluginAvailable()
-			
+
 			this.fnSetPageTitle('文章加载中...');
 			this.queryParams.name = e.name;
 			this.fnGetData();
@@ -1444,18 +1454,19 @@
 	.vote-opra {
 		font-size: 24rpx;
 		font-weight: normal;
-		color:#999;
+		color: #999;
 	}
-	.vote-tip{
-		margin-top:12rpx;
-		padding:50rpx 24rpx;
-		background:#F1F5F9;
-		color:#666;
-		font-size:24rpx;
-		border-radius:12rpx;
+
+	.vote-tip {
+		margin-top: 12rpx;
+		padding: 50rpx 24rpx;
+		background: #F1F5F9;
+		color: #666;
+		font-size: 24rpx;
+		border-radius: 12rpx;
 		text-align: center;
 	}
-	
+
 	.markdown-wrap {
 		overflow: hidden;
 		border-radius: 12rpx;

+ 51 - 85
pagesA/vote-detail/vote-detail.vue

@@ -11,11 +11,9 @@
 				<tm-empty icon="icon-shiliangzhinengduixiang-" label="未查询到数据"></tm-empty>
 			</view>
 			<block v-else>
-				<view class="vote-card">
+				<view class="vote-card vote-info-card">
 					<view class="sub-title"> 投票信息 </view>
-					<view class="vote-card-body flex flex-col"
-						style="margin-top:12rpx;font-size:28rpx;gap:12rpx 0;background:#F3F4F6;color:#2B2F33;padding:24rpx;border-radius:12rpx;">
-
+					<view class="vote-card-body flex flex-col uh-mt-8">
 						<view class="">
 							投票类型:<tm-tags v-if="vote.spec.type==='single'" color="light-blue" :shadow="0" size="xs"
 								model="fill">单选</tm-tags>
@@ -34,9 +32,6 @@
 								model="fill">匿名</tm-tags>
 							<tm-tags v-else color="red" size="xs" :shadow="0" model="fill">不匿名</tm-tags>
 						</view>
-						<view v-if="vote.spec.remark" class="">
-							投票说明:{{ vote.spec.remark||"暂无说明" }}
-						</view>
 						<view class="">
 							截止时间:{{ {d: vote.spec.endDate, f: 'yyyy-MM-dd HH:mm'} | formatTime }}
 						</view>
@@ -49,29 +44,14 @@
 						<view class="sub-content">
 							{{ vote.spec.title }}
 						</view>
+						<view v-if="vote.spec.remark" class="sub-remark">
+							{{ vote.spec.remark  }}
+						</view>
 					</view>
-					<view class="vote-card-body">
+					<view class="vote-card-body uh-mt-8">
 						<view class="sub-title"> 投票选项 <text v-if="vote.spec.type==='multiple'"
 								class="sub-title-count">(最多选择 {{ vote.spec.maxVotes }} 项)</text> </view>
 						<view v-if="vote.spec.type==='single'" class="single">
-							<!-- <tm-groupradio @change="onOptionRadioChange">
-								<tm-radio v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex" dense
-									:disabled="vote.spec.disabled" v-model="option.checked" :extendData="option">
-									<template v-slot:default="{checkData}">
-										<tm-button :shadow="0" :theme="checkData.checked?'light-blue':'grey-lighten-3'"
-											:plan="false" size="m" :height="72">
-											<view class="flex flex-between w-full">
-												<text class="text-align-left text-overflow">
-													{{ checkData.extendData.title }}
-												</text>
-												<text v-if="checkData.extendData.isVoted" class="flex-shrink ml-12">
-													{{checkData.extendData.percent }}%
-												</text>
-											</view>
-										</tm-button>
-									</template>
-								</tm-radio>
-							</tm-groupradio> -->
 							<view class="w-full flex flex-col uh-gap-8">
 								<tm-button v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
 									:shadow="0" :theme="option.checked?'light-blue':'grey-lighten-3'" :plan="false"
@@ -90,25 +70,6 @@
 						</view>
 
 						<view v-else-if="vote.spec.type==='multiple'" class="multiple">
-							<!-- <tm-groupcheckbox @change="onOptionCheckboxChange">
-								<tm-checkbox v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex" dense
-									:disabled="vote.spec.disabled" v-model="option.checked" :extendData="option">
-									<template v-slot:default="{checkData}">
-										<tm-button :shadow="0" :theme="checkData.checked?'light-blue':'grey-lighten-3'"
-											:plan="false" size="m" :height="72">
-											<view class="flex flex-between w-full">
-												<text class="text-align-left text-overflow">
-													{{ checkData.extendData.title }}
-												</text>
-												<text v-if="checkData.extendData.isVoted" class="flex-shrink ml-12">
-													{{checkData.extendData.percent }}%
-												</text>
-											</view>
-										</tm-button>
-									</template>
-								</tm-checkbox>
-							</tm-groupcheckbox> -->
-
 							<view class="w-full flex flex-col uh-gap-8">
 								<tm-button v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
 									:shadow="0" :theme="option.checked?'light-blue':'grey-lighten-3'" :plan="false"
@@ -138,25 +99,6 @@
 								</view>
 							</view>
 							<view class="option-foot w-full flex flex-between">
-								<!-- <tm-groupradio @change="onOptionPkChange" >
-									<tm-radio v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex" dense
-										:disabled="vote.spec.disabled" v-model="option.checked"
-										:extendData="{optionIndex:optionIndex,...option}"  >
-										<template v-slot:default="{checkData}">
-											<tm-button :shadow="0"
-												:theme="checkData.checked?'light-blue':'grey-lighten-3'" :plan="false"
-												size="m" :height="72">
-												<view class="flex flex-between w-full">
-													<text class="text-align-left text-overflow">
-														选项{{checkData.extendData.optionIndex+1}}:{{ checkData.extendData.title }}
-													</text>
-												</view>
-											</tm-button>
-										</template>
-									</tm-radio>
-								</tm-groupradio> -->
-
-
 								<view class="w-full flex flex-between uh-gap-8">
 									<tm-button v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
 										:shadow="0" :theme="option.checked?'light-blue':'grey-lighten-3'" :plan="false"
@@ -169,7 +111,6 @@
 										</view>
 									</tm-button>
 								</view>
-
 							</view>
 						</view>
 					</view>
@@ -181,6 +122,7 @@
 						<view class="">
 							<tm-tags color="grey-darken-4" size="s" model="text">{{ vote.stats.voteCount }}
 								人已参与</tm-tags>
+							<tm-tags v-if="vote.spec.isVoted" color="blue" rounded size="s" model="text">已投票</tm-tags>
 						</view>
 					</view>
 				</view>
@@ -191,6 +133,8 @@
 						:block="true" @click="handleSubmit()">不允许匿名投票</tm-button>
 					<tm-button v-else-if="fnCalcIsVoted()" theme="white" text :block="true"
 						class="w-full">您已参与投票</tm-button>
+					<tm-button v-else-if="submitForm.voteData.length===0" theme="white" text class="w-full"
+						:block="true" @click="handleSubmitTip()">提交投票(请选择选项)</tm-button>
 					<tm-button v-else theme="light-blue" class="w-full" :block="true"
 						@click="handleSubmit()">提交投票</tm-button>
 				</view>
@@ -203,10 +147,6 @@
 	import tmSkeleton from '@/tm-vuetify/components/tm-skeleton/tm-skeleton.vue';
 	import tmEmpty from '@/tm-vuetify/components/tm-empty/tm-empty.vue';
 	import tmButton from '@/tm-vuetify/components/tm-button/tm-button.vue';
-	import tmGroupradio from '@/tm-vuetify/components/tm-groupradio/tm-groupradio.vue';
-	import tmRadio from '@/tm-vuetify/components/tm-radio/tm-radio.vue';
-	import tmGroupcheckbox from '@/tm-vuetify/components/tm-groupcheckbox/tm-groupcheckbox.vue';
-	import tmCheckbox from '@/tm-vuetify/components/tm-checkbox/tm-checkbox.vue';
 	import tmTags from '@/tm-vuetify/components/tm-tags/tm-tags.vue';
 
 	import {
@@ -224,10 +164,6 @@
 			tmSkeleton,
 			tmEmpty,
 			tmButton,
-			tmGroupradio,
-			tmRadio,
-			tmGroupcheckbox,
-			tmCheckbox,
 			tmTags,
 		},
 		data() {
@@ -241,11 +177,6 @@
 				vote: null,
 				submitForm: {
 					voteData: []
-				},
-				votedSelected: {
-					checkbox: [],
-					radio: [],
-					pk: []
 				}
 			};
 		},
@@ -350,6 +281,12 @@
 			formatJsonStr(jsonStr) {
 				return jsonStr ? JSON.parse(jsonStr) : {}
 			},
+			handleSubmitTip(){
+				uni.showToast({
+					icon: "none",
+					title: "请选择选项后继续"
+				})
+			},
 			handleSubmit() {
 				if (!this.vote.spec.canAnonymously) {
 					uni.showModal({
@@ -372,9 +309,6 @@
 					title: "正在保存..."
 				})
 
-				// 使用简单版
-				this.submitForm.voteData = this.vote.spec.options.filter(x => x.checked).map(item => item.id)
-
 				this.$httpApi.v2
 					.submitVote(this.name, this.submitForm, this.vote.spec.canAnonymously)
 					.then(res => {
@@ -410,15 +344,30 @@
 						item.checked = false
 					}
 				})
+
+				this.submitForm.voteData = this.vote.spec.options.filter(x => x.checked).map(item => item.id)
 			},
 
 			handleSelectCheckboxOption(option) {
 				if (this.vote.spec.disabled) return
+
+				const checkedList = this.vote.spec.options.filter(x => x.checked && x.id != option.id)
+
+				if (this.vote.spec.type === 'multiple' && checkedList.length >= this.vote.spec.maxVotes) {
+					uni.showToast({
+						icon: "none",
+						title: `最多选择 ${this.vote.spec.maxVotes} 项`
+					})
+					return
+				}
+
 				this.vote.spec.options.map(item => {
 					if (option.id == item.id) {
 						item.checked = !item.checked
 					}
 				})
+
+				this.submitForm.voteData = this.vote.spec.options.filter(x => x.checked).map(item => item.id)
 			}
 		}
 	};
@@ -469,6 +418,17 @@
 		margin-bottom: 24rpx;
 	}
 
+	.vote-info-card {
+		.vote-card-body {
+			font-size: 28rpx;
+			gap: 12rpx 0;
+			background: #F3F4F6;
+			color: #3F3F3F;
+			padding: 24rpx;
+			border-radius: 12rpx;
+		}
+	}
+
 	.vote-card-head {
 		margin-bottom: 12rpx;
 		display: flex;
@@ -620,20 +580,26 @@
 	}
 
 	.sub-content {
+		margin-bottom: 12rpx;
+		padding: 12rpx 0;
 		font-weight: bold;
 		color: #2B2F33;
-		padding: 12rpx 0;
-		font-size: 32rpx;
-		margin-bottom: 12rpx;
+		font-size: 30rpx;
 	}
 
+	.sub-remark {
+		margin-bottom: 36rpx;
+		padding-top: 12rpx;
+		color: #3F3F3F;
+		font-size: 28rpx;
+	}
 
 	.sub-title {
 		box-sizing: border-box;
 		position: relative;
 		margin-bottom: 12rpx;
 		padding-left: 24rpx;
-		font-weight: bold;
+		// font-weight: bold;
 		font-size: 30rpx;
 
 		&:before {