fix: 页面优化

master
xjs 2025-04-02 18:01:48 +08:00
parent e1f725393e
commit d5225475a1
127 changed files with 10605 additions and 396 deletions

View File

@ -92,6 +92,7 @@ export default defineManifestConfig({
},
requiredPrivateInfos: ['getLocation'],
requiredBackgroundModes: ['audio'],
lazyCodeLoading: 'requiredComponents',
// __usePrivacyCheck__: true,
},
uniStatistics: {

View File

@ -100,8 +100,7 @@
"pinyin-pro": "^3.26.0",
"qs": "6.5.3",
"vue": "3.4.21",
"wot-design-uni": "^1.4.0",
"z-paging": "^2.8.5"
"wot-design-uni": "^1.4.0"
},
"devDependencies": {
"@commitlint/cli": "^18.6.1",

View File

@ -65,7 +65,7 @@ export default defineUniPages({
preloadRule: {
'pages/home/index/index': {
network: 'all',
packages: ['pages-evaluation-sub'],
packages: ['pages-evaluation-sub', 'aiService-sub'],
},
},
condition: {

View File

@ -53,9 +53,6 @@ importers:
wot-design-uni:
specifier: ^1.4.0
version: 1.4.0(vue@3.4.21(typescript@5.7.2))
z-paging:
specifier: ^2.8.5
version: 2.8.5
devDependencies:
'@commitlint/cli':
specifier: ^18.6.1
@ -6593,10 +6590,6 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
z-paging@2.8.5:
resolution: {integrity: sha512-tvMnwo1zudiFATbKYOEzejf9pI94UMXbK7A5tfq9khIJy8YBOLiexLNEJF/s+I7vqyLYwhALoI0cIarEe13kgw==}
engines: {HBuilderX: ^3.0.7}
snapshots:
'@ampproject/remapping@2.3.0':
@ -14564,5 +14557,3 @@ snapshots:
yargs-parser: 21.1.1
yocto-queue@0.1.0: {}
z-paging@2.8.5: {}

View File

@ -1,39 +1,33 @@
<route lang="json5" type="page">
{
style: {
navigationBarTitleText: '小纬',
navigationBarTitleText: '六纬AI小助手',
},
needLogin: true,
}
</route>
<template>
<web-view src="http://localhost:3001/sort-college" @message="handleChildMessage" />
<web-view :src="url" @message="handleChildMessage" :update-title="false" />
</template>
<script setup lang="ts">
import { useUserStore } from '@/store'
const userStore = useUserStore()
//chat.ycymedu.com
const url = ref(
`https://chat.ycymedu.com?userId=${userStore.userInfo.estimatedAchievement.wxId}&subjectGroup=${userStore.userInfo.estimatedAchievement.subjectGroup}&expectedScore=${userStore.userInfo.estimatedAchievement.expectedScore}&provinceName=${userStore.userInfo.estimatedAchievement.provinceName}`,
)
const handleChildMessage = (event) => {
console.log('子应用传递的消息', event)
}
const callback = ({
// B
response,
method,
}) => {
console.log('callback.response: ', response) // {name: ""}
console.log('callback.method: ', method) // passToA
}
onLoad(() => {
const manager = uni.getRecorderManager()
manager.start({
format: 'mp3',
})
manager.onStop((e) => {
console.log('录音结束')
})
uni.getRecorderManager()
uni.getBackgroundAudioManager()
})
defineExpose({ callback })
</script>
<style lang="scss" scoped></style>

View File

@ -6,7 +6,10 @@
@touchend.stop="endDrag"
:style="{ right: position.x + 'px', bottom: position.y + 'px' }"
>
<image class="w-full h-full rounded-full" src="/static/images/home/customerService.svg"></image>
<image
class="w-full h-full rounded-full"
src="https://api.static.ycymedu.com/src/images/home/customerService.svg"
></image>
</view>
</template>

View File

@ -1,12 +1,21 @@
<template>
<view class="mx-5 rounded-lg bg-white px-[32rpx] py-[56rpx]">
<view
class="flex items-center justify-between mx-[34rpx] py-[30rpx]"
class="flex items-center justify-between mx-[34rpx] py-[26rpx]"
style="border-bottom: 2rpx solid #ededed"
@click="handleChange"
>
<text class="text-[40rpx] text-[#636363]">输入模考/高考成绩</text>
<image class="w-[42rpx] h-[39rpx]" src="/static/images/home/pen.svg"></image>
<text class="text-[44rpx] text-[#333]">
{{
userStore.userInfo.estimatedAchievement.expectedScore
? userStore.userInfo.estimatedAchievement.expectedScore
: '输入模考/高考成绩'
}}
</text>
<image
class="w-[42rpx] h-[39rpx]"
src="https://api.static.ycymedu.com/src/images/home/pen.svg"
></image>
</view>
<view class="mt-[56rpx] flex items-center justify-between">
<button
@ -27,7 +36,9 @@
</template>
<script lang="ts" setup>
const value = ref('')
import { useUserStore } from '@/store/user'
const userStore = useUserStore()
const handleChange = () => {
uni.navigateTo({

View File

@ -8,7 +8,7 @@
<text class="text-[32rpx] text-[#333333] font-semibold">高考资讯</text>
<image
class="w-[40rpx] h-[40rpx]"
src="/static/images/home/right.svg"
src="https://api.static.ycymedu.com/src/images/home/right.svg"
@click="toNewsPage"
></image>
</view>

View File

@ -8,7 +8,7 @@
<text class="text-[32rpx] text-[#333333] font-semibold">热门排行榜</text>
<image
class="w-[40rpx] h-[40rpx]"
src="/static/images/home/right.svg"
src="https://api.static.ycymedu.com/src/images/home/right.svg"
@click="toSchool('0')"
></image>
</view>

View File

@ -7,7 +7,7 @@
@click="goPath(item.path, item.isTab)"
>
<image :src="item.icon" class="w-[88rpx] h-[88rpx]" mode="widthFix"></image>
<view class="text-[22rpx] text-[#303030] mt-[8rpx]">{{ item.name }}</view>
<view class="text-[24rpx] text-[#303030] mt-[8rpx]">{{ item.name }}</view>
</view>
</view>
</template>
@ -18,14 +18,14 @@ const subMenus = [
id: 1,
name: '找大学',
path: '/pages-sub/home/college/index',
icon: '/static/images/home/college.svg',
icon: 'https://api.static.ycymedu.com/src/images/home/college.svg',
isTab: false,
},
{
id: 2,
name: '查专业',
path: '/pages-sub/home/major/index',
icon: '/static/images/home/major.svg',
icon: 'https://api.static.ycymedu.com/src/images/home/major.svg',
isTab: false,
},
//
@ -33,7 +33,7 @@ const subMenus = [
id: 3,
name: '看职业',
path: '/pages-sub/home/career/index',
icon: '/static/images/home/career.svg',
icon: 'https://api.static.ycymedu.com/src/images/home/career.svg',
isTab: false,
},
// 线
@ -41,14 +41,14 @@ const subMenus = [
id: 4,
name: '批次线',
path: '/pages-sub/home/line/index',
icon: '/static/images/home/line.svg',
icon: 'https://api.static.ycymedu.com/src/images/home/line.svg',
},
//
{
id: 5,
name: '查位次',
path: '/pages-evaluation-sub/rank/index',
icon: '/static/images/home/rank.svg',
icon: 'https://api.static.ycymedu.com/src/images/home/rank.svg',
isTab: false,
},
//
@ -56,7 +56,7 @@ const subMenus = [
id: 6,
name: '查扩缩招',
path: '/pages-sub/home/expand/index',
icon: '/static/images/home/expand.svg',
icon: 'https://api.static.ycymedu.com/src/images/home/expand.svg',
isTab: false,
},
//
@ -64,7 +64,7 @@ const subMenus = [
id: 7,
name: '专业测评',
path: '/pages/evaluation/index/index',
icon: '/static/images/home/evaluation.svg',
icon: 'https://api.static.ycymedu.com/src/images/home/evaluation.svg',
isTab: true,
},
//
@ -72,7 +72,7 @@ const subMenus = [
id: 8,
name: '大学甄别',
path: '/pages-sub/home/distinguish/index',
icon: '/static/images/home/distinguish.svg',
icon: 'https://api.static.ycymedu.com/src/images/home/distinguish.svg',
isTab: false,
},
]

View File

@ -53,7 +53,7 @@
<script lang="ts" setup>
import { computed } from 'vue'
const props = defineProps({
defineProps({
title: {
type: String,
default: '',
@ -155,6 +155,7 @@ const handleClickLeft = () => {
display: flex;
align-items: center;
height: 100%;
min-width: 100rpx;
}
.back-icon {

View File

@ -14,7 +14,7 @@
{{ phone ? '申请使用您的手机号' : '申请获取您的个人信息' }}
</text>
<button
class="w-[493rpx] mb-[40rpx] h-[88rpx] rounded-[44rpx] text-[32rpx] text-white"
class="w-[493rpx]! mb-[40rpx] h-[88rpx]! rounded-[44rpx] text-[32rpx] text-white flex items-center justify-center"
:class="checked ? 'bg-[#1580FF]' : 'bg-[#BFBFBF]'"
@click.stop="handleClick"
open-type="getPhoneNumber"

View File

@ -1,19 +1,21 @@
<template>
<view
class="radio"
:class="{
'radio--disabled': isDisabled,
'radio-active': isChecked,
}"
@click="handleClick"
<label
class="radio-wrapper"
:class="{ 'radio-wrapper--disabled': isDisabled }"
@click.stop="handleClick"
>
<view class="radio__icon" :class="{ 'radio__icon--checked': isChecked }">
<view v-if="isChecked" class="radio__icon-dot"></view>
</view>
<view class="radio__label">
<radio
class="radio"
:value="String(name)"
:checked="isChecked"
:disabled="isDisabled"
:color="isChecked ? '#0083ff' : ''"
:name="String(name)"
/>
<view class="radio-label" :class="{ 'radio-label--active': isChecked }">
<slot>{{ label }}</slot>
</view>
</view>
</label>
</template>
<script lang="ts" setup>
@ -65,49 +67,23 @@ const handleClick = () => {
</script>
<style scoped lang="scss">
.radio {
.radio-wrapper {
display: inline-flex;
align-items: center;
cursor: pointer;
font-size: 28rpx;
width: 100%;
height: 100%;
justify-content: center;
padding: 8rpx 0;
&--disabled {
cursor: not-allowed;
opacity: 0.5;
}
&__icon {
width: 40rpx;
height: 40rpx;
border: 2rpx solid #dcdfe6;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 8rpx;
transition: all 0.2s;
&--checked {
border-color: #0083ff;
}
}
&__icon-dot {
width: 20rpx;
height: 20rpx;
background-color: #0083ff;
border-radius: 50%;
}
&__label {
line-height: 1;
}
}
.radio-active {
color: #0083ff;
.radio-label {
margin-left: 10rpx;
line-height: 1;
&--active {
color: #0083ff;
}
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<view class="radio-group">
<radio-group class="radio-group" :value="modelValue" @change="handleChange">
<slot></slot>
</view>
</radio-group>
</template>
<script lang="ts" setup>
@ -20,6 +20,13 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue', 'change'])
//
const handleChange = (e: any) => {
const value = e.detail.value
emit('update:modelValue', value)
emit('change', value)
}
//
const toggleOption = (value: string | number) => {
emit('update:modelValue', value)

View File

@ -68,7 +68,8 @@
],
"requiredBackgroundModes": [
"audio"
]
],
"lazyCodeLoading": "requiredComponents"
},
"mp-alipay": {
"usingComponents": true

View File

@ -23,7 +23,7 @@
<view class="flex-1 overflow-auto pb-[30rpx] relative">
<!-- 顶部卡片 -->
<view class="flex flex-col pt-[32rpx] px-[84rpx] h-[244rpx] mb-[-148rpx]">
<image src="/static/images/evaluate/bg.png" class="header-bg" />
<image src="https://api.static.ycymedu.com/src/images/evaluate/bg.png" class="header-bg" />
<text class="text-[#333] text-[28rpx] mb-[14rpx] z-2">您的兴趣类型为</text>
<text class="text-[#117CFC] text-[36rpx] z-2">{{ studyRecord.title }}</text>
</view>

View File

@ -23,7 +23,7 @@
<view class="flex-1 overflow-auto pb-[30rpx] relative">
<!-- 顶部卡片 -->
<view class="flex flex-col pt-[32rpx] px-[84rpx] h-[244rpx] mb-[-148rpx]">
<image src="/static/images/evaluate/bg.png" class="header-bg" />
<image src="https://api.static.ycymedu.com/src/images/evaluate/bg.png" class="header-bg" />
<text class="text-[#333] text-[28rpx] mb-[14rpx] z-2">您的兴趣类型为</text>
<text class="text-[#117CFC] text-[36rpx] z-2">{{ studyRecord.title }}</text>
</view>

View File

@ -23,7 +23,7 @@
<view class="flex-1 overflow-auto pb-[30rpx] relative">
<!-- 顶部卡片 -->
<view class="flex flex-col pt-[32rpx] px-[84rpx] h-[244rpx] mb-[-148rpx]">
<image src="/static/images/evaluate/bg.png" class="header-bg" />
<image src="https://api.static.ycymedu.com/src/images/evaluate/bg.png" class="header-bg" />
<text class="text-[#333] text-[28rpx] mb-[14rpx] z-2">您的职业价值观</text>
<text class="text-[#117CFC] text-[36rpx] z-2">{{ studyRecord.tag }}</text>
</view>

View File

@ -0,0 +1,25 @@
<template>
<view class="rounded-full p-[14rpx] w-max bg-[#fff]">
<view class="w-[162rpx] h-[162rpx] custom-style"></view>
</view>
</template>
<script lang="ts" setup></script>
<style lang="scss" scoped>
.custom-style {
border: 10rpx dashed #00b281;
border-radius: 50%;
position: relative;
}
.custom-style::before {
content: '';
position: absolute;
top: 0;
left: 0;
blur: filter(10px);
width: 162rpx;
height: 162rpx;
}
</style>

View File

@ -0,0 +1,85 @@
<route lang="json5" type="page">
{
style: {
navigationStyle: 'custom',
},
}
</route>
<template>
<scroll-view :scroll-y="true" class="flex flex-col h-screen relative custom-bg">
<Navbar
safeAreaInsetTop
:bordered="false"
leftArrow
@clickLeft="handleBack"
bg-color="transparent"
>
<template #title>
<text class="text-[#1F2329] text-[36rpx] font-medium text-[#fff]">SAS焦虑测评报告</text>
</template>
</Navbar>
<view class="flex-1 overflow-auto pb-[30rpx] relative">
<!-- 顶部卡片 -->
<view class="h-[772rpx] relative">
<Dashboard />
</view>
</view>
</scroll-view>
</template>
<script setup lang="ts">
import Navbar from '@/pages-evaluation-sub/components/navbar/Navbar.vue'
import Dashboard from '@/pages-evaluation-sub/evaluate/components/Dashboard.vue'
import { getAbilityDimension } from '@/service/index/api'
const pageType = ref(0)
const pageId = ref(0)
const handleBack = () => {
uni.navigateBack()
}
const studyRecord = ref({
description: '',
title: '',
linChart: [],
reportItems: [],
hTag: '',
})
onLoad((options) => {
pageType.value = +options.type
pageId.value = options.id
getAbilityDimension({ ScaleId: pageId.value }).then((resp) => {
if (resp.code === 200) {
studyRecord.value = resp.result as {
description: string
title: string
linChart: any[]
reportItems: any[]
hTag: string
}
}
})
})
</script>
<style scoped lang="scss">
.custom-bg {
background: linear-gradient(184deg, #0d79fc 0%, #2186fc 100%);
}
:deep(.icon-class) {
color: #fff !important;
}
.custom-border {
width: 162rpx;
height: 162rpx;
border-radius: 50%;
border: 6rpx dashed;
border-color: #05d69c transparent transparent transparent;
}
</style>

View File

@ -94,7 +94,7 @@
<LEchart ref="echart" class="h-[300rpx]" v-show="!noData"></LEchart>
<view class="flex items-center justify-center flex-col my-[80rpx] relative" v-show="noData">
<image
src="../static/images/no-data.jpg"
src="https://api.static.ycymedu.com/evaluation/sub/no-data.jpg"
mode="scaleToFill"
class="w-[300rpx] h-[300rpx]"
/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -2,6 +2,7 @@
<view class="custom-picker">
<view class="picker-mask" @touchmove.stop.prevent></view>
<picker-view
v-if="visible"
:value="currentIndex"
:indicator-style="indicatorStyle"
:style="{
@ -12,25 +13,18 @@
@change="handleChange"
class="picker-view"
:mask-class="'picker-mask'"
:indicator-class="'picker-indicator'"
>
<picker-view-column class="border-none">
<view
v-for="(item, index) in formattedList"
:key="index"
class="picker-item"
:class="{ 'picker-item-selected': currentIndex[0] === index }"
>
<view v-for="(item, index) in formattedList" :key="index" class="picker-item">
{{ item }}
</view>
</picker-view-column>
</picker-view>
<!-- <view class="picker-indicator-line"></view> -->
</view>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { computed, ref, watch, onMounted } from 'vue'
const props = defineProps({
modelValue: {
@ -57,6 +51,11 @@ const props = defineProps({
})
const emit = defineEmits(['update:modelValue', 'change'])
const visible = ref(false)
onMounted(() => {
visible.value = true
})
//
const formattedList = computed(() => {

View File

@ -0,0 +1,91 @@
<template>
<view>
<page-head :title="title"></page-head>
<view class="uni-padding-wrap">
<view class="uni-title">{{ value }}</view>
</view>
<picker-view
v-if="visible"
:indicator-style="indicatorStyle"
:mask-style="maskStyle"
:value="value"
@change="bindChange"
>
<picker-view-column>
<view class="item" v-for="(item, index) in months" :key="index">{{ item }}</view>
</picker-view-column>
<picker-view-column>
<view class="item" v-for="(item, index) in days" :key="index">{{ item }}</view>
</picker-view-column>
</picker-view>
</view>
</template>
<script>
export default {
data() {
const date = new Date()
const years = []
const year = date.getFullYear()
const months = []
const month = date.getMonth() + 1
const days = []
const day = date.getDate()
for (let i = 1990; i <= date.getFullYear(); i++) {
years.push(i)
}
for (let i = 1; i <= 12; i++) {
months.push(i)
}
for (let i = 1; i <= 31; i++) {
days.push(i)
}
return {
title: 'picker-view',
years,
year,
months,
month,
days,
day,
value: [month, day - 1],
/**
* 解决动态设置indicator-style不生效的问题
*/
visible: true,
// indicatorStyle: `height: ${Math.round(uni.getSystemInfoSync().screenWidth/(750/100))}px;`
indicatorStyle: `height: 50px;`,
// #ifdef MP-KUAISHOU
maskStyle: 'padding:10px 0',
// #endif
// #ifndef MP-KUAISHOU
maskStyle: '',
// #endif
}
},
methods: {
bindChange(e) {
const val = e.detail.value
this.year = this.years[val[0]]
this.month = this.months[val[1]]
this.day = this.days[val[2]]
},
},
}
</script>
<style>
picker-view {
width: 100%;
height: 600rpx;
margin-top: 20rpx;
}
.item {
line-height: 100rpx;
text-align: center;
}
</style>

View File

@ -6,7 +6,7 @@
:key="index"
class="drop-menu__item"
:class="{ 'drop-menu__item--active': index === activeIndex }"
@click="handleTitleClick(index)"
@click.self.stop="handleTitleClick(index)"
>
<text class="drop-menu__title">{{ item }}</text>
<text
@ -22,7 +22,7 @@
v-if="activeIndex !== -1"
class="drop-menu__mask"
:style="{ top: maskTop }"
@click="closeDropMenu"
@click.self.stop="closeDropMenu"
></view>
</view>
</template>
@ -52,7 +52,6 @@ const activeIndex = ref(-1)
const maskTop = ref('88px')
//
const addTitle = (title: string) => {
titles.value.push(title)
}
@ -60,13 +59,10 @@ const addTitle = (title: string) => {
const instance = getCurrentInstance()
const dropMenuRef = ref()
//
const handleTitleClick = (index: number) => {
//
if (activeIndex.value === index) {
activeIndex.value = -1
} else {
//
activeIndex.value = index
}
const query = uni.createSelectorQuery().in(instance.proxy)

View File

@ -1,5 +1,6 @@
<template>
<view
v-if="mounted"
class="drop-menu-item"
:class="[customClass, { 'drop-menu-item--show': isShow }]"
:style="{
@ -9,14 +10,14 @@
>
<view class="drop-menu-item__wrapper" :class="{ 'drop-menu-item__wrapper--show': isShow }">
<!-- 默认选项列表 -->
<scroll-view v-if="!$slots.default" scroll-y class="drop-menu-item__content">
<scroll-view v-if="isShow && !$slots.default" scroll-y class="drop-menu-item__content">
<view class="drop-menu-item__option-list">
<view
v-for="(option, index) in options"
:key="index"
class="drop-menu-item__option"
:class="{ 'drop-menu-item__option--active': isOptionActive(option) }"
@click="handleOptionClick(option)"
@click.self.stop="handleOptionClick(option)"
>
<text class="drop-menu-item__text">{{ getOptionText(option) }}</text>
<text v-if="isOptionActive(option)" class="drop-menu-item__icon"></text>
@ -24,7 +25,7 @@
</view>
</scroll-view>
<!-- 自定义内容插槽 -->
<view v-else class="drop-menu-item__custom-content">
<view v-if="isShow && $slots.default" class="drop-menu-item__custom-content">
<slot></slot>
</view>
</view>
@ -32,7 +33,7 @@
</template>
<script lang="ts" setup>
import { ref, inject, onMounted, computed, watch } from 'vue'
import { ref, inject, onMounted, computed, watch, nextTick } from 'vue'
const props = defineProps({
modelValue: {
@ -64,12 +65,12 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue', 'change', 'open'])
//
const { activeIndex, addTitle, closeDropMenu, zIndex, duration, direction, titles } = inject(
'dropMenu',
) as any
const { activeIndex, addTitle, closeDropMenu, zIndex, duration, titles } = inject('dropMenu') as any
//
const itemIndex = ref(-1)
//
const mounted = ref(false)
//
const isShow = computed(() => activeIndex.value === itemIndex.value)
@ -117,6 +118,11 @@ onMounted(() => {
itemIndex.value = titles.value.length
//
addTitle(props.title)
//
nextTick(() => {
mounted.value = true
})
})
//
@ -148,15 +154,17 @@ watch(
transition: all 0.25s ease;
overflow: hidden;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
opacity: 0;
display: none;
visibility: hidden;
opacity: 0;
z-index: 11;
}
.drop-menu-item__wrapper--show {
transform: translateY(0);
opacity: 1;
display: inline-block;
visibility: visible;
opacity: 1;
}
.drop-menu-item__content {

View File

@ -5,7 +5,6 @@
<view class="i-carbon-search text-[#d9d9d9]"></view>
<input
v-model="searchValue"
type="number"
:placeholder="placeholder"
confirm-type="done"
class="text-start ml-20rpx"

View File

@ -19,7 +19,7 @@
<view class="py-[48rpx] mx-[48rpx] avatar-border flex justify-center items-center">
<image
class="w-[144rpx] h-[144rpx] rounded-full"
src="@/pages-sub/static/images/customerService/avatar.jpg"
src="https://api.static.ycymedu.com/sub/images/customerService/avatar.jpg"
></image>
<view class="flex flex-col text-[#000] ml-[32rpx]">
<text class="mb-[12rpx] font-normal text-[28rpx]">专属客服为您服务</text>

View File

@ -21,37 +21,39 @@
</Navbar>
<view class="h-full w-full custom-bg absolute top-0 left-0 -z-1"></view>
<view class="question-container flex-1 overflow-hidden mt-[30rpx]">
<view
v-for="(question, index) in questions"
:key="index"
:class="`card-container ${currentIndex === index ? 'current-card' : ''}`"
>
<view class="px-[30rpx] py-[40rpx] flex flex-col card-content">
<text class="mb-[30rpx] text-[34rpx] font-semibold">
{{ index + 1 }}{{ question.title }}
</text>
<CheckboxGroup
v-model="checkedList"
checked-color="#1580FF"
@change="handleCheckChange"
:max="questionType === 0 ? 1 : 0"
>
<Checkbox
v-for="item in question.answer"
:key="item.key"
:name="item.key"
cell
shape="button"
class="custom-checkbox"
<view class="question-container flex-1 overflow-hidden mt-[30rpx] flex">
<view class="flex-1 h-0 relative">
<view
v-for="(question, index) in questions"
:key="index"
:class="`h-full overflow-y-auto card-container ${currentIndex === index ? 'current-card' : ''}`"
>
<view class="px-[30rpx] py-[40rpx] flex flex-col card-content">
<text class="mb-[30rpx] text-[34rpx] font-semibold">
{{ index + 1 }}{{ question.title }}
</text>
<CheckboxGroup
v-model="checkedList"
checked-color="#1580FF"
@change="handleCheckChange"
:max="questionType === 0 ? 1 : 0"
>
{{ item.name }}
</Checkbox>
</CheckboxGroup>
<Checkbox
v-for="item in question.answer"
:key="item.key"
:name="item.key"
cell
shape="button"
class="custom-checkbox"
>
{{ item.name }}
</Checkbox>
</CheckboxGroup>
</view>
</view>
</view>
<view class="pb-safe mt-auto px-[30rpx]">
<view class="mt-[86rpx] px-[30rpx]">
<button class="next-question" :disabled="disableBtn" @click="handleNextQuestion">
{{ currentIndex === questions.length - 1 ? '提交' : '下一题' }}
({{ currentIndex + 1 }}/{{ questions.length }})
@ -241,11 +243,13 @@ const handleSubmit = () => {
.next-question {
background: #1580ff;
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding: 22rpx 0;
border-radius: 16rpx;
height: 88rpx;
line-height: 1;
color: #fff;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
:deep(.custom-checkbox) {
@ -289,6 +293,12 @@ const handleSubmit = () => {
position: relative;
display: flex;
flex-direction: column;
padding-bottom: calc(env(safe-area-inset-bottom) + 20rpx);
// safe-area-inset-bottom 0 padding-bottom 20rpx
@if env(safe-area-inset-bottom) == 0 {
padding-bottom: 20rpx;
}
}
.card-container {
@ -298,6 +308,7 @@ const handleSubmit = () => {
position: absolute;
transform: translate3d(100vw, 0, 0);
margin: 0 30rpx;
overflow-y: auto;
}
.current-card {

View File

@ -30,7 +30,7 @@
<image
class="w-[286rpx] h-[286rpx] mt-[134rpx] mix-blend-multiply"
src="@/pages-sub/static/images/autoFill/auto-fill.jpg"
src="https://api.static.ycymedu.com/sub/images/autoFill/auto-fill.jpg"
mode="widthFix"
@click="show = true"
></image>

View File

@ -11,14 +11,6 @@
<wd-index-bar sticky class="overflow-y h-0 flex-auto">
<view v-for="item in cities" :key="item.letter">
<wd-index-anchor :index="item.letter" />
<!-- <wd-cell
border
clickable
v-for="city in item.provinces"
:key="city.id"
:title="city.provincename"
@click="chooseCity(city)"
></wd-cell> -->
<view
v-for="city in item.provinces"
:key="city.id"
@ -55,6 +47,7 @@ const chooseCity = (city: City) => {
userStore.userInfo.estimatedAchievement.provinceCode !== city.code
) {
userStore.clearUserEstimatedAchievement()
// userStore.setEstimatedAchievement({ provinceName: city.provincename, provinceCode: city.code })
}
navigatorBack()
}

View File

@ -8,7 +8,7 @@
</route>
<template>
<view class="">
<view class="h-screen flex flex-col">
<z-paging
ref="paging"
use-virtual-list
@ -55,7 +55,7 @@
class="item-wrapper"
:id="`zp-id-${item.zp_index}`"
:key="item.zp_index"
v-for="(item, index) in schoolList"
v-for="item in schoolList"
@click="itemClick(item, item.zp_index)"
>
<view class="flex items-center p-[32rpx] w-full">
@ -98,6 +98,7 @@ import SearchInput from '@/pages-sub/components/input/SearchInput.vue'
import { getUniversityList } from '@/service/index/api'
const searchValue = ref('')
const isLoading = ref(false)
const handleChange = (e: any) => {
paging.value.reload()
@ -160,6 +161,10 @@ const handleNatureChange = (val) => {
natureInfo.value = val
paging.value.reload()
}
onShow(() => {
isLoading.value = true
})
</script>
<style lang="scss" scoped>

View File

@ -1,7 +0,0 @@
<!-- 专业测评 -->
<template>
<text>专业测评</text>
</template>
<script lang="ts" setup></script>

View File

@ -87,7 +87,7 @@
</view>
<button
block
class="mt-auto mb-[32rpx] rounded-[8rpx]! bg-[#1580FF]! mx-[32rpx]! text-[32rpx]! text-[#fff]! font-normal"
:class="`mt-auto mb-[32rpx] rounded-[8rpx] mx-[32rpx] text-[32rpx] text-[#fff]! font-normal ${btnFlag < 3 ? 'bg-[#BFBFBF]!' : 'bg-[#1580FF]!'}`"
@click="saveScore"
:disabled="btnFlag < 3"
>
@ -103,6 +103,7 @@
value-key="code"
label-key="name"
/>
<!-- <PickerView /> -->
</view>
<view class="flex items-center justify-between px-[32rpx]">
<view class="cancel-btn" @click="show = false">取消</view>
@ -121,6 +122,7 @@ import RadioGroup from '@/pages-sub/components/radio-group/RadioGroup.vue'
import Radio from '@/pages-sub/components/radio-group/Radio.vue'
import CustomPickerView from '@/pages-sub/components/CustomPickerView.vue'
import ActionSheet from '@/pages-sub/components/ActionSheet.vue'
import PickerView from '@/pages-sub/components/TestPickerView.vue'
import {
useRules,
@ -171,8 +173,8 @@ const btnFlag = computed(() => {
return num
})
onLoad(() => {
userStore.$subscribe((mutation, state) => {
onShow(() => {
userStore.$subscribe(() => {
requireSubject.value = userStore.userInfo.estimatedAchievement.requireSubject.code || ''
optionalSubject.value = userStore.userInfo.estimatedAchievement.optionalSubject.map(
(item) => item.code,

View File

@ -22,6 +22,9 @@ export const useRules = () => {
requireSubjectList.value = matchRules.filter((item) => item?.isfirst === 'true')
optionalSubjectList.value = matchRules.filter((item) => !(item?.isfirst === 'true'))
if (userStore.userInfo.city.code !== userStore.userInfo.estimatedAchievement.provinceCode) {
return
}
splitSubject(requireSubjectList.value, optionalSubjectList.value)
}
})

View File

@ -28,15 +28,15 @@
/>
<image
class="absolute top-0 z-[-1]"
src="@/pages-sub/static/images/schoolRank/background.svg"
src="https://api.static.ycymedu.com/sub/images/schoolRank/background.svg"
/>
<image
class="h-[78rpx] w-[270rpx] absolute top-[249rpx] left-[102rpx] z-[-1]"
src="@/pages-sub/static/images/schoolRank/title.svg"
src="https://api.static.ycymedu.com/sub/images/schoolRank/title.svg"
/>
<image
class="h-[190rpx] w-[190rpx] absolute top-[194rpx] left-[460rpx] mix-blend-multiply z-[-1]"
src="@/pages-sub/static/images/schoolRank/trophy.jpg"
src="https://api.static.ycymedu.com/sub/images/schoolRank/trophy.jpg"
/>
</view>
<view class="px-[32rpx] my-[24rpx]">
@ -69,8 +69,8 @@
class="item-wrapper"
:id="`zp-id-${item.zp_index}`"
:key="item.zp_index"
v-for="(item, index) in schoolList"
@click="itemClick(item, item.zp_index)"
v-for="item in schoolList"
@click="itemClick(item)"
>
<view class="flex items-center py-[32rpx] w-full">
<text class="text-[28rpx] text-[#999] font-normal">{{ item.rank }}</text>
@ -115,7 +115,7 @@ const navigatorBack = () => {
const tabIndex = ref<number>(0)
const tabsRef = ref(null)
const itemClick = (item, index) => {
const itemClick = (item) => {
console.log('点击了', item)
}

View File

@ -1,7 +0,0 @@
<template></template>
<script lang="ts" setup>
onShow(() => {
uni.navigateBack()
})
</script>

View File

@ -118,7 +118,7 @@ let editType = ''
let vTbId = ref(0)
let webUrl = computed(() => {
if (vTbId.value !== 0) {
return `http://localhost:3001/sort-college?id=${vTbId.value}&token=${userStore.userInfo.token}&score=${userStore.userInfo.estimatedAchievement.expectedScore}&batchName=${userStore.userInfo.batchName}&subjectGroup=${userStore.userInfo.estimatedAchievement.subjectGroup}&location=${userStore.userInfo.estimatedAchievement.provinceCode}`
return `https://sort.ycymedu.com/sort-college?id=${vTbId.value}&token=${userStore.userInfo.token}&score=${userStore.userInfo.estimatedAchievement.expectedScore}&batchName=${userStore.userInfo.batchName}&subjectGroup=${userStore.userInfo.estimatedAchievement.subjectGroup}&location=${userStore.userInfo.estimatedAchievement.provinceCode}`
}
return ''
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -1,3 +0,0 @@
<svg width="176" height="176" viewBox="0 0 176 176" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.31747 7.79883H79.1685V22.4068H8.31747V7.79883ZM97.1865 7.79883H138.205V22.4068H97.1865V7.79883ZM153.242 7.79883H168.147V22.7038H153.242V7.79883ZM8.31747 64.3498H79.1685V78.9688H8.31747V64.3498ZM7.85547 7.79883H22.4635V78.6498H7.85547V7.79883ZM64.5605 7.79883H79.1685V78.6498H64.5605V7.79883ZM32.5505 34.5178H52.4385V54.4058H32.5505V34.5178ZM97.1865 22.4068H111.409V37.3998H97.1865V22.4068ZM138.194 22.4068H153.792V49.9948H138.194V22.4068ZM153.242 37.3998H168.147V63.5028H153.242V37.3998ZM111.948 48.5868H138.205V67.3748H111.948V48.5868ZM126.644 63.4918H153.352V78.6388H126.644V63.4918ZM97.2745 63.9648H111.948V78.6388H97.2745V63.9648ZM7.85547 93.2908H22.4635V126.39H7.85547V93.2908ZM22.4965 123.277H38.3035V139.095H22.4965V123.277ZM7.85547 138.468H22.4965V168.212H7.85547V138.468ZM37.4125 93.2908H82.3915V111.463H37.4125V93.2908ZM48.3575 109.846H67.1235V127.116H48.3575V109.846ZM63.6255 123.277H82.3915V153.329H63.6255V123.277ZM49.0615 138.468H67.1235V168.212H49.0615V138.468ZM34.0245 149.38H51.5585V168.212H34.0245V149.38ZM108.142 93.2908H141.703V123.277H108.142V93.2908ZM149.733 93.2908H168.147V111.705H149.733V93.2908ZM93.6885 108.284H112.102V141.68H93.6885V108.284ZM123.179 119.075H141.703V138.303H123.179V119.075ZM93.6885 149.38H112.102V168.212H93.6885V149.38ZM137.985 153.329H168.147V168.212H137.985V153.329ZM153.066 138.303H168.147V156.475H153.066V138.303Z" fill="#272636"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 42 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 592 B

View File

@ -27,14 +27,14 @@
/>
<text class="text-[#000] text-[36rpx] font-bold">{{ userStore.userInfo?.nickname }}</text>
<image
src="@/pages-sub/static/images/ucenter/vip-flag.png"
src="https://api.static.ycymedu.com/sub/images/ucenter/vip-flag.png"
mode="scaleToFill"
class="w-[120rpx] h-[28rpx]"
v-if="isVIP"
/>
<image
v-else
src="@/pages-sub/static/images/ucenter/no-vip.png"
src="https://api.static.ycymedu.com/sub/images/ucenter/no-vip.png"
mode="scaleToFill"
class="w-[120rpx] h-[28rpx]"
/>

View File

@ -57,6 +57,14 @@ const toDetail = (item: any) => {
url = `/pages-evaluation-sub/evaluate/academicReport/capabilityReport?id=${item.reportsId}&type=${item.type}`
} else if (item.type === -1) {
url = `/pages-evaluation-sub/evaluate/academicReport/opinionAboutReport?id=${item.reportsId}&type=${item.type}`
} else if (item.type === 6) {
url = `/pages-evaluation-sub/evaluate/psychologicalReport/sasReport?id=${item.reportsId}&type=${item.type}`
} else {
uni.showToast({
title: '开发中....',
icon: 'none',
})
return
}
uni.navigateTo({
url,

View File

@ -9,7 +9,10 @@
<view class="vip-table-header">
<view class="feature-column">功能</view>
<view class="vip-column vip-header">
<image src="@/pages-sub/static/images/ucenter/vip-crown.png" class="vip-icon"></image>
<image
src="https://api.static.ycymedu.com/sub/images/ucenter/vip-crown.png"
class="vip-icon"
></image>
</view>
<view class="normal-column">普通用户</view>
</view>

View File

@ -10,7 +10,7 @@
<view class="h-screen flex flex-col bg-[#f8f8f8]">
<view class="px-[32rpx]">
<image
src="@/pages-sub/static/images/ucenter/vip-back.png"
src="https://api.static.ycymedu.com/sub/images/ucenter/vip-back.png"
class="mt-[32rpx] h-[400rpx]"
mode="aspectFit"
/>

View File

@ -42,6 +42,7 @@
<script setup lang="ts">
import { deleteWishList, getWishList } from '@/service/index/api'
import { useUserStore } from '@/store'
import { downloadPDF } from '@/service/index/api'
const userStore = useUserStore()
@ -65,35 +66,42 @@ const handleDelete = (item, index) => {
}
const handleDownload = (item) => {
uni.downloadFile({
url: '',
success: function (res) {
console.log(res)
let filepathss = res.tempFilePath
setTimeout(
() =>
uni.openDocument({
filePath: filepathss,
showMenu: false,
success: function () {
console.log('打开文档成功')
uni.hideLoading()
},
fail: function () {
uni.showToast({
title: '暂不支持此类型',
duration: 2000,
icon: 'none',
})
uni.hideLoading()
},
}),
1000,
)
},
fail: function (res) {
console.log(res) //
},
downloadPDF({
id: item.vId,
location: userStore.userInfo.estimatedAchievement.provinceCode,
}).then((res) => {
if (res.code === 200) {
uni.showToast({
title: '下载中...',
})
uni.downloadFile({
url: res.result as string,
filePath: '',
success: function (res) {
if (res.statusCode === 200) {
uni.openDocument({
filePath: res.tempFilePath,
showMenu: true,
success: function () {
console.log('打开文档成功')
uni.hideLoading()
},
fail: function () {
uni.showToast({
title: '暂不支持此类型',
duration: 2000,
icon: 'none',
})
uni.hideLoading()
},
})
}
},
fail: function (res) {
console.log(res) //
},
})
}
})
}

View File

@ -86,7 +86,8 @@
"pages/home/index/index": {
"network": "all",
"packages": [
"pages-evaluation-sub"
"pages-evaluation-sub",
"aiService-sub"
]
}
},
@ -185,10 +186,6 @@
"navigationStyle": "custom"
}
},
{
"path": "home/evaluation/index",
"type": "page"
},
{
"path": "home/expand/index",
"type": "page",
@ -254,10 +251,6 @@
"navigationBarTitleText": "我的志愿表"
}
},
{
"path": "home/wishesList/temp",
"type": "page"
},
{
"path": "home/wishesList/wishesList",
"type": "page",
@ -378,6 +371,13 @@
"style": {
"navigationStyle": "custom"
}
},
{
"path": "evaluate/psychologicalReport/sasReport",
"type": "page",
"style": {
"navigationStyle": "custom"
}
}
]
},
@ -388,8 +388,9 @@
"path": "index/index",
"type": "page",
"style": {
"navigationBarTitleText": "小纬"
}
"navigationBarTitleText": "六纬AI小助手"
},
"needLogin": true
}
]
}

View File

@ -61,9 +61,8 @@ import { useUserStore } from '@/store/user'
const list = ref<any[]>([])
const userStore = useUserStore()
const show = ref(true)
onLoad(() => {
onShow(() => {
getMySpecialList({
openId: userStore.userInfo?.estimatedAchievement.wxId.toString(),
}).then((_res) => {
@ -94,6 +93,7 @@ const handleAppointment = (
deleteMyAppointment({ id: item.appointId }).then((res) => {
if (res.code === 200) {
list.value[index].isAppointment = !item.isAppointment
delete list.value[index].appointId
}
})
} else {
@ -105,6 +105,7 @@ const handleAppointment = (
}).then((res) => {
if (res.code === 200) {
list.value[index].isAppointment = !item.isAppointment
list.value[index].appointId = res.result
uni.showToast({
title: item.isAppointment ? '预约成功' : '取消预约成功',
})

View File

@ -1,7 +1,7 @@
<template>
<scroll-view class="" :scroll-y="true">
<view class="gradient-background relative">
<Navbar safeAreaInsetTop bg-color="transparent" placeholder :bordered="false">
<scroll-view class="flex flex-col" :scroll-y="true">
<view class="relative">
<Navbar safeAreaInsetTop :fixed="true" bg-color="transparent" placeholder :bordered="false">
<template #left>
<navigator open-type="navigate" class="left-icon" url="/pages-sub/home/city/index">
<text
@ -15,13 +15,16 @@
</template>
<template #title>
<view class="title">
<image class="w-[198rpx] h-[28rpx]" src="/static/images/home/app-logo.svg"></image>
<image
class="w-[198rpx] h-[28rpx]"
src="https://api.static.ycymedu.com/src/images/home/app-logo.svg"
></image>
</view>
</template>
</Navbar>
<view class="h-[700rpx] w-full custom-background absolute top-0 left-0 z-[-1]"></view>
</view>
<view class="h-full mt-[48rpx]">
<view class="h-full mt-[38rpx]">
<Banner />
<HomeSubMenu />
<HotRank />
@ -44,22 +47,23 @@ import HotRank from '@/components/home/HotRank.vue'
import Consultation from '@/components/home/Consultation.vue'
import FabButton from '@/components/fab/FabButton.vue'
import { getWxUserInfo } from '@/service/index/api'
const userStore = useUserStore()
useCityInfo()
//
const isTriggered = ref(false)
//
const onRefresherRefresh = async () => {
//
isTriggered.value = true
setTimeout(function fn() {
console.log('refresh - onRefresherRefresh')
//
isTriggered.value = false
}, 1000)
}
onShow(() => {
getWxUserInfo().then((resp) => {
const infoData = resp.result as unknown as {
userExtend: { provinceCode: string }
}
if (userStore.userInfo.city.code === infoData.userExtend.provinceCode) {
userStore.setEstimatedAchievement(infoData.userExtend)
return
}
})
})
</script>
<style lang="scss" scoped>
@ -87,8 +91,8 @@ const onRefresherRefresh = async () => {
background-image: linear-gradient(
173deg,
rgb(177, 221, 250) 0,
rgb(177, 221, 250) 13%,
rgba(255, 255, 255, 1) 80%,
rgb(177, 221, 250) 23%,
rgba(255, 255, 255, 1) 90%,
rgba(255, 255, 255, 1) 100%
);
background-position: 50% 50%;

View File

@ -32,7 +32,7 @@
v-if="!userStore.userInfo.estimatedAchievement.isVIP"
>
<image
src="/static/images/ucenter/vip.png"
src="https://api.static.ycymedu.com/src/images/ucenter/vip.png"
mode="scaleToFill"
class="w-[64rpx] h-[64rpx]"
/>
@ -53,7 +53,7 @@
>
<view class="flex flex-col items-center gap-[16rpx]" @click="goWishList">
<image
src="/static/images/ucenter/wish-list.png"
src="https://api.static.ycymedu.com/src/images/ucenter/wish-list.png"
class="w-[51rpx] h-[51rpx]"
mode="scaleToFill"
/>
@ -61,7 +61,7 @@
</view>
<view class="flex flex-col items-center gap-[16rpx]" @click="goEvaluate">
<image
src="/static/images/ucenter/evaluation-list.png"
src="https://api.static.ycymedu.com/src/images/ucenter/evaluation-list.png"
class="w-[51rpx] h-[51rpx]"
mode="scaleToFill"
/>
@ -69,7 +69,7 @@
</view>
<view class="flex flex-col items-center gap-[16rpx]" @click="goStar">
<image
src="/static/images/ucenter/star.png"
src="https://api.static.ycymedu.com/src/images/ucenter/star.png"
class="w-[51rpx] h-[51rpx]"
mode="scaleToFill"
/>

View File

@ -437,3 +437,7 @@ export const getAbilityDimension = (params: { ScaleId: number }) => {
export const getOpinionAbout = (params: { ScaleId: number }) => {
return http.get('/api/busScale/GetOpinionAbout', params)
}
export const downloadPDF = (params: { id: number; location: string }) => {
return http.get('/api/volunTb/downloadpdfUrl', params)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

View File

@ -1,21 +0,0 @@
<svg width="99" height="16" viewBox="0 0 99 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M72.3668 0.5625H74.415V1.70659H80.4203V2.76068H74.415V4.68968H79.8098V5.74378H66.9503V4.68968H72.3668V2.76068H66.3199V1.70659H72.3668V0.5625ZM55.5289 0.607253H57.577V1.72869H62.8743V2.78278H57.577V4.17353H62.8743V5.22763H57.577V6.61839H61.0822C62.0867 6.61839 62.8942 7.53812 62.8942 8.68188V12.3831C62.8942 13.5269 62.0867 14.4466 61.0822 14.4466H59.0539V13.3699H59.4871C60.2355 13.3699 60.846 12.6745 60.846 11.8221V9.2429C60.846 8.39051 60.2355 7.69513 59.4871 7.69513H57.577V14.4466H55.5289V7.69513H51.5508L51.866 6.64074H55.5289V5.25028H51.7674V4.19588H55.5289V2.80542H51.5508V1.75103H55.5289V0.607253ZM37.7466 0.67452L38.3964 4.08409L36.2695 4.10643L35.6197 0.67452H37.7466ZM29.6914 5.00378H44.7369V6.05787H29.6914V5.00378ZM32.055 14.5364H29.7902L33.2366 6.9548H35.4817L32.055 14.5364ZM39.2812 6.9548L42.4126 14.514H44.6771L41.546 6.9548H39.2812ZM51.7276 13.5269H47.395V14.5813H51.7276V13.5269ZM51.7275 5.63163H50.467C50.1521 5.63163 49.9355 5.27261 50.0534 4.93625L51.5306 0.719274H49.4628L47.6312 6.01268C47.5132 6.34935 47.7298 6.70807 48.0448 6.70807H48.36C48.8128 6.70807 49.1476 7.22409 48.9705 7.71747L47.6116 11.9344C47.5132 12.2708 47.7099 12.6072 48.0252 12.6072H51.7275V11.5531H50.467C50.1521 11.5531 49.9355 11.1941 50.0534 10.8577L51.7275 5.63163ZM66.9321 7.42595H69.1576L67.9365 12.9887H65.6522L66.9321 7.42595ZM75.6362 11.2616H73.3911L72.4656 7.42595H74.75L75.6362 11.2616ZM78.1762 12.8543H80.4017L79.2989 7.42595H77.0145L78.1762 12.8543ZM70.5753 10.6562V7.42595H69.63V12.473C69.63 13.6167 70.4375 14.5365 71.4419 14.5365H75.3214C76.3259 14.5365 77.1331 13.6167 77.1331 12.473V10.8355H76.188C76.188 11.6879 75.5775 12.2036 74.8291 12.2036H71.9342C71.1859 12.2036 70.5753 11.5083 70.5753 10.6562ZM92.4536 3.99442H94.3637C94.8689 3.99442 95.3113 4.31135 95.5454 4.77947H89.3612C89.5954 4.31135 90.0378 3.99442 90.543 3.99442H92.4533V3.29878H92.4536V3.99442ZM89.3727 6.03556H95.534C95.297 6.49131 94.8608 6.79798 94.3637 6.79798H93.9305H90.543C90.0459 6.79798 89.6096 6.49131 89.3727 6.03556ZM93.1201 2.91767H95.9588C96.9632 2.91767 97.7707 3.83741 97.7707 4.98118V5.81122C97.7707 6.95499 96.9632 7.87472 95.9588 7.87472H94.5211H93.9305H91.5669H88.9479C87.9434 7.87472 87.1359 6.95499 87.1359 5.81122V4.98118C87.1359 3.83741 87.9434 2.91767 88.9479 2.91767H91.1713L91.3803 2.33438H86.4667V9.53428C86.4667 9.79143 86.4634 10.0411 86.4567 10.2833L88.5152 8.07666H90.465L88.1016 10.5888H86.4465C86.4369 10.8284 86.4239 11.0601 86.4076 11.2841C86.3681 11.8221 86.2697 12.4728 86.1515 12.8989L85.7774 13.5046C85.5609 13.8186 85.3048 14.0653 84.9503 14.2446C84.6155 14.4243 84.1823 14.514 83.6702 14.514H83.1779V12.5625H83.7097C83.8671 12.5625 83.9854 12.4952 84.0837 12.3381C84.1823 12.1811 84.2611 11.9791 84.3398 11.6878C84.3989 11.4184 84.458 11.0821 84.4777 10.7007C84.4973 10.3193 84.5169 9.89329 84.5169 9.42225V0.719274H86.4667V1.27999H98.5386V2.33438H93.2977L93.1201 2.91767ZM87.0569 11.2841H88.9869L87.9235 14.2446H85.974L87.0569 11.2841ZM91.8432 12.4502H93.7731L93.2217 10.8354H91.2719L91.8432 12.4502ZM96.215 10.5888L98.1253 10.6112L96.1363 8.07666H94.1669L96.215 10.5888ZM98.6169 14.2446H96.6869L95.722 11.2841H97.6715L98.6169 14.2446ZM90.032 10.8354V11.3511C90.032 12.0915 90.5442 12.6746 91.1939 12.6746H93.6952C94.3449 12.6746 94.8568 12.2485 94.8568 11.5082H95.6643V12.9213C95.6643 13.886 94.9751 14.6934 94.1087 14.6934H90.7804C89.9337 14.6934 89.2248 13.9083 89.2248 12.9213V10.8354H90.032ZM91.5669 7.91956V7.89692H93.5361C93.8118 9.87104 91.8228 10.5888 91.8228 10.5888L90.602 10.6111L90.6216 9.31003C91.7835 9.08598 91.5669 7.91956 91.5669 7.91956Z" fill="black"/>
<g clip-path="url(#clip0_8135_1215)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.8973 2.08927L17.2217 1.73129L15.1473 6.29709L15.5404 6.93331L18.0065 1.51976L19.2149 1.19433L16.1454 7.93727L16.5356 8.57511L19.9881 0.976294L21.2183 0.650862L17.1565 9.5807L17.551 10.2169L21.9929 0.437705L23.6147 0L17.6265 13.0579L13.6343 6.49235L15.8973 2.08927ZM12.4375 14.0277L14.5671 9.99887L17.1608 14.1026L16.4355 15.7444H13.3035L12.4375 14.0277Z" fill="url(#paint0_linear_8135_1215)"/>
<path d="M6.7194 2.08927L3.9211 8.59138L0 0L6.7194 2.08927Z" fill="#8ACEFF"/>
<path d="M3.89062 8.58122L6.71794 2.08887L10.6419 8.20697L3.89062 8.58122Z" fill="#76C1FF"/>
<path d="M3.89062 8.58128L7.18359 15.7408L10.6419 8.20703L3.89062 8.58128Z" fill="#5CA3FF"/>
<path d="M10.3789 15.744H7.1875L10.6444 8.20703L10.3789 15.744Z" fill="#3E91FF"/>
<path d="M10.3789 15.744L13.9707 9.02875L10.6444 8.20703L10.3789 15.744Z" fill="#2A80FF"/>
<path d="M12.8408 7.15918L13.9709 9.02878L10.6445 8.20707L12.8408 7.15918Z" fill="#5CA3FF"/>
</g>
<defs>
<linearGradient id="paint0_linear_8135_1215" x1="18.0268" y1="0" x2="18.0268" y2="15.7444" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFF5A7"/>
<stop offset="1" stop-color="#FB976D"/>
</linearGradient>
<clipPath id="clip0_8135_1215">
<rect width="23.6165" height="15.7444" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 5.0 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 39 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 30 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 59 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 33 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 24 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.0875 5.2498C15.9375 5.0998 15.9375 4.8748 16.0875 4.7248L17.6813 3.13105C17.8313 2.98105 18.0562 2.98105 18.2062 3.13105L20.85 5.7748C21 5.9248 21 6.1498 20.85 6.2998L19.2562 7.89355C19.1062 8.04355 18.8813 8.04355 18.7313 7.89355L16.0875 5.2498ZM9 18.1873L17.7188 9.46855C17.85 9.3373 17.8313 9.1123 17.6813 8.98105L15.0375 6.31855C14.8875 6.16855 14.6625 6.1498 14.55 6.28105L5.8125 14.9998L4.5 19.4998L9 18.1873ZM1.5 20.9998V22.4998H22.5V20.9998H1.5Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 586 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 42 KiB

View File

@ -1,4 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="10" cy="10" r="10" fill="#F8F8F8"/>
<path d="M9 7L12 10L9 13" stroke="#343434" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 835 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 983 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 829 B

View File

@ -104,6 +104,7 @@ export const useUserStore = defineStore(
requireSubject: { code: 0, name: '', simplename: '' },
optionalSubject: [],
provinceCode: '',
subjectGroup: '',
})
}

View File

@ -18,7 +18,6 @@ interface NavigateToOptions {
"/pages-sub/home/college/index" |
"/pages-sub/home/college/info" |
"/pages-sub/home/distinguish/index" |
"/pages-sub/home/evaluation/index" |
"/pages-sub/home/expand/index" |
"/pages-sub/home/inputScore/index" |
"/pages-sub/home/line/index" |
@ -28,7 +27,6 @@ interface NavigateToOptions {
"/pages-sub/home/news/newsList" |
"/pages-sub/home/schoolRank/index" |
"/pages-sub/home/wishesList/index" |
"/pages-sub/home/wishesList/temp" |
"/pages-sub/home/wishesList/wishesList" |
"/pages-sub/ucenter/active/activePage" |
"/pages-sub/ucenter/appointment/appointment" |
@ -45,6 +43,7 @@ interface NavigateToOptions {
"/pages-evaluation-sub/evaluate/academicReport/characterReport" |
"/pages-evaluation-sub/evaluate/academicReport/interestReport" |
"/pages-evaluation-sub/evaluate/academicReport/opinionAboutReport" |
"/pages-evaluation-sub/evaluate/psychologicalReport/sasReport" |
"/aiService-sub/index/index";
}
interface RedirectToOptions extends NavigateToOptions {}

View File

@ -0,0 +1,41 @@
## 2.8.62025-03-17
1.`新增` 聊天记录模式流式输出类似chatGPT回答演示demo。
2.`新增` z-paging及其公共子组件支持`HBuilderX`代码文档提示。
3.`新增` props`virtual-in-swiper-slot`用以解决vue3+(微信小程序或QQ小程序)中使用非内置列表写法时若z-paging在`swiper-item`中存在的无法获取slot插入的cell高度进而导致虚拟列表失败的问题。
4.`新增` `@scrolltolower`和@`scrolltoupper`支持nvue。
5.`修复` 由`v2.8.1`引出的方法`scrollIntoViewById`在微信小程序+vue3中无效的问题。
6.`修复` 由`v2.8.1`引出的在子组件内使用z-paging虚拟列表无效的问题。
7.`修复` 在微信小程序中基础库版本较高时`wx.getSystemInfoSync is deprecated`警告。
8.`优化` 提升下拉刷新在鸿蒙Next中的性能。
9.`优化` `@scrolltolower`和`@scrolltoupper`在倒置的聊天记录模式下的触发逻辑。
10.`优化` 其他细节调整。
## 2.8.52025-02-09
1.`新增` 方法`scrollToX`支持控制x轴滚动到指定位置。
2.`修复` 快手小程序中报错`await isn't allowed in non-async function`的问题。
3.`修复` 在iOS+nvue中设置了`:loading-more-enabled="false"`后,调用`scrollToBottom`无法滚动到底部的问题。
4.`修复` 在支付宝小程序+页面滚动中,数据为空时空数据图未居中的问题。
5.`优化` fetch types修改。
## 2.8.42024-12-02
1.`修复` 在虚拟列表+vue2中顶部占位采用transformY方案在虚拟列表+vue3中顶部占位采用view占位方案。以解决在vue2+微信小程序+安卓+兼容模式中,可能出现的虚拟列表闪动的问题。
2.`修复` 在列表渲染时(尤其是在虚拟列表中)偶现的【点击加载更多】闪现的问题。
3.`优化` 统一在RefresherStatus枚举中Loading取值。
4.`优化` `defaultPageNo`&`defaultPageSize`修改为只允许number类型。
5.`优化` 提升兼容性&细节优化。
## 2.8.32024-11-27
1.`修复` `doInsertVirtualListItem`插入数据无效的问题。
2.`优化` 提升兼容性&细节优化。
## 2.8.22024-11-25
1.`优化` types中`ZPagingRef`和`ZPagingInstance`支持泛型。
## 2.8.12024-11-24
1.`新增` 完整的`props`、`slots`、`methods`、`events`的typescript types声明可在ts中获得绝佳的代码提示体验。
2.`新增` `virtual-cell-id-prefix`虚拟列表cell id的前缀适用于一个页面有多个虚拟列表的情况用以区分不同虚拟列表cell的id。
3.`修复` 在vue3+(微信小程序或QQ小程序)中,使用非内置列表写法时,若`z-paging`在`swiper-item`标签内的情况下存在的无法获取slot插入的cell高度的问题。
4.`修复` 在虚拟列表中分页数据小于1页时插入新数据虚拟列表未生效的问题。
5.`修复` 在虚拟列表中调用`refresh`时cell的index计算不正确的问题。
6.`修复` 在快手小程序中内容较少或空数据时`z-paging`未能铺满全屏的问题。
7.`优化` `events`中的参数涉及枚举的部分统一由之前的number类型修改为string类型展示更直观涉及的events`@query`中的`from`参数;`@refresherStatusChange`中的`status`参数;`@loadingStatusChange`中的`status`参数;`slot=refresher`中的`refresherStatus`参数;`slot=chatLoading`中的`loadingMoreStatus`参数。更新版本请特别留意!
## 2.8.02024-10-21
1.`新增` 全面支持鸿蒙Next。
2.`修复` 设置了`refresher-complete-delay`后在下拉刷新期间调用reload导致的无法再次下拉刷新的问题。
3.`优化` 废弃虚拟列表transformY顶部占位方案修改为空view占位。解决因使用旧方案导致的vue3中可能出现的虚拟列表闪动问题。提升虚拟列表的兼容性。

View File

@ -0,0 +1,47 @@
<!-- z-paging -->
<!-- github地址:https://github.com/SmileZXLee/uni-z-paging -->
<!-- dcloud地址:https://ext.dcloud.net.cn/plugin?id=3935 -->
<!-- 反馈QQ群790460711 -->
<!-- z-paging-cell用于在nvue中使用cell包裹vue中使用view包裹 -->
<template>
<!-- #ifdef APP-NVUE -->
<cell :style="[cellStyle]" @touchstart="onTouchstart">
<slot />
</cell>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<view :style="[cellStyle]" @touchstart="onTouchstart">
<slot />
</view>
<!-- #endif -->
</template>
<script>
/**
* z-paging-cell 组件
* @description 用于兼容 nvue vue 中的 cell 渲染因为在 nvue z-paging 内置的是 list因此列表 item 必须使用 cell 包住 vue 中不能使用 cell否则会报组件找不到的错误此子组件为了兼容这两种情况内部作了条件编译处理
* @tutorial https://z-paging.zxlee.cn/api/sub-components/main.html#z-paging-cell
* @notice 以下为 z-paging-cell 的配置项
* @property {Object} cellStyle cell 样式默认为 {}
* @example <z-paging-cell :cellStyle="{ backgroundColor: '#f0f0f0' }"></z-paging-cell>
*/
export default {
name: "z-paging-cell",
props: {
//cellStyle
cellStyle: {
type: Object,
default: function() {
return {}
}
}
},
methods: {
onTouchstart(e) {
this.$emit('touchstart', e);
}
}
}
</script>

View File

@ -0,0 +1,209 @@
<!-- z-paging -->
<!-- github地址:https://github.com/SmileZXLee/uni-z-paging -->
<!-- dcloud地址:https://ext.dcloud.net.cn/plugin?id=3935 -->
<!-- 反馈QQ群790460711 -->
<!-- 空数据占位view此组件支持easycom规范可以在项目中直接引用 -->
<template>
<view :class="{'zp-container':true,'zp-container-fixed':emptyViewFixed}" :style="[finalEmptyViewStyle]" @click="emptyViewClick">
<view class="zp-main">
<image v-if="!emptyViewImg.length" :class="{'zp-main-image-rpx':unit==='rpx','zp-main-image-px':unit==='px'}" :style="[emptyViewImgStyle]" :src="emptyImg" />
<image v-else :class="{'zp-main-image-rpx':unit==='rpx','zp-main-image-px':unit==='px'}" mode="aspectFit" :style="[emptyViewImgStyle]" :src="emptyViewImg" />
<text class="zp-main-title" :class="{'zp-main-title-rpx':unit==='rpx','zp-main-title-px':unit==='px'}" :style="[emptyViewTitleStyle]">{{emptyViewText}}</text>
<text v-if="showEmptyViewReload" :class="{'zp-main-error-btn':true,'zp-main-error-btn-rpx':unit==='rpx','zp-main-error-btn-px':unit==='px'}" :style="[emptyViewReloadStyle]" @click.stop="reloadClick">{{emptyViewReloadText}}</text>
</view>
</view>
</template>
<script>
import zStatic from '../z-paging/js/z-paging-static'
/**
* z-paging-empty-view 空数据组件
* @description 通用的 z-paging 空数据组件
* @tutorial https://z-paging.zxlee.cn/api/sub-components/main.html#z-paging-empty-view
* @property {Boolean} emptyViewFixed 空数据图片是否铺满 z-paging默认为 false若设置为 true则为填充满 z-paging 的剩余部分
* @property {String} emptyViewText 空数据图描述文字默认为 '没有数据哦~'
* @property {String} emptyViewImg 空数据图图片默认使用 z-paging 内置的图片 (建议使用绝对路径开头不要添加 "@"请以 "/" 开头)
* @property {String} emptyViewReloadText 空数据图点击重新加载文字默认为 '重新加载'
* @property {Object} emptyViewStyle 空数据图样式可设置空数据 view top : empty-view-style="{'top':'100rpx'}" (如果空数据图不是 fixed 布局则此处是 margin-top)默认为 {}
* @property {Object} emptyViewImgStyle 空数据图 img 样式默认为 {}
* @property {Object} emptyViewTitleStyle 空数据图描述文字样式默认为 {}
* @property {Object} emptyViewReloadStyle 空数据图重新加载按钮样式默认为 {}
* @property {Boolean} showEmptyViewReload 是否显示空数据图重新加载按钮(无数据时)默认为 false
* @property {Boolean} isLoadFailed 是否是加载失败默认为 false
* @property {String} unit 空数据图中布局的单位默认为 'rpx'
* @event {Function} reload 点击了重新加载按钮
* @event {Function} viewClick 点击了空数据图 view
* @example <z-paging-empty-view empty-view-text="" />
*/
export default {
name: "z-paging-empty-view",
data() {
return {
};
},
props: {
//
emptyViewText: {
type: String,
default: '没有数据哦~'
},
//
emptyViewImg: {
type: String,
default: ''
},
//
showEmptyViewReload: {
type: Boolean,
default: false
},
//
emptyViewReloadText: {
type: String,
default: '重新加载'
},
//
isLoadFailed: {
type: Boolean,
default: false
},
//
emptyViewStyle: {
type: Object,
default: function() {
return {}
}
},
// img
emptyViewImgStyle: {
type: Object,
default: function() {
return {}
}
},
//
emptyViewTitleStyle: {
type: Object,
default: function() {
return {}
}
},
//
emptyViewReloadStyle: {
type: Object,
default: function() {
return {}
}
},
// z-index
emptyViewZIndex: {
type: Number,
default: 9
},
// 使fixedz-paging
emptyViewFixed: {
type: Boolean,
default: true
},
// rpx
unit: {
type: String,
default: 'rpx'
}
},
computed: {
emptyImg() {
return this.isLoadFailed ? zStatic.base64Error : zStatic.base64Empty;
},
finalEmptyViewStyle(){
this.emptyViewStyle['z-index'] = this.emptyViewZIndex;
return this.emptyViewStyle;
}
},
methods: {
// reload
reloadClick() {
this.$emit('reload');
},
// view
emptyViewClick() {
this.$emit('viewClick');
}
}
}
</script>
<style scoped>
.zp-container{
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
justify-content: center;
}
.zp-container-fixed {
/* #ifndef APP-NVUE */
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
/* #endif */
/* #ifdef APP-NVUE */
flex: 1;
/* #endif */
}
.zp-main{
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
align-items: center;
padding: 50rpx 0rpx;
}
.zp-main-image-rpx {
width: 240rpx;
height: 240rpx;
}
.zp-main-image-px {
width: 120px;
height: 120px;
}
.zp-main-title {
color: #aaaaaa;
text-align: center;
}
.zp-main-title-rpx {
font-size: 28rpx;
margin-top: 10rpx;
padding: 0rpx 20rpx;
}
.zp-main-title-px {
font-size: 14px;
margin-top: 5px;
padding: 0px 10px;
}
.zp-main-error-btn {
border: solid 1px #dddddd;
color: #aaaaaa;
}
.zp-main-error-btn-rpx {
font-size: 28rpx;
padding: 8rpx 24rpx;
border-radius: 6rpx;
margin-top: 50rpx;
}
.zp-main-error-btn-px {
font-size: 14px;
padding: 4px 12px;
border-radius: 3px;
margin-top: 25px;
}
</style>

View File

@ -0,0 +1,160 @@
<!-- z-paging -->
<!-- github地址:https://github.com/SmileZXLee/uni-z-paging -->
<!-- dcloud地址:https://ext.dcloud.net.cn/plugin?id=3935 -->
<!-- 反馈QQ群790460711 -->
<!-- 滑动切换选项卡swiper-item此组件支持easycom规范可以在项目中直接引用 -->
<template>
<view class="zp-swiper-item-container">
<z-paging ref="paging" :fixed="false"
:auto="false" :useVirtualList="useVirtualList" :useInnerList="useInnerList" :cellKeyName="cellKeyName" :innerListStyle="innerListStyle"
:preloadPage="preloadPage" :cellHeightMode="cellHeightMode" :virtualScrollFps="virtualScrollFps" :virtualListCol="virtualListCol"
@query="_queryList" @listChange="_updateList">
<slot />
<template #header>
<slot name="header"/>
</template>
<template #cell="{item,index}">
<slot name="cell" :item="item" :index="index"/>
</template>
<template #footer>
<slot name="footer"/>
</template>
</z-paging>
</view>
</template>
<script>
import zPaging from '../z-paging/z-paging'
/**
* z-paging-swiper-item 组件
* @description swiper+list极简写法中使用到实际上就是对普通的swiper+list中swiper-item的包装封装用以简化写法但个性化配置局限较多
* @tutorial https://z-paging.zxlee.cn/api/sub-components/main.html#z-paging-swiper-item
* @notice 以下为 z-paging-swiper-item 的配置项
* @property {Number} tabIndex 当前组件的 index也就是当前组件是 swiper 中的第几个默认为 0
* @property {Number} currentIndex 当前 swiper 切换到第几个 index默认为 0
* @property {Boolean} useVirtualList 是否使用虚拟列表默认为 false
* @property {Boolean} useInnerList 是否在 z-paging 内部循环渲染列表内置列表默认为 false useVirtualList true则此项恒为 true
* @property {String} cellKeyName 内置列表 cell key 名称 nvue 有效 nvue 中开启 useInnerList 时必须填此项默认为 ''
* @property {Object} innerListStyle innerList 样式默认为 {}
* @property {Number|String} preloadPage 预加载的列表可视范围列表高度页数默认为 12此数值越大则虚拟列表中加载的 dom 越多内存消耗越大会维持在一个稳定值但增加预加载页面数量可缓解快速滚动短暂白屏问题
* @property {String} cellHeightMode 虚拟列表 cell 高度模式默认为 'fixed'也就是每个 cell 高度完全相同将以第一个 cell 高度为准进行计算可选值dynamic即代表高度是动态非固定的dynamic性能低于fixed
* @property {Number|String} virtualListCol 虚拟列表列数默认为 1常用于每行有多列的情况例如每行有 2 列数据需要将此值设置为 2
* @property {Number|String} virtualScrollFps 虚拟列表 scroll 取样帧率默认为 60过高可能出现卡顿等问题
* @example <z-paging-swiper-item ref="swiperItem" :tabIndex="index" :currentIndex="current" @query="queryList" @updateList="updateList"></z-paging-swiper-item>
*/
export default {
name: "z-paging-swiper-item",
components: { zPaging },
data() {
return {
firstLoaded: false
}
},
props: {
// indexswiper
tabIndex: {
type: Number,
default: function() {
return 0
}
},
// swiperindex
currentIndex: {
type: Number,
default: function() {
return 0
}
},
// 使
useVirtualList: {
type: Boolean,
default: false
},
// z-paging()use-virtual-listtruetrue
useInnerList: {
type: Boolean,
default: false
},
// cellkeynvuenvueuse-inner-list
cellKeyName: {
type: String,
default: ''
},
// innerList
innerListStyle: {
type: Object,
default: function() {
return {};
}
},
// ()1212celldom()
preloadPage: {
type: [Number, String],
default: 12
},
// cellfixedcellcelldynamicdynamicfixed
cellHeightMode: {
type: String,
default: 'fixed'
},
// 122
virtualListCol: {
type: [Number, String],
default: 1
},
// scroll60
virtualScrollFps: {
type: [Number, String],
default: 60
},
},
watch: {
currentIndex: {
handler(newVal, oldVal) {
if (newVal === this.tabIndex) {
// item
if (!this.firstLoaded) {
this.$nextTick(()=>{
let delay = 5;
// #ifdef MP-TOUTIAO
delay = 100;
// #endif
setTimeout(() => {
this.$refs.paging.reload().catch(() => {});
}, delay);
})
}
}
},
immediate: true
}
},
methods: {
reload(data) {
return this.$refs.paging.reload(data);
},
complete(data) {
this.firstLoaded = true;
return this.$refs.paging.complete(data);
},
_queryList(pageNo, pageSize, from) {
this.$emit('query', pageNo, pageSize, from);
},
_updateList(list) {
this.$emit('updateList', list);
}
}
}
</script>
<style scoped>
.zp-swiper-item-container {
/* #ifndef APP-NVUE */
height: 100%;
/* #endif */
/* #ifdef APP-NVUE */
flex: 1;
/* #endif */
}
</style>

View File

@ -0,0 +1,176 @@
<!-- z-paging -->
<!-- github地址:https://github.com/SmileZXLee/uni-z-paging -->
<!-- dcloud地址:https://ext.dcloud.net.cn/plugin?id=3935 -->
<!-- 反馈QQ群790460711 -->
<!-- 滑动切换选项卡swiper容器此组件支持easycom规范可以在项目中直接引用 -->
<template>
<view :class="fixed?'zp-swiper-container zp-swiper-container-fixed':'zp-swiper-container'" :style="[finalSwiperStyle]">
<!-- #ifndef APP-PLUS -->
<view v-if="cssSafeAreaInsetBottom===-1" class="zp-safe-area-inset-bottom"></view>
<!-- #endif -->
<slot v-if="zSlots.top" name="top" />
<view class="zp-swiper-super">
<view v-if="zSlots.left" :class="{'zp-swiper-left':true,'zp-absoulte':isOldWebView}">
<slot name="left" />
</view>
<view :class="{'zp-swiper':true,'zp-absoulte':isOldWebView}" :style="[swiperContentStyle]">
<slot />
</view>
<view v-if="zSlots.right" :class="{'zp-swiper-right':true,'zp-absoulte zp-right':isOldWebView}">
<slot name="right" />
</view>
</view>
<slot v-if="zSlots.bottom" name="bottom" />
</view>
</template>
<script>
import commonLayoutModule from '../z-paging/js/modules/common-layout'
/**
* z-paging-swiper 组件
* @description swiper 中使用 z-paging 左右滑动切换列表在根节点使用 z-paging-swiper其相当于一个 view 容器默认铺满全屏可免计算高度直接插入 swiper 的视图容器
* @tutorial https://z-paging.zxlee.cn/api/sub-components/main.html#z-paging-swiper
* @property {Boolean} fixed 是否使用 fixed 布局默认为 true
* @property {Boolean} safeAreaInsetBottom 是否开启底部安全区域适配默认为 false
* @property {Object} swiperStyle z-paging-swiper 样式默认为 {}
* @example <z-paging-swiper :safeAreaInsetBottom="true"></z-paging-swiper>
*/
export default {
name: "z-paging-swiper",
mixins: [commonLayoutModule],
data() {
return {
swiperContentStyle: {}
};
},
props: {
// 使fixed
fixed: {
type: Boolean,
default: true
},
//
safeAreaInsetBottom: {
type: Boolean,
default: false
},
// z-paging-swiper
swiperStyle: {
type: Object,
default: function() {
return {};
},
}
},
mounted() {
this.$nextTick(() => {
this.systemInfo = this._getSystemInfoSync();
setTimeout(this.updateFixedLayout, 100)
})
// #ifndef APP-PLUS
this._getCssSafeAreaInsetBottom();
// #endif
this.updateLeftAndRightWidth();
this.swiperContentStyle = { 'flex': '1' };
// #ifndef APP-NVUE
this.swiperContentStyle = { width: '100%',height: '100%' };
// #endif
},
computed: {
finalSwiperStyle() {
const swiperStyle = { ...this.swiperStyle };
if (!this.systemInfo) return swiperStyle;
const windowTop = this.windowTop;
const windowBottom = this.systemInfo.windowBottom;
if (this.fixed) {
if (windowTop && !swiperStyle.top) {
swiperStyle.top = windowTop + 'px';
}
if (!swiperStyle.bottom) {
let bottom = windowBottom || 0;
bottom += this.safeAreaInsetBottom ? this.safeAreaBottom : 0;
if (bottom > 0) {
swiperStyle.bottom = bottom + 'px';
}
}
}
return swiperStyle;
}
},
methods: {
// slot="left"slot="right"slot="left"slot="right"
updateLeftAndRightWidth() {
if (!this.isOldWebView) return;
this.$nextTick(() => this._updateLeftAndRightWidth(this.swiperContentStyle, 'zp-swiper'));
}
}
}
</script>
<style scoped>
.zp-swiper-container {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
flex: 1;
}
.zp-swiper-container-fixed {
position: fixed;
/* #ifndef APP-NVUE */
height: auto;
width: auto;
/* #endif */
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.zp-safe-area-inset-bottom {
position: absolute;
/* #ifndef APP-PLUS */
height: env(safe-area-inset-bottom);
/* #endif */
}
.zp-swiper-super {
flex: 1;
overflow: hidden;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.zp-swiper-left,.zp-swiper-right{
/* #ifndef APP-NVUE */
height: 100%;
/* #endif */
}
.zp-swiper {
flex: 1;
/* #ifndef APP-NVUE */
height: 100%;
width: 100%;
/* #endif */
}
.zp-absoulte {
/* #ifndef APP-NVUE */
position: absolute;
top: 0;
width: auto;
/* #endif */
}
.zp-swiper-item {
height: 100%;
}
</style>

View File

@ -0,0 +1,182 @@
<!-- [z-paging]上拉加载更多view -->
<template>
<view class="zp-l-container" :class="{'zp-l-container-rpx':c.unit==='rpx','zp-l-container-px':c.unit==='px'}" :style="[c.customStyle]" @click="doClick">
<template v-if="!c.hideContent">
<!-- 底部加载更多没有更多数据分割线 -->
<text v-if="c.showNoMoreLine&&finalStatus===M.NoMore" :class="{'zp-l-line-rpx':c.unit==='rpx','zp-l-line-px':c.unit==='px'}" :style="[{backgroundColor:zTheme.line[ts]},c.noMoreLineCustomStyle]" />
<!-- 底部加载更多loading -->
<!-- #ifndef APP-NVUE -->
<image v-if="finalStatus===M.Loading&&!!c.loadingIconCustomImage"
:src="c.loadingIconCustomImage" :style="[c.iconCustomStyle]" :class="{'zp-l-line-loading-custom-image':true,'zp-l-line-loading-custom-image-animated':c.loadingAnimated,'zp-l-line-loading-custom-image-rpx':c.unit==='rpx','zp-l-line-loading-custom-image-px':c.unit==='px'}" />
<image v-if="finalStatus===M.Loading&&finalLoadingIconType==='flower'&&!c.loadingIconCustomImage.length"
:class="{'zp-line-loading-image':true,'zp-line-loading-image-rpx':c.unit==='rpx','zp-line-loading-image-px':c.unit==='px'}" :style="[c.iconCustomStyle]" :src="zTheme.flower[ts]" />
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<!-- 在nvue中底部加载更多loading使用系统自带的 -->
<view>
<loading-indicator v-if="finalStatus===M.Loading&&finalLoadingIconType!=='circle'" :class="{'zp-line-loading-image-rpx':c.unit==='rpx','zp-line-loading-image-px':c.unit==='px'}" :style="[{color:zTheme.indicator[ts]}]" :animating="true" />
</view>
<!-- #endif -->
<!-- 底部加载更多文字 -->
<text v-if="finalStatus===M.Loading&&finalLoadingIconType==='circle'&&!c.loadingIconCustomImage.length"
class="zp-l-circle-loading-view" :class="{'zp-l-circle-loading-view-rpx':c.unit==='rpx','zp-l-circle-loading-view-px':c.unit==='px'}" :style="[{borderColor:zTheme.circleBorder[ts],borderTopColor:zTheme.circleBorderTop[ts]},c.iconCustomStyle]" />
<text v-if="!c.isChat||(!c.chatDefaultAsLoading&&finalStatus===M.Default)||finalStatus===M.Fail" :class="{'zp-l-text-rpx':c.unit==='rpx','zp-l-text-px':c.unit==='px'}" :style="[{color:zTheme.title[ts]},c.titleCustomStyle]">{{ownLoadingMoreText}}</text>
<!-- 底部加载更多没有更多数据分割线 -->
<text v-if="c.showNoMoreLine&&finalStatus===M.NoMore" :class="{'zp-l-line-rpx':c.unit==='rpx','zp-l-line-px':c.unit==='px'}" :style="[{backgroundColor:zTheme.line[ts]},c.noMoreLineCustomStyle]" />
</template>
</view>
</template>
<script>
import zStatic from '../js/z-paging-static'
import Enum from '../js/z-paging-enum'
export default {
name: 'z-paging-load-more',
data() {
return {
M: Enum.More,
zTheme: {
title: { white: '#efefef', black: '#a4a4a4' },
line: { white: '#efefef', black: '#eeeeee' },
circleBorder: { white: '#aaaaaa', black: '#c8c8c8' },
circleBorderTop: { white: '#ffffff', black: '#444444' },
flower: { white: zStatic.base64FlowerWhite, black: zStatic.base64Flower },
indicator: { white: '#eeeeee', black: '#777777' }
}
};
},
props: ['zConfig'],
computed: {
ts() {
return this.c.defaultThemeStyle;
},
//
c() {
return this.zConfig || {};
},
//
ownLoadingMoreText() {
return {
[this.M.Default]: this.c.defaultText,
[this.M.Loading]: this.c.loadingText,
[this.M.NoMore]: this.c.noMoreText,
[this.M.Fail]: this.c.failText,
}[this.finalStatus];
},
//
finalStatus() {
if (this.c.defaultAsLoading && this.c.status === this.M.Default) return this.M.Loading;
return this.c.status;
},
// icon
finalLoadingIconType() {
// #ifdef APP-NVUE
return 'flower';
// #endif
return this.c.loadingIconType;
}
},
methods: {
//
doClick() {
this.$emit('doClick');
}
}
}
</script>
<style scoped>
@import "../css/z-paging-static.css";
.zp-l-container {
/* #ifndef APP-NVUE */
clear: both;
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
}
.zp-l-container-rpx {
height: 80rpx;
font-size: 27rpx;
}
.zp-l-container-px {
height: 40px;
font-size: 14px;
}
.zp-l-line-loading-custom-image {
color: #a4a4a4;
}
.zp-l-line-loading-custom-image-rpx {
margin-right: 8rpx;
width: 28rpx;
height: 28rpx;
}
.zp-l-line-loading-custom-image-px {
margin-right: 4px;
width: 14px;
height: 14px;
}
.zp-l-line-loading-custom-image-animated{
/* #ifndef APP-NVUE */
animation: loading-circle 1s linear infinite;
/* #endif */
}
.zp-l-circle-loading-view {
border: 3rpx solid #dddddd;
border-radius: 50%;
/* #ifndef APP-NVUE */
animation: loading-circle 1s linear infinite;
/* #endif */
/* #ifdef APP-NVUE */
width: 30rpx;
height: 30rpx;
/* #endif */
}
.zp-l-circle-loading-view-rpx {
margin-right: 8rpx;
width: 23rpx;
height: 23rpx;
}
.zp-l-circle-loading-view-px {
margin-right: 4px;
width: 12px;
height: 12px;
}
.zp-l-text-rpx {
font-size: 30rpx;
margin: 0rpx 6rpx;
}
.zp-l-text-px {
font-size: 15px;
margin: 0px 3px;
}
.zp-l-line-rpx {
height: 1px;
width: 100rpx;
margin: 0rpx 10rpx;
}
.zp-l-line-px {
height: 1px;
width: 50px;
margin: 0rpx 5px;
}
/* #ifndef APP-NVUE */
@keyframes loading-circle {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
/* #endif */
</style>

View File

@ -0,0 +1,214 @@
<!-- [z-paging]下拉刷新view -->
<template>
<view style="height: 100%;">
<view :class="showUpdateTime?'zp-r-container zp-r-container-padding':'zp-r-container'">
<view class="zp-r-left">
<!-- 非加载中(继续下拉刷新松手立即刷新状态图片) -->
<image v-if="status!==R.Loading" :class="leftImageClass" :style="[leftImageStyle,imgStyle]" :src="leftImageSrc" />
<!-- 加载状态图片 -->
<!-- #ifndef APP-NVUE -->
<image v-else :class="{'zp-line-loading-image':refreshingAnimated,'zp-r-left-image':true,'zp-r-left-image-pre-size-rpx':unit==='rpx','zp-r-left-image-pre-size-px':unit==='px'}" :style="[leftImageStyle,imgStyle]" :src="leftImageSrc" />
<!-- #endif -->
<!-- 在nvue中加载状态loading使用系统loading -->
<!-- #ifdef APP-NVUE -->
<view v-else :style="[{'margin-right':showUpdateTime?addUnit(18,unit):addUnit(12, unit)}]">
<loading-indicator :class="isIos?{'zp-loading-image-ios-rpx':unit==='rpx','zp-loading-image-ios-px':unit==='px'}:{'zp-loading-image-android-rpx':unit==='rpx','zp-loading-image-android-px':unit==='px'}"
:style="[{color:zTheme.indicator[ts]},imgStyle]" :animating="true" />
</view>
<!-- #endif -->
</view>
<!-- 右侧文字内容 -->
<view class="zp-r-right">
<!-- 右侧下拉刷新状态文字 -->
<text class="zp-r-right-text" :style="[rightTextStyle,titleStyle]">{{currentTitle}}</text>
<!-- 右侧下拉刷新时间文字 -->
<text v-if="showUpdateTime&&refresherTimeText.length" class="zp-r-right-text" :class="{'zp-r-right-time-text-rpx':unit==='rpx','zp-r-right-time-text-px':unit==='px'}" :style="[{color:zTheme.title[ts]},updateTimeStyle]">
{{refresherTimeText}}
</text>
</view>
</view>
</view>
</template>
<script>
import zStatic from '../js/z-paging-static'
import u from '../js/z-paging-utils'
import Enum from '../js/z-paging-enum'
export default {
name: 'z-paging-refresh',
data() {
return {
R: Enum.Refresher,
refresherTimeText: '',
zTheme: {
title: { white: '#efefef', black: '#555555' },
arrow: { white: zStatic.base64ArrowWhite, black: zStatic.base64Arrow },
flower: { white: zStatic.base64FlowerWhite, black: zStatic.base64Flower },
success: { white: zStatic.base64SuccessWhite, black: zStatic.base64Success },
indicator: { white: '#eeeeee', black: '#777777' }
}
};
},
props: ['status', 'defaultThemeStyle', 'defaultText', 'pullingText', 'refreshingText', 'completeText', 'goF2Text', 'defaultImg', 'pullingImg',
'refreshingImg', 'completeImg', 'refreshingAnimated', 'showUpdateTime', 'updateTimeKey', 'imgStyle', 'titleStyle', 'updateTimeStyle', 'updateTimeTextMap', 'unit', 'isIos'
],
computed: {
ts() {
return this.defaultThemeStyle;
},
// Map
statusTextMap() {
this.updateTime();
const { R, defaultText, pullingText, refreshingText, completeText, goF2Text } = this;
return {
[R.Default]: defaultText,
[R.ReleaseToRefresh]: pullingText,
[R.Loading]: refreshingText,
[R.Complete]: completeText,
[R.GoF2]: goF2Text,
};
},
//
currentTitle() {
return this.statusTextMap[this.status] || this.defaultText;
},
// class
leftImageClass() {
const preSizeClass = `zp-r-left-image-pre-size-${this.unit}`;
if (this.status === this.R.Complete) return preSizeClass;
return `zp-r-left-image ${preSizeClass} ${this.status === this.R.Default ? 'zp-r-arrow-down' : 'zp-r-arrow-top'}`;
},
// style
leftImageStyle() {
const showUpdateTime = this.showUpdateTime;
const size = showUpdateTime ? u.addUnit(36, this.unit) : u.addUnit(34, this.unit);
return {width: size,height: size,'margin-right': showUpdateTime ? u.addUnit(20, this.unit) : u.addUnit(9, this.unit)};
},
// src
leftImageSrc() {
const R = this.R;
const status = this.status;
if (status === R.Default) {
if (!!this.defaultImg) return this.defaultImg;
return this.zTheme.arrow[this.ts];
} else if (status === R.ReleaseToRefresh) {
if (!!this.pullingImg) return this.pullingImg;
if (!!this.defaultImg) return this.defaultImg;
return this.zTheme.arrow[this.ts];
} else if (status === R.Loading) {
if (!!this.refreshingImg) return this.refreshingImg;
return this.zTheme.flower[this.ts];;
} else if (status === R.Complete) {
if (!!this.completeImg) return this.completeImg;
return this.zTheme.success[this.ts];;
} else if (status === R.GoF2) {
return this.zTheme.arrow[this.ts];
}
return '';
},
// style
rightTextStyle() {
let stl = {};
// #ifdef APP-NVUE
const textHeight = this.showUpdateTime ? u.addUnit(40, this.unit) : u.addUnit(80, this.unit);
stl = {'height': textHeight, 'line-height': textHeight}
// #endif
stl['color'] = this.zTheme.title[this.ts];
stl['font-size'] = u.addUnit(30, this.unit);
return stl;
}
},
methods: {
//
addUnit(value, unit) {
return u.addUnit(value, unit);
},
//
updateTime() {
if (this.showUpdateTime) {
this.refresherTimeText = u.getRefesrherFormatTimeByKey(this.updateTimeKey, this.updateTimeTextMap);
}
}
}
}
</script>
<style scoped>
@import "../css/z-paging-static.css";
.zp-r-container {
/* #ifndef APP-NVUE */
display: flex;
height: 100%;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
}
.zp-r-container-padding {
/* #ifdef APP-NVUE */
padding: 7px 0rpx;
/* #endif */
}
.zp-r-left {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
overflow: hidden;
/* #ifdef MP-ALIPAY */
margin-top: -4rpx;
/* #endif */
}
.zp-r-left-image {
transition-duration: .2s;
transition-property: transform;
color: #666666;
}
.zp-r-left-image-pre-size-rpx {
/* #ifndef APP-NVUE */
width: 34rpx;
height: 34rpx;
overflow: hidden;
/* #endif */
}
.zp-r-left-image-pre-size-px {
/* #ifndef APP-NVUE */
width: 17px;
height: 17px;
overflow: hidden;
/* #endif */
}
.zp-r-arrow-top {
transform: rotate(0deg);
}
.zp-r-arrow-down {
transform: rotate(180deg);
}
.zp-r-right {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
align-items: center;
justify-content: center;
}
.zp-r-right-time-text-rpx {
margin-top: 10rpx;
font-size: 26rpx;
}
.zp-r-right-time-text-px {
margin-top: 5px;
font-size: 13px;
}
</style>

View File

@ -0,0 +1,3 @@
// z-paging全局配置文件注意避免更新时此文件被覆盖若被覆盖可在此文件中右键->点击本地历史记录,找回覆盖前的配置
export default {}

View File

@ -0,0 +1,241 @@
/* [z-paging]公共css*/
.z-paging-content {
position: relative;
flex-direction: column;
/* #ifndef APP-NVUE */
overflow: hidden;
/* #endif */
}
.z-paging-content-full {
/* #ifndef APP-NVUE */
display: flex;
width: 100%;
height: 100%;
/* #endif */
}
.z-paging-content-fixed, .zp-loading-fixed {
position: fixed;
/* #ifndef APP-NVUE */
height: auto;
width: auto;
/* #endif */
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.zp-f2-content {
width: 100%;
position: fixed;
top: 0;
left: 0;
background-color: white;
}
.zp-page-top, .zp-page-bottom {
/* #ifndef APP-NVUE */
width: auto;
/* #endif */
position: fixed;
left: 0;
right: 0;
z-index: 999;
}
.zp-page-left, .zp-page-right {
/* #ifndef APP-NVUE */
height: 100%;
/* #endif */
}
.zp-scroll-view-super {
flex: 1;
overflow: hidden;
position: relative;
}
.zp-view-super {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.zp-scroll-view-container, .zp-scroll-view {
position: relative;
/* #ifndef APP-NVUE */
height: 100%;
width: 100%;
/* #endif */
}
.zp-absoulte {
/* #ifndef APP-NVUE */
position: absolute;
top: 0;
width: auto;
/* #endif */
}
.zp-scroll-view-absolute {
position: absolute;
top: 0;
left: 0;
}
/* #ifndef APP-NVUE */
.zp-scroll-view-hide-scrollbar ::-webkit-scrollbar {
display: none;
-webkit-appearance: none;
width: 0 !important;
height: 0 !important;
background: transparent;
}
/* #endif */
.zp-paging-touch-view {
width: 100%;
height: 100%;
position: relative;
}
.zp-fixed-bac-view {
position: absolute;
width: 100%;
top: 0;
left: 0;
height: 200px;
}
.zp-paging-main {
height: 100%;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.zp-paging-container {
flex: 1;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.zp-chat-record-loading-custom-image {
width: 35rpx;
height: 35rpx;
/* #ifndef APP-NVUE */
animation: loading-flower 1s linear infinite;
/* #endif */
}
.zp-page-bottom-keyboard-placeholder-animate {
transition-property: height;
transition-duration: 0.15s;
/* #ifndef APP-NVUE */
will-change: height;
/* #endif */
}
.zp-custom-refresher-container {
overflow: hidden;
}
.zp-custom-refresher-refresh {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
}
.zp-back-to-top {
z-index: 999;
position: absolute;
bottom: 0rpx;
transition-duration: .3s;
transition-property: opacity;
}
.zp-back-to-top-rpx {
width: 76rpx;
height: 76rpx;
bottom: 0rpx;
right: 25rpx;
}
.zp-back-to-top-px {
width: 38px;
height: 38px;
bottom: 0px;
right: 13px;
}
.zp-back-to-top-show {
opacity: 1;
}
.zp-back-to-top-hide {
opacity: 0;
}
.zp-back-to-top-img {
/* #ifndef APP-NVUE */
width: 100%;
height: 100%;
/* #endif */
/* #ifdef APP-NVUE */
flex: 1;
/* #endif */
z-index: 999;
}
.zp-back-to-top-img-inversion {
transform: rotate(180deg);
}
.zp-empty-view {
/* #ifdef APP-NVUE */
height: 100%;
/* #endif */
flex: 1;
}
.zp-empty-view-center {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
align-items: center;
justify-content: center;
}
.zp-loading-fixed {
z-index: 9999;
}
.zp-safe-area-inset-bottom {
position: absolute;
/* #ifndef APP-PLUS */
height: env(safe-area-inset-bottom);
/* #endif */
}
.zp-n-refresh-container {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
width: 750rpx;
}
.zp-n-list-container{
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex: 1;
}

View File

@ -0,0 +1,50 @@
/* [z-paging]公用的静态css资源 */
.zp-line-loading-image {
/* #ifndef APP-NVUE */
animation: loading-flower 1s steps(12) infinite;
/* #endif */
color: #666666;
}
.zp-line-loading-image-rpx {
margin-right: 8rpx;
width: 34rpx;
height: 34rpx;
}
.zp-line-loading-image-px {
margin-right: 4px;
width: 17px;
height: 17px;
}
.zp-loading-image-ios-rpx {
width: 40rpx;
height: 40rpx;
}
.zp-loading-image-ios-px {
width: 20px;
height: 20px;
}
.zp-loading-image-android-rpx {
width: 34rpx;
height: 34rpx;
}
.zp-loading-image-android-px {
width: 17px;
height: 17px;
}
/* #ifndef APP-NVUE */
@keyframes loading-flower {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(1turn);
transform: rotate(1turn);
}
}
/* #endif */

View File

@ -0,0 +1,23 @@
{
"zp.refresher.default": "Pull down to refresh",
"zp.refresher.pulling": "Release to refresh",
"zp.refresher.refreshing": "Refreshing...",
"zp.refresher.complete": "Refresh succeeded",
"zp.refresher.f2": "Refresh to enter 2f",
"zp.loadingMore.default": "Click to load more",
"zp.loadingMore.loading": "Loading...",
"zp.loadingMore.noMore": "No more data",
"zp.loadingMore.fail": "Load failed,click to reload",
"zp.emptyView.title": "No data",
"zp.emptyView.reload": "Reload",
"zp.emptyView.error": "Sorry,load failed",
"zp.refresherUpdateTime.title": "Last update: ",
"zp.refresherUpdateTime.none": "None",
"zp.refresherUpdateTime.today": "Today",
"zp.refresherUpdateTime.yesterday": "Yesterday",
"zp.systemLoading.title": "Loading..."
}

View File

@ -0,0 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}

View File

@ -0,0 +1,23 @@
{
"zp.refresher.default": "继续下拉刷新",
"zp.refresher.pulling": "松开立即刷新",
"zp.refresher.refreshing": "正在刷新...",
"zp.refresher.complete": "刷新成功",
"zp.refresher.f2": "松手进入二楼",
"zp.loadingMore.default": "点击加载更多",
"zp.loadingMore.loading": "正在加载...",
"zp.loadingMore.noMore": "没有更多了",
"zp.loadingMore.fail": "加载失败,点击重新加载",
"zp.emptyView.title": "没有数据哦~",
"zp.emptyView.reload": "重新加载",
"zp.emptyView.error": "很抱歉,加载失败",
"zp.refresherUpdateTime.title": "最后更新:",
"zp.refresherUpdateTime.none": "无",
"zp.refresherUpdateTime.today": "今天",
"zp.refresherUpdateTime.yesterday": "昨天",
"zp.systemLoading.title": "加载中..."
}

View File

@ -0,0 +1,23 @@
{
"zp.refresher.default": "繼續下拉重繪",
"zp.refresher.pulling": "鬆開立即重繪",
"zp.refresher.refreshing": "正在重繪...",
"zp.refresher.complete": "重繪成功",
"zp.refresher.f2": "鬆手進入二樓",
"zp.loadingMore.default": "點擊加載更多",
"zp.loadingMore.loading": "正在加載...",
"zp.loadingMore.noMore": "沒有更多了",
"zp.loadingMore.fail": "加載失敗,點擊重新加載",
"zp.emptyView.title": "沒有數據哦~",
"zp.emptyView.reload": "重新加載",
"zp.emptyView.error": "很抱歉,加載失敗",
"zp.refresherUpdateTime.title": "最後更新:",
"zp.refresherUpdateTime.none": "無",
"zp.refresherUpdateTime.today": "今天",
"zp.refresherUpdateTime.yesterday": "昨天",
"zp.systemLoading.title": "加載中..."
}

View File

@ -0,0 +1,25 @@
// [z-paging]useZPaging hooks
import { onPageScroll, onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app';
function useZPaging(paging) {
const cPaging = !!paging ? paging.value || paging : null;
onPullDownRefresh(() => {
if (!cPaging || !cPaging.value) return;
cPaging.value.reload().catch(() => {});
})
onPageScroll(e => {
if (!cPaging || !cPaging.value) return;
cPaging.value.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && cPaging.value.doChatRecordLoadMore();
})
onReachBottom(() => {
if (!cPaging || !cPaging.value) return;
cPaging.value.pageReachBottom();
})
}
export default useZPaging

View File

@ -0,0 +1,25 @@
// [z-paging]useZPagingComp hooks
function useZPagingComp(paging) {
const cPaging = !!paging ? paging.value || paging : null;
const reload = () => {
if (!cPaging || !cPaging.value) return;
cPaging.value.reload().catch(() => {});
}
const updatePageScrollTop = scrollTop => {
if (!cPaging || !cPaging.value) return;
cPaging.value.updatePageScrollTop(scrollTop);
}
const doChatRecordLoadMore = () => {
if (!cPaging || !cPaging.value) return;
cPaging.value.doChatRecordLoadMore();
}
const pageReachBottom = () => {
if (!cPaging || !cPaging.value) return;
cPaging.value.pageReachBottom();
}
return { reload, updatePageScrollTop, doChatRecordLoadMore, pageReachBottom };
}
export default useZPagingComp

View File

@ -0,0 +1,125 @@
// [z-paging]点击返回顶部view模块
import u from '.././z-paging-utils'
export default {
props: {
// 自动显示点击返回顶部按钮,默认为否
autoShowBackToTop: {
type: Boolean,
default: u.gc('autoShowBackToTop', false)
},
// 点击返回顶部按钮显示/隐藏的阈值(滚动距离)单位为px默认为400rpx
backToTopThreshold: {
type: [Number, String],
default: u.gc('backToTopThreshold', '400rpx')
},
// 点击返回顶部按钮的自定义图片地址默认使用z-paging内置的图片
backToTopImg: {
type: String,
default: u.gc('backToTopImg', '')
},
// 点击返回顶部按钮返回到顶部时是否展示过渡动画,默认为是
backToTopWithAnimate: {
type: Boolean,
default: u.gc('backToTopWithAnimate', true)
},
// 点击返回顶部按钮与底部的距离注意添加单位px或rpx默认为160rpx
backToTopBottom: {
type: [Number, String],
default: u.gc('backToTopBottom', '160rpx')
},
// 点击返回顶部按钮的自定义样式
backToTopStyle: {
type: Object,
default: u.gc('backToTopStyle', {}),
},
// iOS点击顶部状态栏、安卓双击标题栏时滚动条返回顶部只支持竖向默认为是
enableBackToTop: {
type: Boolean,
default: u.gc('enableBackToTop', true)
},
},
data() {
return {
// 点击返回顶部的class
backToTopClass: 'zp-back-to-top zp-back-to-top-hide',
// 上次点击返回顶部的时间
lastBackToTopShowTime: 0,
// 点击返回顶部显示的class是否在展示中使得按钮展示/隐藏过度效果更自然
showBackToTopClass: false,
}
},
computed: {
backToTopThresholdUnitConverted() {
return u.addUnit(this.backToTopThreshold, this.unit);
},
backToTopBottomUnitConverted() {
return u.addUnit(this.backToTopBottom, this.unit);
},
finalEnableBackToTop() {
return this.usePageScroll ? false : this.enableBackToTop;
},
finalBackToTopThreshold() {
return u.convertToPx(this.backToTopThresholdUnitConverted);
},
finalBackToTopStyle() {
const backToTopStyle = this.backToTopStyle;
if (!backToTopStyle.bottom) {
backToTopStyle.bottom = this.windowBottom + u.convertToPx(this.backToTopBottomUnitConverted) + 'px';
}
if(!backToTopStyle.position){
backToTopStyle.position = this.usePageScroll ? 'fixed': 'absolute';
}
return backToTopStyle;
},
finalBackToTopClass() {
return `${this.backToTopClass} zp-back-to-top-${this.unit}`;
}
},
methods: {
// 点击了返回顶部
_backToTopClick() {
let callbacked = false;
this.$emit('backToTopClick', toTop => {
(toTop === undefined || toTop === true) && this._handleToTop();
callbacked = true;
});
// 如果用户没有禁止默认的返回顶部事件,则触发滚动到顶部
this.$nextTick(() => {
!callbacked && this._handleToTop();
})
},
// 处理滚动到顶部(聊天记录模式中为滚动到底部)
_handleToTop() {
!this.backToTopWithAnimate && this._checkShouldShowBackToTop(0);
!this.useChatRecordMode ? this.scrollToTop(this.backToTopWithAnimate) : this.scrollToBottom(this.backToTopWithAnimate);
},
// 判断是否要显示返回顶部按钮
_checkShouldShowBackToTop(scrollTop) {
if (!this.autoShowBackToTop) {
this.showBackToTopClass = false;
return;
}
if (scrollTop > this.finalBackToTopThreshold) {
if (!this.showBackToTopClass) {
// 记录当前点击返回顶部按钮显示的class生效了
this.showBackToTopClass = true;
this.lastBackToTopShowTime = new Date().getTime();
// 当滚动到需要展示返回顶部的阈值内则延迟300毫秒展示返回到顶部按钮
u.delay(() => {
this.backToTopClass = 'zp-back-to-top zp-back-to-top-show';
}, 300)
}
} else {
// 如果当前点击返回顶部按钮显示的class是生效状态并且滚动小于触发阈值则隐藏返回顶部按钮
if (this.showBackToTopClass) {
this.backToTopClass = 'zp-back-to-top zp-back-to-top-hide';
u.delay(() => {
this.showBackToTopClass = false;
}, new Date().getTime() - this.lastBackToTopShowTime < 500 ? 0 : 300)
}
}
},
}
}

View File

@ -0,0 +1,149 @@
// [z-paging]聊天记录模式模块
import u from '.././z-paging-utils'
export default {
props: {
// 使用聊天记录模式,默认为否
useChatRecordMode: {
type: Boolean,
default: u.gc('useChatRecordMode', false)
},
// 使用聊天记录模式时滚动到顶部后列表垂直移动偏移距离。默认0rpx。单位px暂时无效
chatRecordMoreOffset: {
type: [Number, String],
default: u.gc('chatRecordMoreOffset', '0rpx')
},
// 使用聊天记录模式时是否自动隐藏键盘:在用户触摸列表时候自动隐藏键盘,默认为是
autoHideKeyboardWhenChat: {
type: Boolean,
default: u.gc('autoHideKeyboardWhenChat', true)
},
// 使用聊天记录模式中键盘弹出时是否自动调整slot="bottom"高度,默认为是
autoAdjustPositionWhenChat: {
type: Boolean,
default: u.gc('autoAdjustPositionWhenChat', true)
},
// 使用聊天记录模式中键盘弹出时占位高度偏移距离。默认0rpx。单位px
chatAdjustPositionOffset: {
type: [Number, String],
default: u.gc('chatAdjustPositionOffset', '0rpx')
},
// 使用聊天记录模式中键盘弹出时是否自动滚动到底部,默认为否
autoToBottomWhenChat: {
type: Boolean,
default: u.gc('autoToBottomWhenChat', false)
},
// 使用聊天记录模式中reload时是否显示chatLoading默认为否
showChatLoadingWhenReload: {
type: Boolean,
default: u.gc('showChatLoadingWhenReload', false)
},
// 在聊天记录模式中滑动到顶部状态为默认状态时以加载中的状态展示默认为是。若设置为否则默认会显示【点击加载更多】然后才会显示loading
chatLoadingMoreDefaultAsLoading: {
type: Boolean,
default: u.gc('chatLoadingMoreDefaultAsLoading', true)
},
},
data() {
return {
// 键盘高度
keyboardHeight: 0,
// 键盘高度是否未改变,此时占位高度变化不需要动画效果
isKeyboardHeightChanged: false,
}
},
computed: {
finalChatRecordMoreOffset() {
return u.convertToPx(this.chatRecordMoreOffset);
},
finalChatAdjustPositionOffset() {
return u.convertToPx(this.chatAdjustPositionOffset);
},
// 聊天记录模式旋转180度style
chatRecordRotateStyle() {
let cellStyle;
// 在vue中直接将列表倒置因此在vue的cell中也直接写style="transform: scaleY(-1)"转回来即可。
// #ifndef APP-NVUE
cellStyle = this.useChatRecordMode ? { transform: 'scaleY(-1)' } : {};
// #endif
// 在nvue中需要考虑数据量不满一页的情况因为nvue中的list无法通过flex-end修改不满一页的起始位置会导致不满一页时列表数据从底部开始因此需要特别判断
// 当数据不满一屏的时候,不进行列表倒置
// #ifdef APP-NVUE
cellStyle = this.useChatRecordMode ? { transform: this.isFirstPageAndNoMore ? 'scaleY(1)' : 'scaleY(-1)' } : {};
// #endif
this.$emit('update:cellStyle', cellStyle);
this.$emit('cellStyleChange', cellStyle);
// 在聊天记录模式中,如果列表没有倒置并且当前是第一页,则需要自动滚动到最底部
this.$nextTick(() => {
if (this.isFirstPage && this.isChatRecordModeAndNotInversion) {
this.$nextTick(() => {
// 这里多次触发滚动到底部是为了避免在某些情况下即使是在nextTick但是cell未渲染完毕导致滚动到底部位置不正确的问题
this._scrollToBottom(false);
u.delay(() => {
this._scrollToBottom(false);
u.delay(() => {
this._scrollToBottom(false);
}, 50)
}, 50)
})
}
})
return cellStyle;
},
// 是否是聊天记录列表并且有配置transform
isChatRecordModeHasTransform() {
return this.useChatRecordMode && this.chatRecordRotateStyle && this.chatRecordRotateStyle.transform;
},
// 是否是聊天记录列表并且列表未倒置
isChatRecordModeAndNotInversion() {
return this.isChatRecordModeHasTransform && this.chatRecordRotateStyle.transform === 'scaleY(1)';
},
// 是否是聊天记录列表并且列表倒置
isChatRecordModeAndInversion() {
return this.isChatRecordModeHasTransform && this.chatRecordRotateStyle.transform === 'scaleY(-1)';
},
// 最终的聊天记录模式中底部安全区域的高度,如果开启了底部安全区域并且键盘未弹出,则添加底部区域高度
chatRecordModeSafeAreaBottom() {
return this.safeAreaInsetBottom && !this.keyboardHeight ? this.safeAreaBottom : 0;
}
},
mounted() {
// 监听键盘高度变化H5、百度小程序、抖音小程序、飞书小程序不支持
// #ifndef H5 || MP-BAIDU || MP-TOUTIAO
if (this.useChatRecordMode) {
uni.onKeyboardHeightChange(this._handleKeyboardHeightChange);
}
// #endif
},
methods: {
// 添加聊天记录
addChatRecordData(data, toBottom = true, toBottomWithAnimate = true) {
if (!this.useChatRecordMode) return;
this.isTotalChangeFromAddData = true;
this.addDataFromTop(data, toBottom, toBottomWithAnimate);
},
// 手动触发滚动到顶部加载更多,聊天记录模式时有效
doChatRecordLoadMore() {
this.useChatRecordMode && this._onLoadingMore('click');
},
// 处理键盘高度变化
_handleKeyboardHeightChange(res) {
this.$emit('keyboardHeightChange', res);
if (this.autoAdjustPositionWhenChat) {
this.isKeyboardHeightChanged = true;
this.keyboardHeight = res.height > 0 ? res.height + this.finalChatAdjustPositionOffset : res.height;
}
if (this.autoToBottomWhenChat && this.keyboardHeight > 0) {
u.delay(() => {
this.scrollToBottom(false);
u.delay(() => {
this.scrollToBottom(false);
})
})
}
}
}
}

View File

@ -0,0 +1,152 @@
// [z-paging]通用布局相关模块
import u from '.././z-paging-utils'
// #ifdef APP-NVUE
const weexDom = weex.requireModule('dom');
// #endif
export default {
data() {
return {
systemInfo: null,
cssSafeAreaInsetBottom: -1,
isReadyDestroy: false,
}
},
computed: {
// 顶部可用距离
windowTop() {
if (!this.systemInfo) return 0;
// 暂时修复vue3中隐藏系统导航栏后windowTop获取不正确的问题具体bug详见https://ask.dcloud.net.cn/question/141634
// 感谢litangyuhttps://github.com/SmileZXLee/uni-z-paging/issues/25
// #ifdef VUE3 && H5
const pageHeadNode = document.getElementsByTagName("uni-page-head");
if (!pageHeadNode.length) return 0;
// #endif
return this.systemInfo.windowTop || 0;
},
// 底部安全区域高度
safeAreaBottom() {
if (!this.systemInfo) return 0;
let safeAreaBottom = 0;
// #ifdef APP-PLUS
safeAreaBottom = this.systemInfo.safeAreaInsets.bottom || 0 ;
// #endif
// #ifndef APP-PLUS
safeAreaBottom = Math.max(this.cssSafeAreaInsetBottom, 0);
// #endif
return safeAreaBottom;
},
// 是否是比较老的webview在一些老的webview中需要进行一些特殊处理
isOldWebView() {
// #ifndef APP-NVUE || MP-KUAISHOU
try {
const systemInfos = u.getSystemInfoSync(true).system.split(' ');
const deviceType = systemInfos[0];
const version = parseInt(systemInfos[1]);
if ((deviceType === 'iOS' && version <= 10) || (deviceType === 'Android' && version <= 6)) {
return true;
}
} catch(e) {
return false;
}
// #endif
return false;
},
// 当前组件的$slots兼容不同平台
zSlots() {
// #ifdef VUE2
// #ifdef MP-ALIPAY
return this.$slots;
// #endif
return this.$scopedSlots || this.$slots;
// #endif
return this.$slots;
},
},
beforeDestroy() {
this.isReadyDestroy = true;
},
// #ifdef VUE3
unmounted() {
this.isReadyDestroy = true;
},
// #endif
methods: {
// 更新fixed模式下z-paging的布局
updateFixedLayout() {
this.fixed && this.$nextTick(() => {
this.systemInfo = u.getSystemInfoSync();
})
},
// 获取节点尺寸
_getNodeClientRect(select, inDom = true, scrollOffset = false) {
if (this.isReadyDestroy) {
return Promise.resolve(false);
};
// nvue中获取节点信息
// #ifdef APP-NVUE
select = select.replace(/[.|#]/g, '');
const ref = this.$refs[select];
return new Promise((resolve, reject) => {
if (ref) {
weexDom.getComponentRect(ref, option => {
resolve(option && option.result ? [option.size] : false);
})
} else {
resolve(false);
}
});
return;
// #endif
// vue中获取节点信息
//#ifdef MP-ALIPAY
inDom = false;
//#endif
/*
inDom可能是truefalse也可能是具体的dom节点
如果inDom不为false则使用uni.createSelectorQuery().in()进行查询如果inDom为true则in中的是this否则in中的为具体的dom
如果inDom为false则使用uni.createSelectorQuery()进行查询
*/
let res = !!inDom ? uni.createSelectorQuery().in(inDom === true ? this : inDom) : uni.createSelectorQuery();
scrollOffset ? res.select(select).scrollOffset() : res.select(select).boundingClientRect();
return new Promise((resolve, reject) => {
res.exec(data => {
resolve((data && data != '' && data != undefined && data.length) ? data : false);
});
});
},
// 获取slot="left"和slot="right"宽度并且更新布局
_updateLeftAndRightWidth(targetStyle, parentNodePrefix) {
this.$nextTick(() => {
let delayTime = 0;
// #ifdef MP-BAIDU
delayTime = 10;
// #endif
setTimeout(() => {
['left','right'].map(position => {
this._getNodeClientRect(`.${parentNodePrefix}-${position}`).then(res => {
this.$set(targetStyle, position, res ? res[0].width + 'px' : '0px');
});
})
}, delayTime)
})
},
// 通过获取css设置的底部安全区域占位view高度设置bottom距离直接通过systemInfo在部分平台上无法获取到底部安全区域
_getCssSafeAreaInsetBottom(success) {
this._getNodeClientRect('.zp-safe-area-inset-bottom').then(res => {
this.cssSafeAreaInsetBottom = res ? res[0].height : -1;
res && success && success();
});
},
// 同步获取系统信息兼容不同平台供z-paging-swiper使用
_getSystemInfoSync(useCache = false) {
return u.getSystemInfoSync(useCache);
}
}
}

View File

@ -0,0 +1,736 @@
// [z-paging]数据处理模块
import u from '.././z-paging-utils'
import c from '.././z-paging-constant'
import Enum from '.././z-paging-enum'
import interceptor from '../z-paging-interceptor'
export default {
props: {
// 自定义初始的pageNo默认为1
defaultPageNo: {
type: Number,
default: u.gc('defaultPageNo', 1),
observer: function(newVal) {
this.pageNo = newVal;
},
},
// 自定义pageSize默认为10
defaultPageSize: {
type: Number,
default: u.gc('defaultPageSize', 10),
validator: (value) => {
if (value <= 0) u.consoleErr('default-page-size必须大于0');
return value > 0;
}
},
// 为保证数据一致设置当前tab切换时的标识key并在complete中传递相同key若二者不一致则complete将不会生效
dataKey: {
type: [Number, String, Object],
default: u.gc('dataKey', null),
},
// 使用缓存若开启将自动缓存第一页的数据默认为否。请注意因考虑到切换tab时不同tab数据不同的情况默认仅会缓存组件首次加载时第一次请求到的数据后续的下拉刷新操作不会更新缓存。
useCache: {
type: Boolean,
default: u.gc('useCache', false)
},
// 使用缓存时缓存的key用于区分不同列表的缓存数据useCache为true时必须设置否则缓存无效
cacheKey: {
type: String,
default: u.gc('cacheKey', null)
},
// 缓存模式默认仅会缓存组件首次加载时第一次请求到的数据可设置为always即代表总是缓存每次列表刷新(下拉刷新、调用reload等)都会更新缓存
cacheMode: {
type: String,
default: u.gc('cacheMode', Enum.CacheMode.Default)
},
// 自动注入的list名可自动修改父view(包含ref="paging")中对应name的list值
autowireListName: {
type: String,
default: u.gc('autowireListName', '')
},
// 自动注入的query名可自动调用父view(包含ref="paging")中的query方法
autowireQueryName: {
type: String,
default: u.gc('autowireQueryName', '')
},
// 获取分页数据Function功能与@query类似。若设置了fetch则@query将不再触发
fetch: {
type: Function,
default: null
},
// fetch的附加参数fetch配置后有效
fetchParams: {
type: Object,
default: u.gc('fetchParams', null)
},
// z-paging mounted后自动调用reload方法(mounted后自动调用接口),默认为是
auto: {
type: Boolean,
default: u.gc('auto', true)
},
// 用户下拉刷新时是否触发reload方法默认为是
reloadWhenRefresh: {
type: Boolean,
default: u.gc('reloadWhenRefresh', true)
},
// reload时自动滚动到顶部默认为是
autoScrollToTopWhenReload: {
type: Boolean,
default: u.gc('autoScrollToTopWhenReload', true)
},
// reload时立即自动清空原list默认为是若立即自动清空则在reload之后、请求回调之前页面是空白的
autoCleanListWhenReload: {
type: Boolean,
default: u.gc('autoCleanListWhenReload', true)
},
// 列表刷新时自动显示下拉刷新view默认为否
showRefresherWhenReload: {
type: Boolean,
default: u.gc('showRefresherWhenReload', false)
},
// 列表刷新时自动显示加载更多view且为加载中状态默认为否
showLoadingMoreWhenReload: {
type: Boolean,
default: u.gc('showLoadingMoreWhenReload', false)
},
// 组件created时立即触发reload(可解决一些情况下先看到页面再看到loading的问题)auto为true时有效。为否时将在mounted+nextTick后触发reload默认为否
createdReload: {
type: Boolean,
default: u.gc('createdReload', false)
},
// 本地分页时上拉加载更多延迟时间单位为毫秒默认200毫秒
localPagingLoadingTime: {
type: [Number, String],
default: u.gc('localPagingLoadingTime', 200)
},
// 自动拼接complete中传过来的数组(使用聊天记录模式时无效)
concat: {
type: Boolean,
default: u.gc('concat', true)
},
// 请求失败是否触发reject默认为是
callNetworkReject: {
type: Boolean,
default: u.gc('callNetworkReject', true)
},
// 父组件v-model所绑定的list的值
value: {
type: Array,
default: function() {
return [];
}
},
// #ifdef VUE3
modelValue: {
type: Array,
default: function() {
return [];
}
}
// #endif
},
data (){
return {
currentData: [],
totalData: [],
realTotalData: [],
totalLocalPagingList: [],
dataPromiseResultMap: {
reload: null,
complete: null,
localPaging: null
},
isSettingCacheList: false,
pageNo: 1,
currentRefreshPageSize: 0,
isLocalPaging: false,
isAddedData: false,
isTotalChangeFromAddData: false,
privateConcat: true,
myParentQuery: -1,
firstPageLoaded: false,
pagingLoaded: false,
loaded: false,
isUserReload: true,
fromEmptyViewReload: false,
queryFrom: '',
listRendering: false,
isHandlingRefreshToPage: false,
isFirstPageAndNoMore: false,
totalDataChangeThrow: true
}
},
computed: {
pageSize() {
return this.defaultPageSize;
},
finalConcat() {
return this.concat && this.privateConcat;
},
finalUseCache() {
if (this.useCache && !this.cacheKey) {
u.consoleErr('use-cache为true时必须设置cache-key否则缓存无效');
}
return this.useCache && !!this.cacheKey;
},
finalCacheKey() {
return this.cacheKey ? `${c.cachePrefixKey}-${this.cacheKey}` : null;
},
isFirstPage() {
return this.pageNo === this.defaultPageNo;
}
},
watch: {
totalData(newVal, oldVal) {
this._totalDataChange(newVal, oldVal, this.totalDataChangeThrow);
this.totalDataChangeThrow = true;
},
currentData(newVal, oldVal) {
this._currentDataChange(newVal, oldVal);
},
useChatRecordMode(newVal, oldVal) {
if (newVal) {
this.nLoadingMoreFixedHeight = false;
}
},
value: {
handler(newVal) {
// 当v-model绑定的数据源被更改时此时数据源改变不emit input事件避免循环调用
if (newVal !== this.totalData) {
this.totalDataChangeThrow = false;
this.totalData = newVal;
}
},
immediate: true
},
// #ifdef VUE3
modelValue: {
handler(newVal) {
// 当v-model绑定的数据源被更改时此时数据源改变不emit input事件避免循环调用
if (newVal !== this.totalData) {
this.totalDataChangeThrow = false;
this.totalData = newVal;
}
},
immediate: true
}
// #endif
},
methods: {
// 请求结束(成功或者失败)调用此方法将请求的结果传递给z-paging处理第一个参数为请求结果数组第二个参数为是否成功(默认为是)
complete(data, success = true) {
this.customNoMore = -1;
return this.addData(data, success);
},
//【保证数据一致】请求结束(成功或者失败)调用此方法将请求的结果传递给z-paging处理第一个参数为请求结果数组第二个参数为dataKey需与:data-key绑定的一致第三个参数为是否成功(默认为是)
completeByKey(data, dataKey = null, success = true) {
if (dataKey !== null && this.dataKey !== null && dataKey !== this.dataKey) {
this.isFirstPage && this.endRefresh();
return new Promise(resolve => resolve());
}
this.customNoMore = -1;
return this.addData(data, success);
},
//【通过total判断是否有更多数据】请求结束(成功或者失败)调用此方法将请求的结果传递给z-paging处理第一个参数为请求结果数组第二个参数为total(列表总数),第三个参数为是否成功(默认为是)
completeByTotal(data, total, success = true) {
if (total == 'undefined') {
this.customNoMore = -1;
} else {
const dataTypeRes = this._checkDataType(data, success, false);
data = dataTypeRes.data;
success = dataTypeRes.success;
if (total >= 0 && success) {
return new Promise((resolve, reject) => {
this.$nextTick(() => {
let nomore = false;
const realTotalDataCount = this.pageNo == this.defaultPageNo ? 0 : this.realTotalData.length;
const dataLength = this.privateConcat ? data.length : 0;
let exceedCount = realTotalDataCount + dataLength - total;
// 没有更多数据了
if (exceedCount >= 0) {
nomore = true;
// 仅截取total内部分的数据
exceedCount = this.defaultPageSize - exceedCount;
if (this.privateConcat && exceedCount > 0 && exceedCount < data.length) {
data = data.splice(0, exceedCount);
}
}
this.completeByNoMore(data, nomore, success).then(res => resolve(res)).catch(() => reject());
})
});
}
}
return this.addData(data, success);
},
//【自行判断是否有更多数据】请求结束(成功或者失败)调用此方法将请求的结果传递给z-paging处理第一个参数为请求结果数组第二个参数为是否没有更多数据第三个参数为是否成功(默认是是)
completeByNoMore(data, nomore, success = true) {
if (nomore != 'undefined') {
this.customNoMore = nomore == true ? 1 : 0;
}
return this.addData(data, success);
},
// 请求结束且请求失败时调用,支持传入请求失败原因
completeByError(errorMsg) {
this.customerEmptyViewErrorText = errorMsg;
return this.complete(false);
},
// 与上方complete方法功能一致新版本中设置服务端回调数组请使用complete方法
addData(data, success = true) {
if (!this.fromCompleteEmit) {
this.disabledCompleteEmit = true;
this.fromCompleteEmit = false;
}
const currentTimeStamp = u.getTime();
const disTime = currentTimeStamp - this.requestTimeStamp;
let minDelay = this.minDelay;
if (this.isFirstPage && this.finalShowRefresherWhenReload) {
minDelay = Math.max(400, minDelay);
}
const addDataDalay = (this.requestTimeStamp > 0 && disTime < minDelay) ? minDelay - disTime : 0;
this.$nextTick(() => {
u.delay(() => {
this._addData(data, success, false);
}, this.delay > 0 ? this.delay : addDataDalay)
})
return new Promise((resolve, reject) => {
this.dataPromiseResultMap.complete = { resolve, reject };
});
},
// 从顶部添加数据不会影响分页的pageNo和pageSize
addDataFromTop(data, toTop = true, toTopWithAnimate = true) {
// 数据是否拼接到顶部,如果是聊天记录模式并且列表没有倒置,则应该拼接在底部
let addFromTop = !this.isChatRecordModeAndNotInversion;
data = Object.prototype.toString.call(data) !== '[object Array]' ? [data] : (addFromTop ? data.reverse() : data);
// #ifndef APP-NVUE
this.finalUseVirtualList && this._setCellIndex(data, 'top')
// #endif
this.totalData = addFromTop ? [...data, ...this.totalData] : [...this.totalData, ...data];
if (toTop) {
u.delay(() => this.useChatRecordMode ? this.scrollToBottom(toTopWithAnimate) : this.scrollToTop(toTopWithAnimate));
}
},
// 重新设置列表数据调用此方法不会影响pageNo和pageSize也不会触发请求。适用场景当需要删除列表中某一项时将删除对应项后的数组通过此方法传递给z-paging。(当出现类似的需要修改列表数组的场景时请使用此方法请勿直接修改page中:list.sync绑定的数组)
resetTotalData(data) {
this.isTotalChangeFromAddData = true;
data = Object.prototype.toString.call(data) !== '[object Array]' ? [data] : data;
this.totalData = data;
},
// 设置本地分页数据,请求结束(成功或者失败)调用此方法将请求的结果传递给z-paging作分页处理若调用了此方法则上拉加载更多时内部会自动分页不会触发@query所绑定的事件
setLocalPaging(data, success = true) {
this.isLocalPaging = true;
this.$nextTick(() => {
this._addData(data, success, true);
})
return new Promise((resolve, reject) => {
this.dataPromiseResultMap.localPaging = { resolve, reject };
});
},
// 重新加载分页数据pageNo会恢复为默认值相当于下拉刷新的效果(animate为true时会展示下拉刷新动画默认为false)
reload(animate = this.showRefresherWhenReload) {
if (animate) {
this.privateShowRefresherWhenReload = animate;
this.isUserPullDown = true;
}
if (!this.showLoadingMoreWhenReload) {
this.listRendering = true;
}
this.$nextTick(() => {
this._preReload(animate, false);
})
return new Promise((resolve, reject) => {
this.dataPromiseResultMap.reload = { resolve, reject };
});
},
// 刷新列表数据pageNo和pageSize不会重置列表数据会重新从服务端获取。必须保证@query绑定的方法中的pageNo和pageSize和传给服务端的一致
refresh() {
return this._handleRefreshWithDisPageNo(this.pageNo - this.defaultPageNo + 1);
},
// 刷新列表数据至指定页例如pageNo=5时则代表刷新列表至第5页此时pageNo会变为5列表会展示前5页的数据。必须保证@query绑定的方法中的pageNo和pageSize和传给服务端的一致
refreshToPage(pageNo) {
this.isHandlingRefreshToPage = true;
return this._handleRefreshWithDisPageNo(pageNo + this.defaultPageNo - 1);
},
// 手动更新列表缓存数据将自动截取v-model绑定的list中的前pageSize条覆盖缓存请确保在list数据更新到预期结果后再调用此方法
updateCache() {
if (this.finalUseCache && this.totalData.length) {
this._saveLocalCache(this.totalData.slice(0, Math.min(this.totalData.length, this.pageSize)));
}
},
// 清空分页数据
clean() {
this._reload(true);
this._addData([], true, false);
},
// 清空分页数据
clear() {
this.clean();
},
// reload之前的一些处理
_preReload(animate = this.showRefresherWhenReload, isFromMounted = true, retryCount = 0) {
const showRefresher = this.finalRefresherEnabled && this.useCustomRefresher;
// #ifndef APP-NVUE
// 如果获取slot="refresher"高度失败则不触发reload直到获取slot="refresher"高度成功
if (this.customRefresherHeight === -1 && showRefresher) {
u.delay(() => {
retryCount ++;
// 如果重试次数是10的倍数(也就是每500毫秒)尝试重新获取一下slot="refresher"高度
// 此举是为了解决在某些特殊情况下z-paging组件mounted了但是未展示在用户面前比如在tabbar页面中未切换到对应tabbar但是通过代码让z-paging展示了此时控制台会报Error: Not FoundPage因为这时候去获取dom节点信息获取不到
// 当用户在某个时刻让此z-paging展示在面前时即可顺利获取到slot="refresher"高度,递归停止
if (retryCount % 10 === 0) {
this._updateCustomRefresherHeight();
}
this._preReload(animate, isFromMounted, retryCount);
}, c.delayTime / 2);
return;
}
// #endif
this.isUserReload = true;
this.loadingType = Enum.LoadingType.Refresher;
if (animate) {
this.privateShowRefresherWhenReload = animate;
// #ifndef APP-NVUE
if (this.useCustomRefresher) {
this._doRefresherRefreshAnimate();
} else {
this.refresherTriggered = true;
}
// #endif
// #ifdef APP-NVUE
this.refresherStatus = Enum.Refresher.Loading;
this.refresherRevealStackCount ++;
u.delay(() => {
this._getNodeClientRect('zp-n-refresh-container', false).then((node) => {
if (node) {
let nodeHeight = node[0].height;
this.nShowRefresherReveal = true;
this.nShowRefresherRevealHeight = nodeHeight;
u.delay(() => {
this._nDoRefresherEndAnimation(0, -nodeHeight, false, false);
u.delay(() => {
this._nDoRefresherEndAnimation(nodeHeight, 0);
}, 10)
}, 10)
}
this._reload(false, isFromMounted);
this._doRefresherLoad(false);
});
}, this.pagingLoaded ? 10 : 100)
return;
// #endif
} else {
this._refresherEnd(false, false, false, false);
}
this._reload(false, isFromMounted);
},
// 重新加载分页数据
_reload(isClean = false, isFromMounted = false, isUserPullDown = false) {
this.isAddedData = false;
this.insideOfPaging = -1;
this.cacheScrollNodeHeight = -1;
this.pageNo = this.defaultPageNo;
this._cleanRefresherEndTimeout();
!this.privateShowRefresherWhenReload && !isClean && this._startLoading(true);
this.firstPageLoaded = true;
this.isTotalChangeFromAddData = false;
if (!this.isSettingCacheList) {
this.totalData = [];
}
if (!isClean) {
this._emitQuery(this.pageNo, this.defaultPageSize, isUserPullDown ? Enum.QueryFrom.UserPullDown : Enum.QueryFrom.Reload);
let delay = 0;
// #ifdef MP-TOUTIAO
delay = 5;
// #endif
u.delay(this._callMyParentQuery, delay);
if (!isFromMounted && this.autoScrollToTopWhenReload) {
let checkedNRefresherLoading = true;
// #ifdef APP-NVUE
checkedNRefresherLoading = !this.nRefresherLoading;
// #endif
checkedNRefresherLoading && this._scrollToTop(false);
}
}
// #ifdef APP-NVUE
this.$nextTick(() => {
this.nShowBottom = this.realTotalData.length > 0;
})
// #endif
},
// 处理服务端返回的数组
_addData(data, success, isLocal) {
this.isAddedData = true;
this.fromEmptyViewReload = false;
this.isTotalChangeFromAddData = true;
this.refresherTriggered = false;
this._endSystemLoadingAndRefresh();
const tempIsUserPullDown = this.isUserPullDown;
if (this.showRefresherUpdateTime && this.isFirstPage) {
u.setRefesrherTime(u.getTime(), this.refresherUpdateTimeKey);
this.$refs.refresh && this.$refs.refresh.updateTime();
}
if (!isLocal && tempIsUserPullDown && this.isFirstPage) {
this.isUserPullDown = false;
}
this.listRendering = true;
this.$nextTick(() => {
u.delay(() => this.listRendering = false);
})
let dataTypeRes = this._checkDataType(data, success, isLocal);
data = dataTypeRes.data;
success = dataTypeRes.success;
let delayTime = c.delayTime;
if (this.useChatRecordMode) delayTime = 0;
this.loadingForNow = false;
u.delay(() => {
this.pagingLoaded = true;
this.$nextTick(()=>{
!isLocal && this._refresherEnd(delayTime > 0, true, tempIsUserPullDown);
})
})
if (this.isFirstPage) {
this.isLoadFailed = !success;
this.$emit('isLoadFailedChange', this.isLoadFailed);
if (this.finalUseCache && success && (this.cacheMode === Enum.CacheMode.Always ? true : this.isSettingCacheList)) {
this._saveLocalCache(data);
}
}
this.isSettingCacheList = false;
if (success) {
if (!(this.privateConcat === false && !this.isHandlingRefreshToPage && this.loadingStatus === Enum.More.NoMore)) {
this.loadingStatus = Enum.More.Default;
}
if (isLocal) {
// 如果当前是本地分页则必然是由setLocalPaging方法触发此时直接本地加载第一页数据即可。后续本地分页加载更多方法由滚动到底部加载更多事件处理
this.totalLocalPagingList = data;
const localPageNo = this.defaultPageNo;
const localPageSize = this.queryFrom !== Enum.QueryFrom.Refresh ? this.defaultPageSize : this.currentRefreshPageSize;
this._localPagingQueryList(localPageNo, localPageSize, 0, res => {
u.delay(() => {
this.completeByTotal(res, this.totalLocalPagingList.length);;
}, 0)
})
} else {
// 如果当前不是本地分页,则按照正常分页逻辑进行数据处理&emit数据
let dataChangeDelayTime = 0;
// #ifdef APP-NVUE
if (this.privateShowRefresherWhenReload && this.finalNvueListIs === 'waterfall') {
dataChangeDelayTime = 150;
}
// #endif
u.delay(() => {
this._currentDataChange(data, this.currentData);
this._callDataPromise(true, this.totalData);
}, dataChangeDelayTime)
}
if (this.isHandlingRefreshToPage) {
this.isHandlingRefreshToPage = false;
this.pageNo = this.defaultPageNo + Math.ceil(data.length / this.pageSize) - 1;
if (data.length % this.pageSize !== 0) {
this.customNoMore = 1;
}
}
} else {
this._currentDataChange(data, this.currentData);
this._callDataPromise(false);
this.loadingStatus = Enum.More.Fail;
this.isHandlingRefreshToPage = false;
if (this.loadingType === Enum.LoadingType.LoadMore) {
this.pageNo --;
}
}
},
// 所有数据改变时调用
_totalDataChange(newVal, oldVal, eventThrow=true) {
if ((!this.isUserReload || !this.autoCleanListWhenReload) && this.firstPageLoaded && !newVal.length && oldVal.length) {
return;
}
this._doCheckScrollViewShouldFullHeight(newVal);
if(!this.realTotalData.length && !newVal.length){
eventThrow = false;
}
this.realTotalData = newVal;
// emit列表更新事件
if (eventThrow) {
this.$emit('input', newVal);
// #ifdef VUE3
this.$emit('update:modelValue', newVal);
// #endif
this.$emit('update:list', newVal);
this.$emit('listChange', newVal);
this._callMyParentList(newVal);
}
this.firstPageLoaded = false;
this.isTotalChangeFromAddData = false;
this.$nextTick(() => {
u.delay(()=>{
// emit z-paging内容区域高度改变事件
this._getNodeClientRect('.zp-paging-container-content').then(res => {
res && this.$emit('contentHeightChanged', res[0].height);
});
}, c.delayTime * (this.isIos ? 1 : 3))
// #ifdef APP-NVUE
// 在nvue中延时600毫秒展示底部加载更多避免底部加载更多太早加载闪一下的问题
u.delay(() => {
this.nShowBottom = true;
}, c.delayTime * 6, 'nShowBottomDelay');
// #endif
})
},
// 当前数据改变时调用
_currentDataChange(newVal, oldVal) {
newVal = [...newVal];
// #ifndef APP-NVUE
this.finalUseVirtualList && this._setCellIndex(newVal, 'bottom');
// #endif
if (this.isFirstPage && this.finalConcat) {
this.totalData = [];
}
// customNoMore-1代表交由z-paging自行判断1代表没有更多了0代表还有更多数据
if (this.customNoMore !== -1) {
// 如果customNoMore等于1 或者 customNoMore不是0并且新增数组长度为0(也就是不是明确的还有更多数据并且新增的数组长度为0),则没有更多数据了
if (this.customNoMore === 1 || (this.customNoMore !== 0 && !newVal.length)) {
this.loadingStatus = Enum.More.NoMore;
}
} else {
// 如果新增的数据数组长度为0 或者 新增的数组长度小于默认的pageSize则没有更多数据了
if (!newVal.length || (newVal.length && newVal.length < this.defaultPageSize)) {
this.loadingStatus = Enum.More.NoMore;
}
}
if (!this.totalData.length) {
// #ifdef APP-NVUE
// 如果在聊天记录模式+nvue中并且数据不满一页时需要将列表倒序因为此时没有将列表旋转180度数组中第0条数据应当在最底下显示
if (this.useChatRecordMode && this.finalConcat && this.isFirstPage && this.loadingStatus === Enum.More.NoMore) {
newVal.reverse();
}
// #endif
this.totalData = newVal;
} else {
if (this.finalConcat) {
const currentScrollTop = this.oldScrollTop;
this.totalData = [...this.totalData, ...newVal];
// 此处是为了解决在微信小程序中,在某些情况下滚动到底部加载更多后滚动位置直接变为最底部的问题,因此需要通过代码强制滚动回加载更多前的位置
// #ifdef MP-WEIXIN
if (!this.isIos && !this.refresherOnly && !this.usePageScroll && newVal.length) {
this.loadingMoreTimeStamp = u.getTime();
this.$nextTick(() => {
this.scrollToY(currentScrollTop);
})
}
// #endif
} else {
this.totalData = newVal;
}
}
this.privateConcat = true;
},
// 根据pageNo处理refresh操作
_handleRefreshWithDisPageNo(pageNo) {
if (!this.isHandlingRefreshToPage && !this.realTotalData.length) return this.reload();
if (pageNo >= 1) {
this.loading = true;
this.privateConcat = false;
const totalPageSize = pageNo * this.pageSize;
this.currentRefreshPageSize = totalPageSize;
// 如果调用refresh时是本地分页则在组件内部自己处理分页逻辑不emit query相关事件
if (this.isLocalPaging && this.isHandlingRefreshToPage) {
this._localPagingQueryList(this.defaultPageNo, totalPageSize, 0, res => {
this.complete(res);
})
} else {
// emit query相关事件
this._emitQuery(this.defaultPageNo, totalPageSize, Enum.QueryFrom.Refresh);
this._callMyParentQuery(this.defaultPageNo, totalPageSize);
}
}
return new Promise((resolve, reject) => {
this.dataPromiseResultMap.reload = { resolve, reject };
});
},
// 本地分页请求
_localPagingQueryList(pageNo, pageSize, localPagingLoadingTime, callback) {
pageNo = Math.max(1, pageNo);
pageSize = Math.max(1, pageSize);
const totalPagingList = [...this.totalLocalPagingList];
const pageNoIndex = (pageNo - 1) * pageSize;
const finalPageNoIndex = Math.min(totalPagingList.length, pageNoIndex + pageSize);
const resultPagingList = totalPagingList.splice(pageNoIndex, finalPageNoIndex - pageNoIndex);
u.delay(() => callback(resultPagingList), localPagingLoadingTime)
},
// 存储列表缓存数据
_saveLocalCache(data) {
uni.setStorageSync(this.finalCacheKey, data);
},
// 通过缓存数据填充列表数据
_setListByLocalCache() {
this.totalData = uni.getStorageSync(this.finalCacheKey) || [];
this.isSettingCacheList = true;
},
// 修改父view的list
_callMyParentList(newVal) {
if (this.autowireListName.length) {
const myParent = u.getParent(this.$parent);
if (myParent && myParent[this.autowireListName]) {
myParent[this.autowireListName] = newVal;
}
}
},
// 调用父view的query
_callMyParentQuery(customPageNo = 0, customPageSize = 0) {
if (this.autowireQueryName) {
if (this.myParentQuery === -1) {
const myParent = u.getParent(this.$parent);
if (myParent && myParent[this.autowireQueryName]) {
this.myParentQuery = myParent[this.autowireQueryName];
}
}
if (this.myParentQuery !== -1) {
customPageSize > 0 ? this.myParentQuery(customPageNo, customPageSize) : this.myParentQuery(this.pageNo, this.defaultPageSize);
}
}
},
// emit query事件
_emitQuery(pageNo, pageSize, from){
this.queryFrom = from;
this.requestTimeStamp = u.getTime();
const [lastItem] = this.realTotalData.slice(-1);
if (this.fetch) {
const fetchParams = interceptor._handleFetchParams({pageNo, pageSize, from, lastItem: lastItem || null}, this.fetchParams);
const fetchResult = this.fetch(fetchParams);
if (!interceptor._handleFetchResult(fetchResult, this, fetchParams)) {
u.isPromise(fetchResult) ? fetchResult.then(res => {
this.complete(res);
}).catch(err => {
this.complete(false);
}) : this.complete(fetchResult)
}
} else {
this.$emit('query', ...interceptor._handleQuery(pageNo, pageSize, from, lastItem || null));
}
},
// 触发数据改变promise
_callDataPromise(success, totalList) {
for (const key in this.dataPromiseResultMap) {
const obj = this.dataPromiseResultMap[key];
if (!obj) continue;
success ? obj.resolve({ totalList, noMore: this.loadingStatus === Enum.More.NoMore }) : this.callNetworkReject && obj.reject(`z-paging-${key}-error`);
}
},
// 检查complete data的类型
_checkDataType(data, success, isLocal) {
const dataType = Object.prototype.toString.call(data);
if (dataType === '[object Boolean]') {
success = data;
data = [];
} else if (dataType !== '[object Array]') {
data = [];
if (dataType !== '[object Undefined]' && dataType !== '[object Null]') {
u.consoleErr(`${isLocal ? 'setLocalPaging' : 'complete'}参数类型不正确第一个参数类型必须为Array!`);
}
}
return { data, success };
},
}
}

View File

@ -0,0 +1,144 @@
// [z-paging]空数据图view模块
import u from '.././z-paging-utils'
export default {
props: {
// 是否强制隐藏空数据图,默认为否
hideEmptyView: {
type: Boolean,
default: u.gc('hideEmptyView', false)
},
// 空数据图描述文字,默认为“没有数据哦~”
emptyViewText: {
type: [String, Object],
default: u.gc('emptyViewText', null)
},
// 是否显示空数据图重新加载按钮(无数据时),默认为否
showEmptyViewReload: {
type: Boolean,
default: u.gc('showEmptyViewReload', false)
},
// 加载失败时是否显示空数据图重新加载按钮,默认为是
showEmptyViewReloadWhenError: {
type: Boolean,
default: u.gc('showEmptyViewReloadWhenError', true)
},
// 空数据图点击重新加载文字,默认为“重新加载”
emptyViewReloadText: {
type: [String, Object],
default: u.gc('emptyViewReloadText', null)
},
// 空数据图图片默认使用z-paging内置的图片
emptyViewImg: {
type: String,
default: u.gc('emptyViewImg', '')
},
// 空数据图“加载失败”描述文字,默认为“很抱歉,加载失败”
emptyViewErrorText: {
type: [String, Object],
default: u.gc('emptyViewErrorText', null)
},
// 空数据图“加载失败”图片默认使用z-paging内置的图片
emptyViewErrorImg: {
type: String,
default: u.gc('emptyViewErrorImg', '')
},
// 空数据图样式
emptyViewStyle: {
type: Object,
default: u.gc('emptyViewStyle', {})
},
// 空数据图容器样式
emptyViewSuperStyle: {
type: Object,
default: u.gc('emptyViewSuperStyle', {})
},
// 空数据图img样式
emptyViewImgStyle: {
type: Object,
default: u.gc('emptyViewImgStyle', {})
},
// 空数据图描述文字样式
emptyViewTitleStyle: {
type: Object,
default: u.gc('emptyViewTitleStyle', {})
},
// 空数据图重新加载按钮样式
emptyViewReloadStyle: {
type: Object,
default: u.gc('emptyViewReloadStyle', {})
},
// 空数据图片是否铺满z-paging默认为否即填充满z-paging内列表(滚动区域)部分。若设置为否则为填铺满整个z-paging
emptyViewFixed: {
type: Boolean,
default: u.gc('emptyViewFixed', false)
},
// 空数据图片是否垂直居中默认为是若设置为否即为从空数据容器顶部开始显示。emptyViewFixed为false时有效
emptyViewCenter: {
type: Boolean,
default: u.gc('emptyViewCenter', true)
},
// 加载中时是否自动隐藏空数据图,默认为是
autoHideEmptyViewWhenLoading: {
type: Boolean,
default: u.gc('autoHideEmptyViewWhenLoading', true)
},
// 用户下拉列表触发下拉刷新加载中时是否自动隐藏空数据图,默认为是
autoHideEmptyViewWhenPull: {
type: Boolean,
default: u.gc('autoHideEmptyViewWhenPull', true)
},
// 空数据view的z-index默认为9
emptyViewZIndex: {
type: Number,
default: u.gc('emptyViewZIndex', 9)
},
},
data() {
return {
customerEmptyViewErrorText: ''
}
},
computed: {
finalEmptyViewImg() {
return this.isLoadFailed ? this.emptyViewErrorImg : this.emptyViewImg;
},
finalShowEmptyViewReload() {
return this.isLoadFailed ? this.showEmptyViewReloadWhenError : this.showEmptyViewReload;
},
// 是否展示空数据图
showEmpty() {
if (this.refresherOnly || this.hideEmptyView || this.realTotalData.length) return false;
if (this.autoHideEmptyViewWhenLoading) {
if (this.isAddedData && !this.firstPageLoaded && !this.loading) return true;
} else {
return true;
}
return !this.autoHideEmptyViewWhenPull && !this.isUserReload;
},
},
methods: {
// 点击了空数据view重新加载按钮
_emptyViewReload() {
let callbacked = false;
this.$emit('emptyViewReload', reload => {
if (reload === undefined || reload === true) {
this.fromEmptyViewReload = true;
this.reload().catch(() => {});
}
callbacked = true;
});
// 如果用户没有禁止默认的点击重新加载刷新列表事件,则触发列表重新刷新
this.$nextTick(() => {
if (!callbacked) {
this.fromEmptyViewReload = true;
this.reload().catch(() => {});
}
})
},
// 点击了空数据view
_emptyViewClick() {
this.$emit('emptyViewClick');
},
}
}

Some files were not shown because too many files have changed in this diff Show More