dev
Panzihang 2023-07-13 11:18:17 +08:00
parent ac0c8330aa
commit 66df74758d
36 changed files with 4618 additions and 9 deletions

View File

@ -0,0 +1,605 @@
<template>
<view>
<uni-drawer :visible="visibleDrawer" :hideNoAnimate="showBackButton" mode="right" @close="closeDrawer()">
<!-- #ifdef APP-PLUS -->
<view class="iconfont icon-guanbi" v-if="showBackButton" @tap="closeDrawer()"></view>
<!-- #endif -->
<scroll-view class="drawer-list" scroll-y :style="{'height': drawerHeight, 'padding-top': fixTop}">
<block v-for="(item, index) in menuList" :key="index">
<!-- 单选多选 isMutiple是否支持多选-->
<view v-if="item.type === 'custom' && item.detailList.length">
<view class="drawer-list-title flex justify-between">
<view>
{{item.title}}
</view>
<text v-if="item.detailList.length>showLenght"
@tap="showMore(index)">{{item.showMoreList ? '收起' : '更多'}}</text>
</view>
<view class="draer-list-con">
<template v-if="!item.showMoreList">
<text
:style="{background: textItem.isSelected ? color : '', color: textItem.isSelected ? '#ffffff' : ''}"
v-if="idx<showLenght" v-for="(textItem, idx) in item.detailList" :key="idx"
:class="textItem.isSelected ? 'on' : ''"
@tap="itemTap(idx,item.detailList,item.key, item.isMutiple)">
{{textItem.title}}
</text>
</template>
<template v-else>
<text
:style="{background: textItem.isSelected ? color : '', color: textItem.isSelected ? '#ffffff' : ''}"
v-for="(textItem, idx) in item.detailList" :key="idx"
:class="textItem.isSelected ? 'on' : ''"
@tap="itemTap(idx,item.detailList,item.key, item.isMutiple)">
{{textItem.title}}
</text>
</template>
</view>
</view>
<!-- 时间带时分秒范围选择 -->
<view v-if="item.type === 'rangetime'">
<view class="drawer-list-title flex justify-between">
<view>
{{item.title}}
</view>
</view>
<view class="dateContent" @click="onShowDatePicker('rangetime', item.key, item)">
<view>
<template v-if="result[item.key] && result[item.key].length > 0">
{{result[item.key][0]}}
</template>
</view>
<view>
<template v-if="result[item.key] && result[item.key].length > 0">
{{result[item.key][1]}}
</template>
</view>
</view>
</view>
<!-- 时间不带时分秒范围选择 -->
<view v-if="item.type === 'range'">
<view class="drawer-list-title flex justify-between">
<view>
{{item.title}}
</view>
</view>
<view class="dateContent" @click="onShowDatePicker('range', item.key, item)">
<view>
<template v-if="result[item.key] && result[item.key].length > 0">
{{result[item.key][0]}}-{{result[item.key][1]}}
</template>
</view>
</view>
</view>
<!-- 时间选择 -->
<view v-if="item.type === 'date'">
<view class="drawer-list-title flex justify-between">
<view>
{{item.title}}
</view>
</view>
<view class="dateContent" @click="onShowDatePicker('date', item.key, item)">
<view>
<template v-if="result[item.key]">
{{result[item.key]}}
</template>
</view>
</view>
</view>
<!-- 数值范围选择 -->
<view v-if="item.type === 'rangenumber'">
<view class="drawer-list-title flex justify-between">
<view>
{{item.title}}
</view>
</view>
<view class="dateContent rangenumber-content flex">
<view class="rangenumber-input">
<input class="m-input" type="number" clearable v-model="result[item.minName || (item.key + 'Min')]"
:placeholder="item.minPlaceholder || '最小值'"
@blur="numberInputBlur(item)"></input>
</view>
<text>-</text>
<view class="rangenumber-input">
<input class="m-input" type="number" clearable v-model="result[item.maxName || (item.key + 'Max')]"
:placeholder="item.maxPlaceholder || '最大值'"
@blur="numberInputBlur(item)"></input>
</view>
</view>
</view>
<!-- 单输入框 -->
<view v-if="item.type === 'singleinput'">
<view class="drawer-list-title flex justify-between">
<view>
{{item.title}}
</view>
</view>
<view class="dateContent">
<view>
<input class="m-input" clearable v-model="result[item.key]"
:placeholder="item.placeholder || '请输入关键字'" />
</view>
</view>
</view>
</block>
</scroll-view>
<view class="filter-content-footer flex justify-center">
<!-- #ifdef APP-PLUS-->
<view v-if="showBackButton" class="filter-content-footer-item" :style="{color: '#ccc', 'border': '1rpx solid #ccc'}"
@tap="closeDrawer()">
<text>返回</text>
</view>
<!-- #endif -->
<view class="filter-content-footer-item" :style="{color, 'border': `1rpx solid ${color}`}"
@tap="resetClick">
<text>重置</text>
</view>
<view class="filter-content-footer-item" :style="{'background': color}" @tap="sureClick">
<text>确认</text>
</view>
</view>
</uni-drawer>
<mx-date-picker :show="showPicker" :color="color" :type="dateType" :value="dateValue" :show-tips="true"
:show-seconds="true" @confirm="onSelected" @cancel="onSelected" />
</view>
</template>
<script>
/***
* 筛选组件当前支持多选单选
* item.type (custom 单选多选rangetime 时间范围带时分秒range 时间范围不带时分秒rangenumber 数字范围)
* item.isMutiple 是否支持多选
* 筛选后返回格式{"listName1":[value,value](多选),"listName2":"value"单选,...}
* rangenumber形式-可能为["",1][1,""]表示只有一个最大值或最小值
***/
import uniDrawer from '@/components/uni-drawer/uni-drawer.vue';
import MxDatePicker from "@/components/mx-datepicker/mx-datepicker.vue";
export default {
props: {
list: {
required: true,
type: Array,
default () {
return [];
},
},
color: {
type: String,
default: '#4D7BFE',
},
defaultValue: { //sureClick
type: Object,
default () {
return {}
},
},
showBackButton: {
type: Boolean,
default: false,
}
},
watch: {
list: {
handler(val) {
this.menuList = JSON.parse(JSON.stringify(val));
this.resetResult();
this.defaultValueFun();
},
deep: true // obj
}
},
components: {
uniDrawer,
MxDatePicker
},
beforeCreate() {
Object.isEmpty = (object, except = []) => {
if (!object) {
return false;
}
for (let key in object) {
if (except && except.includes(key)) {
continue;
}
if (object.hasOwnProperty(key)) {
return false;
}
}
return true;
};
Date.prototype.Format = function(fmt) { //author: meizz
var o = {
"M+": this.getMonth() + 1, //
"d+": this.getDate(), //
"h+": this.getHours(), //
"m+": this.getMinutes(), //
"s+": this.getSeconds(), //
"q+": Math.floor((this.getMonth() + 3) / 3), //
"S": this.getMilliseconds() //
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1
.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[
k]) : (("00" + o[
k]).substr(("" + o[k]).length)));
return fmt;
};
String.prototype.replaceAll = function(oldValue, newValue) { return this.toString().replace(new RegExp(oldValue, 'gm'), newValue); }
},
created() {
this.menuList = JSON.parse(JSON.stringify(this.list));
this.resetResult();
uni.getSystemInfo({
success: (res) => {
let windowHeight = res.windowHeight;
// #ifdef H5
if (!(this.$IsWeixin || this.$IsAlipay || this.$IsCloudPay)) {
let thirdApp = getApp().globalData.options?.thirdApp;
if (thirdApp && thirdApp.hideNavBar) {
// App使App
} else {
this.fixTop = (res.statusBarHeight || 0) + 'px';
}
}
windowHeight = window.innerHeight || document.documentElement.clientHeight || document.body
.clientHeight || res.windowHeight;
// #endif
this.drawerHeight = (windowHeight - uni.upx2px(120)) + 'px';
// uni.showModal({
// content: `model: ${res.model}`,
// })
}
});
},
mounted() {
this.defaultValueFun();
},
computed: {
},
data() {
return {
menuList: [],
visibleDrawer: false,
menuKey: 1,
showLenght: 6,
drawerHeight: '500px',
selectDetailList: [],
result: {},
showPicker: false,
dateType: 'rangetime',
dateValue: '',
fixTop: '0px'
};
},
methods: {
defaultValueFun() {
//sureClick
if (!Object.isEmpty(this.defaultValue)) {
const value = this.defaultValue;
const list = JSON.parse(JSON.stringify(this.menuList));
for (let key in value) {
for (let i = 0; i < list.length; i++) {
if (list[i].key === key) {
if (list[i].type === 'custom') {
list[i].detailList.map((item, index) => {
if (Array.isArray(value[key]) && value[key].indexOf(item.value) > -1) {
item.isSelected = true;
} else if (value[key] == item.value) {
item.isSelected = true;
}
return item;
})
continue;
}
if (list[i].type === 'range' || list[i].type === 'rangetime' || list[i].type === 'rangenumber' && Array.isArray(value[key]) && value[key].length === 2) {
this.result[key] = value[key];
this.result[list[i].minName || (list[i].key + 'Min')] = value[key][0];
this.result[list[i].maxName || (list[i].key + 'Max')] = value[key][1];
continue;
}
if (list[i].type === 'date' || list[i].type === 'singleinput' && value[key]) {
this.result[key] = value[key];
continue;
}
}
}
}
if (this.defaultRefeshTimer) {
clearTimeout(this.defaultRefesh·Timer);
}
this.defaultRefeshTimer = setTimeout(() => {
console.log('筛选默认值触发')
this.menuList = list;
this.sureClick();
}, 200);
}
},
resetResult() {
this.result = this.commonResultObj();
},
commonResultObj() {
let obj = {};
this.menuList.map((item) => {
switch(item.type) {
case "custom":
item.isMutiple ? obj[item.key] = [] : obj[item.key] = '';
item.detailList.forEach(dListItem => {
dListItem.isSelected = dListItem.isSelected || false;
});
break;
case 'range':
case 'rangetime':
case 'rangenumber':
this.result[item.key] = [];
this.result[item.minName || (item.key + 'Min')] = '';
this.result[item.maxName || (item.key + 'Max')] = '';
break;
default:
obj[item.key] = '';
}
})
return obj;
},
//
itemTap(index, list, key, isMutiple) {
if (isMutiple == true) {
list[index].isSelected = !list[index].isSelected;
if (list[index].isSelected) {
this.result[key].push(list[index].value);
} else {
list[index].isSelected = false;
var idx = this.result[key].indexOf(list[index].value);
this.result[key].splice(idx, 1);
}
} else {
this.result[key] = list[index].isSelected ? '' : list[index].value;
for (let i = 0; i < list.length; i++) {
if (index == i && !list[i].isSelected) {
list[i].isSelected = true
} else {
list[i].isSelected = false
}
}
}
// #ifdef H5 || APP-PLUS
this.$forceUpdate();
// #endif
},
sureClick() {
this.menuList.forEach(menu => {
let list = menu.detailList || [];
if (menu.type == 'custom' && list.length > 0) {
let selectedValueList = [];
list.forEach(item => {
if (item.isSelected) {
selectedValueList.push(item.value);
}
});
if (menu.isMutiple == true) {
this.result[menu.key] = selectedValueList;
} else {
this.result[menu.key] = selectedValueList[0] || '';
}
}
});
let str_result = {};
let hasChoose = false;
for (let key in this.result) {
if (typeof this.result[key] == 'object') {
str_result[key] = this.result[key].join(',');
if (!hasChoose) {
hasChoose = this.result[key].join(',') !== '' ? true : false;
}
} else {
str_result[key] = this.result[key];
if (!hasChoose) {
hasChoose = this.result[key] !== '' ? true : false;
}
}
}
this.$emit("result", {
'str_result': str_result,
'result': this.result,
'hasChoose': hasChoose,
'visibleDrawer': false
});
},
resetClick() {
this.minNumber = '';
this.maxNumber = '';
for (let key in this.result) {
if (typeof this.result[key] === 'object') {
this.result[key] = [];
} else {
this.result[key] = '';
}
}
for (let i = 0; i < this.menuList.length; i++) {
if (this.menuList[i].type === 'custom') {
for (let j = 0; j < this.menuList[i].detailList.length; j++) {
this.menuList[i].detailList[j].isSelected = false;
}
}
}
// #ifdef H5 || APP-PLUS
this.$forceUpdate();
// #endif
},
closeDrawer() {
this.visibleDrawer = false;
// #ifdef APP-PLUS
this.$emit("result", {
type: 1,
});
// #endif
},
showMore(index) {
this.menuList[index].showMoreList = !this.menuList[index].showMoreList;
++this.menuKey;
// #ifdef H5 || APP-NVUE
this.$forceUpdate();
// #endif
},
onShowDatePicker(type, key, item) { //
this.dateType = type;
this.dateValue = this.result[key] || '';
this.showPicker = true;
this.tempKey = key;
this.item = item;
},
onSelected(e, key) { //
this.showPicker = false;
if (e) {
this.result[this.tempKey] = e.value;
if (e.value && e.value.length && this.item && this.item.type !== 'date') {
let item = this.item;
this.result[item.minName || (item.key + 'Min')] = e.value[0].replaceAll('/', '-');
this.result[item.maxName || (item.key + 'Max')] = e.value[1].replaceAll('/', '-');
}
//
console.log('value => ' + e.value);
//Date
console.log('date => ' + e.date);
}
},
numberInputBlur(item) {
let minNumber = this.result[item.minName || (item.key + 'Min')];
let maxNumber = this.result[item.maxName || (item.key + 'Max')];
if (minNumber != '' && maxNumber != '' && parseFloat(minNumber) > parseFloat(maxNumber)) {
let temp = minNumber;
this.result[item.minName || (item.key + 'Min')] = maxNumber;
this.result[item.maxName || (item.key + 'Max')] = temp;
}
this.result[item.key] = [];
this.result[item.key].push(minNumber && parseFloat(minNumber));
this.result[item.key].push(maxNumber && parseFloat(maxNumber));
}
}
}
</script>
<style lang="scss" scoped>
.flex {
display: flex;
}
.justify-between {
justify-content: space-between;
}
view,
scroll-view,
swiper,
button,
input,
textarea,
label,
navigator,
image {
box-sizing: border-box;
}
/* 筛选样式 */
.drawer-list {
padding: 0 20rpx;
font-size: 26rpx;
}
input {
font-size: 26rpx;
}
.drawer-list .drawer-list-title {
font-size: 34rpx;
font-weight: 400;
line-height: 48rpx;
margin: 38rpx 0 18rpx;
color: rgba(34, 34, 34, 1);
}
.drawer-list .drawer-list-title>text {
font-size: 26rpx;
color: #666666;
}
.drawer-list .draer-list-con>text {
background: rgba(93, 92, 254, 0.1);
border-radius: 28px;
color: #666666;
font-size: 28rpx;
padding: 10rpx 28rpx;
margin: 10rpx 10rpx 10rpx 0;
display: inline-block;
}
.filter-content-footer-item {
flex: 1;
height: 72rpx;
line-height: 72rpx;
text-align: center;
border-radius: 8rpx;
margin: 14rpx;
color: #FFFFFF;
}
.picker {
z-index: 99999 !important;
}
.dateContent {
&>view {
background: rgba(244, 244, 244, 1);
border-radius: 8rpx;
width: 100%;
height: 64rpx;
line-height: 64rpx;
margin-bottom: 12rpx;
padding: 0 12rpx;
}
}
.rangenumber-content {
&>text {
display: inline-block;
width: 10%;
text-align: center;
height: 64rpx;
line-height: 64rpx;
}
.rangenumber-input {
width: 45%;
display: inline-block;
padding: 0 12rpx;
}
}
.m-input {
height: 64rpx;
line-height: 64rpx;
}
::v-deep .picker {
z-index: 999;
}
.icon-guanbi {
position: fixed;
top: 40rpx;
right: 40rpx;
z-index: 1000;
}
</style>

