7.13 pan
parent
ac0c8330aa
commit
66df74758d
|
@ -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>
|
|
@ -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'
|
||||
},
|
||||
//是否显示秒 针对type为datetime或time时生效
|
||||
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>
|
|
@ -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>
|
22
package.json
22
package.json
|
@ -1,5 +1,19 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"vant": "^2.12.54"
|
||||
}
|
||||
}
|
||||
"id": "fjj-condition",
|
||||
"name": "tongtong-条件筛选",
|
||||
"version": "1.0.6",
|
||||
"description": "支持单选多选筛选、日期范围筛选、数量或金额范围筛选, 兼容h5、微信小程序、其它端未测试",
|
||||
"keywords": [
|
||||
"筛选",
|
||||
"条件筛选",
|
||||
"多选",
|
||||
"单选",
|
||||
"日期筛选"
|
||||
],
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
]
|
||||
}
|
||||
}
|
10
pages.json
10
pages.json
|
@ -148,6 +148,16 @@
|
|||
"style": {
|
||||
"navigationBarTitleText": "船舶计划"
|
||||
}
|
||||
}, {
|
||||
"path": "pages/shipWork/brandDetails",
|
||||
"style": {
|
||||
"navigationBarTitleText": "品牌明细"
|
||||
}
|
||||
},{
|
||||
"path": "pages/shipWork/carDetails",
|
||||
"style": {
|
||||
"navigationBarTitleText": "车型明细"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/monitor/index",
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -66,7 +66,7 @@
|
|||
},
|
||||
{
|
||||
name: "作业查询",
|
||||
url: "mixWork"
|
||||
url: "brandDetails"
|
||||
}
|
||||
],
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -0,0 +1,27 @@
|
|||
## 1.2.4(2022-09-19)
|
||||
- 修复,未对主题色设置默认色,导致未引入 uni-scss 变量文件报错。
|
||||
- 修复,未对移动端当前页文字做主题色适配。
|
||||
## 1.2.3(2022-09-15)
|
||||
- 修复未使用 uni-scss 主题色的 bug。
|
||||
## 1.2.2(2022-07-06)
|
||||
- 修复 es 语言 i18n 错误
|
||||
## 1.2.1(2021-11-22)
|
||||
- 修复 vue3中某些scss变量无法找到的问题
|
||||
## 1.2.0(2021-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.2(2021-10-08)
|
||||
- 修复 current 、value 属性未监听,导致高亮样式失效的 bug
|
||||
## 1.1.1(2021-08-20)
|
||||
- 新增 支持国际化
|
||||
## 1.1.0(2021-07-30)
|
||||
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||
## 1.0.7(2021-05-12)
|
||||
- 新增 组件示例地址
|
||||
## 1.0.6(2021-04-12)
|
||||
- 新增 PC 和 移动端适配不同的 ui
|
||||
## 1.0.5(2021-02-05)
|
||||
- 优化 组件引用关系,通过uni_modules引用组件
|
||||
|
||||
## 1.0.4(2021-02-05)
|
||||
- 调整为uni_modules目录规范
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"uni-pagination.prevText": "prev",
|
||||
"uni-pagination.nextText": "next",
|
||||
"uni-pagination.piecePerPage": "piece/page"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"uni-pagination.prevText": "anterior",
|
||||
"uni-pagination.nextText": "prxima",
|
||||
"uni-pagination.piecePerPage": "Art¨ªculo/P¨¢gina"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"uni-pagination.prevText": "précédente",
|
||||
"uni-pagination.nextText": "suivante",
|
||||
"uni-pagination.piecePerPage": "Articles/Pages"
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"uni-pagination.prevText": "上一页",
|
||||
"uni-pagination.nextText": "下一页",
|
||||
"uni-pagination.piecePerPage": "条/页"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"uni-pagination.prevText": "上一頁",
|
||||
"uni-pagination.nextText": "下一頁",
|
||||
"uni-pagination.piecePerPage": "條/頁"
|
||||
}
|
|
@ -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>
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
|
||||
## Pagination 分页器
|
||||
> **组件名:uni-pagination**
|
||||
> 代码块: `uPagination`
|
||||
|
||||
|
||||
分页器组件,用于展示页码、请求数据等。
|
||||
|
||||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-pagination)
|
||||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
|
@ -0,0 +1,27 @@
|
|||
## 1.2.3(2023-03-28)
|
||||
- 修复 在vue3模式下可能会出现错误的问题
|
||||
## 1.2.2(2022-11-29)
|
||||
- 优化 主题样式
|
||||
## 1.2.1(2022-06-06)
|
||||
- 修复 微信小程序存在无使用组件的问题
|
||||
## 1.2.0(2021-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.0(2021-07-30)
|
||||
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||
## 1.0.7(2021-07-08)
|
||||
- 新增 uni-th 支持 date 日期筛选范围
|
||||
## 1.0.6(2021-07-05)
|
||||
- 新增 uni-th 支持 range 筛选范围
|
||||
## 1.0.5(2021-06-28)
|
||||
- 新增 uni-th 筛选功能
|
||||
## 1.0.4(2021-05-12)
|
||||
- 新增 示例地址
|
||||
- 修复 示例项目缺少组件的Bug
|
||||
## 1.0.3(2021-04-16)
|
||||
- 新增 sortable 属性,是否开启单列排序
|
||||
- 优化 表格多选逻辑
|
||||
## 1.0.2(2021-03-22)
|
||||
- uni-tr 添加 disabled 属性,用于 type=selection 时,设置某行是否可由全选按钮控制
|
||||
## 1.0.1(2021-02-05)
|
||||
- 调整为uni_modules目录规范
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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: {
|
||||
// 根据props中的width属性 自动匹配当前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) { // 未携带 rpx或px 的纯数字 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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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"
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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": "日期范围"
|
||||
}
|
|
@ -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": "日期範圍"
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
|
||||
## Table 表单
|
||||
> 组件名:``uni-table``,代码块: `uTable`。
|
||||
|
||||
用于展示多条结构类似的数据
|
||||
|
||||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-table)
|
||||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue