本次新增由后台 virtualPayAudit 开关控制的审核模式,在该模式下: 1. 隐藏底部 Tab 栏的发布按钮 2. 隐藏空状态、分类页、个人页的发布入口 3. 隐藏帖子卡片、详情页、个人发布页的评论数及评价入口 4. 发布页在审核模式下直接拦截并跳转至首页 5. 详情页的用户评价及评价弹层在审核模式下隐藏,避免 UGC 判定
402 行
11 KiB
Vue
402 行
11 KiB
Vue
<template>
|
||
<view
|
||
class="fc-post-card"
|
||
:class="{ 'fc-post-card--compact': compact }"
|
||
hover-class="fc-post-card--active"
|
||
:hover-stay-time="80"
|
||
@click="$emit('click', post)"
|
||
>
|
||
<!-- 缩略图:有真实实拍图展示实拍大图;无图时展示分类图标微名片(分类名统一由下方分类标签承载,避免重复) -->
|
||
<view class="fc-post-card__thumb" :class="{ 'fc-post-card__thumb--badge': !thumbUrl }">
|
||
<image v-if="thumbUrl" class="fc-post-card__thumb-img" :src="thumbUrl" mode="aspectFill" :lazy-load="true" />
|
||
<view v-else class="fc-post-card__deco-badge">
|
||
<view class="fc-post-card__deco-halo">
|
||
<image class="fc-post-card__deco-icon" :src="categoryIconUrl(post.categoryId)" mode="aspectFit" :lazy-load="true" />
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 内容主体 -->
|
||
<view class="fc-post-card__body">
|
||
<view class="fc-post-card__title fc-ellipsis-2">{{ post.title }}</view>
|
||
<view v-if="post.isTop || post.categoryName || (post.tags && post.tags.length) || harvestBadge" class="fc-post-card__tags">
|
||
<text v-if="post.isTop" class="fc-tag fc-post-card__tag fc-post-card__tag--top">置顶</text>
|
||
<!-- 分类标签:列表卡片固定展示,图标 + 分类名 -->
|
||
<view v-if="post.categoryName" class="fc-tag fc-post-card__tag fc-post-card__tag--cat">
|
||
<image class="fc-post-card__tag-icon" :src="categoryIconUrl(post.categoryId)" mode="aspectFit" />
|
||
<text>{{ post.categoryName }}</text>
|
||
</view>
|
||
<!-- 农产品上市时间角标(阳光金,传递新鲜度与采购紧迫感) -->
|
||
<text v-if="harvestBadge" class="fc-tag fc-post-card__tag fc-post-card__tag--harvest">{{ harvestBadge }}</text>
|
||
<text v-for="t in (post.tags || []).slice(0, 2)" :key="t" class="fc-tag fc-post-card__tag">{{ t }}</text>
|
||
</view>
|
||
<view class="fc-post-card__meta">
|
||
<text class="fc-post-card__area">{{ post.area || '同城' }}</text>
|
||
<text v-if="distanceText" class="fc-post-card__dot">·</text>
|
||
<text v-if="distanceText" class="fc-post-card__distance">{{ distanceText }}</text>
|
||
<text class="fc-post-card__dot">·</text>
|
||
<text class="fc-post-card__time">{{ timeText }}</text>
|
||
</view>
|
||
<view class="fc-post-card__bottom">
|
||
<view class="fc-price fc-price--card">
|
||
<template v-if="post.price > 0">
|
||
<text class="fc-price__symbol">¥</text>
|
||
<text class="fc-post-card__amount">{{ post.price }}</text>
|
||
<text class="fc-post-card__unit">{{ post.priceUnit || '元' }}</text>
|
||
</template>
|
||
<!-- 无数值价格时展示用户自定义文本(如:面议 / 价格私聊),与发布页自由输入口径一致 -->
|
||
<text v-else class="fc-post-card__neg">{{ post.priceUnit || '面议' }}</text>
|
||
</view>
|
||
<view class="fc-post-card__stats">
|
||
<view class="fc-post-card__stat">
|
||
<image class="fc-post-card__stat-icon" :src="iconUrl('eye')" mode="aspectFit" />
|
||
<text class="fc-post-card__stat-num">{{ post.views || 0 }}</text>
|
||
</view>
|
||
<view v-if="!isAudit" class="fc-post-card__stat">
|
||
<image class="fc-post-card__stat-icon" :src="iconUrl('comment-gray')" mode="aspectFit" />
|
||
<text class="fc-post-card__stat-num">{{ post.commentCount || 0 }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { iconUrl, categoryIconUrl, uiState } from '@/common/store/ui.js'
|
||
import { fromNow, formatKm, assetUrl } from '@/common/utils/format.js'
|
||
|
||
export default {
|
||
name: 'FcPostCard',
|
||
props: {
|
||
/** 帖子数据模型 */
|
||
post: { type: Object, required: true },
|
||
/** 是否开启紧凑模式(适用于双联分栏、弹层等窄容器环境) */
|
||
compact: { type: Boolean, default: false },
|
||
},
|
||
computed: {
|
||
/**
|
||
* 是否处于提审防审模式(由后台 virtualPayAudit 开关统一控制)
|
||
* @returns {boolean} true=审核中(隐藏评论数统计)
|
||
*/
|
||
isAudit() {
|
||
return uiState.virtualPayAudit !== false
|
||
},
|
||
/** 相对发布时间描述 */
|
||
timeText() {
|
||
return fromNow(this.post.createdAt)
|
||
},
|
||
/** 距离文案(如「1.2km」);契约下发的 distance 为 km,信息无坐标时为 null 不展示 */
|
||
distanceText() {
|
||
return this.post.distance == null ? '' : formatKm(this.post.distance)
|
||
},
|
||
/**
|
||
* 农产品上市角标:解析采摘/上市日期(YYYY-MM-DD)提取月份,如「10月上市」
|
||
* 非标准日期格式(用户自定义文本)不展示角标,避免卡片排版溢出
|
||
*/
|
||
harvestBadge() {
|
||
const m = /^(\d{4})-(\d{1,2})(-\d{1,2})?$/.exec(String(this.post.harvestTime || '').trim())
|
||
return m ? `${parseInt(m[2], 10)}月上市` : ''
|
||
},
|
||
/**
|
||
* 帖子封面图:优先使用实际上传封面或第一张实拍图;
|
||
* 无图时回退为通用默认实拍图(农产品丰收场景 / 招聘货运场景),与有图卡片视觉一致
|
||
*/
|
||
thumbUrl() {
|
||
if (this.post.cover) {
|
||
return assetUrl(this.post.cover)
|
||
}
|
||
if (this.post.media && Array.isArray(this.post.media) && this.post.media.length) {
|
||
const first = this.post.media[0]
|
||
if (typeof first === 'string' && !first.match(/\.(mp4|mov|avi)$/i)) {
|
||
return assetUrl(first)
|
||
}
|
||
}
|
||
// 无图占位:招聘大类用货运场景,农产品用丰收场景(不在小程序包内,需拼后端域名)
|
||
const fallback = Number(this.post.categoryId) === 25 ? '/static/posts/job-default.jpg' : '/static/posts/farm-default.jpg'
|
||
return assetUrl(fallback)
|
||
},
|
||
},
|
||
methods: {
|
||
/** 暴露图标地址解析工具 */
|
||
iconUrl,
|
||
/** 暴露分类图标解析工具 */
|
||
categoryIconUrl,
|
||
},
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.fc-post-card {
|
||
display: flex;
|
||
padding: 24rpx;
|
||
margin: 0 24rpx 20rpx;
|
||
background: #ffffff;
|
||
border-radius: $fc-radius-lg;
|
||
box-shadow: 0 4rpx 16rpx rgba(4, 48, 30, 0.04), 0 10rpx 28rpx rgba(4, 48, 30, 0.03);
|
||
border: 1rpx solid rgba(4, 48, 30, 0.06);
|
||
cursor: pointer;
|
||
box-sizing: border-box;
|
||
transition: all 0.2s ease;
|
||
&:hover {
|
||
box-shadow: 0 8rpx 24rpx rgba(4, 48, 30, 0.1);
|
||
}
|
||
&:active,
|
||
&--active {
|
||
transform: scale(0.985);
|
||
opacity: 0.92;
|
||
}
|
||
}
|
||
|
||
/* 缩略图容器 */
|
||
.fc-post-card__thumb {
|
||
width: 180rpx;
|
||
height: 180rpx;
|
||
flex: 0 0 180rpx;
|
||
margin-right: 22rpx;
|
||
border-radius: 16rpx;
|
||
overflow: hidden;
|
||
background: #f1f5f9;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
|
||
/* 🌟 无实拍图时的分类主题徽章微卡片,精致现代 */
|
||
&--badge {
|
||
background: linear-gradient(145deg, #eefbf4 0%, #e1f7ec 100%);
|
||
border: 1rpx solid rgba(0, 224, 112, 0.18);
|
||
}
|
||
}
|
||
|
||
.fc-post-card__thumb-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.fc-post-card__deco-badge {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.fc-post-card__deco-halo {
|
||
width: 84rpx;
|
||
height: 84rpx;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, 0.88);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-shadow: 0 4rpx 14rpx rgba(4, 48, 30, 0.08);
|
||
}
|
||
|
||
.fc-post-card__deco-icon {
|
||
width: 50rpx;
|
||
height: 50rpx;
|
||
}
|
||
|
||
/* 内容主体 */
|
||
.fc-post-card__body {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-width: 0;
|
||
justify-content: space-between;
|
||
}
|
||
.fc-post-card__title {
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: $fc-text;
|
||
line-height: 1.4;
|
||
margin-bottom: 6rpx;
|
||
word-break: break-all;
|
||
}
|
||
.fc-post-card__tags {
|
||
display: flex;
|
||
flex-wrap: nowrap;
|
||
overflow: hidden;
|
||
gap: 8rpx;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
.fc-post-card__tag {
|
||
margin: 0;
|
||
font-size: 20rpx;
|
||
padding: 2rpx 10rpx;
|
||
white-space: nowrap;
|
||
flex-shrink: 0;
|
||
}
|
||
/* 分类标签:浅绿底 + 墨绿字(亮绿背景禁用白字),与全局 fc-tag 规范一致 */
|
||
.fc-post-card__tag--cat {
|
||
gap: 6rpx;
|
||
padding: 2rpx 14rpx 2rpx 10rpx;
|
||
font-weight: 600;
|
||
}
|
||
.fc-post-card__tag-icon {
|
||
width: 22rpx;
|
||
height: 22rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
.fc-post-card__tag--top {
|
||
background: linear-gradient(135deg, #00d26a 0%, #00bd5f 100%);
|
||
color: #ffffff;
|
||
font-weight: 700;
|
||
border-radius: 6rpx;
|
||
padding: 2rpx 10rpx;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 210, 106, 0.35);
|
||
}
|
||
/* 上市时间角标:阳光金浅底(价值/新鲜度信号),与全局价格色一致 */
|
||
.fc-post-card__tag--harvest {
|
||
background: #fdf3e0;
|
||
color: #b47411;
|
||
font-weight: 600;
|
||
border-radius: 6rpx;
|
||
padding: 2rpx 10rpx;
|
||
}
|
||
.fc-post-card__meta {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 22rpx;
|
||
color: $fc-text-placeholder;
|
||
margin-bottom: 8rpx;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
.fc-post-card__dot {
|
||
margin: 0 8rpx;
|
||
}
|
||
.fc-post-card__distance {
|
||
color: $fc-primary-text;
|
||
font-weight: 600;
|
||
}
|
||
.fc-post-card__bottom {
|
||
display: flex;
|
||
align-items: flex-end;
|
||
justify-content: space-between;
|
||
padding-top: 4rpx;
|
||
gap: 12rpx;
|
||
}
|
||
.fc-price--card {
|
||
display: flex;
|
||
align-items: baseline;
|
||
white-space: nowrap !important;
|
||
flex-shrink: 0;
|
||
}
|
||
.fc-post-card__amount {
|
||
font-size: 36rpx;
|
||
font-weight: 700;
|
||
line-height: 1;
|
||
white-space: nowrap !important;
|
||
}
|
||
.fc-post-card__neg {
|
||
font-size: 28rpx;
|
||
font-weight: 700;
|
||
color: $fc-price;
|
||
white-space: nowrap !important;
|
||
line-height: 1;
|
||
}
|
||
.fc-post-card__unit {
|
||
margin-left: 4rpx;
|
||
font-size: 22rpx;
|
||
color: $fc-text-secondary;
|
||
font-weight: 400;
|
||
white-space: nowrap !important;
|
||
}
|
||
.fc-post-card__stats {
|
||
display: flex;
|
||
align-items: center;
|
||
flex-shrink: 0;
|
||
white-space: nowrap;
|
||
}
|
||
.fc-post-card__stat {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-left: 16rpx;
|
||
}
|
||
.fc-post-card__stat-icon {
|
||
width: 26rpx;
|
||
height: 26rpx;
|
||
flex-shrink: 0;
|
||
opacity: 0.65;
|
||
}
|
||
.fc-post-card__stat-num {
|
||
margin-left: 6rpx;
|
||
font-size: 22rpx;
|
||
color: $fc-text-placeholder;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* 🌟 紧凑模式:双联分栏专属适配 */
|
||
.fc-post-card--compact {
|
||
margin: 0 0 16rpx 0;
|
||
padding: 16rpx 14rpx;
|
||
border-radius: 16rpx;
|
||
box-shadow: 0 2rpx 10rpx rgba(4, 48, 30, 0.05);
|
||
|
||
.fc-post-card__thumb {
|
||
width: 136rpx;
|
||
height: 136rpx;
|
||
flex: 0 0 136rpx;
|
||
margin-right: 14rpx;
|
||
border-radius: 12rpx;
|
||
}
|
||
.fc-post-card__deco-halo {
|
||
width: 64rpx;
|
||
height: 64rpx;
|
||
}
|
||
.fc-post-card__deco-icon {
|
||
width: 38rpx;
|
||
height: 38rpx;
|
||
}
|
||
.fc-post-card__title {
|
||
font-size: 27rpx;
|
||
line-height: 1.35;
|
||
margin-bottom: 4rpx;
|
||
max-height: 72rpx;
|
||
}
|
||
.fc-post-card__tags {
|
||
margin-bottom: 4rpx;
|
||
gap: 6rpx;
|
||
}
|
||
.fc-post-card__tag {
|
||
font-size: 18rpx;
|
||
padding: 2rpx 8rpx;
|
||
}
|
||
.fc-post-card__tag--cat {
|
||
padding: 2rpx 12rpx 2rpx 8rpx;
|
||
}
|
||
.fc-post-card__tag-icon {
|
||
width: 20rpx;
|
||
height: 20rpx;
|
||
}
|
||
.fc-post-card__meta {
|
||
font-size: 20rpx;
|
||
margin-bottom: 4rpx;
|
||
}
|
||
.fc-post-card__bottom {
|
||
padding-top: 2rpx;
|
||
gap: 8rpx;
|
||
}
|
||
.fc-post-card__amount {
|
||
font-size: 32rpx;
|
||
}
|
||
.fc-post-card__neg {
|
||
font-size: 26rpx;
|
||
}
|
||
.fc-post-card__stat {
|
||
margin-left: 10rpx;
|
||
}
|
||
.fc-post-card__stat-icon {
|
||
width: 22rpx;
|
||
height: 22rpx;
|
||
}
|
||
.fc-post-card__stat-num {
|
||
font-size: 20rpx;
|
||
}
|
||
}
|
||
</style>
|