feat(uniapp): restore home page design
This commit is contained in:
@@ -1,7 +1,18 @@
|
||||
<template>
|
||||
<view class="ai-entry" :class="[`ai-entry--${size}`, `ai-entry--align-${align}`]" @tap="goAssistant">
|
||||
<text class="ai-entry__line ai-entry__line--top">AI</text>
|
||||
<text class="ai-entry__line ai-entry__line--bottom">助手</text>
|
||||
<view class="ai-entry" :class="[`ai-entry--${size}`, `ai-entry--align-${align}`, `ai-entry--${variant}`]"
|
||||
@tap="goAssistant">
|
||||
<template v-if="variant === 'orb'">
|
||||
<view class="ai-entry__orb">
|
||||
<view class="ai-entry__face">
|
||||
<view class="ai-entry__eye" />
|
||||
<view class="ai-entry__eye" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<text class="ai-entry__line ai-entry__line--top">AI</text>
|
||||
<text class="ai-entry__line ai-entry__line--bottom">助手</text>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -9,9 +20,11 @@
|
||||
withDefaults(defineProps<{
|
||||
align?: 'left' | 'right'
|
||||
size?: 'compact' | 'regular' | 'large'
|
||||
variant?: 'badge' | 'orb'
|
||||
}>(), {
|
||||
align: 'left',
|
||||
size: 'regular'
|
||||
size: 'regular',
|
||||
variant: 'badge'
|
||||
})
|
||||
|
||||
const goAssistant = () => {
|
||||
@@ -60,6 +73,45 @@ const goAssistant = () => {
|
||||
--entry-bottom-font: 14rpx;
|
||||
}
|
||||
|
||||
&--orb {
|
||||
--entry-width: 72rpx;
|
||||
--entry-height: 72rpx;
|
||||
--entry-radius: 50%;
|
||||
|
||||
background: #f7f9ff;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&__orb {
|
||||
width: 54rpx;
|
||||
height: 54rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle at 34% 28%, #8ec4ff 0%, #387df6 48%, #1557dc 100%);
|
||||
box-shadow: 0 5rpx 10rpx rgba(20, 104, 245, 0.2);
|
||||
}
|
||||
|
||||
&__face {
|
||||
width: 37rpx;
|
||||
height: 25rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
padding: 0 6rpx;
|
||||
border-radius: 14rpx;
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&__eye {
|
||||
width: 6rpx;
|
||||
height: 11rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #1f61e8;
|
||||
}
|
||||
|
||||
&__line {
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
|
||||
@@ -2,25 +2,25 @@
|
||||
<navigator :url="`/pages/news_detail/news_detail?id=${item.id}`" class="feed-card">
|
||||
<view class="feed-card__body">
|
||||
<view class="feed-card__info">
|
||||
<view class="feed-card__title">{{ item.title }}</view>
|
||||
<view v-if="descText" class="feed-card__desc">{{ descText }}</view>
|
||||
<text class="feed-card__title">{{ item.title }}</text>
|
||||
<text v-if="descText" class="feed-card__desc">{{ descText }}</text>
|
||||
<view class="feed-card__footer">
|
||||
<text class="feed-card__author">{{ authorText }}</text>
|
||||
<view class="feed-card__footer-right">
|
||||
<text class="feed-card__meta">{{ item.comment_count || item.click || 0 }}阅读</text>
|
||||
<text class="feed-card__meta">{{ formatTime(item.create_time) }}</text>
|
||||
<text class="feed-card__time">{{ formatRelativeTime(item.create_time) }}</text>
|
||||
<view class="feed-card__comments">
|
||||
<view class="feed-card__comment-icon" />
|
||||
<text>{{ item.comment_count || item.click || 0 }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<UImage v-if="item.image" :src="item.image" width="220" height="140" border-radius="8" mode="aspectFill"
|
||||
class="feed-card__img" />
|
||||
<image v-if="item.image && !imageFailed" :src="item.image" mode="aspectFill" class="feed-card__img"
|
||||
referrerpolicy="no-referrer" @error="imageFailed = true" />
|
||||
</view>
|
||||
</navigator>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import UImage from '@/uni_modules/vk-uview-ui/components/u-image/u-image.vue'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -31,119 +31,145 @@ const props = withDefaults(
|
||||
}
|
||||
)
|
||||
|
||||
const imageFailed = ref(false)
|
||||
|
||||
const stripHtml = (html: string) => {
|
||||
if (!html) return ''
|
||||
return html.replace(/<[^>]+>/g, '').replace(/ /g, ' ').replace(/\s+/g, ' ').trim()
|
||||
return html.replace(/<[^>]+>/g, ' ').replace(/ /g, ' ').replace(/\s+/g, ' ').trim()
|
||||
}
|
||||
|
||||
const descText = computed(() => {
|
||||
if (props.item.desc) return props.item.desc
|
||||
if (props.item.content) return stripHtml(props.item.content).substring(0, 100)
|
||||
return ''
|
||||
return stripHtml(props.item.desc || props.item.content || '').slice(0, 72)
|
||||
})
|
||||
|
||||
const authorText = computed(() => {
|
||||
const rawAuthor = String(props.item.author || '')
|
||||
const cleanedAuthor = rawAuthor.replace(/@懂球帝/g, '').trim()
|
||||
return cleanedAuthor || '体育小编'
|
||||
return cleanedAuthor || 'SB 体育头条'
|
||||
})
|
||||
|
||||
const formatTime = (t: string) => {
|
||||
if (!t) return ''
|
||||
const d = new Date(t.replace(/-/g, '/'))
|
||||
if (isNaN(d.getTime())) return t
|
||||
const m = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
const h = String(d.getHours()).padStart(2, '0')
|
||||
const min = String(d.getMinutes()).padStart(2, '0')
|
||||
return `${m}-${day} ${h}:${min}`
|
||||
const formatRelativeTime = (time: string) => {
|
||||
if (!time) return ''
|
||||
const date = new Date(String(time).replace(/-/g, '/'))
|
||||
const delta = Date.now() - date.getTime()
|
||||
if (Number.isNaN(date.getTime()) || delta < 0) return String(time)
|
||||
const minute = 60 * 1000
|
||||
if (delta < minute) return '刚刚'
|
||||
if (delta < 60 * minute) return `${Math.floor(delta / minute)}分钟前`
|
||||
if (delta < 24 * 60 * minute) return `${Math.floor(delta / (60 * minute))}小时前`
|
||||
if (delta < 7 * 24 * 60 * minute) return `${Math.floor(delta / (24 * 60 * minute))}天前`
|
||||
return `${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.feed-card {
|
||||
display: block;
|
||||
padding: 20rpx 20rpx;
|
||||
padding: 22rpx 20rpx;
|
||||
background: #fff;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
border-top: 1rpx solid #edf0f5;
|
||||
|
||||
&:first-child {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
&__body {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
gap: 20rpx;
|
||||
align-items: flex-start;
|
||||
min-height: 144rpx;
|
||||
}
|
||||
|
||||
&__info {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #111;
|
||||
line-height: 1.45;
|
||||
white-space: nowrap;
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: #151b26;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
&__desc {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-top: 8rpx;
|
||||
white-space: nowrap;
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-top: 8rpx;
|
||||
color: #7c8798;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.42;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 18rpx;
|
||||
min-width: 0;
|
||||
margin-top: auto;
|
||||
padding-top: 12rpx;
|
||||
gap: 16rpx;
|
||||
white-space: nowrap;
|
||||
color: #909aaa;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
&__author,
|
||||
&__time {
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&__author {
|
||||
flex: 1;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: left;
|
||||
max-width: 156rpx;
|
||||
}
|
||||
|
||||
&__footer-right {
|
||||
&__comments {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 12rpx;
|
||||
margin-left: auto;
|
||||
flex-shrink: 0;
|
||||
gap: 6rpx;
|
||||
min-width: 0;
|
||||
margin-left: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__meta {
|
||||
font-size: 24rpx;
|
||||
color: #bbb;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
&__comment-icon {
|
||||
position: relative;
|
||||
width: 24rpx;
|
||||
height: 19rpx;
|
||||
box-sizing: border-box;
|
||||
border: 2rpx solid #8e99a9;
|
||||
border-radius: 10rpx;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 1rpx;
|
||||
bottom: -5rpx;
|
||||
width: 7rpx;
|
||||
height: 7rpx;
|
||||
box-sizing: border-box;
|
||||
border-right: 2rpx solid #8e99a9;
|
||||
border-bottom: 2rpx solid #8e99a9;
|
||||
background: #fff;
|
||||
transform: rotate(28deg);
|
||||
}
|
||||
}
|
||||
|
||||
&__img {
|
||||
width: 216rpx;
|
||||
height: 144rpx;
|
||||
flex-shrink: 0;
|
||||
border-radius: 12rpx;
|
||||
background: #eef1f5;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user