Commit 343da196 authored by 贾慧斌's avatar 贾慧斌

feat: 更新文件

parent 8fa0495e
<template>
<view class="Hl-container-item">
<view class="Hlc-title">失效</view>
<image lazy-load class="Hlc-item-img" mode="aspectFit" :src="goods.skuImg" />
<view class="Hlc-item-info">
<view class="Hlc-item-info-title">
<text v-if="goods.textTag" class="Hlc-item-info-title-tag">{{ goods.textTag }}</text>
<text class="Hlc-item-info-title-name"
><text class="name"> {{ goods.skuName }}</text></text
>
</view>
<view class="Hlc-item-info-bottom">
<view class="Hlc-item-info-bottom-des">{{ goods.invalidStatusDesc }}</view>
<!-- 仅羊小咩展示看相似 2021.11.25 -->
<view v-if="$config('yxm')" class="Hlc-item-info-bottom-btn"
><button class="similar" @click="goSimilar">看相似</button></view
>
</view>
</view>
</view>
</template>
<script>
import { saTrackEvent } from "@/utils/sa.js";
export default {
name: "DisabledGoodsCard",
props: {
goods: {
type: Object,
default: () => {}
}
},
data() {
return {
options: [
{
text: "删除",
style: {
backgroundColor: "#F43530"
}
}
]
};
},
methods: {
delGood(goods) {
this.$emit("delGood", goods);
},
goSimilar() {
saTrackEvent("MINI_ShoppingCartPageViewSimilarityBtnClick", {
sku_no: this.goods.skuId
});
uni.navigateTo({
url: `/pages/product/similar?skuNo=${this.goods.skuId}&goodsName=${this.goods.skuName}&goodsImage=${this.goods.skuImg}&des=${this.goods.invalidStatusDesc}`
});
}
}
};
</script>
<style lang="scss" scoped>
.Hl-container-item {
display: flex;
// margin: 40rpx 0;
align-items: center;
justify-content: space-around;
width: 100%;
padding: 20rpx 0rpx;
.Hlc-title {
color: #fff;
background: #979797;
border-radius: 30rpx;
height: 30rpx;
line-height: 30rpx;
width: 64rpx;
text-align: center;
font-size: 20rpx;
}
.Hlc-item-img {
max-width: 200rpx;
height: 200rpx;
border-radius: 12rpx;
opacity: 0.5;
margin-left: 12rpx;
// background: #aaa;
}
.Hlc-item-info {
width: 365rpx;
height: 200rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
margin: 0 20rpx;
position: relative;
&-title {
position: relative;
opacity: 0.5;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
&-name {
.name {
font-size: 26rpx;
line-height: 36rpx;
color: #333333;
}
.blank {
width: 10rpx;
}
}
&-tag {
font-size: 20rpx;
color: #fff;
background: red;
border-radius: 6rpx;
padding: 0 6rpx;
margin-right: 10rpx;
}
}
&-bottom {
position: absolute;
bottom: 0rpx;
display: flex;
align-items: center;
justify-content: space-around;
width: 100%;
padding-right: 1px;
&-des {
font-size: 26rpx;
// line-height: 36rpx;
width: 60%;
color: #333333;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
&-btn {
width: 40%;
.similar {
height: 60rpx;
line-height: 60rpx;
font-size: 28rpx;
// font-weight: bold;
border-radius: $border-radius-2;
border: $border-sm solid $border-color-search;
// background: $white;
color: $font-color-search;
padding: 0 $padding-sm;
background: #fff;
}
}
}
}
}
</style>
<template>
<view v-if="!isClear && goodsList.length" class="disabledGoods">
<view v-if="goodsList.length" class="disabledGoods-header">
<view class="disabledGoods-header-title">失效商品</view>
<view class="disabledGoods-header-clear" @click="clearDisabledGoods">清空失效商品</view>
</view>
<view class="disabledGoods-list">
<uni-swipe-action>
<view v-for="item in goodsList" :key="item" class="disabledGoods-list-item">
<uni-swipe-action-item :right-options="options" auto-close @click="delGood(item)">
<cardList :goods="item" />
</uni-swipe-action-item>
</view>
</uni-swipe-action>
</view>
<uni-popup ref="confirmPop">
<uni-popup-dialog
type="base"
content="确定删除失效商品吗?"
message=""
title=" "
:duration="2000"
:before-close="true"
cancel-txt="再想想"
confirm-txt="删除"
warning-btn="cancel"
@confirm="confirm(goodsList, true)"
@cancle="cancel"
/>
</uni-popup>
</view>
</template>
<script>
import cardList from "./cardList";
import uniPopupDialog from "@/components/uni-popup/uni-popup-dialog";
import { getInvalidList, addSkuToCart } from "../../api/home.api.js";
import { mapActions } from "@/pages/shopcart/shopCartModules.js";
import uniSwipeAction from "@/components/uni-swipe-action";
import uniSwipeActionItem from "@/components/uni-swipe-action-item";
export default {
name: "DisabledGoodsCard",
components: {
cardList,
uniPopupDialog,
uniSwipeAction,
uniSwipeActionItem
},
data() {
return {
goodsList: [],
isClear: false,
options: [
{
text: "删除",
style: {
backgroundColor: "#F43530"
}
}
]
};
},
mounted() {
this.getList();
uni.$on("updateInvalid", () => this.getList());
},
beforeDestroy() {
uni.$off("updateInvalid");
},
methods: {
...mapActions({
querCartCount: "queryCartCount"
}),
async getList() {
const [data] = await getInvalidList({ pageNo: 1, pageSize: 120 });
this.goodsList = data.invalidSkuList || [];
},
clearDisabledGoods() {
this.$refs["confirmPop"].open();
},
async delGood(goods) {
this.confirm([goods]);
},
async confirm(goodsList, isClear) {
goodsList.forEach(item => {
item.type = 4;
});
const [data] = await addSkuToCart({ shopCartBaseList: goodsList });
if (data) {
if (isClear) {
this.isClear = true;
uni.showToast({
title: "无效商品已清空",
icon: "none"
});
}
if (!isClear) {
uni.showToast({
title: "商品已删除",
icon: "none"
});
}
this.getList();
this.querCartCount();
}
}
}
};
</script>
<style lang="scss" scoped>
.disabledGoods {
background: #fff;
padding: $padding-md;
border-radius: 10rpx;
// margin-top: 20px;
&-header {
display: flex;
justify-content: space-between;
align-items: center;
&-title {
font-weight: bold;
font-size: $uni-font-size-md;
}
&-clear {
color: $uni-color-error;
font-size: $uni-font-size-md;
}
}
&-list {
width: 100%;
&-item {
margin: 40rpx 0;
}
}
}
</style>
<template>
<view class="uploader">
<view v-for="(item, index) in queue" :key="index" class="uploaded">
<image :src="item.url" />
<icon class="close" type="clear" :size="18" @click="remove(index)" />
</view>
<view v-if="!limited" class="upload" @click="upload">
<image src="https://img.lkbang.net/xcx/pic.png" mode="aspectFit" />
<view>
<text class="tips">最多{{ maxCount }}</text>
</view>
</view>
</view>
</template>
<script>
import qiniu from "./qiniu";
export default {
name: "ImageUploader",
props: {
maxCount: {
type: Number,
default: 3
}
},
data() {
return {
queue: [],
uploader: null
// cancelTask: function() {},
};
},
computed: {
limited() {
return this.queue.length >= this.maxCount;
}
},
created() {
this.initQiniu();
this.uploader = qiniu;
},
methods: {
upload() {
uni.chooseImage({
count: 1,
sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
sourceType: ["album"], //从相册选择
success: res => {
uni.showLoading({
title: "上传中"
});
this.uploader.upload(
res.tempFilePaths[0],
this.uploadSuccess,
this.uploadFail,
null,
this.uploadProgress,
// eslint-disable-next-line no-unused-vars
cancelTask => {}
);
}
});
},
uploadSuccess(res) {
uni.hideLoading();
this.queue.push({
url: res.fileURL
});
this.onChange();
},
uploadFail(err) {
console.error(err);
uni.hideLoading();
},
uploadProgress() {},
remove(index) {
this.queue.splice(index, 1);
this.onChange();
},
onChange() {
this.$emit("change", JSON.parse(JSON.stringify(this.queue)));
},
initQiniu() {
const option = {
region: "ECN",
uptokenURL: "https://mapi.q-gp.com/upload/token",
domain: "https://appsync.lkbang.net",
shouldUseQiniuFileName: true
};
qiniu.init(option);
}
}
};
</script>
<style lang="scss" scoped>
.uploader {
display: flex;
flex-direction: row;
flex-wrap: wrap;
.upload {
width: 170rpx;
height: 170rpx;
border: 1px dashed #999;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
image {
width: 40rpx;
height: 36rpx;
}
.tips {
font-size: 24rpx;
color: #999;
}
}
.uploaded {
width: 170rpx;
height: 170rpx;
margin-right: 30rpx;
margin-bottom: 20rpx;
position: relative;
image {
width: 100%;
height: 100%;
}
.close {
position: absolute;
top: 0;
right: 0;
transform: translate(50%, -50%);
}
}
}
</style>
(function() {
// 请参考demo的index.js中的initQiniu()方法,若在使用处对options进行了赋值,则此处config不需要赋默认值。init(options) 即updateConfigWithOptions(options),会对config进行赋值
var config = {
// bucket 所在区域。ECN, SCN, NCN, NA, ASG,分别对应七牛云的:华东,华南,华北,北美,新加坡 5 个区域
qiniuRegion: "",
// 七牛云bucket 外链前缀,外链在下载资源时用到
qiniuBucketURLPrefix: "",
// 获取uptoken方法三选一即可,执行优先级为:uptoken > uptokenURL > uptokenFunc。三选一,剩下两个置空。推荐使用uptokenURL,详情请见 README.md
// 由其他程序生成七牛云uptoken,然后直接写入uptoken
qiniuUploadToken: "",
// 从指定 url 通过 HTTP GET 获取 uptoken,返回的格式必须是 json 且包含 uptoken 字段,例如: {"uptoken": "0MLvWPnyy..."}
qiniuUploadTokenURL: "",
// uptokenFunc 这个属性的值可以是一个用来生成uptoken的函数,详情请见 README.md
qiniuUploadTokenFunction: function() {},
// qiniuShouldUseQiniuFileName 如果是 true,则文件的 key 由 qiniu 服务器分配(全局去重)。如果是 false,则文件的 key 使用微信自动生成的 filename。出于初代sdk用户升级后兼容问题的考虑,默认是 false。
// 微信自动生成的 filename较长,导致fileURL较长。推荐使用{qiniuShouldUseQiniuFileName: true} + "通过fileURL下载文件时,自定义下载名" 的组合方式。
// 自定义上传key 需要两个条件:1. 此处shouldUseQiniuFileName值为false。 2. 通过修改qiniuUploader.upload方法传入的options参数,可以进行自定义key。(请不要直接在sdk中修改options参数,修改方法请见demo的index.js)
// 通过fileURL下载文件时,自定义下载名,请参考:七牛云“对象存储 > 产品手册 > 下载资源 > 下载设置 > 自定义资源下载名”(https://developer.qiniu.com/kodo/manual/1659/download-setting)。本sdk在README.md的"常见问题"板块中,有"通过fileURL下载文件时,自定义下载名"使用样例。
qiniuShouldUseQiniuFileName: false
};
// init(options) 将七牛云相关配置初始化进本sdk
// 在整个程序生命周期中,只需要 init(options); 一次即可
// 如果需要变更七牛云配置,再次调用 init(options); 即可
function init(options) {
updateConfigWithOptions(options);
}
// 更新七牛云配置
function updateConfigWithOptions(options) {
if (options.region) {
config.qiniuRegion = options.region;
} else {
console.error("qiniu uploader need your bucket region");
}
if (options.uptoken) {
config.qiniuUploadToken = options.uptoken;
} else if (options.uptokenURL) {
config.qiniuUploadTokenURL = options.uptokenURL;
} else if (options.uptokenFunc) {
config.qiniuUploadTokenFunction = options.uptokenFunc;
}
if (options.domain) {
config.qiniuBucketURLPrefix = options.domain;
}
config.qiniuShouldUseQiniuFileName = options.shouldUseQiniuFileName;
}
// 正式上传的前置方法,做预处理,应用七牛云配置
function upload(filePath, success, fail, options, progress, cancelTask) {
if (null == filePath) {
console.error("qiniu uploader need filePath to upload");
return;
}
if (options) {
updateConfigWithOptions(options);
}
if (config.qiniuUploadToken) {
doUpload(filePath, success, fail, options, progress, cancelTask);
} else if (config.qiniuUploadTokenURL) {
getQiniuToken(function() {
doUpload(filePath, success, fail, options, progress, cancelTask);
});
} else if (config.qiniuUploadTokenFunction) {
config.qiniuUploadToken = config.qiniuUploadTokenFunction();
if (null == config.qiniuUploadToken && config.qiniuUploadToken.length > 0) {
console.error("qiniu UploadTokenFunction result is null, please check the return value");
return;
}
doUpload(filePath, success, fail, options, progress, cancelTask);
} else {
console.error("qiniu uploader need one of [uptoken, uptokenURL, uptokenFunc]");
return;
}
}
// 正式上传
function doUpload(filePath, success, fail, options, progress, cancelTask) {
if (null == config.qiniuUploadToken && config.qiniuUploadToken.length > 0) {
console.error("qiniu UploadToken is null, please check the init config or networking");
return;
}
var url = uploadURLFromRegionCode(config.qiniuRegion);
var fileName = filePath.split("//")[1];
// 自定义上传key(即自定义上传文件名)。通过修改qiniuUploader.upload方法传入的options参数,可以进行自定义文件名称。如果options非空,则使用options中的key作为fileName
if (options && options.key) {
fileName = options.key;
}
var formData = {
token: config.qiniuUploadToken
};
// qiniuShouldUseQiniuFileName 如果是 true,则文件的 key 由 qiniu 服务器分配(全局去重)。如果是 false,则文件的 key 使用微信自动生成的 filename。出于初代sdk用户升级后兼容问题的考虑,默认是 false。
if (!config.qiniuShouldUseQiniuFileName) {
formData["key"] = fileName;
}
var uploadTask = uni.uploadFile({
url: url,
filePath: filePath,
name: "file",
/* #ifdef MP-ALIPAY */
fileType: "image",
/* #endif */
formData: formData,
success: function(res) {
var dataString = res.data;
// // this if case is a compatibility with wechat server returned a charcode, but was fixed
// if(res.data.hasOwnProperty('type') && res.data.type === 'Buffer'){
// dataString = String.fromCharCode.apply(null, res.data.data)
// }
try {
var dataObject = typeof dataString === "string" ? JSON.parse(dataString) : dataString;
// 拼接fileURL
var fileURL = config.qiniuBucketURLPrefix + "/" + dataObject.key;
dataObject.fileURL = fileURL;
// imageURL字段和fileURL字段重复,但本sdk不做删除,因为在最初版本使用的是imageURL。直接删除可能导致原有用户升级至新版sdk后出现异常。
dataObject.imageURL = fileURL;
console.log(dataObject);
if (success) {
success(dataObject);
}
} catch (e) {
console.log("parse JSON failed, origin String is: " + dataString);
if (fail) {
fail(e);
}
}
},
fail: function(error) {
console.error(error);
if (fail) {
fail(error);
}
}
});
// 文件上传进度
uploadTask.onProgressUpdate(res => {
progress && progress(res);
});
// 中断文件上传
cancelTask &&
cancelTask(() => {
uploadTask.abort();
});
}
// 获取七牛云uptoken, url为后端服务器获取七牛云uptoken接口
function getQiniuToken(callback) {
uni.request({
url: config.qiniuUploadTokenURL,
success: function(res) {
var token = res.data.uptoken;
if (token && token.length > 0) {
config.qiniuUploadToken = token;
if (callback) {
callback();
}
} else {
console.error(
"qiniuUploader cannot get your token, please check the uptokenURL or server"
);
}
},
fail: function(error) {
console.error(
"qiniu UploadToken is null, please check the init config or networking: " + error
);
}
});
}
// 选择七牛云文件上传接口,文件向匹配的接口中传输。ECN, SCN, NCN, NA, ASG,分别对应七牛云的:华东,华南,华北,北美,新加坡 5 个区域
function uploadURLFromRegionCode(code) {
var uploadURL = null;
switch (code) {
case "ECN":
uploadURL = "https://up.qiniup.com";
break;
case "NCN":
uploadURL = "https://up-z1.qiniup.com";
break;
case "SCN":
uploadURL = "https://up-z2.qiniup.com";
break;
case "NA":
uploadURL = "https://up-na0.qiniup.com";
break;
case "ASG":
uploadURL = "https://up-as0.qiniup.com";
break;
default:
console.error("please make the region is with one of [ECN, SCN, NCN, NA, ASG]");
}
return uploadURL;
}
module.exports = {
init: init,
upload: upload
};
})();
<template>
<!-- loading 加载 -->
<view class="mix-loading-content">
<view class="mix-loading-wrapper">
<image
class="mix-loading-icon"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFIAAABRCAYAAABBuPE1AAAOyElEQVR4Xu1ce1hU1RZfe0aQmQHlfopC+cBHiXJvoaafoBXd1Ozh86qFfipXpRTfDxS73StYX/nKa93U8nED+wIrS7CypK6hKZgaoAahSSJcZQBN5DHDa2bfb+3hHM8M8zjncEC63+x/FNh77bV/81trr7322kPA3RRBgCgixS0E3EAqRAI3kG4gFUJAITFuRrqBVAgBhcS4GekGUiEEFBLjZmR7AdI/eMQcAiSEAoTwOlFSSCnNMavI8fLcjByFdG2RGL/gsBCVmT5OCAkBQgM5YQQghwLN0eeeTmzJBLIZ2W1g6CS1irwPAL7OFKCUFhICKY1AEtsaVP+gEYFETZZRCpMIITx4DvStoGBeoc89nSAHUFlAdh8YukylItu5CXv37AlarQaCg4IgNz8fGhtNtb8UFHjZKkSBpoOJxuvzT6fLUVbsGP+gEeFERZYBIZNsx/Tscb/JW6dTo66FRcVQfvMmXCsuFnSj20tyM1eInUvAbGlDmph4CEchgNFR86FPr552hZzJyoYzP/4IP5w911BXX+9x1/Qhh5rNK1wBiowCIL0t4+g1ff7pQmfaIoCgJusJkHCun6eHR/2I4cM8hw8dCsOHDLY7/GpRMbyze7ep+L/X1WwmMP9VKjMlMdI3MMTXS6vJRjNBEONi14JOpxX1SaSfPAkHDn7W+FtFRYe7gNIUaobtoKaBnJ/Ff125CwCoQL/G+TcwkUJQkUhCIJKT3blTp9qZ06d6DRs8RLSOS9euq9aXlnqjfGONoU9FYU6FqMUBSEtaBAwMXQ4q8k8UvmPrZvDr2lXsPHy/I0e/gYTkZMnjpAyIjIiAZ54aI2UI64tmvmRNbI3ZbNYBpW+V5GUuFytEEiMDBoVlA4GQx0aGweKo+WLnYP3QfI4cTYMzWVnUaDQ2m7dfn0B4sH9fuD8gAAb07wc+3kiM5q2quhouXSmAEn0p3NCXQvaFi3b7PT5yJISPGgnBA4Mk6fnqlq1XLubm9cdNUp+X2UfsYNFAWnZA1VUUvHrpEof+xnbi3J/z4ZPUVMjLv2T1p25+XeGJUWHwxKOjYGjIQ2L1tdvvx5wLcC7nPBw/lQG/FDAV+TYoaAA8O3YsDHPgH20FFhQWVq2L2+CDv28EGCw20hANpNCsP074t8uFIwMTk5KsANRptTB+3Bh4btxTMKB/X5cy5HRAph7+Og2SPz0ENTUGK0CnTZwoiqEvzJ3PzJtSiNfnZcSJ0UM8kINCtwMhywYOeBDi18U6lI3KIwOPpH3D9+nu1xUWzJ0Nj4eFgY+PfZMVo6zUPl8cTYP33v8A9GXl/FA0+cgZEU43oCVrYq+VlpX1BgqpJXkZzUIoe3qIBtI/ODSdAHncmX9EM96xdx/cvHWLzYUMfClyFkRMnSwVA0X72wKq1WohZslih+zcnbA//9v09CAK9Lg+N5MPpZwpJRpIbqOZOnECTJ/c/ENKSEq2YuELUybCi3NmtSkDnS20qqoakj49BHv3f8h3e2bsGMZO25aQdEB/JC3NH8OgktyMP4j5VMUDGRxGUaAtkGjKO/fug7PZ2Ww+/25+EBcb0+INRIzycvrgxhS3cQtv7rgZxSxZYmXqaFnxmzYz8SW5GaIwEtUJBQY0ARk9fy6EjxrFJkEQ4zduhsLiIvbzY2GhELd2VbthoSOgkZ1v7ngXvkz7lnUJ7NkLFkbN409obQLk+rVrmG+xBfHZsaMhLna1HJLcszHvJXzAmzr6zfWxaxmYbQZkYK9eVkxcv3YlPPfU2HsGSEsmxo0oftM2JkKr0dAtr8aTsvKbrW/az4wZDXn5l3lzXhn90j3flVsCJI4Vgtm7Rw/TtCmT1Vvf/lfr+kih0r9Hc3YEuhBMjUbDH2MV32y4OJJT5P8JRG5Nb76zCw58lspjTYHe0edmOk1cc51F79pCIAc/9CfYvX2LZIvKOn+BjRnycMvO1q4mbsk8Ly6P4RMhrRKQ+w8KvYp5SMw/Ju/ZBQH+3V2th/97+skM2LbjXSgpLWO/C+jeDVYuWgDho8JEyxDTEWPE+E1b+Xm8vXXsUBDxF1GnPDYFhkbjZ8xmUQlmgGoNxsFi8pKiGClMWEjdXIS+BxWdNvFppvAnqV+Bkrs9flgx/9gAU8aPY0nWo8dOQHVT0kLqPJws1FNs4sIlkJgV13prCymFzlJNGjMxM16MhurqGgbevrfegKeffIz9/6v/nIBlf3sNDn+Y2OIAHlk0YeYciImeB1Gzn2fyM85kwdS5S3giH05KlGRFK19eD9+f/oGNpyZzH1fXHC6B9B8UFkcIrEeBUpURBrxoZpdPp1lZ6H1/HAnzZ89kiY2WNI71N346ZSVm6OjJUKK3uBOpmyOSYMKMORYggSbqczP5awx7ujoFEtmo0WkxU+orVRGcbGZUNFwu+JWf13ahCKRUlttbxKpX4uFERibYyh82ZgpcLynl/fLh5P2SPq91G96Ab9OPi2KlUyCFvvHdbZslJyKG/XmcleLxa5byprdn/0ewfvPb7O9nj30taYG2nSdEzGYbzMqFc2H1onnszx+lfAkrXnndqqvUeX4pKIQZUQssQLpI8joHsumORi5rbIFEhUKHWa5EM89askVKACmcJ3jAA9Cpk7eVfLnzNDQ0QuyG1+HEqQy2gzu7w3EIpPCORuquxyluD0h71JPKFFsZ41+YZZUFd0RvOfMgs7njorM7HIdACs36WOpBWTvrjKiFzS6jbBcpl+1COZyPdOYfME/6+YEPJLuQq0U3YHrkXMs4J1e0jhnZdLXwQL8+kLRnl2QFcIBw13YkQGpcak+Obaxqrw9m7FctXih5HSVlt2DDpq1wLjsbd2+HVw8MSEtpCIAwVgoIDruNu3VLwhPhKcHeCvCU9HnSfllsl2Leck5jnHwE8rPUL/iiBmESQ4gbEdbycIMtFWSW6i08Fz8S8jD7E8aCeI36QN++ohfvjC1bNvxDsWPipSu/wksrVltdwXLrkerj8ayO8vAgUVVjgCsFv/JXKXiPY1tSYzLTyXaBdMV/vFJ48zUWo4tqtvckrXWvg4uP37SF98s4D5qzlDN93Mat/BWEqMUBAANSYNqW+kGVKhwIDcerV/wRNwNswtIQ2f5GXwreOp1oNotdiG0/dCnVNTWSjoScDFu/jvf42H6+dJn9i34SKEkHs5krTSxEl2h3sxEeC+WEDHIBaG/jjLV1oC+z3NHPWbgIjEajw8DcDaSTT6+ysgZuVdxhPdb8PY5drzg64dgFUhhDcozkkqUo1Nlm07H8DmiLS0FtqONVNGk7gqFnd6jz69ympJOrC7fW23eqoW+gxeNxsaRTILGUmRDiSwj1xaJ6Qokvlu85WrWzBEa3Y9ngUWlJmwlbfdfOUD7K4m/bqsnRxVXsixENEECfmEMpqaCUVtQZjYlEyD6xC3QVWyITOt6ymAS2ui6dJbMx+dMUwASrsGEYFjVnplg1WT+pugiTumInQpYSfDahpjSFDSLA1WgXEiAsGYfsGz/Ocmd9n393WTuhWIW4fs4WIzUmlDo31z/rQh7cKNGzH89mZcGRbyxVGXhMpE3WSoD4Ukp9wUwjXR4RpcaMchUXjnNmXnLyolJ1qqo2wM3f7paPv7NnL8sAqVSqn65fPGnXP7Vq0kLqArj+yQcPwbad79kdrsTZ3JleJrMZrt8oB5PZxHeLjF4MBoNBXtICTb4DAEsatpU5CRdoL6PTFkVaeLaurb0bceATFy6NRk3mJxw9aXGa2OXush/s1xc+3LNTLsFkj8Oj5YKVa9h4ORl6qRP/drsS7lRVWw2L27iJlW+rVOT69YunejiS6RxIfEGlVn13r1jZlkDa+kVcsxUbXTxiEnGLGIqZoN54RsZbxLasAcfFYHKYVdvu2dVqc9sDEeeOXhXDyrhdsRH7ugZSwMqnRz8JG16OkWox7bo/7s4IpG37+FAKHEw9zH6N2Z2ynzMtIaKD5hJIHBfQ9KIB/79m2WKYNvG5dg2OGOUaGxuh9GYF1NfXN+uOz/127m16AiPyZYMoIJvutzFtxDK8K6IXwPNTJoBapRKjc7vrg8mIispqqxCHU1JYrQuEFBurax5SrPYHJ2FpdTXJIUA6Y5nw4qgoGB0+Ejr5eP9uAMW02K3bdwCvWe01fGQVv3ETixkJIdUNlD6q+MsvnLgptsTSg07485wZETBh3Djw8dGAj04LHTrcffjanmiIPrCy2mDXjDk9heYsFURRm40tIOxsDhQfL7GcmPAllU6rAZ1OAzpNszfvbY4r+sDKKgMYamsdMpBTaseefXD8lKVuSA6IsoDkzJyoVbiLMZ/ZtUsXWDR/Hv+SSq1Sg5eXJ2i8OoLGy7PNmIqmazTWiQIP9UZ/mJh0gK+Hx7N0vdk8S6w5C9kharNxRCfhbo59hg0eDJEzI5q94/bw6ACeHh7g4aEGT09P8FDjv3e/UEAqXfE8XF/fAA31jdBoMoGxrt6p2drKx3fZHx9K5VmIf8eKs9oa43IxG4s9fVsEZBM7w0FFEjBo5yZAc58+eaKoh/FeXh2t9PLooAa12hINNDSYAEHjmslkcmmmzj4UewDizmwymZe6ihNdfdgtBhInsHxFg3Y5ELqc8534e3yehu+xEdh72dD/fff9Sds345VA6ftGgzFOLgsVM21bcBwBypn98EeGwKABA0QxtSXAY/33uZxsOHMuC3IvXbKkwJoavlQASrbXGgzblQCQk6sII+0CqvOaRECF3wlhKdMQNNyc8Otiuvn5QXAQAttFNrhoruU3b8HVoiIovFbEvi6He+ZsM+15MNMEo9GYoCSArQqkcAEs9jRT9KNYOtwMVFuA8SsauObXpSsDG1uNoQYKiyyPR7HhMzcHgAlFnqcUUkwEUuTsxFKsolUY6UgBNH1PjSZcTSAc7z24ag4pCjvri1UQhEKOiUK6itIcVwX0Ss2LctoUSHuKN1V0BeJ3llG8Egbqy10uOVoogkWBWC5VLKUjrGxESWCkyrrnQEpVuL32dwOp0CfjBtINpEIIKCTGzUg3kAohoJAYNyPdQCqEgEJi3Ix0A6kQAgqJ+R/hGsVgZB67rgAAAABJRU5ErkJggg=="
/>
</view>
</view>
</template>
<script>
export default {
props: {
top: {
//距离顶部距离,单位rpx
type: Number,
default: 0
}
},
data() {
return {};
},
methods: {}
};
</script>
<style>
.mix-loading-content {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: transparent;
}
.mix-loading-wrapper {
display: flex;
justify-content: center;
align-items: center;
animation: loading 0.5s ease-in infinite both alternate;
}
.mix-loading-icon {
width: 80rpx;
height: 80rpx;
transition: 0.3s;
}
@keyframes loading {
0% {
transform: translateY(-20rpx) scaleX(1);
}
100% {
transform: translateY(4rpx) scaleX(1.3);
}
}
</style>
/* eslint-disable */
export default [{"name":"bd","env":"dev","owner":"jinhua.yang","type":null,"status":"Active","createdAt":"2022-10-21 19:39:01"},{"name":"ds","env":"dev","owner":"feng.tang","type":"toc","status":"Active","createdAt":"2022-10-21 19:38:29"},{"name":"saas3","env":"dev","owner":"yulong.zhao","type":"tob","status":"Active","createdAt":"2022-10-21 19:38:11"},{"name":"saas4","env":"test","owner":"liang1.chen","type":"tob","status":"Active","createdAt":"2022-10-21 19:38:07"},{"name":"saas5","env":"dev","owner":"yulong.zhao","type":"tob","status":"Active","createdAt":"2022-10-21 19:38:21"},{"name":"saas6","env":"dev","owner":"yulong.zhao","type":"tob","status":"Active","createdAt":"2022-10-21 19:38:47"},{"name":"sc","env":"dev","owner":"nan.sun","type":"toc","status":"Active","createdAt":"2022-10-21 19:38:17"},{"name":"sc1","env":"dev","owner":"nan.sun","type":"toc","status":"Active","createdAt":"2022-10-27 18:16:00"},{"name":"td","env":"test","owner":"bo.li","type":"qa","status":"Active","createdAt":"2022-10-21 19:38:15"},{"name":"tob1","env":"test","owner":"liang.chen","type":"tob","status":"Active","createdAt":"2022-10-20 19:26:20"},{"name":"tob2","env":"test","owner":"liang.chen","type":"tob","status":"Active","createdAt":"2022-10-20 19:26:55"},{"name":"tob3","env":"test","owner":"liang1.chen","type":"tob","status":"Active","createdAt":"2022-10-22 16:31:47"},{"name":"toc","env":"test","owner":"qiaoling.yu","type":"toc","status":"Active","createdAt":"2022-10-21 19:38:31"},{"name":"xyqb","env":"test","owner":"xiaoqiang.wang","type":"toc","status":"Active","createdAt":"2022-10-21 19:38:41"},{"name":"yxm","env":"test","owner":"qiaoling.yu","type":"toc","status":"Active","createdAt":"2022-10-21 19:38:03"},{"name":"yxm2","env":"test","owner":"qiaoling.yu","type":"toc","status":"Active","createdAt":"2022-10-21 19:38:09"},{"name":"yxm6","env":"test","owner":"qiaoling.yu","type":null,"status":"Active","createdAt":"2023-02-22 14:28:04"}];
\ No newline at end of file
<template>
<view v-if="isNotReleaseEnv" class="container">
<picker :value="value" :range="envList" @change="bindPickerChange">
<image class="goods-order" src="https://img.lkbang.net/xcx/dev.png" />
<text>{{ currentEnv }}</text>
</picker>
</view>
</template>
<script>
import qaList from "./qa.api";
import { mapActions, mapState } from "vuex";
export default {
name: "QASelector",
data() {
return {
envList: [],
value: ""
};
},
computed: {
currentEnv() {
return this.envList[this.value] || "切换环境";
},
...mapState({
isNotReleaseEnv: state => state.qa.isNotReleaseEnv,
localEnv: state => state.qa.currentEnv
})
},
mounted() {
this.isNotReleaseEnv && this.getList();
},
methods: {
...mapActions({
changeEnvTag: "changeEnvTag"
}),
getList() {
this.envList = qaList.map(item => item.name);
this.value = this.envList.findIndex(item => item === this.localEnv);
// this.envList.push = "线上(暂时无效)";
},
bindPickerChange: function(e) {
this.value = e.target.value;
this.changeEnvTag(this.currentEnv);
const storageKeyMap = ["token", "openid", "phone", "userAuthInfo", "userBaseInfo", "orderNo"];
storageKeyMap.forEach(item => {
uni.removeStorageSync(item);
});
uni.showModal({
title: "提示",
content: "切换成功,本地登录信息已清除,请重新登录后继续访问",
showCancel: false,
success: res => {
if (res.confirm) {
this.$emit("clear", true);
uni.$emit("qaEnvChange");
}
}
});
}
}
};
</script>
<style lang="scss" scoped>
.container {
image {
width: 80rpx;
height: 80rpx;
display: block;
}
text {
display: block;
text-align: center;
color: #f00;
}
}
</style>
<template>
<view class="uni-load-more">
<view v-show="status === 'loading' && showIcon" class="uni-load-more__img">
<view class="load1">
<view :style="{ background: color }" />
<view :style="{ background: color }" />
<view :style="{ background: color }" />
<view :style="{ background: color }" />
</view>
<view class="load2">
<view :style="{ background: color }" />
<view :style="{ background: color }" />
<view :style="{ background: color }" />
<view :style="{ background: color }" />
</view>
<view class="load3">
<view :style="{ background: color }" />
<view :style="{ background: color }" />
<view :style="{ background: color }" />
<view :style="{ background: color }" />
</view>
</view>
<text class="uni-load-more__text" :style="{ color: color }">{{
status === "more"
? contentText.contentdown
: status === "loading"
? contentText.contentrefresh
: contentText.contentnomore
}}</text>
</view>
</template>
<script>
export default {
name: "UniLoadMore",
props: {
status: {
//上拉的状态:more-loading前;loading-loading中;noMore-没有更多了
type: String,
default: "more"
},
showIcon: {
type: Boolean,
default: true
},
color: {
type: String,
default: "#777777"
},
contentText: {
type: Object,
default() {
return {
contentdown: "上拉显示更多",
contentrefresh: "正在加载...",
contentnomore: "没有更多数据了"
};
}
}
},
data() {
return {};
}
};
</script>
<style>
@charset "UTF-8";
.uni-load-more {
display: flex;
flex-direction: row;
height: 80rpx;
align-items: center;
justify-content: center;
}
.uni-load-more__text {
font-size: 28rpx;
color: #999;
}
.uni-load-more__img {
height: 24px;
width: 24px;
margin-right: 10px;
}
.uni-load-more__img > view {
position: absolute;
}
.uni-load-more__img > view view {
width: 6px;
height: 2px;
border-top-left-radius: 1px;
border-bottom-left-radius: 1px;
background: #999;
position: absolute;
opacity: 0.2;
transform-origin: 50%;
animation: load 1.56s ease infinite;
}
.uni-load-more__img > view view:nth-child(1) {
transform: rotate(90deg);
top: 2px;
left: 9px;
}
.uni-load-more__img > view view:nth-child(2) {
transform: rotate(180deg);
top: 11px;
right: 0;
}
.uni-load-more__img > view view:nth-child(3) {
transform: rotate(270deg);
bottom: 2px;
left: 9px;
}
.uni-load-more__img > view view:nth-child(4) {
top: 11px;
left: 0;
}
.load1,
.load2,
.load3 {
height: 24px;
width: 24px;
}
.load2 {
transform: rotate(30deg);
}
.load3 {
transform: rotate(60deg);
}
.load1 view:nth-child(1) {
animation-delay: 0s;
}
.load2 view:nth-child(1) {
animation-delay: 0.13s;
}
.load3 view:nth-child(1) {
animation-delay: 0.26s;
}
.load1 view:nth-child(2) {
animation-delay: 0.39s;
}
.load2 view:nth-child(2) {
animation-delay: 0.52s;
}
.load3 view:nth-child(2) {
animation-delay: 0.65s;
}
.load1 view:nth-child(3) {
animation-delay: 0.78s;
}
.load2 view:nth-child(3) {
animation-delay: 0.91s;
}
.load3 view:nth-child(3) {
animation-delay: 1.04s;
}
.load1 view:nth-child(4) {
animation-delay: 1.17s;
}
.load2 view:nth-child(4) {
animation-delay: 1.3s;
}
.load3 view:nth-child(4) {
animation-delay: 1.43s;
}
@-webkit-keyframes load {
0% {
opacity: 1;
}
100% {
opacity: 0.2;
}
}
</style>
.uni-numbox {
display: flex;
justify-content: flex-start;
align-items: center;
width: 280rpx;
height: 60rpx;
background: #fff;
}
.uni-numbox-minus,
.uni-numbox-plus {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
background-color: #f2f3f5;
width: 100rpx;
height: 100%;
text-align: center;
position: relative;
}
.uni-numbox-minus .yticon,
.uni-numbox-plus .yticon {
font-size: 28rpx;
color: #555;
}
.uni-numbox-minus {
border-right: none;
border-top-left-radius: 6rpx;
border-bottom-left-radius: 6rpx;
}
.uni-numbox-plus {
border-left: none;
border-top-right-radius: 6rpx;
border-bottom-right-radius: 6rpx;
}
.uni-numbox-value {
position: relative;
background-color: #f2f3f5;
width: 100rpx;
height: 60rpx;
text-align: center;
padding: 0;
font-size: 28rpx;
margin: 0 4rpx;
}
.uni-numbox-disabled.yticon {
color: #d6d6d6;
}
\ No newline at end of file
<template>
<view class="uni-numbox">
<view class="uni-numbox-minus" @click="_calcValue('subtract')">
<text class="yticon" :class="minDisabled ? 'uni-numbox-disabled' : ''"> - </text>
</view>
<input
class="uni-numbox-value"
type="number"
:disabled="disabled"
:value="inputValue"
@blur="_onBlur"
/>
<view class="uni-numbox-plus" @click="_calcValue('add')">
<text class="yticon" :class="maxDisabled ? 'uni-numbox-disabled' : ''"> + </text>
</view>
</view>
</template>
<script>
let changeTimer = null;
export default {
name: "UniNumberBox",
props: {
isMax: {
type: Boolean,
default: false
},
isMin: {
type: Boolean,
default: false
},
index: {
type: Number,
default: 0
},
value: {
type: Number,
default: 0
},
min: {
type: Number,
default: -Infinity
},
max: {
type: Number,
default: Infinity
},
step: {
type: Number,
default: 1
},
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
inputValue: 1,
minDisabled: false,
maxDisabled: false
};
},
computed: {},
watch: {
inputValue(number) {
const data = {
number: number,
index: this.index
};
this.$emit("eventChange", data);
},
value: {
handler(v) {
this.inputValue = v;
if (v < this.max && this.maxDisabled === true) {
this.maxDisabled = false;
}
if (v > this.min && this.minDisabled === true) {
this.minDisabled = false;
}
},
immediate: true
}
},
created() {
this.maxDisabled = this.isMax;
this.minDisabled = this.isMin;
},
methods: {
_calcValueTimer(type) {
if (changeTimer) clearTimeout(changeTimer);
changeTimer = setTimeout(() => {
this._calcValue(type);
}, 500);
},
_calcValue(type) {
const scale = this._getDecimalScale();
let value = this.inputValue * scale;
let newValue = 0;
let step = this.step * scale;
if (type === "subtract") {
newValue = value - step;
if (newValue <= this.min) {
this.minDisabled = true;
}
if (newValue < this.min) {
newValue = this.min;
}
if (newValue < this.max && this.maxDisabled === true) {
this.maxDisabled = false;
}
} else if (type === "add") {
newValue = value + step;
if (newValue >= this.max) {
this.maxDisabled = true;
uni.showToast({ icon: "none", title: `您当前购买的商品限购${this.max}件` });
}
if (newValue > this.max) {
newValue = this.max;
}
if (newValue > this.min && this.minDisabled === true) {
this.minDisabled = false;
}
}
if (newValue === value) {
return;
}
this.inputValue = newValue / scale;
},
_getDecimalScale() {
let scale = 1;
// 浮点型
if (~~this.step !== this.step) {
scale = Math.pow(10, (this.step + "").split(".")[1].length);
}
return scale;
},
_onBlur(event) {
let value = event.detail.value;
if (!value) {
this.inputValue = 0;
return;
}
value = +value;
if (value > this.max) {
value = this.max;
} else if (value < this.min) {
value = this.min;
}
this.inputValue = value;
}
}
};
</script>
<style lang="scss" src="./index.scss"></style>
<template>
<view class="uni-numbox">
<view class="uni-numbox-minus" @click="_calcValue('subtract')">
<text class="yticon" :class="canSubtract ? 'uni-numbox-disabled' : ''"> - </text>
</view>
<view v-if="disabled" class="uni-numbox-value uni-numbox-txt">{{ value }}</view>
<input v-else class="uni-numbox-value" type="number" :disabled="disabled" :value="value" />
<view class="uni-numbox-plus" @click="_calcValue('add')">
<text class="yticon" :class="canAdd ? '' : 'uni-numbox-disabled'"> + </text>
</view>
</view>
</template>
<script>
export default {
name: "Stepper",
props: {
value: {
type: Number,
default: 0
},
disabled: {
type: Boolean,
default: false
},
index: {
type: Number,
default: 0
},
canAdd: Boolean,
canSubtract: Boolean,
min: {
type: Number,
default: -Infinity
},
max: {
type: Number,
default: Infinity
}
},
data() {
return {
inputValue: this.value
};
},
methods: {
_calcValue(type) {
if (type === "subtract") {
if (this.canSubtract || this.inputValue >= this.min) {
this.$emit("change", { type, index: this.index });
}
} else if (type === "add") {
if (this.canAdd || this.inputValue <= this.max) {
this.$emit("change", { type, index: this.index });
}
}
}
}
};
</script>
<style lang="scss" src="./index.scss"></style>
<style lang="scss" scoped>
.uni-numbox {
width: 176rpx;
}
.uni-numbox,
.uni-numbox-value,
.uni-numbox-minus,
.uni-numbox-plus {
height: 48rpx;
line-height: 48rpx;
}
.uni-numbox-txt {
display: flex;
align-items: center;
justify-content: center;
}
</style>
export default {
created() {
if (this.type === "message") {
// 不显示遮罩
this.maskShow = false;
// 获取子组件对象
this.childrenMsg = null;
}
},
methods: {
customOpen() {
if (this.childrenMsg) {
this.childrenMsg.open();
}
},
customClose() {
if (this.childrenMsg) {
this.childrenMsg.close();
}
}
}
};
import message from "./message.js";
// 定义 type 类型:弹出类型:top/bottom/center
const config = {
// 顶部弹出
top: "top",
// 底部弹出
bottom: "bottom",
// 居中弹出
center: "center",
// 消息提示
message: "top",
// 对话框
dialog: "center",
// 分享
share: "bottom"
};
export default {
data() {
return {
config: config
};
},
mixins: [message]
};
<template>
<view class="uni-popup-dialog" :class="{ 'uni-dialog-stay': stayStyle }">
<view v-if="showTitle" class="uni-dialog-title">
<text class="uni-dialog-title-text" :class="['uni-popup__' + dialogType]">{{ title }}</text>
</view>
<view class="uni-dialog-content">
<!-- 因为支付宝不支持通过slot 传递组件时,slot之内有内容 -->
<template v-if="content.length">
<slot name="default">
<text
v-if="mode === 'base'"
class="uni-dialog-content-text"
:class="{ 'uni-dialog-tip': !showTitle }"
>{{ content }}</text
>
<input
v-else
v-model="val"
class="uni-dialog-input"
type="text"
:placeholder="placeholder"
:focus="focus"
/>
</slot>
</template>
<template v-else>
<slot />
</template>
</view>
<view class="uni-dialog-button-group">
<button v-if="!hideCancelBtn" class="uni-dialog-button cancel" @click="close">
<text
:class="['uni-dialog-button-text', { 'uni-button-color': warningBtn === 'cancel' }]"
>{{ cancelTxt }}</text
>
</button>
<!-- #ifdef MP-WEIXIN -->
<button
v-if="!hideConfirmBtn"
class="uni-dialog-button confirm uni-border-left"
:open-type="openType"
:app-parameter="appParameter"
@click="onOk"
@launchapp="launchappEvent"
@error="errorEvent"
>
<text
:class="['uni-dialog-button-text', { 'uni-button-color': warningBtn === 'confirm' }]"
>{{ confirmTxt }}</text
>
</button>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<button
v-if="!hideConfirmBtn"
class="uni-dialog-button confirm uni-border-left"
@click="onOk"
>
<text
:class="['uni-dialog-button-text', { 'uni-button-color': warningBtn === 'confirm' }]"
>{{ confirmTxt }}</text
>
</button>
<!-- #endif -->
</view>
</view>
</template>
<script>
/**
* PopUp 弹出层-对话框样式
* @description 弹出层-对话框样式
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} value input 模式下的默认值
* @property {String} placeholder input 模式下输入提示
* @property {String} type = [success|warning|info|error] 主题样式
* @value success 成功
* @value warning 提示
* @value info 消息
* @value error 错误
* @property {String} mode = [base|input] 模式、
* @value base 基础对话框
* @value input 可输入对话框
* @property {String} content 对话框内容
* @event {Function} confirm 点击确认按钮触发
* @event {Function} close 点击取消按钮触发
*/
export default {
name: "UniPopupDialog",
inject: ["popup"],
props: {
value: {
type: [String, Number],
default: ""
},
placeholder: {
type: [String, Number],
default: "请输入内容"
},
/**
* 对话框主题 success/warning/info/error 默认 success
*/
type: {
type: String,
default: "error"
},
warningBtn: {
type: String,
default: "confirm"
},
hideCancelBtn: Boolean,
hideConfirmBtn: Boolean,
cancelTxt: {
type: String,
default: "取消"
},
confirmTxt: {
type: String,
default: "确定"
},
stayStyle: Boolean,
/**
* 对话框模式 base/input
*/
mode: {
type: String,
default: "base"
},
/**
* 对话框标题
*/
title: {
type: String,
default: "提示"
},
showTitle: {
type: Boolean,
default: true
},
/**
* 对话框内容
*/
content: {
type: String,
default: ""
},
mkclick: {
type: Boolean,
default: false
},
openType: {
type: String,
default: ""
},
appParams: {
type: Object,
default: () => ({})
}
},
data() {
return {
dialogType: "error",
focus: false,
val: ""
};
},
computed: {
appParameter() {
const appParams = this.appParams;
// console.log("============>appParams", appParams);
return Object.keys(appParams).length ? JSON.stringify(appParams) : "";
}
},
watch: {
type(val) {
this.dialogType = val;
},
mode(val) {
if (val === "input") {
this.dialogType = "info";
}
},
value(val) {
this.val = val;
}
},
created() {
// 对话框遮罩不可点击
this.popup.mkclick = this.mkclick;
if (this.mode === "input") {
this.dialogType = "info";
this.val = this.value;
} else {
this.dialogType = this.type;
}
},
mounted() {
this.focus = true;
},
methods: {
launchappEvent(options) {
console.log(`luachApp-------${JSON.stringify(options || {})}`);
this.$emit("luachapp-suceess");
},
errorEvent(error) {
console.log(`luachApp error-------`, error?.detail?.errMs);
},
/**
* 点击确认按钮
*/
onOk() {
this.$emit("confirm", this.val);
this.mode === "input" ? this.val : "";
this.popup.close();
},
/**
* 点击取消按钮
*/
close() {
this.$emit("cancel");
this.popup.close();
}
}
};
</script>
<style lang="scss" scoped>
.uni-popup-dialog {
width: 622rpx;
background-color: #fff;
padding-top: 48rpx;
}
.uni-dialog-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
padding-bottom: 16rpx;
color: #333333 !important;
}
.uni-dialog-title-text {
font-size: 32rpx;
line-height: 44rpx;
font-weight: 600;
color: #333 !important;
}
.uni-dialog-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
padding: 0 40rpx 48rpx;
}
.uni-dialog-content-text {
font-size: 28rpx;
line-height: 40rpx;
color: #999;
text-align: center;
}
.uni-dialog-button-group {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
border-top-color: #ebedf0;
border-top-style: solid;
border-top-width: 0.5rpx;
}
.uni-dialog-button {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
justify-content: center;
align-items: center;
height: 96rpx;
background-color: transparent;
border: none;
border-radius: 0;
}
.uni-border-left {
border-left-color: #ebedf0;
border-left-style: solid;
border-left-width: 0.5rpx;
}
.uni-dialog-button-text {
font-size: 32rpx;
}
.uni-button-color {
color: $uni-color-primary;
}
.uni-dialog-input {
flex: 1;
font-size: 14px;
}
.uni-popup__success {
color: $uni-color-success;
}
.uni-popup__warn {
color: $uni-color-warning;
}
.uni-popup__error {
color: $uni-color-error;
}
.uni-popup__info {
color: #909399;
}
.uni-dialog-tip {
font-size: 32rpx;
line-height: 44rpx;
color: #333;
}
.uni-dialog-stay {
.uni-dialog {
&-title-text {
color: #333;
}
&-content-text {
color: #333;
text-align: left;
}
&-button {
flex: none;
&-group {
flex-direction: column-reverse;
border-width: 0;
padding: 0 48rpx 44rpx;
}
&.cancel {
padding-top: 36rpx;
.uni-dialog-button-text {
font-size: 28rpx;
color: #ec1500;
line-height: 40rpx;
}
}
&.confirm {
background: linear-gradient(270deg, #ff5d00 0%, #ff1900 100%);
border-left-width: 0;
height: 72rpx;
border-radius: 36rpx;
.uni-dialog-button-text {
color: #fff;
font-size: 28rpx;
line-height: 40rpx;
}
}
}
}
}
</style>
<template>
<view class="uni-popup-message" :class="'uni-popup__' + [type]">
<text class="uni-popup-message-text" :class="'uni-popup__' + [type] + '-text'">{{
message
}}</text>
</view>
</template>
<script>
/**
* PopUp 弹出层-消息提示
* @description 弹出层-消息提示
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} type = [success|warning|info|error] 主题样式
* @value success 成功
* @value warning 提示
* @value info 消息
* @value error 错误
* @property {String} message 消息提示文字
* @property {String} duration 显示时间,设置为 0 则不会自动关闭
*/
export default {
name: "UniPopupMessage",
inject: ["popup"],
props: {
/**
* 主题 success/warning/info/error 默认 success
*/
type: {
type: String,
default: "success"
},
/**
* 消息文字
*/
message: {
type: String,
default: ""
},
/**
* 显示时间,设置为 0 则不会自动关闭
*/
duration: {
type: Number,
default: 3000
}
},
data() {
return {};
},
created() {
this.popup.childrenMsg = this;
},
methods: {
open() {
if (this.duration === 0) return;
clearTimeout(this.popuptimer);
this.popuptimer = setTimeout(() => {
this.popup.close();
}, this.duration);
},
close() {
clearTimeout(this.popuptimer);
}
}
};
</script>
<style lang="scss" scoped>
.uni-popup-message {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
background-color: #e1f3d8;
padding: 10px 15px;
border-color: #eee;
border-style: solid;
border-width: 1px;
}
.uni-popup-message-text {
font-size: 14px;
padding: 0;
}
.uni-popup__success {
background-color: #e1f3d8;
}
.uni-popup__success-text {
color: #67c23a;
}
.uni-popup__warn {
background-color: #faecd8;
}
.uni-popup__warn-text {
color: #e6a23c;
}
.uni-popup__error {
background-color: #fde2e2;
}
.uni-popup__error-text {
color: #f56c6c;
}
.uni-popup__info {
background-color: #f2f6fc;
}
.uni-popup__info-text {
color: #909399;
}
</style>
<template>
<view class="uni-popup-share">
<view class="uni-share-title"
><text class="uni-share-title-text">{{ title }}</text></view
>
<view class="uni-share-content">
<view class="uni-share-content-box">
<view
v-for="(item, index) in bottomData"
:key="index"
class="uni-share-content-item"
@click.stop="select(item, index)"
>
<image class="uni-share-image" :src="item.icon" mode="aspectFill" />
<text class="uni-share-text">{{ item.text }}</text>
</view>
</view>
</view>
<view class="uni-share-button-box">
<button class="uni-share-button" @click="close">取消</button>
</view>
</view>
</template>
<script>
export default {
name: "UniPopupShare",
inject: ["popup"],
props: {
title: {
type: String,
default: "立即分享给好友"
}
},
data() {
return {
bottomData: [
{
text: "微信",
icon: "https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-2.png",
name: "wx"
},
{
text: "支付宝",
icon: "https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-8.png",
name: "wx"
},
{
text: "QQ",
icon: "https://img-cdn-qiniu.dcloud.net.cn/uni-ui/gird-3.png",
name: "qq"
},
{
text: "新浪",
icon: "https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-1.png",
name: "sina"
},
{
text: "百度",
icon: "https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-7.png",
name: "copy"
},
{
text: "其他",
icon: "https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-5.png",
name: "more"
}
]
};
},
created() {},
methods: {
/**
* 选择内容
*/
select(item, index) {
this.$emit(
"select",
{
item,
index
},
() => {
this.popup.close();
}
);
},
/**
* 关闭窗口
*/
close() {
this.popup.close();
}
}
};
</script>
<style lang="scss" scoped>
.uni-popup-share {
background-color: #f7f8fa;
}
.uni-share-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
height: 40px;
background: #fff;
}
.uni-share-title-text {
font-size: 14px;
color: #666;
}
.uni-share-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
padding-top: 10px;
background: #fff;
margin-bottom: 8px;
}
.uni-share-content-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
/* flex-direction: row; */
/* flex-wrap: wrap; */
width: 360px;
background: #fff;
}
.uni-share-content-item {
width: 90px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
padding: 10px 0;
align-items: center;
}
.uni-share-content-item:active {
background-color: #f5f5f5;
}
.uni-share-image {
width: 30px;
height: 30px;
}
.uni-share-text {
margin-top: 10px;
font-size: 14px;
color: #3b4144;
}
.uni-share-button-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
padding: 4px 0;
background-color: #fff;
}
.uni-share-button {
flex: 1;
color: #666;
font-size: 16px;
background-color: transparent;
}
.uni-share-button::after {
border-radius: 50px;
}
</style>
<template>
<view v-if="showPopup" class="uni-popup" :class="[popupstyle]" @touchmove.stop.prevent="clear">
<uni-transition
v-if="maskShow"
:mode-class="['fade']"
:styles="maskClass"
:duration="duration"
:show="showTrans"
@click="onTap"
/>
<uni-transition
:mode-class="ani"
:styles="transClass"
:duration="duration"
:show="showTrans"
@click="onTap"
>
<view class="uni-popup__wrapper-box" :style="{ background }" @click.stop="clear">
<!-- <image
v-if="closeable"
src="https://img.lkbang.net/xcx/close.png"
class="uni-popup-icon "
@click="close"
/> -->
<text v-if="closeable" class="uni-popup-icon iconfont icon-close" @click="close" />
<view v-if="title || desc" class="uni-popup-head">
<view v-if="title" class="uni-popup-title">{{ title }}</view>
<view v-if="desc" class="uni-popup-desc">{{ desc }}</view>
</view>
<slot />
</view>
</uni-transition>
</view>
</template>
<script>
import uniTransition from "../uni-transition/uni-transition.vue";
import popup from "./popup.js";
/**
* PopUp 弹出层
* @description 弹出层组件,为了解决遮罩弹层的问题
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} type = [top|center|bottom] 弹出方式
* @value top 顶部弹出
* @value center 中间弹出
* @value bottom 底部弹出
* @value message 消息提示
* @value dialog 对话框
* @value share 底部分享示例
* @property {Boolean} animation = [ture|false] 是否开启动画
* @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
* @event {Function} change 打开关闭弹窗触发,e={show: false}
*/
export default {
name: "UniPopup",
components: {
uniTransition
},
mixins: [popup],
provide() {
return {
popup: this
};
},
props: {
// 开启动画
animation: {
type: Boolean,
default: true
},
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
// message: 消息提示 ; dialog : 对话框
type: {
type: String,
default: "center"
},
// maskClick
maskClick: {
type: Boolean,
default: true
},
closeable: Boolean,
title: {
type: String,
default: ""
},
desc: {
type: String,
default: ""
},
classCustom: {
type: String,
default: ""
},
background: {
type: String
}
},
data() {
return {
duration: 300,
ani: [],
showPopup: false,
showTrans: false,
maskClass: {
position: "fixed",
bottom: 0,
top: 0,
left: 0,
right: 0,
backgroundColor: "rgba(0, 0, 0, 0.4)"
},
transClass: {
position: "fixed",
left: 0,
right: 0
},
maskShow: true,
mkclick: true,
popupstyle: "top"
};
},
watch: {
/**
* 监听type类型
*/
type: {
handler: function(newVal) {
this[this.config[newVal]]();
},
immediate: true
},
/**
* 监听遮罩是否可点击
* @param {Object} val
*/
maskClick: {
immediate: true,
handler(val) {
this.mkclick = val;
}
}
// customStyle
},
created() {
this.mkclick = this.maskClick;
if (this.animation) {
this.duration = 300;
} else {
this.duration = 0;
}
},
methods: {
clear(e) {
// TODO nvue 取消冒泡
e.stopPropagation();
},
open() {
this.showPopup = true;
this.$nextTick(() => {
this.showTrans = true;
new Promise(resolve => {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
// fixed by mehaotian 兼容 app 端
this.$nextTick(() => {
resolve();
});
}, 50);
}).then(() => {
// 自定义打开事件
clearTimeout(this.msgtimer);
this.msgtimer = setTimeout(() => {
this.customOpen && this.customOpen();
}, 100);
this.$emit("change", {
show: true,
type: this.type
});
});
});
},
close() {
this.showTrans = false;
this.$nextTick(() => {
this.$emit("change", {
show: false,
type: this.type
});
clearTimeout(this.timer);
// 自定义关闭事件
this.customOpen && this.customClose();
this.timer = setTimeout(() => {
this.showPopup = false;
}, 300);
});
},
onTap() {
if (!this.mkclick) return;
this.close();
},
/**
* 顶部弹出样式处理
*/
top() {
this.popupstyle = "top";
this.ani = ["slide-top"];
this.transClass = {
position: "fixed",
left: 0,
right: 0
};
},
/**
* 底部弹出样式处理
*/
bottom() {
this.popupstyle = "bottom";
this.ani = ["slide-bottom"];
this.transClass = {
position: "fixed",
left: 0,
right: 0,
bottom: 0
};
},
/**
* 中间弹出样式处理
*/
center() {
this.popupstyle = "center";
this.ani = ["zoom-out", "fade"];
this.transClass = {
position: "fixed",
/* #ifndef APP-NVUE */
display: "flex",
flexDirection: "column",
/* #endif */
bottom: 0,
left: 0,
right: 0,
top: 0,
justifyContent: "center",
alignItems: "center"
};
}
}
};
</script>
<style lang="scss" scoped>
.uni-popup {
position: fixed;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-popup__mask {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: $uni-bg-color-mask;
opacity: 0;
}
.mask-ani {
transition-property: opacity;
transition-duration: 0.2s;
}
.uni-top-mask {
opacity: 1;
}
.uni-bottom-mask {
opacity: 1;
}
.uni-center-mask {
opacity: 1;
}
.uni-popup__wrapper {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: absolute;
}
.top {
/* #ifdef H5 */
top: var(--window-top);
/* #endif */
/* #ifndef H5 */
top: 0;
/* #endif */
}
.bottom {
bottom: 0;
}
.uni-popup__wrapper-box {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: relative;
/* iphonex 等安全区设置,底部安全区适配 */
/* #ifndef APP-NVUE */
padding-bottom: constant(safe-area-inset-bottom);
// padding-bottom: env(safe-area-inset-bottom);
/* #endif */
border-radius: 32rpx;
background-color: #fff;
.uni-popup-icon {
color: #c8c9cc;
position: absolute;
right: 36rpx;
top: 30rpx;
height: 48rpx;
width: 48rpx;
padding: 10rpx;
z-index: 1;
}
.uni-popup-head {
padding: 48rpx 0 16rpx;
text-align: center;
}
.uni-popup-title {
font-size: 32rpx;
line-height: 44rpx;
font-weight: bold;
color: #333333;
}
.uni-popup-desc {
margin-top: 10rpx;
font-size: 26rpx;
line-height: 38rpx;
color: #999999;
}
}
.content-ani {
// transition: transform 0.3s;
transition-property: transform, opacity;
transition-duration: 0.2s;
}
.uni-top-content {
transform: translateY(0);
}
.uni-bottom-content {
transform: translateY(0);
}
.uni-center-content {
transform: scale(1);
opacity: 1;
}
.top .uni-popup__wrapper-box {
border-radius: 0;
}
.bottom {
.uni-popup__wrapper-box {
border-radius: 32rpx 32rpx 0 0;
}
.uni-popup-head {
padding: 30rpx 0 16rpx;
}
}
.center .uni-popup__wrapper-box {
border-radius: 32rpx;
overflow: hidden;
}
</style>
const BindingX = uni.requireNativePlugin("bindingx");
const dom = uni.requireNativePlugin("dom");
const animation = uni.requireNativePlugin("animation");
export default {
data() {
return {};
},
watch: {
show(newVal) {
if (this.autoClose) return;
if (this.stop) return;
this.stop = true;
if (newVal) {
this.open(newVal);
} else {
this.close();
}
},
leftOptions() {
this.getSelectorQuery();
this.init();
},
rightOptions() {
this.init();
}
},
created() {
if (this.swipeaction.children !== undefined) {
this.swipeaction.children.push(this);
}
},
mounted() {
this.box = this.getEl(this.$refs["selector-box--hock"]);
this.selector = this.getEl(this.$refs["selector-content--hock"]);
this.leftButton = this.getEl(this.$refs["selector-left-button--hock"]);
this.rightButton = this.getEl(this.$refs["selector-right-button--hock"]);
this.init();
},
beforeDestroy() {
this.swipeaction.children.forEach((item, index) => {
if (item === this) {
this.swipeaction.children.splice(index, 1);
}
});
},
methods: {
init() {
this.$nextTick(() => {
this.x = 0;
this.button = {
show: false
};
setTimeout(() => {
this.getSelectorQuery();
}, 200);
});
},
onClick(index, item, position) {
this.$emit("click", {
content: item,
index,
position
});
},
touchstart() {
// 每次只触发一次,避免多次监听造成闪烁
if (this.stop) return;
this.stop = true;
if (this.autoClose) {
this.$emit("closeOther", this);
}
const leftWidth = this.button.left.width;
const rightWidth = this.button.right.width;
let expression = this.range(this.x, -rightWidth, leftWidth);
let leftExpression = this.range(this.x - leftWidth, -leftWidth, 0);
let rightExpression = this.range(this.x + rightWidth, 0, rightWidth);
this.eventpan = BindingX.bind(
{
anchor: this.box,
eventType: "pan",
props: [
{
element: this.selector,
property: "transform.translateX",
expression
},
{
element: this.leftButton,
property: "transform.translateX",
expression: leftExpression
},
{
element: this.rightButton,
property: "transform.translateX",
expression: rightExpression
}
]
},
e => {
// nope
if (e.state === "end") {
this.x = e.deltaX + this.x;
this.isclick = true;
this.bindTiming(e.deltaX);
}
}
);
},
touchend() {
if (this.isopen !== "none" && !this.isclick) {
this.open("none");
}
},
bindTiming(x) {
const left = this.x;
const leftWidth = this.button.left.width;
const rightWidth = this.button.right.width;
const threshold = this.threshold;
if (!this.isopen || this.isopen === "none") {
if (left > threshold) {
this.open("left");
} else if (left < -threshold) {
this.open("right");
} else {
this.open("none");
}
} else {
if ((x > -leftWidth && x < 0) || x > rightWidth) {
if ((x > -threshold && x < 0) || x - rightWidth > threshold) {
this.open("left");
} else {
this.open("none");
}
} else {
if ((x < threshold && x > 0) || x + leftWidth < -threshold) {
this.open("right");
} else {
this.open("none");
}
}
}
},
/**
* 移动范围
* @param {Object} num
* @param {Object} mix
* @param {Object} max
*/
range(num, mix, max) {
return `min(max(x+${num}, ${mix}), ${max})`;
},
/**
* 开启swipe
*/
open(type) {
this.animation(type);
},
/**
* 关闭swipe
*/
close() {
this.animation("none");
},
/**
* 开启关闭动画
* @param {Object} type
*/
animation(type) {
const leftWidth = this.button.left.width;
const rightWidth = this.button.right.width;
if (this.eventpan && this.eventpan.token) {
BindingX.unbind({
token: this.eventpan.token,
eventType: "pan"
});
}
switch (type) {
case "left":
Promise.all([
this.move(this.selector, leftWidth),
this.move(this.leftButton, 0),
this.move(this.rightButton, rightWidth * 2)
]).then(() => {
this.setEmit(leftWidth, type);
});
break;
case "right":
Promise.all([
this.move(this.selector, -rightWidth),
this.move(this.leftButton, -leftWidth * 2),
this.move(this.rightButton, 0)
]).then(() => {
this.setEmit(-rightWidth, type);
});
break;
default:
Promise.all([
this.move(this.selector, 0),
this.move(this.leftButton, -leftWidth),
this.move(this.rightButton, rightWidth)
]).then(() => {
this.setEmit(0, type);
});
}
},
setEmit(x, type) {
const leftWidth = this.button.left.width;
const rightWidth = this.button.right.width;
this.isopen = this.isopen || "none";
this.stop = false;
this.isclick = false;
// 只有状态不一致才会返回结果
if (this.isopen !== type && this.x !== x) {
if (type === "left" && leftWidth > 0) {
this.$emit("change", "left");
}
if (type === "right" && rightWidth > 0) {
this.$emit("change", "right");
}
if (type === "none") {
this.$emit("change", "none");
}
}
this.x = x;
this.isopen = type;
},
move(ref, value) {
return new Promise(resolve => {
animation.transition(
ref,
{
styles: {
transform: `translateX(${value})`
},
duration: 150, //ms
timingFunction: "linear",
needLayout: false,
delay: 0 //ms
},
function(res) {
resolve(res);
}
);
});
},
/**
* 获取ref
* @param {Object} el
*/
getEl(el) {
return el.ref;
},
/**
* 获取节点信息
*/
getSelectorQuery() {
Promise.all([this.getDom("left"), this.getDom("right")]).then(() => {
let show = "none";
if (this.autoClose) {
show = "none";
} else {
show = this.show;
}
if (show === "none") {
// this.close()
} else {
this.open(show);
}
});
},
getDom(str) {
return new Promise((resolve, reject) => {
dom.getComponentRect(this.$refs[`selector-${str}-button--hock`], data => {
if (data) {
this.button[str] = data.size;
resolve(data);
} else {
reject();
}
});
});
}
}
};
This diff is collapsed.
var MIN_DISTANCE = 10;
/**
* 监听页面内值的变化,主要用于动态开关swipe-action
* @param {Object} newValue
* @param {Object} oldValue
* @param {Object} ownerInstance
* @param {Object} instance
*/
function sizeReady(newValue, oldValue, ownerInstance, instance) {
var state = instance.getState()
var buttonPositions = JSON.parse(newValue)
if (!buttonPositions || !buttonPositions.data || buttonPositions.data.length === 0) return
state.leftWidth = buttonPositions.data[0].width
state.rightWidth = buttonPositions.data[1].width
state.threshold = instance.getDataset().threshold
if (buttonPositions.show && buttonPositions.show !== 'none') {
openState(buttonPositions.show, instance, ownerInstance)
return
}
if (state.left) {
openState('none', instance, ownerInstance)
}
resetTouchStatus(instance)
}
/**
* 开始触摸操作
* @param {Object} e
* @param {Object} ins
*/
function touchstart(e, ins) {
var instance = e.instance;
var disabled = instance.getDataset().disabled
var state = instance.getState();
// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false;
if (disabled) return
// 开始触摸时移除动画类
instance.requestAnimationFrame(function(){
instance.removeClass('ani');
ins.callMethod('closeSwipe');
})
// 记录上次的位置
state.x = state.left || 0
// 计算滑动开始位置
stopTouchStart(e, ins)
}
/**
* 开始滑动操作
* @param {Object} e
* @param {Object} ownerInstance
*/
function touchmove(e, ownerInstance) {
var instance = e.instance;
var disabled = instance.getDataset().disabled
var state = instance.getState()
// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false;
if (disabled) return
// 是否可以滑动页面
stopTouchMove(e);
if (state.direction !== 'horizontal') {
return;
}
if (e.preventDefault) {
// 阻止页面滚动
e.preventDefault()
}
move(state.x + state.deltaX, instance, ownerInstance)
}
/**
* 结束触摸操作
* @param {Object} e
* @param {Object} ownerInstance
*/
function touchend(e, ownerInstance) {
var instance = e.instance;
var disabled = instance.getDataset().disabled
var state = instance.getState()
// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false;
if (disabled) return
// 滑动过程中触摸结束,通过阙值判断是开启还是关闭
// fixed by mehaotian 定时器解决点击按钮,touchend 触发比 click 事件时机早的问题 ,主要是 ios13
moveDirection(state.left, instance, ownerInstance)
}
/**
* 设置移动距离
* @param {Object} value
* @param {Object} instance
* @param {Object} ownerInstance
*/
function move(value, instance, ownerInstance) {
value = value || 0
var state = instance.getState()
var leftWidth = state.leftWidth
var rightWidth = state.rightWidth
// 获取可滑动范围
state.left = range(value, -rightWidth, leftWidth);
instance.requestAnimationFrame(function(){
instance.setStyle({
transform: 'translateX(' + state.left + 'px)',
'-webkit-transform': 'translateX(' + state.left + 'px)'
})
})
}
/**
* 获取范围
* @param {Object} num
* @param {Object} min
* @param {Object} max
*/
function range(num, min, max) {
return Math.min(Math.max(num, min), max);
}
/**
* 移动方向判断
* @param {Object} left
* @param {Object} value
* @param {Object} ownerInstance
* @param {Object} ins
*/
function moveDirection(left, ins, ownerInstance) {
var state = ins.getState()
var threshold = state.threshold
var position = state.position
var isopen = state.isopen || 'none'
var leftWidth = state.leftWidth
var rightWidth = state.rightWidth
if (state.deltaX === 0) {
openState('none', ins, ownerInstance)
return
}
if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth > 0 && rightWidth +
left < threshold)) {
// right
openState('right', ins, ownerInstance)
} else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth > 0 &&
leftWidth - left < threshold)) {
// left
openState('left', ins, ownerInstance)
} else {
// default
openState('none', ins, ownerInstance)
}
}
/**
* 开启状态
* @param {Boolean} type
* @param {Object} ins
* @param {Object} ownerInstance
*/
function openState(type, ins, ownerInstance) {
var state = ins.getState()
var position = state.position
var leftWidth = state.leftWidth
var rightWidth = state.rightWidth
var left = ''
state.isopen = state.isopen ? state.isopen : 'none'
switch (type) {
case "left":
left = leftWidth
break
case "right":
left = -rightWidth
break
default:
left = 0
}
// && !state.throttle
if (state.isopen !== type ) {
state.throttle = true
ownerInstance.callMethod('change', {
open: type
})
}
state.isopen = type
// 添加动画类
ins.requestAnimationFrame(function(){
ins.addClass('ani');
move(left, ins, ownerInstance)
})
// 设置最终移动位置,理论上只要进入到这个函数,肯定是要打开的
}
function getDirection(x, y) {
if (x > y && x > MIN_DISTANCE) {
return 'horizontal';
}
if (y > x && y > MIN_DISTANCE) {
return 'vertical';
}
return '';
}
/**
* 重置滑动状态
* @param {Object} event
*/
function resetTouchStatus(instance) {
var state = instance.getState();
state.direction = '';
state.deltaX = 0;
state.deltaY = 0;
state.offsetX = 0;
state.offsetY = 0;
}
/**
* 设置滑动开始位置
* @param {Object} event
*/
function stopTouchStart(event) {
var instance = event.instance;
var state = instance.getState();
resetTouchStatus(instance);
var touch = event.touches[0];
state.startX = touch.clientX;
state.startY = touch.clientY;
}
/**
* 滑动中,是否禁止打开
* @param {Object} event
*/
function stopTouchMove(event) {
var instance = event.instance;
var state = instance.getState();
var touch = event.touches[0];
state.deltaX = touch.clientX - state.startX;
state.deltaY = touch.clientY - state.startY;
state.offsetX = Math.abs(state.deltaX);
state.offsetY = Math.abs(state.deltaY);
state.direction = state.direction || getDirection(state.offsetX, state.offsetY);
}
module.exports = {
sizeReady: sizeReady,
touchstart: touchstart,
touchmove: touchmove,
touchend: touchend
}
export default {
data() {
return {
x: 0,
transition: false,
width: 0,
viewWidth: 0,
swipeShow: 0
};
},
watch: {
show(newVal) {
if (this.autoClose) return;
if (newVal && newVal !== "none") {
this.transition = true;
this.open(newVal);
} else {
this.close();
}
}
},
created() {
if (this.swipeaction.children !== undefined) {
this.swipeaction.children.push(this);
}
},
beforeDestroy() {
this.swipeaction.children.forEach((item, index) => {
if (item === this) {
this.swipeaction.children.splice(index, 1);
}
});
},
mounted() {
this.isopen = false;
setTimeout(() => {
this.getQuerySelect();
}, 50);
},
methods: {
appTouchStart(e) {
const { clientX } = e.changedTouches[0];
this.clientX = clientX;
this.timestamp = new Date().getTime();
},
appTouchEnd(e, index, item, position) {
const { clientX } = e.changedTouches[0];
// fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题
let diff = Math.abs(this.clientX - clientX);
let time = new Date().getTime() - this.timestamp;
if (diff < 40 && time < 300) {
this.$emit("click", {
content: item,
index,
position
});
}
},
// onClick(index, item, position) {
// this.$emit('click', {
// content: item,
// index,
// position
// })
// },
/**
* 移动触发
* @param {Object} e
*/
onChange(e) {
this.moveX = e.detail.x;
this.isclose = false;
},
touchstart() {
this.transition = false;
this.isclose = true;
this.autoClose && this.$emit("closeOther", this);
},
touchmove() {},
touchend() {
// 0的位置什么都不执行
if (this.isclose && this.isopen === "none") return;
if (this.isclose && this.isopen !== "none") {
this.transition = true;
this.close();
} else {
this.move(this.moveX + this.leftWidth);
}
},
/**
* 移动
* @param {Object} moveX
*/
move(moveX) {
// 打开关闭的处理逻辑不太一样
this.transition = true;
// 未打开状态
if (!this.isopen || this.isopen === "none") {
if (moveX > this.threshold) {
this.open("left");
} else if (moveX < -this.threshold) {
this.open("right");
} else {
this.close();
}
} else {
if (moveX < 0 && moveX < this.rightWidth) {
const rightX = this.rightWidth + moveX;
if (rightX < this.threshold) {
this.open("right");
} else {
this.close();
}
} else if (moveX > 0 && moveX < this.leftWidth) {
const leftX = this.leftWidth - moveX;
if (leftX < this.threshold) {
this.open("left");
} else {
this.close();
}
}
}
},
/**
* 打开
*/
open(type) {
this.x = this.moveX;
this.animation(type);
},
/**
* 关闭
*/
close() {
this.x = this.moveX;
// TODO 解决 x 值不更新的问题,所以会多触发一次 nextTick ,待优化
this.$nextTick(() => {
this.x = -this.leftWidth;
if (this.isopen !== "none") {
this.$emit("change", "none");
}
this.isopen = "none";
});
},
/**
* 执行结束动画
* @param {Object} type
*/
animation(type) {
this.$nextTick(() => {
if (type === "left") {
this.x = 0;
} else {
this.x = -this.rightWidth - this.leftWidth;
}
if (this.isopen !== type) {
this.$emit("change", type);
}
this.isopen = type;
});
},
getSlide() {},
getQuerySelect() {
const query = uni.createSelectorQuery().in(this);
query
.selectAll(".movable-view--hock")
.boundingClientRect(data => {
this.leftWidth = data[1].width;
this.rightWidth = data[2].width;
this.width = data[0].width;
this.viewWidth = this.width + this.rightWidth + this.leftWidth;
if (this.leftWidth === 0) {
// TODO 疑似bug ,初始化的时候如果x 是0,会导致移动位置错误,所以让元素超出一点
this.x = -0.1;
} else {
this.x = -this.leftWidth;
}
this.moveX = this.x;
this.$nextTick(() => {
this.swipeShow = 1;
});
if (!this.buttonWidth) {
this.disabledView = true;
}
if (this.autoClose) return;
if (this.show !== "none") {
this.transition = true;
this.open(this.shows);
}
})
.exec();
}
}
};
const MIN_DISTANCE = 10;
export default {
data() {
return {
uniShow: false,
left: 0,
buttonShow: "none",
ani: false,
moveLeft: ""
};
},
watch: {
show(newVal) {
if (this.autoClose) return;
this.openState(newVal);
},
left() {
this.moveLeft = `translateX(${this.left}px)`;
},
buttonShow(newVal) {
if (this.autoClose) return;
this.openState(newVal);
},
leftOptions() {
this.init();
},
rightOptions() {
this.init();
}
},
mounted() {
// this.position = {}
if (this.swipeaction && this.swipeaction.children !== undefined) {
this.swipeaction.children.push(this);
}
this.init();
},
beforeDestoy() {
this.swipeaction &&
this.swipeaction.children.forEach((item, index) => {
if (item === this) {
this.swipeaction.children.splice(index, 1);
}
});
},
methods: {
init() {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.getSelectorQuery();
}, 100);
// 移动距离
this.left = 0;
this.x = 0;
},
closeSwipe() {
if (!this.autoClose) return;
this.$emit("closeOther", this);
},
appTouchStart(e) {
const { clientX } = e.changedTouches[0];
this.clientX = clientX;
this.timestamp = new Date().getTime();
},
appTouchEnd(e, index, item, position) {
const { clientX } = e.changedTouches[0];
// fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题
let diff = Math.abs(this.clientX - clientX);
let time = new Date().getTime() - this.timestamp;
if (diff < 40 && time < 300) {
this.$emit("click", {
content: item,
index,
position
});
}
},
touchstart(e) {
if (this.disabled) return;
this.ani = false;
this.x = this.left || 0;
this.stopTouchStart(e);
this.autoClose && this.closeSwipe();
},
touchmove(e) {
if (this.disabled) return;
// 是否可以滑动页面
this.stopTouchMove(e);
if (this.direction !== "horizontal") {
return;
}
this.move(this.x + this.deltaX);
},
touchend() {
if (this.disabled) return;
this.moveDirection(this.left);
},
/**
* 设置移动距离
* @param {Object} value
*/
move(value) {
value = value || 0;
const leftWidth = this.leftWidth;
const rightWidth = this.rightWidth;
// 获取可滑动范围
this.left = this.range(value, -rightWidth, leftWidth);
},
/**
* 获取范围
* @param {Object} num
* @param {Object} min
* @param {Object} max
*/
range(num, min, max) {
return Math.min(Math.max(num, min), max);
},
/**
* 移动方向判断
* @param {Object} left
* @param {Object} value
*/
moveDirection(left) {
const threshold = this.threshold;
const isopen = this.isopen || "none";
const leftWidth = this.leftWidth;
const rightWidth = this.rightWidth;
if (this.deltaX === 0) {
this.openState("none");
return;
}
if (
(isopen === "none" && rightWidth > 0 && -left > threshold) ||
(isopen !== "none" && rightWidth > 0 && rightWidth + left < threshold)
) {
// right
this.openState("right");
} else if (
(isopen === "none" && leftWidth > 0 && left > threshold) ||
(isopen !== "none" && leftWidth > 0 && leftWidth - left < threshold)
) {
// left
this.openState("left");
} else {
// default
this.openState("none");
}
},
/**
* 开启状态
* @param {Boolean} type
*/
openState(type) {
const leftWidth = this.leftWidth;
const rightWidth = this.rightWidth;
let left = "";
this.isopen = this.isopen ? this.isopen : "none";
switch (type) {
case "left":
left = leftWidth;
break;
case "right":
left = -rightWidth;
break;
default:
left = 0;
}
if (this.isopen !== type) {
this.throttle = true;
this.$emit("change", type);
}
this.isopen = type;
// 添加动画类
this.ani = true;
this.$nextTick(() => {
this.move(left);
});
// 设置最终移动位置,理论上只要进入到这个函数,肯定是要打开的
},
close() {
this.openState("none");
},
getDirection(x, y) {
if (x > y && x > MIN_DISTANCE) {
return "horizontal";
}
if (y > x && y > MIN_DISTANCE) {
return "vertical";
}
return "";
},
/**
* 重置滑动状态
* @param {Object} event
*/
resetTouchStatus() {
this.direction = "";
this.deltaX = 0;
this.deltaY = 0;
this.offsetX = 0;
this.offsetY = 0;
},
/**
* 设置滑动开始位置
* @param {Object} event
*/
stopTouchStart(event) {
this.resetTouchStatus();
const touch = event.touches[0];
this.startX = touch.clientX;
this.startY = touch.clientY;
},
/**
* 滑动中,是否禁止打开
* @param {Object} event
*/
stopTouchMove(event) {
const touch = event.touches[0];
this.deltaX = touch.clientX - this.startX;
this.deltaY = touch.clientY - this.startY;
this.offsetX = Math.abs(this.deltaX);
this.offsetY = Math.abs(this.deltaY);
this.direction = this.direction || this.getDirection(this.offsetX, this.offsetY);
},
getSelectorQuery() {
const views = uni.createSelectorQuery().in(this);
views
.selectAll(".uni-swipe_button-group")
.boundingClientRect(data => {
let show = "none";
if (this.autoClose) {
show = "none";
} else {
show = this.show;
}
this.leftWidth = data[0].width || 0;
this.rightWidth = data[1].width || 0;
this.buttonShow = show;
})
.exec();
}
}
};
export default {
data() {
return {
position: [],
button: {},
btn: "[]"
};
},
// computed: {
// pos() {
// return JSON.stringify(this.position)
// },
// btn() {
// return JSON.stringify(this.button)
// }
// },
watch: {
button: {
handler(newVal) {
this.btn = JSON.stringify(newVal);
},
deep: true
},
show(newVal) {
if (this.autoClose) return;
if (!this.button) {
this.init();
return;
}
this.button.show = newVal;
},
leftOptions() {
this.init();
},
rightOptions() {
this.init();
}
},
created() {
if (this.swipeaction.children !== undefined) {
this.swipeaction.children.push(this);
}
},
mounted() {
this.init();
},
beforeDestroy() {
this.swipeaction.children.forEach((item, index) => {
if (item === this) {
this.swipeaction.children.splice(index, 1);
}
});
},
methods: {
init() {
clearTimeout(this.swipetimer);
this.swipetimer = setTimeout(() => {
this.getButtonSize();
}, 50);
},
closeSwipe() {
if (!this.autoClose) return;
this.$emit("closeOther", this);
},
change(e) {
this.$emit("change", e.open);
let show = this.button.show;
if (show !== e.open) {
this.button.show = e.open;
}
},
appTouchStart(e) {
const { clientX } = e.changedTouches[0];
this.clientX = clientX;
this.timestamp = new Date().getTime();
},
appTouchEnd(e, index, item, position) {
const { clientX } = e.changedTouches[0];
// fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题
let diff = Math.abs(this.clientX - clientX);
let time = new Date().getTime() - this.timestamp;
if (diff < 40 && time < 300) {
this.$emit("click", {
content: item,
index,
position
});
}
},
getButtonSize() {
const views = uni.createSelectorQuery().in(this);
views
.selectAll(".uni-swipe_button-group")
.boundingClientRect(data => {
let show = "none";
if (this.autoClose) {
show = "none";
} else {
show = this.show;
}
this.button = {
data,
show
};
})
.exec();
}
}
};
<template>
<view>
<slot />
</view>
</template>
<script>
/**
* SwipeAction 滑动操作
* @description 通过滑动触发选项的容器
* @tutorial https://ext.dcloud.net.cn/plugin?id=181
*/
export default {
// provide() {
// return {
// swipeaction: this
// };
// },
data() {
return {};
},
created() {
this.children = [];
},
methods: {
closeOther(vm) {
if (this.openItem && this.openItem !== vm) {
// #ifdef APP-VUE || H5 || MP-WEIXIN
this.openItem.button.show = "none";
// #endif
// #ifndef APP-VUE || H5 || MP-WEIXIN
this.openItem.close();
// #endif
}
this.openItem = vm;
}
}
};
</script>
<style></style>
<template>
<view
v-if="isShow"
ref="ani"
class="uni-transition"
:class="[ani.in]"
:style="'transform:' + transform + ';' + stylesObject"
@click="change"
>
<slot />
</view>
</template>
<script>
// #ifdef APP-NVUE
const animation = uni.requireNativePlugin("animation");
// #endif
/**
* Transition 过渡动画
* @description 简单过渡动画组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=985
* @property {Boolean} show = [false|true] 控制组件显示或隐藏
* @property {Array} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
* @value fade 渐隐渐出过渡
* @value slide-top 由上至下过渡
* @value slide-right 由右至左过渡
* @value slide-bottom 由下至上过渡
* @value slide-left 由左至右过渡
* @value zoom-in 由小到大过渡
* @value zoom-out 由大到小过渡
* @property {Number} duration 过渡动画持续时间
* @property {Object} styles 组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red`
*/
export default {
name: "UniTransition",
props: {
show: {
type: Boolean,
default: false
},
modeClass: {
type: Array,
default() {
return [];
}
},
duration: {
type: Number,
default: 300
},
styles: {
type: Object,
default() {
return {};
}
}
},
data() {
return {
isShow: false,
transform: "",
ani: { in: "", active: "" }
};
},
computed: {
stylesObject() {
let styles = {
...this.styles,
"transition-duration": this.duration / 1000 + "s"
};
let transfrom = "";
for (let i in styles) {
let line = this.toLine(i);
transfrom += line + ":" + styles[i] + ";";
}
return transfrom;
}
},
watch: {
show: {
handler(newVal) {
if (newVal) {
this.open();
} else {
this.close();
}
},
immediate: true
}
},
created() {
// this.timer = null
// this.nextTick = (time = 50) => new Promise(resolve => {
// clearTimeout(this.timer)
// this.timer = setTimeout(resolve, time)
// return this.timer
// });
},
methods: {
change() {
this.$emit("click", {
detail: this.isShow
});
},
open() {
clearTimeout(this.timer);
this.isShow = true;
this.transform = "";
this.ani.in = "";
for (let i in this.getTranfrom(false)) {
if (i === "opacity") {
this.ani.in = "fade-in";
} else {
this.transform += `${this.getTranfrom(false)[i]} `;
}
}
this.$nextTick(() => {
let timeout = setTimeout(() => {
clearTimeout(timeout);
timeout = null;
this._animation(true);
}, 50);
});
},
close() {
clearTimeout(this.timer);
this._animation(false);
},
_animation(type) {
let styles = this.getTranfrom(type);
// #ifdef APP-NVUE
if (!this.$refs["ani"]) return;
animation.transition(
this.$refs["ani"].ref,
{
styles,
duration: this.duration, //ms
timingFunction: "ease",
needLayout: false,
delay: 0 //ms
},
() => {
if (!type) {
this.isShow = false;
}
this.$emit("change", {
detail: this.isShow
});
}
);
// #endif
// #ifndef APP-NVUE
this.transform = "";
for (let i in styles) {
if (i === "opacity") {
this.ani.in = `fade-${type ? "out" : "in"}`;
} else {
this.transform += `${styles[i]} `;
}
}
this.timer = setTimeout(() => {
if (!type) {
this.isShow = false;
}
this.$emit("change", {
detail: this.isShow
});
}, this.duration);
// #endif
},
getTranfrom(type) {
let styles = {
transform: ""
};
this.modeClass.forEach(mode => {
switch (mode) {
case "fade":
styles.opacity = type ? 1 : 0;
break;
case "slide-top":
styles.transform += `translateY(${type ? "0" : "-100%"}) `;
break;
case "slide-right":
styles.transform += `translateX(${type ? "0" : "100%"}) `;
break;
case "slide-bottom":
styles.transform += `translateY(${type ? "0" : "100%"}) `;
break;
case "slide-left":
styles.transform += `translateX(${type ? "0" : "-100%"}) `;
break;
case "zoom-in":
styles.transform += `scale(${type ? 1 : 0.8}) `;
break;
case "zoom-out":
styles.transform += `scale(${type ? 1 : 1.2}) `;
break;
}
});
return styles;
},
_modeClassArr(type) {
let mode = this.modeClass;
if (typeof mode !== "string") {
let modestr = "";
mode.forEach(item => {
modestr += item + "-" + type + ",";
});
return modestr.substr(0, modestr.length - 1);
} else {
return mode + "-" + type;
}
},
// getEl(el) {
// console.log(el || el.ref || null);
// return el || el.ref || null
// },
toLine(name) {
return name.replace(/([A-Z])/g, "-$1").toLowerCase();
}
}
};
</script>
<style>
.uni-transition {
transition-timing-function: ease;
transition-duration: 0.3s;
transition-property: transform, opacity;
}
.fade-in {
opacity: 0;
}
.fade-active {
opacity: 1;
}
.slide-top-in {
/* transition-property: transform, opacity; */
transform: translateY(-100%);
}
.slide-top-active {
transform: translateY(0);
/* opacity: 1; */
}
.slide-right-in {
transform: translateX(100%);
}
.slide-right-active {
transform: translateX(0);
}
.slide-bottom-in {
transform: translateY(100%);
}
.slide-bottom-active {
transform: translateY(0);
}
.slide-left-in {
transform: translateX(-100%);
}
.slide-left-active {
transform: translateX(0);
opacity: 1;
}
.zoom-in-in {
transform: scale(0.8);
}
.zoom-out-active {
transform: scale(1);
}
.zoom-out-in {
transform: scale(1.2);
}
</style>
This source diff could not be displayed because it is too large. You can view the blob instead.
import { getCartCount } from "../api/home.api";
import store from "store";
import { SAVE_CART_COUNT } from "store/modules/shoppingCart/type.js";
const saveCartCount = count => {
store.commit(SAVE_CART_COUNT, count);
};
// console.log("saveCartCount", saveCartCount);
export const getCartCountVal = async function() {
const token = uni.getStorageSync("token") || "";
if (!token) return;
const [data] = await getCartCount();
if (!data) return;
saveCartCount(data.count);
const count = data.count > 99 ? "99+" : data.count ? data.count : "";
const params = {
index: 1,
text: `${count}`
};
count ? uni.setTabBarBadge(params) : uni.removeTabBarBadge({ index: 1 });
return count;
};
export const jumpToUrl = function(url) {
if (!url) return;
url = url.toString();
if (!url || url.indexOf("xyqb://") > -1) {
uni.switchTab({
url: "/pages/index/index"
});
return;
}
if (url.indexOf("http://") === 0 || url.indexOf("https://") === 0) {
uni.navigateTo({
url: `/pages/webview/webview?url=${encodeURIComponent(JSON.stringify(url))}`
});
return;
}
const tabUrl = ["/pages/index/index", "/pages/shopcart/index", "/pages/user/user"];
const navigateType = tabUrl.indexOf(url) > -1 ? "switchTab" : "navigateTo";
console.log(navigateType);
console.log(url);
uni[navigateType]({
url
});
};
import authApi from "@/api/address.api";
import { mapMutations } from "vuex";
import { mpConfig } from "@/utils/mpConfig/types";
import { saLogin, saTrackEvent } from "@/utils/sa.js";
import { onLaunchSubmit } from "@/utils/subscribe";
import adApi from "@/api/ad.api";
import { mapState } from "vuex";
import { smTrackEvent } from "@/utils/shumei";
export default {
data() {
return {
loginBtnText: mpConfig.loginBtnText,
loginData: {}
};
},
created() {
// #ifdef MP-WEIXIN
this.setGDTVID();
this.getLoginCode(); // 微信初始化调用一次
// #endif
},
computed: {
...mapState({
gdt_vid: state => state.ad.gdt_vid
})
},
methods: {
async setGDTVID() {
const openId = uni.getStorageSync("openid");
if (!this.gdt_vid || !openId) return;
await adApi.saveGDTVID({
clickId: this.gdt_vid,
wechatOpenId: openId
});
},
async getGDTVID() {
const openId = uni.getStorageSync("openid");
if (!openId) return;
const [res, err] = await adApi.getGDTVID(openId);
if (err) return;
return res;
},
async uploadTencentAdData() {
const openId = uni.getStorageSync("openid");
const gdt_vid = await this.getGDTVID();
// 注册上报
if (!gdt_vid || !openId) return;
await adApi.uploadAdData({
clickId: gdt_vid,
wechatOpenid: openId,
actionType: "REGISTER"
});
},
async getPhoneNumber(e) {
this.uploadSaLoginBtnClick();
const loginCode = await this.getLoginCode();
if (e.detail.errMsg == "getPhoneNumber:ok") {
this.miniAppLogin(loginCode, e.detail);
}
},
/***************************************************************/
/********************** 支付宝登录相关 ****************************/
async getAlipayPhoneNumber() {
this.uploadSaLoginBtnClick();
const result = await this.onGetAuthorize();
console.log("result===============>", result);
const loginCode = await this.getLoginCode();
if (result.response) {
this.miniAppLogin(loginCode, { encryptedData: result.response });
}
},
uploadSaLoginBtnClick() {
try {
const le_channel_code = uni.getStorageSync("vccChannel") || "";
saTrackEvent("MINI_LoginBtnClick", {
le_channel_code,
le_login_type: "微信授权登录"
});
} catch (err) {
console.log(err);
}
},
onGetAuthorize() {
return new Promise((resolve, reject) => {
uni.getPhoneNumber({
success: res => {
resolve(JSON.parse(res.response));
},
fail: res => {
console.log(res);
reject(res);
}
});
});
},
/********************** 支付宝登录相关 ****************************/
/***************************************************************/
getLoginCode() {
return new Promise(resolve => {
// #ifdef MP-BAIDU
uni.getLoginCode({
success: res => {
resolve(res.code);
},
fail: err => {
console.log("getLoginCode====================> fail", err);
}
});
// #endif
// #ifdef MP-WEIXIN || MP-ALIPAY
uni.login({
provider: mpConfig.provider,
// #ifdef MP-ALIPAY
scopes: "auth_base",
// #endif
success: res => {
resolve(res.code);
},
fail: err => {
console.log("login====================> fail", err);
}
});
// #endif
});
},
async miniAppLogin(opt, ueserPhoneData) {
// 登录接口
const [userinfo] = await authApi.login({ code: opt });
this.loginData = userinfo;
if (userinfo) {
userinfo.openid && uni.setStorageSync("openid", userinfo.openid);
if (userinfo.token) {
this.saveUserAuthInfo(userinfo);
this.$ry?.loggedin(userinfo.uuid);
this.setLoginInfoToStore(userinfo, true);
smTrackEvent({
eventId: "login",
type: "signupPlatform"
});
} else {
this.registerApp({
// #ifdef MP-ALIPAY
cursor: userinfo.cursor,
// #endif
// #ifndef MP-ALIPAY
openid: userinfo.openid,
unionId: userinfo.unionId || "",
iv: ueserPhoneData.iv,
// #endif
encryptedData: ueserPhoneData.encryptedData
});
}
} else {
const le_channel_code = uni.getStorageSync("vccChannel") || "";
saTrackEvent("MINI_LoginEvent", {
le_is_login_success: false,
le_login_type: "微信授权登录",
le_channel_code,
le_failure_code: "",
le_failure_message: "登录失败"
});
}
},
async registerApp(opt) {
// 注册
const [userinfo] = await authApi.register(opt);
if (userinfo) {
this.loginData = userinfo;
userinfo.openid && uni.setStorageSync("openid", userinfo.openid); // 注册的时候不会返回openid,只会返回token
userinfo.unionId && uni.setStorageSync("unionid", userinfo.unionId);
this.$ry?.register(userinfo.uuid);
this.setLoginInfoToStore(userinfo, false);
smTrackEvent({
eventId: "login",
type: "signupPlatform"
});
}
},
async setLoginInfoToStore(userinfo) {
uni.setStorageSync("token", userinfo.token);
uni.setStorageSync("phone", userinfo.phoneNo);
uni.setStorageSync("userAuthInfo", userinfo);
/* #ifdef MP-ALIPAY */
uni.setStorageSync("thirdUserId", userinfo.thirdUserId);
/* #endif */
saLogin(userinfo.uuid);
this.loginType && uni.$emit("login", true);
this.close && this.close();
// const saEvent = isLogin ? "MINI_LoginEvent" : "MINI_RegisterEvent";
const le_channel_code = uni.getStorageSync("vccChannel") || "";
saTrackEvent("MINI_LoginEvent", {
le_is_login_success: true,
le_login_type: "微信授权登录",
le_channel_code,
le_failure_code: "",
le_failure_message: ""
});
// #ifdef MP-WEIXIN
await this.setGDTVID();
await this.uploadTencentAdData();
this.isGetUserInfo(userinfo); // 由于获取头像功能当时只是支持百人团项目,其他平台登录无需走此逻辑
onLaunchSubmit(); // 订阅消息上报,只针对微信
// #endif
// #ifndef MP-WEIXIN
this.subscribeConfirm && this.subscribeConfirm(); // 直接返回
// #endif
},
isGetUserInfo(userinfo) {
const tenantId = +uni.getStorageSync("tenantId");
if (tenantId === 560761) {
// 羊小咩走正常授权头像、订阅消息逻辑
if (!userinfo.hasAvatar) {
this.showAuthModal();
} else {
this.$refs["subscribe-dialog"].open();
}
} else {
// 其他租户直接返回
return uni.navigateBack();
}
},
// 打开用户信息授权框
showAuthModal() {
this.$refs["authPopup"].open();
},
// 获取用户信息回调
handleUserInfo(e) {
const loginData = this.loginData;
this.getAvatar({
openid: loginData.openid,
userId: loginData.userId,
...e
});
},
// 如果用户信息取消则是否正常进行后面的授权,待确认
handleUserClose() {
this.$refs["subscribe-dialog"].open();
},
async getAvatar(opt) {
try {
// 发送头像信息成功之后走后面授权流程
await authApi.getAvatar(opt);
this.$refs["subscribe-dialog"].open();
} catch (err) {
console.log(err);
}
},
...mapMutations(["saveUserAuthInfo"])
}
};
export default {
data() {
return {
mpTitle: "欢迎使用羊小咩"
};
},
methods: {
initPrivacyModal() {
let isAgree = uni.getStorageSync("mpyinsi") || false;
let token = uni.getStorageSync("token") || false;
if (!isAgree && !token) {
uni.hideTabBar();
this.$refs.tipCurrent.open();
}
},
tipConfirmEvent() {
this.showModal = false;
uni.$emit("yinsi", true);
uni.setStorageSync("mpyinsi", true); //本地记录小程序同意隐私协议
uni.showTabBar();
}
}
};
import request from "@/utils/request";
export default {
// 页面卸载时触发。如wx.redirectTo或wx.navigateBack到其他页面时
onUnload() {
request.abortAll();
}
};
export default {
// 页面卸载时触发。如wx.redirectTo或wx.navigateBack到其他页面时
methods: {
saveEwm() {
const _self = this;
uni.getSetting({
success(res) {
if (!res.authSetting["scope.writePhotosAlbum"]) {
uni.authorize({
scope: "scope.writePhotosAlbum",
success(opt) {
console.log(opt)
//这里是用户同意授权后的回调
_self.saveImage();
},
fail(error) {
console.log(error);
uni.showModal({
title: "温馨提示",
content: "保存图片功能需要您的微信授权才能使用",
cancelText: "不授权",
confirmText: "授权",
confirmColor: "#ec1500",
success: function (res) {
if (res.confirm) {
// 这个 API 是基础库 1.1.0 才有的,所以需要做兼容处理:
if (uni.openSetting) {
uni.openSetting({
//进入授权设置页面手动授权
success: function (opt) {
console.log(opt);
if (opt.authSetting['scope.writePhotosAlbum']) {
_self.doneSaveImage && _self.doneSaveImage();
} else {
_self.refuseSaveImage && _self.refuseSaveImage();
}
}
});
}
//低版本兼容 做提示操作
else {
uni.showModal({
title: "授权提示",
confirmColor: "#ec1500",
content:
"保存图片需要您的微信授权才能使用,错过授权页面的处理方法:1、删除小程序->重新搜索进入->点击授权按钮;2、可在小程序设置打开相应权限"
});
}
}
//用户继续拒绝授权。
else if (res.cancel) {
uni.showModal({
title: "温馨提示",
content:
"相册授权失败,错过授权页面的处理方法:1、删除小程序->重新搜索进入->点击授权按钮;2、可在小程序设置打开相应权限",
showCancel: false,
confirmColor: "#ec1500",
success: function () {
_self.refuseSaveImage && _self.refuseSaveImage();
}
});
}
}
});
} //这里是用户拒绝授权后的回调
});
} else {
//用户已经授权过了
_self.saveImage();
}
}
});
}
}
};
<template>
<view class="divert" :style="{ backgroundColor: bgColor }">
<image :src="bgUrl" class="divert-bg" mode="widthFix" />
<!-- <image :src="qrcodeUrl" class="divert-img" mode="aspectFit" /> -->
<image :src="btnUrl" class="divert-btn" @click="checkAuth" />
</view>
</template>
<script>
import { saTrackEvent } from "@/utils/sa.js";
import { getPrivDomain } from "../../api/pay.api";
const PAGE_CONFIG = {
// title: "领88元优惠券",
// bgUrl: "https://img.lkbang.net/landing-bg.a1ee5cf9.jpg",
bgColor: "#FF2C40",
// qrcodeUrl: "https://img.lkbang.net/landing-qrcode.acb117ef.jpg",
btnUrl: "https://img.lkbang.net/xcx/save-btn.e8f785b7.png"
};
export default {
data() {
return {
bgUrl: "",
bgColor: "",
qrcodeUrl: "",
btnUrl: ""
};
},
onLoad(option) {
saTrackEvent("PD_YXMMAEC_SiyuLandingPageExtensionBannerExposure", {
page_name: "微信红包"
});
this.getPageInfo(option.activityType);
},
methods: {
async getPageInfo(activityType) {
const [res] = await getPrivDomain(activityType);
this.bgUrl = res.backgroundImg;
this.bgColor = PAGE_CONFIG.bgColor;
this.qrcodeUrl = res.qrCodeImg;
this.btnUrl = PAGE_CONFIG.btnUrl;
uni.setNavigationBarTitle({
title: res.title
});
},
checkAuth() {
/* #ifndef MP-ALIPAY */
uni.getSetting({
success: res => {
if (!res.authSetting["scope.writePhotosAlbum"]) {
uni.authorize({
scope: "scope.writePhotosAlbum",
success: () => {
saTrackEvent("PD_YXMMAEC_UserClickSiyuLandingPageExtensionBanner", {
page_name: "微信红包"
});
this.saveQrcode();
},
fail() {
uni.showModal({
title: "温馨提示",
content: "保存图片功能需要您的授权才能使用",
cancelText: "不授权",
confirmText: "授权",
confirmColor: "#ec1500",
success: function(res) {
console.log(res, "=================>res");
if (res.confirm) {
if (uni.openSetting) {
console.log("uni.openSetting============>", uni.openSetting);
uni.openSetting();
} else {
uni.showModal({
title: "授权提示",
confirmColor: "#ec1500",
content:
"保存图片需要您的授权才能使用,错过授权页面的处理方法:1、删除小程序->重新搜索进入->点击授权按钮;2、可在小程序设置打开相应权限"
});
}
} else if (res.cancel) {
uni.showModal({
title: "温馨提示",
content:
"相册授权失败,错过授权页面的处理方法:1、删除小程序->重新搜索进入->点击授权按钮;2、可在小程序设置打开相应权限",
showCancel: false,
confirmColor: "#ec1500"
});
}
}
});
}
});
} else {
//用户已经授权过了
this.saveQrcode();
}
}
});
/* #endif */
/* #ifdef MP-ALIPAY */
this.saveQrcode();
/* #endif */
},
saveQrcode() {
uni.downloadFile({
url: this.qrcodeUrl,
success: res => {
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
this.$api.msg("保存成功");
},
fail: () => {
this.$api.msg("保存失败");
}
});
},
fail: function(error) {
uni.hideLoading();
console.log(error);
}
});
}
}
};
</script>
<style lang="scss" scoped>
@mixin abs-center {
position: absolute;
left: 0;
right: 0;
margin: auto;
z-index: 2;
}
.divert {
background-color: $uni-bg-color-grey;
position: relative;
height: 100%;
&-bg {
position: relative;
z-index: 1;
height: 100%;
width: 100vw;
margin: 0 auto;
overflow: auto;
display: block;
}
&-img {
@include abs-center();
display: block;
top: 744rpx;
width: 432rpx;
height: 432rpx;
}
&-btn {
@include abs-center();
display: block;
bottom: -73rpx;
width: 282rpx;
height: 60rpx;
line-height: 70rpx;
color: #fff;
font-size: 32rpx;
background: #ff2525;
border-radius: 43rpx;
}
}
</style>
<template>
<view>
<uni-list :border="false" class="address">
<uni-list-item
title="退款原因"
class="required"
clickable
:right-text="reasonName"
:show-arrow="true"
@click="showAction"
/>
<uni-list-item title="退款金额" class="required">
<view slot="footer" class="form-input">
<view class="money">¥{{ refund.amount }}</view>
<view class="tips">不可修改,最多{{ refund.amount }}</view>
</view>
</uni-list-item>
<uni-list-item title="退款说明" class="required">
<view slot="footer" class="form-input">
<textarea
v-model="refund.mark"
:auto-height="true"
:maxlength="200"
placeholder-class="placeholder"
placeholder="请输入退款说明(最多200字)"
/>
</view>
</uni-list-item>
<uni-list-item title="联系电话" class="required">
<view slot="footer" class="form-input">
<input
v-model="refund.phone"
class="uni-input"
type="number"
placeholder-class="placeholder"
placeholder="请填写联系电话"
/>
</view>
</uni-list-item>
<uni-list-item>
<view slot="body">
<view class="upload-desc">
<text>上传凭证</text>
</view>
<view>
<ImageUploader @change="imageChange" />
</view>
</view>
</uni-list-item>
</uni-list>
<ActionSheet ref="popup" action-text="确定" title="请选择原因">
<template>
<view>
<radio-group @change="radioChange">
<label
v-for="(item, index) in reasons"
:key="item.id"
class="uni-list-cell uni-list-cell-pd"
>
<view class="radio-cell">
<radio color="#ec1500" :value="item.id" :checked="index === current" />
<text>{{ item.name }}</text>
</view>
</label>
</radio-group>
</view>
</template>
</ActionSheet>
<view class="row">
<button class="primary-btn" type="default" @click="confirm">
提交申请
</button>
</view>
</view>
</template>
<script>
import { uniList, uniListItem } from "@dcloudio/uni-ui";
import ActionSheet from "../../components/actionSheet";
import ImageUploader from "../../components/imageUploader/index";
import { submit } from "../../api/aftersale.api";
export default {
components: {
uniList,
uniListItem,
ActionSheet,
ImageUploader
},
data() {
return {
reasonName: "请选择",
refund: {
orderNo: "",
reason: "",
amount: "1000.00",
mark: "",
phone: "",
proofs: []
},
reasons: [
{ name: "未按承诺时间发货", id: 1 },
{ name: "多拍/错拍/不想要", id: 4 },
{ name: "其他原因", id: 5 }
]
};
},
onLoad(option) {
this.refund.orderNo = option.orderNo || "";
},
methods: {
showAction() {
this.$refs.popup.open();
},
radioChange(e) {
this.refund.reason = +e.detail.value;
this.reasonName = this.reasons.filter(item => item.id === +e.detail.value)[0].name;
},
imageChange(data) {
this.refund.proofs = data.map(item => item.url);
},
confirm() {
const data = this.refund;
if (!data.orderNo) {
this.$api.msg("缺少订单号");
return;
}
if (!data.reason) {
this.$api.msg("请选择退款原因");
return;
}
if (!/(^1[3|4|5|7|8][0-9]{9}$)/.test(data.phone)) {
this.$api.msg("请输入正确的联系电话");
return;
}
if (!data.mark) {
this.$api.msg("请输入退款说明");
return;
}
const param = Object.assign({}, this.refund);
submit(param)
.then(() => {
this.$api.msg(`申请成功`);
setTimeout(() => {
uni.navigateBack();
}, 400);
})
.catch(e => {
console.error(e);
});
}
}
};
</script>
<style lang="scss" scoped>
::v-deep .uni-list-item__content-title {
font-size: 30rpx;
color: $text-color-n3;
}
.primary-btn {
margin-top: 60px;
@include primary-bg;
color: white;
font-size: $uni-font-size-base;
font-weight: bold;
border-radius: $uni-border-radius-xl;
flex: 1;
}
.form-input {
flex: 3;
}
textarea {
width: 100%;
}
::v-deep .uni-list-item__container {
align-items: center;
}
.required ::v-deep .uni-list-item__content-title::before {
content: "*";
color: red;
}
.radio-cell {
padding: 40rpx 30rpx;
text {
font-size: 30rpx;
margin-left: 20rpx;
}
}
.money {
color: #ec1500;
font-size: 30rpx;
}
.tips {
font-size: 24rpx;
color: #999;
}
.upload-desc {
font-size: 30rpx;
color: #666;
margin-bottom: 24rpx;
}
</style>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
import * as types from "./type";
const ad = {
state: {
// __wxConfig.envVersion !== "release"
gdt_vid: ""
},
mutations: {
[types.SET_GDT_VID](state, data) {
state.gdt_vid = data;
}
},
actions: {
setGDTVID({ commit }, params) {
commit(types.SET_GDT_VID, params);
}
}
};
export default ad;
const SET_GDT_VID = "setGDTVID";
export { SET_GDT_VID };
This diff is collapsed.
const SET_ENV_TAG = "changeEnvTag";
export { SET_ENV_TAG };
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment