Explorar o código

feat: 优化投票功能,调整API

小莫唐尼 hai 7 meses
pai
achega
31ade9908a

+ 1 - 5
api/v2/all.api.js

@@ -252,11 +252,7 @@ export default {
 	 * 获取投票列表
 	 */
 	getVoteList: (params) => {
-		return HttpHandler.Get(`/apis/console.api.vote.kunkunyu.com/v1alpha1/votes`, params, {
-			custom: {
-				personalToken: getPersonalToken()
-			}
-		})
+		return HttpHandler.Get(`/apis/api.vote.kunkunyu.com/v1alpha1/votes`, params)
 	},
 	/**
 	 * 获取投票详情

+ 6 - 1
common/styles/app.base.scss

@@ -340,5 +340,10 @@ $spacing-sizes: (
 }
 
 .justify-center {
-  justify-content: center;
+	justify-content: center;
 }
+
+.text-break {
+	overflow-wrap: break-word;
+	word-break: break-all;
+}

+ 185 - 92
components/article-vote/article-vote.vue

@@ -5,25 +5,34 @@
 		</view>
 		<template v-else>
 			<view class="vote-card-head flex flex-col">
-				<view class="flex">
-					<tm-tags color="orange" style="min-width:40rpx;" :shadow="0" rounded size="s"
-						model="fill">{{ index+1 }}</tm-tags>
-
-					<tm-tags v-if="vote.spec.type==='single'" color="light-blue" :shadow="0" rounded size="s"
-						model="fill">单选</tm-tags>
-					<tm-tags v-else-if="vote.spec.type==='multiple'" color="light-blue" :shadow="0" rounded size="s"
-						model="fill">多选</tm-tags>
-					<tm-tags v-else-if="vote.spec.type==='pk'" color="light-blue" :shadow="0" rounded size="s"
-						model="fill">双选PK</tm-tags>
-
-					<tm-tags v-if="vote.spec.hasEnded" color="red" rounded :shadow="0" size="s"
-						model="text">已结束</tm-tags>
-					<tm-tags v-else color="green" rounded size="s" :shadow="0" model="text">进行中</tm-tags>
+				<view class="flex justify-between">
+					<view class="flex">
+						<tm-tags color="orange" style="min-width:40rpx;" :shadow="0" rounded size="s"
+							model="fill">{{ index+1 }}</tm-tags>
+
+						<tm-tags v-if="vote.spec.type==='single'" color="light-blue" :shadow="0" rounded size="s"
+							model="fill">单选</tm-tags>
+						<tm-tags v-else-if="vote.spec.type==='multiple'" color="light-blue" :shadow="0" rounded size="s"
+							model="fill">多选</tm-tags>
+						<tm-tags v-else-if="vote.spec.type==='pk'" color="light-blue" :shadow="0" rounded size="s"
+							model="fill">双选PK</tm-tags>
+
+						<tm-tags v-if="vote.spec._state=='已结束'" color="red" size="s" rounded :shadow="0"
+							model="fill">已结束</tm-tags>
+						<tm-tags v-else-if="vote.spec._state=='未开始'" color="orange" size="s" rounded :shadow="0"
+							model="fill">未开始</tm-tags>
+						<tm-tags v-else-if="vote.spec._state=='进行中'" color="green" size="s" rounded :shadow="0"
+							model="fill">进行中</tm-tags>
+
+					</view>
+					<view class="flex-shrink">
+						<tm-button theme="light-blue" :shadow="0" dense size="s"
+							@click="handleToVoteDetail(vote)">查看投票详情</tm-button>
+					</view>
 				</view>
 				<view class="title">
 					{{ vote.spec.title }}
 				</view>
-
 			</view>
 			<view class="vote-card-body">
 
@@ -35,38 +44,58 @@
 					<!-- 单选 -->
 					<view v-if="vote.spec.type==='single'" class="single">
 						<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" size="m"
-								:height="72" :block="true" class="flex-1 w-full"
-								@click="handleSelectSingleOption(option)">
-								<view class="flex flex-between w-full">
-									<text class="text-align-left text-overflow">
-										{{option.title }}
-									</text>
-									<text v-if="vote.spec.isVoted" class="flex-shrink ml-12">
-										{{option.percent }}%
-									</text>
+							<template v-if="vote.spec.isVoted">
+								<view v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
+									class="is-voted-item" :class="[option.checked?'selected':'']" :style="{
+										'--percent': option.percent + '%'
+									}">
+									<view class="is-voted-item-content flex w-full flex-between uh-gap-4">
+										<view class="text-align-left flex-1 text-break">
+											{{option.title }}
+										</view>
+										<view class="flex-shrink ">
+											{{option.percent }}%
+										</view>
+									</view>
+								</view>
+							</template>
+							<template v-else>
+								<view v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
+									class="vote-select-option flex-1 w-full text-break"
+									:class="[option.checked?'light-blue':'grey-lighten-3']"
+									@click="handleSelectSingleOption(option)">
+									{{option.title }}
 								</view>
-							</tm-button>
+							</template>
 						</view>
 					</view>
 
 					<!-- 多选 -->
 					<view v-else-if="vote.spec.type==='multiple'" class="multiple">
 						<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" size="m"
-								:height="72" :block="true" class="flex-1 full"
-								@click="handleSelectCheckboxOption(option)">
-								<view class="flex flex-between w-full">
-									<text class="text-align-left text-overflow">
-										{{option.title }}
-									</text>
-									<text v-if="vote.spec.isVoted" class="flex-shrink ml-12">
-										{{option.percent }}%
-									</text>
+							<template v-if="vote.spec.isVoted">
+								<view v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
+									class="is-voted-item" :class="[option.checked?'selected':'']" :style="{
+										'--percent': option.percent + '%'
+									}">
+									<view class="is-voted-item-content flex w-full flex-between uh-gap-4">
+										<view class="text-align-left flex-1 text-break">
+											{{option.title }}
+										</view>
+										<view class="flex-shrink ">
+											{{option.percent }}%
+										</view>
+									</view>
 								</view>
-							</tm-button>
+							</template>
+							<template v-else>
+								<view v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
+									class="vote-select-option flex-1 w-full text-break"
+									:class="[option.checked?'light-blue':'grey-lighten-3']"
+									@click="handleSelectCheckboxOption(option)">
+									{{option.title }}
+								</view>
+							</template>
 						</view>
 					</view>
 
@@ -84,16 +113,29 @@
 						</view>
 						<view class="option-foot w-full flex flex-between uh-mt-12">
 							<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"
-									size="m" :height="72" :block="true" class="flex-1"
-									@click="handleSelectSingleOption(option)">
-									<view class="flex flex-between w-full">
-										<text class="text-align-left text-overflow">
-											选项{{ optionIndex+1}}:{{option.title }}
-										</text>
+								<template v-if="vote.spec.isVoted">
+									<view v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
+										class="is-voted-item" :class="[option.checked?'selected':'']" :style="{
+											'--percent': option.percent + '%'
+										}">
+										<view class="is-voted-item-content flex w-full flex-between uh-gap-4">
+											<view class="text-align-left flex-1 text-break">
+												{{option.title }}
+											</view>
+											<view class="flex-shrink ">
+												{{option.percent }}%
+											</view>
+										</view>
 									</view>
-								</tm-button>
+								</template>
+								<template v-else>
+									<view v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
+										class="vote-select-option flex-1 w-full text-break"
+										:class="[option.checked?'light-blue':'grey-lighten-3']"
+										@click="handleSelectSingleOption(option)">
+										选项{{ optionIndex+1}}:{{option.title }}
+									</view>
+								</template>
 							</view>
 						</view>
 					</view>
@@ -101,8 +143,15 @@
 			</view>
 			<view class="vote-card-foot flex flex-between">
 				<view class="left flex">
-					<tm-tags color="grey-darken-2" rounded size="s"
-						model="text">{{ {d: vote.spec.endDate, f: 'yyyy-MM-dd HH:mm'} | formatTime }} 结束</tm-tags>
+					<tm-tags v-if="vote.spec.timeLimit==='permanent'" color="grey-darken-2" rounded size="s"
+						model="text">结束:永久有效 </tm-tags>
+					<tm-tags v-else color="grey-darken-2" rounded size="s" model="text">
+						<template
+							v-if="vote.spec._state=='未开始'">开始:{{ {d: vote.spec.startDate, f: 'yyyy-MM-dd HH:mm'} | formatTime }}
+						</template>
+						<template v-else>结束:{{ {d: vote.spec.endDate, f: 'yyyy-MM-dd HH:mm'} | formatTime }}
+						</template>
+					</tm-tags>
 				</view>
 
 				<view class="right flex flex-end">
@@ -114,7 +163,7 @@
 
 			<view v-if="submitForm.voteData.length!==0" class="box-border uh-mt-12 w-full uh-px-2">
 				<tm-button v-if="!vote.spec.canAnonymously" theme="red" :shadow="0" class="w-full" text :block="true"
-					:height="72" @click="handleSubmit()">不允许匿名投票</tm-button>
+					:height="72" @click="handleSubmit()">不支持匿名投票(点击)</tm-button>
 				<tm-button v-else-if="fnCalcIsVoted()" theme="white" text :block="true" :height="72"
 					class="w-full">您已参与投票</tm-button>
 				<tm-button v-else theme="light-blue" class="w-full" :block="true" :height="72"
@@ -184,6 +233,7 @@
 
 						tempVoteRes.vote.spec.isVoted = this.fnCalcIsVoted()
 						tempVoteRes.vote.spec.disabled = this.fnCalcIsVoted()
+						tempVoteRes.vote.spec._state = this.handleCalcVoteState(tempVoteRes.vote)
 
 						tempVoteRes.vote.spec.options.map((option, index) => {
 							option.value = option.id
@@ -236,7 +286,23 @@
 				const checked = data.selected.includes(option.id)
 				return checked
 			},
+			handleCalcVoteState(vote) {
+				if (vote.spec.timeLimit !== 'custom') {
+					return vote.spec.hasEnd ? "已结束" : "进行中"
+				}
 
+				const nowTime = new Date().getTime()
+				const startTime = new Date(vote.spec.startDate).getTime()
+				const endTime = new Date(vote.spec.endDate).getTime()
+
+				if (nowTime < startTime) {
+					return "未开始"
+				}
+				if (nowTime < endTime) {
+					return "进行中"
+				}
+				return vote.spec.hasEnd ? "已结束" : "进行中"
+			},
 			formatJsonStr(jsonStr) {
 				return jsonStr ? JSON.parse(jsonStr) : {}
 			},
@@ -251,12 +317,13 @@
 					uni.showModal({
 						icon: "none",
 						title: "提示",
-						content: "该投票不允许匿名,请到博主的 网站端 进行投票!",
+						content: "该投票不支持匿名,请到博主的 网站端 进行投票!",
 						cancelColor: "#666666",
 						cancelText: "关闭",
 						confirmText: "复制地址",
 						success: (res) => {
 							if (res.confirm) {
+								console.log("this.article",this.article)
 								const articleUrl = this.$baseApiUrl + (this.article?.status?.permalink ?? "")
 								this.$utils.copyText(articleUrl, "原文地址复制成功")
 							}
@@ -294,6 +361,10 @@
 			},
 
 			handleSelectSingleOption(option) {
+				if (this.vote.spec._state == '未开始') {
+					this.showToast(`投票未开始`)
+					return
+				}
 				if (this.vote.spec.disabled) return
 				this.vote.spec.options.map(item => {
 					if (option.id == item.id) {
@@ -306,15 +377,16 @@
 			},
 
 			handleSelectCheckboxOption(option) {
+				if (this.vote.spec._state == '未开始') {
+					this.showToast(`投票未开始`)
+					return
+				}
 				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} 项`
-					})
+					this.showToast(`最多选择 ${this.vote.spec.maxVotes} 项`)
 					return
 				}
 
@@ -324,6 +396,18 @@
 					}
 				})
 				this.submitForm.voteData = this.vote.spec.options.filter(x => x.checked).map(item => item.id)
+			},
+			handleToVoteDetail(vote) {
+				uni.navigateTo({
+					url: `/pagesA/vote-detail/vote-detail?name=${vote.metadata.name}`
+				});
+			},
+			showToast(content) {
+				uni.showToast({
+					icon: "none",
+					title: content,
+					mask: true
+				})
 			}
 		}
 	}
@@ -402,51 +486,59 @@
 		.left {}
 	}
 
+	.is-voted-item {
+		min-height: 72rpx;
+		box-sizing: border-box;
+		position: relative;
+		border-radius: 12rpx;
+		background-color: rgba(229, 229, 229, 0.75);
+		font-size: 24rpx;
+		overflow: hidden;
 
-	.single {
-		::v-deep {
-			.tm-groupradio {
-				width: 100%;
-				box-sizing: border-box;
-				display: flex;
-				flex-wrap: wrap;
-				gap: 12rpx 0;
-			}
+		&::before {
+			content: "";
+			width: var(--percent);
+			position: absolute;
+			left: 0;
+			top: 0;
+			bottom: 0;
+			background-color: rgba(208, 208, 208, 1);
+			z-index: 0;
+			border-radius: 6rpx;
+		}
 
-			.tm-checkbox {
-				box-sizing: border-box;
-				display: block;
-				padding: 0 12rpx;
-				width: 50%;
-			}
+		&.selected {
+			background-color: rgba(3, 169, 244, 0.35);
+			color: #ffffff;
 
-			.tm-button-label {
-				width: 100%;
+			&::before {
+				background-color: rgba(3, 169, 244, 1);
 			}
 		}
 	}
 
-	.multiple {
-		::v-deep {
-			.tm-groupcheckbox {
-				width: 100%;
-				box-sizing: border-box;
-				display: flex;
-				flex-wrap: wrap;
-				gap: 12rpx 0;
-			}
+	.is-voted-item-content {
+		box-sizing: border-box;
+		min-height: 72rpx;
+		padding: 12rpx 24rpx;
+		position: relative;
+		z-index: 2;
+	}
 
-			.tm-checkbox {
-				box-sizing: border-box;
-				display: block;
-				padding: 0 12rpx;
-				width: 50%;
-			}
+	.vote-select-option {
+		box-sizing: border-box;
+		padding: 20rpx 24rpx;
+		font-size: 24rpx;
+		border-radius: 12rpx;
+		transition: all 0.1s ease-in-out;
+	}
 
-			.tm-button-label {
-				width: 100%;
-			}
-		}
+	.single {
+		::v-deep {}
+	}
+
+	.multiple {
+		::v-deep {}
 	}
 
 	.pk {
@@ -455,6 +547,7 @@
 		padding: 0 12rpx;
 
 		::v-deep {
+
 			.pk-container {
 				box-sizing: border-box;
 				width: 100%;

+ 28 - 15
components/vote-card/vote-card.vue

@@ -1,7 +1,7 @@
 <template>
 	<view class="vote-card" @click="$emit('on-click',vote)">
 		<view class="vote-card-head flex">
-			<view class="left flex flex-center">
+			<view class="left flex flex-center w-full">
 				<view class="flex-shrink">
 					<tm-tags v-if="vote.spec.type==='single'" color="light-blue" :shadow="0" rounded size="s"
 						model="fill">单选</tm-tags>
@@ -14,12 +14,12 @@
 					{{ vote.spec.title }}
 				</view>
 			</view>
-			<view class="flex-shrink right flex flex-end">
+			<view v-if="false" class="flex-shrink right flex flex-end">
 				<tm-tags v-if="vote.spec.hasEnded" color="red" rounded :shadow="0" size="s" model="text">已结束</tm-tags>
 				<tm-tags v-else color="green" rounded size="s" :shadow="0" model="text">进行中</tm-tags>
 			</view>
 		</view>
-		<view class="vote-card-body">
+		<view class="vote-card-body w-full">
 
 			<view v-if="vote.spec.remark" class="remark text-overflow-2 text-size-s">
 				{{vote.spec.remark}}
@@ -94,13 +94,29 @@
 		</view>
 		<view class="vote-card-foot flex flex-between">
 			<view class="left flex">
-				<tm-tags color="grey-darken-2" rounded size="s"
-					model="text">{{ {d: vote.spec.endDate, f: 'yyyy-MM-dd HH:mm'} | formatTime }} 结束</tm-tags>
+				<tm-tags v-if="vote.spec._state=='已结束'" color="red" size="s" rounded :shadow="0"
+					model="text">已结束</tm-tags>
+				<tm-tags v-else-if="vote.spec._state=='未开始'" color="orange" size="s" rounded :shadow="0"
+					model="text">未开始</tm-tags>
+				<tm-tags v-else-if="vote.spec._state=='进行中'" color="green" size="s" rounded :shadow="0"
+					model="text">进行中</tm-tags>
+				
+				<tm-tags v-if="vote.spec.isVoted" color="blue" rounded size="s" model="text">已投票</tm-tags>
+
+				<tm-tags v-if="vote.spec.timeLimit==='permanent'" color="grey-darken-2" rounded size="s"
+					model="text">结束:永久有效 </tm-tags>
+				<tm-tags v-else color="grey-darken-2" rounded size="s" model="text">
+					<template
+						v-if="vote.spec._state=='未开始'">开始:{{ {d: vote.spec.startDate, f: 'yyyy-MM-dd HH:mm'} | formatTime }}
+					</template>
+					<template v-else>结束:{{ {d: vote.spec.endDate, f: 'yyyy-MM-dd HH:mm'} | formatTime }}
+					</template>
+				</tm-tags>
 			</view>
 
-			<view class="right flex flex-end">
-				<tm-tags color="grey-darken-2" rounded 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 v-if="false" class="right flex flex-end">
+				<tm-tags v-if="false" color="grey-darken-2" rounded size="s" model="text">{{ vote.stats.voteCount }}
+					人已参与</tm-tags>
 			</view>
 		</view>
 	</view>
@@ -140,8 +156,7 @@
 				type: Boolean,
 				default: false
 			}
-		},
-
+		}, 
 		methods: {
 			onOptionRadioChange(e) {
 				console.log("onOptionRadioChange", e)
@@ -197,9 +212,9 @@
 
 		.remark {
 			box-sizing: border-box;
-			padding: 12rpx 6rpx;
 			padding-top: 0;
 			color: rgba(0, 0, 0, 0.75);
+			margin-bottom: 12rpx;
 		}
 	}
 
@@ -208,10 +223,8 @@
 		padding-top: 6px;
 		margin-top: 6px;
 		border-top: 2rpx solid #F7F7F7;
-		
-		.left{
-			
-		}
+
+		.left {}
 	}
 
 

+ 1 - 1
pages/index/index.vue

@@ -15,7 +15,7 @@
 
 	const _DEV_ = false
 	const _DEV_TO_TYPE_ = "page"
-	const _DEV_TO_PATH_ = ""
+	const _DEV_TO_PATH_ = "/pagesA/article-detail/article-detail?name=077efb85-3544-4307-b24c-537a9e53f116"
 
 	export default {
 		mixins: [pluginAvailableMixin],

+ 31 - 18
pagesA/article-detail/article-detail.vue

@@ -115,23 +115,27 @@
 							{{ 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="{
+					<template v-if="reloadVote">
+						<view v-show="voteIsOpen" class="flex flex-col uh-gap-8 uh-mt-8">
+							<PluginUnavailable v-if="!uniHaloPluginAvailable" :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 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>
+							<template v-else>
+								<ArticleVote v-for="(voteId,voteIdIndex) in result._voteIds" :key="voteId"
+									:voteId="voteId" :article="result" :index="voteIdIndex">
+								</ArticleVote>
+
+							</template>
+						</view>
+						<view v-show="uniHaloPluginAvailable && !voteIsOpen" class="vote-tip"
+							@click="voteIsOpen=!voteIsOpen">
+							投票已收起,点击展开 {{result._voteIds.length}} 个投票项
+						</view>
+						<view v-show="!uniHaloPluginAvailable && !voteIsOpen" class="vote-tip"
+							@click="voteIsOpen=!voteIsOpen">
+							提示区域已收起,点击显示
+						</view>
+					</template>
 				</view>
 
 				<!-- 版权声明 -->
@@ -409,7 +413,8 @@
 
 				commentListScrollTop: 0,
 
-				voteIsOpen: true
+				voteIsOpen: true,
+				reloadVote: false
 			};
 		},
 		computed: {
@@ -469,7 +474,14 @@
 			this.queryParams.name = e.name;
 			this.fnGetData();
 		},
-
+		onShow() {
+			if (this.reloadVote) {
+				this.reloadVote = false
+				setTimeout(() => {
+					this.reloadVote = true
+				}, 100);
+			}
+		},
 		onPullDownRefresh() {
 			this.fnGetData();
 		},
@@ -540,6 +552,7 @@
 						this.result = tempResult;
 						this.fnSetPageTitle('文章详情');
 						this.loading = 'success';
+						this.reloadVote = true;
 						this.fnHandleSetFlotButtonItems(this.haloConfigs);
 						this.handleQueryCommentListScrollTop()
 					})

+ 205 - 95
pagesA/vote-detail/vote-detail.vue

@@ -23,9 +23,16 @@
 								model="fill">双选PK</tm-tags>
 						</view>
 						<view class="">
-							投票状态:<tm-tags v-if="vote.spec.hasEnded" color="red" size="xs" :shadow="0"
+							投票状态:<tm-tags v-if="vote.spec._state=='已结束'" color="red" size="xs" :shadow="0"
 								model="fill">已结束</tm-tags>
-							<tm-tags v-else color="green" size="xs" :shadow="0" model="fill">进行中</tm-tags>
+							<tm-tags v-else-if="vote.spec._state=='未开始'" color="orange" size="xs" :shadow="0"
+								model="fill">
+								未开始
+							</tm-tags>
+							<tm-tags v-else-if="vote.spec._state=='进行中'" color="green" size="xs" :shadow="0"
+								model="fill">
+								进行中
+							</tm-tags>
 						</view>
 						<view class="">
 							投票方式:<tm-tags v-if="vote.spec.canAnonymously" color="light-blue" size="xs" :shadow="0"
@@ -33,7 +40,15 @@
 							<tm-tags v-else color="red" size="xs" :shadow="0" model="fill">不匿名</tm-tags>
 						</view>
 						<view class="">
-							截止时间:{{ {d: vote.spec.endDate, f: 'yyyy-MM-dd HH:mm'} | formatTime }}
+							开始时间:{{ {d: vote.spec.startDate, f: 'yyyy-MM-dd HH:mm'} | formatTime }}
+						</view>
+						<view class="">
+							<text v-if="vote.spec.timeLimit==='permanent'">
+								结束时间:永久有效
+							</text>
+							<text v-else>
+								结束时间:{{ {d: vote.spec.endDate, f: 'yyyy-MM-dd HH:mm'} | formatTime }}
+							</text>
 						</view>
 					</view>
 				</view>
@@ -53,37 +68,57 @@
 								class="sub-title-count">(最多选择 {{ vote.spec.maxVotes }} 项)</text> </view>
 						<view v-if="vote.spec.type==='single'" class="single">
 							<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"
-									size="m" :height="72" :block="true" class="flex-1 w-full"
-									@click="handleSelectSingleOption(option)">
-									<view class="flex flex-between w-full">
-										<text class="text-align-left text-overflow">
-											{{option.title }}
-										</text>
-										<text v-if="vote.spec.isVoted" class="flex-shrink ml-12">
-											{{option.percent }}%
-										</text>
+								<template v-if="vote.spec.isVoted">
+									<view v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
+										class="is-voted-item" :class="[option.checked?'selected':'']" :style="{
+											'--percent':option.percent+ '%'
+										}">
+										<view class="is-voted-item-content flex w-full flex-between uh-gap-8">
+											<view class="flex-1 text-align-left text-break">
+												{{option.title }}
+											</view>
+											<view class="flex-shrink">
+												{{option.percent }}%
+											</view>
+										</view>
 									</view>
-								</tm-button>
+								</template>
+								<template v-else>
+									<view v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
+										class="vote-select-option flex-1 w-full text-break"
+										:class="[option.checked?'light-blue':'grey-lighten-3']"
+										@click="handleSelectSingleOption(option)">
+										{{option.title }}
+									</view>
+								</template>
 							</view>
 						</view>
 
 						<view v-else-if="vote.spec.type==='multiple'" class="multiple">
 							<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"
-									size="m" :height="72" :block="true" class="flex-1 full"
-									@click="handleSelectCheckboxOption(option)">
-									<view class="flex flex-between w-full">
-										<text class="text-align-left text-overflow">
-											{{option.title }}
-										</text>
-										<text v-if="vote.spec.isVoted" class="flex-shrink ml-12">
-											{{option.percent }}%
-										</text>
+								<template v-if="vote.spec.isVoted">
+									<view v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
+										class="is-voted-item" :class="[option.checked?'selected':'']" :style="{
+											'--percent':option.percent + '%'
+										}">
+										<view class="is-voted-item-content flex w-full flex-between uh-gap-8">
+											<view class="flex-1 text-align-left text-break">
+												{{option.title }}
+											</view>
+											<view class="flex-shrink">
+												{{option.percent }}%
+											</view>
+										</view>
 									</view>
-								</tm-button>
+								</template>
+								<template v-else>
+									<view v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
+										class="vote-select-option flex-1 w-full text-break"
+										:class="[option.checked?'light-blue':'grey-lighten-3']"
+										@click="handleSelectCheckboxOption(option)">
+										{{option.title }}
+									</view>
+								</template>
 							</view>
 						</view>
 
@@ -91,26 +126,37 @@
 							<view class="pk-container">
 								<view class="radio-item" v-for="(option,optionIndex) in vote.spec.options"
 									:key="optionIndex" :class="[optionIndex==0?'radio-left':'radio-right']"
-									:style="{width:option.percent + '%'}">
+									:style="{width: option.percent + '%'}">
 									<view class="option-item"
 										:class="[optionIndex==0?'option-item-left':'option-item-right']">
 										{{option.percent }}%
 									</view>
 								</view>
 							</view>
-							<view class="option-foot w-full flex flex-between">
-								<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"
-										size="m" :height="72" :block="true" class="flex-1"
-										@click="handleSelectSingleOption(option)">
-										<view class="flex flex-between w-full">
-											<text class="text-align-left text-overflow">
+							<view class="option-foot w-full flex flex-col uh-gap-8">
+								<template v-if="vote.spec.isVoted">
+									<view v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
+										class="is-voted-item" :class="[option.checked?'selected':'']" :style="{
+											'--percent': option.percent + '%'
+										}">
+										<view class="is-voted-item-content flex w-full flex-between uh-gap-8">
+											<view class="flex-1 text-align-left text-break">
 												选项{{ optionIndex+1}}:{{option.title }}
-											</text>
+											</view>
+											<view class="flex-shrink">
+												{{option.percent }}%
+											</view>
 										</view>
-									</tm-button>
-								</view>
+									</view>
+								</template>
+								<template v-else>
+									<view v-for="(option,optionIndex) in vote.spec.options" :key="optionIndex"
+										class="vote-select-option flex-1 w-full text-break"
+										:class="[option.checked?'light-blue':'grey-lighten-3']"
+										@click="handleSelectSingleOption(option)">
+										选项{{ optionIndex+1}}:{{option.title }}
+									</view>
+								</template>
 							</view>
 						</view>
 					</view>
@@ -122,21 +168,32 @@
 						<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>
+							<!-- <tm-tags v-if="vote.spec.isVoted" color="blue" rounded size="s" model="text">已投票</tm-tags> -->
 						</view>
 					</view>
 				</view>
+
+				<!-- 暂时不做,目前没有意义 -->
+				<!-- <view v-if="vote.spec.canSeeVoters" class="vote-card">
+					<view class="vote-card-body">
+						<view class="sub-title"> 投票用户 </view>
+						<view class="">
+							
+						</view>
+					</view>
+				</view> -->
+
 				<view class="vote-submit flex w-full flex-center" :style="{
 					paddingBottom:safeAreaBottom + 'rpx'
 				}">
 					<tm-button v-if="!vote.spec.canAnonymously" theme="red" :shadow="0" class="w-full" text
-						:block="true" @click="handleSubmit()">不允许匿名投票</tm-button>
+						: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>
+					<tm-button v-else theme="light-blue" class="w-full" :block="true" :loading="submitLoading"
+						:disabled="submitLoading" @click="handleSubmit()">提交投票</tm-button>
 				</view>
 			</block>
 		</block>
@@ -170,6 +227,7 @@
 			return {
 				safeAreaBottom: 24,
 				loading: 'loading',
+				submitLoading: false,
 				pageTitle: '加载中...',
 
 				name: '',
@@ -184,7 +242,7 @@
 		onLoad(e) {
 			this.name = e.name;
 			this.fnGetData();
-
+			this.fnGetVoteUserList();
 			// #ifndef H5
 			const systemInfo = uni.getSystemInfoSync();
 			this.safeAreaBottom = systemInfo.safeAreaInsets.bottom + 12;
@@ -192,6 +250,7 @@
 		},
 		onPullDownRefresh() {
 			this.fnGetData();
+			this.fnGetVoteUserList();
 		},
 		methods: {
 			fnGetData() {
@@ -207,6 +266,7 @@
 
 						tempVoteRes.vote.spec.isVoted = this.fnCalcIsVoted()
 						tempVoteRes.vote.spec.disabled = this.fnCalcIsVoted()
+						tempVoteRes.vote.spec._state = this.handleCalcVoteState(tempVoteRes.vote)
 
 						tempVoteRes.vote.spec.options.map((option, index) => {
 							option.value = option.id
@@ -227,9 +287,7 @@
 							return option
 						})
 
-
 						this.vote = tempVoteRes.vote
-						console.log("this.vote", this.vote)
 						this.detail = tempVoteRes;
 
 						setTimeout(() => {
@@ -249,6 +307,16 @@
 						}, 200);
 					});
 			},
+			fnGetVoteUserList() {
+				this.$httpApi.v2
+					.getVoteUserList(this.name)
+					.then(res => {
+						console.log("查询投票用户列表")
+					})
+					.catch(err => {
+						console.log("err")
+					})
+			},
 			fnCalcPercent(voteOption, stats) {
 				if (!this.fnCalcIsVoted()) return 0;
 				if (!stats?.voteDataList) return 0;
@@ -268,7 +336,23 @@
 				const checked = data.selected.includes(option.id)
 				return checked
 			},
+			handleCalcVoteState(vote) {
+				if (vote.spec.timeLimit !== 'custom') {
+					return vote.spec.hasEnd ? "已结束" : "进行中"
+				}
+
+				const nowTime = new Date().getTime()
+				const startTime = new Date(vote.spec.startDate).getTime()
+				const endTime = new Date(vote.spec.endDate).getTime()
 
+				if (nowTime < startTime) {
+					return "未开始"
+				}
+				if (nowTime < endTime) {
+					return "进行中"
+				}
+				return vote.spec.hasEnd ? "已结束" : "进行中"
+			},
 			onOptionRadioChange(e) {
 				this.submitForm.voteData = e.map(item => this.vote.spec.options[item.index]?.id);
 			},
@@ -281,18 +365,15 @@
 			formatJsonStr(jsonStr) {
 				return jsonStr ? JSON.parse(jsonStr) : {}
 			},
-			handleSubmitTip(){
-				uni.showToast({
-					icon: "none",
-					title: "请选择选项后继续"
-				})
+			handleSubmitTip() {
+				this.showToast("请选择选项后继续")
 			},
 			handleSubmit() {
 				if (!this.vote.spec.canAnonymously) {
 					uni.showModal({
 						icon: "none",
 						title: "提示",
-						content: "该投票不允许匿名,请到博主的 网站端 进行投票!",
+						content: "该投票不支持匿名,请到博主的 网站端 进行投票!",
 						cancelColor: "#666666",
 						cancelText: "关闭",
 						confirmText: "复制地址",
@@ -305,6 +386,7 @@
 					return
 				}
 
+				this.submitLoading = true
 				uni.showLoading({
 					title: "正在保存..."
 				})
@@ -312,11 +394,8 @@
 				this.$httpApi.v2
 					.submitVote(this.name, this.submitForm, this.vote.spec.canAnonymously)
 					.then(res => {
-						uni.showToast({
-							icon: "none",
-							title: "提交成功"
-						})
 
+						this.showToast("提交成功")
 						voteCacheUtil.set(this.name, {
 							selected: [...this.submitForm.voteData],
 							data: this.vote
@@ -324,18 +403,21 @@
 
 						setTimeout(() => {
 							uni.startPullDownRefresh()
+							this.submitLoading = false
 						}, 1500);
 					})
 					.catch(err => {
 						console.error(err);
-						uni.showToast({
-							icon: "none",
-							title: "提交失败,请重试"
-						})
+						this.showToast("提交失败,请重试")
+						this.submitLoading = false
 					})
 			},
 
 			handleSelectSingleOption(option) {
+				if (this.vote.spec._state == '未开始') {
+					this.showToast(`投票未开始`)
+					return
+				}
 				if (this.vote.spec.disabled) return
 				this.vote.spec.options.map(item => {
 					if (option.id == item.id) {
@@ -349,15 +431,16 @@
 			},
 
 			handleSelectCheckboxOption(option) {
+				if (this.vote.spec._state == '未开始') {
+					this.showToast(`投票未开始`)
+					return
+				}
 				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} 项`
-					})
+					this.showToast(`最多选择 ${this.vote.spec.maxVotes} 项`)
 					return
 				}
 
@@ -368,6 +451,13 @@
 				})
 
 				this.submitForm.voteData = this.vote.spec.options.filter(x => x.checked).map(item => item.id)
+			},
+			showToast(content) {
+				uni.showToast({
+					icon: "none",
+					title: content,
+					mask: true
+				})
 			}
 		}
 	};
@@ -460,54 +550,74 @@
 		border-top: 2rpx solid #eee;
 	}
 
+	.is-voted-item {
+		min-height: 72rpx;
+		box-sizing: border-box;
+		position: relative;
+		border-radius: 12rpx;
+		background-color: rgba(229, 229, 229, 0.75);
+		font-size: 24rpx;
+		overflow: hidden;
 
-	.single {
-		::v-deep {
-			.tm-groupradio {
-				box-sizing: border-box;
-				display: flex;
-				flex-wrap: wrap;
-				gap: 16rpx 0;
-			}
+		&::before {
+			content: "";
+			width: var(--percent);
+			position: absolute;
+			left: 0;
+			top: 0;
+			bottom: 0;
+			background-color: rgba(208, 208, 208, 1);
+			z-index: 0;
+			border-radius: 6rpx;
+		}
 
-			.tm-checkbox {
-				box-sizing: border-box;
-				// display: block;
-				// width: 100%;
-			}
+		&.selected {
+			background-color: rgba(3, 169, 244, 0.35);
+			color: #ffffff;
 
-			.tm-button-label {
-				width: 100%;
+			&::before {
+				background-color: rgba(3, 169, 244, 1);
 			}
 		}
 	}
 
-	.multiple {
-		::v-deep {
-			.tm-groupcheckbox {
-				box-sizing: border-box;
-				display: flex;
-				flex-wrap: wrap;
-				gap: 16rpx 0;
-			}
+	.is-voted-item-content {
+		box-sizing: border-box;
+		min-height: 72rpx;
+		padding: 12rpx 24rpx;
+		position: relative;
+		z-index: 2;
+	}
 
-			.tm-checkbox {
-				box-sizing: border-box;
-				// display: block;
-				// width: 100%;
-			}
+	.vote-select-option {
+		box-sizing: border-box;
+		padding: 20rpx 24rpx;
+		font-size: 24rpx;
+		border-radius: 12rpx;
+		transition: all 0.1s ease-in-out;
+	}
 
-			.tm-button-label {
-				width: 100%;
-			}
+
+	::v-deep {
+		.tm-button-label {
+			width: 100%;
 		}
 	}
 
+	.single {
+		::v-deep {}
+	}
+
+	.multiple {
+		::v-deep {}
+	}
+
 	.pk {
 		box-sizing: border-box;
 		width: 100%;
 
 		::v-deep {
+
 			.pk-container {
 				box-sizing: border-box;
 				width: 100%;

+ 18 - 1
pagesA/votes/votes.vue

@@ -260,7 +260,7 @@
 						const tempItems = res.items.map(item => {
 							item.spec.disabled = true
 							item.spec.isVoted = this.fnCalcIsVoted(item.metadata.name)
-
+							item.spec._state = this.handleCalcVoteState(item)
 							item.spec.options.map((option, index) => {
 
 								option.checked = this.fnCalcIsChecked(item.metadata.name, option)
@@ -326,6 +326,23 @@
 				const checked = data.selected.includes(option.id)
 				return checked
 			},
+			handleCalcVoteState(vote) {
+				if (vote.spec.timeLimit !== 'custom') {
+					return vote.spec.hasEnd ? "已结束" : "进行中"
+				}
+
+				const nowTime = new Date().getTime()
+				const startTime = new Date(vote.spec.startDate).getTime()
+				const endTime = new Date(vote.spec.endDate).getTime()
+
+				if (nowTime < startTime) {
+					return "未开始"
+				}
+				if (nowTime < endTime) {
+					return "进行中"
+				}
+				return vote.spec.hasEnd ? "已结束" : "进行中"
+			},
 			//跳转详情
 			fnToDetail(item) {
 				if (this.calcAuditModeEnabled) return;