Browse Source

测试

pull/1/head
张立 10 months ago
parent
commit
ac0f8cb931
  1. 14
      src/api/http.ts
  2. 2
      src/api/request2.js
  3. 8
      src/common/calc.js
  4. 1
      src/common/style/new_style.css
  5. 1
      src/components/my-paging/my-paging.vue
  6. 2
      src/mycomponents/balance/pack.vue
  7. 11
      src/mycomponents/detail/comDetailCard.vue
  8. 2
      src/mycomponents/item/itemCompareQty.vue
  9. 2
      src/mycomponents/item/itemQty.vue
  10. 2
      src/mycomponents/job/jobComMainDetailCard.vue
  11. 356
      src/mycomponents/package/packageList.vue
  12. 217
      src/mycomponents/package/packageRecordCard.vue
  13. 20
      src/mycomponents/qty/balanceQtyEdit.vue
  14. 2
      src/mycomponents/record/recordComDetailCard.vue
  15. 26
      src/mycomponents/scan/winScanItem.vue
  16. 2
      src/mycomponents/scan/winScanLocation.vue
  17. 6
      src/mycomponents/status/balanceStatus.vue
  18. 10
      src/pages.json
  19. 2
      src/pages/customerReturn/request/customerReturnRequest.vue
  20. 2
      src/pages/customerReturn/request/customerReturnRequestCreate.vue
  21. 2
      src/pages/deliver/coms/comDeliverRequestPopup.vue
  22. 122
      src/pages/deliver/record/deliverRecord.vue
  23. 2
      src/pages/deliver/request/deliverRequest.vue
  24. 28
      src/pages/deliver/request/deliverRequestCreate.vue
  25. 2
      src/pages/index/index.vue
  26. 3
      src/pages/issue/coms/comIssueRequestPopup.vue
  27. 2
      src/pages/issue/coms/comScanIssuePack.vue
  28. 9
      src/pages/issue/job/issueDetail.vue
  29. 5
      src/pages/issue/record/directIssue.vue
  30. 9
      src/pages/issue/request/issueRequestCreate.vue
  31. 7
      src/pages/package/job/overPackageJobDetail.vue
  32. 1
      src/pages/pointProductReceipt/webview.vue
  33. 2
      src/pages/productPutaway/request/putawayRequest.vue
  34. 4
      src/pages/productReceipt/coms/comFgCard.vue
  35. 2
      src/pages/productReceipt/coms/comProductDetailCard.vue
  36. 23
      src/pages/productReceipt/job/fgProductReceiptDetail.vue
  37. 2
      src/pages/productReceipt/job/productReceiptJob.vue
  38. 3
      src/pages/productReceipt/record/productReceiptRecord.vue
  39. 2
      src/pages/productionReturn/coms/comReturnCommonRequest.vue
  40. 4
      src/pages/productionReturn/coms/comReturnRequestCreator.vue
  41. 37
      src/pages/productionReturn/record/returnToHold.vue
  42. 80
      src/pages/productionReturn/record/returnToStore.vue
  43. 1
      src/pages/productionReturn/request/requestDetail.vue
  44. 11
      src/pages/productionReturn/request/returnRequestCreate.vue
  45. 3
      src/pages/purchaseReceipt/coms/comReceiptDetailCard.vue
  46. 13
      src/pages/purchaseReceipt/job/receiptDetail.vue
  47. 2
      src/pages/purchaseReturn/job/returnDetail.vue
  48. 15
      src/pages/purchaseReturn/request/returnRequest.vue
  49. 1
      src/pages/purchaseReturn/request/returnRequestCreate.vue
  50. 17
      src/pages/putaway/record/putawayRecord.vue
  51. 2
      src/pages/putaway/request/putawayRequest.vue
  52. 2
      src/pages/query/coms/comItemDetailCard.vue
  53. 2
      src/pages/query/item.vue
  54. 117
      src/pages/repleinsh/coms/comScanReplishPack.vue
  55. 14
      src/pages/repleinsh/job/repleinshDetail.vue
  56. 229
      src/pages/repleinsh/record/directRepleinshRecord.vue
  57. 7
      src/pages/repleinsh/record/repleinshRecord.vue
  58. 2
      src/pages/scrap/request/scrapRrequest.vue
  59. 2
      src/pages/unPlanned/request/issueRequest.vue
  60. 2
      src/pages/unPlanned/request/receiptRequest.vue
  61. 6
      src/uni_modules/z-paging/changelog.md
  62. 34
      src/uni_modules/z-paging/components/z-paging-cell/z-paging-cell.vue
  63. 162
      src/uni_modules/z-paging/components/z-paging-empty-view/z-paging-empty-view.vue
  64. 143
      src/uni_modules/z-paging/components/z-paging-swiper-item/z-paging-swiper-item.vue
  65. 170
      src/uni_modules/z-paging/components/z-paging-swiper/z-paging-swiper.vue
  66. 141
      src/uni_modules/z-paging/components/z-paging/components/z-paging-load-more.vue
  67. 182
      src/uni_modules/z-paging/components/z-paging/components/z-paging-refresh.vue
  68. 3
      src/uni_modules/z-paging/components/z-paging/config/index.js
  69. 228
      src/uni_modules/z-paging/components/z-paging/css/z-paging-main.css
  70. 35
      src/uni_modules/z-paging/components/z-paging/css/z-paging-static.css
  71. 22
      src/uni_modules/z-paging/components/z-paging/i18n/en.json
  72. 8
      src/uni_modules/z-paging/components/z-paging/i18n/index.js
  73. 22
      src/uni_modules/z-paging/components/z-paging/i18n/zh-Hans.json
  74. 22
      src/uni_modules/z-paging/components/z-paging/i18n/zh-Hant.json
  75. 25
      src/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js
  76. 26
      src/uni_modules/z-paging/components/z-paging/js/hooks/useZPagingComp.js
  77. 100
      src/uni_modules/z-paging/components/z-paging/js/modules/back-to-top.js
  78. 116
      src/uni_modules/z-paging/components/z-paging/js/modules/common-layout.js
  79. 741
      src/uni_modules/z-paging/components/z-paging/js/modules/data-handle.js
  80. 147
      src/uni_modules/z-paging/components/z-paging/js/modules/empty.js
  81. 101
      src/uni_modules/z-paging/components/z-paging/js/modules/i18n.js
  82. 315
      src/uni_modules/z-paging/components/z-paging/js/modules/load-more.js
  83. 93
      src/uni_modules/z-paging/components/z-paging/js/modules/loading.js
  84. 249
      src/uni_modules/z-paging/components/z-paging/js/modules/nvue.js
  85. 677
      src/uni_modules/z-paging/components/z-paging/js/modules/refresher.js
  86. 464
      src/uni_modules/z-paging/components/z-paging/js/modules/scroller.js
  87. 461
      src/uni_modules/z-paging/components/z-paging/js/modules/virtual-list.js
  88. 21
      src/uni_modules/z-paging/components/z-paging/js/z-paging-config.js
  89. 12
      src/uni_modules/z-paging/components/z-paging/js/z-paging-constant.js
  90. 44
      src/uni_modules/z-paging/components/z-paging/js/z-paging-enum.js
  91. 48
      src/uni_modules/z-paging/components/z-paging/js/z-paging-interceptor.js
  92. 446
      src/uni_modules/z-paging/components/z-paging/js/z-paging-main.js
  93. 22
      src/uni_modules/z-paging/components/z-paging/js/z-paging-mixin.js
  94. 13
      src/uni_modules/z-paging/components/z-paging/js/z-paging-static.js
  95. 228
      src/uni_modules/z-paging/components/z-paging/js/z-paging-utils.js
  96. 58
      src/uni_modules/z-paging/components/z-paging/wxs/z-paging-renderjs.js
  97. 340
      src/uni_modules/z-paging/components/z-paging/wxs/z-paging-wxs.wxs
  98. 307
      src/uni_modules/z-paging/components/z-paging/z-paging.vue
  99. 86
      src/uni_modules/z-paging/package.json
  100. 53
      src/uni_modules/z-paging/readme.md

14
src/api/http.ts

