提交 b3f3a5e1 编写于 作者: DCloud_JSON's avatar DCloud_JSON 提交者: study夏羽

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

上级 85a6028e
{
"prompt" : "template"
}
## 1.1.23(2021-11-20)
- 使用`uni.getUniverifyManager`优化一键登陆中,点击第三方登陆的逻辑:未勾选隐私政策时,toast提醒并阻止了一键登陆界面的close
- 新增支持看激励视频广告签到
## 1.1.22(2021-11-10)
删除`common/openApp.js`中可选链操作符,解决vue3版本在hbuilderX内置浏览器不兼容的问题
## 1.1.21(2021-11-10)
......
......@@ -179,7 +179,7 @@ export default async function() {
oaid,
idfa
}
console.log("重新登录/注册,获取设备id", deviceInfo);
//console.log("重新登录/注册,获取设备id", deviceInfo);
option.data.deviceInfo = deviceInfo
// #ifndef H5
......
......@@ -39,7 +39,7 @@
handler(src) {
// console.log(src);
// console.log(src.substring(0, 8));
if (src.substring(0, 8) == "cloud://") {
if (src&&src.substring(0, 8) == "cloud://") {
uniCloud.getTempFileURL({
fileList: [src]
}).then(res=>{
......
<template>
<view class="root">
<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>
</checkbox-group>
<view class="item" v-for="(agreement,index) in agreements" :key="index">
......@@ -38,6 +38,8 @@
},
created() {
uni.$on('setAgreementsAgree',state=>{
console.log('setAgreementsAgree',state);
this.isAgree = state
this.$emit('setAgree',state)
})
},
......
......@@ -82,7 +82,7 @@
},
success: (e) => {
uni.showToast({
title: e.result.msg,
title: e.result.msg||'绑定成功',
icon: 'none'
});
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>
<view>
<view class="quick-login-box">
<view class="item" v-for="(item,index) in servicesList" :key="index"
@click="item.path?to(item.path):login_before(item.id,false)">
<image class="logo" :src="item.logo" mode="widthFix"></image>
<text class="login-title">{{item.text}}</text>
</view>
</view>
<!-- #ifdef MP-WEIXIN -->
<uni-user-profile @next="doUserProfileNext" ref="userProfile"></uni-user-profile>
<!-- #endif -->
</view>
</template>
<script>
import {mapGetters,mapMutations} from 'vuex';
//前一个窗口的页面地址。控制点击切换快捷登录方式是创建还是返回
import loginSuccess from '@/pages/ucenter/login-page/common/loginSuccess.js';
const db = uniCloud.database();
<template>
<view>
<view class="quick-login-box">
<view class="item" v-for="(item,index) in servicesList" :key="index"
@click="item.path?to(item.path):login_before(item.id,false)">
<image class="logo" :src="item.logo" mode="widthFix"></image>
<text class="login-title">{{item.text}}</text>
</view>
</view>
<!-- #ifdef MP-WEIXIN -->
<uni-user-profile @next="doUserProfileNext" ref="userProfile"></uni-user-profile>
<!-- #endif -->
</view>
</template>
<script>
import {
initVueI18n
} from '@dcloudio/uni-i18n'
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')
export default {
computed: {
loginConfig() {
return getApp().globalData.config.router.login
},
agreements() {
return getApp().globalData.config.about.agreements || []
}
},
data() {
return {
servicesList: [{
"id": "username",
"text": this.$t('uniQuickLogin').accountLogin,
"logo": "/static/uni-quick-login/user.png",
"path": "/pages/ucenter/login-page/pwd-login/pwd-login"
},
{
"id": "smsCode",
"text": this.$t('uniQuickLogin').SMSLogin,
"logo": "/static/uni-quick-login/sms.png",
"path": "/pages/ucenter/login-page/index/index?type=smsCode"
},
{
"id": "weixin",
"text": this.$t('uniQuickLogin').wechatLogin,
"logo": "/static/uni-quick-login/wechat.png",
},
{
"id": "apple",
"text": this.$t('uniQuickLogin').appleLogin,
"logo": "/static/uni-quick-login/apple.png",
},
{
"id": "univerify",
"text":this.$t('uniQuickLogin').oneClickLogin,
"logo": "/static/uni-quick-login/univerify.png",
},
{
"id": "qq",
"text": this.$t('uniQuickLogin').QQLogin, //暂未提供该登录方式的接口示例
"logo": "/static/uni-quick-login/univerify.png",
},
{
"id": "xiaomi",
"text": this.$t('uniQuickLogin').xiaomiLogin, //暂未提供该登录方式的接口示例
"logo": "/static/uni-quick-login/univerify.png",
},
{
"id": "sinaweibo",
"text": this.$t('common').weibo, //暂未提供该登录方式的接口示例
"logo": "/static/uni-quick-login/univerify.png",
}
],
config: {},
univerifyStyle: { //一键登录弹出窗的样式配置参数
"fullScreen": true, // 是否全屏显示,true表示全屏模式,false表示非全屏模式,默认值为false。
"backgroundColor": "#ffffff", // 授权页面背景颜色,默认值:#ffffff
"buttons": { // 自定义登录按钮
"iconWidth": "45px", // 图标宽度(高度等比例缩放) 默认值:45px
"list": []
},
"privacyTerms": {
"defaultCheckBoxState": false, // 条款勾选框初始状态 默认值: true
"textColor": "#BBBBBB", // 文字颜色 默认值:#BBBBBB
"termsColor": "#5496E3", // 协议文字颜色 默认值: #5496E3
"prefix": "我已阅读并同意", // 条款前的文案 默认值:“我已阅读并同意”
"suffix": "并使用本机号码登录", // 条款后的文案 默认值:“并使用本机号码登录”
"privacyItems": []
}
}
}
},
watch: {
agree(agree) {
this.univerifyStyle.privacyTerms.defaultCheckBoxState = agree
}
},
props: {
agree: {
type: Boolean,
default () {
return false
}
}
},
async created() {
let servicesList = this.servicesList
//去掉配置中不存在的 注意,在/common/appInit.js中已清除有配置但设备环境不支持的登录项
servicesList = servicesList.filter(item => this.loginConfig.includes(item.id))
//处理一键登录
if (this.loginConfig.includes('univerify')) {
this.univerifyStyle.privacyTerms.privacyItems = this.agreements
//设置一键登录功能底下的快捷登录按钮
servicesList.forEach(({
id,
logo
}) => {
if (id != 'univerify') {
this.univerifyStyle.buttons.list.push({
"iconPath": logo,
"provider": id
})
}
})
}
console.log(servicesList);
//如果当前页面为默认登录界面。当前第一优先级的“微信和苹果登录”要隐藏,因为他已经被渲染在默认登录界面顶部
if (
this.getRoute(1) == '/pages/ucenter/login-page/index/index' && ['weixin', 'apple'].includes(this
.loginConfig[0])
) {
servicesList = servicesList.filter(item => item.id != this.loginConfig[0])
}
//去掉当前页面对应的登录选项
this.servicesList = servicesList.filter(item => {
let path = item.path ? item.path.split('?')[0] : '';
return path != this.getRoute(1)
})
console.log('servicesList', servicesList, this.servicesList);
},
mounted() {
},
methods: {
...mapMutations({
setUserInfo: 'user/login'
}),
getRoute(n = 0) {
let pages = getCurrentPages();
// console.log('route-pages-length', pages.length);
if (n > pages.length) {
return ''
}
return '/' + pages[pages.length - n].route
},
to(path) {
// console.log('比较', this.getRoute(2), path)
if (this.getRoute(2) == path) { // 控制路由是重新打开还是返回,避免重复打开页面
uni.navigateBack();
} else {
let allServicesList = []
export default {
computed: {
loginConfig() {
return getApp().globalData.config.router.login
},
agreements() {
return getApp().globalData.config.about.agreements || []
}
},
data() {
return {
servicesList: [{
"id": "username",
"text": t('accountLogin'),
"logo": "/static/uni-quick-login/user.png",
"path": "/pages/ucenter/login-page/pwd-login/pwd-login"
},
{
"id": "smsCode",
"text": t('SMSLogin'),
"logo": "/static/uni-quick-login/sms.png",
"path": "/pages/ucenter/login-page/index/index?type=smsCode"
},
{
"id": "weixin",
"text": t('wechatLogin'),
"logo": "/static/uni-quick-login/wechat.png",
},
{
"id": "apple",
"text": t('appleLogin'),
"logo": "/static/uni-quick-login/apple.png",
},
{
"id": "univerify",
"text": t('oneClickLogin'),
"logo": "/static/uni-quick-login/univerify.png",
},
{
"id": "qq",
"text": t('QQLogin'), //暂未提供该登录方式的接口示例
"logo": "/static/uni-quick-login/univerify.png",
},
{
"id": "xiaomi",
"text": t('xiaomiLogin'), //暂未提供该登录方式的接口示例
"logo": "/static/uni-quick-login/univerify.png",
},
{
"id": "sinaweibo",
"text": t('weibo'), //暂未提供该登录方式的接口示例
"logo": "/static/uni-quick-login/univerify.png",
}
],
config: {},
univerifyStyle: { //一键登录弹出窗的样式配置参数
"fullScreen": true, // 是否全屏显示,true表示全屏模式,false表示非全屏模式,默认值为false。
"backgroundColor": "#ffffff", // 授权页面背景颜色,默认值:#ffffff
"buttons": { // 自定义登录按钮
"iconWidth": "45px", // 图标宽度(高度等比例缩放) 默认值:45px
"list": []
},
"privacyTerms": {
"defaultCheckBoxState": false, // 条款勾选框初始状态 默认值: true
"textColor": "#BBBBBB", // 文字颜色 默认值:#BBBBBB
"termsColor": "#5496E3", // 协议文字颜色 默认值: #5496E3
"prefix": "我已阅读并同意", // 条款前的文案 默认值:“我已阅读并同意”
"suffix": "并使用本机号码登录", // 条款后的文案 默认值:“并使用本机号码登录”
"privacyItems": []
}
}
}
},
watch: {
agree(agree) {
this.univerifyStyle.privacyTerms.defaultCheckBoxState = agree
}
},
props: {
agree: {
type: Boolean,
default () {
return false
}
}
},
async created() {
let servicesList = this.servicesList
//去掉配置中不存在的 注意,在/common/appInit.js中已清除有配置但设备环境不支持的登录项
servicesList = servicesList.filter(item => this.loginConfig.includes(item.id))
//处理一键登录
if (this.loginConfig.includes('univerify')) {
this.univerifyStyle.privacyTerms.privacyItems = this.agreements
//设置一键登录功能底下的快捷登录按钮
servicesList.forEach(({
id,
logo,
path
}) => {
if (id != 'univerify') {
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
.loginConfig[0])
) {
servicesList = servicesList.filter(item => item.id != this.loginConfig[0])
}
//去掉当前页面对应的登录选项
this.servicesList = servicesList.filter(item => {
let path = item.path ? item.path.split('?')[0] : '';
return path != this.getRoute(1)
})
console.log('servicesList', servicesList, this.servicesList);
},
mounted() {},
methods: {
...mapMutations({
setUserInfo: 'user/login'
}),
getRoute(n = 0) {
let pages = getCurrentPages();
// console.log('route-pages-length', pages.length);
if (n > pages.length) {
return ''
}
return '/' + pages[pages.length - n].route
},
to(path) {
console.log('比较', this.getRoute(1),this.getRoute(2), path)
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({
url: path,
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{
console.log(type);
console.log('uni.getUniverifyManager:'+uni.getUniverifyManager);
}
uni.login({
"provider": type,
"onlyAuthorize":true, //请勿直接使用前端获取的unionid或openid直接用于登录,前端的数据都是不可靠的
"univerifyStyle": this.univerifyStyle,
complete: (e) => {
uni.hideLoading()
console.log(e);
},
success: async e => {
console.log(e);
if (type == 'apple') {
let res = await this.getUserInfo({
provider: "apple"
})
Object.assign(e.authResult, res.userInfo)
}
this.login( type == 'weixin'?e.code:e.authResult , type)
},
fail:async (err) => {
console.log(err);
if (type == 'univerify') {
if (err.metadata && err.metadata.error_data) {
uni.showToast({
title: this.$t('uniQuickLogin').oneClickLogin + ":" + err.metadata.error_data,
icon: 'none'
});
}
if (err.errMsg) {
console.log('出乎意料的情况,path:'+path);
}
},
login_before(type, navigateBack = true) {
console.log(type);
if (!this.agree && type != 'univerify') {
return uni.showToast({
title: t('noAgree'),
icon: 'none'
});
}
uni.showLoading({mask: true})
if (type == 'univerify' && uni.getUniverifyManager) {
let univerifyManager = uni.getUniverifyManager()
console.log('是新版');
let onButtonsClickFn = async res =>{
console.log('点击了第三方登录,provider:',res, res.provider,this.univerifyStyle.buttons.list);
//同步一键登录弹出层隐私协议框是否打勾
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,this.getRoute(1));
if (path) {
this.to(path)
closeUniverify()
} else {
if(agree){
closeUniverify()
setTimeout(() => {
console.log('login_before');
this.login_before(res.provider)
}, 500)
}else{
console.log(t('noAgree'));
uni.showToast({
title:this.$t('uniQuickLogin').oneClickLogin + ":" + err.errMsg,
title: t('noAgree'),
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;
}
}
}
})
},
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: () => {
function closeUniverify(){
uni.hideLoading()
univerifyManager.close()
// 取消订阅自定义按钮点击事件
univerifyManager.offButtonsClick(onButtonsClickFn)
}
})
},
doUserProfileNext(){
loginSuccess()
},
async getUserInfo(e) {
return new Promise((resolve, reject) => {
uni.getUserInfo({
...e,
success: (res) => {
resolve(res);
// 订阅自定义按钮点击事件
univerifyManager.onButtonsClick(onButtonsClickFn)
// 调用一键登录弹框
return univerifyManager.login({
"univerifyStyle": this.univerifyStyle,
success:res=> {
console.log('login success', res)
this.login(res.authResult, 'univerify')
},
fail: (err) => {
uni.showModal({
content: JSON.stringify(err),
showCancel: false
fail(err) {
uni.showToast({
title: JSON.stringify(err),
icon: 'none'
});
reject(err);
}
},
complete(e){
uni.hideLoading()
// 取消订阅自定义按钮点击事件
univerifyManager.offButtonsClick(onButtonsClickFn)
}
})
})
}
}
}
</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>
\ No newline at end of file
}
uni.login({
"provider": type,
"onlyAuthorize": true, //请勿直接使用前端获取的unionid或openid直接用于登录,前端的数据都是不可靠的
"univerifyStyle": this.univerifyStyle,
complete: (e) => {
console.log(e);
uni.hideLoading()
},
success: async e => {
console.log(e);
if (type == 'apple') {
let res = await this.getUserInfo({
provider: "apple"
})
Object.assign(e.authResult, res.userInfo)
}
this.login(type == 'weixin' ? e.code : e.authResult, type)
},
fail: async (err) => {
console.log(err);
// 以下代码为兼容旧版(HBuilderX3.2.13之前)HBuilderX3.2.13以上版本可直接删除
if (type == 'univerify'&& !uni.getUniverifyManager) {
if (err.metadata && err.metadata.error_data) {
uni.showToast({
title: t('oneClickLogin') + ":" + err.metadata.error_data,
icon: 'none'
});
}
if (err.errMsg) {
uni.showToast({
title: t('oneClickLogin') + ":" + err.errMsg,
icon: 'none'
});
}
switch (err.errCode) {
case 30002:
console.log('在一键登录界面,点击其他登录方式');
break;
case 30003:
console.log('关闭了登录');
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 {
},
mine: {
showText: "Text",
signIn: "Check In Reward",
signIn: "Check In Reward",
signInByAd:"Check In Reward By AD",
toEvaluate: "To Evaluate",
readArticles: "Read Articles",
myScore: "My Score",
......
......@@ -53,7 +53,8 @@ export default {
},
mine:{
showText: "文字",
signIn: "签到有奖",
signIn: "普通签到",
signInByAd:"看广告签到",
toEvaluate: "去评分",
readArticles: "阅读过的文章",
myScore: "我的积分",
......
{
"name": "uuuu",
"name": "uni-starter",
"appid": "请点击重新获取",
"description": "云端一体应用快速开发模版",
"versionName": "1.0.0",
......@@ -112,6 +112,10 @@
}
},
"ad": {
"gdt": {
},
"csj": {
}
},
"share": {
"weixin": {
......@@ -170,7 +174,8 @@
},
"splashscreen": {
"iosStyle": "common",
"androidStyle": "common"
"androidStyle": "common",
"useOriginalMsgbox": true
}
},
"nvueLaunchMode": ""
......
......@@ -32,7 +32,7 @@
</view>
</template>
</uni-list-item>
</uni-list>
</uni-list>
<view class="banner">
<!-- 文章开头,缩略图 -->
<image class="banner-img" :src="data.avatar" mode="widthFix"></image>
......@@ -41,7 +41,7 @@
<text class="uni-ellipsis">{{data.excerpt}}</text>
</view>
</view>
<view class="article-content">
<view class="article-content">
<rich-text :nodes="data.content"></rich-text>
</view>
</template>
......@@ -50,22 +50,29 @@
</template>
<script>
// #ifdef APP
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 readNewsLog = db.collection('read-news-log')
import {
mapGetters
} from 'vuex';
export default {
// #ifdef APP
onBackPress({from}) {
if(from=='backbutton'){
this.$nextTick(function(){
uniShare.hide()
})
if(from == 'backbutton'){
if(uniShare.isShow){
this.$nextTick(function(){
console.log(uniShare);
uniShare.hide()
})
}
return uniShare.isShow;
}
},
},
// #endif
data() {
return {
// 当前显示 _id
......@@ -76,30 +83,28 @@
field: 'user_id.username,user_id._id,avatar,excerpt,last_modify_date,comment_count,like_count,title,content',
formData: {
noData: '<p style="text-align:center;color:#666">详情加载中...</p>'
},
}
}
},
computed: {
//拼接where条件
//查询条件 ,更多详见 :https://uniapp.dcloud.net.cn/uniCloud/unicloud-db?id=jsquery
where() {
return `_id =="${this.id}"`
},
...mapGetters({
'userInfo': 'user/info',
'hasLogin': 'user/hasLogin'
}),
uniStarterConfig() {
return getApp().globalData.config
}
},
where(){
//拼接where条件 查询条件 ,更多详见 :https://uniapp.dcloud.net.cn/uniCloud/unicloud-db?id=jsquery
return `_id =="${this.id}"`
}
},
onLoad(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"}
//获取真实新闻id,通常 id 来自上一个页面
if (event.id) {
this.id = event.id
if (event.id) {
this.id = event.id
}
//若上一页传递了标题过来,则设置导航栏标题
if (event.title) {
......@@ -109,23 +114,26 @@
})
}
},
onNavigationBarButtonTap(event) {
if (event.type == 'share') {
this.shareClick();
}
},
onReady() {
// 开始加载数据,修改 where 条件后才开始去加载 clinetDB 的数据 ,需要等组件渲染完毕后才开始执行 loadData,所以不能再 onLoad 中执行
if (this.id) { // ID 不为空,则发起查询
this.$refs.detail.loadData()
if (this.id) { // ID 不为空,则发起查询
this.$refs.detail.loadData()
} else {
uni.showToast({
icon: 'none',
title: this.$t('listDetail').newsErr
})
}
},
onNavigationBarButtonTap(event) {
if (event.type == 'share') {
this.shareClick();
}
},
methods: {
methods: {
$log(...args){
console.log('args',...args,this.id)
},
setReadNewsLog(){
let item = {
"article_id":this.id,
......@@ -192,89 +200,91 @@
/**
* 分享该文章
*/
shareClick() {
let {
_id,
title,
excerpt,
avatar
// #ifdef APP
shareClick() {
let {
_id,
title,
excerpt,
avatar
} = this.$refs.detail.dataList
console.log( JSON.stringify({
_id,
title,
excerpt,
avatar
console.log( JSON.stringify({
_id,
title,
excerpt,
avatar
}) );
uniShare.show({
content: { //公共的分享类型(type)、链接(herf)、标题(title)、summary(描述)、imageUrl(缩略图)
type: 0,
href: this.uniStarterConfig.h5.url + `/#/pages/list/detail?id=${_id}&title=${title}`,
title: this.title,
summary: excerpt,
imageUrl: avatar + '?x-oss-process=image/resize,m_fill,h_100,w_100' //压缩图片解决,在ios端分享图过大导致的图片失效问题
},
menus: [{
"img": "/static/app-plus/sharemenu/wechatfriend.png",
"text": this.$t('common').wechatFriends,
"share": {
"provider": "weixin",
"scene": "WXSceneSession"
}
},
{
"img": "/static/app-plus/sharemenu/wechatmoments.png",
"text": this.$t('common').wechatBbs,
"share": {
"provider": "weixin",
"scene": "WXSenceTimeline"
}
},
{
"img": "/static/app-plus/sharemenu/mp_weixin.png",
"text": this.$t('common').wechatApplet,
"share": {
provider: "weixin",
scene: "WXSceneSession",
type: 5,
miniProgram: {
id: this.uniStarterConfig.mp.weixin.id,
path: `/pages/list/detail?id=${_id}&title=${title}`,
webUrl: this.uniStarterConfig.h5.url +
`/#/pages/list/detail?id=${_id}&title=${title}`,
type: 0
},
}
},
{
"img": "/static/app-plus/sharemenu/weibo.png",
"text": this.$t('common').weibo,
"share": {
"provider": "sinaweibo"
}
},
{
"img": "/static/app-plus/sharemenu/qq.png",
"text": "QQ",
"share": {
"provider": "qq"
}
},
{
"img": "/static/app-plus/sharemenu/copyurl.png",
"text": this.$t('common').copy,
"share": "copyurl"
},
{
"img": "/static/app-plus/sharemenu/more.png",
"text": this.$t('common').more,
"share": "shareSystem"
}
],
cancelText: this.$t('common').cancelShare,
}, e => { //callback
uniShare.show({
content: { //公共的分享类型(type)、链接(herf)、标题(title)、summary(描述)、imageUrl(缩略图)
type: 0,
href: this.uniStarterConfig.h5.url + `/#/pages/list/detail?id=${_id}&title=${title}`,
title: this.title,
summary: excerpt,
imageUrl: avatar + '?x-oss-process=image/resize,m_fill,h_100,w_100' //压缩图片解决,在ios端分享图过大导致的图片失效问题
},
menus: [{
"img": "/static/app-plus/sharemenu/wechatfriend.png",
"text": this.$t('common').wechatFriends,
"share": {
"provider": "weixin",
"scene": "WXSceneSession"
}
},
{
"img": "/static/app-plus/sharemenu/wechatmoments.png",
"text": this.$t('common').wechatBbs,
"share": {
"provider": "weixin",
"scene": "WXSenceTimeline"
}
},
{
"img": "/static/app-plus/sharemenu/mp_weixin.png",
"text": this.$t('common').wechatApplet,
"share": {
provider: "weixin",
scene: "WXSceneSession",
type: 5,
miniProgram: {
id: this.uniStarterConfig.mp.weixin.id,
path: `/pages/list/detail?id=${_id}&title=${title}`,
webUrl: this.uniStarterConfig.h5.url +
`/#/pages/list/detail?id=${_id}&title=${title}`,
type: 0
},
}
},
{
"img": "/static/app-plus/sharemenu/weibo.png",
"text": this.$t('common').weibo,
"share": {
"provider": "sinaweibo"
}
},
{
"img": "/static/app-plus/sharemenu/qq.png",
"text": "QQ",
"share": {
"provider": "qq"
}
},
{
"img": "/static/app-plus/sharemenu/copyurl.png",
"text": this.$t('common').copy,
"share": "copyurl"
},
{
"img": "/static/app-plus/sharemenu/more.png",
"text": this.$t('common').more,
"share": "shareSystem"
}
],
cancelText: this.$t('common').cancelShare,
}, e => { //callback
console.log(e);
})
},
})
}
// #endif
}
}
</script>
......
......@@ -39,16 +39,20 @@
format="yyyy-MM-dd" :threshold="[60000, 2592000000]" />
</view>
</view>
</template>
</template>
</uni-list-item>
<!-- 加载状态:上拉加载更多,加载中,没有更多数据了,加载错误 -->
<!-- #ifdef APP-PLUS -->
<uni-list-item>
<template v-slot:body>
<!-- #endif -->
<uni-load-state @networkResume="refresh" :state="{data,pagination,hasMore, loading, error}"
@loadMore="loadMore">
</uni-load-state>
<!-- #ifdef APP-PLUS -->
</template>
</uni-list-item>
<!-- #endif -->
</uni-list>
</unicloud-db>
</view>
......
......@@ -63,10 +63,9 @@
<!-- 搜索联想 -->
<view class="search-associative" v-if="associativeShow">
<uni-list>
<template v-for="(item,index) in associativeList">
<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'}" />
</template>
<uni-list-item v-for="(item,index) in associativeList" :key="item._id" :ellipsis="1" :title="item.name" @click="associativeClick(item)" show-extra-icon
clickable :extra-icon="{size:18,color:iconColor,type:'search'}" >
</uni-list-item>
</uni-list>
</view>
</view>
......
......@@ -54,7 +54,13 @@
"top": "2000px" //隐藏当前页面窗体
})
}
//#endif
//#endif
uni.$on('setLoginType',type=>{
this.type = type
})
},
onUnload() {
uni.$off('setLoginType')
},
onReady() {
//#ifdef APP-PLUS
......
......@@ -39,6 +39,7 @@
lock:false,
formData: {
"phone": "",
"code":"",
'pwd': '',
'pwd2': ''
},
......@@ -152,10 +153,10 @@
}
}).then(({result})=>{
console.log(result);
// uni.showToast({
// title: result.msg,
// icon: 'none'
// });
uni.showToast({
title: result.msg||'更新成功',
icon: 'none'
});
if (result.code === 0) {
uni.navigateBack()
}
......@@ -191,7 +192,6 @@
<style>
@import url("../common/login-page.css");
.content{
padding-top: 36rpx;
}
......
......@@ -58,7 +58,8 @@
uni.stopPullDownRefresh()
})
},
handleItemClick(item) {
handleItemClick(item) {
console.log(item);
uni.navigateTo({
url: '/pages/list/detail?id=' + item._id + '&title=' + item.title
})
......
......@@ -69,7 +69,15 @@
}
],
ucenterList: [
[{
[
// #ifdef APP-PLUS
{
"title": this.$t('mine.signInByAd'),
"event": 'signInByAd',
"icon": "compose"
},
// #endif
{
"title": this.$t('mine.signIn'),
"event": 'signIn',
"icon": "compose"
......@@ -174,9 +182,12 @@
url: "/pages/ucenter/settings/settings"
})
},
signIn() { //签到
signIn() { //普通签到
this.$refs.signIn.open()
},
signInByAd(){ //看激励视频广告签到
this.$refs.signIn.showRewardedVideoAd()
},
/**
* 个人中心项目列表点击事件
*/
......
......@@ -65,7 +65,7 @@
console.log(result);
this.setUserInfo({"mobile":result.mobile})
uni.showToast({
title: result.msg,
title: result.msg||'完成',
icon: 'none'
});
if (result.code === 0) {
......
## 1.4.3(2021-09-22)
- 修复 startDate、 endDate 属性失效的 bug
## 1.4.2(2021-08-24)
- 新增 支持国际化
## 1.4.1(2021-08-05)
......
......@@ -184,10 +184,14 @@
this.init(newVal)
},
startDate(val){
this.cale.resetSatrtDate(val)
this.cale.resetSatrtDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
endDate(val){
this.cale.resetEndDate(val)
this.cale.resetEndDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
selected(newVal) {
this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
......
......@@ -139,13 +139,15 @@ class Calendar {
let disableBefore = true
let disableAfter = true
if (this.startDate) {
let dateCompBefore = this.dateCompare(this.startDate, fullDate)
disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
disableBefore = this.dateCompare(this.startDate, nowDate)
}
if (this.endDate) {
let dateCompAfter = this.dateCompare(fullDate, this.endDate)
disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
disableAfter = this.dateCompare(nowDate, this.endDate)
}
let multiples = this.multipleStatus.data
let checked = false
......@@ -169,7 +171,7 @@ class Calendar {
afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate),
month: full.month,
lunar: this.getlunar(full.year, full.month, i),
disable: !disableBefore || !disableAfter,
disable: !(disableBefore && disableAfter),
isDay
}
if (info) {
......
{
"id": "uni-calendar",
"displayName": "uni-calendar 日历",
"version": "1.4.2",
"version": "1.4.3",
"description": "日历组件",
"keywords": [
"uni-ui",
......@@ -80,7 +80,7 @@
},
"Vue": {
"vue2": "y",
"vue3": "u"
"vue3": "y"
}
}
}
......
## 0.4.0(2021-07-13)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.4.9(2021-10-28)
- 修复 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.4(2021-05-28)
- 修复 v-model无效问题
- 修复 v-model 无效问题
- 修复 loaddata 为空数据组时加载时间过长问题
- 修复 上个版本引出的本地数据无法选择带有children的2级节点
- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点
## 0.3.3(2021-05-12)
- 新增 组件示例地址
## 0.3.2(2021-04-22)
- 修复 非树形数据有 where 属性查询报错的问题
## 0.3.1(2021-04-15)
- 修复 本地数据概率无法回显时问题
## 0.3.0(2021-04-07)
- 新增 支持云端非树形表结构数据
- 修复 根节点 parent_field 字段等于null时选择界面错乱问题
- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题
## 0.2.0(2021-03-15)
- 修复 nodeclick、popupopened、popupclosed事件无法触发的问题
- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题
## 0.1.9(2021-03-09)
- 修复 微信小程序某些情况下无法选择的问题
## 0.1.8(2021-02-05)
- 优化 部分样式在nvue上的兼容表现
- 优化 部分样式在 nvue 上的兼容表现
## 0.1.7(2021-02-05)
- 调整为uni_modules目录规范
- 调整为 uni_modules 目录规范
......@@ -16,7 +16,11 @@
</view>
</scroll-view>
<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>
</view>
......@@ -36,7 +40,8 @@
<data-picker-view class="picker-view" ref="pickerView" v-model="dataValue" :localdata="localdata"
:preload="preload" :collection="collection" :field="field" :orderby="orderby" :where="where"
: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>
</template>
......@@ -70,7 +75,7 @@
*/
export default {
name: 'UniDataPicker',
emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change','update:modelValue'],
emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change', 'update:modelValue'],
mixins: [dataPicker],
components: {
DataPickerView
......@@ -98,6 +103,10 @@
type: Boolean,
default: false
},
clearIcon: {
type: Boolean,
default: true
},
border: {
type: Boolean,
default: true
......@@ -105,6 +114,10 @@
split: {
type: String,
default: '/'
},
ellipsis: {
type: Boolean,
default: true
}
},
data() {
......@@ -128,6 +141,10 @@
})
},
methods: {
clear() {
this.inputSelected.splice(0)
this._dispatchEvent([])
},
onPropsChange() {
this._treeData = []
this.selectedIndex = 0
......@@ -142,11 +159,11 @@
if (this.isLocaldata) {
this.loadData()
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.inputSelected = this.selected.slice(0)
})
} else if (this.dataValue.length) {
} else if (this.hasValue) {
this.getTreePath(() => {
this.inputSelected = this.selected.slice(0)
})
......@@ -197,26 +214,34 @@
this.inputSelected = e
this._dispatchEvent(e)
},
_processReadonly(dataList, valueArray) {
_processReadonly(dataList, value) {
var isTree = dataList.findIndex((item) => {
return item.children
})
if (isTree > -1) {
if (Array.isArray(valueArray)) {
let inputValue = valueArray[valueArray.length - 1]
if (isTree > -1) {
let inputValue
if (Array.isArray(value)) {
inputValue = value[value.length - 1]
if (typeof inputValue === 'object' && inputValue.value) {
inputValue = inputValue.value
}
} else {
inputValue = value
}
this.inputSelected = this._findNodePath(inputValue, this.localdata)
return
}
if (!this.hasValue) {
this.inputSelected = []
return
}
let result = []
for (let i = 0; i < valueArray.length; i++) {
var value = valueArray[i]
for (let i = 0; i < value.length; i++) {
var val = value[i]
var item = dataList.find((v) => {
return v.value == value
return v.value == val
})
if (item) {
result.push(item)
......@@ -239,14 +264,17 @@
}
return result
},
_dispatchEvent(selected) {
var value = new Array(selected.length)
for (var i = 0; i < selected.length; i++) {
value[i] = selected[i].value
_dispatchEvent(selected) {
let item = {}
if (selected.length) {
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) {
this.formItem.setValue(item.value)
}
......@@ -341,6 +369,7 @@
position: relative;
width: 20px;
/* #ifndef APP-NVUE */
margin-bottom: 5px;
margin-left: auto;
display: flex;
/* #endif */
......@@ -466,6 +495,10 @@
.dialog-caption {
display: none;
}
.icon-clear {
margin-right: 5px;
}
}
/* #endif */
......
......@@ -6,6 +6,12 @@ export default {
return []
}
},
spaceInfo: {
type: Object,
default () {
return {}
}
},
collection: {
type: String,
default: ''
......@@ -60,12 +66,12 @@ export default {
return []
}
},
modelValue: {
type: [Array, String, Number],
default () {
return []
}
},
modelValue: {
type: [Array, String, Number],
default () {
return []
}
},
preload: {
type: Boolean,
default: false
......@@ -85,6 +91,15 @@ export default {
multiple: {
type: Boolean,
default: false
},
map: {
type: Object,
default() {
return {
text: "text",
value: "value"
}
}
}
},
data() {
......@@ -111,29 +126,29 @@ export default {
return !this.collection.length
},
postField() {
let fields = [this.field];
if (this.parentField) {
fields.push(`${this.parentField} as parent_value`);
}
let fields = [this.field];
if (this.parentField) {
fields.push(`${this.parentField} as parent_value`);
}
return fields.join(',');
},
dataValue(){
let isarr = Array.isArray(this.value) && this.value.length === 0
let isstr = typeof this.value === 'string' && !this.value
let isnum = typeof this.value === 'number' && !this.value
if(isarr || isstr || isnum){
return this.modelValue
}
return this.value
}
dataValue() {
let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null || this.modelValue !== undefined)
return isModelValue ? this.modelValue : this.value
},
hasValue() {
if (typeof this.dataValue === 'number') {
return true
}
return (this.dataValue != null) && (this.dataValue.length > 0)
}
},
created() {
this.$watch(() => {
var al = [];
['pageCurrent',
'pageSize',
'spaceInfo',
'value',
'modelValue',
'localdata',
......@@ -172,7 +187,7 @@ export default {
},
getCommand(options = {}) {
/* eslint-disable no-undef */
let db = uniCloud.database()
let db = uniCloud.database(this.spaceInfo)
const action = options.action || this.action
if (action) {
......@@ -259,7 +274,7 @@ export default {
return
}
if (this.dataValue.length) {
if (this.dataValue != null) {
this._loadNodeData((data) => {
this._treeData = data
this._updateBindData()
......@@ -389,13 +404,15 @@ export default {
_updateSelected() {
var dl = this.dataList
var sl = this.selected
let textField = this.map.text
let valueField = this.map.value
for (var i = 0; i < sl.length; i++) {
var value = sl[i].value
var dl2 = dl[i]
for (var j = 0; j < dl2.length; j++) {
var item2 = dl2[j]
if (item2.value === value) {
sl[i].text = item2.text
if (item2[valueField] === value) {
sl[i].text = item2[textField]
break
}
}
......@@ -430,11 +447,10 @@ export default {
},
_filterData(data, paths) {
let dataList = []
let hasNodes = true
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++) {
var value = paths[i].value
......@@ -456,6 +472,7 @@ export default {
},
_extractTree(nodes, result, parent_value) {
let list = result || []
let valueField = this.map.value
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i]
......@@ -465,14 +482,14 @@ export default {
child[key] = node[key]
}
}
if (parent_value !== undefined) {
if (parent_value !== null && parent_value !== undefined && parent_value !== '') {
child.parent_value = parent_value
}
result.push(child)
let children = node.children
if (children) {
this._extractTree(children, result, node.value)
this._extractTree(children, result, node[valueField])
}
}
},
......@@ -496,12 +513,13 @@ export default {
}
},
_findNodePath(key, nodes, path = []) {
let textField = this.map.text
let valueField = this.map.value
for (let i = 0; i < nodes.length; i++) {
let {
value,
text,
children
} = nodes[i]
let node = nodes[i]
let children = node.children
let text = node[textField]
let value = node[valueField]
path.push({
value,
......@@ -526,7 +544,7 @@ export default {
_processLocalData() {
this._treeData = []
this._extractTree(this.localdata, this._treeData)
var inputValue = this.dataValue
if (inputValue === undefined) {
return
......@@ -534,8 +552,8 @@ export default {
if (Array.isArray(inputValue)) {
inputValue = inputValue[inputValue.length - 1]
if (typeof inputValue === 'object' && inputValue.value) {
inputValue = inputValue.value
if (typeof inputValue === 'object' && inputValue[this.map.value]) {
inputValue = inputValue[this.map.value]
}
}
......
<template>
<view class="uni-data-pickerview">
<scroll-view class="selected-area" scroll-x="true" scroll-y="false" :show-scrollbar="false">
<view class="selected-list">
<template v-for="(item,index) in selected">
<view class="selected-item" :class="{'selected-item-active':index==selectedIndex}"
:key="index" v-if="item.text" @click="handleSelect(index)">
<text class="">{{item.text}}</text>
<view class="uni-data-pickerview">
<scroll-view class="selected-area" scroll-x="true" scroll-y="false" :show-scrollbar="false">
<view class="selected-list">
<template v-for="(item,index) in selected">
<view class="selected-item"
:class="{'selected-item-active':index==selectedIndex, 'selected-item-text-overflow': ellipsis}"
:key="index" v-if="item.text" @click="handleSelect(index)">
<text class="">{{item.text}}</text>
</view>
</template>
</view>
</template>
</view>
</scroll-view>
<view class="tab-c">
<template v-for="(child, i) in dataList">
<scroll-view class="list" :key="i" v-if="i==selectedIndex" :scroll-y="true">
<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}}</text>
<view class="check" v-if="selected.length > i && item.value == selected[i].value"></view>
</view>
</scroll-view>
</template>
<view class="loading-cover" v-if="loading">
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
</view>
<view class="error-message" v-if="errorMessage">
<text class="error-text">{{errorMessage}}</text>
</view>
</view>
</view>
</scroll-view>
<view class="tab-c">
<template v-for="(child, i) in dataList">
<scroll-view class="list" :key="i" v-if="i==selectedIndex" :scroll-y="true">
<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>
<view class="check" v-if="selected.length > i && item[map.value] == selected[i].value"></view>
</view>
</scroll-view>
</template>
<view class="loading-cover" v-if="loading">
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
</view>
<view class="error-message" v-if="errorMessage">
<text class="error-text">{{errorMessage}}</text>
</view>
</view>
</view>
</template>
<script>
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
}
import dataPicker from "./uni-data-picker.js"
this.$nextTick(() => {
this.load()
})
},
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
}
/**
* 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
},
ellipsis: {
type: Boolean,
default: true
}
},
data() {
return {}
},
created() {
if (this.managedMode) {
return
}
const node = this.dataList[i][j]
const {
value,
text
} = node
this.$nextTick(() => {
this.load()
})
},
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) {
this.selected.splice(i, this.selected.length - i)
this.selected.push(node)
} else if (i === this.selected.length - 1) {
this.selected[i] = node
}
if (node.isleaf) {
this.onSelectedChange(node, node.isleaf)
return
}
if (node.isleaf) {
this.onSelectedChange(node, node.isleaf)
return
}
const {
isleaf,
hasNodes
} = this._updateBindData()
const {
isleaf,
hasNodes
} = this._updateBindData()
if (!this._isTreeView() && !hasNodes) {
this.onSelectedChange(node, true)
return
}
if (!this._isTreeView() && !hasNodes) {
this.onSelectedChange(node, true)
return
}
if (this.isLocaldata && (!hasNodes || isleaf)) {
this.onSelectedChange(node, true)
return
}
if (this.isLocaldata && (!hasNodes || isleaf)) {
this.onSelectedChange(node, true)
return
}
if (!isleaf && !hasNodes) {
this._loadNodeData((data) => {
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._loadNodeData((data) => {
if (!data.length) {
node.isleaf = true
} else {
this._treeData.push(...data)
this._updateBindData(node)
}
this.onSelectedChange(node, node.isleaf)
}, this._nodeWhere())
return
}
this.onSelectedChange(node, false)
},
updateData(data) {
this._treeData = data.treeData
this.selected = data.selected
if (!this._treeData.length) {
this.loadData()
} else {
//this.selected = data.selected
this._updateBindData()
}
},
onDataChange() {
this.$emit('datachange')
},
onSelectedChange(node, isleaf) {
if (isleaf) {
this._dispatchEvent()
}
this.onSelectedChange(node, false)
},
updateData(data) {
this._treeData = data.treeData
this.selected = data.selected
if (!this._treeData.length) {
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)
if (node) {
this.$emit('nodeclick', node)
}
},
_dispatchEvent() {
this.$emit('change', this.selected.slice(0))
}
}
},
_dispatchEvent() {
this.$emit('change', this.selected.slice(0))
}
}
}
}
</script>
<style scoped>
.uni-data-pickerview {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
overflow: hidden;
height: 100%;
}
.uni-data-pickerview {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
overflow: hidden;
height: 100%;
}
.error-text {
color: #DD524D;
}
.error-text {
color: #DD524D;
}
.loading-cover {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, .5);
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
align-items: center;
z-index: 1001;
}
.loading-cover {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, .5);
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
align-items: center;
z-index: 1001;
}
.load-more {
.load-more {
/* #ifndef APP-NVUE */
margin: auto;
margin: auto;
/* #endif */
}
}
.error-message {
background-color: #fff;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
padding: 15px;
opacity: .9;
z-index: 102;
}
.error-message {
background-color: #fff;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
padding: 15px;
opacity: .9;
z-index: 102;
}
/* #ifdef APP-NVUE */
.selected-area {
width: 750rpx;
}
/* #ifdef APP-NVUE */
.selected-area {
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 {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: nowrap;
padding: 0 5px;
border-bottom: 1px solid #f8f8f8;
}
.selected-item {
margin-left: 10px;
margin-right: 10px;
padding: 12px 0;
text-align: center;
/* #ifndef APP-NVUE */
white-space: nowrap;
/* #endif */
}
.selected-item {
margin-left: 10px;
margin-right: 10px;
padding: 12px 0;
.selected-item-text-overflow {
width: 168px;
/* fix nvue */
overflow: hidden;
/* #ifndef APP-NVUE */
width: 6em;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
/* #endif */
}
}
.selected-item-active {
border-bottom: 2px solid #007aff;
}
.selected-item-active {
border-bottom: 2px solid #007aff;
}
.selected-item-text {
color: #007aff;
}
.selected-item-text {
color: #007aff;
}
.tab-c {
position: relative;
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
overflow: hidden;
}
.tab-c {
position: relative;
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
overflow: hidden;
}
.list {
flex: 1;
}
.list {
flex: 1;
}
.item {
padding: 12px 15px;
border-bottom: 1px solid #f0f0f0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.item {
padding: 12px 15px;
border-bottom: 1px solid #f0f0f0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
}
.is-disabled {
opacity: .5;
}
.is-disabled {
opacity: .5;
}
.item-text {
flex: 1;
color: #333333;
}
.item-text {
/* flex: 1; */
color: #333333;
}
.check {
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>
.item-text-overflow {
width: 280px;
/* fix nvue */
overflow: hidden;
/* #ifndef APP-NVUE */
width: 20em;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
/* #endif */
}
.check {
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",
"displayName": "uni-data-picker 数据驱动的picker选择器",
"version": "0.4.0",
"description": "Picker选择器",
"version": "0.4.9",
"description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
"keywords": [
"uni-ui",
"uniui",
......@@ -43,7 +43,8 @@
},
"uni_modules": {
"dependencies": [
"uni-load-more"
"uni-load-more",
"uni-icons"
],
"encrypt": [],
"platforms": {
......@@ -79,6 +80,10 @@
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
......
......@@ -23,14 +23,9 @@
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
> - 组件需要依赖 `sass` 插件 ,请自行手动安装
> - 如使用过程中有任何问题,或者您对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`
......@@ -44,9 +39,12 @@
|属性名 | 类型 | 可选值 | 默认值 | 说明|
|:-: | :-: |:-: | :-: | :-: |
|v-model |String/ Number | - | - |绑定数据|
|spaceInfo |Object | | |服务空间配置,[详情](https://uniapp.dcloud.net.cn/uniCloud/init)|
|localdata |Array | | |数据,[详情](https://gitee.com/dcloud/datacom)|
|preload |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-search-url |String | | |分步查询时,动态加载云端数据url格式,`https://xxx.com/{parentValue}`(当前版本暂不支持,下版支持)|
|self-field |String | | |分步查询时当前字段名称|
......@@ -56,7 +54,7 @@
|where |String | | |查询条件,内容较多,另见jql文档:[详情](https://uniapp.dcloud.net.cn/uniCloud/uni-clientDB?id=jsquery)|
|orderby |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)
......@@ -73,6 +71,24 @@
|@popupopened |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)
- 新增 支持国际化
- 优化 范围选择器在 pc 端过宽的问题
......
......@@ -7,7 +7,7 @@
}" @click="choiceDate(weeks)" @mouseenter="handleMousemove(weeks)">
<view class="uni-calendar-item__weeks-box-item" :class="{
'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--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
......@@ -16,9 +16,6 @@
}">
<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 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>
</template>
......@@ -47,18 +44,18 @@
lunar: {
type: Boolean,
default: false
},
checkHover: {
type: Boolean,
default: false
},
checkHover: {
type: Boolean,
default: false
}
},
methods: {
choiceDate(weeks) {
this.$emit('change', weeks)
},
handleMousemove(weeks) {
this.$emit('handleMouse', weeks)
},
handleMousemove(weeks) {
this.$emit('handleMouse', weeks)
}
}
}
......@@ -72,12 +69,13 @@
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
align-items: center;
margin: 3px 0;
}
.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;
}
......@@ -94,13 +92,13 @@
flex-direction: column;
justify-content: center;
align-items: center;
width: 43px;
height: 43px;
width: 40px;
height: 40px;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
}
.uni-calendar-item__weeks-box-circle {
position: absolute;
......@@ -115,12 +113,12 @@
.uni-calendar-item__weeks-box .uni-calendar-item--disable {
// background-color: rgba(249, 249, 249, $uni-opacity-disabled);
color: $uni-text-color-disable;
color: $uni-text-color-disable;
cursor: default;
}
.uni-calendar-item--isDay-text {
color: $uni-color-primary !important;
.uni-calendar-item__weeks-box .uni-calendar-item--isDay-text {
color: $uni-color-primary;
}
.uni-calendar-item--isDay {
......@@ -134,17 +132,17 @@
opacity: 0.8;
}
.uni-calendar-item--checked {
background-color: $uni-color-primary;
// border-radius: 50%;
box-sizing: border-box;
.uni-calendar-item__weeks-box .uni-calendar-item--checked {
background-color: $uni-color-primary;
// border-radius: 50%;
box-sizing: border-box;
border: 6px solid #f2f6fc;
color: #fff;
opacity: 0.8;
}
.uni-calendar-item--multiple .uni-calendar-item--checked-range-text {
color: #333;
}
.uni-calendar-item--multiple .uni-calendar-item--checked-range-text {
color: #333;
}
.uni-calendar-item--multiple {
......@@ -155,29 +153,29 @@
.uni-calendar-item--multiple .uni-calendar-item--before-checked {
background-color: #409eff;
color: #fff !important;
// border-radius: 50%;
box-sizing: border-box;
color: #fff !important;
// border-radius: 50%;
box-sizing: border-box;
border: 6px solid #f2f6fc;
}
.uni-calendar-item--multiple .uni-calendar-item--after-checked {
background-color: #409eff;;
color: #fff !important;
// border-radius: 50%;
box-sizing: border-box;
color: #fff !important;
// border-radius: 50%;
box-sizing: border-box;
border: 6px solid #f2f6fc;
}
.uni-calendar-item--before-checked-x {
// border-top-left-radius: 25px;
// border-bottom-left-radius: 25px;
background-color: #f2f6fc;
}
.uni-calendar-item--after-checked-x {
// border-top-right-radius: 25px;
// border-bottom-right-radius: 25px;
background-color: #f2f6fc;
}
</style>
}
.uni-calendar-item--before-checked-x {
// border-top-left-radius: 25px;
// border-bottom-left-radius: 25px;
background-color: #f2f6fc;
}
.uni-calendar-item--after-checked-x {
// border-top-right-radius: 25px;
// border-bottom-right-radius: 25px;
background-color: #f2f6fc;
}
</style>
......@@ -10,8 +10,7 @@
<view class="uni-calendar__header-btn uni-calendar--left"></view>
</view>
<picker mode="date" :value="date" fields="month" @change="bindDateChange">
<text
class="uni-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
<text class="uni-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
</picker>
<view v-if="right" class="uni-calendar__header-btn-box" @click.stop="next">
<view class="uni-calendar__header-btn uni-calendar--right"></view>
......@@ -56,29 +55,29 @@
</view>
</view>
<view v-if="!insert && !range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top"
style="padding: 0 40px;">
<text class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</text>
style="padding: 0 80px;">
<view class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</view>
<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>
</view>
<view v-if="!insert && range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top">
<view class="uni-date-changed--time-start">
<text class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}}</text>
<time-picker type="time" :start="reactStartTime" v-model="timeRange.startTime" :border="false"
<view class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}}
</view>
<time-picker type="time" :start="reactStartTime" v-model="timeRange.startTime" :border="false" :hide-second="hideSecond"
:disabled="!tempRange.before" class="time-picker-style">
</time-picker>
</view>
<uni-icons type="arrowthinright" color="#999" style="line-height: 50px;"></uni-icons>
<view class="uni-date-changed--time-end">
<text class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : endDateText}}</text>
<time-picker type="time" :end="reactEndTime" v-model="timeRange.endTime" :border="false"
<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" :hide-second="hideSecond"
:disabled="!tempRange.after" class="time-picker-style">
</time-picker>
</view>
</view>
<view v-if="!insert" class="uni-date-changed uni-calendar__header" @click="confirm">
<view class="uni-calendar__header-btn-box">
<text class="uni-calendar__button-text uni-calendar--fixed-width">{{okText}}</text>
......@@ -96,7 +95,9 @@
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from './i18n/index.js'
const { t } = initVueI18n(messages)
const {
t
} = initVueI18n(messages)
/**
* Calendar 日历
* @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
......@@ -186,6 +187,10 @@
checkHover: {
type: Boolean,
default: true
},
hideSecond: {
type: [Boolean],
default: false
},
pleStatus: {
type: Object,
......@@ -207,12 +212,12 @@
nowDate: '',
aniMaskShow: false,
firstEnter: true,
time: this.defTime ? this.defTime : '',
time: '',
timeRange: {
startTime: this.defTime.start ? this.defTime.start : '',
endTime: this.defTime.end ? this.defTime.end : ''
startTime: '',
endTime: ''
},
tempSingleDate: this.date,
tempSingleDate: '',
tempRange: {
before: '',
after: ''
......@@ -223,11 +228,25 @@
date: {
immediate: true,
handler(newVal, oldVal) {
if (!this.range)
setTimeout(() => {
this.init(newVal)
}, 100)
if (!this.range) {
this.tempSingleDate = newVal
setTimeout(() => {
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) {
this.cale.resetSatrtDate(val)
......@@ -261,8 +280,7 @@
this.cale.lastHover = true
if (this.rangeWithinMonth(after, before)) return
this.setDate(before)
}
if (!before && !after) {
} else {
this.cale.setMultiple(fulldate)
this.setDate(this.nowDate.fullDate)
this.calendar.fullDate = ''
......@@ -380,9 +398,26 @@
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) {
const value = e.detail.value + '-1'
console.log(this.cale.getDate(value));
this.init(value)
},
/**
......@@ -494,6 +529,7 @@
choiceDate(weeks) {
if (weeks.disable) return
this.calendar = weeks
this.calendar.userChecked = true
// 设置多选
this.cale.setMultiple(this.calendar.fullDate, true)
this.weeks = this.cale.weeks
......@@ -506,7 +542,6 @@
* 回到今天
*/
backtoday() {
console.log(this.cale.getDate(new Date()).fullDate);
let date = this.cale.getDate(new Date()).fullDate
// this.cale.setDate(date)
this.init(date)
......@@ -678,14 +713,14 @@
}
.uni-calendar__header-btn {
width: 10px;
height: 10px;
width: 8px;
height: 8px;
border-left-color: $uni-text-color-placeholder;
border-left-style: solid;
border-left-width: 2px;
border-left-width: 1px;
border-top-color: $uni-color-subtitle;
border-top-style: solid;
border-top-width: 2px;
border-top-width: 1px;
}
.uni-calendar--left {
......@@ -717,14 +752,14 @@
flex-direction: column;
justify-content: center;
align-items: center;
height: 45px;
height: 40px;
border-bottom-color: #F5F5F5;
border-bottom-style: solid;
border-bottom-width: 1px;
}
.uni-calendar__weeks-day-text {
font-size: 14px;
font-size: 12px;
}
.uni-calendar__box {
......@@ -783,11 +818,12 @@
.uni-date-changed--time-date {
color: #999;
line-height: 50px;
margin-right: 5px;
// opacity: 0.6;
}
.time-picker-style {
width: 62px;
// width: 62px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
......@@ -798,4 +834,4 @@
.mr-10 {
margin-right: 10px;
}
</style>
</style>
......@@ -124,7 +124,7 @@
// 输入框当前时间
time: '',
// 当前的年月日时分秒
year: 1900,
year: 1920,
month: 0,
day: 0,
hour: 0,
......@@ -190,7 +190,8 @@
if (newVal) {
this.parseValue(this.fixIosDateFormat(newVal)) //兼容 iOS、safari 日期格式
this.initTime(false)
} else {
} else {
this.time = ''
this.parseValue(Date.now())
}
},
......@@ -538,7 +539,9 @@
* @param {Object} defaultTime
*/
parseValue(value) {
if (!value) return
if (!value) {
return
}
if (this.type === 'time' && typeof value === "string") {
this.parseTimeType(value)
} else {
......@@ -576,7 +579,7 @@
this.startSecond = 0
}
if (pointType === 'end') {
this.endYear = 120
this.endYear = 2120
this.endMonth = 12
this.endDay = 31
this.endHour = 23
......@@ -770,7 +773,7 @@
<style>
.uni-datetime-picker {
/* #ifndef APP-NVUE */
width: 100%;
/* width: 100%; */
/* #endif */
}
......
......@@ -8,8 +8,8 @@
<view class="uni-date__icon-logo">
<image class="uni-date-editor--logo" :src="iconBase64" mode=""></image>
</view>
<input class="uni-date__x-input" type="text" v-model="singleVal" :placeholder="singlePlaceholderText"
:disabled="true" />
<input class="uni-date__x-input" type="text" v-model="singleVal"
:placeholder="singlePlaceholderText" :disabled="true" />
</view>
<view v-else class="uni-date-x uni-date-range">
<view class="uni-date__icon-logo">
......@@ -23,8 +23,7 @@
<input class="uni-date__x-input t-c" type="text" v-model="range.endDate"
:placeholder="endPlaceholderText" :disabled="true" />
</view>
<view
v-show="clearIcon && !disabled && !isPhone && (singleVal || (range.startDate && range.endDate))"
<view v-show="clearIcon && !disabled && (singleVal || (range.startDate && range.endDate))"
class="uni-date__icon-clear" @click.stop="clear">
<uni-icons type="clear" color="#e1e1e1" size="14"></uni-icons>
</view>
......@@ -39,12 +38,14 @@
<input class="uni-date__input t-c" type="text" v-model="tempSingleDate"
:placeholder="selectDateText" />
<time-picker type="time" v-model="time" :border="false" :disabled="!tempSingleDate"
:start="reactStartTime" :end="reactEndTime">
<input class="uni-date__input t-c" type="text" v-model="time" :placeholder="selectTimeText" :disabled="!tempSingleDate" />
: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" />
</time-picker>
</view>
<calendar ref="pcSingle" class="uni-date_calendar-pc" :showMonth="false" :start-date="caleRange.startDate"
:end-date="caleRange.endDate" :date="defSingleDate" @change="singleChange" />
<calendar ref="pcSingle" class="uni-date_calendar-pc" :showMonth="false"
:start-date="caleRange.startDate" :end-date="caleRange.endDate" :date="defSingleDate"
@change="singleChange" />
<view v-if="hasTime" class="popup-x-footer">
<!-- <text class="">此刻</text> -->
<text class="confirm" @click="confirmSingleChange">{{okText}}</text>
......@@ -58,9 +59,10 @@
<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.startDate"
:placeholder="startDateText" />
<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"
v-model="tempRange.startTime" :placeholder="startTimeText" :disabled="!tempRange.startDate" />
v-model="tempRange.startTime" :placeholder="startTimeText"
:disabled="!tempRange.startDate" />
</time-picker>
</view>
<uni-icons type="arrowthinright" color="#999" style="line-height: 40px;"></uni-icons>
......@@ -68,19 +70,20 @@
<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endDate"
:placeholder="endDateText" />
<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"
:placeholder="endTimeText" :disabled="!tempRange.endDate" />
</time-picker>
</view>
</view>
<view class="popup-x-body">
<calendar ref="left" class="uni-date_calendar-pc" :showMonth="false" :start-date="caleRange.startDate"
:end-date="caleRange.endDate" :range="true" @change="leftChange" :pleStatus="endMultipleStatus"
@firstEnterCale="updateRightCale" @monthSwitch="leftMonthSwitch" />
<calendar ref="right" class="uni-date_calendar-pc" :showMonth="false" :start-date="caleRange.startDate"
:end-date="caleRange.endDate" :range="true" @change="rightChange"
:pleStatus="startMultipleStatus" @firstEnterCale="updateLeftCale"
<calendar ref="left" class="uni-date_calendar-pc" :showMonth="false"
:start-date="caleRange.startDate" :end-date="caleRange.endDate" :range="true"
@change="leftChange" :pleStatus="endMultipleStatus" @firstEnterCale="updateRightCale"
@monthSwitch="leftMonthSwitch" />
<calendar ref="right" class="uni-date_calendar-pc" :showMonth="false"
:start-date="caleRange.startDate" :end-date="caleRange.endDate" :range="true"
@change="rightChange" :pleStatus="startMultipleStatus" @firstEnterCale="updateLeftCale"
@monthSwitch="rightMonthSwitch" style="border-left: 1px solid #F1F1F1;" />
</view>
<view v-if="hasTime" class="popup-x-footer">
......@@ -92,7 +95,7 @@
<calendar v-if="isPhone" ref="mobile" :clearDate="false" :date="defSingleDate" :defTime="reactMobDefTime"
:start-date="caleRange.startDate" :end-date="caleRange.endDate" :selectableTimes="mobSelectableTime"
:pleStatus="endMultipleStatus" :showMonth="false" :range="isRange" :typeHasTime="hasTime" :insert="false"
@confirm="mobileChange" />
:hideSecond="hideSecond" @confirm="mobileChange" />
</view>
</template>
<script>
......@@ -119,7 +122,9 @@
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from './i18n/index.js'
const { t } = initVueI18n(messages)
const {
t
} = initVueI18n(messages)
export default {
name: 'UniDatetimePicker',
......@@ -230,6 +235,10 @@
clearIcon: {
type: [Boolean],
default: true
},
hideSecond: {
type: [Boolean],
default: false
}
},
watch: {
......@@ -300,11 +309,12 @@
const res = activeDate === this.caleRange.endDate ? this.caleRange.endTime : ''
return res
},
reactMobDefTime() {
return this.isRange ? {
reactMobDefTime() {
const times = {
start: this.tempRange.startTime,
end: this.tempRange.endTime
} : this.time
}
return this.isRange ? times : this.time
},
mobSelectableTime() {
return {
......@@ -321,7 +331,8 @@
* for i18n
*/
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() {
return this.startPlaceholder || this.startDateText
......@@ -366,7 +377,7 @@
// }
},
mounted() {
this.platform()
this.platform()
},
methods: {
/**
......@@ -426,7 +437,7 @@
})
this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, defaultRange, {
which: 'left'
})
})
}
},
updateLeftCale(e) {
......@@ -671,11 +682,12 @@
clear(needEmit = true) {
if (!this.isRange) {
this.singleVal = ''
this.tempSingleDate = ''
this.time = ''
if (this.isPhone) {
this.defSingleDate = ''
this.$refs.mobile.clearCalender()
} else {
this.$refs.pcSingle.calendar.fullDate = ''
this.$refs.pcSingle.setDate()
this.$refs.pcSingle.clearCalender()
}
if (needEmit) {
this.formItem && this.formItem.setValue('')
......@@ -686,27 +698,15 @@
} else {
this.range.startDate = ''
this.range.endDate = ''
this.tempRange = {}
this.tempRange.startDate= ''
this.tempRange.startTime= ''
this.tempRange.endDate= ''
this.tempRange.endTime= ''
if (this.isPhone) {
this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, {
before: '',
after: '',
data: [],
fulldate: ''
}, {
which: 'left'
})
this.$refs.mobile.clearCalender()
} else {
this.$refs.left.cale.multipleStatus.before = ''
this.$refs.left.cale.multipleStatus.after = ''
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.left.clearCalender()
this.$refs.right.clearCalender()
this.$refs.right.next()
}
if (needEmit) {
......@@ -728,7 +728,7 @@
const minute = defVal.getMinutes()
const second = defVal.getSeconds()
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 {
defDate,
defTime
......@@ -798,12 +798,12 @@
height: 40px;
width: 100%;
line-height: 40px;
font-size: 14px;
font-size: 14px;
}
.t-c {
text-align: center;
}
.t-c {
text-align: center;
}
.uni-date__input {
height: 40px;
......@@ -813,8 +813,8 @@
}
.uni-date-range__input {
text-align: center;
max-width: 152px;
text-align: center;
max-width: 142px;
}
.uni-date-picker__container {
......@@ -945,6 +945,7 @@
.mr-50 {
margin-right: 50px;
}
.uni-date_calendar-pc {
padding: 0 6px;
}
......
......@@ -143,14 +143,14 @@ class Calendar {
let disableAfter = true
if (this.startDate) {
// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
disableBefore = this.dateCompare(this.startDate, nowDate)
// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
disableBefore = this.dateCompare(this.startDate, nowDate)
}
if (this.endDate) {
// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
disableAfter = this.dateCompare(nowDate, this.endDate)
// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
disableAfter = this.dateCompare(nowDate, this.endDate)
}
let multiples = this.multipleStatus.data
let checked = false
......@@ -175,7 +175,8 @@ class Calendar {
month: full.month,
lunar: this.getlunar(full.year, full.month, i),
disable: !(disableBefore && disableAfter),
isDay
isDay,
userChecked: false
}
if (info) {
data.extraInfo = info
......@@ -294,7 +295,7 @@ class Calendar {
this.lastHover = true
return
}
this.multipleStatus.before = ''
this.multipleStatus.before = fullDate
this.multipleStatus.after = ''
this.multipleStatus.data = []
this.multipleStatus.fulldate = ''
......@@ -347,16 +348,16 @@ class Calendar {
*/
setDefaultMultiple(before, after) {
this.multipleStatus.before = before
this.multipleStatus.after = after
if (before && after) {
if (this.dateCompare(before, after)) {
this.multipleStatus.data = this.geDateAll(before, after);
this._getWeek(after)
} else {
this.multipleStatus.data = this.geDateAll(after, before);
this._getWeek(before)
}
}
this.multipleStatus.after = after
if (before && after) {
if (this.dateCompare(before, after)) {
this.multipleStatus.data = this.geDateAll(before, after);
this._getWeek(after)
} else {
this.multipleStatus.data = this.geDateAll(after, before);
this._getWeek(before)
}
}
}
/**
......@@ -405,4 +406,4 @@ class Calendar {
}
export default Calendar
export default Calendar
{
"id": "uni-datetime-picker",
"displayName": "uni-datetime-picker 日期选择器",
"version": "2.1.1",
"version": "2.1.4",
"description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
"keywords": [
"uni-datetime-picker",
......@@ -81,7 +81,7 @@
},
"Vue": {
"vue2": "y",
"vue3": "u"
"vue3": "y"
}
}
}
......
......@@ -125,13 +125,14 @@ ___点击 picker 默认值规则:___
|start |String、Number |- |- |最小值,可以使用日期的字符串(String)、时间戳(Number) |
|end |String、Number |- |- |最大值,可以使用日期的字符串(String)、时间戳(Number) |
|return-type |String |string |timestamp 、string、date |返回值格式 |
|border |Boolean、String |true | |是否有边框 |
|border |Boolean |true | |是否有边框 |
|rangeSeparator |String |'-' |- |选择范围时的分隔符 |
|placeholder |String |- |- |非范围选择时的占位内容 |
|start-placeholder|String |- |- |范围选择时开始日期的占位内容 |
|end-placeholder |String |- |- |范围选择时结束日期的占位内容 |
|disabled |Boolean、String |false | |是否不可选择 |
|clearIcon |Boolean、String |true | |是否显示清除按钮(仅PC端适用) |
|disabled |Boolean |false | |是否不可选择 |
|clear-icon |Boolean |true | |是否显示清除按钮 |
|hide-second |Boolean |false | |是否显示秒,只显示时分 |
......@@ -149,6 +150,9 @@ ___点击 picker 默认值规则:___
|:-:|:-:|:-:|
|show|打开弹出层|-|
|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)
- 修复 邀请码可能重复的Bug
## 3.3.5(2021-08-10)
......
{
"id": "uni-id",
"displayName": "uni-id",
"version": "3.3.6",
"version": "3.3.9",
"description": "简单、统一、可扩展的用户中心",
"keywords": [
"uniid",
......
{
"name": "uni-id",
"version": "3.3.6",
"version": "3.3.9",
"description": "uni-id for uniCloud",
"main": "index.js",
"homepage": "https://uniapp.dcloud.io/uniCloud/uni-id",
......
## 1.0.3(2021-11-20)
新增支持看激励视频广告签到
## 1.0.2(2021-08-25)
修复时区问题
## 1.0.1(2021-08-23)
......
......@@ -44,6 +44,8 @@
<script>
const db = uniCloud.database();
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 {
name: "uni-signIn",
data() {
......@@ -59,52 +61,124 @@
},
mounted() {},
methods: {
closeMe(e) {
this.$refs.popup.close()
async getSignedInInfo(ToastText = '今日已签过') {
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() {
uni.showLoading({
mask: true
});
try{
const date = new Date(new Date().toLocaleDateString()).getTime()
let res = await signInTable
.where(`'user_id' == $env.uid && 'date' == ${date} && 'isDelete' == false`)
.get()
this.signInRes = res.result
console.log(res);
if (res.result.data.length) {
uni.hideLoading()
uni.showToast({
title: '今日已签过',
duration: 3000,
icon: 'none'
});
} else {
let res = await signInTable.add({});
console.log(res);
uni.hideLoading()
this.signInRes = res.result
if (this.signInRes.days.length == 7) {
uni.showToast({
title: "你已完成7日连续签到,获得60积分!",
icon: "none",
duration: 5000
})
} else {
uni.showToast({
title: "签到成功,获得10积分!",
icon: "none",
duration: 5000
})
}
}
this.$refs.popup.open()
}catch(e){
console.error(e)
uni.hideLoading()
});
try {
let res = await this.getSignedInInfo();
if (res && res.length == 0) {
let res = await signInTable.add({});
console.log(res);
uni.hideLoading()
this.signInRes = res.result
this.$refs.popup.open()
if (this.signInRes.days.length == 7) {
uni.showToast({
title: "你已完成7日连续签到,获得60积分!",
icon: "none",
duration: 5000
})
} else {
uni.showToast({
title: "签到成功,获得10积分!",
icon: "none",
duration: 5000
})
}
}
} catch (e) {
uni.hideLoading()
console.error(e)
}
},
closeMe(e) {
this.$refs.popup.close()
}
}
}
......@@ -117,6 +191,10 @@
flex-direction: column;
}
scroll-view {
-webkit-overflow-scrolling: touch;
}
.background-img {
width: 600rpx;
height: 600rpx;
......
{
"id": "uni-sign-in",
"displayName": "签到插件",
"version": "1.0.2",
"version": "1.0.3",
"description": "uni-sign-in",
"keywords": [
"uni-sign-in",
......
#### 简介:培养应用用户习惯,提升用户粘性。签到得积分的应用营销功能
#### 简介:培养用户习惯,提升用户粘性。签到得积分的应用营销功能,广告流量变现
#### 功能支持:
1. 每日签到奖励
1. 每日签到奖励 (支持:普通签到、看广告签到)
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
......@@ -12,8 +36,11 @@
<script>
export default {
methods: {
signIn() { //签到
this.$refs.signIn.open()
signIn() { //普通签到
this.$refs.signIn.open()
},
signInByAd(){ //看激励视频广告签到
this.$refs.signIn.showRewardedVideoAd()
}
}
}
......@@ -22,6 +49,7 @@
> 详情参考[uni-starter](https://ext.dcloud.net.cn/plugin?id=5057)
##### 插件组成
1. 前端组件
......@@ -36,14 +64,17 @@
- 前置操作,添加操作时检查今日是否未签到,否则拦截
- 后置操作,判断是否已经连续签到7天,决定本次签到用户可得积分
- 后置操作,输出本轮已签到几天,当前积分,已签到的日期数组,本轮签到可得多少分
4. 两个api接口
普通签到`this.$refs.signIn.open()`
看激励视频广告签到`this.$refs.signIn.showRewardedVideoAd()`
#### 常见问题
1. 是否支持配置积分数
答:暂不支持,今后的版本有计划支持
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 @@
"required": [],
"permission": {
"read": "auth.uid == doc.user_id",
"create": "auth.uid != null && 'signIn' in action",
"create": "auth.uid != null && 'signIn' in action", //如果你要使用`看广告签到`的方式请将这里的值改为:false
"update": 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.
先完成此消息的编辑!
想要评论请 注册