Files
ctms-client/uni_modules/uni-cms-article/components/uni-cms-article-list/uni-cms-article-list.vue
fm453 c62d15b288 首次完整推送,
V:1.20240808.006
2024-08-13 18:32:37 +08:00

372 lines
9.3 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>
<unicloud-db
ref='udb'
v-slot:default="{ data, pagination, hasMore, loading, error }"
:collection="collectionList"
:page-size="10"
:loadtime="loadTime"
orderby="publish_date desc"
@load="onListLoad"
@error="onListLoadError"
>
<view
v-if="networkType == 'none'"
class="error-box"
@click="checkNetwork"
>
<image class="disconnect-icon" src="/uni_modules/uni-cms-article/static/disconnection.png" mode="widthFix"></image>
<text class="tip-text">当前网络不可用请点击重试</text>
</view>
<list-view
v-else
class="list-view"
:scroll-y="true"
:refresher-enabled="refresherEnabled"
refresher-default-style="none"
:refresher-triggered="refresherTriggered"
@refresherpulling="refresherpulling"
@refresherrefresh="refresherrefresh"
@scrolltolower="scrolltolower"
>
<list-item slot="refresher" class="refresh-box">
<text class="text">{{ refreshText[refreshState] }}</text>
</list-item>
<!-- 列表渲染 -->
<list-item
v-for="item in articleList"
:class="['list-item', `list-item__thumbnail-${item.thumbnail.length}`]"
:key="item._id"
@click="goToDetailPage(item)"
>
<template v-if="item.thumbnail.length == 0">
<view class="list-item__content">
<view class="list-item__content-title">
<text class="text">{{ item.title }}</text>
</view>
<view class="list-item__content-info">
<view class="list-item__author">
<text class="text">{{ item!.user_id!.length > 0 ? item.user_id[0].nickname : '' }}</text>
</view>
<view class="list-item__publish-date">
<text class="text">{{ publishTime(item.publish_date) }}</text>
</view>
</view>
</view>
</template>
<template v-if="item.thumbnail.length == 1">
<view class="list-item__content">
<view class="list-item__content-title">
<text class="text">{{ item.title }}</text>
</view>
<view class="list-item__content-info">
<view class="list-item__author">
<text class="text">{{ item!.user_id!.length > 0 ? item.user_id[0].nickname : '' }}</text>
</view>
<view class="list-item__publish-date">
<text class="text">{{ publishTime(item.publish_date) }}</text>
</view>
</view>
</view>
<view class="list-item__thumbnails">
<image
v-for="image in item.thumbnail"
:src="image"
mode="aspectFill"
class="list-item__img"
></image>
</view>
</template>
<template v-if="item.thumbnail.length == 3">
<view class="list-item__content">
<view class="list-item__content-title">
<text>{{ item.title }}</text>
</view>
<view class="list-item__thumbnails">
<image
v-for="image in item.thumbnail"
:src="image"
mode="aspectFill"
class="list-item__img"
></image>
</view>
<view class="list-item__content-info">
<view class="list-item__author">
<text class="text">{{ item!.user_id!.length > 0 ? item.user_id[0].nickname : '' }}</text>
</view>
<view class="list-item__publish-date">
<text class="text">{{ publishTime(item.publish_date) }}</text>
</view>
</view>
</view>
</template>
</list-item>
<list-item class="load-state">
<text class="text">{{ loading ? '加载中...' : (hasMore ? '上拉加载更多' : '没有更多数据了') }}</text>
</list-item>
</list-view>
</unicloud-db>
</template>
<script lang="uts">
type ArticleAuthor = {
_id: string
nickname: string
}
type ArticleItem = {
_id: string
title: string
publish_date: number
thumbnail: string[]
user_id: ArticleAuthor[]
}
import {parseImageUrl} from "@/uni_modules/uni-cms-article/common/parse-image-url.uts";
import translatePublishTime from "@/uni_modules/uni-cms-article/common/publish-time.uts";
import type {ParseImageUrlResult} from '@/uni_modules/uni-cms-article/common/parse-image-url.uts'
export default {
name: "uni-cms-article-list",
emits: ['onRefresh', 'onLoadMore'],
props: {
collectionList: {
type: Array as any[],
default: (): any[] => []
},
loadTime: {
type: String,
default: 'auto'
},
refresherEnabled: {
type: Boolean,
default: false
}
},
data() {
return {
articleList: [] as ArticleItem[],
refresherTriggered: false,
refreshState: 0,
refreshText: [
'继续下拉执行刷新',
'释放立即刷新',
'正在加载中',
'加载成功'
],
networkType: ""
}
},
mounted () {
this.checkNetwork()
},
methods: {
checkNetwork() {
uni.getNetworkType({
success: (res) => {
this.networkType = res.networkType;
}
});
},
publishTime(timestamp: number): string {
return translatePublishTime(timestamp)
},
async onListLoad(data: UTSJSONObject[], ended: boolean, pagination: UTSJSONObject): Promise<void> {
const listData: ArticleItem[] = data.map((item: UTSJSONObject): ArticleItem => {
let articleItem: ArticleItem = {
_id: item.getString('_id')!,
title: item.getString('title')!,
publish_date: item.getNumber('publish_date')!,
thumbnail: [],
user_id: item.getArray<ArticleAuthor>('user_id')! as ArticleAuthor[]
}
if (typeof item.getAny('thumbnail') === 'string') {
articleItem.thumbnail = [item.getAny('thumbnail')! as string]
} else {
articleItem.thumbnail = item.getArray<string>('thumbnail')!
}
return articleItem
})
// 处理cloud://文件链接
for (let i = 0; i < listData.length; i++) {
const article = listData[i]
const parseImages = await parseImageUrl(article.thumbnail)
if (parseImages != null) {
article.thumbnail = parseImages.map((image: ParseImageUrlResult): string => image.src)
}
}
this.articleList = pagination.getNumber('current') == 1 ? listData : this.articleList.concat(listData)
},
refresherrefresh() {
this.refresherTriggered = true
this.refreshState = 2;
(this.$refs['udb'] as UniCloudDBElement)!.loadData({
clear: true,
success: (_: any) => {
this.refresherTriggered = false
this.refreshState = 3
}
})
},
refresherpulling(e: RefresherEvent) {
if (e.detail.dy.toDouble() == 0.0) {
this.refreshState = 0
} else if (e.detail.dy > 45) {
this.refreshState = 1
}
},
scrolltolower() {
(this.$refs['udb'] as UniCloudDBElement)!.loadMore()
},
reLoadList() {
(this.$refs['udb'] as UniCloudDBElement)!.loadData({
clear: true
})
},
goToDetailPage(article: ArticleItem) {
uni.navigateTo({
url: `/uni_modules/uni-cms-article/pages/detail/detail?id=${article._id}&title=${article.title}`
})
},
onListLoadError () {
this.checkNetwork()
}
}
}
</script>
<style scoped lang="scss">
.refresh-box {
display: flex;
align-items: center;
justify-content: center;
.text {
padding: 30rpx 0;
font-size: 26rpx;
color: #999999;
}
}
.error-box {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
margin: 0 auto;
align-items: center;
justify-content: center;
.disconnect-icon {
width: 200rpx;
margin: 0 auto;
}
.tip-text {
font-size: 26rpx;
color: #333;
margin-top: 40rpx;
}
}
.load-state {
height: 90rpx;
display: flex;
align-items: center;
justify-content: center;
.text {
font-size: 28rpx;
color: #999999;
}
}
.list-view {
height: 100%;
padding: 0 20rpx;
}
.list-item {
display: flex;
flex-direction: row;
align-items: center;
padding: 20rpx 0;
border-bottom: #f5f5f5 solid 1px;
&__thumbnail-1 {
.list-item__content-title {
height: 88rpx;
}
}
&__thumbnail-3 {
.list-item__thumbnails {
display: flex;
flex-direction: row;
margin: 20rpx -10rpx;
margin-left: -10rpx;
margin-bottom: 0;
}
.list-item__img {
margin: 0 10rpx;
flex: 1;
}
}
&__thumbnails {
margin-left: 20rpx;
}
&__img {
width: 240rpx;
height: 160rpx;
border-radius: 8rpx;
}
&__content {
display: flex;
justify-content: space-between;
flex-direction: column;
flex: 1;
height: 100%;
&-title {
overflow: hidden;
.text {
font-size: 30rpx;
color: #333333;
line-height: 44rpx;
}
}
&-info {
display: flex;
flex-direction: row;
align-items: center;
margin-top: 20rpx;
}
}
&__author,
&__publish-date {
.text {
font-size: 24rpx;
color: #bbbbbb;
}
}
&__author {
margin-right: 14rpx;
}
}
</style>