Explorar el Código

添加邀约面试页面

wkw hace 2 semanas
padre
commit
d4e7848867

+ 21 - 0
App.vue

@@ -566,4 +566,25 @@
 	.bg {
 		background-color: #F7F7F7;
 	}
+	/*文本省略*/
+	.m-ellipsis {
+	    overflow: hidden;
+	    white-space: nowrap;
+	    text-overflow: ellipsis;
+	}
+	.m-ellipsis-l2,
+	.m-ellipsis-l3 {
+	    display: -webkit-box;
+	    overflow: hidden;
+	    text-overflow: ellipsis;
+	    -webkit-box-orient: vertical;
+	    word-break: break-all;
+	}
+	
+	.m-ellipsis-l2 {
+	    -webkit-line-clamp: 2;
+	}
+	.m-ellipsis-l3 {
+	    -webkit-line-clamp: 3;
+	}
 </style>

+ 43 - 29
common/config.js

@@ -1,31 +1,45 @@
-if (process.env.NODE_ENV !== 'development') {
-	//正式环境
-	const ROOTPATH = "https://yizhizan.edccc.cn/sqx_fast";
-	const ROOTPATH1 = "https://yizhizan.edccc.cn/sqx_fast";
-	const ROOTPATH2 = "wss://zp.xianmaxiong.com/wss/websocket/"; //联系客服
-	const ROOTPATH3 = "wss://zp.xianmaxiong.com/wss/chatSocket/"; //聊天
-	const ROOTPATH4 = "https://yizhizan.edccc.cn";
-	module.exports = {
-		APIHOST: ROOTPATH,
-		APIHOST1: ROOTPATH1,
-		WSHOST: ROOTPATH2,
-		WSHOST1: ROOTPATH3,
-		WSHOST4: ROOTPATH4
+// if (process.env.NODE_ENV !== 'development') {
+// 	//正式环境
+// 	const ROOTPATH = "https://yizhizan.edccc.cn/sqx_fast";
+// 	const ROOTPATH1 = "https://yizhizan.edccc.cn/sqx_fast";
+// 	const ROOTPATH2 = "wss://zp.xianmaxiong.com/wss/websocket/"; //联系客服
+// 	const ROOTPATH3 = "wss://zp.xianmaxiong.com/wss/chatSocket/"; //聊天
+// 	const ROOTPATH4 = "https://yizhizan.edccc.cn";
+// 	module.exports = {
+// 		APIHOST: ROOTPATH,
+// 		APIHOST1: ROOTPATH1,
+// 		WSHOST: ROOTPATH2,
+// 		WSHOST1: ROOTPATH3,
+// 		WSHOST4: ROOTPATH4
 	
-	};
-}else{
-	//测试环境
-	const ROOTPATH = "http://192.168.1.73:7155/sqx_fast";
-	const ROOTPATH1 = "http://192.168.1.73:7155/sqx_fast";
-	const ROOTPATH2 = "wss://zp.xianmaxiong.com/wss/websocket/"; //联系客服
-	const ROOTPATH3 = "wss://zp.xianmaxiong.com/wss/chatSocket/"; //聊天
-	const ROOTPATH4 = "http://192.168.1.73:7155";
-	module.exports = {
-		APIHOST: ROOTPATH,
-		APIHOST1: ROOTPATH1,
-		WSHOST: ROOTPATH2,
-		WSHOST1: ROOTPATH3,
-		WSHOST4: ROOTPATH4
+// 	};
+// }else{
+// 	//测试环境
+// 	const ROOTPATH = "http://192.168.1.73:7155/sqx_fast";
+// 	const ROOTPATH1 = "http://192.168.1.73:7155/sqx_fast";
+// 	const ROOTPATH2 = "wss://zp.xianmaxiong.com/wss/websocket/"; //联系客服
+// 	const ROOTPATH3 = "wss://zp.xianmaxiong.com/wss/chatSocket/"; //聊天
+// 	const ROOTPATH4 = "http://192.168.1.73:7155";
+// 	module.exports = {
+// 		APIHOST: ROOTPATH,
+// 		APIHOST1: ROOTPATH1,
+// 		WSHOST: ROOTPATH2,
+// 		WSHOST1: ROOTPATH3,
+// 		WSHOST4: ROOTPATH4
 	
-	};
-}
+// 	};
+// }
+
+const ROOTPATH = "https://yizhizan.edccc.cn/sqx_fast";
+const ROOTPATH1 = "https://yizhizan.edccc.cn/sqx_fast";
+const ROOTPATH2 = "wss://zp.xianmaxiong.com/wss/websocket/"; //联系客服
+const ROOTPATH3 = "wss://zp.xianmaxiong.com/wss/chatSocket/"; //聊天
+const ROOTPATH4 = "https://yizhizan.edccc.cn";
+module.exports = {
+	APIHOST: ROOTPATH,
+	APIHOST1: ROOTPATH1,
+	WSHOST: ROOTPATH2,
+	WSHOST1: ROOTPATH3,
+	WSHOST4: ROOTPATH4
+
+};

+ 1 - 1
main.js

@@ -20,7 +20,7 @@ Vue.prototype.$SysCache = HttpCache;
 App.mpType = 'app'
 
 // 引入全局uView
-import uView from "uview-ui";
+import uView from 'uview-ui'
 Vue.use(uView);
 
 const app = new Vue({

+ 17 - 1
pages.json

@@ -1,8 +1,24 @@
 {
 	"easycom": {
-		"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
+		"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
 	},
 	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+		{
+			"path": "pages/msg/interviewInvitation",
+			"style": {
+				"navigationBarTitleText": "面试邀约",
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path": "pages/msg/selectInterview",
+			"style": {
+				"navigationBarTitleText": "面试地址",
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom"
+			}
+		},
 		{
 			"path": "pages/index/index",
 			"style": {

+ 4 - 1
pages/msg/im.vue

@@ -1485,7 +1485,10 @@
 			// 显示更多选项
 			showMoreOptions() {
 				// 可以添加更多选项的弹窗或菜单
-				console.log('显示更多选项');
+				// console.log('显示更多选项');
+				uni.navigateTo({
+					url:'/pages/msg/interviewInvitation'
+				})
 			},
 			// 切换工作描述展开状态
 			toggleJobDesc() {

+ 618 - 0
pages/msg/interviewInvitation.vue

@@ -0,0 +1,618 @@
+<template>
+	<view class="container">
+		<view class="detail-bg"></view>
+		<nav-bar title="面试邀约"></nav-bar>
+		<view class="content">
+			<view class="detail-title">邀请面试</view>
+			<view class="card-box">
+				<view class="cell">
+					<view class="cell-label">面试类型</view>
+					<u-radio-group v-model="radioValue">
+						<u-radio name="0">线下面试</u-radio>
+						<u-radio name="1">线上面试</u-radio>
+					</u-radio-group>
+
+				</view>
+				<view class="cell">
+					<view class="cell-label">面试职位</view>
+					<view class="cell-input" hover-class="cell-hover" @click="position = true">
+						<view class="m-ellipsis">
+							{{ selectedJob ? selectedJob.title + ' · ' + selectedJob.salary : '请选择职位' }}</view>
+						<image class="cell-icon" src="/static/images/msg/down_arrow.svg" mode="aspectFit"></image>
+					</view>
+				</view>
+				<view class="cell" v-if="radioValue == 0">
+					<view class="cell-label">面试地址</view>
+					<view class="cell-input" hover-class="cell-hover" @click="goPage('address')">
+						<view class="m-ellipsis">{{selectedAddress || '请选择地址'}}</view>
+						<image class="cell-icon" src="/static/images/msg/down_arrow.svg" mode="aspectFit"></image>
+					</view>
+				</view>
+				<view class="cell" v-if="radioValue == 1">
+					<view class="cell-label">面试方式</view>
+					<view class="cell-input" hover-class="cell-hover" @click="method = true">
+						<view class="m-ellipsis">请选择面试方式</view>
+						<image class="cell-icon" src="/static/images/msg/down_arrow.svg" mode="aspectFit"></image>
+					</view>
+				</view>
+				<view class="cell">
+					<view class="cell-label">联系人</view>
+					<view class="cell-input" hover-class="cell-hover" @click="person = true">
+						<view class="m-ellipsis">{{personText || '请选择联系人'}}</view>
+						<image class="cell-icon" src="/static/images/msg/down_arrow.svg" mode="aspectFit"></image>
+					</view>
+				</view>
+				<view class="explanation">为保证求职者联系到面试企业,求职者接受面试后,可查看职位发布人&联系人的电话</view>
+			</view>
+			<view class="card-box" style="padding: 0;">
+				<view class="note">
+					<view class="note-label note-time">面试日期</view>
+					<uni-calendar class="uni-calendar--hook" :showMonth="false" @change="change"
+						@monthSwitch="monthSwitch" />
+				</view>
+			</view>
+			<!-- 选择时间 -->
+			<view class="card-box">
+				<view class="cell" style="margin-bottom: 0;">
+					<view class="cell-label">开始时间</view>
+					<view class="cell-input flex-end" hover-class="cell-hover" @click="isShowTime = true">
+						<view class="m-ellipsis">{{selectedTime || '请选择时间' }}</view>
+						<image class="cell-icon" src="/static/images/msg/down_arrow.svg" mode="aspectFit"></image>
+					</view>
+				</view>
+			</view>
+			<view class="card-box">
+				<view class="note">
+					<view class="note-label">备注事项</view>
+					<view class="textarea-wrapper">
+						<textarea v-model="textareaValue" placeholder-class="placeholder-text"
+							placeholder="请输入告知求职者的其他内容,例如具体路线,所需材料等。" @input="updateLength" :maxlength="140">
+						</textarea>
+						<view class="word-count"><text style="color: #016BF6;">{{ textareaLength }}</text>/140</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<u-button class="btn">发送面试邀请</u-button>
+		<!-- 面试职位 -->
+		<u-popup v-model="position" mode="bottom" border-radius="20">
+			<view class="pop-content">
+				<view class="pop-title">选择面试职位</view>
+				<view class="pop-card">
+					<view class="pop-card-item" v-for="(item, index) in jobList" :key="index" @click="chooseJob(item)">
+						<u-radio-group v-model="popRadioValue">
+							<u-radio :name="item.id"></u-radio>
+						</u-radio-group>
+						<view>{{ item.title }}</view>
+						<view class="pop-tag">
+							{{ item.city }}
+							<u-line color="#999999" direction="col" length="20rpx" margin="10rpx"></u-line>
+							{{ item.edu }}
+							<u-line color="#999999" direction="col" length="20rpx" margin="10rpx"></u-line>
+							{{ item.salary }}
+						</view>
+					</view>
+				</view>
+			</view>
+		</u-popup>
+		<!-- 选择联系人 -->
+		<u-popup v-model="person" mode="bottom" border-radius="20">
+			<view class="pop-content">
+				<view class="pop-title">
+					<view>选择联系人</view>
+					<view class="note">您可填写其他面试联系人电话,请保证已获得其授权同意,求职者接受面试后可以查看该号码</view>
+				</view>
+				<view class="pop-card">
+					<view class="person-item" v-for="(item,index) in personList" :key="item.id"
+						@click="selectPerson(item)">
+						<view>{{item.name}}</view>
+						<view class="pop-phone">{{item.phone}}</view>
+						<image class="pop-icon" src="/static/images/msg/edit.svg" mode="aspectFit"
+							@click="goPage('editPerson',item)"></image>
+					</view>
+				</view>
+				<u-button class="pop-btn" @click="goPage('addPerson')">新增联系人</u-button>
+			</view>
+		</u-popup>
+		<!-- 选择面试方式 -->
+		<u-popup v-model="method" mode="bottom" border-radius="20">
+			<view class="pop-content">
+				<view class="pop-title">选择面试方式</view>
+				<!-- <view class="pop-card">
+					<view class="person-item" v-for="(item,index) in personList" :key="item.id" @click="selectPerson(item)">
+						<view>{{item.name}}</view>
+						<view class="pop-phone">{{item.phone}}</view>
+						<image class="pop-icon" src="/static/images/msg/edit.svg" mode="aspectFit" @click="goPage('editPerson',item)"></image>
+					</view>
+				</view> -->
+				<u-button class="pop-btn">确定</u-button>
+			</view>
+		</u-popup>
+		<!-- 选择时间 -->
+		<u-popup v-model="isShowTime" mode="bottom" border-radius="20">
+			<view class="pop-content">
+				<view class="pop-title">请选择面试开始时间</view>
+				<picker-view :value="timeValue" @change="bindChange" class="picker-view">
+					<picker-view-column>
+						<view class="item" v-for="(item,index) in hours" :key="index">{{ item }}</view>
+					</picker-view-column>
+					<picker-view-column>
+						<view class="item" v-for="(item,index) in minutes" :key="index">{{ item }}</view>
+					</picker-view-column>
+					<picker-view-column>
+						<view class="item" v-for="(item,index) in meridiem" :key="index">{{ item }}</view>
+					</picker-view-column>
+				</picker-view>
+				<u-button class="pop-time-btn" @click="changeBtn">确定</u-button>
+			</view>
+		</u-popup>
+	</view>
+</template>
+
+<script>
+	import navBar from "@/components/nav-bar/index.vue";
+	export default {
+		data() {
+			return {
+				radioValue: 0, //类型
+				position: false,
+				textareaValue: '',
+				textareaLength: 0,
+				popRadioValue: '',
+				jobList: [{
+						id: 1,
+						title: '亚马逊运营',
+						city: '深圳',
+						edu: '本科',
+						salary: '24-36k·16薪'
+					},
+					{
+						id: 2,
+						title: '跨境电商专员',
+						city: '广州',
+						edu: '大专',
+						salary: '15-25k·14薪'
+					},
+					{
+						id: 3,
+						title: '亚马逊运营',
+						city: '深圳',
+						edu: '本科',
+						salary: '24-36k·16薪'
+					},
+					{
+						id: 4,
+						title: '跨境电商专员',
+						city: '广州',
+						edu: '大专',
+						salary: '15-25k·14薪'
+					},
+					{
+						id: 5,
+						title: '亚马逊运营',
+						city: '深圳',
+						edu: '本科',
+						salary: '24-36k·16薪'
+					},
+					{
+						id: 6,
+						title: '跨境电商专员',
+						city: '广州',
+						edu: '大专',
+						salary: '15-25k·14薪'
+					}
+				],
+				selectedJob: '',
+				selectedAddress: '',
+				person: false,
+				personList: [{
+					id: 0,
+					name: '宋先生',
+					phone: '18888888888'
+				}],
+				personText: '',
+				method: false,
+				selected: [],
+				// 选择时间
+				isShowTime: false,
+				selectedTime:'',
+				timeValue: [0, 0, 0],
+				hours: Array.from({length: 12}, (_, i) => i + 1),
+				minutes: Array.from({length: 60}, (_, i) => i),
+				meridiem: ['AM', 'PM']
+			};
+		},
+		components: {
+			navBar
+		},
+		methods: {
+			change(e) {
+				console.log('change 返回:', e)
+			},
+			monthSwitch(e) {
+				console.log('monthSwitchs 返回:', e)
+			},
+			updateLength(e) {
+				this.textareaLength = e.target.value.length
+			},
+			chooseJob(item) {
+				this.selectedJob = item;
+				this.popRadioValue = item.id;
+				this.position = false;
+			},
+			// 选择地址  联系人  以及编辑联系人
+			goPage(type, item) {
+				uni.navigateTo({
+					url: `/pages/msg/selectInterview?type=${type}`,
+					success: (res) => {
+						res.eventChannel.emit('sendData', {
+							type,
+							item,
+							callback: (data) => {
+								console.log(data)
+								if (type === 'address') {
+									this.selectedAddress = data.address + data.floor
+								} else if (type === 'addPerson') {
+									this.personList.push(data)
+								} else if (type === 'editPerson') {
+									const index = this.personList.findIndex(p => p.id === data.id)
+									if (index !== -1) this.personList.splice(index, 1, data);
+									this.personText = data.name;
+								}
+							}
+						})
+					}
+				})
+			},
+			selectPerson(item) {
+				this.personText = item.name;
+				this.person = false;
+			},
+			bindChange(e) {
+				this.timeValue = e.detail.value
+			},
+			changeBtn(){
+				const val = this.timeValue
+				const hour = this.hours[val[0]]
+				const minute = this.minutes[val[1]]
+				const ampm = this.meridiem[val[2]]
+				this.selectedTime = `${hour}:${minute < 10 ? '0' + minute : minute} ${ampm}`
+				this.isShowTime = false;
+			}
+		}
+	};
+</script>
+
+<style scoped lang="scss">
+	.container {
+		display: flex;
+		flex-direction: column;
+		height: 100vh;
+
+		.detail-bg {
+			height: 327px;
+			width: 100%;
+			background: linear-gradient(180deg, rgba(255, 102, 0, 1), rgba(255, 102, 0, 0) 100%);
+			position: absolute;
+		}
+
+		.content {
+			flex: 1;
+			overflow: auto;
+			display: flex;
+			flex-direction: column;
+			z-index: 0;
+			padding: 40rpx 40rpx 0;
+
+			.detail-title {
+				color: #fff;
+				font-size: 50rpx;
+				font-weight: 500;
+				font-family: DM Sans;
+			}
+
+			.card-box {
+				margin: 20rpx 0;
+				padding: 36rpx;
+				box-sizing: border-box;
+				border: 1rpx solid rgba(227, 231, 236, 1);
+				border-radius: 12rpx;
+				background: rgba(253, 253, 253, 1);
+
+				.cell {
+					height: 56rpx;
+					margin-bottom: 12rpx;
+					display: flex;
+					align-items: center;
+
+					.cell-label {
+						width: 120rpx;
+						margin-right: 24rpx;
+						color: rgba(153, 153, 153, 1);
+						font-family: DM Sans;
+						font-size: 24rpx;
+						font-weight: 400;
+						line-height: 32rpx;
+						letter-spacing: 0%;
+					}
+
+					::v-deep .u-radio__icon-wrap {
+						width: 32rpx !important;
+						height: 32rpx !important;
+					}
+
+					::v-deep .u-radio__label {
+						color: rgba(23, 23, 37, 1);
+						font-family: DM Sans;
+						font-size: 24rpx;
+						font-weight: 400;
+						line-height: 48rpx;
+						letter-spacing: 0.5%;
+						margin-left: 8rpx !important;
+						margin-right: 74rpx !important;
+					}
+
+					.cell-input {
+						overflow: hidden;
+						display: flex;
+						align-items: center;
+						justify-content: space-between;
+						flex: 1;
+						height: 56rpx;
+						line-height: 56rpx;
+						box-sizing: border-box;
+						border: 1px solid rgba(0, 0, 0, 0.05);
+						border-radius: 12rpx;
+						padding: 0 20rpx;
+						color: rgba(51, 51, 51, 1);
+						font-family: DM Sans;
+						font-size: 20rpx;
+						font-weight: 400;
+						letter-spacing: 0px;
+
+						.cell-icon {
+							width: 20rpx;
+							height: 14rpx;
+							flex-shrink: 0;
+							margin-left: 10rpx;
+						}
+					}
+
+					.flex-end {
+						justify-content: flex-end;
+					}
+
+					.cell-hover {
+						background-color: rgba(0, 0, 0, 0.02);
+						transition: background-color 0.1s ease;
+					}
+				}
+
+				.explanation {
+					color: rgba(158, 158, 158, 1);
+					font-family: DM Sans;
+					font-size: 20rpx;
+					font-weight: 400;
+					line-height: 26rpx;
+					letter-spacing: 0%;
+				}
+
+				.note {
+					.note-label {
+						color: rgba(29, 33, 41, 1);
+						font-family: DM Sans;
+						font-size: 24rpx;
+						font-weight: 500;
+						line-height: 32rpx;
+						letter-spacing: 0%;
+						margin-bottom: 22rpx;
+					}
+
+					.note-time {
+						padding: 36rpx 36rpx 0;
+						margin-bottom: 0;
+					}
+
+					.uni-calendar--hook {
+						width: 100%;
+
+						::v-deep .uni-calendar__content {
+							background-color: initial;
+						}
+
+						::v-deep .uni-calendar-item__weeks-box-item {
+							width: initial !important;
+						}
+					}
+
+					.textarea-wrapper {
+						position: relative;
+
+						.word-count {
+							position: absolute;
+							bottom: 20rpx;
+							right: 20rpx;
+							font-family: DM Sans;
+							font-size: 22rpx;
+							font-weight: 400;
+							line-height: 26rpx;
+							letter-spacing: 0.5%;
+						}
+					}
+
+					::v-deep uni-textarea {
+						width: 100% !important;
+						height: 170rpx;
+						padding: 28rpx;
+						background: rgba(240, 240, 240, 1);
+						border-radius: 12rpx;
+						box-sizing: border-box;
+						color: #000;
+						font-family: DM Sans;
+						font-size: 22rpx;
+						font-weight: 400;
+						line-height: 30rpx;
+					}
+
+					.placeholder-text {
+						color: rgba(153, 153, 153, 1);
+						font-family: DM Sans;
+						font-size: 20rpx;
+						font-weight: 400;
+					}
+				}
+			}
+		}
+
+		.btn {
+			height: 58rpx;
+			padding: 16rpx 32rpx;
+			border-radius: 999px;
+			background: rgba(1, 107, 246, 1);
+			color: rgba(255, 255, 255, 1);
+			font-family: DM Sans;
+			font-size: 24rpx;
+			font-weight: 400;
+			line-height: 48rpx;
+			letter-spacing: 0%;
+			text-align: center;
+			margin: 28rpx 40rpx;
+		}
+
+		// 弹框
+		.pop-content {
+			height: 333px;
+			padding: 24rpx 34rpx 0;
+			display: flex;
+			flex-direction: column;
+			box-sizing: border-box;
+			background: rgba(253, 253, 253, 1);
+
+			.pop-title {
+				padding: 16rpx 0;
+				border-bottom: 1px solid rgba(153, 153, 153, 0.25);
+				color: rgba(34, 37, 42, 1);
+				font-family: DM Sans;
+				font-size: 36rpx;
+				font-weight: 500;
+				letter-spacing: 0px;
+				text-align: center;
+
+				.note {
+					margin: 16rpx 30rpx 0;
+					color: rgba(34, 37, 42, 1);
+					font-family: DM Sans;
+					font-size: 24rpx;
+					font-weight: 400;
+					line-height: 32rpx;
+					letter-spacing: 0px;
+					text-align: left;
+				}
+			}
+
+			.picker-view {
+				flex: 1;
+				::v-deep uni-picker-view-column {
+					text-align: center;
+				}
+			}
+
+			.pop-card {
+				flex: 1;
+				overflow: auto;
+
+				.pop-card-item {
+					margin: 33rpx 0;
+					box-sizing: border-box;
+					height: 96rpx;
+					padding: 24rpx 32rpx;
+					box-sizing: border-box;
+					border: 1px solid rgba(227, 231, 236, 1);
+					border-radius: 48rpx;
+					background: rgba(255, 255, 255, 1);
+					display: flex;
+					align-items: center;
+					color: rgba(23, 23, 37, 1);
+					font-family: DM Sans;
+					font-size: 28rpx;
+					font-weight: 400;
+					letter-spacing: 0.5%;
+
+					.pop-tag {
+						margin-left: 32rpx;
+						display: flex;
+						align-items: center;
+						color: rgba(153, 153, 153, 1);
+						font-family: DM Sans;
+						font-size: 20rpx;
+						font-weight: 400;
+						letter-spacing: 0.5%;
+					}
+				}
+
+				.person-item {
+					box-sizing: border-box;
+					border: 1px solid rgba(227, 231, 236, 1);
+					border-radius: 48rpx;
+					background: rgba(255, 255, 255, 1);
+					height: 96rpx;
+					padding: 24rpx 32rpx;
+					margin: 24rpx 0;
+					display: flex;
+					align-items: center;
+					color: rgba(1, 107, 246, 1);
+					font-family: DM Sans;
+					font-size: 28rpx;
+					font-weight: 400;
+					line-height: 48rpx;
+					letter-spacing: 0.5%;
+
+					.pop-phone {
+						margin: 0 32rpx;
+						flex: 1;
+						font-size: 20rpx;
+					}
+
+					.pop-icon {
+						width: 24.57px;
+						height: 24px;
+					}
+				}
+			}
+
+			.pop-btn {
+				width: 100%;
+				height: 80rpx;
+				padding: 16rpx 32rpx;
+				box-sizing: border-box;
+				border: 1px solid rgba(255, 102, 0, 1);
+				border-radius: 999px;
+				background: rgba(255, 255, 255, 1);
+				margin-bottom: 60rpx;
+				color: rgba(1, 107, 246, 1);
+				font-family: DM Sans;
+				font-size: 32rpx;
+				font-weight: 400;
+				line-height: 48rpx;
+				letter-spacing: 0%;
+			}
+			.pop-time-btn{
+				margin-bottom: 22rpx;
+				width: 100%;
+				height: 100rpx;
+				border-radius: 16rpx;
+				background: rgba(1, 107, 246, 1);
+				color: rgba(255, 255, 255, 1);
+				font-family: DM Sans;
+				font-size: 34rpx;
+				font-weight: 400;
+				line-height: 44rpx;
+				letter-spacing: -0.41px;
+			}
+		}
+	}
+
+	::v-deep .u-hairline-border:after {
+		border: none !important;
+	}
+</style>

+ 181 - 0
pages/msg/selectInterview.vue

@@ -0,0 +1,181 @@
+<template>
+	<view class="container">
+		<nav-bar :title="title" color="#000"></nav-bar>
+		<view class="content">
+			<view class="cell-box">
+				<view class="cell-title">{{type == 'address'?'面试地点':'姓名'}}</view>
+				<u-input v-model="address" type="text" :border="true" :placeholder="type == 'address'?'请输入办公大楼名称,例:碧桂园凤凰智谷':'请输入联系人姓名'" />
+			</view>
+
+			<view class="cell-box">
+				<view class="cell-title">{{type == 'address'?'楼层/单元室':'电话'}}</view>
+				<div class="input-wrapper">
+					<u-input v-model="floor" :type="type == 'address'?'text':'number'" :border="true" :placeholder="type == 'address'?'楼层/单元室/门牌号,例:3层302室':'请输入联系人电话'"
+						@input="handleInput" :maxlength="20" />
+					<view class="word-count" v-if="type == 'address'">{{ floorLength }}/20</view>
+				</div>
+			</view>
+		</view>
+		<u-button class="btn" :disabled="!canSave" @click="goBack">保存</u-button>
+	</view>
+</template>
+
+
+<script>
+	import navBar from "@/components/nav-bar/index.vue";
+	export default {
+		components: {
+			navBar
+		},
+		data() {
+			return {
+				title: '面试地址',
+				id:'',
+				address: '',
+				floor: '',
+				floorLength: 0,
+				callback: null,
+				type: ''
+			};
+		},
+		onLoad(options) {
+			this.type = options.type
+			if (this.type === 'address') {
+				this.title = '面试地址'
+			} else if (this.type === 'addPerson') {
+				this.title = '添加联系人'
+			} else if (this.type === 'editPerson') {
+				this.title = '编辑联系人'
+			}
+
+			const eventChannel = this.getOpenerEventChannel();
+			this.callback = null;
+			eventChannel.on('sendData', (data) => {
+				this.callback = data.callback;
+				if (data.type === 'editPerson' && data.item) {
+					this.id = data.item.id
+					this.address = data.item.name
+					this.floor = data.item.phone
+				  }
+			})
+		},
+		computed: {
+			canSave() {
+				return this.address.trim() !== '' && this.floor.trim() !== '';
+			}
+		},
+		methods: {
+			handleInput(val) {
+				this.floorLength = val.length;
+			},
+			goBack() {
+				if (this.callback) {
+					if (this.type === 'address') {
+						this.callback({ address: this.address, floor: this.floor })
+					} else if (this.type === 'addPerson') {
+						this.callback({ id: Date.now(), name: this.address, phone: this.floor })
+					} else if (this.type === 'editPerson') {
+						this.callback({ id: this.id, name: this.address, phone: this.floor })
+					}
+				}
+				uni.navigateBack();
+			}
+		}
+	};
+</script>
+
+<style scoped lang="scss">
+	.container {
+		display: flex;
+		flex-direction: column;
+		height: 100vh;
+
+		.content {
+			flex: 1;
+			display: flex;
+			flex-direction: column;
+			z-index: 0;
+			padding: 40rpx;
+
+			.cell-box {
+				margin-bottom: 32rpx;
+
+				.cell-title {
+					color: var(--Neutral/100, rgba(31, 44, 55, 1));
+					font-family: DM Sans;
+					font-size: 28rpx;
+					font-weight: 500;
+					line-height: 44rpx;
+					letter-spacing: 0.5%;
+					margin-bottom: 16rpx;
+				}
+
+				.input-wrapper {
+					position: relative;
+
+					.word-count {
+						position: absolute;
+						top: 50%;
+						right: 26rpx;
+						transform: translateY(-50%);
+						color: rgba(153, 153, 153, 1);
+						font-family: DM Sans;
+						font-size: 24rpx;
+						font-weight: 500;
+						line-height: 48rpx;
+						letter-spacing: 0.5%;
+					}
+				}
+
+				::v-deep .uni-input-placeholder {
+					color: rgba(153, 153, 153, 1);
+					font-family: DM Sans;
+					font-size: 24rpx;
+					font-weight: 500;
+					line-height: 48rpx;
+					letter-spacing: 0.5%;
+				}
+
+				::v-deep .u-input {
+					height: 70rpx;
+					box-sizing: border-box;
+					border: 1px solid rgba(227, 231, 236, 1);
+					border-radius: 48rpx;
+					background: rgba(255, 255, 255, 1);
+					padding: 0 32rpx !important;
+					box-sizing: border-box;
+					text-align: left !important;
+				}
+
+				::v-deep .uni-input-input {
+					font-family: DM Sans;
+					font-size: 24rpx !important;
+					font-weight: 500;
+					line-height: 48rpx;
+					letter-spacing: 0.5%;
+					color: #000 !important;
+				}
+			}
+		}
+
+		.btn {
+			display: flex;
+			height: 80rpx;
+			padding: 16rpx 32rpx;
+			border-radius: 999px;
+			background: rgba(255, 102, 0, 1);
+			margin: 60rpx;
+			color: rgba(255, 255, 255, 1);
+			font-family: DM Sans;
+			font-size: 32rpx;
+			font-weight: 400;
+			line-height: 48rpx;
+			letter-spacing: 0%;
+			box-sizing: border-box;
+
+			::v-deep .u-hairline-border:after {
+				border: none !important;
+			}
+		}
+	}
+</style>

+ 5 - 0
static/images/msg/down_arrow.svg

@@ -0,0 +1,5 @@
+<svg viewBox="0 0 10 7" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="10.000000" height="7.000000" fill="none" customFrame="#000000">
+	<g style="mix-blend-mode:normal">
+		<path id="Vector" d="M1.11333 0.236568L5 5.05006L8.88667 0.236567C9.14136 -0.0788558 9.55429 -0.0788558 9.80898 0.236567C10.0637 0.551991 10.0637 1.06339 9.80898 1.37882L5.46116 6.76343C5.33885 6.9149 5.17297 7 5 7C4.82703 7 4.66115 6.9149 4.53884 6.76343L0.191017 1.37882C-0.0636724 1.06339 -0.0636725 0.551992 0.191017 0.236568C0.445707 -0.0788553 0.858641 -0.0788553 1.11333 0.236568Z" fill="rgb(198,197,202)" fill-rule="evenodd" />
+	</g>
+</svg>

+ 8 - 0
static/images/msg/edit.svg

@@ -0,0 +1,8 @@
+<svg viewBox="0 0 24.5693 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.569336" height="24.000000" fill="none">
+	<rect id="Edit Square" width="24.569492" height="24.000000" x="0.000000" y="0.000000" />
+	<g id="Icon - Edit">
+		<g id="Edit-Square">
+			<path id="Combined-Shape" d="M11.7646 2.0364C12.1884 2.0364 12.5324 2.3724 12.5324 2.7864C12.5324 3.2004 12.1884 3.5364 11.7646 3.5364L7.93688 3.5364C5.29156 3.5364 3.58296 5.3064 3.58296 8.0454L3.58296 16.3594C3.58296 19.0984 5.29156 20.8684 7.93688 20.8684L16.9703 20.8684C19.6156 20.8684 21.3252 19.0984 21.3252 16.3594L21.3252 12.3314C21.3252 11.9174 21.6692 11.5814 22.093 11.5814C22.5168 11.5814 22.8608 11.9174 22.8608 12.3314L22.8608 16.3594C22.8608 19.9534 20.4929 22.3684 16.9703 22.3684L7.93688 22.3684C4.41422 22.3684 2.04736 19.9534 2.04736 16.3594L2.04736 8.0454C2.04736 4.4514 4.41422 2.0364 7.93688 2.0364L11.7646 2.0364ZM20.6809 2.915L21.9267 4.132C22.5338 4.724 22.8676 5.511 22.8665 6.349C22.8665 7.187 22.5328 7.973 21.9267 8.564L14.2396 16.073C13.6755 16.624 12.9241 16.928 12.1256 16.928L8.29068 16.928C8.08388 16.928 7.88528 16.846 7.74093 16.701C7.59659 16.557 7.51776 16.362 7.52288 16.159L7.61911 12.38C7.63856 11.628 7.94875 10.921 8.49337 10.388L8.4944 10.388L16.1447 2.915C17.3957 1.695 19.4299 1.695 20.6809 2.915ZM15.5145 5.651L9.57955 11.449C9.3144 11.708 9.16392 12.052 9.1547 12.417L9.07792 15.428L12.1256 15.428C12.5146 15.428 12.879 15.281 13.1544 15.012L19.1252 9.178L15.5145 5.651ZM17.2299 3.976L16.5997 4.59L20.2104 8.118L20.8416 7.503C21.1569 7.195 21.3309 6.785 21.3309 6.349C21.3309 5.912 21.1569 5.501 20.8416 5.193L19.5957 3.976C18.9436 3.341 17.883 3.341 17.2299 3.976Z" fill="rgb(23,23,37)" fill-rule="evenodd" />
+		</g>
+	</g>
+</svg>

+ 30 - 0
uni_modules/uni-calendar/changelog.md

@@ -0,0 +1,30 @@
+## 1.4.12(2024-09-21)
+- 修复 calendar在选择日期范围后重新选择日期需要点两次的Bug
+## 1.4.11(2024-01-10)
+- 修复 回到今天时,月份显示不一致问题
+## 1.4.10(2023-04-10)
+- 修复 某些情况 monthSwitch 未触发的Bug
+## 1.4.9(2023-02-02)
+- 修复 某些情况切换月份错误的Bug
+## 1.4.8(2023-01-30)
+- 修复 某些情况切换月份错误的Bug [详情](https://ask.dcloud.net.cn/question/161964)
+## 1.4.7(2022-09-16)
+- 优化 支持使用 uni-scss 控制主题色
+## 1.4.6(2022-09-08)
+- 修复 表头年月切换,导致改变当前日期为选择月1号,且未触发change事件的Bug
+## 1.4.5(2022-02-25)
+- 修复 条件编译 nvue 不支持的 css 样式的Bug
+## 1.4.4(2022-02-25)
+- 修复 条件编译 nvue 不支持的 css 样式的Bug
+## 1.4.3(2021-09-22)
+- 修复 startDate、 endDate 属性失效的Bug
+## 1.4.2(2021-08-24)
+- 新增 支持国际化
+## 1.4.1(2021-08-05)
+- 修复 弹出层被 tabbar 遮盖的Bug
+## 1.4.0(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 1.3.16(2021-05-12)
+- 新增 组件示例地址
+## 1.3.15(2021-02-04)
+- 调整为uni_modules目录规范

+ 544 - 0
uni_modules/uni-calendar/components/uni-calendar/calendar.js

@@ -0,0 +1,544 @@
+/**
+* @1900-2100区间内的公历、农历互转
+* @charset UTF-8
+* @github  https://github.com/jjonline/calendar.js
+* @Author  Jea杨(JJonline@JJonline.Cn)
+* @Time    2014-7-21
+* @Time    2016-8-13 Fixed 2033hex、Attribution Annals
+* @Time    2016-9-25 Fixed lunar LeapMonth Param Bug
+* @Time    2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
+* @Version 1.0.3
+* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
+* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
+*/
+/* eslint-disable */
+var calendar = {
+
+  /**
+      * 农历1900-2100的润大小信息表
+      * @Array Of Property
+      * @return Hex
+      */
+  lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
+    0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
+    0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
+    0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
+    0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
+    0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
+    0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
+    0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
+    0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
+    0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
+    0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
+    0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
+    0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
+    0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
+    0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
+    /** Add By JJonline@JJonline.Cn**/
+    0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
+    0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
+    0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
+    0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
+    0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
+    0x0d520], // 2100
+
+  /**
+      * 公历每个月份的天数普通表
+      * @Array Of Property
+      * @return Number
+      */
+  solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
+
+  /**
+      * 天干地支之天干速查表
+      * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
+      * @return Cn string
+      */
+  Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],
+
+  /**
+      * 天干地支之地支速查表
+      * @Array Of Property
+      * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
+      * @return Cn string
+      */
+  Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'],
+
+  /**
+      * 天干地支之地支速查表<=>生肖
+      * @Array Of Property
+      * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
+      * @return Cn string
+      */
+  Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'],
+
+  /**
+      * 24节气速查表
+      * @Array Of Property
+      * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
+      * @return Cn string
+      */
+  solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'],
+
+  /**
+      * 1900-2100各年的24节气日期速查表
+      * @Array Of Property
+      * @return 0x string For splice
+      */
+  sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
+    '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+    '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
+    '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
+    'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
+    '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
+    '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
+    '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
+    '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+    '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+    '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
+    '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
+    '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+    '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+    '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
+    '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
+    '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
+    '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
+    '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
+    '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+    '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+    '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+    '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
+    '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
+    '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+    '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+    '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
+    '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
+    '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
+    '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
+    '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
+    '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+    '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+    '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+    '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
+    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
+    '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+    '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+    '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
+    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
+    '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
+    '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
+    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
+    '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+    '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
+    '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
+    '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+    '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
+    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
+    '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
+    '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+    '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
+    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
+    '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
+    '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
+    '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
+    '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
+    '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
+    '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
+    '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
+    '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
+    '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
+    '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
+    '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
+    '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'],
+
+  /**
+      * 数字转中文速查表
+      * @Array Of Property
+      * @trans ['日','一','二','三','四','五','六','七','八','九','十']
+      * @return Cn string
+      */
+  nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'],
+
+  /**
+      * 日期转农历称呼速查表
+      * @Array Of Property
+      * @trans ['初','十','廿','卅']
+      * @return Cn string
+      */
+  nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
+
+  /**
+      * 月份转农历称呼速查表
+      * @Array Of Property
+      * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
+      * @return Cn string
+      */
+  nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'],
+
+  /**
+      * 返回农历y年一整年的总天数
+      * @param lunar Year
+      * @return Number
+      * @eg:var count = calendar.lYearDays(1987) ;//count=387
+      */
+  lYearDays: function (y) {
+    var i; var sum = 348
+    for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
+    return (sum + this.leapDays(y))
+  },
+
+  /**
+      * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
+      * @param lunar Year
+      * @return Number (0-12)
+      * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
+      */
+  leapMonth: function (y) { // 闰字编码 \u95f0
+    return (this.lunarInfo[y - 1900] & 0xf)
+  },
+
+  /**
+      * 返回农历y年闰月的天数 若该年没有闰月则返回0
+      * @param lunar Year
+      * @return Number (0、29、30)
+      * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
+      */
+  leapDays: function (y) {
+    if (this.leapMonth(y)) {
+      return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
+    }
+    return (0)
+  },
+
+  /**
+      * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
+      * @param lunar Year
+      * @return Number (-1、29、30)
+      * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
+      */
+  monthDays: function (y, m) {
+    if (m > 12 || m < 1) { return -1 }// 月份参数从1至12,参数错误返回-1
+    return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
+  },
+
+  /**
+      * 返回公历(!)y年m月的天数
+      * @param solar Year
+      * @return Number (-1、28、29、30、31)
+      * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
+      */
+  solarDays: function (y, m) {
+    if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
+    var ms = m - 1
+    if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
+      return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
+    } else {
+      return (this.solarMonth[ms])
+    }
+  },
+
+  /**
+     * 农历年份转换为干支纪年
+     * @param  lYear 农历年的年份数
+     * @return Cn string
+     */
+  toGanZhiYear: function (lYear) {
+    var ganKey = (lYear - 3) % 10
+    var zhiKey = (lYear - 3) % 12
+    if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干
+    if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支
+    return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
+  },
+
+  /**
+     * 公历月、日判断所属星座
+     * @param  cMonth [description]
+     * @param  cDay [description]
+     * @return Cn string
+     */
+  toAstro: function (cMonth, cDay) {
+    var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
+    var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
+    return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座
+  },
+
+  /**
+      * 传入offset偏移量返回干支
+      * @param offset 相对甲子的偏移量
+      * @return Cn string
+      */
+  toGanZhi: function (offset) {
+    return this.Gan[offset % 10] + this.Zhi[offset % 12]
+  },
+
+  /**
+      * 传入公历(!)y年获得该年第n个节气的公历日期
+      * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
+      * @return day Number
+      * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
+      */
+  getTerm: function (y, n) {
+    if (y < 1900 || y > 2100) { return -1 }
+    if (n < 1 || n > 24) { return -1 }
+    var _table = this.sTermInfo[y - 1900]
+    var _info = [
+      parseInt('0x' + _table.substr(0, 5)).toString(),
+      parseInt('0x' + _table.substr(5, 5)).toString(),
+      parseInt('0x' + _table.substr(10, 5)).toString(),
+      parseInt('0x' + _table.substr(15, 5)).toString(),
+      parseInt('0x' + _table.substr(20, 5)).toString(),
+      parseInt('0x' + _table.substr(25, 5)).toString()
+    ]
+    var _calday = [
+      _info[0].substr(0, 1),
+      _info[0].substr(1, 2),
+      _info[0].substr(3, 1),
+      _info[0].substr(4, 2),
+
+      _info[1].substr(0, 1),
+      _info[1].substr(1, 2),
+      _info[1].substr(3, 1),
+      _info[1].substr(4, 2),
+
+      _info[2].substr(0, 1),
+      _info[2].substr(1, 2),
+      _info[2].substr(3, 1),
+      _info[2].substr(4, 2),
+
+      _info[3].substr(0, 1),
+      _info[3].substr(1, 2),
+      _info[3].substr(3, 1),
+      _info[3].substr(4, 2),
+
+      _info[4].substr(0, 1),
+      _info[4].substr(1, 2),
+      _info[4].substr(3, 1),
+      _info[4].substr(4, 2),
+
+      _info[5].substr(0, 1),
+      _info[5].substr(1, 2),
+      _info[5].substr(3, 1),
+      _info[5].substr(4, 2)
+    ]
+    return parseInt(_calday[n - 1])
+  },
+
+  /**
+      * 传入农历数字月份返回汉语通俗表示法
+      * @param lunar month
+      * @return Cn string
+      * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
+      */
+  toChinaMonth: function (m) { // 月 => \u6708
+    if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
+    var s = this.nStr3[m - 1]
+    s += '\u6708'// 加上月字
+    return s
+  },
+
+  /**
+      * 传入农历日期数字返回汉字表示法
+      * @param lunar day
+      * @return Cn string
+      * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
+      */
+  toChinaDay: function (d) { // 日 => \u65e5
+    var s
+    switch (d) {
+      case 10:
+        s = '\u521d\u5341'; break
+      case 20:
+        s = '\u4e8c\u5341'; break
+      case 30:
+        s = '\u4e09\u5341'; break
+      default :
+        s = this.nStr2[Math.floor(d / 10)]
+        s += this.nStr1[d % 10]
+    }
+    return (s)
+  },
+
+  /**
+      * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
+      * @param y year
+      * @return Cn string
+      * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
+      */
+  getAnimal: function (y) {
+    return this.Animals[(y - 4) % 12]
+  },
+
+  /**
+      * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
+      * @param y  solar year
+      * @param m  solar month
+      * @param d  solar day
+      * @return JSON object
+      * @eg:console.log(calendar.solar2lunar(1987,11,01));
+      */
+  solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31
+    // 年份限定、上限
+    if (y < 1900 || y > 2100) {
+      return -1// undefined转换为数字变为NaN
+    }
+    // 公历传参最下限
+    if (y == 1900 && m == 1 && d < 31) {
+      return -1
+    }
+    // 未传参  获得当天
+    if (!y) {
+      var objDate = new Date()
+    } else {
+      var objDate = new Date(y, parseInt(m) - 1, d)
+    }
+    var i; var leap = 0; var temp = 0
+    // 修正ymd参数
+    var y = objDate.getFullYear()
+    var m = objDate.getMonth() + 1
+    var d = objDate.getDate()
+    var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
+    for (i = 1900; i < 2101 && offset > 0; i++) {
+      temp = this.lYearDays(i)
+      offset -= temp
+    }
+    if (offset < 0) {
+      offset += temp; i--
+    }
+
+    // 是否今天
+    var isTodayObj = new Date()
+    var isToday = false
+    if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
+      isToday = true
+    }
+    // 星期几
+    var nWeek = objDate.getDay()
+    var cWeek = this.nStr1[nWeek]
+    // 数字表示周几顺应天朝周一开始的惯例
+    if (nWeek == 0) {
+      nWeek = 7
+    }
+    // 农历年
+    var year = i
+    var leap = this.leapMonth(i) // 闰哪个月
+    var isLeap = false
+
+    // 效验闰月
+    for (i = 1; i < 13 && offset > 0; i++) {
+      // 闰月
+      if (leap > 0 && i == (leap + 1) && isLeap == false) {
+        --i
+        isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数
+      } else {
+        temp = this.monthDays(year, i)// 计算农历普通月天数
+      }
+      // 解除闰月
+      if (isLeap == true && i == (leap + 1)) { isLeap = false }
+      offset -= temp
+    }
+    // 闰月导致数组下标重叠取反
+    if (offset == 0 && leap > 0 && i == leap + 1) {
+      if (isLeap) {
+        isLeap = false
+      } else {
+        isLeap = true; --i
+      }
+    }
+    if (offset < 0) {
+      offset += temp; --i
+    }
+    // 农历月
+    var month = i
+    // 农历日
+    var day = offset + 1
+    // 天干地支处理
+    var sm = m - 1
+    var gzY = this.toGanZhiYear(year)
+
+    // 当月的两个节气
+    // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
+    var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始
+    var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始
+
+    // 依据12节气修正干支月
+    var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
+    if (d >= firstNode) {
+      gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
+    }
+
+    // 传入的日期的节气与否
+    var isTerm = false
+    var Term = null
+    if (firstNode == d) {
+      isTerm = true
+      Term = this.solarTerm[m * 2 - 2]
+    }
+    if (secondNode == d) {
+      isTerm = true
+      Term = this.solarTerm[m * 2 - 1]
+    }
+    // 日柱 当月一日与 1900/1/1 相差天数
+    var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
+    var gzD = this.toGanZhi(dayCyclical + d - 1)
+    // 该日期所属的星座
+    var astro = this.toAstro(m, d)
+
+    return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro }
+  },
+
+  /**
+      * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
+      * @param y  lunar year
+      * @param m  lunar month
+      * @param d  lunar day
+      * @param isLeapMonth  lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
+      * @return JSON object
+      * @eg:console.log(calendar.lunar2solar(1987,9,10));
+      */
+  lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
+    var isLeapMonth = !!isLeapMonth
+    var leapOffset = 0
+    var leapMonth = this.leapMonth(y)
+    var leapDay = this.leapDays(y)
+    if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
+    if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值
+    var day = this.monthDays(y, m)
+    var _day = day
+    // bugFix 2016-9-25
+    // if month is leap, _day use leapDays method
+    if (isLeapMonth) {
+      _day = this.leapDays(y, m)
+    }
+    if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验
+
+    // 计算农历的时间差
+    var offset = 0
+    for (var i = 1900; i < y; i++) {
+      offset += this.lYearDays(i)
+    }
+    var leap = 0; var isAdd = false
+    for (var i = 1; i < m; i++) {
+      leap = this.leapMonth(y)
+      if (!isAdd) { // 处理闰月
+        if (leap <= i && leap > 0) {
+          offset += this.leapDays(y); isAdd = true
+        }
+      }
+      offset += this.monthDays(y, i)
+    }
+    // 转换闰月农历 需补充该年闰月的前一个月的时差
+    if (isLeapMonth) { offset += day }
+    // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
+    var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
+    var calObj = new Date((offset + d - 31) * 86400000 + stmap)
+    var cY = calObj.getUTCFullYear()
+    var cM = calObj.getUTCMonth() + 1
+    var cD = calObj.getUTCDate()
+
+    return this.solar2lunar(cY, cM, cD)
+  }
+}
+
+export default calendar