View File

@ -0,0 +1,819 @@
<template>
<view v-if="isShow" class="picker" @tap="onConfirm">
<!-- 日期选择器 -->
<view v-if="type!='time'" class="picker-modal">
<view class="picker-modal-header">
<view class="picker-icon picker-icon-zuozuo" :hover-stay-time="100" hover-class="picker-icon-active" @click.stop="onSetYear('-1')"></view>
<view class="picker-icon picker-icon-zuo" :hover-stay-time="100" hover-class="picker-icon-active" @click.stop="onSetMonth('-1')"></view>
<text class="picker-modal-header-title">{{title}}</text>
<view class="picker-icon picker-icon-you" :hover-stay-time="100" hover-class="picker-icon-active" @click.stop="onSetMonth('+1')"></view>
<view class="picker-icon picker-icon-youyou" :hover-stay-time="100" hover-class="picker-icon-active" @click.stop="onSetYear('+1')"></view>
</view>
<swiper class="picker-modal-body" :circular="true" :duration="200" :skip-hidden-item-layout="true" :current="calendarIndex" @change="onSwiperChange">
<swiper-item class="picker-calendar" v-for="(calendar,calendarIndex2) in calendars" :key="calendarIndex2">
<view class="picker-calendar-view" v-for="(week,index) in weeks" :key="index - 7">
<view class="picker-calendar-view-item">{{week}}</view>
</view>
<view class="picker-calendar-view" v-for="(date,dateIndex) in calendar" :key="dateIndex" @click.stop="onSelectDate(date)">
<!-- 背景样式 -->
<view v-show="date.bgStyle.type" :class="'picker-calendar-view-'+date.bgStyle.type" :style="{background: date.bgStyle.background}"></view>
<!-- 正常和选中样式 -->
<view class="picker-calendar-view-item" :style="{opacity: date.statusStyle.opacity, color: date.statusStyle.color, background: date.statusStyle.background}">
<text>{{date.title}}</text>
</view>
<!-- 小圆点样式 -->
<view class="picker-calendar-view-dot" :style="{opacity: date.dotStyle.opacity, background: date.dotStyle.background}"></view>
<!-- 信息样式 -->
<view v-show="date.tips" class="picker-calendar-view-tips">{{date.tips}}</view>
</view>
</swiper-item>
</swiper>
<view class="picker-modal-footer">
<view class="picker-modal-footer-info">
<block v-if="isMultiSelect">
<view class="picker-display">
<text>{{beginText}}日期</text>
<text class="picker-display-text">{{BeginTitle}}</text>
<view v-if="isContainTime" class="picker-display-link" :hover-stay-time="100" hover-class="picker-display-link-active"
:style="{color}" @click.stop="onShowTimePicker('begin')">{{BeginTimeTitle}}</view>
</view>
<view class="picker-display">
<text>{{endText}}日期</text>
<text class="picker-display-text">{{EndTitle}}</text>
<view v-if="isContainTime" class="picker-display-link" :hover-stay-time="100" hover-class="picker-display-link-active"
:style="{color}" @click.stop="onShowTimePicker('end')">{{EndTimeTitle}}</view>
</view>
</block>
<block v-else>
<view class="picker-display">
<text>当前选择</text>
<text class="picker-display-text">{{BeginTitle}}</text>
<view v-if="isContainTime" class="picker-display-link" :hover-stay-time="100" hover-class="picker-display-link-active"
:style="{color}" @click.stop="onShowTimePicker('begin')">{{BeginTimeTitle}}</view>
</view>
</block>
</view>
<view class="picker-modal-footer-btn">
<view class="picker-btn" :hover-stay-time="100" hover-class="picker-btn-active" @click.stop="onCancel">取消</view>
<view class="picker-btn" :style="{color}" :hover-stay-time="100" hover-class="picker-btn-active" @click.stop="onConfirm">确认</view>
</view>
</view>
</view>
<!-- 时间选择器 -->
<view v-if="showTimePicker" class="picker">
<view class="picker-modal picker-time">
<view class="picker-modal-header">
<text class="picker-modal-header-title">选择日期</text>
</view>
<picker-view class="picker-modal-time" indicator-class="picker-modal-time-item" :value="timeValue" @change.stop="onTimeChange">
<picker-view-column>
<view v-for="(v,i) in 24" :key="i">{{i<10?'0'+i:i}}</view>
</picker-view-column>
<picker-view-column>
<view v-for="(v,i) in 60" :key="i">{{i<10?'0'+i:i}}</view>
</picker-view-column>
<picker-view-column v-if="showSeconds">
<view v-for="(v,i) in 60" :key="i">{{i<10?'0'+i:i}}</view>
</picker-view-column>
</picker-view>
<view class="picker-modal-footer">
<view class="picker-modal-footer-info">
<view class="picker-display">
<text>当前选择</text>
<text class="picker-display-text">{{PickerTimeTitle}}</text>
</view>
</view>
<view class="picker-modal-footer-btn">
<view class="picker-btn" :hover-stay-time="100" hover-class="picker-btn-active" @click.stop="onCancelTime">取消</view>
<view class="picker-btn" :style="{color}" :hover-stay-time="100" hover-class="picker-btn-active" @click.stop="onConfirmTime">确认</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* 工具函数库
*/
const DateTools = {
/**
* 获取公历节日
* @param date Date对象
*/
getHoliday(date) {
let holidays = {
'0101': '元旦',
'0214': '情人',
'0308': '妇女',
'0312': '植树',
'0401': '愚人',
'0501': '劳动',
'0504': '青年',
'0601': '儿童',
'0701': '建党',
'0801': '建军',
'0903': '抗日',
'0910': '教师',
'1001': '国庆',
'1031': '万圣',
'1224': '平安',
'1225': '圣诞'
};
let value = this.format(date, 'mmdd');
if (holidays[value]) return holidays[value];
return false;
},
/**
* 解析标准日期格式
* @param s 日期字符串
* @return 返回Date对象
*/
parse: s => new Date(s.replace(/(年|月|-)/g, '/').replace(/(日)/g, '')),
/**
* 比较日期是否为同一天
* @param a Date对象
* @param b Date对象
* @return Boolean
*/
isSameDay: (a, b) => a.getMonth() == b.getMonth() && a.getFullYear() == b.getFullYear() && a.getDate() == b.getDate(),
/**
* 格式化Date对象
* @param d 日期对象
* @param f 格式字符串
* @return 返回格式化后的字符串
*/
format(d, f) {
var o = {
"m+": d.getMonth() + 1,
"d+": d.getDate(),
"h+": d.getHours(),
"i+": d.getMinutes(),
"s+": d.getSeconds(),
"q+": Math.floor((d.getMonth() + 3) / 3),
};
if (/(y+)/.test(f))
f = f.replace(RegExp.$1, (d.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(f))
f = f.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return f;
},
/**
* 用于format格式化后的反解析
* @param s 日期字符串
* @param f 格式字符串
* @return 返回Date对象
*/
inverse(s, f) {
var o = {
"y": '',
"m": '',
"d": '',
"h": '',
"i": '',
"s": '',
};
let d = new Date();
if (s.length != f.length) return d;
for (let i in f)
if (o[f[i]] != undefined) o[f[i]] += s[i];
if (o.y) d.setFullYear(o.y.length < 4 ? (d.getFullYear() + '').substr(0, 4 - o.y.length) + o.y : o.y);
o.m && d.setMonth(o.m - 1, 1);
o.d && d.setDate(o.d - 0);
o.h && d.setHours(o.h - 0);
o.i && d.setMinutes(o.i - 0);
o.s && d.setSeconds(o.s - 0);
return d;
},
/**
* 获取日历数组42
* @param date 日期对象或日期字符串
* @param proc 处理日历(和forEach类似)传递一个数组中的item
* @return Array
*/
getCalendar(date, proc) {
let it = new Date(date),
calendars = [];
it.setDate(1);
it.setDate(it.getDate() - ((it.getDay() == 0 ? 7 : it.getDay()) - 1)); //
for (let i = 0; i < 42; i++) {
let tmp = {
dateObj: new Date(it),
title: it.getDate(),
isOtherMonth: it.getMonth() < date.getMonth() || it.getMonth() > date.getMonth()
};
calendars.push(Object.assign(tmp, proc ? proc(tmp) : {}));
it.setDate(it.getDate() + 1);
}
return calendars;
},
/**
* 获取日期到指定的月份1号(不改变原来的date对象)
* @param d Date对象
* @param v 指定的月份
* @return Date对象
*/
getDateToMonth(d, v) {
let n = new Date(d);
n.setMonth(v, 1);
return n;
},
/**
* 把时间数组转为时间字符串
* @param t Array[,,]
* @param showSecinds 是否显示秒
* @return 字符串 :[:]
*/
formatTimeArray(t, s) {
let r = [...t];
if (!s) r.length = 2;
r.forEach((v, k) => r[k] = ('0' + v).slice(-2));
return r.join(':');
}
};
export default {
props: {
//
color: {
type: String,
default: '#409eff'
},
// typedatetimetime
showSeconds: {
type: Boolean,
default: false
},
//
value: [String, Array],
//date time datetime range rangetime
type: {
type: String,
default: 'range'
},
//
show: {
type: Boolean,
default: false
},
//
format: {
type: String,
default: ''
},
//
showHoliday: {
type: Boolean,
default: true
},
//
showTips: {
type: Boolean,
default: false
},
// type
beginText: {
type: String,
default: ''
},
// type
endText: {
type: String,
default: ''
}
},
data() {
return {
isShow: false, //
isMultiSelect: false, //
isContainTime: false, //
date: {}, //
weeks: ["一", "二", "三", "四", "五", "六", "日"],
title: '初始化', //
calendars: [[],[],[]], //
calendarIndex: 1, //
checkeds: [], //
showTimePicker: false, //
timeValue: [0, 0, 0], //
timeType: 'begin', //
beginTime: [0, 0, 0], //
endTime: [0, 0, 0], //
};
},
methods: {
//
setValue(value) {
this.date = new Date();
this.checkeds = [];
this.isMultiSelect = this.type.indexOf('range') >= 0;
this.isContainTime = this.type.indexOf('time') >= 0;
//Date
let parseDateStr = (str) => (this.format ? DateTools.inverse(str, this.format) : DateTools.parse(str));
if (value) {
if (this.isMultiSelect) {
Array.isArray(value) && value.forEach((dateStr, index) => {
let date = parseDateStr(dateStr);
let time = [date.getHours(), date.getMinutes(), date.getSeconds()];
if (index == 0) this.beginTime = time;
else this.endTime = time;
this.checkeds.push(date);
});
} else {
if (this.type == 'time') {
let date = parseDateStr('2019/1/1 ' + value);
this.beginTime = [date.getHours(), date.getMinutes(), date.getSeconds()];
this.onShowTimePicker('begin');
} else {
this.checkeds.push(parseDateStr(value));
if (this.isContainTime) this.beginTime = [
this.checkeds[0].getHours(),
this.checkeds[0].getMinutes(),
this.checkeds[0].getSeconds()
];
}
}
if (this.checkeds.length) this.date = new Date(this.checkeds[0]);
} else {
if (this.isContainTime) {
this.beginTime = [this.date.getHours(), this.date.getMinutes(), this.date.getSeconds()];
if (this.isMultiSelect) this.endTime = [...this.beginTime];
}
this.checkeds.push(new Date(this.date));
}
if (this.type != 'time') this.refreshCalendars(true);
else this.onShowTimePicker('begin');
},
//
onSetYear(value) {
this.date.setFullYear(this.date.getFullYear() + parseInt(value));
this.refreshCalendars(true);
},
//
onSetMonth(value) {
this.date.setMonth(this.date.getMonth() + parseInt(value));
this.refreshCalendars(true);
},
//
onTimeChange(e) {
this.timeValue = e.detail.value;
},
//
onShowTimePicker(type) {
this.showTimePicker = true;
this.timeType = type;
this.timeValue = type == 'begin' ? [...this.beginTime] : [...this.endTime];
},
//
procCalendar(item) {
//
item.statusStyle = {
opacity: 1,
color: item.isOtherMonth ? '#ddd' : '#000',
background: 'transparent'
};
item.bgStyle = {
type: '',
background: 'transparent'
};
item.dotStyle = {
opacity: 1,
background: 'transparent'
};
item.tips = "";
//
if (DateTools.isSameDay(new Date(), item.dateObj)) {
item.statusStyle.color = this.color;
if (item.isOtherMonth) item.statusStyle.opacity = 0.3;
}
//
this.checkeds.forEach(date => {
if (DateTools.isSameDay(date, item.dateObj)) {
item.statusStyle.background = this.color;
item.statusStyle.color = '#fff';
item.statusStyle.opacity = 1;
if (this.isMultiSelect && this.showTips) item.tips = this.beginText;
}
});
//
if (item.statusStyle.background != this.color) {
let holiday = this.showHoliday ? DateTools.getHoliday(item.dateObj) : false;
if (holiday || DateTools.isSameDay(new Date(), item.dateObj)) {
item.title = holiday || item.title;
item.dotStyle.background = this.color;
if (item.isOtherMonth) item.dotStyle.opacity = 0.2;
}
} else {
item.title = item.dateObj.getDate();
}
//
if (this.checkeds.length == 2) {
if (DateTools.isSameDay(this.checkeds[0], item.dateObj)) { //
item.bgStyle.type = 'bgbegin';
}
if (DateTools.isSameDay(this.checkeds[1], item.dateObj)) { //
if (this.isMultiSelect && this.showTips) item.tips = item.bgStyle.type ? this.beginText + ' / ' + this.endText : this.endText;
if (!item.bgStyle.type) { //
item.bgStyle.type = 'bgend';
} else {
item.bgStyle.type = '';
}
}
if (!item.bgStyle.type && (+item.dateObj > +this.checkeds[0] && +item.dateObj < +this.checkeds[1])) { //
item.bgStyle.type = 'bg';
item.statusStyle.color = this.color;
}
if (item.bgStyle.type) {
item.bgStyle.background = this.color;
item.dotStyle.opacity = 1;
item.statusStyle.opacity = 1;
}
}
},
//
refreshCalendars(refresh = false) {
let date = new Date(this.date);
let before = DateTools.getDateToMonth(date, date.getMonth() - 1);
let after = DateTools.getDateToMonth(date, date.getMonth() + 1);
if (this.calendarIndex == 0) {
if(refresh) this.calendars.splice(0, 1, DateTools.getCalendar(date, this.procCalendar));
this.calendars.splice(1, 1, DateTools.getCalendar(after, this.procCalendar));
this.calendars.splice(2, 1, DateTools.getCalendar(before, this.procCalendar));
} else if (this.calendarIndex == 1) {
this.calendars.splice(0, 1, DateTools.getCalendar(before, this.procCalendar));
if(refresh) this.calendars.splice(1, 1, DateTools.getCalendar(date, this.procCalendar));
this.calendars.splice(2, 1, DateTools.getCalendar(after, this.procCalendar));
} else if (this.calendarIndex == 2) {
this.calendars.splice(0, 1, DateTools.getCalendar(after, this.procCalendar));
this.calendars.splice(1, 1, DateTools.getCalendar(before, this.procCalendar));
if(refresh) this.calendars.splice(2, 1, DateTools.getCalendar(date, this.procCalendar));
}
this.title = DateTools.format(this.date, 'yyyy年mm月');
},
//
onSwiperChange(e) {
this.calendarIndex = e.detail.current;
let calendar = this.calendars[this.calendarIndex];
this.date = new Date(calendar[22].dateObj); //
this.refreshCalendars();
},
//
onSelectDate(date) {
if (~this.type.indexOf('range') && this.checkeds.length == 2) this.checkeds = [];
else if (!(~this.type.indexOf('range')) && this.checkeds.length) this.checkeds = [];
this.checkeds.push(new Date(date.dateObj));
this.checkeds.sort((a, b) => a - b); //
this.calendars.forEach(calendar => {
calendar.forEach(this.procCalendar); //
});
},
//
onCancelTime() {
this.showTimePicker = false;
this.type == 'time' && this.onCancel();
},
//
onConfirmTime() {
if (this.timeType == 'begin') this.beginTime = this.timeValue;
else this.endTime = this.timeValue;
this.showTimePicker = false;
this.type == 'time' && this.onConfirm();
},
//
onCancel() {
this.$emit('cancel', false);
},
//
onConfirm() {
let result = {
value: null,
date: null
};
//
let defaultFormat = {
'date': 'yyyy/mm/dd',
'time': 'hh:ii' + (this.showSeconds ? ':ss' : ''),
'datetime': ''
};
defaultFormat['datetime'] = defaultFormat.date + ' ' + defaultFormat.time;
let fillTime = (date, timeArr) => {
date.setHours(timeArr[0], timeArr[1]);
if (this.showSeconds) date.setSeconds(timeArr[2]);
};
if (this.type == 'time') {
let date = new Date();
fillTime(date, this.beginTime);
result.value = DateTools.format(date, this.format ? this.format : defaultFormat.time);
result.date = date;
} else {
if (this.isMultiSelect) {
let values = [],
dates = [];
if (this.checkeds.length < 2) return uni.showToast({
icon: 'none',
title: '请选择两个日期'
});
this.checkeds.forEach((date, index) => {
let newDate = new Date(date);
if (this.isContainTime) {
let time = [this.beginTime, this.endTime];
fillTime(newDate, time[index]);
}
values.push(DateTools.format(newDate, this.format ? this.format : defaultFormat[this.isContainTime ?
'datetime' : 'date']));
dates.push(newDate);
});
result.value = values;
result.date = dates;
} else {
let newDate = new Date(this.checkeds[0]);
if (this.isContainTime) {
newDate.setHours(this.beginTime[0], this.beginTime[1]);
if (this.showSeconds) newDate.setSeconds(this.beginTime[2]);
}
result.value = DateTools.format(newDate, this.format ? this.format : defaultFormat[this.isContainTime ?
'datetime' : 'date']);
result.date = newDate;
}
}
this.$emit('confirm', result);
}
},
computed: {
BeginTitle() {
let value = '未选择';
if (this.checkeds.length) value = DateTools.format(this.checkeds[0], 'yy/mm/dd');
return value;
},
EndTitle() {
let value = '未选择';
if (this.checkeds.length == 2) value = DateTools.format(this.checkeds[1], 'yy/mm/dd');
return value;
},
PickerTimeTitle() {
return DateTools.formatTimeArray(this.timeValue, this.showSeconds);
},
BeginTimeTitle() {
return this.BeginTitle != '未选择' ? DateTools.formatTimeArray(this.beginTime, this.showSeconds) : '';
},
EndTimeTitle() {
return this.EndTitle != '未选择' ? DateTools.formatTimeArray(this.endTime, this.showSeconds) : '';
}
},
watch: {
show(newValue, oldValue) {
newValue && this.setValue(this.value);
this.isShow = newValue;
},
value(newValue, oldValue) {
setTimeout(()=>{
this.setValue(newValue);
}, 0);
}
}
}
</script>
<style lang="scss" scoped>
$z-index: 999;
$cell-spacing: 20upx;
$calendar-size: 630upx;
$calendar-item-size: 90upx;
.picker {
position: fixed;
z-index: $z-index;
background: rgba(255, 255, 255, 0);
left: 0;
top: 0;
width: 100%;
height: 100%;
font-size: 28upx;
&-btn {
padding: $cell-spacing*0.5 $cell-spacing;
border-radius: 12upx;
color: #666;
&-active {
background: rgba(0, 0, 0, .1);
}
}
&-display {
color: #666;
&-text {
color: #000;
margin: 0 $cell-spacing*0.5;
}
&-link {
display: inline-block;
&-active {
background: rgba(0, 0, 0, .1);
}
}
}
&-time {
width: $calendar-size - 80upx !important;
left: ((750upx - $calendar-size) / 2 + 40upx) !important;
}
&-modal {
background: #fff;
position: absolute;
top: 50%;
left: (750upx - $calendar-size) / 2;
width: $calendar-size;
transform: translateY(-50%);
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.1);
border-radius: 12upx;
&-header {
text-align: center;
line-height: 80upx;
font-size: 32upx;
&-title {
display: inline-block;
width: 40%;
}
.picker-icon {
display: inline-block;
line-height: 50upx;
width: 50upx;
height: 50upx;
border-radius: 50upx;
text-align: center;
margin: 10upx;
background: #fff;
font-size: 36upx;
&-active {
background: rgba(0, 0, 0, .1);
}
}
}
&-body {
width: $calendar-size !important;
height: $calendar-size !important;
position: relative;
}
&-time {
width: 100%;
height: 180upx;
text-align: center;
line-height: 60upx;
}
&-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding: $cell-spacing;
&-info {
flex-grow: 1;
}
&-btn {
flex-shrink: 0;
display: flex;
}
}
}
&-calendar {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
&-view {
position: relative;
width: $calendar-item-size;
height: $calendar-item-size;
text-align: center;
&-bgbegin,
&-bg,
&-bgend,
&-item,
&-dot,
&-tips {
position: absolute;
transition: .2s;
}
&-bgbegin,
&-bg,
&-bgend {
opacity: .15;
height: 80%;
}
&-bg {
left: 0;
top: 10%;
width: 100%;
}
&-bgbegin {
border-radius: $calendar-item-size 0 0 $calendar-item-size;
top: 10%;
left: 10%;
width: 90%;
}
&-bgend {
border-radius: 0 $calendar-item-size $calendar-item-size 0;
top: 10%;
left: 0%;
width: 90%;
}
&-item {
left: 5%;
top: 5%;
width: 90%;
height: 90%;
border-radius: $calendar-item-size;
display: flex;
align-items: center;
justify-content: center;
}
&-dot {
right: 10%;
top: 10%;
width: 12upx;
height: 12upx;
border-radius: 12upx;
}
&-tips {
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: #4E4B46;
color: #fff;
border-radius: 12upx;
padding: 10upx 20upx;
font-size: 24upx;
width: max-content;
margin-bottom: 5px;
pointer-events: none;
&:after {
content: "";
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-style: solid;
border-width: 5px 5px 0 5px;
border-color: #4E4B46 transparent transparent transparent;
}
}
}
}
}
@font-face {
font-family: "mxdatepickericon";
src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAMYAAsAAAAACBgAAALMAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDIgqDRIJiATYCJAMUCwwABCAFhG0HSRvfBsg+QCa3noNAyAQ9w6GDvbwpNp2vloCyn8bD/x+y+/5qDhtj+T4eRVEcbsCoKMFASzCgLdDkmqYDwgxkWQ6YH5L/YnppOlLEjlnter43YRjU7M6vJ3iGADVAgJn5kqjv/wEii23T86UsAQT+04fV+o97VTMx4PPZt4DlorLXwIQiGMA5uhaVrBWqGHfQXcTEiE+PE+g2SUlxWlLVBHwUYFMgrgwSB3wstTKSGzqF1nOyiGeeOtNjV4An/vvxR58PSc3AzrMViyDvPo/7dVEUzn5GROfIWAcU4rLXfMFdhte56y4We9gGNEVIezkBOOaQXUrbTf/hJVkhGpDdCw7dSOEzByMEn3kIic98hMxnAfeFPKWCbjRcA148/HxhCEkaA94eGWFaGolsblpaWz8/Po2WVuNHh1fmBpZHIpqal9fOjizhTteY+RZ9rv02I/pq0W6QVH3pSncBz3m55r9ZIPycHfmenvxe4uyutIgfT5u4bgkDusl9gcF0rnfnz+b2NpSaQWBFeu8GIL1xQj5AH/6FAsEr/50F28e/gA9ny6KjLrxIp0TE+UucmQOl5AFNLXkzZufWamWHYEI39PEP2If97CMdm51N6DSmIekwAVmneXTBr0PVYx+aTgfQbU3p+R4jKHdRurBq0oEw6AKSfm+QDbpGF/w3VOP+oBnMHbqdx409FjP4RRHHkAj5IWgQiBUjHfMTuQ1Icpg5avI4sQVRu8EHdWptM1aKrIjuscfeL+kZwxBTYoElztOQ2UygjRIjEphaZsyWodHgvm9SC8QC/JygEA6DiCDeEMhAQFhhOpvxa/18A0TiYMahIy0L2hYIZWeYH9JR085Al4qts1re5St2/SR6DINBGEVYQCWOETHDMAHZ+pcZIQJGTV4RtMmg8UbhuWL1+VLLA2RFHYC71kiRo0SNpjwQh8pj2EFU3oTNmS1WqgIA') format('woff2');
}
.picker-icon {
font-family: "mxdatepickericon" !important;
}
.picker-icon-you:before {
content: "\e63e";
}
.picker-icon-zuo:before {
content: "\e640";
}
.picker-icon-zuozuo:before {
content: "\e641";
}
.picker-icon-youyou:before {
content: "\e642";
}
</style>

