<template>
<list-view :id="id" class="list" :bounces="false" :scroll-y="true" :custom-nested-scroll="true"
@scrolltolower="loadData(null)" associative-container="nested-scroll-view">
<list-item class="list-item" v-for="(item, _) in dataList" :key="item.plugin_id" type="10">
<view class="list-item-icon">
<image class="list-item-icon-image" :src="item.plugin_img_link"></image>
</view>
<view class="list-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-list">
<text class="tag-item" v-for="(item2, index2) in item.tags" :key="index2">{{item2}}</text>
</view>
<view class="flex-row update-date">
<text class="update-date-text">更新日期</text>
<text class="update-date-value">{{item.update_date}}</text>
<text class="author">{{item.author_name}}</text>
</view>
</view>
</list-item type="20">
<list-item class="loading">
<uni-loading :loading="loading" color="#999" :text="loadingText"></uni-loading>
</list-item>
</list-view>
</template>
<script setup lang="uts">
const SERVER_URL = "https://unidemo.dcloud.net.cn/plugin/uniappx-plugin-list"
const PAGE_SIZE = 10
type ListItem = {
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 : ListItem[]
}
const props = defineProps({
type: { type: String, default: '' },
preload: { type: Boolean, default: false },
id: { type: String, default: '' }
})
const loading = ref(false)
const dataList = ref<ListItem[]>([])
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 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
}
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
// console.log('responseData',responseData)
if (responseData == null) {
return
}
dataList.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) {
dataList.value.length = 0
currentPage.value = 1
loadData(loadComplete)
}
onMounted(() => {
if (props.preload) {
loadData(null)
}
})
defineExpose({
loadData,
refreshData
})
</script>
<style>
@font-face {
font-family: "UtsStarIcons";
src: url('@/static/fonts/icon-star.ttf');
}
.list {
flex: 1;
background-color: #ffffff;
}
.list-item {
flex-direction: row;
margin-top: 10px;
padding: 10px;
}
.list-item-icon {
position: relative;
}
.list-item-icon-image {
width: 80px;
height: 80px;
}
.list-item-fill {
flex: 1;
margin-left: 15px;
}
.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-list {
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;
margin-left: auto;
}
.loading {
padding: 30px;
align-items: center;
}
.flex-row {
flex-direction: row;
}
</style>