+ 12 - 0
uni_modules/uni-calendar/components/uni-calendar/i18n/en.json

@@ -0,0 +1,12 @@
+{
+	"uni-calender.ok": "ok",
+	"uni-calender.cancel": "cancel",
+	"uni-calender.today": "today",
+	"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"
+}

+ 8 - 0
uni_modules/uni-calendar/components/uni-calendar/i18n/index.js

@@ -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
+}

+ 12 - 0
uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hans.json

@@ -0,0 +1,12 @@
+{
+	"uni-calender.ok": "确定",
+	"uni-calender.cancel": "取消",
+	"uni-calender.today": "今日",
+	"uni-calender.SUN": "日",
+	"uni-calender.MON": "一",
+	"uni-calender.TUE": "二",
+	"uni-calender.WED": "三",
+	"uni-calender.THU": "四",
+	"uni-calender.FRI": "五",
+	"uni-calender.SAT": "六"
+}

+ 12 - 0
uni_modules/uni-calendar/components/uni-calendar/i18n/zh-Hant.json

@@ -0,0 +1,12 @@
+{
+	"uni-calender.ok": "確定",
+	"uni-calender.cancel": "取消",
+	"uni-calender.today": "今日",
+	"uni-calender.SUN": "日",
+	"uni-calender.MON": "一",
+	"uni-calender.TUE": "二",
+	"uni-calender.WED": "三",
+	"uni-calender.THU": "四",
+	"uni-calender.FRI": "五",
+	"uni-calender.SAT": "六"
+}

