Files
1818uniapp/src/components/WorkCard/index.vue
2026-02-13 17:36:42 +08:00

223 lines
4.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="work-card" hover-class="none" @click="handleClick">
<!-- 视频/图片内容 -->
<view class="content-wrapper" hover-class="none">
<!-- 视频作品页面可见时用video显示首帧隐藏时卸载释放名额 -->
<video
v-if="work.contentType === 2 && pageVisible"
class="content-video"
:src="work.contentUrl"
:autoplay="false"
:loop="false"
:muted="true"
:show-play-btn="false"
:show-center-play-btn="false"
:controls="false"
:enable-progress-gesture="false"
object-fit="cover"
/>
<view
v-else-if="work.contentType === 2"
class="content-video video-placeholder"
></view>
<image
v-else
class="content-image"
:src="work.contentUrl"
mode="widthFix"
lazy-load
/>
<!-- 视频类型标识 - 右上角 -->
<view class="video-badge" v-if="work.contentType === 2">
<image class="video-icon" src="/static/icons/video.png" mode="aspectFit" />
</view>
</view>
<!-- 信息区域 -->
<view class="info">
<!-- 标题 -->
<text class="title">{{ truncateTitle(work.title) }}</text>
<!-- 底部作者和点赞 -->
<view class="bottom">
<view class="author">
<image class="avatar" :src="work.avatar || '/static/images/default-avatar.png'" mode="aspectFill" />
<text class="nickname">{{ work.nickname || '匿名用户' }}</text>
</view>
<view class="like" @click.stop="handleLike">
<image
class="like-icon"
:src="work.liked ? '/static/icons/heart-filled.png' : '/static/icons/heart.png'"
mode="aspectFit"
/>
<text class="like-count">{{ formatCount(work.likeCount) }}</text>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { toggleLike } from '@/api/work'
import { checkLogin } from '@/utils/auth'
import { useUserStore } from '@/store/modules/user'
const props = defineProps({
work: {
type: Object,
required: true
},
pageVisible: {
type: Boolean,
default: true
}
})
const emit = defineEmits(['click', 'like-change'])
const userStore = useUserStore()
// 截断标题最多14个字
const truncateTitle = (title) => {
if (!title) return ''
return title.length > 14 ? title.slice(0, 14) + '...' : title
}
const formatCount = (count) => {
if (!count) return '0'
if (count >= 10000) {
return (count / 10000).toFixed(1) + 'w'
}
if (count >= 1000) {
return (count / 1000).toFixed(1) + 'k'
}
return count.toString()
}
const handleClick = () => {
emit('click', props.work)
}
const handleLike = async () => {
// 检查登录
if (!checkLogin()) return
try {
const result = await toggleLike(props.work.id)
emit('like-change', { id: props.work.id, liked: result.liked, likeCount: result.likeCount })
} catch (e) {
console.error('点赞操作失败', e)
}
}
</script>
<style scoped>
.work-card {
border-radius: 12px;
overflow: hidden;
margin-bottom: 12px;
-webkit-transform: translateZ(0);
transform: translateZ(0);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.content-wrapper {
position: relative;
width: 100%;
border-radius: 12px;
overflow: hidden;
-webkit-transform: translateZ(0);
transform: translateZ(0);
}
.content-video {
width: 100%;
height: 200px;
display: block;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.video-placeholder {
background-color: #1a1a1a;
}
.content-image {
width: 100%;
display: block;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
will-change: transform;
}
.video-badge {
position: absolute;
right: 8px;
top: 8px;
}
.video-icon {
width: 24px;
height: 24px;
}
.info {
padding: 8px 4px 10px;
}
.title {
font-size: 14px;
color: #f1f5f9;
line-height: 1.4;
}
.bottom {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 8px;
}
.author {
display: flex;
align-items: center;
flex: 1;
min-width: 0;
}
.avatar {
width: 20px;
height: 20px;
border-radius: 50%;
flex-shrink: 0;
}
.nickname {
font-size: 12px;
color: #71717a;
margin-left: 6px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.like {
display: flex;
align-items: center;
flex-shrink: 0;
padding: 4px 0 4px 8px;
}
.like-icon {
width: 16px;
height: 16px;
}
.like-count {
font-size: 12px;
color: #71717a;
margin-left: 4px;
}
</style>