@ -89,7 +89,19 @@ instance.interceptors.response.use((v) => {
confirmText: '重新登录',
success: function (res) {
if (res.confirm) {
uni.reLaunch({ url: '/pages/login' })
uni.reLaunch({ url: '/pages/login/index' })
}
}
})
} else if(v.data.code == 401){
uni.showModal({
title: '系统提示',
content: '账号未登录,请重新登录',
cancelText: '关闭',
confirmText: '重新登录',
success: function (res) {
if (res.confirm) {
uni.reLaunch({ url: '/pages/login/index' })
}
}
})

2
src/api/request2.js

@ -2108,7 +2108,7 @@ export function productionReturnRequestAddAgain(id) {
export function productionReturnRequestCreate(params) {
return http.put("/wms/productionreturn-request-main/create",params)
return http.post("/wms/productionreturn-request-main/create",params)
}
/**
* 生产退料记录 提交

8
src/common/calc.js

@ -2,15 +2,23 @@
import Decimal from 'decimal.js'
class Calc {
add(num1,num2) {
num1 = num1 || 0
num2 = num2 || 0
return new Decimal(num1).add(new Decimal(num2)).toNumber()
}
sub(num1,num2) {
num1 = num1 || 0
num2 = num2 || 0
return new Decimal(num1).sub(new Decimal(num2)).toNumber()
}
mul(num1,num2) {
num1 = num1 || 0
num2 = num2 || 0
return new Decimal(num1).mul(new Decimal(num2)).toNumber()
}
div(num1,num2) {
num1 = num1 || 0
num2 = num2 || 0
return new Decimal(num1).div(new Decimal(num2)).toNumber()
}
}

1
src/common/style/new_style.css

@ -218,7 +218,6 @@ uni-page-head .uni-page-head__title {
.cen_card {
padding: 0 0rpx;
width: 100%;
box-sizing: border-box;
background:#EEF4FA;
padding:20rpx;

1
src/components/my-paging/my-paging.vue

@ -131,6 +131,7 @@ const reload = (data) => {
}
// completez-paging
const complete = (data) => {
console.log(data)
paging.value.complete(data)
}
/*

2
src/mycomponents/balance/pack.vue

@ -1,6 +1,6 @@
<template>
<view class="card_view">
<text class="card_packing_code card_content">{{ title }}</text>
<text class="card_packing_code">{{ title }}</text>
<text class="card_content">{{ packingCode }}</text>
</view>
</template>

11
src/mycomponents/detail/comDetailCard.vue

@ -10,7 +10,7 @@
</u-swipe-action>
</u-collapse-item>
</u-collapse>
<balance-qty-edit ref="qtyEdit" :settingParam="settingParam" @confirm="confirm"></balance-qty-edit>
<balance-qty-edit ref="qtyEdit" :settingParam="settingParam" :queryBalance="queryBalance" @confirm="confirm"></balance-qty-edit>
<win-scan-location ref="scanLocationCode" title="目标库位" @getLocation="getLocation" :locationAreaTypeList="locationAreaTypeList"></win-scan-location>
<com-message ref="comMessageRef" />
</view>
@ -48,6 +48,10 @@ const props = defineProps({
locationAreaTypeList: {
type: Array,
default: null
},
queryBalance: {
type: Boolean,
default: true
}
})
const option = ref([])
@ -59,6 +63,7 @@ const scanOptions = ref([])
const comMessageRef = ref()
const collapse = ref()
const qtyEdit = ref()
const scanLocationCode = ref()
const dataContent = ref(props.dataContent)
dataContent.value.subList.forEach((item) => {
item.show = false
@ -110,7 +115,7 @@ const swipeClick = (params, item) => {
}
const edit = (item) => {
editItem.value = item
qtyEdit.value.openEditPopup(item.balance, item.handleQty)
qtyEdit.value.openEditPopup(item, item.handleQty)
}
const detail = (item) => {
emit('openDetail', item)
@ -129,7 +134,7 @@ const confirm = (qty) => {
editItem.value.handleQty = qty
emit('updateData')
}
const showLocation = () => {
const showLocation = (item) => {
locatonItem.value = item
scanLocationCode.value.openScanPopup()
}

2
src/mycomponents/item/itemCompareQty.vue

@ -3,7 +3,7 @@
<view style="flex: 1">
<item :dataContent="dataContent"></item>
</view>
<view style="word-break: break-all; display: flex; justify-content: flex-end; margin-right: 10rpx">
<view style="width: 30%; display: flex; justify-content: flex-end; margin-right: 10rpx">
<recommend-qty v-if="handleQty == 0" :dataContent="dataContent" :isShowStatus="false" :isShowStdPack="true" :objTextStyle="objTextStyle"></recommend-qty>
<compare-qty v-else :dataContent="dataContent" :recommendQty="Number(dataContent.qty)" :handleQty="Number(handleQty)" :isShowStatus="false" :isShowPackUnit="isShowPackUnit"> </compare-qty>
</view>

2
src/mycomponents/item/itemQty.vue

@ -1,5 +1,5 @@
<template>
<view class="uni-flex uni-row space-between center" style="width: 100%">
<view class="uni-flex uni-row space-between center u-p-t-20 u-p-b-20" style="width: 100%; border-bottom: 1px solid rgba(230, 230, 2300.5)">
<view style="flex: 1">
<item :dataContent="dataContent"></item>
</view>

2
src/mycomponents/job/jobComMainDetailCard.vue

@ -6,7 +6,7 @@
<pack v-if="isShowPack && dataContent.packingNumber != null" :packingCode="dataContent.packingNumber"> </pack>
<batch v-if="isShowBatch && dataContent.batch != null" :batch="dataContent.batch"></batch>
<div class="u-flex justify-between u-p-b-16">
<location v-if="isShowFromLocation" title="来源库位" :locationCode="dataContent.fromLocationCode"> </location>
<location v-if="isShowFromLocation && dataContent.fromLocationCode" title="来源库位" :locationCode="dataContent.fromLocationCode"> </location>
<to-location v-if="isShowToLocation" title="目标库位" :locationCode="dataContent.toLocationCode"> </to-location>
</div>
<view class="card_view" v-if="isShowDeliverType">

356
src/mycomponents/package/packageList.vue

@ -1,196 +1,176 @@
<template>
<view class="">
<view class="" v-for="(item,index) in dataContent" :key="item.id">
<u-collapse ref="collapse2" >
<u-collapse-item :disabled="false" @change="collapseChange">
<template v-slot:title>
<package-card :dataContent="item" :isShowLocation="false"
:isShowFromLocation="isShowFromLocation" style='flex:1'></package-card>
</template>
<u-swipe-action :show="item.show" :index="index" v-for="(cur,key) in item.packList"
:key="index" :options="(cur.scaned&&isEdit)?editAndRemoveOptions : cur.scaned? removeOptions:options"
bg-color='rgba(255,255,255,0)'
@click="(...event)=>swipeClick($event,cur)"
>
<package-card :dataContent="cur" :isShowLocation="false" :isShowFromLocation="false"
:isShowToLocation="false" :isShowBatch="false"></package-card>
</u-swipe-action>
</u-collapse-item>
</u-collapse>
</view>
<recommend-qty-edit ref="receiptEdit" :dataContent="editItem" :settingParam="settingParam" @confirm="confirm">
</recommend-qty-edit>
<com-message ref="comMessageRef" />
</view>
<view class="">
<view class="" v-for="(item, index) in dataContent" :key="item.id">
<u-collapse ref="collapse2">
<u-collapse-item :disabled="false" @change="collapseChange">
<template v-slot:title>
<package-card :dataContent="item" :isShowLocation="false" :isShowFromLocation="isShowFromLocation" style="flex: 1"></package-card>
</template>
<u-swipe-action :show="item.show" :index="index" v-for="(cur, key) in item.packList" :key="index" :options="cur.scaned && isEdit ? editAndRemoveOptions : cur.scaned ? removeOptions : options" bg-color="rgba(255,255,255,0)" @click="(...event) => swipeClick(event, cur)">
<package-card :dataContent="cur" :isShowLocation="false" :isShowFromLocation="false" :isShowToLocation="false" :isShowBatch="false"></package-card>
</u-swipe-action>
</u-collapse-item>
</u-collapse>
</view>
<recommend-qty-edit ref="receiptEdit" :dataContent="editItem" :settingParam="settingParam" @confirm="confirm"> </recommend-qty-edit>
<com-message ref="comMessageRef" />
</view>
</template>
<script setup lang="ts">
import {
ref,
getCurrentInstance,
onMounted,
nextTick
} from 'vue'
import config from '@/static/config.js'
import packageCard from '@/mycomponents/package/packageCard.vue'
import recommendQtyEdit from '@/mycomponents/qty/recommendQtyEdit.vue'
import { ref, getCurrentInstance, onMounted, nextTick } from 'vue'
import config from '@/static/config.js'
import packageCard from '@/mycomponents/package/packageCard.vue'
import recommendQtyEdit from '@/mycomponents/qty/recommendQtyEdit.vue'
import { getRemoveOption, getEditRemoveOption } from '@/common/array.js'
const editItem = ref({})
const options = ref([])
const removeOptions = ref([])
const editAndRemoveOptions = ref([])
const comMessageRef = ref()
const collapse2 = ref()
onMounted(() => {
removeOptions.value = getRemoveOption()
editAndRemoveOptions.value = getEditRemoveOption()
})
const props = defineProps({
dataContent: {
type: Object,
default: null
},
isShowContainer: {
type: Boolean,
default: true
},
isShowPack: {
type: Boolean,
default: true
},
isShowBatch: {
type: Boolean,
default: true
},
isShowFromLocation: {
type: Boolean,
default: true
},
isShowToLocation: {
type: Boolean,
default: false
},
isShowStatus: {
type: Boolean,
default: true
},
locationTitle: {
type: String,
default: '库位'
},
settingParam: {
type: Object,
default: null
},
isEdit: {
type: Boolean,
default: false
}
})
const dataContent = ref(props.dataContent)
dataContent.value.forEach((item) => {
item.packList.forEach((cur) => {
cur.show = false
})
})
console.log(dataContent.value)
const swipeClick = (params, cur) => {
console.log(params)
console.log(cur)
let text = ''
if (cur.scaned && props.isEdit) {
text = editAndRemoveOptions.value[params[1]].text
// (cur.scaned&&isEdit)?editAndRemoveOptions : cur.scaned? removeOptions:options
} else if (cur.scaned) {
text = removeOptions.value[params[1]].text
} else {
text = options.value[params[1]].text
}
if (text == '编辑') {
edit(cur)
} else if (text == '移除') {
remove(cur)
}
}
const remove = (item) => {
comMessageRef.value.showQuestionMessage('确定移除扫描信息?', (res) => {
if (res) {
item.scaned = false
item.handleQty = null
emit('updateData')
}
})
}
const edit = (item) => {
editItem.value = item
receiptEdit.value.openTaskEditPopup(item.qty, item.handleQty, item.labelQty)
}
const collapseChange = () => {
resizeCollapse()
emit('collapseChange')
}
const resizeCollapse = () => {
nextTick(() => {
collapse2.value.forEach((r) => {
r.childrens.forEach((i) => {
i.init()
})
r.init()
})
})
}
const copy = () => {
// HPQ;V1.0;ICE115F11161AG;PP20230427000026;B20230427002;Q100
const content = `HPQ;V1.0;I${props.dataContent.itemCode};P${props.dataContent.packingNumber};B${props.dataContent.batch};Q${props.dataContent.qty}`
uni.setClipboardData({
data: content,
success: () => {
uni.showToast({
title: '复制采购标签成功'
})
}
})
}
const copyPro = () => {
// HPQ;V1.0;ICE115F11161AG;PP20230427000026;B20230427002;Q100
const content = `HMQ;V1.0;I${props.dataContent.itemCode};P${props.dataContent.packingNumber};B${props.dataContent.batch};Q${props.dataContent.qty}`
import {
getRemoveOption,
getEditRemoveOption
} from '@/common/array.js';
const editItem = ref({})
const options = ref([])
const removeOptions = ref([])
const editAndRemoveOptions = ref([])
const comMessageRef = ref()
const collapse2 = ref()
onMounted(() => {
removeOptions.value = getRemoveOption();
editAndRemoveOptions.value = getEditRemoveOption()
});
const props = defineProps({
dataContent: {
type: Object,
default: null
},
isShowContainer: {
type: Boolean,
default: true
},
isShowPack: {
type: Boolean,
default: true
},
isShowBatch: {
type: Boolean,
default: true
},
isShowFromLocation: {
type: Boolean,
default: true
},
isShowToLocation: {
type: Boolean,
default: false
},
isShowStatus: {
type: Boolean,
default: true
},
locationTitle: {
type: String,
default: '库位'
},
settingParam: {
type: Object,
default: null
},
isEdit: {
type: Boolean,
default: false
}
})
const dataContent = ref(props.dataContent)
dataContent.value.forEach(item=>{
item.packList.forEach(cur=>{
cur.show = false
})
})
console.log(dataContent.value)
const swipeClick=(params,cur)=> {
let text = ''
if(cur.scaned&&props.isEdit){
text = editAndRemoveOptions[params[1]].text
// (cur.scaned&&isEdit)?editAndRemoveOptions : cur.scaned? removeOptions:options
}else{
if(cur.scaned){
text = removeOptions[params[1]].text
}else{
text = options[params[1]].text
}
}
if (text == "编辑") {
edit(cur)
} else if (text == "移除") {
remove(cur)
}
}
const remove=(item)=> {
comMessageRef.value.showQuestionMessage("确定移除扫描信息?", res => {
if (res) {
item.scaned = false
item.handleQty = null;
emit('updateData')
}
});
}
const edit=(item)=> {
editItem.value = item;
receiptEdit.value.openTaskEditPopup(item.qty, item.handleQty, item.labelQty);
}
const collapseChange=()=> {
resizeCollapse();
emit("collapseChange");
}
const resizeCollapse=()=> {
nextTick(()=>{
collapse2.value.forEach(r => {
r.childrens.forEach(i => {
i.init();
})
r.init();
})
});
}
const copy = () => {
// HPQ;V1.0;ICE115F11161AG;PP20230427000026;B20230427002;Q100
var content = "HPQ;V1.0;I" + props.dataContent.itemCode + ";P" + props.dataContent.packingNumber + ";B" + props.dataContent
.batch + ";Q" + props.dataContent.qty
uni.setClipboardData({
data: content,
success: () => {
uni.showToast({
title: '复制采购标签成功'
})
}
})
}
const copyPro = () =>{
// HPQ;V1.0;ICE115F11161AG;PP20230427000026;B20230427002;Q100
var content = "HMQ;V1.0;I" + props.dataContent.itemCode + ";P" + props.dataContent.packingNumber + ";B" + props.dataContent
.batch + ";Q" + props.dataContent.qty
uni.setClipboardData({
data: content,
success: () => {
uni.showToast({
title: '复制制品标签成功'
})
}
})
}
const isDevlement=()=> {
return config.isDevelopment;
}
const confirm=(qty)=> {
editItem.value.handleQty = qty;
emit("updateData")
}
//
const emit = defineEmits(['collapseChange', 'updateData'])
uni.setClipboardData({
data: content,
success: () => {
uni.showToast({
title: '复制制品标签成功'
})
}
})
}
const isDevlement = () => {
return config.isDevelopment
}
const confirm = (qty) => {
editItem.value.handleQty = qty
emit('updateData')
}
//
const emit = defineEmits(['collapseChange', 'updateData'])
</script>
<style>
.open {
/* background-color: green !important; */
padding-top: 0px !important;
}
</style>
.open {
/* background-color: green !important; */
padding-top: 0px !important;
}
</style>

217
src/mycomponents/package/packageRecordCard.vue

@ -1,123 +1,118 @@
<template>
<view :class="dataContent.scaned?'scan_view':''" style="background-color: #fff; ">
<!-- border-bottom: 1upx solid #EEEEEE; -->
<view class="uni-flex uni-row space-between" style="align-items: center">
<!-- uni-inline-item 暂时拿掉-->
<view style="word-break: break-all;">
<!-- <container v-if="isShowContainer&&dataContent.containerNumber!=null" :container="dataContent.containerNumber">
<view :class="dataContent.scaned ? 'scan_view' : ''" style="background-color: #fff">
<!-- border-bottom: 1upx solid #EEEEEE; -->
<view class="uni-flex uni-row space-between" style="align-items: center">
<!-- uni-inline-item 暂时拿掉-->
<view style="word-break: break-all">
<!-- <container v-if="isShowContainer&&dataContent.containerNumber!=null" :container="dataContent.containerNumber">
</container> -->
<pack v-if="isShowPack && dataContent.packingNumber!=null" :packingCode="dataContent.packingNumber">
</pack>
<batch v-if="isShowBatch && dataContent.batch!=null" :batch="dataContent.batch"></batch>
<location v-if="isShowFromLocation" title="来源库位" :locationCode="dataContent.fromLocationCode">
</location>
<!-- <to-location></to-location> -->
<to-location v-if="isShowToLocation" title="目标库位" :locationCode="dataContent.toLocationCode">
</to-location>
</view>
<view class="uni-flex uni-row" style="word-break: break-all;">
<qty v-if="true" :dataContent="dataContent" :isShowStdPack="isShowStdPack" :isShowStatus="isShowStatus">
</qty>
<compare-qty v-else :dataContent="dataContent" :recommendQty="Number(dataContent.qty)"
:handleQty="dataContent.handleQty" :isShowStatus="false" :isShowPack="isShowPack">
</compare-qty>
<pack v-if="isShowPack && dataContent.packingNumber != null" :packingCode="dataContent.packingNumber"> </pack>
<batch v-if="isShowBatch && dataContent.batch != null" :batch="dataContent.batch"></batch>
<location v-if="isShowFromLocation" title="来源库位" :locationCode="dataContent.fromLocationCode"> </location>
<!-- <to-location></to-location> -->
<to-location v-if="isShowToLocation" title="目标库位" :locationCode="dataContent.toLocationCode"> </to-location>
</view>
<view class="uni-flex uni-row" style="word-break: break-all">
<qty v-if="true" :dataContent="dataContent" :isShowStdPack="isShowStdPack" :isShowStatus="isShowStatus"> </qty>
<compare-qty v-else :dataContent="dataContent" :recommendQty="Number(dataContent.qty)" :handleQty="dataContent.handleQty" :isShowStatus="false" :isShowPack="isShowPack"> </compare-qty>
<view class="uni-flex uni-row center" style="vertical-align:center ;" v-if="isDevlement()">
<!-- <text style="font-size: 25rpx;color: #2979ff; width: 45rpx; " @click="copy">复制</text> -->
<image style='width: 26rpx;height: 26rpx;' src="/static/icons/icon_copy.svg" alt="" @click.stop="copy" />
</view>
</view>
</view>
</view>
<view class="uni-flex uni-row center" style="vertical-align: center" v-if="isDevlement()">
<!-- <text style="font-size: 25rpx;color: #2979ff; width: 45rpx; " @click="copy">复制</text> -->
<image style="width: 26rpx; height: 26rpx" src="/static/icons/icon_copy.svg" alt="" @click.stop="copy" />
</view>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import qty from '@/mycomponents/qty/qty.vue'
import container from '@/mycomponents/container/container.vue'
import pack from '@/mycomponents/balance/pack.vue'
import location from '@/mycomponents/balance/location.vue'
import toLocation from '@/mycomponents/balance/toLocation.vue'
import batch from '@/mycomponents/balance/batch.vue'
import recommendQty from '@/mycomponents/qty/recommendQty.vue'
import compareQty from '@/mycomponents/qty/compareQty.vue'
import config from '@/static/config.js'
import balanceQty from '@/mycomponents/qty/balanceQty.vue'
const props = defineProps({
dataContent: {
type: Object,
default: {}
},
isShowContainer: {
type: Boolean,
default: true
},
isShowPack: {
type: Boolean,
default: true
},
isShowBatch: {
type: Boolean,
default: true
},
isShowFromLocation: {
type: Boolean,
default: true
},
isShowToLocation: {
type: Boolean,
default: false
},
isShowStatus: {
type: Boolean,
default: true
},
import qty from '@/mycomponents/qty/qty.vue'
import container from '@/mycomponents/container/container.vue'
import pack from '@/mycomponents/balance/pack.vue'
import location from '@/mycomponents/balance/location.vue'
import toLocation from '@/mycomponents/balance/toLocation.vue'
import batch from '@/mycomponents/balance/batch.vue'
import recommendQty from '@/mycomponents/qty/recommendQty.vue'
import compareQty from '@/mycomponents/qty/compareQty.vue'
import config from '@/static/config.js'
import balanceQty from '@/mycomponents/qty/balanceQty.vue'
locationTitle: {
type: String,
default: '库位'
},
isShowBalanceQty: {
type: Boolean,
default: true
},
showPack: {
type: Boolean,
default: false
}
})
const copy = () => {
// HPQ;V1.0;ICE115F11161AG;PP20230427000026;B20230427002;Q100
var content = "HPQ;V1.0;I" + props.dataContent.itemCode + ";P" + props.dataContent.packingNumber + ";B" + props.dataContent
.batch + ";Q" + props.dataContent.qty
const props = defineProps({
dataContent: {
type: Object,
default: {}
},
isShowStdPack: {
type: Boolean,
default: true
},
isShowContainer: {
type: Boolean,
default: true
},
isShowPack: {
type: Boolean,
default: true
},
isShowBatch: {
type: Boolean,
default: true
},
isShowFromLocation: {
type: Boolean,
default: true
},
isShowToLocation: {
type: Boolean,
default: false
},
isShowStatus: {
type: Boolean,
default: true
},
uni.setClipboardData({
data: content,
success: () => {
uni.showToast({
title: '复制采购标签成功'
})
}
})
}
const copyPro = () => {
// HPQ;V1.0;ICE115F11161AG;PP20230427000026;B20230427002;Q100
var content = "HMQ;V1.0;I" + props.dataContent.itemCode + ";P" + props.dataContent.packingNumber + ";B" + props.dataContent
.batch + ";Q" + props.dataContent.qty
locationTitle: {
type: String,
default: '库位'
},
isShowBalanceQty: {
type: Boolean,
default: true
},
showPack: {
type: Boolean,
default: false
}
})
const copy = () => {
// HPQ;V1.0;ICE115F11161AG;PP20230427000026;B20230427002;Q100
const content = `HPQ;V1.0;I${props.dataContent.itemCode};P${props.dataContent.packingNumber};B${props.dataContent.batch};Q${props.dataContent.qty}`
uni.setClipboardData({
data: content,
success: () => {
uni.showToast({
title: '复制制品标签成功'
})
}
})
uni.setClipboardData({
data: content,
success: () => {
uni.showToast({
title: '复制采购标签成功'
})
}
})
}
const copyPro = () => {
// HPQ;V1.0;ICE115F11161AG;PP20230427000026;B20230427002;Q100
const content = `HMQ;V1.0;I${props.dataContent.itemCode};P${props.dataContent.packingNumber};B${props.dataContent.batch};Q${props.dataContent.qty}`
}
const isDevlement = () => {
return config.isDevelopment;
}
uni.setClipboardData({
data: content,
success: () => {
uni.showToast({
title: '复制制品标签成功'
})
}
})
}
const isDevlement = () => {
return config.isDevelopment
}
</script>
<style>
</style>
<style></style>

20
src/mycomponents/qty/balanceQtyEdit.vue

@ -16,7 +16,7 @@
<text>包装数量 : </text>
<view class="uni-flex uni-row u-col-center">
<u-number-box v-model="stdCount" @change="calcQty"></u-number-box>
<!-- <uom :uom="dataContent.uom"></uom> -->
<!-- <uomCom :uom="dataContent.uom"></uomCom> -->
</view>
</view>
<view class="split_line"></view>
@ -24,7 +24,7 @@
<text>标包量 : </text>
<view class="uni-flex u-col-center uni-row">
<text>{{ Number(dataContent.packQty) }}</text>
<uom :uom="dataContent.uom"></uom>
<uomCom :uom="dataContent.uom"></uomCom>
</view>
</view>
@ -33,25 +33,25 @@
<text>数量 : </text>
<view class="uni-flex uni-row uni-center" style="align-items: center">
<input class="qty_input" v-model="allQty" :focus="true" type="number" @confirm="confirm()" @input="checkNum" :maxlength="maxlength" />
<uom :uom="dataContent.uom"></uom>
<uomCom :uom="dataContent.uom"></uomCom>
</view>
</view>
<view class="split_line"></view>
<view class="uni-flex uni-row space-between padding title u-col-center">
<view class="uni-flex uni-row space-between padding title u-col-center" v-if="queryBalance">
<text>库存数量 : </text>
<view class="uni-flex uni-row uni-center" style="align-items: center">
<text class="text_recommend">{{ Number(dataContent.balanceQty) }}</text>
<uom :uom="dataContent.uom"></uom>
<uomCom :uom="dataContent.uom"></uomCom>
</view>
</view>
<view class="split_line"></view>
<view v-if="isShowStatus" class="uni-flex uni-row space-between title u-col-center" style="padding-left: 30rpx">
<view class="split_line" v-if="queryBalance"></view>
<view v-if="isShowStatus && queryBalance" class="uni-flex uni-row space-between title u-col-center" style="padding-left: 30rpx">
<text>库存状态 : </text>
<view class="uni-flex uni-row uni-center" style="align-items: center">
<balanceStatus ref="balanceStatus" :status="inventoryStatus" :allowEdit="allowEditStatus" @updateStatus="updateStatus"> </balanceStatus>
<balanceStatus ref="balanceStatusRef" :status="inventoryStatus" :allowEdit="allowEditStatus" @updateStatus="updateStatus"> </balanceStatus>
</view>
</view>
<view class="split_line"></view>
<view class="split_line" v-if="queryBalance"></view>
</view>
</view>
</view>
@ -67,7 +67,7 @@
<script setup lang="ts">
import { ref, getCurrentInstance, watch } from 'vue'
import uom from '@/mycomponents/qty/uom.vue'
import uomCom from '@/mycomponents/qty/uom.vue'
import balanceStatus from '@/mycomponents/status/balanceStatus.vue'
const props = defineProps({

2
src/mycomponents/record/recordComDetailCard.vue

@ -3,7 +3,7 @@
<u-collapse ref="collapse1">
<u-collapse-item :open="true">
<template v-slot:title>
<u-swipe-action :show="false" style="width: 90%" :options="removeOptions" bg-color="rgba(255,255,255,0)" class="u-m-b-20" @click="(...event) => removeItem(event, dataContent)">
<u-swipe-action :show="false" style="width: 90%" :options="removeOptions" bg-color="rgba(255,255,255,0)" @click="(...event) => removeItem(event, dataContent)">
<item-qty :dataContent="dataContent" :isShowBalance="true" :isShowBalanceQty="isShowBalanceQty"></item-qty>
</u-swipe-action>
</template>

26
src/mycomponents/scan/winScanItem.vue

@ -69,10 +69,10 @@ const scanClick = () => {
const cancelClick = () => {
scan.value.clearScanValue()
}
const getScanResult = (result) => {
const getScanResult = (resultParams) => {
proxy.$modal.loading('扫描中...')
const scanResult = result
const scanResult = resultParams
if (scanResult.label.barType == 'QRCode') {
code.value = scanResult.label.itemCode
} else if (scanResult.label.barType == 'BarCode') {
@ -87,17 +87,17 @@ const getScanResult = (result) => {
.then((res) => {
uni.hideLoading()
if (res.data != null && res.data.list.length > 0) {
const result = res.data.list[0]
const { status } = result
const { type } = result
const itemCode = result.code
const itemName = result.name
const { uom } = result
const std = result.uom
result.package = scanResult.package
const result1 = res.data.list[0]
const { status } = result1
const { type } = result1
const itemCode = result1.code
const itemName = result1.name
const { uom } = result1
const std = result1.uom
result1.package = scanResult.package
if (status == 'ENABLE') {
if (checkDirectoryItemExist(props.itemCodeTypeList, type)) {
result.value = result
result.value = result1
callBack()
} else {
const hint = getListItemTypeDesc(props.itemCodeTypeList)
@ -118,7 +118,6 @@ const getScanResult = (result) => {
const callBack = () => {
closeScanPopup()
scan.value.clear()
// this.$emit("getScanCode", this.code);
emit('getScanResult', code.value, result.value)
}
const change = (e) => {
@ -138,7 +137,8 @@ const losefocus = () => {
const emit = defineEmits(['getScanResult'])
defineExpose({
openScanPopup,
closeScanPopup
closeScanPopup,
getfocus
})
</script>

2
src/mycomponents/scan/winScanLocation.vue

@ -9,7 +9,7 @@
</view>
<view class="">
<view class="">
<win-com-scan ref="scan" @getResult="getScanResult" :placeholder="title" :clearResult="false" :boxFocus="true" :isShowHistory="isShowHistory" headerType=""> </win-com-scan>
<win-com-scan ref="scan" @getResult="getScanResult" :placeholder="title" :clearResult="true" :boxFocus="true" :isShowHistory="isShowHistory" headerType=""> </win-com-scan>
</view>
</view>
</view>

6
src/mycomponents/status/balanceStatus.vue

@ -1,7 +1,6 @@
<template>
<view class="uni-flex u-col-center" style="background-color: #fff">
<!-- <status :status='status' style='font-size: 70rpx;'></status> -->
<text :class="statusStyle(status)" style="font-size: 38rpx; margin-right: 15rpx"> {{ statusDesc(status) }}</text>
<view class="uni-flex u-col-center u-p-t-30 u-p-b-20" style="background-color: #fff">
<text :class="statusStyle(status)" style="font-size: 28rpx; margin-right: 30rpx"> {{ statusDesc(status) }}</text>
<!-- v-show="allowEdit" -->
<image v-if="allowEdit" style="width: 40rpx; height: 40rpx" src="/static/icons/icons_edit.svg" @click="open"> </image>
</view>
@ -10,7 +9,6 @@
<script setup lang="ts">
import { ref } from 'vue'
import status from '@/mycomponents/status/status.vue'
import statusEdit from '@/mycomponents/status/statusEdit.vue'
import { getInventoryStatusStyle, getInventoryStatusName } from '@/common/directory.js'

10
src/pages.json

@ -652,6 +652,16 @@
}
}
},
{
"path": "pages/repleinsh/record/directRepleinshRecord",
"style": {
"navigationBarTitleText": "直接补料",
"enablePullDownRefresh": true,
"titleNView": {
"autoBackButton": "true"
}
}
},
{
"path": "pages/productionReturn/request/returnRequestCreate",
"style": {

2
src/pages/customerReturn/request/customerReturnRequest.vue

@ -154,7 +154,7 @@ const updateOptions = (status) => {
} else if (status == '3') {
showOptions.value = detailAndHandleOption.value
} else if (status == '4') {
showOptions = detailAndAddAndCloseOption.value
showOptions.value = detailAndAddAndCloseOption.value
} else if (status == '5') {
showOptions.value = addAgainOption.value
} else {

2
src/pages/customerReturn/request/customerReturnRequestCreate.vue

@ -103,7 +103,7 @@ onLoad((option) => {
if (res.data.length > 0) {
const list = res.data
list.forEach((item) => {
item.label = item.name
item.label = item.shortName
item.value = item.code
})
customerList.value = list

2
src/pages/deliver/coms/comDeliverRequestPopup.vue

@ -118,7 +118,7 @@ const openRequestPopup = (editPositionParams) => {
if (res.data.length > 0) {
const list = res.data
list.forEach((item) => {
item.label = item.name
item.label = item.shortName
item.value = item.code
})
customerList.value = list

122
src/pages/deliver/record/deliverRecord.vue

@ -17,7 +17,13 @@
<view class="uni-flex uni-row u-col-center" style="width: 100%">
<view class="" style="text-align: center; font-size: 32rpx; font-weight: 700; margin-left: 10rpx"> 客户 : </view>
<uni-data-picker v-if="detailSource.length > 0" style="padding: 20rpx; background-color: #fff" class="uni-data-picker" placeholder="请选择客户" popup-title="选择客户" :localdata="customerList" @change="reasonChange"> </uni-data-picker>
<!-- <uni-data-picker v-if="detailSource.length > 0" style="padding: 20rpx; background-color: #fff" class="uni-data-picker" placeholder="请选择客户" popup-title="选择客户" :localdata="customerList" @change="reasonChange"> </uni-data-picker> -->
<view class="uni-flex u-col-center uni-row" @click="showCustomer = true" v-if="detailSource.length > 0" s>
<view class="" style="margin-left: 20rpx">
{{ customerText }}
</view>
<u-select v-model="showCustomer" mode="single-column" :list="customerList" @confirm="reasonChange"></u-select>
</view>
</view>
<view class="page-footer">
@ -71,7 +77,7 @@ const fromLocationAreaTypeList = ref([])
const toLocationAreaTypeList = ref([])
const businessType = ref({})
const customerList = ref([])
const customerText = ref('')
const customerText = ref('请选择')
const customerCode = ref('')
const dataContent = ref({})
const managementList = ref([])
@ -79,6 +85,8 @@ const deliverType = ref('') // 发货类型:寄售库CUST,三方库THIRD_PAR
const scanPopup = ref()
const scanLocationCodeRef = ref()
const comMessageRef = ref()
const showCustomer = ref(false)
const toWarehouseCode = ref('')
onLoad((option) => {
deliverType.value = option.deliverType
const typeCode = 'Deliver'
@ -97,7 +105,7 @@ onLoad((option) => {
if (res.data.length > 0) {
const list = res.data
list.forEach((item) => {
item.text = item.name
item.label = item.shortName
item.value = item.code
})
customerList.value = list
@ -197,45 +205,55 @@ const scanLocationCode = (location, code) => {
}
const commit = () => {
if (customerText.value == '') {
showMessage('请先选择客户')
return
}
if (toLocationCode.value == '') {
showMessage('请先选择目标库位')
return
}
if (detailSource.value.length > 0 && detailSource.value[0].subList.length > 0) {
//
proxy.$modal.loading('提交中....')
managementList.value = []
const precisionStrategParams = setPrecisionStrategParams()
getPrecisionStrategyList(precisionStrategParams, (res) => {
if (res.success) {
managementList.value = res.list
const params = setParams()
deliverRecordSubmit(params)
.then((res) => {
uni.hideLoading()
if (res.data) {
showCommitSuccessMessage(`提交成功<br>生成制品发货记录<br>${res.data}`)
} else {
showErrorMessage(`提交失败[${res.msg}]`)
}
})
.catch((error) => {
uni.hideLoading()
showErrorMessage(error)
})
} else {
uni.hideLoading()
showErrorMessage(res.message)
}
})
} else {
showErrorMessage('没有要提交的数据,请先扫描')
try {
if (customerText.value == '') {
showMessage('请先选择客户')
return
}
if (toLocationCode.value == '') {
showMessage('请先选择目标库位')
return
}
if (detailSource.value.length > 0 && detailSource.value[0].subList.length > 0) {
//
proxy.$modal.loading('提交中....')
managementList.value = []
const precisionStrategParams = setPrecisionStrategParams()
console.log(444)
getPrecisionStrategyList(precisionStrategParams, (res) => {
if (res.success) {
console.log(5555)
managementList.value = res.list
const params = setParams()
deliverRecordSubmit(params)
.then((res) => {
uni.hideLoading()
if (res.data) {
console.log(666)
showCommitSuccessMessage(`提交成功<br>生成制品发货记录<br>${res.data}`)
} else {
console.log(7777)
showErrorMessage(`提交失败[${res.msg}]`)
}
})
.catch((error) => {
console.log(888)
uni.hideLoading()
showErrorMessage(error)
})
} else {
console.log(9999)
uni.hideLoading()
showErrorMessage(res.message)
}
})
} else {
showErrorMessage('没有要提交的数据,请先扫描')
}
} catch (e) {
console.log(e)
}
}
const setPrecisionStrategParams = () => {
@ -264,7 +282,7 @@ const setPrecisionStrategParams = () => {
}
const setParams = () => {
const subList = []
const subList1 = []
const creator = store.id
detailSource.value.forEach((item) => {
item.subList.forEach((detail) => {
@ -293,16 +311,23 @@ const setParams = () => {
submitItem.qty = detail.handleQty
submitItem.package = ''
subList.push(submitItem)
subList1.push(submitItem)
}
})
})
dataContent.value.subList = subList
console.log('rr')
dataContent.value.subList = subList1
console.log('dddddd')
dataContent.value.creator = creator
console.log('tttt')
dataContent.value.customerCode = customerCode.value
console.log('uuuuuuuu')
dataContent.value.fromWarehouseCode = detailSource.value[0].subList[0].warehouseCode
console.log('iiiiiiii')
dataContent.value.toWarehouseCode = toWarehouseCode.value
console.log('kkkkkkkk')
dataContent.value.deliverType = deliverType.value
debugger
return dataContent.value
}
@ -365,12 +390,13 @@ const updateData = () => {
}
}
const reasonChange = (e) => {
if (e.detail.value.length == 0) {
console.log(e)
if (e.length == 0) {
customerCode.value = ''
customerText.value = ''
} else {
customerCode.value = e.detail.value[0].value
customerText.value = e.detail.value[0].text
customerText.value = e[0].label
customerCode.value = e[0].value
}
}
</script>

2
src/pages/deliver/request/deliverRequest.vue

@ -147,7 +147,7 @@ const updateOptions = (status) => {
} else if (status == '3') {
showOptions.value = detailAndHandleOption.value
} else if (status == '4') {
showOptions = detailAndAddAndCloseOption.value
showOptions.value = detailAndAddAndCloseOption.value
} else if (status == '5') {
showOptions.value = addAgainOption.value
} else {

28
src/pages/deliver/request/deliverRequestCreate.vue

@ -9,11 +9,13 @@
<button class="btn_add" type="primary" @click="goScan(false)">+去添加</button>
</view>
<div class="btn_bottom">
<view class="" style="flex: 1">
<button class="btn_single_commit" hover-class="btn_commit_after" @click="submit()">提交</button>
<view class="page-footer">
<view class="uni-flex u-col-center space-between padding_20" style="background-color: ghostwhite; width: 100%">
<view class=""> </view>
<button class="btn_single_commit" style="flex: 1" hover-class="btn_commit_after" @click="submit()">提交</button>
</view>
</div>
</view>
<com-message ref="comMessageRef" />
</view>
</view>
@ -25,6 +27,7 @@ import { ref, getCurrentInstance, nextTick, onMounted } from 'vue'
import { onLoad, onNavigationBarButtonTap, onPullDownRefresh } from '@dcloudio/uni-app'
import { deliverRequestSubmit, issueRecordSubmit } from '@/api/request2.js'
import { getBusinessType } from '@/common/record.js'
import { calc } from '@/common/calc.js'
import { goHome, getRemoveOption, getISODateTime } from '@/common/basic.js'
@ -48,6 +51,20 @@ const dataContent = ref({})
const comDeliverRequestPopupRef = ref()
const deliverRequest = ref()
const comMessageRef = ref()
const businessType = ref('')
onLoad((option) => {
const typeCode = 'Deliver'
getBusinessType(typeCode.value, (res) => {
if (res.success) {
businessType.value = res.businessType
// fromLocationAreaTypeList.value = res.fromLocationAreaTypeList
// toLocationAreaTypeList.value = res.toLocationAreaTypeList
// showFromLocationPopup()
} else {
showErrorMessage(res.message)
}
})
})
onMounted(() => {
goScan(true)
})
@ -120,6 +137,9 @@ const setParams = () => {
const submit = () => {
proxy.$modal.loading('提交中....')
const params = setRequestParams()
params.deliverType = 'CUST' //
params.businessType = businessType.value //
deliverRequestSubmit(params)
.then((res) => {
uni.hideLoading()

2
src/pages/index/index.vue

@ -359,7 +359,7 @@ const getDictory = () => {
console.log('包装规格获取失败', res)
})
const switchCode = 'FgPutawayLocationCodeValidate,SemiPutawayLocationCodeValidate,PurchasePutawayToLocationCodeValidate,IssueToLocationCodeValidate'
const switchCode = 'FgPutawayLocationCodeValidate,SemiPutawayLocationCodeValidate,PurchasePutawayToLocationCodeValidate,IssueToLocationCodeValidate,fgProductReceipCommitValidate'
getSwitchByCode(switchCode)
.then((res) => {

3
src/pages/issue/coms/comIssueRequestPopup.vue

@ -255,12 +255,13 @@ const callback = (action) => {
rawLocationCode: rawLocationCode.value,
fgLocationCode: fgLocationCode.value,
fromWarehouseCode: fromWarehouseCode.value,
toWarehouseCode: toWarehouseCode.value,
toWarehouseCode: fromWarehouseCode.value,
itemCode: itemCode.value,
itemName: itemName.value,
uom: uom.value,
qty: qty.value
}
console.log(777, item)
closeRequestPopup()
emit('confirm', action, item)
}

2
src/pages/issue/coms/comScanIssuePack.vue

@ -207,7 +207,7 @@ const onScanResult = (result) => {
showBalanceSelect(balanceRes.data.list)
}
} else {
showErrorMessage(balanceRes.message.message)
showErrorMessage(balanceRes.message)
}
uni.hideLoading()
})

9
src/pages/issue/job/issueDetail.vue

@ -23,16 +23,13 @@
</view>
<view class="page-footer">
<view class="uni-flex u-col-center space-between padding_10" style="background-color: ghostwhite; width: 100%">
<view class=""> </view>
<view class="uni-flex uni-row">
<button class="btn_single_commit" hover-class="btn_commit_after" @click="submit()">提交</button>
</view>
<view class="uni-flex u-col-center space-between padding_20" style="background-color: ghostwhite; width: 100%">
<button class="btn_single_commit" hover-class="btn_commit_after" style="flex: 1" @click="submit()">提交</button>
</view>
</view>
<win-scan-button @goScan="openScanDetailPopup"></win-scan-button>
<com-scan-issue-pack ref="comScanIssuePack" @closeScan="closeScan" @updateData="updateData" @afterScan="afterScan"> </com-scan-issue-pack>
<com-scan-issue-pack ref="comScanIssuePackRef" @closeScan="closeScan" @updateData="updateData" @afterScan="afterScan"> </com-scan-issue-pack>
<com-message ref="comMessageRef" />
</view>
</template>

5
src/pages/issue/record/directIssue.vue

@ -135,6 +135,7 @@ onNavigationBarButtonTap((e) => {
}
})
const getScanResult = (result) => {
console.log(111, result)
const { balance } = result
const { label } = result
const pack = result.package
@ -312,7 +313,9 @@ const scanPopupGetFocus = () => {
const commit = () => {
proxy.$modal.loading('提交中....')
//
console.log(444444, detailSource.value)
const precisionStrategyParams = getPrecisionStrategyParams(detailSource.value)
console.log(555555, precisionStrategyParams)
// 2:
getPrecisionStrategyList(precisionStrategyParams, (res) => {
if (res.success) {
@ -324,7 +327,7 @@ const commit = () => {
.then((res) => {
uni.hideLoading()
if (res.data) {
showCommitSuccessMessage(`提交成功<br>生成采购上架记录<br>${res.data}`)
showCommitSuccessMessage(`提交成功<br>生成直接发料记录<br>${res.data}`)
} else {
showErrorMessage(`提交失败[${res.msg}]`)
}

9
src/pages/issue/request/issueRequestCreate.vue

@ -9,10 +9,10 @@
<button class="btn_add" type="primary" @click="goScan(false)">+去添加</button>
</view>
<view class="page-footer">
<view class="uni-flex u-col-center space-between padding_10" style="background-color: ghostwhite; width: 100%">
<view class="uni-flex u-col-center space-between padding_20" style="background-color: ghostwhite; width: 100%">
<view class=""> </view>
<button class="btn_single_commit" style='flex:' hover-class="btn_commit_after" @click="submit()">提交</button>
<button class="btn_single_commit" style="flex: 1" hover-class="btn_commit_after" @click="submit()">提交</button>
</view>
</view>
@ -80,6 +80,7 @@ const goScan = (editPosition) => {
//
const requestConfirm = (action, item) => {
console.log(item)
if (detailSource.value.subList.length == 0) {
detailSource.value = {
workshopCode: item.workshopCode,
@ -94,7 +95,6 @@ const requestConfirm = (action, item) => {
totalQty: 0,
subList: []
}
var subItem = {
productionLineCode: item.productionLineCode,
workStationCode: item.workStationCode,
@ -106,6 +106,7 @@ const requestConfirm = (action, item) => {
uom: item.uom
}
detailSource.value.subList.push(subItem)
console.log(11, detailSource.value)
} else {
const result = detailSource.value.subList.filter((res) => {
if (res.itemCode == item.itemCode) {

7
src/pages/package/job/overPackageJobDetail.vue

@ -36,11 +36,8 @@
</view>
<view class="page-footer">
<view class="uni-flex u-col-center space-between padding_10" style="background-color: ghostwhite; width: 100%">
<view class=""> </view>
<view class="uni-flex uni-row">
<button class="btn_single_commit" hover-class="btn_commit_after" @click="submit()">提交</button>
</view>
<view class="uni-flex u-col-center space-between padding_20" style="background-color: ghostwhite; width: 100%">
<button class="btn_single_commit" style="flex: 1" hover-class="btn_commit_after" @click="submit()">提交</button>
</view>
</view>

1
src/pages/pointProductReceipt/webview.vue

@ -6,6 +6,7 @@
<script setup lang="ts">
import { ref, reactive, nextTick, createApp, watch } from 'vue'
import { onShow, onLoad } from '@dcloudio/uni-app'
const props = defineProps({
src: {

2
src/pages/productPutaway/request/putawayRequest.vue

@ -149,7 +149,7 @@ const updateOptions = (status) => {
} else if (status == '3') {
showOptions.value = detailAndHandleOption.value
} else if (status == '4') {
showOptions = detailAndAddAndCloseOption.value
showOptions.value = detailAndAddAndCloseOption.value
} else if (status == '5') {
showOptions.value = addAgainOption.value
} else {

4
src/pages/productReceipt/coms/comFgCard.vue

@ -34,12 +34,12 @@ import { ref, getCurrentInstance, onMounted, nextTick, watch } from 'vue'
import recommendQty from '@/mycomponents/qty/recommendQty.vue'
const props = defineProps({
dataContent: {
detail: {
type: Object,
default: {}
}
})
const detail = ref(props.dataContent)
// const detail = ref(props.dataContent)
</script>
<style></style>

2
src/pages/productReceipt/coms/comProductDetailCard.vue

@ -9,7 +9,7 @@
<u-swipe-action :show="item.show" :index="index" :options="item.scaned ? scanOptions : detailOptions" bg-color="rgba(255,255,255,0)" @click="(...event) => swipeClick(event, item)">
<recommend :detail="item" :isShowFromLocation="false" :isShowToLocation="settingParam.allowModifyLocation == 'TRUE'"></recommend>
</u-swipe-action>
<view v-if="item.fgList != undefined && item.fgList.length > 0" v-for="(fg, index) in item.fgList" :key="index">
<view v-if="item.fgList != undefined && item.fgList.length > 0" v-for="(fg, key) in item.fgList" :key="key">
<com-fg-card :detail="fg"></com-fg-card>
</view>
</view>

23
src/pages/productReceipt/job/fgProductReceiptDetail.vue

@ -69,7 +69,7 @@ import { Decimal } from 'decimal.js' // 引入
import { getManagementPrecisions } from '@/common/balance.js'
import { getProductReceiptJobDetail, takeProductReceiptJob, cancleTakeProductReceiptJob, productReceiptJobsubmit, getPrintProductReceiptList, getBalanceToPackage, batchPrintingLable } from '@/api/request2.js'
import { goHome, navigateBack, getPackingNumberAndBatch } from '@/common/basic.js'
import { goHome, navigateBack, getPackingNumberAndBatch, getSwitchInfoByCode } from '@/common/basic.js'
import { getDirectoryItemArray, getInventoryStatusName } from '@/common/directory.js'
@ -368,16 +368,21 @@ const commit = () => {
if (!checkLocation()) {
return
}
const valiDate = getSwitchInfoByCode('fgProductReceipCommitValidate')
detailSource.value.forEach((item) => {
item.subList.forEach((subitem) => {
if (subitem.handleQty == undefined) {
showMessage('还没扫码成品不能提交')
} else if (subitem.handleQty != subitem.packQty) {
showQuestionMessage('制品数量不等于包装数量,是否继续提交?', (res) => {
if (res) {
submitJob()
}
})
if (valiDate) {
if (subitem.handleQty == undefined) {
showMessage('还没扫码成品不能提交')
} else if (subitem.handleQty != subitem.packQty) {
showQuestionMessage('制品数量不等于包装数量,是否继续提交?', (res) => {
if (res) {
submitJob()
}
})
} else {
submitJob()
}
} else {
submitJob()
}

2
src/pages/productReceipt/job/productReceiptJob.vue

@ -13,7 +13,7 @@
<u-loadmore :status="loadingType" v-if="jobList.length > 0" />
</view>
<win-scan-button @goScan="openScanPopup" v-if="jobList.length > 0"></win-scan-button>
<winScanPackJob ref="scanPopup" @getResult="getScanResult" :allowNullBalance="true"></winScanPackJob>
<winScanPackJob ref="scanPopup" @getResult="getScanResult"></winScanPackJob>
<jobListCom ref="jobListRef" @selectItem="selectItem"></jobListCom>
<com-message ref="comMessageRef" />
</view>

3
src/pages/productReceipt/record/productReceiptRecord.vue

@ -195,7 +195,6 @@ const commit = () => {
proxy.$modal.loading('提交中....')
managementList.value = []
const precisionStrategParams = setPrecisionStrategParams()
getPrecisionStrategyList(precisionStrategParams, (res) => {
if (res.success) {
managementList.value = res.list
@ -225,6 +224,7 @@ const commit = () => {
}
const setPrecisionStrategParams = () => {
const itemList = []
console.log(9090, detailSource.value)
detailSource.value.forEach((item) => {
item.subList.forEach((detail) => {
if (detail.scaned) {
@ -389,6 +389,7 @@ const confirmSelect = (e) => {
} else {
rawLocationCode.value = station.rawLocationCode
fgLocationCode.value = station.fgLocationCode
console.log(3434, fgLocationCode.value)
}
} else {
showErrorMessage('生产线-工位基础信息维护错误')

2
src/pages/productionReturn/coms/comReturnCommonRequest.vue

@ -172,7 +172,7 @@ const updateOptions = (status) => {
} else if (status == '3') {
showOptions.value = detailAndHandleOption.value
} else if (status == '4') {
showOptions = detailAndAddAndCloseOption.value
showOptions.value = detailAndAddAndCloseOption.value
} else if (status == '5') {
showOptions.value = addAgainOption.value
} else {

4
src/pages/productionReturn/coms/comReturnRequestCreator.vue

@ -1,6 +1,6 @@
<template>
<view class="" style="background-color: #fff">
<view class="uni-flex uni-column">
<view class="uni-flex uni-column u-p-l-20 u-p-r-20 u-p-t-20">
<comReturnRequestInfo :workShopCode="dataContent.workshopCode" :dataContent="dataContent"> </comReturnRequestInfo>
<!-- <uni-swipe-action ref="swipeAction">
<view v-for="(item, index) in dataContent.subList" :key="index">
@ -10,7 +10,7 @@
</uni-swipe-action-item>
</view>
</uni-swipe-action> -->
<view class="u-p-l-20 u-p-r-20">
<view class="">
<u-swipe-action :show="item.show" :index="index" v-for="(item, index) in dataContent.subList" :key="index" :options="options" bg-color="rgba(255,255,255,0)" @click="(...event) => swipeClick(event, item)">
<item-qty :dataContent="item" :isShowStdPack="false"> </item-qty>
<view class="split_line"></view>

37
src/pages/productionReturn/record/returnToHold.vue

@ -19,7 +19,7 @@
</scroll-view>
</view>
<view class="page-footer">
<!-- <view class="page-footer">
<view class="uni-flex u-col-center space-between padding_10" style="background-color: ghostwhite; width: 100%">
<view class="">
<view class="">
@ -36,6 +36,16 @@
<button class="btn_single_commit" hover-class="btn_commit_after" @click="commit">提交</button>
</view>
</view>
</view> -->
<view class="page-footer">
<view class="uni-flex u-col-center space-between padding_10" style="background-color: ghostwhite; width: 100%">
<view class="">
<requiredLocation title="目标库位" :locationCode="toLocationCode" @getLocation="getToLocation" :locationAreaTypeList="toLocationAreaTypeList" :isShowEdit="true"></requiredLocation>
</view>
<view class="uni-flex uni-row">
<button class="btn_single_commit" hover-class="btn_commit_after" @click="commit">提交</button>
</view>
</view>
</view>
<win-scan-button @goScan="openScanPopup(false)"></win-scan-button>
</view>
@ -97,6 +107,7 @@ const recommendLocationList = ref([]) // 推荐库位列表
const fromWarehouseCode = ref('') //
const fromManagementList = ref([])
const toManagementList = ref([])
const toLocationAreaTypeList = ref([])
const scanPopup = ref()
const comMessageRef = ref()
const toWarehouseCode = ref()
@ -122,7 +133,10 @@ onPullDownRefresh(() => {
const openScanPopup = (isEditPosition) => {
scanPopup.value.openScanPopup(isEditPosition)
}
const getToLocation = (location, code) => {
toLocationCode.value = code
// toLocationInfo.value = location
}
const getScanResult = async (result, param) => {
positionInfo.value = param.positionInfo
workshopCode.value = param.workshopCode
@ -165,7 +179,7 @@ const getScanResult = async (result, param) => {
const itemp = createItemInfo(label, pack)
const newDetail = createDetailInfo(label, pack)
newDetail.toLocationCode = 'HOLD'
newDetail.toLocationCode = toLocationCode.value
newDetail.locationCode = rawLocationCode.value
newDetail.fromLocationCode = rawLocationCode.value
itemp.subList.push(newDetail)
@ -179,7 +193,7 @@ const getScanResult = async (result, param) => {
if (detail == undefined) {
const newDetail = createDetailInfo(label, pack)
newDetail.toLocationCode = 'HOLD'
newDetail.toLocationCode = toLocationCode.value
newDetail.locationCode = rawLocationCode.value
newDetail.fromLocationCode = rawLocationCode.value
item.subList.push(newDetail)
@ -259,7 +273,10 @@ const commit = async () => {
showMessage('请先选择位置')
return
}
if (toLocationCode.value == '') {
showErrorMessage('请先选择目标库位')
return
}
if (detailSource.value.length > 0 && detailSource.value[0].subList.length > 0) {
//
proxy.$modal.loading('提交中....')
@ -298,7 +315,6 @@ const commit = async () => {
showErrorMessage('没有要提交的数据,请先扫描')
}
} catch (e) {
console.log(e)
uni.hideLoading()
showErrorMessage(e)
}
@ -331,6 +347,9 @@ const setToPrecisionStrategParams = () => {
detailSource.value.forEach((item) => {
item.subList.forEach((detail) => {
if (detail.scaned) {
if (detail.toLocationCode == '') {
detail.toLocationCode = toLocationCode.value
}
const filterResult = itemList.filter((res) => {
if (res.itemCode == item.itemCode && detail.toLocationCode == res.toLocationCode) {
return res
@ -351,7 +370,7 @@ const setToPrecisionStrategParams = () => {
}
const setParams = () => {
const subList = []
const subList1 = []
const creator = store.id
detailSource.value.forEach((item) => {
item.subList.forEach((detail) => {
@ -384,11 +403,11 @@ const setParams = () => {
submitItem.qty = detail.handleQty
subList.push(submitItem)
subList1.push(submitItem)
}
})
})
dataContent.value.subList = subList
dataContent.value.subList = subList1
dataContent.value.creator = creator
dataContent.value.workshopCode = workshopCode.value
dataContent.value.businessType = businessTypeCode.value

80
src/pages/productionReturn/record/returnToStore.vue

@ -294,48 +294,52 @@ const removeData = (item) => {
}
const commit = async () => {
if (positionInfo.value == '请选择位置') {
showMessage('请先选择位置')
return
}
try {
if (positionInfo.value == '请选择位置') {
showMessage('请先选择位置')
return
}
if (detailSource.value.length > 0 && detailSource.value[0].subList.length > 0) {
//
if (detailSource.value.length > 0 && detailSource.value[0].subList.length > 0) {
//
proxy.$modal.loading('提交中....')
fromManagementList.value = []
toManagementList.value = []
const fromPrecisionStrategParams = setFromPrecisionStrategParams(detailSource.value)
const toPrecisionStrategParams = setToPrecisionStrategParams(detailSource.value)
const fromManagement = await getPrecisionStrategy(fromPrecisionStrategParams)
fromManagementList.value = fromManagement.data
proxy.$modal.loading('提交中....')
fromManagementList.value = []
toManagementList.value = []
const fromPrecisionStrategParams = setFromPrecisionStrategParams(detailSource.value)
const toPrecisionStrategParams = setToPrecisionStrategParams(detailSource.value)
const fromManagement = await getPrecisionStrategy(fromPrecisionStrategParams)
fromManagementList.value = fromManagement.data
if (fromManagementList.value.length == 0) {
showErrorMessage('查询来源库位管理模式异常')
return
}
const toManagement = await getPrecisionStrategy(toPrecisionStrategParams)
toManagementList.value = toManagement.data
if (toManagementList.value.length == 0) {
showErrorMessage('查询目标库位管理模式异常')
return
if (fromManagementList.value.length == 0) {
showErrorMessage('查询来源库位管理模式异常')
return
}
const toManagement = await getPrecisionStrategy(toPrecisionStrategParams)
toManagementList.value = toManagement.data
if (toManagementList.value.length == 0) {
showErrorMessage('查询目标库位管理模式异常')
return
}
const params = setParams()
productionReturnRecordSubmit(params)
.then((res) => {
uni.hideLoading()
if (res.data) {
showCommitSuccessMessage(`提交成功<br>生成退料记录<br>${res.data}`)
} else {
showErrorMessage(`提交失败[${res.msg}]`)
}
})
.catch((error) => {
uni.hideLoading()
showErrorMessage(error)
})
} else {
showErrorMessage('没有要提交的数据,请先扫描')
}
const params = setParams()
productionReturnRecordSubmit(params)
.then((res) => {
uni.hideLoading()
if (res.data) {
showCommitSuccessMessage(`提交成功<br>生成退料记录<br>${res.data}`)
} else {
showErrorMessage(`提交失败[${res.msg}]`)
}
})
.catch((error) => {
uni.hideLoading()
showErrorMessage(error)
})
} else {
showErrorMessage('没有要提交的数据,请先扫描')
} catch (e) {
showErrorMessage(e)
}
}

1
src/pages/productionReturn/request/requestDetail.vue

@ -45,6 +45,7 @@ const requestContent = ref({}) // 任务内容
const subList = ref([]) //
const detailSource = ref([])
const jobDetailPopup = ref()
const comMessageRef = ref()
onLoad((option) => {
id.value = option.id
const { businessType } = option

11
src/pages/productionReturn/request/returnRequestCreate.vue

@ -9,14 +9,11 @@
<button class="btn_add" type="primary" @click="goScan(false)">+去添加</button>
</view>
<div class="btn_bottom">
<view class="" style="display: flex; flex-direction: row">
<view class="">
<button class="btn_commit" type="primary" hover-class="btn_commit_after" @click="submit()">提交</button>
</view>
<view class="page-footer">
<view class="uni-flex u-col-center space-between padding_20" style="background-color: ghostwhite; width: 100%">
<button class="btn_single_commit" style="flex: 1" hover-class="btn_commit_after" @click="submit()">提交</button>
</view>
</div>
</view>
<comScanReturnPack ref="comScanIssuePack"> </comScanReturnPack>
<com-message ref="comMessageRef" />
</view>

3
src/pages/purchaseReceipt/coms/comReceiptDetailCard.vue

@ -117,6 +117,9 @@ const updateData = () => {
}
//
const emit = defineEmits(['updateData', 'remove'])
defineExpose({
resizeCollapse
})
</script>
<style></style>

13
src/pages/purchaseReceipt/job/receiptDetail.vue

@ -21,7 +21,7 @@
<scroll-view scroll-y="true" class="page-main-scroll">
<view class="detail-list" v-for="(item, index) in detailSource" :key="item.id">
<view class="">
<com-receipt-detail-card :dataContent="item" :index="index" :settingParam="jobContent" @remove="updateData" @updateData="updateData" :locationAreaTypeList="toLocationAreaTypeList"> </com-receipt-detail-card>
<com-receipt-detail-card ref="comReceiptDetailCardRef" :dataContent="item" :index="index" :settingParam="jobContent" @remove="updateData" @updateData="updateData" :locationAreaTypeList="toLocationAreaTypeList" :key="count"> </com-receipt-detail-card>
</view>
</view>
</scroll-view>
@ -93,6 +93,8 @@ const scanedPackingNumber = ref('')
const comMessageRef = ref()
const locationCompareRef = ref()
const scanPopup = ref()
const comReceiptDetailCardRef = ref()
const count = ref(0)
onLoad((option) => {
id.value = option.id
// scanedPackingNumber.value = option.scaned || ''
@ -168,9 +170,11 @@ const getDetail = () => {
detailSource.value = getTreeDataSource(subList.value)
detailSource.value.forEach((r) => {
r.subList.forEach((s) => {
s.scaned = false
if (scanedPackingNumber.value && scanedPackingNumber.value == s.packingNumber) s.scaned = true
})
})
count.value++
isAllReceived.value = false
} else {
showMessage('列表数据为0')
@ -446,6 +450,13 @@ const switchChange = (isOn) => {
})
})
})
console.log(comReceiptDetailCardRef.value)
// comReceiptDetailCardRef.value.resizeCollapse()
nextTick(() => {
comReceiptDetailCardRef.value.forEach((r) => {
r.resizeCollapse()
})
})
calcHandleQty(detailSource.value)
} else {
comMessageRef.value.showQuestionMessage('是否要关闭整单收货?', (res) => {

2
src/pages/purchaseReturn/job/returnDetail.vue

@ -14,7 +14,7 @@
<scroll-view scroll-y="true" class="page-main-scroll">
<view class="detail-list" v-for="(item, index) in detailSource" :key="item.id">
<view class="">
<com-detail-card :dataContent="item" :settingParam="jobContent" @remove="updateData" @updateData="updateData" @openDetail="openDetail"> </com-detail-card>
<com-detail-card :dataContent="item" :settingParam="jobContent" @remove="updateData" :queryBalance="false" @updateData="updateData" @openDetail="openDetail"> </com-detail-card>
</view>
</view>
</scroll-view>

15
src/pages/purchaseReturn/request/returnRequest.vue

@ -111,7 +111,6 @@ const getList = (type) => {
if (type === 'refresh') {
uni.stopPullDownRefresh()
}
const { list } = res.data
totalCount.value = res.data.total
updateTitle(`采购上架申请(${totalCount.value})`)
@ -140,16 +139,16 @@ const getList = (type) => {
showMessage(error)
})
}
const updateOptions = (status) => {
if (status == '1') {
const updateOptions = (statusParams) => {
if (statusParams == '1') {
showOptions.value = detailAndApproveOptions.value
} else if (status == '2') {
} else if (statusParams == '2') {
showOptions.value = detailAndApprovePassAndApproveNoOption.value
} else if (status == '3') {
} else if (statusParams == '3') {
showOptions.value = detailAndHandleOption.value
} else if (status == '4') {
showOptions = detailAndAddAndCloseOption.value
} else if (status == '5') {
} else if (statusParams == '4') {
showOptions.value = detailAndAddAndCloseOption.value
} else if (statusParams == '5') {
showOptions.value = addAgainOption.value
} else {
showOptions.value = detailOptions.value

1
src/pages/purchaseReturn/request/returnRequestCreate.vue

@ -103,7 +103,6 @@ const getDataSource = (result) => {
const { balance } = result
const { label } = result
const pack = result.package
debugger
const item = detailSource.value.find((res) => {
if (res.itemCode == balance.itemCode) {
return res

17
src/pages/putaway/record/putawayRecord.vue

@ -107,6 +107,9 @@ const getScanResult = (result) => {
const { balance } = result
const { label } = result
const pack = result.package
const { poLine } = label
const { poNumber } = label
const { supplierCode } = label
const item = detailSource.value.find((res) => {
if (res.itemCode == balance.itemCode) {
return res
@ -122,6 +125,9 @@ const getScanResult = (result) => {
const newDetail = createDetailInfo(balance, pack) //
newDetail.toLocationCode = toLocation.locationCode
newDetail.toWarehouseCode = toLocation.toWarehouseCode
newDetail.poLine = poLine
newDetail.poNumber = poNumber
newDetail.supplierCode = supplierCode
itemp.subList.push(newDetail)
detailSource.value.push(itemp)
calcHandleQty(detailSource.value)
@ -137,6 +143,9 @@ const getScanResult = (result) => {
const newDetail = createDetailInfo(balance, pack)
newDetail.toLocationCode = toLocation.locationCode
newDetail.toWarehouseCode = toLocation.toWarehouseCode
newDetail.poLine = poLine
newDetail.poNumber = poNumber
newDetail.supplierCode = supplierCode
item.subList.push(newDetail)
calcHandleQty(detailSource.value)
})
@ -329,13 +338,13 @@ const setRecordParams = () => {
return dataContent.value
}
const showMessage = (message) => {
comMessageRef.value.showMessage(scanResult.message, (res) => {
comMessageRef.value.showMessage(message, (res) => {
if (res) {
}
})
}
const showErrorMessage = (message) => {
comMessageRef.value.showErrorMessage(scanResult.message, (res) => {
comMessageRef.value.showErrorMessage(message, (res) => {
if (res) {
}
})
@ -371,12 +380,12 @@ const getToLocationCode = (location, code) => {
const showCommitSuccessMessage = (hint) => {
comMessageRef.value.showSuccessMessage(hint, (res) => {
if (res) {
clearData()
clear()
}
})
}
const clearData = () => {
const clear = () => {
fromLocationInfo.value = {}
fromLocationCode.value = ''
fromWarehouseCode.value = ''

2
src/pages/putaway/request/putawayRequest.vue

@ -147,7 +147,7 @@ const updateOptions = (status) => {
} else if (status == '3') {
showOptions.value = detailAndHandleOption.value
} else if (status == '4') {
showOptions = detailAndAddAndCloseOption.value
showOptions.value = detailAndAddAndCloseOption.value
} else if (status == '5') {
showOptions.value = addAgainOption.value
} else {

2
src/pages/query/coms/comItemDetailCard.vue

@ -1,6 +1,6 @@
<template>
<view>
<com-empty-view v-if="itemList.length == 0"></com-empty-view>
<!-- <com-empty-view v-if="itemList.length == 0"></com-empty-view>s -->
<view class="" style="background-color: #fff; width: 100%; padding: 10rpx 20rpx" v-for="(item, index) in itemList">
<!-- <view class="flex uni-center u-col-center" style="flex-direction: row; "> -->
<view>

2
src/pages/query/item.vue

@ -168,6 +168,7 @@ const getExpectin = (pageNo, pageSize) => {
if (res.data.total > 0) {
paging.value.complete(res.data.list)
} else {
paging.value.complete(false)
showMessage(`未查找到物料【${itemCode.value}`)
}
})
@ -189,6 +190,7 @@ const getExpectout = (pageNo, pageSize) => {
getExpectoutByItemcode(params)
.then((res) => {
uni.hideLoading()
console.log(res)
if (res.data.total > 0) {
paging.value.complete(res.data.list)
} else {

117
src/pages/repleinsh/coms/comScanReplishPack.vue

@ -51,7 +51,7 @@
<scroll-view :scroll-y="true" class="scroll-view" v-if="expand && issueRecord.length > 0" style="width: 100%">
<u-swipe-action :show="item.show" :index="index" v-for="(item, index) in issueRecord" :key="index" :options="scanOptions" bg-color="rgba(255,255,255,0)" @click="(...event) => swipeClick($event, item)">
<view style="padding: 0px 10px">
<balance :dataContent="record" :isShowFromLocation="false" :isShowStatus="true" :isShowStdPack="false"></balance>
<balance :dataContent="item" :isShowFromLocation="false" :isShowStatus="true" :isShowStdPack="false"></balance>
</view>
</u-swipe-action>
</scroll-view>
@ -210,13 +210,17 @@ const onScan = (result) => {
if (balances.list.length == 0) {
showErrorMessage('未查找到该包装的库存信息,请重新扫描')
} else {
const newBalances = balances.list.filter((b) => b.locationCode == that.fromLocationCode)
const newBalances = balances.list.filter((b) => b.locationCode == fromLocationCode.value)
console.log(22222222)
if (newBalances.length == 0) {
console.log(333333)
showErrorMessage('未查找到该包装的库存信息,请重新扫描')
} else if (newBalances.length == 1) {
const balance = newBalances[0]
afterGetBalance(result.label, balance, packageInfo)
console.log(44444444)
const balance1 = newBalances[0]
afterGetBalance(result.label, balance1, packageInfo)
} else {
console.log(5555555)
showBalanceSelect(newBalances)
}
}
@ -235,22 +239,22 @@ const onScan = (result) => {
uni.hideLoading()
}
}
const getBalance = (label, callback) => {
const getBalance = (labelParams, callback) => {
const filters = []
filters.push({
column: 'packingNumber',
action: '==',
value: label.packingNumber
value: labelParams.packingNumber
})
filters.push({
column: 'itemCode',
action: '==',
value: label.itemCode
value: labelParams.itemCode
})
filters.push({
column: 'batch',
action: '==',
value: label.batch
value: labelParams.batch
})
if (fromInventoryStatuses.value != null && fromInventoryStatuses.value != '') {
@ -275,15 +279,15 @@ const getBalance = (label, callback) => {
})
}
const selectBalanceItem = (balance) => {
afterGetBalance(label.value, balance)
const selectBalanceItem = (balanceParams) => {
afterGetBalance(label.value, balanceParams)
}
const afterGetBalance = (label, balance, packageInfo) => {
const afterGetBalance = (labelParams, balanceParams, packageInfo) => {
try {
const { itemCode } = label
const packingCode = label.packingNumber
const lot = label.batch
const { itemCode } = labelParams
const packingCode = labelParams.packingNumber
const lot = labelParams.batch
const item = toLocation.value.Items.find((r) => r.itemCode == itemCode)
const fromLocation = item.Locations.find((l) => l.fromLocationCode == fromLocationCode.value)
if (fromLocation != undefined) {
@ -299,11 +303,11 @@ const afterGetBalance = (label, balance, packageInfo) => {
if (batch.Recommends != undefined && batch.Recommends.length > 0) {
const recommend = batch.Recommends.find((r) => r.packingNumber == packingCode)
if (recommend != undefined) {
addRecord(batch, label, balance, packageInfo)
addRecord(batch, labelParams, balanceParams, packageInfo)
} else {
//
if (jobContent.value.allowModifyPackingNumber == 'TRUE') {
addRecord(batch, label, balance, packageInfo)
addRecord(batch, labelParams, balanceParams, packageInfo)
} else {
showErrorMessage(`未查找到该箱码【${packingCode}】的明细`, (res) => {
getfocus()
@ -311,7 +315,7 @@ const afterGetBalance = (label, balance, packageInfo) => {
}
}
} else {
addRecord(batch, label, balance, packageInfo)
addRecord(batch, labelParams, balanceParams, packageInfo)
}
} else {
showErrorMessage(`箱码【${packingCode}】已经扫描,请继续扫描下一箱`, (res) => {
@ -321,7 +325,7 @@ const afterGetBalance = (label, balance, packageInfo) => {
} else if (jobContent.value.allowModifyBatch == 'TRUE') {
showQuestionMessage(`在【${fromLocationCode.value}】库位下,批次【${lot}】不是推荐批次,是否要继续发料?`, (res) => {
if (res) {
const batch = createBatchInfo(label, balance, packageInfo)
const batch = createBatchInfo(labelParams, balanceParams, packageInfo)
if (fromLocation.Batchs.length > 0) {
batch.detail = fromLocation.Batchs[0].detail
}
@ -345,60 +349,59 @@ const afterGetBalance = (label, balance, packageInfo) => {
}
}
const createBatchInfo = (label, balance, packageInfo) => {
const createBatchInfo = (labelParams, balanceParams, packageInfo) => {
const batch = {
batch: label.batch,
batch: labelParams.batch,
qty: 0,
uom: label.uom,
uom: labelParams.uom,
Records: []
}
let record = {}
if (balance == null) {
record = creatRecordByBalance(label, packageInfo)
batch.handleQty = Number(label.qty)
if (balanceParams == null) {
record = creatRecordByBalance(labelParams, packageInfo)
batch.handleQty = Number(labelParams.qty)
} else {
record = creatRecordByLabel(balance, packageInfo)
batch.handleQty = Number(balance.qty)
record = creatRecordByLabel(balanceParams, packageInfo)
batch.handleQty = Number(balanceParams.qty)
}
batch.Records.push(record)
issueRecord.value.unshift(record)
return batch
}
const creatRecordByLabel = (label, packageInfo) => {
const creatRecordByLabel = (labelParams, packageInfo) => {
const record = {
scaned: true,
itemCode: label.itemCode,
packingNumber: label.packingNumber,
itemCode: labelParams.itemCode,
packingNumber: labelParams.packingNumber,
parentPackingNumber: packageInfo.parentNumber,
batch: label.batch,
qty: Number(label.qty),
batch: labelParams.batch,
qty: Number(labelParams.qty),
// qty: Number(label.qty)>Number(balance.qty)?Number(balance.qty):Number(label.qty),
uom: label.uom,
uom: labelParams.uom,
inventoryStatus: 'OK',
balance: null,
toLocationCode: toLocationCode.value,
supplierCode: label.supplierCode,
supplierCode: labelParams.supplierCode,
packUnit: packageInfo.packUnit,
packQty: packageInfo.packQty
}
return record
}
const creatRecordByBalance = (balance, packageInfo) => {
balance.packQty = packageInfo.packQty
balance.packUnit = packageInfo.packUnit
const creatRecordByBalance = (balanceParams, packageInfo) => {
balanceParams.packQty = packageInfo.packQty
balanceParams.packUnit = packageInfo.packUnit
const record = {
scaned: true,
itemCode: balance.itemCode,
packingNumber: balance.packingNumber,
batch: balance.batch,
qty: Number(balance.qty),
itemCode: balanceParams.itemCode,
packingNumber: balanceParams.packingNumber,
batch: balanceParams.batch,
qty: Number(balanceParams.qty),
// qty: Number(label.qty)>Number(balance.qty)?Number(balance.qty):Number(label.qty),
uom: balance.uom,
inventoryStatus: balance.inventoryStatus,
balance,
uom: balanceParams.uom,
inventoryStatus: balanceParams.inventoryStatus,
balance: balanceParams,
toLocationCode: toLocationCode.value,
supplierCode: balance.supplierCode
}
@ -410,12 +413,11 @@ const calcBatchHandleQty = (batch) => {
handleQty = calc.add(handleQty, res.qty)
})
batch.handleQty = handleQty
dataContent.value.forEach((toLocationCode) => {
toLocationCode.Items.forEach((item) => {
dataContent.value.forEach((toLocationCode1) => {
toLocationCode1.Items.forEach((item) => {
let itemCodeHandleQty = 0
item.Locations.forEach((batch) => {
batch.Batchs.forEach((batchHandleQty) => {
item.Locations.forEach((batch1) => {
batch1.Batchs.forEach((batchHandleQty) => {
itemCodeHandleQty = calc.add(itemCodeHandleQty, batchHandleQty.handleQty)
})
})
@ -424,15 +426,24 @@ const calcBatchHandleQty = (batch) => {
})
}
const addRecord = (batch, label, packageInfo) => {
const addRecord = (batch, labelParams, balanceParams, packageInfo) => {
let record = {}
if (balance == null) {
record = creatRecordByLabel(label, packageInfo)
if (balanceParams == null) {
console.log(9999)
console.log(labelParams)
console.log(packageInfo)
console.log(9999)
record = creatRecordByLabel(labelParams, packageInfo)
} else {
record = creatRecordByBalance(balance, packageInfo)
console.log(8888)
console.log(balanceParams)
console.log(packageInfo)
console.log(8888)
record = creatRecordByBalance(balanceParams, packageInfo)
}
batch.Records.push(record)
console.log(34989, record)
issueRecord.value.unshift(record)
calcBatchHandleQty(batch)
getfocus()

14
src/pages/repleinsh/job/repleinshDetail.vue

@ -157,6 +157,7 @@ const getDetail = () => {
jobStatus.value = res.data.status
subList.value = res.data.subList
toLocationCode.value = subList.value[0].toLocationCode
console.log(`库位${toLocationCode.value}`)
toLocationAreaTypeList.value = getDirectoryItemArray(jobContent.value.toAreaTypes)
detailSource.value = getDataSource(detailSource.value, subList.value)
setTimeout((r) => {
@ -256,8 +257,8 @@ const setParams = () => {
const commitSubList = []
const createTime = getCurrDateTime()
const creator = store.id
detailSource.value.forEach((toLocationCode) => {
toLocationCode.Items.forEach((item) => {
detailSource.value.forEach((toLocationCodeParams) => {
toLocationCodeParams.Items.forEach((item) => {
item.Locations.forEach((fromLocation) => {
fromLocation.Batchs.forEach((batch) => {
const subItem = batch.detail
@ -277,6 +278,7 @@ const setParams = () => {
record.toContainerNumber = r.ContainerNumber
record.toInventoryStatus = r.inventoryStatus
record.toLocationCode = toLocationCode.value
console.log(`提交${toLocationCode.value}`)
record.supplierCode = r.supplierCode
if (r.parentPackingNumber != '' && r.parentPackingNumber != null) {
@ -404,15 +406,15 @@ const openScanDetailPopup = () => {
comScanIssuePackRef.value.openScanPopup(detailSource.value, jobContent.value)
}
const closeScanPopup = () => {
this.updateCommitBtn()
updateCommitBtn()
}
const scanLocationCode = (location, code) => {
this.toLocationCode = code
toLocationCode.value = code
}
const getScanCount = (subList) => {
let scanCount = 0
detailSource.value.forEach((toLocationCode) => {
toLocationCode.Items.forEach((item) => {
detailSource.value.forEach((toLocationCodeParams) => {
toLocationCodeParams.Items.forEach((item) => {
item.Locations.forEach((fromLocation) => {
fromLocation.Batchs.forEach((batch) => {
const subItem = batch.detail

229
src/pages/putaway/record/putawayRecord_bat.vue → src/pages/repleinsh/record/directRepleinshRecord.vue

@ -17,12 +17,16 @@
</view>
</scroll-view>
</view>
<view class="page-footer">
<view class="uni-flex u-col-center space-between padding_10" style="background-color: ghostwhite; width: 100%">
<view class="">
<!-- <requiredLocation v-if="showToLoaction" title="目标库位" :locationCode="toLocationCode"
@getLocation='getToLocationCode' :locationAreaTypeList="toLocationAreaTypeList"></requiredLocation> -->
<view class="uni-row uni-flex">
<text>生产线:</text>
<view class="uni-flex u-col-center uni-row" @click="showSelect">
<view class="" style="margin-left: 20rpx">
{{ positionInfo }}
</view>
<u-select v-model="show" mode="mutil-column-auto" :list="positionList" @confirm="confirmSelect"></u-select>
</view>
</view>
<view class="uni-flex uni-row">
<button class="btn_single_commit" hover-class="btn_commit_after" @click="commit">提交</button>
@ -40,9 +44,9 @@
<script setup lang="ts">
import { ref, getCurrentInstance, nextTick } from 'vue'
import { onLoad, onNavigationBarButtonTap, onReady, onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app'
import { putawayRequestSubmit, putawayRecordSubmit, validateItemAndLocation, getPutawayRecommendLocation } from '@/api/request2.js'
import { repleinshRecordSubmit, getWorkShopLineStation } from '@/api/request2.js'
import { goHome, getCurrDateTime, getPackingNumberAndBatchByList, deepCopyData } from '@/common/basic.js'
import { goHome, getPackingNumberAndBatchByList, deepCopyData } from '@/common/basic.js'
import { calc } from '@/common/calc.js'
@ -65,28 +69,29 @@ import { useCountStore } from '@/store'
const store = useCountStore()
const { proxy } = getCurrentInstance()
const id = ref('')
const dataContent = ref({}) //
const dataContent = ref({})
const detailSource = ref([]) //
const fromLocationInfo = ref({})
const fromLocationCode = ref('')
const fromLocationAreaTypeList = ref([])
const toLocationAreaTypeList = ref([])
const inInventoryStatus = ref('') //
const outInventoryStatus = ref('') //
const inInventoryStatus = ref('')
const outInventoryStatus = ref('')
const businessType = ref({})
const showToLoaction = ref(true)
const recommendLocationList = ref([]) //
const fromWarehouseCode = ref('') //
const businessTypeCode = ref('PurchasePutaway')
const businessTypeCode = ref('Repleinment')
const positionList = ref([])
const show = ref(false)
const positionInfo = ref('请选择生产线')
const comMessageRef = ref()
const show = ref(false)
const scanPopup = ref()
const scanLocationCode = ref()
const managementList = ref([])
const toLocationCode = ref()
const toWarehouseCode = ref('')
onLoad((option) => {
clearData()
getBusinessType(businessTypeCode.value, (res) => {
getBusinessType(typeCode, (res) => {
if (res.success) {
businessType.value = res.businessType
fromLocationAreaTypeList.value = res.fromLocationAreaTypeList
@ -96,6 +101,17 @@ onLoad((option) => {
showErrorMessage(res.message)
}
})
getWorkShopLineStation()
.then((res) => {
if (res.data != null && res.data.length > 0) {
positionList.value = res.data
} else {
showErrorMessage('未查找到位置信息')
}
})
.catch((error) => {
showErrorMessage(error)
})
})
//
onNavigationBarButtonTap((e) => {
@ -118,26 +134,26 @@ const getScanResult = (result) => {
}
if (item == undefined) {
//
getRecommendLocation(balance, pack, (toLocation) => {
const itemp = createItemInfo(balance, pack)
const newDetail = createDetailInfo(balance, pack) //
newDetail.toLocationCode = toLocation.code
newDetail.toWarehouseCode = toLocation.warehouseCode
itemp.subList.push(newDetail)
const dataList = pack.subList
detailSource.value.push(itemp)
detailSource.value.forEach((res) => {
res.subList.forEach((pack) => {
pack.packList = dataList.filter((c) => c.parentNumber == pack.packingNumber)
pack.packList.forEach((pac) => {
pac.parentPackingNumber = pac.parentNumber
pac.packingNumber = pac.number
pac.inventoryStatus = 'OK'
pac.scaned = true
})
// this.getRecommendLocation(balance, pack, toLocation => {
const itemp = createItemInfo(balance, pack)
const newDetail = createDetailInfo(balance, pack) //
// newDetail.toLocationCode = toLocation.code;
// newDetail.toWarehouseCode = toLocation.warehouseCode;
itemp.subList.push(newDetail)
const dataList = pack.subList
detailSource.value.push(itemp)
detailSource.value.forEach((res) => {
res.subList.forEach((pack) => {
pack.packList = dataList.filter((c) => c.parentNumber == pack.packingNumber)
pack.packList.forEach((pac) => {
pac.parentPackingNumber = pac.parentNumber
pac.packingNumber = pac.number
pac.inventoryStatus = 'OK'
pac.scaned = true
})
})
})
// })
} else {
const itemDetail = item.subList.find((r) => r.packingNumber == balance.packingNumber && r.batch == balance.batch)
if (itemDetail != undefined) {
@ -149,7 +165,10 @@ const getScanResult = (result) => {
//
const getRecommendLocation = (balance, pack, callback) => {
proxy.$modal.loading('扫描中­....')
uni.showLoading({
title: '扫描中...',
mask: true
})
const recommend = recommendLocationList.value.find((r) => r.itemCode == balance.itemCode)
if (recommend == undefined) {
const param = {
@ -171,18 +190,11 @@ const getRecommendLocation = (balance, pack, callback) => {
.catch((error) => {
uni.hideLoading()
showErrorMessage(error)
uni.hideLoading()
})
} else {
callback(recommend)
}
}
const showErrorMessage = (message) => {
comMessageRef.value.showErrorMessage(message, (res) => {
if (res) {
}
})
}
const calcTreeHandleQty = () => {
for (const item of detailSource.value) {
@ -195,8 +207,56 @@ const calcTreeHandleQty = () => {
}
}
const updateData = () => {
calcTreeHandleQty()
const showSelect = () => {
// if (this.editPosition) {
show.value = true
// }
}
const confirmSelect = (e) => {
positionInfo.value = `${e[0].label}-${e[1].label}-${e[2].label}`
workshopCode.value = e[0].value
productionLineCode.value = e[1].value
workStationCode.value = e[2].value
workShopName.value = e[0].label
productionLineName.value = e[1].label
workStationName.value = e[2].label
const shop = positionList.value.find((shop) => shop.value == workshopCode.value)
if (shop != undefined && shop.children != undefined) {
const prodLine = shop.children.find((line) => line.value == productionLineCode.value)
if (prodLine != undefined && prodLine.children != undefined) {
const station = prodLine.children.find((r) => r.value == workStationCode.value)
if (station.rawLocationCode == '' && station.rawLocationCode == null) {
showErrorMessage(`${workStationName.value}的原材料库位为空,请重新选择`)
return
}
rawLocationCode.value = station.rawLocationCode
fgLocationCode.value = station.fgLocationCode
} else {
showErrorMessage('生产线-工位基础信息维护错误')
}
} else {
showErrorMessage('车间-生产线基础信息维护错误')
}
//
let toLocationCode = ''
positionList.value.forEach((item) => {
if (workshopCode.value == item.value) {
//
item.children.find((child) => {
if (productionLineCode.value == child.value) {
toLocationCode = child.children.find((subChild) => workStationCode.value == subChild.value).rawLocationCode
}
})
}
})
detailSource.value.forEach((item) => {
item.subList.forEach((detail) => {
detail.toLocationCode = toLocationCode
})
})
}
const removeItem = (index, item) => {
@ -210,7 +270,6 @@ const removePack = () => {
detailSource.value.splice(i, 1)
}
}
updateData()
}
const openScanPopup = () => {
@ -239,28 +298,25 @@ const scanPopupGetFocus = () => {
}
}
// scanLocationCode(location, code) {
// this.toLocationCode = code
// this.toLocationCode = location;
// },
const commit = () => {
proxy.$modal.loading('提交中­....')
uni.showLoading({
title: '提交中....',
mask: true
})
//
const precisionStrategyParams = getPrecisionStrategyParams(detailSource.value)
// 2:
getPrecisionStrategyList(precisionStrategyParams, (res) => {
if (res.success) {
managementList.value = res.list
const params = setRecordParams()
console.log('提交参数', JSON.stringify(params))
const params = { ...setRecordParams() }
putawayRecordSubmit(params)
repleinshRecordSubmit(params)
.then((res) => {
uni.hideLoading()
if (res.data) {
showCommitSuccessMessage(`提交成功<br>生成采购上架记录<br>${res.data}`)
showCommitSuccessMessage(`提交成功<br>生成直接补料记录<br>${res.data}`)
} else {
showErrorMessage(`提交失败[${res.msg}]`)
}
@ -304,12 +360,12 @@ const getItemAndLocationRelations = () => {
}
const setRecordParams = () => {
const subList = []
const subList1 = []
const creator = store.id
detailSource.value.forEach((item) => {
item.subList.forEach((detail) => {
if (detail.scaned) {
const info = getPackingNumberAndBatchByList(managementList.value, detail.itemCode, detail.packingNumber, detail.toLocationCode, detail.batch)
const info = getPackingNumberAndBatchByList(managementL.valueist, detail.itemCode, detail.packingNumber, detail.toLocationCode, detail.batch)
const submitItem = deepCopyData(detail)
submitItem.toPackingNumber = info.packingNumber
submitItem.toBatch = info.batch
@ -326,19 +382,30 @@ const setRecordParams = () => {
// detail.toLocationCode = detail.toLocationCode
submitItem.qty = detail.handleQty
submitItem.package = ''
subList.push(submitItem)
submitItem.recordList = [
{
toInventoryStatus: detail.inventoryStatus,
fromPackingNumber: info.packingNumber,
fromBatch: info.batch,
toPackingNumber: info.packingNumber,
toBatch: info.batch,
fromLocationCode: detail.locationCode,
toLocationCode: detail.toLocationCode,
handleQty: detail.handleQty
}
]
subList1.push(submitItem)
}
})
})
if (subList.length > 0) {
dataContent.value.toWarehouseCode = subList[0].toWarehouseCode
if (subList1.length > 0) {
dataContent.value.toWarehouseCode = subList1[0].toWarehouseCode
}
dataContent.value.subList = subList
dataContent.value.subList = subList1
dataContent.value.creator = creator
dataContent.value.fromWarehouseCode = fromWarehouseCode.value
return dataContent.value
}
const showMessage = (message) => {
comMessageRef.value.showMessage(message, (res) => {
if (res) {
@ -351,7 +418,6 @@ const showErrorMessage = (message) => {
}
})
}
const showScanMessage = (message) => {
comMessageRef.value.showScanMessage(message)
}
@ -359,13 +425,14 @@ const showScanMessage = (message) => {
const afterCloseMessage = () => {
scanPopupGetFocus()
}
const closeScanMessage = () => {
scanPopupGetFocus()
}
const getLocation = (location, code) => {
getFromLocationCode(location, code)
}
const getFromLocationCode = (location, code) => {
fromLocationInfo.value = location
fromLocationCode.value = code
@ -387,9 +454,7 @@ const showCommitSuccessMessage = (hint) => {
clearData()
})
}
const updateData = () => {
// this.calcTreeHandleQty();
for (let i = 0; i < detailSource.value.length; i++) {
const item = detailSource.value[i]
if (item.qty == 0) {
@ -397,7 +462,6 @@ const updateData = () => {
}
}
}
const clearData = () => {
fromLocationInfo.value = {}
fromLocationCode.value = ''
@ -407,37 +471,4 @@ const clearData = () => {
}
</script>
<style scoped lang="scss">
page {
width: 100%;
height: 100%;
background-color: #fff;
}
.page-wraper {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
.page-main {
flex: 1;
position: relative;
}
.page-main-scroll {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.page-main-list {
/* height: 80rpx;
line-height: 80rpx; */
text-align: center;
background: #e0e0e0;
}
</style>
<style scoped lang="scss"></style>

7
src/pages/repleinsh/record/repleinshRecord.vue

@ -19,11 +19,8 @@
</view>
<view class="page-footer">
<view class="uni-flex u-col-center space-between padding_10" style="background-color: ghostwhite; width: 100%">
<view class=""> </view>
<view class="uni-flex uni-row">
<button class="btn_single_commit" hover-class="btn_commit_after" @click="submit">提交</button>
</view>
<view class="uni-flex u-col-center space-between padding_20" style="background-color: ghostwhite; width: 100%">
<button class="btn_single_commit" style="flex: 1" hover-class="btn_commit_after" @click="submit">提交</button>
</view>
</view>
<win-scan-button @goScan="openScanPopup"></win-scan-button>

2
src/pages/scrap/request/scrapRrequest.vue

@ -155,7 +155,7 @@ const updateOptions = (status) => {
} else if (status == '3') {
showOptions.value = detailAndHandleOption.value
} else if (status == '4') {
showOptions = detailAndAddAndCloseOption.value
showOptions.value = detailAndAddAndCloseOption.value
} else if (status == '5') {
showOptions.value = addAgainOption.value
} else {

2
src/pages/unPlanned/request/issueRequest.vue

@ -148,7 +148,7 @@ const updateOptions = (status) => {
} else if (status == '3') {
showOptions.value = detailAndHandleOption.value
} else if (status == '4') {
showOptions = detailAndAddAndCloseOption.value
showOptions.value = detailAndAddAndCloseOption.value
} else if (status == '5') {
showOptions.value = addAgainOption.value
} else {

2
src/pages/unPlanned/request/receiptRequest.vue

@ -144,7 +144,7 @@ const updateOptions = (status) => {
} else if (status == '3') {
showOptions.value = detailAndHandleOption.value
} else if (status == '4') {
showOptions = detailAndAddAndCloseOption.value
showOptions.value = detailAndAddAndCloseOption.value
} else if (status == '5') {
showOptions.value = addAgainOption.value
} else {

6
src/uni_modules/z-paging/changelog.md

@ -0,0 +1,6 @@
## 2.6.0(2023-10-17)
1.`修复` 在安卓中突然滚动到顶部可能出现的无法下拉刷新问题。
2.`修复` 在安卓中可能出现的列表卡住和无法下拉的问题。
3.`修复` 在安卓6.0以下系统中列表为空的问题。
4.`优化` 列表滚动-下拉刷新状态过渡细节。

34
src/uni_modules/z-paging/components/z-paging-cell/z-paging-cell.vue

@ -0,0 +1,34 @@
<!-- 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]">
<slot />
</cell>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<view :style="[cellStyle]">
<slot />
</view>
<!-- #endif -->
</template>
<script>
export default {
name: "z-paging-cell",
props: {
//cellStyle
cellStyle: {
type: Object,
default: function() {
return {}
}
}
}
}
</script>

162
src/uni_modules/z-paging/components/z-paging-empty-view/z-paging-empty-view.vue

@ -0,0 +1,162 @@
<!-- 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" :style="[emptyViewImgStyle]" :src="emptyImg" />
<image v-else class="zp-main-image" mode="aspectFit" :style="[emptyViewImgStyle]" :src="emptyViewImg" />
<text class="zp-main-title" :style="[emptyViewTitleStyle]">{{emptyViewText}}</text>
<text v-if="showEmptyViewReload" class="zp-main-error-btn" :style="[emptyViewReloadStyle]" @click.stop="reloadClick">{{emptyViewReloadText}}</text>
</view>
</view>
</template>
<script>
import zStatic from '../z-paging/js/z-paging-static'
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
}
},
computed: {
emptyImg() {
return this.isLoadFailed ? zStatic.base64Error : zStatic.base64Empty;
},
finalEmptyViewStyle(){
this.emptyViewStyle['z-index'] = this.emptyViewZIndex;
return this.emptyViewStyle;
}
},
methods: {
reloadClick() {
this.$emit('reload');
},
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 {
width: 200rpx;
height: 200rpx;
}
.zp-main-title {
font-size: 26rpx;
color: #aaaaaa;
text-align: center;
margin-top: 10rpx;
}
.zp-main-error-btn {
font-size: 26rpx;
padding: 8rpx 24rpx;
border: solid 1px #dddddd;
border-radius: 6rpx;
color: #aaaaaa;
margin-top: 50rpx;
}
</style>

143
src/uni_modules/z-paging/components/z-paging-swiper-item/z-paging-swiper-item.vue

@ -0,0 +1,143 @@
<!-- 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" style="height: 100%;">
<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'
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>

170
src/uni_modules/z-paging/components/z-paging-swiper/z-paging-swiper.vue

@ -0,0 +1,170 @@
<!-- 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'
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 = uni.getSystemInfoSync();
})
// #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-right{
right: 0;
}
.zp-swiper-item {
height: 100%;
}
</style>

141
src/uni_modules/z-paging/components/z-paging/components/z-paging-load-more.vue

@ -0,0 +1,141 @@
<!-- [z-paging]上拉加载更多view -->
<template>
<view class="zp-l-container" :style="[c.customStyle]" @click="doClick">
<template v-if="!c.hideContent">
<text v-if="c.showNoMoreLine&&finalStatus===M.NoMore" class="zp-l-line" :style="[{backgroundColor:zTheme.line[ts]},c.noMoreLineCustomStyle]" />
<!-- #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}" />
<image v-if="finalStatus===M.Loading&&finalLoadingIconType==='flower'&&!c.loadingIconCustomImage.length"
class="zp-line-loading-image" :style="[c.iconCustomStyle]" :src="zTheme.flower[ts]" />
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view>
<loading-indicator v-if="finalStatus===M.Loading&&finalLoadingIconType!=='circle'" class="zp-line-loading-image" :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" :style="[{borderColor:zTheme.circleBorder[ts],borderTopColor:zTheme.circleBorderTop[ts]},c.iconCustomStyle]" />
<text class="zp-l-text" :style="[{color:zTheme.title[ts]},c.titleCustomStyle]">{{ownLoadingMoreText}}</text>
<text v-if="c.showNoMoreLine&&finalStatus===M.NoMore" class="zp-l-line" :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() {
const statusTextArr = [this.c.defaultText,this.c.loadingText,this.c.noMoreText,this.c.failText];
return statusTextArr[this.finalStatus];
},
finalStatus() {
if (this.c.defaultAsLoading && this.c.status === this.M.Default) return this.M.Loading;
return this.c.status;
},
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 {
height: 80rpx;
font-size: 27rpx;
/* #ifndef APP-NVUE */
clear: both;
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
}
.zp-l-line-loading-custom-image {
color: #a4a4a4;
margin-right: 8rpx;
width: 28rpx;
height: 28rpx;
}
.zp-l-line-loading-custom-image-animated{
/* #ifndef APP-NVUE */
animation: loading-circle 1s linear infinite;
/* #endif */
}
.zp-l-circle-loading-view {
margin-right: 8rpx;
width: 23rpx;
height: 23rpx;
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-text {
/* #ifdef APP-NVUE */
font-size: 30rpx;
margin: 0rpx 10rpx;
/* #endif */
}
.zp-l-line {
height: 1px;
width: 100rpx;
margin: 0rpx 10rpx;
}
/* #ifndef APP-NVUE */
@keyframes loading-circle {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
/* #endif */
</style>

182
src/uni_modules/z-paging/components/z-paging/components/z-paging-refresh.vue

@ -0,0 +1,182 @@
<!-- [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}" :style="[leftImageStyle,imgStyle]" :src="leftImageSrc" />
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view v-else :style="[{'margin-right':showUpdateTime?'18rpx':'12rpx'}]">
<loading-indicator :class="isIos?'zp-loading-image-ios':'zp-loading-image-android'"
: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 zp-r-right-time-text" :style="[rightTextStyle,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,
isIos: uni.getSystemInfoSync().platform === 'ios',
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', 'defaultImg', 'pullingImg',
'refreshingImg', 'completeImg', 'refreshingAnimated', 'showUpdateTime', 'updateTimeKey', 'imgStyle', 'titleStyle', 'updateTimeStyle', 'updateTimeTextMap'
],
computed: {
ts() {
return this.defaultThemeStyle;
},
statusTextArr() {
this.updateTime();
return [this.defaultText,this.pullingText,this.refreshingText,this.completeText];
},
currentTitle() {
return this.statusTextArr[this.status] || this.defaultText;
},
leftImageClass() {
if (this.status === this.R.Complete) return 'zp-r-left-image-pre-size';
return `zp-r-left-image zp-r-left-image-pre-size ${this.status === this.R.Default ? 'zp-r-arrow-down' : 'zp-r-arrow-top'}`;
},
leftImageStyle() {
const showUpdateTime = this.showUpdateTime;
const size = showUpdateTime ? '36rpx' : '30rpx';
return {width: size,height: size,'margin-right': showUpdateTime ? '20rpx' : '9rpx'};
},
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];;
}
return '';
},
rightTextStyle() {
let stl = {};
// #ifdef APP-NVUE
const textHeight = this.showUpdateTime ? '40rpx' : '80rpx';
stl = {'height': textHeight, 'line-height': textHeight}
// #endif
stl['color'] = this.zTheme.title[this.ts];
return stl;
}
},
methods: {
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: 15rpx 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{
/* #ifndef APP-NVUE */
width: 30rpx;
height: 30rpx;
overflow: hidden;
/* #endif */
}
.zp-r-arrow-top {
transform: rotate(0deg);
}
.zp-r-arrow-down {
transform: rotate(180deg);
}
.zp-r-right {
font-size: 27rpx;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
align-items: center;
justify-content: center;
}
.zp-r-right-text {
/* #ifdef APP-NVUE */
font-size: 28rpx;
/* #endif */
}
.zp-r-right-time-text {
margin-top: 10rpx;
font-size: 24rpx;
}
</style>

3
src/uni_modules/z-paging/components/z-paging/config/index.js

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

228
src/uni_modules/z-paging/components/z-paging/css/z-paging-main.css

@ -0,0 +1,228 @@
/* [z-paging]公共css*/
.z-paging-content {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
width: 100%;
height: 100%;
overflow: hidden;
/* #endif */
flex-direction: column;
}
.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-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-custom-refresher-container {
overflow: hidden;
}
.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-right{
right: 0;
}
.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-container {
/* #ifndef APP-NVUE */
display: flex;
width: 100%;
/* #endif */
/* #ifdef APP-NVUE */
width: 750rpx;
/* #endif */
align-items: center;
justify-content: center;
height: 60rpx;
font-size: 26rpx;
}
.zp-chat-record-loading-custom-image {
width: 35rpx;
height: 35rpx;
/* #ifndef APP-NVUE */
animation: loading-flower 1s linear infinite;
/* #endif */
}
.zp-custom-refresher-container {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
}
.zp-back-to-top {
width: 76rpx;
height: 76rpx;
z-index: 999;
position: absolute;
bottom: 0rpx;
right: 25rpx;
transition-duration: .3s;
transition-property: opacity;
}
.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-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;
}

35
src/uni_modules/z-paging/components/z-paging/css/z-paging-static.css

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

22
src/uni_modules/z-paging/components/z-paging/i18n/en.json

@ -0,0 +1,22 @@
{
"zp.refresher.default": "Pull down to refresh",
"zp.refresher.pulling": "Release to refresh",
"zp.refresher.refreshing": "Refreshing...",
"zp.refresher.complete": "Refresh succeeded",
"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..."
}

8
src/uni_modules/z-paging/components/z-paging/i18n/index.js

@ -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
}

22
src/uni_modules/z-paging/components/z-paging/i18n/zh-Hans.json

@ -0,0 +1,22 @@
{
"zp.refresher.default": "继续下拉刷新",
"zp.refresher.pulling": "松开立即刷新",
"zp.refresher.refreshing": "正在刷新...",
"zp.refresher.complete": "刷新成功",
"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": "加载中..."
}

22
src/uni_modules/z-paging/components/z-paging/i18n/zh-Hant.json

@ -0,0 +1,22 @@
{
"zp.refresher.default": "繼續下拉重繪",
"zp.refresher.pulling": "鬆開立即重繪",
"zp.refresher.refreshing": "正在重繪...",
"zp.refresher.complete": "重繪成功",
"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": "加載中..."
}

25
src/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js

@ -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) return;
cPaging.value.reload().catch(() => {});
})
onPageScroll(e => {
if (!cPaging) return;
cPaging.value.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && cPaging.value.doChatRecordLoadMore();
})
onReachBottom(() => {
if (!cPaging) return;
cPaging.value.pageReachBottom();
})
}
export default useZPaging

26
src/uni_modules/z-paging/components/z-paging/js/hooks/useZPagingComp.js

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

100
src/uni_modules/z-paging/components/z-paging/js/modules/back-to-top.js

@ -0,0 +1,100 @@
// [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: function() {
return u.gc('backToTopStyle', {});
},
},
//iOS点击顶部状态栏、安卓双击标题栏时,滚动条返回顶部,只支持竖向,默认为是
enableBackToTop: {
type: Boolean,
default: u.gc('enableBackToTop', true)
},
},
data() {
return {
backToTopClass: 'zp-back-to-top zp-back-to-top-hide',
lastBackToTopShowTime: 0,
showBackToTopClass: false,
}
},
computed: {
finalEnableBackToTop() {
return this.usePageScroll ? false : this.enableBackToTop;
},
finalBackToTopThreshold() {
return u.convertToPx(this.backToTopThreshold);
},
finalBackToTopStyle() {
const backToTopStyle = this.backToTopStyle;
if (!backToTopStyle.bottom) {
backToTopStyle.bottom = this.windowBottom + u.convertToPx(this.backToTopBottom) + 'px';
}
if(!backToTopStyle.position){
backToTopStyle.position = this.usePageScroll ? 'fixed': 'absolute';
}
return backToTopStyle;
},
},
methods: {
//点击返回顶部
_backToTopClick() {
!this.backToTopWithAnimate && this._checkShouldShowBackToTop(0);
this.scrollToTop(this.backToTopWithAnimate);
},
//判断是否要显示返回顶部按钮
_checkShouldShowBackToTop(scrollTop) {
if (!this.autoShowBackToTop) {
this.showBackToTopClass = false;
return;
}
if (scrollTop > this.finalBackToTopThreshold) {
if (!this.showBackToTopClass) {
this.showBackToTopClass = true;
this.lastBackToTopShowTime = new Date().getTime();
u.delay(() => {
this.backToTopClass = 'zp-back-to-top zp-back-to-top-show';
}, 300)
}
} else {
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)
}
}
},
}
}

116
src/uni_modules/z-paging/components/z-paging/js/modules/common-layout.js

@ -0,0 +1,116 @@
// [z-paging]通用布局相关模块
// #ifdef APP-NVUE
const weexDom = weex.requireModule('dom');
// #endif
export default {
data() {
return {
systemInfo: null,
cssSafeAreaInsetBottom: -1,
}
},
computed: {
windowTop() {
if (!this.systemInfo) return 0;
//暂时修复vue3中隐藏系统导航栏后windowTop获取不正确的问题,具体bug详见https://ask.dcloud.net.cn/question/141634
//感谢litangyu!!https://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;
},
isOldWebView() {
// #ifndef APP-NVUE || MP-KUAISHOU
try {
const systemInfos = uni.getSystemInfoSync().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;
},
zSlots() {
// #ifdef VUE2
// #ifdef MP-ALIPAY
return this.$slots;
// #endif
return this.$scopedSlots || this.$slots;
// #endif
return this.$slots;
}
},
methods: {
//获取节点尺寸
_getNodeClientRect(select, inDom = true, scrollOffset = false) {
// #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
//#ifdef MP-ALIPAY
inDom = false;
//#endif
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距离
_getCssSafeAreaInsetBottom(success) {
this._getNodeClientRect('.zp-safe-area-inset-bottom').then(res => {
this.cssSafeAreaInsetBottom = res ? res[0].height : -1;
res && success && success();
});
}
}
}

741
src/uni_modules/z-paging/components/z-paging/js/modules/data-handle.js

@ -0,0 +1,741 @@
// [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, String],
default: u.gc('defaultPageNo', 1),
observer: function(newVal) {
this.pageNo = newVal;
},
},
//自定义pageSize,默认为10
defaultPageSize: {
type: [Number, String],
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: function() {
return 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', '')
},
//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)
},
//使用聊天记录模式,默认为否
useChatRecordMode: {
type: Boolean,
default: u.gc('useChatRecordMode', false)
},
//使用聊天记录模式时是否自动隐藏键盘:在用户触摸列表时候自动隐藏键盘,默认为是
autoHideKeyboardWhenChat: {
type: Boolean,
default: u.gc('autoHideKeyboardWhenChat', true)
},
//自动拼接complete中传过来的数组(使用聊天记录模式时无效)
concat: {
type: Boolean,
default: u.gc('concat', 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
}
},
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);
},
currentData(newVal, oldVal) {
this._currentDataChange(newVal, oldVal);
},
useChatRecordMode(newVal, oldVal) {
if (newVal) {
this.nLoadingMoreFixedHeight = false;
}
},
value: {
handler(newVal) {
this.realTotalData = newVal;
},
immediate: true
},
// #ifdef VUE3
modelValue: {
handler(newVal) {
this.realTotalData = 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;
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);
},
//与上方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) {
data = Object.prototype.toString.call(data) !== '[object Array]' ? [data] : data.reverse();
// #ifndef APP-NVUE
this.finalUseVirtualList && this._setCellIndex(data, 'top')
// #endif
this.totalData = [...data, ...this.totalData];
if (toTop) {
u.delay(() => 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;
},
//添加聊天记录
addChatRecordData(data, toBottom = true, toBottomWithAnimate = true) {
data = Object.prototype.toString.call(data) !== '[object Array]' ? [data] : data;
if (!this.useChatRecordMode) return;
this.isTotalChangeFromAddData = true;
//#ifndef APP-NVUE
this.totalData = [...this.totalData, ...data];
//#endif
//#ifdef APP-NVUE
this.totalData = this.nIsFirstPageAndNoMore ? [...this.totalData, ...data] : [...data, ...this.totalData];
//#endif
if (toBottom) {
u.delay(() => {
//#ifndef APP-NVUE
this._scrollToBottom(toBottomWithAnimate);
//#endif
//#ifdef APP-NVUE
this.nIsFirstPageAndNoMore ? this._scrollToBottom(toBottomWithAnimate) : this._scrollToTop(toBottomWithAnimate);
//#endif
})
}
},
//设置本地分页数据,请求结束(成功或者失败)调用此方法,将请求的结果传递给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();
},
//手动触发滚动到顶部加载更多,聊天记录模式时有效
doChatRecordLoadMore() {
this.useChatRecordMode && this._onLoadingMore('click');
},
//reload之前的一些处理
_preReload(animate = this.showRefresherWhenReload, isFromMounted = true) {
const showRefresher = this.finalRefresherEnabled && this.useCustomRefresher;
// #ifndef APP-NVUE
if (this.customRefresherHeight === -1 && showRefresher) {
u.delay(() => this._preReload(animate, isFromMounted), 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;
}
if (!this.isFirstPage) {
this.listRendering = true;
this.$nextTick(() => {
u.delay(() => this.listRendering = false);
})
} else {
this.listRendering = false;
}
let dataTypeRes = this._checkDataType(data, success, isLocal);
data = dataTypeRes.data;
success = dataTypeRes.success;
let delayTime = c.delayTime;
// #ifdef APP-NVUE
if (this.useChatRecordMode) delayTime = 0;
// #endif
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.loadingStatus === Enum.More.NoMore)) {
this.loadingStatus = Enum.More.Default;
}
if (isLocal) {
this.totalLocalPagingList = data;
const localPageNo = this.defaultPageNo;
const localPageSize = this.queryFrom !== Enum.QueryFrom.Refresh ? this.defaultPageSize : this.currentRefreshPageSize;
this._localPagingQueryList(localPageNo, localPageSize, 0, res => {
this.completeByTotal(res, this.totalLocalPagingList.length);
})
} else {
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.LoadingMore) {
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;
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(()=>{
this._getNodeClientRect('.zp-paging-container-content').then(res => {
res && this.$emit('contentHeightChanged', res[0].height);
});
}, c.delayTime * (this.isIos ? 1 : 3))
// #ifdef APP-NVUE
if (this.useChatRecordMode && this.nIsFirstPageAndNoMore && this.isFirstPage && !this.nFirstPageAndNoMoreChecked) {
this.nFirstPageAndNoMoreChecked = true;
this._scrollToBottom(false);
}
u.delay(() => {
this.nShowBottom = true;
}, c.delayTime * 6, 'nShowBottomDelay');
// #endif
})
},
//当前数据改变时调用
_currentDataChange(newVal, oldVal) {
newVal = [...newVal];
// #ifndef APP-NVUE
this.finalUseVirtualList && this._setCellIndex(newVal, 'bottom');
this.useChatRecordMode && newVal.reverse();
// #endif
if (this.isFirstPage && this.finalConcat) {
this.totalData = [];
}
if (this.customNoMore !== -1) {
if (this.customNoMore === 1 || !newVal.length) {
this.loadingStatus = Enum.More.NoMore;
}
} else {
if (!newVal.length || (newVal.length && newVal.length < this.defaultPageSize)) {
this.loadingStatus = Enum.More.NoMore;
}
}
if (!this.totalData.length) {
if (this.finalConcat) {
// #ifdef APP-NVUE
if (this.useChatRecordMode && this.isFirstPage && this.loadingStatus === Enum.More.NoMore) {
newVal.reverse();
}
// #endif
this.totalData = newVal;
}
if (this.useChatRecordMode) {
// #ifndef APP-NVUE
this.$nextTick(() => {
this._scrollToBottom(false);
})
// #endif
}
} else {
if (this.useChatRecordMode) {
// #ifdef APP-NVUE
this.totalData = [...this.totalData, ...newVal];
// #endif
//#ifndef APP-NVUE
const idIndex = newVal.length;
let idIndexStr = `z-paging-${idIndex}`;
this.totalData = [...newVal, ...this.totalData];
if (this.pageNo !== this.defaultPageNo) {
this.privateScrollWithAnimation = 0;
this.$emit('update:chatIndex', idIndex);
this.$nextTick(() => {
this._scrollIntoView(idIndexStr, 30 + Math.max(0, this.cacheTopHeight), false, () => {
this.$emit('update:chatIndex', 0);
});
})
} else {
this.$nextTick(() => {
this._scrollToBottom(false);
})
}
//#endif
} 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.realTotalData.length) return this.reload();
if (pageNo >= 1) {
this.loading = true;
this.privateConcat = false;
const totalPageSize = pageNo * this.pageSize;
this.currentRefreshPageSize = totalPageSize;
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);
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) break;
success ? obj.resolve({ totalList, noMore: this.loadingStatus === Enum.More.NoMore }) : 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 };
},
}
}

147
src/uni_modules/z-paging/components/z-paging/js/modules/empty.js

@ -0,0 +1,147 @@
// [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: function() {
return u.gc('emptyViewStyle', {});
}
},
//空数据图容器样式
emptyViewSuperStyle: {
type: Object,
default: function() {
return u.gc('emptyViewSuperStyle', {});
}
},
//空数据图img样式
emptyViewImgStyle: {
type: Object,
default: function() {
return u.gc('emptyViewImgStyle', {});
}
},
//空数据图描述文字样式
emptyViewTitleStyle: {
type: Object,
default: function() {
return u.gc('emptyViewTitleStyle', {});
}
},
//空数据图重新加载按钮样式
emptyViewReloadStyle: {
type: Object,
default: function() {
return 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)
},
},
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');
},
}
}

101
src/uni_modules/z-paging/components/z-paging/js/modules/i18n.js

@ -0,0 +1,101 @@
// [z-paging]i18n模块
import { initVueI18n } from '@dcloudio/uni-i18n'
import messages from '../../i18n/index.js'
const { t } = initVueI18n(messages)
import u from '.././z-paging-utils'
import c from '.././z-paging-constant'
import interceptor from '../z-paging-interceptor'
const language = uni.getSystemInfoSync().language;
export default {
data() {
return {
language
}
},
computed: {
finalLanguage() {
try {
const local = uni.getLocale();
const language = this.language;
return local === 'auto' ? interceptor._handleLanguage2Local(language, this._language2Local(language)) : local;
} catch (e) {
return 'zh-Hans';
}
},
finalRefresherDefaultText() {
return this._getI18nText('zp.refresher.default', this.refresherDefaultText);
},
finalRefresherPullingText() {
return this._getI18nText('zp.refresher.pulling', this.refresherPullingText);
},
finalRefresherRefreshingText() {
return this._getI18nText('zp.refresher.refreshing', this.refresherRefreshingText);
},
finalRefresherCompleteText() {
return this._getI18nText('zp.refresher.complete', this.refresherCompleteText);
},
finalRefresherUpdateTimeTextMap() {
return {
title: t('zp.refresherUpdateTime.title'),
none: t('zp.refresherUpdateTime.none'),
today: t('zp.refresherUpdateTime.today'),
yesterday: t('zp.refresherUpdateTime.yesterday')
};
},
finalLoadingMoreDefaultText() {
return this._getI18nText('zp.loadingMore.default', this.loadingMoreDefaultText);
},
finalLoadingMoreLoadingText() {
return this._getI18nText('zp.loadingMore.loading', this.loadingMoreLoadingText);
},
finalLoadingMoreNoMoreText() {
return this._getI18nText('zp.loadingMore.noMore', this.loadingMoreNoMoreText);
},
finalLoadingMoreFailText() {
return this._getI18nText('zp.loadingMore.fail', this.loadingMoreFailText);
},
finalEmptyViewText() {
return this.isLoadFailed ? this.finalEmptyViewErrorText : this._getI18nText('zp.emptyView.title', this.emptyViewText);
},
finalEmptyViewReloadText() {
return this._getI18nText('zp.emptyView.reload', this.emptyViewReloadText);
},
finalEmptyViewErrorText() {
return this._getI18nText('zp.emptyView.error', this.emptyViewErrorText);
},
finalSystemLoadingText() {
return this._getI18nText('zp.systemLoading.title', this.systemLoadingText);
},
},
methods: {
//获取当前z-paging的语言
getLanguage() {
return this.finalLanguage;
},
//获取国际化转换后的文本
_getI18nText(key, value) {
const dataType = Object.prototype.toString.call(value);
if (dataType === '[object Object]') {
const nextValue = value[this.finalLanguage];
if (nextValue) return nextValue;
} else if (dataType === '[object String]') {
return value;
}
return t(key);
},
//系统language转i18n local
_language2Local(language) {
const formatedLanguage = language.toLowerCase().replace(new RegExp('_', ''), '-');
if (formatedLanguage.indexOf('zh') !== -1) {
if (formatedLanguage === 'zh' || formatedLanguage === 'zh-cn' || formatedLanguage.indexOf('zh-hans') !== -1) {
return 'zh-Hans';
}
return 'zh-Hant';
}
if (formatedLanguage.indexOf('en') !== -1) return 'en';
return language;
}
}
}

315
src/uni_modules/z-paging/components/z-paging/js/modules/load-more.js

@ -0,0 +1,315 @@
// [z-paging]滚动到底部加载更多模块
import u from '.././z-paging-utils'
import Enum from '.././z-paging-enum'
export default {
props: {
//自定义底部加载更多样式
loadingMoreCustomStyle: {
type: Object,
default: function() {
return u.gc('loadingMoreCustomStyle', {});
}
},
//自定义底部加载更多文字样式
loadingMoreTitleCustomStyle: {
type: Object,
default: function() {
return u.gc('loadingMoreTitleCustomStyle', {});
}
},
//自定义底部加载更多加载中动画样式
loadingMoreLoadingIconCustomStyle: {
type: Object,
default: function() {
return u.gc('loadingMoreLoadingIconCustomStyle', {});
}
},
//自定义底部加载更多加载中动画图标类型,可选flower或circle,默认为flower
loadingMoreLoadingIconType: {
type: String,
default: u.gc('loadingMoreLoadingIconType', 'flower')
},
//自定义底部加载更多加载中动画图标图片
loadingMoreLoadingIconCustomImage: {
type: String,
default: u.gc('loadingMoreLoadingIconCustomImage', '')
},
//底部加载更多加载中view是否展示旋转动画,默认为是
loadingMoreLoadingAnimated: {
type: Boolean,
default: u.gc('loadingMoreLoadingAnimated', true)
},
//是否启用加载更多数据(含滑动到底部加载更多数据和点击加载更多数据),默认为是
loadingMoreEnabled: {
type: Boolean,
default: u.gc('loadingMoreEnabled', true)
},
//是否启用滑动到底部加载更多数据,默认为是
toBottomLoadingMoreEnabled: {
type: Boolean,
default: u.gc('toBottomLoadingMoreEnabled', true)
},
//滑动到底部状态为默认状态时,以加载中的状态展示,默认为否。若设置为是,可避免滚动到底部看到默认状态然后立刻变为加载中状态的问题,但分页数量未超过一屏时,不会显示【点击加载更多】
loadingMoreDefaultAsLoading: {
type: [Boolean],
default: u.gc('loadingMoreDefaultAsLoading', false)
},
//滑动到底部"默认"文字,默认为【点击加载更多】
loadingMoreDefaultText: {
type: [String, Object],
default: u.gc('loadingMoreDefaultText', null)
},
//滑动到底部"加载中"文字,默认为【正在加载...】
loadingMoreLoadingText: {
type: [String, Object],
default: u.gc('loadingMoreLoadingText', null)
},
//滑动到底部"没有更多"文字,默认为【没有更多了】
loadingMoreNoMoreText: {
type: [String, Object],
default: u.gc('loadingMoreNoMoreText', null)
},
//滑动到底部"加载失败"文字,默认为【加载失败,点击重新加载】
loadingMoreFailText: {
type: [String, Object],
default: u.gc('loadingMoreFailText', null)
},
//当没有更多数据且分页内容未超出z-paging时是否隐藏没有更多数据的view,默认为否
hideNoMoreInside: {
type: Boolean,
default: u.gc('hideNoMoreInside', false)
},
//当没有更多数据且分页数组长度少于这个值时,隐藏没有更多数据的view,默认为0,代表不限制。
hideNoMoreByLimit: {
type: Number,
default: u.gc('hideNoMoreByLimit', 0)
},
//是否显示默认的加载更多text,默认为是
showDefaultLoadingMoreText: {
type: Boolean,
default: u.gc('showDefaultLoadingMoreText', true)
},
//是否显示没有更多数据的view
showLoadingMoreNoMoreView: {
type: Boolean,
default: u.gc('showLoadingMoreNoMoreView', true)
},
//是否显示没有更多数据的分割线,默认为是
showLoadingMoreNoMoreLine: {
type: Boolean,
default: u.gc('showLoadingMoreNoMoreLine', true)
},
//自定义底部没有更多数据的分割线样式
loadingMoreNoMoreLineCustomStyle: {
type: Object,
default: function() {
return u.gc('loadingMoreNoMoreLineCustomStyle', {});
},
},
//当分页未满一屏时,是否自动加载更多,默认为否(nvue无效)
insideMore: {
type: Boolean,
default: u.gc('insideMore', false)
},
//距底部/右边多远时(单位px),触发 scrolltolower 事件,默认为100rpx
lowerThreshold: {
type: [Number, String],
default: u.gc('lowerThreshold', '100rpx')
},
},
data() {
return {
M: Enum.More,
//底部加载更多状态
loadingStatus: Enum.More.Default,
loadingStatusAfterRender: Enum.More.Default,
loadingMoreTimeStamp: 0,
loadingMoreDefaultSlot: null,
showLoadingMore: false,
customNoMore: -1,
}
},
computed: {
zLoadMoreConfig() {
return {
status: this.loadingStatusAfterRender,
defaultAsLoading: this.loadingMoreDefaultAsLoading,
defaultThemeStyle: this.finalLoadingMoreThemeStyle,
customStyle: this.loadingMoreCustomStyle,
titleCustomStyle: this.loadingMoreTitleCustomStyle,
iconCustomStyle: this.loadingMoreLoadingIconCustomStyle,
loadingIconType: this.loadingMoreLoadingIconType,
loadingIconCustomImage: this.loadingMoreLoadingIconCustomImage,
loadingAnimated: this.loadingMoreLoadingAnimated,
showNoMoreLine: this.showLoadingMoreNoMoreLine,
noMoreLineCustomStyle: this.loadingMoreNoMoreLineCustomStyle,
defaultText: this.finalLoadingMoreDefaultText,
loadingText: this.finalLoadingMoreLoadingText,
noMoreText: this.finalLoadingMoreNoMoreText,
failText: this.finalLoadingMoreFailText,
hideContent: !this.loadingMoreDefaultAsLoading && this.listRendering,
};
},
finalLoadingMoreThemeStyle() {
return this.loadingMoreThemeStyle.length ? this.loadingMoreThemeStyle : this.defaultThemeStyle;
},
showLoadingMoreDefault() {
return this._showLoadingMore('Default');
},
showLoadingMoreLoading() {
return this._showLoadingMore('Loading');
},
showLoadingMoreNoMore() {
return this._showLoadingMore('NoMore');
},
showLoadingMoreFail() {
return this._showLoadingMore('Fail');
},
showLoadingMoreCustom() {
return this._showLoadingMore('Custom');
}
},
methods: {
//页面滚动到底部时通知z-paging进行进一步处理
pageReachBottom() {
!this.useChatRecordMode && this._onLoadingMore('toBottom');
},
//手动触发上拉加载更多(非必须,可依据具体需求使用)
doLoadMore(type) {
this._onLoadingMore(type);
},
//通过@scroll事件检测是否滚动到了底部
_checkScrolledToBottom(scrollDiff, checked = false) {
if (this.cacheScrollNodeHeight === -1) {
this._getNodeClientRect('.zp-scroll-view').then((res) => {
if (res) {
const pageScrollNodeHeight = res[0].height;
this.cacheScrollNodeHeight = pageScrollNodeHeight;
if (scrollDiff - pageScrollNodeHeight <= this.finalLowerThreshold) {
this._onLoadingMore('toBottom');
}
}
});
} else {
if (scrollDiff - this.cacheScrollNodeHeight <= this.finalLowerThreshold) {
this._onLoadingMore('toBottom');
} else if (scrollDiff - this.cacheScrollNodeHeight <= 500 && !checked) {
u.delay(() => {
this._getNodeClientRect('.zp-scroll-view', true, true).then((res) => {
this.oldScrollTop = res[0].scrollTop;
const newScrollDiff = res[0].scrollHeight - this.oldScrollTop;
this._checkScrolledToBottom(newScrollDiff, true);
})
}, 150, 'checkScrolledToBottomDelay')
}
}
},
//触发加载更多时调用,from:toBottom-滑动到底部触发;1、click-点击加载更多触发
_onLoadingMore(from = 'click') {
if (this.isIos && from === 'toBottom' && !this.scrollToBottomBounceEnabled && this.scrollEnable) {
this.scrollEnable = false;
this.$nextTick(() => {
this.scrollEnable = true;
})
}
this.$emit('scrolltolower', from);
if (from === 'toBottom' && (!this.toBottomLoadingMoreEnabled || this.useChatRecordMode)) return;
if (this.refresherOnly || !this.loadingMoreEnabled || !(this.loadingStatus === Enum.More.Default || this.loadingStatus === Enum.More.Fail) || this.loading) return;
// #ifdef MP-WEIXIN
if (!this.isIos && !this.refresherOnly && !this.usePageScroll) {
const currentTimestamp = u.getTime();
if (this.loadingMoreTimeStamp > 0 && currentTimestamp - this.loadingMoreTimeStamp < 100) {
this.loadingMoreTimeStamp = 0;
return;
}
}
// #endif
this._doLoadingMore();
},
//处理开始加载更多
_doLoadingMore() {
if (this.pageNo >= this.defaultPageNo && this.loadingStatus !== Enum.More.NoMore) {
this.pageNo ++;
this._startLoading(false);
if (this.isLocalPaging) {
this._localPagingQueryList(this.pageNo, this.defaultPageSize, this.localPagingLoadingTime, res => {
this.completeByTotal(res, this.totalLocalPagingList.length);
})
} else {
this._emitQuery(this.pageNo, this.defaultPageSize, Enum.QueryFrom.LoadingMore);
this._callMyParentQuery();
}
this.loadingType = Enum.LoadingType.LoadingMore;
}
},
//(预处理)判断当没有更多数据且分页内容未超出z-paging时是否显示没有更多数据的view
_preCheckShowNoMoreInside(newVal, scrollViewNode, pagingContainerNode) {
if (this.loadingStatus === Enum.More.NoMore && this.hideNoMoreByLimit > 0 && newVal.length) {
this.showLoadingMore = newVal.length > this.hideNoMoreByLimit;
} else if ((this.loadingStatus === Enum.More.NoMore && this.hideNoMoreInside && newVal.length) || (this.insideMore && this.insideOfPaging !== false && newVal.length)) {
this.$nextTick(() => {
this._checkShowNoMoreInside(newVal, scrollViewNode, pagingContainerNode);
})
if (this.insideMore && this.insideOfPaging !== false && newVal.length) {
this.showLoadingMore = newVal.length;
}
} else {
this.showLoadingMore = newVal.length;
}
},
//判断当没有更多数据且分页内容未超出z-paging时是否显示没有更多数据的view
async _checkShowNoMoreInside(totalData, oldScrollViewNode, oldPagingContainerNode) {
try {
const scrollViewNode = oldScrollViewNode || await this._getNodeClientRect('.zp-scroll-view');
if (this.usePageScroll) {
if (scrollViewNode) {
const scrollViewTotalH = scrollViewNode[0].top + scrollViewNode[0].height;
this.insideOfPaging = scrollViewTotalH < this.windowHeight;
if (this.hideNoMoreInside) {
this.showLoadingMore = !this.insideOfPaging;
}
this._updateInsideOfPaging();
}
} else {
const pagingContainerNode = oldPagingContainerNode || await this._getNodeClientRect('.zp-paging-container-content');
const pagingContainerH = pagingContainerNode ? pagingContainerNode[0].height : 0;
const scrollViewH = scrollViewNode ? scrollViewNode[0].height : 0;
this.insideOfPaging = pagingContainerH < scrollViewH;
if (this.hideNoMoreInside) {
this.showLoadingMore = !this.insideOfPaging;
}
this._updateInsideOfPaging();
}
} catch (e) {
this.insideOfPaging = !totalData.length;
if (this.hideNoMoreInside) {
this.showLoadingMore = !this.insideOfPaging;
}
this._updateInsideOfPaging();
}
},
//是否要展示上拉加载更多view
_showLoadingMore(type) {
if (!this.showLoadingMoreWhenReload && (!(this.loadingStatus === Enum.More.Default ? this.nShowBottom : true) || !this.realTotalData.length)) return false;
if (((!this.showLoadingMoreWhenReload || this.isUserPullDown || this.loadingStatus !== Enum.More.Loading) && !this.showLoadingMore) ||
(!this.loadingMoreEnabled && (!this.showLoadingMoreWhenReload || this.isUserPullDown || this.loadingStatus !== Enum.More.Loading)) || this.refresherOnly) {
return false;
}
if (this.useChatRecordMode && type !== 'Loading') return false;
if (!this.$slots) return false;
if (type === 'Custom') {
return this.showDefaultLoadingMoreText && !(this.loadingStatus === Enum.More.NoMore && !this.showLoadingMoreNoMoreView);
}
const res = this.loadingStatus === Enum.More[type] && this.$slots[`loadingMore${type}`] && (type === 'NoMore' ? this.showLoadingMoreNoMoreView : true);
if (res) {
// #ifdef APP-NVUE
if (!this.isIos) {
this.nLoadingMoreFixedHeight = false;
}
// #endif
}
return res;
},
}
}

93
src/uni_modules/z-paging/components/z-paging/js/modules/loading.js

@ -0,0 +1,93 @@
// [z-paging]loading相关模块
import u from '.././z-paging-utils'
import Enum from '.././z-paging-enum'
export default {
props: {
//第一次加载后自动隐藏loading slot,默认为是
autoHideLoadingAfterFirstLoaded: {
type: Boolean,
default: u.gc('autoHideLoadingAfterFirstLoaded', true)
},
//loading slot是否铺满屏幕并固定,默认为否
loadingFullFixed: {
type: Boolean,
default: u.gc('loadingFullFixed', false)
},
//是否自动显示系统Loading:即uni.showLoading,若开启则将在刷新列表时(调用reload、refresh时)显示,下拉刷新和滚动到底部加载更多不会显示,默认为false。
autoShowSystemLoading: {
type: Boolean,
default: u.gc('autoShowSystemLoading', false)
},
//显示系统Loading时是否显示透明蒙层,防止触摸穿透,默认为是(H5、App、微信小程序、百度小程序有效)
systemLoadingMask: {
type: Boolean,
default: u.gc('systemLoadingMask', true)
},
//显示系统Loading时显示的文字,默认为"加载中"
systemLoadingText: {
type: [String, Object],
default: u.gc('systemLoadingText', null)
},
},
data() {
return {
loading: false,
loadingForNow: false,
}
},
watch: {
loadingStatus(newVal) {
this.$emit('loadingStatusChange', newVal);
this.$nextTick(() => {
this.loadingStatusAfterRender = newVal;
})
// #ifdef APP-NVUE
if (this.useChatRecordMode) {
if (this.pageNo === this.defaultPageNo && newVal === Enum.More.NoMore) {
this.nIsFirstPageAndNoMore = true;
return;
}
}
this.nIsFirstPageAndNoMore = false;
// #endif
},
loading(newVal){
if (newVal) {
this.loadingForNow = newVal;
}
},
},
computed: {
showLoading() {
if (this.firstPageLoaded || !this.loading || !this.loadingForNow) return false;
if (this.finalShowSystemLoading){
uni.showLoading({
title: this.finalSystemLoadingText,
mask: this.systemLoadingMask
})
}
return this.autoHideLoadingAfterFirstLoaded ? (this.fromEmptyViewReload ? true : !this.pagingLoaded) : this.loadingType === Enum.LoadingType.Refresher;
},
finalShowSystemLoading() {
return this.autoShowSystemLoading && this.loadingType === Enum.LoadingType.Refresher;
}
},
methods: {
//处理开始加载更多状态
_startLoading(isReload = false) {
if ((this.showLoadingMoreWhenReload && !this.isUserPullDown) || !isReload) {
this.loadingStatus = Enum.More.Loading;
}
this.loading = true;
},
//停止系统loading和refresh
_endSystemLoadingAndRefresh(){
this.finalShowSystemLoading && uni.hideLoading();
!this.useCustomRefresher && uni.stopPullDownRefresh();
// #ifdef APP-NVUE
this.usePageScroll && uni.stopPullDownRefresh();
// #endif
}
}
}

249
src/uni_modules/z-paging/components/z-paging/js/modules/nvue.js

@ -0,0 +1,249 @@
// [z-paging]nvue独有部分模块
import u from '.././z-paging-utils'
import c from '.././z-paging-constant'
import Enum from '.././z-paging-enum'
// #ifdef APP-NVUE
const weexAnimation = weex.requireModule('animation');
// #endif
export default {
props: {
// #ifdef APP-NVUE
//nvue中修改列表类型,可选值有list、waterfall和scroller,默认为list
nvueListIs: {
type: String,
default: u.gc('nvueListIs', 'list')
},
//nvue waterfall配置,仅在nvue中且nvueListIs=waterfall时有效,配置参数详情参见:https://uniapp.dcloud.io/component/waterfall
nvueWaterfallConfig: {
type: Object,
default: function() {
return u.gc('nvueWaterfallConfig', {});
}
},
//nvue 控制是否回弹效果,iOS不支持动态修改
nvueBounce: {
type: Boolean,
default: u.gc('nvueBounce', true)
},
//nvue中通过代码滚动到顶部/底部时,是否加快动画效果(无滚动动画时无效),默认为否
nvueFastScroll: {
type: Boolean,
default: u.gc('nvueFastScroll', false)
},
//nvue中list的id
nvueListId: {
type: String,
default: u.gc('nvueListId', '')
},
//nvue中refresh组件的样式
nvueRefresherStyle: {
type: Object,
default: function() {
return u.gc('nvueRefresherStyle', {});
}
},
//nvue中是否按分页模式(类似竖向swiper)显示List,默认为false
nvuePagingEnabled: {
type: Boolean,
default: u.gc('nvuePagingEnabled', false)
},
//是否隐藏nvue列表底部的tagView,此view用于标识滚动到底部位置,若隐藏则滚动到底部功能将失效,在nvue中实现吸顶+swiper功能时需将最外层z-paging的此属性设置为true。默认为否
hideNvueBottomTag: {
type: Boolean,
default: u.gc('hideNvueBottomTag', false)
},
//nvue中控制onscroll事件触发的频率:表示两次onscroll事件之间列表至少滚动了10px。注意,将该值设置为较小的数值会提高滚动事件采样的精度,但同时也会降低页面的性能
offsetAccuracy: {
type: Number,
default: u.gc('offsetAccuracy', 10)
},
// #endif
},
data() {
return {
nRefresherLoading: false,
nListIsDragging: false,
nShowBottom: true,
nFixFreezing: false,
nShowRefresherReveal: false,
nIsFirstPageAndNoMore: false,
nFirstPageAndNoMoreChecked: false,
nLoadingMoreFixedHeight: false,
nShowRefresherRevealHeight: 0,
nOldShowRefresherRevealHeight: -1,
nRefresherWidth: uni.upx2px(750),
}
},
watch: {
// #ifdef APP-NVUE
nIsFirstPageAndNoMore: {
handler(newVal) {
const cellStyle = !this.useChatRecordMode || newVal ? {} : { transform: 'rotate(180deg)' };
this.$emit('update:cellStyle', cellStyle);
this.$emit('cellStyleChange', cellStyle);
},
immediate: true
},
// #endif
},
computed: {
// #ifdef APP-NVUE
nScopedSlots() {
// #ifdef VUE2
return this.$scopedSlots;
// #endif
// #ifdef VUE3
return null;
// #endif
},
nWaterfallColumnCount() {
if (this.finalNvueListIs !== 'waterfall') return 0;
return this._nGetWaterfallConfig('column-count', 2);
},
nWaterfallColumnWidth() {
return this._nGetWaterfallConfig('column-width', 'auto');
},
nWaterfallColumnGap() {
return this._nGetWaterfallConfig('column-gap', 'normal');
},
nWaterfallLeftGap() {
return this._nGetWaterfallConfig('left-gap', 0);
},
nWaterfallRightGap() {
return this._nGetWaterfallConfig('right-gap', 0);
},
nViewIs() {
const is = this.finalNvueListIs;
return is === 'scroller' || is === 'view' ? 'view' : is === 'waterfall' ? 'header' : 'cell';
},
nSafeAreaBottomHeight() {
return this.safeAreaInsetBottom ? this.safeAreaBottom : 0;
},
nChatRecordRotateStyle() {
return this.useChatRecordMode ? { transform: this.nIsFirstPageAndNoMore ? 'rotate(0deg)' : 'rotate(180deg)' } : {};
},
finalNvueListIs() {
if (this.usePageScroll) return 'view';
const nvueListIsLowerCase = this.nvueListIs.toLowerCase();
if (['list','waterfall','scroller'].indexOf(nvueListIsLowerCase) !== -1) return nvueListIsLowerCase;
return 'list';
},
finalNvueSuperListIs() {
return this.usePageScroll ? 'view' : 'scroller';
},
finalNvueRefresherEnabled() {
return this.finalNvueListIs !== 'view' && this.finalRefresherEnabled && !this.nShowRefresherReveal && !this.useChatRecordMode;
},
// #endif
},
mounted(){
// #ifdef APP-NVUE
//旋转屏幕时更新宽度
uni.onWindowResize((res) => {
// this._nUpdateRefresherWidth();
})
// #endif
},
methods: {
// #ifdef APP-NVUE
//列表滚动时触发
_nOnScroll(e) {
this.$emit('scroll', e);
const contentOffsetY = -e.contentOffset.y;
this.oldScrollTop = contentOffsetY;
this.nListIsDragging = e.isDragging;
this._checkShouldShowBackToTop(contentOffsetY, contentOffsetY - 1);
},
//下拉刷新刷新中
_nOnRrefresh() {
if (this.nShowRefresherReveal) return;
this.nRefresherLoading = true;
this.refresherStatus = Enum.Refresher.Loading;
this._doRefresherLoad();
},
//下拉刷新下拉中
_nOnPullingdown(e) {
if (this.refresherStatus === Enum.Refresher.Loading || (this.isIos && !this.nListIsDragging)) return;
this._emitTouchmove(e);
const { viewHeight, pullingDistance } = e;
this.refresherStatus = pullingDistance >= viewHeight ? Enum.Refresher.ReleaseToRefresh : Enum.Refresher.Default;
},
//下拉刷新结束
_nRefresherEnd(doEnd = true) {
if (doEnd) {
this._nDoRefresherEndAnimation(0, -this.nShowRefresherRevealHeight);
!this.usePageScroll && this.$refs['zp-n-list'].resetLoadmore();
this.nRefresherLoading = false;
}
},
//执行主动触发下拉刷新动画
_nDoRefresherEndAnimation(height, translateY, animate = true, checkStack = true) {
this._cleanRefresherCompleteTimeout();
this._cleanRefresherEndTimeout();
if (!this.finalShowRefresherWhenReload) {
this.refresherEndTimeout = u.delay(() => {
this.refresherStatus = Enum.Refresher.Default;
}, this.refresherCompleteDuration);
return;
}
const stackCount = this.refresherRevealStackCount;
if (height === 0 && checkStack) {
this.refresherRevealStackCount --;
if (stackCount > 1) return;
this.refresherEndTimeout = u.delay(() => {
this.refresherStatus = Enum.Refresher.Default;
}, this.refresherCompleteDuration);
}
if (stackCount > 1) {
this.refresherStatus = Enum.Refresher.Loading;
}
const duration = animate ? 200 : 0;
if (this.nOldShowRefresherRevealHeight !== height) {
if (height > 0) {
this.nShowRefresherReveal = true;
}
weexAnimation.transition(this.$refs['zp-n-list-refresher-reveal'], {
styles: {
height: `${height}px`,
transform: `translateY(${translateY}px)`,
},
duration,
timingFunction: 'linear',
needLayout: true,
delay: 0
})
}
u.delay(() => {
if (animate) {
this.nShowRefresherReveal = height > 0;
}
}, duration > 0 ? duration - 60 : 0);
this.nOldShowRefresherRevealHeight = height;
},
//滚动到底部加载更多
_nOnLoadmore() {
if (this.nShowRefresherReveal || !this.totalData.length) return;
this.useChatRecordMode ? this.doChatRecordLoadMore() : this._onLoadingMore('toBottom');
},
//获取nvue waterfall单项配置
_nGetWaterfallConfig(key, defaultValue) {
return this.nvueWaterfallConfig[key] || defaultValue;
},
//更新nvue 下拉刷新view容器的宽度
_nUpdateRefresherWidth() {
u.delay(() => {
this.$nextTick(()=>{
this._getNodeClientRect('.zp-n-list').then(node => {
if (node) {
this.nRefresherWidth = node[0].width || this.nRefresherWidth;
}
})
})
})
}
// #endif
}
}

677
src/uni_modules/z-paging/components/z-paging/js/modules/refresher.js

@ -0,0 +1,677 @@
// [z-paging]下拉刷新view模块
import u from '.././z-paging-utils'
import c from '.././z-paging-constant'
import Enum from '.././z-paging-enum'
export default {
props: {
//下拉刷新的主题样式,支持black,white,默认black
refresherThemeStyle: {
type: String,
default: u.gc('refresherThemeStyle', '')
},
//自定义下拉刷新中左侧图标的样式
refresherImgStyle: {
type: Object,
default: function() {
return u.gc('refresherImgStyle', {});
}
},
//自定义下拉刷新中右侧状态描述文字的样式
refresherTitleStyle: {
type: Object,
default: function() {
return u.gc('refresherTitleStyle', {});
}
},
//自定义下拉刷新中右侧最后更新时间文字的样式(show-refresher-update-time为true时有效)
refresherUpdateTimeStyle: {
type: Object,
default: function() {
return u.gc('refresherUpdateTimeStyle', {});
}
},
//在微信小程序和QQ小程序中,是否实时监听下拉刷新中进度,默认为否
watchRefresherTouchmove: {
type: Boolean,
default: u.gc('watchRefresherTouchmove', false)
},
//底部加载更多的主题样式,支持black,white,默认black
loadingMoreThemeStyle: {
type: String,
default: u.gc('loadingMoreThemeStyle', '')
},
//是否只使用下拉刷新,设置为true后将关闭mounted自动请求数据、关闭滚动到底部加载更多,强制隐藏空数据图。默认为否
refresherOnly: {
type: Boolean,
default: u.gc('refresherOnly', false)
},
//自定义下拉刷新默认状态下回弹动画时间,单位为毫秒,默认为100毫秒,nvue无效
refresherDefaultDuration: {
type: [Number, String],
default: u.gc('refresherDefaultDuration', 100)
},
//自定义下拉刷新结束以后延迟回弹的时间,单位为毫秒,默认为0
refresherCompleteDelay: {
type: [Number, String],
default: u.gc('refresherCompleteDelay', 0)
},
//自定义下拉刷新结束回弹动画时间,单位为毫秒,默认为300毫秒(refresherEndBounceEnabled为false时,refresherCompleteDuration为设定值的1/3),nvue无效
refresherCompleteDuration: {
type: [Number, String],
default: u.gc('refresherCompleteDuration', 300)
},
//自定义下拉刷新结束状态下是否允许列表滚动,默认为否
refresherCompleteScrollable: {
type: Boolean,
default: u.gc('refresherCompleteScrollable', false)
},
//是否使用自定义的下拉刷新,默认为是,即使用z-paging的下拉刷新。设置为false即代表使用uni scroll-view自带的下拉刷新,h5、App、微信小程序以外的平台不支持uni scroll-view自带的下拉刷新
useCustomRefresher: {
type: Boolean,
default: u.gc('useCustomRefresher', true)
},
//自定义下拉刷新下拉帧率,默认为40,过高可能会出现抖动问题
refresherFps: {
type: [Number, String],
default: u.gc('refresherFps', 40)
},
//自定义下拉刷新允许触发的最大下拉角度,默认为40度,当下拉角度小于设定值时,自定义下拉刷新动画不会被触发
refresherMaxAngle: {
type: [Number, String],
default: u.gc('refresherMaxAngle', 40)
},
//自定义下拉刷新的角度由未达到最大角度变到达到最大角度时,是否继续下拉刷新手势,默认为否
refresherAngleEnableChangeContinued: {
type: Boolean,
default: u.gc('refresherAngleEnableChangeContinued', false)
},
//自定义下拉刷新默认状态下的文字
refresherDefaultText: {
type: [String, Object],
default: u.gc('refresherDefaultText', null)
},
//自定义下拉刷新松手立即刷新状态下的文字
refresherPullingText: {
type: [String, Object],
default: u.gc('refresherPullingText', null)
},
//自定义下拉刷新刷新中状态下的文字
refresherRefreshingText: {
type: [String, Object],
default: u.gc('refresherRefreshingText', null)
},
//自定义下拉刷新刷新结束状态下的文字
refresherCompleteText: {
type: [String, Object],
default: u.gc('refresherCompleteText', null)
},
//自定义下拉刷新默认状态下的图片
refresherDefaultImg: {
type: String,
default: u.gc('refresherDefaultImg', null)
},
//自定义下拉刷新松手立即刷新状态下的图片,默认与refresherDefaultImg一致
refresherPullingImg: {
type: String,
default: u.gc('refresherPullingImg', null)
},
//自定义下拉刷新刷新中状态下的图片
refresherRefreshingImg: {
type: String,
default: u.gc('refresherRefreshingImg', null)
},
//自定义下拉刷新刷新结束状态下的图片
refresherCompleteImg: {
type: String,
default: u.gc('refresherCompleteImg', null)
},
//自定义下拉刷新刷新中状态下是否展示旋转动画
refresherRefreshingAnimated: {
type: Boolean,
default: u.gc('refresherRefreshingAnimated', true)
},
//是否开启自定义下拉刷新刷新结束回弹效果,默认为是
refresherEndBounceEnabled: {
type: Boolean,
default: u.gc('refresherEndBounceEnabled', true)
},
//是否开启自定义下拉刷新,默认为是
refresherEnabled: {
type: Boolean,
default: u.gc('refresherEnabled', true)
},
//设置自定义下拉刷新阈值,默认为80rpx
refresherThreshold: {
type: [Number, String],
default: u.gc('refresherThreshold', '80rpx')
},
//设置系统下拉刷新默认样式,支持设置 black,white,none,none 表示不使用默认样式,默认为black
refresherDefaultStyle: {
type: String,
default: u.gc('refresherDefaultStyle', 'black')
},
//设置自定义下拉刷新区域背景
refresherBackground: {
type: String,
default: u.gc('refresherBackground', 'transparent')
},
//设置固定的自定义下拉刷新区域背景
refresherFixedBackground: {
type: String,
default: u.gc('refresherFixedBackground', 'transparent')
},
//设置固定的自定义下拉刷新区域高度,默认为0
refresherFixedBacHeight: {
type: [Number, String],
default: u.gc('refresherFixedBacHeight', 0)
},
//设置自定义下拉刷新下拉超出阈值后继续下拉位移衰减的比例,范围0-1,值越大代表衰减越多。默认为0.65(nvue无效)
refresherOutRate: {
type: Number,
default: u.gc('refresherOutRate', 0.65)
},
//设置自定义下拉刷新下拉时实际下拉位移与用户下拉距离的比值,默认为0.75,即代表若用户下拉10px,则实际位移为7.5px(nvue无效)
refresherPullRate: {
type: Number,
default: u.gc('refresherPullRate', 0.75)
},
//是否显示最后更新时间,默认为否
showRefresherUpdateTime: {
type: Boolean,
default: u.gc('showRefresherUpdateTime', false)
},
//如果需要区别不同页面的最后更新时间,请为不同页面的z-paging的`refresher-update-time-key`设置不同的字符串
refresherUpdateTimeKey: {
type: String,
default: u.gc('refresherUpdateTimeKey', 'default')
},
//下拉刷新时下拉到“松手立即刷新”状态时是否使手机短振动,默认为否(h5无效)
refresherVibrate: {
type: Boolean,
default: u.gc('refresherVibrate', false)
},
//下拉刷新时是否禁止下拉刷新view跟随用户触摸竖直移动,默认为否。注意此属性只是禁止下拉刷新view移动,其他下拉刷新逻辑依然会正常触发
refresherNoTransform: {
type: Boolean,
default: u.gc('refresherNoTransform', false)
},
},
data() {
return {
R: Enum.Refresher,
//下拉刷新状态
refresherStatus: Enum.Refresher.Default,
refresherTouchstartY: 0,
lastRefresherTouchmove: null,
refresherReachMaxAngle: true,
refresherTransform: 'translateY(0px)',
refresherTransition: '',
finalRefresherDefaultStyle: 'black',
refresherRevealStackCount: 0,
refresherCompleteTimeout: null,
refresherCompleteSubTimeout: null,
refresherEndTimeout: null,
isTouchmovingTimeout: null,
refresherTriggered: false,
isTouchmoving: false,
isTouchEnded: false,
isUserPullDown: false,
privateRefresherEnabled: -1,
privateShowRefresherWhenReload: false,
customRefresherHeight: -1,
showCustomRefresher: false,
doRefreshAnimateAfter: false,
isRefresherInComplete: false,
pullDownTimeStamp: 0,
moveDis: 0,
oldMoveDis: 0,
currentDis: 0,
oldCurrentMoveDis: 0,
oldRefresherTouchmoveY: 0,
oldTouchDirection: '',
oldEmitedTouchDirection: '',
oldPullingDistance: -1,
refresherThresholdUpdateTag: 0
}
},
watch: {
refresherDefaultStyle: {
handler(newVal) {
if (newVal.length) {
this.finalRefresherDefaultStyle = newVal;
}
},
immediate: true
},
refresherStatus(newVal) {
newVal === Enum.Refresher.Loading && this._cleanRefresherEndTimeout();
this.refresherVibrate && newVal === Enum.Refresher.ReleaseToRefresh && this._doVibrateShort();
this.$emit('refresherStatusChange', newVal);
this.$emit('update:refresherStatus', newVal);
},
refresherEnabled(newVal) {
!newVal && this.endRefresh();
}
},
computed: {
pullDownDisTimeStamp() {
return 1000 / this.refresherFps;
},
finalRefresherEnabled() {
if (this.useChatRecordMode) return false;
if (this.privateRefresherEnabled === -1) return this.refresherEnabled;
return this.privateRefresherEnabled === 1;
},
finalRefresherThreshold() {
let refresherThreshold = this.refresherThreshold;
let idDefault = false;
if (refresherThreshold === '80rpx') {
idDefault = true;
if (this.showRefresherUpdateTime) {
refresherThreshold = '120rpx';
}
}
if (idDefault && this.customRefresherHeight > 0) return this.customRefresherHeight;
return u.convertToPx(refresherThreshold);
},
finalRefresherFixedBacHeight() {
return u.convertToPx(this.refresherFixedBacHeight);
},
finalRefresherThemeStyle() {
return this.refresherThemeStyle.length ? this.refresherThemeStyle : this.defaultThemeStyle;
},
finalRefresherOutRate() {
let rate = this.refresherOutRate;
rate = Math.max(0,rate);
rate = Math.min(1,rate);
return rate;
},
finalRefresherPullRate() {
let rate = this.refresherPullRate;
rate = Math.max(0,rate);
return rate;
},
finalRefresherTransform() {
if (this.refresherNoTransform || this.refresherTransform === 'translateY(0px)') return 'none';
return this.refresherTransform;
},
finalShowRefresherWhenReload() {
return this.showRefresherWhenReload || this.privateShowRefresherWhenReload;
},
finalRefresherTriggered() {
if (!(this.finalRefresherEnabled && !this.useCustomRefresher)) return false;
return this.refresherTriggered;
},
showRefresher() {
const showRefresher = this.finalRefresherEnabled && this.useCustomRefresher;
// #ifndef APP-NVUE
this.customRefresherHeight === -1 && showRefresher && u.delay(() => this.$nextTick(this._updateCustomRefresherHeight));
// #endif
return showRefresher;
},
hasTouchmove(){
// #ifdef VUE2
// #ifdef APP-VUE || H5
if (this.$listeners && !this.$listeners.refresherTouchmove) return false;
// #endif
// #ifdef MP-WEIXIN || MP-QQ
return this.watchRefresherTouchmove;
// #endif
return true;
// #endif
return this.watchRefresherTouchmove;
},
},
methods: {
//终止下拉刷新状态
endRefresh() {
this.totalData = this.realTotalData;
this._refresherEnd();
this._endSystemLoadingAndRefresh();
this._handleScrollViewDisableBounce({ bounce: true });
this.$nextTick(() => {
this.refresherTriggered = false;
})
},
handleRefresherStatusChanged(func) {
this.refresherStatusChangedFunc = func;
},
//自定义下拉刷新被触发
_onRefresh(fromScrollView = false,isUserPullDown = true) {
if (fromScrollView && !(this.finalRefresherEnabled && !this.useCustomRefresher)) return;
this.$emit('onRefresh');
this.$emit('Refresh');
// #ifdef APP-NVUE
if (this.loading) {
u.delay(this._nRefresherEnd, 500)
return;
}
// #endif
if (this.loading || this.isRefresherInComplete) return;
this.loadingType = Enum.LoadingType.Refresher;
if (this.nShowRefresherReveal) return;
this.isUserPullDown = isUserPullDown;
this.isUserReload = !isUserPullDown;
this._startLoading(true);
this.refresherTriggered = true;
if(this.reloadWhenRefresh && isUserPullDown){
this.useChatRecordMode ? this._onLoadingMore('click') : this._reload(false, false, isUserPullDown);
}
},
//自定义下拉刷新被复位
_onRestore() {
this.refresherTriggered = 'restore';
this.$emit('onRestore');
this.$emit('Restore');
},
// #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
//拖拽开始
_refresherTouchstart(e) {
this._handleListTouchstart();
if (this._touchDisabled()) return;
this._handleRefresherTouchstart(u.getTouch(e));
},
// #endif
//进一步处理拖拽开始结果
_handleRefresherTouchstart(touch) {
if (!this.loading && this.isTouchEnded) {
this.isTouchmoving = false;
}
this.loadingType = Enum.LoadingType.Refresher;
this.isTouchmovingTimeout && clearTimeout(this.isTouchmovingTimeout);
this.isTouchEnded = false;
this.refresherTransition = '';
this.refresherTouchstartY = touch.touchY;
this.$emit('refresherTouchstart', this.refresherTouchstartY);
this.lastRefresherTouchmove = touch;
this._cleanRefresherCompleteTimeout();
this._cleanRefresherEndTimeout();
},
// #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
//拖拽中
_refresherTouchmove(e) {
const currentTimeStamp = u.getTime();
let touch = null;
let refresherTouchmoveY = 0;
if (this.watchTouchDirectionChange) {
touch = u.getTouch(e);
refresherTouchmoveY = touch.touchY;
const direction = refresherTouchmoveY > this.oldRefresherTouchmoveY ? 'top' : 'bottom';
if (direction === this.oldTouchDirection && direction !== this.oldEmitedTouchDirection) {
this._handleTouchDirectionChange({ direction });
this.oldEmitedTouchDirection = direction;
}
this.oldTouchDirection = direction;
this.oldRefresherTouchmoveY = refresherTouchmoveY;
}
if (this.pullDownTimeStamp && currentTimeStamp - this.pullDownTimeStamp <= this.pullDownDisTimeStamp) return;
if (this._touchDisabled()) return;
this.pullDownTimeStamp = Number(currentTimeStamp);
touch = u.getTouch(e);
refresherTouchmoveY = touch.touchY;
let moveDis = refresherTouchmoveY - this.refresherTouchstartY;
if (moveDis < 0) return;
if (this.refresherMaxAngle >= 0 && this.refresherMaxAngle <= 90 && this.lastRefresherTouchmove && this.lastRefresherTouchmove.touchY <= refresherTouchmoveY) {
if (!moveDis && !this.refresherAngleEnableChangeContinued && this.moveDis < 1 && !this.refresherReachMaxAngle) return;
const x = Math.abs(touch.touchX - this.lastRefresherTouchmove.touchX);
const y = Math.abs(refresherTouchmoveY - this.lastRefresherTouchmove.touchY);
const z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
if ((x || y) && x > 1) {
const angle = Math.asin(y / z) / Math.PI * 180;
if (angle < this.refresherMaxAngle) {
this.lastRefresherTouchmove = touch;
this.refresherReachMaxAngle = false;
return;
}
}
}
moveDis = this._getFinalRefresherMoveDis(moveDis);
this._handleRefresherTouchmove(moveDis, touch);
if (!this.disabledBounce) {
if(this.isIos){
// #ifndef MP-LARK
this._handleScrollViewDisableBounce({ bounce: false });
// #endif
}
this.disabledBounce = true;
}
this._emitTouchmove({ pullingDistance: moveDis, dy: this.moveDis - this.oldMoveDis });
},
// #endif
//进一步处理拖拽中结果
_handleRefresherTouchmove(moveDis, touch) {
this.refresherReachMaxAngle = true;
this.isTouchmovingTimeout && clearTimeout(this.isTouchmovingTimeout);
this.isTouchmoving = true;
this.isTouchEnded = false;
this.refresherStatus = moveDis >= this.finalRefresherThreshold ? Enum.Refresher.ReleaseToRefresh : this.refresherStatus = Enum.Refresher.Default;
// #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
// this.scrollEnable = false;
this.refresherTransform = `translateY(${moveDis}px)`;
this.lastRefresherTouchmove = touch;
// #endif
this.moveDis = moveDis;
},
// #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
//拖拽结束
_refresherTouchend(e) {
if (this._touchDisabled() || !this.isTouchmoving) return;
const touch = u.getTouch(e);
let refresherTouchendY = touch.touchY;
let moveDis = refresherTouchendY - this.refresherTouchstartY;
moveDis = this._getFinalRefresherMoveDis(moveDis);
this._handleRefresherTouchend(moveDis);
this._handleScrollViewDisableBounce({bounce: true});
this.disabledBounce = false;
},
// #endif
//进一步处理拖拽结束结果
_handleRefresherTouchend(moveDis) {
// #ifndef APP-PLUS || H5 || MP-WEIXIN
if (!this.isTouchmoving) return;
// #endif
this.isTouchmovingTimeout && clearTimeout(this.isTouchmovingTimeout);
this.refresherReachMaxAngle = true;
this.isTouchEnded = true;
const refresherThreshold = this.finalRefresherThreshold;
if (moveDis >= refresherThreshold && this.refresherStatus === Enum.Refresher.ReleaseToRefresh) {
// #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
this.refresherTransform = `translateY(${refresherThreshold}px)`;
this.refresherTransition = 'transform .1s linear';
// #endif
u.delay(() => {
this._emitTouchmove({ pullingDistance: refresherThreshold, dy: this.moveDis - refresherThreshold });
}, 0.1);
this.moveDis = refresherThreshold;
this.refresherStatus = Enum.Refresher.Loading;
this._doRefresherLoad();
} else {
this._refresherEnd();
this.isTouchmovingTimeout = u.delay(() => {
this.isTouchmoving = false;
}, this.refresherDefaultDuration);
}
this.scrollEnable = true;
this.$emit('refresherTouchend', moveDis);
},
//处理列表触摸开始事件
_handleListTouchstart() {
if (this.useChatRecordMode && this.autoHideKeyboardWhenChat) {
uni.hideKeyboard();
this.$emit('hidedKeyboard');
}
},
//处理scroll-view bounce是否生效
_handleScrollViewDisableBounce({ bounce }) {
if (!this.usePageScroll && !this.scrollToTopBounceEnabled && this.wxsScrollTop <= 5) {
// #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5
this.refresherTransition = '';
// #endif
this.scrollEnable = bounce;
}
},
//wxs正在下拉状态改变处理
_handleWxsPullingDownStatusChange(onPullingDown) {
this.wxsOnPullingDown = onPullingDown;
if (onPullingDown && !this.useChatRecordMode) {
this.renderPropScrollTop = 0;
}
},
//wxs正在下拉处理
_handleWxsPullingDown({ moveDis, diffDis }){
this._emitTouchmove({ pullingDistance: moveDis,dy: diffDis });
},
//wxs触摸方向改变
_handleTouchDirectionChange({ direction }) {
this.$emit('touchDirectionChange',direction);
},
//wxs通知更新其props
_handlePropUpdate(){
this.wxsPropType = u.getTime().toString();
},
//下拉刷新结束
_refresherEnd(shouldEndLoadingDelay = true, fromAddData = false, isUserPullDown = false, setLoading = true) {
if (this.loadingType === Enum.LoadingType.Refresher) {
const refresherCompleteDelay = (fromAddData && (isUserPullDown || this.showRefresherWhenReload)) ? this.refresherCompleteDelay : 0;
const refresherStatus = refresherCompleteDelay > 0 ? Enum.Refresher.Complete : Enum.Refresher.Default;
if (this.finalShowRefresherWhenReload) {
const stackCount = this.refresherRevealStackCount;
this.refresherRevealStackCount --;
if (stackCount > 1) return;
}
this._cleanRefresherEndTimeout();
this.refresherEndTimeout = u.delay(() => {
this.refresherStatus = refresherStatus;
}, this.refresherStatus !== Enum.Refresher.Default && refresherStatus === Enum.Refresher.Default ? this.refresherCompleteDuration : 0);
// #ifndef APP-NVUE
if (refresherCompleteDelay > 0) {
this.isRefresherInComplete = true;
}
// #endif
this._cleanRefresherCompleteTimeout();
this.refresherCompleteTimeout = u.delay(() => {
let animateDuration = 1;
const animateType = this.refresherEndBounceEnabled && fromAddData ? 'cubic-bezier(0.19,1.64,0.42,0.72)' : 'linear';
if (fromAddData) {
animateDuration = this.refresherEndBounceEnabled ? this.refresherCompleteDuration / 1000 : this.refresherCompleteDuration / 3000;
}
this.refresherTransition = `transform ${fromAddData ? animateDuration : this.refresherDefaultDuration / 1000}s ${animateType}`;
// #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
this.refresherTransform = 'translateY(0px)';
this.currentDis = 0;
// #endif
// #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5
this.wxsPropType = this.refresherTransition + 'end' + u.getTime();
// #endif
// #ifdef APP-NVUE
this._nRefresherEnd();
// #endif
this.moveDis = 0;
// #ifndef APP-NVUE
if (refresherStatus === Enum.Refresher.Complete) {
if (this.refresherCompleteSubTimeout) {
clearTimeout(this.refresherCompleteSubTimeout);
this.refresherCompleteSubTimeout = null;
}
this.refresherCompleteSubTimeout = u.delay(() => {
this.$nextTick(() => {
this.refresherStatus = Enum.Refresher.Default;
this.isRefresherInComplete = false;
})
}, animateDuration * 800);
}
// #endif
this._emitTouchmove({ pullingDistance: 0, dy: this.moveDis });
}, refresherCompleteDelay);
}
if (setLoading) {
u.delay(() => this.loading = false, shouldEndLoadingDelay ? c.delayTime : 0);
isUserPullDown && this._onRestore();
}
},
//模拟用户手动触发下拉刷新
_doRefresherRefreshAnimate() {
this._cleanRefresherCompleteTimeout();
// #ifndef APP-NVUE
const doRefreshAnimateAfter = !this.doRefreshAnimateAfter && (this.finalShowRefresherWhenReload) && this
.customRefresherHeight === -1 && this.refresherThreshold === '80rpx';
if (doRefreshAnimateAfter) {
this.doRefreshAnimateAfter = true;
return;
}
// #endif
this.refresherRevealStackCount ++;
// #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
this.refresherTransform = `translateY(${this.finalRefresherThreshold}px)`;
// #endif
// #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5
this.wxsPropType = 'begin' + u.getTime();
// #endif
this.moveDis = this.finalRefresherThreshold;
this.refresherStatus = Enum.Refresher.Loading;
this.isTouchmoving = true;
this.isTouchmovingTimeout && clearTimeout(this.isTouchmovingTimeout);
this._doRefresherLoad(false);
},
//触发下拉刷新
_doRefresherLoad(isUserPullDown = true) {
this._onRefresh(false,isUserPullDown);
this.loading = true;
},
// #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
//获取处理后的moveDis
_getFinalRefresherMoveDis(moveDis) {
let diffDis = moveDis - this.oldCurrentMoveDis;
this.oldCurrentMoveDis = moveDis;
if (diffDis > 0) {
diffDis = diffDis * this.finalRefresherPullRate;
if (this.currentDis > this.finalRefresherThreshold) {
diffDis = diffDis * (1 - this.finalRefresherOutRate);
}
}
diffDis = diffDis > 100 ? diffDis / 100 : diffDis;
this.currentDis += diffDis;
this.currentDis = Math.max(0, this.currentDis);
return this.currentDis;
},
//判断touch手势是否要触发
_touchDisabled() {
const checkOldScrollTop = this.oldScrollTop > 5;
return this.loading || this.isRefresherInComplete || this.useChatRecordMode || !this.refresherEnabled || !this.useCustomRefresher ||(this.usePageScroll && this.useCustomRefresher && this.pageScrollTop > 10) || (!(this.usePageScroll && this.useCustomRefresher) && checkOldScrollTop);
},
// #endif
//更新自定义下拉刷新view高度
_updateCustomRefresherHeight() {
this._getNodeClientRect('.zp-custom-refresher-slot-view').then((res) => {
this.customRefresherHeight = res ? res[0].height : 0;
this.showCustomRefresher = this.customRefresherHeight > 0;
if (this.doRefreshAnimateAfter) {
this.doRefreshAnimateAfter = false;
this._doRefresherRefreshAnimate();
}
});
},
//发射pullingDown事件
_emitTouchmove(e) {
// #ifndef APP-NVUE
e.viewHeight = this.finalRefresherThreshold;
// #endif
e.rate = e.viewHeight > 0 ? e.pullingDistance / e.viewHeight : 0;
this.hasTouchmove && this.oldPullingDistance !== e.pullingDistance && this.$emit('refresherTouchmove', e);
this.oldPullingDistance = e.pullingDistance;
},
//清除refresherCompleteTimeout
_cleanRefresherCompleteTimeout() {
this.refresherCompleteTimeout = this._cleanTimeout(this.refresherCompleteTimeout);
// #ifdef APP-NVUE
this._nRefresherEnd(false);
// #endif
},
//清除refresherEndTimeout
_cleanRefresherEndTimeout() {
this.refresherEndTimeout = this._cleanTimeout(this.refresherEndTimeout);
},
}
}

464
src/uni_modules/z-paging/components/z-paging/js/modules/scroller.js

@ -0,0 +1,464 @@
// [z-paging]scroll相关模块
import u from '.././z-paging-utils'
import Enum from '.././z-paging-enum'
// #ifdef APP-NVUE
const weexDom = weex.requireModule('dom');
// #endif
export default {
props: {
//使用页面滚动,默认为否,当设置为是时则使用页面的滚动而非此组件内部的scroll-view的滚动,使用页面滚动时z-paging无需设置确定的高度且对于长列表展示性能更高,但配置会略微繁琐
usePageScroll: {
type: Boolean,
default: u.gc('usePageScroll', false)
},
//是否可以滚动,使用内置scroll-view和nvue时有效,默认为是
scrollable: {
type: Boolean,
default: u.gc('scrollable', true)
},
//控制是否出现滚动条,默认为是
showScrollbar: {
type: Boolean,
default: u.gc('showScrollbar', true)
},
//是否允许横向滚动,默认为否
scrollX: {
type: Boolean,
default: u.gc('scrollX', false)
},
//iOS设备上滚动到顶部时是否允许回弹效果,默认为否。关闭回弹效果后可使滚动到顶部与下拉刷新更连贯,但是有吸顶view时滚动到顶部时可能出现抖动。
scrollToTopBounceEnabled: {
type: Boolean,
default: u.gc('scrollToTopBounceEnabled', false)
},
//iOS设备上滚动到底部时是否允许回弹效果,默认为是。
scrollToBottomBounceEnabled: {
type: Boolean,
default: u.gc('scrollToBottomBounceEnabled', true)
},
//在设置滚动条位置时使用动画过渡,默认为否
scrollWithAnimation: {
type: Boolean,
default: u.gc('scrollWithAnimation', false)
},
//值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素
scrollIntoView: {
type: String,
default: u.gc('scrollIntoView', '')
},
},
data() {
return {
scrollTop: 0,
oldScrollTop: 0,
scrollViewStyle: {},
scrollViewContainerStyle: {},
scrollViewInStyle: {},
pageScrollTop: -1,
scrollEnable: true,
privateScrollWithAnimation: -1,
cacheScrollNodeHeight: -1
}
},
watch: {
oldScrollTop(newVal) {
!this.usePageScroll && this._scrollTopChange(newVal,false);
},
pageScrollTop(newVal) {
this.usePageScroll && this._scrollTopChange(newVal,true);
},
usePageScroll: {
handler(newVal) {
this.loaded && this.autoHeight && this._setAutoHeight(!newVal);
// #ifdef H5
if (newVal) {
this.$nextTick(() => {
const mainScrollRef = this.$refs['zp-scroll-view'].$refs.main;
if (mainScrollRef) {
mainScrollRef.style = {};
}
})
}
// #endif
},
immediate: true
},
finalScrollTop(newVal) {
if (!this.useChatRecordMode) {
this.renderPropScrollTop = newVal < 6 ? 0 : 10;
}
},
},
computed: {
finalScrollWithAnimation() {
if (this.privateScrollWithAnimation !== -1) {
const scrollWithAnimation = this.privateScrollWithAnimation === 1;
this.privateScrollWithAnimation = -1;
return scrollWithAnimation;
}
return this.scrollWithAnimation;
},
finalScrollViewStyle() {
if (this.superContentZIndex != 1) {
this.scrollViewStyle['z-index'] = this.superContentZIndex;
this.scrollViewStyle['position'] = 'relative';
}
return this.scrollViewStyle;
},
finalScrollTop() {
return this.usePageScroll ? this.pageScrollTop : this.oldScrollTop;
},
finalIsOldWebView() {
return this.isOldWebView && !this.usePageScroll;
}
},
methods: {
//滚动到顶部,animate为是否展示滚动动画,默认为是
scrollToTop(animate, checkReverse = true) {
// #ifdef APP-NVUE
if (checkReverse && this.useChatRecordMode) {
if (!this.nIsFirstPageAndNoMore) {
this.scrollToBottom(animate, false);
return;
}
}
// #endif
this.$nextTick(() => {
this._scrollToTop(animate, false);
// #ifdef APP-NVUE
if (this.nvueFastScroll && animate) {
u.delay(() => {
this._scrollToTop(false, false);
});
}
// #endif
})
},
//滚动到底部,animate为是否展示滚动动画,默认为是
scrollToBottom(animate, checkReverse = true) {
// #ifdef APP-NVUE
if (checkReverse && this.useChatRecordMode) {
if (!this.nIsFirstPageAndNoMore) {
this.scrollToTop(animate, false);
return;
}
}
// #endif
this.$nextTick(() => {
this._scrollToBottom(animate);
// #ifdef APP-NVUE
if (this.nvueFastScroll && animate) {
u.delay(() => {
this._scrollToBottom(false);
});
}
// #endif
})
},
//滚动到指定view(vue中有效)。sel为需要滚动的view的id值,不包含"#";offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
scrollIntoViewById(sel, offset, animate) {
this._scrollIntoView(sel, offset, animate);
},
//滚动到指定view(vue中有效)。nodeTop为需要滚动的view的top值(通过uni.createSelectorQuery()获取);offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
scrollIntoViewByNodeTop(nodeTop, offset, animate) {
this.scrollTop = this.oldScrollTop;
this.$nextTick(() => {
this._scrollIntoViewByNodeTop(nodeTop, offset, animate);
})
},
//滚动到指定位置(vue中有效)。y为与顶部的距离,单位为px;offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
scrollToY(y, offset, animate) {
this.scrollTop = this.oldScrollTop;
this.$nextTick(() => {
this._scrollToY(y, offset, animate);
})
},
//滚动到指定view(nvue中有效)。index为需要滚动的view的index(第几个);offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
scrollIntoViewByIndex(index, offset, animate) {
this._scrollIntoView(index, offset, animate);
},
//滚动到指定view(nvue中有效)。view为需要滚动的view(通过`this.$refs.xxx`获取),不包含"#";offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
scrollIntoViewByView(view, offset, animate) {
this._scrollIntoView(view, offset, animate);
},
//当使用页面滚动并且自定义下拉刷新时,请在页面的onPageScroll中调用此方法,告知z-paging当前的pageScrollTop,否则会导致在任意位置都可以下拉刷新
updatePageScrollTop(value) {
this.pageScrollTop = value;
},
//当使用页面滚动并且设置了slot="top"时,默认初次加载会自动获取其高度,并使内部容器下移,当slot="top"的view高度动态改变时,在其高度需要更新时调用此方法
updatePageScrollTopHeight() {
this._updatePageScrollTopOrBottomHeight('top');
},
//当使用页面滚动并且设置了slot="bottom"时,默认初次加载会自动获取其高度,并使内部容器下移,当slot="bottom"的view高度动态改变时,在其高度需要更新时调用此方法
updatePageScrollBottomHeight() {
this._updatePageScrollTopOrBottomHeight('bottom');
},
//更新slot="left"和slot="right"宽度,当slot="left"或slot="right"宽度动态改变时调用
updateLeftAndRightWidth() {
if (!this.finalIsOldWebView) return;
this.$nextTick(() => this._updateLeftAndRightWidth(this.scrollViewContainerStyle, 'zp-page'));
},
//更新z-paging内置scroll-view的scrollTop
updateScrollViewScrollTop(scrollTop, animate = true) {
this.privateScrollWithAnimation = animate ? 1 : 0;
this.scrollTop = this.oldScrollTop;
this.$nextTick(() => {
this.scrollTop = scrollTop;
this.oldScrollTop = this.scrollTop;
});
},
//当滚动到顶部时
_onScrollToUpper() {
this.$emit('scrolltoupper');
this.$emit('scrollTopChange', 0);
this.$nextTick(() => {
this.oldScrollTop = 0;
})
this.useChatRecordMode && this.loadingStatus !== Enum.More.NoMore && this._onLoadingMore('click');
},
//当滚动到底部时
_onScrollToLower(e) {
(!e.detail || !e.detail.direction || e.detail.direction === 'bottom') && this._onLoadingMore('toBottom')
},
//滚动到顶部
_scrollToTop(animate = true, isPrivate = true) {
// #ifdef APP-NVUE
const el = this.$refs['zp-n-list-top-tag'];
if (this.usePageScroll) {
this._getNodeClientRect('zp-page-scroll-top', false).then(node => {
const nodeHeight = node ? node[0].height : 0;
weexDom.scrollToElement(el, {
offset: -nodeHeight,
animated: animate
});
});
} else {
if (!this.isIos && this.nvueListIs === 'scroller') {
this._getNodeClientRect('zp-n-refresh-container', false).then(node => {
const nodeHeight = node ? node[0].height : 0;
weexDom.scrollToElement(el, {
offset: -nodeHeight,
animated: animate
});
});
} else {
weexDom.scrollToElement(el, {
offset: 0,
animated: animate
});
}
}
return;
// #endif
if (this.usePageScroll) {
this.$nextTick(() => {
uni.pageScrollTo({
scrollTop: 0,
duration: animate ? 100 : 0,
});
});
return;
}
this.privateScrollWithAnimation = animate ? 1 : 0;
this.scrollTop = this.oldScrollTop;
this.$nextTick(() => {
this.scrollTop = 0;
this.oldScrollTop = this.scrollTop;
});
},
//滚动到底部
async _scrollToBottom(animate = true) {
// #ifdef APP-NVUE
const el = this.$refs['zp-n-list-bottom-tag'];
if (el) {
weexDom.scrollToElement(el, {
offset: 0,
animated: animate
});
} else {
u.consoleErr('滚动到底部失败,因为您设置了hideNvueBottomTag为true');
}
return;
// #endif
if (this.usePageScroll) {
this.$nextTick(() => {
uni.pageScrollTo({
scrollTop: Number.MAX_VALUE,
duration: animate ? 100 : 0,
});
});
return;
}
try {
this.privateScrollWithAnimation = animate ? 1 : 0;
const pagingContainerNode = await this._getNodeClientRect('.zp-paging-container');
const scrollViewNode = await this._getNodeClientRect('.zp-scroll-view');
const pagingContainerH = pagingContainerNode ? pagingContainerNode[0].height : 0;
const scrollViewH = scrollViewNode ? scrollViewNode[0].height : 0;
if (pagingContainerH > scrollViewH) {
this.scrollTop = this.oldScrollTop;
this.$nextTick(() => {
this.scrollTop = pagingContainerH - scrollViewH + this.virtualPlaceholderTopHeight;
this.oldScrollTop = this.scrollTop;
});
}
} catch (e) {}
},
//滚动到指定view
_scrollIntoView(sel, offset = 0, animate = false, finishCallback) {
try {
this.scrollTop = this.oldScrollTop;
this.$nextTick(() => {
// #ifdef APP-NVUE
const refs = this.$parent.$refs;
if (!refs) return;
const dataType = Object.prototype.toString.call(sel);
let el = null;
if (dataType === '[object Number]') {
const els = refs[`z-paging-${sel}`];
el = els ? els[0] : null;
} else if (dataType === '[object Array]') {
el = sel[0];
} else {
el = sel;
}
if (el) {
weexDom.scrollToElement(el, {
offset: -offset,
animated: animate
});
} else {
u.consoleErr('在nvue中滚动到指定位置,cell必须设置 :ref="`z-paging-${index}`"');
}
return;
// #endif
this._getNodeClientRect('#' + sel.replace('#', ''), this.$parent).then((node) => {
if (node) {
let nodeTop = node[0].top;
this._scrollIntoViewByNodeTop(nodeTop, offset, animate);
finishCallback && finishCallback();
}
});
});
} catch (e) {}
},
//通过nodeTop滚动到指定view
_scrollIntoViewByNodeTop(nodeTop, offset = 0, animate = false) {
this._scrollToY(nodeTop, offset, animate, true);
},
//滚动到指定位置
_scrollToY(y, offset = 0, animate = false, addScrollTop = false) {
this.privateScrollWithAnimation = animate ? 1 : 0;
if (this.usePageScroll) {
uni.pageScrollTo({
scrollTop: y - offset,
duration: animate ? 100 : 0
});
} else {
if(addScrollTop){
y += this.oldScrollTop;
}
this.scrollTop = y - offset;
this.oldScrollTop = this.scrollTop;
}
},
//scroll-view滚动中
_scroll(e) {
this.$emit('scroll', e);
const scrollTop = e.detail.scrollTop;
// #ifndef APP-NVUE
this.finalUseVirtualList && this._updateVirtualScroll(scrollTop, this.oldScrollTop - scrollTop);
// #endif
this.oldScrollTop = scrollTop;
const scrollDiff = e.detail.scrollHeight - this.oldScrollTop;
!this.isIos && this._checkScrolledToBottom(scrollDiff);
},
//检测scrollView是否要铺满屏幕
_doCheckScrollViewShouldFullHeight(totalData) {
if (this.autoFullHeight && this.usePageScroll && this.isTotalChangeFromAddData) {
// #ifndef APP-NVUE
this.$nextTick(() => {
this._checkScrollViewShouldFullHeight((scrollViewNode, pagingContainerNode) => {
this._preCheckShowNoMoreInside(totalData, scrollViewNode, pagingContainerNode)
});
})
// #endif
// #ifdef APP-NVUE
this._preCheckShowNoMoreInside(totalData)
// #endif
} else {
this._preCheckShowNoMoreInside(totalData)
}
},
//检测z-paging是否要全屏覆盖(当使用页面滚动并且不满全屏时,默认z-paging需要铺满全屏,避免数据过少时内部的empty-view无法正确展示)
async _checkScrollViewShouldFullHeight(callback) {
try {
const scrollViewNode = await this._getNodeClientRect('.zp-scroll-view');
const pagingContainerNode = await this._getNodeClientRect('.zp-paging-container-content');
if (!scrollViewNode || !pagingContainerNode) return;
const scrollViewHeight = pagingContainerNode[0].height;
const scrollViewTop = scrollViewNode[0].top;
if (this.isAddedData && scrollViewHeight + scrollViewTop <= this.windowHeight) {
this._setAutoHeight(true, scrollViewNode);
callback(scrollViewNode, pagingContainerNode);
} else {
this._setAutoHeight(false);
callback(null, null);
}
} catch (e) {
callback(null, null);
}
},
//scrollTop改变时触发
_scrollTopChange(newVal, isPageScrollTop){
this.$emit('scrollTopChange', newVal);
this.$emit('update:scrollTop', newVal);
this._checkShouldShowBackToTop(newVal);
const scrollTop = this.isIos ? (newVal > 5 ? 6 : 0) : (newVal > 105 ? 106 : (newVal > 5 ? 6 : 0));
if (isPageScrollTop && this.wxsPageScrollTop !== scrollTop) {
this.wxsPageScrollTop = scrollTop;
} else if (!isPageScrollTop && this.wxsScrollTop !== scrollTop) {
this.wxsScrollTop = scrollTop;
if (scrollTop > 6) {
this.scrollEnable = true;
}
}
},
//更新使用页面滚动时slot="top"或"bottom"插入view的高度
_updatePageScrollTopOrBottomHeight(type) {
// #ifndef APP-NVUE
if (!this.usePageScroll) return;
// #endif
this._doCheckScrollViewShouldFullHeight(this.realTotalData);
const node = `.zp-page-${type}`;
const marginText = `margin${type.slice(0,1).toUpperCase() + type.slice(1)}`;
let safeAreaInsetBottomAdd = this.safeAreaInsetBottom;
this.$nextTick(() => {
let delayTime = 0;
// #ifdef MP-BAIDU || APP-NVUE
delayTime = 50;
// #endif
u.delay(() => {
this._getNodeClientRect(node).then((res) => {
if (res) {
let pageScrollNodeHeight = res[0].height;
if (type === 'bottom') {
if (safeAreaInsetBottomAdd) {
pageScrollNodeHeight += this.safeAreaBottom;
}
} else {
this.cacheTopHeight = pageScrollNodeHeight;
}
this.$set(this.scrollViewStyle, marginText, `${pageScrollNodeHeight}px`);
} else if (safeAreaInsetBottomAdd) {
this.$set(this.scrollViewStyle, marginText, `${this.safeAreaBottom}px`);
}
});
}, delayTime)
})
},
}
}

461
src/uni_modules/z-paging/components/z-paging/js/modules/virtual-list.js

@ -0,0 +1,461 @@
// [z-paging]虚拟列表模块
import u from '.././z-paging-utils'
import c from '.././z-paging-constant'
import Enum from '.././z-paging-enum'
export default {
props: {
//是否使用虚拟列表,默认为否
useVirtualList: {
type: Boolean,
default: u.gc('useVirtualList', false)
},
//在使用虚拟列表时,是否使用兼容模式,默认为否
useCompatibilityMode: {
type: Boolean,
default: u.gc('useCompatibilityMode', false)
},
//使用兼容模式时传递的附加数据
extraData: {
type: Object,
default: function() {
return u.gc('extraData', {});
}
},
//是否在z-paging内部循环渲染列表(内置列表),默认为否。若use-virtual-list为true,则此项恒为true
useInnerList: {
type: Boolean,
default: u.gc('useInnerList', false)
},
//强制关闭inner-list,默认为false,如果为true将强制关闭innerList,适用于开启了虚拟列表后需要强制关闭inner-list的情况
forceCloseInnerList: {
type: Boolean,
default: u.gc('forceCloseInnerList', false)
},
//内置列表cell的key名称,仅nvue有效,在nvue中开启use-inner-list时必须填此项
cellKeyName: {
type: String,
default: u.gc('cellKeyName', '')
},
//innerList样式
innerListStyle: {
type: Object,
default: function() {
return u.gc('innerListStyle', {});
}
},
//innerCell样式
innerCellStyle: {
type: Object,
default: function() {
return u.gc('innerCellStyle', {});
}
},
//预加载的列表可视范围(列表高度)页数,默认为12,即预加载当前页及上下各12页的cell。此数值越大,则虚拟列表中加载的dom越多,内存消耗越大(会维持在一个稳定值),但增加预加载页面数量可缓解快速滚动短暂白屏问题
preloadPage: {
type: [Number, String],
default: u.gc('preloadPage', 12),
validator: (value) => {
if (value <= 0) u.consoleErr('preload-page必须大于0!');
return value > 0;
}
},
//虚拟列表cell高度模式,默认为fixed,也就是每个cell高度完全相同,将以第一个cell高度为准进行计算。可选值【dynamic】,即代表高度是动态非固定的,【dynamic】性能低于【fixed】。
cellHeightMode: {
type: String,
default: u.gc('cellHeightMode', Enum.CellHeightMode.Fixed)
},
//虚拟列表列数,默认为1。常用于每行有多列的情况,例如每行有2列数据,需要将此值设置为2
virtualListCol: {
type: [Number, String],
default: u.gc('virtualListCol', 1)
},
//虚拟列表scroll取样帧率,默认为80,过低容易出现白屏问题,过高容易出现卡顿问题
virtualScrollFps: {
type: [Number, String],
default: u.gc('virtualScrollFps', 80)
},
},
data() {
return {
virtualListKey: u.getInstanceId(),
virtualPageHeight: 0,
virtualCellHeight: 0,
virtualScrollTimeStamp: 0,
virtualList: [],
virtualPlaceholderTopHeight: 0,
virtualPlaceholderBottomHeight: 0,
virtualTopRangeIndex: 0,
virtualBottomRangeIndex: 0,
lastVirtualTopRangeIndex: 0,
lastVirtualBottomRangeIndex: 0,
virtualItemInsertedCount: 0,
virtualHeightCacheList: [],
getCellHeightRetryCount: {
fixed: 0,
dynamic: 0
},
pagingOrgTop: -1,
updateVirtualListFromDataChange: false
}
},
watch: {
realTotalData(newVal) {
// #ifndef APP-NVUE
if (this.finalUseVirtualList) {
this.updateVirtualListFromDataChange = true;
this.$nextTick(() => {
this.getCellHeightRetryCount.fixed = 0;
!newVal.length && this._resetDynamicListState(!this.isUserPullDown);
newVal.length && this.cellHeightMode === Enum.CellHeightMode.Fixed && this.isFirstPage && this._updateFixedCellHeight();
this._updateVirtualScroll(this.oldScrollTop);
})
}
// #endif
},
virtualList(newVal){
this.$emit('update:virtualList', newVal);
this.$emit('virtualListChange', newVal);
}
},
computed: {
virtualCellIndexKey() {
return c.listCellIndexKey;
},
finalUseVirtualList() {
if (this.useVirtualList && this.usePageScroll){
u.consoleErr('使用页面滚动时,开启虚拟列表无效!');
}
return this.useVirtualList && !this.usePageScroll;
},
finalUseInnerList() {
return this.useInnerList || (this.finalUseVirtualList && !this.forceCloseInnerList);
},
finalCellKeyName() {
// #ifdef APP-NVUE
if (this.finalUseVirtualList && !this.cellKeyName.length){
u.consoleErr('在nvue中开启use-virtual-list必须设置cell-key-name,否则将可能导致列表渲染错误!');
}
// #endif
return this.cellKeyName;
},
finalVirtualPageHeight(){
return this.virtualPageHeight > 0 ? this.virtualPageHeight : this.windowHeight;
},
virtualRangePageHeight(){
return this.finalVirtualPageHeight * this.preloadPage;
},
virtualScrollDisTimeStamp() {
return 1000 / this.virtualScrollFps;
},
},
methods: {
//在使用动态高度虚拟列表时,若在列表数组中需要插入某个item,需要调用此方法;item:需要插入的item,index:插入的cell位置,若index为2,则插入的item在原list的index=1之后,index从0开始
doInsertVirtualListItem(item, index) {
if (this.cellHeightMode !== Enum.CellHeightMode.Dynamic) return;
this.virtualItemInsertedCount ++;
if (!item || Object.prototype.toString.call(item) !== '[object Object]') {
item = { item };
}
const cellIndexKey = this.virtualCellIndexKey;
item[cellIndexKey] = `custom-${this.virtualItemInsertedCount}`;
item[c.listCellIndexUniqueKey] = `${this.virtualListKey}-${item[cellIndexKey]}`;
this.totalData.splice(index, 0, item);
this.$nextTick(async () => {
let retryCount = 0;
while (retryCount <= 10) {
await u.wait(c.delayTime);
const cellNode = await this._getNodeClientRect(`#zp-id-${item[cellIndexKey]}`, this.finalUseInnerList);
if (!cellNode) {
retryCount ++;
continue;
}
const currentHeight = cellNode ? cellNode[0].height : 0;
const lastHeightCache = this.virtualHeightCacheList[index - 1];
const lastTotalHeight = lastHeightCache ? lastHeightCache.totalHeight : 0;
this.virtualHeightCacheList.splice(index, 0, {
height: currentHeight,
lastTotalHeight,
totalHeight: lastTotalHeight + currentHeight
});
for (let i = index + 1; i < this.virtualHeightCacheList.length; i++) {
const thisNode = this.virtualHeightCacheList[i];
thisNode.lastTotalHeight += currentHeight;
thisNode.totalHeight += currentHeight;
}
this._updateVirtualScroll(this.oldScrollTop);
break;
}
})
},
//在使用动态高度虚拟列表时,手动更新指定cell的缓存高度(当cell高度在初始化之后再次改变时调用);index:需要更新的cell在列表中的位置,从0开始
didUpdateVirtualListCell(index) {
if (this.cellHeightMode !== Enum.CellHeightMode.Dynamic) return;
const currentNode = this.virtualHeightCacheList[index];
this.$nextTick(() => {
this._getNodeClientRect(`#zp-id-${index}`, this.finalUseInnerList).then(cellNode => {
const cellNodeHeight = cellNode ? cellNode[0].height : 0;
const heightDis = cellNodeHeight - currentNode.height;
currentNode.height = cellNodeHeight;
currentNode.totalHeight = currentNode.lastTotalHeight + cellNodeHeight;
for (let i = index + 1; i < this.virtualHeightCacheList.length; i++) {
const thisNode = this.virtualHeightCacheList[i];
thisNode.totalHeight += heightDis;
thisNode.lastTotalHeight += heightDis;
}
});
})
},
//在使用动态高度虚拟列表时,若删除了列表数组中的某个item,需要调用此方法以更新高度缓存数组;index:删除的cell在列表中的位置,从0开始
didDeleteVirtualListCell(index) {
if (this.cellHeightMode !== Enum.CellHeightMode.Dynamic) return;
const currentNode = this.virtualHeightCacheList[index];
for (let i = index + 1; i < this.virtualHeightCacheList.length; i++) {
const thisNode = this.virtualHeightCacheList[i];
thisNode.totalHeight -= currentNode.height;
thisNode.lastTotalHeight -= currentNode.height;
}
this.virtualHeightCacheList.splice(index, 1);
},
//初始化虚拟列表
_virtualListInit() {
this.$nextTick(() => {
u.delay(() => {
this._getNodeClientRect('.zp-scroll-view').then(node => {
if (node) {
this.pagingOrgTop = node[0].top;
this.virtualPageHeight = node[0].height;
}
});
});
})
},
//cellHeightMode为fixed时获取第一个cell高度
_updateFixedCellHeight() {
this.$nextTick(() => {
u.delay(() => {
this._getNodeClientRect(`#zp-id-${0}`,this.finalUseInnerList).then(cellNode => {
if (!cellNode) {
if (this.getCellHeightRetryCount.fixed > 10) return;
this.getCellHeightRetryCount.fixed ++;
this._updateFixedCellHeight();
} else {
this.virtualCellHeight = cellNode[0].height;
this._updateVirtualScroll(this.oldScrollTop);
}
});
}, c.delayTime, 'updateFixedCellHeightDelay');
})
},
//cellHeightMode为dynamic时获取每个cell高度
_updateDynamicCellHeight(list, dataFrom = 'bottom') {
const dataFromTop = dataFrom === 'top';
const heightCacheList = this.virtualHeightCacheList;
const currentCacheList = dataFromTop ? [] : heightCacheList;
let listTotalHeight = 0;
this.$nextTick(() => {
u.delay(async () => {
for (let i = 0; i < list.length; i++) {
const cellNode = await this._getNodeClientRect(`#zp-id-${list[i][this.virtualCellIndexKey]}`, this.finalUseInnerList);
const currentHeight = cellNode ? cellNode[0].height : 0;
if (!cellNode) {
if (this.getCellHeightRetryCount.dynamic <= 10) {
heightCacheList.splice(heightCacheList.length - i, i);
this.getCellHeightRetryCount.dynamic ++;
this._updateDynamicCellHeight(list, dataFrom);
}
return;
}
const lastHeightCache = currentCacheList.length ? currentCacheList.slice(-1)[0] : null;
const lastTotalHeight = lastHeightCache ? lastHeightCache.totalHeight : 0;
currentCacheList.push({
height: currentHeight,
lastTotalHeight,
totalHeight: lastTotalHeight + currentHeight
});
if (dataFromTop) {
listTotalHeight += currentHeight;
}
}
if (dataFromTop && list.length) {
for (let i = 0; i < heightCacheList.length; i++) {
const heightCacheItem = heightCacheList[i];
heightCacheItem.lastTotalHeight += listTotalHeight;
heightCacheItem.totalHeight += listTotalHeight;
}
this.virtualHeightCacheList = currentCacheList.concat(heightCacheList);
}
this._updateVirtualScroll(this.oldScrollTop);
}, c.delayTime, 'updateDynamicCellHeightDelay')
})
},
//设置cellItem的index
_setCellIndex(list, dataFrom = 'bottom') {
let currentItemIndex = 0;
const cellIndexKey = this.virtualCellIndexKey;
if (this.totalData.length) {
if (dataFrom === 'bottom') {
currentItemIndex = this.realTotalData.length;
const lastItem = this.realTotalData.length ? this.realTotalData.slice(-1)[0] : null;
if (lastItem && lastItem[cellIndexKey] !== undefined) {
currentItemIndex = lastItem[cellIndexKey] + 1;
}
} else if (dataFrom === 'top') {
const firstItem = this.realTotalData.length ? this.realTotalData[0] : null;
if (firstItem && firstItem[cellIndexKey] !== undefined) {
currentItemIndex = firstItem[cellIndexKey] - list.length;
}
}
} else {
this._resetDynamicListState();
}
for (let i = 0; i < list.length; i++) {
let item = list[i];
if (!item || Object.prototype.toString.call(item) !== '[object Object]') {
item = { item };
}
item[cellIndexKey] = currentItemIndex + i;
item[c.listCellIndexUniqueKey] = `${this.virtualListKey}-${item[cellIndexKey]}`;
list[i] = item;
}
this.getCellHeightRetryCount.dynamic = 0;
this.cellHeightMode === Enum.CellHeightMode.Dynamic && this._updateDynamicCellHeight(list, dataFrom);
},
//更新scroll滚动
_updateVirtualScroll(scrollTop, scrollDiff = 0) {
const currentTimeStamp = u.getTime();
scrollTop === 0 && this._resetTopRange();
if (scrollTop !== 0 && this.virtualScrollTimeStamp && currentTimeStamp - this.virtualScrollTimeStamp <= this.virtualScrollDisTimeStamp) {
return;
}
this.virtualScrollTimeStamp = currentTimeStamp;
let scrollIndex = 0;
const cellHeightMode = this.cellHeightMode;
if (cellHeightMode === Enum.CellHeightMode.Fixed) {
scrollIndex = parseInt(scrollTop / this.virtualCellHeight) || 0;
this._updateFixedTopRangeIndex(scrollIndex);
this._updateFixedBottomRangeIndex(scrollIndex);
} else if(cellHeightMode === Enum.CellHeightMode.Dynamic) {
const scrollDirection = scrollDiff > 0 ? 'top' : 'bottom';
const rangePageHeight = this.virtualRangePageHeight;
const topRangePageOffset = scrollTop - rangePageHeight;
const bottomRangePageOffset = scrollTop + this.finalVirtualPageHeight + rangePageHeight;
let virtualBottomRangeIndex = 0;
let virtualPlaceholderBottomHeight = 0;
let reachedLimitBottom = false;
const heightCacheList = this.virtualHeightCacheList;
const lastHeightCache = !!heightCacheList ? heightCacheList.slice(-1)[0] : null;
let startTopRangeIndex = this.virtualTopRangeIndex;
if (scrollDirection === 'bottom') {
for (let i = startTopRangeIndex; i < heightCacheList.length; i++){
const heightCacheItem = heightCacheList[i];
if (heightCacheItem && heightCacheItem.totalHeight > topRangePageOffset) {
this.virtualTopRangeIndex = i;
this.virtualPlaceholderTopHeight = heightCacheItem.lastTotalHeight;
break;
}
}
} else {
let topRangeMatched = false;
for (let i = startTopRangeIndex; i >= 0; i--){
const heightCacheItem = heightCacheList[i];
if (heightCacheItem && heightCacheItem.totalHeight < topRangePageOffset) {
this.virtualTopRangeIndex = i;
this.virtualPlaceholderTopHeight = heightCacheItem.lastTotalHeight;
topRangeMatched = true;
break;
}
}
!topRangeMatched && this._resetTopRange();
}
for (let i = this.virtualTopRangeIndex; i < heightCacheList.length; i++){
const heightCacheItem = heightCacheList[i];
if (heightCacheItem && heightCacheItem.totalHeight > bottomRangePageOffset) {
virtualBottomRangeIndex = i;
virtualPlaceholderBottomHeight = lastHeightCache.totalHeight - heightCacheItem.totalHeight;
reachedLimitBottom = true;
break;
}
}
if (!reachedLimitBottom || this.virtualBottomRangeIndex === 0) {
this.virtualBottomRangeIndex = this.realTotalData.length ? this.realTotalData.length - 1 : this.pageSize;
this.virtualPlaceholderBottomHeight = 0;
} else {
this.virtualBottomRangeIndex = virtualBottomRangeIndex;
this.virtualPlaceholderBottomHeight = virtualPlaceholderBottomHeight;
}
this._updateVirtualList();
}
},
//更新fixedCell模式下topRangeIndex&placeholderTopHeight
_updateFixedTopRangeIndex(scrollIndex) {
let virtualTopRangeIndex = this.virtualCellHeight === 0 ? 0 : scrollIndex - (parseInt(this.finalVirtualPageHeight / this.virtualCellHeight) || 1) * this.preloadPage;
virtualTopRangeIndex *= this.virtualListCol;
virtualTopRangeIndex = Math.max(0, virtualTopRangeIndex);
this.virtualTopRangeIndex = virtualTopRangeIndex;
this.virtualPlaceholderTopHeight = (virtualTopRangeIndex / this.virtualListCol) * this.virtualCellHeight;
},
//更新fixedCell模式下bottomRangeIndex&placeholderBottomHeight
_updateFixedBottomRangeIndex(scrollIndex) {
let virtualBottomRangeIndex = this.virtualCellHeight === 0 ? this.pageSize : scrollIndex + (parseInt(this.finalVirtualPageHeight / this.virtualCellHeight) || 1) * (this.preloadPage + 1);
virtualBottomRangeIndex *= this.virtualListCol;
virtualBottomRangeIndex = Math.min(this.realTotalData.length, virtualBottomRangeIndex);
this.virtualBottomRangeIndex = virtualBottomRangeIndex;
this.virtualPlaceholderBottomHeight = (this.realTotalData.length - virtualBottomRangeIndex) * this.virtualCellHeight / this.virtualListCol;
this._updateVirtualList();
},
//更新virtualList
_updateVirtualList() {
const shouldUpdateList = this.updateVirtualListFromDataChange || (this.lastVirtualTopRangeIndex !== this.virtualTopRangeIndex || this.lastVirtualBottomRangeIndex !== this.virtualBottomRangeIndex);
if (shouldUpdateList) {
this.updateVirtualListFromDataChange = false;
this.lastVirtualTopRangeIndex = this.virtualTopRangeIndex;
this.lastVirtualBottomRangeIndex = this.virtualBottomRangeIndex;
this.virtualList = this.realTotalData.slice(this.virtualTopRangeIndex, this.virtualBottomRangeIndex + 1);
}
},
//重置动态cell模式下的高度缓存数据、虚拟列表和滚动状态
_resetDynamicListState(resetVirtualList = false) {
this.virtualHeightCacheList = [];
if (resetVirtualList) {
this.virtualList = [];
}
this.virtualTopRangeIndex = 0;
this.virtualPlaceholderTopHeight = 0;
},
//重置topRangeIndex和placeholderTopHeight
_resetTopRange() {
this.virtualTopRangeIndex = 0;
this.virtualPlaceholderTopHeight = 0;
this._updateVirtualList();
},
//检测虚拟列表当前滚动位置,如发现滚动位置不正确则重新计算虚拟列表相关参数(为解决在App中可能出现的长时间进入后台后打开App白屏的问题)
_checkVirtualListScroll() {
if (this.finalUseVirtualList) {
this.$nextTick(() => {
this._getNodeClientRect('.zp-paging-touch-view').then(node => {
const currentTop = node ? node[0].top : 0;
if (!node || (currentTop === this.pagingOrgTop && this.virtualPlaceholderTopHeight !== 0)) {
this._updateVirtualScroll(0);
}
});
})
}
},
//处理使用内置列表时点击了cell事件
_innerCellClick(item, index) {
this.$emit('innerCellClick', item, index);
}
}
}

21
src/uni_modules/z-paging/components/z-paging/js/z-paging-config.js

@ -0,0 +1,21 @@
// [z-paging]处理main.js中的配置信息工具
let config = null;
let getedStorage = false;
const storageKey = 'Z-PAGING-CONFIG-STORAGE-KEY'
function setConfig(value) {
uni.setStorageSync(storageKey, value);
}
function getConfig() {
if (getedStorage) return config;
config = uni.getStorageSync(storageKey);
getedStorage = true;
return config;
}
export default {
setConfig,
getConfig
};

12
src/uni_modules/z-paging/components/z-paging/js/z-paging-constant.js

@ -0,0 +1,12 @@
// [z-paging]常量
export default {
version: '2.6.0',
delayTime: 100,
errorUpdateKey: 'z-paging-error-emit',
completeUpdateKey: 'z-paging-complete-emit',
cachePrefixKey: 'z-paging-cache',
listCellIndexKey: 'zp_index',
listCellIndexUniqueKey: 'zp_unique_index'
}

44
src/uni_modules/z-paging/components/z-paging/js/z-paging-enum.js

@ -0,0 +1,44 @@
// [z-paging]枚举
export default {
//当前加载类型 0.下拉刷新 1.上拉加载更多
LoadingType: {
Refresher: 0,
LoadingMore: 1
},
//下拉刷新状态 0.默认状态 1.松手立即刷新 2.刷新中 3.刷新结束
Refresher: {
Default: 0,
ReleaseToRefresh: 1,
Loading: 2,
Complete: 3
},
//底部加载更多状态 0.默认状态 1.加载中 2.没有更多数据 3.加载失败
More: {
Default: 0,
Loading: 1,
NoMore: 2,
Fail: 3
},
//@query触发来源 0.用户主动下拉刷新 1.通过reload触发 2.通过refresh触发 3.通过滚动到底部加载更多或点击底部加载更多触发
QueryFrom: {
UserPullDown: 0,
Reload: 1,
Refresh: 2,
LoadingMore: 3
},
//虚拟列表cell高度模式
CellHeightMode: {
//固定高度
Fixed: 'fixed',
//动态高度
Dynamic: 'dynamic'
},
//列表缓存模式
CacheMode: {
//默认模式,只会缓存一次
Default: 'default',
//总是缓存,每次列表刷新(下拉刷新、调用reload等)都会更新缓存
Always: 'always'
}
}

48
src/uni_modules/z-paging/components/z-paging/js/z-paging-interceptor.js

@ -0,0 +1,48 @@
// [z-paging]拦截器
//拦截&处理@query事件
function handleQuery(callback) {
try {
setTimeout(function() {
_getApp().globalData.zp_handleQueryCallback = callback;
}, 1);
} catch (e) {}
}
//拦截&处理@query事件(私有,请勿调用)
function _handleQuery(pageNo, pageSize, from, lastItem){
const callback = _getApp().globalData.zp_handleQueryCallback;
return callback ? callback(pageNo, pageSize, from, lastItem) : [pageNo, pageSize, from];
}
//拦截&处理系统language转i18n local
function handleLanguage2Local(callback) {
try {
setTimeout(function() {
_getApp().globalData.zp_handleLanguage2LocalCallback = callback;
}, 1);
} catch (e) {}
}
//拦截&处理系统language转i18n local(私有,请勿调用)
function _handleLanguage2Local(language, local){
const callback = _getApp().globalData.zp_handleLanguage2LocalCallback;
return callback ? callback(language, local) : local;
}
//获取当前app对象
function _getApp(){
// #ifndef APP-NVUE
return getApp();
// #endif
// #ifdef APP-NVUE
return getApp({ allowDefault: true });
// #endif
}
export default {
handleQuery,
_handleQuery,
handleLanguage2Local,
_handleLanguage2Local
};

446
src/uni_modules/z-paging/components/z-paging/js/z-paging-main.js

@ -0,0 +1,446 @@
// [z-paging]核心js
import zStatic from './z-paging-static'
import c from './z-paging-constant'
import u from './z-paging-utils'
import zPagingRefresh from '../components/z-paging-refresh'
import zPagingLoadMore from '../components/z-paging-load-more'
import zPagingEmptyView from '../../z-paging-empty-view/z-paging-empty-view'
// modules
import commonLayoutModule from './modules/common-layout'
import dataHandleModule from './modules/data-handle'
import i18nModule from './modules/i18n'
import nvueModule from './modules/nvue'
import emptyModule from './modules/empty'
import refresherModule from './modules/refresher'
import loadMoreModule from './modules/load-more'
import loadingModule from './modules/loading'
import scrollerModule from './modules/scroller'
import backToTopModule from './modules/back-to-top'
import virtualListModule from './modules/virtual-list'
import Enum from './z-paging-enum'
const systemInfo = uni.getSystemInfoSync();
export default {
name: "z-paging",
components: {
zPagingRefresh,
zPagingLoadMore,
zPagingEmptyView
},
mixins: [
commonLayoutModule,
dataHandleModule,
i18nModule,
nvueModule,
emptyModule,
refresherModule,
loadMoreModule,
loadingModule,
scrollerModule,
backToTopModule,
virtualListModule
],
data() {
return {
//--------------静态资源---------------
base64Arrow: zStatic.base64Arrow,
base64Flower: zStatic.base64Flower,
base64BackToTop: zStatic.base64BackToTop,
//-------------全局数据相关--------------
//当前加载类型
loadingType: Enum.LoadingType.Refresher,
requestTimeStamp: 0,
chatRecordLoadingMoreText: '',
wxsPropType: '',
renderPropScrollTop: -1,
checkScrolledToBottomTimeOut: null,
cacheTopHeight: -1,
//--------------状态&判断---------------
insideOfPaging: -1,
isLoadFailed: false,
isIos: systemInfo.platform === 'ios',
disabledBounce: false,
fromCompleteEmit: false,
disabledCompleteEmit: false,
pageLaunched: false,
//---------------wxs相关---------------
wxsIsScrollTopInTopRange: true,
wxsScrollTop: 0,
wxsPageScrollTop: 0,
wxsOnPullingDown: false,
};
},
props: {
//调用complete后延迟处理的时间,单位为毫秒,默认0毫秒,优先级高于minDelay
delay: {
type: [Number, String],
default: u.gc('delay', 0),
},
//触发@query后最小延迟处理的时间,单位为毫秒,默认0毫秒,优先级低于delay(假设设置为300毫秒,若分页请求时间小于300毫秒,则在调用complete后延迟[300毫秒-请求时长];若请求时长大于300毫秒,则不延迟),当show-refresher-when-reload为true或reload(true)时,其最小值为400
minDelay: {
type: [Number, String],
default: u.gc('minDelay', 0),
},
//设置z-paging的style,部分平台(如微信小程序)无法直接修改组件的style,可使用此属性代替
pagingStyle: {
type: Object,
default: function() {
return u.gc('pagingStyle', {});
},
},
//z-paging的高度,优先级低于pagingStyle中设置的height;传字符串,如100px、100rpx、100%
height: {
type: String,
default: u.gc('height', '')
},
//z-paging的宽度,优先级低于pagingStyle中设置的width;传字符串,如100px、100rpx、100%
width: {
type: String,
default: u.gc('width', '')
},
//z-paging的背景色,优先级低于pagingStyle中设置的background。传字符串,如"#ffffff"
bgColor: {
type: String,
default: u.gc('bgColor', '')
},
//设置z-paging的容器(插槽的父view)的style
pagingContentStyle: {
type: Object,
default: function() {
return u.gc('pagingContentStyle', {});
},
},
//z-paging是否自动高度,若自动高度则会自动铺满屏幕
autoHeight: {
type: Boolean,
default: u.gc('autoHeight', false)
},
//z-paging是否自动高度时,附加的高度,注意添加单位px或rpx,若需要减少高度,则传负数
autoHeightAddition: {
type: [Number, String],
default: u.gc('autoHeightAddition', '0px')
},
//loading(下拉刷新、上拉加载更多)的主题样式,支持black,white,默认black
defaultThemeStyle: {
type: String,
default: u.gc('defaultThemeStyle', 'black')
},
//z-paging是否使用fixed布局,若使用fixed布局,则z-paging的父view无需固定高度,z-paging高度默认为100%,默认为是(当使用内置scroll-view滚动时有效)
fixed: {
type: Boolean,
default: u.gc('fixed', true)
},
//是否开启底部安全区域适配
safeAreaInsetBottom: {
type: Boolean,
default: u.gc('safeAreaInsetBottom', false)
},
//开启底部安全区域适配后,是否使用placeholder形式实现,默认为否。为否时滚动区域会自动避开底部安全区域,也就是所有滚动内容都不会挡住底部安全区域,若设置为是,则滚动时滚动内容会挡住底部安全区域,但是当滚动到底部时才会避开底部安全区域
useSafeAreaPlaceholder: {
type: Boolean,
default: u.gc('useSafeAreaPlaceholder', false)
},
//slot="top"的view的z-index,默认为99,仅使用页面滚动时有效
topZIndex: {
type: Number,
default: u.gc('topZIndex', 99)
},
//z-paging内容容器父view的z-index,默认为1
superContentZIndex: {
type: Number,
default: u.gc('superContentZIndex', 1)
},
//z-paging内容容器部分的z-index,默认为10
contentZIndex: {
type: Number,
default: u.gc('contentZIndex', 10)
},
//使用页面滚动时,是否在不满屏时自动填充满屏幕,默认为是
autoFullHeight: {
type: Boolean,
default: u.gc('autoFullHeight', true)
},
//是否监听列表触摸方向改变,默认为否
watchTouchDirectionChange: {
type: Boolean,
default: u.gc('watchTouchDirectionChange', false)
},
},
created(){
if (this.createdReload && !this.refresherOnly && this.auto) {
this._startLoading();
this.$nextTick(this._preReload);
}
},
mounted() {
this.wxsPropType = u.getTime().toString();
this.renderJsIgnore;
if (!this.createdReload && !this.refresherOnly && this.auto) {
this.$nextTick(this._preReload);
}
this.finalUseCache && this._setListByLocalCache();
let delay = 0;
// #ifdef H5 || MP
delay = c.delayTime;
// #endif
this.$nextTick(() => {
this.systemInfo = uni.getSystemInfoSync();
!this.usePageScroll && this.autoHeight && this._setAutoHeight();
this.loaded = true;
})
this.updatePageScrollTopHeight();
this.updatePageScrollBottomHeight();
this.updateLeftAndRightWidth();
if (this.finalRefresherEnabled && this.useCustomRefresher) {
this.$nextTick(() => {
this.isTouchmoving = true;
})
}
this._onEmit();
// #ifdef APP-NVUE
if (!this.isIos && !this.useChatRecordMode) {
this.nLoadingMoreFixedHeight = true;
}
this._nUpdateRefresherWidth();
// #endif
// #ifndef APP-NVUE
this.finalUseVirtualList && this._virtualListInit();
// #endif
// #ifndef APP-PLUS
this.$nextTick(() => {
setTimeout(() => {
this._getCssSafeAreaInsetBottom(() => this.safeAreaInsetBottom && this.updatePageScrollBottomHeight());
}, delay)
})
// #endif
},
destroyed() {
this._offEmit();
},
// #ifdef VUE3
unmounted() {
this._offEmit();
},
// #endif
watch: {
defaultThemeStyle: {
handler(newVal) {
if (newVal.length) {
this.finalRefresherDefaultStyle = newVal;
}
},
immediate: true
},
autoHeight(newVal) {
this.loaded && !this.usePageScroll && this._setAutoHeight(newVal);
},
autoHeightAddition(newVal) {
this.loaded && !this.usePageScroll && this.autoHeight && this._setAutoHeight(newVal);
},
},
computed: {
finalPagingStyle() {
const pagingStyle = this.pagingStyle;
if (!this.systemInfo) return pagingStyle;
const { windowTop, windowBottom } = this;
if (!this.usePageScroll && this.fixed) {
if (windowTop && !pagingStyle.top) {
pagingStyle.top = windowTop + 'px';
}
if (windowBottom && !pagingStyle.bottom) {
pagingStyle.bottom = windowBottom + 'px';
}
}
if (this.bgColor.length && !pagingStyle['background']) {
pagingStyle['background'] = this.bgColor;
}
if (this.height.length && !pagingStyle['height']) {
pagingStyle['height'] = this.height;
}
if (this.width.length && !pagingStyle['width']) {
pagingStyle['width'] = this.width;
}
return pagingStyle;
},
finalLowerThreshold() {
return u.convertToPx(this.lowerThreshold);
},
finalPagingContentStyle() {
if (this.contentZIndex != 1) {
this.pagingContentStyle['z-index'] = this.contentZIndex;
this.pagingContentStyle['position'] = 'relative';
}
return this.pagingContentStyle;
},
renderJsIgnore() {
if ((this.usePageScroll && this.useChatRecordMode) || !this.refresherEnabled || !this.useCustomRefresher) {
this.$nextTick(() => {
this.renderPropScrollTop = 10;
})
}
return 0;
},
windowHeight() {
if (!this.systemInfo) return 0;
return this.systemInfo.windowHeight || 0;
},
windowBottom() {
if (!this.systemInfo) return 0;
let windowBottom = this.systemInfo.windowBottom || 0;
if (this.safeAreaInsetBottom && !this.useSafeAreaPlaceholder) {
windowBottom += this.safeAreaBottom;
}
return windowBottom;
},
isIosAndH5() {
// #ifndef H5
return false;
// #endif
return this.isIos;
}
},
methods: {
//当前版本号
getVersion() {
return `z-paging v${c.version}`;
},
//设置nvue List的specialEffects
setSpecialEffects(args) {
this.setListSpecialEffects(args);
},
//与setSpecialEffects等效,兼容旧版本
setListSpecialEffects(args) {
this.nFixFreezing = args && Object.keys(args).length;
if (this.isIos) {
this.privateRefresherEnabled = 0;
}
!this.usePageScroll && this.$refs['zp-n-list'].setSpecialEffects(args);
},
// #ifdef APP-VUE
//当app长时间进入后台后进入前台,因系统内存管理导致app重新加载时,进行一些适配处理
_handlePageLaunch() {
// 首次触发不进行处理,只有进入后台后打开app重新加载时才处理
if (this.pageLaunched) {
// 解决在vue3+ios中,app ReLaunch时顶部下拉刷新展示位置向下偏移的问题
// #ifdef VUE3
this.refresherThresholdUpdateTag = 1;
this.$nextTick(() => {
this.refresherThresholdUpdateTag = 0;
})
// #endif
// 解决使用虚拟列表时,app ReLaunch时白屏问题
this._checkVirtualListScroll();
}
this.pageLaunched = true;
},
// #endif
//使手机发生较短时间的振动(15ms)
_doVibrateShort() {
// #ifndef H5
// #ifdef APP-PLUS
if (this.isIos) {
const UISelectionFeedbackGenerator = plus.ios.importClass('UISelectionFeedbackGenerator');
const feedbackGenerator = new UISelectionFeedbackGenerator();
feedbackGenerator.init();
setTimeout(() => {
feedbackGenerator.selectionChanged();
}, 0)
} else {
plus.device.vibrate(15);
}
// #endif
// #ifndef APP-PLUS
uni.vibrateShort();
// #endif
// #endif
},
//设置z-paging高度
async _setAutoHeight(shouldFullHeight = true, scrollViewNode = null) {
let heightKey = 'min-height';
// #ifndef APP-NVUE
heightKey = 'min-height';
// #endif
try {
if (shouldFullHeight) {
let finalScrollViewNode = scrollViewNode || await this._getNodeClientRect('.zp-scroll-view');
let finalScrollBottomNode = await this._getNodeClientRect('.zp-page-bottom');
if (finalScrollViewNode) {
const scrollViewTop = finalScrollViewNode[0].top;
let scrollViewHeight = this.windowHeight - scrollViewTop;
scrollViewHeight -= finalScrollBottomNode ? finalScrollBottomNode[0].height : 0;
const additionHeight = u.convertToPx(this.autoHeightAddition);
const finalHeight = scrollViewHeight + additionHeight - (this.insideMore ? 1 : 0) + 'px !important';
this.$set(this.scrollViewStyle, heightKey, finalHeight);
this.$set(this.scrollViewInStyle, heightKey, finalHeight);
}
} else {
this.$delete(this.scrollViewStyle, heightKey);
this.$delete(this.scrollViewInStyle, heightKey);
}
} catch (e) {}
},
//触发更新是否超出页面状态
_updateInsideOfPaging() {
this.insideMore && this.insideOfPaging === true && setTimeout(this.doLoadMore, 200)
},
//清除timeout
_cleanTimeout(timeout) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
return timeout;
},
//添加全局emit监听
_onEmit() {
uni.$on(c.errorUpdateKey, () => {
this.loading && this.complete(false).catch(() => {});
})
uni.$on(c.completeUpdateKey, (data) => {
setTimeout(() => {
if (this.loading) {
if (!this.disabledCompleteEmit) {
const type = data.type || 'normal';
const list = data.list || data;
const rule = data.rule;
this.fromCompleteEmit = true;
switch (type){
case 'normal':
this.complete(list);
break;
case 'total':
this.completeByTotal(list, rule);
break;
case 'nomore':
this.completeByNoMore(list, rule);
break;
case 'key':
this.completeByKey(list, rule);
break;
default:
break;
}
} else {
this.disabledCompleteEmit = false;
}
}
}, 1);
})
},
//销毁全局emit和listener监听
_offEmit(){
uni.$off(c.errorUpdateKey);
uni.$off(c.completeUpdateKey);
}
},
};

22
src/uni_modules/z-paging/components/z-paging/js/z-paging-mixin.js

@ -0,0 +1,22 @@
// [z-paging]使用页面滚动时引入此mixin,用于监听和处理onPullDownRefresh等页面生命周期方法
export default {
onPullDownRefresh() {
if (this.isPagingRefNotFound()) return;
this.$refs.paging.reload().catch(() => {});
},
onPageScroll(e) {
if (this.isPagingRefNotFound()) return;
this.$refs.paging.updatePageScrollTop(e.scrollTop);
e.scrollTop < 10 && this.$refs.paging.doChatRecordLoadMore();
},
onReachBottom() {
if (this.isPagingRefNotFound()) return;
this.$refs.paging.pageReachBottom();
},
methods: {
isPagingRefNotFound() {
return !this.$refs.paging;
}
}
}

13
src/uni_modules/z-paging/components/z-paging/js/z-paging-static.js

@ -0,0 +1,13 @@
// [z-paging]公用的静态图片资源
export default {
base64Arrow: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAD1BMVEVHcExRUVFMTExRUVFRUVE9CdWsAAAABHRSTlMAjjrY9ZnUjwAAAQFJREFUWMPt2MsNgzAMgGEEE1B1gKJmAIRYoCH7z9RCXrabh33iYktcIv35EEg5ZBh07pvxJU6MFSPOSRnjnBUjUsaciRUjMsb4xIoRCWNiYsUInzE5sWKEyxiYWDbyefqHx1zIeiYTk7mQYziTYecxHvEJjwmIT3hMQELCYSISEg4TkZj0mYTEpM8kJCU9JiMp6TEZyUmbAUhO2gxAQNJiIAKSFgMRmNQZhMCkziAEJTUGIyipMRjBSZkhCE7KDEFIUmTeGCHJxWz0zXaE0GTCG8ZFtEaS347r/1fe11YyHYVfubxayfjoHmc0YYwmmmiiiSaaaKLJ7ckyz5ve+dw3Xw2emdwm9xSbAAAAAElFTkSuQmCC',
base64ArrowWhite: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAElBMVEVHcEz///////////////////+IGTx/AAAABnRSTlMA/dAkXZOhASU/AAABYElEQVRYw+2YwXLCIBCGsdAHWGbyAKZ4zxi9O017rxLf/1UaWFAgA1m8dcpedNSPf/l/Vh0Ya/Wn6hN0JcGvoCqRM4C8VBFiDwBqqNuJKV0rAnCgy3AUqZE57x0iqTL8Br4U3WBf/YWaIlTKfAcELU/h9w72CSVPa3C3OCDvhpHbRp/s2vq4fHhCeiCl2A3m4Qd71DQR257mFBlMcTlbFnFWzNtHxewYEfSiaLS4el8d8nyhmKJd1CF4eOS0keLMAuSxubLBIeIGQW8YHCFFo7EH9+YDcQt9FMZEswTheaNxTHwHT8SZorJjMrEVwo4Zo0U8HSEyZvJMOg4RjnmmRr8nDYeIz3OMkbfE/QhBo+U9RnZJxjGCRh/WKmHEMWLNkfPKsGh/CWJk1JjG0kcuJggTt34VDP8aWAFhp4nybVb5+9qQhjSkIQ1pSEMa8k+Q5U9rV3dF8MpFBK+/7miVq1/HZ2qmo9D+pAAAAABJRU5ErkJggg==',
base64Flower: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAKlBMVEVHcEzDw8Ovr6+pqamUlJTCwsKenp61tbWxsbGysrLNzc2bm5u5ubmjo6MpovhuAAAACnRSTlMA/P79/sHDhiZS0DxZowAABBBJREFUWMPtl89rE0EUx7ctTXatB3MI1SWnDbUKPUgXqh4ED8Uf7KUVSm3ooVSpSii0Fn/gD4j4o+APiEoVmos9FO2celiqZVgwgaKHPQiCCkv+F99kM7Ozm5kxq1dfD91k9pPve9/3ZjbRNHHok/mKli4eIPNgSuRObuN9SqSEzM20iGnm0yIbqCuV7NSSSIV7uyPM6JMBYdeTOanh/QihJYZsUCSby+VkMj2AvOt0rAeQAwqE3lfKMZVlQCZk1QOCKkkVPadITCfIRNKxfoJI5+0OIFtJx14CMSg1mRSDko7VAfksRQzEbGYqxOJcVTWMCH2I1/IACNW0PWU2M8cmAVHtnH5mM1VRWtwKZjOd5JbF6s1IbaYqaotjNlPHgDAnlAizubTR6ovMYn052g/U5qcmOpi0WL8xTS/3IfSet5m8MEr5ajjF5le6dq/OJpobrdY0t3i9QgefWrxW9/1BLhk0E9m8FeUMhhXal499iD0eQRfDF+ts/tttORRerfp+oV7f4xJj82iUYm1Yzod+ZQEAlS/8mMBwKebVmCVp1f0JLS6zKd17+iwRKTARVg2SHtz3iEbBH+Q+U28zW2Jiza8Tjb1YFoYZMsJyjDqp3M9XBQdSdPLFdxEpvOB37JrHcmR/y9+LgoTlCFGZEa2sc6d4PGlweEa2JSVPoVm+IfGG3ZL037iV9oH+P+Jxc4HGVflNq1M0pivao/EopO4b/ojVCP9GjmiXOeS0DOn1o/iiccT4ORnyvBGF3yUywkQajW4Ti0SGuiy/wVSg/L8w+X/8Q+hvUx8Xd90z4oV5a1i88MbFWHz0WZZ1UrTwBGPX3Rat9AFiXRMRjoMdIdJLEOt2h7jrYOzgOamKZSWSNspOS0X8SAqRYmxRL7sg4eLzYmNehcxh3uoyud/BH2Udux4ywxFTc1xC7Mgf4vMhc5S+kSH3Y7yj+qpwIWSoPTVCOOPVthGx9FbGqrwFw6wSFxJr+17zeKcztt3u+2roAEVgUjDd+AHGuxHy2rZHaa8JMkTHEeyi85ANPO9j9BVuBRD2FY5LDMo/Sz/2hReqGIs/KiFin+CsPsYO/yvM3jL2vE8EbX7/Bf8ejtr2GLN65bioAdgLd8Bis/mD5GmP2qeqyo2ZwQEOtAjRIDH7mBKpUcMoApbZJ5UIxkEwxyMZyMxW/uKFvHCFR3SSmerHyDNQ2dF4JG6zIMpBgLfjSF9x1D6smFcYnGApjmSLICO3ecCDWrQ48geba9DI3STy2i7ax6WIB62fSyIZIiO3GFQqSURp8wCo7GhJBGwuSovJBNjb7kT6FPVnIa9qJ2Ko+l9mefGIdinaMp0yC1URYiwsdfNE45EuA5Cx9EhalfvN5s+UyItm81vaB3p4joniN+SCP7Qc1hblAAAAAElFTkSuQmCC',
base64FlowerWhite: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAElBMVEX///9HcEz///////////////84chYNAAAABnRSTlP/AGzCOYZj5g1nAAACfklEQVRYw+2YTVPDIBCGtza9Jw25a0bvcax30o73OOr//yvma2F3YWlpPTijXNpAHrK8LLALVPFium2vNIFSbwGKTGQA2GUiHcD29yDNy3sMIdUBQl7r2H8mOEVqAHgPkYZUS6Qc2zYhQqtjyDZEximCZwWZLIBeIgYShs2NzxKpSUehYpMJhURGb+O+w5BpMCAREKPnCDHbIY20SzhM5yxziAXpOiBXydrekT9i5XDEq4NIIHHgyU5mRGqviII4mREJJA4QJzMiILwlRJzpKxJKvCBm8OsBBbLux0tsPl4RKYm5aPu6jw1U4mGxEUR9g8M1PcqBEp/WJliNgYOXueBzS4jZSIcgY5lCtevgDSgyzE+rAfuOTQMq0yzvoGH18qju27Mayzs4fPyMziCx81NJa5RNfW7vPYK9KOfDiVkBxFHG8hAj9txuoBuSWORsFfkpBf7xKFLSeaOefEojh5jz22DJEqMP8fUyaKdQx+RnG+yXMpe8Aars8ueR1pVH/bW3FyyvPRw90upLDHwpgBDtg4aUBNkxRLXMAi03IhcZtr1m+FeI/O/JNyDmmL1djLOauSlNflBpW18RQ2bPqXI22MXXEk75KRHTnkPkYbESbdKP2ZFk0r5sIwffAjy1lx+vx7NLjB6/E7Jfv5ERKhzpN0w8IDE8IGFDv5dhz10s7GFiXRZcUeLCEG5P5nDq9k4PFDcoMpE3GY4OuxuCXhmuyNB6k0RsLIAvqp9NE5r8ZCSS8gxnUp7ODdYhZTqxuiJ9uyJJtPmpqJ7wVj+XVieS903iViHziqAhchLEJAyb7jWU647EpUofQ0ziUuXXXhDddtlllSwjgSQu7r4BRWhQqfDPMVwAAAAASUVORK5CYII=',
base64Success: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAElBMVEVRUVFHcExTU1NRUVFRUVFRUVFOSlSUAAAABnRSTlP/AI6+VySB3ZENAAACcElEQVRYw+2YyYKCMAyGI8hdpdxdZu7gcpdZ7jL6/s8yYheSNi0aPdqbwOffpGmaFOYPD3gj4bisN7vddv17N/JVgxn5x12IWgIaWTuO/IE3PseQbwjGPo2cgRmHFLJwdm/X643zwiqOKPPJ1nj3sjEP2iiifZWj5bhopSyGaEO2HX5fbQJzwJ+W7x/jw5ZFjsEU0PMph9xE8i5EqprKALW95eJQURkgzw98uJ/JvwGecR7bIjWWsUgVrrIfFZ2HlLy3sKETD1mmRLRMRhGVssRa0xJkdn3SpJBymBkM8+pSSDXMDNyDaToVHd2fgpNt0sjwiUZO19+jGQ+gQEg9Oq+bufmAVGihomNmjQG7UG3020vrlm7lkFnKFGU3kZ0KGAdmKe821pipQ+qEKcrZeTL2g5FsUks4cStjEZWwXg0b0n4GxmEpkWwIs5VBynjgK7xZaz1/0D7OxkVuLpsY5BQNFyLS84VBjjbg0iL2r2EQHBOxBhikuUOkdxODVF1cxHoWtPPsiyXO455Iv34hssCO8EV4ZIYTjS8SR4qYSHRiTiYQ4ZFbHi0iIhhBTi6dTCgSWRcnw4h4yGTuyTAiOGBIWGoZTgSHJQl+LcOJ4OCnW6yX2bMnJ9pidCOXtkTkTrIGpYuOynAiOF14SamMiOCk5Ke+mq8BcOrrvym8d0zKIQnWT+M1WwOQNO4fFiWb18hhERxJPx2fblbPHHyC41VyiAtKBUFBIih7JMWVoIQTFIr3lKPN80WvoLSWFPC653ioTZA0I0FrQ7qU6asaK0H7JmkSJa2ooOGVtNUsc3j9FYHkIkJy3SG6VHnfXKXGP9t4N9Q4Ye98AAAAAElFTkSuQmCC',
base64SuccessWhite: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkBAMAAACCzIhnAAAAGFBMVEVHcEz///////////////////////////8dS1W+AAAAB3RSTlMAiVYk6KvDHLfaegAAAo1JREFUWMPtWEtzmzAQNhCTq910ytXpiyvxTNOr60zrayepx9d02gnX4sTm7xcEiJX2gdnkGJ1A4tOnfWqXyeR1vMRYzrcPD9v5h5MBl3/Ldvx4cxIg/FWC8X0xjLjalM54uhhCfCrRuJURX0pi3EmIqZV7O59vrRZmguStHL9b7S7ftfLwOtiZDw7AHMtmquAQ12b5Wwbnordm8g9zLLO49qc/m2n6aKnhwPOGZ08hAiNHhheiHae1lOUPGZpQkPKa3q0mOUjaRzSRaGUjpy/mmWSwySSpllcEteBKAT52KEnSbblA51pJEPxBQoiH1FP4E3s5+FJv07h6/ylD6ui7B+9fq/ehrFB98ghec9EoVtyjK8pqCHLmCBOwMWSCeWFNN4MbPAk55NhsvoFHSSVR0k5TCTTEzlUGcqV/nVp7n9oIVkmtaqbAEqEgfdgHJPwsEAyZ9r4VAZXFjpEwyaw3+H2v42KYxKhs1XvY/gSSGv+IHyUSuHXCeZhLAgVI3EjgSGo1Fb3xO0tGGU9S2/KAIbtjxpJASG73qox6w5LUq0cEOa+iIONIWIilQSQ0pPa2jgaRQAgQP7c0mITRWGxpMAmEQFN2NAQJNCV0mI6GIIEO47hlQ0ORQLd0nL+hoUjg1m6I1TRr8uYEAriBHLcVFQ5UEMiBe3XkTBEG04WXlGKGxPnMS305XQPA1Ocn2JiuAZwE66fxnKwBnDTuXxZTMq85lwW6kt5ndLqZPefiU1yvmktcUSooChJF2aMprhQlnKJQ5FxRKkcVRa+itNYU8Io2oVkY14w0NMWYlqft91Bj9VHq+ca3b43BxjWJmla0sfKohlfTVpPN+93L/yLQ/IjQ/O5Q/VR5HdL4D7mlxmjwVdELAAAAAElFTkSuQmCC',
base64Empty: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIBAMAAABfdrOtAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAbUExURdvc3EdwTMLBwcjIyLSzs/Hx8ff39////19dXXz7IJEAAAAFdFJOU/4A6J9QDyyutAAAB5VJREFUeNrtnM1z4jYYxhUHkR4hdu9eU7Z75Ct7jgPbs9ZZmSuTrUWPmXTA186e+LMrf0uWLMtf2WkHXQgzln88et5XeiVMwPQdGrhCrpAr5Aq5Qv4TkJ07OGQFMLp1B4VYCz+kDblDQhJGeH4eEDLBYdLOHwaDWNBPIeHLYJAJ3meQ83IoCMTHDBKOBoKYGOeM8G0gyD0LObnDQB5ZSCtTNCBfsM9AboaBPLCQcDAIM1zht/dQEkMsd1DjI4hpw2YzMtBJeBbydWpCTJs3YDKGX62YgfGoVwi9KwtZJAzcYHHRm7sYCKD390nQSIoO5JGZIEOYxNoZ4+deISYLyeL5hLHbJ2QK98W0kudMgJe9Qh73odhO+KZHyNYGvgQS9gmJKhUigwSj3iBPUhXxePWmxBqHw0Mej9WQ3qILVjLC177yxNxXQ/7uK+Mn1aNVLsGsBTaWrSAPobYl0aUHt2fIs2Rgz7c9QYL0pSTkSzILLFtAJMH1cidN998T9E0/Sg73/pEEwrgkYRh86wlC949gJsR6EobBcz8hHOVgKYi2m6kZtodIkjEQvF3QjbGpmplB4/lRgJhxgRS2N15iijAvPmByDtCxfQhPJ8J4CR82rgCCBILarScw6X0OcMUyYrFVmbxErl0ZacFIoloOLdJAO42qY+NMDss2kKS8xmiZxcCpFKXWvpRGbQqJp5ixyRfJMmR6x0Fk+z29kmgWDYI5ziFbdug/84HxvduhWhLOJ2StPDQrMJPSjNANklh8QhB7dBO0yTGRwn1fkOk8rbQjiB8Ymww+JuiuN0icmSccK4naLMWYa/euL0+m23GyM8kgAc6sYeL4z04Qa4WjGepcKIliO8EUGSk7d9OGWOsoK31OSdy8TQZ59Y/hWbaV1IVs5/Ed6UzGK4nANAJiyGhRsZPUg2yzLe9hLyiJIyCaDU7udC2uy9pnkKvidlBUEltzFAqxRhBrBZm7HfZnjEQI3boqTsJq15PUDEaKZLgiJYc8OZtCtnM/4G93OFYooXpvdy0guwWWNQkEHl/j7Jw1XRmtlS9HYJkSPjk1IUnyyRqUKQn45NSDlP1mcg9i6En1ZU2IADnEtHF1Q+JwIcS/d5YakPuDUamEShGUHHikAz9oQCaE0CsrpYjDBVkEHQYdyK+EkKPhVErxqh1xbJ/oQf4gEeVsOIEc41WJNAwcd9GBfCZJezXsJhAvH+ImEEIOzlwXgpw5wQ0gH3MIOcsiQAahZuSD69/UQyxcQEggiQARQseVFO/ASAMCgM9gjkHZmhLENzi1AOhA7ullkMWUrfHKfpMiDBHtDIx6yCS6jseEnDUe7zcT6DGCtnrIY3olZw1hrPHkfucIAJa1EDu/lsVEyVmGGA67coKijeogFnMxlEaAV5ghRdDm1kDuuatZTJBGgJdOthIzsvZbDWRRuh6ScgR4EQLgagQvRQIxxQ4sxqcR4GE+c4CkjZQQW9YF89Y4OFAjOCki5KmiDxsBL3PlSJWlAFVogaoIePlYi2ClCJAHRa/cmre5eqTii4uvisqQJxqnip6pNd68DhEvyEs5xIyHBNdh4thCKhU++10kD7Gy1Up1A/o56FKuRJQWSFCuf8dpbisxhqHSKlSSgvG7VTaFKO5TzYD5VMPUxEB2YJNiqq3xYJ0KrroH8mq7xpoXqEZgfgNRUQsDtTVvUOk3sLUKbqrBr7YGvkCkQNC/9SA+vTYtvERrxiKEmcogk4ZqCLUd59MIEiFYHlIoxelCaJWDMmtOPIa80XVLbkb6hzaEwwTcPEmV4AIRlBGNIEmuJBFwLAZoHClJ36J8h+wxihpCqJosAnJrSKwEcQOFAFeWN4RQMYc0Ao4Jhg5gpASzyWcDvjpuDIlTkrGGJEro1rHIjHKR3wJCAj+z5oyi11gJBkXy9QFJIiAu78d+pgSjuWhGN0gUAZAcEncSJf4LRrZ8I94WEmcNCJJqBWYjVbE9bg2JxiyrViBWty6QvO56D8jPVWLA4ZX8dfkxvJJPl8t8aCX+pU/Iz1SCf7lc4OBK0OWfQaKLP0TKjj96VvIp+/BDZjwNKF2ItV2vN7sWStAl87oWkm3dZ+k3lEMoYXe8cT1eq2TOePJDD8KfQdxu6iEPxanUZa4HmZRq3dunGsj3BzFq6yD3wnZNX4n2emI2hXyXQpi6RRZdfSgxHNuxVZBFdyVeBPDmCsiksxKUiDAUEKuzkvRUEs0V08pjVyU2/yqFmF2VZGYop3peitdUiQd1pnrL7qTE01tPzE6eaEKm23dQwh2jNlbiay+/245zl94abw45CzNPyqYQ2++kxHGV1crWzg4A2yvR+BY7wziwnRLN7+O36aA54+ZKGjxZYK3txJpxQyUNn5GwtquII4+ACiWtnvawduu1A3SVtH5uhTvAVSpBG7fDYz6RQ+M6JWjmKm6g+RvTla9UMtspu+s+37VbVCupNqPx43CsNawSb1PbtcmDfQWmUILW7rRXSPHtSq5k5ur0a/hb7DQCUiW3G71ejX/wvV1kSoyNbp8Wvyqn1lCIKvl6gNDkNBYzt0GHdr+Pt9xGl1//ncAVcoVcIVfIFXKFXCFXyP8I8i8SyTW4yTz2lwAAAABJRU5ErkJggg==',
base64Error: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIBAMAAABfdrOtAAAAJFBMVEVHcEzo6Oibm5ukpKSbm5uampqbm5ubm5u5ubnn5+fm5ub6+vpGpDPdAAAAC3RSTlMA/v4hb+u20dq8aQhnHL4AAATwSURBVHja7ZvNb+JGGMbdjjdVe3NPodzeMhj1ZMUGujkh28B9wKR7iwwBqafWSbPqsbm0uTWtVlrTS9v0Et9yqLQS/1zHNiTZMMB4bO92d+dRUITt8c/PvPPx2h4URUpKSkpKSkpK6m3K6lFN73Q+S/+es3W3fzabTh2Dl0FAXEM+BgrgeXxRsdILTDU9n7J0vz/+EsCYC9KEiSFc06pf5zouqAkjkGWo0OG5Fq6j2IwZ6I4/4DhyTxc20oUjAj5PRTTrwvGAZ9p+ADzlD4RDctCoLhb7JUP87xeLxS3BZUIQ+YNCFi8wRwc4GIqGRK/GkM+5ILV8kFflOmkkkH/LddJ4c05eSSfSyTvrZPEmnCw+UCeuk84QvTSnUF0uCL68fBle/swF+RL1QZ/EpU6gHtOsAM64pnjPwxgTLsjoBM58ODNaAXYBT5QeGdr0KwcEA8He0TkPBLCjUDNHpG4qlg8eTCzXht1FVd1MxTPHj5LTtUiSrKK+7iDf8wBGxk4If3arLv/HF4Tox0A2nlFIGp+CIA+LzSamgbp4TNvZjECtDAjyMcB5HybLO6NxsRA1vmFCNjguNXDGWygbRPXh/B+zn9zPWK5RCkT18QxA57YgAqE+HGS6/tAoD4JO0ts+M2tbyQJpc95a5oI0xXNhCZGQ/x8E0VSCkUZY6Z6CIE/qdO5eL+yPlW6tMMgefPs3o7Bdt8iguJj4DThlZSY/rJ0yB+RraLDK2jAQCHyr4zIhT9mQ7vowygMZjpgQG+CYUV2E1EWqixyzICr8eFFnBB5ba1Y4IIfeKQvysW7ssZrwQLEFmvCBM2U6oRkdI5Wgm1QnO8RUTDlASoiESIiESMh7BDHKhlhu/LbSNUuEqL3lu1p945vO3BArADiaum7vBGDUKQfSIjBykooyrRPQnTIglHFfSagHeqd4iErwa9duEebpckGQjx/VT4v5fC0XhJHAd1mPRvJAVMZiAeQzTpgHYrPKqkGnUEiX+dCoNS4UgniHMTnUS4iESIiE7IS0x+mnVAidglDwVcmQJpy2WQ8VC4UgogfbA1RE4Nuw3UghEBV2rKl7V5ygAJPSY9KGQbP01mVjA5Fa2f1kQN2U3k+M9POWB8gnJUNMZJioWTMzKwOklyxgDrCXVcMMEF90tXM9C2TiCqmfCdIRi/jeewNpyerKok9WkGuzfCdYC+fXRsmBxxpVGG2zY0ZBbieJKvPrDQce3lxppBhIjGFWGkVoxUEoZt0Mukn2XBQH0bTHZpaMIp2sU/6qasU70W6/eHjM09VmYSc6C6Jpvz+orKvVxot8kL3HkMr9IZ9qeZ2o6RrO9mOI9ufdIR9peZ2gNIW31yC/MpyI9ngUDNIsezPks3vIsWDGdYA7cZa9pbqUVeCr/neiaR3U3R4BfXPg75vwb8I/b7HjxChobDZCO+Ny4wuxxaVxPPowcoNnrzPmzGFlX3RJHz2FafbhJ41n8PLx2DCM7KkwQgpqka1DVzKdJNHfJwBe9l/n0eSZFsIPjVSY8xZKZpSXnogwled98wAx3xRcdBNq1f1fhFVdIcL5tvaDolC7XaqaWStEtLOJHkbhlSauMLrma4yHEa03AVUoIUs/M2NQFkchBZiGUPeKonAnqhLOo4hrKf0WTyZ1FcU0Ki0hVrSr+Mucnvya7jYUKSkpKSkpKSmpD0f/AXq+Umj5XnXDAAAAAElFTkSuQmCC',
base64BackToTop: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIBAMAAABfdrOtAAAAElBMVEVRUVH+/v5HcEyZmZlRUVFRUVGm1ByOAAAABnRSTlPMzADMTZAJBBGsAAAEnElEQVR42t2cS27jMAyGf7/2U+QCQeDsbeQCgZDujaC5/1UmkzaJn+JDFGcw3LdfflKibJkkDnxrL7dbg7sNt6+L4O8OYBM+B0ys+QrGkHZG+OEEQ8g6go8Bx1GIGMdpNOQyIG6XdMgnSPtKhLQDGEZFBgYMkhKFtGBb0EIEjDgFRowoBVaMGAWpMedEfxMiZtwpUsgZCqtlkCNUdpVAWigtCCCDFtLwIWeoreZCWiRYYEKGFEjDg+yRZCUH0iLRAgNyToXUNCRZyMqWhGnUN2IPm3wSlwJ7IUspyCBkIQUZhCykIIeQuRTkEDKXAuM9srrtYbrZN7Y98giZSoFd+t1OxmMITG0dcrSFXFchZ1tIvQZpYWxhBbK3hpQrkMEa0iwh5t4a+QvZvDXyF7J5a+Qv5PPW21/I5623v5DPW29/IaO3Xv5Clrw1y1/Ikrdm+Qs5svw83yNnSJ5BQb4F/F7EIEJSnThGBAXxkFQfLOviQUE8JAUPsosHBfGQfDAtHhREQ1JxIV00KIgmrnRI84S0yAd5BAXxxJUck0f6Qnwr9qmr6xF5xLMjcwn/iudIEAdWnyjkEXlQKZiRVzoqRyLbgeUKKR8Q4alY7cSnoxzSf2ggsqehKr6YVpcXpOd7H93f60cKhOd7Re2LteUF4eLqiVS1mr0ge4io6C2+soaFkJ7MuuuQs1yITEp9hwwKISIpzR2iESKSIoT0rLNwuVHQqoSIpAQJpGce60vIUSdEIuUqgPTsJ5QFZK8UIpBS8iG94GFrDjlrhfCl8CG96Llxmle4kEr6vKWBPIVo9kqDQSRk9/3cWoikcCFPAd33v4dIChPyEvLzBA6RlEYWke4JEUnhKXkLeUEKxRHJFfKCQHGucIW8IdZSRkLeEGMpYyEjiK2UsZARxFTKRMgYYillImQMMZQyFTKB2EmZCplAuFLIHT8TMoWwpQwiIVMIUwqpZP5bp5CCvCTiQKr5f5lCQN+tPCBn2ZvVDFJwIDUP0m1BYAfZYRNSsCB7BqTbhoARePIxtZ9tgwWkoJcwCalmv3MBAemtO4R6dah2HaKQqj8Zvp9sQDjvJ21+SPCBHPJDDk6QITekEV7gqCC19CpKAym9IMfckKv4olMBCeIrWwVEfvkshzQekO9r9P1/ALk+IG1eSPCDiCJfyG+FyU+A6ZCa/piZDinpz7LpkCv5gdkAEshP5emQhv7onw6pGeULyZCSUYiRDAmMkpJkCKs4JhFSq8p8hJBSVbAkhARV6ZUQoisik0FqXTmcDHLVFfbJIEFXoiiCNMpiSxGkVJaNiiBBWQArgTTaUl4JpNQWJUsgQVteXQg+AKkLxQWFGKW+5J2+eVp4S168X3CF1CltCKdTJ8lb84YK2bUBO+wZW0Pqv9nk4tKu49N45NJC5dMM5tLW5tOg59Jq6NM06dL+abFXwr/RkuvTXJwae1abtE/Dt0/ruksTvs84AZ/BCC4jHnyGVfiM3VBQFANEXEah+Ax18RlP4zNox2dkkM/wI58xTn8yDCXGYCDV3W5RGSajtXyGhG1jbpbjzpwGt/0MJft8jqC7iUbQ/QZaxdnKqcIftwAAAABJRU5ErkJggg==',
}

228
src/uni_modules/z-paging/components/z-paging/js/z-paging-utils.js

@ -0,0 +1,228 @@
// [z-paging]工具类
import zConfig from './z-paging-config'
import zLocalConfig from '../config/index'
import c from './z-paging-constant'
const storageKey = 'Z-PAGING-REFRESHER-TIME-STORAGE-KEY';
let config = null;
const timeoutMap = {};
/*
当z-paging未使用uni_modules管理时控制台会有警告WARNING: Module not found: Error: Can't resolve '@/uni_modules/z-paging'...
此时注释下方try中的代码即可
*/
// #ifdef VUE2
try {
const contextKeys = require.context('@/uni_modules/z-paging', false, /\z-paging-config$/).keys();
if (contextKeys.length) {
const suffix = '.js';
config = require('@/uni_modules/z-paging/z-paging-config' + suffix);
}
} catch (e) {}
// #endif
//获取默认配置信息
function gc(key, defaultValue) {
if (!config) {
if (zLocalConfig && Object.keys(zLocalConfig).length) {
config = zLocalConfig;
} else {
const tempConfig = zConfig.getConfig();
if (zConfig && tempConfig) {
config = tempConfig;
}
}
}
if (!config) return defaultValue;
const value = config[_toKebab(key)];
return value === undefined ? defaultValue : value;
}
//获取最终的touch位置
function getTouch(e) {
let touch = null;
if (e.touches && e.touches.length) {
touch = e.touches[0];
} else if (e.changedTouches && e.changedTouches.length) {
touch = e.changedTouches[0];
} else if (e.datail && e.datail != {}) {
touch = e.datail;
} else {
return {
touchX: 0,
touchY: 0
}
}
return {
touchX: touch.clientX,
touchY: touch.clientY
};
}
//判断当前手势是否在z-paging内触发
function getTouchFromZPaging(target) {
if (target && target.tagName && target.tagName !== 'BODY' && target.tagName !== 'UNI-PAGE-BODY') {
const classList = target.classList;
if (classList && classList.contains('z-paging-content')) {
return {
isFromZp: true,
isPageScroll: classList.contains('z-paging-content-page'),
isReachedTop: classList.contains('z-paging-reached-top')
};
} else {
return getTouchFromZPaging(target.parentNode);
}
} else {
return { isFromZp: false };
}
}
//获取z-paging所在的parent
function getParent(parent) {
if (!parent) return null;
if (parent.$refs.paging) return parent;
return getParent(parent.$parent);
}
//打印错误信息
function consoleErr(err) {
console.error(`[z-paging]${err}`);
}
//延时操作,如果key存在,调用时根据key停止之前的延时操作
function delay(callback, ms = c.delayTime, key) {
const timeout = setTimeout(callback, ms);;
if (!!key) {
timeoutMap[key] && clearTimeout(timeoutMap[key]);
timeoutMap[key] = timeout;
}
return timeout;
}
//设置下拉刷新时间
function setRefesrherTime(time, key) {
const datas = getRefesrherTime() || {};
datas[key] = time;
uni.setStorageSync(storageKey, datas);
}
//获取下拉刷新时间
function getRefesrherTime() {
return uni.getStorageSync(storageKey);
}
//通过下拉刷新标识key获取下拉刷新时间
function getRefesrherTimeByKey(key) {
const datas = getRefesrherTime();
return datas && datas[key] ? datas[key] : null;
}
//通过下拉刷新标识key获取下拉刷新时间(格式化之后)
function getRefesrherFormatTimeByKey(key, textMap) {
const time = getRefesrherTimeByKey(key);
const timeText = time ? _timeFormat(time, textMap) : textMap.none;
return `${textMap.title}${timeText}`;
}
//将文本的px或者rpx转为px的值
function convertToPx(text) {
const dataType = Object.prototype.toString.call(text);
if (dataType === '[object Number]') return text;
let isRpx = false;
if (text.indexOf('rpx') !== -1 || text.indexOf('upx') !== -1) {
text = text.replace('rpx', '').replace('upx', '');
isRpx = true;
} else if (text.indexOf('px') !== -1) {
text = text.replace('px', '');
}
if (!isNaN(text)) {
if (isRpx) return Number(uni.upx2px(text));
return Number(text);
}
return 0;
}
//获取当前时间
function getTime() {
return (new Date()).getTime();
}
//获取z-paging实例id
function getInstanceId() {
const s = [];
const hexDigits = "0123456789abcdef";
for (let i = 0; i < 10; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
return s.join('') + getTime();
}
// 等待一段时间
function wait(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
//------------------ 私有方法 ------------------------
//时间格式化
function _timeFormat(time, textMap) {
const date = new Date(time);
const currentDate = new Date();
const dateDay = new Date(time).setHours(0, 0, 0, 0);
const currentDateDay = new Date().setHours(0, 0, 0, 0);
const disTime = dateDay - currentDateDay;
let dayStr = '';
const timeStr = _dateTimeFormat(date);
if (disTime === 0) {
dayStr = textMap.today;
} else if (disTime === -86400000) {
dayStr = textMap.yesterday;
} else {
dayStr = _dateDayFormat(date, date.getFullYear() !== currentDate.getFullYear());
}
return `${dayStr} ${timeStr}`;
}
//date格式化为年月日
function _dateDayFormat(date, showYear = true) {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
return showYear ? `${year}-${_fullZeroToTwo(month)}-${_fullZeroToTwo(day)}` : `${_fullZeroToTwo(month)}-${_fullZeroToTwo(day)}`;
}
//data格式化为时分
function _dateTimeFormat(date) {
const hour = date.getHours();
const minute = date.getMinutes();
return `${_fullZeroToTwo(hour)}:${_fullZeroToTwo(minute)}`;
}
//不满2位在前面填充0
function _fullZeroToTwo(str) {
str = str.toString();
return str.length === 1 ? '0' + str : str;
}
//驼峰转短横线
function _toKebab(value) {
return value.replace(/([A-Z])/g, "-$1").toLowerCase();
}
export default {
gc,
setRefesrherTime,
getRefesrherFormatTimeByKey,
getTouch,
getTouchFromZPaging,
getParent,
convertToPx,
getTime,
getInstanceId,
consoleErr,
delay,
wait
};

58
src/uni_modules/z-paging/components/z-paging/wxs/z-paging-renderjs.js

@ -0,0 +1,58 @@
// [z-paging]使用renderjs在app-vue和h5中对touchmove事件冒泡进行处理
import u from '../js/z-paging-utils'
const data = {
startY: 0,
isTouchFromZPaging: false,
isUsePageScroll: false,
isReachedTop: true,
isIosAndH5: false,
appLaunched: false
}
export default {
mounted() {
if (window) {
this._handleTouch();
// #ifdef APP-VUE
this.$ownerInstance.callMethod('_handlePageLaunch');
// #endif
}
},
methods: {
//接收逻辑层发送的数据
renderPropIsIosAndH5Change(newVal) {
if (newVal === -1) return;
data.isIosAndH5 = newVal;
},
//拦截处理touch事件
_handleTouch() {
if (!window.$zPagingRenderJsInited) {
window.$zPagingRenderJsInited = true;
window.addEventListener('touchstart', this._handleTouchstart, { passive: true })
window.addEventListener('touchmove', this._handleTouchmove, { passive: false })
}
},
_handleTouchstart(e) {
const touch = u.getTouch(e);
data.startY = touch.touchY;
const touchResult = u.getTouchFromZPaging(e.target);
data.isTouchFromZPaging = touchResult.isFromZp;
data.isUsePageScroll = touchResult.isPageScroll;
data.isReachedTop = touchResult.isReachedTop;
},
_handleTouchmove(e) {
const touch = u.getTouch(e);
const moveY = touch.touchY - data.startY;
if (data.isTouchFromZPaging && ((data.isReachedTop && moveY > 0) || (data.isIosAndH5 && !data.isUsePageScroll && moveY < 0))) {
if (e.cancelable && !e.defaultPrevented) {
e.preventDefault();
}
}
},
_removeAllEventListener(){
window.removeEventListener('touchstart');
window.removeEventListener('touchmove');
}
}
};

340
src/uni_modules/z-paging/components/z-paging/wxs/z-paging-wxs.wxs

@ -0,0 +1,340 @@
// [z-paging]微信小程序、QQ小程序、app-vue、h5上使用wxs实现自定义下拉刷新,降低逻辑层与视图层的通信折损,提升性能
var currentDis = 0;
var isPCFlag = -1;
var startY = -1;
function propObserver(newValue, oldValue, ownerIns, ins) {
var state = ownerIns.getState() || {};
state.currentIns = ins;
var dataset = ins.getDataset();
var loading = dataset.loading == true;
if (newValue && newValue.indexOf('end') != -1) {
var transition = newValue.split('end')[0];
_setTransform('translateY(0px)', ins, false, transition);
state.moveDis = 0;
state.oldMoveDis = 0;
currentDis = 0;
} else if (newValue && newValue.indexOf('begin') != -1) {
var refresherThreshold = ins.getDataset().refresherthreshold;
_setTransformValue(refresherThreshold, ins, state, false);
}
}
function touchstart(e, ownerIns) {
var ins = _getIns(ownerIns);
var state = {};
var dataset = {};
ownerIns.callMethod('_handleListTouchstart');
if (ins) {
state = ins.getState();
dataset = ins.getDataset();
if (_touchDisabled(e, ins, 0)) return;
}
var isTouchEnded = state.isTouchEnded;
state.oldMoveDis = 0;
var touch = _getTouch(e);
var loading = _isTrue(dataset.loading);
state.startY = touch.touchY;
startY = state.startY;
state.lastTouch = touch;
if (!loading && isTouchEnded) {
state.isTouchmoving = false;
}
state.isTouchEnded = false;
ownerIns.callMethod('_handleRefresherTouchstart', touch);
}
function touchmove(e, ownerIns) {
var touch = _getTouch(e);
var ins = _getIns(ownerIns);
var dataset = ins.getDataset();
var refresherThreshold = dataset.refresherthreshold;
var isIos = _isTrue(dataset.isios);
var state = ins.getState();
var watchTouchDirectionChange = _isTrue(dataset.watchtouchdirectionchange);
var moveDisObj = {};
var moveDis = 0;
var prevent = false;
if (watchTouchDirectionChange) {
moveDisObj = _getMoveDis(e, ins);
moveDis = moveDisObj.currentDis;
prevent = moveDisObj.isDown;
var direction = prevent ? 'top' : 'bottom';
if (prevent == state.oldTouchDirection && prevent != state.oldEmitedTouchDirection) {
ownerIns.callMethod('_handleTouchDirectionChange', { direction: direction });
state.oldEmitedTouchDirection = prevent;
}
state.oldTouchDirection = prevent;
}
if (_touchDisabled(e, ins, 1)) {
_handlePullingDown(state, ownerIns, false);
return true;
}
if (!_getAngleIsInRange(e, touch, state, dataset)) {
_handlePullingDown(state, ownerIns, false);
return true;
}
moveDisObj = _getMoveDis(e, ins);
moveDis = moveDisObj.currentDis;
prevent = moveDisObj.isDown;
if (moveDis < 0) {
_setTransformValue(0, ins, state, false);
_handlePullingDown(state, ownerIns, false);
return true;
}
if (prevent && !state.disabledBounce) {
ownerIns.callMethod('_handleScrollViewDisableBounce', {bounce: false});
state.disabledBounce = true;
_handlePullingDown(state, ownerIns, prevent);
return !prevent;
}
_setTransformValue(moveDis, ins, state, false);
var oldRefresherStatus = state.refresherStatus;
var oldIsTouchmoving = _isTrue(dataset.oldistouchmoving);
var hasTouchmove = _isTrue(dataset.hastouchmove);
var isTouchmoving = state.isTouchmoving;
state.refresherStatus = moveDis >= refresherThreshold ? 1 : 0;
if (!isTouchmoving) {
state.isTouchmoving = true;
isTouchmoving = true;
}
if (state.isTouchEnded) {
state.isTouchEnded = false;
}
if (hasTouchmove) {
ownerIns.callMethod('_handleWxsPullingDown', { moveDis:moveDis, diffDis:moveDisObj.diffDis });
}
if (oldRefresherStatus == undefined || oldRefresherStatus != state.refresherStatus || oldIsTouchmoving != isTouchmoving) {
ownerIns.callMethod('_handleRefresherTouchmove', moveDis, touch);
}
_handlePullingDown(state, ownerIns, prevent);
return !prevent;
}
function touchend(e, ownerIns) {
var touch = _getTouch(e);
var ins = _getIns(ownerIns);
var dataset = ins.getDataset();
var state = ins.getState();
if (_touchDisabled(e, ins, 2)) return;
state.reachMaxAngle = true;
state.hitReachMaxAngleCount = 0;
state.disabledBounce = false;
state.fixedIsTopHitCount = 0;
if (!state.isTouchmoving) return;
var oldRefresherStatus = state.refresherStatus;
var oldMoveDis = state.moveDis;
var refresherThreshold = ins.getDataset().refresherthreshold
var moveDis = _getMoveDis(e, ins).currentDis;
if (!(moveDis >= refresherThreshold && oldRefresherStatus === 1)) {
state.isTouchmoving = false;
}
ownerIns.callMethod('_handleRefresherTouchend', moveDis);
state.isTouchEnded = true;
if (oldMoveDis < refresherThreshold) return;
var animate = false;
if (moveDis >= refresherThreshold) {
moveDis = refresherThreshold;
animate = true;
}
_setTransformValue(moveDis, ins, state, animate);
}
// #ifdef H5
function isPC() {
if (!navigator) return false;
if (isPCFlag != -1) return isPCFlag;
var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
isPCFlag = agents.every(function(item) { return navigator.userAgent.indexOf(item) < 0 });
return isPCFlag;
}
var movable = false;
function mousedown(e, ins) {
if (!isPC()) return;
touchstart(e, ins);
movable = true;
}
function mousemove(e, ins) {
if (!isPC() || !movable) return;
touchmove(e, ins);
}
function mouseup(e, ins) {
if (!isPC()) return;
touchend(e, ins);
movable = false;
}
function mouseleave(e, ins) {
if (!isPC()) return;
movable = false;
}
// #endif
function _setTransformValue(value, ins, state, animate) {
value = value || 0;
if (state.moveDis == value) return;
state.moveDis = value;
_setTransform('translateY(' + value + 'px)', ins, animate, '');
}
function _setTransform(transform, ins, animate, transition) {
var dataset = ins.getDataset();
if (_isTrue(dataset.refreshernotransform)) return;
transform = transform == 'translateY(0px)' ? 'none' : transform;
ins.requestAnimationFrame(function() {
var stl = { 'transform': transform };
if (animate) {
stl['transition'] = 'transform .1s linear';
}
if (transition.length) {
stl['transition'] = transition;
}
ins.setStyle(stl);
})
}
function _getMoveDis(e, ins) {
var state = ins.getState();
var refresherThreshold = parseFloat(ins.getDataset().refresherthreshold);
var refresherOutRate = parseFloat(ins.getDataset().refresheroutrate);
var refresherPullRate = parseFloat(ins.getDataset().refresherpullrate);
var touch = _getTouch(e);
var currentStartY = !state.startY || state.startY == 'NaN' ? startY : state.startY;
var moveDis = touch.touchY - currentStartY;
var oldMoveDis = state.oldMoveDis || 0;
state.oldMoveDis = moveDis;
var diffDis = moveDis - oldMoveDis;
if (diffDis > 0) {
diffDis = diffDis * refresherPullRate;
if (currentDis > refresherThreshold) {
diffDis = diffDis * (1 - refresherOutRate);
}
}
diffDis = diffDis > 100 ? diffDis / 100 : (diffDis > 20 ? diffDis / 1.2 : diffDis);
currentDis += diffDis;
currentDis = Math.max(0, currentDis);
return {
currentDis: currentDis,
diffDis: diffDis,
isDown: diffDis > 0
};
}
function _getTouch(e) {
var touch = e;
if (e.touches && e.touches.length) {
touch = e.touches[0];
} else if (e.changedTouches && e.changedTouches.length) {
touch = e.changedTouches[0];
} else if (e.datail && e.datail != {}) {
touch = e.datail;
}
return {
touchX: touch.clientX,
touchY: touch.clientY
};
}
function _getIns(ownerIns) {
var ins = ownerIns.getState().currentIns;
if (!ins) {
ownerIns.callMethod('_handlePropUpdate');
}
return ins;
}
function _touchDisabled(e, ins, processTag) {
var dataset = ins.getDataset();
var state = ins.getState();
var loading = _isTrue(dataset.loading);
var useChatRecordMode = _isTrue(dataset.usechatrecordmode);
var refresherEnabled = _isTrue(dataset.refresherenabled);
var useCustomRefresher = _isTrue(dataset.usecustomrefresher);
var usePageScroll = _isTrue(dataset.usepagescroll);
var pageScrollTop = parseFloat(dataset.pagescrolltop);
var scrollTop = parseFloat(dataset.scrolltop);
var finalScrollTop = usePageScroll ? pageScrollTop : scrollTop;
var fixedIsTop = false;
var isIos = _isTrue(dataset.isios);
if (!isIos && finalScrollTop == (state.startScrollTop || 0) && finalScrollTop <= 105) {
fixedIsTop = true;
}
var fixedIsTopHitCount = state.fixedIsTopHitCount || 0;
if (fixedIsTop) {
fixedIsTopHitCount ++;
if (fixedIsTopHitCount <= 2) {
fixedIsTop = false;
}
state.fixedIsTopHitCount = fixedIsTopHitCount;
} else {
state.fixedIsTopHitCount = 0;
}
if (!isIos && processTag === 0) {
state.startScrollTop = finalScrollTop || 0;
}
if (!isIos && processTag === 2) {
fixedIsTop = true;
}
return loading || useChatRecordMode || !refresherEnabled || !useCustomRefresher ||
((usePageScroll && useCustomRefresher && pageScrollTop > 5) && !fixedIsTop) ||
((!usePageScroll && useCustomRefresher && scrollTop > 5) && !fixedIsTop);
}
function _getAngleIsInRange(e, touch, state, dataset) {
var maxAngle = dataset.refreshermaxangle;
var refresherAecc = _isTrue(dataset.refresheraecc);
var lastTouch = state.lastTouch;
var reachMaxAngle = state.reachMaxAngle;
var moveDis = state.oldMoveDis;
if (!lastTouch) return true;
if (maxAngle >= 0 && maxAngle <= 90 && lastTouch) {
if ((!moveDis || moveDis < 1) && !refresherAecc && reachMaxAngle != null && !reachMaxAngle) return false;
var x = Math.abs(touch.touchX - lastTouch.touchX);
var y = Math.abs(touch.touchY - lastTouch.touchY);
var z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
if ((x || y) && x > 1) {
var angle = Math.asin(y / z) / Math.PI * 180;
if (angle < maxAngle) {
var hitReachMaxAngleCount = state.hitReachMaxAngleCount || 0;
state.hitReachMaxAngleCount = ++hitReachMaxAngleCount;
if (state.hitReachMaxAngleCount > 2) {
state.lastTouch = touch;
state.reachMaxAngle = false;
}
return false;
}
}
}
state.lastTouch = touch;
return true;
}
function _handlePullingDown(state, ins, onPullingDown) {
var oldOnPullingDown = state.onPullingDown || false;
if (oldOnPullingDown != onPullingDown) {
ins.callMethod('_handleWxsPullingDownStatusChange', onPullingDown);
}
state.onPullingDown = onPullingDown;
}
function _isTrue(value) {
value = (typeof(value) === 'string' ? JSON.parse(value) : value) || false;
return value == true || value == 'true';
}
module.exports = {
touchstart: touchstart,
touchmove: touchmove,
touchend: touchend,
mousedown: mousedown,
mousemove: mousemove,
mouseup: mouseup,
mouseleave: mouseleave,
propObserver: propObserver
}

307
src/uni_modules/z-paging/components/z-paging/z-paging.vue

@ -0,0 +1,307 @@
<!-- _
____ _ __ __ _ __ _(_)_ __ __ _
|_ /____| '_ \ / _` |/ _` | | '_ \ / _` |
/ /_____| |_) | (_| | (_| | | | | | (_| |
/___| | .__/ \__,_|\__, |_|_| |_|\__, |
|_| |___/ |___/
v2.6.0 (2023-10-17)
by ZXLee
-->
<!-- 文档地址https://z-paging.zxlee.cn -->
<!-- github地址https://github.com/SmileZXLee/uni-z-paging -->
<!-- dcloud地址https://ext.dcloud.net.cn/plugin?id=3935 -->
<!-- 反馈QQ群790460711(已满)371624008 -->
<template name="z-paging">
<!-- #ifndef APP-NVUE -->
<view :class="{'z-paging-content':true,'z-paging-content-fixed':!usePageScroll&&fixed,'z-paging-content-page':usePageScroll,'z-paging-reached-top':renderPropScrollTop<1}" :style="[finalPagingStyle]">
<!-- #ifndef APP-PLUS -->
<view v-if="cssSafeAreaInsetBottom===-1" class="zp-safe-area-inset-bottom"></view>
<!-- #endif -->
<!-- 顶部固定的slot -->
<slot v-if="!usePageScroll&&zSlots.top" name="top" />
<view class="zp-page-top" @touchmove.stop.prevent v-else-if="usePageScroll&&zSlots.top" :style="[{'top':`${windowTop}px`,'z-index':topZIndex}]">
<slot name="top" />
</view>
<view :class="{'zp-view-super':true,'zp-scroll-view-super':!usePageScroll}" :style="[finalScrollViewStyle]">
<view v-if="zSlots.left" :class="{'zp-page-left':true,'zp-absoulte':finalIsOldWebView}">
<slot name="left" />
</view>
<view :class="{'zp-scroll-view-container':true,'zp-absoulte':finalIsOldWebView}" :style="[scrollViewContainerStyle]">
<scroll-view
ref="zp-scroll-view" :class="{'zp-scroll-view':true,'zp-scroll-view-absolute':!usePageScroll,'zp-scroll-view-hide-scrollbar':!showScrollbar}"
:scroll-top="scrollTop" :scroll-x="scrollX"
:scroll-y="scrollable&&!usePageScroll&&scrollEnable&&(refresherCompleteScrollable?true:refresherStatus!==R.Complete)" :enable-back-to-top="finalEnableBackToTop"
:show-scrollbar="showScrollbar" :scroll-with-animation="finalScrollWithAnimation"
:scroll-into-view="scrollIntoView" :lower-threshold="finalLowerThreshold" :upper-threshold="5"
:refresher-enabled="finalRefresherEnabled&&!useCustomRefresher" :refresher-threshold="finalRefresherThreshold"
:refresher-default-style="finalRefresherDefaultStyle" :refresher-background="refresherBackground"
:refresher-triggered="finalRefresherTriggered" @scroll="_scroll" @scrolltolower="_onScrollToLower"
@scrolltoupper="_onScrollToUpper" @refresherrestore="_onRestore" @refresherrefresh="_onRefresh(true)"
>
<view class="zp-paging-touch-view"
<!-- #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
@touchstart="_refresherTouchstart" @touchmove="_refresherTouchmove" @touchend="_refresherTouchend" @touchcancel="_refresherTouchend"
<!-- #endif -->
<!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
@touchstart="pagingWxs.touchstart" @touchmove="pagingWxs.touchmove" @touchend="pagingWxs.touchend" @touchcancel="pagingWxs.touchend"
@mousedown="pagingWxs.mousedown" @mousemove="pagingWxs.mousemove" @mouseup="pagingWxs.mouseup" @mouseleave="pagingWxs.mouseleave"
<!-- #endif -->
>
<view v-if="finalRefresherFixedBacHeight>0" class="zp-fixed-bac-view" :style="[{'background': refresherFixedBackground,'height': `${finalRefresherFixedBacHeight}px`}]"></view>
<view class="zp-paging-main" :style="[scrollViewInStyle,{'transform': finalRefresherTransform,'transition': refresherTransition}]"
<!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
:change:prop="pagingWxs.propObserver" :prop="wxsPropType"
:data-refresherThreshold="finalRefresherThreshold" :data-isIos="isIos"
:data-loading="loading||isRefresherInComplete" :data-useChatRecordMode="useChatRecordMode"
:data-refresherEnabled="refresherEnabled" :data-useCustomRefresher="useCustomRefresher" :data-pageScrollTop="wxsPageScrollTop"
:data-scrollTop="wxsScrollTop" :data-refresherMaxAngle="refresherMaxAngle" :data-refresherNoTransform="refresherNoTransform"
:data-refresherAecc="refresherAngleEnableChangeContinued" :data-usePageScroll="usePageScroll" :data-watchTouchDirectionChange="watchTouchDirectionChange"
:data-oldIsTouchmoving="isTouchmoving" :data-refresherOutRate="finalRefresherOutRate" :data-refresherPullRate="finalRefresherPullRate" :data-hasTouchmove="hasTouchmove"
<!-- #endif -->
<!-- #ifdef APP-VUE || H5 -->
:change:renderPropIsIosAndH5="pagingRenderjs.renderPropIsIosAndH5Change" :renderPropIsIosAndH5="isIosAndH5"
<!-- #endif -->
>
<view v-if="showRefresher" class="zp-custom-refresher-view" :style="[{'margin-top': `-${finalRefresherThreshold+refresherThresholdUpdateTag}px`,'background': refresherBackground,'opacity': isTouchmoving ? 1 : 0}]">
<view class="zp-custom-refresher-container" :style="[{'height': `${finalRefresherThreshold}px`,'background': refresherBackground}]">
<!-- 下拉刷新view -->
<view class="zp-custom-refresher-slot-view">
<slot v-if="!(zSlots.refresherComplete&&refresherStatus===R.Complete)" :refresherStatus="refresherStatus" name="refresher" />
</view>
<slot v-if="zSlots.refresherComplete&&refresherStatus===R.Complete" name="refresherComplete" />
<z-paging-refresh ref="refresh" v-else-if="!showCustomRefresher" :style="[{'height': `${finalRefresherThreshold}px`}]" :status="refresherStatus"
:defaultThemeStyle="finalRefresherThemeStyle" :defaultText="finalRefresherDefaultText"
:pullingText="finalRefresherPullingText" :refreshingText="finalRefresherRefreshingText" :completeText="finalRefresherCompleteText"
:defaultImg="refresherDefaultImg" :pullingImg="refresherPullingImg" :refreshingImg="refresherRefreshingImg" :completeImg="refresherCompleteImg" :refreshingAnimated="refresherRefreshingAnimated"
:showUpdateTime="showRefresherUpdateTime" :updateTimeKey="refresherUpdateTimeKey" :updateTimeTextMap="finalRefresherUpdateTimeTextMap"
:imgStyle="refresherImgStyle" :titleStyle="refresherTitleStyle" :updateTimeStyle="refresherUpdateTimeStyle" />
</view>
</view>
<view class="zp-paging-container">
<slot v-if="useChatRecordMode&&zSlots.chatLoading&&loadingStatus!==M.NoMore&&realTotalData.length" name="chatLoading" />
<view v-else-if="useChatRecordMode&&loadingStatus!==M.NoMore&&realTotalData.length" class="zp-chat-record-loading-container">
<text v-if="loadingStatus!==M.Loading" @click="_onScrollToUpper"
:class="defaultThemeStyle==='white'?'zp-loading-more-text zp-loading-more-text-white':'zp-loading-more-text zp-loading-more-text-black'">{{chatRecordLoadingMoreText}}</text>
<image v-else :src="base64Flower" class="zp-chat-record-loading-custom-image" />
</view>
<!-- 全屏Loading -->
<slot v-if="showLoading&&zSlots.loading&&!loadingFullFixed" name="loading" />
<!-- 主体内容 -->
<view class="zp-paging-container-content" :style="[{transform:virtualPlaceholderTopHeight>0?`translateY(${virtualPlaceholderTopHeight}px)`:'none'},finalPagingContentStyle]">
<slot />
<!-- 内置列表&虚拟列表 -->
<template v-if="finalUseInnerList">
<slot name="header"/>
<view class="zp-list-container" :style="[innerListStyle]">
<template v-if="finalUseVirtualList">
<view class="zp-list-cell" :style="[innerCellStyle]" :id="`zp-id-${item[virtualCellIndexKey]}`" v-for="(item,index) in virtualList" :key="item['zp_unique_index']" @click="_innerCellClick(item,virtualTopRangeIndex+index)">
<view v-if="useCompatibilityMode">使用兼容模式请在组件源码z-paging.vue第99行中注释这一行并打开下面一行注释</view>
<!-- <zp-public-virtual-cell v-if="useCompatibilityMode" :extraData="extraData" :item="item" :index="virtualTopRangeIndex+index" /> -->
<slot v-else name="cell" :item="item" :index="virtualTopRangeIndex+index"/>
</view>
</template>
<template v-else>
<view class="zp-list-cell" v-for="(item,index) in realTotalData" :key="index" @click="_innerCellClick(item,index)">
<slot name="cell" :item="item" :index="index"/>
</view>
</template>
</view>
<slot name="footer"/>
</template>
<view v-if="useVirtualList" class="zp-virtual-placeholder" :style="[{height:virtualPlaceholderBottomHeight+'px'}]"/>
<!-- 上拉加载更多view -->
<!-- #ifndef MP-ALIPAY -->
<slot v-if="showLoadingMoreDefault" name="loadingMoreDefault" />
<slot v-else-if="showLoadingMoreLoading" name="loadingMoreLoading" />
<slot v-else-if="showLoadingMoreNoMore" name="loadingMoreNoMore" />
<slot v-else-if="showLoadingMoreFail" name="loadingMoreFail" />
<z-paging-load-more @doClick="_onLoadingMore('click')" v-else-if="showLoadingMoreCustom" :zConfig="zLoadMoreConfig" />
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<slot v-if="loadingStatus===M.Default&&zSlots.loadingMoreDefault&&showLoadingMore&&loadingMoreEnabled&&!useChatRecordMode" name="loadingMoreDefault" />
<slot v-else-if="loadingStatus===M.Loading&&zSlots.loadingMoreLoading&&showLoadingMore&&loadingMoreEnabled" name="loadingMoreLoading" />
<slot v-else-if="loadingStatus===M.NoMore&&zSlots.loadingMoreNoMore&&showLoadingMore&&showLoadingMoreNoMoreView&&loadingMoreEnabled&&!useChatRecordMode" name="loadingMoreNoMore" />
<slot v-else-if="loadingStatus===M.Fail&&zSlots.loadingMoreFail&&showLoadingMore&&loadingMoreEnabled&&!useChatRecordMode" name="loadingMoreFail" />
<z-paging-load-more @doClick="_onLoadingMore('click')" v-else-if="showLoadingMore&&showDefaultLoadingMoreText&&!(loadingStatus===M.NoMore&&!showLoadingMoreNoMoreView)&&loadingMoreEnabled&&!useChatRecordMode" :zConfig="zLoadMoreConfig" />
<!-- #endif -->
<view v-if="safeAreaInsetBottom&&useSafeAreaPlaceholder" class="zp-safe-area-placeholder" :style="[{height:safeAreaBottom+'px'}]" />
</view>
<!-- 空数据图 -->
<view v-if="showEmpty" :class="{'zp-empty-view':true,'zp-empty-view-center':emptyViewCenter}" :style="[emptyViewSuperStyle]">
<slot v-if="zSlots.empty" name="empty" :isLoadFailed="isLoadFailed"/>
<z-paging-empty-view v-else :emptyViewImg="finalEmptyViewImg" :emptyViewText="finalEmptyViewText" :showEmptyViewReload="finalShowEmptyViewReload"
:emptyViewReloadText="finalEmptyViewReloadText" :isLoadFailed="isLoadFailed" :emptyViewStyle="emptyViewStyle" :emptyViewTitleStyle="emptyViewTitleStyle"
:emptyViewImgStyle="emptyViewImgStyle" :emptyViewReloadStyle="emptyViewReloadStyle" :emptyViewZIndex="emptyViewZIndex" :emptyViewFixed="emptyViewFixed"
@reload="_emptyViewReload" @viewClick="_emptyViewClick" />
</view>
</view>
</view>
</view>
</scroll-view>
</view>
<view v-if="zSlots.right" :class="{'zp-page-right':true,'zp-absoulte zp-right':finalIsOldWebView}">
<slot name="right" />
</view>
</view>
<!-- 底部固定的slot -->
<slot v-if="!usePageScroll&&zSlots.bottom" name="bottom" />
<view class="zp-page-bottom" @touchmove.stop.prevent v-else-if="usePageScroll&&zSlots.bottom" :style="[{'bottom': `${windowBottom}px`}]">
<slot name="bottom" />
</view>
<!-- 点击返回顶部view -->
<view v-if="showBackToTopClass" :class="backToTopClass" :style="[finalBackToTopStyle]" @click.stop="_backToTopClick">
<slot v-if="zSlots.backToTop" name="backToTop" />
<image v-else class="zp-back-to-top-img" :src="backToTopImg.length?backToTopImg:base64BackToTop" />
</view>
<!-- 全屏Loading(铺满z-paging并固定) -->
<view v-if="showLoading&&zSlots.loading&&loadingFullFixed" class="zp-loading-fixed">
<slot name="loading" />
</view>
</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<component :is="finalNvueSuperListIs" :style="[finalPagingStyle]" :class="{'z-paging-content-fixed':fixed&&!usePageScroll}" :scrollable="false">
<!-- 顶部固定的slot -->
<view ref="zp-page-top" v-if="zSlots.top" :class="{'zp-page-top':usePageScroll}" :style="[usePageScroll?{'top':`${windowTop}px`,'z-index':topZIndex}:{}]">
<slot name="top" />
</view>
<component :is="finalNvueSuperListIs" class="zp-n-list-container" :scrollable="false">
<view v-if="zSlots.left" class="zp-page-left">
<slot name="left" />
</view>
<component :is="finalNvueListIs" ref="zp-n-list" :id="nvueListId" :style="[{'flex': 1,'top':isIos?'0px':'-1px'},usePageScroll?scrollViewStyle:{},nChatRecordRotateStyle]" :alwaysScrollableVertical="true"
:fixFreezing="nFixFreezing" :show-scrollbar="showScrollbar&&!useChatRecordMode" :loadmoreoffset="finalLowerThreshold" :enable-back-to-top="enableBackToTop"
:scrollable="scrollable&&scrollEnable&&(refresherCompleteScrollable?true:refresherStatus!==R.Complete)" :bounce="nvueBounce" :column-count="nWaterfallColumnCount" :column-width="nWaterfallColumnWidth"
:column-gap="nWaterfallColumnGap" :left-gap="nWaterfallLeftGap" :right-gap="nWaterfallRightGap" :pagingEnabled="nvuePagingEnabled" :offset-accuracy="offsetAccuracy"
@loadmore="_nOnLoadmore" @scroll="_nOnScroll">
<refresh v-if="(zSlots.top?cacheTopHeight!==-1:true)&&finalNvueRefresherEnabled" class="zp-n-refresh" :style="[nvueRefresherStyle]" :display="nRefresherLoading?'show':'hide'" @refresh="_nOnRrefresh" @pullingdown="_nOnPullingdown">
<view ref="zp-n-refresh-container" class="zp-n-refresh-container" :style="[{background:refresherBackground,width:nRefresherWidth}]" id="zp-n-refresh-container">
<!-- 下拉刷新view -->
<slot v-if="zSlots.refresherComplete&&refresherStatus===R.Complete" name="refresherComplete" />
<slot v-else-if="(nScopedSlots?nScopedSlots:zSlots).refresher" :refresherStatus="refresherStatus" name="refresher" />
<z-paging-refresh ref="refresh" v-else :status="refresherStatus" :defaultThemeStyle="finalRefresherThemeStyle"
:defaultText="finalRefresherDefaultText" :pullingText="finalRefresherPullingText" :refreshingText="finalRefresherRefreshingText" :completeText="finalRefresherCompleteText"
:defaultImg="refresherDefaultImg" :pullingImg="refresherPullingImg" :refreshingImg="refresherRefreshingImg" :completeImg="refresherCompleteImg" :refreshingAnimated="refresherRefreshingAnimated"
:showUpdateTime="showRefresherUpdateTime" :updateTimeKey="refresherUpdateTimeKey" :updateTimeTextMap="finalRefresherUpdateTimeTextMap"
:imgStyle="refresherImgStyle" :titleStyle="refresherTitleStyle" :updateTimeStyle="refresherUpdateTimeStyle" />
</view>
</refresh>
<component :is="nViewIs" v-if="isIos&&!useChatRecordMode?oldScrollTop>10:true" ref="zp-n-list-top-tag" class="zp-n-list-top-tag" style="margin-top: -1rpx;" :style="[{height:finalNvueRefresherEnabled?'0px':'1px'}]"></component>
<component :is="nViewIs" v-if="nShowRefresherReveal" ref="zp-n-list-refresher-reveal" :style="[{transform:`translateY(-${nShowRefresherRevealHeight}px)`},{background:refresherBackground}]">
<!-- 下拉刷新view -->
<slot v-if="zSlots.refresherComplete&&refresherStatus===R.Complete" name="refresherComplete" />
<slot v-else-if="(nScopedSlots?nScopedSlots:$slots).refresher" :refresherStatus="R.Loading" name="refresher" />
<z-paging-refresh ref="refresh" v-else :status="R.Loading" :defaultThemeStyle="finalRefresherThemeStyle"
:defaultText="finalRefresherDefaultText" :pullingText="finalRefresherPullingText" :refreshingText="finalRefresherRefreshingText" :completeText="finalRefresherCompleteText"
:defaultImg="refresherDefaultImg" :pullingImg="refresherPullingImg" :refreshingImg="refresherRefreshingImg" :completeImg="refresherCompleteImg" :refreshingAnimated="refresherRefreshingAnimated"
:showUpdateTime="showRefresherUpdateTime" :updateTimeKey="refresherUpdateTimeKey" :updateTimeTextMap="finalRefresherUpdateTimeTextMap"
:imgStyle="refresherImgStyle" :titleStyle="refresherTitleStyle" :updateTimeStyle="refresherUpdateTimeStyle" />
</component>
<template v-if="finalUseInnerList">
<component :is="nViewIs">
<slot name="header"/>
</component>
<component :is="nViewIs" class="zp-list-cell" v-for="(item,index) in realTotalData" :key="finalCellKeyName.length?item[finalCellKeyName]:index">
<slot name="cell" :item="item" :index="index"/>
</component>
<component :is="nViewIs">
<slot name="footer"/>
</component>
</template>
<template v-else>
<slot />
</template>
<!-- 全屏Loading -->
<component :is="nViewIs" v-if="showLoading&&zSlots.loading&&!loadingFullFixed" :class="{'z-paging-content-fixed':usePageScroll}" style="flex:1" :style="[nChatRecordRotateStyle]">
<slot name="loading" />
</component>
<!-- 上拉加载更多view -->
<component :is="nViewIs" v-if="!refresherOnly&&loadingMoreEnabled&&!showEmpty">
<view v-if="useChatRecordMode">
<view v-if="loadingStatus!==M.NoMore&&realTotalData.length">
<slot v-if="zSlots.chatLoading" name="chatLoading" />
<view v-else class="zp-chat-record-loading-container">
<text v-if="loadingStatus!==M.Loading" @click="_onScrollToUpper"
:class="defaultThemeStyle==='white'?'zp-loading-more-text zp-loading-more-text-white':'zp-loading-more-text zp-loading-more-text-black'">{{chatRecordLoadingMoreText}}</text>
<view>
<loading-indicator v-if="loadingStatus===M.Loading" class="zp-line-loading-image" animating />
</view>
</view>
</view>
</view>
<view :style="nLoadingMoreFixedHeight?{height:loadingMoreCustomStyle&&loadingMoreCustomStyle.height?loadingMoreCustomStyle.height:'80rpx'}:{}">
<slot v-if="showLoadingMoreDefault" name="loadingMoreDefault" />
<slot v-else-if="showLoadingMoreLoading" name="loadingMoreLoading" />
<slot v-else-if="showLoadingMoreNoMore" name="loadingMoreNoMore" />
<slot v-else-if="showLoadingMoreFail" name="loadingMoreFail" />
<z-paging-load-more @doClick="_onLoadingMore('click')" v-else-if="showLoadingMoreCustom" :zConfig="zLoadMoreConfig" />
<view v-if="safeAreaInsetBottom&&useSafeAreaPlaceholder" class="zp-safe-area-placeholder" :style="[{height:safeAreaBottom+'px'}]" />
</view>
</component>
<!-- 空数据图 -->
<component :is="nViewIs" v-if="showEmpty" :class="{'z-paging-content-fixed':usePageScroll}" :style="[{flex:emptyViewCenter?1:0},emptyViewSuperStyle,nChatRecordRotateStyle]">
<view :class="{'zp-empty-view':true,'zp-empty-view-center':emptyViewCenter}">
<slot v-if="zSlots.empty" name="empty" :isLoadFailed="isLoadFailed" />
<z-paging-empty-view v-else :emptyViewImg="finalEmptyViewImg" :emptyViewText="finalEmptyViewText" :showEmptyViewReload="finalShowEmptyViewReload"
:emptyViewReloadText="finalEmptyViewReloadText" :isLoadFailed="isLoadFailed" :emptyViewStyle="emptyViewStyle" :emptyViewTitleStyle="emptyViewTitleStyle"
:emptyViewImgStyle="emptyViewImgStyle" :emptyViewReloadStyle="emptyViewReloadStyle" :emptyViewZIndex="emptyViewZIndex" :emptyViewFixed="emptyViewFixed"
@reload="_emptyViewReload" @viewClick="_emptyViewClick" />
</view>
</component>
<component is="header" v-if="!hideNvueBottomTag" ref="zp-n-list-bottom-tag" class="zp-n-list-bottom-tag"></component>
</component>
<view v-if="zSlots.right" class="zp-page-right">
<slot name="right" />
</view>
</component>
<!-- 底部固定的slot -->
<slot name="bottom" />
<!-- 点击返回顶部view -->
<view v-if="showBackToTopClass" :class="backToTopClass" :style="[finalBackToTopStyle]" @click.stop="_backToTopClick">
<slot v-if="zSlots.backToTop" name="backToTop" />
<image v-else class="zp-back-to-top-img" :src="backToTopImg.length?backToTopImg:base64BackToTop" />
</view>
<!-- 全屏Loading(铺满z-paging并固定) -->
<view v-if="showLoading&&zSlots.loading&&loadingFullFixed" class="zp-loading-fixed">
<slot name="loading" />
</view>
</component>
<!-- #endif -->
</template>
<!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
<script src="./wxs/z-paging-wxs.wxs" module="pagingWxs" lang="wxs"></script>
<!-- #endif -->
<script module="pagingRenderjs" lang="renderjs">
import pagingRenderjs from './wxs/z-paging-renderjs.js';
/**
* z-paging 分页组件
* @description 高性能全平台兼容支持虚拟列表支持nvuevue3
* @tutorial https://z-paging.zxlee.cn
* @notice 以下仅为部分常用属性方法和事件完整文档请查阅z-paging官网
* @property {Number|String} default-page-no 自定义初始的pageNo默认为1
* @property {Number|String} default-page-size 自定义pageSize默认为10
* @property {Object} paging-style 设置z-paging的style部分平台(如微信小程序)无法直接修改组件的style可使用此属性代替
* @property {String} height z-paging的高度优先级低于pagingStyle中设置的height传字符串如100px100rpx100%
* @property {String} width z-paging的宽度优先级低于pagingStyle中设置的width传字符串如100px100rpx100%
* @property {Boolean} use-page-scroll 使用页面滚动默认为否
* @property {Boolean} use-virtual-list 是否使用虚拟列表默认为否
* @property {Boolean} fixed z-paging是否使用fixed布局若使用fixed布局则z-paging的父view无需固定高度z-paging高度默认为100%默认为是(当使用内置scroll-view滚动时有效)
* @property {Boolean} auto [z-paging]mounted后是否自动调用reload方法(mounted后自动调用接口)默认为是
* @property {Boolean} use-chat-record-mode 使用聊天记录模式默认为否
* @event {Function} query 下拉刷新或滚动到底部时会自动触发此方法z-paging加载时也会触发(若要禁止请设置:auto="false")pageNo和pageSize会自动计算好直接传给服务器即可
* @example <z-paging ref="paging" v-model="dataList" @query="queryList"></z-paging>
*/
export default {
name:"z-paging",
// #ifdef APP-VUE || H5
mixins: [pagingRenderjs],
// #endif
}
</script>
<script src="./js/z-paging-main.js" />
<style scoped>
@import "./css/z-paging-main.css";
@import "./css/z-paging-static.css";
</style>

86
src/uni_modules/z-paging/package.json

@ -0,0 +1,86 @@
{
"id": "z-paging",
"name": "z-paging",
"displayName": "【z-paging下拉刷新、上拉加载】高性能,全平台兼容。支持虚拟列表,支持nvue、vue3",
"version": "2.6.0",
"description": "超简单、低耦合!使用wxs+renderjs实现。支持长列表优化,支持自定义下拉刷新、上拉加载更多,支持自动管理空数据图、点击返回顶部,支持聊天分页、本地分页,支持国际化等100+项配置",
"keywords": [
"下拉刷新",
"上拉加载",
"分页器",
"nvue",
"虚拟列表"
],
"repository": "https://github.com/SmileZXLee/uni-z-paging",
"engines": {
"HBuilderX": "^3.0.7"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": "393727164"
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/z-paging",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y",
"钉钉": "y",
"快手": "y",
"飞书": "y",
"京东": "y"
},
"快应用": {
"华为": "y",
"联盟": "y"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

53
src/uni_modules/z-paging/readme.md

@ -0,0 +1,53 @@
# z-paging
<p align="center">
<img alt="logo" src="https://z-paging.zxlee.cn/img/title-logo.png" height="100" style="margin-bottom: 50px;">
</p>
[![version](https://img.shields.io/badge/version-2.6.0-blue)](https://github.com/SmileZXLee/uni-z-paging)
[![license](https://img.shields.io/github/license/SmileZXLee/uni-z-paging)](https://en.wikipedia.org/wiki/MIT_License)
### 文档地址:[https://z-paging.zxlee.cn](https://z-paging.zxlee.cn)
### 更新组件前,请注意[版本差异](https://z-paging.zxlee.cn/start/upgrade-guide.html)
***
### 功能&特点
* 【配置简单】仅需两步(绑定网络请求方法、绑定分页结果数组)轻松完成完整下拉刷新,上拉加载更多功能。
* 【低耦合,低侵入】分页自动管理。在page中无需处理任何分页相关逻辑,无需在data中定义任何分页相关变量,全由z-paging内部处理。
* 【超灵活,支持各种类型自定义】支持自定义下拉刷新,自定义上拉加载更多等各种自定义效果;支持使用内置自动分页,同时也支持通过监听下拉刷新和滚动到底部事件自行处理;支持使用自带全屏布局规范,同时也支持将z-paging自由放在任意容器中。
* 【功能丰富】支持国际化,支持自定义且自动管理空数据图,支持主题模式切换,支持本地分页,支持聊天分页模式,支持展示最后更新时间,支持吸顶效果,支持内部scroll-view滚动与页面滚动,支持一键滚动到顶部等诸多功能。
* 【全平台兼容】支持vue、nvue,vue2、vue3,支持h5、app及各家小程序。
* 【高性能】在app-vue、h5、微信小程序、QQ小程序上使用wxs+renderjs从视图层实现下拉刷新;支持虚拟列表,轻松渲染万级数据!
***
### 反馈qq群
* 官方1群`已满`:[790460711](https://jq.qq.com/?_wv=1027&k=vU2fKZZH)
* 官方2群:[371624008](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=avPmibADf2TNi4LxkIwjCE5vbfXpa-r1&authKey=dQ%2FVDAR87ONxI4b32Py%2BvmXbhnopjHN7%2FJPtdsqJdsCPFZB6zDQ17L06Uh0kITUZ&noverify=0&group_code=371624008)
***
### 预览
***
| 自定义下拉刷新效果演示 | 滑动切换选项卡+吸顶演示 |
| :----------------------------------------------------------: | :----------------------------------------------------------: |
| ![](https://z-paging.zxlee.cn/public/img/z-paging-demo5.gif) | ![](https://z-paging.zxlee.cn/public/img/z-paging-demo6.gif) |
| 聊天记录模式演示 | 虚拟列表(流畅渲染1万+条)演示 |
| :----------------------------------------------------------: | :----------------------------------------------------------: |
| ![](https://z-paging.zxlee.cn/public/img/z-paging-demo7.gif) | ![](https://z-paging.zxlee.cn/public/img/z-paging-demo8.gif) |
### 在线demo体验地址:
* [https://demo.z-paging.zxlee.cn](https://demo.z-paging.zxlee.cn)
| 扫码体验 |
| ------------------------------------------------------------ |
| ![](https://z-paging.zxlee.cn/public/img/code.png) |
### demo下载
* 支持vue2&vue3的`选项式api`写法demo下载,请点击页面右上角的【使用HBuilderX导入示例项目】或【下载示例项目ZIP】。
* 支持vue3的`组合式api`写法demo下载,请访问[github](https://github.com/SmileZXLee/uni-z-paging)。

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

Loading…
Cancel
Save