View File

@ -0,0 +1,144 @@
<template>
<view v-if="visibleSync" :class="{ 'uni-drawer--visible': showDrawer }" class="uni-drawer">
<view class="uni-drawer__mask" :class="{ 'uni-drawer__mask--visible': showDrawer && mask }" @tap="close" />
<view class="uni-drawer__content" :class="{'uni-drawer--right': rightMode,'uni-drawer--left': !rightMode, 'uni-drawer__content--visible': showDrawer}">
<slot />
</view>
</view>
</template>
<script>
export default {
name: 'UniDrawer',
props: {
/**
* 显示状态
*/
visible: {
type: Boolean,
default: false
},
/**
* 显示模式只在初始化生效
*/
mode: {
type: String,
default: ''
},
/**
* 蒙层显示状态
*/
mask: {
type: Boolean,
default: true
}
},
data() {
return {
visibleSync: false,
showDrawer: false,
rightMode: false,
watchTimer: null
}
},
watch: {
visible(val) {
if (val) {
this.open()
} else {
this.close()
}
}
},
created() {
this.visibleSync = this.visible
setTimeout(() => {
this.showDrawer = this.visible
}, 100)
this.rightMode = this.mode === 'right'
},
methods: {
close() {
this._change('showDrawer', 'visibleSync', false)
},
open() {
this._change('visibleSync', 'showDrawer', true)
},
_change(param1, param2, status) {
this[param1] = status
if (this.watchTimer) {
clearTimeout(this.watchTimer)
}
this.watchTimer = setTimeout(() => {
this[param2] = status
this.$emit(status ? 'open' : 'close')
}, status ? 50 : 300)
}
}
}
</script>
<style lang="scss" scoped>
//
$drawer-width: 220px;
.uni-drawer {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
z-index: 999;
}
.uni-drawer__content {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: absolute;
top: 0;
width: $drawer-width;
bottom: 0;
background-color: $uni-bg-color;
transition: transform 0.3s ease;
}
.uni-drawer--left {
left: 0;
transform: translateX(-$drawer-width);
}
.uni-drawer--right {
right: 0;
transform: translateX($drawer-width);
}
.uni-drawer__content--visible {
transform: translateX(0px);
}
.uni-drawer__mask {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
opacity: 0;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: $uni-bg-color-mask;
transition: opacity 0.3s;
}
.uni-drawer__mask--visible {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
opacity: 1;
}
</style>

