订单,报名,发布,我的等功能

This commit is contained in:
张凯 2025-04-18 18:12:42 +08:00
parent 7d4e41186c
commit 654f12eb11
94 changed files with 16549 additions and 3947 deletions

31
App.vue
View File

@ -64,6 +64,35 @@
}
@font-face {
font-family: 'YouSheBiaoTiHei';
src: url('~@/static/fonts/biaotihei.ttf') format('truetype');
src: url('https://naweigetetest2.hschool.com.cn/dyqc/biaotihei.ttf') format('truetype');
}
.swiper_s{
.uni-swiper-dots{
bottom: 40rpx;
}
.uni-swiper-dot{
background-color: #ffffff ;
width: 30rpx;
height: 8rpx;
border-radius: 0;
}
.uni-swiper-dot-active{
background-color: #0DAE11;
}
//
// #ifdef MP-WEIXIN
.wx-swiper-dots{
bottom: 40rpx;
}
.wx-swiper-dot{
background-color: #ffffff ;
width: 30rpx;
height: 8rpx;
border-radius: 0;
}
.wx-swiper-dot-active{
background-color: #0DAE11;
}
// #endif
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
<template>
<swiper class="swiper" :autoplay="autoplaySwiper" :indicator-dots="dotsShow" :current="swiperCurrent" @change="swiperChange">
<swiper class="swiper_s" :autoplay="autoplaySwiper" indicator-active-color="#0DAE11" indicator-color="#ffffff" :indicator-dots="true" :current="swiperCurrent" @change="swiperChange">
<swiper-item v-for="(item,index) in list" :key="index">
<span class="fnon_tit">{{ item.title?item.title:'' }}</span>
<image class="swiper-image" v-if="isImageUrl(item.image)" @click="click(item.url)" :src="item.image" mode="scaleToFill" lazy-load />
<!-- @click="click(item.url)" 跳转活动链接 -->
<image class="swiper-image" v-if="isImageUrl(item.image)" :src="item.image" mode="scaleToFill" lazy-load />
<div style="height: 100%;width: 100%;position: relative;" v-else>
<!-- #ifdef APP -->
@ -58,7 +59,7 @@
data() {
return {
swiperCurrent: 0, //
autoplaySwiper: false,
autoplaySwiper: true,
isShow: true,
videoIndex: null,
videoId: null,
@ -169,23 +170,11 @@
}
</script>
<style scoped lang="scss">
.swiper {
.swiper_s {
width: 100%;
height: 100%;
::v-deep .uni-swiper-dots{
bottom: 40rpx;
}
::v-deep .uni-swiper-dot{
background-color: #ffffff;
width: 30rpx;
height: 8rpx;
border-radius: 0rpx;
}
::v-deep .uni-swiper-dot-active{
background-color: #0DAE11;
}
}
.swiper-image,
.swiper-video {

View File

@ -156,8 +156,8 @@
justify-content: center;
align-items: center;
width: 100%;
height: 98rpx;
padding-bottom: 12rpx;
height: 128rpx;
padding-bottom: 27rpx;
background-color: #FFFFFF;
box-sizing:border-box;
box-shadow: 0rpx -1rpx 0rpx 0rpx #EEEEEE;

View File

@ -1,19 +1,833 @@
<template>
<view>
<view class="box flex">
<view class="con-center flex flex-column justify-center align-items">
<view class="tabs align-items">
<span class="s-header flex flex-column" v-for="(item,index) in headers" :key="index"
:class="{ selected: headerSelected(item.status) }"
@click="selectheader(item.status)">
{{item.text}}
<span class="lines" :class="{ selected: headerSelected(item.status) }"></span>
</span>
</view>
<view class="flex hdkuai flex-column" v-for="(item,index) in list" :key="index">
<view style="margin:0 30rpx;">
<span class="text_h">活动时间 {{dateWeeks(item.detail.start_time) +' - '+dateWeekends(item.detail.end_time)}}</span>
</view>
<span class="line"></span>
<view style="margin:0 30rpx;" class="flex">
<image class="tut" :src="item.detail.images[0]"></image>
<view style="margin-left: 20rpx;width: 80%;">
<view>
<span>{{ item.detail.title }}</span>
</view>
<view style="margin-top: 40rpx;" class="flex flex-between align-items">
<span style="font-size: 32rpx;">{{item.totalprice}}</span>
<span style="font-size: 26rpx;color: #9C9C9C;">购买数量{{ item.num }}</span>
</view>
</view>
</view>
<span class="line"></span>
<view class="flex foot_btn align-items space-between">
<view>
<span v-if="item.status == 9">已完成</span>
<span v-if="item.status == 0" style="color: #FF4810;display: flex;align-items: center;">
支付倒计时<u-count-down :time="item.cancel_last_seconds*1000"></u-count-down>
</span>
<span v-if="item.status == 2 || item.status == 3">待核销</span>
<span v-if="item.status == (-3)" style="color: #9C9C9C;">已关闭</span>
<span v-if="item.status == 4 || item.status == 7" style="color: #FF4810;">售后中</span>
<span v-if="item.status == 5" style="color: #FF4810;">退款中</span>
<span v-if="item.status == 6" style="color: #FF4810;">已退款</span>
</view>
<view class="flex align-items" style="justify-content: flex-end;">
<view v-if="item.status == 0 && item.cancel_last_seconds > 0" class="btn_xq" @click="toPay(item.id,item.order_no)">去支付</view>
<view v-if="item.status == 2 || item.status == 3" class="btnhx">核销码</view>
<view v-if="item.status != 0" class="btn_xq" @click="toDetail(item.id,item.order_no)">查看详情</view>
</view>
</view>
</view>
<!-- <span class="line"></span> -->
<!-- <view class="sort flex" style="width: 100%;padding: 20rpx 0;">
<JQ-orderBy @switchSort="switchSort" :size="size"></JQ-orderBy>
</view> -->
<!-- <view class="centerBox flex justify-start align-items flex-column">
<view class="flex w-100 center flex-column" style="align-items: center;" v-for="(item,index) in list"
:key="index">
<view class="flex w-100">
<image :src="item.detail.headimage" mode="" style="width: 280rpx; height: 200rpx;border-radius: 12rpx;"
@click="toDetail(item.shop_id,item.id,item.classes_lib_id,item.order_no)"></image>
<view class="flex flex-column rightBox">
<view class="flex flex-column"
@click="toDetail(item.shop_id,item.id,item.classes_lib_id,item.order_no)">
<span class="name">{{item.detail.title}}</span>
<span class="line-row"></span>
<span class="minge" v-if="selected == 0">课程名额 {{ Number(item.detail.verification_num )}}
/
{{item.detail.limit_num}}</span>
<span class="minge" v-if="selected == 0">剩余时间:24:00:00</span>
<span class="minge"
v-if="selected == 3 || selected == 6 || selected == 9">{{'购买时间 ' + item.paytime_text.slice(0,10)}}</span>
<span class="minge" v-if="selected == 2">{{'预约时间 ' + item.make}}</span>
<span class="minge" v-if="selected == 3">{{'课时 ' + item.detail.use_num + "/" + item.detail.classes_num}}</span>
<span class="minge" v-if="selected == 9">{{'核销时间 ' + item.finishtime_text.slice(0,10)}}</span>
<span class="minge" v-if="selected == -3">{{'取消时间 ' + item.canceltime}}</span>
<span class="minge" v-if="selected == 6">{{'退款时间 ' + item.refundtime}}</span>
<span class="money" v-if="item.payprice != 0">
<span>课程价格:</span>
{{'¥' + item.payprice}}</span>
<span class="charge" v-if="item.payprice == 0" >
免费
</span>
<span class="charge" v-if="item.payprice == 0" >
</span>
</view>
<view class="flex align-items" style="justify-content: flex-end;margin-top: 12rpx;">
<span class="Cancel" v-if="selected == 0" @click="Cancel(item.order_no)">取消订单</span>
<span class="make" v-if="selected == 0"
@click="toPay(item.shop_id,item.id,item.classes_lib_id,item.order_no,1)">去付款</span>
<span class="Cancel" v-if="selected == 3 && item.detail.feel == 0" style="width: 100rpx;"
@click="service(item.id)">售后</span>
<span class="Cancel" v-if="selected == 3 && item.detail.feel == 1" style="width: 100rpx;"
@click="service(item.id)">取消</span>
<span class="Cancel" v-if="selected == 3" @click="QR(item.id)"
style="width: 100rpx; margin-left: 24rpx;">核销</span>
<span class="make" v-if="selected == 3"
@click="toMake(item.shop_id,item.id,item.classes_lib_id,2)"
style="width: 100rpx;">预约</span>
<span class="Cancel" v-if="selected == 9">已完成</span>
<span class="make" v-if="selected == 6 || selected == -3 || selected == 9"
@click="againBuy(item.classes_lib_id)">再次购买</span>
<span class="make" v-if="selected == 6 || selected == -3 || selected == 9"
@click.stop="toDetail(item.shop_id,item.id,item.classes_lib_id,item.order_no)">再次购买</span>
<span class="QR" v-if="selected == 2" >二维码</span>
</view>
</view>
</view>
<span class="box-line"></span>
</view>
</view> -->
</view>
<!-- <u-popup :show="show" mode="center" :zIndex="99999" :custom-style="popupStyle" closeable="true" @close="close"
@open="open">
<view class="popup flex flex-column align-items">
<view class="pop-center flex">
<view class="left">
<image :src="qrcode.detail.headimage" mode="" style="width: 280rpx;height: 200rpx;"></image>
</view>
<view class="right flex flex-column">
<span class="title white-space">{{qrcode.detail.title}}</span>
<span class="hui"
style="margin: 16rpx 0 6rpx 0;">课时:{{qrcode.detail.verification_num}}/{{qrcode.detail.limit_num}}</span>
<span class="hui">日期:{{qrcode.detail.classes_date_text}}</span>
<span class="hui" style="margin: 6rpx 0 6rpx 0;">时间:{{qrcode.detail.classes_time_text}}</span>
<span class="hui" v-if="qrcode && qrcode.detail" style="margin-top: 6rpx;">开始时间:{{ formatTimestamp(qrcode.detail.start_time) }}</span>
<span class="hui" v-if="qrcode && qrcode.detail" style="margin: 6rpx 0 6rpx 0;">结束时间:{{ formatTimestamp(qrcode.detail.end_time) }}</span>
<span class="hui">地址:{{qrcode.detail.address_detail}}</span>
</view>
</view>
<span class="line-short"></span>
<image :src="qrcode.codeimage" mode="" style="width: 376rpx;height: 376rpx;"></image>
<span style="margin: 24rpx 0 64rpx 0;">核销二维码</span>
</view>
</u-popup> -->
<!-- <u-loadmore :status="loadStatus" /> -->
</view>
</template>
<script>
import { dateWeek , dateWeekend } from "../../utils/dateFormat";
export default {
data() {
return {
popupStyle: {
width: '690rpx',
margin: '0 auto', //
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
padding: '0',
borderRadius: '20rpx'
},
sortList: [{
text: '按照价格排序',
value: ['acs', 'desc'],
}, {
text: '按照编号排序',
value: ['acs', 'desc'],
}],
size: 13,
sortStyle: ['#ff557f', '#3f3f3f'],
headers: [
{
status: '',
text: '全部'
},
{
status: '0',
text: '待支付'
},
{
status: '2,3',
text: '待核销'
},
{
status: '9',
text: '已完成'
},
{
status: '-3',
text: '已关闭'
},
{
status: '4,5,6,7',
text: '退款/售后'
}
],
selected: '0',
page: 1,
limit: 10,
loadStatus: 'loading',
keywords: '',
list: [],
show: false,
qrcode: '',
count:0
};
},
onLoad(option) {
this.list = []
this.page = 1
// if (option?.status) {
// this.selected = option.status
// this.getList(option.status);
// } else {
this.getList('0');
// }
},
onReachBottom() {
if (this.list.length < this.count) {
this.page++;
this.getList(this.selected);
}
},
methods: {
dateWeeks(e) {
return dateWeek(e);
},
//
dateWeekends(e){
return dateWeekend(e);
},
formatTimestamp(timestamp) {
const date = new Date(timestamp * 1000); // 101000
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
},
//
close() {
this.show = false
// this.qrcode = ''
},
open() {
this.show = true
},
againBuy(id) {
uni.navigateTo({
url: "/pages/center/detail?id=" + id
})
},
//
Cancel(order_no) {
console.log(order_no)
uni.$u.http.post('/api/school/order/cancel', {
order_no: order_no
}).then(res => {
if (res.code == 1) {
this.list = []
this.getList(0);
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
});
}
}).catch(error => {});
},
//
toMake(id, orderId, classes_lib_id, type) {
uni.navigateTo({
// url: "/pages/center/applyDetail?id=" + id + "&orderId=" + orderId + "&type=" + 2
url: "/pages/center/orderDetail?id=" + id + "&orderId=" + orderId + "&type=" + 2 +
"&classes_lib_id=" + classes_lib_id
})
},
//
toDetail(id,order_no) {
uni.navigateTo({
url: "/packageA/my/pendinPayDetail?id=" + id +"&order_no=" + order_no
})
},
//
toPay(id,order_no) {
uni.navigateTo({
url: "/packageA/my/pendinPay?id=" + id +"&order_no=" + order_no
})
},
//
service(id) {
uni.navigateTo({
url: "/pages/afterSales/index?id=" + id
})
},
//
QR(id) {
uni.$u.http.get('/api/school/order/detail', {
params: {
id: id
},
}).then(res => {
if (res.code == 1) {
this.qrcode = res.data.detail
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
});
}
}).catch(error => {});
this.show = true
},
switchSort(index, value) {
console.log(index, value);
},
//
search() {
const that = this
that.page = 1
that.list = []
this.getList(this.selected)
},
//
getList(status) {
// if (this.loadStatus === 'nomore') return;
uni.$u.http.get('/api/school.newactivity.order/order_list', {
params: {
// keywords: this.keywords,
page: this.page,
limit: this.limit,
status: status,
}
}).then(res => {
if (res.code == 1) {
this.count = res.data.count
this.list = [...this.list, ...res.data.list];
if (this.list.length >= res.data.count) {
this.loadStatus = 'nomore';
} else {
this.loadStatus = 'loading';
}
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
});
this.loadStatus = 'loading';
}
}).catch(error => {
console.error('请求失败', error);
this.loadStatus = 'loading';
});
},
selectheader(status) {
const that = this;
that.selected = status;
console.log(status, '')
that.page = 1
that.list = []
that.getList(status)
},
headerSelected(status) {
return this.selected === status;
},
}
}
</script>
<style lang="scss">
<style lang="scss" scoped>
.box {
background: #f5f5f5;
.con-center {
width: 100%;
// margin-top: 25rpx;
// overflow: hidden;
.tabs {
background: #ffffff;
width: 750rpx;
display: flex;
overflow-x: auto;
// margin-top: 10rpx;
-webkit-overflow-scrolling: touch;
font-family: PingFang SC, PingFang SC;
.s-header {
display: flex;
justify-content: center;
align-items: center;
width: 140rpx;
height: 80rpx;
font-weight: 400;
font-size: 28rpx;
color: #9E9E9E;
line-height: 26rpx;
flex: 0 0 auto;
}
.s-header.selected {
width: 140rpx;
height: 80rpx;
background: #ffffff;
font-weight: 800;
font-size: 32rpx;
color: #323232;
line-height: 28rpx;
}
.lines{
padding-top: 16rpx;
width: 44rpx;
}
.lines.selected{
border-bottom: #323232 solid 8rpx;
}
}
.hdkuai{
background: #FFFFFF;
width: 690rpx;
height: 360rpx;
justify-content: space-around;
margin: 30rpx;
border-radius: 18rpx;
.text_h{
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 28rpx;
color: #9C9C9C;
line-height: 39rpx;
text-align: left;
font-style: normal;
text-transform: none;
}
.tut{
width: 130rpx;
height: 130rpx;
border-radius: 8rpx;
}
.foot_btn{
margin:0 30rpx;
justify-content: space-between;
font-size: 28rpx;
color: #323232;
font-weight: 400;
box-sizing: border-box;
.btn_xq{
width: 180rpx;
height: 70rpx;
line-height: 70rpx;
text-align: center;
background: linear-gradient( 270deg, #FBF66D 0%, #9CEAA2 100%);
border-radius: 276rpx 276rpx 276rpx 276rpx;
}
.btnhx{
width: 180rpx;
height: 70rpx;
line-height: 70rpx;
background: #323232;
text-align: center;
border-radius: 276rpx 276rpx 276rpx 276rpx;
border: 1rpx solid #000000;
color: #BBFC5B;
margin-right: 20rpx;
}
.u-count-down__text{
color: #FF4810 !important;
}
}
}
}
}
.w-100 {
width: 100%;
}
.flex {
display: flex;
}
.flex-start {
align-items: flex-start;
}
.justify-center {
justify-content: center;
}
.flex-between {
justify-content: space-between;
}
.align-items {
align-items: center;
}
.flex-column {
flex-flow: column;
}
.justify-start {
justify-content: start;
}
.line {
width: 630rpx;
height: 1rpx;
background: #F0F0F0;
border-radius: 0rpx 0rpx 0rpx 0rpx;
margin:0 30rpx;
}
.centerBox {
width: 690rpx;
.box-line {
width: 400rpx;
height: 1rpx;
background: #D9D9D9;
border-radius: 0rpx 0rpx 0rpx 0rpx;
margin-top: 24rpx;
}
.center {
margin: 32rpx 0 32rpx 0;
}
.rightBox {
margin-left: 32rpx;
width: 50%;
.line-row {
width: 382rpx;
height: 1rpx;
background: #D9D9D9;
box-shadow: 1rpx 1rpx 0rpx 0rpx rgba(102, 102, 102, 0.25);
margin: 14rpx 0 6rpx 0;
}
.name {
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 34rpx;
color: #343434;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
/* 设置行数 */
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
margin-bottom: 24rpx;
/* 防止单词被截断 */
}
.minge {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 24rpx;
color: #7A7A7A;
margin-bottom: 8rpx;
}
.money {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 24rpx;
color: #FF2323;
span {
font-weight: 500;
font-size: 24rpx;
color: #7A7A7A;
}
}
.Cancel {
width: 138rpx;
height: 48rpx;
border-radius: 12rpx 12rpx 12rpx 12rpx;
border: 2rpx solid #008CFF;
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 24rpx;
color: #008CFF;
line-height: 32rpx;
letter-spacing: 4px;
display: flex;
align-items: center;
justify-content: center;
align-self: flex-end;
}
.make {
width: 138rpx;
height: 48rpx;
background: #008CFF;
border-radius: 12rpx 12rpx 12rpx 12rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 24rpx;
color: #FFFFFF;
line-height: 32rpx;
letter-spacing: 4px;
display: flex;
align-items: center;
justify-content: center;
align-self: flex-end;
margin-left: 24rpx;
}
.QR {
width: 138rpx;
height: 48rpx;
background: #4974FF;
box-shadow: 2rpx 2rpx 0rpx 0rpx rgba(0, 0, 0, 0.4);
border-radius: 8rpx 8rpx 8rpx 8rpx;
font-weight: 400;
font-size: 26rpx;
color: #EAEAEA;
display: flex;
align-items: center;
justify-content: center;
align-self: flex-end;
margin-top: 50rpx;
}
}
}
.charge {
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 28rpx;
color: #FF2323;
line-height: 32rpx;
}
.search {
margin-top: 24rpx;
width: 690rpx;
height: 64rpx;
background: #FFFFFF;
box-shadow: 2rpx 2rpx 0rpx 0rpx rgba(0, 0, 0, 0.4);
border-radius: 8rpx 8rpx 8rpx 8rpx;
border: 2rpx solid #008CFF;
.dashed {
image {
width: 52rpx;
height: 52rpx;
}
}
.line-search {
width: 2rpx;
height: 42rpx;
background: #008CFF;
border-radius: 0rpx 0rpx 0rpx 0rpx;
}
.input {
// border: 4rpx solid #EAEAEA;
padding-left: 12rpx;
height: 100%;
width: 100%;
}
::v-deep .input-placeholder {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 32rpx;
color: #C0C0C0;
line-height: 32rpx;
text-align: left;
font-style: normal;
text-transform: none;
}
.searchBtn {
width: 128rpx;
height: 64rpx;
background: #008CFF;
border-radius: 5rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 32rpx;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
}
}
.popup {
.header {
margin-left: 24rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 42rpx;
color: #008CFF;
margin-top: 34rpx;
width: 690rpx;
}
.line-row {
width: 690rpx;
height: 1rpx;
background: #D9D9D9;
margin: 11rpx 0 31rpx 0;
}
.pop-center {
margin-top: 50rpx;
align-items: center;
width: 650rpx;
.left {
image {
border-radius: 12rpx;
}
}
.right {
margin-left: 30rpx;
.title {
width: 340rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 34rpx;
color: #343434;
}
}
}
.line-short {
width: 400rpx;
height: 1rpx;
background: #D9D9D9;
margin: 24rpx 0;
}
.popList {
justify-content: space-between;
width: 600rpx;
margin-top: 32rpx;
.hei {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 26rpx;
color: #343434;
}
}
.pop-btn {
width: 690rpx;
margin-top: 62rpx;
justify-content: space-around;
.Cancel {
width: 306rpx;
height: 80rpx;
border-radius: 401rpx 401rpx 401rpx 401rpx;
border: 2rpx solid #008CFF;
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 34rpx;
color: #008CFF;
}
.Confirm {
width: 306rpx;
height: 80rpx;
background: #008CFF;
border-radius: 401rpx 401rpx 401rpx 401rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 34rpx;
color: #FFFFFF;
}
}
}
.hui {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 24rpx;
color: #7A7A7A;
}
.white-space {
overflow: hidden;
/* 确保超出容器的文本被隐藏 */
white-space: nowrap;
/* 确保文本在一行内显示 */
text-overflow: ellipsis;
/* 使用省略号表示被截断的文本 */
}
</style>
<style lang="scss" >
.foot_btn{
// #ifdef MP-WEIXIN
.u-count-down__text{
color: #FF4810 !important;
}
// #endif
}
</style>

File diff suppressed because it is too large Load Diff

1458
packageA/my/pendinPay.vue Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,13 @@
"navigationStyle": "custom" //
}
},
{
"path": "pages/my/classCheck",
"style": {
"navigationBarTitleText": "活动核销" ,//
"navigationStyle": "custom" //
}
},
{
"path": "pages/center/list",
"style": {
@ -47,7 +54,7 @@
{
"path": "pages/center/detail",
"style": {
"navigationBarTitleText": "课程详情",
"navigationBarTitleText": "",
"navigationStyle": "custom" //
}
},
@ -79,7 +86,7 @@
{
"path": "pages/center/applyDetail",
"style": {
"navigationBarTitleText": "预约订单详情"
"navigationBarTitleText": "支付参加"
}
},
{
@ -188,6 +195,25 @@
"navigationBarTitleText": "我发布的活动"
}
},
{
"path": "my/exercise",
"style": {
"navigationBarTitleText": "我参与的活动"
}
},
{
"path": "my/pendinPay",
"style": {
"navigationBarTitleText": "待支付订单"
}
},
{
"path": "my/pendinPayDetail",
"style": {
"navigationBarTitleText": "待核销订单"
}
},
{
"path": "my/cancel",
"style": {
@ -305,8 +331,8 @@
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
"navigationBarBackgroundColor": "#FFFFFF",
"backgroundColor": "#F5F5F5"
},
"tabBar": {
"custom": true,

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
<template>
<view class="detail_all">
<view class="nav">
<u-navbar :is-back="true" leftIconColor="#FFFFFF" :autoBack='true' title="" :bgColor="background"
<u-navbar :is-back="true" leftIconColor="#FFFFFF" :autoBack="true" :bgColor="background"
:titleStyle='titleStyle'> </u-navbar>
</view>
<view class="box flex justify-start flex-column align-items" :class="overlay ? 'no-scroll' : ''">
@ -35,9 +35,9 @@
<image :src="detail.user.avatar" mode="" class="icon-size" style="width: 36rpx;height: 36rpx;"></image>
<span style="color: #9C9C9C ;width: 32%;">{{ detail.user.nickname }}</span>
<span class="flex justify-center align-items xieyi">
<image src="/static/detail/baohu.png" mode="" style="margin-right: 0;" class="icon-size"></image>
{{ detail.refund_info.title }}
<image src="/static/detail/zidong.png" mode="" style="margin-right: 0;" class="icon-size"></image>
<image src="/static/detail/baohu.png" mode="" style="width: 28rpx;height: 28rpx;margin-right: 0;" ></image>
<span class="white-space" style="width: 90rpx;text-align: center;">{{ detail.refund_info.title }}</span>
<image src="/static/detail/zidong.png" mode="" style="width: 20rpx;height: 20rpx;margin-right: 0;" ></image>
</span>
</span>
@ -117,7 +117,7 @@
</view>
<view class="footer-right flex justify-center align-items">
<span v-if="type == 0 && detail.feel == 0" @click="sign()"> 支付并参加 </span>
<span v-if="type == 0 && detail.feel == 1" @click="sign()"> 支付并参加 </span>
<span v-if="type == 0 && detail.feel == 1" @click="sign()"> 免费参加 </span>
<span v-if="type == 1 && detail.feel == 0" @click="buy()"> 立即支付 </span>
<span v-if="type == 1 && detail.feel == 1" @click="buy()"> 确认报名 </span>
<span v-if="type == 2" @click="open()"> 我要预约 </span>
@ -538,11 +538,13 @@
// 0 1 2 3
sign() {
this.buyShow = true
this.type = 3
// uni.navigateTo({
// url: '/pages/CashierDesk/CashierDesk?id=' + this.id
// })
// this.buyShow = true
// this.type = 3;
uni.navigateTo({
url: '/pages/center/applyDetail?id=' + this.id
})
},
buy() {
@ -788,10 +790,11 @@
moveScroll() {},
//
getMoney() {
uni.$u.http.post('/api/school/order/confirm', {
classes_lib_id: this.id,
uni.$u.http.post('/api/school.newactivity.order/confirm', {
activity_id: this.id,
order_no: this.order_no,
is_compute: 1
is_compute: 1,
num:1
}).then(res => {
if (res.code == 1) {
this.PayPirce = res.data.order_data.totalprice
@ -812,7 +815,7 @@
},
//
create(order_no, PayPirce) {
uni.$u.http.post('/api/school/order/create', {
uni.$u.http.post('/api/school.newactivity.order/create', {
order_no: order_no,
}).then(res => {
if (res.code == 1) {
@ -851,7 +854,7 @@
pament() {
let that = this
that.uloadingShow = false
uni.$u.http.post('/api/school/pay/payment', {
uni.$u.http.post('/api/school.newactivity.pay/payment', {
type: 'wechat',
order_no: that.order_no,
platform: 'miniapp'
@ -1049,8 +1052,8 @@
}
.xieyi{
background-color:#BBFC5B;
width: 30%;
height: 40rpx;
width: 156rpx;
height: 48rpx;
border-radius: 8rpx;
}
}
@ -1081,24 +1084,6 @@
margin: 0 22rpx 0 4rpx;
}
}
.value_slide{
width: 50%;
::v-deep .uni-slider-handle-wrapper{
height: 10rpx;
}
::v-deep .uni-slider-handle{
background: url('@/static/detail/qiu.png') !important;
border-radius: 0;
background-size: 52rpx 52rpx !important;
}
::v-deep .uni-slider-value{
color: #323232;
&::after{
content: '%';
}
}
}
}
.third {
@ -1576,3 +1561,48 @@
}
}
</style>
<style lang="scss">
.value_slide{
width: 50%;
::v-deep .uni-slider-handle-wrapper{
height: 10rpx;
}
::v-deep .uni-slider-handle{
background: url('@/static/detail/qiu.png') !important;
border-radius: 0;
background-size: 36rpx 36rpx !important;
width: 36rpx;
height: 36rpx;
top: 14rpx;
margin-left: -18rpx !important;
}
::v-deep .uni-slider-value{
color: #323232;
&::after{
content: '%';
}
}
// #ifdef MP-WEIXIN
.wx-slider-handle-wrapper{
height: 8rpx;
}
.wx-slider-handle{
background: url('@/static/detail/qiu.png') !important;
border-radius: 0;
background-size: 28rpx 28rpx !important;
width: 28rpx;
height: 28rpx;
top: 18rpx;
margin-left: -14rpx !important;
}
.wx-slider-value{
display: flex;
width: 30rpx;
color: #323232;
&::after{
content: '%';
}
}
// #endif
}
</style>

1578
pages/center/detailSys.vue Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -142,9 +142,9 @@
<script>
// import FilterMenu from "./myFilterMenu/index.vue"
// import {menuOption} from "@/common/menuOptions.js"
import {
updateStaticData
} from '@/common/data.js';
// import {
// updateStaticData
// } from '@/common/data.js';
export default {
// components: {
// FilterMenu

View File

@ -183,6 +183,7 @@
</view>
</u-popup>
<!-- 购买弹窗 -->
<u-popup :show="buyShow" mode="bottom" :round="10" :zIndex="99999" :custom-style="popupStyle" @close="buyClose"
@open="buyOpen">
@ -208,6 +209,7 @@
</view>
</view>
</u-popup>
</view>
</template>

View File

@ -43,11 +43,11 @@
v-for="(tab, index) in list"
:key="index"
:class="['tab-item', { active: current === index }]"
@click="handleClick(index)"
@click="handleClick(index,tab.id)"
>
<image
v-if="index != 0"
:src="tab.url"
v-if="index != 0 && tab.image"
:src="tab.image"
mode=""
class="imgs_bq"
></image>
@ -67,6 +67,8 @@
:key="index"
@click="detail(item.id)"
>
<view
class="flex"
style="margin-top: 24rpx"
@ -80,13 +82,14 @@
<image :src="item.user.avatar" style="width: 36rpx;height: 36rpx;"></image>
<span style="color: #9C9C9C;margin-left: 10rpx;width: 35%;">{{ item.user.nickname }}</span>
<view class="white-space" style="width: 60%;">
<span style="color:#0CA013;margin-left: 20rpx;" v-for="item in item.classes_cate">#{{ item }}</span>
<span style="color:#0CA013;margin-left: 20rpx;" v-for="items_t in item.classes_cate">#{{ items_t }}</span>
</view>
</view>
<view class="flex flex-column" style="margin-top: 20rpx;">
<view class="time flex align-items white-space">
<span class="time_tex" v-if="item.status == 2">{{ '报名中' }}</span>
<span class="time_tex time_texs" v-if="item.status == 4">{{ '进行中' }}</span>
<span style="margin:0 8rpx;">{{ dateWeeks(item.sign_start_time) }}</span>|
<span class="white-space" style="margin-left: 8rpx;width: 260rpx;">{{ item.address_detail }}</span>
</view>
@ -94,13 +97,14 @@
</view>
<view class="flex align-items justify-center" style="margin-top: 20rpx;" >
<image class="imgs_con" v-for="(item,index) in item.images.slice(0,3)" :key="index" :src="item"></image>
<image class="imgs_con" v-for="(items_img,index) in item.images.slice(0,3)" :key="index" :src="items_img"></image>
</view>
</view>
</view>
<view class="bottom flex align-items">
<view class="flex align-items toptext">
<span class="flex align-items">
<span class="flex align-items" style="width: 200rpx">
<u-avatar-group
:urls="item.join_info.users"
keyName="avatar"
@ -109,9 +113,9 @@
gap="0.4"
></u-avatar-group>
<image
v-if="item.join_info.users.length > 0"
src="/static/index/dian.png"
style="width: 60rpx;height: 60rpx;margin-left:-20rpx;"
:class="item.join_info.users.length > 0 ? '' :'smalld'"
style="width: 60rpx;height: 60rpx;margin-left:-20rpx;z-index: 1;"
></image>
</span>
<view class="number flex align-items" >
@ -126,6 +130,8 @@
</span>
</view>
</view>
</view>
</view>
@ -136,16 +142,33 @@
<view class="popup_bq">
<img src="https://naweigetetest2.hschool.com.cn/dyqc/biaoqian.png" alt="" />
<view class="flex flex-column w-100 bqlist">
<span>我的标签</span>
<view class="flex align-items bqpiece">
<span>篮球</span>
<u-icon name="close" color="#babdc7"></u-icon>
<view class="flex align-items allmybqs">
<view class="flex align-items bqpiece" v-for="(item_bq,index) in list" :key="index">
<span>
<image
v-if="item_bq.name != '全部'"
:src="item_bq.image"
style="width: 48rpx;height: 48rpx;margin-right:10rpx;"
></image>
{{ item_bq.name }}
</span>
<u-icon v-if="index != 0" name="close" color="#babdc7" @click="removebq(index)"></u-icon>
</view>
</view>
<span style="margin-top: 50rpx;">全部标签</span>
<view class="flex align-items allbqs">
<view class="flex align-items bqpiece" v-for="(item,index) in bqList" :key="index">
<span>{{ item.name }}</span>
<u-icon name="plus" color="#babdc7"></u-icon>
<span>
<image
:src="item.image"
style="width: 48rpx;height: 48rpx;margin-right:10rpx;"
></image>
{{ item.name }}
</span>
<u-icon name="plus" color="#babdc7" @click="addbq(item)"></u-icon>
</view>
</view>
</view>
@ -154,8 +177,10 @@
</u-popup>
<u-loadmore style="margin-bottom: 120rpx;" :status="loadStatus" />
<view class="bottom_box flex justify-center align-items" style="height: 560rpx;" v-if="hotList.length == 0">
暂无数据
</view>
<u-loadmore v-else style="margin-bottom: 60rpx;" :status="loadStatus" />
</view>
<tab-bar :tabBarShow="0"></tab-bar>
</view>
@ -174,6 +199,7 @@ export default {
return {
showPopbq:false,//
bqList:[],//
cate_ids:'',//id
loadStatus:'nomore',
swiperList: [],
teacherList: [],
@ -193,28 +219,10 @@ export default {
list: [
{
name: "全部",
},
{
name: "篮球",
url: "/static/index/lanqiu.png",
},
{
name: "徒步",
url: "/static/index/tubu.png",
},
{
name: "羽毛球",
url: "/static/index/tubu.png",
},
{
name: "乒乓球",
url: "/static/index/tubu.png",
},
id: 0
}
],
show: false,
// backgroundImage: 'https://testy.hschool.com.cn/uploads/20250219/4554df3bea7bd9cdbd75462ceedb8ea7.png',
// backgroundImage: `url(@/static/index/beijing.png)`,
// groupImage: 'https://testy.hschool.com.cn/uploads/20250219/5b09b1878ab6d7774540f0d1a8c6675a.png'
show: false
};
},
onLoad() {
@ -228,6 +236,7 @@ export default {
this.resetLists();
this.getHotList();
this.getBqList();
this.getitembq();
},
beforeDestroy() {
this.autoplay = false;
@ -238,6 +247,14 @@ export default {
// }
},
methods: {
//
getitembq(){
if (uni.getStorageSync("bqlist") != "") {
this.list = JSON.parse(uni.getStorageSync("bqlist"));
}else{
uni.setStorageSync('bqlist',JSON.stringify(this.list))
}
},
dateWeeks(e){
return dateWeek(e);
},
@ -273,19 +290,9 @@ export default {
this.loadStatus = "loading";
},
//
handleClick(index) {
handleClick(index,val) {
this.current = index;
if (index == 0) {
this.classes_type = "14,15,16,17";
} else if (index == 1) {
this.classes_type = "15";
} else if (index == 2) {
this.classes_type = "16";
} else if (index == 3) {
this.classes_type = "17";
} else if (index == 3) {
this.classes_type = "14";
}
this.cate_ids = val;
this.hotList = [];
this.getHotList();
},
@ -359,17 +366,53 @@ export default {
});
});
},
//
addbq(val){
let arrbql = uni.getStorageSync("bqlist");
let arrbq = JSON.parse(arrbql);
let isbq = true;
for (let i = 0; i < arrbq.length; i++) {
if (arrbq[i].id == val.id) {
uni.showToast({
title: "已添加该标签",
icon: "none",
duration: 2000,
});
return isbq = false;
}
}
if (this.list.length < 9) {
if (isbq) {
this.list.push(val);
uni.setStorageSync('bqlist',JSON.stringify(this.list))
}
}else{
uni.showToast({
title: "最多添加9个标签",
icon: "none",
duration: 2000,
});
}
},
//
removebq(i){
this.list.splice(i,1);
uni.setStorageSync('bqlist',JSON.stringify(this.list))
},
//
getHotList() {
let words = this.keywords
let cate_ids = this.cate_ids
uni.$u.http
.get("/api/school.new_activity/activity_list", {
params: {
keywords:words,
cate_ids:cate_ids,
page: 1,
limit: 6,
order: "normal",
status: "2,3,4" //5
status: "2,3,4",//5
auth_status: 1 //
},
})
.then((res) => {
@ -452,7 +495,7 @@ export default {
margin-top: 30rpx;
position: relative;
display: flex;
justify-content: center;
justify-content: flex-start;
align-items: center;
.allbq {
@ -568,7 +611,7 @@ export default {
.searchBtn{
position:absolute;
width: 133rpx;
height: 60rpx;
height: 100%;
background: #323232 ;
border-radius: 30rpx;
font-family: PingFang SC, PingFang SC;
@ -585,7 +628,7 @@ export default {
.hot {
// margin-top: 30rpx;
margin-bottom: 20rpx;
margin-bottom: 70rpx;
}
}
@ -693,6 +736,10 @@ export default {
line-height: 42rpx;
text-align: center;
}
.time_texs{
background: #FF4810;
color: #ffffff;
}
}
.imgs_con{
@ -702,7 +749,7 @@ export default {
&:first-child{
border-radius: 18rpx 0 0 18rpx;
}
&:last-child{
&:nth-child(3){
border-radius: 0 18rpx 18rpx 0;
}
}
@ -714,6 +761,9 @@ export default {
width: 626rpx;
.toptext{
width: 480rpx;
.smalld{
margin-left: 0 !important;
}
}
.number {
font-family: Source Han Sans CN, Source Han Sans CN;
@ -783,65 +833,7 @@ export default {
margin: 32rpx;
}
.wq-right {
margin-top: 32rpx;
.title {
width: 354rpx;
height: 54rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: bold;
font-size: 36rpx;
color: #000000;
line-height: 42rpx;
text-align: left;
font-style: normal;
text-transform: none;
}
.hot {
width: 230rpx;
height: 48rpx;
background: #fff1ed;
border-radius: 4rpx 4rpx 4rpx 4rpx;
margin-top: 8rpx;
image {
margin: 0 8rpx 0 16rpx;
}
span {
min-width: 155rpx;
height: 36rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 24rpx;
color: #ff4810;
}
}
.length {
width: 354rpx;
height: 40rpx;
margin-top: 24rpx;
image {
margin-right: 18rpx;
}
span {
width: 318rpx;
height: 40rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 26rpx;
color: #a4a4a4;
text-align: left;
font-style: normal;
text-transform: none;
}
}
}
}
}
@ -905,18 +897,19 @@ export default {
width: 180rpx;
height: 70rpx;
background: url(@/static/index/shangche.png);
background-size: 168rpx 70rpx ;
background-size: 162rpx 70rpx;
background-repeat: no-repeat;
font-family: 'YouSheBiaoTiHei';
font-weight: 400;
font-size: 42rpx;
color: #BBFC5B;
}
.part1{
width: 180rpx;
height: 70rpx;
background: url(@/static/index/shangchew.png);
background-size: 168rpx 70rpx ;
background-size: 162rpx 70rpx;
background-repeat: no-repeat;
font-family: 'YouSheBiaoTiHei';
font-weight: 400;
font-size: 42rpx;
@ -944,10 +937,14 @@ export default {
margin-top: 160rpx;
z-index: 1;
margin-left: 80rpx;
.allmybqs{
flex-wrap: wrap;
width: 720rpx;
}
.allbqs{
overflow: scroll;
flex-wrap: wrap;
height: 850rpx;
height: 620rpx;
width: 720rpx;
}
.bqpiece{
@ -964,6 +961,8 @@ export default {
font-weight: 400;
font-size: 26rpx;
color: #323232;
display: flex;
align-items: center;
}
}
}

621
pages/my/classCheck.vue Normal file
View File

@ -0,0 +1,621 @@
<template>
<view class="box flex align-items justify-center flex-column">
<view class="header flex align-items justify-center flex-column">
<view class="search flex align-items" style="width:690rpx;">
<span class="dashed">
<image src="../../static/center/search.png" mode=""></image>
</span>
<span class="line-search"></span>
<input type="text" placeholder="搜索您的审核课程" v-model="keywords" class="input" placeholder-class="plasty" />
<span class="searchBtn" @click.stop="search()">搜索</span>
</view>
</view>
<view class="center">
<view class="center-box flex flex-column" v-for="(item,index) in list" :key="index">
<span class="title white-space w-100">{{item.detail.title}}</span>
<view class="flex align-items w-100" style="margin-top: 29rpx;">
<view class="left">
<image :src="item.detail.headimage" mode="" style="width: 200rpx;height: 140rpx;"></image>
</view>
<view class="right flex flex-column w-100">
<span class="yyTime hui flex align-items white-space">
机构:
<span class="hui white-space" style="font-weight: 800;">{{shopName}}</span>
</span>
<span class="yyRen hui white-space">报名人信息:{{item.user.realname ||item.user.nickname}}</span>
<span class="yyTime hui flex align-items white-space">
课时预约:
<span class="hui white-space" style="font-weight: 800;">{{item.name}}</span>
</span>
<!-- <span class="tel hui white-space flex align-items" @click.stop="handlePhone(detail.tel)">{{item.user.mobile}}
<image src="../../static/tel.png" mode="" style="width: 36rpx;height: 36rpx;"></image>
</span> -->
<span class="line-row"></span>
</view>
</view>
<view class="flex align-items hui w-100 space-between" style="margin-top: 24rpx;">
<span>课时人数:</span>
<span style="color: #FF6D6D;">{{item.sign_num}}/{{item.limit_num}}</span>
</view>
<view class="flex align-items hui w-100 space-between" style="margin-top: 24rpx;" @click.stop="handlePhone(item.user.mobile)">
<span>联系方式:</span>
<span class="flex text-blue">{{item.user.mobile}}
<image src="../../static/tel.png" mode="" style="width: 36rpx;height: 36rpx;"></image>
</span>
</view>
<view class="flex m-top-8 align-items hui w-100 space-between">
<span>订单编号:</span>
<span>{{item.order_no}}</span>
</view>
<view class="flex m-top-8 align-items hui w-100 space-between">
<span>预约时间:</span>
<span>{{item.reservation_time_text}}</span>
</view>
<view class="flex m-top-8 align-items hui w-100 space-between">
<span>开始时间:</span>
<span>{{item.start_time_text}}</span>
</view>
<view class="flex m-top-8 align-items hui w-100 space-between">
<span>结束时间:</span>
<span>{{item.end_time_text}}</span>
</view>
<view class="btn-box flex w-100">
<span class="Refuse flex justify-center align-items" @click="Refuse(item.order_no)"> 拒绝 </span>
<span class="disable flex justify-center align-items"
v-if=" item.limit_num != 0 && item.limit_num == item.sign_num">通过</span>
<span class="pass flex justify-center align-items" v-else @click="Pass(item.order_no)">通过</span>
</view>
</view>
</view>
<!-- 拒绝原因 -->
<u-popup :show="show" mode="bottom" :round="10" :zIndex="999999" :custom-style="popupStyle" @close="close"
@open="open">
<view class="popupBox flex justify-start align-items flex-column">
<view class="pop-header flex align-items" style="justify-content: space-between;">
<span class="selectTime">拒绝原因</span>
</view>
<!-- <span class="line"></span> -->
<view class="times flex align-items justify-center" style="width: 690rpx;margin-top: 43rpx;">
<u-radio-group v-model="radiovalue1" placement="column" @change="groupChange">
<u-radio :customStyle="{marginBottom: '8px'}" v-for="(item, index) in radiolist1" :key="index"
:label="item.name" :name="item.name" @change="radioChange">
</u-radio>
</u-radio-group>
</view>
<view class="" style="width: 690rpx;margin-bottom: 65rpx;">
<u--textarea v-model="textTarea" placeholder="请输入内容" count height="100"
maxlength="50"></u--textarea>
</view>
<view class="pos flex justify-center align-items">
<span class="flex justify-center align-items" @click="confirm()">确认拒绝</span>
</view>
</view>
</u-popup>
</view>
</template>
<script>
export default {
data() {
return {
page: 1,
limit: 10,
status: '-1',
keywords: '',
list: [],
textTarea: '',
selected: null,
show: false,
radiolist1: [{
name: '课程人数已满',
disabled: false
},
{
name: '不符合上课资格',
disabled: false
},
{
name: '不满足开课标准',
disabled: false
}, {
name: '其他',
disabled: false
}
],
// u-radio-groupv-modelradioname
radiovalue1: '苹果',
popupStyle: {
// bottom: '166rpx',
width: '100%',
margin: '0 auto', //
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
},
order_no: '',
shop_id:'',
shopName:'',
};
},
onLoad() {
this.shop_id = uni.getStorageSync('shop_id')
this.shopName = uni.getStorageSync('apply_info').name
this.getList()
},
methods: {
//
Refuse(order_no) {
this.order_no = order_no
this.show = true
},
open() {
},
//
search(){
this.getList()
},
close() {
this.selected = null
this.show = false
},
groupChange(n) {
console.log('groupChange', n);
},
radioChange(n) {
console.log('radioChange', n);
},
handlePhone(tel) {
uni.makePhoneCall({
phoneNumber: tel
})
},
getList() {
uni.$u.http.get('/api/school/worker/hour_order/order_list', {
params: {
page: this.page,
limit: this.limit,
status: this.status,
keywords:this.keywords,
// shop_id:this.shop_id
}
}).then(res => {
if (res.code == 1) {
this.list = res.data.list
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
});
}
}).catch(error => {
uni.showToast({
title: '请求失败,请稍后再试',
icon: 'none',
duration: 2000
});
});
},
//
Pass(order_no) {
uni.$u.http.post('/api/school/worker/hour_order/examine', {
order_no: order_no,
auth_status: 1,
reason: ""
}).then(res => {
if (res.code == 1) {
uni.showToast({
title: '通过',
icon: 'none',
duration: 2000
});
this.show = false
this.getList()
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
});
}
}).catch(error => {
uni.showToast({
title: '请求失败,请稍后再试',
icon: 'none',
duration: 2000
});
});
},
//
confirm() {
uni.$u.http.post('/api/school/worker/hour_order/examine', {
order_no: this.order_no,
auth_status: 2,
reason: this.textTarea
}).then(res => {
if (res.code == 1) {
uni.showToast({
title: '拒绝已通过',
icon: 'none',
duration: 2000
});
this.show = false
this.getList()
} else {
uni.showToast({
title: res.msg,
icon: 'none',
duration: 2000
});
}
}).catch(error => {
uni.showToast({
title: '请求失败,请稍后再试',
icon: 'none',
duration: 2000
});
});
},
}
}
</script>
<style lang="scss" scoped>
.w-100 {
width: 100%;
}
.w-400 {
width: 400rpx;
}
.flex {
display: flex;
}
.justify-center {
justify-content: center;
}
.space-between {
justify-content: space-between;
}
.align-items {
align-items: center;
}
.flex-column {
flex-flow: column;
}
.justify-start {
justify-content: start;
}
.mar-top-30 {
margin-top: 30rpx;
}
.w-100 {
width: 100%;
}
.m-top-8 {
margin-top: 8rpx;
}
.hui {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 24rpx;
color: #7A7A7A;
}
.white-space {
overflow: hidden;
/* 确保超出容器的文本被隐藏 */
white-space: nowrap;
/* 确保文本在一行内显示 */
text-overflow: ellipsis;
}
.box {
height: 100vh;
background-color: #F1F2F8;
.header {
width: 750rpx;
height: 110rpx;
background-color: white;
}
}
.search {
// margin-top: 27rpx;
width: 690rpx;
height: 64rpx;
background: #FFFFFF;
box-shadow: 2rpx 2rpx 0rpx 0rpx rgba(0, 0, 0, 0.4);
border-radius: 8rpx 8rpx 8rpx 8rpx;
border: 2rpx solid #008CFF;
.dashed {
image {
width: 52rpx;
height: 52rpx;
}
}
.line-search {
width: 2rpx;
height: 42rpx;
background: #008CFF;
border-radius: 0rpx 0rpx 0rpx 0rpx;
}
.input {
// border: 4rpx solid #EAEAEA;
padding-left: 12rpx;
height: 100%;
width: 100%;
}
::v-deep .input-placeholder {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 32rpx;
color: #C0C0C0;
line-height: 32rpx;
text-align: left;
font-style: normal;
text-transform: none;
}
.searchBtn{
width: 128rpx;
height: 64rpx;
background: #008CFF;
border-radius: 5rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 32rpx;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
}
}
.hui {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 24rpx;
color: #7A7A7A;
}
.center {
width: 690rpx;
background-color: #F1F2F8;
margin-top: 14rpx;
.center-box {
align-items: self-start;
padding: 30rpx;
background: #FFFFFF;
border-radius: 20rpx 20rpx 20rpx 20rpx;
margin-top: 24rpx;
.title {
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 32rpx;
color: #343434;
}
.right {
width: 414rpx;
margin-left: 16rpx;
.yyRen {
margin: 8rpx 0;
}
.line-row {
margin-top: 27rpx;
width: 414rpx;
height: 1rpx;
background: #D9D9D9;
border-radius: 0rpx 0rpx 0rpx 0rpx;
}
}
}
}
.btn-box {
justify-content: flex-end;
align-items: center;
margin-top: 40rpx;
span {
width: 100rpx;
height: 48rpx;
border-radius: 12rpx 12rpx 12rpx 12rpx;
}
.Refuse {
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 24rpx;
color: #008CFF;
border: 2rpx solid #008CFF;
margin-right: 24rpx;
}
.disable {
background: #D9D9D9;
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 24rpx;
color: #FFFFFF;
}
.pass {
background: #008CFF;
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 24rpx;
color: #FFFFFF;
}
}
.popupBox {
// height: 572rpx;
width: 750rpx;
position: relative;
.pos {
position: absolute;
bottom: 0;
width: 750rpx;
height: 122rpx;
background: #FFFFFF;
box-shadow: 0rpx -6rpx 12rpx 0rpx rgba(111, 190, 255, 0.1);
position: fixed;
bottom: 0;
span {
width: 642rpx;
height: 80rpx;
background: #008CFF;
border-radius: 401rpx 401rpx 401rpx 401rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 34rpx;
color: #FFFFFF;
line-height: 32rpx;
letter-spacing: 14px;
}
}
.pop-header {
width: 93%;
padding-top: 32rpx;
padding-bottom: 17rpx;
border-bottom: 2rpx solid #D9D9D9;
.selectTime {
width: 168rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 42rpx;
color: #008CFF;
}
.quxiao {
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 20rpx;
color: #343434;
}
}
.popup {
display: flex;
align-items: self-start;
justify-content: center;
padding-top: 21rpx;
.popur-right {
align-items: self-start;
margin-left: 24rpx;
width: 418rpx;
.name {
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 28rpx;
color: #343434;
}
.address {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 24rpx;
color: #7A7A7A;
line-height: 32rpx;
margin: 16rpx 0 12rpx 0;
overflow: hidden;
/* 确保超出容器的文本被隐藏 */
white-space: nowrap;
/* 确保文本在一行内显示 */
text-overflow: ellipsis;
/* 使用省略号表示被截断的文本 */
width: 100%;
}
.date {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 24rpx;
color: #7A7A7A;
line-height: 32rpx;
}
.time {
margin: 12rpx 0 73rpx 0;
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 24rpx;
color: #7A7A7A;
line-height: 32rpx;
}
.line-row {
width: 418rpx;
height: 1rpx;
background: #008CFF;
border-radius: 0rpx 0rpx 0rpx 0rpx;
}
.price {
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-size: 24rpx;
color: #7A7A7A;
line-height: 32rpx;
margin-top: 23rpx;
align-self: flex-end;
span {
font-family: PingFang SC, PingFang SC;
font-weight: 800;
font-size: 36rpx;
color: #FF2323;
line-height: 32rpx;
}
}
}
}
.line {
width: 642rpx;
height: 1rpx;
background: #D9D9D9;
box-shadow: 1rpx 1rpx 0rpx 0rpx rgba(102, 102, 102, 0.25);
border-radius: 0rpx 0rpx 0rpx 0rpx;
}
}
</style>

View File

@ -20,18 +20,18 @@
</view>
<view class="top_box flex">
<view class="flex align-items justify-start">
<view class="flex align-items justify-start" @click="toMycy">
<image src="/static/my/wcyd.png" mode=""></image>
<span class="flex flex-column align-items">
<p class="p1">我参与的</p>
<p class="p2">0个活动</p>
<span class="p1">我参与的</span>
<span class="p2">{{actives}}个活动</span>
</span>
</view>
<view class="top_box_right flex align-items justify-start" @click="toMyfb">
<image src="/static/my/wdfb.png" mode=""></image>
<span class="flex flex-column align-items justify-start">
<p class="p1">我发布的</p>
<p class="p2">10个活动</p>
<span class="p1">我发布的</span>
<span class="p2">{{pushActives}}个活动</span>
</span>
</view>
</view>
@ -80,14 +80,14 @@
<image :src="item.user.avatar" style="width: 36rpx;height: 36rpx;"></image>
<span style="color: #9C9C9C;margin-left: 10rpx;width: 35%;">{{ item.user.nickname }}</span>
<view class="white-space" style="width: 60%;">
<span style="color:#0CA013;margin-left: 20rpx;" v-for="item in item.classes_cate">#{{ item }}</span>
<span style="color:#0CA013;margin-left: 20rpx;" v-for="items_t in item.classes_cate">#{{ items_t }}</span>
</view>
</span>
<view class="flex flex-column" style="margin-top: 20rpx;">
<view class="time flex align-items white-space">
<span class="time_tex">{{ '报名中' }}</span>
<span class="time_tex" v-if="item.status == 2">{{ '报名中' }}</span>
<span style="margin:0 8rpx;"
>{{ dateWeeks(item.sign_start_time) }}
</span>|<span class="white-space"
@ -99,7 +99,7 @@
</view>
<view class="flex align-items" style="margin-top: 20rpx;">
<image class="imgs_con" v-for="(item,index) in item.images.slice(0,3)" :key="index" :src="item"></image>
<image class="imgs_con" v-for="(items_img,index) in item.images.slice(0,3)" :key="index" :src="items_img"></image>
</view>
</view>
</view>
@ -108,7 +108,7 @@
<span class="flex align-items" style="width: 200rpx">
<u-avatar-group
:urls="item.join_info.users"
keyName="head_image"
keyName="avatar"
size="30"
maxCount="5"
gap="0.4"
@ -116,7 +116,7 @@
<image
v-if="item.join_info.users.length > 0"
src="/static/index/dian.png"
style="width: 60rpx;height: 60rpx;margin-left:-20rpx;"
style="width: 60rpx;height: 60rpx;margin-left:-20rpx;z-index: 1;"
></image>
</span>
<view class="number flex align-items">
@ -161,8 +161,6 @@
<text id="txt2">为您授权登陆授权成功后可参加多种户外活动</text>
<button class="texbut" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
<u-icon
style="height: 100%;"
class="justify-center"
label="授权登录"
labelColor="#fff"
size="28"
@ -195,6 +193,8 @@
hotList: [],
showPopup: false,
userName: '请登录',
actives: 0,
pushActives: 0,
show: false,
avatar: '',
agree: false,
@ -377,6 +377,7 @@
this.token = uni.getStorageSync('token')
this.unread_number = this.number
const userinfo = uni.getStorageSync('userInfo')
const activityInfo = uni.getStorageSync('activityInfo')
const niName = uni.getStorageSync('niName')
if (niName) {
console.log(1,'niName',niName)
@ -385,6 +386,8 @@
console.log(2)
this.userName = userinfo.name
}
this.actives = activityInfo.join_num;
this.pushActives = activityInfo.release_num;
this.avatar = uni.getStorageSync('userInfo').avatar || '../../static/moren.png';
let openidInfo = uni.getStorageSync('openidInfo')
let _this = this;
@ -424,7 +427,8 @@
page: 1,
limit: 1,
order: "normal",
status: "2,3,4" //5
status: "2,3,4", //5
auth_status: 1,
},
})
.then((res) => {
@ -526,6 +530,16 @@
})
})
},
toMycy(){
// if (!this.token) {
// this.miniLogin()
// this.showPopup = true
// } else {
uni.navigateTo({
url: "/packageA/my/exercise",
})
// }
},
toMyfb(){
// if (!this.token) {
// this.miniLogin()
@ -536,13 +550,7 @@
})
// }
},
//
showModel() {
uni.showToast({
title: '开发中,暂未开放',
icon: 'none'
});
},
// 退
out() {
@ -776,14 +784,20 @@
uni.$u.http.get('/api/user/index', {}).then(res => {
if (res.code == 1) {
uni.setStorageSync('userInfo', res.data.user_info)
uni.setStorageSync('settleInfo', res.data.settle_info)
uni.setStorageSync('activityInfo', res.data.activity_info)
uni.showToast({
title: '登陆成功',
icon: 'none',
duration: 2000
})
this.showPopup = false
this.userName = res.data.user_info.nickname
this.avatar = res.data.user_info.avatar
this.userName = res.data.user_info.nickname;
this.avatar = res.data.user_info.avatar;
this.actives = res.data.activity_info.join_num;
this.pushActives = res.data.activity_info.release_num;
uni.setStorageSync("niName", res.data.user_info.nickname)
this.userinfo = res.data.user_info
this.token = res.data.user_info.token
@ -915,7 +929,7 @@
.box {
border-radius: 8rpx 8rpx 8rpx 8rpx;
// padding-top: env(safe-area-inset-top);
padding-top: 100rpx;
padding-top: 170rpx;
/* 顶部安全距离 */
.backImg {
@ -1017,7 +1031,7 @@
background: #FFFFFF;
border-radius: 18rpx;
width: 330rpx;
height: 152rpx;
padding: 20rpx 0;
image{
width: 70rpx;
height: 70rpx;
@ -1026,16 +1040,15 @@
span{
margin-left: 20rpx;
}
p{
width: 100%;
}
.p1{
width: 100%;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 30rpx;
color: #323232;
}
.p2{
width: 100%;
margin-top: 10rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
@ -1044,7 +1057,7 @@
}
}
.top_box_right{
margin-left:20rpx ;
margin-left:30rpx ;
}
}
@ -1113,6 +1126,9 @@
font-size: 34rpx;
color: #fff;
font-weight: bold;
display: flex;
justify-content: center;
align-items: center;
}
}
@ -1169,7 +1185,7 @@
}
.hot {
// margin-top: 30rpx;
margin-bottom: 40rpx;
margin-bottom: 70rpx;
.hot-top {
// padding-bottom: 12rpx;
@ -1311,7 +1327,7 @@
border-radius: 18rpx 0 0 18rpx;
}
&:last-child{
&:nth-child(3){
border-radius: 0 18rpx 18rpx 0;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

BIN
static/detail/jia.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

BIN
static/detail/jian.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 36 KiB

BIN
static/detail/weixin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 652 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

BIN
static/my/daishenhe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

BIN
static/my/wtg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 KiB

View File

@ -69,7 +69,7 @@
// margin-top: 40rpx;
margin-left: 40rpx;
width: 96%;
width: 90%;
font-size: 28rpx;
color: $themeColor;
font-size: 13px;

View File

@ -0,0 +1,169 @@
## 2.2.402025-04-14
- 修复 绑定字符串值的时,日历面板选中状态未重置到默认值的问题
## 2.2.392025-04-14
- 修复 在 iOS 微信小程序上type='daterange'时,传入'YYYY-MM-DD'格式不生效的问题
## 2.2.382024-10-15
- 修复 微信小程序中的getSystemInfo警告
## 2.2.352024-09-21
- 修复 没有选中日期时点击确定直接报错的Bug [详情](https://ask.dcloud.net.cn/question/198168)
## 2.2.342024-04-24
- 新增 日期点击事件,在点击日期时会触发该事件。
## 2.2.332024-04-15
- 修复 抖音小程序事件传递失效bug
## 2.2.322024-02-20
- 修复 日历的close事件触发异常的bug [详情](https://github.com/dcloudio/uni-ui/issues/844)
## 2.2.312024-02-20
- 修复 h5平台 右边日历的月份默认+1的bug [详情](https://github.com/dcloudio/uni-ui/issues/841)
## 2.2.302024-01-31
- 修复 隐藏“秒”时在IOS15及以下版本时出现 结束时间在开始时间之前 的bug [详情](https://github.com/dcloudio/uni-ui/issues/788)
## 2.2.292024-01-20
- 新增 show事件弹窗弹出时触发该事件 [详情](https://github.com/dcloudio/uni-app/issues/4694)
## 2.2.282024-01-18
- 去除 noChange事件当进行日期范围选择时若只选了一天则开始结束日期都为同一天 [详情](https://github.com/dcloudio/uni-ui/issues/815)
## 2.2.272024-01-10
- 优化 增加noChange事件当进行日期范围选择时若有空值则触发该事件 [详情](https://github.com/dcloudio/uni-ui/issues/815)
## 2.2.262024-01-08
- 修复 字节小程序时间选择范围器失效问题 [详情](https://github.com/dcloudio/uni-ui/issues/834)
## 2.2.252023-10-18
- 修复 PC端初次修改时间开始时间未更新的Bug [详情](https://github.com/dcloudio/uni-ui/issues/737)
## 2.2.242023-06-02
- 修复 部分情况修改时间开始、结束时间显示异常的Bug [详情](https://ask.dcloud.net.cn/question/171146)
- 优化 当前月可以选择上月、下月的日期的Bug
## 2.2.232023-05-02
- 修复 部分情况修改时间开始时间未更新的Bug [详情](https://github.com/dcloudio/uni-ui/issues/737)
- 修复 部分平台及设备第一次点击无法显示弹框的Bug
- 修复 ios 日期格式未补零显示及使用异常的Bug [详情](https://ask.dcloud.net.cn/question/162979)
## 2.2.222023-03-30
- 修复 日历 picker 修改年月后自动选中当月1日的Bug [详情](https://ask.dcloud.net.cn/question/165937)
- 修复 小程序端 低版本 ios NaN的Bug [详情](https://ask.dcloud.net.cn/question/162979)
## 2.2.212023-02-20
- 修复 firefox 浏览器显示区域点击无法拉起日历弹框的Bug [详情](https://ask.dcloud.net.cn/question/163362)
## 2.2.202023-02-17
- 优化 值为空依然选中当天问题
- 优化 提供 default-value 属性支持配置选择器打开时默认显示的时间
- 优化 非范围选择未选择日期时间,点击确认按钮选中当前日期时间
- 优化 字节小程序日期时间范围选择底部日期换行的Bug
## 2.2.192023-02-09
- 修复 2.2.18 引起范围选择配置 end 选择无效的Bug [详情](https://github.com/dcloudio/uni-ui/issues/686)
## 2.2.182023-02-08
- 修复 移动端范围选择change事件触发异常的Bug [详情](https://github.com/dcloudio/uni-ui/issues/684)
- 优化 PC端输入日期格式错误时返回当前日期时间
- 优化 PC端输入日期时间超出 start、end 限制的Bug
- 优化 移动端日期时间范围用法时间展示不完整问题
## 2.2.172023-02-04
- 修复 小程序端绑定 Date 类型报错的Bug [详情](https://github.com/dcloudio/uni-ui/issues/679)
- 修复 vue3 time-picker 无法显示绑定时分秒的Bug
## 2.2.162023-02-02
- 修复 字节小程序报错的Bug
## 2.2.152023-02-02
- 修复 某些情况切换月份错误的Bug
## 2.2.142023-01-30
- 修复 某些情况切换月份错误的Bug [详情](https://ask.dcloud.net.cn/question/162033)
## 2.2.132023-01-10
- 修复 多次加载组件造成内存占用的Bug
## 2.2.122022-12-01
- 修复 vue3 下 i18n 国际化初始值不正确的Bug
## 2.2.112022-09-19
- 修复 支付宝小程序样式错乱的Bug [详情](https://github.com/dcloudio/uni-app/issues/3861)
## 2.2.102022-09-19
- 修复 反向选择日期范围日期显示异常的Bug [详情](https://ask.dcloud.net.cn/question/153401?item_id=212892&rf=false)
## 2.2.92022-09-16
- 可以使用 uni-scss 控制主题色
## 2.2.82022-09-08
- 修复 close事件无效的Bug
## 2.2.72022-09-05
- 修复 移动端 maskClick 无效的Bug [详情](https://ask.dcloud.net.cn/question/140824)
## 2.2.62022-06-30
- 优化 组件样式调整了组件图标大小、高度、颜色等与uni-ui风格保持一致
## 2.2.52022-06-24
- 修复 日历顶部年月及底部确认未国际化的Bug
## 2.2.42022-03-31
- 修复 Vue3 下动态赋值,单选类型未响应的Bug
## 2.2.32022-03-28
- 修复 Vue3 下动态赋值未响应的Bug
## 2.2.22021-12-10
- 修复 clear-icon 属性在小程序平台不生效的Bug
## 2.2.12021-12-10
- 修复 日期范围选在小程序平台必须多点击一次才能取消选中状态的Bug
## 2.2.02021-11-19
- 优化 组件UI并提供设计资源 [详情](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移 [https://uniapp.dcloud.io/component/uniui/uni-datetime-picker](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
## 2.1.52021-11-09
- 新增 提供组件设计资源,组件样式调整
## 2.1.42021-09-10
- 修复 hide-second 在移动端的Bug
- 修复 单选赋默认值时赋值日期未高亮的Bug
- 修复 赋默认值时移动端未正确显示时间的Bug
## 2.1.32021-09-09
- 新增 hide-second 属性,支持只使用时分,隐藏秒
## 2.1.22021-09-03
- 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次
- 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法
- 优化 调整字号大小,美化日历界面
- 修复 因国际化导致的 placeholder 失效的Bug
## 2.1.12021-08-24
- 新增 支持国际化
- 优化 范围选择器在 pc 端过宽的问题
## 2.1.02021-08-09
- 新增 适配 vue3
## 2.0.192021-08-09
- 新增 支持作为 uni-forms 子组件相关功能
- 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的Bug
## 2.0.182021-08-05
- 修复 type 属性动态赋值无效的Bug
- 修复 ‘确认’按钮被 tabbar 遮盖 bug
- 修复 组件未赋值时范围选左、右日历相同的Bug
## 2.0.172021-08-04
- 修复 范围选未正确显示当前值的Bug
- 修复 h5 平台(移动端)报错 'cale' of undefined 的Bug
## 2.0.162021-07-21
- 新增 return-type 属性支持返回 date 日期对象
## 2.0.152021-07-14
- 修复 单选日期类型初始赋值后不在当前日历的Bug
- 新增 clearIcon 属性,显示框的清空按钮可配置显示隐藏(仅 pc 有效)
- 优化 移动端移除显示框的清空按钮,无实际用途
## 2.0.142021-07-14
- 修复 组件赋值为空界面未更新的Bug
- 修复 start 和 end 不能动态赋值的Bug
- 修复 范围选类型用户选择后再次选择右侧日历结束日期显示不正确的Bug
## 2.0.132021-07-08
- 修复 范围选择不能动态赋值的Bug
## 2.0.122021-07-08
- 修复 范围选择的初始时间在一个月内时造成无法选择的bug
## 2.0.112021-07-08
- 优化 弹出层在超出视窗边缘定位不准确的问题
## 2.0.102021-07-08
- 修复 范围起始点样式的背景色与今日样式的字体前景色融合导致日期字体看不清的Bug
- 优化 弹出层在超出视窗边缘被遮盖的问题
## 2.0.92021-07-07
- 新增 maskClick 事件
- 修复 特殊情况日历 rpx 布局错误的Bugrpx -> px
- 修复 范围选择时清空返回值不合理的bug['', ''] -> []
## 2.0.82021-07-07
- 新增 日期时间显示框支持插槽
## 2.0.72021-07-01
- 优化 添加 uni-icons 依赖
## 2.0.62021-05-22
- 修复 图标在小程序上不显示的Bug
- 优化 重命名引用组件,避免潜在组件命名冲突
## 2.0.52021-05-20
- 优化 代码目录扁平化
## 2.0.42021-05-12
- 新增 组件示例地址
## 2.0.32021-05-10
- 修复 ios 下不识别 '-' 日期格式的Bug
- 优化 pc 下弹出层添加边框和阴影
## 2.0.22021-05-08
- 修复 在 admin 中获取弹出层定位错误的bug
## 2.0.12021-05-08
- 修复 type 属性向下兼容,默认值从 date 变更为 datetime
## 2.0.02021-04-30
- 支持日历形式的日期+时间的范围选择
> 注意此版本不向后兼容不再支持单独时间选择type=time及相关的 hide-second 属性(时间选可使用内置组件 picker
## 1.0.62021-03-18
- 新增 hide-second 属性,时间支持仅选择时、分
- 修复 选择跟显示的日期不一样的Bug
- 修复 chang事件触发2次的Bug
- 修复 分、秒 end 范围错误的Bug
- 优化 更好的 nvue 适配

View File

@ -0,0 +1,177 @@
<template>
<view class="uni-calendar-item__weeks-box" :class="{
'uni-calendar-item--disable':weeks.disable,
'uni-calendar-item--before-checked-x':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked-x':weeks.afterMultiple,
}" @click="choiceDate(weeks)" @mouseenter="handleMousemove(weeks)">
<view class="uni-calendar-item__weeks-box-item" :class="{
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && (calendar.userChecked || !checkHover),
'uni-calendar-item--checked-range-text': checkHover,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable,
}">
<text v-if="selected && weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
<text class="uni-calendar-item__weeks-box-text uni-calendar-item__weeks-box-text-disable uni-calendar-item--checked-text">{{weeks.date}}</text>
</view>
<view :class="{'uni-calendar-item--today': weeks.isToday}"></view>
</view>
</template>
<script>
export default {
props: {
weeks: {
type: Object,
default () {
return {}
}
},
calendar: {
type: Object,
default: () => {
return {}
}
},
selected: {
type: Array,
default: () => {
return []
}
},
checkHover: {
type: Boolean,
default: false
}
},
methods: {
choiceDate(weeks) {
this.$emit('change', weeks)
},
handleMousemove(weeks) {
this.$emit('handleMouse', weeks)
}
}
}
</script>
<style lang="scss" >
$uni-primary: #007aff !default;
.uni-calendar-item__weeks-box {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
margin: 1px 0;
position: relative;
}
.uni-calendar-item__weeks-box-text {
font-size: 14px;
// font-family: Lato-Bold, Lato;
font-weight: bold;
color: darken($color: $uni-primary, $amount: 40%);
}
.uni-calendar-item__weeks-box-item {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
width: 40px;
height: 40px;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.uni-calendar-item__weeks-box-circle {
position: absolute;
top: 5px;
right: 5px;
width: 8px;
height: 8px;
border-radius: 8px;
background-color: #dd524d;
}
.uni-calendar-item__weeks-box .uni-calendar-item--disable {
cursor: default;
}
.uni-calendar-item--disable .uni-calendar-item__weeks-box-text-disable {
color: #D1D1D1;
}
.uni-calendar-item--today {
position: absolute;
top: 10px;
right: 17%;
background-color: #dd524d;
width:6px;
height: 6px;
border-radius: 50%;
}
.uni-calendar-item--extra {
color: #dd524d;
opacity: 0.8;
}
.uni-calendar-item__weeks-box .uni-calendar-item--checked {
background-color: $uni-primary;
border-radius: 50%;
box-sizing: border-box;
border: 3px solid #fff;
}
.uni-calendar-item--checked .uni-calendar-item--checked-text {
color: #fff;
}
.uni-calendar-item--multiple .uni-calendar-item--checked-range-text {
color: #333;
}
.uni-calendar-item--multiple {
background-color: #F6F7FC;
// color: #fff;
}
.uni-calendar-item--multiple .uni-calendar-item--before-checked,
.uni-calendar-item--multiple .uni-calendar-item--after-checked {
background-color: $uni-primary;
border-radius: 50%;
box-sizing: border-box;
border: 3px solid #F6F7FC;
}
.uni-calendar-item--before-checked .uni-calendar-item--checked-text,
.uni-calendar-item--after-checked .uni-calendar-item--checked-text {
color: #fff;
}
.uni-calendar-item--before-checked-x {
border-top-left-radius: 50px;
border-bottom-left-radius: 50px;
box-sizing: border-box;
background-color: #F6F7FC;
}
.uni-calendar-item--after-checked-x {
border-top-right-radius: 50px;
border-bottom-right-radius: 50px;
background-color: #F6F7FC;
}
</style>

View File

@ -0,0 +1,947 @@
<template>
<view class="uni-calendar" @mouseleave="leaveCale">
<view v-if="!insert && show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}"
@click="maskClick"></view>
<view v-if="insert || show" class="uni-calendar__content"
:class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow, 'uni-calendar__content-mobile': aniMaskShow}">
<view class="uni-calendar__header" :class="{'uni-calendar__header-mobile' :!insert}">
<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('pre')">
<view class="uni-calendar__header-btn uni-calendar--left"></view>
</view>
<picker mode="date" :value="date" fields="month" @change="bindDateChange">
<text
class="uni-calendar__header-text">{{ (nowDate.year||'') + yearText + ( nowDate.month||'') + monthText}}</text>
</picker>
<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('next')">
<view class="uni-calendar__header-btn uni-calendar--right"></view>
</view>
<view v-if="!insert" class="dialog-close" @click="maskClick">
<view class="dialog-close-plus" data-id="close"></view>
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
</view>
</view>
<view class="uni-calendar__box">
<view v-if="showMonth" class="uni-calendar__box-bg">
<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
</view>
<view class="uni-calendar__weeks" style="padding-bottom: 7px;">
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{MONText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{THUText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{SATText}}</text>
</view>
</view>
<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected"
:checkHover="range" @change="choiceDate" @handleMouse="handleMouse">
</calendar-item>
</view>
</view>
</view>
<view v-if="!insert && !range && hasTime" class="uni-date-changed uni-calendar--fixed-top"
style="padding: 0 80px;">
<view class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</view>
<time-picker type="time" :start="timepickerStartTime" :end="timepickerEndTime" v-model="time"
:disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style">
</time-picker>
</view>
<view v-if="!insert && range && hasTime" class="uni-date-changed uni-calendar--fixed-top">
<view class="uni-date-changed--time-start">
<view class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}}
</view>
<time-picker type="time" :start="timepickerStartTime" v-model="timeRange.startTime" :border="false"
:hide-second="hideSecond" :disabled="!tempRange.before" class="time-picker-style">
</time-picker>
</view>
<view style="line-height: 50px;">
<uni-icons type="arrowthinright" color="#999"></uni-icons>
</view>
<view class="uni-date-changed--time-end">
<view class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : endDateText}}</view>
<time-picker type="time" :end="timepickerEndTime" v-model="timeRange.endTime" :border="false"
:hide-second="hideSecond" :disabled="!tempRange.after" class="time-picker-style">
</time-picker>
</view>
</view>
<view v-if="!insert" class="uni-date-changed uni-date-btn--ok">
<view class="uni-datetime-picker--btn" @click="confirm">{{confirmText}}</view>
</view>
</view>
</view>
</template>
<script>
import {
Calendar,
getDate,
getTime
} from './util.js';
import calendarItem from './calendar-item.vue'
import timePicker from './time-picker.vue'
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import i18nMessages from './i18n/index.js'
const {
t
} = initVueI18n(i18nMessages)
/**
* Calendar 日历
* @description 日历组件可以查看日期选择任意范围内的日期打点操作常用场景如酒店日期预订火车机票选择购买日期上下班打卡等
* @tutorial https://ext.dcloud.net.cn/plugin?id=56
* @property {String} date 自定义当前时间默认为今天
* @property {String} startDate 日期选择范围-开始日期
* @property {String} endDate 日期选择范围-结束日期
* @property {Boolean} range 范围选择
* @property {Boolean} insert = [true|false] 插入模式,默认为false
* @value true 弹窗模式
* @value false 插入模式
* @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
* @property {Array} selected 打点期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
* @property {Boolean} showMonth 是否选择月份为背景
* @property {[String} defaultValue 选择器打开时默认显示的时间
* @event {Function} change 日期改变`insert :ture` 时生效
* @event {Function} confirm 确认选择`insert :false` 时生效
* @event {Function} monthSwitch 切换月份时触发
* @example <uni-calendar :insert="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
*/
export default {
components: {
calendarItem,
timePicker
},
options: {
// #ifdef MP-TOUTIAO
virtualHost: false,
// #endif
// #ifndef MP-TOUTIAO
virtualHost: true
// #endif
},
props: {
date: {
type: String,
default: ''
},
defTime: {
type: [String, Object],
default: ''
},
selectableTimes: {
type: [Object],
default () {
return {}
}
},
selected: {
type: Array,
default () {
return []
}
},
startDate: {
type: String,
default: ''
},
endDate: {
type: String,
default: ''
},
startPlaceholder: {
type: String,
default: ''
},
endPlaceholder: {
type: String,
default: ''
},
range: {
type: Boolean,
default: false
},
hasTime: {
type: Boolean,
default: false
},
insert: {
type: Boolean,
default: true
},
showMonth: {
type: Boolean,
default: true
},
clearDate: {
type: Boolean,
default: true
},
checkHover: {
type: Boolean,
default: true
},
hideSecond: {
type: [Boolean],
default: false
},
pleStatus: {
type: Object,
default () {
return {
before: '',
after: '',
data: [],
fulldate: ''
}
}
},
defaultValue: {
type: [String, Object, Array],
default: ''
}
},
data() {
return {
show: false,
weeks: [],
calendar: {},
nowDate: {},
aniMaskShow: false,
firstEnter: true,
time: '',
timeRange: {
startTime: '',
endTime: ''
},
tempSingleDate: '',
tempRange: {
before: '',
after: ''
}
}
},
watch: {
date: {
immediate: true,
handler(newVal) {
if (!this.range) {
this.tempSingleDate = newVal
setTimeout(() => {
this.init(newVal)
}, 100)
}
}
},
defTime: {
immediate: true,
handler(newVal) {
if (!this.range) {
this.time = newVal
} else {
this.timeRange.startTime = newVal.start
this.timeRange.endTime = newVal.end
}
}
},
startDate(val) {
// watch created
if (!this.cale) {
return
}
this.cale.setStartDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
endDate(val) {
// watch created
if (!this.cale) {
return
}
this.cale.setEndDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
selected(newVal) {
// watch created
if (!this.cale) {
return
}
this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
this.weeks = this.cale.weeks
},
pleStatus: {
immediate: true,
handler(newVal) {
const {
before,
after,
fulldate,
which
} = newVal
this.tempRange.before = before
this.tempRange.after = after
setTimeout(() => {
if (fulldate) {
this.cale.setHoverMultiple(fulldate)
if (before && after) {
this.cale.lastHover = true
if (this.rangeWithinMonth(after, before)) return
this.setDate(before)
} else {
this.cale.setMultiple(fulldate)
this.setDate(this.nowDate.fullDate)
this.calendar.fullDate = ''
this.cale.lastHover = false
}
} else {
// watch created
if (!this.cale) {
return
}
this.cale.setDefaultMultiple(before, after)
if (which === 'left' && before) {
this.setDate(before)
this.weeks = this.cale.weeks
} else if (after) {
this.setDate(after)
this.weeks = this.cale.weeks
}
this.cale.lastHover = true
}
}, 16)
}
}
},
computed: {
timepickerStartTime() {
const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate
return activeDate === this.startDate ? this.selectableTimes.start : ''
},
timepickerEndTime() {
const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate
return activeDate === this.endDate ? this.selectableTimes.end : ''
},
/**
* for i18n
*/
selectDateText() {
return t("uni-datetime-picker.selectDate")
},
startDateText() {
return this.startPlaceholder || t("uni-datetime-picker.startDate")
},
endDateText() {
return this.endPlaceholder || t("uni-datetime-picker.endDate")
},
okText() {
return t("uni-datetime-picker.ok")
},
yearText() {
return t("uni-datetime-picker.year")
},
monthText() {
return t("uni-datetime-picker.month")
},
MONText() {
return t("uni-calender.MON")
},
TUEText() {
return t("uni-calender.TUE")
},
WEDText() {
return t("uni-calender.WED")
},
THUText() {
return t("uni-calender.THU")
},
FRIText() {
return t("uni-calender.FRI")
},
SATText() {
return t("uni-calender.SAT")
},
SUNText() {
return t("uni-calender.SUN")
},
confirmText() {
return t("uni-calender.confirm")
},
},
created() {
//
this.cale = new Calendar({
selected: this.selected,
startDate: this.startDate,
endDate: this.endDate,
range: this.range,
})
//
this.init(this.date)
},
methods: {
leaveCale() {
this.firstEnter = true
},
handleMouse(weeks) {
if (weeks.disable) return
if (this.cale.lastHover) return
let {
before,
after
} = this.cale.multipleStatus
if (!before) return
this.calendar = weeks
//
this.cale.setHoverMultiple(this.calendar.fullDate)
this.weeks = this.cale.weeks
// hover
if (this.firstEnter) {
this.$emit('firstEnterCale', this.cale.multipleStatus)
this.firstEnter = false
}
},
rangeWithinMonth(A, B) {
const [yearA, monthA] = A.split('-')
const [yearB, monthB] = B.split('-')
return yearA === yearB && monthA === monthB
},
//
maskClick() {
this.close()
this.$emit('maskClose')
},
clearCalender() {
if (this.range) {
this.timeRange.startTime = ''
this.timeRange.endTime = ''
this.tempRange.before = ''
this.tempRange.after = ''
this.cale.multipleStatus.before = ''
this.cale.multipleStatus.after = ''
this.cale.multipleStatus.data = []
this.cale.lastHover = false
} else {
this.time = ''
this.tempSingleDate = ''
}
this.calendar.fullDate = ''
this.setDate(new Date())
},
bindDateChange(e) {
const value = e.detail.value + '-1'
this.setDate(value)
},
/**
* 初始化日期显示
* @param {Object} date
*/
init(date) {
// watch created
if (!this.cale) {
return
}
this.cale.setDate(date || new Date())
this.weeks = this.cale.weeks
this.nowDate = this.cale.getInfo(date)
this.calendar = {
...this.nowDate
}
if (!date) {
// date
this.calendar.fullDate = ''
if (this.defaultValue && !this.range) {
//
const defaultDate = new Date(this.defaultValue)
const fullDate = getDate(defaultDate)
const year = defaultDate.getFullYear()
const month = defaultDate.getMonth() + 1
const date = defaultDate.getDate()
const day = defaultDate.getDay()
this.calendar = {
fullDate,
year,
month,
date,
day
},
this.tempSingleDate = fullDate
this.time = getTime(defaultDate, this.hideSecond)
}
}
},
/**
* 打开日历弹窗
*/
open() {
//
if (this.clearDate && !this.insert) {
this.cale.cleanMultipleStatus()
this.init(this.date)
}
this.show = true
this.$nextTick(() => {
setTimeout(() => {
this.aniMaskShow = true
}, 50)
})
},
/**
* 关闭日历弹窗
*/
close() {
this.aniMaskShow = false
this.$nextTick(() => {
setTimeout(() => {
this.show = false
this.$emit('close')
}, 300)
})
},
/**
* 确认按钮
*/
confirm() {
this.setEmit('confirm')
this.close()
},
/**
* 变化触发
*/
change(isSingleChange) {
if (!this.insert && !isSingleChange) return
this.setEmit('change')
},
/**
* 选择月份触发
*/
monthSwitch() {
let {
year,
month
} = this.nowDate
this.$emit('monthSwitch', {
year,
month: Number(month)
})
},
/**
* 派发事件
* @param {Object} name
*/
setEmit(name) {
if (!this.range) {
if (!this.calendar.fullDate) {
this.calendar = this.cale.getInfo(new Date())
this.tempSingleDate = this.calendar.fullDate
}
if (this.hasTime && !this.time) {
this.time = getTime(new Date(), this.hideSecond)
}
}
let {
year,
month,
date,
fullDate,
extraInfo
} = this.calendar
this.$emit(name, {
range: this.cale.multipleStatus,
year,
month,
date,
time: this.time,
timeRange: this.timeRange,
fulldate: fullDate,
extraInfo: extraInfo || {}
})
},
/**
* 选择天触发
* @param {Object} weeks
*/
choiceDate(weeks) {
if (weeks.disable) return
this.calendar = weeks
this.calendar.userChecked = true
//
this.cale.setMultiple(this.calendar.fullDate, true)
this.weeks = this.cale.weeks
this.tempSingleDate = this.calendar.fullDate
const beforeDate = new Date(this.cale.multipleStatus.before).getTime()
const afterDate = new Date(this.cale.multipleStatus.after).getTime()
if (beforeDate > afterDate && afterDate) {
this.tempRange.before = this.cale.multipleStatus.after
this.tempRange.after = this.cale.multipleStatus.before
} else {
this.tempRange.before = this.cale.multipleStatus.before
this.tempRange.after = this.cale.multipleStatus.after
}
this.change(true)
},
changeMonth(type) {
let newDate
if (type === 'pre') {
newDate = this.cale.getPreMonthObj(this.nowDate.fullDate).fullDate
} else if (type === 'next') {
newDate = this.cale.getNextMonthObj(this.nowDate.fullDate).fullDate
}
this.setDate(newDate)
this.monthSwitch()
},
/**
* 设置日期
* @param {Object} date
*/
setDate(date) {
this.cale.setDate(date)
this.weeks = this.cale.weeks
this.nowDate = this.cale.getInfo(date)
}
}
}
</script>
<style lang="scss">
$uni-primary: #007aff !default;
.uni-calendar {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.uni-calendar__mask {
position: fixed;
bottom: 0;
top: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.4);
transition-property: opacity;
transition-duration: 0.3s;
opacity: 0;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-calendar--mask-show {
opacity: 1
}
.uni-calendar--fixed {
position: fixed;
bottom: calc(var(--window-bottom));
left: 0;
right: 0;
transition-property: transform;
transition-duration: 0.3s;
transform: translateY(460px);
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-calendar--ani-show {
transform: translateY(0);
}
.uni-calendar__content {
background-color: #fff;
}
.uni-calendar__content-mobile {
border-top-left-radius: 10px;
border-top-right-radius: 10px;
box-shadow: 0px 0px 5px 3px rgba(0, 0, 0, 0.1);
}
.uni-calendar__header {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
height: 50px;
}
.uni-calendar__header-mobile {
padding: 10px;
padding-bottom: 0;
}
.uni-calendar--fixed-top {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
border-top-color: rgba(0, 0, 0, 0.4);
border-top-style: solid;
border-top-width: 1px;
}
.uni-calendar--fixed-width {
width: 50px;
}
.uni-calendar__backtoday {
position: absolute;
right: 0;
top: 25rpx;
padding: 0 5px;
padding-left: 10px;
height: 25px;
line-height: 25px;
font-size: 12px;
border-top-left-radius: 25px;
border-bottom-left-radius: 25px;
color: #fff;
background-color: #f1f1f1;
}
.uni-calendar__header-text {
text-align: center;
width: 100px;
font-size: 15px;
color: #666;
}
.uni-calendar__button-text {
text-align: center;
width: 100px;
font-size: 14px;
color: $uni-primary;
/* #ifndef APP-NVUE */
letter-spacing: 3px;
/* #endif */
}
.uni-calendar__header-btn-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
}
.uni-calendar__header-btn {
width: 9px;
height: 9px;
border-left-color: #808080;
border-left-style: solid;
border-left-width: 1px;
border-top-color: #555555;
border-top-style: solid;
border-top-width: 1px;
}
.uni-calendar--left {
transform: rotate(-45deg);
}
.uni-calendar--right {
transform: rotate(135deg);
}
.uni-calendar__weeks {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.uni-calendar__weeks-item {
flex: 1;
}
.uni-calendar__weeks-day {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
height: 40px;
border-bottom-color: #F5F5F5;
border-bottom-style: solid;
border-bottom-width: 1px;
}
.uni-calendar__weeks-day-text {
font-size: 12px;
color: #B2B2B2;
}
.uni-calendar__box {
position: relative;
// padding: 0 10px;
padding-bottom: 7px;
}
.uni-calendar__box-bg {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.uni-calendar__box-bg-text {
font-size: 200px;
font-weight: bold;
color: #999;
opacity: 0.1;
text-align: center;
/* #ifndef APP-NVUE */
line-height: 1;
/* #endif */
}
.uni-date-changed {
padding: 0 10px;
// line-height: 50px;
text-align: center;
color: #333;
border-top-color: #DCDCDC;
;
border-top-style: solid;
border-top-width: 1px;
flex: 1;
}
.uni-date-btn--ok {
padding: 20px 15px;
}
.uni-date-changed--time-start {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
}
.uni-date-changed--time-end {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
}
.uni-date-changed--time-date {
color: #999;
line-height: 50px;
/* #ifdef MP-TOUTIAO */
font-size: 16px;
/* #endif */
margin-right: 5px;
// opacity: 0.6;
}
.time-picker-style {
// width: 62px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center
}
.mr-10 {
margin-right: 10px;
}
.dialog-close {
position: absolute;
top: 0;
right: 0;
bottom: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
padding: 0 25px;
margin-top: 10px;
}
.dialog-close-plus {
width: 16px;
height: 2px;
background-color: #737987;
border-radius: 2px;
transform: rotate(45deg);
}
.dialog-close-rotate {
position: absolute;
transform: rotate(-45deg);
}
.uni-datetime-picker--btn {
border-radius: 100px;
height: 40px;
line-height: 40px;
background-color: $uni-primary;
color: #fff;
font-size: 16px;
letter-spacing: 2px;
}
/* #ifndef APP-NVUE */
.uni-datetime-picker--btn:active {
opacity: 0.7;
}
/* #endif */
</style>

View File

@ -0,0 +1,22 @@
{
"uni-datetime-picker.selectDate": "select date",
"uni-datetime-picker.selectTime": "select time",
"uni-datetime-picker.selectDateTime": "select date and time",
"uni-datetime-picker.startDate": "start date",
"uni-datetime-picker.endDate": "end date",
"uni-datetime-picker.startTime": "start time",
"uni-datetime-picker.endTime": "end time",
"uni-datetime-picker.ok": "ok",
"uni-datetime-picker.clear": "clear",
"uni-datetime-picker.cancel": "cancel",
"uni-datetime-picker.year": "-",
"uni-datetime-picker.month": "",
"uni-calender.MON": "MON",
"uni-calender.TUE": "TUE",
"uni-calender.WED": "WED",
"uni-calender.THU": "THU",
"uni-calender.FRI": "FRI",
"uni-calender.SAT": "SAT",
"uni-calender.SUN": "SUN",
"uni-calender.confirm": "confirm"
}

View File

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

View File

@ -0,0 +1,22 @@
{
"uni-datetime-picker.selectDate": "选择日期",
"uni-datetime-picker.selectTime": "选择时间",
"uni-datetime-picker.selectDateTime": "选择日期时间",
"uni-datetime-picker.startDate": "开始日期",
"uni-datetime-picker.endDate": "结束日期",
"uni-datetime-picker.startTime": "开始时间",
"uni-datetime-picker.endTime": "结束时间",
"uni-datetime-picker.ok": "确定",
"uni-datetime-picker.clear": "清除",
"uni-datetime-picker.cancel": "取消",
"uni-datetime-picker.year": "年",
"uni-datetime-picker.month": "月",
"uni-calender.SUN": "日",
"uni-calender.MON": "一",
"uni-calender.TUE": "二",
"uni-calender.WED": "三",
"uni-calender.THU": "四",
"uni-calender.FRI": "五",
"uni-calender.SAT": "六",
"uni-calender.confirm": "确认"
}

View File

@ -0,0 +1,22 @@
{
"uni-datetime-picker.selectDate": "選擇日期",
"uni-datetime-picker.selectTime": "選擇時間",
"uni-datetime-picker.selectDateTime": "選擇日期時間",
"uni-datetime-picker.startDate": "開始日期",
"uni-datetime-picker.endDate": "結束日期",
"uni-datetime-picker.startTime": "開始时间",
"uni-datetime-picker.endTime": "結束时间",
"uni-datetime-picker.ok": "確定",
"uni-datetime-picker.clear": "清除",
"uni-datetime-picker.cancel": "取消",
"uni-datetime-picker.year": "年",
"uni-datetime-picker.month": "月",
"uni-calender.SUN": "日",
"uni-calender.MON": "一",
"uni-calender.TUE": "二",
"uni-calender.WED": "三",
"uni-calender.THU": "四",
"uni-calender.FRI": "五",
"uni-calender.SAT": "六",
"uni-calender.confirm": "確認"
}

View File

@ -0,0 +1,940 @@
<template>
<view class="uni-datetime-picker">
<view @click="initTimePicker">
<slot>
<view class="uni-datetime-picker-timebox-pointer"
:class="{'uni-datetime-picker-disabled': disabled, 'uni-datetime-picker-timebox': border}">
<text class="uni-datetime-picker-text">{{time}}</text>
<view v-if="!time" class="uni-datetime-picker-time">
<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
</view>
</view>
</slot>
</view>
<view v-if="visible" id="mask" class="uni-datetime-picker-mask" @click="tiggerTimePicker"></view>
<view v-if="visible" class="uni-datetime-picker-popup" :class="[dateShow && timeShow ? '' : 'fix-nvue-height']"
:style="fixNvueBug">
<view class="uni-title">
<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
</view>
<view v-if="dateShow" class="uni-datetime-picker__container-box">
<picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="ymd"
@change="bindDateChange">
<picker-view-column>
<view class="uni-datetime-picker-item" v-for="(item,index) in years" :key="index">
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
</view>
</picker-view-column>
<picker-view-column>
<view class="uni-datetime-picker-item" v-for="(item,index) in months" :key="index">
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
</view>
</picker-view-column>
<picker-view-column>
<view class="uni-datetime-picker-item" v-for="(item,index) in days" :key="index">
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
</view>
</picker-view-column>
</picker-view>
<!-- 兼容 nvue 不支持伪类 -->
<text class="uni-datetime-picker-sign sign-left">-</text>
<text class="uni-datetime-picker-sign sign-right">-</text>
</view>
<view v-if="timeShow" class="uni-datetime-picker__container-box">
<picker-view class="uni-datetime-picker-view" :class="[hideSecond ? 'time-hide-second' : '']"
:indicator-style="indicatorStyle" :value="hms" @change="bindTimeChange">
<picker-view-column>
<view class="uni-datetime-picker-item" v-for="(item,index) in hours" :key="index">
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
</view>
</picker-view-column>
<picker-view-column>
<view class="uni-datetime-picker-item" v-for="(item,index) in minutes" :key="index">
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
</view>
</picker-view-column>
<picker-view-column v-if="!hideSecond">
<view class="uni-datetime-picker-item" v-for="(item,index) in seconds" :key="index">
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
</view>
</picker-view-column>
</picker-view>
<!-- 兼容 nvue 不支持伪类 -->
<text class="uni-datetime-picker-sign" :class="[hideSecond ? 'sign-center' : 'sign-left']">:</text>
<text v-if="!hideSecond" class="uni-datetime-picker-sign sign-right">:</text>
</view>
<view class="uni-datetime-picker-btn">
<view @click="clearTime">
<text class="uni-datetime-picker-btn-text">{{clearText}}</text>
</view>
<view class="uni-datetime-picker-btn-group">
<view class="uni-datetime-picker-cancel" @click="tiggerTimePicker">
<text class="uni-datetime-picker-btn-text">{{cancelText}}</text>
</view>
<view @click="setTime">
<text class="uni-datetime-picker-btn-text">{{okText}}</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import i18nMessages from './i18n/index.js'
const {
t
} = initVueI18n(i18nMessages)
import {
fixIosDateFormat
} from './util'
/**
* DatetimePicker 时间选择器
* @description 可以同时选择日期和时间的选择器
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
* @property {String} type = [datetime | date | time] 显示模式
* @property {Boolean} multiple = [true|false] 是否多选
* @property {String|Number} value 默认值
* @property {String|Number} start 起始日期或时间
* @property {String|Number} end 起始日期或时间
* @property {String} return-type = [timestamp | string]
* @event {Function} change 选中发生变化触发
*/
export default {
name: 'UniDatetimePicker',
data() {
return {
indicatorStyle: `height: 50px;`,
visible: false,
fixNvueBug: {},
dateShow: true,
timeShow: true,
title: '日期和时间',
//
time: '',
//
year: 1920,
month: 0,
day: 0,
hour: 0,
minute: 0,
second: 0,
//
startYear: 1920,
startMonth: 1,
startDay: 1,
startHour: 0,
startMinute: 0,
startSecond: 0,
//
endYear: 2120,
endMonth: 12,
endDay: 31,
endHour: 23,
endMinute: 59,
endSecond: 59,
}
},
options: {
// #ifdef MP-TOUTIAO
virtualHost: false,
// #endif
// #ifndef MP-TOUTIAO
virtualHost: true
// #endif
},
props: {
type: {
type: String,
default: 'datetime'
},
value: {
type: [String, Number],
default: ''
},
modelValue: {
type: [String, Number],
default: ''
},
start: {
type: [Number, String],
default: ''
},
end: {
type: [Number, String],
default: ''
},
returnType: {
type: String,
default: 'string'
},
disabled: {
type: [Boolean, String],
default: false
},
border: {
type: [Boolean, String],
default: true
},
hideSecond: {
type: [Boolean, String],
default: false
}
},
watch: {
// #ifndef VUE3
value: {
handler(newVal) {
if (newVal) {
this.parseValue(fixIosDateFormat(newVal))
this.initTime(false)
} else {
this.time = ''
this.parseValue(Date.now())
}
},
immediate: true
},
// #endif
// #ifdef VUE3
modelValue: {
handler(newVal) {
if (newVal) {
this.parseValue(fixIosDateFormat(newVal))
this.initTime(false)
} else {
this.time = ''
this.parseValue(Date.now())
}
},
immediate: true
},
// #endif
type: {
handler(newValue) {
if (newValue === 'date') {
this.dateShow = true
this.timeShow = false
this.title = '日期'
} else if (newValue === 'time') {
this.dateShow = false
this.timeShow = true
this.title = '时间'
} else {
this.dateShow = true
this.timeShow = true
this.title = '日期和时间'
}
},
immediate: true
},
start: {
handler(newVal) {
this.parseDatetimeRange(fixIosDateFormat(newVal), 'start')
},
immediate: true
},
end: {
handler(newVal) {
this.parseDatetimeRange(fixIosDateFormat(newVal), 'end')
},
immediate: true
},
//
months(newVal) {
this.checkValue('month', this.month, newVal)
},
days(newVal) {
this.checkValue('day', this.day, newVal)
},
hours(newVal) {
this.checkValue('hour', this.hour, newVal)
},
minutes(newVal) {
this.checkValue('minute', this.minute, newVal)
},
seconds(newVal) {
this.checkValue('second', this.second, newVal)
}
},
computed: {
//
years() {
return this.getCurrentRange('year')
},
months() {
return this.getCurrentRange('month')
},
days() {
return this.getCurrentRange('day')
},
hours() {
return this.getCurrentRange('hour')
},
minutes() {
return this.getCurrentRange('minute')
},
seconds() {
return this.getCurrentRange('second')
},
// picker
ymd() {
return [this.year - this.minYear, this.month - this.minMonth, this.day - this.minDay]
},
hms() {
return [this.hour - this.minHour, this.minute - this.minMinute, this.second - this.minSecond]
},
// date start
currentDateIsStart() {
return this.year === this.startYear && this.month === this.startMonth && this.day === this.startDay
},
// date end
currentDateIsEnd() {
return this.year === this.endYear && this.month === this.endMonth && this.day === this.endDay
},
//
minYear() {
return this.startYear
},
maxYear() {
return this.endYear
},
minMonth() {
if (this.year === this.startYear) {
return this.startMonth
} else {
return 1
}
},
maxMonth() {
if (this.year === this.endYear) {
return this.endMonth
} else {
return 12
}
},
minDay() {
if (this.year === this.startYear && this.month === this.startMonth) {
return this.startDay
} else {
return 1
}
},
maxDay() {
if (this.year === this.endYear && this.month === this.endMonth) {
return this.endDay
} else {
return this.daysInMonth(this.year, this.month)
}
},
minHour() {
if (this.type === 'datetime') {
if (this.currentDateIsStart) {
return this.startHour
} else {
return 0
}
}
if (this.type === 'time') {
return this.startHour
}
},
maxHour() {
if (this.type === 'datetime') {
if (this.currentDateIsEnd) {
return this.endHour
} else {
return 23
}
}
if (this.type === 'time') {
return this.endHour
}
},
minMinute() {
if (this.type === 'datetime') {
if (this.currentDateIsStart && this.hour === this.startHour) {
return this.startMinute
} else {
return 0
}
}
if (this.type === 'time') {
if (this.hour === this.startHour) {
return this.startMinute
} else {
return 0
}
}
},
maxMinute() {
if (this.type === 'datetime') {
if (this.currentDateIsEnd && this.hour === this.endHour) {
return this.endMinute
} else {
return 59
}
}
if (this.type === 'time') {
if (this.hour === this.endHour) {
return this.endMinute
} else {
return 59
}
}
},
minSecond() {
if (this.type === 'datetime') {
if (this.currentDateIsStart && this.hour === this.startHour && this.minute === this.startMinute) {
return this.startSecond
} else {
return 0
}
}
if (this.type === 'time') {
if (this.hour === this.startHour && this.minute === this.startMinute) {
return this.startSecond
} else {
return 0
}
}
},
maxSecond() {
if (this.type === 'datetime') {
if (this.currentDateIsEnd && this.hour === this.endHour && this.minute === this.endMinute) {
return this.endSecond
} else {
return 59
}
}
if (this.type === 'time') {
if (this.hour === this.endHour && this.minute === this.endMinute) {
return this.endSecond
} else {
return 59
}
}
},
/**
* for i18n
*/
selectTimeText() {
return t("uni-datetime-picker.selectTime")
},
okText() {
return t("uni-datetime-picker.ok")
},
clearText() {
return t("uni-datetime-picker.clear")
},
cancelText() {
return t("uni-datetime-picker.cancel")
}
},
mounted() {
// #ifdef APP-NVUE
const res = uni.getSystemInfoSync();
this.fixNvueBug = {
top: res.windowHeight / 2,
left: res.windowWidth / 2
}
// #endif
},
methods: {
/**
* @param {Object} item
* 小于 10 在前面加个 0
*/
lessThanTen(item) {
return item < 10 ? '0' + item : item
},
/**
* 解析时分秒字符串例如00:00:00
* @param {String} timeString
*/
parseTimeType(timeString) {
if (timeString) {
let timeArr = timeString.split(':')
this.hour = Number(timeArr[0])
this.minute = Number(timeArr[1])
this.second = Number(timeArr[2])
}
},
/**
* 解析选择器初始值类型可以是字符串时间戳例如2000-10-02'08:30:00' 1610695109000
* @param {String | Number} datetime
*/
initPickerValue(datetime) {
let defaultValue = null
if (datetime) {
defaultValue = this.compareValueWithStartAndEnd(datetime, this.start, this.end)
} else {
defaultValue = Date.now()
defaultValue = this.compareValueWithStartAndEnd(defaultValue, this.start, this.end)
}
this.parseValue(defaultValue)
},
/**
* 初始值规则
* - 用户设置初始值 value
* - 设置了起始时间 start终止时间 end start < value < end初始值为 value 否则初始值为 start
* - 只设置了起始时间 start start < value初始值为 value否则初始值为 start
* - 只设置了终止时间 end value < end初始值为 value否则初始值为 end
* - 无起始终止时间则初始值为 value
* - 无初始值 value则初始值为当前本地时间 Date.now()
* @param {Object} value
* @param {Object} dateBase
*/
compareValueWithStartAndEnd(value, start, end) {
let winner = null
value = this.superTimeStamp(value)
start = this.superTimeStamp(start)
end = this.superTimeStamp(end)
if (start && end) {
if (value < start) {
winner = new Date(start)
} else if (value > end) {
winner = new Date(end)
} else {
winner = new Date(value)
}
} else if (start && !end) {
winner = start <= value ? new Date(value) : new Date(start)
} else if (!start && end) {
winner = value <= end ? new Date(value) : new Date(end)
} else {
winner = new Date(value)
}
return winner
},
/**
* 转换为可比较的时间戳接受日期时分秒时间戳
* @param {Object} value
*/
superTimeStamp(value) {
let dateBase = ''
if (this.type === 'time' && value && typeof value === 'string') {
const now = new Date()
const year = now.getFullYear()
const month = now.getMonth() + 1
const day = now.getDate()
dateBase = year + '/' + month + '/' + day + ' '
}
if (Number(value)) {
value = parseInt(value)
dateBase = 0
}
return this.createTimeStamp(dateBase + value)
},
/**
* 解析默认值 value字符串时间戳
* @param {Object} defaultTime
*/
parseValue(value) {
if (!value) {
return
}
if (this.type === 'time' && typeof value === "string") {
this.parseTimeType(value)
} else {
let defaultDate = null
defaultDate = new Date(value)
if (this.type !== 'time') {
this.year = defaultDate.getFullYear()
this.month = defaultDate.getMonth() + 1
this.day = defaultDate.getDate()
}
if (this.type !== 'date') {
this.hour = defaultDate.getHours()
this.minute = defaultDate.getMinutes()
this.second = defaultDate.getSeconds()
}
}
if (this.hideSecond) {
this.second = 0
}
},
/**
* 解析可选择时间范围 startend年月日字符串时间戳
* @param {Object} defaultTime
*/
parseDatetimeRange(point, pointType) {
//
if (!point) {
if (pointType === 'start') {
this.startYear = 1920
this.startMonth = 1
this.startDay = 1
this.startHour = 0
this.startMinute = 0
this.startSecond = 0
}
if (pointType === 'end') {
this.endYear = 2120
this.endMonth = 12
this.endDay = 31
this.endHour = 23
this.endMinute = 59
this.endSecond = 59
}
return
}
if (this.type === 'time') {
const pointArr = point.split(':')
this[pointType + 'Hour'] = Number(pointArr[0])
this[pointType + 'Minute'] = Number(pointArr[1])
this[pointType + 'Second'] = Number(pointArr[2])
} else {
if (!point) {
pointType === 'start' ? this.startYear = this.year - 60 : this.endYear = this.year + 60
return
}
if (Number(point)) {
point = parseInt(point)
}
// datetime end ,
const hasTime = /[0-9]:[0-9]/
if (this.type === 'datetime' && pointType === 'end' && typeof point === 'string' && !hasTime.test(
point)) {
point = point + ' 23:59:59'
}
const pointDate = new Date(point)
this[pointType + 'Year'] = pointDate.getFullYear()
this[pointType + 'Month'] = pointDate.getMonth() + 1
this[pointType + 'Day'] = pointDate.getDate()
if (this.type === 'datetime') {
this[pointType + 'Hour'] = pointDate.getHours()
this[pointType + 'Minute'] = pointDate.getMinutes()
this[pointType + 'Second'] = pointDate.getSeconds()
}
}
},
//
getCurrentRange(value) {
const range = []
for (let i = this['min' + this.capitalize(value)]; i <= this['max' + this.capitalize(value)]; i++) {
range.push(i)
}
return range
},
//
capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1)
},
//
checkValue(name, value, values) {
if (values.indexOf(value) === -1) {
this[name] = values[0]
}
},
//
daysInMonth(year, month) { // Use 1 for January, 2 for February, etc.
return new Date(year, month, 0).getDate();
},
/**
* 生成时间戳
* @param {Object} time
*/
createTimeStamp(time) {
if (!time) return
if (typeof time === "number") {
return time
} else {
time = time.replace(/-/g, '/')
if (this.type === 'date') {
time = time + ' ' + '00:00:00'
}
return Date.parse(time)
}
},
/**
* 生成日期或时间的字符串
*/
createDomSting() {
const yymmdd = this.year +
'-' +
this.lessThanTen(this.month) +
'-' +
this.lessThanTen(this.day)
let hhmmss = this.lessThanTen(this.hour) +
':' +
this.lessThanTen(this.minute)
if (!this.hideSecond) {
hhmmss = hhmmss + ':' + this.lessThanTen(this.second)
}
if (this.type === 'date') {
return yymmdd
} else if (this.type === 'time') {
return hhmmss
} else {
return yymmdd + ' ' + hhmmss
}
},
/**
* 初始化返回值并抛出 change 事件
*/
initTime(emit = true) {
this.time = this.createDomSting()
if (!emit) return
if (this.returnType === 'timestamp' && this.type !== 'time') {
this.$emit('change', this.createTimeStamp(this.time))
this.$emit('input', this.createTimeStamp(this.time))
this.$emit('update:modelValue', this.createTimeStamp(this.time))
} else {
this.$emit('change', this.time)
this.$emit('input', this.time)
this.$emit('update:modelValue', this.time)
}
},
/**
* 用户选择日期或时间更新 data
* @param {Object} e
*/
bindDateChange(e) {
const val = e.detail.value
this.year = this.years[val[0]]
this.month = this.months[val[1]]
this.day = this.days[val[2]]
},
bindTimeChange(e) {
const val = e.detail.value
this.hour = this.hours[val[0]]
this.minute = this.minutes[val[1]]
this.second = this.seconds[val[2]]
},
/**
* 初始化弹出层
*/
initTimePicker() {
if (this.disabled) return
const value = fixIosDateFormat(this.time)
this.initPickerValue(value)
this.visible = !this.visible
},
/**
* 触发或关闭弹框
*/
tiggerTimePicker(e) {
this.visible = !this.visible
},
/**
* 用户点击清空按钮清空当前值
*/
clearTime() {
this.time = ''
this.$emit('change', this.time)
this.$emit('input', this.time)
this.$emit('update:modelValue', this.time)
this.tiggerTimePicker()
},
/**
* 用户点击确定按钮
*/
setTime() {
this.initTime()
this.tiggerTimePicker()
}
}
}
</script>
<style lang="scss">
$uni-primary: #007aff !default;
.uni-datetime-picker {
/* #ifndef APP-NVUE */
/* width: 100%; */
/* #endif */
}
.uni-datetime-picker-view {
height: 130px;
width: 270px;
/* #ifndef APP-NVUE */
cursor: pointer;
/* #endif */
}
.uni-datetime-picker-item {
height: 50px;
line-height: 50px;
text-align: center;
font-size: 14px;
}
.uni-datetime-picker-btn {
margin-top: 60px;
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
flex-direction: row;
justify-content: space-between;
}
.uni-datetime-picker-btn-text {
font-size: 14px;
color: $uni-primary;
}
.uni-datetime-picker-btn-group {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.uni-datetime-picker-cancel {
margin-right: 30px;
}
.uni-datetime-picker-mask {
position: fixed;
bottom: 0px;
top: 0px;
left: 0px;
right: 0px;
background-color: rgba(0, 0, 0, 0.4);
transition-duration: 0.3s;
z-index: 998;
}
.uni-datetime-picker-popup {
border-radius: 8px;
padding: 30px;
width: 270px;
/* #ifdef APP-NVUE */
height: 500px;
/* #endif */
/* #ifdef APP-NVUE */
width: 330px;
/* #endif */
background-color: #fff;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transition-duration: 0.3s;
z-index: 999;
}
.fix-nvue-height {
/* #ifdef APP-NVUE */
height: 330px;
/* #endif */
}
.uni-datetime-picker-time {
color: grey;
}
.uni-datetime-picker-column {
height: 50px;
}
.uni-datetime-picker-timebox {
border: 1px solid #E5E5E5;
border-radius: 5px;
padding: 7px 10px;
/* #ifndef APP-NVUE */
box-sizing: border-box;
cursor: pointer;
/* #endif */
}
.uni-datetime-picker-timebox-pointer {
/* #ifndef APP-NVUE */
cursor: pointer;
/* #endif */
}
.uni-datetime-picker-disabled {
opacity: 0.4;
/* #ifdef H5 */
cursor: not-allowed !important;
/* #endif */
}
.uni-datetime-picker-text {
font-size: 14px;
line-height: 50px
}
.uni-datetime-picker-sign {
position: absolute;
top: 53px;
/* 减掉 10px 的元素高度兼容nvue */
color: #999;
/* #ifdef APP-NVUE */
font-size: 16px;
/* #endif */
}
.sign-left {
left: 86px;
}
.sign-right {
right: 86px;
}
.sign-center {
left: 135px;
}
.uni-datetime-picker__container-box {
position: relative;
display: flex;
align-items: center;
justify-content: center;
margin-top: 40px;
}
.time-hide-second {
width: 180px;
}
</style>

View File

@ -0,0 +1,421 @@
class Calendar {
constructor({
selected,
startDate,
endDate,
range,
} = {}) {
// 当前日期
this.date = this.getDateObj(new Date()) // 当前初入日期
// 打点信息
this.selected = selected || [];
// 起始时间
this.startDate = startDate
// 终止时间
this.endDate = endDate
// 是否范围选择
this.range = range
// 多选状态
this.cleanMultipleStatus()
// 每周日期
this.weeks = {}
this.lastHover = false
}
/**
* 设置日期
* @param {Object} date
*/
setDate(date) {
const selectDate = this.getDateObj(date)
this.getWeeks(selectDate.fullDate)
}
/**
* 清理多选状态
*/
cleanMultipleStatus() {
this.multipleStatus = {
before: '',
after: '',
data: []
}
}
setStartDate(startDate) {
this.startDate = startDate
}
setEndDate(endDate) {
this.endDate = endDate
}
getPreMonthObj(date) {
date = fixIosDateFormat(date)
date = new Date(date)
const oldMonth = date.getMonth()
date.setMonth(oldMonth - 1)
const newMonth = date.getMonth()
if (oldMonth !== 0 && newMonth - oldMonth === 0) {
date.setMonth(newMonth - 1)
}
return this.getDateObj(date)
}
getNextMonthObj(date) {
date = fixIosDateFormat(date)
date = new Date(date)
const oldMonth = date.getMonth()
date.setMonth(oldMonth + 1)
const newMonth = date.getMonth()
if (newMonth - oldMonth > 1) {
date.setMonth(newMonth - 1)
}
return this.getDateObj(date)
}
/**
* 获取指定格式Date对象
*/
getDateObj(date) {
date = fixIosDateFormat(date)
date = new Date(date)
return {
fullDate: getDate(date),
year: date.getFullYear(),
month: addZero(date.getMonth() + 1),
date: addZero(date.getDate()),
day: date.getDay()
}
}
/**
* 获取上一个月日期集合
*/
getPreMonthDays(amount, dateObj) {
const result = []
for (let i = amount - 1; i >= 0; i--) {
const month = dateObj.month - 1
result.push({
date: new Date(dateObj.year, month, -i).getDate(),
month,
disable: true
})
}
return result
}
/**
* 获取本月日期集合
*/
getCurrentMonthDays(amount, dateObj) {
const result = []
const fullDate = this.date.fullDate
for (let i = 1; i <= amount; i++) {
const currentDate = `${dateObj.year}-${dateObj.month}-${addZero(i)}`
const isToday = fullDate === currentDate
// 获取打点信息
const info = this.selected && this.selected.find((item) => {
if (this.dateEqual(currentDate, item.date)) {
return item
}
})
// 日期禁用
let disableBefore = true
let disableAfter = true
if (this.startDate) {
disableBefore = dateCompare(this.startDate, currentDate)
}
if (this.endDate) {
disableAfter = dateCompare(currentDate, this.endDate)
}
let multiples = this.multipleStatus.data
let multiplesStatus = -1
if (this.range && multiples) {
multiplesStatus = multiples.findIndex((item) => {
return this.dateEqual(item, currentDate)
})
}
const checked = multiplesStatus !== -1
result.push({
fullDate: currentDate,
year: dateObj.year,
date: i,
multiple: this.range ? checked : false,
beforeMultiple: this.isLogicBefore(currentDate, this.multipleStatus.before, this.multipleStatus.after),
afterMultiple: this.isLogicAfter(currentDate, this.multipleStatus.before, this.multipleStatus.after),
month: dateObj.month,
disable: (this.startDate && !dateCompare(this.startDate, currentDate)) || (this.endDate && !dateCompare(
currentDate, this.endDate)),
isToday,
userChecked: false,
extraInfo: info
})
}
return result
}
/**
* 获取下一个月日期集合
*/
_getNextMonthDays(amount, dateObj) {
const result = []
const month = dateObj.month + 1
for (let i = 1; i <= amount; i++) {
result.push({
date: i,
month,
disable: true
})
}
return result
}
/**
* 获取当前日期详情
* @param {Object} date
*/
getInfo(date) {
if (!date) {
date = new Date()
}
const res = this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate)
return res ? res : this.getDateObj(date)
}
/**
* 比较时间是否相等
*/
dateEqual(before, after) {
before = new Date(fixIosDateFormat(before))
after = new Date(fixIosDateFormat(after))
return before.valueOf() === after.valueOf()
}
/**
* 比较真实起始日期
*/
isLogicBefore(currentDate, before, after) {
let logicBefore = before
if (before && after) {
logicBefore = dateCompare(before, after) ? before : after
}
return this.dateEqual(logicBefore, currentDate)
}
isLogicAfter(currentDate, before, after) {
let logicAfter = after
if (before && after) {
logicAfter = dateCompare(before, after) ? after : before
}
return this.dateEqual(logicAfter, currentDate)
}
/**
* 获取日期范围内所有日期
* @param {Object} begin
* @param {Object} end
*/
geDateAll(begin, end) {
var arr = []
var ab = begin.split('-')
var ae = end.split('-')
var db = new Date()
db.setFullYear(ab[0], ab[1] - 1, ab[2])
var de = new Date()
de.setFullYear(ae[0], ae[1] - 1, ae[2])
var unixDb = db.getTime() - 24 * 60 * 60 * 1000
var unixDe = de.getTime() - 24 * 60 * 60 * 1000
for (var k = unixDb; k <= unixDe;) {
k = k + 24 * 60 * 60 * 1000
arr.push(this.getDateObj(new Date(parseInt(k))).fullDate)
}
return arr
}
/**
* 获取多选状态
*/
setMultiple(fullDate) {
if (!this.range) return
let {
before,
after
} = this.multipleStatus
if (before && after) {
if (!this.lastHover) {
this.lastHover = true
return
}
this.multipleStatus.before = fullDate
this.multipleStatus.after = ''
this.multipleStatus.data = []
this.multipleStatus.fulldate = ''
this.lastHover = false
} else {
if (!before) {
this.multipleStatus.before = fullDate
this.multipleStatus.after = undefined;
this.lastHover = false
} else {
this.multipleStatus.after = fullDate
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
.after);
} else {
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus
.before);
}
this.lastHover = true
}
}
this.getWeeks(fullDate)
}
/**
* 鼠标 hover 更新多选状态
*/
setHoverMultiple(fullDate) {
//抖音小程序点击会触发hover事件需要避免一下
// #ifndef MP-TOUTIAO
if (!this.range || this.lastHover) return
const {
before
} = this.multipleStatus
if (!before) {
this.multipleStatus.before = fullDate
} else {
this.multipleStatus.after = fullDate
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
} else {
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
}
}
this.getWeeks(fullDate)
// #endif
}
/**
* 更新默认值多选状态
*/
setDefaultMultiple(before, after) {
this.multipleStatus.before = before
this.multipleStatus.after = after
if (before && after) {
if (dateCompare(before, after)) {
this.multipleStatus.data = this.geDateAll(before, after);
this.getWeeks(after)
} else {
this.multipleStatus.data = this.geDateAll(after, before);
this.getWeeks(before)
}
}
}
/**
* 获取每周数据
* @param {Object} dateData
*/
getWeeks(dateData) {
const {
year,
month,
} = this.getDateObj(dateData)
const preMonthDayAmount = new Date(year, month - 1, 1).getDay()
const preMonthDays = this.getPreMonthDays(preMonthDayAmount, this.getDateObj(dateData))
const currentMonthDayAmount = new Date(year, month, 0).getDate()
const currentMonthDays = this.getCurrentMonthDays(currentMonthDayAmount, this.getDateObj(dateData))
const nextMonthDayAmount = 42 - preMonthDayAmount - currentMonthDayAmount
const nextMonthDays = this._getNextMonthDays(nextMonthDayAmount, this.getDateObj(dateData))
const calendarDays = [...preMonthDays, ...currentMonthDays, ...nextMonthDays]
const weeks = new Array(6)
for (let i = 0; i < calendarDays.length; i++) {
const index = Math.floor(i / 7)
if (!weeks[index]) {
weeks[index] = new Array(7)
}
weeks[index][i % 7] = calendarDays[i]
}
this.calendar = calendarDays
this.weeks = weeks
}
}
function getDateTime(date, hideSecond) {
return `${getDate(date)} ${getTime(date, hideSecond)}`
}
function getDate(date) {
date = fixIosDateFormat(date)
date = new Date(date)
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
return `${year}-${addZero(month)}-${addZero(day)}`
}
function getTime(date, hideSecond) {
date = fixIosDateFormat(date)
date = new Date(date)
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return hideSecond ? `${addZero(hour)}:${addZero(minute)}` : `${addZero(hour)}:${addZero(minute)}:${addZero(second)}`
}
function addZero(num) {
if (num < 10) {
num = `0${num}`
}
return num
}
function getDefaultSecond(hideSecond) {
return hideSecond ? '00:00' : '00:00:00'
}
function dateCompare(startDate, endDate) {
startDate = new Date(fixIosDateFormat(startDate))
endDate = new Date(fixIosDateFormat(endDate))
return startDate <= endDate
}
function checkDate(date) {
const dateReg = /((19|20)\d{2})(-|\/)\d{1,2}(-|\/)\d{1,2}/g
return date.match(dateReg)
}
//ios低版本15及以下无法匹配 没有 ’秒‘ 时的情况,所以需要在末尾 秒 加上 问号
const dateTimeReg = /^\d{4}-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])( [0-5]?[0-9]:[0-5]?[0-9](:[0-5]?[0-9])?)?$/;
function fixIosDateFormat(value) {
if (typeof value === 'string' && dateTimeReg.test(value)) {
value = value.replace(/-/g, '/')
}
return value
}
export {
Calendar,
getDateTime,
getDate,
getTime,
addZero,
getDefaultSecond,
dateCompare,
checkDate,
fixIosDateFormat
}

View File

@ -0,0 +1,90 @@
{
"id": "uni-datetime-picker",
"displayName": "uni-datetime-picker 日期选择器",
"version": "2.2.40",
"description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
"keywords": [
"uni-datetime-picker",
"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",
"alipay": "n"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "n",
"app-harmony": "u",
"app-uvue": "u"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@ -0,0 +1,21 @@
> `重要通知:组件升级更新 2.0.0 后,支持日期+时间范围选择,组件 ui 将使用日历选择日期ui 变化较大,同时支持 PC 和 移动端。此版本不向后兼容不再支持单独的时间选择type=time及相关的 hide-second 属性(时间选可使用内置组件 picker。若仍需使用旧版本可在插件市场下载*非uni_modules版本*,旧版本将不再维护`
## DatetimePicker 时间选择器
> **组件名uni-datetime-picker**
> 代码块: `uDatetimePicker`
该组件的优势是,支持**时间戳**输入和输出(起始时间、终止时间也支持时间戳),可**同时选择**日期和时间。
若只是需要单独选择日期和时间,不需要时间戳输入和输出,可使用原生的 picker 组件。
**_点击 picker 默认值规则_**
- 若设置初始值 value, 会显示在 picker 显示框中
- 若无初始值 value则初始值 value 为当前本地时间 Date.now() 但不会显示在 picker 显示框中
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@ -1,3 +1,23 @@
## 2.0.102024-06-07
- 优化 uni-app x 中size 属性的类型
## 2.0.92024-01-12
fix: 修复图标大小默认值错误的问题
## 2.0.82023-12-14
- 修复 项目未使用 ts 情况下打包报错的bug
## 2.0.72023-12-14
- 修复 size 属性为 string 时不加单位导致尺寸异常的bug
## 2.0.62023-12-11
- 优化 兼容老版本icon类型如 top bottom 等
## 2.0.52023-12-11
- 优化 兼容老版本icon类型如 top bottom 等
## 2.0.42023-12-06
- 优化 uni-app x 下示例项目图标排序
## 2.0.32023-12-06
- 修复 nvue下引入组件报错的bug
## 2.0.22023-12-05
-优化 size 属性支持单位
## 2.0.12023-12-05
- 新增 uni-app x 支持定义图标
## 1.3.52022-01-24
- 优化 size 属性可以传入不带单位的字符串数值
## 1.3.42022-01-24

View File

@ -0,0 +1,91 @@
<template>
<text class="uni-icons" :style="styleObj">
<slot>{{unicode}}</slot>
</text>
</template>
<script>
import { fontData, IconsDataItem } from './uniicons_file'
/**
* Icons 图标
* @description 用于展示 icon 图标
* @tutorial https://ext.dcloud.net.cn/plugin?id=28
* @property {Number,String} size 图标大小
* @property {String} type 图标图案,参考示例
* @property {String} color 图标颜色
* @property {String} customPrefix 自定义图标
* @event {Function} click 点击 Icon 触发事件
*/
export default {
name: "uni-icons",
props: {
type: {
type: String,
default: ''
},
color: {
type: String,
default: '#333333'
},
size: {
type: [Number, String],
default: 16
},
fontFamily: {
type: String,
default: ''
}
},
data() {
return {};
},
computed: {
unicode() : string {
let codes = fontData.find((item : IconsDataItem) : boolean => { return item.font_class == this.type })
if (codes !== null) {
return codes.unicode
}
return ''
},
iconSize() : string {
const size = this.size
if (typeof size == 'string') {
const reg = /^[0-9]*$/g
return reg.test(size as string) ? '' + size + 'px' : '' + size;
// return '' + this.size
}
return this.getFontSize(size as number)
},
styleObj() : UTSJSONObject {
if (this.fontFamily !== '') {
return { color: this.color, fontSize: this.iconSize, fontFamily: this.fontFamily }
}
return { color: this.color, fontSize: this.iconSize }
}
},
created() { },
methods: {
/**
* 字体大小
*/
getFontSize(size : number) : string {
return size + 'px';
},
},
}
</script>
<style scoped>
@font-face {
font-family: UniIconsFontFamily;
src: url('./uniicons.ttf');
}
.uni-icons {
font-family: UniIconsFontFamily;
font-size: 18px;
font-style: normal;
color: #333;
}
</style>

View File

@ -1,18 +1,22 @@
<template>
<!-- #ifdef APP-NVUE -->
<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" @click="_onClick">{{unicode}}</text>
<text :style="styleObj" class="uni-icons" @click="_onClick">{{unicode}}</text>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick"></text>
<text :style="styleObj" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick">
<slot></slot>
</text>
<!-- #endif -->
</template>
<script>
import icons from './icons.js';
import { fontData } from './uniicons_file_vue.js';
const getVal = (val) => {
const reg = /^[0-9]*$/g
return (typeof val === 'number' || reg.test(val) )? val + 'px' : val;
return (typeof val === 'number' || reg.test(val)) ? val + 'px' : val;
}
// #ifdef APP-NVUE
var domModule = weex.requireModule('dom');
import iconUrl from './uniicons.ttf'
@ -51,23 +55,33 @@
customPrefix: {
type: String,
default: ''
},
fontFamily: {
type: String,
default: ''
}
},
data() {
return {
icons: icons.glyphs
icons: fontData
}
},
computed: {
unicode() {
let code = this.icons.find(v => v.font_class === this.type)
if (code) {
return unescape(`%u${code.unicode}`)
return code.unicode
}
return ''
},
iconSize() {
return getVal(this.size)
},
styleObj() {
if (this.fontFamily !== '') {
return `color: ${this.color}; font-size: ${this.iconSize}; font-family: ${this.fontFamily};`
}
return `color: ${this.color}; font-size: ${this.iconSize};`
}
},
methods: {
@ -81,9 +95,10 @@
<style lang="scss">
/* #ifndef APP-NVUE */
@import './uniicons.css';
@font-face {
font-family: uniicons;
src: url('./uniicons.ttf') format('truetype');
src: url('./uniicons.ttf');
}
/* #endif */
@ -92,5 +107,4 @@
text-decoration: none;
text-align: center;
}
</style>

View File

@ -1,3 +1,12 @@
.uniui-cart-filled:before {
content: "\e6d0";
}
.uniui-gift-filled:before {
content: "\e6c4";
}
.uniui-color:before {
content: "\e6cf";
}
@ -58,10 +67,6 @@
content: "\e6c3";
}
.uniui-gift-filled:before {
content: "\e6c4";
}
.uniui-fire-filled:before {
content: "\e6c5";
}
@ -82,6 +87,18 @@
content: "\e698";
}
.uniui-arrowthinleft:before {
content: "\e6d2";
}
.uniui-arrowthinup:before {
content: "\e6d3";
}
.uniui-arrowthindown:before {
content: "\e6d4";
}
.uniui-back:before {
content: "\e6b9";
}
@ -94,55 +111,43 @@
content: "\e6bb";
}
.uniui-arrowthinright:before {
content: "\e6bb";
}
.uniui-arrow-left:before {
content: "\e6bc";
}
.uniui-arrowthinleft:before {
content: "\e6bc";
}
.uniui-arrow-up:before {
content: "\e6bd";
}
.uniui-arrowthinup:before {
content: "\e6bd";
}
.uniui-arrow-down:before {
content: "\e6be";
}
.uniui-arrowthindown:before {
content: "\e6be";
.uniui-arrowthinright:before {
content: "\e6d1";
}
.uniui-down:before {
content: "\e6b8";
}
.uniui-bottom:before {
content: "\e6b8";
}
.uniui-arrowdown:before {
content: "\e6b8";
.uniui-arrowright:before {
content: "\e6d5";
}
.uniui-right:before {
content: "\e6b5";
}
.uniui-arrowright:before {
content: "\e6b5";
}
.uniui-top:before {
.uniui-up:before {
content: "\e6b6";
}
.uniui-arrowup:before {
.uniui-top:before {
content: "\e6b6";
}
@ -150,8 +155,8 @@
content: "\e6b7";
}
.uniui-arrowleft:before {
content: "\e6b7";
.uniui-arrowup:before {
content: "\e6d6";
}
.uniui-eye:before {
@ -638,10 +643,6 @@
content: "\e627";
}
.uniui-cart-filled:before {
content: "\e629";
}
.uniui-checkbox:before {
content: "\e62b";
}

View File

@ -0,0 +1,664 @@
export type IconsData = {
id : string
name : string
font_family : string
css_prefix_text : string
description : string
glyphs : Array<IconsDataItem>
}
export type IconsDataItem = {
font_class : string
unicode : string
}
export const fontData = [
{
"font_class": "arrow-down",
"unicode": "\ue6be"
},
{
"font_class": "arrow-left",
"unicode": "\ue6bc"
},
{
"font_class": "arrow-right",
"unicode": "\ue6bb"
},
{
"font_class": "arrow-up",
"unicode": "\ue6bd"
},
{
"font_class": "auth",
"unicode": "\ue6ab"
},
{
"font_class": "auth-filled",
"unicode": "\ue6cc"
},
{
"font_class": "back",
"unicode": "\ue6b9"
},
{
"font_class": "bars",
"unicode": "\ue627"
},
{
"font_class": "calendar",
"unicode": "\ue6a0"
},
{
"font_class": "calendar-filled",
"unicode": "\ue6c0"
},
{
"font_class": "camera",
"unicode": "\ue65a"
},
{
"font_class": "camera-filled",
"unicode": "\ue658"
},
{
"font_class": "cart",
"unicode": "\ue631"
},
{
"font_class": "cart-filled",
"unicode": "\ue6d0"
},
{
"font_class": "chat",
"unicode": "\ue65d"
},
{
"font_class": "chat-filled",
"unicode": "\ue659"
},
{
"font_class": "chatboxes",
"unicode": "\ue696"
},
{
"font_class": "chatboxes-filled",
"unicode": "\ue692"
},
{
"font_class": "chatbubble",
"unicode": "\ue697"
},
{
"font_class": "chatbubble-filled",
"unicode": "\ue694"
},
{
"font_class": "checkbox",
"unicode": "\ue62b"
},
{
"font_class": "checkbox-filled",
"unicode": "\ue62c"
},
{
"font_class": "checkmarkempty",
"unicode": "\ue65c"
},
{
"font_class": "circle",
"unicode": "\ue65b"
},
{
"font_class": "circle-filled",
"unicode": "\ue65e"
},
{
"font_class": "clear",
"unicode": "\ue66d"
},
{
"font_class": "close",
"unicode": "\ue673"
},
{
"font_class": "closeempty",
"unicode": "\ue66c"
},
{
"font_class": "cloud-download",
"unicode": "\ue647"
},
{
"font_class": "cloud-download-filled",
"unicode": "\ue646"
},
{
"font_class": "cloud-upload",
"unicode": "\ue645"
},
{
"font_class": "cloud-upload-filled",
"unicode": "\ue648"
},
{
"font_class": "color",
"unicode": "\ue6cf"
},
{
"font_class": "color-filled",
"unicode": "\ue6c9"
},
{
"font_class": "compose",
"unicode": "\ue67f"
},
{
"font_class": "contact",
"unicode": "\ue693"
},
{
"font_class": "contact-filled",
"unicode": "\ue695"
},
{
"font_class": "down",
"unicode": "\ue6b8"
},
{
"font_class": "bottom",
"unicode": "\ue6b8"
},
{
"font_class": "download",
"unicode": "\ue68d"
},
{
"font_class": "download-filled",
"unicode": "\ue681"
},
{
"font_class": "email",
"unicode": "\ue69e"
},
{
"font_class": "email-filled",
"unicode": "\ue69a"
},
{
"font_class": "eye",
"unicode": "\ue651"
},
{
"font_class": "eye-filled",
"unicode": "\ue66a"
},
{
"font_class": "eye-slash",
"unicode": "\ue6b3"
},
{
"font_class": "eye-slash-filled",
"unicode": "\ue6b4"
},
{
"font_class": "fire",
"unicode": "\ue6a1"
},
{
"font_class": "fire-filled",
"unicode": "\ue6c5"
},
{
"font_class": "flag",
"unicode": "\ue65f"
},
{
"font_class": "flag-filled",
"unicode": "\ue660"
},
{
"font_class": "folder-add",
"unicode": "\ue6a9"
},
{
"font_class": "folder-add-filled",
"unicode": "\ue6c8"
},
{
"font_class": "font",
"unicode": "\ue6a3"
},
{
"font_class": "forward",
"unicode": "\ue6ba"
},
{
"font_class": "gear",
"unicode": "\ue664"
},
{
"font_class": "gear-filled",
"unicode": "\ue661"
},
{
"font_class": "gift",
"unicode": "\ue6a4"
},
{
"font_class": "gift-filled",
"unicode": "\ue6c4"
},
{
"font_class": "hand-down",
"unicode": "\ue63d"
},
{
"font_class": "hand-down-filled",
"unicode": "\ue63c"
},
{
"font_class": "hand-up",
"unicode": "\ue63f"
},
{
"font_class": "hand-up-filled",
"unicode": "\ue63e"
},
{
"font_class": "headphones",
"unicode": "\ue630"
},
{
"font_class": "heart",
"unicode": "\ue639"
},
{
"font_class": "heart-filled",
"unicode": "\ue641"
},
{
"font_class": "help",
"unicode": "\ue679"
},
{
"font_class": "help-filled",
"unicode": "\ue674"
},
{
"font_class": "home",
"unicode": "\ue662"
},
{
"font_class": "home-filled",
"unicode": "\ue663"
},
{
"font_class": "image",
"unicode": "\ue670"
},
{
"font_class": "image-filled",
"unicode": "\ue678"
},
{
"font_class": "images",
"unicode": "\ue650"
},
{
"font_class": "images-filled",
"unicode": "\ue64b"
},
{
"font_class": "info",
"unicode": "\ue669"
},
{
"font_class": "info-filled",
"unicode": "\ue649"
},
{
"font_class": "left",
"unicode": "\ue6b7"
},
{
"font_class": "link",
"unicode": "\ue6a5"
},
{
"font_class": "list",
"unicode": "\ue644"
},
{
"font_class": "location",
"unicode": "\ue6ae"
},
{
"font_class": "location-filled",
"unicode": "\ue6af"
},
{
"font_class": "locked",
"unicode": "\ue66b"
},
{
"font_class": "locked-filled",
"unicode": "\ue668"
},
{
"font_class": "loop",
"unicode": "\ue633"
},
{
"font_class": "mail-open",
"unicode": "\ue643"
},
{
"font_class": "mail-open-filled",
"unicode": "\ue63a"
},
{
"font_class": "map",
"unicode": "\ue667"
},
{
"font_class": "map-filled",
"unicode": "\ue666"
},
{
"font_class": "map-pin",
"unicode": "\ue6ad"
},
{
"font_class": "map-pin-ellipse",
"unicode": "\ue6ac"
},
{
"font_class": "medal",
"unicode": "\ue6a2"
},
{
"font_class": "medal-filled",
"unicode": "\ue6c3"
},
{
"font_class": "mic",
"unicode": "\ue671"
},
{
"font_class": "mic-filled",
"unicode": "\ue677"
},
{
"font_class": "micoff",
"unicode": "\ue67e"
},
{
"font_class": "micoff-filled",
"unicode": "\ue6b0"
},
{
"font_class": "minus",
"unicode": "\ue66f"
},
{
"font_class": "minus-filled",
"unicode": "\ue67d"
},
{
"font_class": "more",
"unicode": "\ue64d"
},
{
"font_class": "more-filled",
"unicode": "\ue64e"
},
{
"font_class": "navigate",
"unicode": "\ue66e"
},
{
"font_class": "navigate-filled",
"unicode": "\ue67a"
},
{
"font_class": "notification",
"unicode": "\ue6a6"
},
{
"font_class": "notification-filled",
"unicode": "\ue6c1"
},
{
"font_class": "paperclip",
"unicode": "\ue652"
},
{
"font_class": "paperplane",
"unicode": "\ue672"
},
{
"font_class": "paperplane-filled",
"unicode": "\ue675"
},
{
"font_class": "person",
"unicode": "\ue699"
},
{
"font_class": "person-filled",
"unicode": "\ue69d"
},
{
"font_class": "personadd",
"unicode": "\ue69f"
},
{
"font_class": "personadd-filled",
"unicode": "\ue698"
},
{
"font_class": "personadd-filled-copy",
"unicode": "\ue6d1"
},
{
"font_class": "phone",
"unicode": "\ue69c"
},
{
"font_class": "phone-filled",
"unicode": "\ue69b"
},
{
"font_class": "plus",
"unicode": "\ue676"
},
{
"font_class": "plus-filled",
"unicode": "\ue6c7"
},
{
"font_class": "plusempty",
"unicode": "\ue67b"
},
{
"font_class": "pulldown",
"unicode": "\ue632"
},
{
"font_class": "pyq",
"unicode": "\ue682"
},
{
"font_class": "qq",
"unicode": "\ue680"
},
{
"font_class": "redo",
"unicode": "\ue64a"
},
{
"font_class": "redo-filled",
"unicode": "\ue655"
},
{
"font_class": "refresh",
"unicode": "\ue657"
},
{
"font_class": "refresh-filled",
"unicode": "\ue656"
},
{
"font_class": "refreshempty",
"unicode": "\ue6bf"
},
{
"font_class": "reload",
"unicode": "\ue6b2"
},
{
"font_class": "right",
"unicode": "\ue6b5"
},
{
"font_class": "scan",
"unicode": "\ue62a"
},
{
"font_class": "search",
"unicode": "\ue654"
},
{
"font_class": "settings",
"unicode": "\ue653"
},
{
"font_class": "settings-filled",
"unicode": "\ue6ce"
},
{
"font_class": "shop",
"unicode": "\ue62f"
},
{
"font_class": "shop-filled",
"unicode": "\ue6cd"
},
{
"font_class": "smallcircle",
"unicode": "\ue67c"
},
{
"font_class": "smallcircle-filled",
"unicode": "\ue665"
},
{
"font_class": "sound",
"unicode": "\ue684"
},
{
"font_class": "sound-filled",
"unicode": "\ue686"
},
{
"font_class": "spinner-cycle",
"unicode": "\ue68a"
},
{
"font_class": "staff",
"unicode": "\ue6a7"
},
{
"font_class": "staff-filled",
"unicode": "\ue6cb"
},
{
"font_class": "star",
"unicode": "\ue688"
},
{
"font_class": "star-filled",
"unicode": "\ue68f"
},
{
"font_class": "starhalf",
"unicode": "\ue683"
},
{
"font_class": "trash",
"unicode": "\ue687"
},
{
"font_class": "trash-filled",
"unicode": "\ue685"
},
{
"font_class": "tune",
"unicode": "\ue6aa"
},
{
"font_class": "tune-filled",
"unicode": "\ue6ca"
},
{
"font_class": "undo",
"unicode": "\ue64f"
},
{
"font_class": "undo-filled",
"unicode": "\ue64c"
},
{
"font_class": "up",
"unicode": "\ue6b6"
},
{
"font_class": "top",
"unicode": "\ue6b6"
},
{
"font_class": "upload",
"unicode": "\ue690"
},
{
"font_class": "upload-filled",
"unicode": "\ue68e"
},
{
"font_class": "videocam",
"unicode": "\ue68c"
},
{
"font_class": "videocam-filled",
"unicode": "\ue689"
},
{
"font_class": "vip",
"unicode": "\ue6a8"
},
{
"font_class": "vip-filled",
"unicode": "\ue6c6"
},
{
"font_class": "wallet",
"unicode": "\ue6b1"
},
{
"font_class": "wallet-filled",
"unicode": "\ue6c2"
},
{
"font_class": "weibo",
"unicode": "\ue68b"
},
{
"font_class": "weixin",
"unicode": "\ue691"
}
] as IconsDataItem[]
// export const fontData = JSON.parse<IconsDataItem>(fontDataJson)

View File

@ -0,0 +1,649 @@
export const fontData = [
{
"font_class": "arrow-down",
"unicode": "\ue6be"
},
{
"font_class": "arrow-left",
"unicode": "\ue6bc"
},
{
"font_class": "arrow-right",
"unicode": "\ue6bb"
},
{
"font_class": "arrow-up",
"unicode": "\ue6bd"
},
{
"font_class": "auth",
"unicode": "\ue6ab"
},
{
"font_class": "auth-filled",
"unicode": "\ue6cc"
},
{
"font_class": "back",
"unicode": "\ue6b9"
},
{
"font_class": "bars",
"unicode": "\ue627"
},
{
"font_class": "calendar",
"unicode": "\ue6a0"
},
{
"font_class": "calendar-filled",
"unicode": "\ue6c0"
},
{
"font_class": "camera",
"unicode": "\ue65a"
},
{
"font_class": "camera-filled",
"unicode": "\ue658"
},
{
"font_class": "cart",
"unicode": "\ue631"
},
{
"font_class": "cart-filled",
"unicode": "\ue6d0"
},
{
"font_class": "chat",
"unicode": "\ue65d"
},
{
"font_class": "chat-filled",
"unicode": "\ue659"
},
{
"font_class": "chatboxes",
"unicode": "\ue696"
},
{
"font_class": "chatboxes-filled",
"unicode": "\ue692"
},
{
"font_class": "chatbubble",
"unicode": "\ue697"
},
{
"font_class": "chatbubble-filled",
"unicode": "\ue694"
},
{
"font_class": "checkbox",
"unicode": "\ue62b"
},
{
"font_class": "checkbox-filled",
"unicode": "\ue62c"
},
{
"font_class": "checkmarkempty",
"unicode": "\ue65c"
},
{
"font_class": "circle",
"unicode": "\ue65b"
},
{
"font_class": "circle-filled",
"unicode": "\ue65e"
},
{
"font_class": "clear",
"unicode": "\ue66d"
},
{
"font_class": "close",
"unicode": "\ue673"
},
{
"font_class": "closeempty",
"unicode": "\ue66c"
},
{
"font_class": "cloud-download",
"unicode": "\ue647"
},
{
"font_class": "cloud-download-filled",
"unicode": "\ue646"
},
{
"font_class": "cloud-upload",
"unicode": "\ue645"
},
{
"font_class": "cloud-upload-filled",
"unicode": "\ue648"
},
{
"font_class": "color",
"unicode": "\ue6cf"
},
{
"font_class": "color-filled",
"unicode": "\ue6c9"
},
{
"font_class": "compose",
"unicode": "\ue67f"
},
{
"font_class": "contact",
"unicode": "\ue693"
},
{
"font_class": "contact-filled",
"unicode": "\ue695"
},
{
"font_class": "down",
"unicode": "\ue6b8"
},
{
"font_class": "bottom",
"unicode": "\ue6b8"
},
{
"font_class": "download",
"unicode": "\ue68d"
},
{
"font_class": "download-filled",
"unicode": "\ue681"
},
{
"font_class": "email",
"unicode": "\ue69e"
},
{
"font_class": "email-filled",
"unicode": "\ue69a"
},
{
"font_class": "eye",
"unicode": "\ue651"
},
{
"font_class": "eye-filled",
"unicode": "\ue66a"
},
{
"font_class": "eye-slash",
"unicode": "\ue6b3"
},
{
"font_class": "eye-slash-filled",
"unicode": "\ue6b4"
},
{
"font_class": "fire",
"unicode": "\ue6a1"
},
{
"font_class": "fire-filled",
"unicode": "\ue6c5"
},
{
"font_class": "flag",
"unicode": "\ue65f"
},
{
"font_class": "flag-filled",
"unicode": "\ue660"
},
{
"font_class": "folder-add",
"unicode": "\ue6a9"
},
{
"font_class": "folder-add-filled",
"unicode": "\ue6c8"
},
{
"font_class": "font",
"unicode": "\ue6a3"
},
{
"font_class": "forward",
"unicode": "\ue6ba"
},
{
"font_class": "gear",
"unicode": "\ue664"
},
{
"font_class": "gear-filled",
"unicode": "\ue661"
},
{
"font_class": "gift",
"unicode": "\ue6a4"
},
{
"font_class": "gift-filled",
"unicode": "\ue6c4"
},
{
"font_class": "hand-down",
"unicode": "\ue63d"
},
{
"font_class": "hand-down-filled",
"unicode": "\ue63c"
},
{
"font_class": "hand-up",
"unicode": "\ue63f"
},
{
"font_class": "hand-up-filled",
"unicode": "\ue63e"
},
{
"font_class": "headphones",
"unicode": "\ue630"
},
{
"font_class": "heart",
"unicode": "\ue639"
},
{
"font_class": "heart-filled",
"unicode": "\ue641"
},
{
"font_class": "help",
"unicode": "\ue679"
},
{
"font_class": "help-filled",
"unicode": "\ue674"
},
{
"font_class": "home",
"unicode": "\ue662"
},
{
"font_class": "home-filled",
"unicode": "\ue663"
},
{
"font_class": "image",
"unicode": "\ue670"
},
{
"font_class": "image-filled",
"unicode": "\ue678"
},
{
"font_class": "images",
"unicode": "\ue650"
},
{
"font_class": "images-filled",
"unicode": "\ue64b"
},
{
"font_class": "info",
"unicode": "\ue669"
},
{
"font_class": "info-filled",
"unicode": "\ue649"
},
{
"font_class": "left",
"unicode": "\ue6b7"
},
{
"font_class": "link",
"unicode": "\ue6a5"
},
{
"font_class": "list",
"unicode": "\ue644"
},
{
"font_class": "location",
"unicode": "\ue6ae"
},
{
"font_class": "location-filled",
"unicode": "\ue6af"
},
{
"font_class": "locked",
"unicode": "\ue66b"
},
{
"font_class": "locked-filled",
"unicode": "\ue668"
},
{
"font_class": "loop",
"unicode": "\ue633"
},
{
"font_class": "mail-open",
"unicode": "\ue643"
},
{
"font_class": "mail-open-filled",
"unicode": "\ue63a"
},
{
"font_class": "map",
"unicode": "\ue667"
},
{
"font_class": "map-filled",
"unicode": "\ue666"
},
{
"font_class": "map-pin",
"unicode": "\ue6ad"
},
{
"font_class": "map-pin-ellipse",
"unicode": "\ue6ac"
},
{
"font_class": "medal",
"unicode": "\ue6a2"
},
{
"font_class": "medal-filled",
"unicode": "\ue6c3"
},
{
"font_class": "mic",
"unicode": "\ue671"
},
{
"font_class": "mic-filled",
"unicode": "\ue677"
},
{
"font_class": "micoff",
"unicode": "\ue67e"
},
{
"font_class": "micoff-filled",
"unicode": "\ue6b0"
},
{
"font_class": "minus",
"unicode": "\ue66f"
},
{
"font_class": "minus-filled",
"unicode": "\ue67d"
},
{
"font_class": "more",
"unicode": "\ue64d"
},
{
"font_class": "more-filled",
"unicode": "\ue64e"
},
{
"font_class": "navigate",
"unicode": "\ue66e"
},
{
"font_class": "navigate-filled",
"unicode": "\ue67a"
},
{
"font_class": "notification",
"unicode": "\ue6a6"
},
{
"font_class": "notification-filled",
"unicode": "\ue6c1"
},
{
"font_class": "paperclip",
"unicode": "\ue652"
},
{
"font_class": "paperplane",
"unicode": "\ue672"
},
{
"font_class": "paperplane-filled",
"unicode": "\ue675"
},
{
"font_class": "person",
"unicode": "\ue699"
},
{
"font_class": "person-filled",
"unicode": "\ue69d"
},
{
"font_class": "personadd",
"unicode": "\ue69f"
},
{
"font_class": "personadd-filled",
"unicode": "\ue698"
},
{
"font_class": "personadd-filled-copy",
"unicode": "\ue6d1"
},
{
"font_class": "phone",
"unicode": "\ue69c"
},
{
"font_class": "phone-filled",
"unicode": "\ue69b"
},
{
"font_class": "plus",
"unicode": "\ue676"
},
{
"font_class": "plus-filled",
"unicode": "\ue6c7"
},
{
"font_class": "plusempty",
"unicode": "\ue67b"
},
{
"font_class": "pulldown",
"unicode": "\ue632"
},
{
"font_class": "pyq",
"unicode": "\ue682"
},
{
"font_class": "qq",
"unicode": "\ue680"
},
{
"font_class": "redo",
"unicode": "\ue64a"
},
{
"font_class": "redo-filled",
"unicode": "\ue655"
},
{
"font_class": "refresh",
"unicode": "\ue657"
},
{
"font_class": "refresh-filled",
"unicode": "\ue656"
},
{
"font_class": "refreshempty",
"unicode": "\ue6bf"
},
{
"font_class": "reload",
"unicode": "\ue6b2"
},
{
"font_class": "right",
"unicode": "\ue6b5"
},
{
"font_class": "scan",
"unicode": "\ue62a"
},
{
"font_class": "search",
"unicode": "\ue654"
},
{
"font_class": "settings",
"unicode": "\ue653"
},
{
"font_class": "settings-filled",
"unicode": "\ue6ce"
},
{
"font_class": "shop",
"unicode": "\ue62f"
},
{
"font_class": "shop-filled",
"unicode": "\ue6cd"
},
{
"font_class": "smallcircle",
"unicode": "\ue67c"
},
{
"font_class": "smallcircle-filled",
"unicode": "\ue665"
},
{
"font_class": "sound",
"unicode": "\ue684"
},
{
"font_class": "sound-filled",
"unicode": "\ue686"
},
{
"font_class": "spinner-cycle",
"unicode": "\ue68a"
},
{
"font_class": "staff",
"unicode": "\ue6a7"
},
{
"font_class": "staff-filled",
"unicode": "\ue6cb"
},
{
"font_class": "star",
"unicode": "\ue688"
},
{
"font_class": "star-filled",
"unicode": "\ue68f"
},
{
"font_class": "starhalf",
"unicode": "\ue683"
},
{
"font_class": "trash",
"unicode": "\ue687"
},
{
"font_class": "trash-filled",
"unicode": "\ue685"
},
{
"font_class": "tune",
"unicode": "\ue6aa"
},
{
"font_class": "tune-filled",
"unicode": "\ue6ca"
},
{
"font_class": "undo",
"unicode": "\ue64f"
},
{
"font_class": "undo-filled",
"unicode": "\ue64c"
},
{
"font_class": "up",
"unicode": "\ue6b6"
},
{
"font_class": "top",
"unicode": "\ue6b6"
},
{
"font_class": "upload",
"unicode": "\ue690"
},
{
"font_class": "upload-filled",
"unicode": "\ue68e"
},
{
"font_class": "videocam",
"unicode": "\ue68c"
},
{
"font_class": "videocam-filled",
"unicode": "\ue689"
},
{
"font_class": "vip",
"unicode": "\ue6a8"
},
{
"font_class": "vip-filled",
"unicode": "\ue6c6"
},
{
"font_class": "wallet",
"unicode": "\ue6b1"
},
{
"font_class": "wallet-filled",
"unicode": "\ue6c2"
},
{
"font_class": "weibo",
"unicode": "\ue68b"
},
{
"font_class": "weixin",
"unicode": "\ue691"
}
]
// export const fontData = JSON.parse<IconsDataItem>(fontDataJson)

View File

@ -1,7 +1,7 @@
{
"id": "uni-icons",
"displayName": "uni-icons 图标",
"version": "1.3.5",
"version": "2.0.10",
"description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
"keywords": [
"uni-ui",
@ -17,10 +17,6 @@
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
@ -37,7 +33,8 @@
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": ["uni-scss"],
@ -45,12 +42,14 @@
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
"aliyun": "y",
"alipay": "n"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
"app-nvue": "y",
"app-uvue": "y"
},
"H5-mobile": {
"Safari": "y",
@ -70,11 +69,15 @@
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
"QQ": "y",
"钉钉": "y",
"快手": "y",
"飞书": "y",
"京东": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
"华为": "y",
"联盟": "y"
},
"Vue": {
"vue2": "y",

View File

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

View File

@ -0,0 +1,460 @@
<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: {
// #ifdef MP-TOUTIAO
virtualHost: false,
// #endif
// #ifndef MP-TOUTIAO
virtualHost: true
// #endif
},
emits:['selection-change'],
props: {
data: {
type: Array,
default() {
return []
}
},
// 线
border: {
type: Boolean,
default: false
},
// 线
stripe: {
type: Boolean,
default: false
},
//
type: {
type: String,
default: ''
},
//
emptyText: {
type: String,
default: '没有更多数据'
},
loading: {
type: Boolean,
default: false
},
rowKey: {
type: String,
default: ''
}
},
data() {
return {
noData: true,
minWidth: 0,
multiTableHeads: []
}
},
watch: {
loading(val) {},
data(newVal) {
let theadChildren = this.theadChildren
let rowspan = 1
if (this.theadChildren) {
rowspan = this.theadChildren.rowspan
}
// this.trChildren.length - rowspan
this.noData = false
// this.noData = newVal.length === 0
}
},
created() {
// tr
this.trChildren = []
this.thChildren = []
this.theadChildren = null
this.backData = []
this.backIndexData = []
},
methods: {
isNodata() {
let theadChildren = this.theadChildren
let rowspan = 1
if (this.theadChildren) {
rowspan = this.theadChildren.rowspan
}
this.noData = this.trChildren.length - rowspan <= 0
},
/**
* 选中所有
*/
selectionAll() {
let startIndex = 1
let theadChildren = this.theadChildren
if (!this.theadChildren) {
theadChildren = this.trChildren[0]
} else {
startIndex = theadChildren.rowspan - 1
}
let isHaveData = this.data && this.data.length > 0
theadChildren.checked = true
theadChildren.indeterminate = false
this.trChildren.forEach((item, index) => {
if (!item.disabled) {
item.checked = true
if (isHaveData && item.keyValue) {
const row = this.data.find(v => v[this.rowKey] === item.keyValue)
if (!this.backData.find(v => v[this.rowKey] === row[this.rowKey])) {
this.backData.push(row)
}
}
if (index > (startIndex - 1) && this.backIndexData.indexOf(index - startIndex) === -1) {
this.backIndexData.push(index - startIndex)
}
}
})
// this.backData = JSON.parse(JSON.stringify(this.data))
this.$emit('selection-change', {
detail: {
value: this.backData,
index: this.backIndexData
}
})
},
/**
* 用于多选表格切换某一行的选中状态如果使用了第二个参数则是设置这一行选中与否selected true 则选中
*/
toggleRowSelection(row, selected) {
// if (!this.theadChildren) return
row = [].concat(row)
this.trChildren.forEach((item, index) => {
// if (item.keyValue) {
const select = row.findIndex(v => {
//
if (typeof v === 'number') {
return v === index - 1
} else {
return v[this.rowKey] === item.keyValue
}
})
let ischeck = item.checked
if (select !== -1) {
if (typeof selected === 'boolean') {
item.checked = selected
} else {
item.checked = !item.checked
}
if (ischeck !== item.checked) {
this.check(item.rowData||item, item.checked, item.rowData?item.keyValue:null, true)
}
}
// }
})
this.$emit('selection-change', {
detail: {
value: this.backData,
index:this.backIndexData
}
})
},
/**
* 用于多选表格清空用户的选择
*/
clearSelection() {
let theadChildren = this.theadChildren
if (!this.theadChildren) {
theadChildren = this.trChildren[0]
}
// if (!this.theadChildren) return
theadChildren.checked = false
theadChildren.indeterminate = false
this.trChildren.forEach(item => {
// if (item.keyValue) {
item.checked = false
// }
})
this.backData = []
this.backIndexData = []
this.$emit('selection-change', {
detail: {
value: [],
index: []
}
})
},
/**
* 用于多选表格切换所有行的选中状态
*/
toggleAllSelection() {
let list = []
let startIndex = 1
let theadChildren = this.theadChildren
if (!this.theadChildren) {
theadChildren = this.trChildren[0]
} else {
startIndex = theadChildren.rowspan - 1
}
this.trChildren.forEach((item, index) => {
if (!item.disabled) {
if (index > (startIndex - 1) ) {
list.push(index-startIndex)
}
}
})
this.toggleRowSelection(list)
},
/**
* 选中\取消选中
* @param {Object} child
* @param {Object} check
* @param {Object} rowValue
*/
check(child, check, keyValue, emit) {
let theadChildren = this.theadChildren
if (!this.theadChildren) {
theadChildren = this.trChildren[0]
}
let childDomIndex = this.trChildren.findIndex((item, index) => child === item)
if(childDomIndex < 0){
childDomIndex = this.data.findIndex(v=>v[this.rowKey] === keyValue) + 1
}
const dataLen = this.trChildren.filter(v => !v.disabled && v.keyValue).length
if (childDomIndex === 0) {
check ? this.selectionAll() : this.clearSelection()
return
}
if (check) {
if (keyValue) {
this.backData.push(child)
}
this.backIndexData.push(childDomIndex - 1)
} else {
const index = this.backData.findIndex(v => v[this.rowKey] === keyValue)
const idx = this.backIndexData.findIndex(item => item === childDomIndex - 1)
if (keyValue) {
this.backData.splice(index, 1)
}
this.backIndexData.splice(idx, 1)
}
const domCheckAll = this.trChildren.find((item, index) => index > 0 && !item.checked && !item.disabled)
if (!domCheckAll) {
theadChildren.indeterminate = false
theadChildren.checked = true
} else {
theadChildren.indeterminate = true
theadChildren.checked = false
}
if (this.backIndexData.length === 0) {
theadChildren.indeterminate = false
}
if (!emit) {
this.$emit('selection-change', {
detail: {
value: this.backData,
index: this.backIndexData
}
})
}
}
}
}
</script>
<style lang="scss">
$border-color: #ebeef5;
.uni-table-scroll {
width: 100%;
/* #ifndef APP-NVUE */
overflow-x: auto;
/* #endif */
}
.uni-table {
position: relative;
width: 100%;
border-radius: 5px;
// box-shadow: 0px 0px 3px 1px rgba(0, 0, 0, 0.1);
background-color: #fff;
/* #ifndef APP-NVUE */
box-sizing: border-box;
display: table;
overflow-x: auto;
::v-deep .uni-table-tr:nth-child(n + 2) {
&:hover {
background-color: #f5f7fa;
}
}
::v-deep .uni-table-thead {
.uni-table-tr {
// background-color: #f5f7fa;
&:hover {
background-color:#fafafa;
}
}
}
/* #endif */
}
.table--border {
border: 1px $border-color solid;
border-right: none;
}
.border-none {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
.table--stripe {
/* #ifndef APP-NVUE */
::v-deep .uni-table-tr:nth-child(2n + 3) {
background-color: #fafafa;
}
/* #endif */
}
/* 表格加载、无数据样式 */
.uni-table-loading {
position: relative;
/* #ifndef APP-NVUE */
display: table-row;
/* #endif */
height: 50px;
line-height: 50px;
overflow: hidden;
box-sizing: border-box;
}
.empty-border {
border-right: 1px $border-color solid;
}
.uni-table-text {
position: absolute;
right: 0;
left: 0;
text-align: center;
font-size: 14px;
color: #999;
}
.uni-table-mask {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(255, 255, 255, 0.8);
z-index: 99;
/* #ifndef APP-NVUE */
display: flex;
margin: auto;
transition: all 0.5s;
/* #endif */
justify-content: center;
align-items: center;
}
.uni-table--loader {
width: 30px;
height: 30px;
border: 2px solid #aaa;
// border-bottom-color: transparent;
border-radius: 50%;
/* #ifndef APP-NVUE */
animation: 2s uni-table--loader linear infinite;
/* #endif */
position: relative;
}
@keyframes uni-table--loader {
0% {
transform: rotate(360deg);
}
10% {
border-left-color: transparent;
}
20% {
border-bottom-color: transparent;
}
30% {
border-right-color: transparent;
}
40% {
border-top-color: transparent;
}
50% {
transform: rotate(0deg);
}
60% {
border-top-color: transparent;
}
70% {
border-left-color: transparent;
}
80% {
border-bottom-color: transparent;
}
90% {
border-right-color: transparent;
}
100% {
transform: rotate(-360deg);
}
}
</style>

View File

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

View File

@ -0,0 +1,95 @@
<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: {
// #ifdef MP-TOUTIAO
virtualHost: false,
// #endif
// #ifndef MP-TOUTIAO
virtualHost: true
// #endif
},
props: {
width: {
type: [String, Number],
default: ''
},
align: {
type: String,
default: 'left'
},
rowspan: {
type: [Number,String],
default: 1
},
colspan: {
type: [Number,String],
default: 1
}
},
data() {
return {
border: false
};
},
created() {
this.root = this.getTable()
this.border = this.root.border
},
methods: {
/**
* 获取父元素实例
*/
getTable() {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== 'uniTable') {
parent = parent.$parent;
if (!parent) return false;
parentName = parent.$options.name;
}
return parent;
},
}
}
</script>
<style lang="scss">
$border-color:#EBEEF5;
.uni-table-td {
display: table-cell;
padding: 8px 10px;
font-size: 14px;
border-bottom: 1px $border-color solid;
font-weight: 400;
color: #606266;
line-height: 23px;
box-sizing: border-box;
}
.table--border {
border-right: 1px $border-color solid;
}
</style>

View File

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

View File

@ -0,0 +1,295 @@
<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: {
// #ifdef MP-TOUTIAO
virtualHost: false,
// #endif
// #ifndef MP-TOUTIAO
virtualHost: true
// #endif
},
components: {
// #ifdef H5
dropdown
// #endif
},
emits:['sort-change','filter-change'],
props: {
width: {
type: [String, Number],
default: ''
},
align: {
type: String,
default: 'left'
},
rowspan: {
type: [Number, String],
default: 1
},
colspan: {
type: [Number, String],
default: 1
},
sortable: {
type: Boolean,
default: false
},
filterType: {
type: String,
default: ""
},
filterData: {
type: Array,
default () {
return []
}
},
filterDefaultValue: {
type: [Array,String],
default () {
return ""
}
}
},
data() {
return {
border: false,
ascending: false,
descending: false
}
},
computed: {
// propswidth th(px)
customWidth(){
if(typeof this.width === 'number'){
return this.width
} else if(typeof this.width === 'string') {
let regexHaveUnitPx = new RegExp(/^[1-9][0-9]*px$/g)
let regexHaveUnitRpx = new RegExp(/^[1-9][0-9]*rpx$/g)
let regexHaveNotUnit = new RegExp(/^[1-9][0-9]*$/g)
if (this.width.match(regexHaveUnitPx) !== null) { // px
return this.width.replace('px', '')
} else if (this.width.match(regexHaveUnitRpx) !== null) { // rpx
let numberRpx = Number(this.width.replace('rpx', ''))
// #ifdef MP-WEIXIN
let widthCoe = uni.getWindowInfo().screenWidth / 750
// #endif
// #ifndef MP-WEIXIN
let widthCoe = uni.getSystemInfoSync().screenWidth / 750
// #endif
return Math.round(numberRpx * widthCoe)
} else if (this.width.match(regexHaveNotUnit) !== null) { // rpxpx String
return this.width
} else { //
return ''
}
} else {
return ''
}
},
contentAlign() {
let align = 'left'
switch (this.align) {
case 'left':
align = 'flex-start'
break
case 'center':
align = 'center'
break
case 'right':
align = 'flex-end'
break
}
return align
}
},
created() {
this.root = this.getTable('uniTable')
this.rootTr = this.getTable('uniTr')
this.rootTr.minWidthUpdate(this.customWidth ? this.customWidth : 140)
this.border = this.root.border
this.root.thChildren.push(this)
},
methods: {
sort() {
if (!this.sortable) return
this.clearOther()
if (!this.ascending && !this.descending) {
this.ascending = true
this.$emit('sort-change', { order: 'ascending' })
return
}
if (this.ascending && !this.descending) {
this.ascending = false
this.descending = true
this.$emit('sort-change', { order: 'descending' })
return
}
if (!this.ascending && this.descending) {
this.ascending = false
this.descending = false
this.$emit('sort-change', { order: null })
}
},
ascendingFn() {
this.clearOther()
this.ascending = !this.ascending
this.descending = false
this.$emit('sort-change', { order: this.ascending ? 'ascending' : null })
},
descendingFn() {
this.clearOther()
this.descending = !this.descending
this.ascending = false
this.$emit('sort-change', { order: this.descending ? 'descending' : null })
},
clearOther() {
this.root.thChildren.map(item => {
if (item !== this) {
item.ascending = false
item.descending = false
}
return item
})
},
ondropdown(e) {
this.$emit("filter-change", e)
},
/**
* 获取父元素实例
*/
getTable(name) {
let parent = this.$parent
let parentName = parent.$options.name
while (parentName !== name) {
parent = parent.$parent
if (!parent) return false
parentName = parent.$options.name
}
return parent
}
}
}
</script>
<style lang="scss">
$border-color: #ebeef5;
$uni-primary: #007aff !default;
.uni-table-th {
padding: 12px 10px;
/* #ifndef APP-NVUE */
display: table-cell;
box-sizing: border-box;
/* #endif */
font-size: 14px;
font-weight: bold;
color: #909399;
border-bottom: 1px $border-color solid;
}
.uni-table-th-row {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.table--border {
border-right: 1px $border-color solid;
}
.uni-table-th-content {
display: flex;
align-items: center;
flex: 1;
}
.arrow-box {
}
.arrow {
display: block;
position: relative;
width: 10px;
height: 8px;
// border: 1px red solid;
left: 5px;
overflow: hidden;
cursor: pointer;
}
.down {
top: 3px;
::after {
content: '';
width: 8px;
height: 8px;
position: absolute;
left: 2px;
top: -5px;
transform: rotate(45deg);
background-color: #ccc;
}
&.active {
::after {
background-color: $uni-primary;
}
}
}
.up {
::after {
content: '';
width: 8px;
height: 8px;
position: absolute;
left: 2px;
top: 5px;
transform: rotate(45deg);
background-color: #ccc;
}
&.active {
::after {
background-color: $uni-primary;
}
}
}
</style>

View File

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

View File

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

View File

@ -0,0 +1,184 @@
<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: {
// #ifdef MP-TOUTIAO
virtualHost: false,
// #endif
// #ifndef MP-TOUTIAO
virtualHost: true
// #endif
},
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 = Number(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)
if (this.widthThArr.length > 0) {
const selectionWidth = this.selection === 'selection' ? 50 : 0;
this.root.minWidth = Number(this.widthThArr.reduce((a, b) => Number(a) + Number(b))) + selectionWidth;
}
},
//
checkboxSelected(e) {
let rootData = this.root.data.find(v => v[this.root.rowKey] === this.keyValue)
this.checked = e.checked
this.root.check(rootData || this, e.checked, rootData ? this.keyValue : null)
},
change(e) {
this.root.trChildren.forEach(item => {
if (item === this) {
this.root.check(this, e.detail.value.length > 0 ? true : false)
}
})
},
/**
* 获取父元素实例
*/
getTable(name = 'uniTable') {
let parent = this.$parent
let parentName = parent.$options.name
while (parentName !== name) {
parent = parent.$parent
if (!parent) return false
parentName = parent.$options.name
}
return parent
}
}
}
</script>
<style lang="scss">
$border-color: #ebeef5;
.uni-table-tr {
/* #ifndef APP-NVUE */
display: table-row;
transition: all 0.3s;
box-sizing: border-box;
/* #endif */
}
.checkbox {
padding: 0 8px;
width: 26px;
padding-left: 12px;
/* #ifndef APP-NVUE */
display: table-cell;
vertical-align: middle;
/* #endif */
color: #333;
font-weight: 500;
border-bottom: 1px $border-color solid;
font-size: 14px;
// text-align: center;
}
.tr-table--border {
border-right: 1px $border-color solid;
}
/* #ifndef APP-NVUE */
.uni-table-tr {
::v-deep .uni-table-th {
&.table--border:last-child {
// border-right: none;
}
}
::v-deep .uni-table-td {
&.table--border:last-child {
// border-right: none;
}
}
}
/* #endif */
</style>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,86 @@
{
"id": "uni-table",
"displayName": "uni-table 表格",
"version": "1.2.9",
"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",
"alipay": "n"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "n",
"app-harmony": "u",
"app-uvue": "u"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "n",
"QQ": "y"
},
"快应用": {
"华为": "n",
"联盟": "n"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

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

View File

@ -22,5 +22,8 @@ export const dateJsing = time =>{
}
export const dateWeek = time =>{
return dayjs.unix(time).format('dddMM.DD HH:mm')
return dayjs.unix(time).format('MM-DD(ddd) HH:mm')
}
export const dateWeekend = time =>{
return dayjs.unix(time).format('HH:mm')
}