commit
					0120e79f37
				
				 667 changed files with 85737 additions and 0 deletions
			
			
		@ -0,0 +1,75 @@
					 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		onLaunch: function() { | 
				
			||||
			// 静默登录 | 
				
			||||
			uni.login({ | 
				
			||||
				success(res) { | 
				
			||||
					uni.$u.http.post('/login', { | 
				
			||||
						code: res.code | 
				
			||||
					}).then(res => { | 
				
			||||
						// 获取token | 
				
			||||
						const token = 'Bearer ' + res.data.data | 
				
			||||
						// 全局存储令牌 | 
				
			||||
						// console.log(token); | 
				
			||||
						uni.$u.vuex('vuex_token', token); | 
				
			||||
						 | 
				
			||||
						uni.$u.http.setConfig((config) => { | 
				
			||||
							config.header = { | 
				
			||||
								authorization: token | 
				
			||||
							}; | 
				
			||||
							return config | 
				
			||||
						}) | 
				
			||||
						// 获取用户接口数据 | 
				
			||||
						uni.$u.http.get('/getInfo', {}).then(res => { | 
				
			||||
							console.log(res.data); | 
				
			||||
							let user = { | 
				
			||||
								roles: res.data.roles, | 
				
			||||
								permissions: res.data.permissions, | 
				
			||||
								// avatar: res.data.user.avatar, | 
				
			||||
								avatar: 'https://jzhome.cn/static/gongan.png', | 
				
			||||
								realName: res.data.user.realName, | 
				
			||||
								sex: res.data.user.sex, | 
				
			||||
								phonenumber: res.data.user.phonenumber, | 
				
			||||
								deptName: res.data.user.deptName, | 
				
			||||
								userType: res.data.user.userType, | 
				
			||||
							} | 
				
			||||
							// 全局存储用户数据 | 
				
			||||
							uni.$u.vuex('vuex_user', user); | 
				
			||||
 | 
				
			||||
							// 跳转到局内注册 | 
				
			||||
							// if (user.userType !== "00") { | 
				
			||||
							// 	uni.$u.route('/pages/index/off_reg'); | 
				
			||||
							// } | 
				
			||||
 | 
				
			||||
						}).catch(err => { | 
				
			||||
							console.log('您没有访问权限'); | 
				
			||||
						}) | 
				
			||||
						// 获取部门接口数据 | 
				
			||||
						uni.$u.http.get('/dept/list', {}).then(res => { | 
				
			||||
							uni.$u.vuex('vuex_dept', res.data.data); | 
				
			||||
						}) | 
				
			||||
 | 
				
			||||
					}).catch(err => { | 
				
			||||
						console.log('访问失败'); | 
				
			||||
					}) | 
				
			||||
 | 
				
			||||
				} | 
				
			||||
			}); | 
				
			||||
		}, | 
				
			||||
		onShow: function() { | 
				
			||||
			console.log('App Show') | 
				
			||||
		}, | 
				
			||||
		onHide: function() { | 
				
			||||
			console.log('App Hide') | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
	/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */ | 
				
			||||
	@import "@/uni_modules/uview-ui/index.scss"; | 
				
			||||
 | 
				
			||||
	page { | 
				
			||||
		background-color: #F9F9F9; | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,20 @@
					 | 
				
			||||
<!DOCTYPE html> | 
				
			||||
<html lang="en"> | 
				
			||||
  <head> | 
				
			||||
    <meta charset="UTF-8" /> | 
				
			||||
    <script> | 
				
			||||
      var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || | 
				
			||||
        CSS.supports('top: constant(a)')) | 
				
			||||
      document.write( | 
				
			||||
        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + | 
				
			||||
        (coverSupport ? ', viewport-fit=cover' : '') + '" />') | 
				
			||||
    </script> | 
				
			||||
    <title></title> | 
				
			||||
    <!--preload-links--> | 
				
			||||
    <!--app-context--> | 
				
			||||
  </head> | 
				
			||||
  <body> | 
				
			||||
    <div id="app"><!--app-html--></div> | 
				
			||||
    <script type="module" src="/main.js"></script> | 
				
			||||
  </body> | 
				
			||||
</html> | 
				
			||||
@ -0,0 +1,49 @@
					 | 
				
			||||
import App from './App' | 
				
			||||
 | 
				
			||||
// #ifndef VUE3
 | 
				
			||||
import Vue from 'vue' | 
				
			||||
 | 
				
			||||
// 引入uView
 | 
				
			||||
import uView from '@/uni_modules/uview-ui' | 
				
			||||
Vue.use(uView) | 
				
			||||
 | 
				
			||||
// 全局配置根域名
 | 
				
			||||
uni.$u.http.setConfig((config) => { | 
				
			||||
	/* config 为默认全局配置*/ | 
				
			||||
	config.baseURL = `http://192.168.2.101:8080/api/app`; | 
				
			||||
	return config | 
				
			||||
}) | 
				
			||||
 | 
				
			||||
// Vuex
 | 
				
			||||
import store from '@/store'; | 
				
			||||
import vuexStore from '@/store/$u.mixin.js'; | 
				
			||||
Vue.mixin(vuexStore); | 
				
			||||
 | 
				
			||||
import './uni.promisify.adaptor' | 
				
			||||
Vue.config.productionTip = false | 
				
			||||
App.mpType = 'app' | 
				
			||||
 | 
				
			||||
const app = new Vue({ | 
				
			||||
	store, | 
				
			||||
	...App | 
				
			||||
}) | 
				
			||||
app.$mount() | 
				
			||||
// #endif
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
// #ifdef VUE3
 | 
				
			||||
import { | 
				
			||||
	createSSRApp | 
				
			||||
} from 'vue' | 
				
			||||
 | 
				
			||||
// 引入uView主JS库
 | 
				
			||||
import uView from '@/uni_modules/uview-ui' | 
				
			||||
Vue.use(uView) | 
				
			||||
 | 
				
			||||
export function createApp() { | 
				
			||||
	const app = createSSRApp(App) | 
				
			||||
	return { | 
				
			||||
		app | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
// #endif
 | 
				
			||||
@ -0,0 +1,72 @@
					 | 
				
			||||
{ | 
				
			||||
    "name" : "智慧环保", | 
				
			||||
    "appid" : "__UNI__20C9AD1", | 
				
			||||
    "description" : "智慧环保", | 
				
			||||
    "versionName" : "1.0.0", | 
				
			||||
    "versionCode" : "100", | 
				
			||||
    "transformPx" : false, | 
				
			||||
    /* 5+App特有相关 */ | 
				
			||||
    "app-plus" : { | 
				
			||||
        "usingComponents" : true, | 
				
			||||
        "nvueStyleCompiler" : "uni-app", | 
				
			||||
        "compilerVersion" : 3, | 
				
			||||
        "splashscreen" : { | 
				
			||||
            "alwaysShowBeforeRender" : true, | 
				
			||||
            "waiting" : true, | 
				
			||||
            "autoclose" : true, | 
				
			||||
            "delay" : 0 | 
				
			||||
        }, | 
				
			||||
        /* 模块配置 */ | 
				
			||||
        "modules" : {}, | 
				
			||||
        /* 应用发布信息 */ | 
				
			||||
        "distribute" : { | 
				
			||||
            /* android打包配置 */ | 
				
			||||
            "android" : { | 
				
			||||
                "permissions" : [ | 
				
			||||
                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", | 
				
			||||
                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", | 
				
			||||
                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>", | 
				
			||||
                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>", | 
				
			||||
                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", | 
				
			||||
                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", | 
				
			||||
                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", | 
				
			||||
                    "<uses-permission android:name=\"android.permission.CAMERA\"/>", | 
				
			||||
                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", | 
				
			||||
                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", | 
				
			||||
                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", | 
				
			||||
                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", | 
				
			||||
                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", | 
				
			||||
                    "<uses-feature android:name=\"android.hardware.camera\"/>", | 
				
			||||
                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" | 
				
			||||
                ] | 
				
			||||
            }, | 
				
			||||
            /* ios打包配置 */ | 
				
			||||
            "ios" : {}, | 
				
			||||
            /* SDK配置 */ | 
				
			||||
            "sdkConfigs" : {} | 
				
			||||
        } | 
				
			||||
    }, | 
				
			||||
    /* 快应用特有相关 */ | 
				
			||||
    "quickapp" : {}, | 
				
			||||
    /* 小程序特有相关 */ | 
				
			||||
    "mp-weixin" : { | 
				
			||||
        "appid" : "wx6a07542e99f7fc98", | 
				
			||||
        "setting" : { | 
				
			||||
            "urlCheck" : false | 
				
			||||
        }, | 
				
			||||
        "usingComponents" : true | 
				
			||||
    }, | 
				
			||||
    "mp-alipay" : { | 
				
			||||
        "usingComponents" : true | 
				
			||||
    }, | 
				
			||||
    "mp-baidu" : { | 
				
			||||
        "usingComponents" : true | 
				
			||||
    }, | 
				
			||||
    "mp-toutiao" : { | 
				
			||||
        "usingComponents" : true | 
				
			||||
    }, | 
				
			||||
    "uniStatistics" : { | 
				
			||||
        "enable" : false | 
				
			||||
    }, | 
				
			||||
    "vueVersion" : "2" | 
				
			||||
} | 
				
			||||
@ -0,0 +1,134 @@
					 | 
				
			||||
{ | 
				
			||||
	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages | 
				
			||||
		{ | 
				
			||||
			"path": "pages/index/index", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "智慧环保" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/index/off_reg", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "部门申请" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/index/ent_reg", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "企业注册" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/task/index", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "执法任务" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/task/list", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "任务列表" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/task/item", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "任务详情" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/ent/index", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "环保企业" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/ent/info", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "企业详情" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/public/sug", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "投诉建议" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/user/index", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "个人中心" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/user/edit", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "编辑资料" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/user/notif", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "消息通知" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/user/law", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "政策法规" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/user/task", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "任务记录" | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		{ | 
				
			||||
			"path": "pages/AI/index", | 
				
			||||
			"style": { | 
				
			||||
				"navigationBarTitleText": "AI" | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	], | 
				
			||||
	"globalStyle": { | 
				
			||||
		"navigationBarTextStyle": "black", | 
				
			||||
		"navigationBarTitleText": "智慧环保", | 
				
			||||
		"navigationBarBackgroundColor": "#FFF", | 
				
			||||
		"backgroundColor": "#FFF" | 
				
			||||
	}, | 
				
			||||
 | 
				
			||||
	"uniIdRouter": {}, | 
				
			||||
 | 
				
			||||
	"tabBar": { | 
				
			||||
		"color": "#7A7E83", | 
				
			||||
		"selectedColor": "#3cc51f", | 
				
			||||
		"borderStyle": "black", | 
				
			||||
		"backgroundColor": "#ffffff", | 
				
			||||
		"list": [{ | 
				
			||||
			"pagePath": "pages/index/index", | 
				
			||||
			"iconPath": "/static/logo.png", | 
				
			||||
			"selectedIconPath": "/static/logo.png", | 
				
			||||
			"text": "首页" | 
				
			||||
		}, { | 
				
			||||
			"pagePath": "pages/task/index", | 
				
			||||
			"iconPath": "/static/logo.png", | 
				
			||||
			"selectedIconPath": "/static/logo.png", | 
				
			||||
			"text": "任务" | 
				
			||||
		}, { | 
				
			||||
			"pagePath": "pages/AI/index", | 
				
			||||
			"iconPath": "/static/logo.png", | 
				
			||||
			"selectedIconPath": "/static/logo.png" | 
				
			||||
		}, { | 
				
			||||
			"pagePath": "pages/ent/index", | 
				
			||||
			"iconPath": "/static/logo.png", | 
				
			||||
			"selectedIconPath": "/static/logo.png", | 
				
			||||
			"text": "企业" | 
				
			||||
		}, { | 
				
			||||
			"pagePath": "pages/user/index", | 
				
			||||
			"iconPath": "/static/logo.png", | 
				
			||||
			"selectedIconPath": "/static/logo.png", | 
				
			||||
			"text": "我的" | 
				
			||||
		}] | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,19 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view> | 
				
			||||
		AI | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				 | 
				
			||||
			}; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
 | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,108 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="wrap"> | 
				
			||||
		<!-- 吸顶 --> | 
				
			||||
		<u-sticky bgColor="#fff"> | 
				
			||||
			<!-- 搜索 --> | 
				
			||||
			<u-search placeholder="日照香炉生紫烟" v-model="keyword"></u-search> | 
				
			||||
			<!-- 筛选 --> | 
				
			||||
			<view class=""> | 
				
			||||
				筛选 | 
				
			||||
			</view> | 
				
			||||
		</u-sticky> | 
				
			||||
 | 
				
			||||
		<!-- 列表 --> | 
				
			||||
		<view class="list"> | 
				
			||||
			<u-list @scrolltolower="scrolltolower"> | 
				
			||||
				<u-list-item v-for="(item, index) in indexList" :key="index" @tap="toInfo"> | 
				
			||||
					<u-cell :title="`列表长度-${index + 1}`"> | 
				
			||||
						<u-avatar slot="icon" shape="square" size="35" :src="item.url" | 
				
			||||
							customStyle="margin: -3px 5px -3px 0"></u-avatar> | 
				
			||||
					</u-cell> | 
				
			||||
				</u-list-item> | 
				
			||||
			</u-list> | 
				
			||||
		</view> | 
				
			||||
		<!-- <view class="list"> | 
				
			||||
			<view class="item" v-for="(item, index) in list" :key="index"> | 
				
			||||
				{{'第' + item + '条数据'}} | 
				
			||||
			</view> | 
				
			||||
			 | 
				
			||||
			<u-loadmore :status="status" /> | 
				
			||||
		</view> --> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				// 搜索 | 
				
			||||
				keyword: '遥看瀑布挂前川', | 
				
			||||
				// 筛选 | 
				
			||||
 | 
				
			||||
				// 列表 | 
				
			||||
				indexList: [], | 
				
			||||
				urls: [ | 
				
			||||
					"https://xxx.com/album/1.jpg", | 
				
			||||
					"https://xxx.com/album/2.jpg", | 
				
			||||
					"https://xxx.com/album/3.jpg", | 
				
			||||
					"https://xxx.com/album/4.jpg", | 
				
			||||
					"https://xxx.com/album/5.jpg", | 
				
			||||
					"https://xxx.com/album/6.jpg", | 
				
			||||
					"https://xxx.com/album/7.jpg", | 
				
			||||
					"https://xxx.com/album/8.jpg", | 
				
			||||
					"https://xxx.com/album/9.jpg", | 
				
			||||
					"https://xxx.com/album/10.jpg", | 
				
			||||
				], | 
				
			||||
				// 加载更多 | 
				
			||||
				status: 'loadmore', | 
				
			||||
				list: 15, | 
				
			||||
				page: 0 | 
				
			||||
			}; | 
				
			||||
		}, | 
				
			||||
		onLoad() { | 
				
			||||
			this.loadmore(); | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			toInfo() { | 
				
			||||
				uni.$u.route('/pages/ent/info'); | 
				
			||||
			}, | 
				
			||||
			scrolltolower() { | 
				
			||||
				this.loadmore(); | 
				
			||||
			}, | 
				
			||||
			loadmore() { | 
				
			||||
				for (let i = 0; i < 30; i++) { | 
				
			||||
					this.indexList.push({ | 
				
			||||
						url: this.urls[uni.$u.random(0, this.urls.length - 1)], | 
				
			||||
					}); | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
		// 触底 | 
				
			||||
		// onReachBottom() { | 
				
			||||
		// 	if (this.page >= 3) return; | 
				
			||||
		// 	this.status = 'loading'; | 
				
			||||
		// 	this.page = ++this.page; | 
				
			||||
		// 	setTimeout(() => { | 
				
			||||
		// 		this.list += 10; | 
				
			||||
		// 		if (this.page >= 3) this.status = 'nomore'; | 
				
			||||
		// 		else this.status = 'loading'; | 
				
			||||
		// 	}, 2000) | 
				
			||||
		// }, | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
	.wrap { | 
				
			||||
		background-color: #F9F9F9; | 
				
			||||
		min-height: 100vh; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
		.list { | 
				
			||||
			display: flex; | 
				
			||||
			flex-direction: column; | 
				
			||||
			gap: 24rpx; | 
				
			||||
			padding: 24rpx; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,71 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="wrap"> | 
				
			||||
		 | 
				
			||||
		<view class=""> | 
				
			||||
			基本信息 | 
				
			||||
		</view> | 
				
			||||
		<view class=""> | 
				
			||||
			环保信息 | 
				
			||||
		</view> | 
				
			||||
		<view class=""> | 
				
			||||
			执法信息 | 
				
			||||
		</view> | 
				
			||||
		 | 
				
			||||
		================================= | 
				
			||||
		<view> | 
				
			||||
			<u-row> | 
				
			||||
				<u-col span="6"> | 
				
			||||
					<view>义县某某环保企业名称</view> | 
				
			||||
				</u-col> | 
				
			||||
				<u-col span="6"> | 
				
			||||
					<view>危废</view> | 
				
			||||
				</u-col> | 
				
			||||
			</u-row> | 
				
			||||
			<u-row> | 
				
			||||
				<view>企业地址 某某区工业产业园5-182号</view> | 
				
			||||
			</u-row> | 
				
			||||
			<u-row> | 
				
			||||
				<view>企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介企业简介</view> | 
				
			||||
			</u-row> | 
				
			||||
			<u-row gutter="24rpx"> | 
				
			||||
				<u-col span="4"> | 
				
			||||
					<u--image src="/static/logo.png" mode="widthFix"></u--image> | 
				
			||||
				</u-col> | 
				
			||||
				<u-col span="4"> | 
				
			||||
					<u--image src="/static/logo.png" mode="widthFix"></u--image> | 
				
			||||
				</u-col> | 
				
			||||
				<u-col span="4"> | 
				
			||||
					 | 
				
			||||
				</u-col> | 
				
			||||
 | 
				
			||||
			</u-row> | 
				
			||||
			<u--image src="/static/logo.png" mode="widthFix"></u--image> | 
				
			||||
			<u-row> | 
				
			||||
				<u-col span="6"> | 
				
			||||
					<view>环保负责/张某某</view> | 
				
			||||
				</u-col> | 
				
			||||
				<u-col span="6"> | 
				
			||||
					<view>成立时间/2017年10月24日</view> | 
				
			||||
				</u-col> | 
				
			||||
			</u-row> | 
				
			||||
		</view> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
 | 
				
			||||
			}; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
	.wrap { | 
				
			||||
		background-color: #F9F9F9; | 
				
			||||
		min-height: 100vh; | 
				
			||||
		padding: 24rpx; | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,243 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="wrap"> | 
				
			||||
		<view class="form"> | 
				
			||||
			<u--form :model="form" ref="uForm" labelWidth="80"> | 
				
			||||
				<!-- 企业名称 --> | 
				
			||||
				<u-form-item label="企业名称" prop="name" borderBottom> | 
				
			||||
					<u-input v-model="form.name" border="none" placeholder="请输入" /> | 
				
			||||
				</u-form-item> | 
				
			||||
				<!-- 企业类型 --> | 
				
			||||
				<u-form-item label="企业类型" prop="type" borderBottom @tap="showType = true;"> | 
				
			||||
					<u--input v-model="form.type" placeholder="请选择" border="none"></u--input> | 
				
			||||
					<u-icon slot="right" name="arrow-right"></u-icon> | 
				
			||||
				</u-form-item> | 
				
			||||
				<!-- 企业地址 --> | 
				
			||||
				<u-form-item label="企业地址" prop="addr" borderBottom> | 
				
			||||
					<u-input v-model="form.addr" border="none" placeholder="请输入" /> | 
				
			||||
				</u-form-item> | 
				
			||||
				<!-- 企业简介 --> | 
				
			||||
				<u-form-item label="企业简介" prop="info" borderBottom> | 
				
			||||
					<u--textarea v-model="form.info" placeholder="请输入" border="none" count="true"></u--textarea> | 
				
			||||
				</u-form-item> | 
				
			||||
				<!-- 企业照片 --> | 
				
			||||
				<u-form-item label="企业照片" borderBottom> | 
				
			||||
					<u-upload :fileList="form.photo" @afterRead="addPhoto" @delete="delPhoto" multiple | 
				
			||||
						:maxCount="6"></u-upload> | 
				
			||||
				</u-form-item> | 
				
			||||
				<!-- 环保负责人 --> | 
				
			||||
				<u-form-item label="环保负责人" prop="manager" borderBottom> | 
				
			||||
					<u-input v-model="form.manager" border="none" placeholder="请输入" /> | 
				
			||||
				</u-form-item> | 
				
			||||
				<!-- 联系方式 --> | 
				
			||||
				<u-form-item label="联系方式" prop="phone" borderBottom> | 
				
			||||
					<u-input v-model="form.phone" border="none" placeholder="请输入" /> | 
				
			||||
				</u-form-item> | 
				
			||||
 | 
				
			||||
				<!-- 成立时间 --> | 
				
			||||
				<u-form-item label="成立时间" prop="regtime" borderBottom @tap="showRegtime = true"> | 
				
			||||
					<u-datetime-picker :show="showRegtime" v-model="defTime" mode="date" @confirm="regtime" | 
				
			||||
						@cancel="showRegtime = false"></u-datetime-picker> | 
				
			||||
					<u-input :value="form.regtime" border="none" placeholder="请输入" /> | 
				
			||||
					<u-icon slot="right" name="arrow-right"></u-icon> | 
				
			||||
				</u-form-item> | 
				
			||||
 | 
				
			||||
 | 
				
			||||
				<u-form-item label="zzlx" prop="hblicense" borderBottom labelPosition="top"> | 
				
			||||
					<u-input v-model="form.hblicense" border="none" placeholder="请输入" /> | 
				
			||||
				</u-form-item> | 
				
			||||
 | 
				
			||||
				<u-form-item label="bh" prop="pwlicense" borderBottom labelPosition="top"> | 
				
			||||
					<u-input v-model="form.pwlicense" border="none" placeholder="请输入" /> | 
				
			||||
				</u-form-item> | 
				
			||||
 | 
				
			||||
				<u-form-item label="bh" prop="pwlicense" borderBottom labelPosition="top"> | 
				
			||||
					<u-input v-model="form.pwlicense" border="none" placeholder="请输入" /> | 
				
			||||
				</u-form-item> | 
				
			||||
 | 
				
			||||
 | 
				
			||||
			</u--form> | 
				
			||||
 | 
				
			||||
			<!-- <view v-if='isEdit'> | 
				
			||||
				<view class="" v-for="zz in zzlist" :key="zz.uid" @tap="edit(zz)"> | 
				
			||||
					<view class=""> | 
				
			||||
						<label for="">zzlx</label><text>{{zz.zzlx}}</text> | 
				
			||||
					</view> | 
				
			||||
				</view> | 
				
			||||
			</view> --> | 
				
			||||
 | 
				
			||||
			<!-- <u--form :model="zzform" v-else> | 
				
			||||
				 | 
				
			||||
		 | 
				
			||||
				<u-form-item label="zzlx" prop="hblicense" borderBottom labelPosition="top"> | 
				
			||||
					<u-input v-model="form.hblicense" border="none" placeholder="请输入" /> | 
				
			||||
				</u-form-item> | 
				
			||||
		 | 
				
			||||
				<u-form-item label="bh" prop="pwlicense" borderBottom labelPosition="top"> | 
				
			||||
					<u-input v-model="form.pwlicense" border="none" placeholder="请输入" /> | 
				
			||||
				</u-form-item> | 
				
			||||
				<u-form-item label="sj" prop="pwlicense" borderBottom labelPosition="top"> | 
				
			||||
					<u-input v-model="form.pwlicense" border="none" placeholder="请输入" /> | 
				
			||||
				</u-form-item> | 
				
			||||
				<u-form-item> | 
				
			||||
					<button @tap='savazz'>save</button> | 
				
			||||
				</u-form-item> | 
				
			||||
			</u--form> --> | 
				
			||||
 | 
				
			||||
			<u-action-sheet :show="showType" :actions="types" title="请选择企业类型" @close="showType = false" | 
				
			||||
				@select="typeSelect"> | 
				
			||||
			</u-action-sheet> | 
				
			||||
 | 
				
			||||
		</view> | 
				
			||||
		<u-button @tap="submit">提交</u-button> | 
				
			||||
	</view> | 
				
			||||
 | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				form: { | 
				
			||||
					name: '', // 企业名称 | 
				
			||||
					type: '', // 企业类型 | 
				
			||||
					info: '', // 企业地址 | 
				
			||||
					addr: '', // 企业简介 | 
				
			||||
					photo: [], // 企业照片 | 
				
			||||
					manager: '', // 环保负责人 | 
				
			||||
					phone: '', // 联系方式 | 
				
			||||
					regtime: '', // 成立时间 | 
				
			||||
					hblicense: '', // 环保许可证 | 
				
			||||
					pwlicense: '', // 排污许可证 | 
				
			||||
				}, | 
				
			||||
				defTime: Number(new Date()), // 初始化日期 | 
				
			||||
				showType: false, | 
				
			||||
				showRegtime: false, | 
				
			||||
				types: [{ | 
				
			||||
						name: '小型', | 
				
			||||
					}, | 
				
			||||
					{ | 
				
			||||
						name: '中型', | 
				
			||||
					}, | 
				
			||||
					{ | 
				
			||||
						name: '大型', | 
				
			||||
					}, | 
				
			||||
				], | 
				
			||||
 | 
				
			||||
				rules: { | 
				
			||||
					name: { | 
				
			||||
						required: true, | 
				
			||||
						message: '请输入企业名称', | 
				
			||||
						trigger: ['blur'] | 
				
			||||
					}, | 
				
			||||
					type: { | 
				
			||||
						type: 'string', | 
				
			||||
						required: true, | 
				
			||||
						message: '请选择企业类型', | 
				
			||||
						trigger: ['blur'] | 
				
			||||
					}, | 
				
			||||
					info: { | 
				
			||||
						type: 'string', | 
				
			||||
						min: 3, | 
				
			||||
						required: true, | 
				
			||||
						message: '不低于3个字', | 
				
			||||
						trigger: ['change'] | 
				
			||||
					}, | 
				
			||||
					addr: { | 
				
			||||
						required: true, | 
				
			||||
						message: '请输入企业地址', | 
				
			||||
						trigger: ['blur'] | 
				
			||||
					}, | 
				
			||||
					manager: { | 
				
			||||
						required: true, | 
				
			||||
						message: '请输入环保负责人', | 
				
			||||
						trigger: ['blur'] | 
				
			||||
					}, | 
				
			||||
					phone: { | 
				
			||||
						required: true, | 
				
			||||
						message: '请输入联系方式', | 
				
			||||
						trigger: ['blur'] | 
				
			||||
					}, | 
				
			||||
				}, | 
				
			||||
				zzform: {}, | 
				
			||||
				zzList: [], | 
				
			||||
				isEdit: false | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			// 提交数据 | 
				
			||||
			submit() { | 
				
			||||
				this.$refs.uForm.validate().then(res => { | 
				
			||||
					uni.$u.toast('校验通过') | 
				
			||||
					// 提交时上传照片 | 
				
			||||
					this.uploadPhoto(this.form.photo) | 
				
			||||
				}).catch(errors => { | 
				
			||||
					uni.$u.toast('校验失败') | 
				
			||||
				}) | 
				
			||||
			}, | 
				
			||||
			// 企业成立时间 | 
				
			||||
			regtime(e) { | 
				
			||||
				this.form.regtime = uni.$u.timeFormat(e.value, 'yyyy-mm-dd'); | 
				
			||||
				this.showRegtime = false | 
				
			||||
			}, | 
				
			||||
			// 选择企业类型 | 
				
			||||
			typeSelect(e) { | 
				
			||||
				this.form.type = e.name | 
				
			||||
				this.$refs.uForm.validateField('type') | 
				
			||||
			}, | 
				
			||||
			// 新增图片 | 
				
			||||
			addPhoto(e) { | 
				
			||||
				this.form.photo = e.file.map(item => { | 
				
			||||
					return { | 
				
			||||
						url: item.url | 
				
			||||
					} | 
				
			||||
				}); | 
				
			||||
			}, | 
				
			||||
			// 删除图片 | 
				
			||||
			delPhoto(e) { | 
				
			||||
				this.form.photo.splice(e.index, 1); | 
				
			||||
			}, | 
				
			||||
			// 提交时上传图片 | 
				
			||||
			async uploadPhoto(photo) { | 
				
			||||
				// 遍历图片数组并上传每张图片 | 
				
			||||
				for (let i = 0; i < photo.length; i++) { | 
				
			||||
					try { | 
				
			||||
						// 获取每张图片的 URL | 
				
			||||
						const url = photo[i].url; | 
				
			||||
						const res = await uni.$u.http.upload('http://192.168.2.101:8080/api/common_file/upload', { | 
				
			||||
							filePath: url, | 
				
			||||
							name: 'file', | 
				
			||||
						}); | 
				
			||||
						console.log(`照片 ${i + 1} 上传结果`, res); | 
				
			||||
					} catch (err) { | 
				
			||||
						console.log(`上传照片 ${i + 1} 失败`, err); | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			savazz() { | 
				
			||||
				const data = this.zzform | 
				
			||||
				data.uid = '' | 
				
			||||
				this.zzList.push(data) | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		onReady() { | 
				
			||||
			//如果需要兼容微信小程序,并且校验规则中含有方法等,只能通过setRules方法设置规则。 | 
				
			||||
			this.$refs.uForm.setRules(this.rules) | 
				
			||||
		}, | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
	.wrap { | 
				
			||||
		background-color: #F9F9F9; | 
				
			||||
		min-height: 100vh; | 
				
			||||
 | 
				
			||||
		.form { | 
				
			||||
			padding: 48rpx; | 
				
			||||
 | 
				
			||||
			.u-textarea { | 
				
			||||
				background-color: inherit; | 
				
			||||
				padding: 0; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,54 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="wrap"> | 
				
			||||
		{{title}} | 
				
			||||
		<u-count-to :start-val="30" :end-val="500" :duration="2000" :useEasing="false"></u-count-to> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				title: '首页' | 
				
			||||
			}; | 
				
			||||
		}, | 
				
			||||
		onLoad() { | 
				
			||||
 | 
				
			||||
			// let aa = this.vuex_version | 
				
			||||
			// console.log(aa); | 
				
			||||
 | 
				
			||||
			// const roles = res.data.roles | 
				
			||||
			// if (!roles.includes('enterprise')) { | 
				
			||||
			// 	// uni.$u.route('/pages/index/off_reg'); | 
				
			||||
			// 	console.log('不是局内角色'); | 
				
			||||
			// } | 
				
			||||
 | 
				
			||||
			// uni.request({ | 
				
			||||
			// 	url: 'https://hb.jzce.com', | 
				
			||||
			// 	method: 'GET', | 
				
			||||
			// 	success: (res) => { | 
				
			||||
			// 		this.title = res.data | 
				
			||||
			// 	} | 
				
			||||
			// }) | 
				
			||||
		}, | 
				
			||||
		onShow() { | 
				
			||||
			// if (this.vuex_user) { | 
				
			||||
			// 	let user = this.vuex_user | 
				
			||||
			// 	// 跳转到局内注册 | 
				
			||||
			// 	if (user.userType !== "00") { | 
				
			||||
			// 		uni.$u.route('/pages/index/off_reg'); | 
				
			||||
			// 	} | 
				
			||||
			// } | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
 | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
	.wrap { | 
				
			||||
		background-color: #F9F9F9; | 
				
			||||
		min-height: 100vh; | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,101 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="wrap"> | 
				
			||||
		<u-action-sheet :actions="list" :title="title" :show="show"></u-action-sheet> | 
				
			||||
		<u-button class="count" @click="show = true">打开ActionSheet</u-button> | 
				
			||||
		<text class="u-line-1">是日也,天朗气清,惠风和畅,仰观宇宙之大,俯察品类之盛</text> | 
				
			||||
		<view class="u-border-bottom box"> | 
				
			||||
			夫人之相与,俯仰一世,或取诸怀抱,悟言一室之内;或因寄所托,放浪形骸之外 | 
				
			||||
		</view> | 
				
			||||
		<view class="box"> | 
				
			||||
			121312 | 
				
			||||
		</view> | 
				
			||||
		<button>点击登录</button> | 
				
			||||
 | 
				
			||||
		<view @click="aa"> | 
				
			||||
			dianwo | 
				
			||||
		</view> | 
				
			||||
		<view class=""> | 
				
			||||
			{{sys}} | 
				
			||||
		</view> | 
				
			||||
 | 
				
			||||
		<view class=""> | 
				
			||||
		 | 
				
			||||
			版本号为:{{vuex_version}} | 
				
			||||
			<<琵琶行>>的作者为{{vuex_user.name}} | 
				
			||||
		</view> | 
				
			||||
 | 
				
			||||
		<u-button @click="modifyVuex">修改变量</u-button> | 
				
			||||
		<u-button @click="api">获取接口</u-button> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				title: '标题', | 
				
			||||
				list: [{ | 
				
			||||
						name: '选项一', | 
				
			||||
						subname: "选项一描述", | 
				
			||||
						color: '#ffaa7f', | 
				
			||||
						fontSize: '20' | 
				
			||||
					}, | 
				
			||||
					{ | 
				
			||||
						name: '选项二禁用', | 
				
			||||
						disabled: true | 
				
			||||
					}, | 
				
			||||
					{ | 
				
			||||
						name: '开启load加载', //开启后文字不显示 | 
				
			||||
						loading: true | 
				
			||||
					} | 
				
			||||
				], | 
				
			||||
				show: false, | 
				
			||||
				sys: '' | 
				
			||||
			}; | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			 | 
				
			||||
			api() { | 
				
			||||
				uni.$u.http.get('/users', {}).then(res => { | 
				
			||||
					console.log(res); | 
				
			||||
				}).catch(err => { | 
				
			||||
				 | 
				
			||||
				}) | 
				
			||||
				//  | 
				
			||||
			}, | 
				
			||||
			 | 
				
			||||
			 | 
				
			||||
			 | 
				
			||||
			aa() { | 
				
			||||
				console.log(uni.$u.pages()); | 
				
			||||
				this.sys = uni.$u.sys().model | 
				
			||||
				// this.sys = uni.$u.pages() | 
				
			||||
			}, | 
				
			||||
 | 
				
			||||
			modifyVuex() { | 
				
			||||
				this.$u.vuex('vuex_version', '1.0.2'); | 
				
			||||
				// 修改对象的形式,中间用"."分隔 | 
				
			||||
				this.$u.vuex('vuex_user.name', '诗圣'); | 
				
			||||
				// this.$u.vuex('aa', 'zxx'); | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
		} | 
				
			||||
	}; | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
 | 
				
			||||
<!-- 请确保在style标签声明了"lang="scss"" --> | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	.wrap { | 
				
			||||
		background-color: $u-bg-color; | 
				
			||||
		min-height: 100vh; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.box { | 
				
			||||
		color: $u-primary-dark; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.count { | 
				
			||||
		border-color: $u-primary-dark; | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,310 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="wrap"> | 
				
			||||
		<view class="form"> | 
				
			||||
			<!-- 我的头像 --> | 
				
			||||
			<view class="item"> | 
				
			||||
				<text>我的头像</text> | 
				
			||||
				<view class="right"> | 
				
			||||
					<button class="u-reset-button" open-type="chooseAvatar" @chooseavatar="getAvatar"> | 
				
			||||
						<image v-if="form.avatar" class="avatar" :src="form.avatar" mode="aspectFill"></image> | 
				
			||||
						<text v-else>点击获取</text> | 
				
			||||
					</button> | 
				
			||||
					<u-icon name="arrow-right" color="#99A1B7" size="16"></u-icon> | 
				
			||||
				</view> | 
				
			||||
			</view> | 
				
			||||
			<!-- 真实姓名 --> | 
				
			||||
			<view class="item"> | 
				
			||||
				<text>真实姓名</text> | 
				
			||||
				<view class="right"> | 
				
			||||
					<input class="input" type="text" placeholder-class="txt" placeholder="请输入" | 
				
			||||
						v-model="form.realName" /> | 
				
			||||
					<u-icon name="arrow-right" color="#99A1B7" size="16"></u-icon> | 
				
			||||
				</view> | 
				
			||||
			</view> | 
				
			||||
			<!-- 用户性别 --> | 
				
			||||
			<view class="item"> | 
				
			||||
				<text>用户性别</text> | 
				
			||||
				<view class="right"> | 
				
			||||
					<picker :range="vuex_sex" range-key="label" @change="onGenderChange"> | 
				
			||||
						<view :class="form.gender?'picker':'picker txt'"> | 
				
			||||
							{{ vuex_sex[form.gender].label || '请选择' }} | 
				
			||||
						</view> | 
				
			||||
					</picker> | 
				
			||||
					<u-icon name="arrow-right" color="#99A1B7" size="16"></u-icon> | 
				
			||||
				</view> | 
				
			||||
			</view> | 
				
			||||
			<!-- 手机号码 --> | 
				
			||||
			<view class="item"> | 
				
			||||
				<text>手机号码</text> | 
				
			||||
				<view class="right"> | 
				
			||||
					<input class="input" type="number" placeholder-class="txt" placeholder="请输入" | 
				
			||||
						v-model="form.mobile" /> | 
				
			||||
					<u-icon name="arrow-right" color="#99A1B7" size="16"></u-icon> | 
				
			||||
				</view> | 
				
			||||
			</view> | 
				
			||||
			<!-- 所属部门 --> | 
				
			||||
			<view class="item"> | 
				
			||||
				<text>所属部门</text> | 
				
			||||
				<view class="right"> | 
				
			||||
					<picker :range="vuex_dept" range-key="label" @change="onDepartmentChange"> | 
				
			||||
						<view :class="form.department?'picker':'picker txt'"> | 
				
			||||
							{{ vuex_dept[form.department].label || '请选择' }} | 
				
			||||
						</view> | 
				
			||||
					</picker> | 
				
			||||
					<u-icon name="arrow-right" color="#99A1B7" size="16"></u-icon> | 
				
			||||
				</view> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
		<view class="submit" @tap="submitForm"> | 
				
			||||
			<text>确认提交</text> | 
				
			||||
		</view> | 
				
			||||
		<view class="auditd"> | 
				
			||||
			<text>等待审核</text> | 
				
			||||
		</view> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				form: { | 
				
			||||
					avatar: '', | 
				
			||||
					realName: '', | 
				
			||||
					gender: '', | 
				
			||||
					mobile: '', | 
				
			||||
					department: '', | 
				
			||||
				} | 
				
			||||
			}; | 
				
			||||
		}, | 
				
			||||
		onLoad() { | 
				
			||||
			// 获取用户信息 | 
				
			||||
			if (this.vuex_dept) { | 
				
			||||
				this.form = { | 
				
			||||
					avatar: this.vuex_user.avatar, | 
				
			||||
					realName: this.vuex_user.realName, | 
				
			||||
					gender: this.vuex_user.sex, | 
				
			||||
					mobile: this.vuex_user.phonenumber, | 
				
			||||
					department: this.vuex_dept.findIndex(item => item.label === this.vuex_user.deptName) | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			getAvatar(res) { | 
				
			||||
				console.log(res.detail.avatarUrl); | 
				
			||||
				this.form.avatar = res.detail.avatarUrl | 
				
			||||
				// this.uploadAvatar(res.detail.avatarUrl) | 
				
			||||
			}, | 
				
			||||
			uploadAvatar(tempAvatarPath) { | 
				
			||||
				uni.uploadFile({ | 
				
			||||
					url: 'https://your-server-api/upload', | 
				
			||||
					filePath: tempAvatarPath, | 
				
			||||
					name: 'file', | 
				
			||||
					header: { | 
				
			||||
						'Content-Type': 'multipart/form-data', | 
				
			||||
					}, | 
				
			||||
					success(res) { | 
				
			||||
						const data = JSON.parse(res.data); | 
				
			||||
						if (data.success) { | 
				
			||||
							this.form.avatar = data.url; | 
				
			||||
							console.log('头像上传成功', data.url); | 
				
			||||
						} else { | 
				
			||||
							console.error('头像上传失败', data.message); | 
				
			||||
						} | 
				
			||||
					}, | 
				
			||||
					fail(err) { | 
				
			||||
						console.error('上传失败', err); | 
				
			||||
					}, | 
				
			||||
				}); | 
				
			||||
			}, | 
				
			||||
			onGenderChange(e) { | 
				
			||||
				this.form.gender = e.target.value; | 
				
			||||
			}, | 
				
			||||
			onDepartmentChange(e) { | 
				
			||||
				this.form.department = e.detail.value | 
				
			||||
			}, | 
				
			||||
			validateForm() { | 
				
			||||
				const requiredFields = [{ | 
				
			||||
						key: 'avatar', | 
				
			||||
						message: '请上传头像' | 
				
			||||
					}, | 
				
			||||
					{ | 
				
			||||
						key: 'realName', | 
				
			||||
						message: '真实姓名不能为空' | 
				
			||||
					}, | 
				
			||||
					{ | 
				
			||||
						key: 'gender', | 
				
			||||
						message: '请选择性别' | 
				
			||||
					}, | 
				
			||||
					{ | 
				
			||||
						key: 'mobile', | 
				
			||||
						message: '手机号码不能为空' | 
				
			||||
					}, | 
				
			||||
					{ | 
				
			||||
						key: 'department', | 
				
			||||
						message: '请选择所属部门' | 
				
			||||
					}, | 
				
			||||
				]; | 
				
			||||
 | 
				
			||||
				for (const field of requiredFields) { | 
				
			||||
					if (!this.form[field.key]) { | 
				
			||||
						uni.showToast({ | 
				
			||||
							title: field.message, | 
				
			||||
							icon: 'none', | 
				
			||||
						}); | 
				
			||||
						return false; | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				const mobilePattern = /^1[3-9]\d{9}$/; // 中国手机号正则表达式 | 
				
			||||
				if (!mobilePattern.test(this.form.mobile)) { | 
				
			||||
					uni.showToast({ | 
				
			||||
						title: '请输入有效的手机号', | 
				
			||||
						icon: 'none', | 
				
			||||
					}); | 
				
			||||
					return false; | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				return true; | 
				
			||||
			}, | 
				
			||||
			submitForm() { | 
				
			||||
 | 
				
			||||
				if (!this.validateForm()) return; | 
				
			||||
				// 提交表单逻辑 | 
				
			||||
				uni.$u.http.put('/register', { | 
				
			||||
					realName: this.form.realName, | 
				
			||||
					sex: this.vuex_sex[this.form.gender].value, | 
				
			||||
					phonenumber: this.form.mobile, | 
				
			||||
					deptId: this.vuex_dept[this.form.department].value, | 
				
			||||
					userType: '00' | 
				
			||||
				}, {}).then(res => { | 
				
			||||
					console.log(res); | 
				
			||||
				}).catch(err => { | 
				
			||||
					console.log('申请失败'); | 
				
			||||
				}) | 
				
			||||
 | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
	}; | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
	.wrap { | 
				
			||||
		background-color: #F9F9F9; | 
				
			||||
		min-height: 100vh; | 
				
			||||
 | 
				
			||||
		.form { | 
				
			||||
			padding: 32rpx; | 
				
			||||
			display: flex; | 
				
			||||
			flex-direction: column; | 
				
			||||
			gap: 32rpx; | 
				
			||||
 | 
				
			||||
			.item { | 
				
			||||
				display: flex; | 
				
			||||
				justify-content: space-between; | 
				
			||||
				align-items: center; | 
				
			||||
				padding: 0 48rpx; | 
				
			||||
				height: 140rpx; | 
				
			||||
				border-radius: 16rpx; | 
				
			||||
				background: #FFF; | 
				
			||||
				font-size: 30rpx; | 
				
			||||
				color: #252F4A; | 
				
			||||
 | 
				
			||||
				text { | 
				
			||||
					font-weight: bold; | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				.right { | 
				
			||||
					display: flex; | 
				
			||||
					align-self: center; | 
				
			||||
					justify-content: center; | 
				
			||||
					gap: 8rpx; | 
				
			||||
 | 
				
			||||
					.avatar { | 
				
			||||
						width: 72rpx; | 
				
			||||
						height: 72rpx; | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					.input { | 
				
			||||
						text-align: right; | 
				
			||||
						width: 400rpx; | 
				
			||||
						height: 80rpx; | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					.picker { | 
				
			||||
						display: flex; | 
				
			||||
						align-items: center; | 
				
			||||
						justify-content: flex-end; | 
				
			||||
						width: 400rpx; | 
				
			||||
						height: 80rpx; | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					.txt { | 
				
			||||
						color: #99A1B7; | 
				
			||||
						font-size: 32rpx; | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					.u-reset-button { | 
				
			||||
 | 
				
			||||
						display: flex; | 
				
			||||
						align-items: center; | 
				
			||||
						justify-content: flex-end; | 
				
			||||
						width: 400rpx; | 
				
			||||
						height: 80rpx; | 
				
			||||
 | 
				
			||||
						text { | 
				
			||||
							color: #17C653; | 
				
			||||
							font-weight: normal; | 
				
			||||
						} | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		.submit { | 
				
			||||
			display: flex; | 
				
			||||
			align-items: center; | 
				
			||||
			justify-content: center; | 
				
			||||
			position: fixed; | 
				
			||||
			left: 0; | 
				
			||||
			right: 0; | 
				
			||||
			bottom: 116rpx; | 
				
			||||
 | 
				
			||||
			text { | 
				
			||||
				display: flex; | 
				
			||||
				align-items: center; | 
				
			||||
				justify-content: center; | 
				
			||||
				font-size: 32rpx; | 
				
			||||
				font-weight: bold; | 
				
			||||
				color: #FFF; | 
				
			||||
				background: #17C653; | 
				
			||||
				padding: 32rpx 128rpx; | 
				
			||||
				border-radius: 100px; | 
				
			||||
				box-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.1); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		.auditd { | 
				
			||||
			display: flex; | 
				
			||||
			align-items: center; | 
				
			||||
			justify-content: center; | 
				
			||||
			position: fixed; | 
				
			||||
			left: 0; | 
				
			||||
			right: 0; | 
				
			||||
			bottom: 116rpx; | 
				
			||||
 | 
				
			||||
			text { | 
				
			||||
				display: flex; | 
				
			||||
				align-items: center; | 
				
			||||
				justify-content: center; | 
				
			||||
				font-size: 32rpx; | 
				
			||||
				font-weight: bold; | 
				
			||||
				color: #17C653; | 
				
			||||
				background: #EAFFF1; | 
				
			||||
				padding: 32rpx 128rpx; | 
				
			||||
				border-radius: 100px; | 
				
			||||
				box-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.1); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,19 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view> | 
				
			||||
		投诉建议 | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				 | 
				
			||||
			}; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
 | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,19 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view> | 
				
			||||
		执法任务 | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				 | 
				
			||||
			}; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
 | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,19 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view> | 
				
			||||
		任务详情 | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				 | 
				
			||||
			}; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
 | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,19 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view> | 
				
			||||
		任务列表 | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				 | 
				
			||||
			}; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
 | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,19 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view> | 
				
			||||
		编辑资料 | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				 | 
				
			||||
			}; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
 | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,187 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="wrap"> | 
				
			||||
		<!-- 我的头像 --> | 
				
			||||
		<view class="item" @tap="goToOff"> | 
				
			||||
			<view class="avatar"> | 
				
			||||
				<view class="user"> | 
				
			||||
					<text>张三丰</text> | 
				
			||||
					<text class="dept">执法一队</text> | 
				
			||||
				</view> | 
				
			||||
				<text class="tel">18604161212</text> | 
				
			||||
			</view> | 
				
			||||
			<view class="right"> | 
				
			||||
				<image class="avatar" :src="vuex_user.avatar" mode="aspectFill"></image> | 
				
			||||
				<u-icon name="arrow-right" color="#99A1B7" size="16"></u-icon> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
		<!-- 消息通知 --> | 
				
			||||
		<view class="item" @tap="goToNotif"> | 
				
			||||
			<view class="box"> | 
				
			||||
				<u-icon name="photo" color="#99A1B7" size="20"></u-icon> | 
				
			||||
				<text>消息通知</text> | 
				
			||||
			</view> | 
				
			||||
			<view class="right"> | 
				
			||||
				<text>2</text> | 
				
			||||
				<u-icon name="arrow-right" color="#99A1B7" size="16"></u-icon> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
		<!-- 执法记录 --> | 
				
			||||
		<view class="item" @tap="goToTask"> | 
				
			||||
			<view class="box"> | 
				
			||||
				<u-icon name="photo" color="#99A1B7" size="20"></u-icon> | 
				
			||||
				<text>执法记录</text> | 
				
			||||
			</view> | 
				
			||||
			<view class="right"> | 
				
			||||
				<text>8</text> | 
				
			||||
				<u-icon name="arrow-right" color="#99A1B7" size="16"></u-icon> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
		<!-- 政策法规 --> | 
				
			||||
		<view class="item" @tap="goToLaw"> | 
				
			||||
			<view class="box"> | 
				
			||||
				<u-icon name="photo" color="#99A1B7" size="20"></u-icon> | 
				
			||||
				<text>政策法规</text> | 
				
			||||
			</view> | 
				
			||||
			<view class="right"> | 
				
			||||
				<!-- <text>8</text> --> | 
				
			||||
				<u-icon name="arrow-right" color="#99A1B7" size="16"></u-icon> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
		<!-- 企业入驻 --> | 
				
			||||
		<view class="item" @tap="goToEnt"> | 
				
			||||
			<view class="box"> | 
				
			||||
				<u-icon name="photo" color="#99A1B7" size="20"></u-icon> | 
				
			||||
				<text>企业入驻</text> | 
				
			||||
			</view> | 
				
			||||
			<view class="right"> | 
				
			||||
				<!-- <text>8</text> --> | 
				
			||||
				<u-icon name="arrow-right" color="#99A1B7" size="16"></u-icon> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
		<!-- 内部专线 --> | 
				
			||||
		<view class="item" @tap="makePhoneCall"> | 
				
			||||
			<view class="box"> | 
				
			||||
				<u-icon name="photo" color="#99A1B7" size="20"></u-icon> | 
				
			||||
				<text>内部专线</text> | 
				
			||||
			</view> | 
				
			||||
			<view class="right"> | 
				
			||||
				<text>点击拨打</text> | 
				
			||||
				<u-icon name="arrow-right" color="#99A1B7" size="16"></u-icon> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
 | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
 | 
				
			||||
			}; | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			goToOff() { | 
				
			||||
				uni.$u.route('/pages/index/off_reg'); | 
				
			||||
			}, | 
				
			||||
			goToNotif() { | 
				
			||||
				uni.$u.route('/pages/user/notif'); | 
				
			||||
			}, | 
				
			||||
			goToTask() { | 
				
			||||
				uni.$u.route('/pages/user/task'); | 
				
			||||
			}, | 
				
			||||
			goToLaw() { | 
				
			||||
				uni.$u.route('/pages/user/law'); | 
				
			||||
			}, | 
				
			||||
			goToEnt() { | 
				
			||||
				uni.$u.route('/pages/index/ent_reg'); | 
				
			||||
			}, | 
				
			||||
			// 拨打内部专线 | 
				
			||||
			makePhoneCall() { | 
				
			||||
				uni.makePhoneCall({ | 
				
			||||
					phoneNumber: '114' // 内部专线 | 
				
			||||
				}); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
	.wrap { | 
				
			||||
		background-color: #F9F9F9; | 
				
			||||
		min-height: 100vh; | 
				
			||||
		padding: 32rpx; | 
				
			||||
		display: flex; | 
				
			||||
		flex-direction: column; | 
				
			||||
		gap: 32rpx; | 
				
			||||
 | 
				
			||||
		.item { | 
				
			||||
			display: flex; | 
				
			||||
			justify-content: space-between; | 
				
			||||
			align-items: center; | 
				
			||||
			padding: 48rpx; | 
				
			||||
			border-radius: 16rpx; | 
				
			||||
			background: #FFF; | 
				
			||||
			font-size: 30rpx; | 
				
			||||
			color: #252F4A; | 
				
			||||
 | 
				
			||||
			text { | 
				
			||||
				font-weight: bold; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			.avatar { | 
				
			||||
				display: flex; | 
				
			||||
				flex-direction: column; | 
				
			||||
				gap: 12rpx; | 
				
			||||
				font-weight: bold; | 
				
			||||
 | 
				
			||||
				.user { | 
				
			||||
					display: flex; | 
				
			||||
					align-items: center; | 
				
			||||
					justify-content: center; | 
				
			||||
					gap: 16rpx; | 
				
			||||
					font-size: 40rpx; | 
				
			||||
 | 
				
			||||
					.dept { | 
				
			||||
						font-size: 24rpx; | 
				
			||||
						padding: 4rpx 16rpx; | 
				
			||||
						background: #252F4A; | 
				
			||||
						color: #FFF; | 
				
			||||
						border-radius: 100px; | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				.tel { | 
				
			||||
					font-size: 28rpx; | 
				
			||||
					font-weight: normal; | 
				
			||||
					color: #4B5675; | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			.box { | 
				
			||||
				display: flex; | 
				
			||||
				align-items: center; | 
				
			||||
				justify-content: center; | 
				
			||||
				gap: 12rpx; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			.right { | 
				
			||||
				display: flex; | 
				
			||||
				align-self: center; | 
				
			||||
				justify-content: center; | 
				
			||||
				gap: 8rpx; | 
				
			||||
 | 
				
			||||
				.avatar { | 
				
			||||
					width: 112rpx; | 
				
			||||
					height: 112rpx; | 
				
			||||
					border-radius: 100px; | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				text { | 
				
			||||
					color: #99A1B7; | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,19 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view> | 
				
			||||
		政策法规 | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				 | 
				
			||||
			}; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
 | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,19 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view> | 
				
			||||
		消息通知 | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				 | 
				
			||||
			}; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
 | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,19 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view> | 
				
			||||
		任务记录 | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				 | 
				
			||||
			}; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss"> | 
				
			||||
 | 
				
			||||
</style> | 
				
			||||
| 
		 After Width: | Height: | Size: 3.9 KiB  | 
@ -0,0 +1,27 @@
					 | 
				
			||||
import { mapState } from 'vuex' | 
				
			||||
import store from "@/store" | 
				
			||||
 | 
				
			||||
// 尝试将用户在根目录中的store/index.js的vuex的state变量,全部加载到全局变量中
 | 
				
			||||
let $uStoreKey = []; | 
				
			||||
try{ | 
				
			||||
	$uStoreKey = store.state ? Object.keys(store.state) : []; | 
				
			||||
}catch(e){ | 
				
			||||
	
 | 
				
			||||
} | 
				
			||||
 | 
				
			||||
module.exports = { | 
				
			||||
	created() { | 
				
			||||
		// 将vuex方法挂在到$u中
 | 
				
			||||
		// 使用方法为:如果要修改vuex的state中的user.name变量为"史诗" => this.$u.vuex('user.name', '史诗')
 | 
				
			||||
		// 如果要修改vuex的state的version变量为1.0.1 => this.$u.vuex('version', '1.0.1')
 | 
				
			||||
		this.$u.vuex = (name, value) => { | 
				
			||||
			this.$store.commit('$uStore', { | 
				
			||||
				name,value | 
				
			||||
			}) | 
				
			||||
		} | 
				
			||||
	}, | 
				
			||||
	computed: { | 
				
			||||
		// 将vuex的state中的所有变量,解构到全局混入的mixin中
 | 
				
			||||
		...mapState($uStoreKey) | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,73 @@
					 | 
				
			||||
import Vue from 'vue' | 
				
			||||
import Vuex from 'vuex' | 
				
			||||
Vue.use(Vuex) | 
				
			||||
 | 
				
			||||
let lifeData = {}; | 
				
			||||
 | 
				
			||||
try { | 
				
			||||
	// 尝试获取本地是否存在lifeData变量,第一次启动APP时是不存在的
 | 
				
			||||
	lifeData = uni.getStorageSync('lifeData'); | 
				
			||||
} catch (e) { | 
				
			||||
 | 
				
			||||
} | 
				
			||||
 | 
				
			||||
// 需要永久存储,且下次APP启动需要取出的,在state中的变量名
 | 
				
			||||
let saveStateKeys = ['vuex_user', 'vuex_token']; | 
				
			||||
 | 
				
			||||
// 保存变量到本地存储中
 | 
				
			||||
const saveLifeData = function(key, value) { | 
				
			||||
	// 判断变量名是否在需要存储的数组中
 | 
				
			||||
	if (saveStateKeys.indexOf(key) != -1) { | 
				
			||||
		// 获取本地存储的lifeData对象,将变量添加到对象中
 | 
				
			||||
		let tmp = uni.getStorageSync('lifeData'); | 
				
			||||
		// 第一次打开APP,不存在lifeData变量,故放一个{}空对象
 | 
				
			||||
		tmp = tmp ? tmp : {}; | 
				
			||||
		tmp[key] = value; | 
				
			||||
		// 执行这一步后,所有需要存储的变量,都挂载在本地的lifeData对象中
 | 
				
			||||
		uni.setStorageSync('lifeData', tmp); | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
const store = new Vuex.Store({ | 
				
			||||
	// 下面这些值仅为示例,使用过程中请删除
 | 
				
			||||
	state: { | 
				
			||||
		// 如果上面从本地获取的lifeData对象下有对应的属性,就赋值给state中对应的变量
 | 
				
			||||
		// 加上vuex_前缀,是防止变量名冲突,也让人一目了然
 | 
				
			||||
		// 如果vuex_version无需保存到本地永久存储,无需lifeData.vuex_version方式
 | 
				
			||||
		// vuex_version: '1.0.1',
 | 
				
			||||
		vuex_token: lifeData.vuex_token ? lifeData.vuex_token : '', | 
				
			||||
		vuex_user: lifeData.vuex_user ? lifeData.vuex_user : {}, | 
				
			||||
		vuex_dept: '', | 
				
			||||
		vuex_sex: [{ | 
				
			||||
			label: '男', | 
				
			||||
			value: 0 | 
				
			||||
		}, { | 
				
			||||
			label: '女', | 
				
			||||
			value: 1 | 
				
			||||
		}] | 
				
			||||
 | 
				
			||||
	}, | 
				
			||||
	mutations: { | 
				
			||||
		$uStore(state, payload) { | 
				
			||||
			// 判断是否多层级调用,state中为对象存在的情况,诸如user.info.score = 1
 | 
				
			||||
			let nameArr = payload.name.split('.'); | 
				
			||||
			let saveKey = ''; | 
				
			||||
			let len = nameArr.length; | 
				
			||||
			if (nameArr.length >= 2) { | 
				
			||||
				let obj = state[nameArr[0]]; | 
				
			||||
				for (let i = 1; i < len - 1; i++) { | 
				
			||||
					obj = obj[nameArr[i]]; | 
				
			||||
				} | 
				
			||||
				obj[nameArr[len - 1]] = payload.value; | 
				
			||||
				saveKey = nameArr[0]; | 
				
			||||
			} else { | 
				
			||||
				// 单层级变量,在state就是一个普通变量的情况
 | 
				
			||||
				state[payload.name] = payload.value; | 
				
			||||
				saveKey = payload.name; | 
				
			||||
			} | 
				
			||||
			// 保存变量到本地,见顶部函数定义
 | 
				
			||||
			saveLifeData(saveKey, state[saveKey]) | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
}) | 
				
			||||
 | 
				
			||||
export default store | 
				
			||||
@ -0,0 +1,13 @@
					 | 
				
			||||
uni.addInterceptor({ | 
				
			||||
  returnValue (res) { | 
				
			||||
    if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) { | 
				
			||||
      return res; | 
				
			||||
    } | 
				
			||||
    return new Promise((resolve, reject) => { | 
				
			||||
      res.then((res) => { | 
				
			||||
        if (!res) return resolve(res) 
 | 
				
			||||
        return res[0] ? reject(res[0]) : resolve(res[1]) | 
				
			||||
      }); | 
				
			||||
    }); | 
				
			||||
  }, | 
				
			||||
}); | 
				
			||||
@ -0,0 +1,79 @@
					 | 
				
			||||
/** | 
				
			||||
 * 这里是uni-app内置的常用样式变量 | 
				
			||||
 * | 
				
			||||
 * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 | 
				
			||||
 * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App | 
				
			||||
 * | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 | 
				
			||||
 * | 
				
			||||
 * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
/* uni.scss */ | 
				
			||||
@import '@/uni_modules/uview-ui/theme.scss'; | 
				
			||||
 | 
				
			||||
/* 颜色变量 */ | 
				
			||||
 | 
				
			||||
/* 行为相关颜色 */ | 
				
			||||
$uni-color-primary: #007aff; | 
				
			||||
$uni-color-success: #4cd964; | 
				
			||||
$uni-color-warning: #f0ad4e; | 
				
			||||
$uni-color-error: #dd524d; | 
				
			||||
 | 
				
			||||
/* 文字基本颜色 */ | 
				
			||||
$uni-text-color:#333;//基本色 | 
				
			||||
$uni-text-color-inverse:#fff;//反色 | 
				
			||||
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 | 
				
			||||
$uni-text-color-placeholder: #808080; | 
				
			||||
$uni-text-color-disable:#c0c0c0; | 
				
			||||
 | 
				
			||||
/* 背景颜色 */ | 
				
			||||
$uni-bg-color:#ffffff; | 
				
			||||
$uni-bg-color-grey:#f8f8f8; | 
				
			||||
$uni-bg-color-hover:#f1f1f1;//点击状态颜色 | 
				
			||||
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 | 
				
			||||
 | 
				
			||||
/* 边框颜色 */ | 
				
			||||
$uni-border-color:#c8c7cc; | 
				
			||||
 | 
				
			||||
/* 尺寸变量 */ | 
				
			||||
 | 
				
			||||
/* 文字尺寸 */ | 
				
			||||
$uni-font-size-sm:12px; | 
				
			||||
$uni-font-size-base:14px; | 
				
			||||
$uni-font-size-lg:16px; | 
				
			||||
 | 
				
			||||
/* 图片尺寸 */ | 
				
			||||
$uni-img-size-sm:20px; | 
				
			||||
$uni-img-size-base:26px; | 
				
			||||
$uni-img-size-lg:40px; | 
				
			||||
 | 
				
			||||
/* Border Radius */ | 
				
			||||
$uni-border-radius-sm: 2px; | 
				
			||||
$uni-border-radius-base: 3px; | 
				
			||||
$uni-border-radius-lg: 6px; | 
				
			||||
$uni-border-radius-circle: 50%; | 
				
			||||
 | 
				
			||||
/* 水平间距 */ | 
				
			||||
$uni-spacing-row-sm: 5px; | 
				
			||||
$uni-spacing-row-base: 10px; | 
				
			||||
$uni-spacing-row-lg: 15px; | 
				
			||||
 | 
				
			||||
/* 垂直间距 */ | 
				
			||||
$uni-spacing-col-sm: 4px; | 
				
			||||
$uni-spacing-col-base: 8px; | 
				
			||||
$uni-spacing-col-lg: 12px; | 
				
			||||
 | 
				
			||||
/* 透明度 */ | 
				
			||||
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 | 
				
			||||
 | 
				
			||||
/* 文章场景相关 */ | 
				
			||||
$uni-color-title: #2C405A; // 文章标题颜色 | 
				
			||||
$uni-font-size-title:20px; | 
				
			||||
$uni-color-subtitle: #555555; // 二级标题颜色 | 
				
			||||
$uni-font-size-subtitle:26px; | 
				
			||||
$uni-color-paragraph: #3F536E; // 文章段落颜色 | 
				
			||||
$uni-font-size-paragraph:15px; | 
				
			||||
@ -0,0 +1,21 @@
					 | 
				
			||||
MIT License | 
				
			||||
 | 
				
			||||
Copyright (c) 2023 www.uviewui.com | 
				
			||||
 | 
				
			||||
Permission is hereby granted, free of charge, to any person obtaining a copy | 
				
			||||
of this software and associated documentation files (the "Software"), to deal | 
				
			||||
in the Software without restriction, including without limitation the rights | 
				
			||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
				
			||||
copies of the Software, and to permit persons to whom the Software is | 
				
			||||
furnished to do so, subject to the following conditions: | 
				
			||||
 | 
				
			||||
The above copyright notice and this permission notice shall be included in all | 
				
			||||
copies or substantial portions of the Software. | 
				
			||||
 | 
				
			||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
				
			||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
				
			||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 
				
			||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
				
			||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
				
			||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 
				
			||||
SOFTWARE. | 
				
			||||
@ -0,0 +1,66 @@
					 | 
				
			||||
<p align="center"> | 
				
			||||
    <img alt="logo" src="https://uviewui.com/common/logo.png" width="120" height="120" style="margin-bottom: 10px;"> | 
				
			||||
</p> | 
				
			||||
<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">uView 2.0</h3> | 
				
			||||
<h3 align="center">多平台快速开发的UI框架</h3> | 
				
			||||
 | 
				
			||||
[](https://github.com/umicro/uView2.0) | 
				
			||||
[](https://github.com/umicro/uView2.0) | 
				
			||||
[](https://github.com/umicro/uView2.0/issues) | 
				
			||||
[](https://uviewui.com) | 
				
			||||
[](https://gitee.com/umicro/uView2.0/releases) | 
				
			||||
[](https://en.wikipedia.org/wiki/MIT_License) | 
				
			||||
 | 
				
			||||
## 说明 | 
				
			||||
 | 
				
			||||
uView UI,是[uni-app](https://uniapp.dcloud.io/)全面兼容nvue的uni-app生态框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水 | 
				
			||||
 | 
				
			||||
## [官方文档:https://uviewui.com](https://uviewui.com) | 
				
			||||
 | 
				
			||||
 | 
				
			||||
## 预览 | 
				
			||||
 | 
				
			||||
您可以通过**微信**扫码,查看最佳的演示效果。 | 
				
			||||
<br> | 
				
			||||
<br> | 
				
			||||
<img src="https://uviewui.com/common/weixin_mini_qrcode.png" width="220" height="220" > | 
				
			||||
 | 
				
			||||
 | 
				
			||||
## 链接 | 
				
			||||
 | 
				
			||||
- [官方文档](https://www.uviewui.com/) | 
				
			||||
- [更新日志](https://www.uviewui.com/components/changelog.html) | 
				
			||||
- [升级指南](https://www.uviewui.com/components/changeGuide.html) | 
				
			||||
- [关于我们](https://www.uviewui.com/cooperation/about.html) | 
				
			||||
 | 
				
			||||
## 交流反馈 | 
				
			||||
 | 
				
			||||
欢迎加入我们的QQ群交流反馈:[点此跳转](https://www.uviewui.com/components/addQQGroup.html) | 
				
			||||
 | 
				
			||||
## 关于PR | 
				
			||||
 | 
				
			||||
> 我们非常乐意接受各位的优质PR,但在此之前我希望您了解uView2.0是一个需要兼容多个平台的(小程序、h5、ios app、android app)包括nvue页面、vue页面。 | 
				
			||||
> 所以希望在您修复bug并提交之前尽可能的去这些平台测试一下兼容性。最好能携带测试截图以方便审核。非常感谢! | 
				
			||||
 | 
				
			||||
## 安装 | 
				
			||||
 | 
				
			||||
#### **uni-app插件市场链接** —— [https://ext.dcloud.net.cn/plugin?id=1593](https://ext.dcloud.net.cn/plugin?id=1593) | 
				
			||||
 | 
				
			||||
请通过[官网安装文档](https://www.uviewui.com/components/install.html)了解更详细的内容 | 
				
			||||
 | 
				
			||||
## 快速上手 | 
				
			||||
 | 
				
			||||
请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容 | 
				
			||||
 | 
				
			||||
## 使用方法 | 
				
			||||
配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。 | 
				
			||||
 | 
				
			||||
```html | 
				
			||||
<template> | 
				
			||||
	<u-button text="按钮"></u-button> | 
				
			||||
</template> | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
## 版权信息 | 
				
			||||
uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uView应用到您的产品中。 | 
				
			||||
 | 
				
			||||
@ -0,0 +1,376 @@
					 | 
				
			||||
## 2.0.38(2024-06-12) | 
				
			||||
插件市场处理 | 
				
			||||
## 2.0.37(2024-03-17) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复表单校验`trigger`触发器参数无效问题 | 
				
			||||
2. 修复`u-input`组件的`password`属性在动态切换为`false`时失效的问题 | 
				
			||||
3. 添加微信小程序用户同意隐私协议事件回调 | 
				
			||||
4. 修复支付宝小程序picker样式问题 | 
				
			||||
5. `u-modal`添加`duration`字段控制动画过度时间 | 
				
			||||
6. 修复`picker` `lastIndex`异常导致的`column`异常问题 | 
				
			||||
7. `tabs`增加长按事件支持 | 
				
			||||
8. 修复`u-avatar` `square`属性在小程序`open-data`下无效问题 | 
				
			||||
9. 其他一些修复 | 
				
			||||
## 2.0.36(2023-03-27) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 重构`deepClone` & `deepMerge`方法 | 
				
			||||
2. 其他优化 | 
				
			||||
## 2.0.34(2022-09-24) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. `u-input`、`u-textarea`增加`ignoreCompositionEvent`属性 | 
				
			||||
2. 修复`route`方法调用可能报错的问题 | 
				
			||||
3. 修复`u-no-network`组件`z-index`无效的问题 | 
				
			||||
4. 修复`textarea`组件在h5上confirmType=""报错的问题 | 
				
			||||
5. `u-rate`适配`nvue` | 
				
			||||
6. 优化验证手机号码的正则表达式(根据工信部发布的《电信网编号计划(2017年版)》进行修改。) | 
				
			||||
7. `form-item`添加`labelPosition`属性 | 
				
			||||
8. `u-calendar`修复`maxDate`设置为当前日期,并且当前时间大于08:00时无法显示日期列表的问题 (#724) | 
				
			||||
9. `u-radio`增加一个默认插槽用于自定义修改label内容 (#680) | 
				
			||||
10. 修复`timeFormat`函数在safari重的兼容性问题 (#664) | 
				
			||||
## 2.0.33(2022-06-17) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复`loadmore`组件`lineColor`类型错误问题 | 
				
			||||
2. 修复`u-parse`组件`imgtap`、`linktap`不生效问题 | 
				
			||||
## 2.0.32(2022-06-16) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
1. `u-loadmore`新增自定义颜色、虚/实线 | 
				
			||||
2. 修复`u-swiper-action`组件部分平台不能上下滑动的问题 | 
				
			||||
3. 修复`u-list`回弹问题 | 
				
			||||
4. 修复`notice-bar`组件动画在低端安卓机可能会抖动的问题 | 
				
			||||
5. `u-loading-page`添加控制图标大小的属性`iconSize` | 
				
			||||
6. 修复`u-tooltip`组件`color`参数不生效的问题 | 
				
			||||
7. 修复`u--input`组件使用`blur`事件输出为`undefined`的bug | 
				
			||||
8. `u-code-input`组件新增键盘弹起时,是否自动上推页面参数`adjustPosition` | 
				
			||||
9. 修复`image`组件`load`事件无回调对象问题 | 
				
			||||
10. 修复`button`组件`loadingSize`设置无效问题 | 
				
			||||
10. 其他修复 | 
				
			||||
## 2.0.31(2022-04-19) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复`upload`在`vue`页面上传成功后没有成功标志的问题 | 
				
			||||
2. 解决演示项目中微信小程序模拟上传图片一直出于上传中问题 | 
				
			||||
3. 修复`u-code-input`组件在`nvue`页面编译到`app`平台上光标异常问题(`app`去除此功能) | 
				
			||||
4. 修复`actionSheet`组件标题关闭按钮点击事件名称错误的问题 | 
				
			||||
5. 其他修复 | 
				
			||||
## 2.0.30(2022-04-04) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. `u-rate`增加`readonly`属性 | 
				
			||||
2. `tabs`滑块支持设置背景图片 | 
				
			||||
3. 修复`u-subsection` `mode`为`subsection`时,滑块样式不正确的问题 | 
				
			||||
4. `u-code-input`添加光标效果动画 | 
				
			||||
5. 修复`popup`的`open`事件不触发 | 
				
			||||
6. 修复`u-flex-column`无效的问题 | 
				
			||||
7. 修复`u-datetime-picker`索引在特定场合异常问题 | 
				
			||||
8. 修复`u-datetime-picker`最小时间字符串模板错误问题 | 
				
			||||
9. `u-swiper`添加`m3u8`验证 | 
				
			||||
10. `u-swiper`修改判断image和video逻辑 | 
				
			||||
11. 修复`swiper`无法使用本地图片问题,增加`type`参数 | 
				
			||||
12. 修复`u-row-notice`格式错误问题 | 
				
			||||
13. 修复`u-switch`组件当`unit`为`rpx`时,`nodeStyle`消失的问题 | 
				
			||||
14. 修复`datetime-picker`组件`showToolbar`与`visibleItemCount`属性无效的问题 | 
				
			||||
15. 修复`upload`组件条件编译位置判断错误,导致`previewImage`属性设置为`false`时,整个组件都会被隐藏的问题 | 
				
			||||
16. 修复`u-checkbox-group`设置`shape`属性无效的问题 | 
				
			||||
17. 修复`u-upload`的`capture`传入字符串的时候不生效的问题 | 
				
			||||
18. 修复`u-action-sheet`组件,关闭事件逻辑错误的问题 | 
				
			||||
19. 修复`u-list`触顶事件的触发错误的问题 | 
				
			||||
20. 修复`u-text`只有手机号可拨打的问题 | 
				
			||||
21. 修复`u-textarea`不能换行的问题 | 
				
			||||
22. 其他修复 | 
				
			||||
## 2.0.29(2022-03-13) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复`u--text`组件设置`decoration`属性未生效的问题 | 
				
			||||
2. 修复`u-datetime-picker`使用`formatter`后返回值不正确 | 
				
			||||
3. 修复`u-datetime-picker` `intercept` 可能为undefined | 
				
			||||
4. 修复已设置单位 uni..config.unit = 'rpx'时,线型指示器 `transform` 的位置翻倍,导致指示器超出宽度 | 
				
			||||
5. 修复mixin中bem方法生成的类名在支付宝和字节小程序中失效 | 
				
			||||
6. 修复默认值传值为空的时候,打开`u-datetime-picker`报错,不能选中第一列时间的bug | 
				
			||||
7. 修复`u-datetime-picker`使用`formatter`后返回值不正确 | 
				
			||||
8. 修复`u-image`组件`loading`无效果的问题 | 
				
			||||
9. 修复`config.unit`属性设为`rpx`时,导航栏占用高度不足导致塌陷的问题 | 
				
			||||
10. 修复`u-datetime-picker`组件`itemHeight`无效问题 | 
				
			||||
11. 其他修复 | 
				
			||||
## 2.0.28(2022-02-22) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. search组件新增searchIconSize属性 | 
				
			||||
2. 兼容Safari/Webkit中传入时间格式如2022-02-17 12:00:56 | 
				
			||||
3. 修复text value.js 判断日期出format错误问题 | 
				
			||||
4. priceFormat格式化金额出现精度错误 | 
				
			||||
5. priceFormat在部分情况下出现精度损失问题 | 
				
			||||
6. 优化表单rules提示 | 
				
			||||
7. 修复avatar组件src为空时,展示状态不对 | 
				
			||||
8. 其他修复 | 
				
			||||
## 2.0.27(2022-01-28) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1.样式修复 | 
				
			||||
## 2.0.26(2022-01-28) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1.样式修复 | 
				
			||||
## 2.0.25(2022-01-27) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复text组件mode=price时,可能会导致精度错误的问题 | 
				
			||||
2. 添加$u.setConfig()方法,可设置uView内置的config, props, zIndex, color属性,详见:[修改uView内置配置方案](https://uviewui.com/components/setting.html#%E9%BB%98%E8%AE%A4%E5%8D%95%E4%BD%8D%E9%85%8D%E7%BD%AE) | 
				
			||||
3. 优化form组件在errorType=toast时,如果输入错误页面会有抖动的问题 | 
				
			||||
4. 修复$u.addUnit()对配置默认单位可能无效的问题 | 
				
			||||
## 2.0.24(2022-01-25) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复swiper在current指定非0时缩放有误 | 
				
			||||
2. 修复u-icon添加stop属性的时候报错 | 
				
			||||
3. 优化遗留的通过正则判断rpx单位的问题 | 
				
			||||
4. 优化Layout布局 vue使用gutter时,会超出固定区域 | 
				
			||||
5. 优化search组件高度单位问题(rpx -> px) | 
				
			||||
6. 修复u-image slot 加载和错误的图片失去了高度 | 
				
			||||
7. 修复u-index-list中footer插槽与header插槽存在性判断错误 | 
				
			||||
8. 修复部分机型下u-popup关闭时会闪烁 | 
				
			||||
9. 修复u-image在nvue-app下失去宽高 | 
				
			||||
10. 修复u-popup运行报错 | 
				
			||||
11. 修复u-tooltip报错 | 
				
			||||
12. 修复box-sizing在app下的警告 | 
				
			||||
13. 修复u-navbar在小程序中报运行时错误 | 
				
			||||
14. 其他修复 | 
				
			||||
## 2.0.23(2022-01-24) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复image组件在hx3.3.9的nvue下可能会显示异常的问题 | 
				
			||||
2. 修复col组件gutter参数带rpx单位处理不正确的问题 | 
				
			||||
3. 修复text组件单行时无法显示省略号的问题 | 
				
			||||
4. navbar添加titleStyle参数 | 
				
			||||
5. 升级到hx3.3.9可消除nvue下控制台样式警告的问题 | 
				
			||||
## 2.0.22(2022-01-19) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. $u.page()方法优化,避免在特殊场景可能报错的问题 | 
				
			||||
2. picker组件添加immediateChange参数 | 
				
			||||
3. 新增$u.pages()方法 | 
				
			||||
## 2.0.21(2022-01-19) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 优化:form组件在用户设置rules的时候提示用户model必传 | 
				
			||||
2. 优化遗留的通过正则判断rpx单位的问题 | 
				
			||||
3. 修复微信小程序环境中tabbar组件开启safeAreaInsetBottom属性后,placeholder高度填充不正确 | 
				
			||||
4. 修复swiper在current指定非0时缩放有误 | 
				
			||||
5. 修复u-icon添加stop属性的时候报错 | 
				
			||||
6. 修复upload组件在accept=all的时候没有作用 | 
				
			||||
7. 修复在text组件mode为phone时call属性无效的问题 | 
				
			||||
8. 处理u-form clearValidate方法 | 
				
			||||
9. 其他修复 | 
				
			||||
## 2.0.20(2022-01-14) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复calendar默认会选择一个日期,如果直接点确定的话,无法取到值的问题 | 
				
			||||
2. 修复Slider缺少disabled props 还有注释 | 
				
			||||
3. 修复u-notice-bar点击事件无法拿到index索引值的问题 | 
				
			||||
4. 修复u-collapse-item在vue文件下,app端自定义插槽不生效的问题 | 
				
			||||
5. 优化头像为空时显示默认头像  | 
				
			||||
6. 修复图片地址赋值后判断加载状态为完成问题 | 
				
			||||
7. 修复日历滚动到默认日期月份区域 | 
				
			||||
8. search组件暴露点击左边icon事件 | 
				
			||||
9. 修复u-form clearValidate方法不生效 | 
				
			||||
10. upload h5端增加返回文件参数(文件的name参数) | 
				
			||||
11. 处理upload选择文件后url为blob类型无法预览的问题 | 
				
			||||
12. u-code-input 修复输入框没有往左移出一半屏幕 | 
				
			||||
13. 修复Upload上传 disabled为true时,控制台报hoverClass类型错误 | 
				
			||||
14. 临时处理ios app下grid点击坍塌问题 | 
				
			||||
15. 其他修复 | 
				
			||||
## 2.0.19(2021-12-29) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 优化微信小程序包体积可在微信中预览,请升级HbuilderX3.3.4,同时在“运行->运行到小程序模拟器”中勾选“运行时是否压缩代码” | 
				
			||||
2. 优化微信小程序setData性能,处理某些方法如$u.route()无法在模板中使用的问题 | 
				
			||||
3. navbar添加autoBack参数 | 
				
			||||
4. 允许avatar组件的事件冒泡 | 
				
			||||
5. 修复cell组件报错问题 | 
				
			||||
6. 其他修复 | 
				
			||||
## 2.0.18(2021-12-28) | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复app端编译报错问题 | 
				
			||||
2. 重新处理微信小程序端setData过大的性能问题 | 
				
			||||
3. 修复边框问题 | 
				
			||||
4. 修复最大最小月份不大于0则没有数据出现的问题 | 
				
			||||
5. 修复SwipeAction微信小程序端无法上下滑动问题 | 
				
			||||
6. 修复input的placeholder在小程序端默认显示为true问题 | 
				
			||||
7. 修复divider组件click事件无效问题 | 
				
			||||
8. 修复u-code-input maxlength 属性值为 String 类型时显示异常 | 
				
			||||
9. 修复当 grid只有 1到2时 在小程序端algin设置无效的问题 | 
				
			||||
10. 处理form-item的label为top时,取消错误提示的左边距 | 
				
			||||
11. 其他修复 | 
				
			||||
## 2.0.17(2021-12-26) | 
				
			||||
## uView正在参与开源中国的“年度最佳项目”评选,之前投过票的现在也可以投票,恳请同学们投一票,[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 解决HBuilderX3.3.3.20211225版本导致的样式问题 | 
				
			||||
2. calendar日历添加monthNum参数 | 
				
			||||
3. navbar添加center slot | 
				
			||||
## 2.0.16(2021-12-25) | 
				
			||||
## uView正在参与开源中国的“年度最佳项目”评选,之前投过票的现在也可以投票,恳请同学们投一票,[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 解决微信小程序setData性能问题 | 
				
			||||
2. 修复count-down组件change事件不触发问题 | 
				
			||||
## 2.0.15(2021-12-21) | 
				
			||||
## uView正在参与开源中国的“年度最佳项目”评选,之前投过票的现在也可以投票,恳请同学们投一票,[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复Cell单元格titleWidth无效 | 
				
			||||
2. 修复cheakbox组件ischecked不更新 | 
				
			||||
3. 修复keyboard是否显示"."按键默认值问题 | 
				
			||||
4. 修复number-keyboard是否显示键盘的"."符号问题 | 
				
			||||
5. 修复Input输入框 readonly无效 | 
				
			||||
6. 修复u-avatar 导致打包app、H5时候报错问题 | 
				
			||||
7. 修复Upload上传deletable无效 | 
				
			||||
8. 修复upload当设置maxSize时无效的问题 | 
				
			||||
9. 修复tabs lineWidth传入带单位的字符串的时候偏移量计算错误问题 | 
				
			||||
10. 修复rate组件在有padding的view内,显示的星星位置和可触摸区域不匹配,无法正常选中星星 | 
				
			||||
## 2.0.13(2021-12-14) | 
				
			||||
## [点击加群交流反馈:364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复配置默认单位为rpx可能会导致自定义导航栏高度异常的问题 | 
				
			||||
## 2.0.12(2021-12-14) | 
				
			||||
## [点击加群交流反馈:364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复tabs组件在vue环境下划线消失的问题 | 
				
			||||
2. 修复upload组件在安卓小程序无法选择视频的问题 | 
				
			||||
3. 添加uni.$u.config.unit配置,用于配置参数默认单位,详见:[默认单位配置](https://www.uviewui.com/components/setting.html#%E9%BB%98%E8%AE%A4%E5%8D%95%E4%BD%8D%E9%85%8D%E7%BD%AE) | 
				
			||||
4. 修复textarea组件在没绑定v-model时,字符统计不生效问题 | 
				
			||||
5. 修复nvue下控制是否出现滚动条失效问题 | 
				
			||||
## 2.0.11(2021-12-13) | 
				
			||||
## [点击加群交流反馈:364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. text组件align参数无效的问题 | 
				
			||||
2. subsection组件添加keyName参数 | 
				
			||||
3. upload组件无法判断[Object file]类型的问题 | 
				
			||||
4. 处理notify层级过低问题 | 
				
			||||
5. codeInput组件添加disabledDot参数 | 
				
			||||
6. 处理actionSheet组件round参数无效的问题 | 
				
			||||
7. calendar组件添加round参数用于控制圆角值 | 
				
			||||
8. 处理swipeAction组件在vue环境下默认被打开的问题 | 
				
			||||
9. button组件的throttleTime节流参数无效的问题 | 
				
			||||
10. 解决u-notify手动关闭方法close()无效的问题 | 
				
			||||
11. input组件readonly不生效问题 | 
				
			||||
12. tag组件type参数为info不生效问题 | 
				
			||||
## 2.0.10(2021-12-08) | 
				
			||||
## [点击加群交流反馈:364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复button sendMessagePath属性不生效 | 
				
			||||
2. 修复DatetimePicker选择器title无效 | 
				
			||||
3. 修复u-toast设置loading=true不生效 | 
				
			||||
4. 修复u-text金额模式传0报错 | 
				
			||||
5. 修复u-toast组件的icon属性配置不生效 | 
				
			||||
6. button的icon在特殊场景下的颜色优化 | 
				
			||||
7. IndexList优化,增加# | 
				
			||||
## 2.0.9(2021-12-01) | 
				
			||||
## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 优化swiper的height支持100%值(仅vue有效),修复嵌入视频时click事件无法触发的问题 | 
				
			||||
2. 优化tabs组件对list值为空的判断,或者动态变化list时重新计算相关尺寸的问题 | 
				
			||||
3. 优化datetime-picker组件逻辑,让其后续打开的默认值为上一次的选中值,需要通过v-model绑定值才有效 | 
				
			||||
4. 修复upload内嵌在其他组件中,选择图片可能不会换行的问题 | 
				
			||||
## 2.0.8(2021-12-01) | 
				
			||||
## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复toast的position参数无效问题 | 
				
			||||
2. 处理input在ios nvue上无法获得焦点的问题 | 
				
			||||
3. avatar-group组件添加extraValue参数,让剩余展示数量可手动控制 | 
				
			||||
4. tabs组件添加keyName参数用于配置从对象中读取的键名 | 
				
			||||
5. 处理text组件名字脱敏默认配置无效的问题 | 
				
			||||
6. 处理picker组件item文本太长换行问题 | 
				
			||||
## 2.0.7(2021-11-30) | 
				
			||||
## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 修复radio和checkbox动态改变v-model无效的问题。 | 
				
			||||
2. 优化form规则validator在微信小程序用法 | 
				
			||||
3. 修复backtop组件mode参数在微信小程序无效的问题 | 
				
			||||
4. 处理Album的previewFullImage属性无效的问题 | 
				
			||||
5. 处理u-datetime-picker组件mode='time'在选择改变时间时,控制台报错的问题 | 
				
			||||
## 2.0.6(2021-11-27) | 
				
			||||
## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. 处理tag组件在vue下边框无效的问题。 | 
				
			||||
2. 处理popup组件圆角参数可能无效的问题。 | 
				
			||||
3. 处理tabs组件lineColor参数可能无效的问题。 | 
				
			||||
4. propgress组件在值很小时,显示异常的问题。 | 
				
			||||
## 2.0.5(2021-11-25) | 
				
			||||
## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. calendar在vue下显示异常问题。  | 
				
			||||
2. form组件labelPosition和errorType参数无效的问题 | 
				
			||||
3. input组件inputAlign无效的问题 | 
				
			||||
4. 其他一些修复 | 
				
			||||
## 2.0.4(2021-11-23) | 
				
			||||
## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
0. input组件缺失@confirm事件,以及subfix和prefix无效问题 | 
				
			||||
1. component.scss文件样式在vue下干扰全局布局问题 | 
				
			||||
2. 修复subsection在vue环境下表现异常的问题 | 
				
			||||
3. tag组件的bgColor等参数无效的问题 | 
				
			||||
4. upload组件不换行的问题 | 
				
			||||
5. 其他的一些修复处理 | 
				
			||||
## 2.0.3(2021-11-16) | 
				
			||||
## [点击加群交流反馈:1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. uView2.0已实现全面兼容nvue | 
				
			||||
2. uView2.0对1.x进行了架构重构,细节和性能都有极大提升 | 
				
			||||
3. 目前uView2.0为公测阶段,相关细节可能会有变动 | 
				
			||||
4. 我们写了一份与1.x的对比指南,详见[对比1.x](https://www.uviewui.com/components/diff1.x.html) | 
				
			||||
5. 处理modal的confirm回调事件拼写错误问题 | 
				
			||||
6. 处理input组件@input事件参数错误问题 | 
				
			||||
7. 其他一些修复 | 
				
			||||
## 2.0.2(2021-11-16) | 
				
			||||
## [点击加群交流反馈:1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. uView2.0已实现全面兼容nvue | 
				
			||||
2. uView2.0对1.x进行了架构重构,细节和性能都有极大提升 | 
				
			||||
3. 目前uView2.0为公测阶段,相关细节可能会有变动 | 
				
			||||
4. 我们写了一份与1.x的对比指南,详见[对比1.x](https://www.uviewui.com/components/diff1.x.html) | 
				
			||||
5. 修复input组件formatter参数缺失问题 | 
				
			||||
6. 优化loading-icon组件的scss写法问题,防止不兼容新版本scss | 
				
			||||
## 2.0.0(2020-11-15) | 
				
			||||
## [点击加群交流反馈:1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU) | 
				
			||||
 | 
				
			||||
# uView2.0重磅发布,利剑出鞘,一统江湖 | 
				
			||||
 | 
				
			||||
1. uView2.0已实现全面兼容nvue | 
				
			||||
2. uView2.0对1.x进行了架构重构,细节和性能都有极大提升 | 
				
			||||
3. 目前uView2.0为公测阶段,相关细节可能会有变动 | 
				
			||||
4. 我们写了一份与1.x的对比指南,详见[对比1.x](https://www.uviewui.com/components/diff1.x.html) | 
				
			||||
5. 修复input组件formatter参数缺失问题 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
@ -0,0 +1,78 @@
					 | 
				
			||||
<template> | 
				
			||||
	<uvForm | 
				
			||||
		ref="uForm" | 
				
			||||
		:model="model" | 
				
			||||
		:rules="rules" | 
				
			||||
		:errorType="errorType" | 
				
			||||
		:borderBottom="borderBottom" | 
				
			||||
		:labelPosition="labelPosition" | 
				
			||||
		:labelWidth="labelWidth" | 
				
			||||
		:labelAlign="labelAlign" | 
				
			||||
		:labelStyle="labelStyle" | 
				
			||||
		:customStyle="customStyle" | 
				
			||||
	> | 
				
			||||
		<slot /> | 
				
			||||
	</uvForm> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	/** | 
				
			||||
	 * 此组件存在的理由是,在nvue下,u-form被uni-app官方占用了,u-form在nvue中相当于form组件 | 
				
			||||
	 * 所以在nvue下,取名为u--form,内部其实还是u-form.vue,只不过做一层中转 | 
				
			||||
	 */ | 
				
			||||
	import uvForm from '../u-form/u-form.vue'; | 
				
			||||
	import props from '../u-form/props.js' | 
				
			||||
	export default { | 
				
			||||
		// #ifdef MP-WEIXIN | 
				
			||||
		name: 'u-form', | 
				
			||||
		// #endif | 
				
			||||
		// #ifndef MP-WEIXIN | 
				
			||||
		name: 'u--form', | 
				
			||||
		// #endif | 
				
			||||
		mixins: [uni.$u.mpMixin, props, uni.$u.mixin], | 
				
			||||
		components: { | 
				
			||||
			uvForm | 
				
			||||
		}, | 
				
			||||
		created() { | 
				
			||||
			this.children = [] | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			// 手动设置校验的规则,如果规则中有函数的话,微信小程序中会过滤掉,所以只能手动调用设置规则 | 
				
			||||
			setRules(rules) { | 
				
			||||
				this.$refs.uForm.setRules(rules) | 
				
			||||
			}, | 
				
			||||
			validate() { | 
				
			||||
				/** | 
				
			||||
				 * 在微信小程序中,通过this.$parent拿到的父组件是u--form,而不是其内嵌的u-form | 
				
			||||
				 * 导致在u-form组件中,拿不到对应的children数组,从而校验无效,所以这里每次调用u-form组件中的 | 
				
			||||
				 * 对应方法的时候,在小程序中都先将u--form的children赋值给u-form中的children | 
				
			||||
				 */ | 
				
			||||
				// #ifdef MP-WEIXIN | 
				
			||||
				this.setMpData() | 
				
			||||
				// #endif | 
				
			||||
				return this.$refs.uForm.validate() | 
				
			||||
			}, | 
				
			||||
			validateField(value, callback, event) { | 
				
			||||
				// #ifdef MP-WEIXIN | 
				
			||||
				this.setMpData() | 
				
			||||
				// #endif | 
				
			||||
				return this.$refs.uForm.validateField(value, callback, event) | 
				
			||||
			}, | 
				
			||||
			resetFields() { | 
				
			||||
				// #ifdef MP-WEIXIN | 
				
			||||
				this.setMpData() | 
				
			||||
				// #endif | 
				
			||||
				return this.$refs.uForm.resetFields() | 
				
			||||
			}, | 
				
			||||
			clearValidate(props) { | 
				
			||||
				// #ifdef MP-WEIXIN | 
				
			||||
				this.setMpData() | 
				
			||||
				// #endif | 
				
			||||
				return this.$refs.uForm.clearValidate(props) | 
				
			||||
			}, | 
				
			||||
			setMpData() { | 
				
			||||
				this.$refs.uForm.children = this.children | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
@ -0,0 +1,47 @@
					 | 
				
			||||
<template> | 
				
			||||
	<uvImage  | 
				
			||||
		:src="src" | 
				
			||||
		:mode="mode" | 
				
			||||
		:width="width" | 
				
			||||
		:height="height" | 
				
			||||
		:shape="shape" | 
				
			||||
		:radius="radius" | 
				
			||||
		:lazyLoad="lazyLoad" | 
				
			||||
		:showMenuByLongpress="showMenuByLongpress" | 
				
			||||
		:loadingIcon="loadingIcon" | 
				
			||||
		:errorIcon="errorIcon" | 
				
			||||
		:showLoading="showLoading" | 
				
			||||
		:showError="showError" | 
				
			||||
		:fade="fade" | 
				
			||||
		:webp="webp" | 
				
			||||
		:duration="duration" | 
				
			||||
		:bgColor="bgColor" | 
				
			||||
		:customStyle="customStyle" | 
				
			||||
		@click="$emit('click')" | 
				
			||||
		@error="$emit('error')" | 
				
			||||
		@load="$emit('load')" | 
				
			||||
	> | 
				
			||||
		<template v-slot:loading> | 
				
			||||
			<slot name="loading"></slot> | 
				
			||||
		</template> | 
				
			||||
		<template v-slot:error> | 
				
			||||
			<slot name="error"></slot> | 
				
			||||
		</template> | 
				
			||||
	</uvImage> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	/** | 
				
			||||
	 * 此组件存在的理由是,在nvue下,u-image被uni-app官方占用了,u-image在nvue中相当于image组件 | 
				
			||||
	 * 所以在nvue下,取名为u--image,内部其实还是u-iamge.vue,只不过做一层中转 | 
				
			||||
	 */ | 
				
			||||
	import uvImage from '../u-image/u-image.vue'; | 
				
			||||
	import props from '../u-image/props.js'; | 
				
			||||
	export default { | 
				
			||||
		name: 'u--image', | 
				
			||||
		mixins: [uni.$u.mpMixin, props, uni.$u.mixin], | 
				
			||||
		components: { | 
				
			||||
			uvImage | 
				
			||||
		}, | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
@ -0,0 +1,73 @@
					 | 
				
			||||
<template> | 
				
			||||
	<uvInput  | 
				
			||||
		:value="value" | 
				
			||||
		:type="type" | 
				
			||||
		:fixed="fixed" | 
				
			||||
		:disabled="disabled" | 
				
			||||
		:disabledColor="disabledColor" | 
				
			||||
		:clearable="clearable" | 
				
			||||
		:password="password" | 
				
			||||
		:maxlength="maxlength" | 
				
			||||
		:placeholder="placeholder" | 
				
			||||
		:placeholderClass="placeholderClass" | 
				
			||||
		:placeholderStyle="placeholderStyle" | 
				
			||||
		:showWordLimit="showWordLimit" | 
				
			||||
		:confirmType="confirmType" | 
				
			||||
		:confirmHold="confirmHold" | 
				
			||||
		:holdKeyboard="holdKeyboard" | 
				
			||||
		:focus="focus" | 
				
			||||
		:autoBlur="autoBlur" | 
				
			||||
		:disableDefaultPadding="disableDefaultPadding" | 
				
			||||
		:cursor="cursor" | 
				
			||||
		:cursorSpacing="cursorSpacing" | 
				
			||||
		:selectionStart="selectionStart" | 
				
			||||
		:selectionEnd="selectionEnd" | 
				
			||||
		:adjustPosition="adjustPosition" | 
				
			||||
		:inputAlign="inputAlign" | 
				
			||||
		:fontSize="fontSize" | 
				
			||||
		:color="color" | 
				
			||||
		:prefixIcon="prefixIcon" | 
				
			||||
		:suffixIcon="suffixIcon" | 
				
			||||
		:suffixIconStyle="suffixIconStyle" | 
				
			||||
		:prefixIconStyle="prefixIconStyle" | 
				
			||||
		:border="border" | 
				
			||||
		:readonly="readonly" | 
				
			||||
		:shape="shape" | 
				
			||||
		:customStyle="customStyle" | 
				
			||||
		:formatter="formatter" | 
				
			||||
		:ignoreCompositionEvent="ignoreCompositionEvent" | 
				
			||||
		@focus="$emit('focus')" | 
				
			||||
		@blur="e => $emit('blur', e)" | 
				
			||||
		@keyboardheightchange="$emit('keyboardheightchange')" | 
				
			||||
		@change="e => $emit('change', e)" | 
				
			||||
		@input="e => $emit('input', e)" | 
				
			||||
		@confirm="e => $emit('confirm', e)" | 
				
			||||
		@clear="$emit('clear')" | 
				
			||||
		@click="$emit('click')" | 
				
			||||
	> | 
				
			||||
		<!-- #ifdef MP --> | 
				
			||||
		<slot name="prefix"></slot> | 
				
			||||
		<slot name="suffix"></slot> | 
				
			||||
		<!-- #endif --> | 
				
			||||
		<!-- #ifndef MP --> | 
				
			||||
		<slot name="prefix" slot="prefix"></slot> | 
				
			||||
		<slot name="suffix" slot="suffix"></slot> | 
				
			||||
		<!-- #endif --> | 
				
			||||
	</uvInput> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	/** | 
				
			||||
	 * 此组件存在的理由是,在nvue下,u-input被uni-app官方占用了,u-input在nvue中相当于input组件 | 
				
			||||
	 * 所以在nvue下,取名为u--input,内部其实还是u-input.vue,只不过做一层中转 | 
				
			||||
	 */ | 
				
			||||
	import uvInput from '../u-input/u-input.vue'; | 
				
			||||
	import props from '../u-input/props.js' | 
				
			||||
	export default { | 
				
			||||
		name: 'u--input', | 
				
			||||
		mixins: [uni.$u.mpMixin, props, uni.$u.mixin], | 
				
			||||
		components: { | 
				
			||||
			uvInput | 
				
			||||
		}, | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
@ -0,0 +1,44 @@
					 | 
				
			||||
<template> | 
				
			||||
    <uvText | 
				
			||||
        :type="type" | 
				
			||||
        :show="show" | 
				
			||||
        :text="text" | 
				
			||||
        :prefixIcon="prefixIcon" | 
				
			||||
        :suffixIcon="suffixIcon" | 
				
			||||
        :mode="mode" | 
				
			||||
        :href="href" | 
				
			||||
        :format="format" | 
				
			||||
        :call="call" | 
				
			||||
        :openType="openType" | 
				
			||||
        :bold="bold" | 
				
			||||
        :block="block" | 
				
			||||
        :lines="lines" | 
				
			||||
        :color="color" | 
				
			||||
		:decoration="decoration" | 
				
			||||
        :size="size" | 
				
			||||
        :iconStyle="iconStyle" | 
				
			||||
        :margin="margin" | 
				
			||||
        :lineHeight="lineHeight" | 
				
			||||
        :align="align" | 
				
			||||
        :wordWrap="wordWrap" | 
				
			||||
        :customStyle="customStyle" | 
				
			||||
        @click="$emit('click')" | 
				
			||||
    ></uvText> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
/** | 
				
			||||
 * 此组件存在的理由是,在nvue下,u-text被uni-app官方占用了,u-text在nvue中相当于input组件 | 
				
			||||
 * 所以在nvue下,取名为u--input,内部其实还是u-text.vue,只不过做一层中转 | 
				
			||||
 * 不使用v-bind="$attrs",而是分开独立写传参,是因为微信小程序不支持此写法 | 
				
			||||
 */ | 
				
			||||
import uvText from "../u-text/u-text.vue"; | 
				
			||||
import props from "../u-text/props.js"; | 
				
			||||
export default { | 
				
			||||
    name: "u--text", | 
				
			||||
    mixins: [uni.$u.mpMixin, props, uni.$u.mixin], | 
				
			||||
    components: { | 
				
			||||
        uvText, | 
				
			||||
    }, | 
				
			||||
}; | 
				
			||||
</script> | 
				
			||||
@ -0,0 +1,48 @@
					 | 
				
			||||
<template> | 
				
			||||
	<uvTextarea | 
				
			||||
		:value="value" | 
				
			||||
		:placeholder="placeholder" | 
				
			||||
		:height="height" | 
				
			||||
		:confirmType="confirmType" | 
				
			||||
		:disabled="disabled" | 
				
			||||
		:count="count" | 
				
			||||
		:focus="focus" | 
				
			||||
		:autoHeight="autoHeight" | 
				
			||||
		:fixed="fixed" | 
				
			||||
		:cursorSpacing="cursorSpacing" | 
				
			||||
		:cursor="cursor" | 
				
			||||
		:showConfirmBar="showConfirmBar" | 
				
			||||
		:selectionStart="selectionStart" | 
				
			||||
		:selectionEnd="selectionEnd" | 
				
			||||
		:adjustPosition="adjustPosition" | 
				
			||||
		:disableDefaultPadding="disableDefaultPadding" | 
				
			||||
		:holdKeyboard="holdKeyboard" | 
				
			||||
		:maxlength="maxlength" | 
				
			||||
		:border="border" | 
				
			||||
		:customStyle="customStyle" | 
				
			||||
		:formatter="formatter" | 
				
			||||
		:ignoreCompositionEvent="ignoreCompositionEvent" | 
				
			||||
		@focus="e => $emit('focus')" | 
				
			||||
		@blur="e => $emit('blur')" | 
				
			||||
		@linechange="e => $emit('linechange', e)" | 
				
			||||
		@confirm="e => $emit('confirm')" | 
				
			||||
		@input="e => $emit('input', e)" | 
				
			||||
		@keyboardheightchange="e => $emit('keyboardheightchange')" | 
				
			||||
	></uvTextarea> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	/** | 
				
			||||
	 * 此组件存在的理由是,在nvue下,u--textarea被uni-app官方占用了,u-textarea在nvue中相当于textarea组件 | 
				
			||||
	 * 所以在nvue下,取名为u--textarea,内部其实还是u-textarea.vue,只不过做一层中转 | 
				
			||||
	 */ | 
				
			||||
	import uvTextarea from '../u-textarea/u-textarea.vue'; | 
				
			||||
	import props from '../u-textarea/props.js' | 
				
			||||
	export default { | 
				
			||||
		name: 'u--textarea', | 
				
			||||
		mixins: [uni.$u.mpMixin, props, uni.$u.mixin], | 
				
			||||
		components: { | 
				
			||||
			uvTextarea | 
				
			||||
		}, | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
@ -0,0 +1,54 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 操作菜单是否展示 (默认false)
 | 
				
			||||
        show: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.actionSheet.show | 
				
			||||
        }, | 
				
			||||
        // 标题
 | 
				
			||||
        title: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.actionSheet.title | 
				
			||||
        }, | 
				
			||||
        // 选项上方的描述信息
 | 
				
			||||
        description: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.actionSheet.description | 
				
			||||
        }, | 
				
			||||
        // 数据
 | 
				
			||||
        actions: { | 
				
			||||
            type: Array, | 
				
			||||
            default: uni.$u.props.actionSheet.actions | 
				
			||||
        }, | 
				
			||||
        // 取消按钮的文字,不为空时显示按钮
 | 
				
			||||
        cancelText: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.actionSheet.cancelText | 
				
			||||
        }, | 
				
			||||
        // 点击某个菜单项时是否关闭弹窗
 | 
				
			||||
        closeOnClickAction: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.actionSheet.closeOnClickAction | 
				
			||||
        }, | 
				
			||||
        // 处理底部安全区(默认true)
 | 
				
			||||
        safeAreaInsetBottom: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.actionSheet.safeAreaInsetBottom | 
				
			||||
        }, | 
				
			||||
        // 小程序的打开方式
 | 
				
			||||
        openType: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.actionSheet.openType | 
				
			||||
        }, | 
				
			||||
        // 点击遮罩是否允许关闭 (默认true)
 | 
				
			||||
        closeOnClickOverlay: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.actionSheet.closeOnClickOverlay | 
				
			||||
        }, | 
				
			||||
        // 圆角值
 | 
				
			||||
        round: { | 
				
			||||
            type: [Boolean, String, Number], | 
				
			||||
            default: uni.$u.props.actionSheet.round | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,278 @@
					 | 
				
			||||
 | 
				
			||||
<template> | 
				
			||||
	<u-popup | 
				
			||||
	    :show="show" | 
				
			||||
	    mode="bottom" | 
				
			||||
	    @close="closeHandler" | 
				
			||||
	    :safeAreaInsetBottom="safeAreaInsetBottom" | 
				
			||||
	    :round="round" | 
				
			||||
	> | 
				
			||||
		<view class="u-action-sheet"> | 
				
			||||
			<view | 
				
			||||
			    class="u-action-sheet__header" | 
				
			||||
			    v-if="title" | 
				
			||||
			> | 
				
			||||
				<text class="u-action-sheet__header__title u-line-1">{{title}}</text> | 
				
			||||
				<view | 
				
			||||
				    class="u-action-sheet__header__icon-wrap" | 
				
			||||
				    @tap.stop="cancel" | 
				
			||||
				> | 
				
			||||
					<u-icon | 
				
			||||
					    name="close" | 
				
			||||
					    size="17" | 
				
			||||
					    color="#c8c9cc" | 
				
			||||
					    bold | 
				
			||||
					></u-icon> | 
				
			||||
				</view> | 
				
			||||
			</view> | 
				
			||||
			<text | 
				
			||||
			    class="u-action-sheet__description" | 
				
			||||
				:style="[{ | 
				
			||||
					marginTop: `${title && description ? 0 : '18px'}` | 
				
			||||
				}]" | 
				
			||||
			    v-if="description" | 
				
			||||
			>{{description}}</text> | 
				
			||||
			<slot> | 
				
			||||
				<u-line v-if="description"></u-line> | 
				
			||||
				<view class="u-action-sheet__item-wrap"> | 
				
			||||
					<template v-for="(item, index) in actions"> | 
				
			||||
						<!-- #ifdef MP --> | 
				
			||||
						<button | 
				
			||||
						    :key="index" | 
				
			||||
						    class="u-reset-button" | 
				
			||||
						    :openType="item.openType" | 
				
			||||
						    @getuserinfo="onGetUserInfo" | 
				
			||||
						    @contact="onContact" | 
				
			||||
						    @getphonenumber="onGetPhoneNumber" | 
				
			||||
						    @error="onError" | 
				
			||||
						    @launchapp="onLaunchApp" | 
				
			||||
						    @opensetting="onOpenSetting" | 
				
			||||
						    :lang="lang" | 
				
			||||
						    :session-from="sessionFrom" | 
				
			||||
						    :send-message-title="sendMessageTitle" | 
				
			||||
						    :send-message-path="sendMessagePath" | 
				
			||||
						    :send-message-img="sendMessageImg" | 
				
			||||
						    :show-message-card="showMessageCard" | 
				
			||||
						    :app-parameter="appParameter" | 
				
			||||
						    @tap="selectHandler(index)" | 
				
			||||
						    :hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''" | 
				
			||||
						> | 
				
			||||
							<!-- #endif --> | 
				
			||||
							<view | 
				
			||||
							    class="u-action-sheet__item-wrap__item" | 
				
			||||
							    @tap.stop="selectHandler(index)" | 
				
			||||
							    :hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''" | 
				
			||||
							    :hover-stay-time="150" | 
				
			||||
							> | 
				
			||||
								<template v-if="!item.loading"> | 
				
			||||
									<text | 
				
			||||
									    class="u-action-sheet__item-wrap__item__name" | 
				
			||||
									    :style="[itemStyle(index)]" | 
				
			||||
									>{{ item.name }}</text> | 
				
			||||
									<text | 
				
			||||
									    v-if="item.subname" | 
				
			||||
									    class="u-action-sheet__item-wrap__item__subname" | 
				
			||||
									>{{ item.subname }}</text> | 
				
			||||
								</template> | 
				
			||||
								<u-loading-icon | 
				
			||||
								    v-else | 
				
			||||
								    custom-class="van-action-sheet__loading" | 
				
			||||
								    size="18" | 
				
			||||
								    mode="circle" | 
				
			||||
								/> | 
				
			||||
							</view> | 
				
			||||
							<!-- #ifdef MP --> | 
				
			||||
						</button> | 
				
			||||
						<!-- #endif --> | 
				
			||||
						<u-line v-if="index !== actions.length - 1"></u-line> | 
				
			||||
					</template> | 
				
			||||
				</view> | 
				
			||||
			</slot> | 
				
			||||
			<u-gap | 
				
			||||
			    bgColor="#eaeaec" | 
				
			||||
			    height="6" | 
				
			||||
			    v-if="cancelText" | 
				
			||||
			></u-gap> | 
				
			||||
			<view hover-class="u-action-sheet--hover"> | 
				
			||||
				<text | 
				
			||||
				    @touchmove.stop.prevent | 
				
			||||
				    :hover-stay-time="150" | 
				
			||||
				    v-if="cancelText" | 
				
			||||
				    class="u-action-sheet__cancel-text" | 
				
			||||
				    @tap="cancel" | 
				
			||||
				>{{cancelText}}</text> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
	</u-popup> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import openType from '../../libs/mixin/openType' | 
				
			||||
	import button from '../../libs/mixin/button' | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * ActionSheet 操作菜单 | 
				
			||||
	 * @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/actionSheet.html | 
				
			||||
	 *  | 
				
			||||
	 * @property {Boolean}			show				操作菜单是否展示 (默认 false ) | 
				
			||||
	 * @property {String}			title				操作菜单标题 | 
				
			||||
	 * @property {String}			description			选项上方的描述信息 | 
				
			||||
	 * @property {Array<Object>}	actions				按钮的文字数组,见官方文档示例 | 
				
			||||
	 * @property {String}			cancelText			取消按钮的提示文字,不为空时显示按钮 | 
				
			||||
	 * @property {Boolean}			closeOnClickAction	点击某个菜单项时是否关闭弹窗 (默认 true ) | 
				
			||||
	 * @property {Boolean}			safeAreaInsetBottom	处理底部安全区 (默认 true ) | 
				
			||||
	 * @property {String}			openType			小程序的打开方式 (contact | launchApp | getUserInfo | openSetting |getPhoneNumber |error ) | 
				
			||||
	 * @property {Boolean}			closeOnClickOverlay	点击遮罩是否允许关闭  (默认 true ) | 
				
			||||
	 * @property {Number|String}	round				圆角值,默认无圆角  (默认 0 ) | 
				
			||||
	 * @property {String}			lang				指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文 | 
				
			||||
	 * @property {String}			sessionFrom			会话来源,openType="contact"时有效 | 
				
			||||
	 * @property {String}			sendMessageTitle	会话内消息卡片标题,openType="contact"时有效 | 
				
			||||
	 * @property {String}			sendMessagePath		会话内消息卡片点击跳转小程序路径,openType="contact"时有效 | 
				
			||||
	 * @property {String}			sendMessageImg		会话内消息卡片图片,openType="contact"时有效 | 
				
			||||
	 * @property {Boolean}			showMessageCard		是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效 (默认 false ) | 
				
			||||
	 * @property {String}			appParameter		打开 APP 时,向 APP 传递的参数,openType=launchApp 时有效 | 
				
			||||
	 *  | 
				
			||||
	 * @event {Function} select			点击ActionSheet列表项时触发  | 
				
			||||
	 * @event {Function} close			点击取消按钮时触发 | 
				
			||||
	 * @event {Function} getuserinfo	用户点击该按钮时,会返回获取到的用户信息,回调的 detail 数据与 wx.getUserInfo 返回的一致,openType="getUserInfo"时有效 | 
				
			||||
	 * @event {Function} contact		客服消息回调,openType="contact"时有效 | 
				
			||||
	 * @event {Function} getphonenumber	获取用户手机号回调,openType="getPhoneNumber"时有效 | 
				
			||||
	 * @event {Function} error			当使用开放能力时,发生错误的回调,openType="error"时有效 | 
				
			||||
	 * @event {Function} launchapp		打开 APP 成功的回调,openType="launchApp"时有效 | 
				
			||||
	 * @event {Function} opensetting	在打开授权设置页后回调,openType="openSetting"时有效 | 
				
			||||
	 * @example <u-action-sheet :actions="list" :title="title" :show="show"></u-action-sheet> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: "u-action-sheet", | 
				
			||||
		// 一些props参数和methods方法,通过mixin混入,因为其他文件也会用到 | 
				
			||||
		mixins: [openType, button, uni.$u.mixin, props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
 | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			// 操作项目的样式 | 
				
			||||
			itemStyle() { | 
				
			||||
				return (index) => { | 
				
			||||
					let style = {}; | 
				
			||||
					if (this.actions[index].color) style.color = this.actions[index].color | 
				
			||||
					if (this.actions[index].fontSize) style.fontSize = uni.$u.addUnit(this.actions[index].fontSize) | 
				
			||||
					// 选项被禁用的样式 | 
				
			||||
					if (this.actions[index].disabled) style.color = '#c0c4cc' | 
				
			||||
					return style; | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			closeHandler() { | 
				
			||||
				// 允许点击遮罩关闭时,才发出close事件 | 
				
			||||
				if(this.closeOnClickOverlay) { | 
				
			||||
					this.$emit('close') | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			// 点击取消按钮 | 
				
			||||
			cancel() { | 
				
			||||
				this.$emit('close') | 
				
			||||
			}, | 
				
			||||
			selectHandler(index) { | 
				
			||||
				const item = this.actions[index] | 
				
			||||
				if (item && !item.disabled && !item.loading) { | 
				
			||||
					this.$emit('select', item) | 
				
			||||
					if (this.closeOnClickAction) { | 
				
			||||
						this.$emit('close') | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
	$u-action-sheet-reset-button-width:100% !default; | 
				
			||||
	$u-action-sheet-title-font-size: 16px !default; | 
				
			||||
	$u-action-sheet-title-padding: 12px 30px !default; | 
				
			||||
	$u-action-sheet-title-color: $u-main-color !default; | 
				
			||||
	$u-action-sheet-header-icon-wrap-right:15px !default; | 
				
			||||
	$u-action-sheet-header-icon-wrap-top:15px !default; | 
				
			||||
	$u-action-sheet-description-font-size:13px !default; | 
				
			||||
	$u-action-sheet-description-color:14px !default; | 
				
			||||
	$u-action-sheet-description-margin: 18px 15px !default; | 
				
			||||
	$u-action-sheet-item-wrap-item-padding:15px !default; | 
				
			||||
	$u-action-sheet-item-wrap-name-font-size:16px !default; | 
				
			||||
	$u-action-sheet-item-wrap-subname-font-size:13px !default; | 
				
			||||
	$u-action-sheet-item-wrap-subname-color: #c0c4cc !default; | 
				
			||||
	$u-action-sheet-item-wrap-subname-margin-top:10px !default; | 
				
			||||
	$u-action-sheet-cancel-text-font-size:16px !default; | 
				
			||||
	$u-action-sheet-cancel-text-color:$u-content-color !default; | 
				
			||||
	$u-action-sheet-cancel-text-font-size:15px !default; | 
				
			||||
	$u-action-sheet-cancel-text-hover-background-color:rgb(242, 243, 245) !default; | 
				
			||||
 | 
				
			||||
	.u-reset-button { | 
				
			||||
		width: $u-action-sheet-reset-button-width; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-action-sheet { | 
				
			||||
		text-align: center; | 
				
			||||
		&__header { | 
				
			||||
			position: relative; | 
				
			||||
			padding: $u-action-sheet-title-padding; | 
				
			||||
			&__title { | 
				
			||||
				font-size: $u-action-sheet-title-font-size; | 
				
			||||
				color: $u-action-sheet-title-color; | 
				
			||||
				font-weight: bold; | 
				
			||||
				text-align: center; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&__icon-wrap { | 
				
			||||
				position: absolute; | 
				
			||||
				right: $u-action-sheet-header-icon-wrap-right; | 
				
			||||
				top: $u-action-sheet-header-icon-wrap-top; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__description { | 
				
			||||
			font-size: $u-action-sheet-description-font-size; | 
				
			||||
			color: $u-tips-color; | 
				
			||||
			margin: $u-action-sheet-description-margin; | 
				
			||||
			text-align: center; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__item-wrap { | 
				
			||||
 | 
				
			||||
			&__item { | 
				
			||||
				padding: $u-action-sheet-item-wrap-item-padding; | 
				
			||||
				@include flex; | 
				
			||||
				align-items: center; | 
				
			||||
				justify-content: center; | 
				
			||||
				flex-direction: column; | 
				
			||||
 | 
				
			||||
				&__name { | 
				
			||||
					font-size: $u-action-sheet-item-wrap-name-font-size; | 
				
			||||
					color: $u-main-color; | 
				
			||||
					text-align: center; | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				&__subname { | 
				
			||||
					font-size: $u-action-sheet-item-wrap-subname-font-size; | 
				
			||||
					color: $u-action-sheet-item-wrap-subname-color; | 
				
			||||
					margin-top: $u-action-sheet-item-wrap-subname-margin-top; | 
				
			||||
					text-align: center; | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__cancel-text { | 
				
			||||
			font-size: $u-action-sheet-cancel-text-font-size; | 
				
			||||
			color: $u-action-sheet-cancel-text-color; | 
				
			||||
			text-align: center; | 
				
			||||
			padding: $u-action-sheet-cancel-text-font-size; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--hover { | 
				
			||||
			background-color: $u-action-sheet-cancel-text-hover-background-color; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,59 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 图片地址,Array<String>|Array<Object>形式
 | 
				
			||||
        urls: { | 
				
			||||
            type: Array, | 
				
			||||
            default: uni.$u.props.album.urls | 
				
			||||
        }, | 
				
			||||
        // 指定从数组的对象元素中读取哪个属性作为图片地址
 | 
				
			||||
        keyName: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.album.keyName | 
				
			||||
        }, | 
				
			||||
        // 单图时,图片长边的长度
 | 
				
			||||
        singleSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.album.singleSize | 
				
			||||
        }, | 
				
			||||
        // 多图时,图片边长
 | 
				
			||||
        multipleSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.album.multipleSize | 
				
			||||
        }, | 
				
			||||
        // 多图时,图片水平和垂直之间的间隔
 | 
				
			||||
        space: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.album.space | 
				
			||||
        }, | 
				
			||||
        // 单图时,图片缩放裁剪的模式
 | 
				
			||||
        singleMode: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.album.singleMode | 
				
			||||
        }, | 
				
			||||
        // 多图时,图片缩放裁剪的模式
 | 
				
			||||
        multipleMode: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.album.multipleMode | 
				
			||||
        }, | 
				
			||||
        // 最多展示的图片数量,超出时最后一个位置将会显示剩余图片数量
 | 
				
			||||
        maxCount: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.album.maxCount | 
				
			||||
        }, | 
				
			||||
        // 是否可以预览图片
 | 
				
			||||
        previewFullImage: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.album.previewFullImage | 
				
			||||
        }, | 
				
			||||
        // 每行展示图片数量,如设置,singleSize和multipleSize将会无效
 | 
				
			||||
        rowCount: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.album.rowCount | 
				
			||||
        }, | 
				
			||||
        // 超出maxCount时是否显示查看更多的提示
 | 
				
			||||
        showMore: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.album.showMore | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,259 @@
					 | 
				
			||||
<template> | 
				
			||||
    <view class="u-album"> | 
				
			||||
        <view | 
				
			||||
            class="u-album__row" | 
				
			||||
            ref="u-album__row" | 
				
			||||
            v-for="(arr, index) in showUrls" | 
				
			||||
            :forComputedUse="albumWidth" | 
				
			||||
            :key="index" | 
				
			||||
        > | 
				
			||||
            <view | 
				
			||||
                class="u-album__row__wrapper" | 
				
			||||
                v-for="(item, index1) in arr" | 
				
			||||
                :key="index1" | 
				
			||||
                :style="[imageStyle(index + 1, index1 + 1)]" | 
				
			||||
                @tap="previewFullImage ? onPreviewTap(getSrc(item)) : ''" | 
				
			||||
            > | 
				
			||||
                <image | 
				
			||||
                    :src="getSrc(item)" | 
				
			||||
                    :mode=" | 
				
			||||
                        urls.length === 1 | 
				
			||||
                            ? imageHeight > 0 | 
				
			||||
                                ? singleMode | 
				
			||||
                                : 'widthFix' | 
				
			||||
                            : multipleMode | 
				
			||||
                    " | 
				
			||||
                    :style="[ | 
				
			||||
                        { | 
				
			||||
                            width: imageWidth, | 
				
			||||
                            height: imageHeight | 
				
			||||
                        } | 
				
			||||
                    ]" | 
				
			||||
                ></image> | 
				
			||||
                <view | 
				
			||||
                    v-if=" | 
				
			||||
                        showMore && | 
				
			||||
                        urls.length > rowCount * showUrls.length && | 
				
			||||
                        index === showUrls.length - 1 && | 
				
			||||
                        index1 === showUrls[showUrls.length - 1].length - 1 | 
				
			||||
                    " | 
				
			||||
                    class="u-album__row__wrapper__text" | 
				
			||||
                > | 
				
			||||
                    <u--text | 
				
			||||
                        :text="`+${urls.length - maxCount}`" | 
				
			||||
                        color="#fff" | 
				
			||||
                        :size="multipleSize * 0.3" | 
				
			||||
                        align="center" | 
				
			||||
                        customStyle="justify-content: center" | 
				
			||||
                    ></u--text> | 
				
			||||
                </view> | 
				
			||||
            </view> | 
				
			||||
        </view> | 
				
			||||
    </view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
import props from './props.js' | 
				
			||||
// #ifdef APP-NVUE | 
				
			||||
// 由于weex为阿里的KPI业绩考核的产物,所以不支持百分比单位,这里需要通过dom查询组件的宽度 | 
				
			||||
const dom = uni.requireNativePlugin('dom') | 
				
			||||
// #endif | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Album 相册 | 
				
			||||
 * @description 本组件提供一个类似相册的功能,让开发者开发起来更加得心应手。减少重复的模板代码 | 
				
			||||
 * @tutorial https://www.uviewui.com/components/album.html | 
				
			||||
 * | 
				
			||||
 * @property {Array}           urls             图片地址列表 Array<String>|Array<Object>形式 | 
				
			||||
 * @property {String}          keyName          指定从数组的对象元素中读取哪个属性作为图片地址 | 
				
			||||
 * @property {String | Number} singleSize       单图时,图片长边的长度  (默认 180 ) | 
				
			||||
 * @property {String | Number} multipleSize     多图时,图片边长 (默认 70 ) | 
				
			||||
 * @property {String | Number} space            多图时,图片水平和垂直之间的间隔 (默认 6 ) | 
				
			||||
 * @property {String}          singleMode       单图时,图片缩放裁剪的模式 (默认 'scaleToFill' ) | 
				
			||||
 * @property {String}          multipleMode     多图时,图片缩放裁剪的模式 (默认 'aspectFill' ) | 
				
			||||
 * @property {String | Number} maxCount         取消按钮的提示文字 (默认 9 ) | 
				
			||||
 * @property {Boolean}         previewFullImage 是否可以预览图片 (默认 true ) | 
				
			||||
 * @property {String | Number} rowCount         每行展示图片数量,如设置,singleSize和multipleSize将会无效	(默认 3 ) | 
				
			||||
 * @property {Boolean}         showMore         超出maxCount时是否显示查看更多的提示 (默认 true ) | 
				
			||||
 * | 
				
			||||
 * @event    {Function}        albumWidth       某些特殊的情况下,需要让文字与相册的宽度相等,这里事件的形式对外发送  (回调参数 width ) | 
				
			||||
 * @example <u-album :urls="urls2" @albumWidth="width => albumWidth = width" multipleSize="68" ></u-album> | 
				
			||||
 */ | 
				
			||||
export default { | 
				
			||||
    name: 'u-album', | 
				
			||||
    mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
    data() { | 
				
			||||
        return { | 
				
			||||
            // 单图的宽度 | 
				
			||||
            singleWidth: 0, | 
				
			||||
            // 单图的高度 | 
				
			||||
            singleHeight: 0, | 
				
			||||
            // 单图时,如果无法获取图片的尺寸信息,让图片宽度默认为容器的一定百分比 | 
				
			||||
            singlePercent: 0.6 | 
				
			||||
        } | 
				
			||||
    }, | 
				
			||||
    watch: { | 
				
			||||
        urls: { | 
				
			||||
            immediate: true, | 
				
			||||
            handler(newVal) { | 
				
			||||
                if (newVal.length === 1) { | 
				
			||||
                    this.getImageRect() | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
    }, | 
				
			||||
    computed: { | 
				
			||||
        imageStyle() { | 
				
			||||
            return (index1, index2) => { | 
				
			||||
                const { space, rowCount, multipleSize, urls } = this, | 
				
			||||
                    { addUnit, addStyle } = uni.$u, | 
				
			||||
                    rowLen = this.showUrls.length, | 
				
			||||
                    allLen = this.urls.length | 
				
			||||
                const style = { | 
				
			||||
                    marginRight: addUnit(space), | 
				
			||||
                    marginBottom: addUnit(space) | 
				
			||||
                } | 
				
			||||
                // 如果为最后一行,则每个图片都无需下边框 | 
				
			||||
                if (index1 === rowLen) style.marginBottom = 0 | 
				
			||||
                // 每行的最右边一张和总长度的最后一张无需右边框 | 
				
			||||
                if ( | 
				
			||||
                    index2 === rowCount || | 
				
			||||
                    (index1 === rowLen && | 
				
			||||
                        index2 === this.showUrls[index1 - 1].length) | 
				
			||||
                ) | 
				
			||||
                    style.marginRight = 0 | 
				
			||||
                return style | 
				
			||||
            } | 
				
			||||
        }, | 
				
			||||
        // 将数组划分为二维数组 | 
				
			||||
        showUrls() { | 
				
			||||
            const arr = [] | 
				
			||||
            this.urls.map((item, index) => { | 
				
			||||
                // 限制最大展示数量 | 
				
			||||
                if (index + 1 <= this.maxCount) { | 
				
			||||
                    // 计算该元素为第几个素组内 | 
				
			||||
                    const itemIndex = Math.floor(index / this.rowCount) | 
				
			||||
                    // 判断对应的索引是否存在 | 
				
			||||
                    if (!arr[itemIndex]) { | 
				
			||||
                        arr[itemIndex] = [] | 
				
			||||
                    } | 
				
			||||
                    arr[itemIndex].push(item) | 
				
			||||
                } | 
				
			||||
            }) | 
				
			||||
            return arr | 
				
			||||
        }, | 
				
			||||
        imageWidth() { | 
				
			||||
            return uni.$u.addUnit( | 
				
			||||
                this.urls.length === 1 ? this.singleWidth : this.multipleSize | 
				
			||||
            ) | 
				
			||||
        }, | 
				
			||||
        imageHeight() { | 
				
			||||
            return uni.$u.addUnit( | 
				
			||||
                this.urls.length === 1 ? this.singleHeight : this.multipleSize | 
				
			||||
            ) | 
				
			||||
        }, | 
				
			||||
        // 此变量无实际用途,仅仅是为了利用computed特性,让其在urls长度等变化时,重新计算图片的宽度 | 
				
			||||
        // 因为用户在某些特殊的情况下,需要让文字与相册的宽度相等,所以这里事件的形式对外发送 | 
				
			||||
        albumWidth() { | 
				
			||||
            let width = 0 | 
				
			||||
            if (this.urls.length === 1) { | 
				
			||||
                width = this.singleWidth | 
				
			||||
            } else { | 
				
			||||
                width = | 
				
			||||
                    this.showUrls[0].length * this.multipleSize + | 
				
			||||
                    this.space * (this.showUrls[0].length - 1) | 
				
			||||
            } | 
				
			||||
            this.$emit('albumWidth', width) | 
				
			||||
            return width | 
				
			||||
        } | 
				
			||||
    }, | 
				
			||||
    methods: { | 
				
			||||
        // 预览图片 | 
				
			||||
        onPreviewTap(url) { | 
				
			||||
            const urls = this.urls.map((item) => { | 
				
			||||
                return this.getSrc(item) | 
				
			||||
            }) | 
				
			||||
            uni.previewImage({ | 
				
			||||
                current: url, | 
				
			||||
                urls | 
				
			||||
            }) | 
				
			||||
        }, | 
				
			||||
        // 获取图片的路径 | 
				
			||||
        getSrc(item) { | 
				
			||||
            return uni.$u.test.object(item) | 
				
			||||
                ? (this.keyName && item[this.keyName]) || item.src | 
				
			||||
                : item | 
				
			||||
        }, | 
				
			||||
        // 单图时,获取图片的尺寸 | 
				
			||||
        // 在小程序中,需要将网络图片的的域名添加到小程序的download域名才可能获取尺寸 | 
				
			||||
        // 在没有添加的情况下,让单图宽度默认为盒子的一定宽度(singlePercent) | 
				
			||||
        getImageRect() { | 
				
			||||
            const src = this.getSrc(this.urls[0]) | 
				
			||||
            uni.getImageInfo({ | 
				
			||||
                src, | 
				
			||||
                success: (res) => { | 
				
			||||
                    // 判断图片横向还是竖向展示方式 | 
				
			||||
                    const isHorizotal = res.width >= res.height | 
				
			||||
                    this.singleWidth = isHorizotal | 
				
			||||
                        ? this.singleSize | 
				
			||||
                        : (res.width / res.height) * this.singleSize | 
				
			||||
                    this.singleHeight = !isHorizotal | 
				
			||||
                        ? this.singleSize | 
				
			||||
                        : (res.height / res.width) * this.singleWidth | 
				
			||||
                }, | 
				
			||||
                fail: () => { | 
				
			||||
                    this.getComponentWidth() | 
				
			||||
                } | 
				
			||||
            }) | 
				
			||||
        }, | 
				
			||||
        // 获取组件的宽度 | 
				
			||||
        async getComponentWidth() { | 
				
			||||
            // 延时一定时间,以获取dom尺寸 | 
				
			||||
            await uni.$u.sleep(30) | 
				
			||||
            // #ifndef APP-NVUE | 
				
			||||
            this.$uGetRect('.u-album__row').then((size) => { | 
				
			||||
                this.singleWidth = size.width * this.singlePercent | 
				
			||||
            }) | 
				
			||||
            // #endif | 
				
			||||
 | 
				
			||||
            // #ifdef APP-NVUE | 
				
			||||
            // 这里ref="u-album__row"所在的标签为通过for循环出来,导致this.$refs['u-album__row']是一个数组 | 
				
			||||
            const ref = this.$refs['u-album__row'][0] | 
				
			||||
            ref && | 
				
			||||
                dom.getComponentRect(ref, (res) => { | 
				
			||||
                    this.singleWidth = res.size.width * this.singlePercent | 
				
			||||
                }) | 
				
			||||
            // #endif | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
@import '../../libs/css/components.scss'; | 
				
			||||
 | 
				
			||||
.u-album { | 
				
			||||
    @include flex(column); | 
				
			||||
 | 
				
			||||
    &__row { | 
				
			||||
        @include flex(row); | 
				
			||||
        flex-wrap: wrap; | 
				
			||||
 | 
				
			||||
        &__wrapper { | 
				
			||||
            position: relative; | 
				
			||||
 | 
				
			||||
            &__text { | 
				
			||||
                position: absolute; | 
				
			||||
                top: 0; | 
				
			||||
                left: 0; | 
				
			||||
                right: 0; | 
				
			||||
                bottom: 0; | 
				
			||||
                background-color: rgba(0, 0, 0, 0.3); | 
				
			||||
                @include flex(row); | 
				
			||||
                justify-content: center; | 
				
			||||
                align-items: center; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,44 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 显示文字
 | 
				
			||||
        title: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.alert.title | 
				
			||||
        }, | 
				
			||||
        // 主题,success/warning/info/error
 | 
				
			||||
        type: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.alert.type | 
				
			||||
        }, | 
				
			||||
        // 辅助性文字
 | 
				
			||||
        description: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.alert.description | 
				
			||||
        }, | 
				
			||||
        // 是否可关闭
 | 
				
			||||
        closable: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.alert.closable | 
				
			||||
        }, | 
				
			||||
        // 是否显示图标
 | 
				
			||||
        showIcon: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.alert.showIcon | 
				
			||||
        }, | 
				
			||||
        // 浅或深色调,light-浅色,dark-深色
 | 
				
			||||
        effect: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.alert.effect | 
				
			||||
        }, | 
				
			||||
        // 文字是否居中
 | 
				
			||||
        center: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.alert.center | 
				
			||||
        }, | 
				
			||||
        // 字体大小
 | 
				
			||||
        fontSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.alert.fontSize | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,243 @@
					 | 
				
			||||
<template> | 
				
			||||
	<u-transition | 
				
			||||
	    mode="fade" | 
				
			||||
	    :show="show" | 
				
			||||
	> | 
				
			||||
		<view | 
				
			||||
		    class="u-alert" | 
				
			||||
		    :class="[`u-alert--${type}--${effect}`]" | 
				
			||||
		    @tap.stop="clickHandler" | 
				
			||||
		    :style="[$u.addStyle(customStyle)]" | 
				
			||||
		> | 
				
			||||
			<view | 
				
			||||
			    class="u-alert__icon" | 
				
			||||
			    v-if="showIcon" | 
				
			||||
			> | 
				
			||||
				<u-icon | 
				
			||||
				    :name="iconName" | 
				
			||||
				    size="18" | 
				
			||||
				    :color="iconColor" | 
				
			||||
				></u-icon> | 
				
			||||
			</view> | 
				
			||||
			<view | 
				
			||||
			    class="u-alert__content" | 
				
			||||
			    :style="[{ | 
				
			||||
					paddingRight: closable ? '20px' : 0 | 
				
			||||
				}]" | 
				
			||||
			> | 
				
			||||
				<text | 
				
			||||
				    class="u-alert__content__title" | 
				
			||||
				    v-if="title" | 
				
			||||
					:style="[{ | 
				
			||||
						fontSize: $u.addUnit(fontSize), | 
				
			||||
						textAlign: center ? 'center' : 'left' | 
				
			||||
					}]" | 
				
			||||
				    :class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]" | 
				
			||||
				>{{ title }}</text> | 
				
			||||
				<text | 
				
			||||
				    class="u-alert__content__desc" | 
				
			||||
					v-if="description" | 
				
			||||
					:style="[{ | 
				
			||||
						fontSize: $u.addUnit(fontSize), | 
				
			||||
						textAlign: center ? 'center' : 'left' | 
				
			||||
					}]" | 
				
			||||
				    :class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]" | 
				
			||||
				>{{ description }}</text> | 
				
			||||
			</view> | 
				
			||||
			<view | 
				
			||||
			    class="u-alert__close" | 
				
			||||
			    v-if="closable" | 
				
			||||
			    @tap.stop="closeHandler" | 
				
			||||
			> | 
				
			||||
				<u-icon | 
				
			||||
				    name="close" | 
				
			||||
				    :color="iconColor" | 
				
			||||
				    size="15" | 
				
			||||
				></u-icon> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
	</u-transition> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * Alert  警告提示 | 
				
			||||
	 * @description 警告提示,展现需要关注的信息。 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/alertTips.html | 
				
			||||
	 *  | 
				
			||||
	 * @property {String}			title       显示的文字  | 
				
			||||
	 * @property {String}			type        使用预设的颜色  (默认 'warning' ) | 
				
			||||
	 * @property {String}			description 辅助性文字,颜色比title浅一点,字号也小一点,可选   | 
				
			||||
	 * @property {Boolean}			closable    关闭按钮(默认为叉号icon图标)  (默认 false ) | 
				
			||||
	 * @property {Boolean}			showIcon    是否显示左边的辅助图标   ( 默认 false ) | 
				
			||||
	 * @property {String}			effect      多图时,图片缩放裁剪的模式  (默认 'light' ) | 
				
			||||
	 * @property {Boolean}			center		文字是否居中  (默认 false ) | 
				
			||||
	 * @property {String | Number}	fontSize    字体大小  (默认 14 ) | 
				
			||||
	 * @property {Object}			customStyle	定义需要用到的外部样式 | 
				
			||||
	 * @event    {Function}        click       点击组件时触发 | 
				
			||||
	 * @example  <u-alert :title="title"  type = "warning" :closable="closable" :description = "description"></u-alert> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'u-alert', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				show: true | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			iconColor() { | 
				
			||||
				return this.effect === 'light' ? this.type : '#fff' | 
				
			||||
			}, | 
				
			||||
			// 不同主题对应不同的图标 | 
				
			||||
			iconName() { | 
				
			||||
				switch (this.type) { | 
				
			||||
					case 'success': | 
				
			||||
						return 'checkmark-circle-fill'; | 
				
			||||
						break; | 
				
			||||
					case 'error': | 
				
			||||
						return 'close-circle-fill'; | 
				
			||||
						break; | 
				
			||||
					case 'warning': | 
				
			||||
						return 'error-circle-fill'; | 
				
			||||
						break; | 
				
			||||
					case 'info': | 
				
			||||
						return 'info-circle-fill'; | 
				
			||||
						break; | 
				
			||||
					case 'primary': | 
				
			||||
						return 'more-circle-fill'; | 
				
			||||
						break; | 
				
			||||
					default:  | 
				
			||||
						return 'error-circle-fill'; | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			// 点击内容 | 
				
			||||
			clickHandler() { | 
				
			||||
				this.$emit('click') | 
				
			||||
			}, | 
				
			||||
			// 点击关闭按钮 | 
				
			||||
			closeHandler() { | 
				
			||||
				this.show = false | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
	.u-alert { | 
				
			||||
		position: relative; | 
				
			||||
		background-color: $u-primary; | 
				
			||||
		padding: 8px 10px; | 
				
			||||
		@include flex(row); | 
				
			||||
		align-items: center; | 
				
			||||
		border-top-left-radius: 4px; | 
				
			||||
		border-top-right-radius: 4px; | 
				
			||||
		border-bottom-left-radius: 4px; | 
				
			||||
		border-bottom-right-radius: 4px; | 
				
			||||
 | 
				
			||||
		&--primary--dark { | 
				
			||||
			background-color: $u-primary; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--primary--light { | 
				
			||||
			background-color: #ecf5ff; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--error--dark { | 
				
			||||
			background-color: $u-error; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--error--light { | 
				
			||||
			background-color: #FEF0F0; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--success--dark { | 
				
			||||
			background-color: $u-success; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--success--light { | 
				
			||||
			background-color: #f5fff0; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--warning--dark { | 
				
			||||
			background-color: $u-warning; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--warning--light { | 
				
			||||
			background-color: #FDF6EC; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--info--dark { | 
				
			||||
			background-color: $u-info; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--info--light { | 
				
			||||
			background-color: #f4f4f5; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__icon { | 
				
			||||
			margin-right: 5px; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__content { | 
				
			||||
			@include flex(column); | 
				
			||||
			flex: 1; | 
				
			||||
 | 
				
			||||
			&__title { | 
				
			||||
				color: $u-main-color; | 
				
			||||
				font-size: 14px; | 
				
			||||
				font-weight: bold; | 
				
			||||
				color: #fff; | 
				
			||||
				margin-bottom: 2px; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&__desc { | 
				
			||||
				color: $u-main-color; | 
				
			||||
				font-size: 14px; | 
				
			||||
				flex-wrap: wrap; | 
				
			||||
				color: #fff; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__title--dark, | 
				
			||||
		&__desc--dark { | 
				
			||||
			color: #FFFFFF; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__text--primary--light, | 
				
			||||
		&__text--primary--light { | 
				
			||||
			color: $u-primary; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__text--success--light, | 
				
			||||
		&__text--success--light { | 
				
			||||
			color: $u-success; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__text--warning--light, | 
				
			||||
		&__text--warning--light { | 
				
			||||
			color: $u-warning; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__text--error--light, | 
				
			||||
		&__text--error--light { | 
				
			||||
			color: $u-error; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__text--info--light, | 
				
			||||
		&__text--info--light { | 
				
			||||
			color: $u-info; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__close { | 
				
			||||
			position: absolute; | 
				
			||||
			top: 11px; | 
				
			||||
			right: 10px; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,52 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 头像图片组
 | 
				
			||||
        urls: { | 
				
			||||
            type: Array, | 
				
			||||
            default: uni.$u.props.avatarGroup.urls | 
				
			||||
        }, | 
				
			||||
        // 最多展示的头像数量
 | 
				
			||||
        maxCount: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.avatarGroup.maxCount | 
				
			||||
        }, | 
				
			||||
        // 头像形状
 | 
				
			||||
        shape: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.avatarGroup.shape | 
				
			||||
        }, | 
				
			||||
        // 图片裁剪模式
 | 
				
			||||
        mode: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.avatarGroup.mode | 
				
			||||
        }, | 
				
			||||
        // 超出maxCount时是否显示查看更多的提示
 | 
				
			||||
        showMore: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.avatarGroup.showMore | 
				
			||||
        }, | 
				
			||||
        // 头像大小
 | 
				
			||||
        size: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.avatarGroup.size | 
				
			||||
        }, | 
				
			||||
        // 指定从数组的对象元素中读取哪个属性作为图片地址
 | 
				
			||||
        keyName: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.avatarGroup.keyName | 
				
			||||
        }, | 
				
			||||
		// 头像之间的遮挡比例
 | 
				
			||||
        gap: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            validator(value) { | 
				
			||||
                return value >= 0 && value <= 1 | 
				
			||||
            }, | 
				
			||||
            default: uni.$u.props.avatarGroup.gap | 
				
			||||
        }, | 
				
			||||
		// 需额外显示的值
 | 
				
			||||
		extraValue: { | 
				
			||||
			type: [Number, String], | 
				
			||||
			default: uni.$u.props.avatarGroup.extraValue | 
				
			||||
		} | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,103 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="u-avatar-group"> | 
				
			||||
		<view | 
				
			||||
		    class="u-avatar-group__item" | 
				
			||||
		    v-for="(item, index) in showUrl" | 
				
			||||
		    :key="index" | 
				
			||||
		    :style="{ | 
				
			||||
				marginLeft: index === 0 ? 0 : $u.addUnit(-size * gap) | 
				
			||||
			}" | 
				
			||||
		> | 
				
			||||
			<u-avatar | 
				
			||||
			    :size="size" | 
				
			||||
			    :shape="shape" | 
				
			||||
			    :mode="mode" | 
				
			||||
			    :src="$u.test.object(item) ? keyName && item[keyName] || item.url : item" | 
				
			||||
			></u-avatar> | 
				
			||||
			<view | 
				
			||||
			    class="u-avatar-group__item__show-more" | 
				
			||||
			    v-if="showMore && index === showUrl.length - 1 && (urls.length > maxCount || extraValue > 0)" | 
				
			||||
				@tap="clickHandler" | 
				
			||||
			> | 
				
			||||
				<u--text | 
				
			||||
				    color="#ffffff" | 
				
			||||
				    :size="size * 0.4" | 
				
			||||
				    :text="`+${extraValue || urls.length - showUrl.length}`" | 
				
			||||
					align="center" | 
				
			||||
					customStyle="justify-content: center" | 
				
			||||
				></u--text> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * AvatarGroup  头像组 | 
				
			||||
	 * @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/avatar.html | 
				
			||||
	 *  | 
				
			||||
	 * @property {Array}           urls     头像图片组 (默认 [] ) | 
				
			||||
	 * @property {String | Number} maxCount 最多展示的头像数量 ( 默认 5 ) | 
				
			||||
	 * @property {String}          shape    头像形状( 'circle' (默认) | 'square' ) | 
				
			||||
	 * @property {String}          mode     图片裁剪模式(默认 'scaleToFill' ) | 
				
			||||
	 * @property {Boolean}         showMore 超出maxCount时是否显示查看更多的提示 (默认 true ) | 
				
			||||
	 * @property {String | Number} size      头像大小 (默认 40 ) | 
				
			||||
	 * @property {String}          keyName  指定从数组的对象元素中读取哪个属性作为图片地址  | 
				
			||||
	 * @property {String | Number} gap      头像之间的遮挡比例(0.4代表遮挡40%)  (默认 0.5 ) | 
				
			||||
	 * @property {String | Number} extraValue  需额外显示的值 | 
				
			||||
	 * @event    {Function}        showMore 头像组更多点击 | 
				
			||||
	 * @example  <u-avatar-group:urls="urls" size="35" gap="0.4" ></u-avatar-group:urls=> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'u-avatar-group', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
 | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			showUrl() { | 
				
			||||
				return this.urls.slice(0, this.maxCount) | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			clickHandler() { | 
				
			||||
				this.$emit('showMore') | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
	.u-avatar-group { | 
				
			||||
		@include flex; | 
				
			||||
 | 
				
			||||
		&__item { | 
				
			||||
			margin-left: -10px; | 
				
			||||
			position: relative; | 
				
			||||
 | 
				
			||||
			&--no-indent { | 
				
			||||
				// 如果你想质疑作者不会使用:first-child,说明你太年轻,因为nvue不支持 | 
				
			||||
				margin-left: 0; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&__show-more { | 
				
			||||
				position: absolute; | 
				
			||||
				top: 0; | 
				
			||||
				bottom: 0; | 
				
			||||
				left: 0; | 
				
			||||
				right: 0; | 
				
			||||
				background-color: rgba(0, 0, 0, 0.3); | 
				
			||||
				@include flex; | 
				
			||||
				align-items: center; | 
				
			||||
				justify-content: center; | 
				
			||||
				border-radius: 100px; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,78 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 头像图片路径(不能为相对路径)
 | 
				
			||||
        src: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.avatar.src | 
				
			||||
        }, | 
				
			||||
        // 头像形状,circle-圆形,square-方形
 | 
				
			||||
        shape: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.avatar.shape | 
				
			||||
        }, | 
				
			||||
        // 头像尺寸
 | 
				
			||||
        size: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.avatar.size | 
				
			||||
        }, | 
				
			||||
        // 裁剪模式
 | 
				
			||||
        mode: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.avatar.mode | 
				
			||||
        }, | 
				
			||||
        // 显示的文字
 | 
				
			||||
        text: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.avatar.text | 
				
			||||
        }, | 
				
			||||
        // 背景色
 | 
				
			||||
        bgColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.avatar.bgColor | 
				
			||||
        }, | 
				
			||||
        // 文字颜色
 | 
				
			||||
        color: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.avatar.color | 
				
			||||
        }, | 
				
			||||
        // 文字大小
 | 
				
			||||
        fontSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.avatar.fontSize | 
				
			||||
        }, | 
				
			||||
        // 显示的图标
 | 
				
			||||
        icon: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.avatar.icon | 
				
			||||
        }, | 
				
			||||
        // 显示小程序头像,只对百度,微信,QQ小程序有效
 | 
				
			||||
        mpAvatar: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.avatar.mpAvatar | 
				
			||||
        }, | 
				
			||||
        // 是否使用随机背景色
 | 
				
			||||
        randomBgColor: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.avatar.randomBgColor | 
				
			||||
        }, | 
				
			||||
        // 加载失败的默认头像(组件有内置默认图片)
 | 
				
			||||
        defaultUrl: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.avatar.defaultUrl | 
				
			||||
        }, | 
				
			||||
        // 如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间
 | 
				
			||||
        colorIndex: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            // 校验参数规则,索引在0-19之间
 | 
				
			||||
            validator(n) { | 
				
			||||
                return uni.$u.test.range(n, [0, 19]) || n === '' | 
				
			||||
            }, | 
				
			||||
            default: uni.$u.props.avatar.colorIndex | 
				
			||||
        }, | 
				
			||||
        // 组件标识符
 | 
				
			||||
        name: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.avatar.name | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,173 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view | 
				
			||||
		class="u-avatar" | 
				
			||||
		:class="[`u-avatar--${shape}`]" | 
				
			||||
		:style="[{ | 
				
			||||
			backgroundColor: (text || icon) ? (randomBgColor ? colors[colorIndex !== '' ? colorIndex : $u.random(0, 19)] : bgColor) : 'transparent', | 
				
			||||
			width: $u.addUnit(size), | 
				
			||||
			height: $u.addUnit(size), | 
				
			||||
		}, $u.addStyle(customStyle)]" | 
				
			||||
		@tap="clickHandler" | 
				
			||||
	> | 
				
			||||
		<slot> | 
				
			||||
			<!-- #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU  --> | 
				
			||||
			<open-data | 
				
			||||
				v-if="mpAvatar && allowMp" | 
				
			||||
				type="userAvatarUrl" | 
				
			||||
				:style="[{ | 
				
			||||
					width: $u.addUnit(size), | 
				
			||||
					height: $u.addUnit(size) | 
				
			||||
				}]" | 
				
			||||
			/> | 
				
			||||
			<!-- #endif --> | 
				
			||||
			<!-- #ifndef MP-WEIXIN && MP-QQ && MP-BAIDU  --> | 
				
			||||
			<template v-if="mpAvatar && allowMp"></template> | 
				
			||||
			<!-- #endif --> | 
				
			||||
			<u-icon | 
				
			||||
				v-else-if="icon" | 
				
			||||
				:name="icon" | 
				
			||||
				:size="fontSize" | 
				
			||||
				:color="color" | 
				
			||||
			></u-icon> | 
				
			||||
			<u--text | 
				
			||||
				v-else-if="text" | 
				
			||||
				:text="text" | 
				
			||||
				:size="fontSize" | 
				
			||||
				:color="color" | 
				
			||||
				align="center" | 
				
			||||
				customStyle="justify-content: center" | 
				
			||||
			></u--text> | 
				
			||||
			<image | 
				
			||||
				class="u-avatar__image" | 
				
			||||
				v-else | 
				
			||||
				:class="[`u-avatar__image--${shape}`]" | 
				
			||||
				:src="avatarUrl || defaultUrl" | 
				
			||||
				:mode="mode" | 
				
			||||
				@error="errorHandler" | 
				
			||||
				:style="[{ | 
				
			||||
					width: $u.addUnit(size), | 
				
			||||
					height: $u.addUnit(size) | 
				
			||||
				}]" | 
				
			||||
			></image> | 
				
			||||
		</slot> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	const base64Avatar = | 
				
			||||
		"data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjREMEQwRkY0RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjREMEQwRkY1RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEQwRDBGRjJGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NEQwRDBGRjNGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYGCAsMCgoLCgoMEAwMDAwMDBAMDg8QDw4MExMUFBMTHBsbGxwfHx8fHx8fHx8fAQcHBw0MDRgQEBgaFREVGh8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx//wAARCADIAMgDAREAAhEBAxEB/8QAcQABAQEAAwEBAAAAAAAAAAAAAAUEAQMGAgcBAQAAAAAAAAAAAAAAAAAAAAAQAAIBAwICBgkDBQAAAAAAAAABAhEDBCEFMVFBYXGREiKBscHRMkJSEyOh4XLxYjNDFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHbHFyZ/Dam+yLA+Z2L0Pjtyj2poD4AAAAAAAAAAAAAAAAAAAAAAAAKWFs9y6lcvvwQeqj8z9wFaziY1n/HbUX9XF97A7QAGXI23EvJ1goyfzR0YEfN269jeZ+a03pNe0DIAAAAAAAAAAAAAAAAAAAACvtO3RcVkXlWutuL9YFYAAAAAOJRjKLjJVi9GmB5/csH/mu1h/in8PU+QGMAAAAAAAAAAAAAAAAAAaMDG/6MmMH8C80+xAelSSVFolwQAAAAAAAHVlWI37ErUulaPk+hgeYnCUJuElSUXRrrQHAAAAAAAAAAAAAAAAABa2Oz4bM7r4zdF2ICmAAAAAAAAAg7zZ8GX41wuJP0rRgYAAAAAAAAAAAAAAAAAD0m2R8ODaXU33tsDSAAAAAAAAAlb9HyWZcnJd9PcBHAAAAAAAAAAAAAAAAAPS7e64Vn+KA0AAAAAAAAAJm+v8Ftf3ewCKAAAAAAAAAAAAAAAAAX9muqeGo9NttP06+0DcAAAAAAAAAjb7dTu2ra+VOT9P8AQCWAAAAAAAAAAAAAAAAAUNmyPt5Ltv4bui/kuAF0AAAAAAADiUlGLlJ0SVW+oDzOXfd/Ind6JPRdS0QHSAAAAAAAAAAAAAAAAAE2nVaNcGB6Lbs6OTao9LsF51z60BrAAAAAABJ3jOVHjW3r/sa9QEgAAAAAAAAAAAAAAAAAAAPu1duWriuW34ZR4MC9hbnZyEoy8l36XwfYBsAAADaSq9EuLAlZ+7xSdrGdW9Hc5dgEdtt1erfFgAAAAAAAAAAAAAAAAADVjbblX6NR8MH80tEBRs7HYivyzlN8lovaBPzduvY0m6eK10TXtAyAarO55lpJK54orolr+4GqO/Xaea1FvqbXvA+Z77kNeW3GPbV+4DJfzcm/pcm3H6Vou5AdAFLC2ed2Pjv1txa8sV8T6wOL+yZEKu1JXFy4MDBOE4ScZxcZLinoB8gAAAAAAAAAAAB242LeyJ+C3GvN9C7QLmJtePYpKS+5c+p8F2IDYAANJqj1T4oCfk7Nj3G5Wn9qXJax7gJ93Z82D8sVNc4v30A6Xg5i42Z+iLfqARwcyT0sz9MWvWBps7LlTf5Grce9/oBTxdtxseklHxT+uWr9AGoAB138ezfj4bsFJdD6V2MCPm7RdtJzs1uW1xXzL3gTgAAAAAAAAADRhYc8q74I6RWs5ckB6GxYtWLat21SK731sDsAAAAAAAAAAAAAAAASt021NO/YjrxuQXT1oCOAAAAAAABzGLlJRSq26JAelwsWONYjbXxcZvmwO8AAAAAAAAAAAAAAAAAAef3TEWPkVivx3NY9T6UBiAAAAAABo2+VmGXblddIJ8eivRUD0oAAAAAAAAAAAAAAAAAAAYt4tKeFKVNYNSXfRgefAAAAAAAAr7VuSSWPedKaW5v1MCsAAAAAAAAAAAAAAAAAAIe6bj96Ts2n+JPzSXzP3ATgAAAAAAAAFbbt1UUrOQ9FpC4/UwK6aaqtU+DAAAAAAAAAAAAAAA4lKMIuUmoxWrb4ARNx3R3q2rLpa4Sl0y/YCcAAAAAAAAAAANmFud7G8r89r6X0dgFvGzLGRGtuWvTF6NAdwAAAAAAAAAAAy5W442PVN+K59EePp5ARMvOv5MvO6QXCC4AZwAAAAAAAAAAAAAcxlKLUotprg1owN+PvORborq+7Hnwl3gUbO74VzRydt8pKn68ANcJwmqwkpLmnUDkAAAAfNy9atqtyagut0AxXt5xIV8Fbj6lRd7Am5G65V6qUvtwfyx94GMAAAAAAAAAAAAAAAAAAAOU2nVOj5gdsc3LiqRvTpyqwOxbnnrhdfpSfrQB7pnv/AGvuS9gHXPMy5/Fem1yq0v0A6W29XqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//Z"; | 
				
			||||
	/** | 
				
			||||
	 * Avatar  头像 | 
				
			||||
	 * @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/avatar.html | 
				
			||||
	 * | 
				
			||||
	 * @property {String}			src				头像路径,如加载失败,将会显示默认头像(不能为相对路径) | 
				
			||||
	 * @property {String}			shape			头像形状  ( circle (默认) | square) | 
				
			||||
	 * @property {String | Number}	size			头像尺寸,可以为指定字符串(large, default, mini),或者数值 (默认 40 ) | 
				
			||||
	 * @property {String}			mode			头像图片的裁剪类型,与uni的image组件的mode参数一致,如效果达不到需求,可尝试传widthFix值 (默认 'scaleToFill' ) | 
				
			||||
	 * @property {String}			text			用文字替代图片,级别优先于src | 
				
			||||
	 * @property {String}			bgColor			背景颜色,一般显示文字时用 (默认 '#c0c4cc' ) | 
				
			||||
	 * @property {String}			color			文字颜色 (默认 '#ffffff' ) | 
				
			||||
	 * @property {String | Number}	fontSize		文字大小  (默认 18 ) | 
				
			||||
	 * @property {String}			icon			显示的图标 | 
				
			||||
	 * @property {Boolean}			mpAvatar		显示小程序头像,只对百度,微信,QQ小程序有效  (默认 false ) | 
				
			||||
	 * @property {Boolean}			randomBgColor	是否使用随机背景色  (默认 false ) | 
				
			||||
	 * @property {String}			defaultUrl		加载失败的默认头像(组件有内置默认图片) | 
				
			||||
	 * @property {String | Number}	colorIndex		如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间 | 
				
			||||
	 * @property {String}			name			组件标识符  (默认 'level' ) | 
				
			||||
	 * @property {Object}			customStyle		定义需要用到的外部样式 | 
				
			||||
	 * | 
				
			||||
	 * @event    {Function}        click       点击组件时触发   index: 用户传递的标识符 | 
				
			||||
	 * @example  <u-avatar :src="src" mode="square"></u-avatar> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'u-avatar', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				// 如果配置randomBgColor参数为true,在图标或者文字的模式下,会随机从中取出一个颜色值当做背景色 | 
				
			||||
				colors: ['#ffb34b', '#f2bba9', '#f7a196', '#f18080', '#88a867', '#bfbf39', '#89c152', '#94d554', '#f19ec2', | 
				
			||||
					'#afaae4', '#e1b0df', '#c38cc1', '#72dcdc', '#9acdcb', '#77b1cc', '#448aca', '#86cefa', '#98d1ee', | 
				
			||||
					'#73d1f1', | 
				
			||||
					'#80a7dc' | 
				
			||||
				], | 
				
			||||
				avatarUrl: this.src, | 
				
			||||
				allowMp: false | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		watch: { | 
				
			||||
			// 监听头像src的变化,赋值给内部的avatarUrl变量,因为图片加载失败时,需要修改图片的src为默认值 | 
				
			||||
			// 而组件内部不能直接修改props的值,所以需要一个中间变量 | 
				
			||||
			src: { | 
				
			||||
				immediate: true, | 
				
			||||
				handler(newVal) { | 
				
			||||
					this.avatarUrl = newVal | 
				
			||||
					// 如果没有传src,则主动触发error事件,用于显示默认的头像,否则src为''空字符等的时候,会无内容展示 | 
				
			||||
					if(!newVal) { | 
				
			||||
						this.errorHandler() | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			imageStyle() { | 
				
			||||
				const style = {} | 
				
			||||
				return style | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		created() { | 
				
			||||
			this.init() | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			init() { | 
				
			||||
				// 目前只有这几个小程序平台具有open-data标签 | 
				
			||||
				// 其他平台可以通过uni.getUserInfo类似接口获取信息,但是需要弹窗授权(首次),不合符组件逻辑 | 
				
			||||
				// 故目前自动获取小程序头像只支持这几个平台 | 
				
			||||
				// #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU | 
				
			||||
				this.allowMp = true | 
				
			||||
				// #endif | 
				
			||||
			}, | 
				
			||||
			// 判断传入的name属性,是否图片路径,只要带有"/"均认为是图片形式 | 
				
			||||
			isImg() { | 
				
			||||
				return this.src.indexOf('/') !== -1 | 
				
			||||
			}, | 
				
			||||
			// 图片加载时失败时触发 | 
				
			||||
			errorHandler() { | 
				
			||||
				this.avatarUrl = this.defaultUrl || base64Avatar | 
				
			||||
			}, | 
				
			||||
			clickHandler() { | 
				
			||||
				this.$emit('click', this.name) | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
	.u-avatar { | 
				
			||||
		@include flex; | 
				
			||||
		align-items: center; | 
				
			||||
		justify-content: center; | 
				
			||||
 | 
				
			||||
		&--circle { | 
				
			||||
			border-radius: 100px; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--square { | 
				
			||||
			border-radius: 4px; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__image { | 
				
			||||
			&--circle { | 
				
			||||
				border-radius: 100px; | 
				
			||||
				overflow: hidden; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&--square { | 
				
			||||
				border-radius: 4px; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,54 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 返回顶部的形状,circle-圆形,square-方形
 | 
				
			||||
        mode: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.backtop.mode | 
				
			||||
        }, | 
				
			||||
        // 自定义图标
 | 
				
			||||
        icon: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.backtop.icon | 
				
			||||
        }, | 
				
			||||
        // 提示文字
 | 
				
			||||
        text: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.backtop.text | 
				
			||||
        }, | 
				
			||||
        // 返回顶部滚动时间
 | 
				
			||||
        duration: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.backtop.duration | 
				
			||||
        }, | 
				
			||||
        // 滚动距离
 | 
				
			||||
        scrollTop: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.backtop.scrollTop | 
				
			||||
        }, | 
				
			||||
        // 距离顶部多少距离显示,单位px
 | 
				
			||||
        top: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.backtop.top | 
				
			||||
        }, | 
				
			||||
        // 返回顶部按钮到底部的距离,单位px
 | 
				
			||||
        bottom: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.backtop.bottom | 
				
			||||
        }, | 
				
			||||
        // 返回顶部按钮到右边的距离,单位px
 | 
				
			||||
        right: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.backtop.right | 
				
			||||
        }, | 
				
			||||
        // 层级
 | 
				
			||||
        zIndex: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.backtop.zIndex | 
				
			||||
        }, | 
				
			||||
        // 图标的样式,对象形式
 | 
				
			||||
        iconStyle: { | 
				
			||||
            type: Object, | 
				
			||||
            default: uni.$u.props.backtop.iconStyle | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,129 @@
					 | 
				
			||||
<template> | 
				
			||||
	<u-transition | 
				
			||||
	    mode="fade" | 
				
			||||
	    :customStyle="backTopStyle" | 
				
			||||
	    :show="show" | 
				
			||||
	> | 
				
			||||
		<view | 
				
			||||
		    class="u-back-top" | 
				
			||||
			:style="[contentStyle]" | 
				
			||||
		    v-if="!$slots.default && !$slots.$default" | 
				
			||||
			@click="backToTop" | 
				
			||||
		> | 
				
			||||
			<u-icon | 
				
			||||
			    :name="icon" | 
				
			||||
			    :custom-style="iconStyle" | 
				
			||||
			></u-icon> | 
				
			||||
			<text | 
				
			||||
			    v-if="text" | 
				
			||||
			    class="u-back-top__text" | 
				
			||||
			>{{text}}</text> | 
				
			||||
		</view> | 
				
			||||
		<slot v-else /> | 
				
			||||
	</u-transition> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	// #ifdef APP-NVUE | 
				
			||||
	const dom = weex.requireModule('dom') | 
				
			||||
	// #endif | 
				
			||||
	/** | 
				
			||||
	 * backTop 返回顶部 | 
				
			||||
	 * @description 本组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。 | 
				
			||||
	 * @tutorial https://uviewui.com/components/backTop.html | 
				
			||||
	 *  | 
				
			||||
	 * @property {String}			mode  		返回顶部的形状,circle-圆形,square-方形 (默认 'circle' ) | 
				
			||||
	 * @property {String} 			icon 		自定义图标 (默认 'arrow-upward' ) 见官方文档示例 | 
				
			||||
	 * @property {String} 			text 		提示文字  | 
				
			||||
	 * @property {String | Number}  duration	返回顶部滚动时间 (默认 100) | 
				
			||||
	 * @property {String | Number}  scrollTop	滚动距离 (默认 0 ) | 
				
			||||
	 * @property {String | Number}  top  		距离顶部多少距离显示,单位px (默认 400 ) | 
				
			||||
	 * @property {String | Number}  bottom  	返回顶部按钮到底部的距离,单位px (默认 100 ) | 
				
			||||
	 * @property {String | Number}  right  		返回顶部按钮到右边的距离,单位px (默认 20 ) | 
				
			||||
	 * @property {String | Number}  zIndex 		层级   (默认 9 ) | 
				
			||||
	 * @property {Object<Object>}  	iconStyle 	图标的样式,对象形式   (默认 {color: '#909399',fontSize: '19px'}) | 
				
			||||
	 * @property {Object}			customStyle	定义需要用到的外部样式 | 
				
			||||
	 *  | 
				
			||||
	 * @example <u-back-top :scrollTop="scrollTop"></u-back-top> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'u-back-top', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin,props], | 
				
			||||
		computed: { | 
				
			||||
			backTopStyle() { | 
				
			||||
				// 动画组件样式 | 
				
			||||
				const style = { | 
				
			||||
					bottom: uni.$u.addUnit(this.bottom), | 
				
			||||
					right: uni.$u.addUnit(this.right), | 
				
			||||
					width: '40px', | 
				
			||||
					height: '40px', | 
				
			||||
					position: 'fixed', | 
				
			||||
					zIndex: 10, | 
				
			||||
				} | 
				
			||||
				return style | 
				
			||||
			}, | 
				
			||||
			show() { | 
				
			||||
				return uni.$u.getPx(this.scrollTop) > uni.$u.getPx(this.top) | 
				
			||||
			}, | 
				
			||||
			contentStyle() { | 
				
			||||
				const style = {} | 
				
			||||
				let radius = 0 | 
				
			||||
				// 是否圆形 | 
				
			||||
				if(this.mode === 'circle') { | 
				
			||||
					radius = '100px' | 
				
			||||
				} else { | 
				
			||||
					radius = '4px' | 
				
			||||
				} | 
				
			||||
				// 为了兼容安卓nvue,只能这么分开写 | 
				
			||||
				style.borderTopLeftRadius = radius | 
				
			||||
				style.borderTopRightRadius = radius | 
				
			||||
				style.borderBottomLeftRadius = radius | 
				
			||||
				style.borderBottomRightRadius = radius | 
				
			||||
				return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle)) | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			backToTop() { | 
				
			||||
				// #ifdef APP-NVUE | 
				
			||||
				if (!this.$parent.$refs['u-back-top']) { | 
				
			||||
					uni.$u.error(`nvue页面需要给页面最外层元素设置"ref='u-back-top'`) | 
				
			||||
				} | 
				
			||||
				dom.scrollToElement(this.$parent.$refs['u-back-top'], { | 
				
			||||
					offset: 0 | 
				
			||||
				}) | 
				
			||||
				// #endif | 
				
			||||
				 | 
				
			||||
				// #ifndef APP-NVUE | 
				
			||||
				uni.pageScrollTo({ | 
				
			||||
					scrollTop: 0, | 
				
			||||
					duration: this.duration | 
				
			||||
				}); | 
				
			||||
				// #endif | 
				
			||||
				this.$emit('click') | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import '../../libs/css/components.scss'; | 
				
			||||
     $u-back-top-flex:1 !default; | 
				
			||||
     $u-back-top-height:100% !default; | 
				
			||||
     $u-back-top-background-color:#E1E1E1 !default; | 
				
			||||
     $u-back-top-tips-font-size:12px !default; | 
				
			||||
	.u-back-top { | 
				
			||||
		@include flex; | 
				
			||||
		flex-direction: column; | 
				
			||||
		align-items: center; | 
				
			||||
		flex:$u-back-top-flex; | 
				
			||||
		height: $u-back-top-height; | 
				
			||||
		justify-content: center; | 
				
			||||
		background-color: $u-back-top-background-color; | 
				
			||||
 | 
				
			||||
		&__tips { | 
				
			||||
			font-size:$u-back-top-tips-font-size; | 
				
			||||
			transform: scale(0.8); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,72 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 是否显示圆点
 | 
				
			||||
        isDot: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.badge.isDot | 
				
			||||
        }, | 
				
			||||
        // 显示的内容
 | 
				
			||||
        value: { | 
				
			||||
            type: [Number, String], | 
				
			||||
            default: uni.$u.props.badge.value | 
				
			||||
        }, | 
				
			||||
        // 是否显示
 | 
				
			||||
        show: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.badge.show | 
				
			||||
        }, | 
				
			||||
        // 最大值,超过最大值会显示 '{max}+'
 | 
				
			||||
        max: { | 
				
			||||
            type: [Number, String], | 
				
			||||
            default: uni.$u.props.badge.max | 
				
			||||
        }, | 
				
			||||
        // 主题类型,error|warning|success|primary
 | 
				
			||||
        type: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.badge.type | 
				
			||||
        }, | 
				
			||||
        // 当数值为 0 时,是否展示 Badge
 | 
				
			||||
        showZero: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.badge.showZero | 
				
			||||
        }, | 
				
			||||
        // 背景颜色,优先级比type高,如设置,type参数会失效
 | 
				
			||||
        bgColor: { | 
				
			||||
            type: [String, null], | 
				
			||||
            default: uni.$u.props.badge.bgColor | 
				
			||||
        }, | 
				
			||||
        // 字体颜色
 | 
				
			||||
        color: { | 
				
			||||
            type: [String, null], | 
				
			||||
            default: uni.$u.props.badge.color | 
				
			||||
        }, | 
				
			||||
        // 徽标形状,circle-四角均为圆角,horn-左下角为直角
 | 
				
			||||
        shape: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.badge.shape | 
				
			||||
        }, | 
				
			||||
        // 设置数字的显示方式,overflow|ellipsis|limit
 | 
				
			||||
        // overflow会根据max字段判断,超出显示`${max}+`
 | 
				
			||||
        // ellipsis会根据max判断,超出显示`${max}...`
 | 
				
			||||
        // limit会依据1000作为判断条件,超出1000,显示`${value/1000}K`,比如2.2k、3.34w,最多保留2位小数
 | 
				
			||||
        numberType: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.badge.numberType | 
				
			||||
        }, | 
				
			||||
        // 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效
 | 
				
			||||
        offset: { | 
				
			||||
            type: Array, | 
				
			||||
            default: uni.$u.props.badge.offset | 
				
			||||
        }, | 
				
			||||
        // 是否反转背景和字体颜色
 | 
				
			||||
        inverted: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.badge.inverted | 
				
			||||
        }, | 
				
			||||
        // 是否绝对定位
 | 
				
			||||
        absolute: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.badge.absolute | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,171 @@
					 | 
				
			||||
<template> | 
				
			||||
	<text | 
				
			||||
		v-if="show && ((Number(value) === 0 ? showZero : true) || isDot)" | 
				
			||||
		:class="[isDot ? 'u-badge--dot' : 'u-badge--not-dot', inverted && 'u-badge--inverted', shape === 'horn' && 'u-badge--horn', `u-badge--${type}${inverted ? '--inverted' : ''}`]" | 
				
			||||
		:style="[$u.addStyle(customStyle), badgeStyle]" | 
				
			||||
		class="u-badge" | 
				
			||||
	>{{ isDot ? '' :showValue }}</text> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * badge 徽标数 | 
				
			||||
	 * @description 该组件一般用于图标右上角显示未读的消息数量,提示用户点击,有圆点和圆包含文字两种形式。 | 
				
			||||
	 * @tutorial https://uviewui.com/components/badge.html | 
				
			||||
	 *  | 
				
			||||
	 * @property {Boolean} 			isDot 		是否显示圆点 (默认 false ) | 
				
			||||
	 * @property {String | Number} 	value 		显示的内容 | 
				
			||||
	 * @property {Boolean} 			show 		是否显示 (默认 true ) | 
				
			||||
	 * @property {String | Number} 	max 		最大值,超过最大值会显示 '{max}+'  (默认999) | 
				
			||||
	 * @property {String} 			type 		主题类型,error|warning|success|primary (默认 'error' ) | 
				
			||||
	 * @property {Boolean} 			showZero	当数值为 0 时,是否展示 Badge (默认 false ) | 
				
			||||
	 * @property {String} 			bgColor 	背景颜色,优先级比type高,如设置,type参数会失效 | 
				
			||||
	 * @property {String} 			color 		字体颜色 (默认 '#ffffff' ) | 
				
			||||
	 * @property {String} 			shape 		徽标形状,circle-四角均为圆角,horn-左下角为直角 (默认 'circle' ) | 
				
			||||
	 * @property {String} 			numberType	设置数字的显示方式,overflow|ellipsis|limit  (默认 'overflow' ) | 
				
			||||
	 * @property {Array}} 			offset		设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效 | 
				
			||||
	 * @property {Boolean} 			inverted	是否反转背景和字体颜色(默认 false ) | 
				
			||||
	 * @property {Boolean} 			absolute	是否绝对定位(默认 false ) | 
				
			||||
	 * @property {Object}			customStyle	定义需要用到的外部样式 | 
				
			||||
	 * @example <u-badge :type="type" :count="count"></u-badge> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'u-badge', | 
				
			||||
		mixins: [uni.$u.mpMixin, props, uni.$u.mixin], | 
				
			||||
		computed: { | 
				
			||||
			// 是否将badge中心与父组件右上角重合 | 
				
			||||
			boxStyle() { | 
				
			||||
				let style = {}; | 
				
			||||
				return style; | 
				
			||||
			}, | 
				
			||||
			// 整个组件的样式 | 
				
			||||
			badgeStyle() { | 
				
			||||
				const style = {} | 
				
			||||
				if(this.color) { | 
				
			||||
					style.color = this.color | 
				
			||||
				} | 
				
			||||
				if (this.bgColor && !this.inverted) { | 
				
			||||
					style.backgroundColor = this.bgColor | 
				
			||||
				} | 
				
			||||
				if (this.absolute) { | 
				
			||||
					style.position = 'absolute' | 
				
			||||
					// 如果有设置offset参数 | 
				
			||||
					if(this.offset.length) { | 
				
			||||
						// top和right分为为offset的第一个和第二个值,如果没有第二个值,则right等于top | 
				
			||||
						const top = this.offset[0] | 
				
			||||
						const right = this.offset[1] || top | 
				
			||||
						style.top = uni.$u.addUnit(top) | 
				
			||||
						style.right = uni.$u.addUnit(right) | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
				return style | 
				
			||||
			}, | 
				
			||||
			showValue() { | 
				
			||||
				switch (this.numberType) { | 
				
			||||
					case "overflow": | 
				
			||||
						return Number(this.value) > Number(this.max) ? this.max + "+" : this.value | 
				
			||||
						break; | 
				
			||||
					case "ellipsis": | 
				
			||||
						return Number(this.value) > Number(this.max) ? "..." : this.value | 
				
			||||
						break; | 
				
			||||
					case "limit": | 
				
			||||
						return Number(this.value) > 999 ? Number(this.value) >= 9999 ? | 
				
			||||
							Math.floor(this.value / 1e4 * 100) / 100 + "w" : Math.floor(this.value / | 
				
			||||
								1e3 * 100) / 100 + "k" : this.value | 
				
			||||
						break; | 
				
			||||
					default: | 
				
			||||
						return Number(this.value) | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
	$u-badge-primary: $u-primary !default; | 
				
			||||
	$u-badge-error: $u-error !default; | 
				
			||||
	$u-badge-success: $u-success !default; | 
				
			||||
	$u-badge-info: $u-info !default; | 
				
			||||
	$u-badge-warning: $u-warning !default; | 
				
			||||
	$u-badge-dot-radius: 100px !default; | 
				
			||||
	$u-badge-dot-size: 8px !default; | 
				
			||||
	$u-badge-dot-right: 4px !default; | 
				
			||||
	$u-badge-dot-top: 0 !default; | 
				
			||||
	$u-badge-text-font-size: 11px !default; | 
				
			||||
	$u-badge-text-right: 10px !default; | 
				
			||||
	$u-badge-text-padding: 2px 5px !default; | 
				
			||||
	$u-badge-text-align: center !default; | 
				
			||||
	$u-badge-text-color: #FFFFFF !default; | 
				
			||||
 | 
				
			||||
	.u-badge { | 
				
			||||
		border-top-right-radius: $u-badge-dot-radius; | 
				
			||||
		border-top-left-radius: $u-badge-dot-radius; | 
				
			||||
		border-bottom-left-radius: $u-badge-dot-radius; | 
				
			||||
		border-bottom-right-radius: $u-badge-dot-radius; | 
				
			||||
		@include flex; | 
				
			||||
		line-height: $u-badge-text-font-size; | 
				
			||||
		text-align: $u-badge-text-align; | 
				
			||||
		font-size: $u-badge-text-font-size; | 
				
			||||
		color: $u-badge-text-color; | 
				
			||||
 | 
				
			||||
		&--dot { | 
				
			||||
			height: $u-badge-dot-size; | 
				
			||||
			width: $u-badge-dot-size; | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		&--inverted { | 
				
			||||
			font-size: 13px; | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		&--not-dot { | 
				
			||||
			padding: $u-badge-text-padding; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--horn { | 
				
			||||
			border-bottom-left-radius: 0; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--primary { | 
				
			||||
			background-color: $u-badge-primary; | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		&--primary--inverted { | 
				
			||||
			color: $u-badge-primary; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--error { | 
				
			||||
			background-color: $u-badge-error; | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		&--error--inverted { | 
				
			||||
			color: $u-badge-error; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--success { | 
				
			||||
			background-color: $u-badge-success; | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		&--success--inverted { | 
				
			||||
			color: $u-badge-success; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--info { | 
				
			||||
			background-color: $u-badge-info; | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		&--info--inverted { | 
				
			||||
			color: $u-badge-info; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--warning { | 
				
			||||
			background-color: $u-badge-warning; | 
				
			||||
		} | 
				
			||||
		 | 
				
			||||
		&--warning--inverted { | 
				
			||||
			color: $u-badge-warning; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,46 @@
					 | 
				
			||||
$u-button-active-opacity:0.75 !default; | 
				
			||||
$u-button-loading-text-margin-left:4px !default; | 
				
			||||
$u-button-text-color: #FFFFFF !default; | 
				
			||||
$u-button-text-plain-error-color:$u-error !default; | 
				
			||||
$u-button-text-plain-warning-color:$u-warning !default; | 
				
			||||
$u-button-text-plain-success-color:$u-success !default; | 
				
			||||
$u-button-text-plain-info-color:$u-info !default; | 
				
			||||
$u-button-text-plain-primary-color:$u-primary !default; | 
				
			||||
.u-button { | 
				
			||||
	&--active { | 
				
			||||
		opacity: $u-button-active-opacity; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&--active--plain { | 
				
			||||
		background-color: rgb(217, 217, 217); | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&__loading-text { | 
				
			||||
		margin-left:$u-button-loading-text-margin-left; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&__text, | 
				
			||||
	&__loading-text { | 
				
			||||
		color:$u-button-text-color; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&__text--plain--error { | 
				
			||||
		color:$u-button-text-plain-error-color; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&__text--plain--warning { | 
				
			||||
		color:$u-button-text-plain-warning-color; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&__text--plain--success{ | 
				
			||||
		color:$u-button-text-plain-success-color; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&__text--plain--info { | 
				
			||||
		color:$u-button-text-plain-info-color; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&__text--plain--primary { | 
				
			||||
		color:$u-button-text-plain-primary-color; | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,161 @@
					 | 
				
			||||
/* | 
				
			||||
 * @Author       : LQ | 
				
			||||
 * @Description  : | 
				
			||||
 * @version      : 1.0 | 
				
			||||
 * @Date         : 2021-08-16 10:04:04 | 
				
			||||
 * @LastAuthor   : LQ | 
				
			||||
 * @lastTime     : 2021-08-16 10:04:24 | 
				
			||||
 * @FilePath     : /u-view2.0/uview-ui/components/u-button/props.js | 
				
			||||
 */ | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 是否细边框
 | 
				
			||||
        hairline: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.button.hairline | 
				
			||||
        }, | 
				
			||||
        // 按钮的预置样式,info,primary,error,warning,success
 | 
				
			||||
        type: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.type | 
				
			||||
        }, | 
				
			||||
        // 按钮尺寸,large,normal,small,mini
 | 
				
			||||
        size: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.size | 
				
			||||
        }, | 
				
			||||
        // 按钮形状,circle(两边为半圆),square(带圆角)
 | 
				
			||||
        shape: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.shape | 
				
			||||
        }, | 
				
			||||
        // 按钮是否镂空
 | 
				
			||||
        plain: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.button.plain | 
				
			||||
        }, | 
				
			||||
        // 是否禁止状态
 | 
				
			||||
        disabled: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.button.disabled | 
				
			||||
        }, | 
				
			||||
        // 是否加载中
 | 
				
			||||
        loading: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.button.loading | 
				
			||||
        }, | 
				
			||||
        // 加载中提示文字
 | 
				
			||||
        loadingText: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.button.loadingText | 
				
			||||
        }, | 
				
			||||
        // 加载状态图标类型
 | 
				
			||||
        loadingMode: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.loadingMode | 
				
			||||
        }, | 
				
			||||
        // 加载图标大小
 | 
				
			||||
        loadingSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.button.loadingSize | 
				
			||||
        }, | 
				
			||||
        // 开放能力,具体请看uniapp稳定关于button组件部分说明
 | 
				
			||||
        // https://uniapp.dcloud.io/component/button
 | 
				
			||||
        openType: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.openType | 
				
			||||
        }, | 
				
			||||
        // 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
 | 
				
			||||
        // 取值为submit(提交表单),reset(重置表单)
 | 
				
			||||
        formType: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.formType | 
				
			||||
        }, | 
				
			||||
        // 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效
 | 
				
			||||
        // 只微信小程序、QQ小程序有效
 | 
				
			||||
        appParameter: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.appParameter | 
				
			||||
        }, | 
				
			||||
        // 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
 | 
				
			||||
        hoverStopPropagation: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.button.hoverStopPropagation | 
				
			||||
        }, | 
				
			||||
        // 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效
 | 
				
			||||
        lang: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.lang | 
				
			||||
        }, | 
				
			||||
        // 会话来源,open-type="contact"时有效。只微信小程序有效
 | 
				
			||||
        sessionFrom: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.sessionFrom | 
				
			||||
        }, | 
				
			||||
        // 会话内消息卡片标题,open-type="contact"时有效
 | 
				
			||||
        // 默认当前标题,只微信小程序有效
 | 
				
			||||
        sendMessageTitle: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.sendMessageTitle | 
				
			||||
        }, | 
				
			||||
        // 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效
 | 
				
			||||
        // 默认当前分享路径,只微信小程序有效
 | 
				
			||||
        sendMessagePath: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.sendMessagePath | 
				
			||||
        }, | 
				
			||||
        // 会话内消息卡片图片,open-type="contact"时有效
 | 
				
			||||
        // 默认当前页面截图,只微信小程序有效
 | 
				
			||||
        sendMessageImg: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.sendMessageImg | 
				
			||||
        }, | 
				
			||||
        // 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
 | 
				
			||||
        // 用户点击后可以快速发送小程序消息,open-type="contact"时有效
 | 
				
			||||
        showMessageCard: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.button.showMessageCard | 
				
			||||
        }, | 
				
			||||
        // 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
 | 
				
			||||
        dataName: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.dataName | 
				
			||||
        }, | 
				
			||||
        // 节流,一定时间内只能触发一次
 | 
				
			||||
        throttleTime: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.button.throttleTime | 
				
			||||
        }, | 
				
			||||
        // 按住后多久出现点击态,单位毫秒
 | 
				
			||||
        hoverStartTime: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.button.hoverStartTime | 
				
			||||
        }, | 
				
			||||
        // 手指松开后点击态保留时间,单位毫秒
 | 
				
			||||
        hoverStayTime: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.button.hoverStayTime | 
				
			||||
        }, | 
				
			||||
        // 按钮文字,之所以通过props传入,是因为slot传入的话
 | 
				
			||||
        // nvue中无法控制文字的样式
 | 
				
			||||
        text: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.button.text | 
				
			||||
        }, | 
				
			||||
        // 按钮图标
 | 
				
			||||
        icon: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.icon | 
				
			||||
        }, | 
				
			||||
        // 按钮图标
 | 
				
			||||
        iconColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.icon | 
				
			||||
        }, | 
				
			||||
        // 按钮颜色,支持传入linear-gradient渐变色
 | 
				
			||||
        color: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.button.color | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,495 @@
					 | 
				
			||||
<template> | 
				
			||||
    <!-- #ifndef APP-NVUE --> | 
				
			||||
    <button | 
				
			||||
        :hover-start-time="Number(hoverStartTime)" | 
				
			||||
        :hover-stay-time="Number(hoverStayTime)" | 
				
			||||
        :form-type="formType" | 
				
			||||
        :open-type="openType" | 
				
			||||
        :app-parameter="appParameter" | 
				
			||||
        :hover-stop-propagation="hoverStopPropagation" | 
				
			||||
        :send-message-title="sendMessageTitle" | 
				
			||||
        :send-message-path="sendMessagePath" | 
				
			||||
        :lang="lang" | 
				
			||||
        :data-name="dataName" | 
				
			||||
        :session-from="sessionFrom" | 
				
			||||
        :send-message-img="sendMessageImg" | 
				
			||||
        :show-message-card="showMessageCard" | 
				
			||||
        @getphonenumber="getphonenumber" | 
				
			||||
        @getuserinfo="getuserinfo" | 
				
			||||
        @error="error" | 
				
			||||
        @opensetting="opensetting" | 
				
			||||
        @launchapp="launchapp" | 
				
			||||
        @agreeprivacyauthorization="agreeprivacyauthorization" | 
				
			||||
        :hover-class="!disabled && !loading ? 'u-button--active' : ''" | 
				
			||||
        class="u-button u-reset-button" | 
				
			||||
        :style="[baseColor, $u.addStyle(customStyle)]" | 
				
			||||
        @tap="clickHandler" | 
				
			||||
        :class="bemClass" | 
				
			||||
    > | 
				
			||||
        <template v-if="loading"> | 
				
			||||
            <u-loading-icon | 
				
			||||
                :mode="loadingMode" | 
				
			||||
                :size="loadingSize * 1.15" | 
				
			||||
                :color="loadingColor" | 
				
			||||
            ></u-loading-icon> | 
				
			||||
            <text | 
				
			||||
                class="u-button__loading-text" | 
				
			||||
                :style="[{ fontSize: textSize + 'px' }]" | 
				
			||||
                >{{ loadingText || text }}</text | 
				
			||||
            > | 
				
			||||
        </template> | 
				
			||||
        <template v-else> | 
				
			||||
            <u-icon | 
				
			||||
                v-if="icon" | 
				
			||||
                :name="icon" | 
				
			||||
                :color="iconColorCom" | 
				
			||||
                :size="textSize * 1.35" | 
				
			||||
                :customStyle="{ marginRight: '2px' }" | 
				
			||||
            ></u-icon> | 
				
			||||
            <slot> | 
				
			||||
                <text | 
				
			||||
                    class="u-button__text" | 
				
			||||
                    :style="[{ fontSize: textSize + 'px' }]" | 
				
			||||
                    >{{ text }}</text | 
				
			||||
                > | 
				
			||||
            </slot> | 
				
			||||
        </template> | 
				
			||||
    </button> | 
				
			||||
    <!-- #endif --> | 
				
			||||
 | 
				
			||||
    <!-- #ifdef APP-NVUE --> | 
				
			||||
    <view | 
				
			||||
        :hover-start-time="Number(hoverStartTime)" | 
				
			||||
        :hover-stay-time="Number(hoverStayTime)" | 
				
			||||
        class="u-button" | 
				
			||||
        :hover-class=" | 
				
			||||
            !disabled && !loading && !color && (plain || type === 'info') | 
				
			||||
                ? 'u-button--active--plain' | 
				
			||||
                : !disabled && !loading && !plain | 
				
			||||
                ? 'u-button--active' | 
				
			||||
                : '' | 
				
			||||
        " | 
				
			||||
        @tap="clickHandler" | 
				
			||||
        :class="bemClass" | 
				
			||||
        :style="[baseColor, $u.addStyle(customStyle)]" | 
				
			||||
    > | 
				
			||||
        <template v-if="loading"> | 
				
			||||
            <u-loading-icon | 
				
			||||
                :mode="loadingMode" | 
				
			||||
                :size="loadingSize * 1.15" | 
				
			||||
                :color="loadingColor" | 
				
			||||
            ></u-loading-icon> | 
				
			||||
            <text | 
				
			||||
                class="u-button__loading-text" | 
				
			||||
                :style="[nvueTextStyle]" | 
				
			||||
                :class="[plain && `u-button__text--plain--${type}`]" | 
				
			||||
                >{{ loadingText || text }}</text | 
				
			||||
            > | 
				
			||||
        </template> | 
				
			||||
        <template v-else> | 
				
			||||
            <u-icon | 
				
			||||
                v-if="icon" | 
				
			||||
                :name="icon" | 
				
			||||
                :color="iconColorCom" | 
				
			||||
                :size="textSize * 1.35" | 
				
			||||
            ></u-icon> | 
				
			||||
            <text | 
				
			||||
                class="u-button__text" | 
				
			||||
                :style="[ | 
				
			||||
                    { | 
				
			||||
                        marginLeft: icon ? '2px' : 0, | 
				
			||||
                    }, | 
				
			||||
                    nvueTextStyle, | 
				
			||||
                ]" | 
				
			||||
                :class="[plain && `u-button__text--plain--${type}`]" | 
				
			||||
                >{{ text }}</text | 
				
			||||
            > | 
				
			||||
        </template> | 
				
			||||
    </view> | 
				
			||||
    <!-- #endif --> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
import button from "../../libs/mixin/button.js"; | 
				
			||||
import openType from "../../libs/mixin/openType.js"; | 
				
			||||
import props from "./props.js"; | 
				
			||||
/** | 
				
			||||
 * button 按钮 | 
				
			||||
 * @description Button 按钮 | 
				
			||||
 * @tutorial https://www.uviewui.com/components/button.html | 
				
			||||
 * | 
				
			||||
 * @property {Boolean}			hairline				是否显示按钮的细边框 (默认 true ) | 
				
			||||
 * @property {String}			type					按钮的预置样式,info,primary,error,warning,success (默认 'info' ) | 
				
			||||
 * @property {String}			size					按钮尺寸,large,normal,mini (默认 normal) | 
				
			||||
 * @property {String}			shape					按钮形状,circle(两边为半圆),square(带圆角) (默认 'square' ) | 
				
			||||
 * @property {Boolean}			plain					按钮是否镂空,背景色透明 (默认 false) | 
				
			||||
 * @property {Boolean}			disabled				是否禁用 (默认 false) | 
				
			||||
 * @property {Boolean}			loading					按钮名称前是否带 loading 图标(App-nvue 平台,在 ios 上为雪花,Android上为圆圈) (默认 false) | 
				
			||||
 * @property {String | Number}	loadingText				加载中提示文字 | 
				
			||||
 * @property {String}			loadingMode				加载状态图标类型 (默认 'spinner' ) | 
				
			||||
 * @property {String | Number}	loadingSize				加载图标大小 (默认 15 ) | 
				
			||||
 * @property {String}			openType				开放能力,具体请看uniapp稳定关于button组件部分说明 | 
				
			||||
 * @property {String}			formType				用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件 | 
				
			||||
 * @property {String}			appParameter			打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效 (注:只微信小程序、QQ小程序有效) | 
				
			||||
 * @property {Boolean}			hoverStopPropagation	指定是否阻止本节点的祖先节点出现点击态,微信小程序有效(默认 true ) | 
				
			||||
 * @property {String}			lang					指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文(默认 en ) | 
				
			||||
 * @property {String}			sessionFrom				会话来源,openType="contact"时有效 | 
				
			||||
 * @property {String}			sendMessageTitle		会话内消息卡片标题,openType="contact"时有效 | 
				
			||||
 * @property {String}			sendMessagePath			会话内消息卡片点击跳转小程序路径,openType="contact"时有效 | 
				
			||||
 * @property {String}			sendMessageImg			会话内消息卡片图片,openType="contact"时有效 | 
				
			||||
 * @property {Boolean}			showMessageCard			是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效(默认false) | 
				
			||||
 * @property {String}			dataName				额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取 | 
				
			||||
 * @property {String | Number}	throttleTime			节流,一定时间内只能触发一次 (默认 0 ) | 
				
			||||
 * @property {String | Number}	hoverStartTime			按住后多久出现点击态,单位毫秒 (默认 0 ) | 
				
			||||
 * @property {String | Number}	hoverStayTime			手指松开后点击态保留时间,单位毫秒 (默认 200 ) | 
				
			||||
 * @property {String | Number}	text					按钮文字,之所以通过props传入,是因为slot传入的话(注:nvue中无法控制文字的样式) | 
				
			||||
 * @property {String}			icon					按钮图标 | 
				
			||||
 * @property {String}			iconColor				按钮图标颜色 | 
				
			||||
 * @property {String}			color					按钮颜色,支持传入linear-gradient渐变色 | 
				
			||||
 * @property {Object}			customStyle				定义需要用到的外部样式 | 
				
			||||
 * | 
				
			||||
 * @event {Function}	click			非禁止并且非加载中,才能点击 | 
				
			||||
 * @event {Function}	getphonenumber	open-type="getPhoneNumber"时有效 | 
				
			||||
 * @event {Function}	getuserinfo		用户点击该按钮时,会返回获取到的用户信息,从返回参数的detail中获取到的值同uni.getUserInfo | 
				
			||||
 * @event {Function}	error			当使用开放能力时,发生错误的回调 | 
				
			||||
 * @event {Function}	opensetting		在打开授权设置页并关闭后回调 | 
				
			||||
 * @event {Function}	launchapp		打开 APP 成功的回调 | 
				
			||||
 * @event {Function}	agreeprivacyauthorization	用户同意隐私协议事件回调 | 
				
			||||
 * @example <u-button>月落</u-button> | 
				
			||||
 */ | 
				
			||||
export default { | 
				
			||||
    name: "u-button", | 
				
			||||
    // #ifdef MP | 
				
			||||
    mixins: [uni.$u.mpMixin, uni.$u.mixin, button, openType, props], | 
				
			||||
    // #endif | 
				
			||||
    // #ifndef MP | 
				
			||||
    mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
    // #endif | 
				
			||||
    data() { | 
				
			||||
        return {}; | 
				
			||||
    }, | 
				
			||||
    computed: { | 
				
			||||
        // 生成bem风格的类名 | 
				
			||||
        bemClass() { | 
				
			||||
            // this.bem为一个computed变量,在mixin中 | 
				
			||||
            if (!this.color) { | 
				
			||||
                return this.bem( | 
				
			||||
                    "button", | 
				
			||||
                    ["type", "shape", "size"], | 
				
			||||
                    ["disabled", "plain", "hairline"] | 
				
			||||
                ); | 
				
			||||
            } else { | 
				
			||||
                // 由于nvue的原因,在有color参数时,不需要传入type,否则会生成type相关的类型,影响最终的样式 | 
				
			||||
                return this.bem( | 
				
			||||
                    "button", | 
				
			||||
                    ["shape", "size"], | 
				
			||||
                    ["disabled", "plain", "hairline"] | 
				
			||||
                ); | 
				
			||||
            } | 
				
			||||
        }, | 
				
			||||
        loadingColor() { | 
				
			||||
            if (this.plain) { | 
				
			||||
                // 如果有设置color值,则用color值,否则使用type主题颜色 | 
				
			||||
                return this.color | 
				
			||||
                    ? this.color | 
				
			||||
                    : uni.$u.config.color[`u-${this.type}`]; | 
				
			||||
            } | 
				
			||||
            if (this.type === "info") { | 
				
			||||
                return "#c9c9c9"; | 
				
			||||
            } | 
				
			||||
            return "rgb(200, 200, 200)"; | 
				
			||||
        }, | 
				
			||||
        iconColorCom() { | 
				
			||||
            // 如果是镂空状态,设置了color就用color值,否则使用主题颜色, | 
				
			||||
            // u-icon的color能接受一个主题颜色的值 | 
				
			||||
			if (this.iconColor) return this.iconColor; | 
				
			||||
			if (this.plain) { | 
				
			||||
                return this.color ? this.color : this.type; | 
				
			||||
            } else { | 
				
			||||
                return this.type === "info" ? "#000000" : "#ffffff"; | 
				
			||||
            } | 
				
			||||
        }, | 
				
			||||
        baseColor() { | 
				
			||||
            let style = {}; | 
				
			||||
            if (this.color) { | 
				
			||||
                // 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色 | 
				
			||||
                style.color = this.plain ? this.color : "white"; | 
				
			||||
                if (!this.plain) { | 
				
			||||
                    // 非镂空,背景色使用自定义的颜色 | 
				
			||||
                    style["background-color"] = this.color; | 
				
			||||
                } | 
				
			||||
                if (this.color.indexOf("gradient") !== -1) { | 
				
			||||
                    // 如果自定义的颜色为渐变色,不显示边框,以及通过backgroundImage设置渐变色 | 
				
			||||
                    // weex文档说明可以写borderWidth的形式,为什么这里需要分开写? | 
				
			||||
                    // 因为weex是阿里巴巴为了部门业绩考核而做的你懂的东西,所以需要这么写才有效 | 
				
			||||
                    style.borderTopWidth = 0; | 
				
			||||
                    style.borderRightWidth = 0; | 
				
			||||
                    style.borderBottomWidth = 0; | 
				
			||||
                    style.borderLeftWidth = 0; | 
				
			||||
                    if (!this.plain) { | 
				
			||||
                        style.backgroundImage = this.color; | 
				
			||||
                    } | 
				
			||||
                } else { | 
				
			||||
                    // 非渐变色,则设置边框相关的属性 | 
				
			||||
                    style.borderColor = this.color; | 
				
			||||
                    style.borderWidth = "1px"; | 
				
			||||
                    style.borderStyle = "solid"; | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
            return style; | 
				
			||||
        }, | 
				
			||||
        // nvue版本按钮的字体不会继承父组件的颜色,需要对每一个text组件进行单独的设置 | 
				
			||||
        nvueTextStyle() { | 
				
			||||
            let style = {}; | 
				
			||||
            // 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色 | 
				
			||||
            if (this.type === "info") { | 
				
			||||
                style.color = "#323233"; | 
				
			||||
            } | 
				
			||||
            if (this.color) { | 
				
			||||
                style.color = this.plain ? this.color : "white"; | 
				
			||||
            } | 
				
			||||
            style.fontSize = this.textSize + "px"; | 
				
			||||
            return style; | 
				
			||||
        }, | 
				
			||||
        // 字体大小 | 
				
			||||
        textSize() { | 
				
			||||
            let fontSize = 14, | 
				
			||||
                { size } = this; | 
				
			||||
            if (size === "large") fontSize = 16; | 
				
			||||
            if (size === "normal") fontSize = 14; | 
				
			||||
            if (size === "small") fontSize = 12; | 
				
			||||
            if (size === "mini") fontSize = 10; | 
				
			||||
            return fontSize; | 
				
			||||
        }, | 
				
			||||
    }, | 
				
			||||
    methods: { | 
				
			||||
        clickHandler() { | 
				
			||||
            // 非禁止并且非加载中,才能点击 | 
				
			||||
            if (!this.disabled && !this.loading) { | 
				
			||||
				// 进行节流控制,每this.throttle毫秒内,只在开始处执行 | 
				
			||||
				uni.$u.throttle(() => { | 
				
			||||
					this.$emit("click"); | 
				
			||||
				}, this.throttleTime); | 
				
			||||
            } | 
				
			||||
        }, | 
				
			||||
        // 下面为对接uniapp官方按钮开放能力事件回调的对接 | 
				
			||||
        getphonenumber(res) { | 
				
			||||
            this.$emit("getphonenumber", res); | 
				
			||||
        }, | 
				
			||||
        getuserinfo(res) { | 
				
			||||
            this.$emit("getuserinfo", res); | 
				
			||||
        }, | 
				
			||||
        error(res) { | 
				
			||||
            this.$emit("error", res); | 
				
			||||
        }, | 
				
			||||
        opensetting(res) { | 
				
			||||
            this.$emit("opensetting", res); | 
				
			||||
        }, | 
				
			||||
        launchapp(res) { | 
				
			||||
            this.$emit("launchapp", res); | 
				
			||||
        }, | 
				
			||||
        agreeprivacyauthorization(res) { | 
				
			||||
            this.$emit("agreeprivacyauthorization", res); | 
				
			||||
        }, | 
				
			||||
    }, | 
				
			||||
}; | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
/* #ifndef APP-NVUE */ | 
				
			||||
@import "./vue.scss"; | 
				
			||||
/* #endif */ | 
				
			||||
 | 
				
			||||
/* #ifdef APP-NVUE */ | 
				
			||||
@import "./nvue.scss"; | 
				
			||||
/* #endif */ | 
				
			||||
 | 
				
			||||
$u-button-u-button-height: 40px !default; | 
				
			||||
$u-button-text-font-size: 15px !default; | 
				
			||||
$u-button-loading-text-font-size: 15px !default; | 
				
			||||
$u-button-loading-text-margin-left: 4px !default; | 
				
			||||
$u-button-large-width: 100% !default; | 
				
			||||
$u-button-large-height: 50px !default; | 
				
			||||
$u-button-normal-padding: 0 12px !default; | 
				
			||||
$u-button-large-padding: 0 15px !default; | 
				
			||||
$u-button-normal-font-size: 14px !default; | 
				
			||||
$u-button-small-min-width: 60px !default; | 
				
			||||
$u-button-small-height: 30px !default; | 
				
			||||
$u-button-small-padding: 0px 8px !default; | 
				
			||||
$u-button-mini-padding: 0px 8px !default; | 
				
			||||
$u-button-small-font-size: 12px !default; | 
				
			||||
$u-button-mini-height: 22px !default; | 
				
			||||
$u-button-mini-font-size: 10px !default; | 
				
			||||
$u-button-mini-min-width: 50px !default; | 
				
			||||
$u-button-disabled-opacity: 0.5 !default; | 
				
			||||
$u-button-info-color: #323233 !default; | 
				
			||||
$u-button-info-background-color: #fff !default; | 
				
			||||
$u-button-info-border-color: #ebedf0 !default; | 
				
			||||
$u-button-info-border-width: 1px !default; | 
				
			||||
$u-button-info-border-style: solid !default; | 
				
			||||
$u-button-success-color: #fff !default; | 
				
			||||
$u-button-success-background-color: $u-success !default; | 
				
			||||
$u-button-success-border-color: $u-button-success-background-color !default; | 
				
			||||
$u-button-success-border-width: 1px !default; | 
				
			||||
$u-button-success-border-style: solid !default; | 
				
			||||
$u-button-primary-color: #fff !default; | 
				
			||||
$u-button-primary-background-color: $u-primary !default; | 
				
			||||
$u-button-primary-border-color: $u-button-primary-background-color !default; | 
				
			||||
$u-button-primary-border-width: 1px !default; | 
				
			||||
$u-button-primary-border-style: solid !default; | 
				
			||||
$u-button-error-color: #fff !default; | 
				
			||||
$u-button-error-background-color: $u-error !default; | 
				
			||||
$u-button-error-border-color: $u-button-error-background-color !default; | 
				
			||||
$u-button-error-border-width: 1px !default; | 
				
			||||
$u-button-error-border-style: solid !default; | 
				
			||||
$u-button-warning-color: #fff !default; | 
				
			||||
$u-button-warning-background-color: $u-warning !default; | 
				
			||||
$u-button-warning-border-color: $u-button-warning-background-color !default; | 
				
			||||
$u-button-warning-border-width: 1px !default; | 
				
			||||
$u-button-warning-border-style: solid !default; | 
				
			||||
$u-button-block-width: 100% !default; | 
				
			||||
$u-button-circle-border-top-right-radius: 100px !default; | 
				
			||||
$u-button-circle-border-top-left-radius: 100px !default; | 
				
			||||
$u-button-circle-border-bottom-left-radius: 100px !default; | 
				
			||||
$u-button-circle-border-bottom-right-radius: 100px !default; | 
				
			||||
$u-button-square-border-top-right-radius: 3px !default; | 
				
			||||
$u-button-square-border-top-left-radius: 3px !default; | 
				
			||||
$u-button-square-border-bottom-left-radius: 3px !default; | 
				
			||||
$u-button-square-border-bottom-right-radius: 3px !default; | 
				
			||||
$u-button-icon-min-width: 1em !default; | 
				
			||||
$u-button-plain-background-color: #fff !default; | 
				
			||||
$u-button-hairline-border-width: 0.5px !default; | 
				
			||||
 | 
				
			||||
.u-button { | 
				
			||||
    height: $u-button-u-button-height; | 
				
			||||
    position: relative; | 
				
			||||
    align-items: center; | 
				
			||||
    justify-content: center; | 
				
			||||
    @include flex; | 
				
			||||
    /* #ifndef APP-NVUE */ | 
				
			||||
    box-sizing: border-box; | 
				
			||||
    /* #endif */ | 
				
			||||
    flex-direction: row; | 
				
			||||
 | 
				
			||||
    &__text { | 
				
			||||
        font-size: $u-button-text-font-size; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &__loading-text { | 
				
			||||
        font-size: $u-button-loading-text-font-size; | 
				
			||||
        margin-left: $u-button-loading-text-margin-left; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--large { | 
				
			||||
        /* #ifndef APP-NVUE */ | 
				
			||||
        width: $u-button-large-width; | 
				
			||||
        /* #endif */ | 
				
			||||
        height: $u-button-large-height; | 
				
			||||
        padding: $u-button-large-padding; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--normal { | 
				
			||||
        padding: $u-button-normal-padding; | 
				
			||||
        font-size: $u-button-normal-font-size; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--small { | 
				
			||||
        /* #ifndef APP-NVUE */ | 
				
			||||
        min-width: $u-button-small-min-width; | 
				
			||||
        /* #endif */ | 
				
			||||
        height: $u-button-small-height; | 
				
			||||
        padding: $u-button-small-padding; | 
				
			||||
        font-size: $u-button-small-font-size; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--mini { | 
				
			||||
        height: $u-button-mini-height; | 
				
			||||
        font-size: $u-button-mini-font-size; | 
				
			||||
        /* #ifndef APP-NVUE */ | 
				
			||||
        min-width: $u-button-mini-min-width; | 
				
			||||
        /* #endif */ | 
				
			||||
        padding: $u-button-mini-padding; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--disabled { | 
				
			||||
        opacity: $u-button-disabled-opacity; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--info { | 
				
			||||
        color: $u-button-info-color; | 
				
			||||
        background-color: $u-button-info-background-color; | 
				
			||||
        border-color: $u-button-info-border-color; | 
				
			||||
        border-width: $u-button-info-border-width; | 
				
			||||
        border-style: $u-button-info-border-style; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--success { | 
				
			||||
        color: $u-button-success-color; | 
				
			||||
        background-color: $u-button-success-background-color; | 
				
			||||
        border-color: $u-button-success-border-color; | 
				
			||||
        border-width: $u-button-success-border-width; | 
				
			||||
        border-style: $u-button-success-border-style; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--primary { | 
				
			||||
        color: $u-button-primary-color; | 
				
			||||
        background-color: $u-button-primary-background-color; | 
				
			||||
        border-color: $u-button-primary-border-color; | 
				
			||||
        border-width: $u-button-primary-border-width; | 
				
			||||
        border-style: $u-button-primary-border-style; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--error { | 
				
			||||
        color: $u-button-error-color; | 
				
			||||
        background-color: $u-button-error-background-color; | 
				
			||||
        border-color: $u-button-error-border-color; | 
				
			||||
        border-width: $u-button-error-border-width; | 
				
			||||
        border-style: $u-button-error-border-style; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--warning { | 
				
			||||
        color: $u-button-warning-color; | 
				
			||||
        background-color: $u-button-warning-background-color; | 
				
			||||
        border-color: $u-button-warning-border-color; | 
				
			||||
        border-width: $u-button-warning-border-width; | 
				
			||||
        border-style: $u-button-warning-border-style; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--block { | 
				
			||||
        @include flex; | 
				
			||||
        width: $u-button-block-width; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--circle { | 
				
			||||
        border-top-right-radius: $u-button-circle-border-top-right-radius; | 
				
			||||
        border-top-left-radius: $u-button-circle-border-top-left-radius; | 
				
			||||
        border-bottom-left-radius: $u-button-circle-border-bottom-left-radius; | 
				
			||||
        border-bottom-right-radius: $u-button-circle-border-bottom-right-radius; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--square { | 
				
			||||
        border-bottom-left-radius: $u-button-square-border-top-right-radius; | 
				
			||||
        border-bottom-right-radius: $u-button-square-border-top-left-radius; | 
				
			||||
        border-top-left-radius: $u-button-square-border-bottom-left-radius; | 
				
			||||
        border-top-right-radius: $u-button-square-border-bottom-right-radius; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &__icon { | 
				
			||||
        /* #ifndef APP-NVUE */ | 
				
			||||
        min-width: $u-button-icon-min-width; | 
				
			||||
        line-height: inherit !important; | 
				
			||||
        vertical-align: top; | 
				
			||||
        /* #endif */ | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--plain { | 
				
			||||
        background-color: $u-button-plain-background-color; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    &--hairline { | 
				
			||||
        border-width: $u-button-hairline-border-width !important; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,80 @@
					 | 
				
			||||
// nvue下hover-class无效 | 
				
			||||
$u-button-before-top:50% !default; | 
				
			||||
$u-button-before-left:50% !default; | 
				
			||||
$u-button-before-width:100% !default; | 
				
			||||
$u-button-before-height:100% !default; | 
				
			||||
$u-button-before-transform:translate(-50%, -50%) !default; | 
				
			||||
$u-button-before-opacity:0 !default; | 
				
			||||
$u-button-before-background-color:#000 !default; | 
				
			||||
$u-button-before-border-color:#000 !default; | 
				
			||||
$u-button-active-before-opacity:.15 !default; | 
				
			||||
$u-button-icon-margin-left:4px !default; | 
				
			||||
$u-button-plain-u-button-info-color:$u-info; | 
				
			||||
$u-button-plain-u-button-success-color:$u-success; | 
				
			||||
$u-button-plain-u-button-error-color:$u-error; | 
				
			||||
$u-button-plain-u-button-warning-color:$u-error; | 
				
			||||
 | 
				
			||||
.u-button { | 
				
			||||
	width: 100%; | 
				
			||||
	 | 
				
			||||
	&__text { | 
				
			||||
		white-space: nowrap; | 
				
			||||
		line-height: 1; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&:before { | 
				
			||||
		position: absolute; | 
				
			||||
		top:$u-button-before-top; | 
				
			||||
		left:$u-button-before-left; | 
				
			||||
		width:$u-button-before-width; | 
				
			||||
		height:$u-button-before-height; | 
				
			||||
		border: inherit; | 
				
			||||
		border-radius: inherit; | 
				
			||||
		transform:$u-button-before-transform; | 
				
			||||
		opacity:$u-button-before-opacity; | 
				
			||||
		content: " "; | 
				
			||||
		background-color:$u-button-before-background-color; | 
				
			||||
		border-color:$u-button-before-border-color; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&--active { | 
				
			||||
		&:before { | 
				
			||||
			opacity: .15 | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&__icon+&__text:not(:empty), | 
				
			||||
	&__loading-text { | 
				
			||||
		margin-left:$u-button-icon-margin-left; | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&--plain { | 
				
			||||
		&.u-button--primary { | 
				
			||||
			color: $u-primary; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&--plain { | 
				
			||||
		&.u-button--info { | 
				
			||||
			color:$u-button-plain-u-button-info-color; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&--plain { | 
				
			||||
		&.u-button--success { | 
				
			||||
			color:$u-button-plain-u-button-success-color; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&--plain { | 
				
			||||
		&.u-button--error { | 
				
			||||
			color:$u-button-plain-u-button-error-color; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	&--plain { | 
				
			||||
		&.u-button--warning { | 
				
			||||
			color:$u-button-plain-u-button-warning-color; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
@ -0,0 +1,99 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="u-calendar-header u-border-bottom"> | 
				
			||||
		<text | 
				
			||||
			class="u-calendar-header__title" | 
				
			||||
			v-if="showTitle" | 
				
			||||
		>{{ title }}</text> | 
				
			||||
		<text | 
				
			||||
			class="u-calendar-header__subtitle" | 
				
			||||
			v-if="showSubtitle" | 
				
			||||
		>{{ subtitle }}</text> | 
				
			||||
		<view class="u-calendar-header__weekdays"> | 
				
			||||
			<text class="u-calendar-header__weekdays__weekday">一</text> | 
				
			||||
			<text class="u-calendar-header__weekdays__weekday">二</text> | 
				
			||||
			<text class="u-calendar-header__weekdays__weekday">三</text> | 
				
			||||
			<text class="u-calendar-header__weekdays__weekday">四</text> | 
				
			||||
			<text class="u-calendar-header__weekdays__weekday">五</text> | 
				
			||||
			<text class="u-calendar-header__weekdays__weekday">六</text> | 
				
			||||
			<text class="u-calendar-header__weekdays__weekday">日</text> | 
				
			||||
		</view> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	export default { | 
				
			||||
		name: 'u-calendar-header', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin], | 
				
			||||
		props: { | 
				
			||||
			// 标题 | 
				
			||||
			title: { | 
				
			||||
				type: String, | 
				
			||||
				default: '' | 
				
			||||
			}, | 
				
			||||
			// 副标题 | 
				
			||||
			subtitle: { | 
				
			||||
				type: String, | 
				
			||||
				default: '' | 
				
			||||
			}, | 
				
			||||
			// 是否显示标题 | 
				
			||||
			showTitle: { | 
				
			||||
				type: Boolean, | 
				
			||||
				default: true | 
				
			||||
			}, | 
				
			||||
			// 是否显示副标题 | 
				
			||||
			showSubtitle: { | 
				
			||||
				type: Boolean, | 
				
			||||
				default: true | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
 | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			name() { | 
				
			||||
 | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
	.u-calendar-header { | 
				
			||||
		padding-bottom: 4px; | 
				
			||||
 | 
				
			||||
		&__title { | 
				
			||||
			font-size: 16px; | 
				
			||||
			color: $u-main-color; | 
				
			||||
			text-align: center; | 
				
			||||
			height: 42px; | 
				
			||||
			line-height: 42px; | 
				
			||||
			font-weight: bold; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__subtitle { | 
				
			||||
			font-size: 14px; | 
				
			||||
			color: $u-main-color; | 
				
			||||
			height: 40px; | 
				
			||||
			text-align: center; | 
				
			||||
			line-height: 40px; | 
				
			||||
			font-weight: bold; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__weekdays { | 
				
			||||
			@include flex; | 
				
			||||
			justify-content: space-between; | 
				
			||||
 | 
				
			||||
			&__weekday { | 
				
			||||
				font-size: 13px; | 
				
			||||
				color: $u-main-color; | 
				
			||||
				line-height: 30px; | 
				
			||||
				flex: 1; | 
				
			||||
				text-align: center; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,579 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="u-calendar-month-wrapper" ref="u-calendar-month-wrapper"> | 
				
			||||
		<view v-for="(item, index) in months" :key="index" :class="[`u-calendar-month-${index}`]" | 
				
			||||
			:ref="`u-calendar-month-${index}`" :id="`month-${index}`"> | 
				
			||||
			<text v-if="index !== 0" class="u-calendar-month__title">{{ item.year }}年{{ item.month }}月</text> | 
				
			||||
			<view class="u-calendar-month__days"> | 
				
			||||
				<view v-if="showMark" class="u-calendar-month__days__month-mark-wrapper"> | 
				
			||||
					<text class="u-calendar-month__days__month-mark-wrapper__text">{{ item.month }}</text> | 
				
			||||
				</view> | 
				
			||||
				<view class="u-calendar-month__days__day" v-for="(item1, index1) in item.date" :key="index1" | 
				
			||||
					:style="[dayStyle(index, index1, item1)]" @tap="clickHandler(index, index1, item1)" | 
				
			||||
					:class="[item1.selected && 'u-calendar-month__days__day__select--selected']"> | 
				
			||||
					<view class="u-calendar-month__days__day__select" :style="[daySelectStyle(index, index1, item1)]"> | 
				
			||||
						<text class="u-calendar-month__days__day__select__info" | 
				
			||||
							:class="[item1.disabled && 'u-calendar-month__days__day__select__info--disabled']" | 
				
			||||
							:style="[textStyle(item1)]">{{ item1.day }}</text> | 
				
			||||
						<text v-if="getBottomInfo(index, index1, item1)" | 
				
			||||
							class="u-calendar-month__days__day__select__buttom-info" | 
				
			||||
							:class="[item1.disabled && 'u-calendar-month__days__day__select__buttom-info--disabled']" | 
				
			||||
							:style="[textStyle(item1)]">{{ getBottomInfo(index, index1, item1) }}</text> | 
				
			||||
						<text v-if="item1.dot" class="u-calendar-month__days__day__select__dot"></text> | 
				
			||||
					</view> | 
				
			||||
				</view> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	// #ifdef APP-NVUE | 
				
			||||
	// 由于nvue不支持百分比单位,需要查询宽度来计算每个日期的宽度 | 
				
			||||
	const dom = uni.requireNativePlugin('dom') | 
				
			||||
	// #endif | 
				
			||||
	import dayjs from '../../libs/util/dayjs.js'; | 
				
			||||
	export default { | 
				
			||||
		name: 'u-calendar-month', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin], | 
				
			||||
		props: { | 
				
			||||
			// 是否显示月份背景色 | 
				
			||||
			showMark: { | 
				
			||||
				type: Boolean, | 
				
			||||
				default: true | 
				
			||||
			}, | 
				
			||||
			// 主题色,对底部按钮和选中日期有效 | 
				
			||||
			color: { | 
				
			||||
				type: String, | 
				
			||||
				default: '#3c9cff' | 
				
			||||
			}, | 
				
			||||
			// 月份数据 | 
				
			||||
			months: { | 
				
			||||
				type: Array, | 
				
			||||
				default: () => [] | 
				
			||||
			}, | 
				
			||||
			// 日期选择类型 | 
				
			||||
			mode: { | 
				
			||||
				type: String, | 
				
			||||
				default: 'single' | 
				
			||||
			}, | 
				
			||||
			// 日期行高 | 
				
			||||
			rowHeight: { | 
				
			||||
				type: [String, Number], | 
				
			||||
				default: 58 | 
				
			||||
			}, | 
				
			||||
			// mode=multiple时,最多可选多少个日期 | 
				
			||||
			maxCount: { | 
				
			||||
				type: [String, Number], | 
				
			||||
				default: Infinity | 
				
			||||
			}, | 
				
			||||
			// mode=range时,第一个日期底部的提示文字 | 
				
			||||
			startText: { | 
				
			||||
				type: String, | 
				
			||||
				default: '开始' | 
				
			||||
			}, | 
				
			||||
			// mode=range时,最后一个日期底部的提示文字 | 
				
			||||
			endText: { | 
				
			||||
				type: String, | 
				
			||||
				default: '结束' | 
				
			||||
			}, | 
				
			||||
			// 默认选中的日期,mode为multiple或range是必须为数组格式 | 
				
			||||
			defaultDate: { | 
				
			||||
				type: [Array, String, Date], | 
				
			||||
				default: null | 
				
			||||
			}, | 
				
			||||
			// 最小的可选日期 | 
				
			||||
			minDate: { | 
				
			||||
				type: [String, Number], | 
				
			||||
				default: 0 | 
				
			||||
			}, | 
				
			||||
			// 最大可选日期 | 
				
			||||
			maxDate: { | 
				
			||||
				type: [String, Number], | 
				
			||||
				default: 0 | 
				
			||||
			}, | 
				
			||||
			// 如果没有设置maxDate,则往后推多少个月 | 
				
			||||
			maxMonth: { | 
				
			||||
				type: [String, Number], | 
				
			||||
				default: 2 | 
				
			||||
			}, | 
				
			||||
			// 是否为只读状态,只读状态下禁止选择日期 | 
				
			||||
			readonly: { | 
				
			||||
				type: Boolean, | 
				
			||||
				default: uni.$u.props.calendar.readonly | 
				
			||||
			}, | 
				
			||||
			// 日期区间最多可选天数,默认无限制,mode = range时有效 | 
				
			||||
			maxRange: { | 
				
			||||
				type: [Number, String], | 
				
			||||
				default: Infinity | 
				
			||||
			}, | 
				
			||||
			// 范围选择超过最多可选天数时的提示文案,mode = range时有效 | 
				
			||||
			rangePrompt: { | 
				
			||||
				type: String, | 
				
			||||
				default: '' | 
				
			||||
			}, | 
				
			||||
			// 范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效 | 
				
			||||
			showRangePrompt: { | 
				
			||||
				type: Boolean, | 
				
			||||
				default: true | 
				
			||||
			}, | 
				
			||||
			// 是否允许日期范围的起止时间为同一天,mode = range时有效 | 
				
			||||
			allowSameDay: { | 
				
			||||
				type: Boolean, | 
				
			||||
				default: false | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				// 每个日期的宽度 | 
				
			||||
				width: 0, | 
				
			||||
				// 当前选中的日期item | 
				
			||||
				item: {}, | 
				
			||||
				selected: [] | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		watch: { | 
				
			||||
			selectedChange: { | 
				
			||||
				immediate: true, | 
				
			||||
				handler(n) { | 
				
			||||
					this.setDefaultDate() | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			// 多个条件的变化,会引起选中日期的变化,这里统一管理监听 | 
				
			||||
			selectedChange() { | 
				
			||||
				return [this.minDate, this.maxDate, this.defaultDate] | 
				
			||||
			}, | 
				
			||||
			dayStyle(index1, index2, item) { | 
				
			||||
				return (index1, index2, item) => { | 
				
			||||
					const style = {} | 
				
			||||
					let week = item.week | 
				
			||||
					// 不进行四舍五入的形式保留2位小数 | 
				
			||||
					const dayWidth = Number(parseFloat(this.width / 7).toFixed(3).slice(0, -1)) | 
				
			||||
					// 得出每个日期的宽度 | 
				
			||||
					// #ifdef APP-NVUE | 
				
			||||
					style.width = uni.$u.addUnit(dayWidth) | 
				
			||||
					// #endif | 
				
			||||
					style.height = uni.$u.addUnit(this.rowHeight) | 
				
			||||
					if (index2 === 0) { | 
				
			||||
						// 获取当前为星期几,如果为0,则为星期天,减一为每月第一天时,需要向左偏移的item个数 | 
				
			||||
						week = (week === 0 ? 7 : week) - 1 | 
				
			||||
						style.marginLeft = uni.$u.addUnit(week * dayWidth) | 
				
			||||
					} | 
				
			||||
					if (this.mode === 'range') { | 
				
			||||
						// 之所以需要这么写,是因为DCloud公司的iOS客户端的开发者能力有限导致的bug | 
				
			||||
						style.paddingLeft = 0 | 
				
			||||
						style.paddingRight = 0 | 
				
			||||
						style.paddingBottom = 0 | 
				
			||||
						style.paddingTop = 0 | 
				
			||||
					} | 
				
			||||
					return style | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			daySelectStyle() { | 
				
			||||
				return (index1, index2, item) => { | 
				
			||||
					let date = dayjs(item.date).format("YYYY-MM-DD"), | 
				
			||||
						style = {} | 
				
			||||
					// 判断date是否在selected数组中,因为月份可能会需要补0,所以使用dateSame判断,而不用数组的includes判断 | 
				
			||||
					if (this.selected.some(item => this.dateSame(item, date))) { | 
				
			||||
						style.backgroundColor = this.color | 
				
			||||
					} | 
				
			||||
					if (this.mode === 'single') { | 
				
			||||
						if (date === this.selected[0]) { | 
				
			||||
							// 因为需要对nvue的兼容,只能这么写,无法缩写,也无法通过类名控制等等 | 
				
			||||
							style.borderTopLeftRadius = '3px' | 
				
			||||
							style.borderBottomLeftRadius = '3px' | 
				
			||||
							style.borderTopRightRadius = '3px' | 
				
			||||
							style.borderBottomRightRadius = '3px' | 
				
			||||
						} | 
				
			||||
					} else if (this.mode === 'range') { | 
				
			||||
						if (this.selected.length >= 2) { | 
				
			||||
							const len = this.selected.length - 1 | 
				
			||||
							// 第一个日期设置左上角和左下角的圆角 | 
				
			||||
							if (this.dateSame(date, this.selected[0])) { | 
				
			||||
								style.borderTopLeftRadius = '3px' | 
				
			||||
								style.borderBottomLeftRadius = '3px' | 
				
			||||
							} | 
				
			||||
							// 最后一个日期设置右上角和右下角的圆角 | 
				
			||||
							if (this.dateSame(date, this.selected[len])) { | 
				
			||||
								style.borderTopRightRadius = '3px' | 
				
			||||
								style.borderBottomRightRadius = '3px' | 
				
			||||
							} | 
				
			||||
							// 处于第一和最后一个之间的日期,背景色设置为浅色,通过将对应颜色进行等分,再取其尾部的颜色值 | 
				
			||||
							if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this | 
				
			||||
									.selected[len]))) { | 
				
			||||
								style.backgroundColor = uni.$u.colorGradient(this.color, '#ffffff', 100)[90] | 
				
			||||
								// 增加一个透明度,让范围区间的背景色也能看到底部的mark水印字符 | 
				
			||||
								style.opacity = 0.7 | 
				
			||||
							} | 
				
			||||
						} else if (this.selected.length === 1) { | 
				
			||||
							// 之所以需要这么写,是因为DCloud公司的iOS客户端的开发者能力有限导致的bug | 
				
			||||
							// 进行还原操作,否则在nvue的iOS,uni-app有bug,会导致诡异的表现 | 
				
			||||
							style.borderTopLeftRadius = '3px' | 
				
			||||
							style.borderBottomLeftRadius = '3px' | 
				
			||||
						} | 
				
			||||
					} else { | 
				
			||||
						if (this.selected.some(item => this.dateSame(item, date))) { | 
				
			||||
							style.borderTopLeftRadius = '3px' | 
				
			||||
							style.borderBottomLeftRadius = '3px' | 
				
			||||
							style.borderTopRightRadius = '3px' | 
				
			||||
							style.borderBottomRightRadius = '3px' | 
				
			||||
						} | 
				
			||||
					} | 
				
			||||
					return style | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			// 某个日期是否被选中 | 
				
			||||
			textStyle() { | 
				
			||||
				return (item) => { | 
				
			||||
					const date = dayjs(item.date).format("YYYY-MM-DD"), | 
				
			||||
						style = {} | 
				
			||||
					// 选中的日期,提示文字设置白色 | 
				
			||||
					if (this.selected.some(item => this.dateSame(item, date))) { | 
				
			||||
						style.color = '#ffffff' | 
				
			||||
					} | 
				
			||||
					if (this.mode === 'range') { | 
				
			||||
						const len = this.selected.length - 1 | 
				
			||||
						// 如果是范围选择模式,第一个和最后一个之间的日期,文字颜色设置为高亮的主题色 | 
				
			||||
						if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this | 
				
			||||
								.selected[len]))) { | 
				
			||||
							style.color = this.color | 
				
			||||
						} | 
				
			||||
					} | 
				
			||||
					return style | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			// 获取底部的提示文字 | 
				
			||||
			getBottomInfo() { | 
				
			||||
				return (index1, index2, item) => { | 
				
			||||
					const date = dayjs(item.date).format("YYYY-MM-DD") | 
				
			||||
					const bottomInfo = item.bottomInfo | 
				
			||||
					// 当为日期范围模式时,且选择的日期个数大于0时 | 
				
			||||
					if (this.mode === 'range' && this.selected.length > 0) { | 
				
			||||
						if (this.selected.length === 1) { | 
				
			||||
							// 选择了一个日期时,如果当前日期为数组中的第一个日期,则显示底部文字为“开始” | 
				
			||||
							if (this.dateSame(date, this.selected[0])) return this.startText | 
				
			||||
							else return bottomInfo | 
				
			||||
						} else { | 
				
			||||
							const len = this.selected.length - 1 | 
				
			||||
							// 如果数组中的日期大于2个时,第一个和最后一个显示为开始和结束日期 | 
				
			||||
							if (this.dateSame(date, this.selected[0]) && this.dateSame(date, this.selected[1]) && | 
				
			||||
								len === 1) { | 
				
			||||
								// 如果长度为2,且第一个等于第二个日期,则提示语放在同一个item中 | 
				
			||||
								return `${this.startText}/${this.endText}` | 
				
			||||
							} else if (this.dateSame(date, this.selected[0])) { | 
				
			||||
								return this.startText | 
				
			||||
							} else if (this.dateSame(date, this.selected[len])) { | 
				
			||||
								return this.endText | 
				
			||||
							} else { | 
				
			||||
								return bottomInfo | 
				
			||||
							} | 
				
			||||
						} | 
				
			||||
					} else { | 
				
			||||
						return bottomInfo | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		mounted() { | 
				
			||||
			this.init() | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			init() { | 
				
			||||
				// 初始化默认选中 | 
				
			||||
				this.$emit('monthSelected', this.selected) | 
				
			||||
				this.$nextTick(() => { | 
				
			||||
					// 这里需要另一个延时,因为获取宽度后,会进行月份数据渲染,只有渲染完成之后,才有真正的高度 | 
				
			||||
					// 因为nvue下,$nextTick并不是100%可靠的 | 
				
			||||
					uni.$u.sleep(10).then(() => { | 
				
			||||
						this.getWrapperWidth() | 
				
			||||
						this.getMonthRect() | 
				
			||||
					}) | 
				
			||||
				}) | 
				
			||||
			}, | 
				
			||||
			// 判断两个日期是否相等 | 
				
			||||
			dateSame(date1, date2) { | 
				
			||||
				return dayjs(date1).isSame(dayjs(date2)) | 
				
			||||
			}, | 
				
			||||
			// 获取月份数据区域的宽度,因为nvue不支持百分比,所以无法通过css设置每个日期item的宽度 | 
				
			||||
			getWrapperWidth() { | 
				
			||||
				// #ifdef APP-NVUE | 
				
			||||
				dom.getComponentRect(this.$refs['u-calendar-month-wrapper'], res => { | 
				
			||||
					this.width = res.size.width | 
				
			||||
				}) | 
				
			||||
				// #endif | 
				
			||||
				// #ifndef APP-NVUE | 
				
			||||
				this.$uGetRect('.u-calendar-month-wrapper').then(size => { | 
				
			||||
					this.width = size.width | 
				
			||||
				}) | 
				
			||||
				// #endif | 
				
			||||
			}, | 
				
			||||
			getMonthRect() { | 
				
			||||
				// 获取每个月份数据的尺寸,用于父组件在scroll-view滚动事件中,监听当前滚动到了第几个月份 | 
				
			||||
				const promiseAllArr = this.months.map((item, index) => this.getMonthRectByPromise( | 
				
			||||
					`u-calendar-month-${index}`)) | 
				
			||||
				// 一次性返回 | 
				
			||||
				Promise.all(promiseAllArr).then( | 
				
			||||
					sizes => { | 
				
			||||
						let height = 1 | 
				
			||||
						const topArr = [] | 
				
			||||
						for (let i = 0; i < this.months.length; i++) { | 
				
			||||
							// 添加到months数组中,供scroll-view滚动事件中,判断当前滚动到哪个月份 | 
				
			||||
							topArr[i] = height | 
				
			||||
							height += sizes[i].height | 
				
			||||
						} | 
				
			||||
						// 由于微信下,无法通过this.months[i].top的形式(引用类型)去修改父组件的month的top值,所以使用事件形式对外发出 | 
				
			||||
						this.$emit('updateMonthTop', topArr) | 
				
			||||
					}) | 
				
			||||
			}, | 
				
			||||
			// 获取每个月份区域的尺寸 | 
				
			||||
			getMonthRectByPromise(el) { | 
				
			||||
				// #ifndef APP-NVUE | 
				
			||||
				// $uGetRect为uView自带的节点查询简化方法,详见文档介绍:https://www.uviewui.com/js/getRect.html | 
				
			||||
				// 组件内部一般用this.$uGetRect,对外的为uni.$u.getRect,二者功能一致,名称不同 | 
				
			||||
				return new Promise(resolve => { | 
				
			||||
					this.$uGetRect(`.${el}`).then(size => { | 
				
			||||
						resolve(size) | 
				
			||||
					}) | 
				
			||||
				}) | 
				
			||||
				// #endif | 
				
			||||
 | 
				
			||||
				// #ifdef APP-NVUE | 
				
			||||
				// nvue下,使用dom模块查询元素高度 | 
				
			||||
				// 返回一个promise,让调用此方法的主体能使用then回调 | 
				
			||||
				return new Promise(resolve => { | 
				
			||||
					dom.getComponentRect(this.$refs[el][0], res => { | 
				
			||||
						resolve(res.size) | 
				
			||||
					}) | 
				
			||||
				}) | 
				
			||||
				// #endif | 
				
			||||
			}, | 
				
			||||
			// 点击某一个日期 | 
				
			||||
			clickHandler(index1, index2, item) { | 
				
			||||
				if (this.readonly) { | 
				
			||||
					return; | 
				
			||||
				} | 
				
			||||
				this.item = item | 
				
			||||
				const date = dayjs(item.date).format("YYYY-MM-DD") | 
				
			||||
				if (item.disabled) return | 
				
			||||
				// 对上一次选择的日期数组进行深度克隆 | 
				
			||||
				let selected = uni.$u.deepClone(this.selected) | 
				
			||||
				if (this.mode === 'single') { | 
				
			||||
					// 单选情况下,让数组中的元素为当前点击的日期 | 
				
			||||
					selected = [date] | 
				
			||||
				} else if (this.mode === 'multiple') { | 
				
			||||
					if (selected.some(item => this.dateSame(item, date))) { | 
				
			||||
						// 如果点击的日期已在数组中,则进行移除操作,也就是达到反选的效果 | 
				
			||||
						const itemIndex = selected.findIndex(item => item === date) | 
				
			||||
						selected.splice(itemIndex, 1) | 
				
			||||
					} else { | 
				
			||||
						// 如果点击的日期不在数组中,且已有的长度小于总可选长度时,则添加到数组中去 | 
				
			||||
						if (selected.length < this.maxCount) selected.push(date) | 
				
			||||
					} | 
				
			||||
				} else { | 
				
			||||
					// 选择区间形式 | 
				
			||||
					if (selected.length === 0 || selected.length >= 2) { | 
				
			||||
						// 如果原来就为0或者大于2的长度,则当前点击的日期,就是开始日期 | 
				
			||||
						selected = [date] | 
				
			||||
					} else if (selected.length === 1) { | 
				
			||||
						// 如果已经选择了开始日期 | 
				
			||||
						const existsDate = selected[0] | 
				
			||||
						// 如果当前选择的日期小于上一次选择的日期,则当前的日期定为开始日期 | 
				
			||||
						if (dayjs(date).isBefore(existsDate)) { | 
				
			||||
							selected = [date] | 
				
			||||
						} else if (dayjs(date).isAfter(existsDate)) { | 
				
			||||
							// 当前日期减去最大可选的日期天数,如果大于起始时间,则进行提示 | 
				
			||||
							if(dayjs(dayjs(date).subtract(this.maxRange, 'day')).isAfter(dayjs(selected[0])) && this.showRangePrompt) { | 
				
			||||
								if(this.rangePrompt) { | 
				
			||||
									uni.$u.toast(this.rangePrompt) | 
				
			||||
								} else { | 
				
			||||
									uni.$u.toast(`选择天数不能超过 ${this.maxRange} 天`) | 
				
			||||
								} | 
				
			||||
								return | 
				
			||||
							} | 
				
			||||
							// 如果当前日期大于已有日期,将当前的添加到数组尾部 | 
				
			||||
							selected.push(date) | 
				
			||||
							const startDate = selected[0] | 
				
			||||
							const endDate = selected[1] | 
				
			||||
							const arr = [] | 
				
			||||
							let i = 0 | 
				
			||||
							do { | 
				
			||||
								// 将开始和结束日期之间的日期添加到数组中 | 
				
			||||
								arr.push(dayjs(startDate).add(i, 'day').format("YYYY-MM-DD")) | 
				
			||||
								i++ | 
				
			||||
								// 累加的日期小于结束日期时,继续下一次的循环 | 
				
			||||
							} while (dayjs(startDate).add(i, 'day').isBefore(dayjs(endDate))) | 
				
			||||
							// 为了一次性修改数组,避免computed中多次触发,这里才用arr变量一次性赋值的方式,同时将最后一个日期添加近来 | 
				
			||||
							arr.push(endDate) | 
				
			||||
							selected = arr | 
				
			||||
						} else { | 
				
			||||
							// 选择区间时,只有一个日期的情况下,且不允许选择起止为同一天的话,不允许选择自己 | 
				
			||||
							if (selected[0] === date && !this.allowSameDay) return | 
				
			||||
							selected.push(date) | 
				
			||||
						} | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
				this.setSelected(selected) | 
				
			||||
			}, | 
				
			||||
			// 设置默认日期 | 
				
			||||
			setDefaultDate() { | 
				
			||||
				if (!this.defaultDate) { | 
				
			||||
					// 如果没有设置默认日期,则将当天日期设置为默认选中的日期 | 
				
			||||
					const selected = [dayjs().format("YYYY-MM-DD")] | 
				
			||||
					return this.setSelected(selected, false) | 
				
			||||
				} | 
				
			||||
				let defaultDate = [] | 
				
			||||
				const minDate = this.minDate || dayjs().format("YYYY-MM-DD") | 
				
			||||
				const maxDate = this.maxDate || dayjs(minDate).add(this.maxMonth - 1, 'month').format("YYYY-MM-DD") | 
				
			||||
				if (this.mode === 'single') { | 
				
			||||
					// 单选模式,可以是字符串或数组,Date对象等 | 
				
			||||
					if (!uni.$u.test.array(this.defaultDate)) { | 
				
			||||
						defaultDate = [dayjs(this.defaultDate).format("YYYY-MM-DD")] | 
				
			||||
					} else { | 
				
			||||
						defaultDate = [this.defaultDate[0]] | 
				
			||||
					} | 
				
			||||
				} else { | 
				
			||||
					// 如果为非数组,则不执行 | 
				
			||||
					if (!uni.$u.test.array(this.defaultDate)) return | 
				
			||||
					defaultDate = this.defaultDate | 
				
			||||
				} | 
				
			||||
				// 过滤用户传递的默认数组,取出只在可允许最大值与最小值之间的元素 | 
				
			||||
				defaultDate = defaultDate.filter(item => { | 
				
			||||
					return dayjs(item).isAfter(dayjs(minDate).subtract(1, 'day')) && dayjs(item).isBefore(dayjs( | 
				
			||||
						maxDate).add(1, 'day')) | 
				
			||||
				}) | 
				
			||||
				this.setSelected(defaultDate, false) | 
				
			||||
			}, | 
				
			||||
			setSelected(selected, event = true) { | 
				
			||||
				this.selected = selected | 
				
			||||
				event && this.$emit('monthSelected', this.selected) | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
	.u-calendar-month-wrapper { | 
				
			||||
		margin-top: 4px; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-calendar-month { | 
				
			||||
 | 
				
			||||
		&__title { | 
				
			||||
			font-size: 14px; | 
				
			||||
			line-height: 42px; | 
				
			||||
			height: 42px; | 
				
			||||
			color: $u-main-color; | 
				
			||||
			text-align: center; | 
				
			||||
			font-weight: bold; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__days { | 
				
			||||
			position: relative; | 
				
			||||
			@include flex; | 
				
			||||
			flex-wrap: wrap; | 
				
			||||
 | 
				
			||||
			&__month-mark-wrapper { | 
				
			||||
				position: absolute; | 
				
			||||
				top: 0; | 
				
			||||
				bottom: 0; | 
				
			||||
				left: 0; | 
				
			||||
				right: 0; | 
				
			||||
				@include flex; | 
				
			||||
				justify-content: center; | 
				
			||||
				align-items: center; | 
				
			||||
 | 
				
			||||
				&__text { | 
				
			||||
					font-size: 155px; | 
				
			||||
					color: rgba(231, 232, 234, 0.83); | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&__day { | 
				
			||||
				@include flex; | 
				
			||||
				padding: 2px; | 
				
			||||
				/* #ifndef APP-NVUE */ | 
				
			||||
				// vue下使用css进行宽度计算,因为某些安卓机会无法进行js获取父元素宽度进行计算得出,会有偏移 | 
				
			||||
				width: calc(100% / 7); | 
				
			||||
				box-sizing: border-box; | 
				
			||||
				/* #endif */ | 
				
			||||
 | 
				
			||||
				&__select { | 
				
			||||
					flex: 1; | 
				
			||||
					@include flex; | 
				
			||||
					align-items: center; | 
				
			||||
					justify-content: center; | 
				
			||||
					position: relative; | 
				
			||||
 | 
				
			||||
					&__dot { | 
				
			||||
						width: 7px; | 
				
			||||
						height: 7px; | 
				
			||||
						border-radius: 100px; | 
				
			||||
						background-color: $u-error; | 
				
			||||
						position: absolute; | 
				
			||||
						top: 12px; | 
				
			||||
						right: 7px; | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					&__buttom-info { | 
				
			||||
						color: $u-content-color; | 
				
			||||
						text-align: center; | 
				
			||||
						position: absolute; | 
				
			||||
						bottom: 5px; | 
				
			||||
						font-size: 10px; | 
				
			||||
						text-align: center; | 
				
			||||
						left: 0; | 
				
			||||
						right: 0; | 
				
			||||
 | 
				
			||||
						&--selected { | 
				
			||||
							color: #ffffff; | 
				
			||||
						} | 
				
			||||
 | 
				
			||||
						&--disabled { | 
				
			||||
							color: #cacbcd; | 
				
			||||
						} | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					&__info { | 
				
			||||
						text-align: center; | 
				
			||||
						font-size: 16px; | 
				
			||||
 | 
				
			||||
						&--selected { | 
				
			||||
							color: #ffffff; | 
				
			||||
						} | 
				
			||||
 | 
				
			||||
						&--disabled { | 
				
			||||
							color: #cacbcd; | 
				
			||||
						} | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					&--selected { | 
				
			||||
						background-color: $u-primary; | 
				
			||||
						@include flex; | 
				
			||||
						justify-content: center; | 
				
			||||
						align-items: center; | 
				
			||||
						flex: 1; | 
				
			||||
						border-radius: 3px; | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					&--range-selected { | 
				
			||||
						opacity: 0.3; | 
				
			||||
						border-radius: 0; | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					&--range-start-selected { | 
				
			||||
						border-top-right-radius: 0; | 
				
			||||
						border-bottom-right-radius: 0; | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					&--range-end-selected { | 
				
			||||
						border-top-left-radius: 0; | 
				
			||||
						border-bottom-left-radius: 0; | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,144 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 日历顶部标题
 | 
				
			||||
        title: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.calendar.title | 
				
			||||
        }, | 
				
			||||
        // 是否显示标题
 | 
				
			||||
        showTitle: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.calendar.showTitle | 
				
			||||
        }, | 
				
			||||
        // 是否显示副标题
 | 
				
			||||
        showSubtitle: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.calendar.showSubtitle | 
				
			||||
        }, | 
				
			||||
        // 日期类型选择,single-选择单个日期,multiple-可以选择多个日期,range-选择日期范围
 | 
				
			||||
        mode: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.calendar.mode | 
				
			||||
        }, | 
				
			||||
        // mode=range时,第一个日期底部的提示文字
 | 
				
			||||
        startText: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.calendar.startText | 
				
			||||
        }, | 
				
			||||
        // mode=range时,最后一个日期底部的提示文字
 | 
				
			||||
        endText: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.calendar.endText | 
				
			||||
        }, | 
				
			||||
        // 自定义列表
 | 
				
			||||
        customList: { | 
				
			||||
            type: Array, | 
				
			||||
            default: uni.$u.props.calendar.customList | 
				
			||||
        }, | 
				
			||||
        // 主题色,对底部按钮和选中日期有效
 | 
				
			||||
        color: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.calendar.color | 
				
			||||
        }, | 
				
			||||
        // 最小的可选日期
 | 
				
			||||
        minDate: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.calendar.minDate | 
				
			||||
        }, | 
				
			||||
        // 最大可选日期
 | 
				
			||||
        maxDate: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.calendar.maxDate | 
				
			||||
        }, | 
				
			||||
        // 默认选中的日期,mode为multiple或range是必须为数组格式
 | 
				
			||||
        defaultDate: { | 
				
			||||
            type: [Array, String, Date, null], | 
				
			||||
            default: uni.$u.props.calendar.defaultDate | 
				
			||||
        }, | 
				
			||||
        // mode=multiple时,最多可选多少个日期
 | 
				
			||||
        maxCount: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.calendar.maxCount | 
				
			||||
        }, | 
				
			||||
        // 日期行高
 | 
				
			||||
        rowHeight: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.calendar.rowHeight | 
				
			||||
        }, | 
				
			||||
        // 日期格式化函数
 | 
				
			||||
        formatter: { | 
				
			||||
            type: [Function, null], | 
				
			||||
            default: uni.$u.props.calendar.formatter | 
				
			||||
        }, | 
				
			||||
        // 是否显示农历
 | 
				
			||||
        showLunar: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.calendar.showLunar | 
				
			||||
        }, | 
				
			||||
        // 是否显示月份背景色
 | 
				
			||||
        showMark: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.calendar.showMark | 
				
			||||
        }, | 
				
			||||
        // 确定按钮的文字
 | 
				
			||||
        confirmText: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.calendar.confirmText | 
				
			||||
        }, | 
				
			||||
        // 确认按钮处于禁用状态时的文字
 | 
				
			||||
        confirmDisabledText: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.calendar.confirmDisabledText | 
				
			||||
        }, | 
				
			||||
        // 是否显示日历弹窗
 | 
				
			||||
        show: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.calendar.show | 
				
			||||
        }, | 
				
			||||
        // 是否允许点击遮罩关闭日历
 | 
				
			||||
        closeOnClickOverlay: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.calendar.closeOnClickOverlay | 
				
			||||
        }, | 
				
			||||
        // 是否为只读状态,只读状态下禁止选择日期
 | 
				
			||||
        readonly: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.calendar.readonly | 
				
			||||
        }, | 
				
			||||
        // 	是否展示确认按钮
 | 
				
			||||
        showConfirm: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.calendar.showConfirm | 
				
			||||
        }, | 
				
			||||
        // 日期区间最多可选天数,默认无限制,mode = range时有效
 | 
				
			||||
        maxRange: { | 
				
			||||
            type: [Number, String], | 
				
			||||
            default: uni.$u.props.calendar.maxRange | 
				
			||||
        }, | 
				
			||||
        // 范围选择超过最多可选天数时的提示文案,mode = range时有效
 | 
				
			||||
        rangePrompt: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.calendar.rangePrompt | 
				
			||||
        }, | 
				
			||||
        // 范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效
 | 
				
			||||
        showRangePrompt: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.calendar.showRangePrompt | 
				
			||||
        }, | 
				
			||||
        // 是否允许日期范围的起止时间为同一天,mode = range时有效
 | 
				
			||||
        allowSameDay: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.calendar.allowSameDay | 
				
			||||
        }, | 
				
			||||
		// 圆角值
 | 
				
			||||
		round: { | 
				
			||||
		    type: [Boolean, String, Number], | 
				
			||||
		    default: uni.$u.props.calendar.round | 
				
			||||
		}, | 
				
			||||
		// 最多展示月份数量
 | 
				
			||||
		monthNum: { | 
				
			||||
			type: [Number, String], | 
				
			||||
			default: 3 | 
				
			||||
		}	
 | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,384 @@
					 | 
				
			||||
<template> | 
				
			||||
	<u-popup | 
				
			||||
		:show="show" | 
				
			||||
		mode="bottom" | 
				
			||||
		closeable | 
				
			||||
		@close="close" | 
				
			||||
		:round="round" | 
				
			||||
		:closeOnClickOverlay="closeOnClickOverlay" | 
				
			||||
	> | 
				
			||||
		<view class="u-calendar"> | 
				
			||||
			<uHeader | 
				
			||||
				:title="title" | 
				
			||||
				:subtitle="subtitle" | 
				
			||||
				:showSubtitle="showSubtitle" | 
				
			||||
				:showTitle="showTitle" | 
				
			||||
			></uHeader> | 
				
			||||
			<scroll-view | 
				
			||||
				:style="{ | 
				
			||||
                    height: $u.addUnit(listHeight) | 
				
			||||
                }" | 
				
			||||
				scroll-y | 
				
			||||
				@scroll="onScroll" | 
				
			||||
				:scroll-top="scrollTop" | 
				
			||||
				:scrollIntoView="scrollIntoView" | 
				
			||||
			> | 
				
			||||
				<uMonth | 
				
			||||
					:color="color" | 
				
			||||
					:rowHeight="rowHeight" | 
				
			||||
					:showMark="showMark" | 
				
			||||
					:months="months" | 
				
			||||
					:mode="mode" | 
				
			||||
					:maxCount="maxCount" | 
				
			||||
					:startText="startText" | 
				
			||||
					:endText="endText" | 
				
			||||
					:defaultDate="defaultDate" | 
				
			||||
					:minDate="innerMinDate" | 
				
			||||
					:maxDate="innerMaxDate" | 
				
			||||
					:maxMonth="monthNum" | 
				
			||||
					:readonly="readonly" | 
				
			||||
					:maxRange="maxRange" | 
				
			||||
					:rangePrompt="rangePrompt" | 
				
			||||
					:showRangePrompt="showRangePrompt" | 
				
			||||
					:allowSameDay="allowSameDay" | 
				
			||||
					ref="month" | 
				
			||||
					@monthSelected="monthSelected" | 
				
			||||
					@updateMonthTop="updateMonthTop" | 
				
			||||
				></uMonth> | 
				
			||||
			</scroll-view> | 
				
			||||
			<slot name="footer" v-if="showConfirm"> | 
				
			||||
				<view class="u-calendar__confirm"> | 
				
			||||
					<u-button | 
				
			||||
						shape="circle" | 
				
			||||
						:text=" | 
				
			||||
                            buttonDisabled ? confirmDisabledText : confirmText | 
				
			||||
                        " | 
				
			||||
						:color="color" | 
				
			||||
						@click="confirm" | 
				
			||||
						:disabled="buttonDisabled" | 
				
			||||
					></u-button> | 
				
			||||
				</view> | 
				
			||||
			</slot> | 
				
			||||
		</view> | 
				
			||||
	</u-popup> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
import uHeader from './header.vue' | 
				
			||||
import uMonth from './month.vue' | 
				
			||||
import props from './props.js' | 
				
			||||
import util from './util.js' | 
				
			||||
import dayjs from '../../libs/util/dayjs.js' | 
				
			||||
import Calendar from '../../libs/util/calendar.js' | 
				
			||||
/** | 
				
			||||
 * Calendar 日历 | 
				
			||||
 * @description  此组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中. | 
				
			||||
 * @tutorial https://www.uviewui.com/components/calendar.html | 
				
			||||
 * | 
				
			||||
 * @property {String}				title				标题内容 (默认 日期选择 ) | 
				
			||||
 * @property {Boolean}				showTitle			是否显示标题  (默认 true ) | 
				
			||||
 * @property {Boolean}				showSubtitle		是否显示副标题	(默认 true ) | 
				
			||||
 * @property {String}				mode				日期类型选择  single-选择单个日期,multiple-可以选择多个日期,range-选择日期范围 ( 默认 'single' ) | 
				
			||||
 * @property {String}				startText			mode=range时,第一个日期底部的提示文字  (默认 '开始' ) | 
				
			||||
 * @property {String}				endText				mode=range时,最后一个日期底部的提示文字 (默认 '结束' ) | 
				
			||||
 * @property {Array}				customList			自定义列表 | 
				
			||||
 * @property {String}				color				主题色,对底部按钮和选中日期有效  (默认 ‘#3c9cff' ) | 
				
			||||
 * @property {String | Number}		minDate				最小的可选日期	 (默认 0 ) | 
				
			||||
 * @property {String | Number}		maxDate				最大可选日期  (默认 0 ) | 
				
			||||
 * @property {Array | String| Date}	defaultDate			默认选中的日期,mode为multiple或range是必须为数组格式 | 
				
			||||
 * @property {String | Number}		maxCount			mode=multiple时,最多可选多少个日期  (默认 	Number.MAX_SAFE_INTEGER  ) | 
				
			||||
 * @property {String | Number}		rowHeight			日期行高 (默认 56 ) | 
				
			||||
 * @property {Function}				formatter			日期格式化函数 | 
				
			||||
 * @property {Boolean}				showLunar			是否显示农历  (默认 false ) | 
				
			||||
 * @property {Boolean}				showMark			是否显示月份背景色 (默认 true ) | 
				
			||||
 * @property {String}				confirmText			确定按钮的文字 (默认 '确定' ) | 
				
			||||
 * @property {String}				confirmDisabledText	确认按钮处于禁用状态时的文字 (默认 '确定' ) | 
				
			||||
 * @property {Boolean}				show				是否显示日历弹窗 (默认 false ) | 
				
			||||
 * @property {Boolean}				closeOnClickOverlay	是否允许点击遮罩关闭日历 (默认 false ) | 
				
			||||
 * @property {Boolean}				readonly	        是否为只读状态,只读状态下禁止选择日期 (默认 false ) | 
				
			||||
 * @property {String | Number}		maxRange	        日期区间最多可选天数,默认无限制,mode = range时有效 | 
				
			||||
 * @property {String}				rangePrompt	        范围选择超过最多可选天数时的提示文案,mode = range时有效 | 
				
			||||
 * @property {Boolean}				showRangePrompt	    范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效 (默认 true ) | 
				
			||||
 * @property {Boolean}				allowSameDay	    是否允许日期范围的起止时间为同一天,mode = range时有效 (默认 false ) | 
				
			||||
 * @property {Number|String}	    round				圆角值,默认无圆角  (默认 0 ) | 
				
			||||
 * @property {Number|String}	    monthNum			最多展示的月份数量  (默认 3 ) | 
				
			||||
 * | 
				
			||||
 * @event {Function()} confirm 		点击确定按钮时触发		选择日期相关的返回参数 | 
				
			||||
 * @event {Function()} close 		日历关闭时触发			可定义页面关闭时的回调事件 | 
				
			||||
 * @example <u-calendar  :defaultDate="defaultDateMultiple" :show="show" mode="multiple" @confirm="confirm"> | 
				
			||||
	</u-calendar> | 
				
			||||
 * */ | 
				
			||||
export default { | 
				
			||||
	name: 'u-calendar', | 
				
			||||
	mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
	components: { | 
				
			||||
		uHeader, | 
				
			||||
		uMonth | 
				
			||||
	}, | 
				
			||||
	data() { | 
				
			||||
		return { | 
				
			||||
			// 需要显示的月份的数组 | 
				
			||||
			months: [], | 
				
			||||
			// 在月份滚动区域中,当前视图中月份的index索引 | 
				
			||||
			monthIndex: 0, | 
				
			||||
			// 月份滚动区域的高度 | 
				
			||||
			listHeight: 0, | 
				
			||||
			// month组件中选择的日期数组 | 
				
			||||
			selected: [], | 
				
			||||
			scrollIntoView: '', | 
				
			||||
			scrollTop:0, | 
				
			||||
			// 过滤处理方法 | 
				
			||||
			innerFormatter: (value) => value | 
				
			||||
		} | 
				
			||||
	}, | 
				
			||||
	watch: { | 
				
			||||
		selectedChange: { | 
				
			||||
			immediate: true, | 
				
			||||
			handler(n) { | 
				
			||||
				this.setMonth() | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		// 打开弹窗时,设置月份数据 | 
				
			||||
		show: { | 
				
			||||
			immediate: true, | 
				
			||||
			handler(n) { | 
				
			||||
				this.setMonth() | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	}, | 
				
			||||
	computed: { | 
				
			||||
		// 由于maxDate和minDate可以为字符串(2021-10-10),或者数值(时间戳),但是dayjs如果接受字符串形式的时间戳会有问题,这里进行处理 | 
				
			||||
		innerMaxDate() { | 
				
			||||
			return uni.$u.test.number(this.maxDate) | 
				
			||||
				? Number(this.maxDate) | 
				
			||||
				: this.maxDate | 
				
			||||
		}, | 
				
			||||
		innerMinDate() { | 
				
			||||
			return uni.$u.test.number(this.minDate) | 
				
			||||
				? Number(this.minDate) | 
				
			||||
				: this.minDate | 
				
			||||
		}, | 
				
			||||
		// 多个条件的变化,会引起选中日期的变化,这里统一管理监听 | 
				
			||||
		selectedChange() { | 
				
			||||
			return [this.innerMinDate, this.innerMaxDate, this.defaultDate] | 
				
			||||
		}, | 
				
			||||
		subtitle() { | 
				
			||||
			// 初始化时,this.months为空数组,所以需要特别判断处理 | 
				
			||||
			if (this.months.length) { | 
				
			||||
				return `${this.months[this.monthIndex].year}年${ | 
				
			||||
					this.months[this.monthIndex].month | 
				
			||||
				}月` | 
				
			||||
			} else { | 
				
			||||
				return '' | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		buttonDisabled() { | 
				
			||||
			// 如果为range类型,且选择的日期个数不足1个时,让底部的按钮出于disabled状态 | 
				
			||||
			if (this.mode === 'range') { | 
				
			||||
				if (this.selected.length <= 1) { | 
				
			||||
					return true | 
				
			||||
				} else { | 
				
			||||
					return false | 
				
			||||
				} | 
				
			||||
			} else { | 
				
			||||
				return false | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	}, | 
				
			||||
	mounted() { | 
				
			||||
		this.start = Date.now() | 
				
			||||
		this.init() | 
				
			||||
	}, | 
				
			||||
	methods: { | 
				
			||||
		// 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用 | 
				
			||||
		setFormatter(e) { | 
				
			||||
			this.innerFormatter = e | 
				
			||||
		}, | 
				
			||||
		// month组件内部选择日期后,通过事件通知给父组件 | 
				
			||||
		monthSelected(e) { | 
				
			||||
			this.selected = e | 
				
			||||
			if (!this.showConfirm) { | 
				
			||||
				// 在不需要确认按钮的情况下,如果为单选,或者范围多选且已选长度大于2,则直接进行返还 | 
				
			||||
				if ( | 
				
			||||
					this.mode === 'multiple' || | 
				
			||||
					this.mode === 'single' || | 
				
			||||
					(this.mode === 'range' && this.selected.length >= 2) | 
				
			||||
				) { | 
				
			||||
					this.$emit('confirm', this.selected) | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		init() { | 
				
			||||
			// 校验maxDate,不能小于minDate | 
				
			||||
			if ( | 
				
			||||
				this.innerMaxDate && | 
				
			||||
				this.innerMinDate && | 
				
			||||
				new Date(this.innerMaxDate).getTime() < new Date(this.innerMinDate).getTime() | 
				
			||||
			) { | 
				
			||||
				return uni.$u.error('maxDate不能小于minDate') | 
				
			||||
			} | 
				
			||||
			// 滚动区域的高度 | 
				
			||||
			this.listHeight = this.rowHeight * 5 + 30 | 
				
			||||
			this.setMonth() | 
				
			||||
		}, | 
				
			||||
		close() { | 
				
			||||
			this.$emit('close') | 
				
			||||
		}, | 
				
			||||
		// 点击确定按钮 | 
				
			||||
		confirm() { | 
				
			||||
			if (!this.buttonDisabled) { | 
				
			||||
				this.$emit('confirm', this.selected) | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		// 获得两个日期之间的月份数 | 
				
			||||
		getMonths(minDate, maxDate) { | 
				
			||||
			const minYear = dayjs(minDate).year() | 
				
			||||
			const minMonth = dayjs(minDate).month() + 1 | 
				
			||||
			const maxYear = dayjs(maxDate).year() | 
				
			||||
			const maxMonth = dayjs(maxDate).month() + 1 | 
				
			||||
			return (maxYear - minYear) * 12 + (maxMonth - minMonth) + 1 | 
				
			||||
		}, | 
				
			||||
		// 设置月份数据 | 
				
			||||
		setMonth() { | 
				
			||||
			// 最小日期的毫秒数 | 
				
			||||
			const minDate = this.innerMinDate || dayjs().valueOf() | 
				
			||||
			// 如果没有指定最大日期,则往后推3个月 | 
				
			||||
			const maxDate = | 
				
			||||
				this.innerMaxDate || | 
				
			||||
				dayjs(minDate) | 
				
			||||
					.add(this.monthNum - 1, 'month') | 
				
			||||
					.valueOf() | 
				
			||||
			// 最大最小月份之间的共有多少个月份, | 
				
			||||
			const months = uni.$u.range( | 
				
			||||
				1, | 
				
			||||
				this.monthNum, | 
				
			||||
				this.getMonths(minDate, maxDate) | 
				
			||||
			) | 
				
			||||
			// 先清空数组 | 
				
			||||
			this.months = [] | 
				
			||||
			for (let i = 0; i < months; i++) { | 
				
			||||
				this.months.push({ | 
				
			||||
					date: new Array( | 
				
			||||
						dayjs(minDate).add(i, 'month').daysInMonth() | 
				
			||||
					) | 
				
			||||
						.fill(1) | 
				
			||||
						.map((item, index) => { | 
				
			||||
							// 日期,取值1-31 | 
				
			||||
							let day = index + 1 | 
				
			||||
							// 星期,0-6,0为周日 | 
				
			||||
							const week = dayjs(minDate) | 
				
			||||
								.add(i, 'month') | 
				
			||||
								.date(day) | 
				
			||||
								.day() | 
				
			||||
							const date = dayjs(minDate) | 
				
			||||
								.add(i, 'month') | 
				
			||||
								.date(day) | 
				
			||||
								.format('YYYY-MM-DD') | 
				
			||||
							let bottomInfo = '' | 
				
			||||
							if (this.showLunar) { | 
				
			||||
								// 将日期转为农历格式 | 
				
			||||
								const lunar = Calendar.solar2lunar( | 
				
			||||
									dayjs(date).year(), | 
				
			||||
									dayjs(date).month() + 1, | 
				
			||||
									dayjs(date).date() | 
				
			||||
								) | 
				
			||||
								bottomInfo = lunar.IDayCn | 
				
			||||
							} | 
				
			||||
							let config = { | 
				
			||||
								day, | 
				
			||||
								week, | 
				
			||||
								// 小于最小允许的日期,或者大于最大的日期,则设置为disabled状态 | 
				
			||||
								disabled: | 
				
			||||
									dayjs(date).isBefore( | 
				
			||||
										dayjs(minDate).format('YYYY-MM-DD') | 
				
			||||
									) || | 
				
			||||
									dayjs(date).isAfter( | 
				
			||||
										dayjs(maxDate).format('YYYY-MM-DD') | 
				
			||||
									), | 
				
			||||
								// 返回一个日期对象,供外部的formatter获取当前日期的年月日等信息,进行加工处理 | 
				
			||||
								date: new Date(date), | 
				
			||||
								bottomInfo, | 
				
			||||
								dot: false, | 
				
			||||
								month: | 
				
			||||
									dayjs(minDate).add(i, 'month').month() + 1 | 
				
			||||
							} | 
				
			||||
							const formatter = | 
				
			||||
								this.formatter || this.innerFormatter | 
				
			||||
							return formatter(config) | 
				
			||||
						}), | 
				
			||||
					// 当前所属的月份 | 
				
			||||
					month: dayjs(minDate).add(i, 'month').month() + 1, | 
				
			||||
					// 当前年份 | 
				
			||||
					year: dayjs(minDate).add(i, 'month').year() | 
				
			||||
				}) | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
		}, | 
				
			||||
		// 滚动到默认设置的月份 | 
				
			||||
		scrollIntoDefaultMonth(selected) { | 
				
			||||
			// 查询默认日期在可选列表的下标 | 
				
			||||
			const _index = this.months.findIndex(({ | 
				
			||||
				  year, | 
				
			||||
				  month | 
				
			||||
			  }) => { | 
				
			||||
				month = uni.$u.padZero(month) | 
				
			||||
				return `${year}-${month}` === selected | 
				
			||||
			}) | 
				
			||||
			if (_index !== -1) { | 
				
			||||
				// #ifndef MP-WEIXIN | 
				
			||||
				this.$nextTick(() => { | 
				
			||||
					this.scrollIntoView = `month-${_index}` | 
				
			||||
				}) | 
				
			||||
				// #endif | 
				
			||||
				// #ifdef MP-WEIXIN | 
				
			||||
				this.scrollTop = this.months[_index].top || 0; | 
				
			||||
				// #endif | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		// scroll-view滚动监听 | 
				
			||||
		onScroll(event) { | 
				
			||||
			// 不允许小于0的滚动值,如果scroll-view到顶了,继续下拉,会出现负数值 | 
				
			||||
			const scrollTop = Math.max(0, event.detail.scrollTop) | 
				
			||||
			// 将当前滚动条数值,除以滚动区域的高度,可以得出当前滚动到了哪一个月份的索引 | 
				
			||||
			for (let i = 0; i < this.months.length; i++) { | 
				
			||||
				if (scrollTop >= (this.months[i].top || this.listHeight)) { | 
				
			||||
					this.monthIndex = i | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		// 更新月份的top值 | 
				
			||||
		updateMonthTop(topArr = []) { | 
				
			||||
			// 设置对应月份的top值,用于onScroll方法更新月份 | 
				
			||||
			topArr.map((item, index) => { | 
				
			||||
				this.months[index].top = item | 
				
			||||
			}) | 
				
			||||
 | 
				
			||||
			// 获取默认日期的下标 | 
				
			||||
			if (!this.defaultDate) { | 
				
			||||
				// 如果没有设置默认日期,则将当天日期设置为默认选中的日期 | 
				
			||||
				const selected = dayjs().format("YYYY-MM") | 
				
			||||
				this.scrollIntoDefaultMonth(selected) | 
				
			||||
				return | 
				
			||||
			} | 
				
			||||
			let selected = dayjs().format("YYYY-MM"); | 
				
			||||
			// 单选模式,可以是字符串或数组,Date对象等 | 
				
			||||
			if (!uni.$u.test.array(this.defaultDate)) { | 
				
			||||
				selected = dayjs(this.defaultDate).format("YYYY-MM") | 
				
			||||
			} else { | 
				
			||||
				selected = dayjs(this.defaultDate[0]).format("YYYY-MM"); | 
				
			||||
			} | 
				
			||||
			this.scrollIntoDefaultMonth(selected) | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
@import '../../libs/css/components.scss'; | 
				
			||||
 | 
				
			||||
.u-calendar { | 
				
			||||
	&__confirm { | 
				
			||||
		padding: 7px 18px; | 
				
			||||
	} | 
				
			||||
} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,85 @@
					 | 
				
			||||
export default { | 
				
			||||
    methods: { | 
				
			||||
        // 设置月份数据
 | 
				
			||||
        setMonth() { | 
				
			||||
            // 月初是周几
 | 
				
			||||
            const day = dayjs(this.date).date(1).day() | 
				
			||||
            const start = day == 0 ? 6 : day - 1 | 
				
			||||
 | 
				
			||||
            // 本月天数
 | 
				
			||||
            const days = dayjs(this.date).endOf('month').format('D') | 
				
			||||
 | 
				
			||||
            // 上个月天数
 | 
				
			||||
            const prevDays = dayjs(this.date).endOf('month').subtract(1, 'month').format('D') | 
				
			||||
 | 
				
			||||
            // 日期数据
 | 
				
			||||
            const arr = [] | 
				
			||||
            // 清空表格
 | 
				
			||||
            this.month = [] | 
				
			||||
 | 
				
			||||
            // 添加上月数据
 | 
				
			||||
            arr.push( | 
				
			||||
                ...new Array(start).fill(1).map((e, i) => { | 
				
			||||
                    const day = prevDays - start + i + 1 | 
				
			||||
 | 
				
			||||
                    return { | 
				
			||||
                        value: day, | 
				
			||||
                        disabled: true, | 
				
			||||
                        date: dayjs(this.date).subtract(1, 'month').date(day).format('YYYY-MM-DD') | 
				
			||||
                    } | 
				
			||||
                }) | 
				
			||||
            ) | 
				
			||||
 | 
				
			||||
            // 添加本月数据
 | 
				
			||||
            arr.push( | 
				
			||||
                ...new Array(days - 0).fill(1).map((e, i) => { | 
				
			||||
                    const day = i + 1 | 
				
			||||
 | 
				
			||||
                    return { | 
				
			||||
                        value: day, | 
				
			||||
                        date: dayjs(this.date).date(day).format('YYYY-MM-DD') | 
				
			||||
                    } | 
				
			||||
                }) | 
				
			||||
            ) | 
				
			||||
 | 
				
			||||
            // 添加下个月
 | 
				
			||||
            arr.push( | 
				
			||||
                ...new Array(42 - days - start).fill(1).map((e, i) => { | 
				
			||||
                    const day = i + 1 | 
				
			||||
 | 
				
			||||
                    return { | 
				
			||||
                        value: day, | 
				
			||||
                        disabled: true, | 
				
			||||
                        date: dayjs(this.date).add(1, 'month').date(day).format('YYYY-MM-DD') | 
				
			||||
                    } | 
				
			||||
                }) | 
				
			||||
            ) | 
				
			||||
 | 
				
			||||
            // 分割数组
 | 
				
			||||
            for (let n = 0; n < arr.length; n += 7) { | 
				
			||||
                this.month.push( | 
				
			||||
                    arr.slice(n, n + 7).map((e, i) => { | 
				
			||||
                        e.index = i + n | 
				
			||||
 | 
				
			||||
                        // 自定义信息
 | 
				
			||||
                        const custom = this.customList.find((c) => c.date == e.date) | 
				
			||||
 | 
				
			||||
                        // 农历
 | 
				
			||||
                        if (this.lunar) { | 
				
			||||
                            const { | 
				
			||||
                                IDayCn, | 
				
			||||
                                IMonthCn | 
				
			||||
                            } = this.getLunar(e.date) | 
				
			||||
                            e.lunar = IDayCn == '初一' ? IMonthCn : IDayCn | 
				
			||||
                        } | 
				
			||||
 | 
				
			||||
                        return { | 
				
			||||
                            ...e, | 
				
			||||
                            ...custom | 
				
			||||
                        } | 
				
			||||
                    }) | 
				
			||||
                ) | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,14 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 是否打乱键盘按键的顺序
 | 
				
			||||
        random: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: false | 
				
			||||
        }, | 
				
			||||
        // 输入一个中文后,是否自动切换到英文
 | 
				
			||||
        autoChange: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: false | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,311 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view | 
				
			||||
		class="u-keyboard" | 
				
			||||
		@touchmove.stop.prevent="noop" | 
				
			||||
	> | 
				
			||||
		<view | 
				
			||||
			v-for="(group, i) in abc ? engKeyBoardList : areaList" | 
				
			||||
			:key="i" | 
				
			||||
			class="u-keyboard__button" | 
				
			||||
			:index="i" | 
				
			||||
			:class="[i + 1 === 4 && 'u-keyboard__button--center']" | 
				
			||||
		> | 
				
			||||
			<view | 
				
			||||
				v-if="i === 3" | 
				
			||||
				class="u-keyboard__button__inner-wrapper" | 
				
			||||
			> | 
				
			||||
				<view | 
				
			||||
					class="u-keyboard__button__inner-wrapper__left" | 
				
			||||
					hover-class="u-hover-class" | 
				
			||||
					:hover-stay-time="200" | 
				
			||||
					@tap="changeCarInputMode" | 
				
			||||
				> | 
				
			||||
					<text | 
				
			||||
						class="u-keyboard__button__inner-wrapper__left__lang" | 
				
			||||
						:class="[!abc && 'u-keyboard__button__inner-wrapper__left__lang--active']" | 
				
			||||
					>中</text> | 
				
			||||
					<text class="u-keyboard__button__inner-wrapper__left__line">/</text> | 
				
			||||
					<text | 
				
			||||
						class="u-keyboard__button__inner-wrapper__left__lang" | 
				
			||||
						:class="[abc && 'u-keyboard__button__inner-wrapper__left__lang--active']" | 
				
			||||
					>英</text> | 
				
			||||
				</view> | 
				
			||||
			</view> | 
				
			||||
			<view | 
				
			||||
				class="u-keyboard__button__inner-wrapper" | 
				
			||||
				v-for="(item, j) in group" | 
				
			||||
				:key="j" | 
				
			||||
			> | 
				
			||||
				<view | 
				
			||||
					class="u-keyboard__button__inner-wrapper__inner" | 
				
			||||
					:hover-stay-time="200" | 
				
			||||
					@tap="carInputClick(i, j)" | 
				
			||||
					hover-class="u-hover-class" | 
				
			||||
				> | 
				
			||||
					<text class="u-keyboard__button__inner-wrapper__inner__text">{{ item }}</text> | 
				
			||||
				</view> | 
				
			||||
			</view> | 
				
			||||
			<view | 
				
			||||
				v-if="i === 3" | 
				
			||||
				@touchstart="backspaceClick" | 
				
			||||
				@touchend="clearTimer" | 
				
			||||
				class="u-keyboard__button__inner-wrapper" | 
				
			||||
			> | 
				
			||||
				<view | 
				
			||||
					class="u-keyboard__button__inner-wrapper__right" | 
				
			||||
					hover-class="u-hover-class" | 
				
			||||
					:hover-stay-time="200" | 
				
			||||
				> | 
				
			||||
					<u-icon | 
				
			||||
						size="28" | 
				
			||||
						name="backspace" | 
				
			||||
						color="#303133" | 
				
			||||
					></u-icon> | 
				
			||||
				</view> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * keyboard 键盘组件 | 
				
			||||
	 * @description 此为uView自定义的键盘面板,内含了数字键盘,车牌号键,身份证号键盘3种模式,都有可以打乱按键顺序的选项。 | 
				
			||||
	 * @tutorial https://uviewui.com/components/keyboard.html | 
				
			||||
	 * @property {Boolean} random 是否打乱键盘的顺序 | 
				
			||||
	 * @event {Function} change 点击键盘触发 | 
				
			||||
	 * @event {Function} backspace 点击退格键触发 | 
				
			||||
	 * @example <u-keyboard ref="uKeyboard" mode="car" v-model="show"></u-keyboard> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: "u-keyboard", | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				// 车牌输入时,abc=true为输入车牌号码,bac=false为输入省份中文简称 | 
				
			||||
				abc: false | 
				
			||||
			}; | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			areaList() { | 
				
			||||
				let data = [ | 
				
			||||
					'京', | 
				
			||||
					'沪', | 
				
			||||
					'粤', | 
				
			||||
					'津', | 
				
			||||
					'冀', | 
				
			||||
					'豫', | 
				
			||||
					'云', | 
				
			||||
					'辽', | 
				
			||||
					'黑', | 
				
			||||
					'湘', | 
				
			||||
					'皖', | 
				
			||||
					'鲁', | 
				
			||||
					'苏', | 
				
			||||
					'浙', | 
				
			||||
					'赣', | 
				
			||||
					'鄂', | 
				
			||||
					'桂', | 
				
			||||
					'甘', | 
				
			||||
					'晋', | 
				
			||||
					'陕', | 
				
			||||
					'蒙', | 
				
			||||
					'吉', | 
				
			||||
					'闽', | 
				
			||||
					'贵', | 
				
			||||
					'渝', | 
				
			||||
					'川', | 
				
			||||
					'青', | 
				
			||||
					'琼', | 
				
			||||
					'宁', | 
				
			||||
					'挂', | 
				
			||||
					'藏', | 
				
			||||
					'港', | 
				
			||||
					'澳', | 
				
			||||
					'新', | 
				
			||||
					'使', | 
				
			||||
					'学' | 
				
			||||
				]; | 
				
			||||
				let tmp = []; | 
				
			||||
				// 打乱顺序 | 
				
			||||
				if (this.random) data = uni.$u.randomArray(data); | 
				
			||||
				// 切割成二维数组 | 
				
			||||
				tmp[0] = data.slice(0, 10); | 
				
			||||
				tmp[1] = data.slice(10, 20); | 
				
			||||
				tmp[2] = data.slice(20, 30); | 
				
			||||
				tmp[3] = data.slice(30, 36); | 
				
			||||
				return tmp; | 
				
			||||
			}, | 
				
			||||
			engKeyBoardList() { | 
				
			||||
				let data = [ | 
				
			||||
					1, | 
				
			||||
					2, | 
				
			||||
					3, | 
				
			||||
					4, | 
				
			||||
					5, | 
				
			||||
					6, | 
				
			||||
					7, | 
				
			||||
					8, | 
				
			||||
					9, | 
				
			||||
					0, | 
				
			||||
					'Q', | 
				
			||||
					'W', | 
				
			||||
					'E', | 
				
			||||
					'R', | 
				
			||||
					'T', | 
				
			||||
					'Y', | 
				
			||||
					'U', | 
				
			||||
					'I', | 
				
			||||
					'O', | 
				
			||||
					'P', | 
				
			||||
					'A', | 
				
			||||
					'S', | 
				
			||||
					'D', | 
				
			||||
					'F', | 
				
			||||
					'G', | 
				
			||||
					'H', | 
				
			||||
					'J', | 
				
			||||
					'K', | 
				
			||||
					'L', | 
				
			||||
					'Z', | 
				
			||||
					'X', | 
				
			||||
					'C', | 
				
			||||
					'V', | 
				
			||||
					'B', | 
				
			||||
					'N', | 
				
			||||
					'M' | 
				
			||||
				]; | 
				
			||||
				let tmp = []; | 
				
			||||
				if (this.random) data = uni.$u.randomArray(data); | 
				
			||||
				tmp[0] = data.slice(0, 10); | 
				
			||||
				tmp[1] = data.slice(10, 20); | 
				
			||||
				tmp[2] = data.slice(20, 30); | 
				
			||||
				tmp[3] = data.slice(30, 36); | 
				
			||||
				return tmp; | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			// 点击键盘按钮 | 
				
			||||
			carInputClick(i, j) { | 
				
			||||
				let value = ''; | 
				
			||||
				// 不同模式,获取不同数组的值 | 
				
			||||
				if (this.abc) value = this.engKeyBoardList[i][j]; | 
				
			||||
				else value = this.areaList[i][j]; | 
				
			||||
				// 如果允许自动切换,则将中文状态切换为英文 | 
				
			||||
				if (!this.abc && this.autoChange) uni.$u.sleep(200).then(() => this.abc = true) | 
				
			||||
				this.$emit('change', value); | 
				
			||||
			}, | 
				
			||||
			// 修改汽车牌键盘的输入模式,中文|英文 | 
				
			||||
			changeCarInputMode() { | 
				
			||||
				this.abc = !this.abc; | 
				
			||||
			}, | 
				
			||||
			// 点击退格键 | 
				
			||||
			backspaceClick() { | 
				
			||||
				this.$emit('backspace'); | 
				
			||||
				clearInterval(this.timer); //再次清空定时器,防止重复注册定时器 | 
				
			||||
				this.timer = null; | 
				
			||||
				this.timer = setInterval(() => { | 
				
			||||
					this.$emit('backspace'); | 
				
			||||
				}, 250); | 
				
			||||
			}, | 
				
			||||
			clearTimer() { | 
				
			||||
				clearInterval(this.timer); | 
				
			||||
				this.timer = null; | 
				
			||||
			}, | 
				
			||||
		} | 
				
			||||
	}; | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
	$u-car-keyboard-background-color: rgb(224, 228, 230) !default; | 
				
			||||
	$u-car-keyboard-padding:6px 0 6px !default; | 
				
			||||
	$u-car-keyboard-button-inner-width:64rpx !default; | 
				
			||||
	$u-car-keyboard-button-inner-background-color:#FFFFFF !default; | 
				
			||||
	$u-car-keyboard-button-height:80rpx !default; | 
				
			||||
	$u-car-keyboard-button-inner-box-shadow:0 1px 0px #999992 !default; | 
				
			||||
	$u-car-keyboard-button-border-radius:4px !default; | 
				
			||||
	$u-car-keyboard-button-inner-margin:8rpx 5rpx !default; | 
				
			||||
	$u-car-keyboard-button-text-font-size:16px !default; | 
				
			||||
	$u-car-keyboard-button-text-color:$u-main-color !default; | 
				
			||||
	$u-car-keyboard-center-inner-margin: 0 4rpx !default; | 
				
			||||
	$u-car-keyboard-special-button-width:134rpx !default; | 
				
			||||
	$u-car-keyboard-lang-font-size:16px !default; | 
				
			||||
	$u-car-keyboard-lang-color:$u-main-color !default; | 
				
			||||
	$u-car-keyboard-active-color:$u-primary !default; | 
				
			||||
	$u-car-keyboard-line-font-size:15px !default; | 
				
			||||
	$u-car-keyboard-line-color:$u-main-color !default; | 
				
			||||
	$u-car-keyboard-line-margin:0 1px !default; | 
				
			||||
	$u-car-keyboard-u-hover-class-background-color:#BBBCC6 !default; | 
				
			||||
 | 
				
			||||
	.u-keyboard { | 
				
			||||
		@include flex(column); | 
				
			||||
		justify-content: space-around; | 
				
			||||
		background-color: $u-car-keyboard-background-color; | 
				
			||||
		align-items: stretch; | 
				
			||||
		padding: $u-car-keyboard-padding; | 
				
			||||
 | 
				
			||||
		&__button { | 
				
			||||
			@include flex; | 
				
			||||
			justify-content: center; | 
				
			||||
			flex: 1; | 
				
			||||
			/* #ifndef APP-NVUE */ | 
				
			||||
			/* #endif */ | 
				
			||||
 | 
				
			||||
			&__inner-wrapper { | 
				
			||||
				box-shadow: $u-car-keyboard-button-inner-box-shadow; | 
				
			||||
				margin: $u-car-keyboard-button-inner-margin; | 
				
			||||
				border-radius: $u-car-keyboard-button-border-radius; | 
				
			||||
 | 
				
			||||
				&__inner { | 
				
			||||
					@include flex; | 
				
			||||
					justify-content: center; | 
				
			||||
					align-items: center; | 
				
			||||
					width: $u-car-keyboard-button-inner-width; | 
				
			||||
					background-color: $u-car-keyboard-button-inner-background-color; | 
				
			||||
					height: $u-car-keyboard-button-height; | 
				
			||||
					border-radius: $u-car-keyboard-button-border-radius; | 
				
			||||
 | 
				
			||||
					&__text { | 
				
			||||
						font-size: $u-car-keyboard-button-text-font-size; | 
				
			||||
						color: $u-car-keyboard-button-text-color; | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				&__left, | 
				
			||||
				&__right { | 
				
			||||
					border-radius: $u-car-keyboard-button-border-radius; | 
				
			||||
					width: $u-car-keyboard-special-button-width; | 
				
			||||
					height: $u-car-keyboard-button-height; | 
				
			||||
					background-color: $u-car-keyboard-u-hover-class-background-color; | 
				
			||||
					@include flex; | 
				
			||||
					justify-content: center; | 
				
			||||
					align-items: center; | 
				
			||||
					box-shadow: $u-car-keyboard-button-inner-box-shadow; | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				&__left { | 
				
			||||
					&__line { | 
				
			||||
						font-size: $u-car-keyboard-line-font-size; | 
				
			||||
						color: $u-car-keyboard-line-color; | 
				
			||||
						margin: $u-car-keyboard-line-margin; | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					&__lang { | 
				
			||||
						font-size: $u-car-keyboard-lang-font-size; | 
				
			||||
						color: $u-car-keyboard-lang-color; | 
				
			||||
 | 
				
			||||
						&--active { | 
				
			||||
							color: $u-car-keyboard-active-color; | 
				
			||||
						} | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-hover-class { | 
				
			||||
		background-color: $u-car-keyboard-u-hover-class-background-color; | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,14 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 分组标题
 | 
				
			||||
        title: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.cellGroup.title | 
				
			||||
        }, | 
				
			||||
        // 是否显示外边框
 | 
				
			||||
        border: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.cellGroup.border | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,61 @@
					 | 
				
			||||
<template> | 
				
			||||
    <view :style="[$u.addStyle(customStyle)]" :class="[customClass]" class="u-cell-group"> | 
				
			||||
        <view v-if="title" class="u-cell-group__title"> | 
				
			||||
            <slot name="title"> | 
				
			||||
				<text class="u-cell-group__title__text">{{ title }}</text> | 
				
			||||
			</slot> | 
				
			||||
        </view> | 
				
			||||
        <view class="u-cell-group__wrapper"> | 
				
			||||
			<u-line v-if="border"></u-line> | 
				
			||||
            <slot /> | 
				
			||||
        </view> | 
				
			||||
    </view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * cellGroup  单元格 | 
				
			||||
	 * @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。 | 
				
			||||
	 * @tutorial https://uviewui.com/components/cell.html | 
				
			||||
	 *  | 
				
			||||
	 * @property {String}	title		分组标题 | 
				
			||||
	 * @property {Boolean}	border		是否显示外边框 (默认 true ) | 
				
			||||
	 * @property {Object}	customStyle	定义需要用到的外部样式 | 
				
			||||
	 *  | 
				
			||||
	 * @event {Function} click 	点击cell列表时触发 | 
				
			||||
	 * @example <u-cell-group title="设置喜好"> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'u-cell-group', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin,props], | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
	 | 
				
			||||
	$u-cell-group-title-padding: 16px 16px 8px !default; | 
				
			||||
	$u-cell-group-title-font-size: 15px !default; | 
				
			||||
	$u-cell-group-title-line-height: 16px !default; | 
				
			||||
	$u-cell-group-title-color: $u-main-color !default; | 
				
			||||
 | 
				
			||||
    .u-cell-group { | 
				
			||||
		flex: 1; | 
				
			||||
		 | 
				
			||||
        &__title { | 
				
			||||
            padding: $u-cell-group-title-padding; | 
				
			||||
 | 
				
			||||
            &__text { | 
				
			||||
                font-size: $u-cell-group-title-font-size; | 
				
			||||
                line-height: $u-cell-group-title-line-height; | 
				
			||||
                color: $u-cell-group-title-color; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
		 | 
				
			||||
		&__wrapper { | 
				
			||||
			position: relative; | 
				
			||||
		} | 
				
			||||
    } | 
				
			||||
</style> | 
				
			||||
 | 
				
			||||
@ -0,0 +1,110 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 标题
 | 
				
			||||
        title: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.cell.title | 
				
			||||
        }, | 
				
			||||
        // 标题下方的描述信息
 | 
				
			||||
        label: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.cell.label | 
				
			||||
        }, | 
				
			||||
        // 右侧的内容
 | 
				
			||||
        value: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.cell.value | 
				
			||||
        }, | 
				
			||||
        // 左侧图标名称,或者图片链接(本地文件建议使用绝对地址)
 | 
				
			||||
        icon: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.cell.icon | 
				
			||||
        }, | 
				
			||||
        // 是否禁用cell
 | 
				
			||||
        disabled: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.cell.disabled | 
				
			||||
        }, | 
				
			||||
        // 是否显示下边框
 | 
				
			||||
        border: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.cell.border | 
				
			||||
        }, | 
				
			||||
        // 内容是否垂直居中(主要是针对右侧的value部分)
 | 
				
			||||
        center: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.cell.center | 
				
			||||
        }, | 
				
			||||
        // 点击后跳转的URL地址
 | 
				
			||||
        url: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.cell.url | 
				
			||||
        }, | 
				
			||||
        // 链接跳转的方式,内部使用的是uView封装的route方法,可能会进行拦截操作
 | 
				
			||||
        linkType: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.cell.linkType | 
				
			||||
        }, | 
				
			||||
        // 是否开启点击反馈(表现为点击时加上灰色背景)
 | 
				
			||||
        clickable: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.cell.clickable | 
				
			||||
        }, | 
				
			||||
        // 是否展示右侧箭头并开启点击反馈
 | 
				
			||||
        isLink: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.cell.isLink | 
				
			||||
        }, | 
				
			||||
        // 是否显示表单状态下的必填星号(此组件可能会内嵌入input组件)
 | 
				
			||||
        required: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.cell.required | 
				
			||||
        }, | 
				
			||||
        // 右侧的图标箭头
 | 
				
			||||
        rightIcon: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.cell.rightIcon | 
				
			||||
        }, | 
				
			||||
        // 右侧箭头的方向,可选值为:left,up,down
 | 
				
			||||
        arrowDirection: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.cell.arrowDirection | 
				
			||||
        }, | 
				
			||||
        // 左侧图标样式
 | 
				
			||||
        iconStyle: { | 
				
			||||
            type: [Object, String], | 
				
			||||
            default: () => { | 
				
			||||
				return uni.$u.props.cell.iconStyle | 
				
			||||
			} | 
				
			||||
        }, | 
				
			||||
        // 右侧箭头图标的样式
 | 
				
			||||
        rightIconStyle: { | 
				
			||||
            type: [Object, String], | 
				
			||||
            default: () => { | 
				
			||||
				return uni.$u.props.cell.rightIconStyle | 
				
			||||
			} | 
				
			||||
        }, | 
				
			||||
        // 标题的样式
 | 
				
			||||
        titleStyle: { | 
				
			||||
            type: [Object, String], | 
				
			||||
			default: () => { | 
				
			||||
				return uni.$u.props.cell.titleStyle | 
				
			||||
			} | 
				
			||||
        }, | 
				
			||||
        // 单位元的大小,可选值为large
 | 
				
			||||
        size: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.cell.size | 
				
			||||
        }, | 
				
			||||
        // 点击cell是否阻止事件传播
 | 
				
			||||
        stop: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.cell.stop | 
				
			||||
        }, | 
				
			||||
        // 标识符,cell被点击时返回
 | 
				
			||||
        name: { | 
				
			||||
            type: [Number, String], | 
				
			||||
            default: uni.$u.props.cell.name | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,229 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="u-cell" :class="[customClass]" :style="[$u.addStyle(customStyle)]" | 
				
			||||
		:hover-class="(!disabled && (clickable || isLink)) ? 'u-cell--clickable' : ''" :hover-stay-time="250" | 
				
			||||
		@tap="clickHandler"> | 
				
			||||
		<view class="u-cell__body" :class="[ center && 'u-cell--center', size === 'large' && 'u-cell__body--large']"> | 
				
			||||
			<view class="u-cell__body__content"> | 
				
			||||
				<view class="u-cell__left-icon-wrap" v-if="$slots.icon || icon"> | 
				
			||||
					<slot name="icon" v-if="$slots.icon"> | 
				
			||||
					</slot> | 
				
			||||
					<u-icon v-else :name="icon" :custom-style="iconStyle" :size="size === 'large' ? 22 : 18"></u-icon> | 
				
			||||
				</view> | 
				
			||||
				<view class="u-cell__title"> | 
				
			||||
					<slot name="title"> | 
				
			||||
						<text v-if="title" class="u-cell__title-text" :style="[titleTextStyle]" | 
				
			||||
							:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__title-text--large']">{{ title }}</text> | 
				
			||||
					</slot> | 
				
			||||
					<slot name="label"> | 
				
			||||
						<text class="u-cell__label" v-if="label" | 
				
			||||
							:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__label--large']">{{ label }}</text> | 
				
			||||
					</slot> | 
				
			||||
				</view> | 
				
			||||
			</view> | 
				
			||||
			<slot name="value"> | 
				
			||||
				<text class="u-cell__value" | 
				
			||||
					:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__value--large']" | 
				
			||||
					v-if="!$u.test.empty(value)">{{ value }}</text> | 
				
			||||
			</slot> | 
				
			||||
			<view class="u-cell__right-icon-wrap" v-if="$slots['right-icon'] || isLink" | 
				
			||||
				:class="[`u-cell__right-icon-wrap--${arrowDirection}`]"> | 
				
			||||
				<slot name="right-icon" v-if="$slots['right-icon']"> | 
				
			||||
				</slot> | 
				
			||||
				<u-icon v-else :name="rightIcon" :custom-style="rightIconStyle" :color="disabled ? '#c8c9cc' : 'info'" | 
				
			||||
					:size="size === 'large' ? 18 : 16"></u-icon> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
		<u-line v-if="border"></u-line> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * cell  单元格 | 
				
			||||
	 * @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。 | 
				
			||||
	 * @tutorial https://uviewui.com/components/cell.html | 
				
			||||
	 * @property {String | Number}	title			标题 | 
				
			||||
	 * @property {String | Number}	label			标题下方的描述信息 | 
				
			||||
	 * @property {String | Number}	value			右侧的内容 | 
				
			||||
	 * @property {String}			icon			左侧图标名称,或者图片链接(本地文件建议使用绝对地址) | 
				
			||||
	 * @property {Boolean}			disabled		是否禁用cell	 | 
				
			||||
	 * @property {Boolean}			border			是否显示下边框 (默认 true ) | 
				
			||||
	 * @property {Boolean}			center			内容是否垂直居中(主要是针对右侧的value部分) (默认 false ) | 
				
			||||
	 * @property {String}			url				点击后跳转的URL地址 | 
				
			||||
	 * @property {String}			linkType		链接跳转的方式,内部使用的是uView封装的route方法,可能会进行拦截操作 (默认 'navigateTo' ) | 
				
			||||
	 * @property {Boolean}			clickable		是否开启点击反馈(表现为点击时加上灰色背景) (默认 false )  | 
				
			||||
	 * @property {Boolean}			isLink			是否展示右侧箭头并开启点击反馈 (默认 false ) | 
				
			||||
	 * @property {Boolean}			required		是否显示表单状态下的必填星号(此组件可能会内嵌入input组件) (默认 false ) | 
				
			||||
	 * @property {String}			rightIcon		右侧的图标箭头 (默认 'arrow-right') | 
				
			||||
	 * @property {String}			arrowDirection	右侧箭头的方向,可选值为:left,up,down | 
				
			||||
	 * @property {Object | String}			rightIconStyle	右侧箭头图标的样式 | 
				
			||||
	 * @property {Object | String}			titleStyle		标题的样式 | 
				
			||||
	 * @property {Object | String}			iconStyle		左侧图标样式 | 
				
			||||
	 * @property {String}			size			单位元的大小,可选值为 large,normal,mini  | 
				
			||||
	 * @property {Boolean}			stop			点击cell是否阻止事件传播 (默认 true ) | 
				
			||||
	 * @property {Object}			customStyle		定义需要用到的外部样式 | 
				
			||||
	 *  | 
				
			||||
	 * @event {Function}			click			点击cell列表时触发 | 
				
			||||
	 * @example 该组件需要搭配cell-group组件使用,见官方文档示例 | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'u-cell', | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
 | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
		computed: { | 
				
			||||
			titleTextStyle() { | 
				
			||||
				return uni.$u.addStyle(this.titleStyle) | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			// 点击cell | 
				
			||||
			clickHandler(e) { | 
				
			||||
				if (this.disabled) return | 
				
			||||
				this.$emit('click', { | 
				
			||||
					name: this.name | 
				
			||||
				}) | 
				
			||||
				// 如果配置了url(此props参数通过mixin引入)参数,跳转页面 | 
				
			||||
				this.openPage() | 
				
			||||
				// 是否阻止事件传播 | 
				
			||||
				this.stop && this.preventEvent(e) | 
				
			||||
			}, | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
	$u-cell-padding: 10px 15px !default; | 
				
			||||
	$u-cell-font-size: 15px !default; | 
				
			||||
	$u-cell-line-height: 24px !default; | 
				
			||||
	$u-cell-color: $u-main-color !default; | 
				
			||||
	$u-cell-icon-size: 16px !default; | 
				
			||||
	$u-cell-title-font-size: 15px !default; | 
				
			||||
	$u-cell-title-line-height: 22px !default; | 
				
			||||
	$u-cell-title-color: $u-main-color !default; | 
				
			||||
	$u-cell-label-font-size: 12px !default; | 
				
			||||
	$u-cell-label-color: $u-tips-color !default; | 
				
			||||
	$u-cell-label-line-height: 18px !default; | 
				
			||||
	$u-cell-value-font-size: 14px !default; | 
				
			||||
	$u-cell-value-color: $u-content-color !default; | 
				
			||||
	$u-cell-clickable-color: $u-bg-color !default; | 
				
			||||
	$u-cell-disabled-color: #c8c9cc !default; | 
				
			||||
	$u-cell-padding-top-large: 13px !default; | 
				
			||||
	$u-cell-padding-bottom-large: 13px !default; | 
				
			||||
	$u-cell-value-font-size-large: 15px !default; | 
				
			||||
	$u-cell-label-font-size-large: 14px !default; | 
				
			||||
	$u-cell-title-font-size-large: 16px !default; | 
				
			||||
	$u-cell-left-icon-wrap-margin-right: 4px !default; | 
				
			||||
	$u-cell-right-icon-wrap-margin-left: 4px !default; | 
				
			||||
	$u-cell-title-flex:1 !default; | 
				
			||||
	$u-cell-label-margin-top:5px !default; | 
				
			||||
 | 
				
			||||
 | 
				
			||||
	.u-cell { | 
				
			||||
		&__body { | 
				
			||||
			@include flex(); | 
				
			||||
			/* #ifndef APP-NVUE */ | 
				
			||||
			box-sizing: border-box; | 
				
			||||
			/* #endif */ | 
				
			||||
			padding: $u-cell-padding; | 
				
			||||
			font-size: $u-cell-font-size; | 
				
			||||
			color: $u-cell-color; | 
				
			||||
			// line-height: $u-cell-line-height; | 
				
			||||
			align-items: center; | 
				
			||||
 | 
				
			||||
			&__content { | 
				
			||||
				@include flex(row); | 
				
			||||
				align-items: center; | 
				
			||||
				flex: 1; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&--large { | 
				
			||||
				padding-top: $u-cell-padding-top-large; | 
				
			||||
				padding-bottom: $u-cell-padding-bottom-large; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__left-icon-wrap, | 
				
			||||
		&__right-icon-wrap { | 
				
			||||
			@include flex(); | 
				
			||||
			align-items: center; | 
				
			||||
			// height: $u-cell-line-height; | 
				
			||||
			font-size: $u-cell-icon-size; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__left-icon-wrap { | 
				
			||||
			margin-right: $u-cell-left-icon-wrap-margin-right; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__right-icon-wrap { | 
				
			||||
			margin-left: $u-cell-right-icon-wrap-margin-left; | 
				
			||||
			transition: transform 0.3s; | 
				
			||||
 | 
				
			||||
			&--up { | 
				
			||||
				transform: rotate(-90deg); | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&--down { | 
				
			||||
				transform: rotate(90deg); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__title { | 
				
			||||
			flex: $u-cell-title-flex; | 
				
			||||
 | 
				
			||||
			&-text { | 
				
			||||
				font-size: $u-cell-title-font-size; | 
				
			||||
				line-height: $u-cell-title-line-height; | 
				
			||||
				color: $u-cell-title-color; | 
				
			||||
 | 
				
			||||
				&--large { | 
				
			||||
					font-size: $u-cell-title-font-size-large; | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__label { | 
				
			||||
			margin-top: $u-cell-label-margin-top; | 
				
			||||
			font-size: $u-cell-label-font-size; | 
				
			||||
			color: $u-cell-label-color; | 
				
			||||
			line-height: $u-cell-label-line-height; | 
				
			||||
 | 
				
			||||
			&--large { | 
				
			||||
				font-size: $u-cell-label-font-size-large; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__value { | 
				
			||||
			text-align: right; | 
				
			||||
			font-size: $u-cell-value-font-size; | 
				
			||||
			line-height: $u-cell-line-height; | 
				
			||||
			color: $u-cell-value-color; | 
				
			||||
 | 
				
			||||
			&--large { | 
				
			||||
				font-size: $u-cell-value-font-size-large; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--clickable { | 
				
			||||
			background-color: $u-cell-clickable-color; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--disabled { | 
				
			||||
			color: $u-cell-disabled-color; | 
				
			||||
			/* #ifndef APP-NVUE */ | 
				
			||||
			cursor: not-allowed; | 
				
			||||
			/* #endif */ | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--center { | 
				
			||||
			align-items: center; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,82 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 标识符
 | 
				
			||||
        name: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.checkboxGroup.name | 
				
			||||
        }, | 
				
			||||
        // 绑定的值
 | 
				
			||||
        value: { | 
				
			||||
            type: Array, | 
				
			||||
            default: uni.$u.props.checkboxGroup.value | 
				
			||||
        }, | 
				
			||||
        // 形状,circle-圆形,square-方形
 | 
				
			||||
        shape: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.checkboxGroup.shape | 
				
			||||
        }, | 
				
			||||
        // 是否禁用全部checkbox
 | 
				
			||||
        disabled: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.checkboxGroup.disabled | 
				
			||||
        }, | 
				
			||||
 | 
				
			||||
        // 选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值
 | 
				
			||||
        activeColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.checkboxGroup.activeColor | 
				
			||||
        }, | 
				
			||||
        // 未选中的颜色
 | 
				
			||||
        inactiveColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.checkboxGroup.inactiveColor | 
				
			||||
        }, | 
				
			||||
 | 
				
			||||
        // 整个组件的尺寸,默认px
 | 
				
			||||
        size: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.checkboxGroup.size | 
				
			||||
        }, | 
				
			||||
        // 布局方式,row-横向,column-纵向
 | 
				
			||||
        placement: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.checkboxGroup.placement | 
				
			||||
        }, | 
				
			||||
        // label的字体大小,px单位
 | 
				
			||||
        labelSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.checkboxGroup.labelSize | 
				
			||||
        }, | 
				
			||||
        // label的字体颜色
 | 
				
			||||
        labelColor: { | 
				
			||||
            type: [String], | 
				
			||||
            default: uni.$u.props.checkboxGroup.labelColor | 
				
			||||
        }, | 
				
			||||
        // 是否禁止点击文本操作
 | 
				
			||||
        labelDisabled: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.checkboxGroup.labelDisabled | 
				
			||||
        }, | 
				
			||||
        // 图标颜色
 | 
				
			||||
        iconColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.checkboxGroup.iconColor | 
				
			||||
        }, | 
				
			||||
        // 图标的大小,单位px
 | 
				
			||||
        iconSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.checkboxGroup.iconSize | 
				
			||||
        }, | 
				
			||||
        // 勾选图标的对齐方式,left-左边,right-右边
 | 
				
			||||
        iconPlacement: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.checkboxGroup.iconPlacement | 
				
			||||
        }, | 
				
			||||
        // 竖向配列时,是否显示下划线
 | 
				
			||||
        borderBottom: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.checkboxGroup.borderBottom | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,103 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view | 
				
			||||
	    class="u-checkbox-group" | 
				
			||||
	    :class="bemClass" | 
				
			||||
	> | 
				
			||||
		<slot></slot> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * checkboxGroup 复选框组 | 
				
			||||
	 * @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/checkbox.html | 
				
			||||
	 * @property {String}			name			标识符  | 
				
			||||
	 * @property {Array}			value			绑定的值 | 
				
			||||
	 * @property {String}			shape			形状,circle-圆形,square-方形 (默认 'square' ) | 
				
			||||
	 * @property {Boolean}			disabled		是否禁用全部checkbox (默认 false ) | 
				
			||||
	 * @property {String}			activeColor		选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值 (默认 '#2979ff' ) | 
				
			||||
	 * @property {String}			inactiveColor	未选中的颜色 (默认 '#c8c9cc' ) | 
				
			||||
	 * @property {String | Number}	size			整个组件的尺寸 单位px (默认 18 ) | 
				
			||||
	 * @property {String}			placement		布局方式,row-横向,column-纵向 (默认 'row' ) | 
				
			||||
	 * @property {String | Number}	labelSize		label的字体大小,px单位  (默认 14 ) | 
				
			||||
	 * @property {String}			labelColor		label的字体颜色 (默认 '#303133' ) | 
				
			||||
	 * @property {Boolean}			labelDisabled	是否禁止点击文本操作 (默认 false ) | 
				
			||||
	 * @property {String}			iconColor		图标颜色 (默认 '#ffffff' ) | 
				
			||||
	 * @property {String | Number}	iconSize		图标的大小,单位px (默认 12 ) | 
				
			||||
	 * @property {String}			iconPlacement	勾选图标的对齐方式,left-左边,right-右边  (默认 'left' ) | 
				
			||||
	 * @property {Boolean}			borderBottom	placement为row时,是否显示下边框 (默认 false ) | 
				
			||||
	 * @event {Function}	change	任一个checkbox状态发生变化时触发,回调为一个对象 | 
				
			||||
	 * @event {Function}	input	修改通过v-model绑定的值时触发,回调为一个对象 | 
				
			||||
	 * @example <u-checkbox-group></u-checkbox-group> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'u-checkbox-group', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin,props], | 
				
			||||
		computed: { | 
				
			||||
			// 这里computed的变量,都是子组件u-checkbox需要用到的,由于头条小程序的兼容性差异,子组件无法实时监听父组件参数的变化 | 
				
			||||
			// 所以需要手动通知子组件,这里返回一个parentData变量,供watch监听,在其中去通知每一个子组件重新从父组件(u-checkbox-group) | 
				
			||||
			// 拉取父组件新的变化后的参数 | 
				
			||||
			parentData() { | 
				
			||||
				return [this.value, this.disabled, this.inactiveColor, this.activeColor, this.size, this.labelDisabled, this.shape, | 
				
			||||
					this.iconSize, this.borderBottom, this.placement | 
				
			||||
				] | 
				
			||||
			}, | 
				
			||||
			bemClass() { | 
				
			||||
				// this.bem为一个computed变量,在mixin中 | 
				
			||||
				return this.bem('checkbox-group', ['placement']) | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
		watch: { | 
				
			||||
			// 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件 | 
				
			||||
			parentData() { | 
				
			||||
				if (this.children.length) { | 
				
			||||
					this.children.map(child => { | 
				
			||||
						// 判断子组件(u-checkbox)如果有init方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值) | 
				
			||||
						typeof(child.init) === 'function' && child.init() | 
				
			||||
					}) | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
 | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		created() { | 
				
			||||
			this.children = [] | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			// 将其他的checkbox设置为未选中的状态 | 
				
			||||
			unCheckedOther(childInstance) { | 
				
			||||
				const values = [] | 
				
			||||
				this.children.map(child => { | 
				
			||||
					// 将被选中的checkbox,放到数组中返回 | 
				
			||||
					if (child.isChecked) { | 
				
			||||
						values.push(child.name) | 
				
			||||
					} | 
				
			||||
				}) | 
				
			||||
				// 发出事件 | 
				
			||||
				this.$emit('change', values) | 
				
			||||
				// 修改通过v-model绑定的值 | 
				
			||||
				this.$emit('input', values) | 
				
			||||
			}, | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
	.u-checkbox-group { | 
				
			||||
 | 
				
			||||
		&--row { | 
				
			||||
			@include flex; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&--column { | 
				
			||||
			@include flex(column); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,69 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // checkbox的名称
 | 
				
			||||
        name: { | 
				
			||||
            type: [String, Number, Boolean], | 
				
			||||
            default: uni.$u.props.checkbox.name | 
				
			||||
        }, | 
				
			||||
        // 形状,square为方形,circle为圆型
 | 
				
			||||
        shape: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.checkbox.shape | 
				
			||||
        }, | 
				
			||||
        // 整体的大小
 | 
				
			||||
        size: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.checkbox.size | 
				
			||||
        }, | 
				
			||||
        // 是否默认选中
 | 
				
			||||
        checked: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.checkbox.checked | 
				
			||||
        }, | 
				
			||||
        // 是否禁用
 | 
				
			||||
        disabled: { | 
				
			||||
            type: [String, Boolean], | 
				
			||||
            default: uni.$u.props.checkbox.disabled | 
				
			||||
        }, | 
				
			||||
        // 选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值
 | 
				
			||||
        activeColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.checkbox.activeColor | 
				
			||||
        }, | 
				
			||||
        // 未选中的颜色
 | 
				
			||||
        inactiveColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.checkbox.inactiveColor | 
				
			||||
        }, | 
				
			||||
        // 图标的大小,单位px
 | 
				
			||||
        iconSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.checkbox.iconSize | 
				
			||||
        }, | 
				
			||||
        // 图标颜色
 | 
				
			||||
        iconColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.checkbox.iconColor | 
				
			||||
        }, | 
				
			||||
        // label提示文字,因为nvue下,直接slot进来的文字,由于特殊的结构,无法修改样式
 | 
				
			||||
        label: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.checkbox.label | 
				
			||||
        }, | 
				
			||||
        // label的字体大小,px单位
 | 
				
			||||
        labelSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.checkbox.labelSize | 
				
			||||
        }, | 
				
			||||
        // label的颜色
 | 
				
			||||
        labelColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.checkbox.labelColor | 
				
			||||
        }, | 
				
			||||
        // 是否禁止点击提示语选中复选框
 | 
				
			||||
        labelDisabled: { | 
				
			||||
            type: [String, Boolean], | 
				
			||||
            default: uni.$u.props.checkbox.labelDisabled | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,344 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view | 
				
			||||
	    class="u-checkbox" | 
				
			||||
	    :style="[checkboxStyle]" | 
				
			||||
	    @tap.stop="wrapperClickHandler" | 
				
			||||
	    :class="[`u-checkbox-label--${parentData.iconPlacement}`, parentData.borderBottom && parentData.placement === 'column' && 'u-border-bottom']" | 
				
			||||
	> | 
				
			||||
		<view | 
				
			||||
		    class="u-checkbox__icon-wrap" | 
				
			||||
		    @tap.stop="iconClickHandler" | 
				
			||||
		    :class="iconClasses" | 
				
			||||
		    :style="[iconWrapStyle]" | 
				
			||||
		> | 
				
			||||
			<slot name="icon"> | 
				
			||||
				<u-icon | 
				
			||||
				    class="u-checkbox__icon-wrap__icon" | 
				
			||||
				    name="checkbox-mark" | 
				
			||||
				    :size="elIconSize" | 
				
			||||
				    :color="elIconColor" | 
				
			||||
				/> | 
				
			||||
			</slot> | 
				
			||||
		</view> | 
				
			||||
		<text | 
				
			||||
		    @tap.stop="labelClickHandler" | 
				
			||||
		    :style="{ | 
				
			||||
				color: elDisabled ? elInactiveColor : elLabelColor, | 
				
			||||
				fontSize: elLabelSize, | 
				
			||||
				lineHeight: elLabelSize | 
				
			||||
			}" | 
				
			||||
		>{{label}}</text> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * checkbox  复选框 | 
				
			||||
	 * @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便 | 
				
			||||
	 * @tutorial https://uviewui.com/components/checkbox.html | 
				
			||||
	 * @property {String | Number | Boolean}	name			checkbox组件的标示符 | 
				
			||||
	 * @property {String}						shape			形状,square为方形,circle为圆型 | 
				
			||||
	 * @property {String | Number}				size			整体的大小 | 
				
			||||
	 * @property {Boolean}						checked			是否默认选中 | 
				
			||||
	 * @property {String | Boolean}				disabled		是否禁用 | 
				
			||||
	 * @property {String}						activeColor		选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值 | 
				
			||||
	 * @property {String}						inactiveColor	未选中的颜色 | 
				
			||||
	 * @property {String | Number}				iconSize		图标的大小,单位px | 
				
			||||
	 * @property {String}						iconColor		图标颜色 | 
				
			||||
	 * @property {String | Number}				label			label提示文字,因为nvue下,直接slot进来的文字,由于特殊的结构,无法修改样式 | 
				
			||||
	 * @property {String}						labelColor 		label的颜色 | 
				
			||||
	 * @property {String | Number}				labelSize		label的字体大小,px单位 | 
				
			||||
	 * @property {String | Boolean}				labelDisabled	是否禁止点击提示语选中复选框 | 
				
			||||
	 * @property {Object}						customStyle		定义需要用到的外部样式 | 
				
			||||
	 *  | 
				
			||||
	 * @event {Function}	change	任一个checkbox状态发生变化时触发,回调为一个对象 | 
				
			||||
	 * @example <u-checkbox v-model="checked" :disabled="false">天涯</u-checkbox> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: "u-checkbox", | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin,props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				isChecked: false, | 
				
			||||
				// 父组件的默认值,因为头条小程序不支持在computed中使用this.parent.shape的形式 | 
				
			||||
				// 故只能使用如此方法 | 
				
			||||
				parentData: { | 
				
			||||
					iconSize: 12, | 
				
			||||
					labelDisabled: null, | 
				
			||||
					disabled: null, | 
				
			||||
					shape: 'square', | 
				
			||||
					activeColor: null, | 
				
			||||
					inactiveColor: null, | 
				
			||||
					size: 18, | 
				
			||||
					value: null, | 
				
			||||
					iconColor: null, | 
				
			||||
					placement: 'row', | 
				
			||||
					borderBottom: false, | 
				
			||||
					iconPlacement: 'left' | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			// 是否禁用,如果父组件u-raios-group禁用的话,将会忽略子组件的配置 | 
				
			||||
			elDisabled() { | 
				
			||||
				return this.disabled !== '' ? this.disabled : this.parentData.disabled !== null ? this.parentData.disabled : false; | 
				
			||||
			}, | 
				
			||||
			// 是否禁用label点击 | 
				
			||||
			elLabelDisabled() { | 
				
			||||
				return this.labelDisabled !== '' ? this.labelDisabled : this.parentData.labelDisabled !== null ? this.parentData.labelDisabled : | 
				
			||||
					false; | 
				
			||||
			}, | 
				
			||||
			// 组件尺寸,对应size的值,默认值为21px | 
				
			||||
			elSize() { | 
				
			||||
				return this.size ? this.size : (this.parentData.size ? this.parentData.size : 21); | 
				
			||||
			}, | 
				
			||||
			// 组件的勾选图标的尺寸,默认12px | 
				
			||||
			elIconSize() { | 
				
			||||
				return this.iconSize ? this.iconSize : (this.parentData.iconSize ? this.parentData.iconSize : 12); | 
				
			||||
			}, | 
				
			||||
			// 组件选中激活时的颜色 | 
				
			||||
			elActiveColor() { | 
				
			||||
				return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : '#2979ff'); | 
				
			||||
			}, | 
				
			||||
			// 组件选未中激活时的颜色 | 
				
			||||
			elInactiveColor() { | 
				
			||||
				return this.inactiveColor ? this.inactiveColor : (this.parentData.inactiveColor ? this.parentData.inactiveColor : | 
				
			||||
					'#c8c9cc'); | 
				
			||||
			}, | 
				
			||||
			// label的颜色 | 
				
			||||
			elLabelColor() { | 
				
			||||
				return this.labelColor ? this.labelColor : (this.parentData.labelColor ? this.parentData.labelColor : '#606266') | 
				
			||||
			}, | 
				
			||||
			// 组件的形状 | 
				
			||||
			elShape() { | 
				
			||||
				return this.shape ? this.shape : (this.parentData.shape ? this.parentData.shape : 'circle'); | 
				
			||||
			}, | 
				
			||||
			// label大小 | 
				
			||||
			elLabelSize() { | 
				
			||||
				return uni.$u.addUnit(this.labelSize ? this.labelSize : (this.parentData.labelSize ? this.parentData.labelSize : | 
				
			||||
					'15')) | 
				
			||||
			}, | 
				
			||||
			elIconColor() { | 
				
			||||
				const iconColor = this.iconColor ? this.iconColor : (this.parentData.iconColor ? this.parentData.iconColor : | 
				
			||||
					'#ffffff'); | 
				
			||||
				// 图标的颜色 | 
				
			||||
				if (this.elDisabled) { | 
				
			||||
					// disabled状态下,已勾选的checkbox图标改为elInactiveColor | 
				
			||||
					return this.isChecked ? this.elInactiveColor : 'transparent' | 
				
			||||
				} else { | 
				
			||||
					return this.isChecked ? iconColor : 'transparent' | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			iconClasses() { | 
				
			||||
				let classes = [] | 
				
			||||
				// 组件的形状 | 
				
			||||
				classes.push('u-checkbox__icon-wrap--' + this.elShape) | 
				
			||||
				if (this.elDisabled) { | 
				
			||||
					classes.push('u-checkbox__icon-wrap--disabled') | 
				
			||||
				} | 
				
			||||
				if (this.isChecked && this.elDisabled) { | 
				
			||||
					classes.push('u-checkbox__icon-wrap--disabled--checked') | 
				
			||||
				} | 
				
			||||
				// 支付宝,头条小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效 | 
				
			||||
				// #ifdef MP-ALIPAY || MP-TOUTIAO | 
				
			||||
				classes = classes.join(' ') | 
				
			||||
				// #endif | 
				
			||||
				return classes | 
				
			||||
			}, | 
				
			||||
			iconWrapStyle() { | 
				
			||||
				// checkbox的整体样式 | 
				
			||||
				const style = {} | 
				
			||||
				style.backgroundColor = this.isChecked && !this.elDisabled ? this.elActiveColor : '#ffffff' | 
				
			||||
				style.borderColor = this.isChecked && !this.elDisabled ? this.elActiveColor : this.elInactiveColor | 
				
			||||
				style.width = uni.$u.addUnit(this.elSize) | 
				
			||||
				style.height = uni.$u.addUnit(this.elSize) | 
				
			||||
				// 如果是图标在右边的话,移除它的右边距 | 
				
			||||
				if (this.parentData.iconPlacement === 'right') { | 
				
			||||
					style.marginRight = 0 | 
				
			||||
				} | 
				
			||||
				return style | 
				
			||||
			}, | 
				
			||||
			checkboxStyle() { | 
				
			||||
				const style = {} | 
				
			||||
				if (this.parentData.borderBottom && this.parentData.placement === 'row') { | 
				
			||||
					uni.$u.error('检测到您将borderBottom设置为true,需要同时将u-checkbox-group的placement设置为column才有效') | 
				
			||||
				} | 
				
			||||
				// 当父组件设置了显示下边框并且排列形式为纵向时,给内容和边框之间加上一定间隔 | 
				
			||||
				if (this.parentData.borderBottom && this.parentData.placement === 'column') { | 
				
			||||
					style.paddingBottom = '8px' | 
				
			||||
				} | 
				
			||||
				return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle)) | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		mounted() { | 
				
			||||
			this.init() | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			init() { | 
				
			||||
				// 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环引用 | 
				
			||||
				this.updateParentData() | 
				
			||||
				if (!this.parent) { | 
				
			||||
					uni.$u.error('u-checkbox必须搭配u-checkbox-group组件使用') | 
				
			||||
				} | 
				
			||||
				// 设置初始化时,是否默认选中的状态,父组件u-checkbox-group的value可能是array,所以额外判断 | 
				
			||||
				if (this.checked) { | 
				
			||||
					this.isChecked = true | 
				
			||||
				} else if (uni.$u.test.array(this.parentData.value)) { | 
				
			||||
					// 查找数组是是否存在this.name元素值 | 
				
			||||
					this.isChecked = this.parentData.value.some(item => { | 
				
			||||
						return item === this.name | 
				
			||||
					}) | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			updateParentData() { | 
				
			||||
				this.getParentData('u-checkbox-group') | 
				
			||||
			}, | 
				
			||||
			// 横向两端排列时,点击组件即可触发选中事件 | 
				
			||||
			wrapperClickHandler(e) { | 
				
			||||
				this.parentData.iconPlacement === 'right' && this.iconClickHandler(e) | 
				
			||||
			}, | 
				
			||||
			// 点击图标 | 
				
			||||
			iconClickHandler(e) { | 
				
			||||
				this.preventEvent(e) | 
				
			||||
				// 如果整体被禁用,不允许被点击 | 
				
			||||
				if (!this.elDisabled) { | 
				
			||||
					this.setRadioCheckedStatus() | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			// 点击label | 
				
			||||
			labelClickHandler(e) { | 
				
			||||
				this.preventEvent(e) | 
				
			||||
				// 如果按钮整体被禁用或者label被禁用,则不允许点击文字修改状态 | 
				
			||||
				if (!this.elLabelDisabled && !this.elDisabled) { | 
				
			||||
					this.setRadioCheckedStatus() | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			emitEvent() { | 
				
			||||
				this.$emit('change', this.isChecked) | 
				
			||||
				// 尝试调用u-form的验证方法,进行一定延迟,否则微信小程序更新可能会不及时 | 
				
			||||
				this.$nextTick(() => { | 
				
			||||
					uni.$u.formValidate(this, 'change') | 
				
			||||
				}) | 
				
			||||
			}, | 
				
			||||
			// 改变组件选中状态 | 
				
			||||
			// 这里的改变的依据是,更改本组件的checked值为true,同时通过父组件遍历所有u-checkbox实例 | 
				
			||||
			// 将本组件外的其他u-checkbox的checked都设置为false(都被取消选中状态),因而只剩下一个为选中状态 | 
				
			||||
			setRadioCheckedStatus() { | 
				
			||||
				// 将本组件标记为与原来相反的状态 | 
				
			||||
				this.isChecked = !this.isChecked | 
				
			||||
				this.emitEvent() | 
				
			||||
				typeof this.parent.unCheckedOther === 'function' && this.parent.unCheckedOther(this) | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		watch:{ | 
				
			||||
			checked(){ | 
				
			||||
				this.isChecked = this.checked | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
	$u-checkbox-icon-wrap-margin-right:6px !default; | 
				
			||||
	$u-checkbox-icon-wrap-font-size:6px !default; | 
				
			||||
	$u-checkbox-icon-wrap-border-width:1px !default; | 
				
			||||
	$u-checkbox-icon-wrap-border-color:#c8c9cc !default; | 
				
			||||
	$u-checkbox-icon-wrap-icon-line-height:0 !default; | 
				
			||||
	$u-checkbox-icon-wrap-circle-border-radius:100% !default; | 
				
			||||
	$u-checkbox-icon-wrap-square-border-radius:3px !default; | 
				
			||||
	$u-checkbox-icon-wrap-checked-color:#fff !default; | 
				
			||||
	$u-checkbox-icon-wrap-checked-background-color:red !default; | 
				
			||||
	$u-checkbox-icon-wrap-checked-border-color:#2979ff !default; | 
				
			||||
	$u-checkbox-icon-wrap-disabled-background-color:#ebedf0 !default; | 
				
			||||
	$u-checkbox-icon-wrap-disabled-checked-color:#c8c9cc !default; | 
				
			||||
	$u-checkbox-label-margin-left:5px !default; | 
				
			||||
	$u-checkbox-label-margin-right:12px !default; | 
				
			||||
	$u-checkbox-label-color:$u-content-color !default; | 
				
			||||
	$u-checkbox-label-font-size:15px !default; | 
				
			||||
	$u-checkbox-label-disabled-color:#c8c9cc !default; | 
				
			||||
 | 
				
			||||
	.u-checkbox { | 
				
			||||
		/* #ifndef APP-NVUE */ | 
				
			||||
		@include flex(row); | 
				
			||||
		/* #endif */ | 
				
			||||
		overflow: hidden; | 
				
			||||
		flex-direction: row; | 
				
			||||
		align-items: center; | 
				
			||||
 | 
				
			||||
		&-label--left { | 
				
			||||
			flex-direction: row | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&-label--right { | 
				
			||||
			flex-direction: row-reverse; | 
				
			||||
			justify-content: space-between | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__icon-wrap { | 
				
			||||
			/* #ifndef APP-NVUE */ | 
				
			||||
			box-sizing: border-box; | 
				
			||||
			// nvue下,border-color过渡有问题 | 
				
			||||
			transition-property: border-color, background-color, color; | 
				
			||||
			transition-duration: 0.2s; | 
				
			||||
			/* #endif */ | 
				
			||||
			color: $u-content-color; | 
				
			||||
			@include flex; | 
				
			||||
			align-items: center; | 
				
			||||
			justify-content: center; | 
				
			||||
			color: transparent; | 
				
			||||
			text-align: center; | 
				
			||||
			margin-right: $u-checkbox-icon-wrap-margin-right; | 
				
			||||
 | 
				
			||||
			font-size: $u-checkbox-icon-wrap-font-size; | 
				
			||||
			border-width: $u-checkbox-icon-wrap-border-width; | 
				
			||||
			border-color: $u-checkbox-icon-wrap-border-color; | 
				
			||||
			border-style: solid; | 
				
			||||
 | 
				
			||||
			/* #ifdef MP-TOUTIAO */ | 
				
			||||
			// 头条小程序兼容性问题,需要设置行高为0,否则图标偏下 | 
				
			||||
			&__icon { | 
				
			||||
				line-height: $u-checkbox-icon-wrap-icon-line-height; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			/* #endif */ | 
				
			||||
 | 
				
			||||
			&--circle { | 
				
			||||
				border-radius: $u-checkbox-icon-wrap-circle-border-radius; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&--square { | 
				
			||||
				border-radius: $u-checkbox-icon-wrap-square-border-radius; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&--checked { | 
				
			||||
				color: $u-checkbox-icon-wrap-checked-color; | 
				
			||||
				background-color: $u-checkbox-icon-wrap-checked-background-color; | 
				
			||||
				border-color: $u-checkbox-icon-wrap-checked-border-color; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&--disabled { | 
				
			||||
				background-color: $u-checkbox-icon-wrap-disabled-background-color !important; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&--disabled--checked { | 
				
			||||
				color: $u-checkbox-icon-wrap-disabled-checked-color !important; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__label { | 
				
			||||
			/* #ifndef APP-NVUE */ | 
				
			||||
			word-wrap: break-word; | 
				
			||||
			/* #endif */ | 
				
			||||
			margin-left: $u-checkbox-label-margin-left; | 
				
			||||
			margin-right: $u-checkbox-label-margin-right; | 
				
			||||
			color: $u-checkbox-label-color; | 
				
			||||
			font-size: $u-checkbox-label-font-size; | 
				
			||||
 | 
				
			||||
			&--disabled { | 
				
			||||
				color: $u-checkbox-label-disabled-color; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,8 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        percentage: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.circleProgress.percentage | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,198 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="u-circle-progress"> | 
				
			||||
		<view class="u-circle-progress__left"> | 
				
			||||
			<view | 
				
			||||
			    class="u-circle-progress__left__circle" | 
				
			||||
			    :style="[leftSyle]" | 
				
			||||
			    ref="left-circle" | 
				
			||||
			> | 
				
			||||
 | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
		<view | 
				
			||||
		    class="u-circle-progress__right" | 
				
			||||
		> | 
				
			||||
			<view | 
				
			||||
			    class="u-circle-progress__right__circle" | 
				
			||||
			    ref="right-circle" | 
				
			||||
				:style="[rightSyle]" | 
				
			||||
			> | 
				
			||||
 | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
		<view class="u-circle-progress__circle"> | 
				
			||||
 | 
				
			||||
		</view> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	// #ifdef APP-NVUE | 
				
			||||
	const animation = uni.requireNativePlugin('animation') | 
				
			||||
	// #endif | 
				
			||||
	/** | 
				
			||||
	 * CircleProgress 圆形进度条 TODO: 待完善  | 
				
			||||
	 * @description 展示操作或任务的当前进度,比如上传文件,是一个圆形的进度环。 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/circleProgress.html | 
				
			||||
	 * @property {String | Number}	percentage	圆环进度百分比值,为数值类型,0-100 (默认 30 ) | 
				
			||||
	 * @example | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'u-circle-progress', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin,props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				leftBorderColor: 'rgb(200, 200, 200)', | 
				
			||||
				rightBorderColor: 'rgb(200, 200, 200)', | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			leftSyle() { | 
				
			||||
				const style = {} | 
				
			||||
				style.borderTopColor = this.leftBorderColor | 
				
			||||
				style.borderRightColor = this.leftBorderColor | 
				
			||||
				return style | 
				
			||||
			}, | 
				
			||||
			rightSyle() { | 
				
			||||
				const style = {} | 
				
			||||
				style.borderLeftColor = this.rightBorderColor | 
				
			||||
				style.borderBottomColor = this.rightBorderColor | 
				
			||||
				return style | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		mounted() { | 
				
			||||
			uni.$u.sleep().then(() => { | 
				
			||||
				this.rightBorderColor = 'rgb(66, 185, 131)' | 
				
			||||
				// this.init() | 
				
			||||
			}) | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			init() { | 
				
			||||
				animation.transition(this.$refs['right-circle'].ref, { | 
				
			||||
					styles: { | 
				
			||||
						transform: 'rotate(45deg)', | 
				
			||||
						transformOrigin: 'center center' | 
				
			||||
					}, | 
				
			||||
				}, () => { | 
				
			||||
					this.rightBorderColor = 'rgb(66, 185, 131)' | 
				
			||||
					// animation.transition(this.$refs['right-circle'].ref, { | 
				
			||||
					// 	styles: { | 
				
			||||
					// 		transform: 'rotate(225deg)', | 
				
			||||
					// 		transformOrigin: 'center center' | 
				
			||||
					// 	}, | 
				
			||||
					// 	duration: 3000, | 
				
			||||
					// }, () => { | 
				
			||||
					// 	animation.transition(this.$refs['left-circle'].ref, { | 
				
			||||
					// 		styles: { | 
				
			||||
					// 			transform: 'rotate(45deg)', | 
				
			||||
					// 			transformOrigin: 'center center' | 
				
			||||
					// 		}, | 
				
			||||
					// 	}, () => { | 
				
			||||
					// 		this.leftBorderColor = 'rgb(66, 185, 131)' | 
				
			||||
					// 		animation.transition(this.$refs['left-circle'].ref, { | 
				
			||||
					// 			styles: { | 
				
			||||
					// 				transform: 'rotate(225deg)', | 
				
			||||
					// 				transformOrigin: 'center center' | 
				
			||||
					// 			}, | 
				
			||||
					// 			duration: 1500, | 
				
			||||
					// 		}, () => { | 
				
			||||
 | 
				
			||||
					// 		}) | 
				
			||||
					// 	}) | 
				
			||||
					// }) | 
				
			||||
				}) | 
				
			||||
 | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
	.u-circle-progress { | 
				
			||||
		@include flex(row); | 
				
			||||
		position: relative; | 
				
			||||
		border-radius: 100px; | 
				
			||||
		height: 100px; | 
				
			||||
		width: 100px; | 
				
			||||
		// transform: rotate(0deg); | 
				
			||||
		// background-color: rgb(66, 185, 131); | 
				
			||||
		background-color: rgb(200, 200, 200); | 
				
			||||
		overflow: hidden; | 
				
			||||
		justify-content: space-between; | 
				
			||||
 | 
				
			||||
		&__circle { | 
				
			||||
			border-radius: 100px; | 
				
			||||
			height: 90px; | 
				
			||||
			width: 90px; | 
				
			||||
			transform: translate(-50%, -50%); | 
				
			||||
			background-color: rgb(255, 255, 255); | 
				
			||||
			left: 50px; | 
				
			||||
			top: 50px; | 
				
			||||
			position: absolute; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__left { | 
				
			||||
			position: absolute; | 
				
			||||
			left: 0; | 
				
			||||
			width: 50px; | 
				
			||||
			height: 100px; | 
				
			||||
			overflow: hidden; | 
				
			||||
			box-sizing: border-box; | 
				
			||||
			// background-color: rgb(66, 185, 131); | 
				
			||||
			// background-color: rgb(200, 200, 200); | 
				
			||||
			// transform-origin: left center; | 
				
			||||
 | 
				
			||||
			&__circle { | 
				
			||||
				box-sizing: border-box; | 
				
			||||
				// background-color: red; | 
				
			||||
				border-left-color: transparent; | 
				
			||||
				border-bottom-color: transparent; | 
				
			||||
				border-top-left-radius: 50px; | 
				
			||||
				border-top-right-radius: 50px; | 
				
			||||
				border-bottom-right-radius: 50px; | 
				
			||||
				// border-left-color: rgb(66, 185, 131); | 
				
			||||
				// border-bottom-color: rgb(66, 185, 131); | 
				
			||||
				border-top-color: rgb(66, 185, 131); | 
				
			||||
				border-right-color: rgb(66, 185, 131); | 
				
			||||
				border-width: 5px; | 
				
			||||
				width: 100px; | 
				
			||||
				height: 100px; | 
				
			||||
				transform: rotate(225deg); | 
				
			||||
				// border-radius: 100px; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__right { | 
				
			||||
			position: absolute; | 
				
			||||
			right: 0; | 
				
			||||
			width: 50px; | 
				
			||||
			height: 100px; | 
				
			||||
			overflow: hidden; | 
				
			||||
 | 
				
			||||
			&__circle { | 
				
			||||
				position: absolute; | 
				
			||||
				right: 0; | 
				
			||||
				box-sizing: border-box; | 
				
			||||
				// background-color: red; | 
				
			||||
				border-top-color: transparent; | 
				
			||||
				border-right-color: transparent; | 
				
			||||
				border-top-left-radius: 50px; | 
				
			||||
				border-bottom-left-radius: 50px; | 
				
			||||
				border-bottom-right-radius: 50px; | 
				
			||||
				// border-left-color: rgb(66, 185, 131); | 
				
			||||
				// border-bottom-color: rgb(66, 185, 131); | 
				
			||||
				border-left-color: rgb(200, 200, 200); | 
				
			||||
				border-bottom-color: rgb(200, 200, 200); | 
				
			||||
				border-width: 5px; | 
				
			||||
				width: 100px; | 
				
			||||
				height: 100px; | 
				
			||||
				transform: rotate(45deg); | 
				
			||||
				transform-origin: center center; | 
				
			||||
				// border-radius: 100px; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,79 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
		// 键盘弹起时,是否自动上推页面
 | 
				
			||||
		adjustPosition: { | 
				
			||||
			type: Boolean, | 
				
			||||
            default: uni.$u.props.codeInput.adjustPosition | 
				
			||||
		}, | 
				
			||||
        // 最大输入长度
 | 
				
			||||
        maxlength: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.codeInput.maxlength | 
				
			||||
        }, | 
				
			||||
        // 是否用圆点填充
 | 
				
			||||
        dot: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.codeInput.dot | 
				
			||||
        }, | 
				
			||||
        // 显示模式,box-盒子模式,line-底部横线模式
 | 
				
			||||
        mode: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.codeInput.mode | 
				
			||||
        }, | 
				
			||||
        // 是否细边框
 | 
				
			||||
        hairline: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.codeInput.hairline | 
				
			||||
        }, | 
				
			||||
        // 字符间的距离
 | 
				
			||||
        space: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.codeInput.space | 
				
			||||
        }, | 
				
			||||
        // 预置值
 | 
				
			||||
        value: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.codeInput.value | 
				
			||||
        }, | 
				
			||||
        // 是否自动获取焦点
 | 
				
			||||
        focus: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.codeInput.focus | 
				
			||||
        }, | 
				
			||||
        // 字体是否加粗
 | 
				
			||||
        bold: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.codeInput.bold | 
				
			||||
        }, | 
				
			||||
        // 字体颜色
 | 
				
			||||
        color: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.codeInput.color | 
				
			||||
        }, | 
				
			||||
        // 字体大小
 | 
				
			||||
        fontSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.codeInput.fontSize | 
				
			||||
        }, | 
				
			||||
        // 输入框的大小,宽等于高
 | 
				
			||||
        size: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.codeInput.size | 
				
			||||
        }, | 
				
			||||
        // 是否隐藏原生键盘,如果想用自定义键盘的话,需设置此参数为true
 | 
				
			||||
        disabledKeyboard: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.codeInput.disabledKeyboard | 
				
			||||
        }, | 
				
			||||
        // 边框和线条颜色
 | 
				
			||||
        borderColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.codeInput.borderColor | 
				
			||||
        }, | 
				
			||||
		// 是否禁止输入"."符号
 | 
				
			||||
		disabledDot: { | 
				
			||||
			type: Boolean, | 
				
			||||
			default: uni.$u.props.codeInput.disabledDot | 
				
			||||
		} | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,252 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="u-code-input"> | 
				
			||||
		<view | 
				
			||||
			class="u-code-input__item" | 
				
			||||
			:style="[itemStyle(index)]" | 
				
			||||
			v-for="(item, index) in codeLength" | 
				
			||||
			:key="index" | 
				
			||||
		> | 
				
			||||
			<view | 
				
			||||
				class="u-code-input__item__dot" | 
				
			||||
				v-if="dot && codeArray.length > index" | 
				
			||||
			></view> | 
				
			||||
			<text | 
				
			||||
				v-else | 
				
			||||
				:style="{ | 
				
			||||
					fontSize: $u.addUnit(fontSize), | 
				
			||||
					fontWeight: bold ? 'bold' : 'normal', | 
				
			||||
					color: color | 
				
			||||
				}" | 
				
			||||
			>{{codeArray[index]}}</text> | 
				
			||||
			<view | 
				
			||||
				class="u-code-input__item__line" | 
				
			||||
				v-if="mode === 'line'" | 
				
			||||
				:style="[lineStyle]" | 
				
			||||
			></view> | 
				
			||||
			<!-- #ifndef APP-PLUS --> | 
				
			||||
			<view v-if="isFocus && codeArray.length === index" :style="{backgroundColor: color}" class="u-code-input__item__cursor"></view> | 
				
			||||
			<!-- #endif --> | 
				
			||||
		</view> | 
				
			||||
		<input | 
				
			||||
			:disabled="disabledKeyboard" | 
				
			||||
			type="number" | 
				
			||||
			:focus="focus" | 
				
			||||
			:value="inputValue" | 
				
			||||
			:maxlength="maxlength" | 
				
			||||
			:adjustPosition="adjustPosition" | 
				
			||||
			class="u-code-input__input" | 
				
			||||
			@input="inputHandler" | 
				
			||||
			:style="{ | 
				
			||||
				height: $u.addUnit(size)  | 
				
			||||
			}" | 
				
			||||
			@focus="isFocus = true" | 
				
			||||
			@blur="isFocus = false" | 
				
			||||
		/> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * CodeInput 验证码输入 | 
				
			||||
	 * @description 该组件一般用于验证用户短信验证码的场景,也可以结合uView的键盘组件使用 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/codeInput.html | 
				
			||||
	 * @property {String | Number}	maxlength			最大输入长度 (默认 6 ) | 
				
			||||
	 * @property {Boolean}			dot					是否用圆点填充 (默认 false ) | 
				
			||||
	 * @property {String}			mode				显示模式,box-盒子模式,line-底部横线模式 (默认 'box' ) | 
				
			||||
	 * @property {Boolean}			hairline			是否细边框 (默认 false ) | 
				
			||||
	 * @property {String | Number}	space				字符间的距离 (默认 10 ) | 
				
			||||
	 * @property {String | Number}	value				预置值 | 
				
			||||
	 * @property {Boolean}			focus				是否自动获取焦点 (默认 false ) | 
				
			||||
	 * @property {Boolean}			bold				字体和输入横线是否加粗 (默认 false ) | 
				
			||||
	 * @property {String}			color				字体颜色 (默认 '#606266' ) | 
				
			||||
	 * @property {String | Number}	fontSize			字体大小,单位px (默认 18 ) | 
				
			||||
	 * @property {String | Number}	size				输入框的大小,宽等于高 (默认 35 ) | 
				
			||||
	 * @property {Boolean}			disabledKeyboard	是否隐藏原生键盘,如果想用自定义键盘的话,需设置此参数为true (默认 false ) | 
				
			||||
	 * @property {String}			borderColor			边框和线条颜色 (默认 '#c9cacc' ) | 
				
			||||
	 * @property {Boolean}			disabledDot			是否禁止输入"."符号 (默认 true ) | 
				
			||||
	 *  | 
				
			||||
	 * @event {Function}	change	输入内容发生改变时触发,具体见上方说明			value:当前输入的值 | 
				
			||||
	 * @event {Function}	finish	输入字符个数达maxlength值时触发,见上方说明	value:当前输入的值 | 
				
			||||
	 * @example	<u-code-input v-model="value4" :focus="true"></u-code-input> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'u-code-input', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				inputValue: '', | 
				
			||||
				isFocus: this.focus | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		watch: { | 
				
			||||
			value: { | 
				
			||||
				immediate: true, | 
				
			||||
				handler(val) { | 
				
			||||
					// 转为字符串,超出部分截掉 | 
				
			||||
					this.inputValue = String(val).substring(0, this.maxlength) | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			// 根据长度,循环输入框的个数,因为头条小程序数值不能用于v-for | 
				
			||||
			codeLength() { | 
				
			||||
				return new Array(Number(this.maxlength)) | 
				
			||||
			}, | 
				
			||||
			// 循环item的样式 | 
				
			||||
			itemStyle() { | 
				
			||||
				return index => { | 
				
			||||
					const addUnit = uni.$u.addUnit | 
				
			||||
					const style = { | 
				
			||||
						width: addUnit(this.size), | 
				
			||||
						height: addUnit(this.size) | 
				
			||||
					} | 
				
			||||
					// 盒子模式下,需要额外进行处理 | 
				
			||||
					if (this.mode === 'box') { | 
				
			||||
						// 设置盒子的边框,如果是细边框,则设置为0.5px宽度 | 
				
			||||
						style.border = `${this.hairline ? 0.5 : 1}px solid ${this.borderColor}` | 
				
			||||
						// 如果盒子间距为0的话 | 
				
			||||
						if (uni.$u.getPx(this.space) === 0) { | 
				
			||||
							// 给第一和最后一个盒子设置圆角 | 
				
			||||
							if (index === 0) { | 
				
			||||
								style.borderTopLeftRadius = '3px' | 
				
			||||
								style.borderBottomLeftRadius = '3px' | 
				
			||||
							} | 
				
			||||
							if (index === this.codeLength.length - 1) { | 
				
			||||
								style.borderTopRightRadius = '3px' | 
				
			||||
								style.borderBottomRightRadius = '3px' | 
				
			||||
							} | 
				
			||||
							// 最后一个盒子的右边框需要保留 | 
				
			||||
							if (index !== this.codeLength.length - 1) { | 
				
			||||
								style.borderRight = 'none' | 
				
			||||
							} | 
				
			||||
						} | 
				
			||||
					} | 
				
			||||
					if (index !== this.codeLength.length - 1) { | 
				
			||||
						// 设置验证码字符之间的距离,通过margin-right设置,最后一个字符,无需右边框 | 
				
			||||
						style.marginRight = addUnit(this.space) | 
				
			||||
					} else { | 
				
			||||
						// 最后一个盒子的有边框需要保留 | 
				
			||||
						style.marginRight = 0 | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					return style | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			// 将输入的值,转为数组,给item历遍时,根据当前的索引显示数组的元素 | 
				
			||||
			codeArray() { | 
				
			||||
				return String(this.inputValue).split('') | 
				
			||||
			}, | 
				
			||||
			// 下划线模式下,横线的样式 | 
				
			||||
			lineStyle() { | 
				
			||||
				const style = {} | 
				
			||||
				style.height = this.hairline ? '2px' : '4px' | 
				
			||||
				style.width = uni.$u.addUnit(this.size) | 
				
			||||
				// 线条模式下,背景色即为边框颜色 | 
				
			||||
				style.backgroundColor = this.borderColor | 
				
			||||
				return style | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			// 监听输入框的值发生变化 | 
				
			||||
			inputHandler(e) { | 
				
			||||
				const value = e.detail.value | 
				
			||||
				this.inputValue = value | 
				
			||||
				// 是否允许输入“.”符号 | 
				
			||||
				if(this.disabledDot) { | 
				
			||||
					this.$nextTick(() => { | 
				
			||||
						this.inputValue = value.replace('.', '') | 
				
			||||
					}) | 
				
			||||
				} | 
				
			||||
				// 未达到maxlength之前,发送change事件,达到后发送finish事件 | 
				
			||||
				this.$emit('change', value) | 
				
			||||
				// 修改通过v-model双向绑定的值 | 
				
			||||
				this.$emit('input', value) | 
				
			||||
				// 达到用户指定输入长度时,发出完成事件 | 
				
			||||
				if (String(value).length >= Number(this.maxlength)) { | 
				
			||||
					this.$emit('finish', value) | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
	$u-code-input-cursor-width: 1px; | 
				
			||||
	$u-code-input-cursor-height: 40%; | 
				
			||||
	$u-code-input-cursor-animation-duration: 1s; | 
				
			||||
	$u-code-input-cursor-animation-name: u-cursor-flicker; | 
				
			||||
 | 
				
			||||
	.u-code-input { | 
				
			||||
		@include flex; | 
				
			||||
		position: relative; | 
				
			||||
		overflow: hidden; | 
				
			||||
 | 
				
			||||
		&__item { | 
				
			||||
			@include flex; | 
				
			||||
			justify-content: center; | 
				
			||||
			align-items: center; | 
				
			||||
			position: relative; | 
				
			||||
 | 
				
			||||
			&__text { | 
				
			||||
				font-size: 15px; | 
				
			||||
				color: $u-content-color; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&__dot { | 
				
			||||
				width: 7px; | 
				
			||||
				height: 7px; | 
				
			||||
				border-radius: 100px; | 
				
			||||
				background-color: $u-content-color; | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&__line { | 
				
			||||
				position: absolute; | 
				
			||||
				bottom: 0; | 
				
			||||
				height: 4px; | 
				
			||||
				border-radius: 100px; | 
				
			||||
				width: 40px; | 
				
			||||
				background-color: $u-content-color; | 
				
			||||
			} | 
				
			||||
			/* #ifndef APP-PLUS */ | 
				
			||||
			&__cursor { | 
				
			||||
				position: absolute; | 
				
			||||
				top: 50%; | 
				
			||||
				left: 50%; | 
				
			||||
				transform: translate(-50%,-50%); | 
				
			||||
				width: $u-code-input-cursor-width; | 
				
			||||
				height: $u-code-input-cursor-height; | 
				
			||||
				animation: $u-code-input-cursor-animation-duration u-cursor-flicker infinite; | 
				
			||||
			} | 
				
			||||
			/* #endif */ | 
				
			||||
			 | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__input { | 
				
			||||
			// 之所以需要input输入框,是因为有它才能唤起键盘 | 
				
			||||
			// 这里将它设置为两倍的屏幕宽度,再将左边的一半移出屏幕,为了不让用户看到输入的内容 | 
				
			||||
			position: absolute; | 
				
			||||
			left: -750rpx; | 
				
			||||
			width: 1500rpx; | 
				
			||||
			top: 0; | 
				
			||||
			background-color: transparent; | 
				
			||||
			text-align: left; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
	 | 
				
			||||
	/* #ifndef APP-PLUS */ | 
				
			||||
	@keyframes u-cursor-flicker { | 
				
			||||
		0% { | 
				
			||||
		    opacity: 0; | 
				
			||||
		} | 
				
			||||
		50% { | 
				
			||||
		    opacity: 1; | 
				
			||||
		} | 
				
			||||
		100% { | 
				
			||||
		    opacity: 0; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
	/* #endif */ | 
				
			||||
 | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,34 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 倒计时总秒数
 | 
				
			||||
        seconds: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.code.seconds | 
				
			||||
        }, | 
				
			||||
        // 尚未开始时提示
 | 
				
			||||
        startText: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.code.startText | 
				
			||||
        }, | 
				
			||||
        // 正在倒计时中的提示
 | 
				
			||||
        changeText: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.code.changeText | 
				
			||||
        }, | 
				
			||||
        // 倒计时结束时的提示
 | 
				
			||||
        endText: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.code.endText | 
				
			||||
        }, | 
				
			||||
        // 是否在H5刷新或各端返回再进入时继续倒计时
 | 
				
			||||
        keepRunning: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.code.keepRunning | 
				
			||||
        }, | 
				
			||||
        // 为了区分多个页面,或者一个页面多个倒计时组件本地存储的继续倒计时变了
 | 
				
			||||
        uniqueKey: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.code.uniqueKey | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,129 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="u-code"> | 
				
			||||
		<!-- 此组件功能由js完成,无需写html逻辑 --> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * Code 验证码输入框 | 
				
			||||
	 * @description 考虑到用户实际发送验证码的场景,可能是一个按钮,也可能是一段文字,提示语各有不同,所以本组件 不提供界面显示,只提供提示语,由用户将提示语嵌入到具体的场景 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/code.html | 
				
			||||
	 * @property {String | Number}	seconds			倒计时所需的秒数(默认 60 ) | 
				
			||||
	 * @property {String}			startText		开始前的提示语,见官网说明(默认 '获取验证码' ) | 
				
			||||
	 * @property {String}			changeText		倒计时期间的提示语,必须带有字母"x",见官网说明(默认 'X秒重新获取' ) | 
				
			||||
	 * @property {String}			endText			倒计结束的提示语,见官网说明(默认 '重新获取' ) | 
				
			||||
	 * @property {Boolean}			keepRunning		是否在H5刷新或各端返回再进入时继续倒计时( 默认false ) | 
				
			||||
	 * @property {String}			uniqueKey		为了区分多个页面,或者一个页面多个倒计时组件本地存储的继续倒计时变了 | 
				
			||||
	 * | 
				
			||||
	 * @event {Function}	change	倒计时期间,每秒触发一次 | 
				
			||||
	 * @event {Function}	start	开始倒计时触发 | 
				
			||||
	 * @event {Function}	end		结束倒计时触发 | 
				
			||||
	 * @example <u-code ref="uCode" @change="codeChange" seconds="20"></u-code> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: "u-code", | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin,props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				secNum: this.seconds, | 
				
			||||
				timer: null, | 
				
			||||
				canGetCode: true, // 是否可以执行验证码操作 | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		mounted() { | 
				
			||||
			this.checkKeepRunning() | 
				
			||||
		}, | 
				
			||||
		watch: { | 
				
			||||
			seconds: { | 
				
			||||
				immediate: true, | 
				
			||||
				handler(n) { | 
				
			||||
					this.secNum = n | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			checkKeepRunning() { | 
				
			||||
				// 获取上一次退出页面(H5还包括刷新)时的时间戳,如果没有上次的保存,此值可能为空 | 
				
			||||
				let lastTimestamp = Number(uni.getStorageSync(this.uniqueKey + '_$uCountDownTimestamp')) | 
				
			||||
				if(!lastTimestamp) return this.changeEvent(this.startText) | 
				
			||||
				// 当前秒的时间戳 | 
				
			||||
				let nowTimestamp = Math.floor((+ new Date()) / 1000) | 
				
			||||
				// 判断当前的时间戳,是否小于上一次的本该按设定结束,却提前结束的时间戳 | 
				
			||||
				if(this.keepRunning && lastTimestamp && lastTimestamp > nowTimestamp) { | 
				
			||||
					// 剩余尚未执行完的倒计秒数 | 
				
			||||
					this.secNum = lastTimestamp - nowTimestamp | 
				
			||||
					// 清除本地保存的变量 | 
				
			||||
					uni.removeStorageSync(this.uniqueKey + '_$uCountDownTimestamp') | 
				
			||||
					// 开始倒计时 | 
				
			||||
					this.start() | 
				
			||||
				} else { | 
				
			||||
					// 如果不存在需要继续上一次的倒计时,执行正常的逻辑 | 
				
			||||
					this.changeEvent(this.startText) | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			// 开始倒计时 | 
				
			||||
			start() { | 
				
			||||
				// 防止快速点击获取验证码的按钮而导致内部产生多个定时器导致混乱 | 
				
			||||
				if(this.timer) { | 
				
			||||
					clearInterval(this.timer) | 
				
			||||
					this.timer = null | 
				
			||||
				} | 
				
			||||
				this.$emit('start') | 
				
			||||
				this.canGetCode = false | 
				
			||||
				// 这里放这句,是为了一开始时就提示,否则要等setInterval的1秒后才会有提示 | 
				
			||||
				this.changeEvent(this.changeText.replace(/x|X/, this.secNum)) | 
				
			||||
				this.timer = setInterval(() => { | 
				
			||||
					if (--this.secNum) { | 
				
			||||
						// 用当前倒计时的秒数替换提示字符串中的"x"字母 | 
				
			||||
						this.changeEvent(this.changeText.replace(/x|X/, this.secNum)) | 
				
			||||
					} else { | 
				
			||||
						clearInterval(this.timer) | 
				
			||||
						this.timer = null | 
				
			||||
						this.changeEvent(this.endText) | 
				
			||||
						this.secNum = this.seconds | 
				
			||||
						this.$emit('end') | 
				
			||||
						this.canGetCode = true | 
				
			||||
					} | 
				
			||||
				}, 1000) | 
				
			||||
        this.setTimeToStorage() | 
				
			||||
      }, | 
				
			||||
			// 重置,可以让用户再次获取验证码 | 
				
			||||
			reset() { | 
				
			||||
				this.canGetCode = true | 
				
			||||
				clearInterval(this.timer) | 
				
			||||
				this.secNum = this.seconds | 
				
			||||
				this.changeEvent(this.endText) | 
				
			||||
			}, | 
				
			||||
			changeEvent(text) { | 
				
			||||
				this.$emit('change', text) | 
				
			||||
			}, | 
				
			||||
			// 保存时间戳,为了防止倒计时尚未结束,H5刷新或者各端的右上角返回上一页再进来 | 
				
			||||
			setTimeToStorage() { | 
				
			||||
				if(!this.keepRunning || !this.timer) return | 
				
			||||
				// 记录当前的时间戳,为了下次进入页面,如果还在倒计时内的话,继续倒计时 | 
				
			||||
				// 倒计时尚未结束,结果大于0;倒计时已经开始,就会小于初始值,如果等于初始值,说明没有开始倒计时,无需处理 | 
				
			||||
				if(this.secNum > 0 && this.secNum <= this.seconds) { | 
				
			||||
					// 获取当前时间戳(+ new Date()为特殊写法),除以1000变成秒,再去除小数部分 | 
				
			||||
					let nowTimestamp = Math.floor((+ new Date()) / 1000) | 
				
			||||
					// 将本该结束时候的时间戳保存起来 => 当前时间戳 + 剩余的秒数 | 
				
			||||
					uni.setStorage({ | 
				
			||||
						key: this.uniqueKey + '_$uCountDownTimestamp', | 
				
			||||
						data: nowTimestamp + Number(this.secNum) | 
				
			||||
					}) | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		// 组件销毁的时候,清除定时器,否则定时器会继续存在,系统不会自动清除 | 
				
			||||
		beforeDestroy() { | 
				
			||||
			this.setTimeToStorage() | 
				
			||||
			clearTimeout(this.timer) | 
				
			||||
			this.timer = null | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,29 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 占父容器宽度的多少等分,总分为12份
 | 
				
			||||
        span: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.col.span | 
				
			||||
        }, | 
				
			||||
        // 指定栅格左侧的间隔数(总12栏)
 | 
				
			||||
        offset: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.col.offset | 
				
			||||
        }, | 
				
			||||
        // 水平排列方式,可选值为`start`(或`flex-start`)、`end`(或`flex-end`)、`center`、`around`(或`space-around`)、`between`(或`space-between`)
 | 
				
			||||
        justify: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.col.justify | 
				
			||||
        }, | 
				
			||||
        // 垂直对齐方式,可选值为top、center、bottom、stretch
 | 
				
			||||
        align: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.col.align | 
				
			||||
        }, | 
				
			||||
        // 文字对齐方式
 | 
				
			||||
        textAlign: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.col.textAlign | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,162 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view | 
				
			||||
	    class="u-col" | 
				
			||||
		ref="u-col" | 
				
			||||
	    :class="[ | 
				
			||||
			'u-col-' + span | 
				
			||||
		]" | 
				
			||||
	    :style="[colStyle]" | 
				
			||||
	    @tap="clickHandler" | 
				
			||||
	> | 
				
			||||
		<slot></slot> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * CodeInput 栅格系统的列  | 
				
			||||
	 * @description 该组件一般用于Layout 布局 通过基础的 12 分栏,迅速简便地创建布局 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/Layout.html | 
				
			||||
	 * @property {String | Number}	span		栅格占据的列数,总12等份 (默认 12 )  | 
				
			||||
	 * @property {String | Number}	offset		分栏左边偏移,计算方式与span相同 (默认 0 )  | 
				
			||||
	 * @property {String}			justify		水平排列方式,可选值为`start`(或`flex-start`)、`end`(或`flex-end`)、`center`、`around`(或`space-around`)、`between`(或`space-between`)  (默认 'start' )  | 
				
			||||
	 * @property {String}			align		垂直对齐方式,可选值为top、center、bottom、stretch (默认 'stretch' )  | 
				
			||||
	 * @property {String}			textAlign	文字水平对齐方式 (默认 'left' )  | 
				
			||||
	 * @property {Object}			customStyle	定义需要用到的外部样式 | 
				
			||||
	 * @event {Function}	click	col被点击,会阻止事件冒泡到row | 
				
			||||
	 * @example	 <u-col  span="3" offset="3" > <view class="demo-layout bg-purple"></view> </u-col> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'u-col', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				width: 0, | 
				
			||||
				parentData: { | 
				
			||||
					gutter: 0 | 
				
			||||
				}, | 
				
			||||
				gridNum: 12 | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			uJustify() { | 
				
			||||
				if (this.justify == 'end' || this.justify == 'start') return 'flex-' + this.justify | 
				
			||||
				else if (this.justify == 'around' || this.justify == 'between') return 'space-' + this.justify | 
				
			||||
				else return this.justify | 
				
			||||
			}, | 
				
			||||
			uAlignItem() { | 
				
			||||
				if (this.align == 'top') return 'flex-start' | 
				
			||||
				if (this.align == 'bottom') return 'flex-end' | 
				
			||||
				else return this.align | 
				
			||||
			}, | 
				
			||||
			colStyle() { | 
				
			||||
				const style = { | 
				
			||||
					// 这里写成"padding: 0 10px"的形式是因为nvue的需要 | 
				
			||||
					paddingLeft: uni.$u.addUnit(uni.$u.getPx(this.parentData.gutter)/2), | 
				
			||||
					paddingRight: uni.$u.addUnit(uni.$u.getPx(this.parentData.gutter)/2), | 
				
			||||
					alignItems: this.uAlignItem, | 
				
			||||
					justifyContent: this.uJustify, | 
				
			||||
					textAlign: this.textAlign, | 
				
			||||
					// #ifndef APP-NVUE | 
				
			||||
					// 在非nvue上,使用百分比形式 | 
				
			||||
					flex: `0 0 ${100 / this.gridNum * this.span}%`, | 
				
			||||
					marginLeft: 100 / 12 * this.offset + '%', | 
				
			||||
					// #endif | 
				
			||||
					// #ifdef APP-NVUE | 
				
			||||
					// 在nvue上,由于无法使用百分比单位,这里需要获取父组件的宽度,再计算得出该有对应的百分比尺寸 | 
				
			||||
					width: uni.$u.addUnit(Math.floor(this.width / this.gridNum * Number(this.span))), | 
				
			||||
					marginLeft: uni.$u.addUnit(Math.floor(this.width / this.gridNum * Number(this.offset))), | 
				
			||||
					// #endif | 
				
			||||
				} | 
				
			||||
				return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle)) | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		mounted() { | 
				
			||||
			this.init() | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			async init() { | 
				
			||||
				// 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环引用 | 
				
			||||
				this.updateParentData() | 
				
			||||
				this.width = await this.parent.getComponentWidth() | 
				
			||||
			}, | 
				
			||||
			updateParentData() { | 
				
			||||
				this.getParentData('u-row') | 
				
			||||
			}, | 
				
			||||
			clickHandler(e) { | 
				
			||||
				this.$emit('click'); | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
	.u-col { | 
				
			||||
		padding: 0; | 
				
			||||
		/* #ifndef APP-NVUE */ | 
				
			||||
		box-sizing:border-box; | 
				
			||||
		/* #endif */ | 
				
			||||
		/* #ifdef MP */ | 
				
			||||
		display: block; | 
				
			||||
		/* #endif */ | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	// nvue下百分比无效 | 
				
			||||
	/* #ifndef APP-NVUE */ | 
				
			||||
	.u-col-0 { | 
				
			||||
		width: 0; | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-col-1 { | 
				
			||||
		width: calc(100%/12); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-col-2 { | 
				
			||||
		width: calc(100%/12 * 2); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-col-3 { | 
				
			||||
		width: calc(100%/12 * 3); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-col-4 { | 
				
			||||
		width: calc(100%/12 * 4); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-col-5 { | 
				
			||||
		width: calc(100%/12 * 5); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-col-6 { | 
				
			||||
		width: calc(100%/12 * 6); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-col-7 { | 
				
			||||
		width: calc(100%/12 * 7); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-col-8 { | 
				
			||||
		width: calc(100%/12 * 8); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-col-9 { | 
				
			||||
		width: calc(100%/12 * 9); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-col-10 { | 
				
			||||
		width: calc(100%/12 * 10); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-col-11 { | 
				
			||||
		width: calc(100%/12 * 11); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	.u-col-12 { | 
				
			||||
		width: calc(100%/12 * 12); | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	/* #endif */ | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,59 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 标题
 | 
				
			||||
        title: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.collapseItem.title | 
				
			||||
        }, | 
				
			||||
        // 标题右侧内容
 | 
				
			||||
        value: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.collapseItem.value | 
				
			||||
        }, | 
				
			||||
        // 标题下方的描述信息
 | 
				
			||||
        label: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.collapseItem.label | 
				
			||||
        }, | 
				
			||||
        // 是否禁用折叠面板
 | 
				
			||||
        disabled: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.collapseItem.disabled | 
				
			||||
        }, | 
				
			||||
        // 是否展示右侧箭头并开启点击反馈
 | 
				
			||||
        isLink: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.collapseItem.isLink | 
				
			||||
        }, | 
				
			||||
        // 是否开启点击反馈
 | 
				
			||||
        clickable: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.collapseItem.clickable | 
				
			||||
        }, | 
				
			||||
        // 是否显示内边框
 | 
				
			||||
        border: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.collapseItem.border | 
				
			||||
        }, | 
				
			||||
        // 标题的对齐方式
 | 
				
			||||
        align: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.collapseItem.align | 
				
			||||
        }, | 
				
			||||
        // 唯一标识符
 | 
				
			||||
        name: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.collapseItem.name | 
				
			||||
        }, | 
				
			||||
        // 标题左侧图片,可为绝对路径的图片或内置图标
 | 
				
			||||
        icon: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.collapseItem.icon | 
				
			||||
        }, | 
				
			||||
        // 面板展开收起的过渡时间,单位ms
 | 
				
			||||
        duration: { | 
				
			||||
            type: Number, | 
				
			||||
            default: uni.$u.props.collapseItem.duration | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,225 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="u-collapse-item"> | 
				
			||||
		<u-cell | 
				
			||||
			:title="title" | 
				
			||||
			:value="value" | 
				
			||||
			:label="label" | 
				
			||||
			:icon="icon" | 
				
			||||
			:isLink="isLink" | 
				
			||||
			:clickable="clickable" | 
				
			||||
			:border="parentData.border && showBorder" | 
				
			||||
			@click="clickHandler" | 
				
			||||
			:arrowDirection="expanded ? 'up' : 'down'" | 
				
			||||
			:disabled="disabled" | 
				
			||||
		> | 
				
			||||
			<!-- #ifndef MP-WEIXIN --> | 
				
			||||
			<!-- 微信小程序不支持,因为微信中不支持 <slot name="title" slot="title" />的写法 --> | 
				
			||||
			<template slot="title"> | 
				
			||||
				<slot name="title"></slot> | 
				
			||||
			</template> | 
				
			||||
			<template slot="icon"> | 
				
			||||
				<slot name="icon"></slot> | 
				
			||||
			</template> | 
				
			||||
			<template slot="value"> | 
				
			||||
				<slot name="value"></slot> | 
				
			||||
			</template> | 
				
			||||
			<template slot="right-icon"> | 
				
			||||
				<slot name="right-icon"></slot> | 
				
			||||
			</template> | 
				
			||||
			<!-- #endif --> | 
				
			||||
		</u-cell> | 
				
			||||
		<view | 
				
			||||
			class="u-collapse-item__content" | 
				
			||||
			:animation="animationData" | 
				
			||||
			ref="animation" | 
				
			||||
		> | 
				
			||||
			<view | 
				
			||||
				class="u-collapse-item__content__text content-class" | 
				
			||||
				:id="elId" | 
				
			||||
				:ref="elId" | 
				
			||||
			><slot /></view> | 
				
			||||
		</view> | 
				
			||||
		<u-line v-if="parentData.border"></u-line> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	// #ifdef APP-NVUE | 
				
			||||
	const animation = uni.requireNativePlugin('animation') | 
				
			||||
	const dom = uni.requireNativePlugin('dom') | 
				
			||||
	// #endif | 
				
			||||
	/** | 
				
			||||
	 * collapseItem 折叠面板Item | 
				
			||||
	 * @description 通过折叠面板收纳内容区域(搭配u-collapse使用) | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/collapse.html | 
				
			||||
	 * @property {String}			title 		标题 | 
				
			||||
	 * @property {String}			value 		标题右侧内容 | 
				
			||||
	 * @property {String}			label 		标题下方的描述信息 | 
				
			||||
	 * @property {Boolean}			disbled 	是否禁用折叠面板 ( 默认 false ) | 
				
			||||
	 * @property {Boolean}			isLink 		是否展示右侧箭头并开启点击反馈 ( 默认 true ) | 
				
			||||
	 * @property {Boolean}			clickable	是否开启点击反馈 ( 默认 true ) | 
				
			||||
	 * @property {Boolean}			border		是否显示内边框 ( 默认 true ) | 
				
			||||
	 * @property {String}			align		标题的对齐方式 ( 默认 'left' ) | 
				
			||||
	 * @property {String | Number}	name		唯一标识符 | 
				
			||||
	 * @property {String}			icon		标题左侧图片,可为绝对路径的图片或内置图标 | 
				
			||||
	 * @event {Function}			change 			某个item被打开或者收起时触发 | 
				
			||||
	 * @example <u-collapse-item :title="item.head" v-for="(item, index) in itemList" :key="index">{{item.body}}</u-collapse-item> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: "u-collapse-item", | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				elId: uni.$u.guid(), | 
				
			||||
				// uni.createAnimation的导出数据 | 
				
			||||
				animationData: {}, | 
				
			||||
				// 是否展开状态 | 
				
			||||
				expanded: false, | 
				
			||||
				// 根据expanded确定是否显示border,为了控制展开时,cell的下划线更好的显示效果,进行一定时间的延时 | 
				
			||||
				showBorder: false, | 
				
			||||
				// 是否动画中,如果是则不允许继续触发点击 | 
				
			||||
				animating: false, | 
				
			||||
				// 父组件u-collapse的参数 | 
				
			||||
				parentData: { | 
				
			||||
					accordion: false, | 
				
			||||
					border: false | 
				
			||||
				} | 
				
			||||
			}; | 
				
			||||
		}, | 
				
			||||
		watch: { | 
				
			||||
			expanded(n) { | 
				
			||||
				clearTimeout(this.timer) | 
				
			||||
				this.timer = null | 
				
			||||
				// 这里根据expanded的值来进行一定的延时,是为了cell的下划线更好的显示效果 | 
				
			||||
				this.timer = setTimeout(() => { | 
				
			||||
					this.showBorder = n | 
				
			||||
				}, n ? 10 : 290) | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		mounted() { | 
				
			||||
			this.init() | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			// 异步获取内容,或者动态修改了内容时,需要重新初始化 | 
				
			||||
			init() { | 
				
			||||
				// 初始化数据 | 
				
			||||
				this.updateParentData() | 
				
			||||
				if (!this.parent) { | 
				
			||||
					return uni.$u.error('u-collapse-item必须要搭配u-collapse组件使用') | 
				
			||||
				} | 
				
			||||
				const { | 
				
			||||
					value, | 
				
			||||
					accordion, | 
				
			||||
					children = [] | 
				
			||||
				} = this.parent | 
				
			||||
 | 
				
			||||
				if (accordion) { | 
				
			||||
					if (uni.$u.test.array(value)) { | 
				
			||||
						return uni.$u.error('手风琴模式下,u-collapse组件的value参数不能为数组') | 
				
			||||
					} | 
				
			||||
					this.expanded = this.name == value | 
				
			||||
				} else { | 
				
			||||
					if (!uni.$u.test.array(value) && value !== null) { | 
				
			||||
						return uni.$u.error('非手风琴模式下,u-collapse组件的value参数必须为数组') | 
				
			||||
					} | 
				
			||||
					this.expanded = (value || []).some(item => item == this.name) | 
				
			||||
				} | 
				
			||||
				// 设置组件的展开或收起状态 | 
				
			||||
				this.$nextTick(function() { | 
				
			||||
					this.setContentAnimate() | 
				
			||||
				}) | 
				
			||||
			}, | 
				
			||||
			updateParentData() { | 
				
			||||
				// 此方法在mixin中 | 
				
			||||
				this.getParentData('u-collapse') | 
				
			||||
			}, | 
				
			||||
			async setContentAnimate() { | 
				
			||||
				// 每次面板打开或者收起时,都查询元素尺寸 | 
				
			||||
				// 好处是,父组件从服务端获取内容后,变更折叠面板后可以获得最新的高度 | 
				
			||||
				const rect = await this.queryRect() | 
				
			||||
				const height = this.expanded ? rect.height : 0 | 
				
			||||
				this.animating = true | 
				
			||||
				// #ifdef APP-NVUE | 
				
			||||
				const ref = this.$refs['animation'].ref | 
				
			||||
				animation.transition(ref, { | 
				
			||||
					styles: { | 
				
			||||
						height: height + 'px' | 
				
			||||
					}, | 
				
			||||
					duration: this.duration, | 
				
			||||
					// 必须设置为true,否则会到面板收起或展开时,页面其他元素不会随之调整它们的布局 | 
				
			||||
					needLayout: true, | 
				
			||||
					timingFunction: 'ease-in-out', | 
				
			||||
				}, () => { | 
				
			||||
					this.animating = false | 
				
			||||
				}) | 
				
			||||
				// #endif | 
				
			||||
 | 
				
			||||
				// #ifndef APP-NVUE | 
				
			||||
				const animation = uni.createAnimation({ | 
				
			||||
					timingFunction: 'ease-in-out', | 
				
			||||
				}); | 
				
			||||
				animation | 
				
			||||
					.height(height) | 
				
			||||
					.step({ | 
				
			||||
						duration: this.duration, | 
				
			||||
					}) | 
				
			||||
					.step() | 
				
			||||
				// 导出动画数据给面板的animationData值 | 
				
			||||
				this.animationData = animation.export() | 
				
			||||
				// 标识动画结束 | 
				
			||||
				uni.$u.sleep(this.duration).then(() => { | 
				
			||||
					this.animating = false | 
				
			||||
				}) | 
				
			||||
				// #endif | 
				
			||||
			}, | 
				
			||||
			// 点击collapsehead头部 | 
				
			||||
			clickHandler() { | 
				
			||||
				if (this.disabled && this.animating) return | 
				
			||||
				// 设置本组件为相反的状态 | 
				
			||||
				this.parent && this.parent.onChange(this) | 
				
			||||
			}, | 
				
			||||
			// 查询内容高度 | 
				
			||||
			queryRect() { | 
				
			||||
				// #ifndef APP-NVUE | 
				
			||||
				// $uGetRect为uView自带的节点查询简化方法,详见文档介绍:https://www.uviewui.com/js/getRect.html | 
				
			||||
				// 组件内部一般用this.$uGetRect,对外的为uni.$u.getRect,二者功能一致,名称不同 | 
				
			||||
				return new Promise(resolve => { | 
				
			||||
					this.$uGetRect(`#${this.elId}`).then(size => { | 
				
			||||
						resolve(size) | 
				
			||||
					}) | 
				
			||||
				}) | 
				
			||||
				// #endif | 
				
			||||
 | 
				
			||||
				// #ifdef APP-NVUE | 
				
			||||
				// nvue下,使用dom模块查询元素高度 | 
				
			||||
				// 返回一个promise,让调用此方法的主体能使用then回调 | 
				
			||||
				return new Promise(resolve => { | 
				
			||||
					dom.getComponentRect(this.$refs[this.elId], res => { | 
				
			||||
						resolve(res.size) | 
				
			||||
					}) | 
				
			||||
				}) | 
				
			||||
				// #endif | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
	}; | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
	.u-collapse-item { | 
				
			||||
 | 
				
			||||
		&__content { | 
				
			||||
			overflow: hidden; | 
				
			||||
			height: 0; | 
				
			||||
 | 
				
			||||
			&__text { | 
				
			||||
				padding: 12px 15px; | 
				
			||||
				color: $u-content-color; | 
				
			||||
				font-size: 14px; | 
				
			||||
				line-height: 18px; | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,19 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 当前展开面板的name,非手风琴模式:[<string | number>],手风琴模式:string | number
 | 
				
			||||
        value: { | 
				
			||||
            type: [String, Number, Array, null], | 
				
			||||
            default: uni.$u.props.collapse.value | 
				
			||||
        }, | 
				
			||||
        // 是否手风琴模式
 | 
				
			||||
        accordion: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.collapse.accordion | 
				
			||||
        }, | 
				
			||||
        // 是否显示外边框
 | 
				
			||||
        border: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.collapse.border | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,90 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="u-collapse"> | 
				
			||||
		<u-line v-if="border"></u-line> | 
				
			||||
		<slot /> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * collapse 折叠面板  | 
				
			||||
	 * @description 通过折叠面板收纳内容区域 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/collapse.html | 
				
			||||
	 * @property {String | Number | Array}	value		当前展开面板的name,非手风琴模式:[<string | number>],手风琴模式:string | number | 
				
			||||
	 * @property {Boolean}					accordion	是否手风琴模式( 默认 false ) | 
				
			||||
	 * @property {Boolean}					border		是否显示外边框 ( 默认 true ) | 
				
			||||
	 * @event {Function}	change 		当前激活面板展开时触发(如果是手风琴模式,参数activeNames类型为String,否则为Array) | 
				
			||||
	 * @example <u-collapse></u-collapse> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: "u-collapse", | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin,props], | 
				
			||||
		watch: { | 
				
			||||
			needInit() { | 
				
			||||
				this.init() | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		created() { | 
				
			||||
			this.children = [] | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			needInit() { | 
				
			||||
				// 通过computed,同时监听accordion和value值的变化 | 
				
			||||
				// 再通过watch去执行init()方法,进行再一次的初始化 | 
				
			||||
				return [this.accordion, this.value] | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		watch: { | 
				
			||||
			// 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件 | 
				
			||||
			parentData() { | 
				
			||||
				if (this.children.length) { | 
				
			||||
					this.children.map(child => { | 
				
			||||
						// 判断子组件(u-checkbox)如果有updateParentData方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值) | 
				
			||||
						typeof(child.updateParentData) === 'function' && child.updateParentData() | 
				
			||||
					}) | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			// 重新初始化一次内部的所有子元素 | 
				
			||||
			init() { | 
				
			||||
				this.children.map(child => { | 
				
			||||
					child.init() | 
				
			||||
				}) | 
				
			||||
			}, | 
				
			||||
			/** | 
				
			||||
			 * collapse-item被点击时触发,由collapse统一处理各子组件的状态 | 
				
			||||
			 * @param {Object} target 被操作的面板的实例 | 
				
			||||
			 */ | 
				
			||||
			onChange(target) { | 
				
			||||
				let changeArr = [] | 
				
			||||
				this.children.map((child, index) => { | 
				
			||||
					// 如果是手风琴模式,将其他的折叠面板收起来 | 
				
			||||
					if (this.accordion) { | 
				
			||||
						child.expanded = child === target ? !target.expanded : false | 
				
			||||
						child.setContentAnimate() | 
				
			||||
					} else { | 
				
			||||
						if(child === target) { | 
				
			||||
							child.expanded = !child.expanded | 
				
			||||
							child.setContentAnimate() | 
				
			||||
						} | 
				
			||||
					} | 
				
			||||
					// 拼接change事件中,数组元素的状态 | 
				
			||||
					changeArr.push({ | 
				
			||||
						// 如果没有定义name属性,则默认返回组件的index索引 | 
				
			||||
						name: child.name || index, | 
				
			||||
						status: child.expanded ? 'open' : 'close' | 
				
			||||
					}) | 
				
			||||
				}) | 
				
			||||
 | 
				
			||||
				this.$emit('change', changeArr) | 
				
			||||
				this.$emit(target.expanded ? 'open' : 'close', target.name) | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,55 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 显示的内容,字符串
 | 
				
			||||
        text: { | 
				
			||||
            type: [Array], | 
				
			||||
            default: uni.$u.props.columnNotice.text | 
				
			||||
        }, | 
				
			||||
        // 是否显示左侧的音量图标
 | 
				
			||||
        icon: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.columnNotice.icon | 
				
			||||
        }, | 
				
			||||
        // 通告模式,link-显示右箭头,closable-显示右侧关闭图标
 | 
				
			||||
        mode: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.columnNotice.mode | 
				
			||||
        }, | 
				
			||||
        // 文字颜色,各图标也会使用文字颜色
 | 
				
			||||
        color: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.columnNotice.color | 
				
			||||
        }, | 
				
			||||
        // 背景颜色
 | 
				
			||||
        bgColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.columnNotice.bgColor | 
				
			||||
        }, | 
				
			||||
        // 字体大小,单位px
 | 
				
			||||
        fontSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.columnNotice.fontSize | 
				
			||||
        }, | 
				
			||||
        // 水平滚动时的滚动速度,即每秒滚动多少px(px),这有利于控制文字无论多少时,都能有一个恒定的速度
 | 
				
			||||
        speed: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.columnNotice.speed | 
				
			||||
        }, | 
				
			||||
        // direction = row时,是否使用步进形式滚动
 | 
				
			||||
        step: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.columnNotice.step | 
				
			||||
        }, | 
				
			||||
        // 滚动一个周期的时间长,单位ms
 | 
				
			||||
        duration: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.columnNotice.duration | 
				
			||||
        }, | 
				
			||||
        // 是否禁止用手滑动切换
 | 
				
			||||
        // 目前HX2.6.11,只支持App 2.5.5+、H5 2.5.5+、支付宝小程序、字节跳动小程序
 | 
				
			||||
        disableTouch: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.columnNotice.disableTouch | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,160 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view | 
				
			||||
		class="u-notice" | 
				
			||||
		@tap="clickHandler" | 
				
			||||
	> | 
				
			||||
		<slot name="icon"> | 
				
			||||
			<view | 
				
			||||
				class="u-notice__left-icon" | 
				
			||||
				v-if="icon" | 
				
			||||
			> | 
				
			||||
				<u-icon | 
				
			||||
					:name="icon" | 
				
			||||
					:color="color" | 
				
			||||
					size="19" | 
				
			||||
				></u-icon> | 
				
			||||
			</view> | 
				
			||||
		</slot> | 
				
			||||
		<swiper | 
				
			||||
			:disable-touch="disableTouch" | 
				
			||||
			:vertical="step ? false : true" | 
				
			||||
			circular | 
				
			||||
			:interval="duration" | 
				
			||||
			:autoplay="true" | 
				
			||||
			class="u-notice__swiper" | 
				
			||||
			@change="noticeChange" | 
				
			||||
		> | 
				
			||||
			<swiper-item | 
				
			||||
				v-for="(item, index) in text" | 
				
			||||
				:key="index" | 
				
			||||
				class="u-notice__swiper__item" | 
				
			||||
			> | 
				
			||||
				<text | 
				
			||||
					class="u-notice__swiper__item__text u-line-1" | 
				
			||||
					:style="[textStyle]" | 
				
			||||
				>{{ item }}</text> | 
				
			||||
			</swiper-item> | 
				
			||||
		</swiper> | 
				
			||||
		<view | 
				
			||||
			class="u-notice__right-icon" | 
				
			||||
			v-if="['link', 'closable'].includes(mode)" | 
				
			||||
		> | 
				
			||||
			<u-icon | 
				
			||||
				v-if="mode === 'link'" | 
				
			||||
				name="arrow-right" | 
				
			||||
				:size="17" | 
				
			||||
				:color="color" | 
				
			||||
			></u-icon> | 
				
			||||
			<u-icon | 
				
			||||
				v-if="mode === 'closable'" | 
				
			||||
				name="close" | 
				
			||||
				:size="16" | 
				
			||||
				:color="color" | 
				
			||||
				@click="close" | 
				
			||||
			></u-icon> | 
				
			||||
		</view> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * ColumnNotice 滚动通知中的垂直滚动 内部组件 | 
				
			||||
	 * @description 该组件用于滚动通告场景,是其中的垂直滚动方式 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/noticeBar.html | 
				
			||||
	 * @property {Array}			text 			显示的内容,字符串 | 
				
			||||
	 * @property {String}			icon 			是否显示左侧的音量图标 ( 默认 'volume' ) | 
				
			||||
	 * @property {String}			mode 			通告模式,link-显示右箭头,closable-显示右侧关闭图标 | 
				
			||||
	 * @property {String}			color 			文字颜色,各图标也会使用文字颜色 ( 默认 '#f9ae3d' ) | 
				
			||||
	 * @property {String}			bgColor 		背景颜色 ( 默认 '#fdf6ec' ) | 
				
			||||
	 * @property {String | Number}	fontSize		字体大小,单位px  ( 默认 14 ) | 
				
			||||
	 * @property {String | Number}	speed			水平滚动时的滚动速度,即每秒滚动多少px(rpx),这有利于控制文字无论多少时,都能有一个恒定的速度 ( 默认 80 ) | 
				
			||||
	 * @property {Boolean}			step			direction = row时,是否使用步进形式滚动 ( 默认 false ) | 
				
			||||
	 * @property {String | Number}	duration		滚动一个周期的时间长,单位ms ( 默认 1500 ) | 
				
			||||
	 * @property {Boolean}			disableTouch	是否禁止用手滑动切换   目前HX2.6.11,只支持App 2.5.5+、H5 2.5.5+、支付宝小程序、字节跳动小程序 ( 默认 true ) | 
				
			||||
	 * @example  | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin,props], | 
				
			||||
		watch: { | 
				
			||||
			text: { | 
				
			||||
				immediate: true, | 
				
			||||
				handler(newValue, oldValue) { | 
				
			||||
					if(!uni.$u.test.array(newValue)) { | 
				
			||||
						uni.$u.error('noticebar组件direction为column时,要求text参数为数组形式') | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			// 文字内容的样式 | 
				
			||||
			textStyle() { | 
				
			||||
				let style = {} | 
				
			||||
				style.color = this.color | 
				
			||||
				style.fontSize = uni.$u.addUnit(this.fontSize) | 
				
			||||
				return style | 
				
			||||
			}, | 
				
			||||
			// 垂直或者水平滚动 | 
				
			||||
			vertical() { | 
				
			||||
				if (this.mode == 'horizontal') return false | 
				
			||||
				else return true | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				index:0 | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			noticeChange(e){ | 
				
			||||
				this.index = e.detail.current | 
				
			||||
			}, | 
				
			||||
			// 点击通告栏 | 
				
			||||
			clickHandler() { | 
				
			||||
				this.$emit('click', this.index) | 
				
			||||
			}, | 
				
			||||
			// 点击关闭按钮 | 
				
			||||
			close() { | 
				
			||||
				this.$emit('close') | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	}; | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
	.u-notice { | 
				
			||||
		@include flex; | 
				
			||||
		align-items: center; | 
				
			||||
		justify-content: space-between; | 
				
			||||
 | 
				
			||||
		&__left-icon { | 
				
			||||
			align-items: center; | 
				
			||||
			margin-right: 5px; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__right-icon { | 
				
			||||
			margin-left: 5px; | 
				
			||||
			align-items: center; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__swiper { | 
				
			||||
			height: 16px; | 
				
			||||
			@include flex; | 
				
			||||
			align-items: center; | 
				
			||||
			flex: 1; | 
				
			||||
 | 
				
			||||
			&__item { | 
				
			||||
				@include flex; | 
				
			||||
				align-items: center; | 
				
			||||
				overflow: hidden; | 
				
			||||
 | 
				
			||||
				&__text { | 
				
			||||
					font-size: 14px; | 
				
			||||
					color: $u-warning; | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,24 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 倒计时时长,单位ms
 | 
				
			||||
        time: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.countDown.time | 
				
			||||
        }, | 
				
			||||
        // 时间格式,DD-日,HH-时,mm-分,ss-秒,SSS-毫秒
 | 
				
			||||
        format: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.countDown.format | 
				
			||||
        }, | 
				
			||||
        // 是否自动开始倒计时
 | 
				
			||||
        autoStart: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.countDown.autoStart | 
				
			||||
        }, | 
				
			||||
        // 是否展示毫秒倒计时
 | 
				
			||||
        millisecond: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.countDown.millisecond | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,163 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="u-count-down"> | 
				
			||||
		<slot> | 
				
			||||
			<text class="u-count-down__text">{{ formattedTime }}</text> | 
				
			||||
		</slot> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	import { | 
				
			||||
		isSameSecond, | 
				
			||||
		parseFormat, | 
				
			||||
		parseTimeData | 
				
			||||
	} from './utils'; | 
				
			||||
	/** | 
				
			||||
	 * u-count-down 倒计时 | 
				
			||||
	 * @description 该组件一般使用于某个活动的截止时间上,通过数字的变化,给用户明确的时间感受,提示用户进行某一个行为操作。 | 
				
			||||
	 * @tutorial https://uviewui.com/components/countDown.html | 
				
			||||
	 * @property {String | Number}	time		倒计时时长,单位ms (默认 0 ) | 
				
			||||
	 * @property {String}			format		时间格式,DD-日,HH-时,mm-分,ss-秒,SSS-毫秒  (默认 'HH:mm:ss' ) | 
				
			||||
	 * @property {Boolean}			autoStart	是否自动开始倒计时 (默认 true ) | 
				
			||||
	 * @property {Boolean}			millisecond	是否展示毫秒倒计时 (默认 false ) | 
				
			||||
	 * @event {Function} finish 倒计时结束时触发  | 
				
			||||
	 * @event {Function} change 倒计时变化时触发  | 
				
			||||
	 * @event {Function} start	开始倒计时 | 
				
			||||
	 * @event {Function} pause	暂停倒计时  | 
				
			||||
	 * @event {Function} reset	重设倒计时,若 auto-start 为 true,重设后会自动开始倒计时  | 
				
			||||
	 * @example <u-count-down :time="time"></u-count-down> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'u-count-down', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				timer: null, | 
				
			||||
				// 各单位(天,时,分等)剩余时间 | 
				
			||||
				timeData: parseTimeData(0), | 
				
			||||
				// 格式化后的时间,如"03:23:21" | 
				
			||||
				formattedTime: '0', | 
				
			||||
				// 倒计时是否正在进行中 | 
				
			||||
				runing: false, | 
				
			||||
				endTime: 0, // 结束的毫秒时间戳 | 
				
			||||
				remainTime: 0, // 剩余的毫秒时间 | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		watch: { | 
				
			||||
			time(n) { | 
				
			||||
				this.reset() | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		mounted() { | 
				
			||||
			this.init() | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			init() { | 
				
			||||
				this.reset() | 
				
			||||
			}, | 
				
			||||
			// 开始倒计时 | 
				
			||||
			start() { | 
				
			||||
				if (this.runing) return | 
				
			||||
				// 标识为进行中 | 
				
			||||
				this.runing = true | 
				
			||||
				// 结束时间戳 = 此刻时间戳 + 剩余的时间 | 
				
			||||
				this.endTime = Date.now() + this.remainTime | 
				
			||||
				this.toTick() | 
				
			||||
			}, | 
				
			||||
			// 根据是否展示毫秒,执行不同操作函数 | 
				
			||||
			toTick() { | 
				
			||||
				if (this.millisecond) { | 
				
			||||
					this.microTick() | 
				
			||||
				} else { | 
				
			||||
					this.macroTick() | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			macroTick() { | 
				
			||||
				this.clearTimeout() | 
				
			||||
				// 每隔一定时间,更新一遍定时器的值 | 
				
			||||
				// 同时此定时器的作用也能带来毫秒级的更新 | 
				
			||||
				this.timer = setTimeout(() => { | 
				
			||||
					// 获取剩余时间 | 
				
			||||
					const remain = this.getRemainTime() | 
				
			||||
					// 重设剩余时间 | 
				
			||||
					if (!isSameSecond(remain, this.remainTime) || remain === 0) { | 
				
			||||
						this.setRemainTime(remain) | 
				
			||||
					} | 
				
			||||
					// 如果剩余时间不为0,则继续检查更新倒计时 | 
				
			||||
					if (this.remainTime !== 0) { | 
				
			||||
						this.macroTick() | 
				
			||||
					} | 
				
			||||
				}, 30) | 
				
			||||
			}, | 
				
			||||
			microTick() { | 
				
			||||
				this.clearTimeout() | 
				
			||||
				this.timer = setTimeout(() => { | 
				
			||||
					this.setRemainTime(this.getRemainTime()) | 
				
			||||
					if (this.remainTime !== 0) { | 
				
			||||
						this.microTick() | 
				
			||||
					} | 
				
			||||
				}, 50) | 
				
			||||
			}, | 
				
			||||
			// 获取剩余的时间 | 
				
			||||
			getRemainTime() { | 
				
			||||
				// 取最大值,防止出现小于0的剩余时间值 | 
				
			||||
				return Math.max(this.endTime - Date.now(), 0) | 
				
			||||
			}, | 
				
			||||
			// 设置剩余的时间 | 
				
			||||
			setRemainTime(remain) { | 
				
			||||
				this.remainTime = remain | 
				
			||||
				// 根据剩余的毫秒时间,得出该有天,小时,分钟等的值,返回一个对象 | 
				
			||||
				const timeData = parseTimeData(remain) | 
				
			||||
				this.$emit('change', timeData) | 
				
			||||
				// 得出格式化后的时间 | 
				
			||||
				this.formattedTime = parseFormat(this.format, timeData) | 
				
			||||
				// 如果时间已到,停止倒计时 | 
				
			||||
				if (remain <= 0) { | 
				
			||||
					this.pause() | 
				
			||||
					this.$emit('finish') | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			// 重置倒计时 | 
				
			||||
			reset() { | 
				
			||||
				this.pause() | 
				
			||||
				this.remainTime = this.time | 
				
			||||
				this.setRemainTime(this.remainTime) | 
				
			||||
				if (this.autoStart) { | 
				
			||||
					this.start() | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			// 暂停倒计时 | 
				
			||||
			pause() { | 
				
			||||
				this.runing = false; | 
				
			||||
				this.clearTimeout() | 
				
			||||
			}, | 
				
			||||
			// 清空定时器 | 
				
			||||
			clearTimeout() { | 
				
			||||
				clearTimeout(this.timer) | 
				
			||||
				this.timer = null | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		beforeDestroy() { | 
				
			||||
			this.clearTimeout() | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style | 
				
			||||
	lang="scss" | 
				
			||||
	scoped | 
				
			||||
> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
	$u-count-down-text-color:$u-content-color !default; | 
				
			||||
	$u-count-down-text-font-size:15px !default; | 
				
			||||
	$u-count-down-text-line-height:22px !default; | 
				
			||||
 | 
				
			||||
	.u-count-down { | 
				
			||||
		&__text { | 
				
			||||
			color: $u-count-down-text-color; | 
				
			||||
			font-size: $u-count-down-text-font-size; | 
				
			||||
			line-height: $u-count-down-text-line-height; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,62 @@
					 | 
				
			||||
// 补0,如1 -> 01
 | 
				
			||||
function padZero(num, targetLength = 2) { | 
				
			||||
    let str = `${num}` | 
				
			||||
    while (str.length < targetLength) { | 
				
			||||
        str = `0${str}` | 
				
			||||
    } | 
				
			||||
    return str | 
				
			||||
} | 
				
			||||
const SECOND = 1000 | 
				
			||||
const MINUTE = 60 * SECOND | 
				
			||||
const HOUR = 60 * MINUTE | 
				
			||||
const DAY = 24 * HOUR | 
				
			||||
export function parseTimeData(time) { | 
				
			||||
    const days = Math.floor(time / DAY) | 
				
			||||
    const hours = Math.floor((time % DAY) / HOUR) | 
				
			||||
    const minutes = Math.floor((time % HOUR) / MINUTE) | 
				
			||||
    const seconds = Math.floor((time % MINUTE) / SECOND) | 
				
			||||
    const milliseconds = Math.floor(time % SECOND) | 
				
			||||
    return { | 
				
			||||
        days, | 
				
			||||
        hours, | 
				
			||||
        minutes, | 
				
			||||
        seconds, | 
				
			||||
        milliseconds | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
export function parseFormat(format, timeData) { | 
				
			||||
    let { | 
				
			||||
        days, | 
				
			||||
        hours, | 
				
			||||
        minutes, | 
				
			||||
        seconds, | 
				
			||||
        milliseconds | 
				
			||||
    } = timeData | 
				
			||||
    // 如果格式化字符串中不存在DD(天),则将天的时间转为小时中去
 | 
				
			||||
    if (format.indexOf('DD') === -1) { | 
				
			||||
        hours += days * 24 | 
				
			||||
    } else { | 
				
			||||
        // 对天补0
 | 
				
			||||
        format = format.replace('DD', padZero(days)) | 
				
			||||
    } | 
				
			||||
    // 其他同理于DD的格式化处理方式
 | 
				
			||||
    if (format.indexOf('HH') === -1) { | 
				
			||||
        minutes += hours * 60 | 
				
			||||
    } else { | 
				
			||||
        format = format.replace('HH', padZero(hours)) | 
				
			||||
    } | 
				
			||||
    if (format.indexOf('mm') === -1) { | 
				
			||||
        seconds += minutes * 60 | 
				
			||||
    } else { | 
				
			||||
        format = format.replace('mm', padZero(minutes)) | 
				
			||||
    } | 
				
			||||
    if (format.indexOf('ss') === -1) { | 
				
			||||
        milliseconds += seconds * 1000 | 
				
			||||
    } else { | 
				
			||||
        format = format.replace('ss', padZero(seconds)) | 
				
			||||
    } | 
				
			||||
    return format.replace('SSS', padZero(milliseconds, 3)) | 
				
			||||
} | 
				
			||||
export function isSameSecond(time1, time2) { | 
				
			||||
    return Math.floor(time1 / 1000) === Math.floor(time2 / 1000) | 
				
			||||
} | 
				
			||||
@ -0,0 +1,59 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 开始的数值,默认从0增长到某一个数
 | 
				
			||||
        startVal: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.countTo.startVal | 
				
			||||
        }, | 
				
			||||
        // 要滚动的目标数值,必须
 | 
				
			||||
        endVal: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.countTo.endVal | 
				
			||||
        }, | 
				
			||||
        // 滚动到目标数值的动画持续时间,单位为毫秒(ms)
 | 
				
			||||
        duration: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.countTo.duration | 
				
			||||
        }, | 
				
			||||
        // 设置数值后是否自动开始滚动
 | 
				
			||||
        autoplay: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.countTo.autoplay | 
				
			||||
        }, | 
				
			||||
        // 要显示的小数位数
 | 
				
			||||
        decimals: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.countTo.decimals | 
				
			||||
        }, | 
				
			||||
        // 是否在即将到达目标数值的时候,使用缓慢滚动的效果
 | 
				
			||||
        useEasing: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.countTo.useEasing | 
				
			||||
        }, | 
				
			||||
        // 十进制分割
 | 
				
			||||
        decimal: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.countTo.decimal | 
				
			||||
        }, | 
				
			||||
        // 字体颜色
 | 
				
			||||
        color: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.countTo.color | 
				
			||||
        }, | 
				
			||||
        // 字体大小
 | 
				
			||||
        fontSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.countTo.fontSize | 
				
			||||
        }, | 
				
			||||
        // 是否加粗字体
 | 
				
			||||
        bold: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.countTo.bold | 
				
			||||
        }, | 
				
			||||
        // 千位分隔符,类似金额的分割(¥23,321.05中的",")
 | 
				
			||||
        separator: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.countTo.separator | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,184 @@
					 | 
				
			||||
<template> | 
				
			||||
	<text | 
				
			||||
		class="u-count-num" | 
				
			||||
		:style="{ | 
				
			||||
			fontSize: $u.addUnit(fontSize), | 
				
			||||
			fontWeight: bold ? 'bold' : 'normal', | 
				
			||||
			color: color | 
				
			||||
		}" | 
				
			||||
	>{{ displayValue }}</text> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
/** | 
				
			||||
 * countTo 数字滚动 | 
				
			||||
 * @description 该组件一般用于需要滚动数字到某一个值的场景,目标要求是一个递增的值。 | 
				
			||||
 * @tutorial https://www.uviewui.com/components/countTo.html | 
				
			||||
 * @property {String | Number}	startVal	开始的数值,默认从0增长到某一个数(默认 0 ) | 
				
			||||
 * @property {String | Number}	endVal		要滚动的目标数值,必须 (默认 0 ) | 
				
			||||
 * @property {String | Number}	duration	滚动到目标数值的动画持续时间,单位为毫秒(ms) (默认 2000 ) | 
				
			||||
 * @property {Boolean}			autoplay	设置数值后是否自动开始滚动 (默认 true ) | 
				
			||||
 * @property {String | Number}	decimals	要显示的小数位数,见官网说明(默认 0 ) | 
				
			||||
 * @property {Boolean}			useEasing	滚动结束时,是否缓动结尾,见官网说明(默认 true ) | 
				
			||||
 * @property {String}			decimal		十进制分割 ( 默认 "." ) | 
				
			||||
 * @property {String}			color		字体颜色( 默认 '#606266' ) | 
				
			||||
 * @property {String | Number}	fontSize	字体大小,单位px( 默认 22 ) | 
				
			||||
 * @property {Boolean}			bold		字体是否加粗(默认 false ) | 
				
			||||
 * @property {String}			separator	千位分隔符,见官网说明 | 
				
			||||
 * @event {Function} end 数值滚动到目标值时触发 | 
				
			||||
 * @example <u-count-to ref="uCountTo" :end-val="endVal" :autoplay="autoplay"></u-count-to> | 
				
			||||
 */ | 
				
			||||
export default { | 
				
			||||
	name: 'u-count-to', | 
				
			||||
	data() { | 
				
			||||
		return { | 
				
			||||
			localStartVal: this.startVal, | 
				
			||||
			displayValue: this.formatNumber(this.startVal), | 
				
			||||
			printVal: null, | 
				
			||||
			paused: false, // 是否暂停 | 
				
			||||
			localDuration: Number(this.duration), | 
				
			||||
			startTime: null, // 开始的时间 | 
				
			||||
			timestamp: null, // 时间戳 | 
				
			||||
			remaining: null, // 停留的时间 | 
				
			||||
			rAF: null, | 
				
			||||
			lastTime: 0 // 上一次的时间 | 
				
			||||
		}; | 
				
			||||
	}, | 
				
			||||
	mixins: [uni.$u.mpMixin, uni.$u.mixin,props], | 
				
			||||
	computed: { | 
				
			||||
		countDown() { | 
				
			||||
			return this.startVal > this.endVal; | 
				
			||||
		} | 
				
			||||
	}, | 
				
			||||
	watch: { | 
				
			||||
		startVal() { | 
				
			||||
			this.autoplay && this.start(); | 
				
			||||
		}, | 
				
			||||
		endVal() { | 
				
			||||
			this.autoplay && this.start(); | 
				
			||||
		} | 
				
			||||
	}, | 
				
			||||
	mounted() { | 
				
			||||
		this.autoplay && this.start(); | 
				
			||||
	}, | 
				
			||||
	methods: { | 
				
			||||
		easingFn(t, b, c, d) { | 
				
			||||
			return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b; | 
				
			||||
		}, | 
				
			||||
		requestAnimationFrame(callback) { | 
				
			||||
			const currTime = new Date().getTime(); | 
				
			||||
			// 为了使setTimteout的尽可能的接近每秒60帧的效果 | 
				
			||||
			const timeToCall = Math.max(0, 16 - (currTime - this.lastTime)); | 
				
			||||
			const id = setTimeout(() => { | 
				
			||||
				callback(currTime + timeToCall); | 
				
			||||
			}, timeToCall); | 
				
			||||
			this.lastTime = currTime + timeToCall; | 
				
			||||
			return id; | 
				
			||||
		}, | 
				
			||||
		cancelAnimationFrame(id) { | 
				
			||||
			clearTimeout(id); | 
				
			||||
		}, | 
				
			||||
		// 开始滚动数字 | 
				
			||||
		start() { | 
				
			||||
			this.localStartVal = this.startVal; | 
				
			||||
			this.startTime = null; | 
				
			||||
			this.localDuration = this.duration; | 
				
			||||
			this.paused = false; | 
				
			||||
			this.rAF = this.requestAnimationFrame(this.count); | 
				
			||||
		}, | 
				
			||||
		// 暂定状态,重新再开始滚动;或者滚动状态下,暂停 | 
				
			||||
		reStart() { | 
				
			||||
			if (this.paused) { | 
				
			||||
				this.resume(); | 
				
			||||
				this.paused = false; | 
				
			||||
			} else { | 
				
			||||
				this.stop(); | 
				
			||||
				this.paused = true; | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		// 暂停 | 
				
			||||
		stop() { | 
				
			||||
			this.cancelAnimationFrame(this.rAF); | 
				
			||||
		}, | 
				
			||||
		// 重新开始(暂停的情况下) | 
				
			||||
		resume() { | 
				
			||||
			if (!this.remaining) return | 
				
			||||
			this.startTime = 0; | 
				
			||||
			this.localDuration = this.remaining; | 
				
			||||
			this.localStartVal = this.printVal; | 
				
			||||
			this.requestAnimationFrame(this.count); | 
				
			||||
		}, | 
				
			||||
		// 重置 | 
				
			||||
		reset() { | 
				
			||||
			this.startTime = null; | 
				
			||||
			this.cancelAnimationFrame(this.rAF); | 
				
			||||
			this.displayValue = this.formatNumber(this.startVal); | 
				
			||||
		}, | 
				
			||||
		count(timestamp) { | 
				
			||||
			if (!this.startTime) this.startTime = timestamp; | 
				
			||||
			this.timestamp = timestamp; | 
				
			||||
			const progress = timestamp - this.startTime; | 
				
			||||
			this.remaining = this.localDuration - progress; | 
				
			||||
			if (this.useEasing) { | 
				
			||||
				if (this.countDown) { | 
				
			||||
					this.printVal = this.localStartVal - this.easingFn(progress, 0, this.localStartVal - this.endVal, this.localDuration); | 
				
			||||
				} else { | 
				
			||||
					this.printVal = this.easingFn(progress, this.localStartVal, this.endVal - this.localStartVal, this.localDuration); | 
				
			||||
				} | 
				
			||||
			} else { | 
				
			||||
				if (this.countDown) { | 
				
			||||
					this.printVal = this.localStartVal - (this.localStartVal - this.endVal) * (progress / this.localDuration); | 
				
			||||
				} else { | 
				
			||||
					this.printVal = this.localStartVal + (this.endVal - this.localStartVal) * (progress / this.localDuration); | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
			if (this.countDown) { | 
				
			||||
				this.printVal = this.printVal < this.endVal ? this.endVal : this.printVal; | 
				
			||||
			} else { | 
				
			||||
				this.printVal = this.printVal > this.endVal ? this.endVal : this.printVal; | 
				
			||||
			} | 
				
			||||
			this.displayValue = this.formatNumber(this.printVal) || 0; | 
				
			||||
			if (progress < this.localDuration) { | 
				
			||||
				this.rAF = this.requestAnimationFrame(this.count); | 
				
			||||
			} else { | 
				
			||||
				this.$emit('end'); | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		// 判断是否数字 | 
				
			||||
		isNumber(val) { | 
				
			||||
			return !isNaN(parseFloat(val)); | 
				
			||||
		}, | 
				
			||||
		formatNumber(num) { | 
				
			||||
			// 将num转为Number类型,因为其值可能为字符串数值,调用toFixed会报错 | 
				
			||||
			num = Number(num); | 
				
			||||
			num = num.toFixed(Number(this.decimals)); | 
				
			||||
			num += ''; | 
				
			||||
			const x = num.split('.'); | 
				
			||||
			let x1 = x[0]; | 
				
			||||
			const x2 = x.length > 1 ? this.decimal + x[1] : ''; | 
				
			||||
			const rgx = /(\d+)(\d{3})/; | 
				
			||||
			if (this.separator && !this.isNumber(this.separator)) { | 
				
			||||
				while (rgx.test(x1)) { | 
				
			||||
					x1 = x1.replace(rgx, '$1' + this.separator + '$2'); | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
			return x1 + x2; | 
				
			||||
		}, | 
				
			||||
		destroyed() { | 
				
			||||
			this.cancelAnimationFrame(this.rAF); | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
}; | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
.u-count-num { | 
				
			||||
	/* #ifndef APP-NVUE */ | 
				
			||||
	display: inline-flex; | 
				
			||||
	/* #endif */ | 
				
			||||
	text-align: center; | 
				
			||||
} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,116 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 是否打开组件
 | 
				
			||||
        show: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.datetimePicker.show | 
				
			||||
        }, | 
				
			||||
        // 是否展示顶部的操作栏
 | 
				
			||||
        showToolbar: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.datetimePicker.showToolbar | 
				
			||||
        }, | 
				
			||||
        // 绑定值
 | 
				
			||||
        value: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.datetimePicker.value | 
				
			||||
        }, | 
				
			||||
        // 顶部标题
 | 
				
			||||
        title: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.datetimePicker.title | 
				
			||||
        }, | 
				
			||||
        // 展示格式,mode=date为日期选择,mode=time为时间选择,mode=year-month为年月选择,mode=datetime为日期时间选择
 | 
				
			||||
        mode: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.datetimePicker.mode | 
				
			||||
        }, | 
				
			||||
        // 可选的最大时间
 | 
				
			||||
        maxDate: { | 
				
			||||
            type: Number, | 
				
			||||
            // 最大默认值为后10年
 | 
				
			||||
            default: uni.$u.props.datetimePicker.maxDate | 
				
			||||
        }, | 
				
			||||
        // 可选的最小时间
 | 
				
			||||
        minDate: { | 
				
			||||
            type: Number, | 
				
			||||
            // 最小默认值为前10年
 | 
				
			||||
            default: uni.$u.props.datetimePicker.minDate | 
				
			||||
        }, | 
				
			||||
        // 可选的最小小时,仅mode=time有效
 | 
				
			||||
        minHour: { | 
				
			||||
            type: Number, | 
				
			||||
            default: uni.$u.props.datetimePicker.minHour | 
				
			||||
        }, | 
				
			||||
        // 可选的最大小时,仅mode=time有效
 | 
				
			||||
        maxHour: { | 
				
			||||
            type: Number, | 
				
			||||
            default: uni.$u.props.datetimePicker.maxHour | 
				
			||||
        }, | 
				
			||||
        // 可选的最小分钟,仅mode=time有效
 | 
				
			||||
        minMinute: { | 
				
			||||
            type: Number, | 
				
			||||
            default: uni.$u.props.datetimePicker.minMinute | 
				
			||||
        }, | 
				
			||||
        // 可选的最大分钟,仅mode=time有效
 | 
				
			||||
        maxMinute: { | 
				
			||||
            type: Number, | 
				
			||||
            default: uni.$u.props.datetimePicker.maxMinute | 
				
			||||
        }, | 
				
			||||
        // 选项过滤函数
 | 
				
			||||
        filter: { | 
				
			||||
            type: [Function, null], | 
				
			||||
            default: uni.$u.props.datetimePicker.filter | 
				
			||||
        }, | 
				
			||||
        // 选项格式化函数
 | 
				
			||||
        formatter: { | 
				
			||||
            type: [Function, null], | 
				
			||||
            default: uni.$u.props.datetimePicker.formatter | 
				
			||||
        }, | 
				
			||||
        // 是否显示加载中状态
 | 
				
			||||
        loading: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.datetimePicker.loading | 
				
			||||
        }, | 
				
			||||
        // 各列中,单个选项的高度
 | 
				
			||||
        itemHeight: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.datetimePicker.itemHeight | 
				
			||||
        }, | 
				
			||||
        // 取消按钮的文字
 | 
				
			||||
        cancelText: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.datetimePicker.cancelText | 
				
			||||
        }, | 
				
			||||
        // 确认按钮的文字
 | 
				
			||||
        confirmText: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.datetimePicker.confirmText | 
				
			||||
        }, | 
				
			||||
        // 取消按钮的颜色
 | 
				
			||||
        cancelColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.datetimePicker.cancelColor | 
				
			||||
        }, | 
				
			||||
        // 确认按钮的颜色
 | 
				
			||||
        confirmColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.datetimePicker.confirmColor | 
				
			||||
        }, | 
				
			||||
        // 每列中可见选项的数量
 | 
				
			||||
        visibleItemCount: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.datetimePicker.visibleItemCount | 
				
			||||
        }, | 
				
			||||
        // 是否允许点击遮罩关闭选择器
 | 
				
			||||
        closeOnClickOverlay: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.datetimePicker.closeOnClickOverlay | 
				
			||||
        }, | 
				
			||||
        // 各列的默认索引
 | 
				
			||||
        defaultIndex: { | 
				
			||||
            type: Array, | 
				
			||||
            default: uni.$u.props.datetimePicker.defaultIndex | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,360 @@
					 | 
				
			||||
<template> | 
				
			||||
	<u-picker | 
				
			||||
		ref="picker" | 
				
			||||
		:show="show" | 
				
			||||
		:closeOnClickOverlay="closeOnClickOverlay" | 
				
			||||
		:columns="columns" | 
				
			||||
		:title="title" | 
				
			||||
		:itemHeight="itemHeight" | 
				
			||||
		:showToolbar="showToolbar" | 
				
			||||
		:visibleItemCount="visibleItemCount" | 
				
			||||
		:defaultIndex="innerDefaultIndex" | 
				
			||||
		:cancelText="cancelText" | 
				
			||||
		:confirmText="confirmText" | 
				
			||||
		:cancelColor="cancelColor" | 
				
			||||
		:confirmColor="confirmColor" | 
				
			||||
		@close="close" | 
				
			||||
		@cancel="cancel" | 
				
			||||
		@confirm="confirm" | 
				
			||||
		@change="change" | 
				
			||||
	> | 
				
			||||
	</u-picker> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	function times(n, iteratee) { | 
				
			||||
	    let index = -1 | 
				
			||||
	    const result = Array(n < 0 ? 0 : n) | 
				
			||||
	    while (++index < n) { | 
				
			||||
	        result[index] = iteratee(index) | 
				
			||||
	    } | 
				
			||||
	    return result | 
				
			||||
	} | 
				
			||||
	import props from './props.js'; | 
				
			||||
	import dayjs from '../../libs/util/dayjs.js'; | 
				
			||||
	/** | 
				
			||||
	 * DatetimePicker 时间日期选择器 | 
				
			||||
	 * @description 此选择器用于时间日期 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/datetimePicker.html | 
				
			||||
	 * @property {Boolean}			show				用于控制选择器的弹出与收起 ( 默认 false ) | 
				
			||||
	 * @property {Boolean}			showToolbar			是否显示顶部的操作栏  ( 默认 true ) | 
				
			||||
	 * @property {String | Number}	value				绑定值 | 
				
			||||
	 * @property {String}			title				顶部标题 | 
				
			||||
	 * @property {String}			mode				展示格式 mode=date为日期选择,mode=time为时间选择,mode=year-month为年月选择,mode=datetime为日期时间选择  ( 默认 ‘datetime ) | 
				
			||||
	 * @property {Number}			maxDate				可选的最大时间  默认值为后10年 | 
				
			||||
	 * @property {Number}			minDate				可选的最小时间  默认值为前10年 | 
				
			||||
	 * @property {Number}			minHour				可选的最小小时,仅mode=time有效   ( 默认 0 ) | 
				
			||||
	 * @property {Number}			maxHour				可选的最大小时,仅mode=time有效	  ( 默认 23 ) | 
				
			||||
	 * @property {Number}			minMinute			可选的最小分钟,仅mode=time有效	  ( 默认 0 ) | 
				
			||||
	 * @property {Number}			maxMinute			可选的最大分钟,仅mode=time有效   ( 默认 59 ) | 
				
			||||
	 * @property {Function}			filter				选项过滤函数 | 
				
			||||
	 * @property {Function}			formatter			选项格式化函数 | 
				
			||||
	 * @property {Boolean}			loading				是否显示加载中状态   ( 默认 false ) | 
				
			||||
	 * @property {String | Number}	itemHeight			各列中,单个选项的高度   ( 默认 44 ) | 
				
			||||
	 * @property {String}			cancelText			取消按钮的文字  ( 默认 '取消' ) | 
				
			||||
	 * @property {String}			confirmText			确认按钮的文字  ( 默认 '确认' ) | 
				
			||||
	 * @property {String}			cancelColor			取消按钮的颜色  ( 默认 '#909193' ) | 
				
			||||
	 * @property {String}			confirmColor		确认按钮的颜色  ( 默认 '#3c9cff' ) | 
				
			||||
	 * @property {String | Number}	visibleItemCount	每列中可见选项的数量  ( 默认 5 ) | 
				
			||||
	 * @property {Boolean}			closeOnClickOverlay	是否允许点击遮罩关闭选择器  ( 默认 false ) | 
				
			||||
	 * @property {Array}			defaultIndex		各列的默认索引 | 
				
			||||
	 * @event {Function} close 关闭选择器时触发 | 
				
			||||
	 * @event {Function} confirm 点击确定按钮,返回当前选择的值 | 
				
			||||
	 * @event {Function} change 当选择值变化时触发 | 
				
			||||
	 * @event {Function} cancel 点击取消按钮 | 
				
			||||
	 * @example  <u-datetime-picker :show="show" :value="value1"  mode="datetime" ></u-datetime-picker> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'datetime-picker', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				columns: [], | 
				
			||||
				innerDefaultIndex: [], | 
				
			||||
				innerFormatter: (type, value) => value | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		watch: { | 
				
			||||
			show(newValue, oldValue) { | 
				
			||||
				if (newValue) { | 
				
			||||
					this.updateColumnValue(this.innerValue) | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			propsChange() { | 
				
			||||
				this.init() | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			// 如果以下这些变量发生了变化,意味着需要重新初始化各列的值 | 
				
			||||
			propsChange() { | 
				
			||||
				return [this.mode, this.maxDate, this.minDate, this.minHour, this.maxHour, this.minMinute, this.maxMinute, this.filter, ] | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		mounted() { | 
				
			||||
			this.init() | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			init() { | 
				
			||||
				this.innerValue = this.correctValue(this.value) | 
				
			||||
				this.updateColumnValue(this.innerValue) | 
				
			||||
			}, | 
				
			||||
			// 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用 | 
				
			||||
			setFormatter(e) { | 
				
			||||
				this.innerFormatter = e | 
				
			||||
			}, | 
				
			||||
			// 关闭选择器 | 
				
			||||
			close() { | 
				
			||||
				if (this.closeOnClickOverlay) { | 
				
			||||
					this.$emit('close') | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			// 点击工具栏的取消按钮 | 
				
			||||
			cancel() { | 
				
			||||
				this.$emit('cancel') | 
				
			||||
			}, | 
				
			||||
			// 点击工具栏的确定按钮 | 
				
			||||
			confirm() { | 
				
			||||
				this.$emit('confirm', { | 
				
			||||
					value: this.innerValue, | 
				
			||||
					mode: this.mode | 
				
			||||
				}) | 
				
			||||
				this.$emit('input', this.innerValue) | 
				
			||||
			}, | 
				
			||||
			//用正则截取输出值,当出现多组数字时,抛出错误 | 
				
			||||
			intercept(e,type){ | 
				
			||||
				let judge = e.match(/\d+/g) | 
				
			||||
				//判断是否掺杂数字 | 
				
			||||
				if(judge.length>1){ | 
				
			||||
					uni.$u.error("请勿在过滤或格式化函数时添加数字") | 
				
			||||
					return 0 | 
				
			||||
				}else if(type&&judge[0].length==4){//判断是否是年份 | 
				
			||||
					return judge[0] | 
				
			||||
				}else if(judge[0].length>2){ | 
				
			||||
					uni.$u.error("请勿在过滤或格式化函数时添加数字") | 
				
			||||
					return 0 | 
				
			||||
				}else{ | 
				
			||||
					return judge[0] | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			// 列发生变化时触发 | 
				
			||||
			change(e) { | 
				
			||||
				const { indexs, values } = e | 
				
			||||
				let selectValue = '' | 
				
			||||
				if(this.mode === 'time') { | 
				
			||||
					// 根据value各列索引,从各列数组中,取出当前时间的选中值 | 
				
			||||
					selectValue = `${this.intercept(values[0][indexs[0]])}:${this.intercept(values[1][indexs[1]])}` | 
				
			||||
				} else { | 
				
			||||
					// 将选择的值转为数值,比如'03'转为数值的3,'2019'转为数值的2019 | 
				
			||||
					const year = parseInt(this.intercept(values[0][indexs[0]],'year')) | 
				
			||||
					const month = parseInt(this.intercept(values[1][indexs[1]])) | 
				
			||||
					let date = parseInt(values[2] ? this.intercept(values[2][indexs[2]]) : 1) | 
				
			||||
					let hour = 0, minute = 0 | 
				
			||||
					// 此月份的最大天数 | 
				
			||||
					const maxDate = dayjs(`${year}-${month}`).daysInMonth() | 
				
			||||
					// year-month模式下,date不会出现在列中,设置为1,为了符合后边需要减1的需求 | 
				
			||||
					if (this.mode === 'year-month') { | 
				
			||||
					    date = 1 | 
				
			||||
					} | 
				
			||||
					// 不允许超过maxDate值 | 
				
			||||
					date = Math.min(maxDate, date) | 
				
			||||
					if (this.mode === 'datetime') { | 
				
			||||
					    hour = parseInt(this.intercept(values[3][indexs[3]])) | 
				
			||||
					    minute = parseInt(this.intercept(values[4][indexs[4]])) | 
				
			||||
					} | 
				
			||||
					// 转为时间模式 | 
				
			||||
					selectValue = Number(new Date(year, month - 1, date, hour, minute)) | 
				
			||||
				} | 
				
			||||
				// 取出准确的合法值,防止超越边界的情况 | 
				
			||||
				selectValue = this.correctValue(selectValue) | 
				
			||||
				this.innerValue = selectValue | 
				
			||||
				this.updateColumnValue(selectValue) | 
				
			||||
				// 发出change时间,value为当前选中的时间戳 | 
				
			||||
				this.$emit('change', { | 
				
			||||
					value: selectValue, | 
				
			||||
					// #ifndef MP-WEIXIN || MP-TOUTIAO | 
				
			||||
					// 微信小程序不能传递this实例,会因为循环引用而报错 | 
				
			||||
					picker: this.$refs.picker, | 
				
			||||
					// #endif | 
				
			||||
					mode: this.mode | 
				
			||||
				}) | 
				
			||||
			}, | 
				
			||||
			// 更新各列的值,进行补0、格式化等操作 | 
				
			||||
			updateColumnValue(value) { | 
				
			||||
				this.innerValue = value | 
				
			||||
				this.updateColumns() | 
				
			||||
				this.updateIndexs(value) | 
				
			||||
			}, | 
				
			||||
			// 更新索引 | 
				
			||||
			updateIndexs(value) { | 
				
			||||
				let values = [] | 
				
			||||
				const formatter = this.formatter || this.innerFormatter | 
				
			||||
				const padZero = uni.$u.padZero | 
				
			||||
				if (this.mode === 'time') { | 
				
			||||
					// 将time模式的时间用:分隔成数组 | 
				
			||||
				    const timeArr = value.split(':') | 
				
			||||
					// 使用formatter格式化方法进行管道处理 | 
				
			||||
				    values = [formatter('hour', timeArr[0]), formatter('minute', timeArr[1])] | 
				
			||||
				} else { | 
				
			||||
				    const date = new Date(value) | 
				
			||||
				    values = [ | 
				
			||||
				        formatter('year', `${dayjs(value).year()}`), | 
				
			||||
						// 月份补0 | 
				
			||||
				        formatter('month', padZero(dayjs(value).month() + 1)) | 
				
			||||
				    ] | 
				
			||||
				    if (this.mode === 'date') { | 
				
			||||
						// date模式,需要添加天列 | 
				
			||||
				        values.push(formatter('day', padZero(dayjs(value).date()))) | 
				
			||||
				    } | 
				
			||||
				    if (this.mode === 'datetime') { | 
				
			||||
						// 数组的push方法,可以写入多个参数 | 
				
			||||
				        values.push(formatter('day', padZero(dayjs(value).date())), formatter('hour', padZero(dayjs(value).hour())), formatter('minute', padZero(dayjs(value).minute()))) | 
				
			||||
				    } | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				// 根据当前各列的所有值,从各列默认值中找到默认值在各列中的索引 | 
				
			||||
				const indexs = this.columns.map((column, index) => { | 
				
			||||
					// 通过取大值,可以保证不会出现找不到索引的-1情况 | 
				
			||||
					return Math.max(0, column.findIndex(item => item === values[index])) | 
				
			||||
				}) | 
				
			||||
				this.innerDefaultIndex = indexs | 
				
			||||
			}, | 
				
			||||
			// 更新各列的值 | 
				
			||||
			updateColumns() { | 
				
			||||
			    const formatter = this.formatter || this.innerFormatter | 
				
			||||
				// 获取各列的值,并且map后,对各列的具体值进行补0操作 | 
				
			||||
			    const results = this.getOriginColumns().map((column) => column.values.map((value) => formatter(column.type, value))) | 
				
			||||
				this.columns = results | 
				
			||||
			}, | 
				
			||||
			getOriginColumns() { | 
				
			||||
			    // 生成各列的值 | 
				
			||||
			    const results = this.getRanges().map(({ type, range }) => { | 
				
			||||
			        let values = times(range[1] - range[0] + 1, (index) => { | 
				
			||||
			            let value = range[0] + index | 
				
			||||
			            value = type === 'year' ? `${value}` : uni.$u.padZero(value) | 
				
			||||
			            return value | 
				
			||||
			        }) | 
				
			||||
					// 进行过滤 | 
				
			||||
			        if (this.filter) { | 
				
			||||
			            values = this.filter(type, values) | 
				
			||||
			        } | 
				
			||||
			        return { type, values } | 
				
			||||
			    }) | 
				
			||||
			    return results | 
				
			||||
			}, | 
				
			||||
			// 通过最大值和最小值生成数组 | 
				
			||||
			generateArray(start, end) { | 
				
			||||
				return Array.from(new Array(end + 1).keys()).slice(start) | 
				
			||||
			}, | 
				
			||||
			// 得出合法的时间 | 
				
			||||
			correctValue(value) { | 
				
			||||
				const isDateMode = this.mode !== 'time' | 
				
			||||
				if (isDateMode && !uni.$u.test.date(value)) { | 
				
			||||
					// 如果是日期类型,但是又没有设置合法的当前时间的话,使用最小时间为当前时间 | 
				
			||||
					value = this.minDate | 
				
			||||
				} else if (!isDateMode && !value) { | 
				
			||||
					// 如果是时间类型,而又没有默认值的话,就用最小时间 | 
				
			||||
					value = `${uni.$u.padZero(this.minHour)}:${uni.$u.padZero(this.minMinute)}` | 
				
			||||
				} | 
				
			||||
				// 时间类型 | 
				
			||||
				if (!isDateMode) { | 
				
			||||
					if (String(value).indexOf(':') === -1) return uni.$u.error('时间错误,请传递如12:24的格式') | 
				
			||||
					let [hour, minute] = value.split(':') | 
				
			||||
					// 对时间补零,同时控制在最小值和最大值之间 | 
				
			||||
					hour = uni.$u.padZero(uni.$u.range(this.minHour, this.maxHour, Number(hour))) | 
				
			||||
					minute = uni.$u.padZero(uni.$u.range(this.minMinute, this.maxMinute, Number(minute))) | 
				
			||||
					return `${ hour }:${ minute }` | 
				
			||||
				} else { | 
				
			||||
					// 如果是日期格式,控制在最小日期和最大日期之间 | 
				
			||||
					value = dayjs(value).isBefore(dayjs(this.minDate)) ? this.minDate : value | 
				
			||||
					value = dayjs(value).isAfter(dayjs(this.maxDate)) ? this.maxDate : value | 
				
			||||
					return value | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			// 获取每列的最大和最小值 | 
				
			||||
			getRanges() { | 
				
			||||
			    if (this.mode === 'time') { | 
				
			||||
			        return [ | 
				
			||||
			            { | 
				
			||||
			                type: 'hour', | 
				
			||||
			                range: [this.minHour, this.maxHour], | 
				
			||||
			            }, | 
				
			||||
			            { | 
				
			||||
			                type: 'minute', | 
				
			||||
			                range: [this.minMinute, this.maxMinute], | 
				
			||||
			            }, | 
				
			||||
			        ]; | 
				
			||||
			    } | 
				
			||||
			    const { maxYear, maxDate, maxMonth, maxHour, maxMinute, } = this.getBoundary('max', this.innerValue); | 
				
			||||
			    const { minYear, minDate, minMonth, minHour, minMinute, } = this.getBoundary('min', this.innerValue); | 
				
			||||
			    const result = [ | 
				
			||||
			        { | 
				
			||||
			            type: 'year', | 
				
			||||
			            range: [minYear, maxYear], | 
				
			||||
			        }, | 
				
			||||
			        { | 
				
			||||
			            type: 'month', | 
				
			||||
			            range: [minMonth, maxMonth], | 
				
			||||
			        }, | 
				
			||||
			        { | 
				
			||||
			            type: 'day', | 
				
			||||
			            range: [minDate, maxDate], | 
				
			||||
			        }, | 
				
			||||
			        { | 
				
			||||
			            type: 'hour', | 
				
			||||
			            range: [minHour, maxHour], | 
				
			||||
			        }, | 
				
			||||
			        { | 
				
			||||
			            type: 'minute', | 
				
			||||
			            range: [minMinute, maxMinute], | 
				
			||||
			        }, | 
				
			||||
			    ]; | 
				
			||||
			    if (this.mode === 'date') | 
				
			||||
			        result.splice(3, 2); | 
				
			||||
			    if (this.mode === 'year-month') | 
				
			||||
			        result.splice(2, 3); | 
				
			||||
			    return result; | 
				
			||||
			}, | 
				
			||||
			// 根据minDate、maxDate、minHour、maxHour等边界值,判断各列的开始和结束边界值 | 
				
			||||
			getBoundary(type, innerValue) { | 
				
			||||
			    const value = new Date(innerValue) | 
				
			||||
			    const boundary = new Date(this[`${type}Date`]) | 
				
			||||
			    const year = dayjs(boundary).year() | 
				
			||||
			    let month = 1 | 
				
			||||
			    let date = 1 | 
				
			||||
			    let hour = 0 | 
				
			||||
			    let minute = 0 | 
				
			||||
			    if (type === 'max') { | 
				
			||||
			        month = 12 | 
				
			||||
					// 月份的天数 | 
				
			||||
			        date = dayjs(value).daysInMonth() | 
				
			||||
			        hour = 23 | 
				
			||||
			        minute = 59 | 
				
			||||
			    } | 
				
			||||
				// 获取边界值,逻辑是:当年达到了边界值(最大或最小年),就检查月允许的最大和最小值,以此类推 | 
				
			||||
			    if (dayjs(value).year() === year) { | 
				
			||||
			        month = dayjs(boundary).month() + 1 | 
				
			||||
			        if (dayjs(value).month() + 1 === month) { | 
				
			||||
			            date = dayjs(boundary).date() | 
				
			||||
			            if (dayjs(value).date() === date) { | 
				
			||||
			                hour = dayjs(boundary).hour() | 
				
			||||
			                if (dayjs(value).hour() === hour) { | 
				
			||||
			                    minute = dayjs(boundary).minute() | 
				
			||||
			                } | 
				
			||||
			            } | 
				
			||||
			        } | 
				
			||||
			    } | 
				
			||||
			    return { | 
				
			||||
			        [`${type}Year`]: year, | 
				
			||||
			        [`${type}Month`]: month, | 
				
			||||
			        [`${type}Date`]: date, | 
				
			||||
			        [`${type}Hour`]: hour, | 
				
			||||
			        [`${type}Minute`]: minute | 
				
			||||
			    } | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import '../../libs/css/components.scss'; | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,44 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 是否虚线
 | 
				
			||||
        dashed: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.divider.dashed | 
				
			||||
        }, | 
				
			||||
        // 是否细线
 | 
				
			||||
        hairline: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.divider.hairline | 
				
			||||
        }, | 
				
			||||
        // 是否以点替代文字,优先于text字段起作用
 | 
				
			||||
        dot: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.divider.dot | 
				
			||||
        }, | 
				
			||||
        // 内容文本的位置,left-左边,center-中间,right-右边
 | 
				
			||||
        textPosition: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.divider.textPosition | 
				
			||||
        }, | 
				
			||||
        // 文本内容
 | 
				
			||||
        text: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.divider.text | 
				
			||||
        }, | 
				
			||||
        // 文本大小
 | 
				
			||||
        textSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.divider.textSize | 
				
			||||
        }, | 
				
			||||
        // 文本颜色
 | 
				
			||||
        textColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.divider.textColor | 
				
			||||
        }, | 
				
			||||
        // 线条颜色
 | 
				
			||||
        lineColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.divider.lineColor | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,116 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view | 
				
			||||
	    class="u-divider" | 
				
			||||
	    :style="[$u.addStyle(customStyle)]" | 
				
			||||
		@tap="click" | 
				
			||||
	> | 
				
			||||
		<u-line | 
				
			||||
		    :color="lineColor" | 
				
			||||
		    :customStyle="leftLineStyle" | 
				
			||||
		    :hairline="hairline" | 
				
			||||
			:dashed="dashed" | 
				
			||||
		></u-line> | 
				
			||||
		<text | 
				
			||||
		    v-if="dot" | 
				
			||||
		    class="u-divider__dot" | 
				
			||||
		>●</text> | 
				
			||||
		<text | 
				
			||||
		    v-else-if="text" | 
				
			||||
		    class="u-divider__text" | 
				
			||||
		    :style="[textStyle]" | 
				
			||||
		>{{text}}</text> | 
				
			||||
		<u-line | 
				
			||||
		    :color="lineColor" | 
				
			||||
		    :customStyle="rightLineStyle" | 
				
			||||
		    :hairline="hairline" | 
				
			||||
			:dashed="dashed" | 
				
			||||
		></u-line> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * divider 分割线 | 
				
			||||
	 * @description 区隔内容的分割线,一般用于页面底部"没有更多"的提示。 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/divider.html | 
				
			||||
	 * @property {Boolean}			dashed			是否虚线 (默认 false ) | 
				
			||||
	 * @property {Boolean}			hairline		是否细线 (默认  true ) | 
				
			||||
	 * @property {Boolean}			dot				是否以点替代文字,优先于text字段起作用 (默认 false ) | 
				
			||||
	 * @property {String}			textPosition	内容文本的位置,left-左边,center-中间,right-右边 (默认 'center' ) | 
				
			||||
	 * @property {String | Number}	text			文本内容 | 
				
			||||
	 * @property {String | Number}	textSize		文本大小 (默认 14) | 
				
			||||
	 * @property {String}			textColor		文本颜色 (默认 '#909399' ) | 
				
			||||
	 * @property {String}			lineColor		线条颜色 (默认 '#dcdfe6' ) | 
				
			||||
	 * @property {Object}			customStyle		定义需要用到的外部样式 | 
				
			||||
	 * | 
				
			||||
	 * @event {Function}	click	divider组件被点击时触发 | 
				
			||||
	 * @example <u-divider :color="color">锦瑟无端五十弦</u-divider> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name:'u-divider', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin,props], | 
				
			||||
		computed: { | 
				
			||||
			textStyle() { | 
				
			||||
				const style = {} | 
				
			||||
				style.fontSize = uni.$u.addUnit(this.textSize) | 
				
			||||
				style.color = this.textColor | 
				
			||||
				return style | 
				
			||||
			}, | 
				
			||||
			// 左边线条的的样式 | 
				
			||||
			leftLineStyle() { | 
				
			||||
				const style = {} | 
				
			||||
				// 如果是在左边,设置左边的宽度为固定值 | 
				
			||||
				if (this.textPosition === 'left') { | 
				
			||||
					style.width = '80rpx' | 
				
			||||
				} else { | 
				
			||||
					style.flex = 1 | 
				
			||||
				} | 
				
			||||
				return style | 
				
			||||
			}, | 
				
			||||
			// 右边线条的的样式 | 
				
			||||
			rightLineStyle() { | 
				
			||||
				const style = {} | 
				
			||||
				// 如果是在右边,设置右边的宽度为固定值 | 
				
			||||
				if (this.textPosition === 'right') { | 
				
			||||
					style.width = '80rpx' | 
				
			||||
				} else { | 
				
			||||
					style.flex = 1 | 
				
			||||
				} | 
				
			||||
				return style | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			// divider组件被点击时触发 | 
				
			||||
			click() { | 
				
			||||
				this.$emit('click'); | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import '../../libs/css/components.scss'; | 
				
			||||
	$u-divider-margin:15px 0 !default; | 
				
			||||
	$u-divider-text-margin:0 15px !default; | 
				
			||||
	$u-divider-dot-font-size:12px !default; | 
				
			||||
	$u-divider-dot-margin:0 12px !default; | 
				
			||||
	$u-divider-dot-color: #c0c4cc !default; | 
				
			||||
 | 
				
			||||
	.u-divider { | 
				
			||||
		@include flex; | 
				
			||||
		flex-direction: row; | 
				
			||||
		align-items: center; | 
				
			||||
		margin: $u-divider-margin; | 
				
			||||
 | 
				
			||||
		&__text { | 
				
			||||
			margin: $u-divider-text-margin; | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		&__dot { | 
				
			||||
			font-size: $u-divider-dot-font-size; | 
				
			||||
			margin: $u-divider-dot-margin; | 
				
			||||
			color: $u-divider-dot-color; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,36 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 当前选中项的value值
 | 
				
			||||
        value: { | 
				
			||||
            type: [Number, String, Array], | 
				
			||||
            default: '' | 
				
			||||
        }, | 
				
			||||
        // 菜单项标题
 | 
				
			||||
        title: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: '' | 
				
			||||
        }, | 
				
			||||
        // 选项数据,如果传入了默认slot,此参数无效
 | 
				
			||||
        options: { | 
				
			||||
            type: Array, | 
				
			||||
            default() { | 
				
			||||
                return [] | 
				
			||||
            } | 
				
			||||
        }, | 
				
			||||
        // 是否禁用此菜单项
 | 
				
			||||
        disabled: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: false | 
				
			||||
        }, | 
				
			||||
        // 下拉弹窗的高度
 | 
				
			||||
        height: { | 
				
			||||
            type: [Number, String], | 
				
			||||
            default: 'auto' | 
				
			||||
        }, | 
				
			||||
        // 点击遮罩是否可以收起弹窗
 | 
				
			||||
        closeOnClickOverlay: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: true | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,65 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 标题选中时的样式
 | 
				
			||||
        activeStyle: { | 
				
			||||
            type: [String, Object], | 
				
			||||
            default: () => ({ | 
				
			||||
                color: '#2979ff', | 
				
			||||
                fontSize: '14px' | 
				
			||||
            }) | 
				
			||||
        }, | 
				
			||||
        // 标题未选中时的样式
 | 
				
			||||
        inactiveStyle: { | 
				
			||||
            type: [String, Object], | 
				
			||||
            default: () => ({ | 
				
			||||
                color: '#606266', | 
				
			||||
                fontSize: '14px' | 
				
			||||
            }) | 
				
			||||
        }, | 
				
			||||
        // 点击遮罩是否关闭菜单
 | 
				
			||||
        closeOnClickMask: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: true | 
				
			||||
        }, | 
				
			||||
        // 点击当前激活项标题是否关闭菜单
 | 
				
			||||
        closeOnClickSelf: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: true | 
				
			||||
        }, | 
				
			||||
        // 过渡时间
 | 
				
			||||
        duration: { | 
				
			||||
            type: [Number, String], | 
				
			||||
            default: 300 | 
				
			||||
        }, | 
				
			||||
        // 标题菜单的高度
 | 
				
			||||
        height: { | 
				
			||||
            type: [Number, String], | 
				
			||||
            default: 40 | 
				
			||||
        }, | 
				
			||||
        // 是否显示下边框
 | 
				
			||||
        borderBottom: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: false | 
				
			||||
        }, | 
				
			||||
        // 标题的字体大小
 | 
				
			||||
        titleSize: { | 
				
			||||
            type: [Number, String], | 
				
			||||
            default: 14 | 
				
			||||
        }, | 
				
			||||
        // 下拉出来的内容部分的圆角值
 | 
				
			||||
        borderRadius: { | 
				
			||||
            type: [Number, String], | 
				
			||||
            default: 0 | 
				
			||||
        }, | 
				
			||||
        // 菜单右侧的icon图标
 | 
				
			||||
        menuIcon: { | 
				
			||||
            type: String, | 
				
			||||
            default: 'arrow-down' | 
				
			||||
        }, | 
				
			||||
        // 菜单右侧图标的大小
 | 
				
			||||
        menuIconSize: { | 
				
			||||
            type: [Number, String], | 
				
			||||
            default: 14 | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,59 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 内置图标名称,或图片路径,建议绝对路径
 | 
				
			||||
        icon: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.empty.icon | 
				
			||||
        }, | 
				
			||||
        // 提示文字
 | 
				
			||||
        text: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.empty.text | 
				
			||||
        }, | 
				
			||||
        // 文字颜色
 | 
				
			||||
        textColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.empty.textColor | 
				
			||||
        }, | 
				
			||||
        // 文字大小
 | 
				
			||||
        textSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.empty.textSize | 
				
			||||
        }, | 
				
			||||
        // 图标的颜色
 | 
				
			||||
        iconColor: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.empty.iconColor | 
				
			||||
        }, | 
				
			||||
        // 图标的大小
 | 
				
			||||
        iconSize: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.empty.iconSize | 
				
			||||
        }, | 
				
			||||
        // 选择预置的图标类型
 | 
				
			||||
        mode: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.empty.mode | 
				
			||||
        }, | 
				
			||||
        //  图标宽度,单位px
 | 
				
			||||
        width: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.empty.width | 
				
			||||
        }, | 
				
			||||
        // 图标高度,单位px
 | 
				
			||||
        height: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.empty.height | 
				
			||||
        }, | 
				
			||||
        // 是否显示组件
 | 
				
			||||
        show: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.empty.show | 
				
			||||
        }, | 
				
			||||
        // 组件距离上一个元素之间的距离,默认px单位
 | 
				
			||||
        marginTop: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.empty.marginTop | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,128 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view | 
				
			||||
	    class="u-empty" | 
				
			||||
	    :style="[emptyStyle]" | 
				
			||||
	    v-if="show" | 
				
			||||
	> | 
				
			||||
		<u-icon | 
				
			||||
		    v-if="!isSrc" | 
				
			||||
		    :name="mode === 'message' ? 'chat' : `empty-${mode}`" | 
				
			||||
		    :size="iconSize" | 
				
			||||
		    :color="iconColor" | 
				
			||||
		    margin-top="14" | 
				
			||||
		></u-icon> | 
				
			||||
		<image | 
				
			||||
		    v-else | 
				
			||||
		    :style="{ | 
				
			||||
				width: $u.addUnit(width), | 
				
			||||
				height: $u.addUnit(height), | 
				
			||||
			}" | 
				
			||||
		    :src="icon" | 
				
			||||
		    mode="widthFix" | 
				
			||||
		></image> | 
				
			||||
		<text | 
				
			||||
		    class="u-empty__text" | 
				
			||||
		    :style="[textStyle]" | 
				
			||||
		>{{text ? text : icons[mode]}}</text> | 
				
			||||
		<view class="u-empty__wrap" v-if="$slots.default || $slots.$default"> | 
				
			||||
			<slot /> | 
				
			||||
		</view> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
 | 
				
			||||
	/** | 
				
			||||
	 * empty 内容为空 | 
				
			||||
	 * @description 该组件用于需要加载内容,但是加载的第一页数据就为空,提示一个"没有内容"的场景, 我们精心挑选了十几个场景的图标,方便您使用。 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/empty.html | 
				
			||||
	 * @property {String}			icon		内置图标名称,或图片路径,建议绝对路径 | 
				
			||||
	 * @property {String}			text		提示文字 | 
				
			||||
	 * @property {String}			textColor	文字颜色 (默认 '#c0c4cc' ) | 
				
			||||
	 * @property {String | Number}	textSize	文字大小 (默认 14 ) | 
				
			||||
	 * @property {String}			iconColor	图标的颜色 (默认 '#c0c4cc' ) | 
				
			||||
	 * @property {String | Number}	iconSize	图标的大小 (默认 90 ) | 
				
			||||
	 * @property {String}			mode		选择预置的图标类型 (默认 'data' ) | 
				
			||||
	 * @property {String | Number}	width		图标宽度,单位px (默认 160 ) | 
				
			||||
	 * @property {String | Number}	height		图标高度,单位px (默认 160 ) | 
				
			||||
	 * @property {Boolean}			show		是否显示组件 (默认 true ) | 
				
			||||
	 * @property {String | Number}	marginTop	组件距离上一个元素之间的距离,默认px单位 (默认 0 ) | 
				
			||||
	 * @property {Object}			customStyle	定义需要用到的外部样式 | 
				
			||||
	 *  | 
				
			||||
	 * @event {Function} click 点击组件时触发 | 
				
			||||
	 * @event {Function} close 点击关闭按钮时触发 | 
				
			||||
	 * @example <u-empty text="所谓伊人,在水一方" mode="list"></u-empty> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: "u-empty", | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				icons: { | 
				
			||||
					car: '购物车为空', | 
				
			||||
					page: '页面不存在', | 
				
			||||
					search: '没有搜索结果', | 
				
			||||
					address: '没有收货地址', | 
				
			||||
					wifi: '没有WiFi', | 
				
			||||
					order: '订单为空', | 
				
			||||
					coupon: '没有优惠券', | 
				
			||||
					favor: '暂无收藏', | 
				
			||||
					permission: '无权限', | 
				
			||||
					history: '无历史记录', | 
				
			||||
					news: '无新闻列表', | 
				
			||||
					message: '消息列表为空', | 
				
			||||
					list: '列表为空', | 
				
			||||
					data: '数据为空', | 
				
			||||
					comment: '暂无评论', | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			// 组件样式 | 
				
			||||
			emptyStyle() { | 
				
			||||
				const style = {} | 
				
			||||
				style.marginTop = uni.$u.addUnit(this.marginTop) | 
				
			||||
				// 合并customStyle样式,此参数通过mixin中的props传递 | 
				
			||||
				return uni.$u.deepMerge(uni.$u.addStyle(this.customStyle), style) | 
				
			||||
			}, | 
				
			||||
			// 文本样式 | 
				
			||||
			textStyle() { | 
				
			||||
				const style = {} | 
				
			||||
				style.color = this.textColor | 
				
			||||
				style.fontSize = uni.$u.addUnit(this.textSize) | 
				
			||||
				return style | 
				
			||||
			}, | 
				
			||||
			// 判断icon是否图片路径 | 
				
			||||
			isSrc() { | 
				
			||||
				return this.icon.indexOf('/') >= 0 | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import '../../libs/css/components.scss'; | 
				
			||||
	$u-empty-text-margin-top:20rpx !default; | 
				
			||||
	$u-empty-slot-margin-top:20rpx !default; | 
				
			||||
 | 
				
			||||
	.u-empty { | 
				
			||||
		@include flex; | 
				
			||||
		flex-direction: column; | 
				
			||||
		justify-content: center; | 
				
			||||
		align-items: center; | 
				
			||||
 | 
				
			||||
		&__text { | 
				
			||||
			@include flex; | 
				
			||||
			justify-content: center; | 
				
			||||
			align-items: center; | 
				
			||||
			margin-top: $u-empty-text-margin-top; | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
		.u-slot-wrap { | 
				
			||||
			@include flex; | 
				
			||||
			justify-content: center; | 
				
			||||
			align-items: center; | 
				
			||||
			margin-top:$u-empty-slot-margin-top; | 
				
			||||
		} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,48 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // input的label提示语
 | 
				
			||||
        label: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.formItem.label | 
				
			||||
        }, | 
				
			||||
        // 绑定的值
 | 
				
			||||
        prop: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.formItem.prop | 
				
			||||
        }, | 
				
			||||
        // 是否显示表单域的下划线边框
 | 
				
			||||
        borderBottom: { | 
				
			||||
            type: [String, Boolean], | 
				
			||||
            default: uni.$u.props.formItem.borderBottom | 
				
			||||
        }, | 
				
			||||
        // label的位置,left-左边,top-上边
 | 
				
			||||
        labelPosition: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.formItem.labelPosition | 
				
			||||
        }, | 
				
			||||
        // label的宽度,单位px
 | 
				
			||||
        labelWidth: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.formItem.labelWidth | 
				
			||||
        }, | 
				
			||||
        // 右侧图标
 | 
				
			||||
        rightIcon: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.formItem.rightIcon | 
				
			||||
        }, | 
				
			||||
        // 左侧图标
 | 
				
			||||
        leftIcon: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.formItem.leftIcon | 
				
			||||
        }, | 
				
			||||
        // 是否显示左边的必填星号,只作显示用,具体校验必填的逻辑,请在rules中配置
 | 
				
			||||
        required: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.formItem.required | 
				
			||||
        }, | 
				
			||||
        leftIconStyle: { | 
				
			||||
            type: [String, Object], | 
				
			||||
            default: uni.$u.props.formItem.leftIconStyle, | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,235 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="u-form-item"> | 
				
			||||
		<view | 
				
			||||
			class="u-form-item__body" | 
				
			||||
			@tap="clickHandler" | 
				
			||||
			:style="[$u.addStyle(customStyle), { | 
				
			||||
				flexDirection: (labelPosition || parentData.labelPosition) === 'left' ? 'row' : 'column' | 
				
			||||
			}]" | 
				
			||||
		> | 
				
			||||
			<!-- 微信小程序中,将一个参数设置空字符串,结果会变成字符串"true" --> | 
				
			||||
			<slot name="label"> | 
				
			||||
				<!-- {{required}} --> | 
				
			||||
				<view | 
				
			||||
					class="u-form-item__body__left" | 
				
			||||
					v-if="required || leftIcon || label" | 
				
			||||
					:style="{ | 
				
			||||
						width: $u.addUnit(labelWidth || parentData.labelWidth), | 
				
			||||
						marginBottom: parentData.labelPosition === 'left' ? 0 : '5px', | 
				
			||||
					}" | 
				
			||||
				> | 
				
			||||
					<!-- 为了块对齐 --> | 
				
			||||
					<view class="u-form-item__body__left__content"> | 
				
			||||
						<!-- nvue不支持伪元素before --> | 
				
			||||
						<text | 
				
			||||
							v-if="required" | 
				
			||||
							class="u-form-item__body__left__content__required" | 
				
			||||
						>*</text> | 
				
			||||
						<view | 
				
			||||
							class="u-form-item__body__left__content__icon" | 
				
			||||
							v-if="leftIcon" | 
				
			||||
						> | 
				
			||||
							<u-icon | 
				
			||||
								:name="leftIcon" | 
				
			||||
								:custom-style="leftIconStyle" | 
				
			||||
							></u-icon> | 
				
			||||
						</view> | 
				
			||||
						<text | 
				
			||||
							class="u-form-item__body__left__content__label" | 
				
			||||
							:style="[parentData.labelStyle, { | 
				
			||||
								justifyContent: parentData.labelAlign === 'left' ? 'flex-start' : parentData.labelAlign === 'center' ? 'center' : 'flex-end' | 
				
			||||
							}]" | 
				
			||||
						>{{ label }}</text> | 
				
			||||
					</view> | 
				
			||||
				</view> | 
				
			||||
			</slot> | 
				
			||||
			<view class="u-form-item__body__right"> | 
				
			||||
				<view class="u-form-item__body__right__content"> | 
				
			||||
					<view class="u-form-item__body__right__content__slot"> | 
				
			||||
						<slot /> | 
				
			||||
					</view> | 
				
			||||
					<view | 
				
			||||
						class="item__body__right__content__icon" | 
				
			||||
						v-if="$slots.right" | 
				
			||||
					> | 
				
			||||
						<slot name="right" /> | 
				
			||||
					</view> | 
				
			||||
				</view> | 
				
			||||
			</view> | 
				
			||||
		</view> | 
				
			||||
		<slot name="error"> | 
				
			||||
			<text | 
				
			||||
				v-if="!!message && parentData.errorType === 'message'" | 
				
			||||
				class="u-form-item__body__right__message" | 
				
			||||
				:style="{ | 
				
			||||
					marginLeft:  $u.addUnit(parentData.labelPosition === 'top' ? 0 : (labelWidth || parentData.labelWidth)) | 
				
			||||
				}" | 
				
			||||
			>{{ message }}</text> | 
				
			||||
		</slot> | 
				
			||||
		<u-line | 
				
			||||
			v-if="borderBottom" | 
				
			||||
			:color="message && parentData.errorType === 'border-bottom' ? $u.color.error : propsLine.color" | 
				
			||||
			:customStyle="`margin-top: ${message && parentData.errorType === 'message' ? '5px' : 0}`" | 
				
			||||
		></u-line> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from './props.js'; | 
				
			||||
	/** | 
				
			||||
	 * Form 表单 | 
				
			||||
	 * @description 此组件一般用于表单场景,可以配置Input输入框,Select弹出框,进行表单验证等。 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/form.html | 
				
			||||
	 * @property {String}			label			input的label提示语 | 
				
			||||
	 * @property {String}			prop			绑定的值 | 
				
			||||
	 * @property {String | Boolean}	borderBottom	是否显示表单域的下划线边框 | 
				
			||||
	 * @property {String | Number}	labelWidth		label的宽度,单位px | 
				
			||||
	 * @property {String}			rightIcon		右侧图标 | 
				
			||||
	 * @property {String}			leftIcon		左侧图标 | 
				
			||||
	 * @property {String | Object} leftIconStyle 左侧图标的样式 | 
				
			||||
	 * @property {Boolean}			required		是否显示左边的必填星号,只作显示用,具体校验必填的逻辑,请在rules中配置 (默认 false ) | 
				
			||||
	 * | 
				
			||||
	 * @example <u-form-item label="姓名" prop="userInfo.name" borderBottom ref="item1"></u-form-item> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: 'u-form-item', | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				// 错误提示语 | 
				
			||||
				message: '', | 
				
			||||
				parentData: { | 
				
			||||
					// 提示文本的位置 | 
				
			||||
					labelPosition: 'left', | 
				
			||||
					// 提示文本对齐方式 | 
				
			||||
					labelAlign: 'left', | 
				
			||||
					// 提示文本的样式 | 
				
			||||
					labelStyle: {}, | 
				
			||||
					// 提示文本的宽度 | 
				
			||||
					labelWidth: 45, | 
				
			||||
					// 错误提示方式 | 
				
			||||
					errorType: 'message' | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		// 组件创建完成时,将当前实例保存到u-form中 | 
				
			||||
		computed: { | 
				
			||||
			propsLine() { | 
				
			||||
				return uni.$u.props.line | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
		mounted() { | 
				
			||||
			this.init() | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			init() { | 
				
			||||
				// 父组件的实例 | 
				
			||||
				this.updateParentData() | 
				
			||||
				if (!this.parent) { | 
				
			||||
					uni.$u.error('u-form-item需要结合u-form组件使用') | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			// 获取父组件的参数 | 
				
			||||
			updateParentData() { | 
				
			||||
				// 此方法写在mixin中 | 
				
			||||
				this.getParentData('u-form'); | 
				
			||||
			}, | 
				
			||||
			// 移除u-form-item的校验结果 | 
				
			||||
			clearValidate() { | 
				
			||||
				this.message = null | 
				
			||||
			}, | 
				
			||||
			// 清空当前的组件的校验结果,并重置为初始值 | 
				
			||||
			resetField() { | 
				
			||||
				// 找到原始值 | 
				
			||||
				const value = uni.$u.getProperty(this.parent.originalModel, this.prop) | 
				
			||||
				// 将u-form的model的prop属性链还原原始值 | 
				
			||||
				uni.$u.setProperty(this.parent.model, this.prop, value) | 
				
			||||
				// 移除校验结果 | 
				
			||||
				this.message = null | 
				
			||||
			}, | 
				
			||||
			// 点击组件 | 
				
			||||
			clickHandler() { | 
				
			||||
				this.$emit('click') | 
				
			||||
			} | 
				
			||||
		}, | 
				
			||||
	} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
	@import "../../libs/css/components.scss"; | 
				
			||||
 | 
				
			||||
	.u-form-item { | 
				
			||||
		@include flex(column); | 
				
			||||
		font-size: 14px; | 
				
			||||
		color: $u-main-color; | 
				
			||||
 | 
				
			||||
		&__body { | 
				
			||||
			@include flex; | 
				
			||||
			padding: 10px 0; | 
				
			||||
 | 
				
			||||
			&__left { | 
				
			||||
				@include flex; | 
				
			||||
				align-items: center; | 
				
			||||
 | 
				
			||||
				&__content { | 
				
			||||
					position: relative; | 
				
			||||
					@include flex; | 
				
			||||
					align-items: center; | 
				
			||||
					padding-right: 10rpx; | 
				
			||||
					flex: 1; | 
				
			||||
 | 
				
			||||
					&__icon { | 
				
			||||
						margin-right: 8rpx; | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					&__required { | 
				
			||||
						position: absolute; | 
				
			||||
						left: -9px; | 
				
			||||
						color: $u-error; | 
				
			||||
						line-height: 20px; | 
				
			||||
						font-size: 20px; | 
				
			||||
						top: 3px; | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					&__label { | 
				
			||||
						@include flex; | 
				
			||||
						align-items: center; | 
				
			||||
						flex: 1; | 
				
			||||
						color: $u-main-color; | 
				
			||||
						font-size: 15px; | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
 | 
				
			||||
			&__right { | 
				
			||||
				flex: 1; | 
				
			||||
 | 
				
			||||
				&__content { | 
				
			||||
					@include flex; | 
				
			||||
					align-items: center; | 
				
			||||
					flex: 1; | 
				
			||||
 | 
				
			||||
					&__slot { | 
				
			||||
						flex: 1; | 
				
			||||
						/* #ifndef MP */ | 
				
			||||
						@include flex; | 
				
			||||
						align-items: center; | 
				
			||||
						/* #endif */ | 
				
			||||
					} | 
				
			||||
 | 
				
			||||
					&__icon { | 
				
			||||
						margin-left: 10rpx; | 
				
			||||
						color: $u-light-color; | 
				
			||||
						font-size: 30rpx; | 
				
			||||
					} | 
				
			||||
				} | 
				
			||||
 | 
				
			||||
				&__message { | 
				
			||||
					font-size: 12px; | 
				
			||||
					line-height: 12px; | 
				
			||||
					color: $u-error; | 
				
			||||
				} | 
				
			||||
			} | 
				
			||||
		} | 
				
			||||
	} | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,45 @@
					 | 
				
			||||
export default { | 
				
			||||
    props: { | 
				
			||||
        // 当前form的需要验证字段的集合
 | 
				
			||||
        model: { | 
				
			||||
            type: Object, | 
				
			||||
            default: uni.$u.props.form.model | 
				
			||||
        }, | 
				
			||||
        // 验证规则
 | 
				
			||||
        rules: { | 
				
			||||
            type: [Object, Function, Array], | 
				
			||||
            default: uni.$u.props.form.rules | 
				
			||||
        }, | 
				
			||||
        // 有错误时的提示方式,message-提示信息,toast-进行toast提示
 | 
				
			||||
        // border-bottom-下边框呈现红色,none-无提示
 | 
				
			||||
        errorType: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.form.errorType | 
				
			||||
        }, | 
				
			||||
        // 是否显示表单域的下划线边框
 | 
				
			||||
        borderBottom: { | 
				
			||||
            type: Boolean, | 
				
			||||
            default: uni.$u.props.form.borderBottom | 
				
			||||
        }, | 
				
			||||
        // label的位置,left-左边,top-上边
 | 
				
			||||
        labelPosition: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.form.labelPosition | 
				
			||||
        }, | 
				
			||||
        // label的宽度,单位px
 | 
				
			||||
        labelWidth: { | 
				
			||||
            type: [String, Number], | 
				
			||||
            default: uni.$u.props.form.labelWidth | 
				
			||||
        }, | 
				
			||||
        // lable字体的对齐方式
 | 
				
			||||
        labelAlign: { | 
				
			||||
            type: String, | 
				
			||||
            default: uni.$u.props.form.labelAlign | 
				
			||||
        }, | 
				
			||||
        // lable的样式,对象形式
 | 
				
			||||
        labelStyle: { | 
				
			||||
            type: Object, | 
				
			||||
            default: uni.$u.props.form.labelStyle | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,214 @@
					 | 
				
			||||
<template> | 
				
			||||
	<view class="u-form"> | 
				
			||||
		<slot /> | 
				
			||||
	</view> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
	import props from "./props.js"; | 
				
			||||
	import Schema from "../../libs/util/async-validator"; | 
				
			||||
	// 去除警告信息 | 
				
			||||
	Schema.warning = function() {}; | 
				
			||||
	/** | 
				
			||||
	 * Form 表单 | 
				
			||||
	 * @description 此组件一般用于表单场景,可以配置Input输入框,Select弹出框,进行表单验证等。 | 
				
			||||
	 * @tutorial https://www.uviewui.com/components/form.html | 
				
			||||
	 * @property {Object}						model			当前form的需要验证字段的集合 | 
				
			||||
	 * @property {Object | Function | Array}	rules			验证规则 | 
				
			||||
	 * @property {String}						errorType		错误的提示方式,见上方说明 ( 默认 message ) | 
				
			||||
	 * @property {Boolean}						borderBottom	是否显示表单域的下划线边框   ( 默认 true ) | 
				
			||||
	 * @property {String}						labelPosition	表单域提示文字的位置,left-左侧,top-上方 ( 默认 'left' ) | 
				
			||||
	 * @property {String | Number}				labelWidth		提示文字的宽度,单位px  ( 默认 45 ) | 
				
			||||
	 * @property {String}						labelAlign		lable字体的对齐方式   ( 默认 ‘left' ) | 
				
			||||
	 * @property {Object}						labelStyle		lable的样式,对象形式 | 
				
			||||
	 * @example <u--formlabelPosition="left" :model="model1" :rules="rules" ref="form1"></u--form> | 
				
			||||
	 */ | 
				
			||||
	export default { | 
				
			||||
		name: "u-form", | 
				
			||||
		mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
				
			||||
		provide() { | 
				
			||||
			return { | 
				
			||||
				uForm: this, | 
				
			||||
			}; | 
				
			||||
		}, | 
				
			||||
		data() { | 
				
			||||
			return { | 
				
			||||
				formRules: {}, | 
				
			||||
				// 规则校验器 | 
				
			||||
				validator: {}, | 
				
			||||
				// 原始的model快照,用于resetFields方法重置表单时使用 | 
				
			||||
				originalModel: null, | 
				
			||||
			}; | 
				
			||||
		}, | 
				
			||||
		watch: { | 
				
			||||
			// 监听规则的变化 | 
				
			||||
			rules: { | 
				
			||||
				immediate: true, | 
				
			||||
				handler(n) { | 
				
			||||
					this.setRules(n); | 
				
			||||
				}, | 
				
			||||
			}, | 
				
			||||
			// 监听属性的变化,通知子组件u-form-item重新获取信息 | 
				
			||||
			propsChange(n) { | 
				
			||||
				if (this.children?.length) { | 
				
			||||
					this.children.map((child) => { | 
				
			||||
						// 判断子组件(u-form-item)如果有updateParentData方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值) | 
				
			||||
						typeof child.updateParentData == "function" && | 
				
			||||
							child.updateParentData(); | 
				
			||||
					}); | 
				
			||||
				} | 
				
			||||
			}, | 
				
			||||
			// 监听model的初始值作为重置表单的快照 | 
				
			||||
			model: { | 
				
			||||
				immediate: true, | 
				
			||||
				handler(n) { | 
				
			||||
					if (!this.originalModel) { | 
				
			||||
						this.originalModel = uni.$u.deepClone(n); | 
				
			||||
					} | 
				
			||||
				}, | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
		computed: { | 
				
			||||
			propsChange() { | 
				
			||||
				return [ | 
				
			||||
					this.errorType, | 
				
			||||
					this.borderBottom, | 
				
			||||
					this.labelPosition, | 
				
			||||
					this.labelWidth, | 
				
			||||
					this.labelAlign, | 
				
			||||
					this.labelStyle, | 
				
			||||
				]; | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
		created() { | 
				
			||||
			// 存储当前form下的所有u-form-item的实例 | 
				
			||||
			// 不能定义在data中,否则微信小程序会造成循环引用而报错 | 
				
			||||
			this.children = []; | 
				
			||||
		}, | 
				
			||||
		methods: { | 
				
			||||
			// 手动设置校验的规则,如果规则中有函数的话,微信小程序中会过滤掉,所以只能手动调用设置规则 | 
				
			||||
			setRules(rules) { | 
				
			||||
				// 判断是否有规则 | 
				
			||||
				if (Object.keys(rules).length === 0) return; | 
				
			||||
				if (process.env.NODE_ENV === 'development' && Object.keys(this.model).length === 0) { | 
				
			||||
					uni.$u.error('设置rules,model必须设置!如果已经设置,请刷新页面。'); | 
				
			||||
					return; | 
				
			||||
				}; | 
				
			||||
				this.formRules = rules; | 
				
			||||
				// 重新将规则赋予Validator | 
				
			||||
				this.validator = new Schema(rules); | 
				
			||||
			}, | 
				
			||||
			// 清空所有u-form-item组件的内容,本质上是调用了u-form-item组件中的resetField()方法 | 
				
			||||
			resetFields() { | 
				
			||||
				this.resetModel(); | 
				
			||||
			}, | 
				
			||||
			// 重置model为初始值的快照 | 
				
			||||
			resetModel(obj) { | 
				
			||||
				// 历遍所有u-form-item,根据其prop属性,还原model的原始快照 | 
				
			||||
				this.children.map((child) => { | 
				
			||||
					const prop = child?.prop; | 
				
			||||
					const value = uni.$u.getProperty(this.originalModel, prop); | 
				
			||||
					uni.$u.setProperty(this.model, prop, value); | 
				
			||||
				}); | 
				
			||||
			}, | 
				
			||||
			// 清空校验结果 | 
				
			||||
			clearValidate(props) { | 
				
			||||
				props = [].concat(props); | 
				
			||||
				this.children.map((child) => { | 
				
			||||
					// 如果u-form-item的prop在props数组中,则清除对应的校验结果信息 | 
				
			||||
					if (props[0] === undefined || props.includes(child.prop)) { | 
				
			||||
						child.message = null; | 
				
			||||
					} | 
				
			||||
				}); | 
				
			||||
			}, | 
				
			||||
			// 对部分表单字段进行校验 | 
				
			||||
			async validateField(value, callback, event = null) { | 
				
			||||
				// $nextTick是必须的,否则model的变更,可能会延后于此方法的执行 | 
				
			||||
				this.$nextTick(() => { | 
				
			||||
					// 校验错误信息,返回给回调方法,用于存放所有form-item的错误信息 | 
				
			||||
					const errorsRes = []; | 
				
			||||
					// 如果为字符串,转为数组 | 
				
			||||
					value = [].concat(value); | 
				
			||||
					// 历遍children所有子form-item | 
				
			||||
					this.children.map((child) => { | 
				
			||||
						// 用于存放form-item的错误信息 | 
				
			||||
						const childErrors = []; | 
				
			||||
						if (value.includes(child.prop)) { | 
				
			||||
							// 获取对应的属性,通过类似'a.b.c'的形式 | 
				
			||||
							const propertyVal = uni.$u.getProperty( | 
				
			||||
								this.model, | 
				
			||||
								child.prop | 
				
			||||
							); | 
				
			||||
							// 属性链数组 | 
				
			||||
							const propertyChain = child.prop.split("."); | 
				
			||||
							const propertyName = | 
				
			||||
								propertyChain[propertyChain.length - 1]; | 
				
			||||
 | 
				
			||||
							const rule = this.formRules[child.prop]; | 
				
			||||
							// 如果不存在对应的规则,直接返回,否则校验器会报错 | 
				
			||||
							if (!rule) return; | 
				
			||||
							// rule规则可为数组形式,也可为对象形式,此处拼接成为数组 | 
				
			||||
							const rules = [].concat(rule); | 
				
			||||
 | 
				
			||||
							// 对rules数组进行校验 | 
				
			||||
							for (let i = 0; i < rules.length; i++) { | 
				
			||||
								const ruleItem = rules[i]; | 
				
			||||
								// 将u-form-item的触发器转为数组形式 | 
				
			||||
								const trigger = [].concat(ruleItem?.trigger); | 
				
			||||
								// 如果是有传入触发事件,但是此form-item却没有配置此触发器的话,不执行校验操作 | 
				
			||||
								if (event && !trigger.includes(event)) continue; | 
				
			||||
								// 实例化校验对象,传入构造规则 | 
				
			||||
								const validator = new Schema({ | 
				
			||||
									[propertyName]: ruleItem, | 
				
			||||
								}); | 
				
			||||
								validator.validate({ | 
				
			||||
										[propertyName]: propertyVal, | 
				
			||||
									}, | 
				
			||||
									(errors, fields) => { | 
				
			||||
										if (uni.$u.test.array(errors)) { | 
				
			||||
											errorsRes.push(...errors); | 
				
			||||
											childErrors.push(...errors); | 
				
			||||
										} | 
				
			||||
										child.message = | 
				
			||||
											childErrors[0]?.message ?? null; | 
				
			||||
									} | 
				
			||||
								); | 
				
			||||
							} | 
				
			||||
						} | 
				
			||||
					}); | 
				
			||||
					// 执行回调函数 | 
				
			||||
					typeof callback === "function" && callback(errorsRes); | 
				
			||||
				}); | 
				
			||||
			}, | 
				
			||||
			// 校验全部数据 | 
				
			||||
			validate(callback) { | 
				
			||||
				// 开发环境才提示,生产环境不会提示 | 
				
			||||
				if (process.env.NODE_ENV === 'development' && Object.keys(this.formRules).length === 0) { | 
				
			||||
					uni.$u.error('未设置rules,请看文档说明!如果已经设置,请刷新页面。'); | 
				
			||||
					return; | 
				
			||||
				} | 
				
			||||
				return new Promise((resolve, reject) => { | 
				
			||||
					// $nextTick是必须的,否则model的变更,可能会延后于validate方法 | 
				
			||||
					this.$nextTick(() => { | 
				
			||||
						// 获取所有form-item的prop,交给validateField方法进行校验 | 
				
			||||
						const formItemProps = this.children.map( | 
				
			||||
							(item) => item.prop | 
				
			||||
						); | 
				
			||||
						this.validateField(formItemProps, (errors) => { | 
				
			||||
							if(errors.length) { | 
				
			||||
								// 如果错误提示方式为toast,则进行提示 | 
				
			||||
								this.errorType === 'toast' && uni.$u.toast(errors[0].message) | 
				
			||||
								reject(errors) | 
				
			||||
							} else { | 
				
			||||
								resolve(true) | 
				
			||||
							} | 
				
			||||
						}); | 
				
			||||
					}); | 
				
			||||
				}); | 
				
			||||
			}, | 
				
			||||
		}, | 
				
			||||
	}; | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style lang="scss" scoped> | 
				
			||||
</style> | 
				
			||||
Some files were not shown because too many files have changed in this diff Show More
					Loading…
					
					
				
		Reference in new issue