View File

@ -1,5 +1,19 @@
{
"dependencies": {
"vant": "^2.12.54"
}
}
"id": "fjj-condition",
"name": "tongtong-条件筛选",
"version": "1.0.6",
"description": "支持单选多选筛选、日期范围筛选、数量或金额范围筛选, 兼容h5、微信小程序、其它端未测试",
"keywords": [
"筛选",
"条件筛选",
"多选",
"单选",
"日期筛选"
],
"dcloudext": {
"category": [
"前端组件",
"通用组件"
]
}
}

View File

@ -148,6 +148,16 @@
"style": {
"navigationBarTitleText": "船舶计划"
}
}, {
"path": "pages/shipWork/brandDetails",
"style": {
"navigationBarTitleText": "品牌明细"
}
},{
"path": "pages/shipWork/carDetails",
"style": {
"navigationBarTitleText": "车型明细"
}
},
{
"path": "pages/monitor/index",

View File

@ -0,0 +1,238 @@
<template>
<view class="brandDetails">
<view class="container">
<view class="topBox">
<view class="searchBox">
<uni-easyinput suffixIcon="search" v-model="searchValue" placeholder="提单号/车架号/长/宽/高/重量"
@iconClick="iconClick"></uni-easyinput>
<text @tap="screen"></text>
<fjj-condition ref='condition' @touchmove.stop :color="color" :list="menuList"
:defaultValue="defaultValue" @result="resultConditon" />
</view>
</view>
<view class="ul">
<view class="li" v-for="item in 6" :key="item" @click="togoCar">
<p class="title">品牌特斯拉</p>
<p>提单号TD85875876</p>
<p>源类型新能源</p>
<p>场位C4区15道*2,16*2</p>
<p>航次HC8595986</p>
<p>报关状态未报关</p>
<p>车型轿车</p>
<p>数量100</p>
<p>港口巴塞罗那</p>
<p>报关单号BG09759724</p>
<p>车型明细无动力半挂车</p>
<p>货代华图供应链管理天津有限公司</p>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
searchValue: "",
color: '#4D7BFE',
hasChoose: false,
menuList: [],
defaultValue: {},
}
},
mounted() {
setTimeout(() => {
this.menuList = [{
'title': '按港口',
'type': 'custom',
'key': 'custom1',
'isMutiple': true, //
'detailList': [{
title: '港口1',
value: "1",
isSelected: true
}, {
title: '港口2',
value: "2",
}, {
title: '港口3',
value: "3",
}, {
title: '港口4',
value: "4",
}, {
title: '港口5',
value: "5",
}, {
title: '港口6',
value: "6",
}],
}, {
'title': '按车型',
'type': 'custom',
'key': 'custom2',
'isMutiple': true, //
'detailList': [{
title: '车型1',
value: "1",
}, {
title: '车型2',
value: "2",
}, {
title: '车型3',
value: "3",
}, {
title: '车型4',
value: "4",
}, {
title: '车型5',
value: "5",
}, {
title: '车型6',
value: "6",
}, {
title: '车型7',
value: "7",
}],
}, {
'title': '按品牌',
'type': 'custom',
'key': 'custom3',
'isMutiple': true, //
'detailList': [{
title: '品牌1',
value: "1",
}, {
title: '品牌2',
value: "2",
}, {
title: '品牌3',
value: "3",
}, {
title: '品牌4',
value: "4",
}, {
title: '品牌5',
value: "5",
}, {
title: '品牌6',
value: "6",
}],
}, {
'title': '按型号',
'type': 'custom',
'key': 'custom4',
'isMutiple': true, //
'detailList': [{
title: '型号1',
value: "1",
}, {
title: '型号2',
value: "2",
}, {
title: '型号3',
value: "3",
}, {
title: '型号4',
value: "4",
}, {
title: '型号5',
value: "5",
}, {
title: '型号6',
value: "6",
}],
}, {
'title': '单选',
'type': 'custom',
'key': 'custom5',
'isMutiple': false, //
'detailList': [{
title: '选项1',
value: "1",
}, {
title: '选项2',
value: "2",
}],
}, ]
this.defaultValue = {
custom1: ['1'],
custom5: 1,
};
}, 2000)
},
methods: {
//
iconClick() {},
//
screen() {
this.$refs.condition.visibleDrawer = true;
},
resultConditon(obj) {
this.$refs.condition.visibleDrawer = false;
this.hasChoose = obj.hasChoose;
console.log(obj);
},
//
togoCar(){
uni.navigateTo({
url: `/pages/shipWork/carDetails`
})
}
}
}
</script>
<style lang="less" scoped>
.brandDetails {
.container {
padding: 30px 20px;
background-color: #fff;
.topBox {
display: flex;
justify-content: flex-end;
.searchBox {
width: 33%;
display: flex;
text {
margin-left: 10px;
color: #2979ff;
line-height: 36px;
}
/deep/.uni-drawer__content {
width: 500px;
}
}
}
.ul {
padding: 20px 0;
.li {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
border-bottom: 1px solid #ccc;
.title {
font-size: 16px;
font-weight: bold;
color: #000;
}
p {
width: 22%;
margin: 10px;
color: rgba(0, 0, 0, .5);
}
}
}
}
}
</style>

View File

@ -0,0 +1,122 @@
<template>
<view class="carDetails">
<view class="container">
<view class="ul">
<view class="li">船名运程10</view>
<view class="li">航次HC97759809</view>
<view class="li">贸易类型外贸</view>
<view class="li">进出口进口</view>
<view class="li">港口巴塞罗那</view>
<view class="li">提单号TD6955975087</view>
<view class="li">报关状态未报关</view>
<view class="li">报关单号TD6955975087</view>
<view class="li">场位c4区15道*2</view>
<view class="li">货代上海海通国际汽车物流有限公司</view>
<view class="li">联系人张星星</view>
<view class="li">联系方式13266688888</view>
<view class="li">品牌特斯拉</view>
<view class="li">车型轿车</view>
<view class="li">车型明细轿车</view>
<view class="li">型号STAY-CONNECTB</view>
<view class="li">源类型新能源</view>
<view class="li">数量199</view>
<view class="li">车长199</view>
<view class="li">车宽199</view>
<view class="li">车高100</view>
<view class="li">重量1978</view>
<view class="li">体积979</view>
<view class="li">单票数量100</view>
<view class="li">单票重量1978</view>
<view class="li">单票体积979</view>
</view>
<view class="tableInfo">
<view class="title">车架号明细</view>
<uni-table ref="table" :loading="loading" border emptyText="暂无更多数据">
<uni-tr>
<uni-th width="150" align="center">序号</uni-th>
<uni-th align="center">车架号/条形码</uni-th>
<uni-th align="center">场位</uni-th>
</uni-tr>
<uni-tr v-for="(item, index) in tableData" :key="index">
<uni-td align="center">{{ item.id }}</uni-td>
<uni-td align="center">{{item.vinCod}}</uni-td>
<uni-td align="center">{{ item.field }}</uni-td>
</uni-tr>
</uni-table>
<view class="pagination">
<uni-pagination :total="total" :pageSize="pageSize" v-model="pageCurrent" title="标题文字" />
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
tableData: [{
id: "01",
vinCod: "CJH67892734895917",
field: "A1-09-03"
}, {
id: "02",
vinCod: "CJH67892734895917",
field: "A1-09-03"
}, {
id: "03",
vinCod: "CJH67892734895917",
field: "A1-09-03"
}],
loading: false,
//
pageSize: 20,
//
pageCurrent: 1,
//
total: 50,
}
},
methods: {},
}
</script>
<style lang="less" scoped>
.carDetails {
.container {
padding: 30px 20px;
background-color: #fff;
.ul {
display: flex;
flex-wrap: wrap;
padding: 20px;
border-bottom: 1px solid #ccc;
.li {
width: 32%;
font-weight: bold;
margin-bottom: 10px;
}
}
.tableInfo {
padding: 20px;
.title {
font-size: 16px;
font-weight: bold;
margin-bottom: 20px;
}
/deep/.uni-table-th {
background-color: #fafafa;
}
.pagination {
margin-top: 10px;
}
}
}
}
</style>

View File

@ -66,7 +66,7 @@
},
{
name: "作业查询",
url: "mixWork"
url: "brandDetails"
}
],
}

View File

@ -16,7 +16,7 @@
</view>
</view>
<view class="itemList">
<view v-for="(item, index) in ltemList" :key="index" class="item">
<view v-for="(item, index) in ltemList" :key="index" class="item" @click="toGo">
<view class="title">
<view class="name">
海王星领袖
@ -72,7 +72,7 @@
上传
</view>
</view>
</view>
</view>
</view>
@ -89,7 +89,7 @@
data() {
return {
value: 0,
value1:'',
value1: '',
range: [{
value: 0,
text: "一号港"
@ -117,6 +117,11 @@
change(e) {
console.log("e:", e);
},
toGo() {
uni.navigateTo({
url: `/pages/shipWork/documentList`
})
}
}
};
</script>
@ -203,4 +208,4 @@
}
}
}
</style>
</style>

View File

@ -0,0 +1,27 @@
## 1.2.42022-09-19
- 修复,未对主题色设置默认色,导致未引入 uni-scss 变量文件报错。
- 修复,未对移动端当前页文字做主题色适配。
## 1.2.32022-09-15
- 修复未使用 uni-scss 主题色的 bug。
## 1.2.22022-07-06
- 修复 es 语言 i18n 错误
## 1.2.12021-11-22
- 修复 vue3中某些scss变量无法找到的问题
## 1.2.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-pagination](https://uniapp.dcloud.io/component/uniui/uni-pagination)
## 1.1.22021-10-08
- 修复 current 、value 属性未监听,导致高亮样式失效的 bug
## 1.1.12021-08-20
- 新增 支持国际化
## 1.1.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.72021-05-12
- 新增 组件示例地址
## 1.0.62021-04-12
- 新增 PC 和 移动端适配不同的 ui
## 1.0.52021-02-05
- 优化 组件引用关系通过uni_modules引用组件
## 1.0.42021-02-05
- 调整为uni_modules目录规范

View File

@ -0,0 +1,5 @@
{
"uni-pagination.prevText": "prev",
"uni-pagination.nextText": "next",
"uni-pagination.piecePerPage": "piece/page"
}

View File

