<template>
<waterflow :id="id" class="grid" :bounces="false" :scroll-y="true" :custom-nested-scroll="true"
main-axis-gap="8px" cross-axis-gap="8px" cross-axis-count=2
@scrolltolower="loadData(null)" associative-container="nested-scroll-view">
<flow-item class="flow-item" v-for="(item, _) in datagrid" :key="item.plugin_id" type=1>
<view class="flow-item-icon">
<image class="flow-item-icon-image" :src="item.plugin_img_link" mode="aspectFit"></image>
</view>
<view class="flow-item-fill">
<view class="flex-row">
<text class="title">{{item.plugin_name}}</text>
</view>
<view>
<text class="description-text">{{item.plugin_intro}}</text>
</view>
<text class="icon-star">{{convertToStarUnicode(item.score)}}</text>
<view class="tag-grid">
<text class="tag-item" v-for="(item2, index2) in item.tags.slice(0,1)" :key="index2">{{item2}}</text>
</view>
<view class="flex-row update-date">
<text class="author">{{item.author_name}}</text>
</view>
<view class="flex-row update-date">
<text class="update-date-text">更新日期</text>
<text class="update-date-value">{{item.update_date}}</text>
</view>
</view>
</flow-item type="20">
<flow-item slot="load-more" class="loading" type=6>
<uni-loading :loading="loading" color="#999" :text="loadingText"></uni-loading>
</flow-item>
</waterflow>
</template>
<script setup lang="ts">
const SERVER_URL = "https://unidemo.dcloud.net.cn/plugin/uniappx-plugin-list"
const PAGE_SIZE = 10; // 最大值 10
type flowItem = {
plugin_id : number,
plugin_img_link : string,
plugin_name : string,
plugin_intro : string,
score : number,
tags : Array<string>,
update_date : string,
author_name : string,
}
type ResponseDataType = {
code : number,
data : flowItem[]
}
const props = defineProps({
type: { type: String, default: '' },
preload: { type: Boolean, default: false },
id: { type: String, default: '' }
})
const loading = ref(false);
const datagrid = ref([] as flowItem[]);
const isEnded = ref(false);
const loadingError = ref('');
const currentPage = ref(1);
const loadingText = computed(() : string => {
if (loading.value) {
return "加载中..."
} else if (isEnded.value) {
return "没有更多了"
} else if (loadingError.value.length > 0) {
return loadingError.value
} else {
return ""
}
});
function loadData(loadComplete : (() => void) | null) {
if (loading.value || isEnded.value) {
return
}
loading.value = true
uni.request<ResponseDataType>({
url: SERVER_URL,
data: {
type: props.type,
page: currentPage.value,
page_size: PAGE_SIZE
},
success: (res) => {
const responseData = res.data
if (responseData == null) {
return
}
datagrid.value.push(...responseData.data)
if (responseData.data.length == 0) {
isEnded.value = true
} else {
currentPage.value++
}
},
fail: (err) => {
loadingError.value = err.errMsg
},
complete: () => {
loading.value = false
if (loadComplete != null) {
loadComplete()
}
}
})
}
function refreshData(loadComplete : (() => void) | null) {
datagrid.value.length = 0
currentPage.value = 1
loadData(loadComplete)
}
// score 0 ~ 50
function convertToStarUnicode(score : number) : string {
const fill_code = '\ue879'
const half_code = '\ue87a'
const null_code = '\ue87b'
const fillStarCount = parseInt(score / 10 % 10 + '')
const halfStarCount = score % 10 >= 5 ? 1 : 0
const nullStarCount = 5 - fillStarCount - halfStarCount
let result = ''
if (fillStarCount > 0) { result += fill_code.repeat(fillStarCount) }
if (halfStarCount > 0) { result += half_code.repeat(halfStarCount) }
if (nullStarCount > 0) { result += null_code.repeat(nullStarCount) }
return result
}
onMounted(() => {
if (props.preload) {
loadData(null)
}
});
defineExpose({
refreshData,
loadData
});
</script>
<style>
@font-face {
font-family: "UtsStarIcons";
src: url('@/static/fonts/icon-star.ttf');
}
.grid {
flex: 1;
background-color: #f7f7f7;
}
.flow-item {
flex-direction: column;
border-radius: 5px;
background-color: #ffffff;
}
.flow-item-icon {
position: relative;
}
.flow-item-icon-image {
width: 100%;
}
.flow-item-fill {
flex: 1;
padding: 5px;
}
.description-text {
font-size: 13px;
color: #666;
line-height: 19px;
}
.icon-star {
font-family: "UtsStarIcons";
font-size: 16px;
font-style: normal;
color: #ffca3e;
letter-spacing: 3px;
}
.tag-grid {
flex-direction: row;
margin-top: 5px;
}
.tag-item {
font-size: 12px;
background-color: #EFF9F0;
color: #639069;
border-radius: 20px;
margin-right: 5px;
padding: 2px 5px;
}
.update-date {
margin-top: 10px;
}
.update-date-text {
font-size: 12px;
color: #888888;
}
.update-date-value {
font-size: 12px;
color: #777777;
margin-left: 5px;
}
.author {
font-size: 12px;
color: #008000;
}
.loading {
padding: 30px;
align-items: center;
height: 80px;
}
.flex-row {
flex-direction: row;
}
</style>