提交 f547a4ed 编写于 作者: DCloud_JSON's avatar DCloud_JSON

- 使用优化一键登陆中,点击第三方登陆的逻辑:未勾选隐私政策时,toast提醒并阻止了一键登陆界面的close - 新增支持看激励视频广告签到

上级 e9dce09f
{
"prompt" : "template"
}
## 1.1.23(2021-11-20)
- 使用`uni.getUniverifyManager`优化一键登陆中,点击第三方登陆的逻辑:未勾选隐私政策时,toast提醒并阻止了一键登陆界面的close
- 新增支持看激励视频广告签到
## 1.1.22(2021-11-10) ## 1.1.22(2021-11-10)
删除`common/openApp.js`中可选链操作符,解决vue3版本在hbuilderX内置浏览器不兼容的问题 删除`common/openApp.js`中可选链操作符,解决vue3版本在hbuilderX内置浏览器不兼容的问题
## 1.1.21(2021-11-10) ## 1.1.21(2021-11-10)
......
...@@ -179,7 +179,7 @@ export default async function() { ...@@ -179,7 +179,7 @@ export default async function() {
oaid, oaid,
idfa idfa
} }
console.log("重新登录/注册,获取设备id", deviceInfo); //console.log("重新登录/注册,获取设备id", deviceInfo);
option.data.deviceInfo = deviceInfo option.data.deviceInfo = deviceInfo
// #ifndef H5 // #ifndef H5
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
handler(src) { handler(src) {
// console.log(src); // console.log(src);
// console.log(src.substring(0, 8)); // console.log(src.substring(0, 8));
if (src.substring(0, 8) == "cloud://") { if (src&&src.substring(0, 8) == "cloud://") {
uniCloud.getTempFileURL({ uniCloud.getTempFileURL({
fileList: [src] fileList: [src]
}).then(res=>{ }).then(res=>{
......
<template> <template>
<view class="root"> <view class="root">
<checkbox-group @change="setAgree" class="checkbox-group"> <checkbox-group @change="setAgree" class="checkbox-group">
<checkbox style="transform: scale(0.7);" /> <checkbox :checked="isAgree" style="transform: scale(0.7);" />
<text>{{$t('common.agree')}}</text> <text>{{$t('common.agree')}}</text>
</checkbox-group> </checkbox-group>
<view class="item" v-for="(agreement,index) in agreements" :key="index"> <view class="item" v-for="(agreement,index) in agreements" :key="index">
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
}, },
created() { created() {
uni.$on('setAgreementsAgree',state=>{ uni.$on('setAgreementsAgree',state=>{
console.log('setAgreementsAgree',state);
this.isAgree = state
this.$emit('setAgree',state) this.$emit('setAgree',state)
}) })
}, },
......
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
}, },
success: (e) => { success: (e) => {
uni.showToast({ uni.showToast({
title: e.result.msg, title: e.result.msg||'绑定成功',
icon: 'none' icon: 'none'
}); });
if(e.result.code === 0){ if(e.result.code === 0){
......
{
"accountLogin": "Account",
"SMSLogin": "SMS",
"wechatLogin": "wechat",
"appleLogin": "Apple",
"oneClickLogin": "One click login",
"QQLogin": "QQ",
"xiaomiLogin": "Xiaomi",
"getProviderFail": "Failed to get service provider",
"loginErr": "Login service initialization error",
"chooseOtherLogin": "Click the third-party login",
"weibo":"weibo",
"noAgree": "You have not agreed to the privacy policy agreement",
"gotIt": "got it"
}
import en from './en.json'
import zhHans from './zh-Hans.json'
export default {
en,
'zh-Hans': zhHans
}
{
"accountLogin": "账号登录",
"SMSLogin": "短信验证码",
"wechatLogin": "微信登录",
"appleLogin": "苹果登录",
"oneClickLogin": "一键登录",
"QQLogin": "QQ登录",
"xiaomiLogin": "小米登录",
"getProviderFail": "获取服务供应商失败",
"loginErr": "登录服务初始化错误",
"chooseOtherLogin": "点击了第三方登录",
"weibo": "微博",
"noAgree": "你未同意隐私政策协议",
"gotIt": "知道了"
}
<template> <template>
<view> <view>
<view class="quick-login-box"> <view class="quick-login-box">
<view class="item" v-for="(item,index) in servicesList" :key="index" <view class="item" v-for="(item,index) in servicesList" :key="index"
@click="item.path?to(item.path):login_before(item.id,false)"> @click="item.path?to(item.path):login_before(item.id,false)">
<image class="logo" :src="item.logo" mode="widthFix"></image> <image class="logo" :src="item.logo" mode="widthFix"></image>
<text class="login-title">{{item.text}}</text> <text class="login-title">{{item.text}}</text>
</view> </view>
</view> </view>
<!-- #ifdef MP-WEIXIN --> <!-- #ifdef MP-WEIXIN -->
<uni-user-profile @next="doUserProfileNext" ref="userProfile"></uni-user-profile> <uni-user-profile @next="doUserProfileNext" ref="userProfile"></uni-user-profile>
<!-- #endif --> <!-- #endif -->
</view> </view>
</template> </template>
<script> <script>
import {mapGetters,mapMutations} from 'vuex'; import {
//前一个窗口的页面地址。控制点击切换快捷登录方式是创建还是返回 initVueI18n
import loginSuccess from '@/pages/ucenter/login-page/common/loginSuccess.js'; } from '@dcloudio/uni-i18n'
const db = uniCloud.database(); import messages from './i18n/index.js'
const {
t
} = initVueI18n(messages)
import {
mapGetters,
mapMutations
} from 'vuex';
//前一个窗口的页面地址。控制点击切换快捷登录方式是创建还是返回
import loginSuccess from '@/pages/ucenter/login-page/common/loginSuccess.js';
const db = uniCloud.database();
const usersTable = db.collection('uni-id-users') const usersTable = db.collection('uni-id-users')
export default { let allServicesList = []
computed: { export default {
loginConfig() { computed: {
return getApp().globalData.config.router.login loginConfig() {
}, return getApp().globalData.config.router.login
agreements() { },
return getApp().globalData.config.about.agreements || [] agreements() {
} return getApp().globalData.config.about.agreements || []
}, }
data() { },
return { data() {
servicesList: [{ return {
"id": "username", servicesList: [{
"text": this.$t('uniQuickLogin').accountLogin, "id": "username",
"logo": "/static/uni-quick-login/user.png", "text": t('accountLogin'),
"path": "/pages/ucenter/login-page/pwd-login/pwd-login" "logo": "/static/uni-quick-login/user.png",
}, "path": "/pages/ucenter/login-page/pwd-login/pwd-login"
{ },
"id": "smsCode", {
"text": this.$t('uniQuickLogin').SMSLogin, "id": "smsCode",
"logo": "/static/uni-quick-login/sms.png", "text": t('SMSLogin'),
"path": "/pages/ucenter/login-page/index/index?type=smsCode" "logo": "/static/uni-quick-login/sms.png",
}, "path": "/pages/ucenter/login-page/index/index?type=smsCode"
{ },
"id": "weixin", {
"text": this.$t('uniQuickLogin').wechatLogin, "id": "weixin",
"logo": "/static/uni-quick-login/wechat.png", "text": t('wechatLogin'),
}, "logo": "/static/uni-quick-login/wechat.png",
{ },
"id": "apple", {
"text": this.$t('uniQuickLogin').appleLogin, "id": "apple",
"logo": "/static/uni-quick-login/apple.png", "text": t('appleLogin'),
}, "logo": "/static/uni-quick-login/apple.png",
{ },
"id": "univerify", {
"text":this.$t('uniQuickLogin').oneClickLogin, "id": "univerify",
"logo": "/static/uni-quick-login/univerify.png", "text": t('oneClickLogin'),
}, "logo": "/static/uni-quick-login/univerify.png",
{ },
"id": "qq", {
"text": this.$t('uniQuickLogin').QQLogin, //暂未提供该登录方式的接口示例 "id": "qq",
"logo": "/static/uni-quick-login/univerify.png", "text": t('QQLogin'), //暂未提供该登录方式的接口示例
}, "logo": "/static/uni-quick-login/univerify.png",
{ },
"id": "xiaomi", {
"text": this.$t('uniQuickLogin').xiaomiLogin, //暂未提供该登录方式的接口示例 "id": "xiaomi",
"logo": "/static/uni-quick-login/univerify.png", "text": t('xiaomiLogin'), //暂未提供该登录方式的接口示例
}, "logo": "/static/uni-quick-login/univerify.png",
{ },
"id": "sinaweibo", {
"text": this.$t('common').weibo, //暂未提供该登录方式的接口示例 "id": "sinaweibo",
"logo": "/static/uni-quick-login/univerify.png", "text": t('weibo'), //暂未提供该登录方式的接口示例
} "logo": "/static/uni-quick-login/univerify.png",
], }
config: {}, ],
univerifyStyle: { //一键登录弹出窗的样式配置参数 config: {},
"fullScreen": true, // 是否全屏显示,true表示全屏模式,false表示非全屏模式,默认值为false。 univerifyStyle: { //一键登录弹出窗的样式配置参数
"backgroundColor": "#ffffff", // 授权页面背景颜色,默认值:#ffffff "fullScreen": true, // 是否全屏显示,true表示全屏模式,false表示非全屏模式,默认值为false。
"buttons": { // 自定义登录按钮 "backgroundColor": "#ffffff", // 授权页面背景颜色,默认值:#ffffff
"iconWidth": "45px", // 图标宽度(高度等比例缩放) 默认值:45px "buttons": { // 自定义登录按钮
"list": [] "iconWidth": "45px", // 图标宽度(高度等比例缩放) 默认值:45px
}, "list": []
"privacyTerms": { },
"defaultCheckBoxState": false, // 条款勾选框初始状态 默认值: true "privacyTerms": {
"textColor": "#BBBBBB", // 文字颜色 默认值:#BBBBBB "defaultCheckBoxState": false, // 条款勾选框初始状态 默认值: true
"termsColor": "#5496E3", // 协议文字颜色 默认值: #5496E3 "textColor": "#BBBBBB", // 文字颜色 默认值:#BBBBBB
"prefix": "我已阅读并同意", // 条款前的文案 默认值:“我已阅读并同意” "termsColor": "#5496E3", // 协议文字颜色 默认值: #5496E3
"suffix": "并使用本机号码登录", // 条款后的文案 默认值:“并使用本机号码登录” "prefix": "我已阅读并同意", // 条款前的文案 默认值:“我已阅读并同意”
"privacyItems": [] "suffix": "并使用本机号码登录", // 条款后的文案 默认值:“并使用本机号码登录”
} "privacyItems": []
} }
} }
}, }
watch: { },
agree(agree) { watch: {
this.univerifyStyle.privacyTerms.defaultCheckBoxState = agree agree(agree) {
} this.univerifyStyle.privacyTerms.defaultCheckBoxState = agree
}, }
props: { },
agree: { props: {
type: Boolean, agree: {
default () { type: Boolean,
return false default () {
} return false
} }
}, }
async created() { },
let servicesList = this.servicesList async created() {
//去掉配置中不存在的 注意,在/common/appInit.js中已清除有配置但设备环境不支持的登录项 let servicesList = this.servicesList
servicesList = servicesList.filter(item => this.loginConfig.includes(item.id)) //去掉配置中不存在的 注意,在/common/appInit.js中已清除有配置但设备环境不支持的登录项
//处理一键登录 servicesList = servicesList.filter(item => this.loginConfig.includes(item.id))
if (this.loginConfig.includes('univerify')) { //处理一键登录
this.univerifyStyle.privacyTerms.privacyItems = this.agreements if (this.loginConfig.includes('univerify')) {
//设置一键登录功能底下的快捷登录按钮 this.univerifyStyle.privacyTerms.privacyItems = this.agreements
servicesList.forEach(({ //设置一键登录功能底下的快捷登录按钮
id, servicesList.forEach(({
logo id,
}) => { logo,
if (id != 'univerify') { path
this.univerifyStyle.buttons.list.push({ }) => {
"iconPath": logo, if (id != 'univerify') {
"provider": id this.univerifyStyle.buttons.list.push({
}) "iconPath": logo,
} "provider": id,
}) // path
} })
console.log(servicesList); }
//如果当前页面为默认登录界面。当前第一优先级的“微信和苹果登录”要隐藏,因为他已经被渲染在默认登录界面顶部 })
if ( }
this.getRoute(1) == '/pages/ucenter/login-page/index/index' && ['weixin', 'apple'].includes(this console.log(servicesList);
.loginConfig[0]) //如果当前页面为默认登录界面。当前第一优先级的“微信和苹果登录”要隐藏,因为他已经被渲染在默认登录界面顶部
) { if (
servicesList = servicesList.filter(item => item.id != this.loginConfig[0]) this.getRoute(1) == '/pages/ucenter/login-page/index/index' && ['weixin', 'apple'].includes(this
} .loginConfig[0])
//去掉当前页面对应的登录选项 ) {
this.servicesList = servicesList.filter(item => { servicesList = servicesList.filter(item => item.id != this.loginConfig[0])
let path = item.path ? item.path.split('?')[0] : ''; }
return path != this.getRoute(1) //去掉当前页面对应的登录选项
}) this.servicesList = servicesList.filter(item => {
console.log('servicesList', servicesList, this.servicesList); let path = item.path ? item.path.split('?')[0] : '';
}, return path != this.getRoute(1)
mounted() { })
}, console.log('servicesList', servicesList, this.servicesList);
methods: { },
...mapMutations({ mounted() {},
setUserInfo: 'user/login' methods: {
}), ...mapMutations({
getRoute(n = 0) { setUserInfo: 'user/login'
let pages = getCurrentPages(); }),
// console.log('route-pages-length', pages.length); getRoute(n = 0) {
if (n > pages.length) { let pages = getCurrentPages();
return '' // console.log('route-pages-length', pages.length);
} if (n > pages.length) {
return '/' + pages[pages.length - n].route return ''
}, }
to(path) { return '/' + pages[pages.length - n].route
// console.log('比较', this.getRoute(2), path) },
if (this.getRoute(2) == path) { // 控制路由是重新打开还是返回,避免重复打开页面 to(path) {
uni.navigateBack(); console.log('比较', this.getRoute(1),this.getRoute(2), path)
} else { if(this.getRoute(1) == path.split('?')[0] && this.getRoute(1) == '/pages/ucenter/login-page/index/index'){
//如果要被打开的页面已经打开,且这个页面是 /pages/ucenter/login-page/index/index 则把类型参数传给他
let type = path.split('?')[1].split('=')[1]
uni.$emit('setLoginType',type)
}else if(this.getRoute(2) == path) { // 如果上一个页面就是,马上要打开的页面,直接返回。防止重复开启
uni.navigateBack();
}else if(this.getRoute(1) != path) {
uni.navigateTo({ uni.navigateTo({
url: path, url: path,
animationType: 'slide-in-left' animationType: 'slide-in-left'
}) })
}
},
login_before(type, navigateBack = true) {
if (!this.agree && type != 'univerify') {
return uni.showToast({
title: this.$t('common').noAgree,
icon: 'none'
});
}
uni.showLoading({
mask: true
})
//univerifyManager
if(type == 'univerify' && uni.getUniverifyManager){
// 调用一键登录弹框
const univerifyManager = uni.getUniverifyManager()
univerifyManager.login({
"univerifyStyle": this.univerifyStyle,
success (res) {
console.log('login success', res)
}
})
const callback = (res) => {
// 获取一键登录弹框协议勾选状态
univerifyManager.getCheckBoxState({
success(res) {
console.log("getCheckBoxState res: ", res);
if (res.state) {
// 关闭一键登录弹框
univerifyManager.close()
}
}
})
}
// 订阅自定义按钮点击事件
univerifyManager.onButtonsClick(callback)
// 取消订阅自定义按钮点击事件
univerifyManager.offButtonsClick(callback)
}else{ }else{
console.log(type); console.log('出乎意料的情况,path:'+path);
console.log('uni.getUniverifyManager:'+uni.getUniverifyManager); }
} },
login_before(type, navigateBack = true) {
console.log(type);
if (!this.agree && type != 'univerify') {
uni.login({ return uni.showToast({
"provider": type, title: t('noAgree'),
"onlyAuthorize":true, //请勿直接使用前端获取的unionid或openid直接用于登录,前端的数据都是不可靠的 icon: 'none'
"univerifyStyle": this.univerifyStyle, });
complete: (e) => { }
uni.hideLoading() uni.showLoading({mask: true})
console.log(e); if (type == 'univerify' && uni.getUniverifyManager) {
}, let univerifyManager = uni.getUniverifyManager()
success: async e => { console.log('是新版');
console.log(e); let onButtonsClickFn = async res =>{
if (type == 'apple') { console.log('点击了第三方登录,provider:',res, res.provider,this.univerifyStyle.buttons.list);
let res = await this.getUserInfo({ //同步一键登录弹出层隐私协议框是否打勾
provider: "apple" let agree = (await uni.getCheckBoxState())[1].state
}) console.log('agree',agree);
Object.assign(e.authResult, res.userInfo) uni.$emit('setAgreementsAgree', agree)
} let {
this.login( type == 'weixin'?e.code:e.authResult , type) path
}, } = this.univerifyStyle.buttons.list[res.index]
fail:async (err) => { console.log('path', path,this.getRoute(1));
console.log(err); if (path) {
if (type == 'univerify') { this.to(path)
if (err.metadata && err.metadata.error_data) { closeUniverify()
uni.showToast({ } else {
title: this.$t('uniQuickLogin').oneClickLogin + ":" + err.metadata.error_data, if(agree){
icon: 'none' closeUniverify()
}); setTimeout(() => {
} console.log('login_before');
if (err.errMsg) { this.login_before(res.provider)
}, 500)
}else{
console.log(t('noAgree'));
uni.showToast({ uni.showToast({
title:this.$t('uniQuickLogin').oneClickLogin + ":" + err.errMsg, title: t('noAgree'),
icon: 'none' icon: 'none'
}); });
} }
switch (err.errCode) {
case 30002:
console.log('在一键登录界面,点击其他登录方式');
break;
case 30003:
console.log('关闭了登录');
if (navigateBack) {
uni.navigateBack()
}
break;
case 30006:
uni.showModal({
title: this.$t('uniQuickLogin').loginErr,
content: err.metadata.error_data,
showCancel: false,
confirmText: this.$t('common').gotIt,
});
break;
case "30008":
uni.showToast({
title: this.$t('uniQuickLogin').chooseOtherLogin,
icon: 'none'
});
console.log('点击了第三方登录,provider:', err.provider);
//同步一键登录弹出层隐私协议框是否打勾
let agree = (await uni.getCheckBoxState())[1].state
console.log('agree',agree);
uni.$emit('setAgreementsAgree',agree)
let {
path
} = this.servicesList.find(item => item.id == err.provider) || {}
console.log('path', path);
if (path && path != this.getRoute(1)) { //存在路径,且并不是当前已经打开的路径
this.to(path)
} else {
setTimeout(()=>{
console.log('agree',this.agree);
this.login_before(err.provider)
},500)
}
break;
default:
console.log(err);
break;
}
} }
} }
}) function closeUniverify(){
},
login(params, type) { //联网验证登录
console.log({
params,
type
});
let action = 'loginBy' + type.trim().toLowerCase().replace(type[0], type[0].toUpperCase())
uniCloud.callFunction({
name: 'uni-id-cf',
data: {
action,
params
},
success: async ({
result
}) => {
console.log("login-result", result);
if (result.code === 0) {
if (type == 'univerify') {
uni.closeAuthView()
}
uni.hideLoading()
delete result.userInfo.token
// #ifdef MP-WEIXIN
if (type == 'weixin' && !result.userInfo.nickname) {
return this.$refs.userProfile.open(result.uid)
}
// #endif
this.setUserInfo(result.userInfo)
loginSuccess(result)
} else {
uni.showModal({
content: result.msg,
showCancel: false
});
}
},
complete: () => {
uni.hideLoading() uni.hideLoading()
univerifyManager.close()
// 取消订阅自定义按钮点击事件
univerifyManager.offButtonsClick(onButtonsClickFn)
} }
}) // 订阅自定义按钮点击事件
}, univerifyManager.onButtonsClick(onButtonsClickFn)
doUserProfileNext(){ // 调用一键登录弹框
loginSuccess() return univerifyManager.login({
}, "univerifyStyle": this.univerifyStyle,
async getUserInfo(e) { success:res=> {
return new Promise((resolve, reject) => { console.log('login success', res)
uni.getUserInfo({ this.login(res.authResult, 'univerify')
...e,
success: (res) => {
resolve(res);
}, },
fail: (err) => { fail(err) {
uni.showModal({ uni.showToast({
content: JSON.stringify(err), title: JSON.stringify(err),
showCancel: false icon: 'none'
}); });
reject(err); },
} complete(e){
uni.hideLoading()
// 取消订阅自定义按钮点击事件
univerifyManager.offButtonsClick(onButtonsClickFn)
}
}) })
}) }
} uni.login({
} "provider": type,
} "onlyAuthorize": true, //请勿直接使用前端获取的unionid或openid直接用于登录,前端的数据都是不可靠的
</script> "univerifyStyle": this.univerifyStyle,
complete: (e) => {
<style lang="scss" scoped> console.log(e);
/* #ifndef APP-NVUE */ uni.hideLoading()
view { },
display: flex; success: async e => {
box-sizing: border-box; console.log(e);
flex-direction: column; if (type == 'apple') {
} let res = await this.getUserInfo({
provider: "apple"
/* #endif */ })
.quick-login-box { Object.assign(e.authResult, res.userInfo)
flex-direction: row; }
width: 750rpx; this.login(type == 'weixin' ? e.code : e.authResult, type)
justify-content: space-around; },
position: fixed; fail: async (err) => {
bottom: 10rpx; console.log(err);
left: 0; // 以下代码为兼容旧版(HBuilderX3.2.13之前)HBuilderX3.2.13以上版本可直接删除
} if (type == 'univerify'&& !uni.getUniverifyManager) {
if (err.metadata && err.metadata.error_data) {
.item { uni.showToast({
flex-direction: column; title: t('oneClickLogin') + ":" + err.metadata.error_data,
justify-content: center; icon: 'none'
align-items: center; });
height: 200rpx; }
} if (err.errMsg) {
uni.showToast({
.logo { title: t('oneClickLogin') + ":" + err.errMsg,
width: 60rpx; icon: 'none'
height: 60rpx; });
} }
switch (err.errCode) {
.login-title { case 30002:
margin-top: 4px; console.log('在一键登录界面,点击其他登录方式');
font-size: 26rpx; break;
} case 30003:
</style> console.log('关闭了登录');
\ No newline at end of file if (navigateBack) {
uni.navigateBack()
}
break;
case 30006:
uni.showModal({
title: t('loginErr'),
content: err.metadata.error_data,
showCancel: false,
confirmText: t('gotIt'),
});
break;
case "30008":
console.log('点击了第三方登录,provider:', err.provider);
//同步一键登录弹出层隐私协议框是否打勾
let agree = (await uni.getCheckBoxState())[1].state
console.log('agree', agree);
uni.$emit('setAgreementsAgree', agree)
let {
path
} = this.univerifyStyle.buttons.list[res.index]
console.log('path', path);
if (path) {
this.to(path)
} else {
setTimeout(() => {
console.log('agree', this.agree);
this.login_before(err.provider)
}, 500)
}
break;
default:
console.log(err);
break;
}
}
// 以上代码为兼容旧版(HBuilderX3.2.13之前)HBuilderX3.2.13以上版本可直接删除
}
})
},
login(params, type) { //联网验证登录
console.log({
params,
type
});
let action = 'loginBy' + type.trim().toLowerCase().replace(type[0], type[0].toUpperCase())
uniCloud.callFunction({
name: 'uni-id-cf',
data: {
action,
params
},
success: async ({
result
}) => {
console.log("login-result", result);
if (result.code === 0) {
delete result.userInfo.token
// #ifdef MP-WEIXIN
if (type == 'weixin' && !result.userInfo.nickname) {
return this.$refs.userProfile.open(result.uid)
}
// #endif
this.setUserInfo(result.userInfo)
loginSuccess(result)
} else {
uni.showModal({
content: result.msg,
showCancel: false
});
}
},
complete: (e) => {
console.log(e);
if (type == 'univerify') {
uni.closeAuthView()
}
uni.hideLoading()
}
})
},
doUserProfileNext() {
loginSuccess()
},
async getUserInfo(e) {
return new Promise((resolve, reject) => {
uni.getUserInfo({
...e,
success: (res) => {
resolve(res);
},
fail: (err) => {
uni.showModal({
content: JSON.stringify(err),
showCancel: false
});
reject(err);
}
})
})
}
}
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
view {
display: flex;
box-sizing: border-box;
flex-direction: column;
}
/* #endif */
.quick-login-box {
flex-direction: row;
width: 750rpx;
justify-content: space-around;
position: fixed;
bottom: 10rpx;
left: 0;
}
.item {
flex-direction: column;
justify-content: center;
align-items: center;
height: 200rpx;
}
.logo {
width: 60rpx;
height: 60rpx;
}
.login-title {
margin-top: 4px;
font-size: 26rpx;
}
</style>
...@@ -52,7 +52,8 @@ export default { ...@@ -52,7 +52,8 @@ export default {
}, },
mine: { mine: {
showText: "Text", showText: "Text",
signIn: "Check In Reward", signIn: "Check In Reward",
signInByAd:"Check In Reward By AD",
toEvaluate: "To Evaluate", toEvaluate: "To Evaluate",
readArticles: "Read Articles", readArticles: "Read Articles",
myScore: "My Score", myScore: "My Score",
......
...@@ -53,7 +53,8 @@ export default { ...@@ -53,7 +53,8 @@ export default {
}, },
mine:{ mine:{
showText: "文字", showText: "文字",
signIn: "签到有奖", signIn: "普通签到",
signInByAd:"看广告签到",
toEvaluate: "去评分", toEvaluate: "去评分",
readArticles: "阅读过的文章", readArticles: "阅读过的文章",
myScore: "我的积分", myScore: "我的积分",
......
{ {
"name": "uuuu", "name": "uni-starter",
"appid": "请点击重新获取", "appid": "请点击重新获取",
"description": "云端一体应用快速开发模版", "description": "云端一体应用快速开发模版",
"versionName": "1.0.0", "versionName": "1.0.0",
...@@ -112,6 +112,10 @@ ...@@ -112,6 +112,10 @@
} }
}, },
"ad": { "ad": {
"gdt": {
},
"csj": {
}
}, },
"share": { "share": {
"weixin": { "weixin": {
...@@ -170,7 +174,8 @@ ...@@ -170,7 +174,8 @@
}, },
"splashscreen": { "splashscreen": {
"iosStyle": "common", "iosStyle": "common",
"androidStyle": "common" "androidStyle": "common",
"useOriginalMsgbox": true
} }
}, },
"nvueLaunchMode": "" "nvueLaunchMode": ""
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
</view> </view>
</template> </template>
</uni-list-item> </uni-list-item>
</uni-list> </uni-list>
<view class="banner"> <view class="banner">
<!-- 文章开头,缩略图 --> <!-- 文章开头,缩略图 -->
<image class="banner-img" :src="data.avatar" mode="widthFix"></image> <image class="banner-img" :src="data.avatar" mode="widthFix"></image>
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
<text class="uni-ellipsis">{{data.excerpt}}</text> <text class="uni-ellipsis">{{data.excerpt}}</text>
</view> </view>
</view> </view>
<view class="article-content"> <view class="article-content">
<rich-text :nodes="data.content"></rich-text> <rich-text :nodes="data.content"></rich-text>
</view> </view>
</template> </template>
...@@ -50,22 +50,29 @@ ...@@ -50,22 +50,29 @@
</template> </template>
<script> <script>
// #ifdef APP
import UniShare from '@/uni_modules/uni-share/js_sdk/uni-share.js'; import UniShare from '@/uni_modules/uni-share/js_sdk/uni-share.js';
const uniShare = new UniShare() const uniShare = new UniShare()
// #endif
const db = uniCloud.database(); const db = uniCloud.database();
const readNewsLog = db.collection('read-news-log') const readNewsLog = db.collection('read-news-log')
import { import {
mapGetters mapGetters
} from 'vuex'; } from 'vuex';
export default { export default {
// #ifdef APP
onBackPress({from}) { onBackPress({from}) {
if(from=='backbutton'){ if(from == 'backbutton'){
this.$nextTick(function(){ if(uniShare.isShow){
uniShare.hide() this.$nextTick(function(){
}) console.log(uniShare);
uniShare.hide()
})
}
return uniShare.isShow; return uniShare.isShow;
} }
}, },
// #endif
data() { data() {
return { return {
// 当前显示 _id // 当前显示 _id
...@@ -76,30 +83,28 @@ ...@@ -76,30 +83,28 @@
field: 'user_id.username,user_id._id,avatar,excerpt,last_modify_date,comment_count,like_count,title,content', field: 'user_id.username,user_id._id,avatar,excerpt,last_modify_date,comment_count,like_count,title,content',
formData: { formData: {
noData: '<p style="text-align:center;color:#666">详情加载中...</p>' noData: '<p style="text-align:center;color:#666">详情加载中...</p>'
}, }
} }
}, },
computed: { computed: {
//拼接where条件
//查询条件 ,更多详见 :https://uniapp.dcloud.net.cn/uniCloud/unicloud-db?id=jsquery
where() {
return `_id =="${this.id}"`
},
...mapGetters({ ...mapGetters({
'userInfo': 'user/info', 'userInfo': 'user/info',
'hasLogin': 'user/hasLogin' 'hasLogin': 'user/hasLogin'
}), }),
uniStarterConfig() { uniStarterConfig() {
return getApp().globalData.config return getApp().globalData.config
} },
where(){
//拼接where条件 查询条件 ,更多详见 :https://uniapp.dcloud.net.cn/uniCloud/unicloud-db?id=jsquery
return `_id =="${this.id}"`
}
}, },
onLoad(event) { onLoad(event) {
console.log(event); console.log(event);
// event = {"id":"60783c5cb781700001375672","title":"阿里小程序IDE官方内嵌uni-app,为开发者提供多端开发服务","excerpt":"阿里小程序IDE官方内嵌uni-app,为开发者提供多端开发服务","avatar":"https://vkceyugu.cdn.bspapp.com/VKCEYUGU-aliyun-gacrhzeynhss7c6d04/249516a0-3941-11eb-899d-733ae62bed2f.jpg"} // event = {"id":"60783c5cb781700001375672","title":"阿里小程序IDE官方内嵌uni-app,为开发者提供多端开发服务","excerpt":"阿里小程序IDE官方内嵌uni-app,为开发者提供多端开发服务","avatar":"https://vkceyugu.cdn.bspapp.com/VKCEYUGU-aliyun-gacrhzeynhss7c6d04/249516a0-3941-11eb-899d-733ae62bed2f.jpg"}
//获取真实新闻id,通常 id 来自上一个页面 //获取真实新闻id,通常 id 来自上一个页面
if (event.id) { if (event.id) {
this.id = event.id this.id = event.id
} }
//若上一页传递了标题过来,则设置导航栏标题 //若上一页传递了标题过来,则设置导航栏标题
if (event.title) { if (event.title) {
...@@ -109,23 +114,26 @@ ...@@ -109,23 +114,26 @@
}) })
} }
}, },
onNavigationBarButtonTap(event) {
if (event.type == 'share') {
this.shareClick();
}
},
onReady() { onReady() {
// 开始加载数据,修改 where 条件后才开始去加载 clinetDB 的数据 ,需要等组件渲染完毕后才开始执行 loadData,所以不能再 onLoad 中执行 // 开始加载数据,修改 where 条件后才开始去加载 clinetDB 的数据 ,需要等组件渲染完毕后才开始执行 loadData,所以不能再 onLoad 中执行
if (this.id) { // ID 不为空,则发起查询 if (this.id) { // ID 不为空,则发起查询
this.$refs.detail.loadData() this.$refs.detail.loadData()
} else { } else {
uni.showToast({ uni.showToast({
icon: 'none', icon: 'none',
title: this.$t('listDetail').newsErr title: this.$t('listDetail').newsErr
}) })
} }
},
onNavigationBarButtonTap(event) {
if (event.type == 'share') {
this.shareClick();
}
}, },
methods: { methods: {
$log(...args){
console.log('args',...args,this.id)
},
setReadNewsLog(){ setReadNewsLog(){
let item = { let item = {
"article_id":this.id, "article_id":this.id,
...@@ -192,89 +200,91 @@ ...@@ -192,89 +200,91 @@
/** /**
* 分享该文章 * 分享该文章
*/ */
shareClick() { // #ifdef APP
let { shareClick() {
_id, let {
title, _id,
excerpt, title,
avatar excerpt,
avatar
} = this.$refs.detail.dataList } = this.$refs.detail.dataList
console.log( JSON.stringify({ console.log( JSON.stringify({
_id, _id,
title, title,
excerpt, excerpt,
avatar avatar
}) ); }) );
uniShare.show({ uniShare.show({
content: { //公共的分享类型(type)、链接(herf)、标题(title)、summary(描述)、imageUrl(缩略图) content: { //公共的分享类型(type)、链接(herf)、标题(title)、summary(描述)、imageUrl(缩略图)
type: 0, type: 0,
href: this.uniStarterConfig.h5.url + `/#/pages/list/detail?id=${_id}&title=${title}`, href: this.uniStarterConfig.h5.url + `/#/pages/list/detail?id=${_id}&title=${title}`,
title: this.title, title: this.title,
summary: excerpt, summary: excerpt,
imageUrl: avatar + '?x-oss-process=image/resize,m_fill,h_100,w_100' //压缩图片解决,在ios端分享图过大导致的图片失效问题 imageUrl: avatar + '?x-oss-process=image/resize,m_fill,h_100,w_100' //压缩图片解决,在ios端分享图过大导致的图片失效问题
}, },
menus: [{ menus: [{
"img": "/static/app-plus/sharemenu/wechatfriend.png", "img": "/static/app-plus/sharemenu/wechatfriend.png",
"text": this.$t('common').wechatFriends, "text": this.$t('common').wechatFriends,
"share": { "share": {
"provider": "weixin", "provider": "weixin",
"scene": "WXSceneSession" "scene": "WXSceneSession"
} }
}, },
{ {
"img": "/static/app-plus/sharemenu/wechatmoments.png", "img": "/static/app-plus/sharemenu/wechatmoments.png",
"text": this.$t('common').wechatBbs, "text": this.$t('common').wechatBbs,
"share": { "share": {
"provider": "weixin", "provider": "weixin",
"scene": "WXSenceTimeline" "scene": "WXSenceTimeline"
} }
}, },
{ {
"img": "/static/app-plus/sharemenu/mp_weixin.png", "img": "/static/app-plus/sharemenu/mp_weixin.png",
"text": this.$t('common').wechatApplet, "text": this.$t('common').wechatApplet,
"share": { "share": {
provider: "weixin", provider: "weixin",
scene: "WXSceneSession", scene: "WXSceneSession",
type: 5, type: 5,
miniProgram: { miniProgram: {
id: this.uniStarterConfig.mp.weixin.id, id: this.uniStarterConfig.mp.weixin.id,
path: `/pages/list/detail?id=${_id}&title=${title}`, path: `/pages/list/detail?id=${_id}&title=${title}`,
webUrl: this.uniStarterConfig.h5.url + webUrl: this.uniStarterConfig.h5.url +
`/#/pages/list/detail?id=${_id}&title=${title}`, `/#/pages/list/detail?id=${_id}&title=${title}`,
type: 0 type: 0
}, },
} }
}, },
{ {
"img": "/static/app-plus/sharemenu/weibo.png", "img": "/static/app-plus/sharemenu/weibo.png",
"text": this.$t('common').weibo, "text": this.$t('common').weibo,
"share": { "share": {
"provider": "sinaweibo" "provider": "sinaweibo"
} }
}, },
{ {
"img": "/static/app-plus/sharemenu/qq.png", "img": "/static/app-plus/sharemenu/qq.png",
"text": "QQ", "text": "QQ",
"share": { "share": {
"provider": "qq" "provider": "qq"
} }
}, },
{ {
"img": "/static/app-plus/sharemenu/copyurl.png", "img": "/static/app-plus/sharemenu/copyurl.png",
"text": this.$t('common').copy, "text": this.$t('common').copy,
"share": "copyurl" "share": "copyurl"
}, },
{ {
"img": "/static/app-plus/sharemenu/more.png", "img": "/static/app-plus/sharemenu/more.png",
"text": this.$t('common').more, "text": this.$t('common').more,
"share": "shareSystem" "share": "shareSystem"
} }
], ],
cancelText: this.$t('common').cancelShare, cancelText: this.$t('common').cancelShare,
}, e => { //callback }, e => { //callback
console.log(e); console.log(e);
}) })
}, }
// #endif
} }
} }
</script> </script>
......
...@@ -41,15 +41,18 @@ ...@@ -41,15 +41,18 @@
</view> </view>
</template> </template>
</uni-list-item> </uni-list-item>
<!-- 加载状态:上拉加载更多,加载中,没有更多数据了,加载错误 -->
<!-- 加载状态:上拉加载更多,加载中,没有更多数据了,加载错误 --> <!-- #ifdef APP-PLUS -->
<uni-list-item> <uni-list-item>
<template v-slot:body> <template v-slot:body>
<!-- #endif -->
<uni-load-state @networkResume="refresh" :state="{data,pagination,hasMore, loading, error}" <uni-load-state @networkResume="refresh" :state="{data,pagination,hasMore, loading, error}"
@loadMore="loadMore"> @loadMore="loadMore">
</uni-load-state> </uni-load-state>
</template> <!-- #ifdef APP-PLUS -->
</uni-list-item> </template>
</uni-list-item>
<!-- #endif -->
</uni-list> </uni-list>
</unicloud-db> </unicloud-db>
</view> </view>
......
...@@ -63,10 +63,9 @@ ...@@ -63,10 +63,9 @@
<!-- 搜索联想 --> <!-- 搜索联想 -->
<view class="search-associative" v-if="associativeShow"> <view class="search-associative" v-if="associativeShow">
<uni-list> <uni-list>
<template v-for="(item,index) in associativeList"> <uni-list-item v-for="(item,index) in associativeList" :key="item._id" :ellipsis="1" :title="item.name" @click="associativeClick(item)" show-extra-icon
<uni-list-item :key="item._id" :ellipsis="1" :title="item.name" @click="associativeClick(item)" show-extra-icon clickable :extra-icon="{size:18,color:iconColor,type:'search'}" >
clickable :extra-icon="{size:18,color:iconColor,type:'search'}" /> </uni-list-item>
</template>
</uni-list> </uni-list>
</view> </view>
</view> </view>
......
...@@ -54,7 +54,13 @@ ...@@ -54,7 +54,13 @@
"top": "2000px" //隐藏当前页面窗体 "top": "2000px" //隐藏当前页面窗体
}) })
} }
//#endif //#endif
uni.$on('setLoginType',type=>{
this.type = type
})
},
onUnload() {
uni.$off('setLoginType')
}, },
onReady() { onReady() {
//#ifdef APP-PLUS //#ifdef APP-PLUS
......
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
} else { } else {
if (result.needCaptcha) { if (result.needCaptcha) {
uni.showToast({ uni.showToast({
title: result.msg, title: result.msg||'完成',
icon: 'none' icon: 'none'
}); });
this.createCaptcha() this.createCaptcha()
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
:placeholder="$t('common.confirmNewPasswordPlaceholder')"></uni-easyinput> :placeholder="$t('common.confirmNewPasswordPlaceholder')"></uni-easyinput>
</uni-forms-item> </uni-forms-item>
<button class="send-btn-box" :disabled="!canSubmit" :type="canSubmit?'primary':'default'" <button class="send-btn-box" :disabled="!canSubmit" :type="canSubmit?'primary':'default'"
@click="submit">{{$t('common.complete')}}</button> @click="submit">{{$t('common.complete')}}</button>
</uni-forms> </uni-forms>
</view> </view>
</template> </template>
...@@ -38,7 +38,8 @@ ...@@ -38,7 +38,8 @@
return { return {
lock:false, lock:false,
formData: { formData: {
"phone": "", "phone": "",
"code":"",
'pwd': '', 'pwd': '',
'pwd2': '' 'pwd2': ''
}, },
...@@ -100,7 +101,7 @@ ...@@ -100,7 +101,7 @@
} }
}, },
computed: { computed: {
canSubmit() { canSubmit() {
return this.isPhone && this.isPwd && this.isCode; return this.isPhone && this.isPwd && this.isCode;
}, },
isPhone() { isPhone() {
...@@ -115,7 +116,7 @@ ...@@ -115,7 +116,7 @@
}, },
isCode() { isCode() {
let reg_code = /^\d{6}$/; let reg_code = /^\d{6}$/;
let isCode = reg_code.test(this.formData.code); let isCode = reg_code.test(this.formData.code);
return isCode; return isCode;
} }
}, },
...@@ -137,7 +138,9 @@ ...@@ -137,7 +138,9 @@
/** /**
* 完成并提交 * 完成并提交
*/ */
submit() { submit() {
console.log("formData",this.formData);
console.log('rules',this.rules);
this.$refs.form.validate() this.$refs.form.validate()
.then(res => { .then(res => {
uniCloud.callFunction({ uniCloud.callFunction({
...@@ -153,7 +156,7 @@ ...@@ -153,7 +156,7 @@
success: ({result}) => { success: ({result}) => {
console.log(result); console.log(result);
uni.showToast({ uni.showToast({
title: result.msg, title: result.msg||'更新成功',
icon: 'none' icon: 'none'
}); });
if (result.code === 0) { if (result.code === 0) {
...@@ -169,7 +172,6 @@ ...@@ -169,7 +172,6 @@
<style> <style>
@import url("../common/login-page.css"); @import url("../common/login-page.css");
.content{ .content{
padding-top: 36rpx; padding-top: 36rpx;
} }
......
...@@ -58,7 +58,8 @@ ...@@ -58,7 +58,8 @@
uni.stopPullDownRefresh() uni.stopPullDownRefresh()
}) })
}, },
handleItemClick(item) { handleItemClick(item) {
console.log(item);
uni.navigateTo({ uni.navigateTo({
url: '/pages/list/detail?id=' + item._id + '&title=' + item.title url: '/pages/list/detail?id=' + item._id + '&title=' + item.title
}) })
......
...@@ -69,7 +69,15 @@ ...@@ -69,7 +69,15 @@
} }
], ],
ucenterList: [ ucenterList: [
[{ [
// #ifdef APP-PLUS
{
"title": this.$t('mine.signInByAd'),
"event": 'signInByAd',
"icon": "compose"
},
// #endif
{
"title": this.$t('mine.signIn'), "title": this.$t('mine.signIn'),
"event": 'signIn', "event": 'signIn',
"icon": "compose" "icon": "compose"
...@@ -168,9 +176,12 @@ ...@@ -168,9 +176,12 @@
url: "/pages/ucenter/settings/settings" url: "/pages/ucenter/settings/settings"
}) })
}, },
signIn() { //签到 signIn() { //普通签到
this.$refs.signIn.open() this.$refs.signIn.open()
}, },
signInByAd(){ //看激励视频广告签到
this.$refs.signIn.showRewardedVideoAd()
},
/** /**
* 个人中心项目列表点击事件 * 个人中心项目列表点击事件
*/ */
......
...@@ -64,7 +64,7 @@ ...@@ -64,7 +64,7 @@
console.log(result); console.log(result);
this.setUserInfo({"mobile":result.mobile}) this.setUserInfo({"mobile":result.mobile})
uni.showToast({ uni.showToast({
title: result.msg, title: result.msg||'完成',
icon: 'none' icon: 'none'
}); });
if (result.code === 0) { if (result.code === 0) {
......
## 1.4.3(2021-09-22)
- 修复 startDate、 endDate 属性失效的 bug
## 1.4.2(2021-08-24) ## 1.4.2(2021-08-24)
- 新增 支持国际化 - 新增 支持国际化
## 1.4.1(2021-08-05) ## 1.4.1(2021-08-05)
......
...@@ -184,10 +184,14 @@ ...@@ -184,10 +184,14 @@
this.init(newVal) this.init(newVal)
}, },
startDate(val){ startDate(val){
this.cale.resetSatrtDate(val) this.cale.resetSatrtDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
}, },
endDate(val){ endDate(val){
this.cale.resetEndDate(val) this.cale.resetEndDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
}, },
selected(newVal) { selected(newVal) {
this.cale.setSelectInfo(this.nowDate.fullDate, newVal) this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
......
...@@ -139,13 +139,15 @@ class Calendar { ...@@ -139,13 +139,15 @@ class Calendar {
let disableBefore = true let disableBefore = true
let disableAfter = true let disableAfter = true
if (this.startDate) { if (this.startDate) {
let dateCompBefore = this.dateCompare(this.startDate, fullDate) // let dateCompBefore = this.dateCompare(this.startDate, fullDate)
disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate) // disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
disableBefore = this.dateCompare(this.startDate, nowDate)
} }
if (this.endDate) { if (this.endDate) {
let dateCompAfter = this.dateCompare(fullDate, this.endDate) // let dateCompAfter = this.dateCompare(fullDate, this.endDate)
disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate) // disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
disableAfter = this.dateCompare(nowDate, this.endDate)
} }
let multiples = this.multipleStatus.data let multiples = this.multipleStatus.data
let checked = false let checked = false
...@@ -169,7 +171,7 @@ class Calendar { ...@@ -169,7 +171,7 @@ class Calendar {
afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate), afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate),
month: full.month, month: full.month,
lunar: this.getlunar(full.year, full.month, i), lunar: this.getlunar(full.year, full.month, i),
disable: !disableBefore || !disableAfter, disable: !(disableBefore && disableAfter),
isDay isDay
} }
if (info) { if (info) {
......
{ {
"id": "uni-calendar", "id": "uni-calendar",
"displayName": "uni-calendar 日历", "displayName": "uni-calendar 日历",
"version": "1.4.2", "version": "1.4.3",
"description": "日历组件", "description": "日历组件",
"keywords": [ "keywords": [
"uni-ui", "uni-ui",
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
}, },
"Vue": { "Vue": {
"vue2": "y", "vue2": "y",
"vue3": "u" "vue3": "y"
} }
} }
} }
......
## 0.4.0(2021-07-13) ## 0.4.9(2021-10-28)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) - 修复 VUE2 v-model 概率无效的bug
## 0.4.8(2021-10-27)
- 修复 v-model 概率无效的bug
## 0.4.7(2021-10-25)
- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+
- 修复 树型 uniCloud 数据类型为 int 时报错的bug
## 0.4.6(2021-10-19)
- 修复 非VUE3 v-model 为 0 时无法选中的 bug
## 0.4.5(2021-09-26)
- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效
- 修复 readonly 为 true 时报错的 bug
## 0.4.4(2021-09-26)
- 修复 上一版本造成的 map 属性失效的bug
- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略
## 0.4.3(2021-09-24)
- 修复 某些情况下级联未触发的 bug
## 0.4.2(2021-09-23)
- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用
- 新增 选项内容过长自动添加省略号
## 0.4.1(2021-09-15)
- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段
## 0.4.0(2021-07-13)
- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.3.5(2021-06-04) ## 0.3.5(2021-06-04)
- 修复 无法加载云端数据的问题 - 修复 无法加载云端数据的问题
## 0.3.4(2021-05-28) ## 0.3.4(2021-05-28)
- 修复 v-model无效问题
- 修复 v-model 无效问题
- 修复 loaddata 为空数据组时加载时间过长问题 - 修复 loaddata 为空数据组时加载时间过长问题
- 修复 上个版本引出的本地数据无法选择带有children的2级节点 - 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点
## 0.3.3(2021-05-12) ## 0.3.3(2021-05-12)
- 新增 组件示例地址 - 新增 组件示例地址
## 0.3.2(2021-04-22) ## 0.3.2(2021-04-22)
- 修复 非树形数据有 where 属性查询报错的问题 - 修复 非树形数据有 where 属性查询报错的问题
## 0.3.1(2021-04-15) ## 0.3.1(2021-04-15)
- 修复 本地数据概率无法回显时问题 - 修复 本地数据概率无法回显时问题
## 0.3.0(2021-04-07) ## 0.3.0(2021-04-07)
- 新增 支持云端非树形表结构数据 - 新增 支持云端非树形表结构数据
- 修复 根节点 parent_field 字段等于null时选择界面错乱问题 - 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题
## 0.2.0(2021-03-15) ## 0.2.0(2021-03-15)
- 修复 nodeclick、popupopened、popupclosed事件无法触发的问题
- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题
## 0.1.9(2021-03-09) ## 0.1.9(2021-03-09)
- 修复 微信小程序某些情况下无法选择的问题 - 修复 微信小程序某些情况下无法选择的问题
## 0.1.8(2021-02-05) ## 0.1.8(2021-02-05)
- 优化 部分样式在nvue上的兼容表现
- 优化 部分样式在 nvue 上的兼容表现
## 0.1.7(2021-02-05) ## 0.1.7(2021-02-05)
- 调整为uni_modules目录规范
- 调整为 uni_modules 目录规范
...@@ -16,7 +16,11 @@ ...@@ -16,7 +16,11 @@
</view> </view>
</scroll-view> </scroll-view>
<text v-else class="selected-area placeholder">{{placeholder}}</text> <text v-else class="selected-area placeholder">{{placeholder}}</text>
<view class="arrow-area" v-if="!readonly"> <view v-show="clearIcon && !readonly && inputSelected.length" class="icon-clear"
@click.stop="clear">
<uni-icons type="clear" color="#e1e1e1" size="14"></uni-icons>
</view>
<view class="arrow-area" v-if="(!clearIcon || !inputSelected.length) && !readonly ">
<view class="input-arrow"></view> <view class="input-arrow"></view>
</view> </view>
</view> </view>
...@@ -36,7 +40,8 @@ ...@@ -36,7 +40,8 @@
<data-picker-view class="picker-view" ref="pickerView" v-model="dataValue" :localdata="localdata" <data-picker-view class="picker-view" ref="pickerView" v-model="dataValue" :localdata="localdata"
:preload="preload" :collection="collection" :field="field" :orderby="orderby" :where="where" :preload="preload" :collection="collection" :field="field" :orderby="orderby" :where="where"
:step-searh="stepSearh" :self-field="selfField" :parent-field="parentField" :managed-mode="true" :step-searh="stepSearh" :self-field="selfField" :parent-field="parentField" :managed-mode="true"
@change="onchange" @datachange="ondatachange" @nodeclick="onnodeclick"></data-picker-view> :map="map" :ellipsis="ellipsis" @change="onchange" @datachange="ondatachange" @nodeclick="onnodeclick">
</data-picker-view>
</view> </view>
</view> </view>
</template> </template>
...@@ -70,7 +75,7 @@ ...@@ -70,7 +75,7 @@
*/ */
export default { export default {
name: 'UniDataPicker', name: 'UniDataPicker',
emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change','update:modelValue'], emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change', 'update:modelValue'],
mixins: [dataPicker], mixins: [dataPicker],
components: { components: {
DataPickerView DataPickerView
...@@ -98,6 +103,10 @@ ...@@ -98,6 +103,10 @@
type: Boolean, type: Boolean,
default: false default: false
}, },
clearIcon: {
type: Boolean,
default: true
},
border: { border: {
type: Boolean, type: Boolean,
default: true default: true
...@@ -105,6 +114,10 @@ ...@@ -105,6 +114,10 @@
split: { split: {
type: String, type: String,
default: '/' default: '/'
},
ellipsis: {
type: Boolean,
default: true
} }
}, },
data() { data() {
...@@ -128,6 +141,10 @@ ...@@ -128,6 +141,10 @@
}) })
}, },
methods: { methods: {
clear() {
this.inputSelected.splice(0)
this._dispatchEvent([])
},
onPropsChange() { onPropsChange() {
this._treeData = [] this._treeData = []
this.selectedIndex = 0 this.selectedIndex = 0
...@@ -142,11 +159,11 @@ ...@@ -142,11 +159,11 @@
if (this.isLocaldata) { if (this.isLocaldata) {
this.loadData() this.loadData()
this.inputSelected = this.selected.slice(0) this.inputSelected = this.selected.slice(0)
} else if (!this.parentField && !this.selfField && this.dataValue) { } else if (!this.parentField && !this.selfField && this.hasValue) {
this.getNodeData(() => { this.getNodeData(() => {
this.inputSelected = this.selected.slice(0) this.inputSelected = this.selected.slice(0)
}) })
} else if (this.dataValue.length) { } else if (this.hasValue) {
this.getTreePath(() => { this.getTreePath(() => {
this.inputSelected = this.selected.slice(0) this.inputSelected = this.selected.slice(0)
}) })
...@@ -197,26 +214,34 @@ ...@@ -197,26 +214,34 @@
this.inputSelected = e this.inputSelected = e
this._dispatchEvent(e) this._dispatchEvent(e)
}, },
_processReadonly(dataList, valueArray) { _processReadonly(dataList, value) {
var isTree = dataList.findIndex((item) => { var isTree = dataList.findIndex((item) => {
return item.children return item.children
}) })
if (isTree > -1) { if (isTree > -1) {
if (Array.isArray(valueArray)) { let inputValue
let inputValue = valueArray[valueArray.length - 1] if (Array.isArray(value)) {
inputValue = value[value.length - 1]
if (typeof inputValue === 'object' && inputValue.value) { if (typeof inputValue === 'object' && inputValue.value) {
inputValue = inputValue.value inputValue = inputValue.value
} }
} else {
inputValue = value
} }
this.inputSelected = this._findNodePath(inputValue, this.localdata) this.inputSelected = this._findNodePath(inputValue, this.localdata)
return return
} }
if (!this.hasValue) {
this.inputSelected = []
return
}
let result = [] let result = []
for (let i = 0; i < valueArray.length; i++) { for (let i = 0; i < value.length; i++) {
var value = valueArray[i] var val = value[i]
var item = dataList.find((v) => { var item = dataList.find((v) => {
return v.value == value return v.value == val
}) })
if (item) { if (item) {
result.push(item) result.push(item)
...@@ -239,14 +264,17 @@ ...@@ -239,14 +264,17 @@
} }
return result return result
}, },
_dispatchEvent(selected) { _dispatchEvent(selected) {
var value = new Array(selected.length) let item = {}
for (var i = 0; i < selected.length; i++) { if (selected.length) {
value[i] = selected[i].value var value = new Array(selected.length)
for (var i = 0; i < selected.length; i++) {
value[i] = selected[i].value
}
item = selected[selected.length - 1]
} else {
item.value = ''
} }
const item = selected[selected.length - 1]
if (this.formItem) { if (this.formItem) {
this.formItem.setValue(item.value) this.formItem.setValue(item.value)
} }
...@@ -341,6 +369,7 @@ ...@@ -341,6 +369,7 @@
position: relative; position: relative;
width: 20px; width: 20px;
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
margin-bottom: 5px;
margin-left: auto; margin-left: auto;
display: flex; display: flex;
/* #endif */ /* #endif */
...@@ -466,6 +495,10 @@ ...@@ -466,6 +495,10 @@
.dialog-caption { .dialog-caption {
display: none; display: none;
} }
.icon-clear {
margin-right: 5px;
}
} }
/* #endif */ /* #endif */
......
...@@ -6,6 +6,12 @@ export default { ...@@ -6,6 +6,12 @@ export default {
return [] return []
} }
}, },
spaceInfo: {
type: Object,
default () {
return {}
}
},
collection: { collection: {
type: String, type: String,
default: '' default: ''
...@@ -60,12 +66,12 @@ export default { ...@@ -60,12 +66,12 @@ export default {
return [] return []
} }
}, },
modelValue: { modelValue: {
type: [Array, String, Number], type: [Array, String, Number],
default () { default () {
return [] return []
} }
}, },
preload: { preload: {
type: Boolean, type: Boolean,
default: false default: false
...@@ -85,6 +91,15 @@ export default { ...@@ -85,6 +91,15 @@ export default {
multiple: { multiple: {
type: Boolean, type: Boolean,
default: false default: false
},
map: {
type: Object,
default() {
return {
text: "text",
value: "value"
}
}
} }
}, },
data() { data() {
...@@ -111,29 +126,29 @@ export default { ...@@ -111,29 +126,29 @@ export default {
return !this.collection.length return !this.collection.length
}, },
postField() { postField() {
let fields = [this.field]; let fields = [this.field];
if (this.parentField) { if (this.parentField) {
fields.push(`${this.parentField} as parent_value`); fields.push(`${this.parentField} as parent_value`);
} }
return fields.join(','); return fields.join(',');
}, },
dataValue(){ dataValue() {
let isarr = Array.isArray(this.value) && this.value.length === 0 let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null || this.modelValue !== undefined)
let isstr = typeof this.value === 'string' && !this.value return isModelValue ? this.modelValue : this.value
let isnum = typeof this.value === 'number' && !this.value },
hasValue() {
if(isarr || isstr || isnum){ if (typeof this.dataValue === 'number') {
return this.modelValue return true
} }
return (this.dataValue != null) && (this.dataValue.length > 0)
return this.value }
}
}, },
created() { created() {
this.$watch(() => { this.$watch(() => {
var al = []; var al = [];
['pageCurrent', ['pageCurrent',
'pageSize', 'pageSize',
'spaceInfo',
'value', 'value',
'modelValue', 'modelValue',
'localdata', 'localdata',
...@@ -172,7 +187,7 @@ export default { ...@@ -172,7 +187,7 @@ export default {
}, },
getCommand(options = {}) { getCommand(options = {}) {
/* eslint-disable no-undef */ /* eslint-disable no-undef */
let db = uniCloud.database() let db = uniCloud.database(this.spaceInfo)
const action = options.action || this.action const action = options.action || this.action
if (action) { if (action) {
...@@ -259,7 +274,7 @@ export default { ...@@ -259,7 +274,7 @@ export default {
return return
} }
if (this.dataValue.length) { if (this.dataValue != null) {
this._loadNodeData((data) => { this._loadNodeData((data) => {
this._treeData = data this._treeData = data
this._updateBindData() this._updateBindData()
...@@ -389,13 +404,15 @@ export default { ...@@ -389,13 +404,15 @@ export default {
_updateSelected() { _updateSelected() {
var dl = this.dataList var dl = this.dataList
var sl = this.selected var sl = this.selected
let textField = this.map.text
let valueField = this.map.value
for (var i = 0; i < sl.length; i++) { for (var i = 0; i < sl.length; i++) {
var value = sl[i].value var value = sl[i].value
var dl2 = dl[i] var dl2 = dl[i]
for (var j = 0; j < dl2.length; j++) { for (var j = 0; j < dl2.length; j++) {
var item2 = dl2[j] var item2 = dl2[j]
if (item2.value === value) { if (item2[valueField] === value) {
sl[i].text = item2.text sl[i].text = item2[textField]
break break
} }
} }
...@@ -430,11 +447,10 @@ export default { ...@@ -430,11 +447,10 @@ export default {
}, },
_filterData(data, paths) { _filterData(data, paths) {
let dataList = [] let dataList = []
let hasNodes = true let hasNodes = true
dataList.push(data.filter((item) => { dataList.push(data.filter((item) => {
return item.parent_value === undefined return (item.parent_value === null || item.parent_value === undefined || item.parent_value === '')
})) }))
for (let i = 0; i < paths.length; i++) { for (let i = 0; i < paths.length; i++) {
var value = paths[i].value var value = paths[i].value
...@@ -456,6 +472,7 @@ export default { ...@@ -456,6 +472,7 @@ export default {
}, },
_extractTree(nodes, result, parent_value) { _extractTree(nodes, result, parent_value) {
let list = result || [] let list = result || []
let valueField = this.map.value
for (let i = 0; i < nodes.length; i++) { for (let i = 0; i < nodes.length; i++) {
let node = nodes[i] let node = nodes[i]
...@@ -465,14 +482,14 @@ export default { ...@@ -465,14 +482,14 @@ export default {
child[key] = node[key] child[key] = node[key]
} }
} }
if (parent_value !== undefined) { if (parent_value !== null && parent_value !== undefined && parent_value !== '') {
child.parent_value = parent_value child.parent_value = parent_value
} }
result.push(child) result.push(child)
let children = node.children let children = node.children
if (children) { if (children) {
this._extractTree(children, result, node.value) this._extractTree(children, result, node[valueField])
} }
} }
}, },
...@@ -496,12 +513,13 @@ export default { ...@@ -496,12 +513,13 @@ export default {
} }
}, },
_findNodePath(key, nodes, path = []) { _findNodePath(key, nodes, path = []) {
let textField = this.map.text
let valueField = this.map.value
for (let i = 0; i < nodes.length; i++) { for (let i = 0; i < nodes.length; i++) {
let { let node = nodes[i]
value, let children = node.children
text, let text = node[textField]
children let value = node[valueField]
} = nodes[i]
path.push({ path.push({
value, value,
...@@ -526,7 +544,7 @@ export default { ...@@ -526,7 +544,7 @@ export default {
_processLocalData() { _processLocalData() {
this._treeData = [] this._treeData = []
this._extractTree(this.localdata, this._treeData) this._extractTree(this.localdata, this._treeData)
var inputValue = this.dataValue var inputValue = this.dataValue
if (inputValue === undefined) { if (inputValue === undefined) {
return return
...@@ -534,8 +552,8 @@ export default { ...@@ -534,8 +552,8 @@ export default {
if (Array.isArray(inputValue)) { if (Array.isArray(inputValue)) {
inputValue = inputValue[inputValue.length - 1] inputValue = inputValue[inputValue.length - 1]
if (typeof inputValue === 'object' && inputValue.value) { if (typeof inputValue === 'object' && inputValue[this.map.value]) {
inputValue = inputValue.value inputValue = inputValue[this.map.value]
} }
} }
......
<template> <template>
<view class="uni-data-pickerview"> <view class="uni-data-pickerview">
<scroll-view class="selected-area" scroll-x="true" scroll-y="false" :show-scrollbar="false"> <scroll-view class="selected-area" scroll-x="true" scroll-y="false" :show-scrollbar="false">
<view class="selected-list"> <view class="selected-list">
<template v-for="(item,index) in selected"> <template v-for="(item,index) in selected">
<view class="selected-item" :class="{'selected-item-active':index==selectedIndex}" <view class="selected-item"
:key="index" v-if="item.text" @click="handleSelect(index)"> :class="{'selected-item-active':index==selectedIndex, 'selected-item-text-overflow': ellipsis}"
<text class="">{{item.text}}</text> :key="index" v-if="item.text" @click="handleSelect(index)">
<text class="">{{item.text}}</text>
</view>
</template>
</view> </view>
</template> </scroll-view>
</view> <view class="tab-c">
</scroll-view> <template v-for="(child, i) in dataList">
<view class="tab-c"> <scroll-view class="list" :key="i" v-if="i==selectedIndex" :scroll-y="true">
<template v-for="(child, i) in dataList"> <view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in child" :key="j"
<scroll-view class="list" :key="i" v-if="i==selectedIndex" :scroll-y="true"> @click="handleNodeClick(item, i, j)">
<view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in child" :key="j" @click="handleNodeClick(item, i, j)"> <text class="item-text item-text-overflow">{{item[map.text]}}</text>
<text class="item-text">{{item.text}}</text> <view class="check" v-if="selected.length > i && item[map.value] == selected[i].value"></view>
<view class="check" v-if="selected.length > i && item.value == selected[i].value"></view> </view>
</view> </scroll-view>
</scroll-view> </template>
</template>
<view class="loading-cover" v-if="loading">
<view class="loading-cover" v-if="loading"> <uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more> </view>
</view> <view class="error-message" v-if="errorMessage">
<view class="error-message" v-if="errorMessage"> <text class="error-text">{{errorMessage}}</text>
<text class="error-text">{{errorMessage}}</text> </view>
</view> </view>
</view> </view>
</view>
</template> </template>
<script> <script>
import dataPicker from "./uni-data-picker.js" import dataPicker from "./uni-data-picker.js"
/**
* DataPickerview
* @description uni-data-pickerview
* @tutorial https://ext.dcloud.net.cn/plugin?id=3796
* @property {Array} localdata 本地数据,参考
* @property {Boolean} step-searh = [true|false] 是否分布查询
* @value true 启用分布查询,仅查询当前选中节点
* @value false 关闭分布查询,一次查询出所有数据
* @property {String|DBFieldString} self-field 分布查询当前字段名称
* @property {String|DBFieldString} parent-field 分布查询父字段名称
* @property {String|DBCollectionString} collection 表名
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
* @property {String} orderby 排序字段及正序倒叙设置
* @property {String|JQLString} where 查询条件
*/
export default {
name: 'UniDataPickerView',
emits:['nodeclick','change','datachange','update:modelValue'],
mixins: [dataPicker],
props: {
managedMode: {
type: Boolean,
default: false
}
},
data() {
return {}
},
created() {
if (this.managedMode) {
return
}
this.$nextTick(() => { /**
this.load() * DataPickerview
}) * @description uni-data-pickerview
}, * @tutorial https://ext.dcloud.net.cn/plugin?id=3796
methods: { * @property {Array} localdata 本地数据,参考
onPropsChange() { * @property {Boolean} step-searh = [true|false] 是否分布查询
this._treeData = [] * @value true 启用分布查询,仅查询当前选中节点
this.selectedIndex = 0 * @value false 关闭分布查询,一次查询出所有数据
this.load() * @property {String|DBFieldString} self-field 分布查询当前字段名称
}, * @property {String|DBFieldString} parent-field 分布查询父字段名称
load() { * @property {String|DBCollectionString} collection 表名
if (this.isLocaldata) { * @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
this.loadData() * @property {String} orderby 排序字段及正序倒叙设置
} else if (this.dataValue.length) { * @property {String|JQLString} where 查询条件
this.getTreePath((res) => { */
this.loadData() export default {
}) name: 'UniDataPickerView',
} emits: ['nodeclick', 'change', 'datachange', 'update:modelValue'],
}, mixins: [dataPicker],
handleSelect(index) { props: {
this.selectedIndex = index managedMode: {
}, type: Boolean,
handleNodeClick(item, i, j) { default: false
if (item.disable) { },
return ellipsis: {
} type: Boolean,
default: true
}
},
data() {
return {}
},
created() {
if (this.managedMode) {
return
}
const node = this.dataList[i][j] this.$nextTick(() => {
const { this.load()
value, })
text },
} = node methods: {
onPropsChange() {
this._treeData = []
this.selectedIndex = 0
this.load()
},
load() {
if (this.isLocaldata) {
this.loadData()
} else if (this.dataValue.length) {
this.getTreePath((res) => {
this.loadData()
})
}
},
handleSelect(index) {
this.selectedIndex = index
},
handleNodeClick(item, i, j) {
if (item.disable) {
return
}
const node = this.dataList[i][j]
const text = node[this.map.text]
const value = node[this.map.value]
if (i < this.selected.length - 1) {
this.selected.splice(i, this.selected.length - i)
this.selected.push({
text,
value
})
} else if (i === this.selected.length - 1) {
this.selected.splice(i, 1, {
text,
value
})
}
if (i < this.selected.length - 1) { if (node.isleaf) {
this.selected.splice(i, this.selected.length - i) this.onSelectedChange(node, node.isleaf)
this.selected.push(node) return
} else if (i === this.selected.length - 1) { }
this.selected[i] = node
}
if (node.isleaf) { const {
this.onSelectedChange(node, node.isleaf) isleaf,
return hasNodes
} } = this._updateBindData()
const { if (!this._isTreeView() && !hasNodes) {
isleaf, this.onSelectedChange(node, true)
hasNodes return
} = this._updateBindData() }
if (!this._isTreeView() && !hasNodes) { if (this.isLocaldata && (!hasNodes || isleaf)) {
this.onSelectedChange(node, true) this.onSelectedChange(node, true)
return return
} }
if (this.isLocaldata && (!hasNodes || isleaf)) { if (!isleaf && !hasNodes) {
this.onSelectedChange(node, true) this._loadNodeData((data) => {
return if (!data.length) {
} node.isleaf = true
} else {
this._treeData.push(...data)
this._updateBindData(node)
}
this.onSelectedChange(node, node.isleaf)
}, this._nodeWhere())
return
}
if (!isleaf && !hasNodes) { this.onSelectedChange(node, false)
this._loadNodeData((data) => { },
if (!data.length) { updateData(data) {
node.isleaf = true this._treeData = data.treeData
} else { this.selected = data.selected
this._treeData.push(...data) if (!this._treeData.length) {
this._updateBindData(node) this.loadData()
} } else {
this.onSelectedChange(node, node.isleaf) //this.selected = data.selected
}, this._nodeWhere()) this._updateBindData()
return }
} },
onDataChange() {
this.$emit('datachange')
},
onSelectedChange(node, isleaf) {
if (isleaf) {
this._dispatchEvent()
}
this.onSelectedChange(node, false) if (node) {
}, this.$emit('nodeclick', node)
updateData(data) { }
this._treeData = data.treeData },
this.selected = data.selected _dispatchEvent() {
if (!this._treeData.length) { this.$emit('change', this.selected.slice(0))
this.loadData() }
} else {
//this.selected = data.selected
this._updateBindData()
}
},
onDataChange() {
this.$emit('datachange')
},
onSelectedChange(node, isleaf) {
if (isleaf) {
this._dispatchEvent()
}
if (node) {
this.$emit('nodeclick', node)
} }
}, }
_dispatchEvent() {
this.$emit('change', this.selected.slice(0))
}
}
}
</script> </script>
<style scoped> <style scoped>
.uni-data-pickerview { .uni-data-pickerview {
flex: 1; flex: 1;
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
display: flex; display: flex;
/* #endif */ /* #endif */
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
height: 100%; height: 100%;
} }
.error-text { .error-text {
color: #DD524D; color: #DD524D;
} }
.loading-cover { .loading-cover {
position: absolute; position: absolute;
left: 0; left: 0;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
background-color: rgba(255, 255, 255, .5); background-color: rgba(255, 255, 255, .5);
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
display: flex; display: flex;
/* #endif */ /* #endif */
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
z-index: 1001; z-index: 1001;
} }
.load-more { .load-more {
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
margin: auto; margin: auto;
/* #endif */ /* #endif */
} }
.error-message { .error-message {
background-color: #fff; background-color: #fff;
position: absolute; position: absolute;
left: 0; left: 0;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
padding: 15px; padding: 15px;
opacity: .9; opacity: .9;
z-index: 102; z-index: 102;
} }
/* #ifdef APP-NVUE */ /* #ifdef APP-NVUE */
.selected-area { .selected-area {
width: 750rpx; width: 750rpx;
} }
/* #endif */ /* #endif */
.selected-list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: nowrap;
padding: 0 5px;
border-bottom: 1px solid #f8f8f8;
}
.selected-list { .selected-item {
/* #ifndef APP-NVUE */ margin-left: 10px;
display: flex; margin-right: 10px;
/* #endif */ padding: 12px 0;
flex-direction: row; text-align: center;
flex-wrap: nowrap; /* #ifndef APP-NVUE */
padding: 0 5px; white-space: nowrap;
border-bottom: 1px solid #f8f8f8; /* #endif */
} }
.selected-item { .selected-item-text-overflow {
margin-left: 10px; width: 168px;
margin-right: 10px; /* fix nvue */
padding: 12px 0; overflow: hidden;
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
width: 6em;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
/* #endif */ /* #endif */
} }
.selected-item-active { .selected-item-active {
border-bottom: 2px solid #007aff; border-bottom: 2px solid #007aff;
} }
.selected-item-text { .selected-item-text {
color: #007aff; color: #007aff;
} }
.tab-c { .tab-c {
position: relative; position: relative;
flex: 1; flex: 1;
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
display: flex; display: flex;
/* #endif */ /* #endif */
flex-direction: row; flex-direction: row;
overflow: hidden; overflow: hidden;
} }
.list { .list {
flex: 1; flex: 1;
} }
.item { .item {
padding: 12px 15px; padding: 12px 15px;
border-bottom: 1px solid #f0f0f0; border-bottom: 1px solid #f0f0f0;
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
display: flex; display: flex;
/* #endif */ /* #endif */
flex-direction: row; flex-direction: row;
} justify-content: space-between;
}
.is-disabled { .is-disabled {
opacity: .5; opacity: .5;
} }
.item-text { .item-text {
flex: 1; /* flex: 1; */
color: #333333; color: #333333;
} }
.check { .item-text-overflow {
margin-right: 5px; width: 280px;
border: 2px solid #007aff; /* fix nvue */
border-left: 0; overflow: hidden;
border-top: 0; /* #ifndef APP-NVUE */
height: 12px; width: 20em;
width: 6px; white-space: nowrap;
transform-origin: center; text-overflow: ellipsis;
/* #ifndef APP-NVUE */ -o-text-overflow: ellipsis;
transition: all 0.3s; /* #endif */
/* #endif */ }
transform: rotate(45deg);
} .check {
</style> margin-right: 5px;
border: 2px solid #007aff;
border-left: 0;
border-top: 0;
height: 12px;
width: 6px;
transform-origin: center;
/* #ifndef APP-NVUE */
transition: all 0.3s;
/* #endif */
transform: rotate(45deg);
}
</style>
{ {
"id": "uni-data-picker", "id": "uni-data-picker",
"displayName": "uni-data-picker 数据驱动的picker选择器", "displayName": "uni-data-picker 数据驱动的picker选择器",
"version": "0.4.0", "version": "0.4.9",
"description": "Picker选择器", "description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
"keywords": [ "keywords": [
"uni-ui", "uni-ui",
"uniui", "uniui",
...@@ -43,7 +43,8 @@ ...@@ -43,7 +43,8 @@
}, },
"uni_modules": { "uni_modules": {
"dependencies": [ "dependencies": [
"uni-load-more" "uni-load-more",
"uni-icons"
], ],
"encrypt": [], "encrypt": [],
"platforms": { "platforms": {
...@@ -79,6 +80,10 @@ ...@@ -79,6 +80,10 @@
"快应用": { "快应用": {
"华为": "u", "华为": "u",
"联盟": "u" "联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
} }
} }
} }
......
...@@ -23,14 +23,9 @@ ...@@ -23,14 +23,9 @@
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。 > 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
> - 组件需要依赖 `sass` 插件 ,请自行手动安装 > - 组件需要依赖 `sass` 插件 ,请自行手动安装
> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 > - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
> - `<uni-data-picker>` 内部包含了弹出层组件 `<uni-data-pickerview>` 外层的布局可能会影响弹出层,[详情](https://developer.mozilla.org/zh-Hans/docs/Web/CSS/Common_CSS_Questions) > - `<uni-data-picker>` 内部包含了弹出层组件 `<uni-data-pickerview>` 外层的布局可能会影响弹出层,[详情](https://developer.mozilla.org/zh-CN/docs/Web/CSS/Common_CSS_Questions)
### 平台差异说明
暂不支持在nvue页面中使用
### 安装方式 ### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`componets` 本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`componets`
...@@ -44,9 +39,12 @@ ...@@ -44,9 +39,12 @@
|属性名 | 类型 | 可选值 | 默认值 | 说明| |属性名 | 类型 | 可选值 | 默认值 | 说明|
|:-: | :-: |:-: | :-: | :-: | |:-: | :-: |:-: | :-: | :-: |
|v-model |String/ Number | - | - |绑定数据| |v-model |String/ Number | - | - |绑定数据|
|spaceInfo |Object | | |服务空间配置,[详情](https://uniapp.dcloud.net.cn/uniCloud/init)|
|localdata |Array | | |数据,[详情](https://gitee.com/dcloud/datacom)| |localdata |Array | | |数据,[详情](https://gitee.com/dcloud/datacom)|
|preload |Boolean | true/false | false |预加载数据| |preload |Boolean | true/false | false |预加载数据|
|readonly |Boolean | true/false | false |是否禁用| |readonly |Boolean | true/false | false |是否禁用|
|clear-icon |Boolean | true/false | true |是否显示清除按钮|
|ellipsis |Boolean | true/false | true |是否隐藏 tab 标签过长的文本|
|step-searh |Boolean | true/false | true |分步查询时,点击节点请求数据| |step-searh |Boolean | true/false | true |分步查询时,点击节点请求数据|
|step-search-url |String | | |分步查询时,动态加载云端数据url格式,`https://xxx.com/{parentValue}`(当前版本暂不支持,下版支持)| |step-search-url |String | | |分步查询时,动态加载云端数据url格式,`https://xxx.com/{parentValue}`(当前版本暂不支持,下版支持)|
|self-field |String | | |分步查询时当前字段名称| |self-field |String | | |分步查询时当前字段名称|
...@@ -56,7 +54,7 @@ ...@@ -56,7 +54,7 @@
|where |String | | |查询条件,内容较多,另见jql文档:[详情](https://uniapp.dcloud.net.cn/uniCloud/uni-clientDB?id=jsquery)| |where |String | | |查询条件,内容较多,另见jql文档:[详情](https://uniapp.dcloud.net.cn/uniCloud/uni-clientDB?id=jsquery)|
|orderby |String | | |排序字段及正序倒叙设置| |orderby |String | | |排序字段及正序倒叙设置|
|popup-title |String | | |弹出层标题| |popup-title |String | | |弹出层标题|
|map |Object | |{text:'text',value:'value'}|字段映射,将text/value映射到数据中的其他字段|
> **** > ****
> `collection/where/orderby` 和 `<unicloud-db>` 的用法一致,[详情](https://uniapp.dcloud.net.cn/uniCloud/unicloud-db) > `collection/where/orderby` 和 `<unicloud-db>` 的用法一致,[详情](https://uniapp.dcloud.net.cn/uniCloud/unicloud-db)
...@@ -73,6 +71,24 @@ ...@@ -73,6 +71,24 @@
|@popupopened |EventHandle | 弹出层弹出时触发 | |@popupopened |EventHandle | 弹出层弹出时触发 |
|@popupclosed |EventHandle | 弹出层关闭时触发 | |@popupclosed |EventHandle | 弹出层关闭时触发 |
### DataPicker Methods
|方法称名 |说明|参数|
|:-:|:-:|:-:|
|show|打开弹出层|-|
|hide|关闭弹出层|-|
|clear|清除已选项|-|
**使用方法:**
```js
this.$refs.picker.show() // `picker` 为组件的 ref 名称
```
### DataPicker Slots
|名称|说明|
|:-:|:-:|
|default|覆盖显示框内容|
### 基本用法 ### 基本用法
......
## 2.1.4(2021-09-10)
- 修复 hide-second 在移动端的 bug
- 修复 单选赋默认值时,赋值日期未高亮的 bug
- 修复 赋默认值时,移动端未正确显示时间的 bug
## 2.1.3(2021-09-09)
- 新增 hide-second 属性,支持只使用时分,隐藏秒
## 2.1.2(2021-09-03)
- 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次
- 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法
- 优化 调整字号大小,美化日历界面
- 修复 因国际化导致的 placeholder 失效的 bug
## 2.1.1(2021-08-24) ## 2.1.1(2021-08-24)
- 新增 支持国际化 - 新增 支持国际化
- 优化 范围选择器在 pc 端过宽的问题 - 优化 范围选择器在 pc 端过宽的问题
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
}" @click="choiceDate(weeks)" @mouseenter="handleMousemove(weeks)"> }" @click="choiceDate(weeks)" @mouseenter="handleMousemove(weeks)">
<view class="uni-calendar-item__weeks-box-item" :class="{ <view class="uni-calendar-item__weeks-box-item" :class="{
'uni-calendar-item--isDay-text': weeks.isDay, 'uni-calendar-item--isDay-text': weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay, 'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && (calendar.userChecked || !checkHover),
'uni-calendar-item--checked-range-text': checkHover, 'uni-calendar-item--checked-range-text': checkHover,
'uni-calendar-item--before-checked':weeks.beforeMultiple, 'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple, 'uni-calendar-item--multiple': weeks.multiple,
...@@ -16,9 +16,6 @@ ...@@ -16,9 +16,6 @@
}"> }">
<text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text> <text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
<text class="uni-calendar-item__weeks-box-text">{{weeks.date}}</text> <text class="uni-calendar-item__weeks-box-text">{{weeks.date}}</text>
<!-- <text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uni-calendar-item__weeks-lunar-text">今天</text>
<text v-if="lunar&&!weeks.extraInfo" class="uni-calendar-item__weeks-lunar-text" >{{weeks.isDay?'今天': (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text> -->
<!-- <text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uni-calendar-item__weeks-lunar-text">{{weeks.extraInfo.info}}</text> -->
</view> </view>
</view> </view>
</template> </template>
...@@ -47,18 +44,18 @@ ...@@ -47,18 +44,18 @@
lunar: { lunar: {
type: Boolean, type: Boolean,
default: false default: false
}, },
checkHover: { checkHover: {
type: Boolean, type: Boolean,
default: false default: false
} }
}, },
methods: { methods: {
choiceDate(weeks) { choiceDate(weeks) {
this.$emit('change', weeks) this.$emit('change', weeks)
}, },
handleMousemove(weeks) { handleMousemove(weeks) {
this.$emit('handleMouse', weeks) this.$emit('handleMouse', weeks)
} }
} }
} }
...@@ -72,12 +69,13 @@ ...@@ -72,12 +69,13 @@
/* #endif */ /* #endif */
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
margin: 3px 0; margin: 3px 0;
} }
.uni-calendar-item__weeks-box-text { .uni-calendar-item__weeks-box-text {
font-size: $uni-font-size-base; font-size: 12px;
// font-size: $uni-font-size-base;
// color: $uni-text-color; // color: $uni-text-color;
} }
...@@ -94,13 +92,13 @@ ...@@ -94,13 +92,13 @@
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
width: 43px; width: 40px;
height: 43px; height: 40px;
/* #ifdef H5 */ /* #ifdef H5 */
cursor: pointer; cursor: pointer;
/* #endif */ /* #endif */
} }
.uni-calendar-item__weeks-box-circle { .uni-calendar-item__weeks-box-circle {
position: absolute; position: absolute;
...@@ -115,12 +113,12 @@ ...@@ -115,12 +113,12 @@
.uni-calendar-item__weeks-box .uni-calendar-item--disable { .uni-calendar-item__weeks-box .uni-calendar-item--disable {
// background-color: rgba(249, 249, 249, $uni-opacity-disabled); // background-color: rgba(249, 249, 249, $uni-opacity-disabled);
color: $uni-text-color-disable; color: $uni-text-color-disable;
cursor: default; cursor: default;
} }
.uni-calendar-item--isDay-text { .uni-calendar-item__weeks-box .uni-calendar-item--isDay-text {
color: $uni-color-primary !important; color: $uni-color-primary;
} }
.uni-calendar-item--isDay { .uni-calendar-item--isDay {
...@@ -134,17 +132,17 @@ ...@@ -134,17 +132,17 @@
opacity: 0.8; opacity: 0.8;
} }
.uni-calendar-item--checked { .uni-calendar-item__weeks-box .uni-calendar-item--checked {
background-color: $uni-color-primary; background-color: $uni-color-primary;
// border-radius: 50%; // border-radius: 50%;
box-sizing: border-box; box-sizing: border-box;
border: 6px solid #f2f6fc; border: 6px solid #f2f6fc;
color: #fff; color: #fff;
opacity: 0.8; opacity: 0.8;
} }
.uni-calendar-item--multiple .uni-calendar-item--checked-range-text { .uni-calendar-item--multiple .uni-calendar-item--checked-range-text {
color: #333; color: #333;
} }
.uni-calendar-item--multiple { .uni-calendar-item--multiple {
...@@ -155,29 +153,29 @@ ...@@ -155,29 +153,29 @@
.uni-calendar-item--multiple .uni-calendar-item--before-checked { .uni-calendar-item--multiple .uni-calendar-item--before-checked {
background-color: #409eff; background-color: #409eff;
color: #fff !important; color: #fff !important;
// border-radius: 50%; // border-radius: 50%;
box-sizing: border-box; box-sizing: border-box;
border: 6px solid #f2f6fc; border: 6px solid #f2f6fc;
} }
.uni-calendar-item--multiple .uni-calendar-item--after-checked { .uni-calendar-item--multiple .uni-calendar-item--after-checked {
background-color: #409eff;; background-color: #409eff;;
color: #fff !important; color: #fff !important;
// border-radius: 50%; // border-radius: 50%;
box-sizing: border-box; box-sizing: border-box;
border: 6px solid #f2f6fc; border: 6px solid #f2f6fc;
} }
.uni-calendar-item--before-checked-x { .uni-calendar-item--before-checked-x {
// border-top-left-radius: 25px; // border-top-left-radius: 25px;
// border-bottom-left-radius: 25px; // border-bottom-left-radius: 25px;
background-color: #f2f6fc; background-color: #f2f6fc;
} }
.uni-calendar-item--after-checked-x { .uni-calendar-item--after-checked-x {
// border-top-right-radius: 25px; // border-top-right-radius: 25px;
// border-bottom-right-radius: 25px; // border-bottom-right-radius: 25px;
background-color: #f2f6fc; background-color: #f2f6fc;
} }
</style> </style>
...@@ -10,8 +10,7 @@ ...@@ -10,8 +10,7 @@
<view class="uni-calendar__header-btn uni-calendar--left"></view> <view class="uni-calendar__header-btn uni-calendar--left"></view>
</view> </view>
<picker mode="date" :value="date" fields="month" @change="bindDateChange"> <picker mode="date" :value="date" fields="month" @change="bindDateChange">
<text <text class="uni-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
class="uni-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
</picker> </picker>
<view v-if="right" class="uni-calendar__header-btn-box" @click.stop="next"> <view v-if="right" class="uni-calendar__header-btn-box" @click.stop="next">
<view class="uni-calendar__header-btn uni-calendar--right"></view> <view class="uni-calendar__header-btn uni-calendar--right"></view>
...@@ -56,29 +55,29 @@ ...@@ -56,29 +55,29 @@
</view> </view>
</view> </view>
<view v-if="!insert && !range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top" <view v-if="!insert && !range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top"
style="padding: 0 40px;"> style="padding: 0 80px;">
<text class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</text> <view class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</view>
<time-picker type="time" :start="reactStartTime" :end="reactEndTime" v-model="time" <time-picker type="time" :start="reactStartTime" :end="reactEndTime" v-model="time"
:disabled="!tempSingleDate" :border="false" class="time-picker-style"> :disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style">
</time-picker> </time-picker>
</view> </view>
<view v-if="!insert && range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top"> <view v-if="!insert && range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top">
<view class="uni-date-changed--time-start"> <view class="uni-date-changed--time-start">
<text class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}}</text> <view class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}}
<time-picker type="time" :start="reactStartTime" v-model="timeRange.startTime" :border="false" </view>
<time-picker type="time" :start="reactStartTime" v-model="timeRange.startTime" :border="false" :hide-second="hideSecond"
:disabled="!tempRange.before" class="time-picker-style"> :disabled="!tempRange.before" class="time-picker-style">
</time-picker> </time-picker>
</view> </view>
<uni-icons type="arrowthinright" color="#999" style="line-height: 50px;"></uni-icons> <uni-icons type="arrowthinright" color="#999" style="line-height: 50px;"></uni-icons>
<view class="uni-date-changed--time-end"> <view class="uni-date-changed--time-end">
<text class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : endDateText}}</text> <view class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : endDateText}}</view>
<time-picker type="time" :end="reactEndTime" v-model="timeRange.endTime" :border="false" <time-picker type="time" :end="reactEndTime" v-model="timeRange.endTime" :border="false" :hide-second="hideSecond"
:disabled="!tempRange.after" class="time-picker-style"> :disabled="!tempRange.after" class="time-picker-style">
</time-picker> </time-picker>
</view> </view>
</view> </view>
<view v-if="!insert" class="uni-date-changed uni-calendar__header" @click="confirm"> <view v-if="!insert" class="uni-date-changed uni-calendar__header" @click="confirm">
<view class="uni-calendar__header-btn-box"> <view class="uni-calendar__header-btn-box">
<text class="uni-calendar__button-text uni-calendar--fixed-width">{{okText}}</text> <text class="uni-calendar__button-text uni-calendar--fixed-width">{{okText}}</text>
...@@ -96,7 +95,9 @@ ...@@ -96,7 +95,9 @@
initVueI18n initVueI18n
} from '@dcloudio/uni-i18n' } from '@dcloudio/uni-i18n'
import messages from './i18n/index.js' import messages from './i18n/index.js'
const { t } = initVueI18n(messages) const {
t
} = initVueI18n(messages)
/** /**
* Calendar 日历 * Calendar 日历
* @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等 * @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
...@@ -186,6 +187,10 @@ ...@@ -186,6 +187,10 @@
checkHover: { checkHover: {
type: Boolean, type: Boolean,
default: true default: true
},
hideSecond: {
type: [Boolean],
default: false
}, },
pleStatus: { pleStatus: {
type: Object, type: Object,
...@@ -207,12 +212,12 @@ ...@@ -207,12 +212,12 @@
nowDate: '', nowDate: '',
aniMaskShow: false, aniMaskShow: false,
firstEnter: true, firstEnter: true,
time: this.defTime ? this.defTime : '', time: '',
timeRange: { timeRange: {
startTime: this.defTime.start ? this.defTime.start : '', startTime: '',
endTime: this.defTime.end ? this.defTime.end : '' endTime: ''
}, },
tempSingleDate: this.date, tempSingleDate: '',
tempRange: { tempRange: {
before: '', before: '',
after: '' after: ''
...@@ -223,11 +228,25 @@ ...@@ -223,11 +228,25 @@
date: { date: {
immediate: true, immediate: true,
handler(newVal, oldVal) { handler(newVal, oldVal) {
if (!this.range) if (!this.range) {
setTimeout(() => { this.tempSingleDate = newVal
this.init(newVal) setTimeout(() => {
}, 100) this.init(newVal)
}, 100)
}
} }
},
defTime: {
immediate: true,
handler(newVal, oldVal) {
if (!this.range) {
this.time = newVal
} else {
// console.log('-----', newVal);
this.timeRange.startTime = newVal.start
this.timeRange.endTime = newVal.end
}
}
}, },
startDate(val) { startDate(val) {
this.cale.resetSatrtDate(val) this.cale.resetSatrtDate(val)
...@@ -261,8 +280,7 @@ ...@@ -261,8 +280,7 @@
this.cale.lastHover = true this.cale.lastHover = true
if (this.rangeWithinMonth(after, before)) return if (this.rangeWithinMonth(after, before)) return
this.setDate(before) this.setDate(before)
} } else {
if (!before && !after) {
this.cale.setMultiple(fulldate) this.cale.setMultiple(fulldate)
this.setDate(this.nowDate.fullDate) this.setDate(this.nowDate.fullDate)
this.calendar.fullDate = '' this.calendar.fullDate = ''
...@@ -380,9 +398,26 @@ ...@@ -380,9 +398,26 @@
this.close() this.close()
}, },
clearCalender() {
if (this.range) {
this.timeRange.startTime = ''
this.timeRange.endTime = ''
this.tempRange.before = ''
this.tempRange.after = ''
this.cale.multipleStatus.before = ''
this.cale.multipleStatus.after = ''
this.cale.multipleStatus.data = []
this.cale.lastHover = false
} else {
this.time = ''
this.tempSingleDate = ''
}
this.calendar.fullDate = ''
this.setDate()
},
bindDateChange(e) { bindDateChange(e) {
const value = e.detail.value + '-1' const value = e.detail.value + '-1'
console.log(this.cale.getDate(value));
this.init(value) this.init(value)
}, },
/** /**
...@@ -494,6 +529,7 @@ ...@@ -494,6 +529,7 @@
choiceDate(weeks) { choiceDate(weeks) {
if (weeks.disable) return if (weeks.disable) return
this.calendar = weeks this.calendar = weeks
this.calendar.userChecked = true
// 设置多选 // 设置多选
this.cale.setMultiple(this.calendar.fullDate, true) this.cale.setMultiple(this.calendar.fullDate, true)
this.weeks = this.cale.weeks this.weeks = this.cale.weeks
...@@ -506,7 +542,6 @@ ...@@ -506,7 +542,6 @@
* 回到今天 * 回到今天
*/ */
backtoday() { backtoday() {
console.log(this.cale.getDate(new Date()).fullDate);
let date = this.cale.getDate(new Date()).fullDate let date = this.cale.getDate(new Date()).fullDate
// this.cale.setDate(date) // this.cale.setDate(date)
this.init(date) this.init(date)
...@@ -678,14 +713,14 @@ ...@@ -678,14 +713,14 @@
} }
.uni-calendar__header-btn { .uni-calendar__header-btn {
width: 10px; width: 8px;
height: 10px; height: 8px;
border-left-color: $uni-text-color-placeholder; border-left-color: $uni-text-color-placeholder;
border-left-style: solid; border-left-style: solid;
border-left-width: 2px; border-left-width: 1px;
border-top-color: $uni-color-subtitle; border-top-color: $uni-color-subtitle;
border-top-style: solid; border-top-style: solid;
border-top-width: 2px; border-top-width: 1px;
} }
.uni-calendar--left { .uni-calendar--left {
...@@ -717,14 +752,14 @@ ...@@ -717,14 +752,14 @@
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 45px; height: 40px;
border-bottom-color: #F5F5F5; border-bottom-color: #F5F5F5;
border-bottom-style: solid; border-bottom-style: solid;
border-bottom-width: 1px; border-bottom-width: 1px;
} }
.uni-calendar__weeks-day-text { .uni-calendar__weeks-day-text {
font-size: 14px; font-size: 12px;
} }
.uni-calendar__box { .uni-calendar__box {
...@@ -783,11 +818,12 @@ ...@@ -783,11 +818,12 @@
.uni-date-changed--time-date { .uni-date-changed--time-date {
color: #999; color: #999;
line-height: 50px; line-height: 50px;
margin-right: 5px;
// opacity: 0.6; // opacity: 0.6;
} }
.time-picker-style { .time-picker-style {
width: 62px; // width: 62px;
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
display: flex; display: flex;
/* #endif */ /* #endif */
...@@ -798,4 +834,4 @@ ...@@ -798,4 +834,4 @@
.mr-10 { .mr-10 {
margin-right: 10px; margin-right: 10px;
} }
</style> </style>
...@@ -124,7 +124,7 @@ ...@@ -124,7 +124,7 @@
// 输入框当前时间 // 输入框当前时间
time: '', time: '',
// 当前的年月日时分秒 // 当前的年月日时分秒
year: 1900, year: 1920,
month: 0, month: 0,
day: 0, day: 0,
hour: 0, hour: 0,
...@@ -190,7 +190,8 @@ ...@@ -190,7 +190,8 @@
if (newVal) { if (newVal) {
this.parseValue(this.fixIosDateFormat(newVal)) //兼容 iOS、safari 日期格式 this.parseValue(this.fixIosDateFormat(newVal)) //兼容 iOS、safari 日期格式
this.initTime(false) this.initTime(false)
} else { } else {
this.time = ''
this.parseValue(Date.now()) this.parseValue(Date.now())
} }
}, },
...@@ -538,7 +539,9 @@ ...@@ -538,7 +539,9 @@
* @param {Object} defaultTime * @param {Object} defaultTime
*/ */
parseValue(value) { parseValue(value) {
if (!value) return if (!value) {
return
}
if (this.type === 'time' && typeof value === "string") { if (this.type === 'time' && typeof value === "string") {
this.parseTimeType(value) this.parseTimeType(value)
} else { } else {
...@@ -576,7 +579,7 @@ ...@@ -576,7 +579,7 @@
this.startSecond = 0 this.startSecond = 0
} }
if (pointType === 'end') { if (pointType === 'end') {
this.endYear = 120 this.endYear = 2120
this.endMonth = 12 this.endMonth = 12
this.endDay = 31 this.endDay = 31
this.endHour = 23 this.endHour = 23
...@@ -770,7 +773,7 @@ ...@@ -770,7 +773,7 @@
<style> <style>
.uni-datetime-picker { .uni-datetime-picker {
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
width: 100%; /* width: 100%; */
/* #endif */ /* #endif */
} }
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
<view class="uni-date__icon-logo"> <view class="uni-date__icon-logo">
<image class="uni-date-editor--logo" :src="iconBase64" mode=""></image> <image class="uni-date-editor--logo" :src="iconBase64" mode=""></image>
</view> </view>
<input class="uni-date__x-input" type="text" v-model="singleVal" :placeholder="singlePlaceholderText" <input class="uni-date__x-input" type="text" v-model="singleVal"
:disabled="true" /> :placeholder="singlePlaceholderText" :disabled="true" />
</view> </view>
<view v-else class="uni-date-x uni-date-range"> <view v-else class="uni-date-x uni-date-range">
<view class="uni-date__icon-logo"> <view class="uni-date__icon-logo">
...@@ -23,8 +23,7 @@ ...@@ -23,8 +23,7 @@
<input class="uni-date__x-input t-c" type="text" v-model="range.endDate" <input class="uni-date__x-input t-c" type="text" v-model="range.endDate"
:placeholder="endPlaceholderText" :disabled="true" /> :placeholder="endPlaceholderText" :disabled="true" />
</view> </view>
<view <view v-show="clearIcon && !disabled && (singleVal || (range.startDate && range.endDate))"
v-show="clearIcon && !disabled && !isPhone && (singleVal || (range.startDate && range.endDate))"
class="uni-date__icon-clear" @click.stop="clear"> class="uni-date__icon-clear" @click.stop="clear">
<uni-icons type="clear" color="#e1e1e1" size="14"></uni-icons> <uni-icons type="clear" color="#e1e1e1" size="14"></uni-icons>
</view> </view>
...@@ -39,12 +38,14 @@ ...@@ -39,12 +38,14 @@
<input class="uni-date__input t-c" type="text" v-model="tempSingleDate" <input class="uni-date__input t-c" type="text" v-model="tempSingleDate"
:placeholder="selectDateText" /> :placeholder="selectDateText" />
<time-picker type="time" v-model="time" :border="false" :disabled="!tempSingleDate" <time-picker type="time" v-model="time" :border="false" :disabled="!tempSingleDate"
:start="reactStartTime" :end="reactEndTime"> :start="reactStartTime" :end="reactEndTime" :hideSecond="hideSecond" style="width: 100%;">
<input class="uni-date__input t-c" type="text" v-model="time" :placeholder="selectTimeText" :disabled="!tempSingleDate" /> <input class="uni-date__input t-c" type="text" v-model="time" :placeholder="selectTimeText"
:disabled="!tempSingleDate" />
</time-picker> </time-picker>
</view> </view>
<calendar ref="pcSingle" class="uni-date_calendar-pc" :showMonth="false" :start-date="caleRange.startDate" <calendar ref="pcSingle" class="uni-date_calendar-pc" :showMonth="false"
:end-date="caleRange.endDate" :date="defSingleDate" @change="singleChange" /> :start-date="caleRange.startDate" :end-date="caleRange.endDate" :date="defSingleDate"
@change="singleChange" />
<view v-if="hasTime" class="popup-x-footer"> <view v-if="hasTime" class="popup-x-footer">
<!-- <text class="">此刻</text> --> <!-- <text class="">此刻</text> -->
<text class="confirm" @click="confirmSingleChange">{{okText}}</text> <text class="confirm" @click="confirmSingleChange">{{okText}}</text>
...@@ -58,9 +59,10 @@ ...@@ -58,9 +59,10 @@
<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.startDate" <input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.startDate"
:placeholder="startDateText" /> :placeholder="startDateText" />
<time-picker type="time" v-model="tempRange.startTime" :start="reactStartTime" :border="false" <time-picker type="time" v-model="tempRange.startTime" :start="reactStartTime" :border="false"
:disabled="!tempRange.startDate"> :disabled="!tempRange.startDate" :hideSecond="hideSecond">
<input class="uni-date__input uni-date-range__input" type="text" <input class="uni-date__input uni-date-range__input" type="text"
v-model="tempRange.startTime" :placeholder="startTimeText" :disabled="!tempRange.startDate" /> v-model="tempRange.startTime" :placeholder="startTimeText"
:disabled="!tempRange.startDate" />
</time-picker> </time-picker>
</view> </view>
<uni-icons type="arrowthinright" color="#999" style="line-height: 40px;"></uni-icons> <uni-icons type="arrowthinright" color="#999" style="line-height: 40px;"></uni-icons>
...@@ -68,19 +70,20 @@ ...@@ -68,19 +70,20 @@
<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endDate" <input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endDate"
:placeholder="endDateText" /> :placeholder="endDateText" />
<time-picker type="time" v-model="tempRange.endTime" :end="reactEndTime" :border="false" <time-picker type="time" v-model="tempRange.endTime" :end="reactEndTime" :border="false"
:disabled="!tempRange.endDate"> :disabled="!tempRange.endDate" :hideSecond="hideSecond">
<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endTime" <input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endTime"
:placeholder="endTimeText" :disabled="!tempRange.endDate" /> :placeholder="endTimeText" :disabled="!tempRange.endDate" />
</time-picker> </time-picker>
</view> </view>
</view> </view>
<view class="popup-x-body"> <view class="popup-x-body">
<calendar ref="left" class="uni-date_calendar-pc" :showMonth="false" :start-date="caleRange.startDate" <calendar ref="left" class="uni-date_calendar-pc" :showMonth="false"
:end-date="caleRange.endDate" :range="true" @change="leftChange" :pleStatus="endMultipleStatus" :start-date="caleRange.startDate" :end-date="caleRange.endDate" :range="true"
@firstEnterCale="updateRightCale" @monthSwitch="leftMonthSwitch" /> @change="leftChange" :pleStatus="endMultipleStatus" @firstEnterCale="updateRightCale"
<calendar ref="right" class="uni-date_calendar-pc" :showMonth="false" :start-date="caleRange.startDate" @monthSwitch="leftMonthSwitch" />
:end-date="caleRange.endDate" :range="true" @change="rightChange" <calendar ref="right" class="uni-date_calendar-pc" :showMonth="false"
:pleStatus="startMultipleStatus" @firstEnterCale="updateLeftCale" :start-date="caleRange.startDate" :end-date="caleRange.endDate" :range="true"
@change="rightChange" :pleStatus="startMultipleStatus" @firstEnterCale="updateLeftCale"
@monthSwitch="rightMonthSwitch" style="border-left: 1px solid #F1F1F1;" /> @monthSwitch="rightMonthSwitch" style="border-left: 1px solid #F1F1F1;" />
</view> </view>
<view v-if="hasTime" class="popup-x-footer"> <view v-if="hasTime" class="popup-x-footer">
...@@ -92,7 +95,7 @@ ...@@ -92,7 +95,7 @@
<calendar v-if="isPhone" ref="mobile" :clearDate="false" :date="defSingleDate" :defTime="reactMobDefTime" <calendar v-if="isPhone" ref="mobile" :clearDate="false" :date="defSingleDate" :defTime="reactMobDefTime"
:start-date="caleRange.startDate" :end-date="caleRange.endDate" :selectableTimes="mobSelectableTime" :start-date="caleRange.startDate" :end-date="caleRange.endDate" :selectableTimes="mobSelectableTime"
:pleStatus="endMultipleStatus" :showMonth="false" :range="isRange" :typeHasTime="hasTime" :insert="false" :pleStatus="endMultipleStatus" :showMonth="false" :range="isRange" :typeHasTime="hasTime" :insert="false"
@confirm="mobileChange" /> :hideSecond="hideSecond" @confirm="mobileChange" />
</view> </view>
</template> </template>
<script> <script>
...@@ -119,7 +122,9 @@ ...@@ -119,7 +122,9 @@
initVueI18n initVueI18n
} from '@dcloudio/uni-i18n' } from '@dcloudio/uni-i18n'
import messages from './i18n/index.js' import messages from './i18n/index.js'
const { t } = initVueI18n(messages) const {
t
} = initVueI18n(messages)
export default { export default {
name: 'UniDatetimePicker', name: 'UniDatetimePicker',
...@@ -230,6 +235,10 @@ ...@@ -230,6 +235,10 @@
clearIcon: { clearIcon: {
type: [Boolean], type: [Boolean],
default: true default: true
},
hideSecond: {
type: [Boolean],
default: false
} }
}, },
watch: { watch: {
...@@ -300,11 +309,12 @@ ...@@ -300,11 +309,12 @@
const res = activeDate === this.caleRange.endDate ? this.caleRange.endTime : '' const res = activeDate === this.caleRange.endDate ? this.caleRange.endTime : ''
return res return res
}, },
reactMobDefTime() { reactMobDefTime() {
return this.isRange ? { const times = {
start: this.tempRange.startTime, start: this.tempRange.startTime,
end: this.tempRange.endTime end: this.tempRange.endTime
} : this.time }
return this.isRange ? times : this.time
}, },
mobSelectableTime() { mobSelectableTime() {
return { return {
...@@ -321,7 +331,8 @@ ...@@ -321,7 +331,8 @@
* for i18n * for i18n
*/ */
singlePlaceholderText() { singlePlaceholderText() {
return this.placeholder || this.type === 'date' ? this.selectDateText : t("uni-datetime-picker.selectDateTime") return this.placeholder || (this.type === 'date' ? this.selectDateText : t(
"uni-datetime-picker.selectDateTime"))
}, },
startPlaceholderText() { startPlaceholderText() {
return this.startPlaceholder || this.startDateText return this.startPlaceholder || this.startDateText
...@@ -366,7 +377,7 @@ ...@@ -366,7 +377,7 @@
// } // }
}, },
mounted() { mounted() {
this.platform() this.platform()
}, },
methods: { methods: {
/** /**
...@@ -426,7 +437,7 @@ ...@@ -426,7 +437,7 @@
}) })
this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, defaultRange, { this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, defaultRange, {
which: 'left' which: 'left'
}) })
} }
}, },
updateLeftCale(e) { updateLeftCale(e) {
...@@ -671,11 +682,12 @@ ...@@ -671,11 +682,12 @@
clear(needEmit = true) { clear(needEmit = true) {
if (!this.isRange) { if (!this.isRange) {
this.singleVal = '' this.singleVal = ''
this.tempSingleDate = ''
this.time = ''
if (this.isPhone) { if (this.isPhone) {
this.defSingleDate = '' this.$refs.mobile.clearCalender()
} else { } else {
this.$refs.pcSingle.calendar.fullDate = '' this.$refs.pcSingle.clearCalender()
this.$refs.pcSingle.setDate()
} }
if (needEmit) { if (needEmit) {
this.formItem && this.formItem.setValue('') this.formItem && this.formItem.setValue('')
...@@ -686,27 +698,15 @@ ...@@ -686,27 +698,15 @@
} else { } else {
this.range.startDate = '' this.range.startDate = ''
this.range.endDate = '' this.range.endDate = ''
this.tempRange = {} this.tempRange.startDate= ''
this.tempRange.startTime= ''
this.tempRange.endDate= ''
this.tempRange.endTime= ''
if (this.isPhone) { if (this.isPhone) {
this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, { this.$refs.mobile.clearCalender()
before: '',
after: '',
data: [],
fulldate: ''
}, {
which: 'left'
})
} else { } else {
this.$refs.left.cale.multipleStatus.before = '' this.$refs.left.clearCalender()
this.$refs.left.cale.multipleStatus.after = '' this.$refs.right.clearCalender()
this.$refs.left.cale.multipleStatus.data = []
this.$refs.left.cale.lastHover = false
this.$refs.left.setDate()
this.$refs.right.cale.multipleStatus.before = ''
this.$refs.right.cale.multipleStatus.after = ''
this.$refs.right.cale.multipleStatus.data = []
this.$refs.right.cale.lastHover = false
this.$refs.right.setDate()
this.$refs.right.next() this.$refs.right.next()
} }
if (needEmit) { if (needEmit) {
...@@ -728,7 +728,7 @@ ...@@ -728,7 +728,7 @@
const minute = defVal.getMinutes() const minute = defVal.getMinutes()
const second = defVal.getSeconds() const second = defVal.getSeconds()
const defDate = year + '-' + this.lessTen(month) + '-' + this.lessTen(day) const defDate = year + '-' + this.lessTen(month) + '-' + this.lessTen(day)
const defTime = this.lessTen(hour) + ':' + this.lessTen(minute) + ':' + this.lessTen(second) const defTime = this.lessTen(hour) + ':' + this.lessTen(minute) + (this.hideSecond ? '' : (':' + this.lessTen(second)))
return { return {
defDate, defDate,
defTime defTime
...@@ -798,12 +798,12 @@ ...@@ -798,12 +798,12 @@
height: 40px; height: 40px;
width: 100%; width: 100%;
line-height: 40px; line-height: 40px;
font-size: 14px; font-size: 14px;
}
.t-c {
text-align: center;
} }
.t-c {
text-align: center;
}
.uni-date__input { .uni-date__input {
height: 40px; height: 40px;
...@@ -813,8 +813,8 @@ ...@@ -813,8 +813,8 @@
} }
.uni-date-range__input { .uni-date-range__input {
text-align: center; text-align: center;
max-width: 152px; max-width: 142px;
} }
.uni-date-picker__container { .uni-date-picker__container {
...@@ -945,6 +945,7 @@ ...@@ -945,6 +945,7 @@
.mr-50 { .mr-50 {
margin-right: 50px; margin-right: 50px;
} }
.uni-date_calendar-pc { .uni-date_calendar-pc {
padding: 0 6px; padding: 0 6px;
} }
......
...@@ -143,14 +143,14 @@ class Calendar { ...@@ -143,14 +143,14 @@ class Calendar {
let disableAfter = true let disableAfter = true
if (this.startDate) { if (this.startDate) {
// let dateCompBefore = this.dateCompare(this.startDate, fullDate) // let dateCompBefore = this.dateCompare(this.startDate, fullDate)
// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate) // disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
disableBefore = this.dateCompare(this.startDate, nowDate) disableBefore = this.dateCompare(this.startDate, nowDate)
} }
if (this.endDate) { if (this.endDate) {
// let dateCompAfter = this.dateCompare(fullDate, this.endDate) // let dateCompAfter = this.dateCompare(fullDate, this.endDate)
// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate) // disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
disableAfter = this.dateCompare(nowDate, this.endDate) disableAfter = this.dateCompare(nowDate, this.endDate)
} }
let multiples = this.multipleStatus.data let multiples = this.multipleStatus.data
let checked = false let checked = false
...@@ -175,7 +175,8 @@ class Calendar { ...@@ -175,7 +175,8 @@ class Calendar {
month: full.month, month: full.month,
lunar: this.getlunar(full.year, full.month, i), lunar: this.getlunar(full.year, full.month, i),
disable: !(disableBefore && disableAfter), disable: !(disableBefore && disableAfter),
isDay isDay,
userChecked: false
} }
if (info) { if (info) {
data.extraInfo = info data.extraInfo = info
...@@ -294,7 +295,7 @@ class Calendar { ...@@ -294,7 +295,7 @@ class Calendar {
this.lastHover = true this.lastHover = true
return return
} }
this.multipleStatus.before = '' this.multipleStatus.before = fullDate
this.multipleStatus.after = '' this.multipleStatus.after = ''
this.multipleStatus.data = [] this.multipleStatus.data = []
this.multipleStatus.fulldate = '' this.multipleStatus.fulldate = ''
...@@ -347,16 +348,16 @@ class Calendar { ...@@ -347,16 +348,16 @@ class Calendar {
*/ */
setDefaultMultiple(before, after) { setDefaultMultiple(before, after) {
this.multipleStatus.before = before this.multipleStatus.before = before
this.multipleStatus.after = after this.multipleStatus.after = after
if (before && after) { if (before && after) {
if (this.dateCompare(before, after)) { if (this.dateCompare(before, after)) {
this.multipleStatus.data = this.geDateAll(before, after); this.multipleStatus.data = this.geDateAll(before, after);
this._getWeek(after) this._getWeek(after)
} else { } else {
this.multipleStatus.data = this.geDateAll(after, before); this.multipleStatus.data = this.geDateAll(after, before);
this._getWeek(before) this._getWeek(before)
} }
} }
} }
/** /**
...@@ -405,4 +406,4 @@ class Calendar { ...@@ -405,4 +406,4 @@ class Calendar {
} }
export default Calendar export default Calendar
{ {
"id": "uni-datetime-picker", "id": "uni-datetime-picker",
"displayName": "uni-datetime-picker 日期选择器", "displayName": "uni-datetime-picker 日期选择器",
"version": "2.1.1", "version": "2.1.4",
"description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择", "description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
"keywords": [ "keywords": [
"uni-datetime-picker", "uni-datetime-picker",
...@@ -81,7 +81,7 @@ ...@@ -81,7 +81,7 @@
}, },
"Vue": { "Vue": {
"vue2": "y", "vue2": "y",
"vue3": "u" "vue3": "y"
} }
} }
} }
......
...@@ -125,13 +125,14 @@ ___点击 picker 默认值规则:___ ...@@ -125,13 +125,14 @@ ___点击 picker 默认值规则:___
|start |String、Number |- |- |最小值,可以使用日期的字符串(String)、时间戳(Number) | |start |String、Number |- |- |最小值,可以使用日期的字符串(String)、时间戳(Number) |
|end |String、Number |- |- |最大值,可以使用日期的字符串(String)、时间戳(Number) | |end |String、Number |- |- |最大值,可以使用日期的字符串(String)、时间戳(Number) |
|return-type |String |string |timestamp 、string、date |返回值格式 | |return-type |String |string |timestamp 、string、date |返回值格式 |
|border |Boolean、String |true | |是否有边框 | |border |Boolean |true | |是否有边框 |
|rangeSeparator |String |'-' |- |选择范围时的分隔符 | |rangeSeparator |String |'-' |- |选择范围时的分隔符 |
|placeholder |String |- |- |非范围选择时的占位内容 | |placeholder |String |- |- |非范围选择时的占位内容 |
|start-placeholder|String |- |- |范围选择时开始日期的占位内容 | |start-placeholder|String |- |- |范围选择时开始日期的占位内容 |
|end-placeholder |String |- |- |范围选择时结束日期的占位内容 | |end-placeholder |String |- |- |范围选择时结束日期的占位内容 |
|disabled |Boolean、String |false | |是否不可选择 | |disabled |Boolean |false | |是否不可选择 |
|clearIcon |Boolean、String |true | |是否显示清除按钮(仅PC端适用) | |clear-icon |Boolean |true | |是否显示清除按钮 |
|hide-second |Boolean |false | |是否显示秒,只显示时分 |
...@@ -149,6 +150,9 @@ ___点击 picker 默认值规则:___ ...@@ -149,6 +150,9 @@ ___点击 picker 默认值规则:___
|:-:|:-:|:-:| |:-:|:-:|:-:|
|show|打开弹出层|-| |show|打开弹出层|-|
|close|关闭弹出层 |-| |close|关闭弹出层 |-|
|clear|清除上次选中的状态和值|-|
###
## 组件示例 ## 组件示例
......
## 3.3.9(2021-11-09)
- 去除重复的context.xxx未找到的提示语
## 3.3.8(2021-10-28)
- 新增 用户账户封禁接口 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=ban-account)
- 新增 用户账户注销接口 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=close-account)
- 修复 未传appid时用户重复注册的Bug
## 3.3.7(2021-10-08)
- 移除部分接口的废弃提示
## 3.3.6(2021-09-08) ## 3.3.6(2021-09-08)
- 修复 邀请码可能重复的Bug - 修复 邀请码可能重复的Bug
## 3.3.5(2021-08-10) ## 3.3.5(2021-08-10)
......
{ {
"id": "uni-id", "id": "uni-id",
"displayName": "uni-id", "displayName": "uni-id",
"version": "3.3.6", "version": "3.3.9",
"description": "简单、统一、可扩展的用户中心", "description": "简单、统一、可扩展的用户中心",
"keywords": [ "keywords": [
"uniid", "uniid",
......
{ {
"name": "uni-id", "name": "uni-id",
"version": "3.3.6", "version": "3.3.9",
"description": "uni-id for uniCloud", "description": "uni-id for uniCloud",
"main": "index.js", "main": "index.js",
"homepage": "https://uniapp.dcloud.io/uniCloud/uni-id", "homepage": "https://uniapp.dcloud.io/uniCloud/uni-id",
......
## 1.0.3(2021-11-20)
新增支持看激励视频广告签到
## 1.0.2(2021-08-25) ## 1.0.2(2021-08-25)
修复时区问题 修复时区问题
## 1.0.1(2021-08-23) ## 1.0.1(2021-08-23)
......
...@@ -44,6 +44,8 @@ ...@@ -44,6 +44,8 @@
<script> <script>
const db = uniCloud.database(); const db = uniCloud.database();
const signInTable = db.action('signIn').collection('opendb-sign-in') const signInTable = db.action('signIn').collection('opendb-sign-in')
const date = new Date(new Date().toLocaleDateString()).getTime()
import AD from "../../utils/ad.js"
export default { export default {
name: "uni-signIn", name: "uni-signIn",
data() { data() {
...@@ -59,52 +61,124 @@ ...@@ -59,52 +61,124 @@
}, },
mounted() {}, mounted() {},
methods: { methods: {
closeMe(e) { async getSignedInInfo(ToastText = '今日已签过') {
this.$refs.popup.close() const date = new Date(new Date().toLocaleDateString()).getTime()
let res = await signInTable
.where(`'user_id' == $env.uid && 'date' == ${date} && 'isDelete' == false`)
.get()
if (res.result.data.length) {
this.signInRes = res.result
this.$refs.popup.open()
uni.showToast({
title: ToastText,
duration: 3000,
icon: 'none'
});
}
return res.result.data
},
//看激励视频广告签到
async showRewardedVideoAd() {
let res = await this.getSignedInInfo();
console.log(res);
if (res && res.length == 0) {
let {
_id: userId
} = uni.getStorageSync('userInfo')
console.log(userId, uni.getStorageSync('userInfo'));
if (!userId) {
return uni.navigateTo({
url: "/pages/ucenter/login-page/index/index"
})
}
// 调用后会显示 loading 界面
AD.show({
adpid: 1733738477, // HBuilder 基座测试广告位
adType: "RewardedVideo",
urlCallback: {
userId,
extra: 'uniSignIn'
}
}, res => {
// 用户点击了【关闭广告】按钮
if (res && res.isEnded) {
// 正常播放结束
console.log("onClose " + res.isEnded);
//3次轮训查结果
// uni.showLoading({mask: true});
let i = 0;
uni.showLoading({
mask: true
})
let myIntive = setInterval(async e => {
i++;
res = await this.getSignedInInfo('签到成功');
if (i > 2 || res.length) {
if (!res.length) {
uni.showToast({
title: '签到失败!',
icon: 'error',
duration: 6000
});
}
clearInterval(myIntive)
uni.hideLoading()
}
}, 2000);
} else {
// 播放中途退出
console.log("onClose " + res.isEnded);
uni.showToast({
title: '播放中途退出,签到失败!',
icon: 'error',
duration: 5000
});
}
// 在此处理服务器回调逻辑
}, (err) => {
// 广告加载错误
console.log(err)
uni.showToast({
title: err.errMsg,
icon: 'none'
});
})
}
}, },
//普通点击签到
async open() { async open() {
uni.showLoading({ uni.showLoading({
mask: true mask: true
}); });
try{ try {
const date = new Date(new Date().toLocaleDateString()).getTime() let res = await this.getSignedInInfo();
let res = await signInTable if (res && res.length == 0) {
.where(`'user_id' == $env.uid && 'date' == ${date} && 'isDelete' == false`) let res = await signInTable.add({});
.get() console.log(res);
this.signInRes = res.result uni.hideLoading()
console.log(res); this.signInRes = res.result
if (res.result.data.length) { this.$refs.popup.open()
uni.hideLoading() if (this.signInRes.days.length == 7) {
uni.showToast({ uni.showToast({
title: '今日已签过', title: "你已完成7日连续签到,获得60积分!",
duration: 3000, icon: "none",
icon: 'none' duration: 5000
}); })
} else { } else {
let res = await signInTable.add({}); uni.showToast({
console.log(res); title: "签到成功,获得10积分!",
uni.hideLoading() icon: "none",
this.signInRes = res.result duration: 5000
if (this.signInRes.days.length == 7) { })
uni.showToast({ }
title: "你已完成7日连续签到,获得60积分!", }
icon: "none", } catch (e) {
duration: 5000 uni.hideLoading()
}) console.error(e)
} else {
uni.showToast({
title: "签到成功,获得10积分!",
icon: "none",
duration: 5000
})
}
}
this.$refs.popup.open()
}catch(e){
console.error(e)
uni.hideLoading()
} }
},
closeMe(e) {
this.$refs.popup.close()
} }
} }
} }
...@@ -117,6 +191,10 @@ ...@@ -117,6 +191,10 @@
flex-direction: column; flex-direction: column;
} }
scroll-view {
-webkit-overflow-scrolling: touch;
}
.background-img { .background-img {
width: 600rpx; width: 600rpx;
height: 600rpx; height: 600rpx;
......
{ {
"id": "uni-sign-in", "id": "uni-sign-in",
"displayName": "签到插件", "displayName": "签到插件",
"version": "1.0.2", "version": "1.0.3",
"description": "uni-sign-in", "description": "uni-sign-in",
"keywords": [ "keywords": [
"uni-sign-in", "uni-sign-in",
......
#### 简介:培养应用用户习惯,提升用户粘性。签到得积分的应用营销功能 #### 简介:培养用户习惯,提升用户粘性。签到得积分的应用营销功能,广告流量变现
#### 功能支持: #### 功能支持:
1. 每日签到奖励 1. 每日签到奖励 (支持:普通签到、看广告签到)
2. 周期性连续7日签到,奖励翻倍 2. 周期性连续7日签到,奖励翻倍
### 使用看广告签到功能必读
1.`普通签到`是通过clientDb实现,如果你要使用`看广告签到`的方式,
需要修改`opendb-sign-in.schema``permission` -> `create` 的值设置为`false`
> 文件路径 :`uni_modules/uni-sign-in/uniCloud/database/opendb-sign-in.schema.json`
示例:
```javascript
{
"bsonType": "object",
"required": [],
"permission": {
"read": "auth.uid == doc.user_id",
"create": false,
"update": false,
"delete": false
}
}
```
2. 你需要看激励视频广告相关文档
详情:[https://uniapp.dcloud.net.cn/api/a-d/rewarded-video](https://uniapp.dcloud.net.cn/api/a-d/rewarded-video)
##### 使用方式 ##### 使用方式
```js ```js
...@@ -12,8 +36,11 @@ ...@@ -12,8 +36,11 @@
<script> <script>
export default { export default {
methods: { methods: {
signIn() { //签到 signIn() { //普通签到
this.$refs.signIn.open() this.$refs.signIn.open()
},
signInByAd(){ //看激励视频广告签到
this.$refs.signIn.showRewardedVideoAd()
} }
} }
} }
...@@ -22,6 +49,7 @@ ...@@ -22,6 +49,7 @@
> 详情参考[uni-starter](https://ext.dcloud.net.cn/plugin?id=5057) > 详情参考[uni-starter](https://ext.dcloud.net.cn/plugin?id=5057)
##### 插件组成 ##### 插件组成
1. 前端组件 1. 前端组件
...@@ -36,14 +64,17 @@ ...@@ -36,14 +64,17 @@
- 前置操作,添加操作时检查今日是否未签到,否则拦截 - 前置操作,添加操作时检查今日是否未签到,否则拦截
- 后置操作,判断是否已经连续签到7天,决定本次签到用户可得积分 - 后置操作,判断是否已经连续签到7天,决定本次签到用户可得积分
- 后置操作,输出本轮已签到几天,当前积分,已签到的日期数组,本轮签到可得多少分 - 后置操作,输出本轮已签到几天,当前积分,已签到的日期数组,本轮签到可得多少分
4. 两个api接口
普通签到`this.$refs.signIn.open()`
看激励视频广告签到`this.$refs.signIn.showRewardedVideoAd()`
#### 常见问题 #### 常见问题
1. 是否支持配置积分数 1. 是否支持配置积分数
答:暂不支持,今后的版本有计划支持 答:暂不支持,今后的版本有计划支持
2. 有没有更多玩法 2. 有没有更多玩法
答:计划今后推出需要看广告才能签到或者补签的玩法 答:计划今后推出
\ No newline at end of file (2.1)需要看广告才能签到 --- 已支持
(2.2)补签的玩法
\ No newline at end of file
// 开发文档:https://uniapp.dcloud.io/uniCloud/clientdb?id=action
const db = uniCloud.database();
const dbCmd = db.command
const signInTable = db.collection('opendb-sign-in');
const scoresTable = db.collection('uni-id-scores');
module.exports = async function({user_id,ip}) {
let date = todayTimestamp()
let {
total
} = await signInTable.where({
user_id,
date,
isDelete: false
}).count()
console.log(total);
if (total) {
throw new Error("今天已经签到")
}
// state.newData.date = date
// state.newData.isDelete = false
await signInTable.add({
ip,
date,
user_id,
create_date:Date.now(),
isDelete:false,
})
// after -------------------------
//查最近7天的签到情况
let {
data: signInData
} = await signInTable.where({
user_id,
date: dbCmd.gte(date - 3600 * 24 * 6 * 1000),
isDelete: false
}).get()
let allDate = signInData.map(item => item.date)
//今天是本轮签到的第几天
const n = (date - Math.min(...allDate)) / 3600 / 24 / 1000 + 1;
//换成数字--第几天
let days = signInData.map(item => {
return (n * 10000 - (date - item.date) / 3600 / 24 / 1000 * 10000) / 10000 - 1
})
//查出来用户当前有多少积分
let {
data: [userScore]
} = await scoresTable
.where({
user_id
})
.orderBy("create_date", "desc")
.limit(1)
.get()
let balance = 0
if (userScore) {
balance = userScore.balance
}
if (n == 7) { //如果已经满一轮就软删除之前的内容
let setIsDeleteRes = await signInTable.where({
user_id,
date: dbCmd.neq(date)
}).update({
isDelete: true
})
console.log({
setIsDeleteRes
});
}
//给加积分
let score = n == 7 ? 60 : 10 //如果是第七天就多加50分,也就是60分
balance += score
let addScores = await scoresTable.add({
user_id,
balance,
score,
type: 1,
create_date: Date.now()
})
console.log({
addScores
});
return {
score: balance,
signInData,
n,
days
}
}
function todayTimestamp() {
//时区
let timeZone = new Date().getTimezoneOffset() / 60
//获得相对于北京时间的时间戳
let timestamp = Date.now() + 3600 * 1000 * (8 + timeZone)
//一天一共多少毫秒
const D = 3600 * 24 * 1000
//去掉余数,再减去东8区的8小时 得到当天凌晨的时间戳
return parseInt(timestamp / D) * D - 3600 * 1000 * 8
}
{
"name": "sign-in",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
'use strict';
const uniADConfig = require('uni-config-center')({
pluginId: 'uni-ad'
}).config()
const signIn = require('sign-in')
let ip = null
async function nextFn(data) {
//写自己的业务逻辑
switch (data.extra) {
case "uniSignIn": //签到
let {
user_id
} = data;
await signIn({
user_id,
ip
})
break;
default:
break;
}
return {
"isValid": true //如果不返回,广点通会2次调用本云函数
}
}
const crypto = require('crypto');
const db = uniCloud.database();
exports.main = async (event, context) => {
ip = context.CLIENTIP;
//event为客户端上传的参数
console.log('event : ', event);
const {
path,
queryStringParameters
} = event;
const data = {
adpid: event.adpid,
platform: event.platform,
provider: event.provider,
trans_id: event.trans_id,
sign: event.sign,
user_id: event.user_id,
extra: event.extra,
}
// 注意::必须验签请求来源
const trans_id = event.trans_id;
//去uni-config-center通过adpid获取secret
const secret = uniADConfig[event.adpid]
const sign2 = crypto.createHash('sha256').update(`${secret}:${trans_id}`).digest('hex');
if (event.sign !== sign2) {
console.log('验签失败');
return null;
}
//自己的逻辑
try {
return await nextFn(data)
} catch (e) {
console.error(e)
return {
"isValid": false
}
}
};
\ No newline at end of file
{
"name": "rewarded-video-ad-notify-url",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"sign-in": "file:../common/sign-in",
"uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center"
}
}
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"required": [], "required": [],
"permission": { "permission": {
"read": "auth.uid == doc.user_id", "read": "auth.uid == doc.user_id",
"create": "auth.uid != null && 'signIn' in action", "create": "auth.uid != null && 'signIn' in action", //如果你要使用`看广告签到`的方式请将这里的值改为:false
"update": false, "update": false,
"delete": false "delete": false
}, },
......
// ad.js
const ADType = {
RewardedVideo: "RewardedVideo",
FullScreenVideo: "FullScreenVideo"
}
class AdHelper {
constructor() {
this._ads = {}
}
load(options, onload, onerror) {
let ops = this._fixOldOptions(options)
let {
adpid
} = ops
if (!adpid || this.isBusy(adpid)) {
return
}
this.get(ops).load(onload, onerror)
}
show(options, onsuccess, onfail) {
let ops = this._fixOldOptions(options)
let {
adpid
} = ops
if (!adpid) {
return
}
uni.showLoading({
mask: true
})
var ad = this.get(ops)
ad.load(() => {
uni.hideLoading()
ad.show((e) => {
onsuccess && onsuccess(e)
})
}, (err) => {
uni.hideLoading()
onfail && onfail(err)
})
}
isBusy(adpid) {
return (this._ads[adpid] && this._ads[adpid].isLoading)
}
get(options) {
const {
adpid,
singleton = true
} = options
if (singleton === false) {
if (this._ads[adpid]) {
this._ads[adpid].destroy()
delete this._ads[adpid]
}
}
delete options.singleton
if (!this._ads[adpid]) {
this._ads[adpid] = this._createAdInstance(options)
}
return this._ads[adpid]
}
_createAdInstance(options) {
const adType = options.adType || ADType.RewardedVideo
delete options.adType
let ad = null;
if (adType === ADType.RewardedVideo) {
ad = new RewardedVideo(options)
} else if (adType === ADType.FullScreenVideo) {
ad = new FullScreenVideo(options)
}
return ad
}
_fixOldOptions(options) {
return (typeof options === "string") ? {
adpid: options
} : options
}
}
const EXPIRED_TIME = 1000 * 60 * 30
const ProviderType = {
CSJ: 'csj',
GDT: 'gdt'
}
const RETRY_COUNT = 1
class AdBase {
constructor(adInstance, options = {}) {
this._isLoad = false
this._isLoading = false
this._lastLoadTime = 0
this._lastError = null
this._retryCount = 0
this._loadCallback = null
this._closeCallback = null
this._errorCallback = null
const ad = this._ad = adInstance
ad.onLoad((e) => {
this._isLoading = false
this._isLoad = true
this._lastLoadTime = Date.now()
this.onLoad()
})
ad.onClose((e) => {
this._isLoad = false
this.onClose(e)
})
ad.onVerify && ad.onVerify((e) => {
// e.isValid
})
ad.onError(({
code,
message
}) => {
this._isLoading = false
const data = {
code: code,
errMsg: message
}
if (code === -5008) {
this._loadAd()
return
}
if (this._retryCount < RETRY_COUNT) {
this._retryCount += 1
this._loadAd()
return
}
this._lastError = data
this.onError(data)
})
}
get isExpired() {
return (this._lastLoadTime !== 0 && (Math.abs(Date.now() - this._lastLoadTime) > EXPIRED_TIME))
}
get isLoading() {
return this._isLoading
}
getProvider() {
return this._ad.getProvider()
}
load(onload, onerror) {
this._loadCallback = onload
this._errorCallback = onerror
if (this._isLoading) {
return
}
if (this._isLoad) {
this.onLoad()
return
}
this._retryCount = 0
this._loadAd()
}
show(onclose) {
this._closeCallback = onclose
if (this._isLoading || !this._isLoad) {
return
}
if (this._lastError !== null) {
this.onError(this._lastError)
return
}
const provider = this.getProvider()
if (provider === ProviderType.CSJ && this.isExpired) {
this._loadAd()
return
}
this._ad.show()
}
onLoad(e) {
if (this._loadCallback != null) {
this._loadCallback()
}
}
onClose(e) {
if (this._closeCallback != null) {
this._closeCallback({
isEnded: e.isEnded
})
}
}
onError(e) {
if (this._errorCallback != null) {
this._errorCallback(e)
}
}
destroy() {
this._ad.destroy()
}
_loadAd() {
this._isLoad = false
this._isLoading = true
this._lastError = null
this._ad.load()
}
}
class RewardedVideo extends AdBase {
constructor(options = {}) {
super(plus.ad.createRewardedVideoAd(options), options)
}
}
class FullScreenVideo extends AdBase {
constructor(options = {}) {
super(plus.ad.createFullScreenVideoAd(options), options)
}
}
export default new AdHelper()
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册