贴这段代码的原因就是在这次项目中,我不会写这个自定义时间。同时也给大家参考一下
1.效果显示
2.源代码
search.vue
<template>
<view class="search">
<view class="header">
<x-nav-bar
back
title="工单查询"
input
placeholder="请输入问题描述"
@onInputChange="setKeyword"
></x-nav-bar>
<view class="filter" :class="{ hidden: !filterState }">
<u-dropdown
font-size="28px"
font-weight="400"
color="#333333"
menu-icon="arrow-down-fill"
menu-icon-size="16"
ref="uDropdown"
@open="filterState = true"
@close="filterState = false"
border-bottom
duration="0"
>
<u-dropdown-item :title="filterProjectTitle">
<view class="list-item" @click="setProject()">全部</view>
<view
class="list-item"
@click="setProject(item)"
v-for="(item, index) of projects"
:key="index"
>{{ item.projectName }}</view
>
</u-dropdown-item>
<u-dropdown-item :title="filterTimeTitle">
<view class="list-item" @click="setTimeFromDay(TimeType.Unset)"
>全部</view
>
<view class="list-item" @click="setTimeFromDay(TimeType.D7)"
>近7天</view
>
<view class="list-item" @click="setTimeFromDay(TimeType.D30)"
>近30天</view
>
<view class="list-item" @click="setTimeFromDay(TimeType.D90)"
>近90天</view
>
<view class="picker-container">
<view class="title">自定义</view>
<view class="picker-date">
<view class="pickers">
<picker
mode="date"
:value="startDate"
@change="startDateChange"
>
<view class="date-container" v-if="startDate">{{
startDate
}}</view>
<view class="date-container undefined" v-if="!startDate"
>初始时间</view
>
</picker>
<view class="text">至</view>
<picker mode="date" :value="endDate" @change="endDateChange">
<view class="date-container" v-if="endDate">{{
endDate
}}</view>
<view class="date-container undefined" v-if="!endDate"
>结束时间</view
>
</picker>
</view>
<view class="btn" @click="setTimeFromDay(TimeType.Custom)"
>确定</view
>
</view>
</view>
</u-dropdown-item>
<u-dropdown-item :title="filterStatusTitle">
<view class="list-item" @click="setState()">全部</view>
<view
class="list-item"
@click="setState(OrderStatus.OrderPendingReview)"
>报单待审核</view
>
<view class="list-item" @click="setState(OrderStatus.OrderRejected)"
>报单被驳回</view
>
<view class="list-item" @click="setState(OrderStatus.Unclaimed)"
>待领取</view
>
<view class="list-item" @click="setState(OrderStatus.Pending)"
>待执行</view
>
<view class="list-item" @click="setState(OrderStatus.Executing)"
>执行中</view
>
<view
class="list-item"
@click="setState(OrderStatus.AcceptanceCheck)"
>待验收</view
>
<view
class="list-item"
@click="setState(OrderStatus.AcceptanceCheckRejected)"
>验收被驳回</view
>
<view class="list-item" @click="setState(OrderStatus.Done)"
>已完成</view
>
</u-dropdown-item>
<u-dropdown-item :title="filterTypeTitle">
<view class="list-item" @click="setType()">全部</view>
<view class="list-item" @click="setType(OrderType.Device)"
>设备设施</view
>
<view class="list-item" @click="setType(OrderType.FireSafety)"
>消防安全</view
>
<view
class="list-item"
@click="setType(OrderType.EnvironmentalQuality)"
>环境品质</view
>
<view class="list-item" @click="setType(OrderType.Other)"
>其他问题</view
>
</u-dropdown-item>
</u-dropdown>
</view>
</view>
<scroll-view
class="wrapper safe-area-inset-bottom"
refresher-background="transparent"
:scroll-y="true"
:refresher-enabled="true"
:refresher-triggered="refresh"
@refresherrefresh="refreshData()"
@scrolltolower="loadNextData()"
>
<template v-if="items.length > 0">
<view class="padding">
<x-card :list-data="items"></x-card>
</view>
</template>
<template v-else>
<x-no-data v-if="!loading"></x-no-data>
</template>
<template v-if="!loaded && !refresh">
<view class="loading">
<u-loading mode="circle"></u-loading>
</view>
</template>
</scroll-view>
</view>
</template>
<style lang="scss" scoped src="./search.scss"></style>
<script lang="ts" src="./search.ts"></script>
search.scss
.search{
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
}
.header{
width: 100%;
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.08);
font-size: 32px;
font-weight: 400;
color: #333333;
}
.loading{
display: flex;
justify-content: center;
align-items: center;
margin: 40rpx 0;
}
.filter{
background-color: #fff;
&.hidden{
overflow: hidden;
}
}
.list-item{
width: 100%;
height: 100rpx;
line-height: 100rpx;
padding: 0 40rpx;
background-color: #fff;
border-bottom: 1px solid #eaeaea;
font-size: 28rpx;
color: #333333;
}
.picker-container{
width: 100%;
display: flex;
flex-direction: column;
padding: 20rpx 40rpx;
background-color: #fff;
.title{
font-size: 32rpx;
margin: 0 0 20rpx 0;
}
.picker-date{
display: flex;
align-items: center;
justify-content: space-between;
.pickers{
display: flex;
align-items: center;
justify-content: space-between;
.date-container{
width: 216rpx;
height: 68rpx;
line-height: 68rpx;
background-color: #F5F5F5;
text-align: center;
font-size: 28rpx;
color: #333333;
&.undefined{
color: #999999;
}
}
}
.text{
width: 70rpx;
text-align: center;
font-size: 28rpx;
}
.btn{
width: 140rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 140rpx;
border: 1px solid #3880ff;
font-size: 28rpx;
text-align: center;
color: #3880ff;
}
}
}
.wrapper{
flex: 1;
overflow: auto;
background-color: transparent;
.padding{
padding-left: 30rpx;
padding-right: 30rpx;
box-sizing: border-box;
}
}
search.js
import { Vue, Component } from 'vue-property-decorator'
import xCard from '@/components/x-card/x-card.vue'
import xNavBar from '@/components/x-nav-bar/x-nav-bar.vue'
import xNoData from '@/components/x-no-data/x-no-data.vue'
import uLoading from 'uview-ui/components/u-loading/u-loading.vue'
import uDropdown from 'uview-ui/components/u-dropdown/u-dropdown.vue'
import uDropdownItem from 'uview-ui/components/u-dropdown-item/u-dropdown-item.vue'
import { OnPageShow, Created, BeforeDestroy } from '@/lib/lifecycle'
import { FindProjectReq, Project, OrderType, OrderStatus, FindOrderConditionalQuery, Order } from '@/services'
import { debounceTime, merge, of, Subject, switchMap, tap } from 'rxjs'
import { map, takeUntil } from 'rxjs/operators'
import { getUnixTime, subDays, parse } from 'date-fns'
enum TimeType {
Unset,
D7,
D30,
D90,
Custom,
}
interface Filter {
project: Project | null
timeMode: TimeType | null
status: OrderStatus | null
type: OrderType | null
start: number | null
end: number | null
keyword: string | null
}
// @ts-ignore
@Component({
components: {
xCard,
xNavBar,
uDropdown,
uDropdownItem,
xNoData,
uLoading
}
})
export default class Search extends Vue implements Created, OnPageShow, BeforeDestroy{
projects: Project[] = []
OrderType = OrderType
OrderStatus = OrderStatus
TimeType = TimeType
refresh = false
loading = true
loaded = false
refresh$!: Subject<void>
next$!: Subject<void>
filter$!: Subject<void>
unsubscribe!: Subject<void>
items: Order[] = []
startDate = ''
endDate = ''
filterState: boolean = false
filterData: Filter = {
project: null,
timeMode: null,
status: null,
type: null,
start: null,
end: null,
keyword: ''
}
get filterProjectTitle(): string{
return this.filterData.project?.projectName || '项目'
}
get filterStatusTitle(): string{
switch (this.filterData.status) {
case OrderStatus.OrderPendingReview:
return '报单待审核'
case OrderStatus.OrderRejected:
return '报单被驳回'
case OrderStatus.Unclaimed:
return '待领取'
case OrderStatus.Pending:
return '待执行'
case OrderStatus.Executing:
return '执行中'
case OrderStatus.AcceptanceCheck:
return '待验收'
case OrderStatus.AcceptanceCheckRejected:
return '验收被驳回'
case OrderStatus.Done:
return '已完成'
default:
return '工单状态'
}
}
get filterTimeTitle(): string{
switch (this.filterData.timeMode) {
case TimeType.Custom:
return '自定义'
case TimeType.D7:
return '近7天'
case TimeType.D30:
return '近30天'
case TimeType.D90:
return '近90天'
default:
return '报单时间'
}
}
get filterTypeTitle(): string{
switch (this.filterData.type) {
case OrderType.Device:
return '设备设施'
case OrderType.FireSafety:
return '消防安全'
case OrderType.EnvironmentalQuality:
return '环境品质'
case OrderType.Other:
return '其他问题'
default:
return '工单类型'
}
}
created() {
this.refresh$ = new Subject()
this.next$ = new Subject()
this.filter$ = new Subject()
this.unsubscribe = new Subject()
}
onShow() {
this.$services.user.findProjectList(new FindProjectReq())
.pipe(takeUntil(this.unsubscribe))
.subscribe({
next: rs => {
if (rs.ok && rs.data?.rows) {
this.projects = rs.data.rows
}
},
error: err => {
console.log(err)
}
})
of(null).pipe(
switchMap(() => {
let req = new FindOrderConditionalQuery()
return merge(
of(null).pipe(
switchMap(() => {
this.loading = true
return this.$services.order.findAllByConditional(req)
}),
map(rs => {
this.loaded = rs.length < req.rowCount
return rs
})
),
this.filter$.pipe(
debounceTime(300),
switchMap(() => {
this.loading = true
this.loaded = false
this.items = []
req.current = 1
req.searchPhrase = this.filterData.keyword || undefined
req.projectId = this.filterData.project?.projectId || undefined
req.reportStartDate = this.filterData.start || undefined
req.reportEndDate = this.filterData.end || undefined
req.orderStatus = this.filterData.status || undefined
req.orderType = this.filterData.type || undefined
return this.$services.order.findAllByConditional(req)
}),
map(rs => {
this.loaded = rs.length < req.rowCount
return rs
})
),
this.next$.pipe(
switchMap(() => {
this.loading = true
req.current += 1
return this.$services.order.findAllByConditional(req)
}),
map(rs => {
this.loaded = rs.length < req.rowCount
return this.items.concat(rs || [])
})
),
this.refresh$.pipe(
switchMap(() => {
this.loading = true
this.loaded = false
this.items = []
req = new FindOrderConditionalQuery()
return this.$services.order.findAllByConditional(req)
}),
map(rs => {
this.loaded = rs.length < req.rowCount
this.refresh = false
return rs
})
)
)
})
).pipe(takeUntil(this.unsubscribe)).subscribe({
next: rs => {
this.items = rs
this.loading = false
},
error: err => {
console.log(err)
this.loading = false
}
})
}
closeDropdown(): void{
// @ts-ignore
this.$refs.uDropdown.close()
}
setDropdownHighlight(index?: number): void{
// @ts-ignore
this.$refs.uDropdown.highlight(index)
}
setType(value?: OrderType): void{
this.filterData.type = value || null
this.closeDropdown()
this.filter$.next()
}
setState(value?: OrderStatus): void{
this.filterData.status = value || null
this.closeDropdown()
this.filter$.next()
}
setProject(value?: Project): void{
this.filterData.project = value || null
this.closeDropdown()
this.filter$.next()
}
setKeyword(value: string): void{
this.filterData.keyword = value
this.closeDropdown()
this.filter$.next()
}
setTimeFromDay(type: TimeType): void{
switch (type) {
case TimeType.Unset:
this.filterData.start = null
this.filterData.end = null
this.startDate = ''
this.endDate = ''
this.filterData.timeMode = TimeType.Unset
break
case TimeType.D7:
this.filterData.start = getUnixTime(subDays(new Date(), 7))
this.filterData.end = getUnixTime(new Date())
this.filterData.timeMode = TimeType.D7
break
case TimeType.D30:
this.filterData.start = getUnixTime(subDays(new Date(), 30))
this.filterData.end = getUnixTime(new Date())
this.filterData.timeMode = TimeType.D30
break
case TimeType.D90:
this.filterData.start = getUnixTime(subDays(new Date(), 90))
this.filterData.end = getUnixTime(new Date())
this.filterData.timeMode = TimeType.D90
break
case TimeType.Custom:
if (this.startDate && this.endDate){
const sp = parse(this.startDate, 'yyyy-MM-dd', new Date())
const ep = parse(this.endDate, 'yyyy-MM-dd', new Date())
this.filterData.start = getUnixTime(sp)
this.filterData.end = getUnixTime(ep)
this.filterData.timeMode = TimeType.Custom
}else {
uni.showToast({
title: '参数不完整',
duration: 1000
})
return
}
break
}
this.closeDropdown()
this.filter$.next()
}
beforeDestroy() {
this.unsubscribe.next()
this.unsubscribe.complete()
}
startDateChange(e: any): void{
this.startDate = e.detail.value
}
endDateChange(e: any): void{
this.endDate = e.detail.value
}
refreshData(): void{
this.refresh = true
this.refresh$.next()
}
loadNextData(): void{
if (!this.loaded && !this.loading){
this.next$.next()
}
}
}
3.我的理解
刚开始我用的是uview里面的u-dorpdown,但是里面的自定义的不会写,以及自定义时间不太会写。后来明白了,自定义就是里面的下拉筛选框自己写。