+ 187 - 0
uni_modules/uni-calendar/components/uni-calendar/uni-calendar-item.vue

@@ -0,0 +1,187 @@
+<template>
+	<view class="uni-calendar-item__weeks-box" :class="{
+		'uni-calendar-item--disable':weeks.disable,
+		'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
+		'uni-calendar-item--checked':(calendar.fullDate === weeks.fullDate && !weeks.isDay) ,
+		'uni-calendar-item--before-checked':weeks.beforeMultiple,
+		'uni-calendar-item--multiple': weeks.multiple,
+		'uni-calendar-item--after-checked':weeks.afterMultiple,
+		}"
+	 @click="choiceDate(weeks)">
+		<view class="uni-calendar-item__weeks-box-item">
+			<text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
+			<text class="uni-calendar-item__weeks-box-text" :class="{
+				'uni-calendar-item--isDay-text': weeks.isDay,
+				'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
+				'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,
+				}">{{weeks.date}}</text>
+			<text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uni-calendar-item__weeks-lunar-text" :class="{
+				'uni-calendar-item--isDay-text':weeks.isDay,
+				'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
+				'uni-calendar-item--before-checked':weeks.beforeMultiple,
+				'uni-calendar-item--multiple': weeks.multiple,
+				'uni-calendar-item--after-checked':weeks.afterMultiple,
+				}">{{todayText}}</text>
+			<text v-if="lunar&&!weeks.extraInfo" class="uni-calendar-item__weeks-lunar-text" :class="{
+				'uni-calendar-item--isDay-text':weeks.isDay,
+				'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
+				'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,
+				}">{{weeks.isDay ? todayText : (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text>
+			<text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uni-calendar-item__weeks-lunar-text" :class="{
+				'uni-calendar-item--extra':weeks.extraInfo.info,
+				'uni-calendar-item--isDay-text':weeks.isDay,
+				'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
+				'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
+				'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,
+				}">{{weeks.extraInfo.info}}</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { initVueI18n } from '@dcloudio/uni-i18n'
+	import i18nMessages from './i18n/index.js'
+	const {	t	} = initVueI18n(i18nMessages)
+
+	export default {
+		emits:['change'],
+		props: {
+			weeks: {
+				type: Object,
+				default () {
+					return {}
+				}
+			},
+			calendar: {
+				type: Object,
+				default: () => {
+					return {}
+				}
+			},
+			selected: {
+				type: Array,
+				default: () => {
+					return []
+				}
+			},
+			lunar: {
+				type: Boolean,
+				default: false
+			}
+		},
+		computed: {
+			todayText() {
+				return t("uni-calender.today")
+			},
+		},
+		methods: {
+			choiceDate(weeks) {
+				this.$emit('change', weeks)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$uni-font-size-base:14px;
+	$uni-text-color:#333;
+	$uni-font-size-sm:12px;
+	$uni-color-error: #e43d33;
+	$uni-opacity-disabled: 0.3;
+	$uni-text-color-disable:#c0c0c0;
+	$uni-primary: #2979ff !default;
+	.uni-calendar-item__weeks-box {
+		flex: 1;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.uni-calendar-item__weeks-box-text {
+		font-size: $uni-font-size-base;
+		color: $uni-text-color;
+	}
+
+	.uni-calendar-item__weeks-lunar-text {
+		font-size: $uni-font-size-sm;
+		color: $uni-text-color;
+	}
+
+	.uni-calendar-item__weeks-box-item {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		width: 100rpx;
+		height: 100rpx;
+	}
+
+	.uni-calendar-item__weeks-box-circle {
+		position: absolute;
+		top: 5px;
+		right: 5px;
+		width: 8px;
+		height: 8px;
+		border-radius: 8px;
+		background-color: $uni-color-error;
+
+	}
+
+	.uni-calendar-item--disable {
+		background-color: rgba(249, 249, 249, $uni-opacity-disabled);
+		color: $uni-text-color-disable;
+	}
+
+	.uni-calendar-item--isDay-text {
+		color: $uni-primary;
+	}
+
+	.uni-calendar-item--isDay {
+		background-color: $uni-primary;
+		opacity: 0.8;
+		color: #fff;
+	}
+
+	.uni-calendar-item--extra {
+		color: $uni-color-error;
+		opacity: 0.8;
+	}
+
+	.uni-calendar-item--checked {
+		background-color: $uni-primary;
+		color: #fff;
+		opacity: 0.8;
+	}
+
+	.uni-calendar-item--multiple {
+		background-color: $uni-primary;
+		color: #fff;
+		opacity: 0.8;
+	}
+	.uni-calendar-item--before-checked {
+		background-color: #ff5a5f;
+		color: #fff;
+	}
+	.uni-calendar-item--after-checked {
+		background-color: #ff5a5f;
+		color: #fff;
+	}
+</style>

+ 567 - 0
uni_modules/uni-calendar/components/uni-calendar/uni-calendar.vue

@@ -0,0 +1,567 @@
+<template>
+	<view class="uni-calendar">
+		<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="clean"></view>
+		<view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}">
+			<view v-if="!insert" class="uni-calendar__header uni-calendar--fixed-top">
+				<view class="uni-calendar__header-btn-box" @click="close">
+					<text class="uni-calendar__header-text uni-calendar--fixed-width">{{cancelText}}</text>
+				</view>
+				<view class="uni-calendar__header-btn-box" @click="confirm">
+					<text class="uni-calendar__header-text uni-calendar--fixed-width">{{okText}}</text>
+				</view>
+			</view>
+			<view class="uni-calendar__header">
+				<view class="uni-calendar__header-btn-box" @click.stop="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||'') +' / '+( nowDate.month||'')}}</text>
+				</picker>
+				<view class="uni-calendar__header-btn-box" @click.stop="next">
+					<view class="uni-calendar__header-btn uni-calendar--right"></view>
+				</view>
+				<text class="uni-calendar__backtoday" @click="backToday">{{todayText}}</text>
+
+			</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">
+					<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" :lunar="lunar" @change="choiceDate"></calendar-item>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import Calendar from './util.js';
+	import CalendarItem from './uni-calendar-item.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 {Boolean} lunar 显示农历
+	 * @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 是否选择月份为背景
+	 * @event {Function} change 日期改变,`insert :ture` 时生效
+	 * @event {Function} confirm 确认选择`insert :false` 时生效
+	 * @event {Function} monthSwitch 切换月份时触发
+	 * @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
+	 */
+	export default {
+		components: {
+			CalendarItem
+		},
+		emits:['close','confirm','change','monthSwitch'],
+		props: {
+			date: {
+				type: String,
+				default: ''
+			},
+			selected: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			lunar: {
+				type: Boolean,
+				default: false
+			},
+			startDate: {
+				type: String,
+				default: ''
+			},
+			endDate: {
+				type: String,
+				default: ''
+			},
+			range: {
+				type: Boolean,
+				default: false
+			},
+			insert: {
+				type: Boolean,
+				default: true
+			},
+			showMonth: {
+				type: Boolean,
+				default: true
+			},
+			clearDate: {
+				type: Boolean,
+				default: true
+			}
+		},
+		data() {
+			return {
+				show: false,
+				weeks: [],
+				calendar: {},
+				nowDate: '',
+				aniMaskShow: false
+			}
+		},
+		computed:{
+			/**
+			 * for i18n
+			 */
+
+			okText() {
+				return t("uni-calender.ok")
+			},
+			cancelText() {
+				return t("uni-calender.cancel")
+			},
+			todayText() {
+				return t("uni-calender.today")
+			},
+			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")
+			},
+		},
+		watch: {
+			date(newVal) {
+				// this.cale.setDate(newVal)
+				this.init(newVal)
+			},
+			startDate(val){
+				this.cale.resetSatrtDate(val)
+				this.cale.setDate(this.nowDate.fullDate)
+				this.weeks = this.cale.weeks
+			},
+			endDate(val){
+				this.cale.resetEndDate(val)
+				this.cale.setDate(this.nowDate.fullDate)
+				this.weeks = this.cale.weeks
+			},
+			selected(newVal) {
+				this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
+				this.weeks = this.cale.weeks
+			}
+		},
+		created() {
+			this.cale = new Calendar({
+				selected: this.selected,
+				startDate: this.startDate,
+				endDate: this.endDate,
+				range: this.range,
+			})
+			this.init(this.date)
+		},
+		methods: {
+			// 取消穿透
+			clean() {},
+			bindDateChange(e) {
+				const value = e.detail.value + '-1'
+				this.setDate(value)
+
+				const { year,month } = this.cale.getDate(value)
+        this.$emit('monthSwitch', {
+            year,
+            month
+        })
+			},
+			/**
+			 * 初始化日期显示
+			 * @param {Object} date
+			 */
+			init(date) {
+				this.cale.setDate(date)
+				this.weeks = this.cale.weeks
+				this.nowDate = this.calendar = this.cale.getInfo(date)
+			},
+			/**
+			 * 打开日历弹窗
+			 */
+			open() {
+				// 弹窗模式并且清理数据
+				if (this.clearDate && !this.insert) {
+					this.cale.cleanMultipleStatus()
+					// this.cale.setDate(this.date)
+					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() {
+				if (!this.insert) return
+				this.setEmit('change')
+			},
+			/**
+			 * 选择月份触发
+			 */
+			monthSwitch() {
+				let {
+					year,
+					month
+				} = this.nowDate
+				this.$emit('monthSwitch', {
+					year,
+					month: Number(month)
+				})
+			},
+			/**
+			 * 派发事件
+			 * @param {Object} name
+			 */
+			setEmit(name) {
+				let {
+					year,
+					month,
+					date,
+					fullDate,
+					lunar,
+					extraInfo
+				} = this.calendar
+				this.$emit(name, {
+					range: this.cale.multipleStatus,
+					year,
+					month,
+					date,
+					fulldate: fullDate,
+					lunar,
+					extraInfo: extraInfo || {}
+				})
+			},
+			/**
+			 * 选择天触发
+			 * @param {Object} weeks
+			 */
+			choiceDate(weeks) {
+				if (weeks.disable) return
+				this.calendar = weeks
+				// 设置多选
+				this.cale.setMultiple(this.calendar.fullDate)
+				this.weeks = this.cale.weeks
+				this.change()
+			},
+			/**
+			 * 回到今天
+			 */
+			backToday() {
+				const nowYearMonth = `${this.nowDate.year}-${this.nowDate.month}`
+				const date = this.cale.getDate(new Date())
+        const todayYearMonth = `${date.year}-${date.month}`
+
+				this.init(date.fullDate)
+
+        if(nowYearMonth !== todayYearMonth) {
+          this.monthSwitch()
+        }
+
+				this.change()
+			},
+			/**
+			 * 上个月
+			 */
+			pre() {
+				const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
+				this.setDate(preDate)
+				this.monthSwitch()
+
+			},
+			/**
+			 * 下个月
+			 */
+			next() {
+				const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
+				this.setDate(nextDate)
+				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" scoped>
+	$uni-bg-color-mask: rgba($color: #000000, $alpha: 0.4);
+	$uni-border-color: #EDEDED;
+	$uni-text-color: #333;
+	$uni-bg-color-hover:#f1f1f1;
+	$uni-font-size-base:14px;
+	$uni-text-color-placeholder: #808080;
+	$uni-color-subtitle: #555555;
+	$uni-text-color-grey:#999;
+	.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: $uni-bg-color-mask;
+		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;
+		/* #ifdef APP-NVUE */
+		bottom: 0;
+		/* #endif */
+		left: 0;
+		right: 0;
+		transition-property: transform;
+		transition-duration: 0.3s;
+		transform: translateY(460px);
+		/* #ifndef APP-NVUE */
+		bottom: calc(var(--window-bottom));
+		z-index: 99;
+		/* #endif */
+	}
+
+	.uni-calendar--ani-show {
+		transform: translateY(0);
+	}
+
+	.uni-calendar__content {
+		background-color: #fff;
+	}
+
+	.uni-calendar__header {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		height: 50px;
+		border-bottom-color: $uni-border-color;
+		border-bottom-style: solid;
+		border-bottom-width: 1px;
+	}
+
+	.uni-calendar--fixed-top {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: space-between;
+		border-top-color: $uni-border-color;
+		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: $uni-text-color;
+		background-color: $uni-bg-color-hover;
+	}
+
+	.uni-calendar__header-text {
+		text-align: center;
+		width: 100px;
+		font-size: $uni-font-size-base;
+		color: $uni-text-color;
+	}
+
+	.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: 10px;
+		height: 10px;
+		border-left-color: $uni-text-color-placeholder;
+		border-left-style: solid;
+		border-left-width: 2px;
+		border-top-color: $uni-color-subtitle;
+		border-top-style: solid;
+		border-top-width: 2px;
+	}
+
+	.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: 45px;
+		border-bottom-color: #F5F5F5;
+		border-bottom-style: solid;
+		border-bottom-width: 1px;
+	}
+
+	.uni-calendar__weeks-day-text {
+		font-size: 14px;
+	}
+
+	.uni-calendar__box {
+		position: relative;
+	}
+
+	.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: $uni-text-color-grey;
+		opacity: 0.1;
+		text-align: center;
+		/* #ifndef APP-NVUE */
+		line-height: 1;
+		/* #endif */
+	}
+</style>

+ 360 - 0
uni_modules/uni-calendar/components/uni-calendar/util.js

@@ -0,0 +1,360 @@
+import CALENDAR from './calendar.js'
+
+class Calendar {
+	constructor({
+		date,
+		selected,
+		startDate,
+		endDate,
+		range
+	} = {}) {
+		// 当前日期
+		this.date = this.getDate(new Date()) // 当前初入日期
+		// 打点信息
+		this.selected = selected || [];
+		// 范围开始
+		this.startDate = startDate
+		// 范围结束
+		this.endDate = endDate
+		this.range = range
+		// 多选状态
+		this.cleanMultipleStatus()
+		// 每周日期
+		this.weeks = {}
+		// this._getWeek(this.date.fullDate)
+	}
+	/**
+	 * 设置日期
+	 * @param {Object} date
+	 */
+	setDate(date) {
+		this.selectDate = this.getDate(date)
+		this._getWeek(this.selectDate.fullDate)
+	}
+
+	/**
+	 * 清理多选状态
+	 */
+	cleanMultipleStatus() {
+		this.multipleStatus = {
+			before: '',
+			after: '',
+			data: []
+		}
+	}
+
+	/**
+	 * 重置开始日期
+	 */
+	resetSatrtDate(startDate) {
+		// 范围开始
+		this.startDate = startDate
+
+	}
+
+	/**
+	 * 重置结束日期
+	 */
+	resetEndDate(endDate) {
+		// 范围结束
+		this.endDate = endDate
+	}
+
+	/**
+	 * 获取任意时间
+	 */
+	getDate(date, AddDayCount = 0, str = 'day') {
+		if (!date) {
+			date = new Date()
+		}
+		if (typeof date !== 'object') {
+			date = date.replace(/-/g, '/')
+		}
+		const dd = new Date(date)
+		switch (str) {
+			case 'day':
+				dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
+				break
+			case 'month':
+				if (dd.getDate() === 31 && AddDayCount>0) {
+					dd.setDate(dd.getDate() + AddDayCount)
+				} else {
+					const preMonth = dd.getMonth()
+					dd.setMonth(preMonth + AddDayCount) // 获取AddDayCount天后的日期
+					const nextMonth = dd.getMonth()
+					// 处理 pre 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
+					if(AddDayCount<0 && preMonth!==0 && nextMonth-preMonth>AddDayCount){
+						dd.setMonth(nextMonth+(nextMonth-preMonth+AddDayCount))
+					}
+					// 处理 next 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
+					if(AddDayCount>0 && nextMonth-preMonth>AddDayCount){
+						dd.setMonth(nextMonth-(nextMonth-preMonth-AddDayCount))
+					}
+				}
+				break
+			case 'year':
+				dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
+				break
+		}
+		const y = dd.getFullYear()
+		const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
+		const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
+		return {
+			fullDate: y + '-' + m + '-' + d,
+			year: y,
+			month: m,
+			date: d,
+			day: dd.getDay()
+		}
+	}
+
+
+	/**
+	 * 获取上月剩余天数
+	 */
+	_getLastMonthDays(firstDay, full) {
+		let dateArr = []
+		for (let i = firstDay; i > 0; i--) {
+			const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
+			dateArr.push({
+				date: beforeDate,
+				month: full.month - 1,
+				lunar: this.getlunar(full.year, full.month - 1, beforeDate),
+				disable: true
+			})
+		}
+		return dateArr
+	}
+	/**
+	 * 获取本月天数
+	 */
+	_currentMonthDys(dateData, full) {
+		let dateArr = []
+		let fullDate = this.date.fullDate
+		for (let i = 1; i <= dateData; i++) {
+			let nowDate = full.year + '-' + (full.month < 10 ?
+				full.month : full.month) + '-' + (i < 10 ?
+				'0' + i : i)
+			// 是否今天
+			let isDay = fullDate === nowDate
+			// 获取打点信息
+			let info = this.selected && this.selected.find((item) => {
+				if (this.dateEqual(nowDate, item.date)) {
+					return item
+				}
+			})
+
+			// 日期禁用
+			let disableBefore = true
+			let disableAfter = true
+			if (this.startDate) {
+				// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
+				// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
+				disableBefore = this.dateCompare(this.startDate, nowDate)
+			}
+
+			if (this.endDate) {
+				// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
+				// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
+				disableAfter = this.dateCompare(nowDate, this.endDate)
+			}
+			let multiples = this.multipleStatus.data
+			let checked = false
+			let multiplesStatus = -1
+			if (this.range) {
+				if (multiples) {
+					multiplesStatus = multiples.findIndex((item) => {
+						return this.dateEqual(item, nowDate)
+					})
+				}
+				if (multiplesStatus !== -1) {
+					checked = true
+				}
+			}
+			let data = {
+				fullDate: nowDate,
+				year: full.year,
+				date: i,
+				multiple: this.range ? checked : false,
+				beforeMultiple: this.dateEqual(this.multipleStatus.before, nowDate),
+				afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate),
+				month: full.month,
+				lunar: this.getlunar(full.year, full.month, i),
+				disable: !(disableBefore && disableAfter),
+				isDay
+			}
+			if (info) {
+				data.extraInfo = info
+			}
+
+			dateArr.push(data)
+		}
+		return dateArr
+	}
+	/**
+	 * 获取下月天数
+	 */
+	_getNextMonthDays(surplus, full) {
+		let dateArr = []
+		for (let i = 1; i < surplus + 1; i++) {
+			dateArr.push({
+				date: i,
+				month: Number(full.month) + 1,
+				lunar: this.getlunar(full.year, Number(full.month) + 1, i),
+				disable: true
+			})
+		}
+		return dateArr
+	}
+
+	/**
+	 * 获取当前日期详情
+	 * @param {Object} date
+	 */
+	getInfo(date) {
+		if (!date) {
+			date = new Date()
+		}
+		const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
+		return dateInfo
+	}
+
+	/**
+	 * 比较时间大小
+	 */
+	dateCompare(startDate, endDate) {
+		// 计算截止时间
+		startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
+		// 计算详细项的截止时间
+		endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
+		if (startDate <= endDate) {
+			return true
+		} else {
+			return false
+		}
+	}
+
+	/**
+	 * 比较时间是否相等
+	 */
+	dateEqual(before, after) {
+		// 计算截止时间
+		before = new Date(before.replace('-', '/').replace('-', '/'))
+		// 计算详细项的截止时间
+		after = new Date(after.replace('-', '/').replace('-', '/'))
+		if (before.getTime() - after.getTime() === 0) {
+			return true
+		} else {
+			return false
+		}
+	}
+
+
+	/**
+	 * 获取日期范围内所有日期
+	 * @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.getDate(new Date(parseInt(k))).fullDate)
+		}
+		return arr
+	}
+	/**
+	 * 计算阴历日期显示
+	 */
+	getlunar(year, month, date) {
+		return CALENDAR.solar2lunar(year, month, date)
+	}
+	/**
+	 * 设置打点
+	 */
+	setSelectInfo(data, value) {
+		this.selected = value
+		this._getWeek(data)
+	}
+
+	/**
+	 *  获取多选状态
+	 */
+	setMultiple(fullDate) {
+		let {
+			before,
+			after
+		} = this.multipleStatus
+
+		if (!this.range) return
+		if (before && after) {
+			this.multipleStatus.before = fullDate
+			this.multipleStatus.after = ''
+			this.multipleStatus.data = []
+		} else {
+			if (!before) {
+				this.multipleStatus.before = fullDate
+			} else {
+				this.multipleStatus.after = fullDate
+				if (this.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._getWeek(fullDate)
+	}
+
+	/**
+	 * 获取每周数据
+	 * @param {Object} dateData
+	 */
+	_getWeek(dateData) {
+		const {
+			year,
+			month
+		} = this.getDate(dateData)
+		let firstDay = new Date(year, month - 1, 1).getDay()
+		let currentDay = new Date(year, month, 0).getDate()
+		let dates = {
+			lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
+			currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
+			nextMonthDays: [], // 下个月开始几天
+			weeks: []
+		}
+		let canlender = []
+		const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
+		dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
+		canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
+		let weeks = {}
+		// 拼接数组  上个月开始几天 + 本月天数+ 下个月开始几天
+		for (let i = 0; i < canlender.length; i++) {
+			if (i % 7 === 0) {
+				weeks[parseInt(i / 7)] = new Array(7)
+			}
+			weeks[parseInt(i / 7)][i % 7] = canlender[i]
+		}
+		this.canlender = canlender
+		this.weeks = weeks
+	}
+
+	//静态方法
+	// static init(date) {
+	// 	if (!this.instance) {
+	// 		this.instance = new Calendar(date);
+	// 	}
+	// 	return this.instance;
+	// }
+}
+
+
+export default Calendar

+ 86 - 0
uni_modules/uni-calendar/package.json

@@ -0,0 +1,86 @@
+{
+  "id": "uni-calendar",
+  "displayName": "uni-calendar 日历",
+  "version": "1.4.12",
+  "description": "日历组件",
+  "keywords": [
+    "uni-ui",
+    "uniui",
+    "日历",
+    "",
+    "打卡",
+    "日历选择"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": ""
+  },
+  "directories": {
+    "example": "../../temps/example_temps"
+  },
+"dcloudext": {
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+    "type": "component-vue"
+  },
+  "uni_modules": {
+    "dependencies": [],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y",
+        "alipay": "n"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "y"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+          "QQ": "y"
+        },
+        "快应用": {
+          "华为": "u",
+          "联盟": "u"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

+ 103 - 0
uni_modules/uni-calendar/readme.md

@@ -0,0 +1,103 @@
+
+
+## Calendar 日历
+> **组件名:uni-calendar**
+> 代码块: `uCalendar`
+
+
+日历组件
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 本组件农历转换使用的js是 [@1900-2100区间内的公历、农历互转](https://github.com/jjonline/calendar.js)  
+> - 仅支持自定义组件模式
+> - `date`属性传入的应该是一个 String ,如: 2019-06-27 ,而不是 new Date()
+> - 通过 `insert` 属性来确定当前的事件是 @change 还是 @confirm 。理应合并为一个事件,但是为了区分模式,现使用两个事件,这里需要注意
+> - 弹窗模式下无法阻止后面的元素滚动,如有需要阻止,请在弹窗弹出后,手动设置滚动元素为不可滚动
+
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+在 ``template`` 中使用组件
+
+```html
+<view>
+	<uni-calendar 
+	:insert="true"
+	:lunar="true" 
+	:start-date="'2019-3-2'"
+	:end-date="'2019-5-20'"
+	@change="change"
+	 />
+</view>
+```
+
+### 通过方法打开日历
+
+需要设置 `insert` 为 `false`
+
+```html
+<view>
+	<uni-calendar 
+	ref="calendar"
+	:insert="false"
+	@confirm="confirm"
+	 />
+	 <button @click="open">打开日历</button>
+</view>
+```
+
+```javascript
+
+export default {
+	data() {
+		return {};
+	},
+	methods: {
+		open(){
+			this.$refs.calendar.open();
+		},
+		confirm(e) {
+			console.log(e);
+		}
+	}
+};
+
+```
+
+
+## API
+
+### Calendar Props
+
+|  属性名	|    类型	| 默认值| 说明																													|
+| -	| -	| - | - |
+| date		| String	|-		| 自定义当前时间,默认为今天																							|
+| lunar		| Boolean	| false	| 显示农历																												|
+| startDate	| String	|-		| 日期选择范围-开始日期																									|
+| endDate	| String	|-		| 日期选择范围-结束日期																									|
+| range		| Boolean	| false	| 范围选择																												|
+| insert	| Boolean	| false	| 插入模式,可选值,ture:插入模式;false:弹窗模式;默认为插入模式														|
+|clearDate	|Boolean	|true	|弹窗模式是否清空上次选择内容	|
+| selected	| Array		|-		| 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]	|
+|showMonth	| Boolean	| true	| 是否显示月份为背景																									|
+
+### Calendar Events
+
+|  事件名		| 说明								|返回值|
+| -	|	-	| -	|
+| open	| 弹出日历组件,`insert :false` 时生效|- 	|
+
+
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar](https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar)