1. 执行npm命令安装mescroll : npm install --save mescroll.js
2. 引入mescroll组件 : import MescrollVue from 'mescroll.js/mescroll.vue’
<!-- 1.修改请求路径 参数
2.可以在created里面请求看一下是否成功 然后在将上拉下拉刷新请求修改 在查看属性渲染数据
3.npm install less less-loader --save
-->
<template>
<div>
<nav-bar />
<demo-section>
//全引入Vant-Ul组件 才能使用van-tabs
<van-tabs v-model="tabType" type="card" @click="tabChange">
<van-tab :title="`${tab.pending.name}(${tab.pending.dataNum})`" name="0"></van-tab>
<van-tab :title="tab.deal.name" name="1"></van-tab>
<van-tab :title="tab.done.name" name="2"></van-tab>
<!-- 待处理 -->
<mescroll-vue
v-show="tabType == 0"
ref="mescroll0"
:down="getMescrollDown(0)"
:up="getMescrollUp(0)"
@init="mescrollInit0"
>
<ul class="itemlist" id="itemlist0">
<li class="card" v-for="item in pending.data" :key="item.oafdUuid">
<router-link :to="{name: getType(item, 'name'), query: getType(item, 'query', 0)}">
<div class="card-body">
<span class="tag tag-blue">{{ getType(item, 'text') }}</span
>{{ item.oafdSubjectos }}
</div>
<div class="card-footer">
<span>{{ item.oafdCusrname }}</span
><i class="time">{{ item.oafdCdate | formatDate('yyyy-MM-dd hh:mm') }}</i>
</div>
</router-link>
</li>
</ul>
</mescroll-vue>
<!-- 已处理 -->
<mescroll-vue
v-show="tabType == 1"
ref="mescroll1"
:down="getMescrollDown(1)"
:up="getMescrollUp(1)"
@init="mescrollInit1"
>
<ul class="itemlist" id="itemlist1">
<li class="card" v-for="item in deal.data" :key="item.oafdUuid">
<router-link :to="{name: getType(item, 'name'), query: getType(item, 'query', 1)}">
<div class="card-body">
<span class="tag tag-gray">{{ getType(item, 'text') }}</span
>{{ item.oafdSubjectos }}
</div>
<div class="card-footer">
<span>{{ item.oafdCusrname }}</span
><i class="time">{{ item.oafdCdate | formatDate('yyyy-MM-dd hh:mm') }}</i>
</div>
</router-link>
</li>
</ul>
</mescroll-vue>
<!-- 已完成 -->
<mescroll-vue
v-show="tabType == 2"
ref="mescroll1"
:down="getMescrollDown(2)"
:up="getMescrollUp(2)"
@init="mescrollInit2"
>
<ul class="itemlist" id="itemlist2">
<li class="card" v-for="item in done.data" :key="item.oafdUuid">
<router-link :to="{name: getType(item, 'name'), query: getType(item, 'query', 2)}">
<div class="card-body">
<span class="tag tag-gray">{{ getType(item, 'text') }}</span
>{{ item.oafdSubjectos }}
</div>
<div class="card-footer">
<span>{{ item.oafdCusrname }}</span
><i class="time">{{ item.oafdCdate | formatDate('yyyy-MM-dd hh:mm') }}</i>
</div>
</router-link>
</li>
</ul>
</mescroll-vue>
</van-tabs>
</demo-section>
</div>
</template>
<script>
// 引入mescroll的vue组件
import MescrollVue from 'mescroll.js/mescroll.vue'
import {getFiledispatchList} from '@/api/official-review.js'
export default {
components: {
MescrollVue,
},
data() {
return {
pending: {
mescroll: null,
isListInit: false,
data: [] //请求的列表数据
},
deal: {
mescroll: null,
isListInit: false,
data: []
},
done: {
mescroll: null,
isListInit: false,
data: []
},
//tab切换的参数 pending deal done
tab: {
pending: {
name: '待处理',
dataNum: 0
},
deal: {
name: '已处理'
},
done: {
name: '已完成'
}
},
//控制tab切换的变量
tabType: 0
}
},
beforeRouteEnter(to, from, next) {
next(vm => {
setTimeout(() => {
// 如果是从表单详情或新建表单返回 则回写当前类型
let theType
//official-send-view 路径时你要跳转的详情也路径
if (from.name == 'official-send-view') {
theType = localStorage.getItem('listTabType')
//这串代码的意思时在vm.tab.pending上添加dataNum属性名 只是localStorage.getItem('dataNum')
vm.$set(vm.tab.pending, 'dataNum', localStorage.getItem('dataNum'))
} else {
theType = 0
}
vm.tabType = theType
vm.tabChange(theType)
})
})
},
beforeRouteLeave(to, from, next) {
// 如果是进入表单详情或新建表单 则保存当前的类型 否则清空
if (to.name == 'official-send-view') {
localStorage.setItem('listTabType', this.tabType)
localStorage.setItem('dataNum', this.tab.pending.dataNum)
} else {
localStorage.removeItem('listTabType')
localStorage.removeItem('dataNum')
}
next()
},
methods: {
// mescroll组件初始化的回调,可获取到mescroll对象
//tab切换时的回调函数
mescrollInit0(mescroll) {
mescroll.tabType = 0
this.pending.mescroll = mescroll
},
mescrollInit1(mescroll) {
mescroll.tabType = 1
this.deal.mescroll = mescroll
},
mescrollInit2(mescroll) {
mescroll.tabType = 2
this.done.mescroll = mescroll
},
// 多mescroll的配置,需通过方法获取,保证每个配置是单例
getMescrollDown(tabNum) {
//id="itemlist1"
let wrapId = 'itemlist' + tabNum //拼接和的id
return {
auto: false,
callback: this.downCallback,
empty: {
warpId: wrapId,
tip: '— 暂无更多数据 —'
}
}
},
getMescrollUp(tabNum) {
let wrapId = 'itemlist' + tabNum
return {
auto: false,
callback: this.upCallback, // 上拉回调,此处可简写; 相当于 callback: function (page) { upCallback(page); }
htmlNodata: '<p class="upwarp-nodata">— 暂无更多数据 —</p>',
noMoreSize: 1, // 如果列表已无数据,可设置列表的总数量要大于半页才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看; 默认5
page: {
//当前第几页
num: 0,
//当前页数的数量
size: 10
},
empty: {
warpId: wrapId,
tip: '— 暂无更多数据 —'
}
}
},
//上拉加载的回调
downCallback(mescroll) {
// 这里加载你想下拉刷新的数据, 比如刷新sent的轮播数据
if (mescroll.tabType == 0) {
// loadSwiper();
} else if (mescroll.tabType == 1) {
// ....
} else if (mescroll.tabType == 2) {
// ....
}
mescroll.resetUpScroll() // 触发下拉刷新的回调,加载第一页的数据
},
/* 上拉加载的回调 page = {num:1, size:10}; num:当前页 从1开始, size:每页数据条数 */
upCallback(page, mescroll) {
mescroll.endByPage(page.num * page.size, page.num)
let currentTab
if (mescroll.tabType == 0) {
currentTab = this.pending
currentTab.isListInit = true // 标记列表已初始化,保证列表只初始化一次
getFiledispatchList({
//动态的页数
'page.start': String(page.num == 1 ? 0 : currentTab.data.length),
'page.limit': '10',
'strMap.type': 'pending',
'strMap.searchKeyWords': '',
'strMap.postType': 'dd'
})
.then(response => {
if (response.success && response.data.length == 0) {
if (page.num == 1) {
currentTab.data = []
this.$set(this.tab.pending, 'dataNum', 0)
}
}
if (response.success && response.data.length > 0) {
const arr = response.data
if (page.num == 1) {
currentTab.data = []
}
currentTab.data = currentTab.data.concat(arr)
this.$set(this.tab.pending, 'dataNum', response.recordcount)
this.$nextTick(() => {
mescroll.endSuccess(response.recordcount)
})
} else {
mescroll.endDownScroll()
mescroll.endUpScroll(true)
}
})
.catch(e => {
console.log(e)
mescroll.endErr()
})
} else if (mescroll.tabType == 1) {
currentTab = this.deal
currentTab.isListInit = true // 标记列表已初始化,保证列表只初始化一次
getFiledispatchList({
//动态的页数
'page.start': String(page.num == 1 ? 0 : currentTab.data.length),
'page.limit': '10',
'strMap.type': 'deal',
'strMap.searchKeyWords': '',
'strMap.postType': 'dd'
})
.then(response => {
if (response.success && response.data.length == 0) {
if (page.num == 1) {
currentTab.data = []
}
}
if (response.success && response.data.length > 0) {
const arr = response.data
if (page.num == 1) {
currentTab.data = []
}
currentTab.data = currentTab.data.concat(arr)
this.$nextTick(() => {
mescroll.endSuccess(response.recordcount)
})
} else {
mescroll.endDownScroll()
mescroll.endUpScroll(true)
}
})
.catch(e => {
console.log(e)
mescroll.endErr()
})
} else if (mescroll.tabType == 2) {
currentTab = this.done
currentTab.isListInit = true // 标记列表已初始化,保证列表只初始化一次
getFiledispatchList({
'page.start': String(page.num == 1 ? 0 : currentTab.data.length),
'page.limit': '10',
'strMap.type': 'done',
'strMap.searchKeyWords': '',
'strMap.postType': 'dd'
})
.then(response => {
if (response.success && response.data.length == 0) {
if (page.num == 1) {
currentTab.data = []
}
}
if (response.success && response.data.length > 0) {
const arr = response.data
if (page.num == 1) {
currentTab.data = []
}
currentTab.data = currentTab.data.concat(arr)
this.$nextTick(() => {
mescroll.endSuccess(response.recordcount)
})
} else {
mescroll.endDownScroll()
mescroll.endUpScroll(true)
}
})
.catch(e => {
console.log(e)
mescroll.endErr()
})
}
},
// 切换菜单
tabChange(name) {
let newTab = this.getTabData(name) // 新转换的列表
if (!newTab.isListInit) {
newTab.mescroll.triggerDownScroll() // 加载列表
}
},
// 获取菜单对应的数据
getTabData(tabNum) {
if (tabNum == null) tabNum = this.tabNum
if (tabNum == 0) {
return this.pending
} else if (tabNum == 1) {
return this.deal
} else {
return this.done
}
},
// 获取每条数据对应的参数
getType(data, prop, tabType) {
const typeObj = {
text: '发文管理',
name: 'official-send-view', //跳转详情也路径
//穿过去的参数
query: {
uuid: data.oafdUuid,
//详情页数据不同时进行的判断
hideBtn: tabType != '0' ? 'yes' : 'no',
openType: 1
}
}
return typeObj[prop]
}
}
}
</script>
<style lang="less" scoped>
// tab 切换
@import '../../../style/common/tabs.less';
.mescroll {
position: fixed;
top: 102px;
bottom: 0;
height: auto;
}
.mescroll-padding {
bottom: 48px;
}
/deep/ .mescroll-upwarp {
min-height: 20px;
line-height: 20px;
padding: 8px 0;
font-size: 16px;
}
/deep/ .mescroll-upwarp .upwarp-nodata {
font-size: 16px;
color: rgba(25, 31, 37, 0.56);
}
/deep/ .mescroll-empty {
min-height: 20px;
line-height: 20px;
padding: 8px 0;
.empty-tip {
margin-top: 0;
font-size: 12px;
color: rgba(25, 31, 37, 0.56);
}
}
// 列表
.itemlist {
padding: 16px;
.card {
padding: 20px 16px;
background: rgba(255, 255, 255, 1) url('../../../assets/meeting/icon2.png') 92% bottom no-repeat;
background-size: 52px;
box-shadow: 0px 2px 4px 0px rgba(25, 31, 37, 0.04);
border-radius: 6px;
.tag {
margin-right: 5px;
padding-left: 6px;
padding-right: 16px;
display: inline-block;
min-width: 68px;
height: 26px;
line-height: 26px;
font-size: 14px;
color: #fff;
box-sizing: border-box;
vertical-align: middle;
&.tag-blue {
background: url('../../../assets/official-review/tag-blue.png');
background-size: 100% 100%;
}
&.tag-gray {
background: url('../../../assets/official-review/tag-gray.png');
background-size: 100% 100%;
}
}
.card-body {
margin-bottom: 14px;
line-height: 28px;
font-size: 20px;
color: rgba(25, 31, 37, 1);
}
.card-footer {
display: flex;
align-items: center;
line-height: 20px;
font-size: 16px;
color: rgba(25, 31, 37, 0.56);
span {
margin-right: 10px;
vertical-align: middle;
}
i {
font-style: normal;
vertical-align: middle;
}
.doc {
display: inline-block;
margin-right: 4px;
}
}
}
.card + .card {
margin-top: 16px;
}
}
// 筛选
.filter-panel {
padding-top: 44px;
.filter-title {
padding: 12px 16px 7px;
line-height: 21px;
font-size: 15px;
color: rgba(25, 31, 37, 1);
box-sizing: content-box;
}
.filter-body {
ul {
padding: 0 12px 18px;
display: flex;
flex-wrap: wrap;
}
li {
padding: 5px 4px;
flex-basis: 33.33%;
box-sizing: border-box;
}
p {
display: flex;
justify-content: center;
align-items: center;
height: 34px;
font-size: 14px;
background: rgba(25, 31, 37, 0.04);
color: rgba(25, 31, 37, 0.72);
border: 1px solid rgba(151, 151, 151, 0.04);
border-radius: 3px;
text-align: center;
&.active {
color: rgba(50, 150, 250, 1);
border: 1px solid rgba(50, 150, 250, 1);
background: rgba(50, 150, 250, 0.04);
}
}
}
.filter-footer {
display: flex;
button {
margin: 0;
padding: 0;
display: flex;
flex-basis: 50%;
height: 44px;
font-size: 17px;
justify-content: center;
align-items: center;
border: none;
outline: none;
}
.btn-reset {
color: rgba(50, 150, 250, 1);
background: rgba(50, 150, 250, 0.08);
}
.btn-confirm {
color: rgba(255, 255, 255, 1);
background: rgba(50, 150, 250, 1);
}
}
}
</style>