@ -0,0 +1,5 @@
{
"uni-pagination.prevText": "anterior",
"uni-pagination.nextText": "prxima",
"uni-pagination.piecePerPage": "Art¨ªculo/P¨¢gina"
}

View File

@ -0,0 +1,5 @@
{
"uni-pagination.prevText": "précédente",
"uni-pagination.nextText": "suivante",
"uni-pagination.piecePerPage": "Articles/Pages"
}

View File

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

View File

@ -0,0 +1,5 @@
{
"uni-pagination.prevText": "上一页",
"uni-pagination.nextText": "下一页",
"uni-pagination.piecePerPage": "条/页"
}

View File

@ -0,0 +1,5 @@
{
"uni-pagination.prevText": "上一頁",
"uni-pagination.nextText": "下一頁",
"uni-pagination.piecePerPage": "條/頁"
}

View File

@ -0,0 +1,465 @@
<template>
<view class="uni-pagination">
<!-- #ifndef MP -->
<picker v-if="showPageSize === true || showPageSize === 'true'" class="select-picker" mode="selector"
:value="pageSizeIndex" :range="pageSizeRange" @change="pickerChange" @cancel="pickerClick"
@click.native="pickerClick">
<button type="default" size="mini" :plain="true">
<text>{{pageSizeRange[pageSizeIndex]}} {{piecePerPage}}</text>
<uni-icons class="select-picker-icon" type="arrowdown" size="12" color="#999"></uni-icons>
</button>
</picker>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<view class="uni-pagination__total is-phone-hide"> {{ total }} </view>
<!-- #endif -->
<view class="uni-pagination__btn"
:class="currentIndex === 1 ? 'uni-pagination--disabled' : 'uni-pagination--enabled'"
:hover-class="currentIndex === 1 ? '' : 'uni-pagination--hover'" :hover-start-time="20"
:hover-stay-time="70" @click="clickLeft">
<template v-if="showIcon === true || showIcon === 'true'">
<uni-icons color="#666" size="16" type="left" />
</template>
<template v-else>
<text class="uni-pagination__child-btn">{{ prevPageText }}</text>
</template>
</view>
<view class="uni-pagination__num uni-pagination__num-flex-none">
<view class="uni-pagination__num-current">
<text class="uni-pagination__num-current-text is-pc-hide current-index-text">{{ currentIndex }}</text>
<text class="uni-pagination__num-current-text is-pc-hide">/{{ maxPage || 0 }}</text>
<!-- #ifndef APP-NVUE -->
<view v-for="(item, index) in paper" :key="index" :class="{ 'page--active': item === currentIndex }"
class="uni-pagination__num-tag tag--active is-phone-hide" @click.top="selectPage(item, index)">
<text>{{ item }}</text>
</view>
<!-- #endif -->
</view>
</view>
<view class="uni-pagination__btn"
:class="currentIndex >= maxPage ? 'uni-pagination--disabled' : 'uni-pagination--enabled'"
:hover-class="currentIndex === maxPage ? '' : 'uni-pagination--hover'" :hover-start-time="20"
:hover-stay-time="70" @click="clickRight">
<template v-if="showIcon === true || showIcon === 'true'">
<uni-icons color="#666" size="16" type="right" />
</template>
<template v-else>
<text class="uni-pagination__child-btn">{{ nextPageText }}</text>
</template>
</view>
</view>
</template>
<script>
/**
* Pagination 分页器
* @description 分页器组件用于展示页码请求数据等
* @tutorial https://ext.dcloud.net.cn/plugin?id=32
* @property {String} prevText 左侧按钮文字
* @property {String} nextText 右侧按钮文字
* @property {String} piecePerPageText /页文字
* @property {Number} current 当前页
* @property {Number} total 数据总量
* @property {Number} pageSize 每页数据量
* @property {Boolean} showIcon = [true|false] 是否以 icon 形式展示按钮
* @property {Boolean} showPageSize = [true|false] 是否展示每页条数
* @property {Array} pageSizeRange = [20, 50, 100, 500] 每页条数选框
* @event {Function} change 点击页码按钮时触发 ,e={type,current} current为当前页type值为next/prev表示点击的是上一页还是下一个
* * @event {Function} pageSizeChange 当前每页条数改变时触发 ,e={pageSize} pageSize 为当前所选的每页条数
*/
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from './i18n/index.js'
const {
t
} = initVueI18n(messages)
export default {
name: 'UniPagination',
emits: ['update:modelValue', 'input', 'change', 'pageSizeChange'],
props: {
value: {
type: [Number, String],
default: 1
},
modelValue: {
type: [Number, String],
default: 1
},
prevText: {
type: String,
},
nextText: {
type: String,
},
piecePerPageText: {
type: String
},
current: {
type: [Number, String],
default: 1
},
total: {
//
type: [Number, String],
default: 0
},
pageSize: {
//
type: [Number, String],
default: 10
},
showIcon: {
// icon
type: [Boolean, String],
default: false
},
showPageSize: {
// icon
type: [Boolean, String],
default: false
},
pagerCount: {
type: Number,
default: 7
},
pageSizeRange: {
type: Array,
default: () => [20, 50, 100, 500]
}
},
data() {
return {
pageSizeIndex: 0,
currentIndex: 1,
paperData: [],
pickerShow: false
}
},
computed: {
piecePerPage() {
return this.piecePerPageText || t('uni-pagination.piecePerPage')
},
prevPageText() {
return this.prevText || t('uni-pagination.prevText')
},
nextPageText() {
return this.nextText || t('uni-pagination.nextText')
},
maxPage() {
let maxPage = 1
let total = Number(this.total)
let pageSize = Number(this.pageSize)
if (total && pageSize) {
maxPage = Math.ceil(total / pageSize)
}
return maxPage
},
paper() {
const num = this.currentIndex
// TODO
const pagerCount = this.pagerCount
// const total = 181
const total = this.total
const pageSize = this.pageSize
let totalArr = []
let showPagerArr = []
let pagerNum = Math.ceil(total / pageSize)
for (let i = 0; i < pagerNum; i++) {
totalArr.push(i + 1)
}
showPagerArr.push(1)
const totalNum = totalArr[totalArr.length - (pagerCount + 1) / 2]
totalArr.forEach((item, index) => {
if ((pagerCount + 1) / 2 >= num) {
if (item < pagerCount + 1 && item > 1) {
showPagerArr.push(item)
}
} else if (num + 2 <= totalNum) {
if (item > num - (pagerCount + 1) / 2 && item < num + (pagerCount + 1) / 2) {
showPagerArr.push(item)
}
} else {
if ((item > num - (pagerCount + 1) / 2 || pagerNum - pagerCount < item) && item < totalArr[
totalArr.length - 1]) {
showPagerArr.push(item)
}
}
})
if (pagerNum > pagerCount) {
if ((pagerCount + 1) / 2 >= num) {
showPagerArr[showPagerArr.length - 1] = '...'
} else if (num + 2 <= totalNum) {
showPagerArr[1] = '...'
showPagerArr[showPagerArr.length - 1] = '...'
} else {
showPagerArr[1] = '...'
}
showPagerArr.push(totalArr[totalArr.length - 1])
} else {
if ((pagerCount + 1) / 2 >= num) {} else if (num + 2 <= totalNum) {} else {
showPagerArr.shift()
showPagerArr.push(totalArr[totalArr.length - 1])
}
}
return showPagerArr
}
},
watch: {
current: {
immediate: true,
handler(val, old) {
if (val < 1) {
this.currentIndex = 1
} else {
this.currentIndex = val
}
}
},
value: {
immediate: true,
handler(val) {
if (Number(this.current) !== 1) return
if (val < 1) {
this.currentIndex = 1
} else {
this.currentIndex = val
}
}
},
pageSizeIndex(val) {
this.$emit('pageSizeChange', this.pageSizeRange[val])
}
},
methods: {
pickerChange(e) {
this.pageSizeIndex = e.detail.value
this.pickerClick()
},
pickerClick() {
// #ifdef H5
const body = document.querySelector('body')
if (!body) return
const className = 'uni-pagination-picker-show'
this.pickerShow = !this.pickerShow
if (this.pickerShow) {
body.classList.add(className)
} else {
setTimeout(() => body.classList.remove(className), 300)
}
// #endif
},
//
selectPage(e, index) {
if (parseInt(e)) {
this.currentIndex = e
this.change('current')
} else {
let pagerNum = Math.ceil(this.total / this.pageSize)
// let pagerNum = Math.ceil(181 / this.pageSize)
//
if (index <= 1) {
if (this.currentIndex - 5 > 1) {
this.currentIndex -= 5
} else {
this.currentIndex = 1
}
return
}
//
if (index >= 6) {
if (this.currentIndex + 5 > pagerNum) {
this.currentIndex = pagerNum
} else {
this.currentIndex += 5
}
return
}
}
},
clickLeft() {
if (Number(this.currentIndex) === 1) {
return
}
this.currentIndex -= 1
this.change('prev')
},
clickRight() {
if (Number(this.currentIndex) >= this.maxPage) {
return
}
this.currentIndex += 1
this.change('next')
},
change(e) {
this.$emit('input', this.currentIndex)
this.$emit('update:modelValue', this.currentIndex)
this.$emit('change', {
type: e,
current: this.currentIndex
})
}
}
}
</script>
<style lang="scss" scoped>
$uni-primary: #2979ff !default;
.uni-pagination {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
position: relative;
overflow: hidden;
flex-direction: row;
justify-content: center;
align-items: center;
}
.uni-pagination__total {
font-size: 14px;
color: #999;
margin-right: 15px;
}
.uni-pagination__btn {
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
padding: 0 8px;
line-height: 30px;
font-size: 12px;
position: relative;
background-color: #F0F0F0;
flex-direction: row;
justify-content: center;
align-items: center;
text-align: center;
border-radius: 5px;
// border-width: 1px;
// border-style: solid;
// border-color: $uni-border-color;
}
.uni-pagination__child-btn {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
font-size: 12px;
position: relative;
flex-direction: row;
justify-content: center;
align-items: center;
text-align: center;
color: #666;
font-size: 12px;
}
.uni-pagination__num {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
justify-content: center;
align-items: center;
height: 30px;
line-height: 30px;
font-size: 12px;
color: #666;
margin: 0 5px;
}
.uni-pagination__num-tag {
/* #ifdef H5 */
cursor: pointer;
min-width: 30px;
/* #endif */
margin: 0 5px;
height: 30px;
text-align: center;
line-height: 30px;
// border: 1px red solid;
color: #999;
border-radius: 4px;
// border-width: 1px;
// border-style: solid;
// border-color: $uni-border-color;
}
.uni-pagination__num-current {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.uni-pagination__num-current-text {
font-size: 15px;
}
.current-index-text{
color: $uni-primary;
}
.uni-pagination--enabled {
color: #333333;
opacity: 1;
}
.uni-pagination--disabled {
opacity: 0.5;
/* #ifdef H5 */
cursor: default;
/* #endif */
}
.uni-pagination--hover {
color: rgba(0, 0, 0, 0.6);
background-color: #eee;
}
.tag--active:hover {
color: $uni-primary;
}
.page--active {
color: #fff;
background-color: $uni-primary;
}
.page--active:hover {
color: #fff;
}
/* #ifndef APP-NVUE */
.is-pc-hide {
display: block;
}
.is-phone-hide {
display: none;
}
@media screen and (min-width: 450px) {
.is-pc-hide {
display: none;
}
.is-phone-hide {
display: block;
}
.uni-pagination__num-flex-none {
flex: none;
}
}
/* #endif */
</style>

View File

@ -0,0 +1,83 @@
{
"id": "uni-pagination",
"displayName": "uni-pagination 分页器",
"version": "1.2.4",
"description": "Pagination 分页器组件,用于展示页码、请求数据等。",
"keywords": [
"uni-ui",
"uniui",
"分页器",
"页码"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": ["uni-scss","uni-icons"],
"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"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@ -0,0 +1,11 @@
## Pagination 分页器
> **组件名uni-pagination**
> 代码块: `uPagination`
分页器组件,用于展示页码、请求数据等。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-pagination)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@ -0,0 +1,27 @@
## 1.2.32023-03-28
- 修复 在vue3模式下可能会出现错误的问题
## 1.2.22022-11-29
- 优化 主题样式
## 1.2.12022-06-06
- 修复 微信小程序存在无使用组件的问题
## 1.2.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-table](https://uniapp.dcloud.io/component/uniui/uni-table)
## 1.1.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.72021-07-08
- 新增 uni-th 支持 date 日期筛选范围
## 1.0.62021-07-05
- 新增 uni-th 支持 range 筛选范围
## 1.0.52021-06-28
- 新增 uni-th 筛选功能
## 1.0.42021-05-12
- 新增 示例地址
- 修复 示例项目缺少组件的Bug
## 1.0.32021-04-16
- 新增 sortable 属性,是否开启单列排序
- 优化 表格多选逻辑
## 1.0.22021-03-22
- uni-tr 添加 disabled 属性,用于 type=selection 时,设置某行是否可由全选按钮控制
## 1.0.12021-02-05
- 调整为uni_modules目录规范

View File

@ -0,0 +1,455 @@
<template>
<view class="uni-table-scroll" :class="{ 'table--border': border, 'border-none': !noData }">
<!-- #ifdef H5 -->
<table class="uni-table" border="0" cellpadding="0" cellspacing="0" :class="{ 'table--stripe': stripe }" :style="{ 'min-width': minWidth + 'px' }">
<slot></slot>
<tr v-if="noData" class="uni-table-loading">
<td class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</td>
</tr>
<view v-if="loading" class="uni-table-mask" :class="{ 'empty-border': border }"><div class="uni-table--loader"></div></view>
</table>
<!-- #endif -->
<!-- #ifndef H5 -->
<view class="uni-table" :style="{ 'min-width': minWidth + 'px' }" :class="{ 'table--stripe': stripe }">
<slot></slot>
<view v-if="noData" class="uni-table-loading">
<view class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</view>
</view>
<view v-if="loading" class="uni-table-mask" :class="{ 'empty-border': border }"><div class="uni-table--loader"></div></view>
</view>
<!-- #endif -->
</view>
</template>
<script>
/**
* Table 表格
* @description 用于展示多条结构类似的数据
* @tutorial https://ext.dcloud.net.cn/plugin?id=3270
* @property {Boolean} border 是否带有纵向边框
* @property {Boolean} stripe 是否显示斑马线
* @property {Boolean} type 是否开启多选
* @property {String} emptyText 空数据时显示的文本内容
* @property {Boolean} loading 显示加载中
* @event {Function} selection-change 开启多选时当选择项发生变化时会触发该事件
*/
export default {
name: 'uniTable',
options: {
virtualHost: true
},
emits:['selection-change'],
props: {
data: {
type: Array,
default() {
return []
}
},
// 线
border: {
type: Boolean,
default: false
},
// 线
stripe: {
type: Boolean,
default: false
},
//
type: {
type: String,
default: ''
},
//
emptyText: {
type: String,
default: '没有更多数据'
},
loading: {
type: Boolean,
default: false
},
rowKey: {
type: String,
default: ''
}
},
data() {
return {
noData: true,
minWidth: 0,
multiTableHeads: []
}
},
watch: {
loading(val) {},
data(newVal) {
let theadChildren = this.theadChildren
let rowspan = 1
if (this.theadChildren) {
rowspan = this.theadChildren.rowspan
}
// this.trChildren.length - rowspan
this.noData = false
// this.noData = newVal.length === 0
}
},
created() {
// tr
this.trChildren = []
this.thChildren = []
this.theadChildren = null
this.backData = []
this.backIndexData = []
},
methods: {
isNodata() {
let theadChildren = this.theadChildren
let rowspan = 1
if (this.theadChildren) {
rowspan = this.theadChildren.rowspan
}
this.noData = this.trChildren.length - rowspan <= 0
},
/**
* 选中所有
*/
selectionAll() {
let startIndex = 1
let theadChildren = this.theadChildren
if (!this.theadChildren) {
theadChildren = this.trChildren[0]
} else {
startIndex = theadChildren.rowspan - 1
}
let isHaveData = this.data && this.data.length > 0
theadChildren.checked = true
theadChildren.indeterminate = false
this.trChildren.forEach((item, index) => {
if (!item.disabled) {
item.checked = true
if (isHaveData && item.keyValue) {
const row = this.data.find(v => v[this.rowKey] === item.keyValue)
if (!this.backData.find(v => v[this.rowKey] === row[this.rowKey])) {
this.backData.push(row)
}
}
if (index > (startIndex - 1) && this.backIndexData.indexOf(index - startIndex) === -1) {
this.backIndexData.push(index - startIndex)
}
}
})
// this.backData = JSON.parse(JSON.stringify(this.data))
this.$emit('selection-change', {
detail: {
value: this.backData,
index: this.backIndexData
}
})
},
/**
* 用于多选表格切换某一行的选中状态如果使用了第二个参数则是设置这一行选中与否selected true 则选中
*/
toggleRowSelection(row, selected) {
// if (!this.theadChildren) return
row = [].concat(row)
this.trChildren.forEach((item, index) => {
// if (item.keyValue) {
const select = row.findIndex(v => {
//
if (typeof v === 'number') {
return v === index - 1
} else {
return v[this.rowKey] === item.keyValue
}
})
let ischeck = item.checked
if (select !== -1) {
if (typeof selected === 'boolean') {
item.checked = selected
} else {
item.checked = !item.checked
}
if (ischeck !== item.checked) {
this.check(item.rowData||item, item.checked, item.rowData?item.keyValue:null, true)
}
}
// }
})
this.$emit('selection-change', {
detail: {
value: this.backData,
index:this.backIndexData
}
})
},
/**
* 用于多选表格清空用户的选择
*/
clearSelection() {
let theadChildren = this.theadChildren
if (!this.theadChildren) {
theadChildren = this.trChildren[0]
}
// if (!this.theadChildren) return
theadChildren.checked = false
theadChildren.indeterminate = false
this.trChildren.forEach(item => {
// if (item.keyValue) {
item.checked = false
// }
})
this.backData = []
this.backIndexData = []
this.$emit('selection-change', {
detail: {
value: [],
index: []
}
})
},
/**
* 用于多选表格切换所有行的选中状态
*/
toggleAllSelection() {
let list = []
let startIndex = 1
let theadChildren = this.theadChildren
if (!this.theadChildren) {
theadChildren = this.trChildren[0]
} else {
startIndex = theadChildren.rowspan - 1
}
this.trChildren.forEach((item, index) => {
if (!item.disabled) {
if (index > (startIndex - 1) ) {
list.push(index-startIndex)
}
}
})
this.toggleRowSelection(list)
},
/**
* 选中\取消选中
* @param {Object} child
* @param {Object} check
* @param {Object} rowValue
*/
check(child, check, keyValue, emit) {
let theadChildren = this.theadChildren
if (!this.theadChildren) {
theadChildren = this.trChildren[0]
}
let childDomIndex = this.trChildren.findIndex((item, index) => child === item)
if(childDomIndex < 0){
childDomIndex = this.data.findIndex(v=>v[this.rowKey] === keyValue) + 1
}
const dataLen = this.trChildren.filter(v => !v.disabled && v.keyValue).length
if (childDomIndex === 0) {
check ? this.selectionAll() : this.clearSelection()
return
}
if (check) {
if (keyValue) {
this.backData.push(child)
}
this.backIndexData.push(childDomIndex - 1)
} else {
const index = this.backData.findIndex(v => v[this.rowKey] === keyValue)
const idx = this.backIndexData.findIndex(item => item === childDomIndex - 1)
if (keyValue) {
this.backData.splice(index, 1)
}
this.backIndexData.splice(idx, 1)
}
const domCheckAll = this.trChildren.find((item, index) => index > 0 && !item.checked && !item.disabled)
if (!domCheckAll) {
theadChildren.indeterminate = false
theadChildren.checked = true
} else {
theadChildren.indeterminate = true
theadChildren.checked = false
}
if (this.backIndexData.length === 0) {
theadChildren.indeterminate = false
}
if (!emit) {
this.$emit('selection-change', {
detail: {
value: this.backData,
index: this.backIndexData
}
})
}
}
}
}
</script>
<style lang="scss">
$border-color: #ebeef5;
.uni-table-scroll {
width: 100%;
/* #ifndef APP-NVUE */
overflow-x: auto;
/* #endif */
}
.uni-table {
position: relative;
width: 100%;
border-radius: 5px;
// box-shadow: 0px 0px 3px 1px rgba(0, 0, 0, 0.1);
background-color: #fff;
/* #ifndef APP-NVUE */
box-sizing: border-box;
display: table;
overflow-x: auto;
::v-deep .uni-table-tr:nth-child(n + 2) {
&:hover {
background-color: #f5f7fa;
}
}
::v-deep .uni-table-thead {
.uni-table-tr {
// background-color: #f5f7fa;
&:hover {
background-color:#fafafa;
}
}
}
/* #endif */
}
.table--border {
border: 1px $border-color solid;
border-right: none;
}
.border-none {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
.table--stripe {
/* #ifndef APP-NVUE */
::v-deep .uni-table-tr:nth-child(2n + 3) {
background-color: #fafafa;
}
/* #endif */
}
/* 表格加载、无数据样式 */
.uni-table-loading {
position: relative;
/* #ifndef APP-NVUE */
display: table-row;
/* #endif */
height: 50px;
line-height: 50px;
overflow: hidden;
box-sizing: border-box;
}
.empty-border {
border-right: 1px $border-color solid;
}
.uni-table-text {
position: absolute;
right: 0;
left: 0;
text-align: center;
font-size: 14px;
color: #999;
}
.uni-table-mask {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(255, 255, 255, 0.8);
z-index: 99;
/* #ifndef APP-NVUE */
display: flex;
margin: auto;
transition: all 0.5s;
/* #endif */
justify-content: center;
align-items: center;
}
.uni-table--loader {
width: 30px;
height: 30px;
border: 2px solid #aaa;
// border-bottom-color: transparent;
border-radius: 50%;
/* #ifndef APP-NVUE */
animation: 2s uni-table--loader linear infinite;
/* #endif */
position: relative;
}
@keyframes uni-table--loader {
0% {
transform: rotate(360deg);
}
10% {
border-left-color: transparent;
}
20% {
border-bottom-color: transparent;
}
30% {
border-right-color: transparent;
}
40% {
border-top-color: transparent;
}
50% {
transform: rotate(0deg);
}
60% {
border-top-color: transparent;
}
70% {
border-left-color: transparent;
}
80% {
border-bottom-color: transparent;
}
90% {
border-right-color: transparent;
}
100% {
transform: rotate(-360deg);
}
}
</style>

View File

@ -0,0 +1,29 @@
<template>
<!-- #ifdef H5 -->
<tbody>
<slot></slot>
</tbody>
<!-- #endif -->
<!-- #ifndef H5 -->
<view><slot></slot></view>
<!-- #endif -->
</template>
<script>
export default {
name: 'uniBody',
options: {
virtualHost: true
},
data() {
return {
}
},
created() {},
methods: {}
}
</script>
<style>
</style>

View File

@ -0,0 +1,90 @@
<template>
<!-- #ifdef H5 -->
<td class="uni-table-td" :rowspan="rowspan" :colspan="colspan" :class="{'table--border':border}" :style="{width:width + 'px','text-align':align}">
<slot></slot>
</td>
<!-- #endif -->
<!-- #ifndef H5 -->
<!-- :class="{'table--border':border}" -->
<view class="uni-table-td" :class="{'table--border':border}" :style="{width:width + 'px','text-align':align}">
<slot></slot>
</view>
<!-- #endif -->
</template>
<script>
/**
* Td 单元格
* @description 表格中的标准单元格组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=3270
* @property {Number} align = [left|center|right] 单元格对齐方式
*/
export default {
name: 'uniTd',
options: {
virtualHost: true
},
props: {
width: {
type: [String, Number],
default: ''
},
align: {
type: String,
default: 'left'
},
rowspan: {
type: [Number,String],
default: 1
},
colspan: {
type: [Number,String],
default: 1
}
},
data() {
return {
border: false
};
},
created() {
this.root = this.getTable()
this.border = this.root.border
},
methods: {
/**
* 获取父元素实例
*/
getTable() {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== 'uniTable') {
parent = parent.$parent;
if (!parent) return false;
parentName = parent.$options.name;
}
return parent;
},
}
}
</script>
<style lang="scss">
$border-color:#EBEEF5;
.uni-table-td {
display: table-cell;
padding: 8px 10px;
font-size: 14px;
border-bottom: 1px $border-color solid;
font-weight: 400;
color: #606266;
line-height: 23px;
box-sizing: border-box;
}
.table--border {
border-right: 1px $border-color solid;
}
</style>

View File

@ -0,0 +1,511 @@
<template>
<view class="uni-filter-dropdown">
<view class="dropdown-btn" @click="onDropdown">
<view class="icon-select" :class="{active: canReset}" v-if="isSelect || isRange"></view>
<view class="icon-search" :class="{active: canReset}" v-if="isSearch">
<view class="icon-search-0"></view>
<view class="icon-search-1"></view>
</view>
<view class="icon-calendar" :class="{active: canReset}" v-if="isDate">
<view class="icon-calendar-0"></view>
<view class="icon-calendar-1"></view>
</view>
</view>
<view class="uni-dropdown-cover" v-if="isOpened" @click="handleClose"></view>
<view class="dropdown-popup dropdown-popup-right" v-if="isOpened" @click.stop>
<!-- select-->
<view v-if="isSelect" class="list">
<label class="flex-r a-i-c list-item" v-for="(item,index) in dataList" :key="index"
@click="onItemClick($event, index)">
<check-box class="check" :checked="item.checked" />
<view class="checklist-content">
<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
</view>
</label>
</view>
<view v-if="isSelect" class="flex-r opera-area">
<view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleSelectReset">
{{resource.reset}}</view>
<view class="flex-f btn btn-submit" @click="handleSelectSubmit">{{resource.submit}}</view>
</view>
<!-- search -->
<view v-if="isSearch" class="search-area">
<input class="search-input" v-model="filterValue" />
</view>
<view v-if="isSearch" class="flex-r opera-area">
<view class="flex-f btn btn-submit" @click="handleSearchSubmit">{{resource.search}}</view>
<view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleSearchReset">
{{resource.reset}}</view>
</view>
<!-- range -->
<view v-if="isRange">
<view class="input-label">{{resource.gt}}</view>
<input class="input" v-model="gtValue" />
<view class="input-label">{{resource.lt}}</view>
<input class="input" v-model="ltValue" />
</view>
<view v-if="isRange" class="flex-r opera-area">
<view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleRangeReset">
{{resource.reset}}</view>
<view class="flex-f btn btn-submit" @click="handleRangeSubmit">{{resource.submit}}</view>
</view>
<!-- date -->
<view v-if="isDate">
<uni-datetime-picker ref="datetimepicker" :value="dateRange" type="datetimerange" return-type="timestamp" @change="datetimechange" @maskClick="timepickerclose">
<view></view>
</uni-datetime-picker>
</view>
</view>
</view>
</template>
<script>
import checkBox from '../uni-tr/table-checkbox.vue'
const resource = {
"reset": "重置",
"search": "搜索",
"submit": "确定",
"filter": "筛选",
"gt": "大于等于",
"lt": "小于等于",
"date": "日期范围"
}
const DropdownType = {
Select: "select",
Search: "search",
Range: "range",
Date: "date",
Timestamp: "timestamp"
}
export default {
name: 'FilterDropdown',
emits:['change'],
components: {
checkBox
},
options: {
virtualHost: true
},
props: {
filterType: {
type: String,
default: DropdownType.Select
},
filterData: {
type: Array,
default () {
return []
}
},
mode: {
type: String,
default: 'default'
},
map: {
type: Object,
default () {
return {
text: 'text',
value: 'value'
}
}
},
filterDefaultValue: {
type: [Array,String],
default () {
return ""
}
}
},
computed: {
canReset() {
if (this.isSearch) {
return this.filterValue.length > 0
}
if (this.isSelect) {
return this.checkedValues.length > 0
}
if (this.isRange) {
return (this.gtValue.length > 0 && this.ltValue.length > 0)
}
if (this.isDate) {
return this.dateSelect.length > 0
}
return false
},
isSelect() {
return this.filterType === DropdownType.Select
},
isSearch() {
return this.filterType === DropdownType.Search
},
isRange() {
return this.filterType === DropdownType.Range
},
isDate() {
return (this.filterType === DropdownType.Date || this.filterType === DropdownType.Timestamp)
}
},
watch: {
filterData(newVal) {
this._copyFilters()
},
indeterminate(newVal) {
this.isIndeterminate = newVal
}
},
data() {
return {
resource,
enabled: true,
isOpened: false,
dataList: [],
filterValue: this.filterDefaultValue,
checkedValues: [],
gtValue: '',
ltValue: '',
dateRange: [],
dateSelect: []
};
},
created() {
this._copyFilters()
},
methods: {
_copyFilters() {
let dl = JSON.parse(JSON.stringify(this.filterData))
for (let i = 0; i < dl.length; i++) {
if (dl[i].checked === undefined) {
dl[i].checked = false
}
}
this.dataList = dl
},
openPopup() {
this.isOpened = true
if (this.isDate) {
this.$nextTick(() => {
if (!this.dateRange.length) {
this.resetDate()
}
this.$refs.datetimepicker.show()
})
}
},
closePopup() {
this.isOpened = false
},
handleClose(e) {
this.closePopup()
},
resetDate() {
let date = new Date()
let dateText = date.toISOString().split('T')[0]
this.dateRange = [dateText + ' 0:00:00', dateText + ' 23:59:59']
},
onDropdown(e) {
this.openPopup()
},
onItemClick(e, index) {
let items = this.dataList
let listItem = items[index]
if (listItem.checked === undefined) {
items[index].checked = true
} else {
items[index].checked = !listItem.checked
}
let checkvalues = []
for (let i = 0; i < items.length; i++) {
const item = items[i]
if (item.checked) {
checkvalues.push(item.value)
}
}
this.checkedValues = checkvalues
},
datetimechange(e) {
this.closePopup()
this.dateRange = e
this.dateSelect = e
this.$emit('change', {
filterType: this.filterType,
filter: e
})
},
timepickerclose(e) {
this.closePopup()
},
handleSelectSubmit() {
this.closePopup()
this.$emit('change', {
filterType: this.filterType,
filter: this.checkedValues
})
},
handleSelectReset() {
if (!this.canReset) {
return;
}
var items = this.dataList
for (let i = 0; i < items.length; i++) {
let item = items[i]
this.$set(item, 'checked', false)
}
this.checkedValues = []
this.handleSelectSubmit()
},
handleSearchSubmit() {
this.closePopup()
this.$emit('change', {
filterType: this.filterType,
filter: this.filterValue
})
},
handleSearchReset() {
if (!this.canReset) {
return;
}
this.filterValue = ''
this.handleSearchSubmit()
},
handleRangeSubmit(isReset) {
this.closePopup()
this.$emit('change', {
filterType: this.filterType,
filter: isReset === true ? [] : [parseInt(this.gtValue), parseInt(this.ltValue)]
})
},
handleRangeReset() {
if (!this.canReset) {
return;
}
this.gtValue = ''
this.ltValue = ''
this.handleRangeSubmit(true)
}
}
}
</script>
<style lang="scss">
$uni-primary: #1890ff !default;
.flex-r {
display: flex;
flex-direction: row;
}
.flex-f {
flex: 1;
}
.a-i-c {
align-items: center;
}
.j-c-c {
justify-content: center;
}
.icon-select {
width: 14px;
height: 16px;
border: solid 6px transparent;
border-top: solid 6px #ddd;
border-bottom: none;
background-color: #ddd;
background-clip: content-box;
box-sizing: border-box;
}
.icon-select.active {
background-color: $uni-primary;
border-top-color: $uni-primary;
}
.icon-search {
width: 12px;
height: 16px;
position: relative;
}
.icon-search-0 {
border: 2px solid #ddd;
border-radius: 8px;
width: 7px;
height: 7px;
}
.icon-search-1 {
position: absolute;
top: 8px;
right: 0;
width: 1px;
height: 7px;
background-color: #ddd;
transform: rotate(-45deg);
}
.icon-search.active .icon-search-0 {
border-color: $uni-primary;
}
.icon-search.active .icon-search-1 {
background-color: $uni-primary;
}
.icon-calendar {
color: #ddd;
width: 14px;
height: 16px;
}
.icon-calendar-0 {
height: 4px;
margin-top: 3px;
margin-bottom: 1px;
background-color: #ddd;
border-radius: 2px 2px 1px 1px;
position: relative;
}
.icon-calendar-0:before, .icon-calendar-0:after {
content: '';
position: absolute;
top: -3px;
width: 4px;
height: 3px;
border-radius: 1px;
background-color: #ddd;
}
.icon-calendar-0:before {
left: 2px;
}
.icon-calendar-0:after {
right: 2px;
}
.icon-calendar-1 {
height: 9px;
background-color: #ddd;
border-radius: 1px 1px 2px 2px;
}
.icon-calendar.active {
color: $uni-primary;
}
.icon-calendar.active .icon-calendar-0,
.icon-calendar.active .icon-calendar-1,
.icon-calendar.active .icon-calendar-0:before,
.icon-calendar.active .icon-calendar-0:after {
background-color: $uni-primary;
}
.uni-filter-dropdown {
position: relative;
font-weight: normal;
}
.dropdown-popup {
position: absolute;
top: 100%;
background-color: #fff;
box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d;
min-width: 150px;
z-index: 1000;
}
.dropdown-popup-left {
left: 0;
}
.dropdown-popup-right {
right: 0;
}
.uni-dropdown-cover {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: transparent;
z-index: 100;
}
.list {
margin-top: 5px;
margin-bottom: 5px;
}
.list-item {
padding: 5px 10px;
text-align: left;
}
.list-item:hover {
background-color: #f0f0f0;
}
.check {
margin-right: 5px;
}
.search-area {
padding: 10px;
}
.search-input {
font-size: 12px;
border: 1px solid #f0f0f0;
border-radius: 3px;
padding: 2px 5px;
min-width: 150px;
text-align: left;
}
.input-label {
margin: 10px 10px 5px 10px;
text-align: left;
}
.input {
font-size: 12px;
border: 1px solid #f0f0f0;
border-radius: 3px;
margin: 10px;
padding: 2px 5px;
min-width: 150px;
text-align: left;
}
.opera-area {
cursor: default;
border-top: 1px solid #ddd;
padding: 5px;
}
.opera-area .btn {
font-size: 12px;
border-radius: 3px;
margin: 5px;
padding: 4px 4px;
}
.btn-default {
border: 1px solid #ddd;
}
.btn-default.disable {
border-color: transparent;
}
.btn-submit {
background-color: $uni-primary;
color: #ffffff;
}
</style>

View File

@ -0,0 +1,285 @@
<template>
<!-- #ifdef H5 -->
<th :rowspan="rowspan" :colspan="colspan" class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: customWidth + 'px', 'text-align': align }">
<view class="uni-table-th-row">
<view class="uni-table-th-content" :style="{ 'justify-content': contentAlign }" @click="sort">
<slot></slot>
<view v-if="sortable" class="arrow-box">
<text class="arrow up" :class="{ active: ascending }" @click.stop="ascendingFn"></text>
<text class="arrow down" :class="{ active: descending }" @click.stop="descendingFn"></text>
</view>
</view>
<dropdown v-if="filterType || filterData.length" :filterDefaultValue="filterDefaultValue" :filterData="filterData" :filterType="filterType" @change="ondropdown"></dropdown>
</view>
</th>
<!-- #endif -->
<!-- #ifndef H5 -->
<view class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: customWidth + 'px', 'text-align': align }"><slot></slot></view>
<!-- #endif -->
</template>
<script>
// #ifdef H5
import dropdown from './filter-dropdown.vue'
// #endif
/**
* Th 表头
* @description 表格内的表头单元格组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=3270
* @property {Number | String} width 单元格宽度支持纯数字携带单位px或rpx
* @property {Boolean} sortable 是否启用排序
* @property {Number} align = [left|center|right] 单元格对齐方式
* @value left 单元格文字左侧对齐
* @value center 单元格文字居中
* @value right 单元格文字右侧对齐
* @property {Array} filterData 筛选数据
* @property {String} filterType [search|select] 筛选类型
* @value search 关键字搜素
* @value select 条件选择
* @event {Function} sort-change 排序触发事件
*/
export default {
name: 'uniTh',
options: {
virtualHost: true
},
components: {
// #ifdef H5
dropdown
// #endif
},
emits:['sort-change','filter-change'],
props: {
width: {
type: [String, Number],
default: ''
},
align: {
type: String,
default: 'left'
},
rowspan: {
type: [Number, String],
default: 1
},
colspan: {
type: [Number, String],
default: 1
},
sortable: {
type: Boolean,
default: false
},
filterType: {
type: String,
default: ""
},
filterData: {
type: Array,
default () {
return []
}
},
filterDefaultValue: {
type: [Array,String],
default () {
return ""
}
}
},
data() {
return {
border: false,
ascending: false,
descending: false
}
},
computed: {
// propswidth th(px)
customWidth(){
if(typeof this.width === 'number'){
return this.width
} else if(typeof this.width === 'string') {
let regexHaveUnitPx = new RegExp(/^[1-9][0-9]*px$/g)
let regexHaveUnitRpx = new RegExp(/^[1-9][0-9]*rpx$/g)
let regexHaveNotUnit = new RegExp(/^[1-9][0-9]*$/g)
if (this.width.match(regexHaveUnitPx) !== null) { // px
return this.width.replace('px', '')
} else if (this.width.match(regexHaveUnitRpx) !== null) { // rpx
let numberRpx = Number(this.width.replace('rpx', ''))
let widthCoe = uni.getSystemInfoSync().screenWidth / 750
return Math.round(numberRpx * widthCoe)
} else if (this.width.match(regexHaveNotUnit) !== null) { // rpxpx String
return this.width
} else { //
return ''
}
} else {
return ''
}
},
contentAlign() {
let align = 'left'
switch (this.align) {
case 'left':
align = 'flex-start'
break
case 'center':
align = 'center'
break
case 'right':
align = 'flex-end'
break
}
return align
}
},
created() {
this.root = this.getTable('uniTable')
this.rootTr = this.getTable('uniTr')
this.rootTr.minWidthUpdate(this.customWidth ? this.customWidth : 140)
this.border = this.root.border
this.root.thChildren.push(this)
},
methods: {
sort() {
if (!this.sortable) return
this.clearOther()
if (!this.ascending && !this.descending) {
this.ascending = true
this.$emit('sort-change', { order: 'ascending' })
return
}
if (this.ascending && !this.descending) {
this.ascending = false
this.descending = true
this.$emit('sort-change', { order: 'descending' })
return
}
if (!this.ascending && this.descending) {
this.ascending = false
this.descending = false
this.$emit('sort-change', { order: null })
}
},
ascendingFn() {
this.clearOther()
this.ascending = !this.ascending
this.descending = false
this.$emit('sort-change', { order: this.ascending ? 'ascending' : null })
},
descendingFn() {
this.clearOther()
this.descending = !this.descending
this.ascending = false
this.$emit('sort-change', { order: this.descending ? 'descending' : null })
},
clearOther() {
this.root.thChildren.map(item => {
if (item !== this) {
item.ascending = false
item.descending = false
}
return item
})
},
ondropdown(e) {
this.$emit("filter-change", e)
},
/**
* 获取父元素实例
*/
getTable(name) {
let parent = this.$parent
let parentName = parent.$options.name
while (parentName !== name) {
parent = parent.$parent
if (!parent) return false
parentName = parent.$options.name
}
return parent
}
}
}
</script>
<style lang="scss">
$border-color: #ebeef5;
$uni-primary: #007aff !default;
.uni-table-th {
padding: 12px 10px;
/* #ifndef APP-NVUE */
display: table-cell;
box-sizing: border-box;
/* #endif */
font-size: 14px;
font-weight: bold;
color: #909399;
border-bottom: 1px $border-color solid;
}
.uni-table-th-row {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.table--border {
border-right: 1px $border-color solid;
}
.uni-table-th-content {
display: flex;
align-items: center;
flex: 1;
}
.arrow-box {
}
.arrow {
display: block;
position: relative;
width: 10px;
height: 8px;
// border: 1px red solid;
left: 5px;
overflow: hidden;
cursor: pointer;
}
.down {
top: 3px;
::after {
content: '';
width: 8px;
height: 8px;
position: absolute;
left: 2px;
top: -5px;
transform: rotate(45deg);
background-color: #ccc;
}
&.active {
::after {
background-color: $uni-primary;
}
}
}
.up {
::after {
content: '';
width: 8px;
height: 8px;
position: absolute;
left: 2px;
top: 5px;
transform: rotate(45deg);
background-color: #ccc;
}
&.active {
::after {
background-color: $uni-primary;
}
}
}
</style>

View File

@ -0,0 +1,129 @@
<template>
<!-- #ifdef H5 -->
<thead class="uni-table-thead">
<tr class="uni-table-tr">
<th :rowspan="rowspan" colspan="1" class="checkbox" :class="{ 'tr-table--border': border }">
<table-checkbox :indeterminate="indeterminate" :checked="checked" @checkboxSelected="checkboxSelected"></table-checkbox>
</th>
</tr>
<slot></slot>
</thead>
<!-- #endif -->
<!-- #ifndef H5 -->
<view class="uni-table-thead"><slot></slot></view>
<!-- #endif -->
</template>
<script>
import tableCheckbox from '../uni-tr/table-checkbox.vue'
export default {
name: 'uniThead',
components: {
tableCheckbox
},
options: {
virtualHost: true
},
data() {
return {
border: false,
selection: false,
rowspan: 1,
indeterminate: false,
checked: false
}
},
created() {
this.root = this.getTable()
// #ifdef H5
this.root.theadChildren = this
// #endif
this.border = this.root.border
this.selection = this.root.type
},
methods: {
init(self) {
this.rowspan++
},
checkboxSelected(e) {
this.indeterminate = false
const backIndexData = this.root.backIndexData
const data = this.root.trChildren.filter(v => !v.disabled && v.keyValue)
if (backIndexData.length === data.length) {
this.checked = false
this.root.clearSelection()
} else {
this.checked = true
this.root.selectionAll()
}
},
/**
* 获取父元素实例
*/
getTable(name = 'uniTable') {
let parent = this.$parent
let parentName = parent.$options.name
while (parentName !== name) {
parent = parent.$parent
if (!parent) return false
parentName = parent.$options.name
}
return parent
}
}
}
</script>
<style lang="scss">
$border-color: #ebeef5;
.uni-table-thead {
display: table-header-group;
}
.uni-table-tr {
/* #ifndef APP-NVUE */
display: table-row;
transition: all 0.3s;
box-sizing: border-box;
/* #endif */
border: 1px red solid;
background-color: #fafafa;
}
.checkbox {
padding: 0 8px;
width: 26px;
padding-left: 12px;
/* #ifndef APP-NVUE */
display: table-cell;
vertical-align: middle;
/* #endif */
color: #333;
font-weight: 500;
border-bottom: 1px $border-color solid;
font-size: 14px;
// text-align: center;
}
.tr-table--border {
border-right: 1px $border-color solid;
}
/* #ifndef APP-NVUE */
.uni-table-tr {
::v-deep .uni-table-th {
&.table--border:last-child {
// border-right: none;
}
}
::v-deep .uni-table-td {
&.table--border:last-child {
// border-right: none;
}
}
}
/* #endif */
</style>

View File

@ -0,0 +1,179 @@
<template>
<view class="uni-table-checkbox" @click="selected">
<view v-if="!indeterminate" class="checkbox__inner" :class="{'is-checked':isChecked,'is-disable':isDisabled}">
<view class="checkbox__inner-icon"></view>
</view>
<view v-else class="checkbox__inner checkbox--indeterminate">
<view class="checkbox__inner-icon"></view>
</view>
</view>
</template>
<script>
export default {
name: 'TableCheckbox',
emits:['checkboxSelected'],
props: {
indeterminate: {
type: Boolean,
default: false
},
checked: {
type: [Boolean,String],
default: false
},
disabled: {
type: Boolean,
default: false
},
index: {
type: Number,
default: -1
},
cellData: {
type: Object,
default () {
return {}
}
}
},
watch:{
checked(newVal){
if(typeof this.checked === 'boolean'){
this.isChecked = newVal
}else{
this.isChecked = true
}
},
indeterminate(newVal){
this.isIndeterminate = newVal
}
},
data() {
return {
isChecked: false,
isDisabled: false,
isIndeterminate:false
}
},
created() {
if(typeof this.checked === 'boolean'){
this.isChecked = this.checked
}
this.isDisabled = this.disabled
},
methods: {
selected() {
if (this.isDisabled) return
this.isIndeterminate = false
this.isChecked = !this.isChecked
this.$emit('checkboxSelected', {
checked: this.isChecked,
data: this.cellData
})
}
}
}
</script>
<style lang="scss">
$uni-primary: #007aff !default;
$border-color: #DCDFE6;
$disable:0.4;
.uni-table-checkbox {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
position: relative;
margin: 5px 0;
cursor: pointer;
//
.checkbox__inner {
/* #ifndef APP-NVUE */
flex-shrink: 0;
box-sizing: border-box;
/* #endif */
position: relative;
width: 16px;
height: 16px;
border: 1px solid $border-color;
border-radius: 2px;
background-color: #fff;
z-index: 1;
.checkbox__inner-icon {
position: absolute;
/* #ifdef APP-NVUE */
top: 2px;
/* #endif */
/* #ifndef APP-NVUE */
top: 2px;
/* #endif */
left: 5px;
height: 7px;
width: 3px;
border: 1px solid #fff;
border-left: 0;
border-top: 0;
opacity: 0;
transform-origin: center;
transform: rotate(45deg);
box-sizing: content-box;
}
&.checkbox--indeterminate {
border-color: $uni-primary;
background-color: $uni-primary;
.checkbox__inner-icon {
position: absolute;
opacity: 1;
transform: rotate(0deg);
height: 2px;
top: 0;
bottom: 0;
margin: auto;
left: 0px;
right: 0px;
bottom: 0;
width: auto;
border: none;
border-radius: 2px;
transform: scale(0.5);
background-color: #fff;
}
}
&:hover{
border-color: $uni-primary;
}
//
&.is-disable {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
background-color: #F2F6FC;
border-color: $border-color;
}
//
&.is-checked {
border-color: $uni-primary;
background-color: $uni-primary;
.checkbox__inner-icon {
opacity: 1;
transform: rotate(45deg);
}
//
&.is-disable {
opacity: $disable;
}
}
}
}
</style>

View File

@ -0,0 +1,171 @@
<template>
<!-- #ifdef H5 -->
<tr class="uni-table-tr">
<th v-if="selection === 'selection' && ishead" class="checkbox" :class="{ 'tr-table--border': border }">
<table-checkbox :checked="checked" :indeterminate="indeterminate" :disabled="disabled" @checkboxSelected="checkboxSelected"></table-checkbox>
</th>
<slot></slot>
<!-- <uni-th class="th-fixed">123</uni-th> -->
</tr>
<!-- #endif -->
<!-- #ifndef H5 -->
<view class="uni-table-tr">
<view v-if="selection === 'selection' " class="checkbox" :class="{ 'tr-table--border': border }">
<table-checkbox :checked="checked" :indeterminate="indeterminate" :disabled="disabled" @checkboxSelected="checkboxSelected"></table-checkbox>
</view>
<slot></slot>
</view>
<!-- #endif -->
</template>
<script>
import tableCheckbox from './table-checkbox.vue'
/**
* Tr 表格行组件
* @description 表格行组件 仅包含 th,td 组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=
*/
export default {
name: 'uniTr',
components: { tableCheckbox },
props: {
disabled: {
type: Boolean,
default: false
},
keyValue: {
type: [String, Number],
default: ''
}
},
options: {
virtualHost: true
},
data() {
return {
value: false,
border: false,
selection: false,
widthThArr: [],
ishead: true,
checked: false,
indeterminate:false
}
},
created() {
this.root = this.getTable()
this.head = this.getTable('uniThead')
if (this.head) {
this.ishead = false
this.head.init(this)
}
this.border = this.root.border
this.selection = this.root.type
this.root.trChildren.push(this)
const rowData = this.root.data.find(v => v[this.root.rowKey] === this.keyValue)
if(rowData){
this.rowData = rowData
}
this.root.isNodata()
},
mounted() {
if (this.widthThArr.length > 0) {
const selectionWidth = this.selection === 'selection' ? 50 : 0
this.root.minWidth = this.widthThArr.reduce((a, b) => Number(a) + Number(b)) + selectionWidth
}
},
// #ifndef VUE3
destroyed() {
const index = this.root.trChildren.findIndex(i => i === this)
this.root.trChildren.splice(index, 1)
this.root.isNodata()
},
// #endif
// #ifdef VUE3
unmounted() {
const index = this.root.trChildren.findIndex(i => i === this)
this.root.trChildren.splice(index, 1)
this.root.isNodata()
},
// #endif
methods: {
minWidthUpdate(width) {
this.widthThArr.push(width)
},
//
checkboxSelected(e) {
let rootData = this.root.data.find(v => v[this.root.rowKey] === this.keyValue)
this.checked = e.checked
this.root.check(rootData||this, e.checked,rootData? this.keyValue:null)
},
change(e) {
this.root.trChildren.forEach(item => {
if (item === this) {
this.root.check(this, e.detail.value.length > 0 ? true : false)
}
})
},
/**
* 获取父元素实例
*/
getTable(name = 'uniTable') {
let parent = this.$parent
let parentName = parent.$options.name
while (parentName !== name) {
parent = parent.$parent
if (!parent) return false
parentName = parent.$options.name
}
return parent
}
}
}
</script>
<style lang="scss">
$border-color: #ebeef5;
.uni-table-tr {
/* #ifndef APP-NVUE */
display: table-row;
transition: all 0.3s;
box-sizing: border-box;
/* #endif */
}
.checkbox {
padding: 0 8px;
width: 26px;
padding-left: 12px;
/* #ifndef APP-NVUE */
display: table-cell;
vertical-align: middle;
/* #endif */
color: #333;
font-weight: 500;
border-bottom: 1px $border-color solid;
font-size: 14px;
// text-align: center;
}
.tr-table--border {
border-right: 1px $border-color solid;
}
/* #ifndef APP-NVUE */
.uni-table-tr {
::v-deep .uni-table-th {
&.table--border:last-child {
// border-right: none;
}
}
::v-deep .uni-table-td {
&.table--border:last-child {
// border-right: none;
}
}
}
/* #endif */
</style>

View File

@ -0,0 +1,9 @@
{
"filter-dropdown.reset": "Reset",
"filter-dropdown.search": "Search",
"filter-dropdown.submit": "Submit",
"filter-dropdown.filter": "Filter",
"filter-dropdown.gt": "Greater or equal to",
"filter-dropdown.lt": "Less than or equal to",
"filter-dropdown.date": "Date"
}

View File

@ -0,0 +1,9 @@
{
"filter-dropdown.reset": "Reiniciar",
"filter-dropdown.search": "Búsqueda",
"filter-dropdown.submit": "Entregar",
"filter-dropdown.filter": "Filtrar",
"filter-dropdown.gt": "Mayor o igual a",
"filter-dropdown.lt": "Menos que o igual a",
"filter-dropdown.date": "Fecha"
}

View File

@ -0,0 +1,9 @@
{
"filter-dropdown.reset": "Réinitialiser",
"filter-dropdown.search": "Chercher",
"filter-dropdown.submit": "Soumettre",
"filter-dropdown.filter": "Filtre",
"filter-dropdown.gt": "Supérieur ou égal à",
"filter-dropdown.lt": "Inférieur ou égal à",
"filter-dropdown.date": "Date"
}

View File

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

View File

@ -0,0 +1,9 @@
{
"filter-dropdown.reset": "重置",
"filter-dropdown.search": "搜索",
"filter-dropdown.submit": "确定",
"filter-dropdown.filter": "筛选",
"filter-dropdown.gt": "大于等于",
"filter-dropdown.lt": "小于等于",
"filter-dropdown.date": "日期范围"
}

View File

@ -0,0 +1,9 @@
{
"filter-dropdown.reset": "重置",
"filter-dropdown.search": "搜索",
"filter-dropdown.submit": "確定",
"filter-dropdown.filter": "篩選",
"filter-dropdown.gt": "大於等於",
"filter-dropdown.lt": "小於等於",
"filter-dropdown.date": "日期範圍"
}

View File

@ -0,0 +1,83 @@
{
"id": "uni-table",
"displayName": "uni-table 表格",
"version": "1.2.3",
"description": "表格组件,多用于展示多条结构类似的数据,如",
"keywords": [
"uni-ui",
"uniui",
"table",
"表格"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": ["uni-scss","uni-datetime-picker"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "n"
},
"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",
"字节跳动": "n",
"QQ": "y"
},
"快应用": {
"华为": "n",
"联盟": "n"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@ -0,0 +1,13 @@
## Table 表单
> 组件名:``uni-table``,代码块: `uTable`
用于展示多条结构类似的数据
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-table)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839