1.修改商品规格中可能出现的sku判断,优化选择商品规格上下滑动。2.优化登录页面样式。3.优化购物车样式

master
lemon橪 2021-10-26 15:27:13 +08:00
parent 5f6c1adf91
commit ebf32a18b0
15 changed files with 987 additions and 812 deletions

View File

@ -48,7 +48,7 @@
</view>
</view>
<!-- 商品信息 -->
<view class="goods-skus-box">
<scroll-view class="goods-skus-box" :scroll-y="true">
<!-- 规格 -->
<view class="goods-skus-view" :key="specIndex" v-for="(spec, specIndex) in formatList">
<view class="skus-view-list">
@ -65,7 +65,7 @@
:input-height="numberBox.height" :size="numberBox.size" :min="1" v-model="num">
</u-number-box>
</view>
</view>
</scroll-view>
<!-- 按钮 -->
<view class="btns">
@ -142,7 +142,7 @@ export default {
/**点击规格 */
handleClickSpec(val, index, specValue) {
this.$set(this.currentSelceted, index, specValue.value);
this.currentSelceted[index] = specValue.value;
let selectedSkuId = this.goodsSpec.find((i) => {
let matched = true;
let specValues = i.specValues.filter((j) => j.specName !== "images");
@ -156,6 +156,8 @@ export default {
return i;
}
});
if (selectedSkuId?.skuId) {
this.$set(this.currentSelceted, index, specValue.value);
this.selectSkuList = {
spec: {
specName: val.name,
@ -169,6 +171,13 @@ export default {
skuId: selectedSkuId.skuId,
goodsId: this.goodsDetail.goodsId,
});
} else {
uni.showToast({
title: "暂无该商品!",
duration: 2000,
icon: "none",
});
}
},
/**

View File

@ -0,0 +1,278 @@
<template>
<view class="xt__verify-code">
<!-- 输入框 -->
<input
id="xt__input"
:value="code"
class="xt__input"
:focus="isFocus"
:password="isPassword"
:type="inputType"
:maxlength="size"
@input="input"
@focus="inputFocus"
@blur="inputBlur"
/>
<!-- 光标 -->
<view
id="xt__cursor"
v-if="cursorVisible && type !== 'middle'"
class="xt__cursor"
:style="{ left: codeCursorLeft[code.length] + 'px', height: cursorHeight + 'px', backgroundColor: cursorColor }"
></view>
<!-- 输入框 - -->
<view id="xt__input-ground" class="xt__input-ground">
<template v-for="(item, index) in size">
<view
:key="index"
:style="{ borderColor: code.length === index && cursorVisible ? boxActiveColor : boxNormalColor }"
:class="['xt__box', `xt__box-${type + ''}`, `xt__box::after`]"
>
<view :style="{ borderColor: boxActiveColor }" class="xt__middle-line" v-if="type === 'middle' && !code[index]"></view>
<text class="xt__code-text">{{ code[index] | codeFormat(isPassword) }}</text>
</view>
</template>
</view>
</view>
</template>
<script>
/**
* @description 输入验证码组件
* @property {string} type = [box|middle|bottom] - 显示类型 默认box -eg:bottom
* @property {string} inputType = [text|number] - 输入框类型 默认number -eg:number
* @property {number} size = [4|6] - 支持的验证码数量 默认6 -eg:6
* @property {boolean} isFocus - 是否立即聚焦 默认true
* @property {boolean} isPassword - 是否以密码形式显示 默认false -eg:false
* @property {string} cursorColor - 光标颜色 默认#cccccc
* @property {string} boxNormalColor - 光标未聚焦到的框的颜色 默认#cccccc
* @property {string} boxActiveColor - 光标聚焦到的框的颜色 默认#000000
* @event {Function(data)} confirm - 输入完成
*/
export default {
name: 'xt-verify-code',
props: {
value: {
type: String,
default: () => ''
},
type: {
type: String,
default: () => 'box'
},
inputType: {
type: String,
default: () => 'number'
},
size: {
type: Number,
default: () => 6
},
isFocus: {
type: Boolean,
default: () => true
},
isPassword: {
type: Boolean,
default: () => false
},
cursorColor: {
type: String,
default: () => '#cccccc'
},
boxNormalColor: {
type: String,
default: () => '#cccccc'
},
boxActiveColor: {
type: String,
default: () => '#000000'
}
},
model: {
prop: 'value',
event: 'input'
},
data() {
return {
cursorVisible: false,
cursorHeight: 35,
code: '', //
codeCursorLeft: [] //
};
},
created() {
this.cursorVisible = this.isFocus;
},
mounted() {
this.init();
},
methods: {
/**
* @description 初始化
*/
init() {
this.getCodeCursorLeft();
this.setCursorHeight();
},
/**
* @description 获取元素节点
* @param {string} elm - 节点的idclass 相当于 document.querySelect的参数 -eg: #id
* @param {string} type = [single|array] - 单个元素获取多个元素 默认是单个元素
* @param {Function} callback - 回调函数
*/
getElement(elm, type = 'single', callback) {
uni
.createSelectorQuery()
.in(this)
[type === 'array' ? 'selectAll' : 'select'](elm)
.boundingClientRect()
.exec(data => {
callback(data[0]);
});
},
/**
* @description 计算光标的高度
*/
setCursorHeight() {
this.getElement('.xt__box', 'single', boxElm => {
this.cursorHeight = boxElm.height * 0.6;
});
},
/**
* @description 获取光标在每一个box的left位置
*/
getCodeCursorLeft() {
//
this.getElement('#xt__input-ground', 'single', parentElm => {
const parentLeft = parentElm.left;
// box
this.getElement('.xt__box', 'array', elms => {
this.codeCursorLeft = [];
elms.forEach(elm => {
this.codeCursorLeft.push(elm.left - parentLeft + elm.width / 2);
});
});
});
},
//
input(e) {
const value = e.detail.value;
this.cursorVisible = value.length !== this.size;
this.$emit('input', value);
this.inputSuccess(value);
},
//
inputSuccess(value) {
if (value.length === this.size) {
this.$emit('confirm', value);
}
},
//
inputFocus() {
this.cursorVisible = this.code.length !== this.size;
},
//
inputBlur() {
this.cursorVisible = false;
}
},
watch: {
value(val) {
this.code = val;
}
},
filters: {
codeFormat(val, isPassword) {
let value = '';
if (val) {
value = isPassword ? '*' : val;
}
return value;
}
}
};
</script>
<style lang="scss" scoped>
.xt__verify-code {
position: relative;
width: 100%;
box-sizing: border-box;
.xt__input {
height: 100%;
width: 200%;
position: absolute;
left: -100%;
z-index: 1;
}
.xt__cursor {
position: absolute;
top: 50%;
transform: translateY(-50%);
display: inline-block;
width: 2px;
animation-name: cursor;
animation-duration: 0.8s;
animation-iteration-count: infinite;
}
.xt__input-ground {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
box-sizing: border-box;
.xt__box {
position: relative;
display: inline-block;
width: 76rpx;
height: 112rpx;
&-bottom {
border-bottom-width: 2px;
border-bottom-style: solid;
}
&-box {
border-width: 2px;
border-style: solid;
}
&-middle {
border: none;
}
.xt__middle-line {
position: absolute;
top: 50%;
left: 50%;
width: 50%;
transform: translate(-50%, -50%);
border-bottom-width: 2px;
border-bottom-style: solid;
}
.xt__code-text {
position: absolute;
top: 50%;
left: 50%;
font-size:52rpx;
transform: translate(-50%, -50%);
}
}
}
}
@keyframes cursor {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>

View File

@ -2,8 +2,8 @@
"name" : "lili商城",
"appid" : "__UNI__C100675",
"description" : "",
"versionName" : "4.0.46",
"versionCode" : 4000046,
"versionName" : "4.0.47",
"versionCode" : 4000047,
"transformPx" : false,
"app-plus" : {
"compatible" : {

View File

@ -48,7 +48,7 @@
</view>
</view>
<!-- 商品信息 -->
<view class="goods-skus-box">
<scroll-view class="goods-skus-box" :scroll-y="true">
<!-- 规格 -->
<view class="goods-skus-view" :key="specIndex" v-for="(spec, specIndex) in formatList">
<view class="skus-view-list">
@ -65,7 +65,7 @@
:input-height="numberBox.height" :size="numberBox.size" :min="1" v-model="num">
</u-number-box>
</view>
</view>
</scroll-view>
<!-- 按钮 -->
<view class="btns">
@ -142,7 +142,7 @@ export default {
/**点击规格 */
handleClickSpec(val, index, specValue) {
this.$set(this.currentSelceted, index, specValue.value);
this.currentSelceted[index] = specValue.value;
let selectedSkuId = this.goodsSpec.find((i) => {
let matched = true;
let specValues = i.specValues.filter((j) => j.specName !== "images");
@ -156,6 +156,8 @@ export default {
return i;
}
});
if (selectedSkuId?.skuId) {
this.$set(this.currentSelceted, index, specValue.value);
this.selectSkuList = {
spec: {
specName: val.name,
@ -169,6 +171,13 @@ export default {
skuId: selectedSkuId.skuId,
goodsId: this.goodsDetail.goodsId,
});
} else {
uni.showToast({
title: "暂无该商品!",
duration: 2000,
icon: "none",
});
}
},
/**

View File

@ -1,250 +0,0 @@
<template>
<div class="form">
<u-form :model="codeForm" ref="validateCodeForm">
<u-form-item class="cell" label-width="120" label="手机号" prop="mobile">
<u-input maxlength="11" v-model="codeForm.mobile" placeholder="请输入您的手机号" />
</u-form-item>
<u-form-item class="cell code" label-width="120" prop="code" label="验证码">
<div style="display:flex; width:100%;">
<u-input maxlength="6" v-model="codeForm.code" placeholder="请输入验证码" />
<u-verification-code keep-running unique-key="page-login" :seconds="seconds" @end="end" @start="start"
ref="uCode" @change="codeChange"></u-verification-code>
<view @tap="getCode" :style="{color:aiderLightColor}" class="text-tips">{{ tips }}</view>
</div>
</u-form-item>
<view class="submit bg-linear-gradient" @click="submit"></view>
<view :style="{color:aiderLightColor}" class="text-tips cell" @click="clickLogin"></view>
<myVerification v-if="codeFlag" @send="verification" class="verification" ref="verification" business="LOGIN" />
</u-form>
</div>
</template>
<script>
import { sendMobile, smsLogin } from "@/api/login";
import { getUserInfo } from "@/api/members";
import storage from "@/utils/storage.js"; //
import { whetherNavigate } from "@/utils/Foundation"; //
import myVerification from "@/components/verification/verification.vue"; //
import uuid from "@/utils/uuid.modified.js"; // uuid
export default {
components: {
myVerification,
},
props: ["status"], //
data() {
return {
aiderLightColor: this.$aiderLightColor,
uuid,
flage: false, //
codeFlag: true, //
codeForm: {
mobile: "", //
code: "", //
},
tips: "", //
clientType: "", //
seconds: 60, //
//
codeRules: {
//
mobile: [
{
validator: (rule, value, callback) => {
return this.$u.test.mobile(value);
},
message: "手机号码不正确",
trigger: ["blur"],
},
],
//
code: [
{
min: 4,
max: 6,
required: true,
message: "请输入验证码",
trigger: ["blur"],
},
],
},
};
},
// onReadysetRulesonLoad
mounted() {
this.$refs.validateCodeForm.setRules(this.codeRules);
/**
* 条件编译判断当前客户端类型
*/
//#ifdef H5
this.clientType = "H5";
//#endif
//#ifdef APP-PLUS
this.clientType = "APP";
//#endif
},
watch: {
async flage(val) {
if (val) {
if (this.$refs.uCode.canGetCode) {
//
uni.showLoading({
title: "正在获取验证码",
});
let res = await sendMobile(this.codeForm.mobile);
uni.hideLoading();
// this.start()
if (res.data.success) {
this.$refs.uCode.start();
} else {
uni.showToast({
title: res.data.message,
duration: 2000,
icon: "none",
});
this.flage = false;
}
} else {
this.$u.toast("请倒计时结束后再发送");
}
} else {
this.$refs.verification.hide();
}
},
},
methods: {
//
verification(val) {
this.flage = val == this.$store.state.verificationKey ? true : false;
},
//
submit() {
if (!this.status) {
/**
* 用户必须了解
* 用户协议以及隐私政策
*/
uni.showToast({
title: "请您阅读并同意用户协议以及隐私政策",
duration: 2000,
icon: "none",
});
return false;
}
let _this = this;
this.$refs.validateCodeForm.validate((valid) => {
if (valid) {
/**
* 清空当前账号信息
*/
storage.setHasLogin(false);
storage.setAccessToken("");
storage.setRefreshToken("");
storage.setUuid(this.uuid.v1());
storage.setUserInfo({});
/**
* 执行登录
*/
smsLogin(this.codeForm, _this.clientType).then((res) => {
if (res.data.success) {
storage.setAccessToken(res.data.result.accessToken);
storage.setRefreshToken(res.data.result.refreshToken);
/**
* 登录成功后获取个人信息
*/
getUserInfo().then((user) => {
if (user.data.success) {
/**
* 个人信息存储到缓存userInfo中
*/
storage.setUserInfo(user.data.result);
storage.setHasLogin(true);
//
uni.showToast({
title: "登录成功!",
icon: "none",
});
/**
* 计算出当前router路径
* 1.如果跳转的链接为登录页面或跳转的链接为空页面则会重新跳转到首页
* 2.都不满足返回跳转页面
*/
whetherNavigate();
} else {
uni.switchTab({
url: "/pages/tabbar/home/index",
});
}
});
}
});
}
});
},
//
clickLogin() {
this.$emit("open", "click");
},
/**点击验证码*/
codeChange(text) {
this.tips = text;
},
/** 结束验证码后执行 */
end() {},
/**获取验证码 */
getCode() {
if (this.tips == "重新获取") {
this.codeFlag = true;
uni.showLoading({
title: "加载中",
});
setTimeout(() => {
this.$refs.verification.hide();
uni.hideLoading();
}, 2000);
}
if (!this.$u.test.mobile(this.codeForm.mobile)) {
uni.showToast({
title: "请输入正确手机号",
icon: "none",
});
return false;
}
if (!this.flage) {
this.$refs.verification.error();
return false;
}
},
//
start() {
this.$u.toast("验证码已发送");
this.flage = false;
this.codeFlag = false;
this.$refs.verification.hide();
},
},
};
</script>
<style lang="scss" scoped>
@import url("./login.scss");
// #ifdef MP-WEIXIN
@import url("./mp-codeLogin.scss");
// #endif
</style>

View File

@ -1,68 +0,0 @@
.sub-title {
font-size: 24rpx;
color: #999;
}
.cell {
margin: 40rpx 0;
}
.login-ball {
border-bottom-left-radius: 300rpx;
height: 400rpx;
position: relative;
}
/deep/ .u-form-item--right__content__slot {
width: 100%;
display: block;
}
.title {
font-size: 48rpx;
color: #000;
text-align: center;
}
.privacy {
font-size: 24upx;
color: #999;
text-align: center;
margin-top: 360rpx;
width: 100%;
display: flex;
justify-content: center;
}
span {
color: $aider-light-color;
}
.form {
padding: 0 72rpx;
}
.divider {
margin: 30rpx 0 !important;
}
.submit {
height: 80rpx;
line-height: 80rpx;
color: #fff;
text-align: center;
font-size: 30rpx;
border-radius: 100px;
}
.logo {
margin-top: 20rpx;
width: 200rpx;
height: 200rpx;
text-align: center;
}
.logo-cell {
text-align: center;
}
.text-tips {
text-align: center;
}
.tips {
position: absolute;
bottom: 10rpx;
width: 100%;
text-align: center;
}

View File

@ -1,113 +1,242 @@
<template>
<view>
<!-- -->
<view v-if="codeLogin">
<!-- 背景 -->
<view class="login-ball bg-linear-gradient small"></view>
<view class="logo-cell">
<image class="logo" :src="config.logo" mode="aspectFit"></image>
</view>
<view class="title">{{config.name}}</view>
<!-- 验证码登录 -->
<codeLogin @open="open" :status="value" v-if="login && loginData.code" />
<!-- 账号密码登录 -->
<onClickLogin @open="open" :status="value" v-if="login && loginData.click" />
<view class="form"> </view>
<!-- 隐私政策 -->
<div class="privacy">
<u-checkbox-group :icon-size="24" width="45rpx">
<u-checkbox v-model="value" :active-color="lightColor"></u-checkbox>
</u-checkbox-group>
同意<span @click="handleClick('user')"></span><span @click="handleClick('privacy')"></span>
<div class="wrapper">
<u-navbar :is-back="showBack" :border-bottom="false"></u-navbar>
<div>
<div class="title">{{loginTitleWay[current].title}}</div>
<div :class="current == 1 ? 'desc-light':'desc'">{{loginTitleWay[current].desc}}<span
v-if="current == 1">{{mobile | secrecyMobile}}</span></div>
</div>
<!-- 手机号 -->
<div v-show="current==0">
<u-input :custom-style="inputStyle" :placeholder-style="placeholderStyle" placeholder="请输入手机号 (11位)"
class='mobile' focus v-model="mobile" type="number" maxlength="11" />
<div :class="!enabuleFetchCode ?'disable':'fetch'" @click="fetchCode" class=" btn">获取验证码</div>
<div class="flex">
<u-checkbox-group :icon-size="24" width="45rpx">
<u-checkbox shape="circle" v-model="enabulePrivacy" active-color="#FF5E00"></u-checkbox>
</u-checkbox-group>
<div class="tips">未注册的手机号验证后将自动创建用户账号登录即代表您已同意<span @click="navigateToPrivacy('privacy')">使</span>
</div>
</div>
</div>
<!-- 输入验证码 -->
<div v-show="current==1" class="box-code">
<verifyCode type="bottom" @confirm="submit" boxActiveColor="#D8D8D8" v-model="code" isFocus
boxNormalColor="#D8D8D8" cursorColor="#D8D8D8" />
<div class="fetch-btn">
<u-verification-code change-text="x" end-text="" keep-running unique-key="page-login"
:seconds="seconds" @end="end" @start="start" ref="uCode" @change="codeChange"></u-verification-code>
<span @tap="fetchCode" :style="{color:codeColor}"> {{tips}}</span>
</div>
</div>
<!-- 循环出当前可使用的第三方登录模式 -->
<div class="flex login-list">
<div :style="{background:item.color}" class="login-item" v-for="(item,index) in loginList" :key="index">
<u-icon v-if="item.title!='APPLE'" color="#fff" size="42" :name="item.icon" @click="navigateLogin(item)">
</u-icon>
<u-image v-else src="/static/appleidButton@2x.png" :lazy-load="false" @click="navigateLogin(item)" width="80"
height="80" />
</div>
</div>
<myVerification v-if="codeFlag" @send="verification" class="verification" ref="verification" business="LOGIN" />
</div>
</view>
<view v-if="wechatLogin">
<wechatH5Login />
</view>
</view>
</template>
<script>
import codeLogin from "./codeLogin";
import onClickLogin from "./onClickLogin";
import { openIdLogin ,loginCallback } from "@/api/connect.js";
import api from "@/config/api.js";
import { sendMobile, smsLogin } from "@/api/login";
import myVerification from "@/components/verification/verification.vue"; //
import uuid from "@/utils/uuid.modified.js"; // uuid
import verifyCode from "@/components/verify-code/verify-code";
import { getUserInfo } from "@/api/members";
import storage from "@/utils/storage.js";
import { loginCallback } from "@/api/connect.js";
import { webConnect } from "@/api/connect.js";
import config from "@/config/config";
import wechatH5Login from "./wechatH5Login.vue";
import { whetherNavigate } from "@/utils/Foundation"; //
import storage from "@/utils/storage.js"; //
export default {
onShow() {
//#ifdef H5
let isWXBrowser = /micromessenger/i.test(navigator.userAgent);
if (isWXBrowser) {
webConnect("WECHAT").then((res) => {
let data = res.data;
if (data.success) {
window.location = data.result;
}
});
}
//#endif
},
components: { myVerification, verifyCode },
data() {
return {
config,
uuid,
flage: false, //
codeFlag: true, //
tips: "",
current: 0,
codeColor: "#999", //
lightColor: this.$lightColor,
wechatLogin: false, //
codeLogin: false, //
value: true, //
loginData: {
code: true, //
click: false,
seconds: 60, //
loginTitleWay: [
{
title: "欢迎登录",
desc: "登录后更精彩,美好生活即将开始",
},
login: true, //
{
title: "请输入验证码",
desc: "已经发送验证码至",
},
],
showBack: false,
enabuleFetchCode: false,
enabulePrivacy: false, //
mobile: "", //
code: "", //
inputStyle: {
height: "104rpx",
"border-bottom": "1rpx solid #D8D8D8",
"letter-spacing": "1rpx",
"font-size": "40rpx",
"line-height": "40rpx",
color: "#333",
},
placeholderStyle: "font-size: 32rpx;line-height: 32rpx;color: #999999;",
loginList: [
//
{
icon: "weixin-fill",
color: "#00a327",
title: "微信",
code: "WECHAT",
},
{
icon: "qq-fill",
color: "#38ace9",
title: "QQ",
code: "QQ",
},
{
icon: "apple-fill",
color: "#000000",
title: "Apple",
code: "APPLE",
},
],
};
},
watch: {},
components: {
codeLogin,
onClickLogin,
wechatH5Login,
},
mounted() {
// #ifndef APP-PLUS
//
var ua = window.navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == "micromessenger") {
this.wechatLogin = true;
return;
} else {
this.codeLogin = true;
}
/**
* 条件编译判断当前客户端类型
*/
//#ifdef H5
this.clientType = "H5";
//#endif
//#ifdef APP-PLUS
this.codeLogin = true;
this.clientType = "APP";
/**如果是app 加载支持的登录方式*/
let _this = this;
uni.getProvider({
service: "oauth",
success: (result) => {
_this.loginList = result.provider.map((value) => {
//title
let title = "";
//code
let code = "";
//
let color = "#8b8b8b";
//
let icon = "";
//uni code
let appcode = "";
switch (value) {
case "weixin":
icon = "weixin-circle-fill";
color = "#00a327";
title = "微信";
code = "WECHAT";
break;
case "qq":
icon = "qq-circle-fill";
color = "#38ace9";
title = "QQ";
code = "QQ";
break;
case "apple":
icon = "apple-fill";
color = "#000000";
title = "Apple";
code = "APPLE";
break;
}
return {
title: title,
code: code,
color: color,
icon: icon,
appcode: value,
};
});
},
fail: (error) => {
uni.showToast({
title: "获取登录通道失败" + error,
duration: 2000,
icon: "none",
});
},
});
//#endif
//
// #ifdef H5
this.methodFilter(["QQ"]);
// #endif
//
// #ifdef MP-WEIXIN
this.methodFilter(["WECHAT"]);
// #endif
},
watch: {
current(val) {
val ? (this.showBack = true) : (this.showBack = false);
},
mobile: {
handler(val) {
if (val.length == 11) {
this.enabuleFetchCode = true;
}
},
},
async flage(val) {
if (val) {
if (this.$refs.uCode.canGetCode) {
//
uni.showLoading({});
let res = await sendMobile(this.mobile);
uni.hideLoading();
// this.start()
if (res.data.success) {
this.current = 1;
this.$refs.uCode.start();
} else {
uni.showToast({
title: res.data.message,
duration: 2000,
icon: "none",
});
this.flage = false;
}
} else {
this.$u.toast("请倒计时结束后再发送");
}
} else {
this.$refs.verification.hide();
}
},
},
onLoad(options) {
if (options && options.state) {
this.stateLogin(options.state);
}
},
methods: {
handleClick(val) {
uni.navigateTo({
url: "/pages/mine/help/tips?type=" + val,
});
},
// open
open(val) {
Object.keys(this.loginData).forEach((item) => {
this.$set(this.loginData, item, false);
});
this.$set(this.loginData, val, true);
},
//
stateLogin(state) {
loginCallback(state).then((res) => {
@ -134,9 +263,362 @@ export default {
}
});
},
/** 根据参数显示登录模块 */
methodFilter(code) {
let way = [];
this.loginList.forEach((item) => {
if (code.length != 0) {
code.forEach((val) => {
if (item.code == val) {
way.push(item);
}
});
} else {
uni.showToast({
title: "配置有误请联系管理员",
duration: 2000,
icon: "none",
});
}
});
this.loginList = way;
},
//h5 openid
async nonH5OpenId(item) {
let _this = this;
//openid
await uni.login({
provider: item.appcode,
// #ifdef MP-ALIPAY
scopes: "auth_user", //
// #endif
success: function (res) {
uni.setStorageSync("type", item.code);
//storageopenid
// #ifndef MP-WEIXIN
uni.setStorageSync("openid", res.authResult.openid);
// #endif
},
fail(e) {
uni.showToast({
title: "第三方登录暂不可用!",
icon: "none",
duration: 3000,
});
},
complete(e) {
//
uni.getUserInfo({
provider: item.appcode,
success: function (infoRes) {
//
uni.setStorageSync("nickname", infoRes.userInfo.nickName);
uni.setStorageSync("avatar", infoRes.userInfo.avatarUrl);
// #ifdef MP-WEIXIN
//openid openiduni-id: https://uniapp.dcloud.net.cn/uniCloud/uni-id
_this.weixinMPOpenID(res).then((res) => {
//openid使openid
_this.goOpenidLogin("WECHAT_MP");
});
// #endif
// #ifndef MP-WEIXIN
_this.goOpenidLogin("APP");
//#endif
},
});
},
});
},
//openid
goOpenidLogin(clientType) {
//
let params = {
uuid: uni.getStorageSync("openid"), //id
source: uni.getStorageSync("type"), //
nickname: uni.getStorageSync("nickname"), //
avatar: uni.getStorageSync("avatar"), //
uniAccessToken: uni.getStorageSync("uni_access_token"), //token
};
openIdLogin(params, clientType).then((res) => {
if (!res.data.success) {
let errormessage = "第三方登录暂不可用";
uni.showToast({
// title: '',
title: errormessage,
icon: "none",
duration: 3000,
});
return;
} else {
storage.setAccessToken(res.data.result.accessToken);
storage.setRefreshToken(res.data.result.refreshToken);
//
uni.showToast({
title: "第三方登录成功!",
icon: "none",
});
//
getUserInfo().then((user) => {
if (user.data.success) {
/**
* 个人信息存储到缓存userInfo中
*/
storage.setUserInfo(user.data.result);
storage.setHasLogin(true);
/**
* 计算出当前router路径
* 1.如果跳转的链接为登录页面或跳转的链接为空页面则会重新跳转到首页
* 2.都不满足返回跳转页面
*/
whetherNavigate();
} else {
uni.switchTab({
url: "/pages/tabbar/home/index",
});
}
});
}
});
},
//openid
async weixinMPOpenID(res) {
await miniProgramLogin(res.code).then((res) => {
uni.setStorageSync("openid", res.data);
});
},
/**跳转到登录页面 */
navigateLogin(connectLogin) {
// #ifdef H5
let code = connectLogin.code;
let buyer = api.buyer;
window.open(buyer + `/connect/login/web/` + code, "_self");
// #endif
// #ifdef APP-PLUS
this.nonH5OpenId(connectLogin);
// #endif
},
//
submit() {
/**
* 清空当前账号信息
*/
storage.setHasLogin(false);
storage.setAccessToken("");
storage.setRefreshToken("");
storage.setUuid(this.uuid.v1());
storage.setUserInfo({});
/**
* 执行登录
*/
smsLogin({ mobile: this.mobile, code: this.code }, this.clientType).then(
(res) => {
if (res.data.success) {
storage.setAccessToken(res.data.result.accessToken);
storage.setRefreshToken(res.data.result.refreshToken);
/**
* 登录成功后获取个人信息
*/
getUserInfo().then((user) => {
if (user.data.success) {
/**
* 个人信息存储到缓存userInfo中
*/
storage.setUserInfo(user.data.result);
storage.setHasLogin(true);
//
uni.showToast({
title: "登录成功!",
icon: "none",
});
/**
* 计算出当前router路径
* 1.如果跳转的链接为登录页面或跳转的链接为空页面则会重新跳转到首页
* 2.都不满足返回跳转页面
*/
whetherNavigate();
} else {
uni.switchTab({
url: "/pages/tabbar/home/index",
});
}
});
}
}
);
},
//
verification(val) {
this.flage = val == this.$store.state.verificationKey ? true : false;
},
//
navigateToPrivacy(val) {
uni.navigateTo({
url: "/pages/mine/help/tips?type=" + val,
});
},
//
start() {
this.codeColor = "#999";
this.$u.toast("验证码已发送");
this.flage = false;
this.codeFlag = false;
this.$refs.verification.hide();
},
/**点击验证码*/
codeChange(text) {
this.tips = text;
},
/** 结束验证码后执行 */
end() {
this.codeColor = this.lightColor;
console.log(this.codeColor);
},
//
fetchCode() {
if (!this.enabulePrivacy) {
uni.showToast({
title: "请同意用户隐私",
duration: 2000,
icon: "none",
});
return false;
}
if (!this.$u.test.mobile(this.mobile)) {
uni.showToast({
title: "请填写正确手机号",
duration: 2000,
icon: "none",
});
return false;
}
if (this.tips == "重新获取验证码") {
uni.showLoading({
title: "加载中",
});
if (!this.codeFlag) {
this.codeFlag = true;
let timer = setInterval(() => {
if (this.$refs.verification) {
this.$refs.verification.error(); //
}
clearInterval(timer);
}, 100);
}
uni.hideLoading();
}
if (!this.flage) {
this.$refs.verification.error(); //
return false;
}
},
},
};
</script>
<style lang="scss" scoped>
@import url("./login.scss");
<style >
page {
background: #fff;
}
</style>
<style lang="scss" scoped>
.wrapper {
padding: 0 80rpx;
}
.title {
padding-top: calc(104rpx);
font-style: normal;
line-height: 1;
font-weight: 500;
font-size: 56rpx;
color: #333;
}
.box-code {
margin-top: 78rpx;
}
.desc,
.desc-light {
font-size: 32rpx;
line-height: 32rpx;
color: #333333;
margin-top: 40rpx;
}
.desc {
color: #333;
}
.desc-light {
color: #999999;
> span {
color: #333;
margin-left: 8rpx;
}
}
.mobile {
margin-top: 80rpx;
}
.disable {
background: linear-gradient(90deg, #ffdcba 2.21%, #ffcfb2 99.86%);
}
.fetch {
background: linear-gradient(57.72deg, #ff8a19 18.14%, #ff5e00 98.44%);
}
.btn {
border-radius: 100px;
width: 590rpx;
margin-top: 97rpx;
height: 80rpx;
font-size: 30rpx;
line-height: 80rpx;
text-align: center;
color: #ffffff;
}
.tips {
font-size: 12px;
line-height: 20px;
margin-top: 32rpx;
width: 546rpx;
> span {
color: $light-color;
}
}
.fetch-btn {
width: 370rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
background: #f2f2f2;
border-radius: 100rpx;
font-size: 28rpx;
color: #999;
margin: 71rpx auto 0 auto;
}
.login-list {
display: flex;
width: 590rpx;
position: absolute;
bottom: 20px;
align-items: center;
justify-content: space-around;
}
.login-item {
width: 80rpx;
border-radius: 10rpx;
height: 80rpx;
display: flex;
justify-content: center;
align-items: center;
}
</style>

View File

@ -1,8 +0,0 @@
/deep/ .u-form-item {
margin: 40rpx 0 !important;
padding: 40rpx 0 !important;
}
.submit {
margin-top: 40rpx;
}

View File

@ -1,296 +0,0 @@
<template>
<div class="form">
<u-form ref="validateCodeForm">
<div class="login-list">
<!-- 循环出当前可使用的第三方登录模式 -->
<div :style="{background:item.color}" class="login-item" v-for="(item,index) in loginList" :key="index">
<u-icon v-if="item.title!='APPLE'" color="#fff" size="42" :name="item.icon" @click="navigateLogin(item)"></u-icon>
<u-image v-else src="/static/appleidButton@2x.png" :lazy-load="false" @click="navigateLogin(item)" width="80" height="80" />
</div>
</div>
<view :style="{color:aiderLightColor}" class="text-tips cell" @click="clickCodeLogin"></view>
</u-form>
</div>
</template>
<script>
import { openIdLogin } from "@/api/connect.js";
import { whetherNavigate } from "@/utils/Foundation"; //
import { getUserInfo } from "@/api/members";
import storage from "@/utils/storage.js";
import api from "@/config/api.js";
export default {
data() {
return {
aiderLightColor: this.$aiderLightColor,
loginList: [
{
icon: "weixin-fill",
color: "#00a327",
title: "微信",
code: "WECHAT",
},
{
icon: "qq-fill",
color: "#38ace9",
title: "QQ",
code: "QQ",
},
{
icon: "apple-fill",
color: "#000000",
title: "Apple",
code: "APPLE",
},
],
tips: "",
};
},
props: ["status"],
mounted() {
//#ifdef APP-PLUS
/**如果是app 加载支持的登录方式*/
let _this = this;
uni.getProvider({
service: "oauth",
success: (result) => {
_this.loginList = result.provider.map((value) => {
//title
let title = "";
//code
let code = "";
//
let color = "#8b8b8b";
//
let icon = "";
//uni code
let appcode = "";
switch (value) {
case "weixin":
icon = "weixin-circle-fill";
color = "#00a327";
title = "微信";
code = "WECHAT";
break;
case "qq":
icon = "qq-circle-fill";
color = "#38ace9";
title = "QQ";
code = "QQ";
break;
case "apple":
icon = "apple-fill";
color = "#000000";
title = "Apple";
code = "APPLE";
break;
}
return {
title: title,
code: code,
color: color,
icon: icon,
appcode: value,
};
});
},
fail: (error) => {
uni.showToast({
title: "获取登录通道失败" + error,
duration: 2000,
icon: "none",
});
},
});
//#endif
//
// #ifdef H5
this.methodFilter(["QQ"]);
// #endif
//
// #ifdef MP-WEIXIN
this.methodFilter(["WECHAT"]);
// #endif
},
methods: {
/** 根据参数显示登录模块 */
methodFilter(code) {
let way = [];
this.loginList.forEach((item) => {
if (code.length != 0) {
code.forEach((val) => {
if (item.code == val) {
way.push(item);
}
});
} else {
uni.showToast({
title: "配置有误请联系管理员",
duration: 2000,
icon: "none",
});
}
});
this.loginList = way;
},
/**跳转到登录页面 */
navigateLogin(connectLogin) {
if (!this.status) {
uni.showToast({
title: "请您阅读并同意用户协议以及隐私政策",
duration: 2000,
icon: "none",
});
return false;
}
// #ifdef H5
let code = connectLogin.code;
let buyer = api.buyer;
window.open(buyer + `/connect/login/web/` + code, "_self");
// #endif
// #ifdef APP-PLUS
this.nonH5OpenId(connectLogin);
// #endif
},
//
clickCodeLogin() {
this.$emit("open", "code");
},
//h5 openid
async nonH5OpenId(item) {
let _this = this;
//openid
await uni.login({
provider: item.appcode,
// #ifdef MP-ALIPAY
scopes: "auth_user", //
// #endif
success: function (res) {
uni.setStorageSync("type", item.code);
//storageopenid
// #ifndef MP-WEIXIN
uni.setStorageSync("openid", res.authResult.openid);
// #endif
},
fail(e) {
uni.showToast({
title: "第三方登录暂不可用!",
icon: "none",
duration: 3000,
});
},
complete(e) {
//
uni.getUserInfo({
provider: item.appcode,
success: function (infoRes) {
//
uni.setStorageSync("nickname", infoRes.userInfo.nickName);
uni.setStorageSync("avatar", infoRes.userInfo.avatarUrl);
// #ifdef MP-WEIXIN
//openid openiduni-id: https://uniapp.dcloud.net.cn/uniCloud/uni-id
_this.weixinMPOpenID(res).then((res) => {
//openid使openid
_this.goOpenidLogin("WECHAT_MP");
});
// #endif
// #ifndef MP-WEIXIN
_this.goOpenidLogin("APP");
//#endif
},
});
},
});
},
//openid
goOpenidLogin(clientType) {
let _this = this;
//
let params = {
uuid: uni.getStorageSync("openid"), //id
source: uni.getStorageSync("type"), //
nickname: uni.getStorageSync("nickname"), //
avatar: uni.getStorageSync("avatar"), //
uniAccessToken: uni.getStorageSync("uni_access_token"), //token
};
openIdLogin(params, clientType).then((res) => {
if (!res.data.success) {
let errormessage = "第三方登录暂不可用";
uni.showToast({
// title: '',
title: errormessage,
icon: "none",
duration: 3000,
});
return;
} else {
storage.setAccessToken(res.data.result.accessToken);
storage.setRefreshToken(res.data.result.refreshToken);
//
uni.showToast({
title: "第三方登录成功!",
icon: "none",
});
//
getUserInfo().then((user) => {
if (user.data.success) {
/**
* 个人信息存储到缓存userInfo中
*/
storage.setUserInfo(user.data.result);
storage.setHasLogin(true);
/**
* 计算出当前router路径
* 1.如果跳转的链接为登录页面或跳转的链接为空页面则会重新跳转到首页
* 2.都不满足返回跳转页面
*/
whetherNavigate();
} else {
uni.switchTab({
url: "/pages/tabbar/home/index",
});
}
});
}
});
},
//openid
async weixinMPOpenID(res) {
await miniProgramLogin(res.code).then((res) => {
uni.setStorageSync("openid", res.data);
});
},
},
};
</script>
<style lang="scss" scoped>
@import url("./login.scss");
.login-list {
margin: 140rpx 0;
display: flex;
align-items: center;
justify-content: space-around;
}
.login-item {
width: 80rpx;
border-radius: 10rpx;
height: 80rpx;
display: flex;
justify-content: center;
align-items: center;
}
</style>

View File

@ -410,17 +410,7 @@ export default {
routerVal: "",
};
},
// #ifdef MP-WEIXNI
shareAppMessage() {
return {
title: this.goodsDetail.goodsName,
type: 0,
query: `id=${this.routerVal.id}&goodsId=${this.routerVal.goodsId}`,
path: `/pages/product/goods`,
imageUrl: this.goodsDetail.goodsGalleryList[0],
};
},
// #endif
watch: {
isGroup(val) {
if (val) {
@ -483,7 +473,7 @@ export default {
getMpScene(this.routerVal.scene).then((res) => {
if (res.data.success) {
let data = res.data.result.split(","); // skuId,goodsId,distributionId
console.warn(data)
console.warn(data);
this.init(data[0], data[1], data[2]);
}
});
@ -495,7 +485,19 @@ export default {
);
}
},
// #ifdef MP-WEIXIN
onShareAppMessage(res) {
return {
path: this.share(),
title: `[好友推荐]${this.goodsDetail.goodsName}`,
imageUrl: this.goodsDetail.goodsGalleryList[0],
};
},
// #endif
methods: {
share() {
return `/pages/product/goods?id=${this.routerVal.id}&goodsId=${this.routerVal.goodsId}`;
},
/**
* 导航栏列表栏
*/
@ -527,6 +529,8 @@ export default {
//
let response = await getGoods(id, goodsId);
console.log(response);
if (!response.data.success) {
setTimeout(() => {
uni.navigateBack();
@ -536,7 +540,7 @@ export default {
if (distributionId || this.$store.state.distributionId) {
let disResult = await getGoodsDistribution(distributionId);
if (!disResult.data.success || disResult.statusCode == 403) {
console.log("绑定成功!")
console.log("绑定成功!");
this.$store.state.distributionId = distributionId;
}
}

View File

@ -53,7 +53,7 @@
</view>
</view>
<!-- 商品信息 -->
<view class="goods-skus-box">
<scroll-view class="goods-skus-box" :scroll-y="true">
<!-- 规格 -->
<view class="goods-skus-view" :key="specIndex" v-for="(spec, specIndex) in formatList">
<view class="skus-view-list">
@ -71,7 +71,7 @@
v-model="num">
</u-number-box>
</view>
</view>
</scroll-view>
<!-- 按钮 -->
<view class="btns">
@ -86,6 +86,7 @@
<script>
import * as API_trade from "@/api/trade.js";
import setup from "./popup";
export default {
data() {
return {
@ -148,7 +149,7 @@ export default {
/**点击规格 */
handleClickSpec(val, index, specValue) {
this.$set(this.currentSelceted, index, specValue.value);
this.currentSelceted[index] = specValue.value;
let selectedSkuId = this.goodsSpec.find((i) => {
let matched = true;
let specValues = i.specValues.filter((j) => j.specName !== "images");
@ -162,6 +163,8 @@ export default {
return i;
}
});
if (selectedSkuId?.skuId) {
this.$set(this.currentSelceted, index, specValue.value);
this.selectSkuList = {
spec: {
specName: val.name,
@ -175,6 +178,13 @@ export default {
skuId: selectedSkuId.skuId,
goodsId: this.goodsDetail.goodsId,
});
} else {
uni.showToast({
title: "暂无该商品!",
duration: 2000,
icon: "none",
});
}
},
/**
@ -230,7 +240,7 @@ export default {
},
formatSku(list) {
//
console.log(list);
let arr = [{}];
list.forEach((item, index) => {
item.specValues.forEach((spec, specIndex) => {
@ -238,6 +248,7 @@ export default {
let values = {
value: spec.specValue,
quantity: item.quantity,
skuId: item.skuId,
};
if (name === "images") {
return;
@ -247,7 +258,9 @@ export default {
if (
arrItem.name == name &&
arrItem.values &&
!arrItem.values.find((i) => i.value === values.value)
!arrItem.values.find((i) => {
return i.value === values.value;
})
) {
arrItem.values.push(values);
}
@ -256,6 +269,7 @@ export default {
return key.name;
});
if (!keys.includes(name)) {
console.log(name, values);
arr.push({
name: name,
values: [values],
@ -269,6 +283,7 @@ export default {
this.formatList = arr;
list.forEach((item) => {
//
if (item.skuId === this.goodsDetail.id) {
item.specValues
.filter((i) => i.specName !== "images")
@ -286,13 +301,12 @@ export default {
});
this.skuList = list;
// console.log(" this.skuList", this.skuList)
},
},
mounted() {
this.formatSku(this.goodsSpec);
console.log(this.goodsDetail);
},
};
</script>

View File

@ -71,7 +71,8 @@ page {
font-size: 32rpx;
}
.-goods-desc {
padding: 36rpx 0 24rpx 0;
padding: 36rpx 0 0 0;
margin-bottom: 24rpx;
font-size: 24rpx;
color: #666;
display: -webkit-box;

View File

@ -26,17 +26,17 @@
@change="checkboxChangeDP(item)"></u-checkbox>
<!-- #endif -->
</u-checkbox-group>
<span class="storeName store-line-desc" @click.stop="navigateToStore(item)">{{
<span class="store-name store-line-desc" @click.stop="navigateToStore(item)">{{
item.storeName
}}</span>
</view>
<view class="right_Col" @click="navigateToConpon(item)">
<div class="right_Line"></div>
<view class="right-col" @click="navigateToConpon(item)">
<div class="right-line"></div>
<span>领劵</span>
</view>
</view>
<u-swipe-action :show="skuItem.selected" @open="openAction(skuItem)" :options="options" bg-color="#fff"
ref="swiperAction" class="cartItem" v-for="(skuItem, i) in item.skuList" :index="i" :key="skuItem.goodsSku.id"
ref="swiperAction" class="cart-item" v-for="(skuItem, i) in item.skuList" :index="i" :key="skuItem.goodsSku.id"
@click="changeActionTab(skuItem)" @longpress="changeActionTab(skuItem)">
<!-- 满减活动 -->
<div v-if="skuItem.promotions" v-for="(fullDiscount,fullDiscountIndex) in skuItem.promotions"
@ -64,8 +64,8 @@
</u-checkbox-group>
<span class="invalid" v-else style="font-size: 24rpx">失效</span>
</view>
<u-image border-radius="20" :fade="true" @click="navigateToGoods(skuItem)" width="200rpx"
height="200rpx" :src="skuItem.goodsSku.thumbnail" />
<u-image border-radius="10" :fade="true" @click="navigateToGoods(skuItem)" width="160rpx" height="160rpx"
:src="skuItem.goodsSku.thumbnail" />
</view>
<view class="goods-content">
<!-- 商品名称 -->
@ -76,7 +76,8 @@
<p class="sp-type">{{skuItem.goodsSku.simpleSpecs}}</p>
<p class="sp-number">
<view class="sp-price">
<div class="default-color" :class="{'theme-color':skuItem.promotions.length <=0 }">
<div class="default-color" :class="{'main-color':skuItem.promotions.length ==0 }">
<span>{{ formatPrice(skuItem.goodsSku.price)[0] }}</span>
<span>.{{ formatPrice(skuItem.goodsSku.price)[1] }}</span>
</div>
@ -101,11 +102,10 @@
font-size="24" :timestamp="getCountDownTime(seckill.endTime)">
</u-count-down>
</div>
</div>
<!-- 如果有活动 并且是选中的状态,显示预估到手价格 -->
<div class="priceDetail-flowPrice" :class="{'theme-color':skuItem.priceDetailDTO}"
<div class="priceDetail-flowPrice" :class="{'main-color':skuItem.priceDetailDTO}"
v-if="skuItem.priceDetailDTO && skuItem.invalid == 0 && skuItem.promotions.length!=0 && skuItem.checked && skuItem.checked">
预估到手价 <span>{{ formatPrice(skuItem.priceDetailDTO.flowPrice)[0]}}</span>
<span>.{{ formatPrice(skuItem.priceDetailDTO.flowPrice)[1] }} </span>
@ -137,7 +137,7 @@
class="discountPrice">
<span>优惠减:{{(cartDetail.priceDetailDTO.goodsPrice - cartDetail.priceDetailDTO.flowPrice) | unitPrice}}
</span>
<span class="discountDetails" @click="discountDetails"></span>
<span class="discount-details" @click="discountDetails"></span>
</div>
</div>
</span>
@ -208,6 +208,7 @@ export default {
WEIXIN_num: "", //
};
},
mounted() {
// #ifdef MP-WEIXIN
//
@ -542,6 +543,11 @@ export default {
};
</script>
<style lang="scss">
page {
background: #f2f2f2;
}
</style>
<style scoped lang="scss">
// #ifdef MP-WEIXIN
@import "./mp-carui.scss";
@ -566,7 +572,9 @@ export default {
color: #fff;
}
}
.default-color {
color: #333;
}
.goods-row {
padding: 30rpx 0;
@ -574,20 +582,18 @@ export default {
align-items: center;
}
.storeName {
.store-name {
font-weight: bold;
}
.invalid {
filter: grayscale(1);
}
.cartItem {
.cart-item {
border-radius: 0.4em;
transition: 0.35s;
}
/* 空白页 */
/deep/ .u-number-input {
background: #fff !important;
@ -660,16 +666,16 @@ export default {
}
.box2 {
border-radius: 30rpx;
padding: 32rpx 40rpx 32rpx;
border-radius: 20rpx;
padding: 0 16rpx 0;
margin: 0 16rpx 20rpx;
.u-checkbox {
display: flex;
align-items: center;
text-align: center;
}
background: #fff;
margin-bottom: 20rpx;
}
.wrapper {
@ -689,11 +695,6 @@ export default {
}
}
.allCheck {
// padding: 0 10rpx;
font-size: 24rpx;
}
.content {
padding: 20rpx 0 20rpx 0;
margin-bottom: 80rpx;
@ -733,10 +734,10 @@ export default {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx 0;
padding: 30rpx 0 0 0;
}
.right_Col {
.right-col {
color: $light-color;
font-size: 26rpx;
@ -745,7 +746,7 @@ export default {
}
}
.right_Line {
.right-line {
width: 3px;
float: left;
height: 40rpx;
@ -782,7 +783,6 @@ export default {
}
}
.sp-type {
color: $u-light-color;
padding: 10rpx 0;
@ -794,9 +794,8 @@ export default {
white-space: nowrap;
}
.default-color {
color: #333;
}.sp-number {
.sp-number {
font-weight: bold;
display: flex;
@ -829,7 +828,7 @@ export default {
color: rgb(201, 199, 199);
}
}
.discountDetails {
.discount-details {
margin-left: 10px;
color: #666;
padding: 4rpx 10rpx;

View File

@ -1,5 +1,6 @@
.box2 {
padding: calc(32rpx) 40rpx 32rpx !important;
padding: 0 16rpx 0;
margin: 0 16rpx 20rpx;
}
.uNumber{

View File

@ -61,7 +61,7 @@ $font-weight: 400;
color: $light-color;
}
.main-color {
color: $main-color;
color: $main-color !important;
}
.bg-light-color {
background-color: $light-color !important;