feat: 更新点赞功能样式和交互效果

- 替换点赞图标为红色版本
- 添加点赞动画效果
- 优化点赞交互体验
- 更新开发环境配置
- 修复缓存处理逻辑
This commit is contained in:
DESKTOP-RQ919RC\Pc
2025-08-22 11:25:14 +08:00
parent 01e8a789d8
commit 637aad70fc
71 changed files with 538 additions and 399 deletions

View File

@@ -685,7 +685,8 @@ const selectEomjiListPop = (key) => {
const { $cache } = useNuxtApp();
try {
if (process.server) {
if (process.env.NODE_ENV === 'development') {}
else if (process.server) {
console.log(`----------------------------------`);
const cacheKey = `details_${id}`;
@@ -699,8 +700,6 @@ try {
seo.value = data.seo;
} else {
await detailsHttp({ uniqid: id }).then((res) => {
// console.log("res", res);
if (res.code == 200) {
let data = res.data;
info.value = data["info"];

View File

@@ -11,8 +11,8 @@
<div class="halving-line"></div>
<div class="search-result"> {{ count }} 条搜索数据</div>
</div>
<div class="vote-list-box" :class="{ 'firstdata': firstdataState }" ref="gridContainer" v-loading="loading">
<a class="vote-item" target="_blank" :href="`/details/${item['uniqid']}?colorI=${index % 6}`" v-for="(item, index) in list" :key="index" :class="{ 'isvote': item['isvote'] == 1 || item['status'] == 0 }" :style="{ '--main-color': colourValue[index % 6]['main'], '--bg-color': colourValue[index % 6]['bg'], '--bc-color': colourValue[index % 6]['bc'] }">
<div class="vote-list-box" :class="{ firstdata: firstdataState }" ref="gridContainer" v-loading="loading">
<a class="vote-item" target="_blank" :href="`/details/${item['uniqid']}?colorI=${index % 6}`" v-for="(item, index) in list" :key="index" :class="{ isvote: item['isvote'] == 1 || item['status'] == 0 }" :style="{ '--main-color': colourValue[index % 6]['main'], '--bg-color': colourValue[index % 6]['bg'], '--bc-color': colourValue[index % 6]['bc'] }">
<div class="vote-title">
<div class="vote-state" v-if="item['status'] == 1">进行中</div>
<div class="vote-state finish" v-else>已结束</div>
@@ -20,8 +20,8 @@
</div>
<div class="vote-explain">{{ item["message"] }}</div>
<div class="vote-option-list flexflex">
<div class="vote-option-item flexflex" :class="{ 'pitch': item.selected == 1 }" v-for="(item, index) in item?.option" :key="index">
<div class="flexflex" style="padding: 2px 0;">
<div class="vote-option-item flexflex" :class="{ pitch: item.selected == 1 }" v-for="(item, index) in item?.option" :key="index">
<div class="flexflex" style="padding: 2px 0">
<div class="vote-option-number flexcenter">{{ index + 1 }}</div>
<img class="tick-icon" src="@/assets/img/tick-black.svg" />
<div class="vote-option-content flex1">{{ item["value"] }}</div>
@@ -40,7 +40,7 @@
<div class="vote-data-item flexacenter"><img class="vote-data-icon" src="@/assets/img/eye-icon.svg" />&nbsp; {{ item.views }}</div>
<div class="vote-data-item flexacenter" @click.stop.prevent="handleLike(item['token'], index)">
<img v-if="item['islike'] == 0" class="vote-data-icon" src="@/assets/img/like-icon-gray.png" />
<img v-else class="vote-data-icon" src="@/assets/img/like-yes.png" />&nbsp; {{ item["likes"] }}
<img v-else class="vote-data-icon" src="@/assets/img/like-red-pitch.png" />&nbsp; {{ item["likes"] }}
<!-- <img class="vote-data-icon" src="@/assets/img/expression-icon.png" />&nbsp; {{ item["ripostes"] }} -->
</div>
<div class="vote-data-item flexacenter"><img class="vote-data-icon" src="@/assets/img/comment-icon.svg" />&nbsp; {{ item["comments"] }}</div>
@@ -49,57 +49,59 @@
</a>
<div class="empty-box flexcenter" v-if="keyword && list.length == 0 && !loading"><Empty :isNeedIssue="true"></Empty></div>
</div>
<Like v-if="isLikeGif"></Like>
</template>
<script setup>
useHead({ script: [{ src: "https://app.gter.net/bottom?tpl=header&menukey=vote" }, { src: "https://app.gter.net/bottom?tpl=footer,popupnotification", body: true }] })
useHead({ script: [{ src: "https://app.gter.net/bottom?tpl=header&menukey=vote" }, { src: "https://app.gter.net/bottom?tpl=footer,popupnotification", body: true }] });
let isNeedLogin = inject("isNeedLogin")
const goLogin = inject("goLogin")
import { useRoute } from "vue-router"
const route = useRoute()
const router = useRouter()
let keyword = ref("")
let page = ref(1) // 投票页数从 1 开始
let count = ref(0)
let list = ref([])
let loading = ref(false) // 加载中
let isNeedLogin = inject("isNeedLogin");
const goLogin = inject("goLogin");
const firstdataState = ref(true)
import { useRoute } from "vue-router";
const route = useRoute();
const router = useRouter();
let keyword = ref("");
let page = ref(1); // 投票页数从 1 开始
let count = ref(0);
let list = ref([]);
let loading = ref(false); // 加载中
keyword.value = route.query["keyword"]
const gridContainer = ref(null)
let masonryInstance = null
const firstdataState = ref(true);
keyword.value = route.query["keyword"];
const gridContainer = ref(null);
let masonryInstance = null;
onMounted(async () => {
let Masonry = await import("masonry-layout")
let Masonry = await import("masonry-layout");
masonryInstance = new Masonry.default(gridContainer.value, {
itemSelector: ".vote-item",
gutter: 22.5,
})
getList()
window.addEventListener("scroll", handleScroll)
})
});
getList();
window.addEventListener("scroll", handleScroll);
});
const getList = () => {
if (page.value == 0 || loading.value) return
if (page.value == 0 || loading.value) return;
loading.value = true
loading.value = true;
getListHttp({ page: page.value, keyword: keyword.value, limit: 20 })
.then(res => {
.then((res) => {
if (res.code != 200) {
page.value = 0
ElMessage.error(res.message)
return
page.value = 0;
ElMessage.error(res.message);
return;
}
let data = res.data
let data = res.data;
list.value = list.value.concat(data.data)
count.value = data.count
if (data.count > list.value.length) page.value++
else page.value = 0
list.value = list.value.concat(data.data);
count.value = data.count;
if (data.count > list.value.length) page.value++;
else page.value = 0;
firstdataState.value = false
firstdataState.value = false;
// data.data.forEach((element, index) => {
// // let uniqidEnd = element["uniqid"].charAt(element["uniqid"].length - 1)
@@ -108,27 +110,29 @@ const getList = () => {
// })
nextTick(() => {
masonryInstance.reloadItems()
masonryInstance.layout()
})
masonryInstance.reloadItems();
masonryInstance.layout();
});
})
.finally(() => (loading.value = false))
}
.finally(() => (loading.value = false));
};
const handleScroll = () => {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
const scrollHeight = document.documentElement.scrollHeight
const clientHeight = document.documentElement.clientHeight
const scrollHeight = document.documentElement.scrollHeight;
const clientHeight = document.documentElement.clientHeight;
// 列表下 滑动到底部 获取新数据
if (scrollTop + clientHeight >= scrollHeight - 40) getList()
}
if (scrollTop + clientHeight >= scrollHeight - 40) getList();
};
const userInfoWin = inject("userInfoWin");
let openAttest = inject("openAttest");
const realname = inject("realname");
let isLikeGif = ref(false);
let isLikeTimer = null
// 处理点赞
const handleLike = (token, index) => {
if (realname.value == 0 && userInfoWin.value.uin > 0) {
@@ -137,48 +141,59 @@ const handleLike = (token, index) => {
}
if (isNeedLogin.value) {
goLogin()
return
goLogin();
return;
}
operateLikeHttp({ token }).then(res => {
operateLikeHttp({ token }).then((res) => {
if (res.code != 200) {
ElMessage.error(res.message)
return
ElMessage.error(res.message);
return;
}
let data = res.data
let data = res.data;
const status = data["status"];
list.value[index].likes = data["count"]
list.value[index].islike = data["status"]
ElMessage.success(res.message)
})
}
list.value[index].likes = data["count"];
list.value[index].islike = status;
ElMessage.success(res.message);
if (status) {
isLikeGif.value = false;
clearTimeout(isLikeTimer);
nextTick(() => {
isLikeGif.value = true;
isLikeTimer = setTimeout(() => (isLikeGif.value = false), 2000);
});
}
});
};
// 使用 process.client 判断是否在浏览器环境下
const isServer = computed(() => {
return process.server // 使用 process.client 判断是否在浏览器环境下
})
return process.server; // 使用 process.client 判断是否在浏览器环境下
});
// 点击关闭搜索
const closeKeyword = () => router.push("./index.html")
const closeKeyword = () => router.push("./index.html");
watch(
() => route.query,
() => {
keyword.value = route.query["keyword"]
page.value = 1
list.value = []
count.value = 0
getList()
keyword.value = route.query["keyword"];
page.value = 1;
list.value = [];
count.value = 0;
getList();
}
)
);
try {
if (process.server) {
await getListHttp({ page: 1, keyword: keyword.value }).then(res => {
let data = res.data
list.value = list.value.concat(data.data)
count.value = data.count
})
if (process.env.NODE_ENV === 'development') {}
else if (process.server) {
await getListHttp({ page: 1, keyword: keyword.value }).then((res) => {
let data = res.data;
list.value = list.value.concat(data.data);
count.value = data.count;
});
}
} catch (error) {}
</script>